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

INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

  • Upload
    others

  • View
    6

  • Download
    0

Embed Size (px)

Citation preview

Page 1: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

1

INF2440 Uke 10, v2015 :

Arne Maus PSE,

Inst. for informatikk

Page 2: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Hva så vi på i uke 9

2

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 ?

Page 3: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

Page 4: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

4

Generelt er Linux 15-20% raskere enn Windows (ikke optimalisert)

Page 5: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Hvor lang tid i µs tar egentlig ulike mekanismer i Java ? (fra Petter A. Busteruds master-oppgave: Investigating Different

Concurrency Mechanisms in Java)

5

A) Metodekall på Windows og Linux (ikke optimalisert)

Generelt er kan vi gjøre mer enn 500-700 metodekall per millisek.

Page 6: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Å lage et nytt objekt av en klasse (new) og kalle en metode i objektet (µs)

6

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

Object

Page 7: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

7

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

Page 8: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Lage en ExecutorService

8

Page 9: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

9

Page 10: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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 (> 106 ) tar det bare ca. 2x tid (det siste er sannynligvis en cache-effekt)

10 En parallell løsning må alltid sammenlignes med hvor mye vi kunne ha gjort (f.eks sortert) sekvensielt på den samme tida!

Page 11: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Nye målinger i Java8 i 2015 – metodekall-eks. mm.

11

//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; // skriv i array k = ia[i%55]; // les fra array

Page 12: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

4156.0 202.0 391.0 92.7 44

new C() + metodekall

3214.0 1.05 0.28 0.08 40175

new D() + metodekall

4497.0 1.4 0.70 0.11 40881

Ett Array write/read

0.35 0.24 0.24 0.03 12

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

Page 13: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

4156.0 391.0 1814 284

new C() + metodekall

3214.0 0.28 770 53

new D() + metodekall

4497.0 0.70 770 53

Ett Array write/read

0.35 0.24 0.27

13

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

Page 14: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

2) Generelt om rekursiv oppdeling av a[] i to deler

14

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){..}; }

Page 15: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Hvor mange kall gjør vi i en rekursiv løsning?

Anta Quicksort av n =2k tall (k= 10 ⇒ n = 1000, k= 20 ⇒ n= 1 mill)

Kalltreet vil på første nivå ha 2 lengder av 219, på neste: 4 = 22 hver med 218 og helt ned til nivå 20, hvor vi vil ha 220 kall hver med 1 = 20 element.

I hele kalltreet gjør vi altså 2 millioner -1 kall for å sortere 1 mill tall !

Bruker vi innstikksortering for n < 32 = 25

så får vi ‘bare’ 220-5 = 215 = 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())

15

nivå: 0 1 2

20

Vi kan IKKE bare erstatte rekursive kall med nye tråder i en rekursiv løsning !

Page 16: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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:

Speedup > 1 og ca. 10 000x fortere enn ren oversettelse. 16

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

Page 17: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

Page 18: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

PRP: Den grunnleggende ideen: – Rekursjonstreet og treet av tråder er ‘like’, men

18

A

B

D

C

E F G

A

B

D

C

E F G

Dybde først Bredde først

1

Rekursjon

2

3 4

Tråder

5

6 7

8 1 2

3 4

6 5

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

Page 19: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Fra rekursjon til parallelle prosedyrer (metoder)

19

A

B

D

C

E F G

Rekursjon

A

B

D

C

E F G

Kjerne 0

Kjerne 2 Kjerne 1

Kjerne3 Kjerne 4

Multikjerne CPU

Page 20: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

Page 21: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Et eksempel før mer ‘teori’ med en kjørbar sekvensiell Quicksort

21

import java.util.Random; 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); } } }

Nesten helt vanlig QuickSort – vi har riktignok pakket den inn i en klasse Vi kompilerer og kjører den og tar tiden (11 ganger)

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++){ 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; 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; } }

Page 22: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

QuickSort av 10 mill tall (ca. 0.95 sek) sekvensielt

22

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

Page 23: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Nå legger vi til tre kommentarer så den kan preprosessereres over i en parallell versjon (/*REC*/ og /*FUNC*/ ):

23

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

Page 24: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Kompilér JavaPRP -systemet, så start det

24

M:\INF2440Para\PRP>javac JavaPRP.java M:\INF2440Para\PRP>java JavaPRP

Det starter et GUI-interface

Page 25: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

25

Page 26: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

26

Trykker: Choose a file

Page 27: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

27

Page 28: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

28

Trykket så Compile: - Kompilerte da den

parallelliserte filen: QuicksortProgPara.java

- Legger så inn parameter (10 mill) på kommandolinja og velger Execute.

Page 29: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

29

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

Page 30: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Oversettelsen : Quicksort

30

import java.util.Random; 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); } } }

class QuicksortProgPara{ public static void main(String[] args){ new Admin(args); } } 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å brukerens kode (77 linjer) Starten på oversatt kode (245 linjer)

Page 31: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

Page 32: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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:

Innfører da to nye Kommentarkoder: /*ADMIN*/ og /*FUNC 1*/ , /*FUNC 2*/,… osv

32

/*ADMIN*/ public int minAdminMetode(...){ int svar = rekursivMetode1(...); sekvensiellKode1(); svar = rekursivMetode2(...); sekvensiellKode2(...); svar = rekursivMetode3(...); sekvensiellKode3(...); svar = rekursivMetode4(...); sekvensiellKode4(...); return svar; }

Page 33: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Og hver av disse rekursive metodene er i hver sin klasse.

33

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

Page 34: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

Page 35: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Fra sekvensielt program til parallelt:

35

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.

Page 36: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

Eksempel: Parallellisering med to tråder

36

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

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

Page 37: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

37 Figur 7: Administratoren oppretter datastrukturen til arbeiderne.

Figur 8: Datastrukturen etter at Figur 7 er ferdig.

Page 38: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

38

Figur 9: Arbeiderstacken beregner seg innover til roten.

Page 39: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

39

Page 40: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

Page 41: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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

Page 42: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

42

Eksempel 2: Største tall i en array

class Search{ int k = 5; /*FUNC*/ int findLargest(int[] arr, int start, int end){ 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; } }

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."); } }

Page 43: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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:

Kjør det i linjemodus (n= 100 mill.):

43

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

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.

Page 44: INF2440 – Effektiv parallellprogrammering Uke 1, v2014 · Det finnes særlig to typer av sekvensielle programmer som tar ’lang’ tid: A) Med løkker (enkle, doble,..) B) Rekursive

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