Browse Source

done?

master
mortie 7 years ago
parent
commit
43d937956f
6 changed files with 233 additions and 54 deletions
  1. 11
    15
      inf2440/hw2/Main.java
  2. 91
    31
      inf2440/hw2/Parallel.java
  3. 14
    5
      inf2440/hw2/Sequential.java
  4. 4
    3
      inf2440/hw2/Test.java
  5. 37
    0
      inf2440/hw2/output.txt
  6. 76
    0
      inf2440/hw2/rapport.txt

+ 11
- 15
inf2440/hw2/Main.java View File

@@ -12,13 +12,12 @@ class Main {
t.start();
s.solve(sieve);
t.end();
System.out.println("Test "+i+": "+t.prettyTime());
}

return Timer.median(timers);
}

static Timer testFactor(Solver s, int maxNum, Sieve sieve) {
static Timer testFactor(Solver s, long maxNum, Sieve sieve) {
Timer[] timers = new Timer[nTests];

for (int i = 0; i < nTests; ++i) {
@@ -26,20 +25,17 @@ class Main {
t.start();
long n = maxNum * maxNum;
for (long j = n; j >= n - 100; --j) {
Timer t2 = new Timer().start();
long[] factors = s.factor(sieve, j);
t2.end();

if (j > (n - 5) || j < (n - 95)) {
if (j == n - 95)
if (j == n - 96)
System.out.println(".............");

System.out.println(
t2.prettyTime()+" "+
Util.factors(j, factors));
}
}
t.end();
System.out.println("Test "+i+": "+t.prettyTime());
}

return Timer.median(timers);
@@ -54,7 +50,7 @@ class Main {
Sequential sseq = new Sequential();
Parallel spar = new Parallel();

boolean findPrimes = false;
boolean findPrimes = true;
boolean factor = true;

int maxNum = Integer.parseInt(args[0]);
@@ -63,11 +59,11 @@ class Main {
if (findPrimes) {
System.out.println("\nFinding primes sequentially...");
Timer seq = testFindPrimes(sseq, maxNum);
System.out.println("Sequential median: "+seq.prettyTime());
System.out.println("Sequential: "+seq.prettyTime());

System.out.println("\nFinding primes in parallel...");
Timer par = testFindPrimes(sseq, maxNum);
System.out.println("Parallel median: "+par.prettySpeedup(seq));
Timer par = testFindPrimes(spar, maxNum);
System.out.println("Parallel: "+par.prettySpeedup(seq));
}

if (factor) {
@@ -75,13 +71,13 @@ class Main {
Sieve sieve = new Sieve(maxNum);
spar.solve(sieve);

System.out.println("\nFactorizing sequentially...");
System.out.println("\nFactoring sequentially...");
Timer seq = testFactor(sseq, maxNum, sieve);
System.out.println("Sequential median: "+seq.prettyTime());
System.out.println("Sequential: "+seq.prettyTime());

System.out.println("\nFactorizing in parallel...");
System.out.println("\nFactoring in parallel...");
Timer par = testFactor(spar, maxNum, sieve);
System.out.println("Parallel median: "+par.prettySpeedup(seq));
System.out.println("Parallel: "+par.prettySpeedup(seq));
}

spar.stopThreads();

+ 91
- 31
inf2440/hw2/Parallel.java View File

@@ -60,19 +60,36 @@ class Parallel implements Solver {
FactorMonitor monitor;
int step;
int offset;
int num;
long num;
long currentPrime;
long biggestPossible;
Sieve sieve;
boolean ready = false;
boolean done = false;

// Offset should start at 0
synchronized public void start(FactorMonitor monitor, int step, int offset) {
this.monitor = monitor;
this.step = step;
this.offset = offset;
this.num = monitor.currentNum;
this.biggestPossible = (long)Math.sqrt(num);
this.sieve = monitor.sieve;
ready = true;
notify();

this.ready = true;
this.done = false;

findFirstPrime();
}

void findFirstPrime() {
currentPrime = 3;
for (int i = 0; i < offset; ++i) {
currentPrime += 2;
while (!monitor.isPrime(currentPrime))
currentPrime += 2;
}
}

synchronized public void stop() {
@@ -81,24 +98,46 @@ class Parallel implements Solver {
notify();
}

void nextPrime() {
if (currentPrime > biggestPossible)
return;

for (int i = 0; i < step; ++i) {
currentPrime += 2;
while (!monitor.isPrime(currentPrime) && currentPrime <= biggestPossible)
currentPrime += 2;

if (currentPrime > biggestPossible) {
this.ready = false;
monitor.foundBiggest();
return;
}
}
}

void findFactor() {
boolean found = false;
while (!found && this.ready) {
if ((num % currentPrime) == 0) {
found = true;
if (!monitor.addFactor(currentPrime, num)) {
this.num = monitor.currentNum;
findFirstPrime();
return;
}
}

nextPrime();
}
}

synchronized public void run() {
while (!ready && !done)
try { wait(); } catch (InterruptedException ex) {}

while (!done) {
while (!monitor.isDone()) {
num = monitor.currentNum;
int limit = num / 2;
for (int i = offset; i <= limit; i += (step * 2)) {
if (i == 1)
continue;

if (num % i == 0 && sieve.isPrime(i)) {
if (!monitor.addFactor(i, num)) {
this.num = monitor.currentNum;
}
}
}
while (!monitor.isDone() && this.ready) {
findFactor();
}

ready = false;
@@ -110,30 +149,34 @@ class Parallel implements Solver {
}

class FactorMonitor {
int currentNum;
Sieve sieve;
long original;
long currentNum;
int biggestLeft;

boolean done = false;
ArrayList<Integer> arr = new ArrayList<>();
ArrayList<Long> arr = new ArrayList<>();

FactorMonitor(Sieve sieve, int num) {
FactorMonitor(Sieve sieve, long num, int nThreads) {
this.sieve = sieve;
this.original = num;
this.currentNum = num;
this.biggestLeft = nThreads;

// We don't want to have to deal with the fact that 2 is a prime
if (num % 2 == 0)
addFactor(2, num);
}

synchronized boolean addFactor(int factor, int num) {
synchronized boolean addFactor(long factor, long num) {
// If the thread is working with a stale num,
// just discard it and tell the thread to restart.
if (num != currentNum) {
if (num != currentNum)
return false;
}

while ((currentNum % factor) == 0) {
currentNum /= factor;
Integer i = new Integer(factor);
Long i = new Long(factor);
arr.add(i);
}
notify();
@@ -141,15 +184,29 @@ class Parallel implements Solver {
return true;
}

synchronized void foundBiggest() {
this.biggestLeft -= 1;
if (biggestLeft == 0) {
done = true;
notify();
}
}

boolean isPrime(long num) {
if (num > sieve.maxNum)
return false;
else
return sieve.isPrime((int)num);
}

synchronized boolean isDone() {
if (done) {
return true;
} else if (sieve.isPrime(currentNum)) {
} else if (isPrime(currentNum)) {
done = true;
if (currentNum != 1)
arr.add(new Integer(currentNum));
else
notify();
arr.add(new Long(currentNum));
notify();
return true;
} else {
return false;
@@ -160,6 +217,10 @@ class Parallel implements Solver {
while (!isDone())
try { wait(); } catch (InterruptedException ex) {}

Long curr = new Long(currentNum);
if (currentNum > (long)Math.sqrt(original) && !arr.contains(curr))
arr.add(curr);

long[] a = new long[arr.size()];
for (int i = 0; i < a.length; ++i) {
a[i] = arr.get(i);
@@ -171,12 +232,11 @@ class Parallel implements Solver {
FactorWorker[] factorWorkers = null;
Thread[] factorThreadPool = null;

public long[] factor(Sieve sieve, long lnum) {
int num = (int)lnum;
public long[] factor(Sieve sieve, long num) {
int nThreads = Runtime.getRuntime().availableProcessors();
nThreads = Math.min(nThreads, 8);

if (sieve.isPrime(num))
if (num <= sieve.maxNum && sieve.isPrime((int)num))
return new long[] { num };

// Initiate thread pool
@@ -191,12 +251,12 @@ class Parallel implements Solver {
}
}

FactorMonitor monitor = new FactorMonitor(sieve, num);
FactorMonitor monitor = new FactorMonitor(sieve, num, nThreads);

// Start workers
for (int i = 0; i < nThreads; ++i) {
FactorWorker w = factorWorkers[i];
w.start(monitor, nThreads, (i * 2) + 1);
w.start(monitor, nThreads, i);
}

long[] arr = monitor.getFactors();

+ 14
- 5
inf2440/hw2/Sequential.java View File

@@ -9,21 +9,30 @@ class Sequential implements Solver {
if (num < sieve.maxNum && sieve.isPrime((int)num))
return new long[] { num };

int sqrt = (int)Math.sqrt(num);

ArrayList<Long> arr = new ArrayList<>();

while (true) {
for (long i = 2; true; ++i) {
if (num % i == 0) {
arr.add(new Long(i));
num /= i;
long prime;
for (prime = 2; prime <= sqrt; ++prime) {
if (num % prime == 0) {
arr.add(new Long(prime));
num /= prime;
break;
}
}

if (sieve.isPrime((int)num)) {
if (prime > sqrt) {
arr.add(new Long(num));
break;
}

if (num <= sqrt && sieve.isPrime((int)num)) {
if (num != 1)
arr.add(new Long(num));
break;
}
}

long[] a = new long[arr.size()];

+ 4
- 3
inf2440/hw2/Test.java View File

@@ -5,7 +5,7 @@ class Test {
String desc;

{ desc = "Sequential and Parallel solvers produce the same primes";
int maxNum = 100000;
int maxNum = 200000;
Sieve sieve1 = new Sieve(maxNum);
Sieve sieve2 = new Sieve(maxNum);

@@ -36,7 +36,7 @@ class Test {
}

{ desc = "Sequential and parallel produces the same factors";
int maxNum = 1000;
int maxNum = 10000000;
Sieve sieve = new Sieve(maxNum);

Sequential s1 = new Sequential();
@@ -45,7 +45,8 @@ class Test {
s2.solve(sieve);

boolean failed = false;
for (long i = 900; i < maxNum; ++i) {
long num = maxNum * maxNum;
for (long i = num - 100; i < num; ++i) {
long[] arr1 = s1.factor(sieve, i);
long[] arr2 = s2.factor(sieve, i);


+ 37
- 0
inf2440/hw2/output.txt View File

@@ -0,0 +1,37 @@
elli ~/tmp $ java Main 2000000000
Max prime: 2000000000

Finding primes sequentially...
Sequential: 9.83s

Finding primes in parallel...
Parallel: 6.92s (1.42x speedup)

Factoring sequentially...
4000000000000000000 = 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
3999999999999999999 = 3 * 31 * 64516129 * 666666667
3999999999999999998 = 2 * 432809599 * 4620969601
3999999999999999997 = 421 * 9501187648456057
3999999999999999996 = 2 * 2 * 3 * 3 * 3 * 3 * 7 * 11 * 13 * 19 * 37 * 52579 * 333667
.............
3999999999999999904 = 2 * 2 * 2 * 2 * 2 * 1061 * 117813383600377
3999999999999999903 = 3 * 101 * 241 * 54777261958561
3999999999999999902 = 2 * 49965473 * 40027640687
3999999999999999901 = 19 * 2897 * 72670457642207
3999999999999999900 = 2 * 2 * 3 * 5 * 5 * 89 * 1447 * 1553 * 66666667
Sequential: 1176.19s

Factoring in parallel...
4000000000000000000 = 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
3999999999999999999 = 3 * 31 * 64516129 * 666666667
3999999999999999998 = 2 * 432809599 * 4620969601
3999999999999999997 = 421 * 9501187648456057
3999999999999999996 = 2 * 2 * 3 * 3 * 3 * 3 * 7 * 11 * 13 * 19 * 37 * 52579 * 333667
.............
3999999999999999904 = 2 * 2 * 2 * 2 * 2 * 1061 * 117813383600377
3999999999999999903 = 3 * 101 * 241 * 54777261958561
3999999999999999902 = 2 * 49965473 * 40027640687
3999999999999999901 = 19 * 2897 * 72670457642207
3999999999999999900 = 2 * 2 * 3 * 5 * 5 * 89 * 1447 * 1553 * 66666667
Parallel: 356.50s (3.30x speedup)


+ 76
- 0
inf2440/hw2/rapport.txt View File

@@ -0,0 +1,76 @@
Kompilering: `javac *.java`
Kjøring: `java Main <tall>`

# Eksempelutskrift

I filen output.txt finner du et eksempel på å kjøre `java Main 2000000000`.

# Hvordan jeg har parallellisert

## Sil

Silen har jeg parallellisert ved å først generere de sqrt(n) første
primtallene sekvensielt, og så lager jeg n tråder som hver får en kopi av
det arrayet som har løst de sqrt(n) første tallene. Hver tråd krysser av
en del av tallene som ikke primtall. Når alle trådene er ferdige, slår jeg
sammen arrayene til de forskjellige trådene ved å ORe hver byte i hvert array,
slik at bare de tallene som ingen har markert som ikke primtall blir igjen.
Jeg bruker OR istedenfor AND fordi jeg lar 0 bety at tallet er primtall og
1 bety at det ikke er primtall, fordi det gjør at jeg slipper å gå igjennom
hele arrayet og sette hver byte til 11111111 når jeg oppretter silen,
siden et array av tall i Java starter som et array av 0.

## Faktorisering

Hver tråd får en del av primtallene opp til sqrt(n). Tråden går igjennom disse
primtallene, og når den finner et primtall som n kan deles på, gir den det
tallet til en monitor, som legger det til i en liste over faktorer og deler n
på primtallet. Alle trådene må deretter oppdatere hvilket tall de jobber med
og begynne på nytt. Når trådene har kommet til et tall som er større enn
sqrt(n) uten å finne faktorer, stopper tråden. Når alle trådene har stoppet,
vet monitoren at den er ferdig. Hvis tallet monitoren har kommet frem til så
langt etter å ha latt trådene faktorisere, er større enn sqrt(n), legges dette
tallet til listen faktorer, siden vi da vet at det er en faktor.

Måten primtallene fordeles på, er at hver tråd tar hvert n-te primtall, hvor n
er antall tråder, og hver tråd gis en unik startposisjon. Hvis det for eksempel
er 2 tråder, vil tråd 1 ta primtall 1(3), 3(7), 5(13), etc, og tråd 2 vil ta
primtall 2(5), 4(11), 6(17), etc. (I trådene later jeg som at alle primtall er
oddetall og at 3 er det første primtallet, og lar monitoren ta seg av 2, fordi
det gjør ting mye lettere.)

Legg også merke til at jeg gjenbruker trådene mine, fordi det hadde tatt en del
tid å lage 400 tråder, 4 for hver faktorisering.

Noe jeg kunne ha gjort, som ville ha gjort koden min mye raskere,
er å lage et array av primtall, istedenfor å bare gå igjennom oddetall og
spørre silen om det er et primtall. Dette kom jeg på for sent til å kunne
prøve det ut.

# Tider

CPU: quad core Intel Xeon E31225 @ 3.1 GHz (ingen hyperthreading)

2 000 000 000:
* Erastothenes' Sil sekvensielt: 9.82s
* Erastothenes' Sil parallelt: 6.77s (1.45x speedup)
* Faktorisering sekvensielt: 1176.19s
* Faktorisering parallelt: 356.50s (3.3x speedup)

200 000 000:
* Erastothenes' Sil sekvensielt: 829.98ms
* Erastothenes' Sil parallelt: 618.72ms (1.34x speedup)
* Faktorisering sekvensielt: 115.10s
* Faktorisering parallelt: 37.20s (3.09x speedup)

20 000 000:
* Erastothenes' Sil sekvensielt: 68.11ms
* Erastothenes' Sil parallelt: 41.41ms (1.64x speedup)
* Faktorisering sekvensielt: 13.82s
* Faktorisering parallelt: 4.31s (3.21x speedup)

2 000 000:
* Erastothenes' Sil sekvensielt: 15.67ms
* Erastothenes' Sil parallelt: 9.58ms (1.64x speedup)
* Faktorisering sekvensielt: 1.17s
* Faktorisering parallelt: 534.75s (2.18x speedup)

Loading…
Cancel
Save