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

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

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

7) Radix-sortering sekvensielt kode og effekten av cache

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

INF2440, Uke 3, våren2015 Regler for parallelle programmer, mer om cache og Radix-algoritmen. Arne Maus OMS, 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 3, våren2014 Regler for parallelle programmer, mer om cache og Radix-algoritmen. Arne Maus OMS, Inst. for informatikk

UNIVERSITETET I OSLO

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

INF2440 Uke 5, våren2015 Om oppdeling av et problem for parallellisering, mye om primtall + thread-safe. Arne Maus PSE, Inst.

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

UNIVERSITETET I OSLO

Arne Maus OMS, Inst. for informatikk

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

UNIVERSITETET I OSLO

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

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

UNIVERSITETET I OSLO

INF2440 Uke 4, v2018 Om å samle parallelle svar, matrisemultiplikasjon og The Java Memory Model. Eric Jul PSE, Inst.

UNIVERSITETET I OSLO

UNIVERSITETET I OSLO

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

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

INF NOV PARALLELL SORTERING. Arne Maus, PSE, Ifi

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

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

Parallellprogrammering og Sortering INF nov. 2015

INF2440 Uke 9, v2017 : Om Oblig 3 - radixsortering, Ulike Threadpools, JIT-kompilering. Arne Maus PSE, Inst. for informatikk

INF2220 høsten 2017, 12. okt.

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

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

INF1010 Tråder II 6. april 2016

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

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

Kap 19. Mer om parallelle programmer i Java og Kvikksort

Tråder Repetisjon. 9. og 13. mai Tråder

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

INF2440 Uke 15, v2014 oppsummering. Arne Maus OMS, Inst. for informatikk

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

UNIVERSITETET I OSLO

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

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

UNIVERSITETET I OSLO

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

INF 1000 høsten 2011 Uke september

INF1000 undervisningen INF 1000 høsten 2011 Uke september

INF2220 høsten 2017, 19. okt.

INF2220 høsten 2016, 9. nov.

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

MER OM PARALLELLE PROGRAMMER I JAVA OG KVIKKSORT

INF2220 høsten 2015, 5. nov.

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

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

UNIVERSITETET I OSLO

Tråder Repetisjon. 9. og 13. mai Tråder

Java PRP brukermanual

Sortering med tråder - Quicksort

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

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

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

INF1000: noen avsluttende ord

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

INF2440 Uke 15, v2017 litt om parallellisering av Oblig4 + oppsummering av kurset. Arne Maus PSE, Inst. for informatikk

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

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

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

La oss begynne med en repetisjon av hva som skjer når du kjører Javaprogrammet

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

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

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

IN1010 våren Repetisjon av tråder. 15. mai 2018

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

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

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

UNIVERSITETET I OSLO

INF1010 notat: Binærsøking og quicksort

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

Forelesning inf Java 5

Forelesning inf Java 5

Norsk informatikkolympiade runde

INF1010 Sortering. Marit Nybakken 1. mars 2004

Oversikt. INF1000 Uke 1 time 2. Repetisjon - Introduksjon. Repetisjon - Program

Repetisjon: operatorene ++ og -- Java 5. Nøtt. Oppgave 1 (fra forrige gang) 0 udefinert udefinert. Alternativ 1 Prefiks-operator

LITT OM OPPLEGGET. INF1000 EKSTRATILBUD Stoff fra uke September 2012 Siri Moe Jensen EKSEMPLER

INF1010 Tråder J. Marit Nybakken Motivasjon. Å lage en tråd

Programmeringsspråket C

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

Oppgave 1. INF1000 Uke 13. Oppgave 2. Oppgave 3. Er dette lovlige deklarasjoner (når de foretas inni en metode)? JA NEI

INF Notater. Veronika Heimsbakk 10. juni 2012

INF2220: Time 12 - Sortering

2 Om statiske variable/konstanter og statiske metoder.

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

Litt mer om uttrykk: ++ og -- INF1000 : Forelesning 4. Oppgave. Blokker. 0 udefinert udefinert. Alternativ 2 Postfiks-operator

Algoritmer og datastrukturer Kapittel 1 - Delkapittel 1.8

Tre måter å lese fra terminal. Java 4. Eksempel. Formatert utskrift til skjerm

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister Videre

UNIVERSITETET I OSLO

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister

Transkript:

INF Uke, v7 Om å samle parallelle svar, matrisemultiplikasjon og The Java Memory Model + evt bedre forklaring Radix Arne Maus PSE, Inst. for informatikk

Hva så vi på i uke. Presisering av hva som er pensum. Samtidig skriving av flere tråder i en array?. Går det langsommere når aksessen er til naboelementer?. Synlighetsproblemet (hvilke verdier ser ulike tråder). Java har as-if sequential semantikk for et sekvensielt program.. viktigste regler om lesing og skriving på felles data.. To enkle regler for synkronisering og felles variable 7. Jit-kompilering kan gi meget store hastighetsforbedringer 8. Effekten på eksekveringstid av cache. Del Radix-sortering sekvensiell 9. Kommentarer til Oblig

Plan for uke I. Om å avlutte k tråder med å samle svarene fra disse. gal + riktige måter. II. III. IV. Kommentarer til svar på ukeoppgaven om matrisemultiplikasjon I. Hvorfor disse gode resultatene (speedup > ) II. Hvordan bør vi fremstille slike ytelsestall 8 alternativer Vi bruker ikke PRAM modellen for parallelle beregninger I. Hva er PRAM og hvorfor er den ubrukelig for oss Hva skjer egentlig i lageret (main memory) når vi kjører parallelle tråder - the Java Memory Model V. Hvorfor synkroniserer vi, og hva skjer da? VI. + evt: Ny, bedre forklaring på Radix

I) Hvordan samle data fra trådene til ett, felles svar Kursets mål: Riktig og Raskt - begge deler Skal se på ulike måter å løse flg. problem: Vi har delt opp problemet vår i k deler på k kjerner/tråder og parallellisert det. Hvordan kombinerer vi disse delresultatene til ett, felles og riktig svar? Ser på problemet FinnMax og «løsninger» på denne avslutningen:. GAL ingen synkronisering. Synchronized metode for hvert element i a[]. ReentrantLock beskyttet metode for hvert element i a[]. Bare kall på samme ReentrantLock beskyttet metode hvis ny verdi > hittil største verdi.. Alle trådene kaller samme ReentrantLock beskyttet metode med hver sin lokalemaks når de er ferdige. Tråd finner max de andre trådene venter

) GAL ingen synkronisering, koden i trådene: // Riktig oppdeling ant= a.length/anttråder; // antall elementer per tråd start = ant*ind; num = ant; if (ind == anttråder-) num = ant + (a.length % anttråder) ; // GAL IKKE synkronisert: for (int i = ; i< num; i++) { if (a[start+i] > globalmax) globalmax = a[start+i]; } Mulig feilsituasjon, anta tråd leser a[i] der GlobalMax ligger: Tråd Les a[i] = og GM = 8 Skriv GM = Tråd Les a[j] =9 og GM = 8 Skriv GM = 9 main Les GM = 9 Hvor sannsynlig er dette? Skal vi ta sjansen??

) Nei det er like raske og ALLTID riktige løsninger, og slike feil er farlige! Det er vanskelig å få denne gale måten til å feile, men med mye prøving og feiling (lure data) kan vi få den til å feile ca. ca. hver gang. I Nets (tidl. Bankenes Betaligssentral) behandler de opp til mill. transaksjoner hver dag. Vil vi lage programmer som kanskje feiler ganger per dag? Hvor lette tror du slike programmer er å debugge (teste og rette)?

) Bruk av synchronized metode for alle elementene i a[] synchronized void updateglobalmax (int val){ if (val > globalmax ) globalmax=val; } // end updateglobalmax.. // i run-metoden i hver tråd: for (int i = ; i< num; i++) { updateglobalmax(a[start+i]); } % riktig svar alltid Det gjøres n kall på den synkroniserte metoden (n/k kall fra hver av de k trådene) synchronized tar mye tid! Elendig løsning 7

) Bruk av ReentrantLock metode for alle elementene i a[] void updateglobalmax (int val){ lock.lock(); try{ if (val > globalmax ) globalmax=val; } finally { lock.unlock(); } } // end updateglobalmax. // i run-metoden i hver tråd for (int i = ; i< num; i++) { updateglobalmax(a[start+i]); } % riktig svar alltid Det gjøres n kall på lock metoden (n/k kall fra hver av de k trådene) Lock er raskere enn synchronized, men tar fortsatt mye tid! Elendig løsning 8

) Bruk av ReentrantLock metode hver gang nytt element er større void updateglobalmax (int val){ lock.lock(); try{ if (val > globalmax ) globalmax=val; } finally { lock.unlock(); } } // end updateglobalmax. // i run-metoden i hver tråd for (int i = ; i< num; i++) { if (a[start+i] > globalmax ){ updateglobalmax(a[start+i]); }} % riktig svar alltid Det gjøres logn kall på lock metoden (logn/k kall fra hver av de k trådene) Lock er raskere enn synchronized, og logn kall er mye mindre enn n (eks. n= mill, logn =)! Ikke helt bra løsning 9

) lokal max (threadmax) i hver tråd, så oppdatering med lock - metode // i run-metoden i hver tråd for (int i = ; i< num; i++) { if (a[start+i] > threadmax ) threadmax = a[start+i]; } updateglobalmax(threadmax); } % riktig svar alltid Det gjøres k kall på lock-metoden (ett kall fra hver av de k trådene) Utmerket løsning

) lokal max (threadmax) i hver tråd, så venting i ny CyclicBarrier (ventm), og tråd ordner opp // i hver tråd i run-metoden for (int i = ; i < num; i++) { if (a[start+i] > threadmax ) threadmax = a[start+i]; } lokalmax[ind] = threadmax; try { // wait on all other threads ventm.await(); } catch (Exception e) {return;} % riktig svar alltid if (ind Det == gjøres ) { k kall på lock metoden (ett kall fra hver av de k trådene) for (int j = ; j < anttråder; j++){ Utmerket løsning } } if (lokalmax[j] > globalmax) globalmax = lokalmax[j]; Riktig og det gjøres k kall på en CylicBarrier(ett kall fra hver av de k trådene) Utmerket løsning

Speedup for n=,,, mrd med 8 tråder/kjerner

Hva lærer vi av dette? En gal, to elendige, en dårlig og to gode løsninger Aldri bruk en gal metode (går alltid galt med i++ - programmet, sjelden galt her, men..) Det er alltid en eller flere like raske og riktige løsninger Antall synkroniseringer er helt avgjørende n, log n eller k (k er et fast, lite tall) Generelt: Det er langt flere alternativer i det parallelle programmet enn i det sekvensielle. Her har vi en løsning hvor vi bare lager trådene bare én gang. Vi kunne (langsommere) ha laget nye tråder hver gang og at main sa join() på dem nye alternativer.

Tillegg, hva om sekvensiell max lages som metode? int RegnutMaxSeq(int [] a) { int seq =; for (int i=;i < a.length;i++){ if (a[i] > seq) seq = a[i]; } return seq; }//end RegnutMaxSeq.. globalmaxseq = RegnutMaxSeq(a); // for (int i=;i < a.length;i++){ // if(a[i] > globalmaxseq) globalmaxseq = a[i]; // } Hvorfor skulle det gå fortere?? JIT-kompilering??

Mye bedre JIT-kompilering av sekvensiell beregning (= raskere sekvensiell bergning); samme parallelle og samme form på kurvene, men da lavere speedup. Her ca. x raskere - bedre JIT kompilering av små metoder enn koden inline i en større metode.

Ny I DAG: Hvis vi ser på kjøretidene, så burde de kunne gjøres noe bedre! // i run-metoden i hver tråd noe langsom for (int i = ; i< num; i++) { if (a[start+i] > threadmax ) threadmax = a[start+i]; } updateglobalmax(threadmax); } // bedre: i run-metoden i hver tråd - raskere for (int i = fra; i< til; i++) { if (a[i] > threadmax ) threadmax = a[i]; } updateglobalmax(threadmax); }

Ny I DAG: Hvis vi ser på kjøretidene, så burde de kunne gjøres noe bedre med ny for-løkke + små metoder Speedup går opp fra. til7, Kjøretider for N= mil - ny forløkke og liten metode for hver løkke: Met:, Para: 9.8 ms; Sekv:. ms., SUp:. Met:, Para: 9. ms; Sekv:. ms., SUp:.7 Met:, Para: 8. ms; Sekv:. ms., SUp:.98 Met:, Para:. ms; Sekv:. ms., SUp:.7 Met:, Para: 9.8 ms; Sekv:. ms., SUp:. Met:, Para:. ms; Sekv:. ms., SUp:. Speedup går opp fra. til7, Kjøretider for N= mil - gammel forløkke og liten metode for hver løkke : Met:, Para:.8 ms; Sekv:.987 ms., SUp:. Met:, Para: 9. ms; Sekv:.987 ms., SUp:.8 Met:, Para: 9.9 ms; Sekv:.987 ms., SUp:. Met:, Para:. ms; Sekv:.987 ms., SUp:. Met:, Para:. ms; Sekv:.987 ms., SUp:.88 Met:, Para:. ms; Sekv:.987 ms., SUp:.8 7

II) Ukeoppgaven forrige og denne uka, matrisemultiplisering Matriser er todimensjonale arrayer Skal beregne C=AxB (A,B,C er matriser) n c i [j] = a i k b k [j] k= C i,j = A i cc X B cc j n- n- 8

Idé transponer B (=bytte om rader og kolonner) Bytt om elementene i B (B i,j byttes om med B j,i ) Da blir kolonnene lagret radvis. B cc j B T cc j n- n- Begrunnelse: Det blir for mange cache-linjer (hver byte) fra B i cachene 9

Vi har da at litt ny formel for C c i [j] = n k= a i k b T j [k] C i,j = A i cc X B T c c j n- n- Vi får multiplisert to rader med hverandre går det fortere?

Kjøretider i millisek. (y-aksen logaritmisk)

Kjøretidsresultater Speedup, y-aksen logaritmisk

Speedup med lineær y-akse

Konklusjon Matrisemultiplikasjon En rett frem implementasjon gikk ikke særlig fort (når n= ), tok det :, sek med vanlig sekvensiell løsning, sek. med rett fram parallellisering,9 sek med sekvensiell + transponering av B, sek med først transponering av B, så parallellisert Det viktigste når vi skal parallelliser er: Ha den beste sekvensielle algoritmen Så kan du parallellisere den Hvis du er venner med cachen, vil parallellisering av en slik algoritme i tillegg nesten alltid lønne seg Dette er ett eksempel på at det å aksessere data fortløpende, ikke på tvers av data, kan gi en speedup på - ganger. (bare multiplikasjonen ikke transponeringen, ble parallellisert)

Speedup Hvordan fremstille det? Disse to kurvene er like! Hvordan?

Hvordan framstille ytelse I Disse fire kurvene fremviser samme tall! Hvordan?

Både logaritmisk x- og y-akse Fordel med log-akse er at den viser fram nøyaktigere små verdier, men vanskelig å lese nøyaktig mellom to merker på aksene. 7

III) PRAM modellen for parallelle beregninger PRAM (Parallel Random Access Memory) antar to ting: Du har uendelig mange kjerner til beregningene Enhver aksess i lageret tar like lag tid, - ignorerer f.eks fordelen med cache-hukommelsen Da blir mange algoritmer lette å beregne og programmere Problemet er at begge forutsetningene er helt gale. Det PRAM gjør er å telle antall instruksjoner utført Det har vi sett er helt feilaktig (Radix og Matrise-mult) Svært mange kurs og lærebøker er basert på PRAM PRAM vil si at de to sekvensielle algoritmene (med og uten transponering) gikk den utransponerte fortest! Dette kurset bruker ikke PRAM-modellen! 8

Noen kommentarer til modell for parallelle programmer import java.util.concurrent.*; class Problem { int x,y,r,r,..; // felles data public static void main(string [] args) { Problem p = new Problem(); p.utfoer(); } void utfoer (int antt) { Thread [] t = new Thread [antt]; } for (int i =; i< antt; i++) ( t[i] = new Thread(new Arbeider(i))).start(); for (int i =; i< antt; i++) t[i].join(); :Problem int x,y,r,r,..; Thread t[] class Arbeider implements Runnable { int ind, lokaledata; // lokale data Arbeider (int in) {ind = in;) public void run() { // kalles når tråden er startet } // end run } // end indre klasse Arbeider } // end class Problem :Arbeider int ind,lokaldata; :Arbeider int ind,lokaldata; 9

Noen kommentarer til modell for parallelle programmer import java.util.concurrent.*; class Problem { int [] a; int anttr=;// felles data public static void main(string [] args) { Problem p = new Problem(); p.utfoer(anttr); } void utfoer (int antt) { Thread [] t = new Thread [antt]; a = new int []; // + fyll a[] med tilfeldige tall } for (int i =; i< antt; i++) ( t[i] = new Thread(new Arbeider(i))).start(); for (int i =; i< antt; i++) t[i].join(); class Arbeider implements Runnable { int ind, fra,til,num; // lokale data Arbeider (int in) {ind = in; num= a.length/anttr; fra =ind*num; til = (ind+)*num; if ( ind == anttr -) til = a.length; } public void run() { // kalles når tråden er startet } // end run } // end indre klasse Arbeider } // end class Problem

IV) Utsatte operasjoner i JIT-kompilering JIT-kompilatoren kan godt tenke seg å utsette å gjøre noen setninger eks: y = 7; x = ; z = x + ; Vi ser at x trenges i neste setning, så den blir utført, men ingen trenger y så den kan vente (til vi får tid, eller droppes hvis ingen andre setninger bruker y) Vi kan ikke vite at y == 7 selv om x == ; Vi trenger da en måte å ordne opp i bl.a: Utsatte operasjoner blir gjort Alle trådene ser de samme verdiene på felles data.

Repetisjon: viktigste regler om lesing og skriving på felles data. Før (og etter) synkronisering på felles synkroniseringsvariabel gjelder : A. Hvis ingen tråder skriver på en felles variabel, kan alle tråder lese denne. B. To tråder må aldri skrive samtidig på en felles variabel (eks. i++) C. Hvis derimot én tråd skriver på en variabel må bare den tråden lese denne variabelen før synkronisering ingen andre tråder må lese den før synkronisering. Muligens ikke helt tidsoptimalt, men enkel å følge gjør det mulig/mye enklere å skrive parallelle programmer. Regel C er i hovedsak problemet i Java Memory Model

IV) Hva er en memory-modell og hvorfor trenger vi en! Vi har hittil sett at med flere tråder så: Instruksjoner kan bli utsatt og byttet om av CPU, kompilator, cache-systemet Ulike tråder kan samtidig se ulike verdier på felles variabel Programmet du skrev er optimalisert og har liten direkte likhet med det som eksekverer Vi må likevel ha en viss orden på (visse steder i eksekveringen): På rekkefølgen av instruksjonene Synlighet - når ser én tråd det en annen har skrevet? Maskinvare og hukommelse hvor alle-ser-det samme-alltid tar for lang tid Atomære operasjoner Når en operasjon først utføres, skal hele utføres uten at andre operasjoner blander seg inn og ødelegger (som i++) Ulike maskinvare-fabrikanter kan ulike memory-modeller, men Intel/AMD modellen er rask og understøttes av Java.

The Java memory model (JMM) hva skjer i lageret når vi utfører ulike setninger i et Java-program med tråder? JMM definerer hva som er lovlige tilstander på variable når vi har flere tråder, og særlig når flere tråder leser hva en tråd har skrevet; data-kappløp (data-race) om en variabel lest før eller etter den ble skrevet til gammel eller ny verdi?. JMM prøver å tillate så mye som mulig av kompilatoroptimaliseringer (særlig ombytting av setninger) uten at vi får ulogiske/gale resultater. Et sentralt begrep er hendt før (happens before) som betyr at av og til må vi vite at noen setninger har blitt utført, før den setningen vi nå ser på kan utføres. Det gode budskapet er: Hvis alle trådene oppfyller regel c : Hvis bare én tråd skriver på en variabel må også bare denne tråden lese denne variabelen før synkronisering ingen andre tråder må lese den før (neste) synkronisering. så sier JMM at programmet er fritt for data-kappløp og vi kan resonere om programmet vårt som om det utføres sekvensielt!

Et kort innblikk i JMM tillatte og ikke tillatte effekter (ikke pensum) Initially, x == y == Thread Thread : r = x; : r = y : y = ; : x = r ==, r == violates sequential consistency. Kommentar : r kan lett bli, men da er T utført først og r blir da ; alternativt T først og da er r==, men r== Initially, x ==, ready == false. ready is a volatile variable. Thread Thread x = ; if (ready) ready = true; r = x; If r = x; executes, it will read. Figure : Use of Happens-Before Memory Model with Volatiles

Et kort innblikk i JMM tillatte og ikke tillatte effekter (ikke pensum) Initially, x == y == Thread Thread : r = x : r = y : if (r == ) 7: x = r : x = ; : r = x ; : y = r ; Compiler transformations can result in r == r == r == Figure : Behavior that must be allowed Det rare er her hvordan r kan bli ; bare hvis : blir utført etter : og : Konklusjon: Å sette seg inn i og programmere etter JMM er meget vanskelig (nær umulig å gjøre det riktig) hvis vi tillater data-kappløp om variable. Slik programmering overlater vi til de som programmerer våre synkroniserings-mekanismer (CyclickBarrier, Semaphore,..) og de som skriver JIT-kompilatoren.

V) Effekten av synkronisering på samme synkroniseringsvariabel og The Java memory model (JMM) - pensum fortsetter Hva gjør vi hvis vi vil (i en tråd) lese hva en annen tråd har skrevet? Har den andre skrevet enda og har det kommet ned i lageret? Svar: Vi lar begge (alle) trådene synkronisere på samme synkroniseringsvariabel (en CyclicBarrier eller en Semaphore, ): Da skjer følgende før noen fortsetter:. Alle felles variable blir skrevet ned fra cachene og ned i lageret.. Alle operasjoner som er utsatt, blir utført før noen av trådene slipper gjennom synkroniseringen.. Følgelig ser alle trådene de samme verdiene på alle felles variable når de fortsetter etter synkroniseringa! 7

JMM og volatile variable del Enhver variabel i Java kan deklareres som volatile eks: volatile int i =; volatile boolean stop = false; En volatile variabel skal ikke caches, men skrives så fort som mulig ned i lageret. Er tenkt å dekke behovet for delte felles variable som kan oppdateres og straks leses av andre tråder. Å oppdatere (skrive til) en volatile garanterer også at alle utsatte operasjoner i koden utføres før denne skrivingen. Imidlertid er det lett å gjøre feil med volatile variable: Hvis vi deklarerer volatile int i; i vårt program som testet i++, vil det likevel gå galt ved at vi mister oppdateringer. Grunnen til det er at i++ fortsatt er tre operasjoner (les i, i = i+; skriv i), og den samme problemer ved at to tråder gjør dette samtidig. 8

JMM og volatile variable del volatile variable har likevel en nyttig funksjon, ved at den kan nyttes til at en tråd (også main) kan signalisere til de andre trådene at nå er oppgaven løst ferdig. Antar da at alle trådene har en evig løkke i sin run-metode: public void run() {{ while do (!{ stop); try try {{ // // wait on on all all other threads + main vent.await(); }} catch (Exception e) e) {return;} if if (moresort) (! stop) { { sort (a,threadindex ); sort (a,threadindex); // parallell-algoritmen try { // wait on all other threads + main } else ferdig.await(); { } try catch { //(Exception wait all e) other {return;} threads + main ferdig.await(); } //} end catch if (Exception e) {return;} } while (moresort); } // end run } // end else } // end while } // end run I ytre felles klasse: CyclicBarrier vent, ferdig; volatile boolean stop = false;. /** Terminate infinite loop */ synchronized void exit(){ stop= true; try{ // start all treads to // terminate themselves vent.await(); } catch (Exception e) {return ;} } // end exit 9

V) Synkronisering på samme synkroniseringsobjekt løser alle problemer - løser synlighet og utsatte operasjoner. Hvis alle arbeider-trådene gjør en synkronisering på samme synkroniseringsvariabel (en Semaphore, en CyclicBarrier,..) Før de slipper løs, er : Alle felles variable som er skrevet på, skrevet med i hoved-lageret Alle utsatte operasjoner er utført Alle trådene kan da etter å ha gjennomgått den samme synkroniseringa lese samme verdier på alle felles variable! Ingen problemer med en vanskelig JMM hvis vi følger regel C om lesing/skriving på felles variable: «når én tråd skriver på en variabel, må ingen andre tråder lese eller skrive på den» Vi må altså først synkronisere på en felles synkroniseringsvariabel for at en tråds skrivinger skal bli fornuftig lesbart for alle andre trådene og evt. kunne skrives på av en annen tråd.

VII) Radix-sortering den sekvensielle algoritmen Vi aksepterer at vi forrige gang greide å finne verdien av et siffer i a[]: (a[i]>> shift) & mask regner ut sifferverdien av et siffer i a[i] som : Har ett eller flere sifre til høyre for seg (mindre signifikante) som til sammen i sum har shift bit Mask inneholder så mange -ere nederst som det er bit i det sifferet vi vil finne nå og er ellers. Anta at vi skal sortere denne a[] på to sifre, a 7 7

Speedup rel Arrays.sort Jevnt over alle n = lengden av a[], er Radix bra/best. Velger den her! Speedup Radix,, mot QuickSort 8 7 Arrays.sort Radix siffer Radix siffer n - lengde av sortert array

Høyre, minst signifikant siffer først sortering på to sifre: Radix som vi nå bruker Radix-sortering, nå siffer: Radix: Radix-sortering på to sifre Radix bestås av to metoder: radix som først regner ut max-verdien i a[]. Så regnes ut noen konstanter, som antall bit i de to sifrene a[] skal sorteres med. Deretter kalles metoden radixsort for hvert av de to sifrene (dvs. to ganger) radix radixsort radixsort

/** Regn ut størrelsen på de to sifrene i a[] og kall RadixSort()*/ static void radix(int [] a) { // siffer radixsort: a[left..right] int max = a[], numbit =, n =a.length; // finner max = største element i a[] for (int i = ; i < n ; i++) if (a[i] > max) max = a[i]; // numbit = antall bit i max while (max >= (<<numbit) ) numbit++; int bit = numbit/, // lengden i bit av første siffer bit = numbit-bit; // lengden i bit av andre siffer } int[] b = new int [n]; radixsort( a,b, bit, ); // sortert fra a[] til b[] på første siffer radixsort( b,a, bit, bit); // sortert fra b[] til a[] på andre siffer

/** Sorter a[] på ett siffer som har masklen antall bit, og hvor det sifferet er shiftet opp shift antall bit i a[] */ static void radixsort ( int [] a, int [] b, int masklen, int shift){ int acumval =, j, n = a.length; int mask = (<<masklen) -; int [] count = new int [mask+]; // count er nå fylt med // a) count= hvor mange ganger finnes de ulike siffervediene i a[] for (int i = ; i < n; i++) count[(a[i]>> shift) & mask]++; // b) Addér sammen count slik at count[i] sier hvor i b[] vi skal // plassere første element i a[] vi finner med sifferverdien i for (int i = ; i <= mask; i++) { j = count[i]; count[i] = acumval; acumval += j; } // c) Finn siffervediene i a[] og flytt de til b[] der count[sifferverdien] sier. // Øk count[sifferverdien] til neste plass i b[] for (int i = ; i < n; i++) b[count[(a[i]>>shift) & mask]++] = a[i]; // steg d) kan fjernes for Radix (og Radix,,..) ved å bytte om // på a og b i kallet /* d) kopier b tilbake til a for (int i = ; i < n; i++) a[i] = b[i] ; */ }// end radixsort

Stegene i en radixsort: a) Tell opp i en array count slik at count[k] = hvor mange ganger k er en sifferverdi a[]. Eks. hvor mange tall i a[] = i dette sifferet? b) Legg sammen antallene i count slik at count[k] sier hvor i b[] vi skal plassere første element i a[] vi finner med sifferverdien k. count[] settes da lik, count[] = gamle count[], dvs, antall -er i dette sifferet i a[].. c) Finn sifferverdien i a[k] og flytt a[k] til b[] der count[sifferverdien] sier a[k] skal være. Øk count[sifferverdien] med til neste plass i b[]

Radix-sortering steg a) første, bakerste siffer Vi skal sorterere på siste siffer med bit sifferlengde (tallene -7) a) Tell opp sifferverdier i count[]: a 7 7 7 Før telling: count 7 Etter telling: count

Radix-sortering steg b) finne ut hvor sifferverdien skal plasseres De a[i] ene som inneholder j hvor skal de flyttes sortert inn i b[]? - Hvor skal -erne stare å flyttes, -erne,.osv b) Adder opp sifferverdier i count[]: Før addering: Etter addering : count 7 7 count b Kan også sies sånn: Første -er vi finner plasserer vi b[], første -er i b[] fordi det er stk -ere, og de må først. -erne starter vi å plassere i b[] fordi stk -ere og stk -ere må før -erne,.osv.

Radix-sortering steg c) flytt a[k] til b[] der count[s] peker, hvor s= sifferverdien i a[k] her det første, lengst til høyre sifferet a c) flytt a[k] til b[] der count[s] peker, hvor s= sifferverdien i a[k], øk count[s] med. 7 7 Før flytting 7 count Før flytting b Etter flytting b 7 7

Så sortering på siffer fra b[] til a[] trinn a) og b) Etter telling på siffer : Etter addering : b 7 7 7 count count 7 a

Så sortering på siffer fra b[] til a[] trinn c) b 7 7 Etter telling på siffer : 7 count Etter addering : count 7 7 a 7

Situasjonen etter sortering fra b[] til a[] på siffer Etter flytteing b 7 7 count 7 7 a 7 7 a[] er sortert!

Hva her vi sett på i Uke I. Om å avlutte k tråder med å samle svarene fra disse. gal + riktige måter + bedre for-løkke betyr mye! II. III. IV. Kommentarer til svar på ukeoppgaven om matrisemultiplikasjon I. Hvorfor disse gode resultatene (speedup > ) II. Hvordan bør vi fremstille slike ytelsestall 8 alternativer Vi bruker ikke PRAM modellen for parallelle beregninger I. Hva er PRAM og hvorfor er den ubrukelig for oss Å lage små metoder gir bedre, raskere JIT kompilering V. Hva skjer egentlig i lageret (main memory) når vi kjører parallelle tråder - the Java Memory Model VI. Hvorfor synkroniserer vi, og hva skjer da? VII. + evt: Ny, bedre forklaring på Radix