Transcript Rendimiento

Rendimiento
Aplicado a programas openMP
Speedup
• Speedup = ts /tp donde ts es el tiempo
que se requiere para ejecutar el
programa secuencialmente y tp es el
tiempo que se requiere para ejecutar el
programa en paralelo
• El autor del texto denota speedup por
ψ(n,p) donde n es el tamaño del
problema y p es el número de procesos
Speedup (cont)
– ψ(n,p)≤p
– ψ(n,p)=p si el problema se particiona
perfectamente en p procesos iguales
y no hay ningun “overhead” debido
a, por ejemplo, comunicaciones,
coordenació de procesos, el costo de
particionar, etc.
omp_get_wtime
Esta función devuelve un valor en punto flotante
doble igual al tiempo que ha transcurrido desde
algun tiempo en el pasado.
Se puede medir el tiempo que tarda un como
sigue:
empezar = omp_get_wtime;
// aqui va el código cuyo tiempo de ejecutación se desea medir
final = omp_get_wtime;
tiempo = final – empezar;
Medir el tiempo para aproximar π
// Entramos el numero de hilos desde la linea de comando
#include <omp.h>
#include <stdio.h>
#include<time.h>
#include<sys/time.h>
int main (int argc, char *argv[]) {
double area,x,start,end;
int i,n;
area = 0.0;
printf("n=");
scanf("%d",&n);
Medir tiempo de aproximar π
(cont)
omp_set_num_threads(atoi(argv[1]));
start=omp_get_wtime;
#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);
}
end=omp_get_wtime;
printf(“tiempo=%lf\n”,end-start);
printf("pi = %lf\n", area/n);
return 0;
}
Algunos trucos para mejorar
rendimiento
• Invertir bucles
• Ejecutar bucles condicionalmente
• Usar la cláusula schedule
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”
Ejemplo 1
for (j=2;j<n;j++)
for (i=1;i<n;i++)
a[i][j] = a[i][j]+a[i][j-1]];
Lo mejor es paralelizar el bucle exterior,
pero en este caso hay dependencias.l
Ejemplo 1 (cont)
Se puede invertir los bucles:
#omp parallel for
for (i=1;i<n;i++)
for (j=2; j<n;j++)
a[i][j] = a[i][j]+a[i][j-1]];
Aqui hemos reducido los gastos de
paralelizar, pero el nuevo bulce podria
utilizar peor el cache.
Ejemplo 2
Intercambiando los bulces en
for (i=2;i<=m;i++)
for (j=1;j<=n;j++)
a[i][j] = 2*a[i][j];
tenemos
#pragma parallel for private(i)
for(j=1;j<=n;j++)
for(i=2;i<=m;i++)
a[i][j] = 2*a[i][j];
(columnas se pueden poner al dia simultaneamente – no
filas)
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)
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.
Ejemplo
for (i=0;i<n;i++)
for (j=i;j<n;j++)
a[i][j] = alpha_omega(i,j);
Si toda iteraciión requiere el mismo tiempo,
entonces el tiempo que requiere la
primera iteración es n veces del tiempo
que requiere la ultima iteraciión.
Estático vs. Dinámico
• Schedule estática: todas las iteraciones
se asignan a los hilos 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.
Estático vs. Dinámico (cont)
• Static scheduling:
• -Gastos generales menores (“low
overhead”)
• Dynamic scheduling
– Gastos generales mayores
– Puede reduce el imbalance de trabajo
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
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
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ámicamente iteraciones una por una.
• schedule(dynamic,C): asignar
dinámicamente C iteraciones a la vez
Opciones para schedule (cont)
• schedule(guided, C): asignar chunks
dinámicamente. Los tamaños de los chunks
disminuyen 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.
El ejemplo anterior con schedule
#pragma omp parallel for private(j) schedule(static,1)
for (i=0;i<n;i++)
for (j=i;j<n;j++)
a[i][j] = alpha_omega(i,j)
Se podria aumentar el tamaño de chunk para mejorar la
razón de “cache hits”, al costo de aumentar el imbalance
de trabajo de los hilos.
Mas sobre speedup
Los componentes de tiempo de ejecutación:
- Computaciones que tienen que hacer
secuencialmente: (n)
- Computaciones que se pueden llevar a
cabo en paralelo: (n)
- Operaciones de comunicaciones: (n,p)
Expresión para Speedup
• ts = (n) + (n)
• tp = (n) + (n)/p + (n,p)
• Por lo tanto,
ψ(n,p) ≤ ((n) + (n))/((n) + (n)/p + (n,p))
(n)/p
• Aumentar el número
de procesadores
reduce el tiempo
computacional
(n)/p
(n,p)
• El tiempo de
comunicaciones
crece con la cantidad
de procesadores
(n,p)
(n)/p + (n,p)
• En algun momento el
tiempo de
comunicaciones será
mayor que el tiempo
computacional
(n)/p + (n,p)
Speedup
Eficiencia
• Eficiencia = tS / (p*tp) donde p es el número
de procesadores
• Ya que tp ≤ tS / p, tenemos que
0 ≤ Eficiencia ≤ 1
• El autor denota eficiencia por (n,p)
• Notemos que (n,p)=ψ(n,p)/p
La Ley de Amdahl
ψ(n,p) ≤ ((n) + (n))/((n) + (n)/p + (n,p))
≤ ((n) + (n))/((n) + (n)/p )
La Ley de Amdahl: Si f es la porción de la
computación que es inherentemente
secuencial, es decir que f=(n)/((n) + (n)),
entonces
ψ ≤ 1/(f+(1-f)/p)
Notemos que ψ ≤ 1/f
Ejemplo 1
• Hay un programa secuencial que pasa
90% de su tiempo dentro de funciones
que se pueden paralelizar. Hay que hacer
el otro 10% en un solo procesador. ¿Vale
la pena implantar una versión paralela si
hay 8 procesadores disponibles?
• ψ ≤ 1/(f+(1-f)/p)=1/(.1 + (1-.1)/8) = 4.7
• El máximo speedup posible es
lim p →∞ 1/(.1 + (1-.1)/p) = 10
Pop Quiz
• A computer animation program generates
a feature movie frame-by-frame. Each
frame can be generated independently
and is output to its own file. If it takes 99
seconds to render a frame and 1 second
to output it, how much speedup can be
achieved by rendering the movie on 100
processors?