Está en la página 1de 34

Cmputo en paralelo con OpenMP 1

Miguel Vargas-Flix
miguelvargas@cimat.mx
http://www.cimat.mx/~miguelvargas
CIMAT, September 2, 2015

1/34

1e10

1970

http://www.cimat.mx/~miguelvargas
2e10

1975
1985
1990
1995

4e10

3e10

2000

5e10

Intel Core 2
(49G ips)

6e10

PlayStation 3 Cell
(10G ips)

AMD Athlon XP (5.9G ips)


Intel Pentium IV (9.7G ips)

Intel Pentium III


(1.4G ips)

Motorola 68040
(44M ips)
Intel 80x486
(54M ips)
Motorola 68060
(88M ips)
Intel Pentium Pro
(541M ips)

0e0

Intel 80x386
(11M ips)

1980
Intel 80x286
(4M ips)

Motorola 68000
(1M ips)

Intel 8080
(500K ips)

Intel 4004
(92K ips)

Intel Core i7
(76G ips)

8e10

2005

AMD Phenom II X4
(43G ips)

Number of instructions per second

Velocidad de los procesadores de escritorio

Recientemente, la velocidad de procesamiento a crecido debido al uso de procesadores multi-core.

7e10

2010

multi-core
processors
2/34

Tenemos que cambiar nuestros algoritmos para que corran lo ms eficientemente posible en los
procesadores multi-core.
instruction
instruction
instruction

Serial
algorithm

instruction
instruction

Parallel
algorithm

instruction

instruction

instruction

instruction

instruction

instruction

reduction
instruction

instruction

instruction

reduction

instruction
reduction
instruction
instruction
instruction
reduction

La meta es reducir tiempo necesario para realizar una secuencia de instrucciones.


La buena noticia es:
Hacer programas en paralelo con OpenMP es muy sencillo.
La mala noticia es:
Hacer programas en paralelo eficientes requiere un esfuerzo extra.
http://www.cimat.mx/~miguelvargas

3/34

Operaciones matemticas en paralelo


Fcilmente paralelizables
Esto significa que pueden separarse en varias sub-operaciones que puede realizarse de forma
independiente.
Por ejemplo, la suma de dos vectores w=x+y, con w , x , y n,
w i = x i + y i.
Y supongamos que tenemos n procesadores.
x1+y1

x2+y2

x3+y3

x4+y4

x5+y5

x6+y6

x7+y7

x8+y8

...

xn+yn

w1

w2

w3

w4

w5

w6

w7

w8

...

wn

En este caso las sumas pueden realizarse simultneamente, asignando una a cada procesador.
Lo que hay que resaltar es que no hay dependencia entre los diferentes pares de datos, tenemos
entonces el paralelismo ms eficiente.
http://www.cimat.mx/~miguelvargas

4/34

No tan fciles de paralelizar


Por ejemplo el producto punto, a= x , y , con x , y n,
n

a= x i y i
i=1

donde a es un escalar.

Una primera aproximacin sera verlo como una secuencia de sumas de productos que requieren
irse acumulando.

x1 y1 + x2 y2 + x3 y3 + x4 y4 + x5 y5 + x6 y6 + x7 y7 +

...

+ xn yn

Time

Al verlo as no es una operacin paralelizable.

http://www.cimat.mx/~miguelvargas

5/34

Sin embargo, podemos reorganizar el proceso como se muestra en la figura:

x1 y1

x2 y2

x3 y3

x4 y4

x5 y5

x6 y6

x7 y7

x8 y8
+

...
...

xn-1 yn-1

xn y n

+
+
+
a

En este caso se tiene una paralelizacin eficiente de la multiplicacin de las entradas de los
vectores, despus se va reduciendo la eficiencia al dividir las operaciones de suma en pares.
Muchos algoritmos seriales requieren, para ser paralelizados, de re-ordenar las operaciones con
una estrategia de divide y vencers, como en el caso del producto punto.
http://www.cimat.mx/~miguelvargas

6/34

Usualmente se tendrn memos procesadores que el tamao del vector, por lo que se asignan varias
operaciones de un grupo a cada procesador, las cuales se ejecutarn en serie, lo que limita la
eficiencia del paralelismo.

x1 y1

x5 y5
x2 y2

x6 y6
x3 y3

x7 y7

xn-1 yn-1

x4 y4
+

x8 y8

...

xn yn

+
+
a

http://www.cimat.mx/~miguelvargas

7/34

El esquema OpenMP
Sirve para paralelizar programas en C, C++ o Fortran en computadoras multi-core.
Busca que escribir cdigo en paralelo sea sencillo.
Es un esquema de paralelizacin con memoria compartida (todos los cores accesan a la misma
memoria).
Su funcionamiento interno es con threads, en el caso de sistemas POSIX se utiliza la librera de
POSIX-Threads (libpthread).
Una descripcin ms a detalle de OpenMP 2.5 la pueden encontrar en [Chap08].

http://www.cimat.mx/~miguelvargas

8/34

Compiladores que soportan OpenMP


Algunos de los compiladores que tienen soporte para OpenMP son:
GNU Compiler Collection GCC (versin 4.3.2).
The LLVM Compiler Infrastructure (versin 3.7.0)
Intel C++ and Fortran Compilers (version 10.1) 1
Microsoft Visual Studio Professional (version 2008) 2
Microsoft Visual Studio Express (version 2012) 3
Microsoft Visual Studio Community (2015) 4
La lista completa se puede consultar en http://openmp.org/wp/openmp-compilers
1

Versin gratuita para Linux para estudiantes.


http://software.intel.com/en-us/non-commercial-software-development
Descargable de forma gratuita para estudiantes de instituciones de educacin superior en Microsoft DreamSpark.
http://www.dreamspark.com
Gratis para todo tipo de desarrollo.
http://www.microsoft.com/visualstudio/eng/products/visual-studio-express-products
Completamente gratis para empresas pequeas y desarrollo open source.
https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx

http://www.cimat.mx/~miguelvargas

9/34

Programacin con multi-hilos (multi-threads)


A la ejecucin secuencial de una conjunto de instrucciones se le conoce como un hilo de
procesamiento o thread.

1 thread

3 threads

start

instruction

instruction

instruction

instruction

instruction

instruction

1 thread
3 threads
1 thread

http://www.cimat.mx/~miguelvargas

reduction

instruction

instruction

instruction

reduction

10/34

En las computadoras multi-core logra la mejor eficiencia cuando cada core ejecuta slo un thread.
Parallel
section

Serial
section
Core 0
Core 1

Inactive
core

Core 2
Core 3

Active
core

Core n
Thread
creation

Synchronization

Waiting
core

Time

Cuando se paraleliza no todos los threads terminan al mismo tiempo.


Dentro de un programa, cada thread posee sus propios registros de control y su propio stack de
datos, mientas que comparte el uso de las regiones de memoria heap y data con los dems threads
del programa.
http://www.cimat.mx/~miguelvargas

11/34

Paralelizacin con OpenMP


Suma de vectores
Comencemos con la paralelizacin de la suma de dos vectores:

void Suma(double* a, double* b, double* c, int size)


{
for (int i = 0; i < size; ++i)
{
c[i] = a[i] + b[i];
}
}

La paralelizacin sera...

http://www.cimat.mx/~miguelvargas

12/34

... la paralelizacin sera:

void Suma(double* a, double* b, double* c, int size)


{
#pragma omp parallel for
for (int i = 0; i < size; ++i)
{
c[i] = a[i] + b[i];
}
}

Un #pragma es una directiva para el compilador, significa que tiene que insertar cdigo especial
que haga algo que no est definido en el estandar de C o C++.
En este caso el #pragma internamente inserta cdigo oculto de OpenMP para paralelizar el for.

http://www.cimat.mx/~miguelvargas

13/34

Compilacin de un cdigo con OpenMP


No es suficiente con agregar el #pragma, hace falta decirle al compilador que agregue el soporte
para OpenMP.
Para compilar con GCC es necesario agregar:
g++ -o programa -fopenmp suma.cpp

En Visual C++ hay una opcin en las preferencias del proyecto para activar OpenMP

http://www.cimat.mx/~miguelvargas

14/34

Paralelizacin del for


La forma en que OpenMP paraleliza un for es formando bloques de ndices (el tamao de los
bloques es controlable).
Supongamos que tenemos una computadora con 3 cores.
Para la suma de vectores size=30 y que los bloques son de tamao 10.
void Suma(double* a, double* b, double* c, int size)
{
#pragma omp parallel for
for (int i = 0; i < 10; ++i)
for (int i = 10; i < 20; ++i)
{
{
c[i] = a[i] + b[i];
c[i] = a[i] + b[i];
}
}
}

for (int i = 20; i < 30; ++i)


{
c[i] = a[i] + b[i];
}

OpenMP asigna un bloque de ndices a cada core.


Al core 0 le toca procesar el for con los ndices 0-9
Al core 1 le toca procesar el for con los ndices 10-19
Al core 2 le toca procesar el for con los ndices 20-29
http://www.cimat.mx/~miguelvargas

15/34

Por ejemplo, supongamos ahora que size=100 y que los bloques siguen siendo de tamao 10.
La distribucin de ndices podra ser algo como:
void Suma(double* a, double* b, double* c, int size)
{
#pragma omp parallel for
for (int i = 0; i < 10; ++i)
for (int i = 10; i < 20; ++i)
{
{
c[i] = a[i] + b[i];
c[i] = a[i] + b[i];
}
}
for (int i = 40; i < 50; ++i)
for (int i = 30; i < 40; ++i)
{
{
c[i] = a[i] + b[i];
c[i] = a[i] + b[i];
}
}
for (int i = 80; i < 90; ++i)
for (int i = 70; i < 80; ++i)
{
{
c[i] = a[i] + b[i];
c[i] = a[i] + b[i];
}
}
for (int i = 90; i < 100; ++i)
{
c[i] = a[i] + b[i];
}
}

for (int i = 20; i < 30; ++i)


{
c[i] = a[i] + b[i];
}
for (int i = 50; i < 60; ++i)
{
c[i] = a[i] + b[i];
}
for (int i = 60; i < 70; ++i)
{
c[i] = a[i] + b[i];
}

A los bloques se les llama chunk, y su tamao puede ser controlado por el programador.
http://www.cimat.mx/~miguelvargas

16/34

La distribucin de los ndices es controlada por OpenMP.


Nosotros simplemente tenemos que escribir
void Suma(double* a, double* b, double* c, int size)
{
#pragma omp parallel for
for (int i = 0; i < size; ++i)
{
c[i] = a[i] + b[i];
}
}

y dejamos que OpenMP haga el resto.


Si el compilador no tiene soporte para OpenMP, entonces el #pragma es ignorado y tendremos la
versin serial del programa.
Si la computadora no es multi-core, entonces tambin se ejecutar el cdigo en serie.
Este esquema permite primero probar nuestro cdigo en serie y luego ejecutarlo en paralelo.

http://www.cimat.mx/~miguelvargas

17/34

Paralelizar bloques de cdigo


Adems de paralelizar ciclos, es posible paralelizar bloques

#pragma omp parallel


{
// ... codigo a ejecutar en paralelo...
int thread = omp_get_thread_num();
}

omp_get_thread_num regresa el nmero de thread actual.

http://www.cimat.mx/~miguelvargas

18/34

Controlar el nmero de threads


#include <stdio.h>
#include <omp.h>
int main()
{
int max = omp_get_max_threads();
printf("omp_get_max_threads = %i\n", max);
#pragma omp parallel
{
int t = omp_get_thread_num();
printf(" omp_get_thread_num = %i\n", t);
}
return 0;
}
g++ -o test -fopenmp test.cpp
./test

La funcin omp_get_max_threads regresa la cantidad mxima de threads establecida.


omp_get_thread_num regresa el ID del thread, los threads se identifican enumeran iniciando en 0.
http://www.cimat.mx/~miguelvargas

19/34

Si una computadora tiene un procesador con 4 cores, podemos decidir no utilizarlos todos.
Cmo se define el nmero de cores/threads a utilizar?
Por default el nmero de threads es igual al nmero de cores en la computadora.
Se puede establecer por medio de variables de ambiente.
Se puede definir en el cdigo en run-time.

Establecer nmero de threads con variables de ambiente


Se hace a travs de la variable de ambiente OMP_NUM_THREADS. La variable se tiene que
inicializar antes de ejecutar el programa.
En Linux/Unix (Bash):
export OMP_NUM_THREADS=3
./test

En Windows:
set OMP_NUM_THREADS=3
test.exe
http://www.cimat.mx/~miguelvargas

20/34

Establecer nmero de threads con cdigo


Una forma es utilizando una funcin de OpenMP, para esto es necesario incluir el header omp.h,
el cual incluye varias funciones para el control de threads.
#include <omp.h>
void Suma(double* a, double* b, double* c, int size)
{
#pragma omp parallel for
for (int i = 0; i < size; ++i) {
c[i] = a[i] + b[i];
}
}
int main()
{
omp_set_num_threads(3);
...
Suma(a, b, c, 100);
}

omp_set_num_threads permite establecer el nmero de threads a utilizar en todas las siguientes


paralelizaciones.

http://www.cimat.mx/~miguelvargas

21/34

Otra forma sera utilizando la clausula num_threads.


void Suma(double* a, double* b, double* c, int size, int threads)
{
#pragma omp parallel for num_threads(threads)
for (int i = 0; i < size; ++i) {
c[i] = a[i] + b[i];
}
}
int main()
{
int threads = 3;
...
Suma(a, b, c, 100, threads);
}

De esta forma se puede tener un control ms fino del nmero de threads para cada paralelizacin.

http://www.cimat.mx/~miguelvargas

22/34

Reducciones
El ejemplo que mostraremos es la paralelizacin del producto punto:
double ProductoPunto(double* a, double* b, int size)
{
double c = 0;
for (int i = 0; i < size; ++i)
c += a[i]*b[i];
return c;
}

Qu pasa si hacemos...?
double ProductoPunto(double* a, double* b, int size)
{
double c = 0;
#pragma omp parallel for
for (int i = 0; i < size; ++i)
c += a[i]*b[i];
return c;
}

http://www.cimat.mx/~miguelvargas

23/34

La forma en que OpenMP permite hacer operaciones de este tipo es por medio de la clusula
reduction.

double ProductoPunto(double* a, double* b, int size)


{
double c = 0;
#pragma omp parallel for reduction(+:c)
for (int i = 0; i < size; ++i)
c += a[i]*b[i];
return c;
}

Lo que hace reduction es crear tantas copias de c como threads existan e irlas acumulando por
separado, al terminar se suman stas y se tendr un solo resultado.

http://www.cimat.mx/~miguelvargas

24/34

Las operaciones soportadas en las reduciones son:


Operador de
reduccin
+
*
&
|
^
&&
||
max
min

Valor de
inicializacin
0
1
0
~0
0
0
1
0

Para poner mltiples reduciones, puede ser como:


double minimum = a[0];
double maximum = a[0];
#pragma omp parallel for reduction(min:minimum) reduction(max:maximum)
for (int i = 1; i < size; ++i)
{
if (minimum > a[i])
minimum = a[i];
else if (maximum < a[i])
maximum = a[i];
}
http://www.cimat.mx/~miguelvargas

25/34

Multiplicacin matriz-vector
Ahora veamos la multiplicacin matriz-vector.
void Mult(double* A, double* x, double* y, int rows, int cols)
{
#pragma omp parallel for
for (int i = 0; i < rows; ++i)
{
double sum = 0;
for (int k = 0; k < cols; ++k)
{
sum += A[i*cols + k]*x[k];
}
y[i] = sum;
}
}

Hay que notar que las operaciones no se interfieren, dado que cada iteracin slo escribe en el
elemento y[i].

http://www.cimat.mx/~miguelvargas

26/34

Speed-up
La aceleracin (speed-up) de un programa en paralelo,
t1
S= .
tn
12
Speed-up
Ideal Speed-up

10

Speed-up

0
0

10

12

14

16

Threads

http://www.cimat.mx/~miguelvargas

27/34

Prdida de eficiencia con el aumento de threads


Ejemplo de un programa trabajando en una computadora con 16 cores/threads
25

Real time [m]


Ideal time [m]
20

Time [m]

15

10

0
1

10

11

12

13

14

15

16

Threads

Sea t 1 el tiempo real que tard el resolverse un problema con un thread, n el nmero de
procesadores utilizado, el tiempo ideal de ejecucin lo podemos definir como
t1
i n= .
n
http://www.cimat.mx/~miguelvargas

28/34

Podemos dar una medida de eficiencia E de un algoritmo

i
t
E= n = 1 .
t n nt n
1.0
0.9
0.8
0.7

Efficiency

0.6
0.5
0.4
0.3
0.2
0.1
0.0
1

10

11

12

13

14

15

16

Threads

http://www.cimat.mx/~miguelvargas

29/34

Teorema de Gergorin
nn

Sea A

, con entradas ai j . Definamos los radios


r i = |ai j|, i=1, 2, , n,
ji

como la suma de las entradas fuera de la diagonal del rengln i.


Sea D ( ai i , r i ) un disco cerrado en el plano complejo, con centro en a ii y radio r i . Estos discos son
llamados discos de Gergorin [Varg04].
Teorema: Cada eigenvalor de A est dentro de alguno de los discos de Gergorin D ( aii , r i ).

http://www.cimat.mx/~miguelvargas

30/34

Ejemplo, podemos estimar los eigenvalores de

10 1 0
1
A= 0.2 8 0.2 0.2 ,
1
1
2
1
1 1 1 11
se obtienen cuatro discos D ( 10, 2 ), D ( 8, 0.6 ), D ( 2, 3 ), D (11,3 ).
i
10

D (8, 0.6 )

x
-10

D (11, 3 )

-5

D ( 2, 3 )

10

D (10, 2 )

-5

Los eigenvalores de A son: 9.8218, 8.1478, 1.8995, -10.86.


http://www.cimat.mx/~miguelvargas

31/34

El nmero de condicin de una matriz A no singular, para una norma est dado por
( A )=AA1.

Para la norma 2,
max ( A )
( A )=AA =
,
min ( A )
1

donde son los valores singulares de la matriz.


Para una matriz A simtrica positiva definida,
max ( A )
( A )=
,
min ( A )
donde son los eigenvalores de A. As, matrices con un nmero de condicin cercano a 1 se dicen
que estn bien condicionadas.
Podemos utilizar el teorema de Gergorin para encontar un aproximado del nmero de condicin
para de matrices dispersas (simtricas positivas definidas).

http://www.cimat.mx/~miguelvargas

32/34

Preguntas?

miguelvargas@cimat.mx

http://www.cimat.mx/~miguelvargas

33/34

Referencias
[Chap08] B. Chapman, G. Jost, R. van der Pas. Using OpenMP: Portable Shared Memory Parallel
Programming. The MIT Press, 2008.
[Varg04] R. S. Varga. Gergorin and His Circles. Springer. 2004.

http://www.cimat.mx/~miguelvargas

34/34

También podría gustarte