| import java.util.Random; | |||||
| class Main { | |||||
| public static void main(String[] args) { | |||||
| Solver sseq = new Sequential(); | |||||
| Solver spar = new Parallel(); | |||||
| if (args.length != 1) { | |||||
| System.out.println(" bruk : >java SekvensiellRadix <n> "); | |||||
| } else { | |||||
| int n = Integer.parseInt(args[0]); | |||||
| Timer seq = test(sseq, n); | |||||
| System.out.println("Sequential: "+seq.prettyTime()); | |||||
| Timer par = test(spar, n); | |||||
| System.out.println("Parallel: "+par.prettySpeedup(seq)); | |||||
| } | |||||
| } | |||||
| static Timer test (Solver s, int len) { | |||||
| Random r = new Random(123); | |||||
| int[] a = new int[len]; | |||||
| for (int j = 0; j < len; j++) { | |||||
| a[j] = r.nextInt(len); | |||||
| } | |||||
| Timer t = new Timer().start(); | |||||
| a = s.sort(a); | |||||
| t.end(); | |||||
| new MultiRadix().testSort(a); | |||||
| return t; | |||||
| } // end doIt | |||||
| } |
| import java.util.*; | |||||
| /*********************************************************** | |||||
| * Oblig 3 - sekvensiell kode, INF2440 v2017. | |||||
| * Ifi, Uio, Arne Maus | |||||
| * for store verdier av n > 100 m, kjør (f.eks): | |||||
| * >java -Xmx16000m MultiRadix 1000000000 | |||||
| ************************************************************/ | |||||
| class MultiRadix{ | |||||
| int n; | |||||
| int [] a; | |||||
| final static int NUM_BIT = 7; // alle tall 6-11 .. finn ut hvilken verdi som er best | |||||
| int [] radixMulti(int [] a) { | |||||
| long tt = System.nanoTime(); | |||||
| // 1-5 digit radixSort of : a[] | |||||
| int max = a[0], numBit = 2, numDigits, n =a.length; | |||||
| int [] bit ; | |||||
| // a) finn max verdi i a[] | |||||
| //Timer ta = new Timer().start(); | |||||
| for (int i = 1 ; i < n ; i++) | |||||
| if (a[i] > max) max = a[i]; | |||||
| while (max >= (1L<<numBit) )numBit++; // antall binaere siffer i max | |||||
| //System.out.println("A: "+ta.end().prettyTime()); | |||||
| // bestem antall bit i numBits sifre | |||||
| numDigits = Math.max(1, numBit/NUM_BIT); | |||||
| bit = new int[numDigits]; | |||||
| int rest = (numBit%numDigits), sum =0;; | |||||
| // fordel bitene vi skal sortere paa jevnt | |||||
| for (int i = 0; i < bit.length; i++){ | |||||
| bit[i] = numBit/numDigits; | |||||
| if ( rest-- > 0) bit[i]++; | |||||
| } | |||||
| int[] t=a, b = new int [n]; | |||||
| for (int i =0; i < bit.length; i++) { | |||||
| radixSort( a,b,bit[i],sum ); // i-te siffer fra a[] til b[] | |||||
| sum += bit[i]; | |||||
| // swap arrays (pointers only) | |||||
| t = a; | |||||
| a = b; | |||||
| b = t; | |||||
| } | |||||
| if (bit.length%2 != 0 ) { | |||||
| // et odde antall sifre, kopier innhold tilbake til original a[] (nå b) | |||||
| System.arraycopy (a,0,b,0,a.length); | |||||
| } | |||||
| return a; | |||||
| } // end radixMulti | |||||
| /** Sort a[] on one digit ; number of bits = maskLen, shiftet up 'shift' bits */ | |||||
| void radixSort ( int [] a, int [] b, int maskLen, int shift){ | |||||
| int acumVal = 0, j, n = a.length; | |||||
| int mask = (1<<maskLen) -1; | |||||
| int [] count = new int [mask+1]; | |||||
| // b) count=the frequency of each radix value in a | |||||
| //Timer tb = new Timer().start(); | |||||
| for (int i = 0; i < n; i++) { | |||||
| count[(a[i]>>> shift) & mask]++; | |||||
| } | |||||
| //System.out.println("B: "+tb.end().prettyTime()); | |||||
| // c) Add up in 'count' - accumulated values | |||||
| //Timer tc = new Timer().start(); | |||||
| for (int i = 0; i <= mask; i++) { | |||||
| j = count[i]; | |||||
| count[i] = acumVal; | |||||
| acumVal += j; | |||||
| } | |||||
| //System.out.println("C: "+tc.end().prettyTime()); | |||||
| // d) move numbers in sorted order a to b | |||||
| //Timer t = new Timer().start(); | |||||
| for (int i = 0; i < n; i++) { | |||||
| b[count[(a[i]>>>shift) & mask]++] = a[i]; | |||||
| } | |||||
| //t.end(); | |||||
| //System.out.println("seq D: "+t.prettyTime()); | |||||
| }// end radixSort | |||||
| void testSort(int [] a){ | |||||
| for (int i = 0; i< a.length-1;i++) { | |||||
| if (a[i] > a[i+1]){ | |||||
| System.out.println("SorteringsFEIL på plass: "+i +" a["+i+"]:"+a[i]+" > a["+(i+1)+"]:"+a[i+1]); | |||||
| return; | |||||
| } | |||||
| } | |||||
| }// end simple sorteingstest | |||||
| }// end SekvensiellRadix |
| import java.util.*; | |||||
| class MultiRadixPar{ | |||||
| int n; | |||||
| volatile int[] a; | |||||
| final static int NUM_BIT = 7; // alle tall 6-11 .. finn ut hvilken verdi som er best | |||||
| int nThreads = Math.min( | |||||
| Runtime.getRuntime().availableProcessors(), | |||||
| 8); | |||||
| class PartAWorker implements Runnable { | |||||
| int start; | |||||
| int end; | |||||
| int biggest; | |||||
| PartAWorker(int start, int end) { | |||||
| this.start = start; | |||||
| this.end = end; | |||||
| this.biggest = a[start]; | |||||
| } | |||||
| public void run() { | |||||
| for (int i = start + 1; i < end; ++i) { | |||||
| if (a[i] > biggest) | |||||
| biggest = a[i]; | |||||
| } | |||||
| } | |||||
| } | |||||
| int [] radixMulti(int [] a_) { | |||||
| this.a = a_; | |||||
| // 1-5 digit radixSort of : a[] | |||||
| int max = a[0], numBit = 2, numDigits, n =a.length; | |||||
| int [] bit ; | |||||
| // a) finn max verdi i a[] | |||||
| //Timer ta = new Timer().start(); | |||||
| int d = a.length / nThreads; | |||||
| Thread[] threads = new Thread[nThreads]; | |||||
| PartAWorker[] workers = new PartAWorker[nThreads]; | |||||
| for (int i = 0; i < nThreads; ++i) { | |||||
| PartAWorker w = workers[i] = new PartAWorker( | |||||
| d * i, i == nThreads - 1 ? a.length : d * (i + 1)); | |||||
| Thread t = threads[i] = new Thread(w); | |||||
| t.start(); | |||||
| } | |||||
| for (Thread t: threads) { try { t.join(); } catch (InterruptedException ex) {} } | |||||
| max = workers[0].biggest; | |||||
| for (int i = 1; i < nThreads; ++i) { | |||||
| if (workers[i].biggest > max) | |||||
| max = workers[i].biggest; | |||||
| } | |||||
| while (max >= (1L<<numBit) )numBit++; // antall binaere siffer i max | |||||
| //System.out.println("A: "+ta.end().prettyTime()); | |||||
| // bestem antall bit i numBits sifre | |||||
| numDigits = Math.max(1, numBit/NUM_BIT); | |||||
| bit = new int[numDigits]; | |||||
| int rest = (numBit%numDigits), sum =0;; | |||||
| // fordel bitene vi skal sortere paa jevnt | |||||
| for (int i = 0; i < bit.length; i++){ | |||||
| bit[i] = numBit/numDigits; | |||||
| if ( rest-- > 0) bit[i]++; | |||||
| } | |||||
| int[] t=a, b = new int [n]; | |||||
| for (int i =0; i < bit.length; i++) { | |||||
| radixSort( b,bit[i],sum ); // i-te siffer fra a[] til b[] | |||||
| sum += bit[i]; | |||||
| // swap arrays (pointers only) | |||||
| t = a; | |||||
| a = b; | |||||
| b = t; | |||||
| } | |||||
| if (bit.length%2 == 0 ) { | |||||
| // et odde antall sifre, kopier innhold tilbake til original a[] (nå b) | |||||
| System.arraycopy (b,0,a,0,a.length); | |||||
| } | |||||
| return a; | |||||
| } // end radixMulti | |||||
| class PartDWorker implements Runnable { | |||||
| int start, end, shift, mask; | |||||
| int[] b, count; | |||||
| PartDWorker(int start, int end, int[] b, int[] count, int shift, int mask) { | |||||
| this.start = start; | |||||
| this.end = end; | |||||
| this.b = b; | |||||
| this.count = count; | |||||
| this.shift = shift; | |||||
| this.mask = mask; | |||||
| } | |||||
| public void run() { | |||||
| for (int i = 0; i < n; i++) { | |||||
| int var = (a[i] >>> shift) & mask; | |||||
| if (var >= start && var < end) { | |||||
| b[count[var]++] = a[i]; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /** Sort a[] on one digit ; number of bits = maskLen, shiftet up 'shift' bits */ | |||||
| void radixSort (int [] b, int maskLen, int shift){ | |||||
| int n = a.length; | |||||
| int mask = (1<<maskLen) -1; | |||||
| int [] count = new int [mask+1]; | |||||
| int biggestVar = 0; | |||||
| // b) count=the frequency of each radix value in a | |||||
| //Timer tb = new Timer().start(); | |||||
| for (int i = 0; i < n; i++) { | |||||
| int var = (a[i]>>>shift) & mask; | |||||
| count[var]++; | |||||
| if (var > biggestVar) | |||||
| biggestVar = var; | |||||
| } | |||||
| //System.out.println("B: "+tb.end().prettyTime()); | |||||
| // c) Add up in 'count' - accumulated values | |||||
| //Timer tc = new Timer().start(); | |||||
| int j = 0; | |||||
| int acumVal = 0; | |||||
| for (int i = 0; i <= mask; i++) { | |||||
| j = count[i]; | |||||
| count[i] = acumVal; | |||||
| acumVal += j; | |||||
| } | |||||
| //System.out.println("C: "+tc.end().prettyTime()); | |||||
| //Timer td = new Timer().start(); | |||||
| int d = biggestVar / nThreads; | |||||
| Thread[] threads = new Thread[nThreads]; | |||||
| for (int i = 0; i < nThreads; ++i) { | |||||
| int start = d * i; | |||||
| int end = i == nThreads - 1 ? n + 1 : d * (i + 1); | |||||
| PartDWorker w = new PartDWorker(start, end, b, count, shift, mask); | |||||
| Thread t = threads[i] = new Thread(w); | |||||
| t.start(); | |||||
| } | |||||
| for (Thread t: threads) { | |||||
| try { t.join(); } catch (InterruptedException ex) {} | |||||
| } | |||||
| //System.out.println("par D: "+td.end().prettyTime()); | |||||
| }// end radixSort | |||||
| void testSort(int [] a){ | |||||
| for (int i = 0; i< a.length-1;i++) { | |||||
| if (a[i] > a[i+1]){ | |||||
| System.out.println("SorteringsFEIL på plass: "+i +" a["+i+"]:"+a[i]+" > a["+(i+1)+"]:"+a[i+1]); | |||||
| return; | |||||
| } | |||||
| } | |||||
| }// end simple sorteingstest | |||||
| }// end SekvensiellRadix |
| class Parallel implements Solver { | |||||
| public int[] sort(int[] arr) { | |||||
| return new MultiRadixPar().radixMulti(arr); | |||||
| } | |||||
| } |
| class Sequential implements Solver { | |||||
| public int[] sort(int[] arr) { | |||||
| return new MultiRadix().radixMulti(arr); | |||||
| } | |||||
| } |
| interface Solver { | |||||
| int[] sort(int[] a); | |||||
| } |
| import java.util.Arrays; | |||||
| class Timer implements Comparable<Timer> { | |||||
| public long time = 0; | |||||
| private long start = 0; | |||||
| Timer() {} | |||||
| Timer(long time) { | |||||
| this.time = time; | |||||
| } | |||||
| public Timer start() { | |||||
| start = System.nanoTime(); | |||||
| return this; | |||||
| } | |||||
| public Timer end() { | |||||
| time = System.nanoTime() - start; | |||||
| return this; | |||||
| } | |||||
| public String prettyTime() { | |||||
| if (time < 1000) | |||||
| return String.format("%.2fns", time / 1f); | |||||
| else if (time < 1000000) | |||||
| return String.format("%.2fμs", time / 1000f); | |||||
| else if (time < 1000000000) | |||||
| return String.format("%.2fms", time / 1000000f); | |||||
| else | |||||
| return String.format("%.2fs", time / 1000000000f); | |||||
| } | |||||
| public String prettySpeedup(Timer base) { | |||||
| double speedup = (double)base.time / (double)time; | |||||
| return String.format("%s (%.2fx speedup)", | |||||
| prettyTime(), speedup); | |||||
| } | |||||
| public static Timer median(Timer[] timers) { | |||||
| Arrays.sort(timers); | |||||
| Timer med = new Timer(); | |||||
| int mid = timers.length / 2; | |||||
| if (timers.length % 2 == 0) | |||||
| med.time = (timers[mid].time + timers[mid+1].time) / 2; | |||||
| else | |||||
| med.time = timers[mid].time; | |||||
| return med; | |||||
| } | |||||
| public int compareTo(Timer t) { | |||||
| if (this.time < t.time) | |||||
| return -1; | |||||
| else if (this.time > t.time) | |||||
| return 1; | |||||
| else | |||||
| return 0; | |||||
| } | |||||
| } |
| martin@elli:~/tmp$ java Main 200000000 | |||||
| Sequential: 4.99s | |||||
| Parallel: 2.11s (2.37x speedup) |
| Kompilering: `javac *.java` | |||||
| Kjøring: `java Main <tall>` | |||||
| # Eksempelutskrift | |||||
| I filen output.txt finner du et eksempel på å kjøre `java Main 2000000000`. | |||||
| # Tider | |||||
| CPU: quad core Intel Xeon E31225 @ 3.1 GHz (ingen hyperthreading) | |||||
| 200 000 000: | |||||
| * Sekvensiell: 4.99s | |||||
| * Parallell: 2.11s (2.37x speedup) | |||||
| 20 000 000: | |||||
| * Sekvensiell: 257.75ms | |||||
| * Parallell: 186.53ms (1.48x speedup) | |||||
| 2 000 000: | |||||
| * Sekvensiell: 54.04ms | |||||
| * Parallell: 44.87 (1.20x speedup) | |||||
| 200 000: | |||||
| * Sekvensiell: 22.94ms | |||||
| * Parallell: 12.46ms (1.84x speedup) | |||||
| 20 000: | |||||
| * Sekvensiell: 3.87ms | |||||
| * Parallell: 4.54ms (0.85x speedup) | |||||
| 2 000: | |||||
| * Sekvensiell:895.36μs | |||||
| * Parallell: 2.68ms (0.33x speedup) | |||||
| ## Del C | |||||
| Jeg skjønte ikke helt grunnen til å paralellisere del C. I mine tester tar C | |||||
| mikrosekunder, så det ville tatt lengre tid å spawne trådene enn å bare | |||||
| gjøre det sekvensielt?? |