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

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

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

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

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

Java PRP brukermanual

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

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

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 12, v2014. Arne Maus OMS, Inst. for informatikk

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

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

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

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

UNIVERSITETET I OSLO

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

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

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

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

UNIVERSITETET I OSLO

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

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

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

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

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

UNIVERSITETET I OSLO

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

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

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

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

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

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

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

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

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

Arne Maus OMS, Inst. for informatikk

Logaritmiske sorteringsalgoritmer

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

Kap 19. Mer om parallelle programmer i Java og Kvikksort

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

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

Sortering med tråder - Quicksort

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

7) Radix-sortering sekvensielt kode og effekten av cache

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

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

IN3030 Uke 12, v2019. Eric Jul PSE, Inst. for informatikk

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

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

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

Binære trær: Noen algoritmer og anvendelser

Fra Python til Java, del 2

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

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

INF1000: noen avsluttende ord

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

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

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

INF2220 høsten 2017, 12. okt.

UNIVERSITETET I OSLO

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister

Stack. En enkel, lineær datastruktur

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

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

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

Eivind Gard Lund. 24. Mars 2009 Foilene bygger på 2009 utgaven av Andreas Svendsen

Hvor raskt klarer vi å sortere?

UNIVERSITETET I OSLO

Kort repetisjon av doble (nestede) løkker Mer om 1D-arrayer Introduksjon til 2D-arrayer Metoder

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:

Algoritmer og datastrukturer Løsningsforslag

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

INF1000 undervisningen INF 1000 høsten 2011 Uke september

EKSAMEN Løsningsforslag. med forbehold om bugs :-)

Algoritmer og Datastrukturer

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

Løsningsforslag 2017 eksamen

INF Notater. Veronika Heimsbakk 10. juni 2012

INF1000 (Uke 5) Mer om løkker, arrayer og metoder

Sorteringsproblemet. Gitt en array A med n elementer som kan sammenlignes med hverandre:

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister Videre

INF1000 Metoder. Marit Nybakken 16. februar 2004

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

UNIVERSITETET I OSLO

INF1000 EKSTRATILBUD. Stoff fra uke 1-5 (6) 3. oktober 2012 Siri Moe Jensen

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

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

Innhold uke 4. INF 1000 høsten 2011 Uke 4: 13. september. Deklarasjon av peker og opprettelse av arrayobjektet. Representasjon av array i Java

EKSAMEN med løsningsforslag

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

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

Parallellprogrammering og Sortering INF nov. 2015

UNIVERSITETET I OSLO

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

Transkript:

INF2440 Uke 10, v2016 : 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 Oblig4 Ukeoppgavene Bla. bør lage klasse IntList Hvor lang tid tar de ulike mekanismene vi har i Java 6 og 8? 2

Hva skal vi se på i Uke10 Oppklaring om rekursiv parallellisering 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 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 Noen Tips til Oblig3 - MultiRadix 3

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){; 4

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; B A Oppdeling med to tråder per nivå i treet: Når ventes det i den rekursive løsningen Har det betydning for rekkefølgen av venting? Når ventes det i den parallelle løsningen A? Har rekkefølgen på venting på t1 og t2 betydning? Antar at kall på Rek tar T millisek. Hvor lang tid tar A og B Hvilken er raskest? if (deling- left > LIMIT ) (t1 = new Thread (a,left, deling -1)).start(); else <enkel løsning>; if (right - deling> LIMIT) (t2 = new Thread (a, deling, right)).start(); else <enkel løsning> try{ if (t1!=null)t1.join(); if (t2!=null)t2.join(); catch(exception e){return;; 5

A 1 8 2 5 9 12 3 4 6 7 10 11 13 14 Rekursjon Tråd Dybde først (alltid venstre gren først) - sekvensiell B 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Rekursjon Tråd Bredde først - parallell 6

Oppdeling med en tråd per nivå i treet: Hvorfor virker dette? To alternativ løsning med 1 tråd Har det betydning for rekkefølgen av venting? Når ventes det i C-løsningen? Har rekkefølgen på venting på t1 betydning? Når ventes det i D-løsningen? Antar at kall på Rek tar T millisek. Hvor lang tid tar C Hvor lang tid tar D Hvilken er klart raskest: C eller D? void Rek(int [] a, int left, int right) { <del opp omradet a[left..right]> int deling = partition (a, left,right); Thread t1; if (deling - left > LIMIT ) Rek (a,left,deling-1); else <enkel løsning>; if (right - deling > LIMIT) t1 = new Thread (a,right,deling-1); else <enkel løsning> try{t1.join(); catch(exception e){; void Rek(int [] a, int left, int right) { <del opp omradet a[left..right]> int deling = partition (a, left,right); Thread t1; if (deling - left > LIMIT ) t1 = new Thread (a,left,deling-1); else <enkel løsning>; if (right - deling > LIMIT) Rek (a,deling, right); else <enkel løsning> try{t1.join(); catch(exception e){; C D 7

C 1 8 2 5 9 12 3 4 6 7 10 11 13 14 D 7 8 Rekursjon Tråd 3 Dybde først - sekvensiell 1 2 4 5 9 10 11 12 6 13 14 Forskjellen på C og Der at: i C tar vi rekursjonen før vi starter tråden I D starter vi tråden før vi tar rekursjonen D er raskest fordi både høyre og venstre gren startes før man venter. Rekursjon Tråd Bredde først - parallell 8

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 : 5-0.02 µs og kan også optimaliseres bort (og gis speedup >1) Å lage en tråd og starte den opp tar: ca.3000 µs, men ca. 62 µ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! 9

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 Bare tråder med insertsort 100000 7.682 5.198 1.4777 Tråder bare i toppen med så rekursjon og insertsort Speedup > 1 og ca. 10 000x fortere enn ren oversettelse. 10

Drømmen om lage automatisk parallellisering 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 parallelliserte løkker (slo ikke helt an) Intel har laget en rekke slike systemer (se neste foil) Rekursive metoder vi skal se på PRP (et system jeg har fått lager som hovedfagsoppgaver flere ganger siden ca. 1995) 11

Noen av Intels parallelliserings-biblioteker i C, /C++ og Fortran Intel Math Kernel Library Ferdig parallelliserte metoder basert på MPI Cilk Plus parallellisering av særlig løkker Implementerer tre kompilator direktiver cilk_spawn, cilk_sync og cilk_for for Open MP MPI en overbygning over MPI med en rekke kompilator-direktiver for parallellisere blokker av koden, særlig for-løkker (har en felles hukommelses-modell, melitt for lett å gjøre data-r). Standard bibliotek for meldingsutveksling mellom prosesser (uten felles hukommelse). Brukes bla. I kurset INF3380 for grid-programmering Pthreads I Linux og C. Som tråder i Java full kontroll over parallelliteten og da ikke automatisk parallellisering. 12

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.. 13

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 14

Løst beskrevet, den grunnleggende PRP-ideen: Vi omformer alle rekursive metoder slik: Vi stjeler parametrene til det første kallet. Koden frem til det rekursive kallet blir en egen metode: Istedenfor å gjøre det rekursive kallet, kaller vi en metode som stjeler alle parametrene til det rekursive kallet - disse parametrene er da en parallell arbeids-pakke. Vi kjører denne metoden bredde først til vi har nok parameter-pakker. En ny metode i hver sin tråd : kalles med en slik parameter-pakke Blir en egen metode i en egen tråd som får en slik parameterpakke, utfører beregningene vanlig sekvensielt og rekursivt, og returnerer svaret. og når alle disse vanlige metodene har returnert sine svar, utføres resten av metodene i de metodekallene hvor vi stjal parametrene nedenfra og opp i treet. Vi har altså 3 versjoner av den rekursive metoden: Den hvor vi stjeler parametrene Den som henter et svar istedenfor å utføre kallet Den vanlige rekursive metoden uendret 15

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 parallelliseres. 16

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(); int[] k 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); 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) 17

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 18

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; 19

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

21

Trykker: Choose a file 22

23

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

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

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) 26

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 27

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 28

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...; 29

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

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. 31

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 32

Fra bredde først til dybde først og så vanlig rekursjon Trådene blir når de lages lagt i en Lenket Liste (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. 33

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. 34

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

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 å flytte på de samme elementene i a[]. 36

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. 37

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; 38

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. 39

Litt tips til Oblig3 - MultiRadix Problemet med data-konkurranse: To eller flere tråder skriver samtidig på samme variabel (i++-problemet), i samme plass i en array: Løsning: Hver tråd har en kopi av disse felles variable Etter at alle trådene er ferdig (f.eks. etter en barrier-synk) kan resultatene fra hver tråd samstilles (også dette helst i parallell) til et felles svar Muligens må man kopiere data mer enn en gang? Oppdeling av data i arrayer man skal behandle med k tråder: Dele opp arrayen i like store deler (det er indeksene man deler opp) Dele opp etter verdiene i elementene (tråd 0 eier de minste verdiene, tråd 1 de nest-minste,..,) 40

a) finn max verdi i a[] a[] eies av tråd0 eies av tråd1 allmax[] int globalmax 0 1 k-1 eies av tråd k-1 Tråd-i finner max i sin del av a[] og legger svaret i allmax[i] <sync på en CyclicBarrier cb> Nå har alle trådene sin max i allmax[] valg nå: Skal en av trådene (f.eks. tråd-0) finne svaret og legge det i en felles globalmax (mens de andre trådene venter i så fall nok en <sync på en CyclicBarrier cb>)? Skal alle trådene hver regne ut en lokal globalmax (de får vel samme svar?) og fortsette direkte til steg b) 41

b) count= oppttelling av ulike sifferverdier i a[] Anta at det er 10 bit i et siffer dvs. 1024 mulige sifferverdier a[] eies av tråd0 eies av tråd1 count[] 0 1 allcount[] [] 0. k eies av tråd k-1 1023 Skal: 1. Hver tråd ha en kopi av count[] 2. Eller skal count være en AtomicIntegerArray 3. Eller skal de ulike trådene gå gjennom hele a[] og tråd-0 bare ta de små verdiene, tråd-1 de nest minste verdien,..(dvs: dele verdiene mellom trådene) 42

Om Oblig3 feil i programmet som er lagt ut Det er et kall på en metode testsort(a); Kommenter ut det kallet så virker koden Hva tror dere metoden gjør skriv den selv Jeg skal legge ut java-koden med tastsort nå. 43

Hva så vi på i Uke10 Hvordan ikke gå i fella: Et Rekursivt kall = En Tråd Halvautomatisk oversettelse (hint/kommandoer fra kommentarer) 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 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. Litt tips til Oblig 3 44