INF2440 Uke 10, v2015 : Arne Maus PSE, Inst. for informatikk

Like dokumenter
INF2440 Uke 10, v2014 : Arne Maus OMS, Inst. for informatikk

INF2440 Uke 10, v2016 : Arne Maus PSE, Inst. for informatikk

INF2440 Uke 10, v2017 : Arne Maus PSE, Inst. for informatikk

INF2440 Uke 10, v2018 : Arne Maus PSE, Inst. for informatikk

INF2440 Uke 8, v2017. Arne Maus PSE, Inst. for informatikk

INF2440 Uke 9, v2014 : Arne Maus OMS, Inst. for informatikk

Java PRP brukermanual

INF2440 Uke 9, v2015 : Arne Maus PSE, Inst. for informatikk

INF NOV PARALLELL SORTERING. Arne Maus, PSE, Ifi

I et Java-program må programmøren lage og starte hver tråd som programmet bruker. Er dette korrekt? Velg ett alternativ

INF2440 Uke 13, v2015. Arne Maus PSE, Inst. for informatikk

INF2440 Prøveeksamen, løsningsforslag, 20 mai Arne Maus PSE, Inst. for informatikk

INF2440 Uke 13, v2014. Arne Maus OMS, Inst. for informatikk

INF2440 Eksamen 2016 løsningsforslag. Arne Maus, PSE ifi, UiO

INF3030, Uke 3, våren 2019 Regler for parallelle programmer, mer om cache og Matrise-multiplikasjon. Arne Maus / Eric Jul PSE, Inst.

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

INF2440 Uke 12, v2014. Arne Maus OMS, Inst. for informatikk

Fig1. Den konvekse innhyllinga av 100 tilfeldige punkter i planet (de samme som nyttes i oppgaven.)

UNIVERSITETET I OSLO

Prøveeksamen INF2440 v Arne Maus PSE, Inst. for informatikk

UNIVERSITETET I OSLO

INF2440 Uke 8, v2015 : Om Oblig 3, Ulike Threadpools, JIT-kompilering. Arne Maus PSE, Inst. for informatikk

INF2440 Uke 11, v2014 om parallell debugging og Goldbachs problem, om Oblig 3. Arne Maus OMS, Inst. for informatikk

INF2440 Uke 7, våren2015. Arne Maus PSE, Inst. for informatikk

UNIVERSITETET I OSLO

INF2440 Uke 4, våren2014 Avsluttende om matrisemultiplikasjon og The Java Memory Model + bedre forklaring Radix. Arne Maus OMS, Inst.

Arne Maus OMS, Inst. for informatikk

INF2440 Effektiv parallellprogrammering Uke 2 -, våren tidtaking. Arne Maus PSE, Inst. for informatikk

Sortering med tråder - Quicksort

Rekursjon. (Big Java kapittel 13) Fra Urban dictionary: recursion see recursion. IN1010 uke 8 våren Dag Langmyhr

Rekursjon. (Big Java kapittel 13) Fra Urban dictionary: recursion see recursion. IN1010 uke 8 våren Dag Langmyhr

INF2440 Effektiv parallellprogrammering Uke 1, våren Arne Maus PSE, Inst. for informatikk

INF2440 Uke 7, våren2017. Arne Maus PSE, Inst. for informatikk

Kap 19. Mer om parallelle programmer i Java og Kvikksort

Fra Python til Java, del 2

INF2440, Uke 3, våren2015 Regler for parallelle programmer, mer om cache og Radix-algoritmen. Arne Maus OMS, Inst. for informatikk

EKSAMEN. Dato: 28. mai 2018 Eksamenstid: 09:00 13:00

INF2440 Effektiv parallellprogrammering Uke 1, våren Arne Maus PSE, Inst. for informatikk

INF2440 Uke 13, v2017. Arne Maus PSE, Inst. for informatikk

Innhold. Forord Det første programmet Variabler, tilordninger og uttrykk Innlesing og utskrift...49

INF2220: Forelesning 1. Praktisk informasjon Analyse av algoritmer (kapittel 2) (Binær)trær (kapittel )

UNIVERSITETET I OSLO Institutt for informatikk. PRP-2014: Parallelle, faseoppdelte og rekursive algoritmer. Masteroppgave. Peter Ludvik Eidsvik

IN1010. Fra Python til Java. En introduksjon til programmeringsspråkenes verden Dag Langmyhr

UNIVERSITETET I OSLO

INF2440 Uke 5, våren2016. Arne Maus PSE, Inst. for informatikk

INF2440 Uke 6, våren2014 Mer om oppdeling av et problem for parallellisering, mye om primtall + thread-safe. Arne Maus OMS, Inst.

INF2440 Uke 13, v2016. Arne Maus PSE, Inst. for informatikk

Løsnings forslag i java In115, Våren 1999

INF2440 Uke 11, v2017 om Goldbachs problem og Oblig 2,3. Arne Maus PSE, Inst. for informatikk

INF1000 : Forelesning 4

i=0 i=1 Repetisjon: nesting av løkker INF1000 : Forelesning 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker j=0 j=1 j=2 j=3 j=4

INF2220 høsten 2017, 12. okt.

INF2440, Uke 3, våren2014 Regler for parallelle programmer, mer om cache og Radix-algoritmen. Arne Maus OMS, Inst. for informatikk

Binære søketrær. En ordnet datastruktur med raske oppslag. Sigmund Hansen

Binære søketrær. Et notat for INF1010 Stein Michael Storleer 16. mai 2013

Algoritmer og Datastrukturer

INF1010 Rekursive metoder, binære søketrær. Algoritmer: Mer om rekursive kall mellom objekter Ny datastruktur: binært tre

Forkurs INF1010. Dag 1. Andreas Færøvig Olsen Tuva Kristine Thoresen

UNIVERSITETET I OSLO

Ny/utsatt EKSAMEN. Dato: 5. januar 2018 Eksamenstid: 09:00 13:00

Repetisjon: Statiske språk uten rekursive metoder (C1 og C2) Dagens tema Kjøresystemer (Ghezzi&Jazayeri 2.6, 2.7)

Rekursjon. Binærsøk. Hanois tårn.

Dagens tema Kjøresystemer (Ghezzi&Jazayeri 2.6, 2.7)

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

INF2440 Uke 4, v2017 Om å samle parallelle svar, matrisemultiplikasjon og The Java Memory Model + evt bedre forklaring Radix

MER OM PARALLELLE PROGRAMMER I JAVA OG KVIKKSORT

Rekursiv programmering

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

i=0 Repetisjon: arrayer Forelesning inf Java 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker 0*0 0*2 0*3 0*1 0*4

Forelesning inf Java 4

UNIVERSITETET I OSLO

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister

Inf 1000 høst 2005 Løsningsforslag ordinær eksamen

Bakgrunnen for INF2100. Velkommen til INF2100. Prosjektet. Hva gjør en kompilator?

UNIVERSITETET I OSLO

Løsnings forslag i java In115, Våren 1996

Løsnings forslag i java In115, Våren 1998

Binære trær: Noen algoritmer og anvendelser

UNIVERSITETET I OSLO

Løsningsforslag ukeoppg. 6: 28. sep - 4. okt (INF Høst 2011)

"behrozm" Oppsummering - programskisse for traversering av en graf (dybde først) Forelesning i INF februar 2009

INF110 Algoritmer og datastrukturer TRÆR. Vi skal i denne forelesningen se litt på ulike typer trær:

INF1000 Metoder. Marit Nybakken 16. februar 2004

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister Videre

INF2440 Uke 4, v2015 Om å samle parallelle svar, matrisemultiplikasjon og The Java Memory Model + evt bedre forklaring Radix

Algoritmer og datastrukturer Løsningsforslag

INF1010, 22. mai Prøveeksamen (Eksamen 12. juni 2012) Stein Gjessing Inst. for Informatikk Universitetet i Oslo

EKSAMEN. Dato: 18. mai 2017 Eksamenstid: 09:00 13:00

INF2440 Uke 15, v2015 oppsummering. Arne Maus PSE, Inst. for informatikk

INF 1000 høsten 2011 Uke september

INF1010 Sortering. Marit Nybakken 1. mars 2004

INF1010 notat: Binærsøking og quicksort

INF2440 Uke 11, v2015 om parallell debugging og Goldbachs problem, om Oblig 2,3 og 4. Arne Maus PSE, Inst. for informatikk

INF Notater. Veronika Heimsbakk 10. juni 2012

INF2440 Uke 14, v2016. Arne Maus PSE, Inst. for informatikk

Oppgave 1 a. INF1020 Algoritmer og datastrukturer. Oppgave 1 b

INF1000 undervisningen INF 1000 høsten 2011 Uke september

Heap* En heap er et komplett binært tre: En heap er også et monotont binært tre:

EKSAMEN med løsningsforslag

Transkript:

INF2440 Uke 10, v2015 : Arne Maus PSE, Inst. for informatikk 1

Hva så vi på i uke 9 Et sitat om tidsforbruk ved faktorisering Om en feil i Java 7 ved tidtaking Hvordan parallellisere rekursive algoritmer Gå ikke i direkte oversettelses-fella eksemplifisert ved Kvikk-sort, 3 ulike løsninger Oblig3 det sekvensielle tilfellet Bla. bør lage klasse IntList (hvis tid) Hvor lang tid tar de ulike mekanismene vi har i Java? 2

Hva skal vi se på i Uke10 Hvor lang tid de ulike mekanismene vi har i Java tar. Java 6 (2012) og Java 8 (2015) Automatisk parallellisering av rekursjon PRP- Parallel Recursive Procedures Nåværende løsning (Java, multicore CPU, felles hukommelse) implementasjon: Peter L. Eidsvik Mange tidligere implementasjoner fra 1994 (C over nettet, C# på.net, Java over nettet,..) Demo av to kjøringer Hvordan ikke gå i fella: Et Rekursivt kall = En Tråd Halvautomatisk Hvordan kan vi bygge en kompilator (preprosessor) for automatisk parallellisering Prinsipper ( bredde-først og dybde-først traversering av r-treet) Datastruktur Eksekvering Krav til et program som skal bruke PRP 3

Hvor lang tid tar egentlig ulike mekanismer i Java? (fra Petter A. Busteruds master-oppgave: Invesigating Different Concurrency Mechanisms in Java) - i 2012 Dette er målinger på en relativt ny CPU (2009): Intel Pentium i7 920 GHz 4 core 2 GB DDR2 RAM @ 533 MHz Windows 7 32bit og Java 6 (med noe HotSpot kompilering) Linux Mint 13, 32bit Det er de relative hastighetene som teller Petter målte bl.a. : kalle en metode lage et nytt objekt (new C() ) + kalle en metode lage en Tråd (new Thread + kalle run() ) Lage en ExecutorService + legge inn tråder Tider på int[] og trådsikre AtomicIntegerArray Generelt er Linux 15-20% raskere enn Windows (ikke optimalisert) 4

Hvor lang tid i µs tar egentlig ulike mekanismer i Java? (fra Petter A. Busteruds master-oppgave: Investigating Different Concurrency Mechanisms in Java) A) Metodekall på Windows og Linux (ikke optimalisert) Generelt er kan vi gjøre mer enn 500-700 metodekall per millisek. 5

Å lage et nytt objekt av en klasse (new) og kalle en metode i objektet (µs) Object Konklusjon: - Verken det å kalle en metode eller å lage et objekt tar særlig lang tid - Mye blir optimalisert videre - Forskjellen mellom første og andre kall er at det sannsynligvis er blitt JIT-kompilert til maskinkode, men ikke optimalisert 6

Lage en tråd (new Thread()) og kalle run() - µs 7

Lage en ExecutorService 8

Lage og bruke en vanlig int [] a (IKKE trådsikker) mot AtomicIntegerArray (trådsikre heltall) 9

Oppsummering om kjøretider fra Petter: Metodekall tar svært liten tid: 2-5 µs og kan også optimaliseres bort (og gis speedup >1) Å lage et objekt av en klasse (og kalle en metode i det) tar liten tid: ca.785 µs Å lage en tråd og starte den opp tar en del tid: ca.1500 µs, men lite, ca. 180 µs for de neste trådene (med start() ) Å lage en en tråd-samling og legge tråder (og Futures) opp i den tar ca. 7000 µs for første tråd og ca. 210 µs for neste tråd. Å bruke trådsikre heltall (AtomicInteger og AtomicIntegerArray) mot vanlige int og int[] tar vanligvis 10-20 x så lang tid, men for mye bruk (> 10 6 ) tar det bare ca. 2x tid (det siste er sannynligvis en cache-effekt) En parallell løsning må alltid sammenlignes med hvor mye vi kunne ha gjort (f.eks sortert) sekvensielt på den samme tida! 10

Nye målinger i Java8 i 2015 metodekall-eks. mm. //Metodekall s ="Metodekall"; t = System.nanoTime(); k=neste(k); d = (double) ((System.nanoTime() -t)/1000.0); println(s+format.align(d,10,4)+"us. forste gang"); t = System.nanoTime(); for (int i = 0; i<n; i++) { k+=neste(k); d = (double) ((System.nanoTime() -t)/(n*1000.0)); println(s+format.align(d,10,4)+"us.snitt " + n+" ganger"); // Koden de andre tilfellene som ble testet ia = new int[100]; // new Array (t1 = new Thread(new Arbeider(3))).start(); // new Thread start&join() try{t1.join();catch (Exception e){ k= new C(k).les(); // lage Object C + metodekall k= new D(k).les(); // lage Object D+ metodekall ia[i%100] =i; k = ia[i%55]; // skriv i array // les fra array 11

Hva med i dag (Java 8) har kjøretidene endret seg? Tid første (us) Tid neste (us) Snitt tid 10 (us) Snitt tid 100000 (us) Speedup Metodekall 3.15 0.7 0.14 0.034 92 new int[100] 0.67 1.4 0.49 0.32 2 new Thread() start()+join() new C() + metodekall new D() + metodekall Ett Array write/read 4156.0 202.0 391.0 92.7 44 3214.0 1.05 0.28 0.08 40175 4497.0 1.4 0.70 0.11 40881 0.35 0.24 0.24 0.03 12 Konklusjoner:!) Ulik speedup. Best: å lage objekter, og metodekall 2) relativt lite speedup på arrayer Det er vår program som blir raskere, IKKE JVM (java) som tolker det bedre. De på det å lage objekter av en klasse C, gjør ikke noe for klasse D-objekter 12

Sammenlignet med Petters tider? Java8: Tid første (us) Java8 Snitt tid neste 10 (us) Java 6: Tid første (us) Java6: Snitt tid 16 (us) Uten join() Metodekall 3.15 0.14 4.75 1.96 new int[100] 0.67 0.49 new Thread() start()+join() new C() + metodekall new D() + metodekall Ett Array write/read 4156.0 391.0 1814 284 3214.0 0.28 770 53 4497.0 0.70 770 53 0.35 0.24 0.27 Konklusjoner:!) Ulik speedup. Best: å lage objekter, og metodekall 2) relativt lite speedup på arrayer Det er vår program som blir raskere, IKKE JVM (java) som tolker det bedre. De på det å lage objekter av en klasse C, gjør ikke noe for klasse D-objekter 13

2) Generelt om rekursiv oppdeling av a[] i to deler void Rek (int [] a, int left, int right) { <del opp omradet a[left..right] > int deling = partition (a, left,right); if (deling - left > LIMIT ) Rek (a,left,deling-1); else <enkel løsning>; if (right - deling > LIMIT) Rek (a,deling, right); else <enkel løsning> void Rek(int [] a, int left, int right) { <del opp omradet a[left..right]> int deling = partition (a, left,right); Thread t1 = null, t2= null; if (deling - left > LIMIT ) t1 = new Thread (a,left,deling-1); else <enkel løsning>; if (right - deling > LIMIT) t2 = new Thread (a,deling, right); else <enkel løsning> try{ if (t1!=null)t1.join(); if (t2!=null)t2.join(); catch(exception e){..; 14

Hvor mange kall gjør vi i en rekursiv løsning? Anta Quicksort av n =2 k tall (k= 10 n = 1000, k= 20 n= 1 mill) Kalltreet vil på første nivå ha 2 lengder av 2 19, på neste: 4 = 2 2 hver med 2 18 og helt ned til nivå 20, hvor vi vil ha 2 20 kall hver med 1 = 2 0 element. I hele kalltreet gjør vi altså 2 millioner -1 kall for å sortere 1 mill tall! Bruker vi innstikksortering for n < 32 = 2 5 så får vi bare 2 20-5 = 2 15 = 32 768 kall. Metodekall tar : 0.2-5 µs og kan også optimaliseres bort (og gis speedup >1) Å lage en tråd og starte den opp tar: ca.1500 µs, men ca. 180 µs for de neste trådene (med start() og join()) nivå: 0 1 2 20 Vi kan IKKE bare erstatte rekursive kall med nye tråder i en rekursiv løsning! 15

Konklusjon om å parallellisere rekursjon Antall tråder må begrenses! I toppen av treet brukes tråder (til vi ikke har flere og kanskje litt mer) I resten av treet bruker vi sekvensiell løsning i hver tråd! Viktig også å kutte av nedre del av treet (her med insertsort) som å redusere treets størrelse drastisk (i antall noder) Vi har for n = 100 000 gått fra: n sekv.tid(ms) para.tid(ms) Speedup 100000 34.813 41310.276 0.0008 Ren trådbasert 100000 8.118 823.432 0.0099 Med insertsort 100000 7.682 5.198 1.4777 + Avkutting i toppen Speedup > 1 og ca. 10 000x fortere enn ren oversettelse. 16

Drømmen om lage automatisk parallelliseing Parallellisering gir lang og vanskelig å lage kode Det finnes særlig to typer av sekvensielle programmer som tar lang tid: A) Med løkker (enkle, doble,..) B) Rekursive Drømmen er man bare helt automatisk, eller bare med noen få kommandoer kan oversette et sekvensielt program til et parallelt. Med løkker hadde vi bl.a HPFortran (Fortran90) som paralleliserte løkker (slo ikke helt an) Reursive metoder vi skal se på PRP (et system jeg har fått lager som hovedfagsoppgaver flere ganger siden ca. 1995) 17

PRP: Den grunnleggende ideen: Rekursjonstreet og treet av tråder er like, men Rekursjon Tråder 3 D 4 2 A 1 8 B C 5 E F G 6 7 3 D A 1 2 B C 4 5 6 E F G Dybde først Bredde først Tråder: - Kan ikke bruke svaret fra venstre-tråd til å lage parametere for høyre-tråd - Venter på trådene (og svaret ) først når begge trådene er sendt ut.. 18

Fra rekursjon til parallelle prosedyrer (metoder) Rekursjon Multikjerne CPU Kjerne 0 A Kjerne 1 A Kjerne 2 D B C E F G Kjerne3 D B C Kjerne 4 E F G 19

I Uke 9 så vi på å overføre Rekursjon til tråder - her fra Peter Eidsviks masteroppgave Vi skal nå automatisere det Vi lager en preprosessor: javaprp dvs. et Java-program som leser et annet Java-program og omformer det til et annet, gyldig Java-program (som er det parallelliserte programmet med tråder) For at JavaPRP skal kunne gjøre dette, må vi legge inn visse kommentarer i koden: Hvor er den rekursive metoden Hvor er de rekursive kallene Bare rekursive metoder med to eller flere kall, kan paralllelliseres. 20

Et eksempel før mer teori med en kjørbar sekvensiell Quicksort import java.util.random; class QuicksortProg{ public static void main(string[] args){ import java.util.random; int len = Integer.parseInt(args[0]); int [] tid = new int[11]; class QuicksortProg{ public for(int static i void = 0; main(string[] i < 11; i++){ args){ int len int[] = Integer.parseInt(args[0]); arr = new int[len]; for(int Random i = 0; i < r = 11; new i++){ Random(); int[] for(int arr = j new = 0; int[len]; j < arr.length; j++){ Random r = new Random(); arr[j] = r.nextint(len-1); for(int j = 0; j < arr.length; j++){ arr[j] = r.nextint(len-1); long start = System.nanoTime(); long int[] start k = System.nanoTime(); int[] k = new QuicksortCalc().quicksort (arr,0,arr.length-1); long timetakenns = System.nanoTime() - start; tid[i] = (int) timetakenns/1000000; System.out.println(timeTakenNS/100000.0); new QuicksortCalc().quicksort (arr,0,arr.length-1); long timetakenns = System.nanoTime() - start; System.out.println(timeTakenNS/100000.0); tid = QuicksortCalc.insertSort(tid,0,10); System.out.println("Median sorteringstid for 11 gjennomlop:"+tid[5]+"ms. for n="+len); class QuicksortCalc{ int INSERT_LIM = 48; int[] quicksort (int[] a, int left, int right){ if (right-left < INSERT_LIM){ return insertsort(a,left,right); else{ int pivotvalue = a[(left + right) / 2]; swap(a, (left + right) / 2, right); int index = left; for (int i = left; i < right; i++) { if (a[i] <= pivotvalue) { swap(a, i, index); index++; swap(a, index, right); int index2 = index; while(index2 > left && a[index2] == pivotvalue){ index2--; a = quicksort (a, left, index2); a = quicksort (a, index + 1, right); return a; Nesten helt vanlig QuickSort vi har riktignok pakket den inn i en klasse Vi kompilerer og kjører den og tar tiden (11 ganger) 21

QuickSort av 10 mill tall (ca. 0.95 sek) sekvensielt M:\INF2440Para\PRP>java QuicksortProg 10000000 919.320237 948.897802 950.035171 946.001883 937.006513 940.43017 1027.33572 995.356381 1011.87974 934.688378 957.091764 Median sorteringstid for 11 gjennomlop:948ms. for n=10000000 22

Nå legger vi til tre kommentarer så den kan preprosessereres over i en parallell versjon (/*REC*/ og /*FUNC*/ ): import java.util.random; class QuicksortProg{ public static void main(string[] args){ int len = Integer.parseInt(args[0]); int [] tid = new int[11]; for(int i = 0; i < 11; i++){ for(int i = 0; i < 11; i++){ int[] arr = new int[len]; Random r = new Random(); for(int j = 0; j < arr.length; j++){ arr[j] = r.nextint(len-1); long start = System.nanoTime(); int[] k = new QuicksortCalc().quicksort(arr,0,arr.length-1); long timetakenns = System.nanoTime() - start; tid[i] = (int) timetakenns/1000000; System.out.println(timeTakenNS/100000.0); tid = QuicksortCalc.insertSort(tid,0,10); System.out.println("Median sorteringstid for 11 gjennomlop:"+tid[5]+"ms. for n="+len); class QuicksortCalc{ int INSERT_LIM = 48; /*FUNC*/ int[] quicksort(int[] a, int left, int right){ if (right-left < INSERT_LIM){ return insertsort(a,left,right); else{ int pivotvalue = a[(left + right) / 2]; swap(a, (left + right) / 2, right); int index = left; for (int i = left; i < right; i++) { if (a[i] <= pivotvalue) { swap(a, i, index); index++; swap(a, index, right); int index2 = index; while(index2 > left && a[index2] == pivotvalue){ index2--; /*REC*/ a = quicksort(a, left, index2); /*REC*/ a = quicksort(a, index + 1, right); return a; 23

Kompilér JavaPRP -systemet, så start det M:\INF2440Para\PRP>javac JavaPRP.java M:\INF2440Para\PRP>java JavaPRP Det starter et GUI-interface 24

25

Trykker: Choose a file 26

27

Trykket så Compile: - Kompilerte da den parallelliserte filen: QuicksortProgPara.java - Legger så inn parameter (10 mill) på kommandolinja og velger Execute. 28

Resultatet kommer i log-vinduet. -en OK speedup for den parallelle utførelsen: S=948/525= 1,80 29

Oversettelsen : Quicksort import java.util.random; class QuicksortProgPara{ public static void main(string[] args){ new Admin(args); class QuicksortProg{ public static void main(string[] args){ int len = Integer.parseInt(args[0]); for(int i = 0; i < 11; i++){ int[] arr = new int[len]; Random r = new Random(); for(int j = 0; j < arr.length; j++){ arr[j] = r.nextint(len-1); long start = System.nanoTime(); int[] k = new QuicksortCalc().quicksort (arr,0,arr.length-1); long timetakenns = System.nanoTime() - start; System.out.println(timeTakenNS/100000.0); Starten på brukerens kode (77 linjer) class Admin{ public Admin(String[] args){ initiateparallel(args); void initiateparallel(string[] args){ int len = Integer.parseInt(args[0]); for(int i = 0; i < 11; i++){ int[] arr = new int[len]; Random r = new Random(); for(int j = 0; j < arr.length; j++){ arr[j] = r.nextint(len-1); long start = System.nanoTime(); int[] k = startthreads (arr,0,arr.length-1); long timetakenns = System.nanoTime() - start System.out.println(timeTakenNS/100000.0); Starten på oversatt kode (245 linjer) 30

Dette kan også kjøres delvis linjeorientert Din sekvensielle rekursive løsning (som er annotert for PRP) heter MittProg.java 1) Hvis du ønsker det, kjør ditt egent program og notere eksekveringstiden. >javac MittProg.java >java MittProg 1000000 2) Kompilér PRP-systemet (hvis du ikke har gjort det tidligere) >java javaprp.java 3) Oversett ditt program (MittProg.java) til et parallelt program (MittProgPara.java) dette må gjøres via GUI >java javaprp velg da MittProg.java og trykk Compile 4) Kjør det genererte parallelle programmet (MittProgPara.java) > java MittProgPara 1000000 31

PRP kan også kan parallelliseres et fasedelt program Et fasedelt PRP-program har flere faser som hver består av først en parallell rekursiv del og så en sekvensiell del (kan sløyfes). Da må brukeren beskrive det i en egen ADMIN metode: /*ADMIN*/ public int minadminmetode(...){ int svar = rekursivmetode1(...); sekvensiellkode1(); svar = rekursivmetode2(...); sekvensiellkode2(...); svar = rekursivmetode3(...); sekvensiellkode3(...); svar = rekursivmetode4(...); sekvensiellkode4(...); return svar; Innfører da to nye Kommentarkoder: /*ADMIN*/ og /*FUNC 1*/, /*FUNC 2*/, osv 32

Og hver av disse rekursive metodene er i hver sin klasse. class MittFaseProgram{ public static void main(string[] args){ <returverdi> svar = new MittFaseProgram().minAdminMetode(...); /*ADMIN*/ <returverdi> minadminmetode(...){ <returverdi> svar1 = new Fase1().rekursivMetode(...); sekvensiellkode1(...); <returverdi> svar2 = new Fase2().rekursivMetode(...); sekvensiellkode2(...); return...; void sekvensiellkode1(...){ void sekvensiellkode2(...){ // end MittFaseProgram class Fase1{ /*FUNC 1*/ <returverdi> rekursivmetode(...){ /*REC*/ <returverdi> svar1 = rekursivmetode(...); /*REC*/ <returverdi> svar2 = rekursivmetode(...); return...; class Fase2{ /*FUNC 2*/ <returverdi> rekursivmetode(...){ /*REC*/ <returverdi> svar1 = rekursivmetode(...); /*REC*/ <returverdi> svar2 = rekursivmetode(...); /*REC*/ <returverdi> svar3 = rekursivmetode(...); return...; 33

Hvordan gjøres dette? Administrator arbeider modell Oppgaver legges ut i et fellesområde Arbeiderne tar oppgaver og legger svar tilbake i fellesområdet 34

Fra sekvensielt program til parallelt: Figur 5: Fra det sekvensielle programmet, gjennom Java PRP og til det parallelle resultatet. Det nye, parallelle programmet vil inneholde en klasse for main, Admin, Worker pluss eventuelt andre klasser fra det sekvensielle programmet, som ikke er en del av parallelliseringen. 35

Eksempel: Parallellisering med to tråder PRP: Toppen kjøres med tråder bredde-først, så går hver tråd over til dybde først og vanlige rekursive kall Figur 6: Visualisering av treet der vi ønsker å parallellisere med to tråder. Toppen av treet tilsvarer bredde først traversering til vi ender på, i dette tilfelle, to subtrær. Disse to subtrærne vil traverseres dybde først 36

Fra bredde først til dybde først og så vanlig rekursjon Trådene blir når de lages lagt i en LenkaListe (FIFO-kø) Så tas den første(a) i køen ut, og den lager to nye barne-tråder (B,C) som legges i lista. A legges i en stack (LIFO-kø) Neste på i Lista (B) tas ut og dens nye barne-tråder (D,E) legges inn i Lista B legges på stacken, osv. Bunnen av bredde-først ligger da på toppen av stacken Figur 7: Administratoren oppretter datastrukturen til arbeiderne. Figur 8: Datastrukturen etter at Figur 7 er ferdig. 37

Kjøring og retur av verdier Når trådene er brukt opp, pop-es stacken (f.eks øverst er E) og vanlige rekursive kall gjøres fra E, neste pop-es osv. til stacken er tom Svarene fra ethvert element som tas av stacken legges i en tabell og plukkes opp av den som kalte elementet. Den som kalte, kan så fortsette sin kode og selv returnere sitt svar,.. Figur 9: Arbeiderstacken beregner seg innover til roten. 38

Svarene genereres nederst stacken og svarene propaganderer oppover til første kall på den rekursive metoden 39

Hvorfor dette med bredde-og dybde-først? Kunne vi ikke bare startet trådene og latt de alle gå i parallell? NEI fordi: Vi har lovet rekursiv semantikk (virkemåte) i den parallelle. Vi skal derfor oversette det rekursive programmet slik at det gir alltid samme resultat parallelt. Eks Quicksort: Anta at vi parallelliserer ned til nivå 3 i treet Hvis nivå 2 og 3 går samtidig, vil dette gå galt fordi de prøver begge lagene og flytte på de samme elementene i a[]. 40

Hva gjøres teknisk vår program består av (minst) to klasser Klassen med main og en klasse som inneholder den rekursive metoden Er det flere rekursive metoder som skal parallelliseres, så skal de være inne i hver sin klasse Det genererte programmet består av minst følgende klasser: Admin Worker Kort og greit: Det oversatte programmet xxxxxpara.java skal vi egentlig ikke se på og spesielt ikke endre. Det bare virker og parallelliserer etter visse prinsipper. 41

Eksempel 2: Største tall i en array class Search{ int k = 5; /*FUNC*/ int findlargest(int[] arr, int start, int end){ class LargestNumber{ public static void main(string[] args){ int len = Integer.parseInt(args[0]); int cores = Runtime.getRuntime().availableProcessors(); int[] arr = new int[len]; Random r = new Random(); for(int i = 0; i < arr.length; i++){ arr[i] = r.nextint(len-1); long t = System.nanoTime(); /*CALL*/ int k = (new Search()).findLargest(arr,0,arr.length); Double t2 =(System.nanoTime()-t)/1000000.0; System.out.println("Largest number is " + k+ ", paa:"+t2+"ms."); if((end-start) < k){ return largest_basecase(arr,start,end); int half = (end-start) / 2; int mid = start + half; /*REC*/ int leftval = findlargest (arr,start,mid); /*REC*/ int rightval = findlargest (arr,mid+1,end); if(leftval > rightval) return leftval; return rightval; int largest_basecase(int[] arr, int start, int end){ int largest = 0; for(int i = start; i < end; i++){ if(arr[i] > largest){ largest = arr[i]; return largest; 42

NB. for å få kjøretiden riktig for det parallelle programmet N.B det som oppgis som «program execution time» er med overhead fra GUI løsningen. Fra GUI-en: Opening: LargestNumber.java Created: LargestNumberPara.java javac LargestNumberPara.java java LargestNumberPara 100000000 Largest number is 99999994, paa:152.171677ms. program execution time: 1511.89 ms Kjør det i linjemodus (n= 100 mill.): M:\INF2440Para\PRP>java LargestNumberPara 100000000 Largest number is 99999998, paa:135.922687ms. M:\INF2440Para\PRP>java LargestNumber 100000000 Largest number is 99999998, paa:417.98199ms. 43

Hva så vi på i Uke10 Automatisk parallellisering av rekursjon PRP- Parallel Recursive Procedures Nåværende løsning (Java, multicore CPU, felles hukommelse) implementasjon: Peter L. Eidsvik Demo av to eksempler kjøring Hvordan ikke gå i fella: Et Rekursivt kall = En Tråd Halvautomatisk oversettelse (hint/kommandoer fra kommentarer) Hvordan virker en kompilator (preprosessor) for automatisk parallellisering Prinsipper ( bredde-først og dybde-først traversering av r-treet) Datastruktur Eksekvering Krav til et program som skal bruke PRP Slik bruker du PRP Ukeoppgave neste uke. 44