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


s1
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