Vous êtes sur la page 1sur 17

Contents

1 Introduccion 3

1.1 Por que el paralelismo desde los 2000 a hoy da? . . . . . . . . . . . . . . . . . . . . . . . . 3

1.2 Ejecucion concurrente y paralelismo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

1.2.1 Ejecucion serial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

1.2.2 Ejecucion concurrente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

1.2.3 Ejecucion paralela . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.2.4 Throughput vs- parallel computing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.3 Ejemplos y problemas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.3.1 Problemas potenciales de la concurrencia . . . . . . . . . . . . . . . . . . . . . . . . 4

2 Entendiendo el paralelismo 6

2.1 Paralelismo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2.1.1 Buscando la concurrencia/paralelismo . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2.1.2 La abstraccion del grafo de tareas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2.1.3 Calculando el tiempo de ejecucion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2.1.4 Calculando el paralelismo: ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.2 Speedup y ley de Amdahl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.2.1 Speedup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.2.2 Ley de Amndahl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.3 Data sharing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.3.1 How to model data sharing overhead . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2.3.2 Haciendo blocking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

3 Parallel programming principles: Task decomposition 9

1
3.1 Task creation in OpenMP (summary) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

3.2 Patrones para identificar tareas en el codigo secuencial . . . . . . . . . . . . . . . . . . . . . 9

3.2.1 Ejemplo 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3.2.2 Ejemplo 2: descomposicion de tareas iterativas) . . . . . . . . . . . . . . . . . . . . . 10

3.2.3 Ejemplo 3: descomposicion de tarea iterativa . . . . . . . . . . . . . . . . . . . . . . 11

3.2.4 Ejemplo 4: Descomposicion de tarea Divide-and-conquer . . . . . . . . . . . . . . 11

3.3 Control de la generacion de tareas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

3.3.1 Cut-off control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

3.4 Ejecucion imnediata de la tarea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3.5 Task syncronization in OpenMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3.5.1 taskwait vs. taskgroup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3.6 Fibonacci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3.6.1 Sequencial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

3.6.2 Codigo OpenMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

3.7 Task dependences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2
Tema 1

Introduccion

1.1 Por que el paralelismo desde los 2000 a hoy da?

El consumo de energa esta en un lmite tecnologico

Retornos decrecientes cuando se intenta utilizar los transistores para lograr un mayor numero de
paralelismo a nivel de instrucciones.

Para escalar en rendimiento, poniendo mas nucleos en el microprocesador en lugar de incrementar


la frecuencia y la complejidad.

1.2 Ejecucion concurrente y paralelismo

1.2.1 Ejecucion serial

Tradicionalmente los programas estaban escritos para su ejecucion serial

Para correr en un PC con una sola CPU

El programa esta compuesto por una secuencia de instrucciones, que se ejecutan de una en una y
solo 1 en un momento determinado

1.2.2 Ejecucion concurrente

Explotar la concurrencia consisten en romper un problema en partes discretas, llamadas tareas, para
garantizar su correcta ejecucion simultanea

Cada tarea se ejecuta de manera serial y la ejecucion de las tareas es multiplexadas en una unica
CPU.

Es necesario controlar y coordinar la ejecucion de las tareas, garantizando el correcto acceso a los recur-
sos compartidos.

3
1.2.3 Ejecucion paralela

Es cuando utilizamos multiples procesadores (CPU) para ejecutar en paralelo las tareas creadas para
ejecucion concurrente.

Idealmente, cada CPU recibira 1


p del programa, reduciendo su tiempo de ejecucion p veces.

1.2.4 Throughput vs- parallel computing

Multiples procesadores tambien pueden ser utilizados para incrementar el numero de programas ejecuta-
dos por unidad de tiempo.

Throughput computing: Multiple, unrelated, instrucin streams (programs) executing at the same
time on multiple processors.

p
n programas on p procesadores; si (n p) cada programa recibe n procesadores, o un procesador
en caso contrario.

Hay que fijarse que esto no es lo mismo que el paralelismo, cuyo objetivo es reducir el tiempo de eje-
cucion de un solo programa:

1 programa en p procesadores, cada procesador ejecutando 1


p

1.3 Ejemplos y problemas

1.3.1 Problemas potenciales de la concurrencia

Race condition: multiples tareas leen y escriben datos y el resultado final depende del timing
relativo de la ejecucion

Deadlock: 2 o mas tareas no pueden avanzar debido a que cada una esta esperando a que las
otras hagan alguna cosa

Starvation: Una tarea no puede conseguir acceso a los recursos compartidos debido a que no
puede progresar.

Livelock: 2 o mas tareas cambian su estado continuamente en respuesta a cambios en otras tar-
eas, sin llegar a hacer trabajo util.

Ejemplo de un banco con diferentes cuentas:

2 operaciones de retirar dinero simultaneas

Corregir: data race, starvation

2 transferencias de dinero simultaneas

Corregir: Deadlock

4
Estadsticas simples del banco

Eficiencia: overheads, falta de dependencia en el trabajo...

5
Tema 2

Entendiendo el paralelismo

2.1 Paralelismo

2.1.1 Buscando la concurrencia/paralelismo

Se puede dividir la computacion en partes?

Basandose en lo que se tiene que procesar

Descomposicon de tareas (tasks), por ejemplo funciones, bucles...

Basado en los datos a procesar

Descomposicion de datos (ej matriz). Implica descomposicion de tareas.

Puede haber dependencias entre tareas

La descomposicion determina el paralelismo que se puede obtener.

2.1.2 La abstraccion del grafo de tareas

Es un grafo dirigido y aciclico

Nodo = tarea

Secuencia de computacion arbitraria

Su peso determina la cantidad de trabajo que hace

2.1.3 Calculando el tiempo de ejecucion

T1 = nodes
i=1 (work nodei ). Es la suma de todos los nodos.

T = icriticalpath (work nodei ), asumiendo recursos (infinitos) suficientes.

6
Es la suma del camino crtico: camino hasta una hoja que tarda mas en ejecutarse.

Paralelismo = TT1 , independiente del numero de procesadores P. Como de rapido ira el programa si tengo
suficientes (infinitos) recursos disponibles.

Pmin es el numero mnimo de procesadores necesarios para conseguir paralelismo

Arista = dependencia

El nodo sucesor necesita (lee) datos producidos (escritos) por el nodo predecesor.

Orden de ejecucion entre el sucesor y el predecesor.

2.1.4 Calculando el paralelismo: ejemplo

2.2 Speedup y ley de Amdahl

2.2.1 Speedup

Tp = tiempo de ejecucion usando P procesadores. Depende de la planificacion del grafo de nodos en los
procesadores.

Lower bounds:

Tp = T1
P

Tp T
T1
Speedup en P procesadores: Sp = Tp

T1
Paralelismo = T

7
Ejemplo de speedup

2.2.2 Ley de Amndahl

T1 = Tseq + Tpar
Tpar
Fraccion paralela: = T1

T1 = (1 ) T1 + T1
Tpar
Tp = Tseq + P

T1
Tp = (1 ) T1 + ( P )

T1
Sp = Tp

2.3 Data sharing

2.3.1 How to model data sharing overhead

Taccess = ts + m tw

2.3.2 Haciendo blocking

Tp = ( nc + P 1) ( Pn c) tbody + (ts + n tw ) + (( nc + P 2) (ts + c tw ))

8
Tema 3

Parallel programming principles: Task


decomposition

3.1 Task creation in OpenMP (summary)

#pragma omp parallel: se crea una tarea implcita para cada thread en el equipo y se ejecuta in-
mediatamente

#pragma omp task: Se crea una tarea explcita, empaquetando codigo y datos para una posible
ejecucion en diferido

3.2 Patrones para identificar tareas en el codigo secuencial

Descomposicion de tareas lineales

Tarea = bloque de codigo o invocacion a funcion.

(Lineal) Descomposicion de tarea iterativa

Tarea = cuerpo de la estructura iterativa, por ejemplo bucles (con contador o sin)

Ejemplos: Calculo de Pi, equacion de difusion de Mandelbrot y calor, operaciones sobre vec-
tores y matrices.

Descomposicion de tareas recursivas

Tarea = invocacion a la funcion recursiva, por ejemplo problemas de dividir y conquistar

Ejemplos: Fibonacci, multisort (se hara en practicas)...

9
3.2.1 Ejemplo 1

Una tarea es una secuencia de instrucciones, como por ejemplo la suma de 2 vectores divididos artificial-
mente en 2 partes:

1 v o i d vector add ( i n t A , i n t B , i n t C , i n t n ) {
2 #pragma omp t a s k
3 f o r ( i n t i =0; i< n / 2 ; i++)
4 C[i] = A[i] + B[i];
5
6 #pragma omp t a s k
7 f o r ( i n t i=n / 2 ; i< n ; i++)
8 C[i] = A[i] + B[i];
9 }
10 v o i d main ( ) { . . . .
11 #pragma omp p a r a l l e l
12 #pragma omp s i n g l e
13 vector add ( a , b , c , N ) ;
14 ...
15 }

3.2.2 Ejemplo 2: descomposicion de tareas iterativas)

Una tarea puede ser un loop individual de la iteracion

1 v o i d vector_add ( i n t A , i n t B , i n t C , i n t n ) {
2 f o r ( i n t i =0; i< n ; ii++)
3 #pragma omp t a s k
4 C[i] = A[i] + B[i];
5 }
6
7 v o i d main ( ) {
8 ....
9 #pragma omp p a r a l l e l
10 #pragma omp s i n g l e
11 vector_add ( a , b , c , N ) ;
12 ...
13 }

Cada tarea explicita ejecuta una iteracion i del bucle, hay un overhead en la creacion de muchas tareas y
la granularidad es muy fina.

OpenMP ofrece 2 alternativas de construccion. La primera utilizando taskloop:

1 v o i d vector_add ( i n t A , i n t B , i n t C , i n t n ) {
2 #pragma omp t a s k l o o p g r a i n s i z e (BS)
3 f o r ( i n t i =0; i< n ; i++)
4 C[i] = A[i] + B[i];
5 }
6
7 v o i d main ( ) {
8 #pragma omp p a r a l l e l
9 #pragma omp s i n g l e
10 ...
11 vector_add ( a , b , c , N ) ;
12 ...
13 }

10
Otro ejemplo utilizando tareas implicitas y worksharing:

1 v o i d vector_add ( i n t A , i n t B , i n t C , i n t n ) {
2 #pragma omp p a r a l l e l f o r s c h e d u l e ( dynamic , BS)
3 f o r ( i n t i =0; i< n ; i++)
4 C[i] = A[i] + B[i];
5 }
6
7 v o i d main ( ) {
8 ...
9 vector_add ( a , b , c , N ) ;
10 ...
11 }

3.2.3 Ejemplo 3: descomposicion de tarea iterativa

Lista de elementos, recorridos usando un bucle while sin contador:

1 i n t main ( ) {
2 s t r u c t node p ;
3 p = init list ( n ) ; . . .
4 #pragma omp p a r a l l e l
5 #pragma omp s i n g l e
6 w h i l e ( p != NULL ) {
7 #pragma omp t a s k f i r s t p r i v a t e ( p )
8 process_work ( p ) ;
9 p = p>next ;
10 }
11 ...
12 }

3.2.4 Ejemplo 4: Descomposicion de tarea Divide-and-conquer

Suma de 2 vectores dividiendo recursivamente el problema en subproblemas mas pequenos:

1 #d e f i n e N 1024
2 #d e f i n e MIN SIZE 64
3 v o i d vector add ( i n t A , i n t B , i n t C , i n t n ) {
4 f o r ( i n t i =0; i< n ; i++) C [ i ] = A [ i ] + B [ i ] ;
5 }
6
7 v o i d rec vector add ( i n t A , i n t B , i n t C , i n t n ) {
8 i f ( n>MIN_SIZE ) {
9 i n t n2 = n / 2 ;
10 rec vector add ( A , B , C , n2 ) ;
11 rec vector add ( A+n2 , B+n2 , C+n2 , nn2 ) ;
12 }
13 e l s e vector add ( A , B , C , n ) ;
14 }
15
16 v o i d main ( ) {
17 ....
18 rec vector add ( a , b , c , N ) ;

11
19 ...
20 }

Leaf strategy

Una tarea corresponde con cada invocacion de vector add una vez las invocaciones recursivas paran.

Implementacion:

1 #d e f i n e N 1024
2 #d e f i n e MIN SIZE 64
3 v o i d vector_add ( i n t A , i n t B , i n t C , i n t n ) {
4 f o r ( i n t i =0; i< n ; i++) C [ i ] = A [ i ] + B [ i ] ;
5 }
6
7 v o i d rec_vector_add ( i n t A , i n t B , i n t C , i n t n ) {
8 i f ( n>MIN_SIZE ) {
9 i n t n2 = n / 2 ;
10 rec_vector_add ( A , B , C , n2 ) ;
11 rec_vector_add ( A+n2 , B+n2 , C+n2 , nn2 ) ;
12 } else
13 #pragma omp t a s k
14 vector_add ( A , B , C , n ) ;
15 }
16
17 v o i d main ( ) {
18 ....

12
19 #pragma omp p a r a l l e l
20 #pragma omp s i n g l e
21 rec_vector_add ( a , b , c , N ) ;
22 ...
23 }

Tree strategy

Una tarea corresponde a cada invocacion de rec vector add

Generacion paralela de tareas 6 Granularidad: algunas tareas simplemente generan nuevas tareas

Implementacion:

1 #d e f i n e N 1024
2 #d e f i n e MIN SIZE 64
3 v o i d vector_add ( i n t A , i n t B , i n t C , i n t n ) {
4 f o r ( i n t i =0; i< n ; i++) C [ i ] = A [ i ] + B [ i ] ;
5 }
6
7 v o i d rec_vector_add ( i n t A , i n t B , i n t C , i n t n ) {
8 i f ( n>MIN_SIZE ) {
9 i n t n2 = n / 2 ;
10 #pragma omp t a s k
11 rec_vector_add ( A , B , C , n2 ) ;
12 #pragma omp t a s k
13 rec_vector_add ( A+n2 , B+n2 , C+n2 , nn2 ) ;
14 }
15 e l s e vector_add ( A , B , C , n ) ;
16 }
17
18 v o i d main ( ) {
19 ....
20 #pragma omp p a r a l l e l
21 #pragma omp s i n g l e
22 rec_vector_add ( a , b , c , N ) ;
23 ...
24 }

13
3.3 Control de la generacion de tareas

En recursion, la ganeracion de tareas puede ser excesiva:

Puede causar overhead

Puede no ser necesario para ciertos problemas

En algun momento se tiene que parar la generacion de tareas cut-off control

Control estatico: tras un numero de llamadas recursivas

Control estatico: Cuando el tamano del vector es demasiado pequeno

Control dinamico: Cuando el numero de tareas es demasiado grande

3.3.1 Cut-off control

Tree parallelization con control de profundidad recursiva:

1 #d e f i n e CUTOFF 3
2 ...
3 v o i d rec_vector_add ( i n t A , i n t B , i n t C , i n t n , i n t depth ) {
4 i f ( n>MIN_SIZE ) {
5 i n t n2 = n / 2 ;
6 i f ( depth < CUTOFF ) {
7 #pragma omp t a s k
8 rec_vector_add ( A , B , C , n2 , depth +1) ;
9 #pragma omp t a s k
10 rec_vector_add ( A+n2 , B+n2 , C+n2 , nn2 , depth +1) ;
11 }
12 else {
13 rec_vector_add ( A , B , C , n2 , depth +1) ;
14 rec_vector_add ( A+n2 , B+n2 , C+n2 , nn2 , depth +1) ;
15 }
16 }
17 e l s e vector_add ( A , B , C , n ) ;
18 }
19
20 v o i d main ( ) {
21 ....
22 #pragma omp p a r a l l e l

14
23 #pragma omp s i n g l e
24 rec_vector_add ( a , b , c , N , 0 ) ;
25 ...
26 }

Leaf-parallelization with depth recursion control:

1 #d e f i n e CUTOFF 2
2 ...
3 v o i d rec_vector_add ( i n t A , i n t B , i n t C , i n t n , i n t depth ) {
4 i f ( n>MIN_SIZE ) {
5 i n t n2 = n / 2 ;
6 i f ( depth == CUTOFF ) {
7 #pragma omp t a s k
8 rec_vector_add ( A , B , C , n2 , depth +1) ;
9 #pragma omp t a s k
10 rec_vector_add ( A+n2 , B+n2 , C+n2 , nn2 , depth +1) ;
11 }
12 else {
13 rec_vector_add ( A , B , C , n2 , depth +1) ;
14 rec_vector_add ( A+n2 , B+n2 , C+n2 , nn2 , depth +1) ; }
15 } else
16 i f ( depth <= CUTOFF )
17 #pragma omp t a s k
18 vector_add ( A , B , C , n ) ;
19 else
20 vector_add ( A , B , C , n ) ;
21 }
22 ...

3.4 Ejecucion imnediata de la tarea

if: Si la expresion de un if se evalua a falso, la tarea padre se suspende y se inicia una nueva (no
necesariamente en el mismo thread). El padre vuelve a ejecutarse cuando la tarea finaliza.

final clause: Si la expresion de una clausula final evalua a true, todas las tareas que descienda de
ella seran final. La ejecucion de una tarea final es incluida secuencialmente en la tarea generada.

mergeable clause:

15
3.5 Task syncronization in OpenMP

Barrearas de threads (#pragma omp barrier): espera a que todos los threads acaben el trabajo que
estaba haciendo

Task barriers:

taskwait: Suspende la tarea actual esperando a que finalicen las tareas hijas de ella.

taskgroup: suspende la tarea actual al final del bucle estructurado, esperando a la finalizacion
de las tareas hijas de la tarea actual y sus tareas descendientes.

3.5.1 taskwait vs. taskgroup

Taskwait

1 #pragma omp t a s k {} // T1
2 #pragma omp t a s k // T2
3 {
4 #pragma omp t a s k {} // T3
5 }
6 #pragma omp t a s k {} // T4
7
8 #pragma omp t a s k w a i t
9 // Only T1 , T2 and T4 a r e g u a r a n t e e d t o have f i n i s h e d a t t h i s p o i n t

Taskgroup

1 #pragma omp t a s k {} // T1
2 #pragma omp t a s k g r o u p
3 {
4 #pragma omp t a s k // T2
5 {
6 #pragma omp t a s k {} // T3
7 }
8 #pragma omp t a s k {} // T4
9 }
10 // Only T2 , T3 and T4 a r e g u a r a n t e e d t o have f i n i s h e d a t t h i s p o i n t

3.6 Fibonacci

3.6.1 Sequencial

1 l o n g fib ( l o n g n ) {
2 i f ( n < 2) return n ;
3 r e t u r n ( fib ( n1) + fib ( n2) ) ;
4 }
5
6 v o i d main ( i n t argc , c h a r argv [ ] ) {
7 n = atoi ( argv [ 1 ] ) ;

16
8 res = fib ( n ) ;
9 printf ( F i b o n a c c i f o r %d i s %d , n , res ) ;
10 }

Las llamadas a fib para n-1 y n-2 pueden ser una task

Necesitamos garantizar que ambas instancias de fib acaben antes de devolver el resultado

3.6.2 Codigo OpenMP

1 l o n g fib parallel ( l o n g n , i n t d ) {
2 long x , y ;
3 i f ( n < 2 ) r e t u r n n ; i f ( d<CUTOFF {
4 #pragma omp t a s k s h a r e d ( x ) // f i r s t p r i v a t e ( n ) by d e f a u l t
5 x = fib parallel ( n 1, d+1) ;
6 #pragma omp t a s k s h a r e d ( y ) // f i r s t p r i v a t e ( n ) by d e f a u l t
7 y = fib parallel ( n 2, d+1) ;
8 #pragma omp t a s k w a i t
9 }
10 else {
11 x = fib parallel ( n 1, d ) ; // o r f i b ( n1)
12 y = fib parallel ( n 2, d ) ; // o r f i b ( n2)
13 }
14 r e t u r n ( x+y ) ;
15 }
16
17 v o i d main ( i n t argc , c h a r argv [ ] ) {
18 n = atoi ( argv [ 1 ] ) ;
19 #pragma omp p a r a l l e l
20 #pragma omp s i n g l e
21 res = fib parallel ( n , 0 ) ;
22 printf ( F i b o n a c c i f o r %d i s %d , n , res ) ;
23 }

3.7 Task dependences

OpenMP permite definir dependencias entre tareas hermanas (p.e. que vengan del mismo padre)

1 #pragma omp t a s k [ depend ( i n v a r l i s t ) ]


2 [ depend ( out : var_list ) ]
3 [ depend ( inout : var_list ) ]

Tipo in: la task generada sera dependiente de todas las tareas hermanas generadas anteriormente que
hagan referencia a al menos uno de los telementos de la lista en tipo de dependencia out o inout.

Out e inout: la tarea creada sera dependiente de todas las tareas hermanas creadas anteriormente que
hagan referencia a un item de la lista en in, out o inout.

1 256 2 1 calls 3 528 4 64 tasks 5 4 calls 6 192 t.u 7 84 calls 8 4 calls 9 88 t.u

17