Browse Source

parallel factoring algorithm with speedup

Note that it's still around 2x slower than my best sequential solution,
but because uni, I use the slow sequential solution and the
fast parallel solution.
master
mortie 7 years ago
parent
commit
a365022078
3 changed files with 153 additions and 158 deletions
  1. 2
    8
      inf2440/hw2/Main.java
  2. 132
    150
      inf2440/hw2/Parallel.java
  3. 19
    0
      inf2440/hw2/Sieve.java

+ 2
- 8
inf2440/hw2/Main.java View File

@@ -26,13 +26,8 @@ class Main {
long n = maxNum * maxNum;
for (long j = n; j >= n - 100; --j) {

Timer t2 = new Timer().start();
long[] factors = s.factor(sieve, j);
System.out.println(
t2.end().prettyTime()+": "+
Util.factors(j, factors));

/*
if (j > (n - 5) || j < (n - 95)) {
if (j == n - 96)
System.out.println(".............");
@@ -40,7 +35,6 @@ class Main {
System.out.println(
Util.factors(j, factors));
}
*/
}
t.end();
}
@@ -57,8 +51,7 @@ class Main {
Sequential sseq = new Sequential();
Parallel spar = new Parallel();

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

int maxNum = Integer.parseInt(args[0]);
@@ -78,6 +71,7 @@ class Main {
// We need a solved sieve
Sieve sieve = new Sieve(maxNum);
spar.solve(sieve);
sieve.getPrimes();

System.out.println("\nFactoring sequentially...");
Timer seq = testFactor(sseq, maxNum, sieve);

+ 132
- 150
inf2440/hw2/Parallel.java View File

@@ -58,218 +58,200 @@ class Parallel implements Solver {

class FactorWorker implements Runnable {
FactorMonitor monitor;
long num;
int sqrt;
int[] primes;
int step;
int offset;
long num;
long currentPrime;
long biggestPossible;
Sieve sieve;
boolean ready = false;
boolean done = false;
boolean running;
boolean done;

// Offset should start at 0
synchronized public void start(FactorMonitor monitor, int step, int offset) {
FactorWorker(FactorMonitor monitor, int step, int offset) {
this.monitor = monitor;
this.primes = monitor.primes;
this.num = monitor.num;
this.sqrt = (int)Math.sqrt(num);
this.step = step;
this.offset = offset;
this.num = monitor.currentNum;
this.biggestPossible = (long)Math.sqrt(num);
this.sieve = monitor.sieve;
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;
}
}
void go() {
int start = offset + monitor.sequentialPrimes;
for (int i = start; monitor.running; i += step) {
if (primes[i] == 0 || primes[i] > sqrt)
break;

synchronized public void stop() {
ready = false;
done = true;
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;
if (num % primes[i] == 0) {
monitor.addFactor(primes[i], num);
break;
}
}

running = false;
monitor.workerStopped();
}

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;
}
}
synchronized void start(long num) {
this.num = num;
this.sqrt = (int)Math.sqrt(num);
running = true;
notify();
}

nextPrime();
}
synchronized void stop() {
done = true;
notify();
}

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

while (!done) {
while (!monitor.isDone() && this.ready) {
findFactor();
}

ready = false;

while (!ready && !done)
while (!running && !done)
try { wait(); } catch (InterruptedException ex) {}

if (!done)
go();
}
}
}

class FactorMonitor {
final int sequentialPrimes = 4;

Sieve sieve;
long original;
long currentNum;
int biggestLeft;
long num;
int nThreads;

int[] primes;
boolean running;
boolean done;
boolean foundFactor;

int workersLeft;

FactorWorker[] workers;
Thread[] threads;

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

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);
}
this.primes = sieve.getPrimes();
this.num = num;
this.nThreads = nThreads;

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)
return false;
this.done = false;

while ((currentNum % factor) == 0) {
currentNum /= factor;
Long i = new Long(factor);
arr.add(i);
// We do the first few primes sequentially, as they're
// very likely to be factors
for (int i = 0; i < sequentialPrimes; ++i) {
while (this.num % primes[i] == 0) {
factors.add(new Long(primes[i]));
this.num /= primes[i];
}
}
notify();

return true;
}
synchronized void foundBiggest() {
this.biggestLeft -= 1;
if (biggestLeft == 0) {
done = true;
notify();
this.workers = new FactorWorker[nThreads];
this.threads = new Thread[nThreads];
for (int i = 0; i < nThreads; ++i) {
FactorWorker w = new FactorWorker(this, nThreads, i);
Thread t = new Thread(w);
this.workers[i] = w;
this.threads[i] = t;
t.start();
}

go();
}

boolean isPrime(long num) {
if (num > sieve.maxNum)
return false;
else
return sieve.isPrime((int)num);
synchronized void addFactor(int prime, long num) {
foundFactor = true;
if (num != this.num)
return;

do {
this.num /= prime;
factors.add(new Long(prime));
} while (this.num % prime == 0);
running = false;
}

synchronized boolean isDone() {
if (done) {
return true;
} else if (isPrime(currentNum)) {
synchronized void workerStopped() {
workersLeft -= 1;
if (workersLeft != 0)
return;

if (foundFactor) {
go();
} else {
done = true;
if (currentNum != 1)
arr.add(new Long(currentNum));
notify();
return true;
} else {
return false;

for (FactorWorker w: workers)
w.stop();
}
}

synchronized long[] getFactors() {
while (!isDone())
while (!done)
try { wait(); } catch (InterruptedException ex) {}

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

long[] a = new long[arr.size()];
for (int i = 0; i < a.length; ++i) {
a[i] = arr.get(i);
}
return a;
long[] arr = new long[factors.size()];
for (int i = 0; i < arr.length; ++i)
arr[i] = factors.get(i);

Arrays.sort(arr);
return arr;
}
}

FactorWorker[] factorWorkers = null;
Thread[] factorThreadPool = null;
synchronized void go() {
running = true;
foundFactor = false;
workersLeft = nThreads;
for (FactorWorker w: workers)
w.start(num);
}
}

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

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

// Initiate thread pool
if (factorThreadPool == null) {
factorThreadPool = new Thread[nThreads];
factorWorkers = new FactorWorker[nThreads];
for (int i = 0; i < nThreads; ++i) {
FactorWorker w = new FactorWorker();
factorWorkers[i] = w;
factorThreadPool[i] = new Thread(w);
factorThreadPool[i].start();
}
}
/*
int[] primes = sieve.getPrimes();

FactorMonitor monitor = new FactorMonitor(sieve, num, nThreads);
ArrayList<Long> factors = new ArrayList<>();
int sqrt = (int)Math.sqrt(num);
for (int i = 0; i < primes.length; ++i) {
int p = primes[i];
if (p == 0)
break;

// Start workers
for (int i = 0; i < nThreads; ++i) {
FactorWorker w = factorWorkers[i];
w.start(monitor, nThreads, i);
if (p > sqrt)
break;

while (num % p == 0) {
factors.add(new Long(p));
num /= p;
sqrt = (int)Math.sqrt(num);
}
}

long[] arr = monitor.getFactors();
Arrays.sort(arr);
if (num != 1)
factors.add(num);

long[] arr = new long[factors.size()];
for (int i = 0; i < arr.length; ++i)
arr[i] = factors.get(i);
return arr;
*/
}

public void stopThreads() {
if (factorWorkers == null)
return;

for (FactorWorker w: factorWorkers) {
w.stop();
}
}
}

+ 19
- 0
inf2440/hw2/Sieve.java View File

@@ -5,12 +5,16 @@
* Stores prime/not prime in all 8 bits in each byte.
*/

import java.util.ArrayList;

class Sieve {
public byte[] arr;
public int maxNum;
public boolean smallPrimesGenerated = false;

private int sqrtNum;
private int numPrimes = 0;
private int[] primes = null;

Sieve(int maxNum, byte[] arr) {
this.maxNum = maxNum;
@@ -21,6 +25,21 @@ class Sieve {
this(maxNum, new byte[(maxNum / 16) + 1]);
}

public int[] getPrimes() {
if (primes == null) {
primes = new int[(maxNum / (int)Math.log(maxNum)) * 2];

int i = 0;
primes[i++] = 2;
for (int p = 3; p < maxNum; p += 2) {
if (isPrime(p))
primes[i++] = p;
}
}

return primes;
}

// Find all prime numbers.
public void generatePrimes(int step, int offset) {
if (!smallPrimesGenerated)

Loading…
Cancel
Save