Transcript tema 8
Arquitecturas Paralelas 8. Paralelización de bucles. Reparto de tareas. - Introducción - Paralelización de bucles - Mecanismos de sincronización - Optimizaciones principales - Reparto de las iteraciones - Secciones paralelas Arquitecturas Paralelas IF - EHU P. Bucl. Introducción Objetivo: ejecutar los programas P veces más rápido; caso particular: bucles. Identificar qué tareas pueden ejecutarse en paralelo y cuáles no (análisis de dependencias). Sincronizar los procesos. Repartir los procesos a los procesadores. Hacerlo de manera eficiente. Arquitecturas Paralelas IF - EHU 8 2 Introducción P. Bucl. 8 Tipos de paralelismo (1) (a) Paralelismo de datos do i = 1, 3000 A(i) = func(i) enddo P0 do i = 1, 1000 A(i) = func(i) enddo Arquitecturas Paralelas IF - EHU P1 P2 do i = 1001, 2000 A(i) = func(i) enddo do i = 2001, 3000 A(i) = func(i) enddo 3 P. Bucl. Introducción 8 Tipos de paralelismo (1) (b) Paralelismo de función Arquitecturas Paralelas IF - EHU P0 P1 F1 F3 F2 F4 4 P. Bucl. Introducción Tipos de paralelismo (2) ▪ grano fino (fine grain) tareas “pequeñas” / mucha comunicación ▪ grano medio ▪ grano grueso (coarse grain) tareas “grandes” / poca comunicación ▪ grado de paralelismo Arquitecturas Paralelas IF - EHU 8 5 Introducción P. Bucl. ¿Dependencias entre tareas? P0 P1 F1 F3 Sincronización F4 - global (barreras) - punto a punto (eventos) F2 Arquitecturas Paralelas IF - EHU 8 6 P. Bucl. Introducción 8 Dos modelos ▪ Maestro-esclavo Un thread master genera P threads para ser ejecutados en paralelo, que “mueren” al terminar su tarea. ▪ SPMD (Single-Program-Multiple-Data) Se ejecutan P copias iguales independientes. Las tareas se diferencian mediante el pid del proceso. Arquitecturas Paralelas IF - EHU 7 P. Bucl. Introducción Paralelización de bucles grano fino / medio reparto de iteraciones del bucle análisis de dependencias Hacerlo de manera eficiente. ¿El programador o el compilador? Arquitecturas Paralelas IF - EHU 8 8 P. Bucl. Introducción Salvo casos muy obvios, la paralelización del código (análisis de dependencias, reparto de tareas, etc.) sigue siendo responsabilidad del programador. Por ello, vamos a ver algunas de las opciones más habituales a la hora de paralelizar bucles de manera eficiente. Arquitecturas Paralelas IF - EHU 8 9 P. Bucl. Introducción Se necesita que una fracción importante del código pueda ejecutarse en paralelo. ¡No olvides la ley de Amdahl! Paralelizar (como vectorizar) código implica cambiar el orden original de las instrucciones del bucle. Por tanto, tenemos que analizar las dependencias entre las instrucciones del bucle. Arquitecturas Paralelas IF - EHU 8 10 P. Bucl. Introducción 8 Ejemplo: do i = 0, N-1 A(i) = A(i) + 1 enddo En paralelo Arquitecturas Paralelas IF - EHU L0 +0 S0 L1 +1 S1 L2 +2 S2 ... P0: L0 +0 S0 P1: L1 +1 S1 P2: L2 +2 S2 … ... 11 Introducción: depend. P. Bucl. dependencias verdaderas dependencia 8 dependencias de nombre antidependencia dependen. de salida RAW WAR WAW i: A = i: i: A = ... j: = A i Arquitecturas Paralelas IF - EHU j = A ... j: A = i ... j: A = j i j 12 Introducción: depend. P. Bucl. Bucles + Grafo de dependencias + Distancia de la dependencia do i = 2, N-2 1 A(i) = B(i) + 2 2 C(i) = A(i-2) + A(i+1) enddo A(2) = B(2) + 2 C(2) = A(0) + A(3) 1 A, 2 A(3) = B(3) + 2 C(3) = A(1) + A(4) 2 A, 1 A(4) = B(4) + 2 C(4) = A(2) + A(5) A(5) = B(5) + 2 C(5) = A(3) + A(6) Arquitecturas Paralelas IF - EHU 8 13 P. Bucl. Introducción: grafos de dep. 1 do i = 2, N-31 1 A(i) = B(i) + 2 2 C(i) = A(i-2) 3 D(i+1) = C(i) + C(i+1) 4 B(i+1) = B(i) + 1 5 D(i+30) = A(i) enddo C, 0 A, 0 C, 1 3 B, 1 4 5 IF - EHU A, 2 2 B, 1 Arquitecturas Paralelas 8 D, 29 14 P. Bucl. Introducción: grafos de dep. + Espacio de iteraciones do i = 2, N-1 do j = 1, N-2 1 A(i,j) = A(i,j-1) * 2 2 C(i,j) = A(i-2,j+1) + 1 enddo enddo A 0,1 1 A 2,-1 2 Arquitecturas Paralelas IF - EHU j i 8 15 P. Bucl. Introducción: test de dep. 8 Test de dependencias: únicamente para funciones lineales del índice del bucle. a*i+b c*i+d do i = L1, L2 ? X(a*i+b) = = X(c*i+d) enddo i L1 i1 d-b Z → MCD(c,a) Arquitecturas Paralelas IF - EHU no hay depend. i2 L2 16 P. Bucl. Paralelización de bucles 8 Paralelizar el código significa repartir tareas (iteraciones de un bucle) a procesadores. Pero hay que respetar las dependencias de datos. El problema principal son las dependencias de distancia > 0, y sobre todo aquellas que forman ciclos en el grafo de dependencias. Arquitecturas Paralelas IF - EHU 17 P. Bucl. Paralelización de bucles 8 Siempre es posible ejecutar un bucle en P procesadores, añadiendo sincronización para asegurar que se respetan las dependencias de datos… … lo que no significa que siempre sea sensato hacerlo, pues hay que tener en cuenta el coste global: cálculo + sincronización (comunicación). Arquitecturas Paralelas IF - EHU 18 P. Bucl. Paralelización de bucles Objetivos: Repartir las iteraciones de un bucle entre los procesadores, para que se ejecuten “a la par”. Siempre que se pueda, que se ejecuten de manera independiente, sin necesidad de sincronizar (dependencias de distancia 0). En función de las características del sistema (comunicación, reparto de tareas…) intentar que las tareas tengan un cierto tamaño. Arquitecturas Paralelas IF - EHU 8 19 P. Bucl. Paralelización de bucles Tal vez sólo se pueda utilizar un número limitado de procesadores. Atención al rendimiento (p. e., problemas en la cache). Arquitecturas Paralelas IF - EHU 8 20 P. Bucl. Paralelización de bucles 8 > Ejemplos do i = 0, N-1 A(i) = A(i) + 1 B(i) = A(i) * 2 enddo Arquitecturas Paralelas IF - EHU P0 P1 P2 P3 21 P. Bucl. Paralelización de bucles 8 > Ejemplos do i = 0, N-2 A(i) = B(i) + 1 B(i+1) = A(i) * 2 enddo P0 P1 P2 ? Arquitecturas Paralelas IF - EHU P3 22 P. Bucl. Paralelización de bucles 8 > Ejemplos do i = 0, N-3 A(i+2) = A(i) + 1 enddo Arquitecturas Paralelas IF - EHU P0 P1 P0 P1 23 P. Bucl. Paralelización de bucles 8 > Ejemplos do i = 0, N-1 do j = 1, M-1 A(i,j) = A(i,j-1) + 1 enddo enddo Arquitecturas Paralelas IF - EHU P0 P1 P2 P3 24 P. Bucl. Paralelización de bucles > Ejemplos do i = 0, N-1 do j = 1, M-1 A(i,j) = A(i,j-1) + 1 enddo enddo P0 P1 P2 P3 Arquitecturas Paralelas IF - EHU 8 25 P. Bucl. Paralelización de bucles Si todas las dependencias son de distancia 0 (las iteraciones son independientes), éstas se pueden repartir como se quiera entre los procesadores, sin tener que sincronizarlas: doall. Si hay dependencias entre iteraciones, pero todas van hacia adelante, se pueden sincronizar mediante barreras: forall (o doall + barrier). Si las dependencias forman ciclos, hay que utilizar sincronización punto a punto: doacross. Arquitecturas Paralelas IF - EHU 8 26 P. Bucl. 8 Bucles doall Las iteraciones son independientes, por lo que el reparto puede hacerse como se quiera: doall. do i = 0, N-1 C(i) = C(i) * C(i) A(i) = C(i) + B(i) D(i) = C(i) / A(i) enddo 1 2 A, 0 3 Arquitecturas Paralelas IF - EHU C, 0 doall i = 0, C(i) = C(i) A(i) = C(i) D(i) = C(i) enddoall i=0 1 2 3 N-1 * C(i) + B(i) / A(i) 27 P. Bucl. Bucles forall Hay dependencias entre iteraciones, pero todas van “hacia adelante”: forall. Cada dependencia puede sincronizarse con una barrera: los procesos esperan a que todos hayan ejecutado una determinada instrucción antes de pasar a ejecutar la siguiente. Hay más sincronización que la estrictamente necesaria, pero es sencillo de implementar. Arquitecturas Paralelas IF - EHU 8 28 P. Bucl. 8 Bucles forall do i = 1, N-1 C(i) = C(i) * C(i) A(i) = C(i) + B(i) D(i) = C(i-1) / A(i) enddo 1 C, 0 2 A, 0 IF - EHU i=1 2 3 4 C, 1 barrera 3 Arquitecturas Paralelas forall i = 1, N-1 C(i) = C(i) * C(i) A(i) = C(i) + B(i) BARRERA (...) D(i) = C(i-1) / A(i) endforall 29 P. Bucl. 8 Bucles forall doall i = 1, N-1 C(i) = C(i) * C(i) A(i) = C(i) + B(i) enddoall [ BARERRA (...) ] doall i = 1, N-1 D(i) = C(i-1) / A(i) enddoall do i = 1, N-1 C(i) = C(i) * C(i) A(i) = C(i) + B(i) D(i) = C(i-1) / A(i) enddo 1 C, 0 2 A, 0 IF - EHU 2 3 4 C, 1 barrera 3 Arquitecturas Paralelas i=1 30 P. Bucl. Bucles doacross 8 Las dependencias forman ciclos: doacross, sincronización punto a punto (productor / consumidor). Sincronización de las dependencias mediante vectores de eventos: post(vA,i) → vA(i) := 1 wait(vA,i) → esperar a que vA(i) = 1 Si vA(i) = 0, aún no se ha ejecutado la iteración i de la instrucción que se está sincronizando. Arquitecturas Paralelas IF - EHU 31 P. Bucl. 8 Bucles doacross do i = 2, N-2 A(i) = B(i-2) + 1 B(i+1) = A(i-2) * 2 enddo doacross i = 2, N-2 wait (vB,i-3) A(i) = B(i-2) + 1 post (vA,i) 1 A,2 B,3 2 Arquitecturas Paralelas IF - EHU i=2 3 4 5 6 7 1 1 1 . . . 2 2 2 . . . 1 1 1 2 2 2 wait (vA,i-2) B(i+1) = A(i-2) * 2 post (vB,i) enddoacross 32 P. Bucl. do i = 2, N-2 A(i) = B(i-2) + 1 B(i+1) = A(i-2) * 2 enddo 1 A,2 B,3 2 doacross i = 2, N-2, 3 wait (vB,i-3) A(i) = B(i-2) + 1 post (vA,i) P0 P1 P2 12 13 14 22 23 24 15 16 17 25 26 27 ... Arquitecturas Paralelas IF - EHU 8 Bucles doacross wait (vA,i-2) B(i+1) = A(i-2) * 2 post (vB,i) enddoacross 33 P. Bucl. 8 Bucles doacross No siempre hay que ejecutar en paralelo do i = 0, N-2 A(i) = B(i) + C(i) B(i+1) = A(i) / 2 enddo 1 2 p 1 A,0 B,1 2 Arquitecturas Paralelas IF - EHU doacross i = 0, N-2 wait (vB,i-1) A(i) = B(i) + C(i) B(i+1) = A(i) / 2 post (vB,i) enddoacross w 1 2 p w 1 … ?? 34 P. Bucl. Bucles doacross 8 35 Vectores de eventos en dos dimensiones do i = 0, N-2 do j = 0, N-2 A(i+1,j+1) = A(i+1,j) + 1 B(i,j) = A(i,j) enddo doacross i = 0, N-2 enddo do j = 0, N-2 A(i+1,j+1) = A(i+1,j) + 1 P0 post (vA,i,j) wait (vA,i-1,j-1) P1 B(i,j) = A(i,j) P2 enddo enddoacross P3 Arquitecturas Paralelas IF - EHU P. Bucl. 8 Otras dependencias Antidependencias / Dependencias de salida Si son entre procesos, hay que sincronizarlas. do i = 0, N-3 A(i) = B(i+2) / A(i) B(i) = B(i) + C(i) enddo doacross i = 0, N-3 A(i) = B(i+2) / A(i) 1 post (vB,i) wait (vB,i-2) B,2 B(i) = B(i) + C(i) enddoacross 2 Arquitecturas Paralelas IF - EHU LD B(i+2) post ... wait ST B(i) 36 P. Bucl. 8 Instrucciones if Instrucciones de tipo if do i = 1, N-1 if (B(i) > 0) then A(i) = A(i) + B(i) C(i) = A(i-1) / 2 endif enddo 0 1 A,1 2 Arquitecturas Paralelas IF - EHU doacross i = 1, N-1 if (B(i) > 0) then A(i) = A(i) + B(i) post (vA,i) wait (vA,i-1) C(i) = A(i-1) / 2 endif else post (vA,i) endif enddoacross 37 P. Bucl. Mecanismos de sincron. 8 Cómo sincronizar las instrucciones • mediante vectores de eventos (post/wait) - inicialización - tamaño (memoria) - ojo con la falsa compartición • mediante contadores Arquitecturas Paralelas IF - EHU 38 P. Bucl. Contadores de sincron. 8 Contadores de sincronización (uno por cada dependencia) - las instrucciones van “acabando” en orden estricto, e incrementan el contador. - cA = j han terminado todas las iteraciones hasta la j, y no la j+1. i = 0 1 2 3 4 5 6 7 8 9... vA(i) = 1 1 1 0 1 0 1 1 0 0... cA = 2 Arquitecturas Paralelas IF - EHU 39 P. Bucl. Contadores de sincron. Para sincronizar una dependencia mediante un contador: - tras ejecutar la iteración i, esperar a que el valor del contador sea i-1 (es decir, a que se haya ejecutado esa instrucción hasta la iteración i-1). wait (cA,i-1) → esperar a que cA = i-1 - incrementar el contador, para indicar que también se ha ejecutado la iteración i. post (cA,i) Arquitecturas Paralelas IF - EHU → cA := cA + 1 (cA := i) 8 40 P. Bucl. Contadores de sincron. do i = 3, N-1 C(i) = C(i) * D(i-3) A(i) = C(i) + B(i) D(i) = C(i-1) / A(i) enddo D,3 1 C, 0 2 C,1 A, 0 3 Arquitecturas Paralelas IF - EHU 1 2 3 1 2 3 8 doacross doacross ii == 3, 3, N-1 N-1 wait wait (vD,i-3) (cD,i-3) C(i) == C(i) C(i) ** D(i-3) D(i-3) C(i) wait (vC,i) (cC,i-1) post post (cC,i) A(i) = C(i) + B(i) A(i) = C(i) + B(i) wait D(i) (vC,i-1) = C(i-1) / A(i) D(i) C(i-1) / A(i) wait =(cD,i-1) post (vD,i) (cD,i) post enddoacross enddoacross 1 2 3 1 2 3 1 2 3 1 2 3 41 P. Bucl. do i = 3, N-1 C(i) = C(i) * D(i-3) A(i) = C(i) + B(i) D(i) = C(i-1) / A(i) enddo doacross i = 3, N-1 C(i) = C(i) * D(i-3) wait (cC,i-1) post (cC,i) A(i) = C(i) + B(i) D(i) = C(i-1) / A(i) enddoacross P0 D,3 1 C, 0 2 C,1 A, 0 3 Arquitecturas Paralelas IF - EHU 8 Contadores de sincron. 1 2 3 1 2 3 1 2 3 P0 1 2 3 1 2 3 1 2 3 Minimizar la sincronización 42 P. Bucl. 1 A, 1 3 B,0 C, 2 4 Arquitecturas Paralelas IF - EHU doacross ... forall ii == ... [ [1 1] ] post (vA,i) barrera(...) wait [ 2 (vA,i-1) ] [ [2 3] ] post (vC,i) barrera(...) 2 A,0 8 Ejemplo [ [3 4] ] endforall wait (vC,i-2) [ 4 ] enddoacross doacross i = ... [ 1 ] wait (cA,i-1) post (cA,i) [ 2 ] wait (cC,i-1) post (cC,i) [ 3 ] [ 4 ] enddoacross 43 P. Bucl. Principales optimizaciones 8 0. Deshacer la definición de constantes y las variables de inducción. 1. Eliminar todas las dependencias que no son intrínsecas al bucle. Por ejemplo: do i = 0, N-1 X = A(i) * B(i) C(i) = SQRT(X) D(i) = X - 1 enddo Arquitecturas Paralelas IF - EHU convertir X en una variable privada doall i = 0, N-1 X(i) = A(i) * B(i) C(i) = SQRT(X(i)) D(i) = X(i) - 1 enddoall 44 P. Bucl. Principales optimizaciones 2. Fisión del bucle. Si una parte del bucle hay que ejecutarla en serie, romper el bucle convenientemente y ejecutar lo que sea posible en paralelo. do i = 1, N-1 A(i) = A(i-1) / 2 D(i) = D(i) + 1 enddo do i = 1, N-1 A(i) = A(i-1) / 2 enddo doall i = 1, N-1 D(i) = D(i) + 1 enddoall Arquitecturas Paralelas IF - EHU 8 45 P. Bucl. Principales optimizaciones 3. Ordenar las dependencias (hacia adelante). do i = 1, N-1 A(i) = D(i-1) / 2 D(i) = C(i) + 1 enddo 1…2.. 1 D, 1 2 Arquitecturas Paralelas IF - EHU forall i = 1, N-1 D(i) = C(i) + 1 BARRERA (...) A(i) = D(i-1) / 2 endforall 1…2.. ?? 1…2.. 2………….1 2………1 2…….1 8 46 P. Bucl. Principales optimizaciones 8 4. Alinear las dependencias: peeling. do i = 1, N-1 A(i) = B(i) C(i) = A(i-1) + 2 enddo 1 A, 1 2 Arquitecturas Paralelas IF - EHU C(1) = A(0) + 2 doall i = 1, N-2 A(i) = B(i) C(i+1) = A(i) + 2 enddoall A(N-1) = B(N-1) 47 P. Bucl. Principales optimizaciones do i = 2, N-1 A(i) = B(i) C(i) = A(i-1) + A(i-2) enddo do i = A(i) X(i) C(i) enddo 1 2, N-1 = B(i) = B(i) = X(i-1) + A(i-2) 1 ’ X, 1 A, 2 2 Arquitecturas Paralelas IF - EHU A, 2 1 8 A, 1 2 C(2) = A(1) + A(0) C(3) = B(2) + A(1) doall i = 2, N-3 A(i) = B(i) X(i+1) = B(i+1) C(i+2) = X(i+1) + A(i) enddoall A(N-2) = B(N-2) A(N-1) = B(N-1) 48 P. Bucl. Principales optimizaciones 8 5. Generar hilos independientes B(2) = A(0) * 3 C(0) = B(2) - 2 do i = 0, N-3 A(i+1) = B(i) + 1 B(i+2) = A(i) * 3 C(i) = B(i+2) - 2 enddo 1 A,1 B,2 2 B,0 3 Arquitecturas Paralelas IF - EHU 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 doall k = 0, 2 do i = pid, N-4, 3 A(i+1) = B(i) + 1 B(i+3) = A(i+1) * 3 C(i+1) = B(i+3) – 2 enddo enddoall A(N-2) = B(N-3) + 1 49 P. Bucl. 8 Principales optimizaciones 6. Minimizar la sincronización do i = B(i) C(i) A(i) D(i) E(i) enddo i=2 3 4 ... 1 1 1 2, N-1 = B(i) + = C(i) / = B(i) + = A(i-1) = D(i) + 2 2 2 Arquitecturas Paralelas IF - EHU 3 3 3 1 1 doacross i = 2, N-1 3 B(i) = B(i) + 1 C(i-1) * C(i-2) C(i) = C(i) / 3 post (vC,i) B(i-1) 4 4 4 5 5 5 wait (vC,i-1) A(i) = B(i) + C(i-1) post (vA,i) wait (vA,i-1) D(i) = A(i-1) * C(i-2) E(i) = D(i) + B(i-1) enddoacross B,0 2 C, 1 3 C,2 A,1 4 B,1 D,0 5 50 P. Bucl. 8 Principales optimizaciones 7. Tratamiento de bucles: intercambio. do i do_par j Arquitecturas Paralelas IF - EHU do_par i do j do j do_par i do_par j do i 51 P. Bucl. 8 Principales optimizaciones Ejemplo: j=0 do i = 1, N-1 do j = 0, N-1 A(i,j) = A(i-1,j) + 1 enddo enddo i=1 2 3 4 do i = 1, N-1 doall j = 0, N-1 A(i,j) = A(i-1,j) + 1 enddoall enddo Arquitecturas Paralelas IF - EHU 1 2 3 52 P. Bucl. 8 Principales optimizaciones Ejemplo: j=0 do i = 1, N-1 do j = 0, N-1 A(i,j) = A(i-1,j) + 1 enddo enddo i=1 2 3 4 doall j = 0, N-1 do i = 1, N-1 A(i,j) = A(i-1,j) + 1 enddo enddoall Arquitecturas Paralelas IF - EHU 1 2 3 53 P. Bucl. 8 Principales optimizaciones 8. Tratamiento de bucles: cambio de sentido. do i = 1, 100 do j = 0, 2 A(i,j) = A(i,j) - 1 D(i) = A(i-1,j+1) * 3 enddo enddo do j = 2, 0, -1 doall i = 1, 100 A(i,j) = A(i,j) - 1 D(i) = A(i-1,j+1) * 3 enddoall enddo Arquitecturas Paralelas IF - EHU j=0 i=1 2 3 4 1 2 54 P. Bucl. Principales optimizaciones 9. Skew do i = 1, N do j = 1, N A(i,j) = A(i-1,j) + A(i,j-1) enddo enddo do j = 1, 2N-1 doall i = max(1,j-N+1), min(j,N) A(i,j-(i-1)) = A(i-1,j-(i-1)) + A(i,j-1-(i-1)) enddoall enddo Arquitecturas Paralelas IF - EHU 8 55 P. Bucl. Principales optimizaciones 8 10. Otras optimizaciones típicas Aumento del tamaño de grano y reducción del overhead de la paralelización. - Juntar dos bucles en uno (¡manteniendo la semántica!): fusión. Convertir un bucle de dos dimensiones en otro de una sola dimensión: colapso o coalescencia. … Arquitecturas Paralelas IF - EHU 56 P. Bucl. Reparto de iteraciones 8 ¿Cómo se reparten las iteraciones de un bucle entre los procesadores? Si hay tantos procesadores como iteraciones, tal vez una por procesador. Pero si hay menos (lo normal), hay que repartir. El reparto puede ser: estático: en tiempo de compilación. dinámico: en ejecución. Arquitecturas Paralelas IF - EHU 57 P. Bucl. Reparto de iteraciones El objetivo: intentar que el tiempo de ejecución de los trozos que se reparten a cada procesador sea similar, para evitar tiempos muertos (load balancing). En todo caso, OJO con las dependencias (sincronización), el tamaño de grano, la localidad de los accesos y el coste del propio reparto. Arquitecturas Paralelas IF - EHU 8 58 P. Bucl. Reparto de iteraciones 8 Planificación estática Qué ejecuta cada procesador se decide en tiempo de compilación. Es por tanto una decisión prefijada. Cada proceso tiene una variable local que lo identifica, pid [0..P-1]. Dos opciones básicas: reparto consecutivo y reparto entrelazado. Arquitecturas Paralelas IF - EHU 59 P. Bucl. 8 Reparto de iteraciones ▪ Consecutivo 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0000111122223333 principio = pid * N/P fin = (pid+1) * N/P – 1 do i = principio, fin ... enddo 60 ▪ Entrelazado 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0123012301230123 do i = pid, N, P ... enddo - No añade carga a la ejecución de los threads. - Pero no asegura el equilibrio de la carga entre los procesos. - Permite cierto control sobre la localidad de los accesos a cache. Arquitecturas Paralelas IF - EHU P. Bucl. 8 Reparto de iteraciones Equilibrio en el reparto de carga do i = 1, 80 if (A(i) > 0) calcular() enddo asignación dinámica de una nueva tarea estático (fijo) 1-20 1-10 21-40 11-20 41-60 21-30 61-80 31-40 Tej Arquitecturas Paralelas IF - EHU Tej 61 P. Bucl. Reparto de iteraciones 8 Planificación dinámica Para intentar mantener la carga equilibrada, las tareas se van escogiendo en tiempo de ejecución de un cola de tareas. Cuando un proceso acaba con una tarea (un trozo del bucle) se asigna un nuevo trozo. Dos opciones básicas: los trozos que se van repartiendo son de tamaño constante o son cada vez más pequeños. Arquitecturas Paralelas IF - EHU 62 P. Bucl. Reparto de iteraciones 8 Self / Chunk scheduling Las iteraciones se reparten una a una, o por trozos de tamaño Z. Añade carga a la ejecución de los threads. Hay que comparar ejecución y reparto. Arquitecturas Paralelas IF - EHU LOCK (C); mia = i; i = i + Z; UNLOCK (C); Z = 1 self while (mia <= N-1) do j = mia, min(mia+Z-1, N-1) ... enddo LOCK (C) mia = i; i = i + Z; UNLOCK (C) endwhile 63 P. Bucl. Reparto de iteraciones 8 Guided / Trapezoidal Los trozos de bucle que se reparten son cada vez más pequeños según nos acercamos al final. ▪ Guided : parte proporcional de lo que queda por ejecutar: Zs = (N – i) / P que equivale a: Zi = Zi-1 (1 - 1/P) Arquitecturas Paralelas IF - EHU (entero superior) 64 P. Bucl. 8 Reparto de iteraciones ▪ Trapezoidal: reduciendo el trozo anterior en una constante: Zi = Zi-1 - k k Z1 Z2 Zn 1 2 i n op. de planificación Z1 Z n Z1 Z n Z1 Z n Z n 1 N s 2 2 k s1 n Arquitecturas Paralelas IF - EHU Z12 Z n2 k 2 N ( Z1 Z n ) 65 P. Bucl. Reparto de iteraciones En general, el reparto dinámico busca un mejor equilibrio en el reparto de carga, pero: - hay que considerar la carga que se añade (overhead), en relación al coste de las tareas que se asignan. - hay que considerar la localidad en los accesos a los datos y los posibles problemas de falsa compartición. Arquitecturas Paralelas IF - EHU 8 66 P. Bucl. 8 Reparto de iteraciones Ejemplo de reparto (1.000 iteraciones, 4 procesadores): ▪ chunk (Z = 100) 100 100 100 100 100 100 100 100 100 100 (10) ▪ guided quedan: se reparten: 1000 750 562 421 … 17 12 9 6 4 3 2 1 250 188 141 106 … ▪ trapezoidal 5 3 3 2 1 1 1 1 (Z1 = 76, Zn = 4 >> k = 3) 76 73 70 67 … 16 13 10 7 4 Arquitecturas Paralelas IF - EHU (22) (25) 67 P. Bucl. 8 Secciones paralelas Paralelismo a nivel de procedimiento o función: - modelo Fork / Join - Parallel sections F1 F2 F3 F4 F5 Arquitecturas Paralelas IF - EHU Fork F1 F2 Join Fork F3 F4 Join F5 doall k = 0, 1 if (pid = 0) then F1 if (pid = 1) then F2 endoall [barrera] doall k = 0, 1 if (pid = 0) then F3 if (pid = 1) then F4 endoall F5 68 P. Bucl. | Secciones paralelas Paralelismo a nivel de procedimiento o función: - Modelo Fork / Join - Parallel sections F1 último tema… ¡el año que viene! F2 F3 F4 F5 Arquitecturas Paralelas IF - EHU Fork F1 F2 Join Fork F3 F4 Join F5 doall k = 0, 1 if (pid=0) then if (pid=1) then endoall [hesia] doall k = 0, 1 if (pid=0) then if (pid=1) then endoall F5 F1 F2 F3 F4