programación de memoria compartida
DESCRIPTION
Programación de Memoria Compartida. openMP. El Modelo de Memoria Compartida. Los procesadores interactuan uno con otro mediante variables compartidas. OpenMP es el estandar para programaci ón de memoria compartida. ¿Que es openMP?. - PowerPoint PPT PresentationTRANSCRIPT
![Page 1: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/1.jpg)
Programación de Memoria Compartida
openMP
![Page 2: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/2.jpg)
El Modelo de Memoria Compartida
P r o c es s o r P r o c es s o r P r o c es s o r P r o c es s o r
M em o r y
Los procesadores interactuan uno con otromediante variables compartidas.
OpenMP es el estandar para programación de memoria compartida.
![Page 3: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/3.jpg)
¿Que es openMP?
• openMP es una especificación para una implementación portable de paralelismo en FORTRAN y C/C++.
• La especificación provee directivos de compilador, rutinas de biblioteca que se pueden usar para controlar paralelismo.
![Page 4: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/4.jpg)
Paralelismo Fork/Join
• Inicialmente solamente el hilo maestro está activo
• El hilo maestro ejecuta el código secuencial
• Fork: El hilo maestro crea hilos adicionales para ejecutar el código paralelo
• Join: Al finalizar de código paralelo, los hilos creados mueren o se suspendienden
![Page 5: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/5.jpg)
Ejemplo
#include <omp.h> #include <stdio.h> int main (int argc, char *argv[]) {#pragma omp parallel printf(“Hello world\n”);return 0; }
![Page 6: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/6.jpg)
El Modelo de Memoria Compartida vs. el Modelo que
Pasa Mensajes (#1)• El modelo de memoria compartida
– El número de hilos es 1 al principio y al final y cambia dinámicamente durante de la ejecutación del programa
• El Modelo que pasa mensajes– Todos los procesos estan activos durante de
la ejecutacion del programa.
![Page 7: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/7.jpg)
Paralelización Incremental
• Un programa secuencial es un caso especial de un programa de memoria compartida
• Paralelización incremental es el procesos de convertir un programa secuencial a un programa paralelo poco a poco
![Page 8: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/8.jpg)
Un Bucle for Paralelo
• Las iteraciones de un bucle for se pueden ejecutar en paralelo si ninguna iteración depende de otra anterior.
• Ejemplos: Las iteraciones de
- for (i=first;i<size;i += prime; marked[i]=1) se pueden ejecutar en paralelo, pero
-for (i=1;i<=n;i++) suma += suma + v[i]
no
![Page 9: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/9.jpg)
Pragmas
• Una pragma en C o C++ es un directivo al compilador.
• La sintaxis es
#pragma omp <el resto de la pragma>
Ejemplo:
#pragma omp parallel for
es una directriz que dice al compilador que trate a paralelizar el bucle for que sigue
![Page 10: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/10.jpg)
La Pragma for Paralelo
#pragma omp parallel forfor (i = 0; i < N; i++) a[i] = b[i] + c[i];
• El compilador tiene que verificar que cuando se ejecuta, habrá disponible la información necesaria para llevar a cabo las iteraciones
![Page 11: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/11.jpg)
La sintaxis de la pragma for paralelo
inc
inc
inc
incincultimoprimero
indiceindex
indiceindice
indiceindice
indiceindice
indice
indiceindice
indice
;indice;indice(for
![Page 12: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/12.jpg)
El Contexto de Ejecutación
• Todo hilo tiene un contexto de ejecutación, que consiste del espacio de direcciones que el hilo puede acesar
• El contexto de ejecutación incluye variables estáticas, estructuras dinámicamente asignadas, y variables en el “run-time stack”
![Page 13: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/13.jpg)
“Variables Compartidas y Variables Privadas
• Una variable compartida tiene la misma dirección en el contexto de ejecutación de cada hilo.
• Una variable privada tiene una dirección distinta en el contexto de ejecutación de cada hilo.
• Un hilo no puede acesar las variables privadas de otro hilo.
![Page 14: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/14.jpg)
Función omp_set_num_threads
• Se usa para asignar el número de hilos a ser activos en secciones paralelas del código
• Se puede llamar en varios puntos del programa
void omp_set_num_threads (int t)
![Page 15: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/15.jpg)
omp_get_thread_num()
• Todo hilo tiene una identificación que es el número del hilo
• omp_get_thread_num()devuelve el número del hilo
![Page 16: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/16.jpg)
Función omp_get_num_procs
• Devuelve el número de procesadores fisicos que están dispondible para el uso del programa paralelo
int omp_get_num_procs (void)
![Page 17: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/17.jpg)
Hello World• #include <omp.h>• #include <stdio.h>• • int main (int argc, char *argv[]) {• int p,th_id;• p=omp_get_num_procs(); • omp_set_num_threads(p);• #pragma omp parallel private(th_id);• {• th_id = omp_get_thread_num();• printf("Hello World from thread %d\n", th_id);• }• return 0;• }
![Page 18: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/18.jpg)
Pragmas - REPASO
• Una pragma en C o C++ es un directivo al compilador.
• La sintaxis es
#pragma omp <el resto de la pragma>
Ejemplo:
#pragma omp parallel for
es una directriz que dice al compilador que trate a paralelizar el bucle for que sigue
![Page 19: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/19.jpg)
La sintaxis de la pragma for paralelo
inc
inc
inc
incincultimoprimero
indiceindex
indiceindice
indiceindice
indiceindice
indice
indiceindice
indice
;indice;indice(for
![Page 20: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/20.jpg)
Ejemplo 1
#pragma omp parallel for
for (i=0;i<(int) sqrt(x);i++)
a[i] = 2.3*I;
if (i < 10) b[i]=a[i];
![Page 21: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/21.jpg)
Ejemplo 2
flag = 0;
for (i=0;(i<n) & (!flag);i++){
a[i] = 2.3*i;
if (a[i] < b[i]) flag = 1;
No se puede paralelizar el bucle pues no
no satisface el requisito de sintaxis.
![Page 22: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/22.jpg)
Ejemplo 3
for (i=0;i<n;i++) {
a[i] = foo(i);
if (a[i] < b[i]) break;
No se puede paralelizar un bucle cuyo cuerpo contiene break, return, o exit.
![Page 23: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/23.jpg)
Variables privadas y compartidas
• #pragma omp parallel <clausula>
bloque
• La clausula puede ser
private (lista de variables)
shared (lista de variables)
y otras.
![Page 24: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/24.jpg)
Variables privadas y compartidas(2)
• Una variable compartida tiene la misma dirección en el contexto de ejecutación de cada hilo
• Una variable privada tiene una dirección distinta en el contexto de ejecutación de cada hilo
• Cada variable en el cuerpo de un bucle paralelo, excepto la variable de iteración, que no se especifica como privada es compartida.
![Page 25: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/25.jpg)
Ejemplo
//Despues de ejecutar del siguiente código, debe ser cierto que a[i] <= b[i] para todo i
#pragma omp parallel for for (i=0;i<n;i++) if (a[i] > b[i]) {temp=a[i];a[i]=b[i]; b[i]=temp;} ¿Funciona este código?
![Page 26: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/26.jpg)
Ejemplo(continuado)
• No funciona correctamente, pues la variable temp debe ser privada
• //El código correcto
#pragma omp parallel for private(temp)
for (i=0;i<n;i++)
if (a[i] > b[i])
{temp=a[i];a[i]=b[i]; b[i]=temp;}
![Page 27: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/27.jpg)
Grafos con Pesos
• Un grafo dirigido en la cual hay asociado con cada arista un número positivo (el “peso”) se llama un grafo dirigido con pesos.
• El largo de una trayectoria de un vértice u a otro vértice v es la suma de los pesos de las aristas que componen la trayectoria.
![Page 28: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/28.jpg)
El Problema de Todos Pares Distancias mas Cortas
• Dado un grafo dirigido con pesos, ¿cuales son las trayectorias de largos mínimos (es decir “distancias mas cortas”) entre todos los pares de vértices?
![Page 29: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/29.jpg)
La Matríz de Adyacencias
• Representar un grafo dirigido con pesos G con n vértices por una matríz AG como sigue:
• Si 1,2, … ,n son los vértices, entonces el elemento en la fila #i y la columna #j es 0 si i=j, es ∞ (un número mas grande que
cualquier peso) si no hay arista de I a j, y es el peso de la arista de i a j si tal arista existe.
Llamemos AG la matríz de adyacencias.
![Page 30: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/30.jpg)
Ejemplo
A
E
B
C
D
4
6
1 35
3
1
2
0 6 3 ∞
4 0 ∞ 1
∞ ∞ 0 5
∞ 3 ∞ 0
∞ ∞ ∞ 2
A
B
C
D
E
A B C D
∞
∞
1
∞
0
E
Matríz de Adyacencias
![Page 31: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/31.jpg)
El Algoritmo de Floyd
for (k= 0;k<n;k++)
for (i =0;i< n;i++)
for (j= 0;j<n;j++)
a[i,j] min (a[i,j], a[i,k] + a[k,j])
![Page 32: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/32.jpg)
La Solución al Ejemplo Anterior
A
E
B
C
D
4
6
1 35
3
1
2
0 6 3 6
4 0 7 1
10 6 0 3
7 3 10 0
9 5 12 2
A
B
C
D
E
A B C D
8
8
1
11
0
E
Matríz de Distancias
![Page 33: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/33.jpg)
La Idea del Algoritmo
i
k
j
La trayectoria mas corta de i a k que pasa por 0, 1, …, k-1
La trayectoria mas corta de k a j que pasa por 0, 1, …, k-1
La trayectoria mas cortade i a j que pasa por 0, 1, …, k-1
Computedin previousiterations
![Page 34: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/34.jpg)
¿Como se puede paralelizar el algoritmo de Floyd?
for (k= 0;k<n;k++) for (i =0;i< n;i++)
for (j= 0;j<n;j++)a[i,j] min (a[i,j], a[i,k] + a[k,j])
No se puede paralelizar el primer bucle.Se puede paralelizar el segundo o el tercero.¿Cual es mejor?
![Page 35: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/35.jpg)
El algoritmo de Floyd paralelizado
for (k= 0;k<n;k++) #pragma omp parallel for private(j)
for (i =0;i< n;i++)for (j= 0;j<n;j++)a[i,j] min (a[i,j], a[i,k] + a[k,j])
Mejor paralelizar el segundo bucle en vez del tercero para evitar el costo de “fork join” repetido
![Page 36: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/36.jpg)
Asignación
Escribir un programa sequencial en C (o C++) para resolver el problema de Floyd. La entrada debe consistir de n, el número de vértices en el grafo con pesos, y la matriz de adjacencias. Esta matriz debe ser implementada como un arreglo dinámico.
La entrada puede ser mediante el teclado o mediante un archivo.
La salida debe consistir de un arreglo n X n en donde cada posición (i,j) contiene el peso de la trayectoria mas corta de i a j.
![Page 37: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/37.jpg)
Arreglos Dinámicos Unidimensionales/
main(){ Int i, n=10; int *A; A=(int *) malloc (n* sizeof(int));//Ahora, A se puede usar como un arreglo ordinario.// Por ejemplo, for (i=0;i<n;i++) { A[i]=2*i; printf("%d\n",A[i]); }}
![Page 38: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/38.jpg)
Arreglos Dinámicos Bidimensionales
main(){ int i,j,m=4,n=3; int **B, *Bstorage; Bstorage=(int *) malloc (m*n*sizeof(int));//asignar memoria para arreglo mXn B= (int **) malloc (m*sizeof(int *)); //asignar memoria para el arreglo //de apuntadores a las filas for (i=0;i<m;i++) B[i]=&Bstorage[i*n]; //Inicializar el arrego de apuntadores a las filas //Ahora podemos tratar como un m Xn arreglo ordinario. //Por ejemplo,
for (i=0;i<m;i++) { for (j=0;j<n;j++) { B[i][j]=i*j; printf("%d ",B[i][j]); } printf("\n"); }}
![Page 39: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/39.jpg)
¿Como se puede paralelizar el siguiente código?
x[0] = complex_function();
for (i=0;j<n;i++) {
for (j=1;j<4;j++)
x[j]=g(i,x[j-1]);
answer[i] = x[1] – x[3];}
![Page 40: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/40.jpg)
Como se puede paralelizar el siguiente código:
x[0] = complex_function();for (i=0;j<n;i++) { for (j=1;j<4;j++) x[j]=g(i,x[j-1]); answer[i] = x[1] – x[3];}Se puede hacer el bucle exterior paralelo si
hacemos j y x privadas. Sin embargo, x[0] se necesita en la primera iteración del bucle interior.
![Page 41: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/41.jpg)
firstprivate
Se podría mover la inicialización de x[0] a dentro del bucle anterior, pero es caro.
Mejor usar la cláusula firstprivate.x[0] = complex_function();#pragma omp parallel for private[j] firstprivate(x)for (i-0;j<n;i++) { for (j=1;j<4;j++) x[j]=g(i,x[j-1]); answer[i] = x[1] – x[3];}
![Page 42: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/42.jpg)
firstprivate (cont)
• Se usa para crear una variable privada que tiene su valor inicial igual al valor de la variable controlada por el hilo maestro cuando se entra el bucle.
• Si un hilo cambia el valor de una variable en alguna iteración, entonces este valor será el valor de la variable en iteraciones subsecuentes
![Page 43: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/43.jpg)
lastprivate
• La secuencialmente última iteración es la última iteración que se lleva a cabo cuando el bucle se ejecuta secuencialmente
• La cláusula lastprivate se usa para copiar el valor privado del hilo que ejecutó la secuencialmente última iteración a la copia del hilo maestro
![Page 44: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/44.jpg)
Ejemplo
for (i=0;i<n;i++){ x[0] = 1.0; for (j=1;j<4;j++) x[j] = x[j-1] * (i+1); sum_of_powers[i] = x[0]+x[1]+x[2]+x[3];}n_cubed = x[3]; No se puede predecir el valor de x[3]!
![Page 45: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/45.jpg)
Una solución para que x[3]=n3
#pragma omp parallel for private(j) lastprivate(x)
for (i=0;i<n;i++){
x[0] = 1.0;
for (j=1;j<4;j++)
x[j] = x[j-1] * (i+1);
sum_of_powers[i] = x[0]+x[1]+x[2]+x[3];
}
n_cubed = x[3];
![Page 46: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/46.jpg)
La Regla Rectangulo para Computar
= ∫0
1 4/(1+x2) dx
• La Regla de Rectangulo consiste de estimar el area debajo de la curva y=4/(1+x2) entre x=0 y x=1 mediante areas de rectangulos
![Page 47: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/47.jpg)
Código para aproximar
double area, pi, x;int i, n;...area = 0.0;for (i = 0; i < n; i++) { x += (i+0.5)/n; area += 4.0/(1.0 + x*x);}pi = area / n;
![Page 48: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/48.jpg)
¿Como se puede paralelizar el código para aproximar a ?for (i = 0; i < n; i++) { x += (i+0.5)/n; area += 4.0/(1.0 + x*x);}Si dos hilos, digamos A y B están ejecutando dos iteraciones, entonces B podria intentar a poner area al dia mientras que A está haciendo lo mismo,B podría usar el valor de area antes deque A ha terminado a poner su nuevo valor Esto se llama una “condición de carrera”
![Page 49: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/49.jpg)
La Pragma critical
• #pragma omp critical
bloque de código
garantiza que solamente un hilo ejecuta
el bloque a la vez
![Page 50: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/50.jpg)
Código correcto, pero no eficientedouble area, pi, x;int i, n;...area = 0.0;#pragma omp parallel for private(x)for (i = 0; i < n; i++) { x += (i+0.5)/n;#pragma omp critical area += 4.0/(1.0 + x*x);}pi = area / n;
![Page 51: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/51.jpg)
Ineficiente porque …
Poner area al dia a dentro de una sección crítica no es eficiente ya que
• Solamente un hilo puede ejecutar la asignación a la vez, es decir, es código secuencial.
• El tiempo para ejecutarla puede ser una parte significativa del bucle
• Por la Ley de Amdahl, esto podria limitar el speedup
![Page 52: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/52.jpg)
Reducciones
Se puede añadir una cláusula de reducción a una pragma parallel for
Hay que especificar la operación y la variable
OpenMP lleva cuenta de los resultados parciales y como combinarlos despues del bucle
![Page 53: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/53.jpg)
La Cláusula reduction
• La sintaxis es:reduction (<op> :<variable>)
• Operadores + Suma * Producto & Bitwise and | Bitwise or ^ Bitwise exclusive or && Logical and || Logical or
![Page 54: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/54.jpg)
El Código con la Cláusula reduction
double area, pi, x;int i, n;...area = 0.0;#pragma omp parallel for \ private(x) reduction(+:area)for (i = 0; i < n; i++) { x = (i + 0.5)/n; area += 4.0/(1.0 + x*x);}pi = area / n;
![Page 55: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/55.jpg)
Mejormiento en Rendimiento Invertiendo Bucles
• Muchos fork/joins puede empeorar el rendimiento
• Invertir bucles puede mejorar el rendimiento si– Hay paralelismo en el bucle interio– El bucle exterior se puede paralelizar
después de la inversión.– La inversión no disminuye la razón de
“cache hits”
![Page 56: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/56.jpg)
Mejormiento en Rendimiento Ejecutando Bucles Condicionalmente
• Si un bucle tiene pocas iteraciones, los gastos generales podría ser mayor que la economia de ejecutación paralela.
• La cláusula if instruye al compilador determinar si el bucle se debe ejecutar en paralelo.
#pragma omp parallel for if(n > 5000)
![Page 57: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/57.jpg)
Mejormiento en Rendimiento usando la cláusula schedule
• Las iteraciones de un bucles pueden variar mucho en duración.
• Se puede usar una cláusula schedule para indicar como las iteraciones se asignan a los hilos.
• Schedule estática: todas las iteraciones se asignan a los hijos antes de ejecutarla
• Schedule dinámica: solamente algunas iteraciones se asignan al prinicipio de la ejecutación de un bucle. Las otras iteraciones se asignan a hilos que terminan sus iteraciones asignadas.
![Page 58: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/58.jpg)
Estático vs. Dinámico
• Static scheduling:
• -Gastos generales menores (“low overhead”)
• Dynamic scheduling
– Podría exhibir un cargo de trabajo no balanceado
– Gastos generales mayores
– Puede reduce el imbalance de trabajo
![Page 59: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/59.jpg)
Chunks
• Un chunk es un conjunto contiguos de iteraciones que se asignan a hilos
• Aumentar el tamaño de un chunk reduce los gastos generales y podría aumentar el “cache hit rate”
• Disminuir el tamaño de chunk permite uno a obtener un balance mas preciso del trabajo
![Page 60: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/60.jpg)
La Cláusula schedule
• La sintaxis:schedule (<tipo>[,<chunk> ])
• Se requiere tipo, pero el tamaño del chunk es opcional
• El tipo puede ser– static– dynamic– guided– runtime
![Page 61: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/61.jpg)
Opciones para schedule
• schedule(static): asignar bloques de aproximadamente n/t iteraciones contiguas a cada hilo
• schedule(static,C): asignar chunks de tamaño C
• schedule(dynamic): asignar dinámcamente iteracones una por una.
• schedule(dynamic,C): asignar dinámcamente C iteraciones a la vez
![Page 62: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/62.jpg)
Opciones para schedule (cont)
• schedule(guided, C): asignar chunks dinámicamente. Los tamaños de los chunks decrecen dependiendo de la implementación.
C es el tamaño mínimo.• schedule(guided): Lo mismo excepto 1 es el
tamaño mínimo.• schedule(runtime): el tipo de schedule se
escoge al tiempo de ejecutación basado en el
valor de la variable omp_schedule.
![Page 63: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/63.jpg)
Para compilar y ejecutar
• Compilar: cc –openmp –o pi pi.c• Ejecutar: Hay que especificar el número
de hilos con osetenv OMP_NUM_THREADS = número de
hilosafuera del programa o con
omp_set_num_threads( número de hilos)a dentro del programa
![Page 64: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/64.jpg)
Otro uso del la Pragma parallelEjemplo: ¿Como se puede optimizarlo siguiente?for (i = 0; i < m; i++) { low = a[i]; high = b[i]; if (low > high) { printf ("Exiting (%d)\n", i); break; }for (j = low; j < high; j++) c[j] = (c[j] - a[i])/b[i];}No se puede paralelizar el bucle exterionpues contiene break.
![Page 65: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/65.jpg)
Primer Intento#pragma omp parallel private(i,j)for (i = 0; i < m; i++) { low = a[i]; high = b[i]; if (low > high) { printf ("Exiting (%d)\n", i); break; }for (j = low; j < high; j++) c[j] = (c[j] - a[i])/b[i];}Ahora, cada hilo va a ejectar todas las iteraciones del bucle interior. Nos gustaria que los hilos los compartan.
![Page 66: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/66.jpg)
Segundo Intento#pragma omp parallel private(i,j)for (i = 0; i < m; i++) { low = a[i]; high = b[i]; if (low > high) { printf ("Exiting (%d)\n", i); break; }#pragma omp forfor (j = low; j < high; j++) c[j] = (c[j] - a[i])/b[i];}
![Page 67: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/67.jpg)
La pragma for
• #pragma omp for
<bucle for>
dentro de una región paralela dice al compilador particionar las iteraciones entre los hilos
![Page 68: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/68.jpg)
Segundo IntentoAhora hay, solamente un problema: Cada hilo va a escribir un mensaje “Exiting..” #pragma omp parallel private(i,j)for (i = 0; i < m; i++) { low = a[i]; high = b[i]; if (low > high) { printf ("Exiting (%d)\n", i); break; }#pragma omp forfor (j = low; j < high; j++) c[j] = (c[j] - a[i])/b[i];}
![Page 69: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/69.jpg)
Tercer Intento#pragma omp parallel private(i,j)for (i = 0; i < m; i++) { low = a[i]; high = b[i]; if (low > high) {#prama omp single printf ("Exiting (%d)\n", i); break; }#pragma omp forfor (j = low; j < high; j++) c[j] = (c[j] - a[i])/b[i];}
![Page 70: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/70.jpg)
La Pragma single
• #pragma omp single
<bloque de código>
dice al compilar que solamente un solo hilo deberia ejecutar el bloque que sigue.
![Page 71: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/71.jpg)
Cuarto IntentoFinalmente se puede remover la barrera al finalizar del segundo bucle#pragma omp parallel private(i,j,low,high)for (i = 0; i < m; i++) { low = a[i]; high = b[i]; if (low > high) {#prama omp single printf ("Exiting (%d)\n", i); break; }#pragma omp for nowaitfor (j = low; j < high; j++) c[j] = (c[j] - a[i])/b[i];}
![Page 72: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/72.jpg)
La cláusula nowait
• Cuando se añade a un bucle for paralelo, elimina la barrera al finalizar de un bucle.
![Page 73: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/73.jpg)
Dos Tipos de Paralelismo de Data
• La paralelización del bucles for
• Ejemplos: El computo de π, el algoritmo de Floyd
• Paralelismo de data mas general – la creación de una región paralela mediante la pragma omp parallel
• Ejemplos: hello, satisfacer un circuito
![Page 74: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/74.jpg)
Paralelismo Funcional
• Hasta ahora hemos considerado paralelismo de data nada mas
• OpenMP nos permite asignar hilos distintos a partes distintas del código (paralelismo funcional)
![Page 75: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/75.jpg)
Ejemplo de Paralelismo Funcional
v = alpha(); w = beta(); x = gamma(v, w); y = delta(); printf ("%6.2f\n", epsilon(x,y));
a lp h a b e ta
g am m a d elta
ep s ilo n
Se puede ejecutaralpha, beta, and deltaen paralelo.
![Page 76: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/76.jpg)
La pragma parallel sections
• Precede un bloque de k bloques de código que se puede ejecutar en paralelo por k hilos
• La sintaxis:
#pragma omp parallel sections
![Page 77: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/77.jpg)
La pragma section
• Precede cada bloque de código dentro del bloque grande
• Se puede omitir para el primer bloque después de la pragma parallel sections
• La sintaxis:
#pragma omp section
![Page 78: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/78.jpg)
Ejemplo de parallel sections
#pragma omp parallel sections {#pragma omp section /* Optional */ v = alpha();#pragma omp section w = beta();#pragma omp section y = delta(); } x = gamma(v, w); printf ("%6.2f\n", epsilon(x,y));
![Page 79: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/79.jpg)
Otra Posibilidad
a lp h a b e ta
g am m a d elta
ep s ilo n
Ejecutar alpha ybeta en paralelo.Ejecutar gama ydelta en paralelo.
![Page 80: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/80.jpg)
La pragma sections
• Aparece a dentro de un bloque paralelo de código
• Tiene el mismo significado como la pragma parallel sections
• Varias pragmas sections dentro de un bloque paralelo podría reducir los gastos de fork/join
![Page 81: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/81.jpg)
Uso de la pragma sections
#pragma omp parallel { #pragma omp sections { #pragma omp section v = alpha(); #pragma omp section w = beta(); } #pragma omp sections { #pragma omp section x = gamma(v, w); #pragma omp section y = delta(); } } printf ("%6.2f\n", epsilon(x,y));
![Page 82: Programación de Memoria Compartida](https://reader036.vdocuments.pub/reader036/viewer/2022081503/56813b77550346895da48b1a/html5/thumbnails/82.jpg)
Como medir tiempos en openMP
• Ejemplo: double empezar,terminar; empezar=omp_get_wtime( ); … algun código terminar=omp_get_wtime(); printf(“TIEMPO=%lf\n”,empezar-terminar)
El resultado es en segundos.