proPar Curso 14/15
1 Computadores Paralelos
2 Programación basada en paso de mensajes
3 Técnicas básicas de programación paralela
Compulsiva, Divide y Vencerás, Pipeline,
Síncrona, Equilibrado de carga y Terminación
4 Programación basada en memoria común
5 Algoritmos y aplicaciones
Ordenación, …
4
4
2, 3, 2
2, 2
5
4
Procesamiento Paralelo Temario pasoMsj-2
2 PROGRAMACIÓN BASADA EN PASO DE MENSAJES
1 Recordar concurrencia pthreads: contar y ordenar
2 Un modelo de paso de mensajes• Opciones de programación• Creación de procesos• Rutinas genéricas de paso de mensajes
3 MPI• Introducción• Procesos• Envío y recepción de mensajes• Comunicación colectiva
4 Evaluación de programas paralelos
5 Herramientas de depuración y monitorización
proPar Recordar concurrencia pthreads pasoMsj-3
• contarPar.c: Número de apariciones de un número en un vector
6 2 0 7 4 9 3 4 9 8 0 6 7 9 6 0 6 7 9 8 6 2 5 2 6 4 7 9 3 5 2 1 7 3 2 6 6 4 4 0
const N = 40; objetivo = 6; numCPUs = 4;var vector array[1..N] of integer;
¿ Algoritmo paralelo ?
T1 T2 T3 T4
1 3 2 2
+8
proPar Recordar concurrencia pthreads pasoMsj-4int longRodaja, numVecesLocal[MAX_ESCLAVOS], *vector;
void *esclavo (void *parametro) { ..... }
int main (int argc, char *argv[]) { int i, numVeces, cardinalidad = atoi (argv[1]); int numEsclavos = atoi (argv[2]); pthread_t pids[MAX_ESCLAVOS];
// Pedir memoria e inicializar vector
// Crear esclavos y esperar a que terminen su trabajo for (i = 0; i < numEsclavos; i++) pthread_create (&pids[i], NULL, esclavo, (void *) i); for (i = 0; i < numEsclavos; i++) pthread_join (pids[i], NULL);
// Sumar los valores de todos e informar del resultado numVeces = numVecesLocal[0]; for (i = 1; i < numEsclavos; i++) numVeces = numVeces + numVecesLocal[i]; printf (“Veces que aparece = %d\n”, numVeces);}
%cuentaPar 1000000 4
proPar Recordar concurrencia pthreads pasoMsj-5
// Variables globalesint longRodaja, numVecesLocal[MAX_ESCLAVOS], *vector;
void *esclavo (void *parametro) { int yo, inicio, fin, i, j, numVeces;
yo = (int) parametro; inicio = yo * longRodaja; fin = inicio + longRodaja;
// Buscar en mi parte del vector numVeces = 0; for (i = inicio, i < fin; i++) if (vector[i] == NUM_BUSCADO) numVeces++; numVecesLocal[yo] = numVeces; pthread_exit (NULL);}
proPar Recordar concurrencia pthreads pasoMsj-6
5 1,286 4,26 0,85
6 1,127 4,86 0,81
7 1,113 4,92 0,70
8 0,998 5,49 0,69
Esclavos Tiempo Aceleración Eficiencia
1 5,480
2 2,721 2,01 1,01
4 1,408 3,89 0,97
cuentaPar 400.000.000 1..8 // Recorriéndolo diez veces
2 Xeon E5520 Quad2,26GHz • 8ML3 • 12GB • 500GB
proPar Recordar concurrencia pthreads pasoMsj-7
• sortPar.c: Ordenar un vector en memoria
3 8 15 2 4 1 7 10 6 14 13 5 11 9 12 16
T1 T2 T3 T4
2 3 8 15 1 4 7 10 5 6 13 14 9 11 12 16
ordenar
1 2 3 4 7 8 10 15 5 6 9 11 12 13 14 16
T1 T3mezclar
T1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
mezclar
proPar Recordar concurrencia pthreads pasoMsj-8
• sortPar.c: Ordenar un vector en memoria [Refinamiento]
A B C D
E F
G
1 2 3 4
1 3
1
esclavo (yo: integer);
ordenarRodaja(yo); case yo of 1: mezclar(A,B,E); mezclar(E,F,G); 2: ; 3: mezclar(C,D,F); 4: ; end;
?
1. La mezcla es destructiva => vector auxiliar
Va
Va
Vb
Va
2 Mezclar requiere haber ordenado … => semáforos
proPar Recordar concurrencia pthreads pasoMsj-9#define MAX_ENTERO 10000#define MAX_ESCLAVOS 4 // Solo funciona con 4 esclavos
//-------------- VARIABLES GLOBALES ------------------------------- int cardinalidad, longRodaja; int *vector, *vectorBis; sem_t S2a1, S4a3, S3a1;
void imprimir (int *vector) { int i;
printf ("Contenido del vector\n"); printf ("====================\n"); for (i=0; i<cardinalidad; i++) { printf ("%6d ", vector[i]); if ((i%10) == 0) printf ("\n"); } printf ("\n");}
void mezclar (int i, int longRodaja, int *vOrg, int *vDst) { int iDst, iTope, j, jTope;
iTope = i + longRodaja; j = iTope; jTope = j + longRodaja; for (iDst = i; iDst < jTope; iDst++) { if (i == iTope ) vDst[iDst] = vOrg[j++]; else if (j == jTope ) vDst[iDst] = vOrg[i++]; else if (vOrg[i] < vOrg[j]) vDst[iDst] = vOrg[i++]; else vDst[iDst] = vOrg[j++]; }}
proPar Recordar concurrencia pthreads pasoMsj-10void *esclavo(void *parametro) { int yo, inicio, fin, i, j, imenor, menor; int unCuarto, unMedio;
yo = (int) parametro; inicio = yo * longRodaja; fin = inicio + longRodaja; unMedio = cardinalidad / 2; unCuarto = cardinalidad / 4;
// Ordenar por insercion directa for (i = inicio; i < fin; i++) { imenor = i; menor = vector[i]; for (j = i; j < fin; j++) if (vector[j] < menor) { imenor = j; menor = vector[j]; } vector[imenor] = vector[i]; vector[i] = menor; }
// Fase de mezclas. Solo valida para 4 esclavos switch (yo) { case 0: sem_wait (&S2a1); mezclar(0, unCuarto, vector, vectorBis); sem_wait (&S3a1); mezclar(0, unMedio, vectorBis, vector); break; case 1: sem_post (&S2a1); break; case 2: sem_wait (&S4a3); mezclar(unMedio, unCuarto, vector, vectorBis); sem_post (&S3a1); break; case 3: sem_post (&S4a3); break; default: printf ("Error\n"); break; } pthread_exit(NULL);}
proPar Recordar concurrencia pthreads pasoMsj-11int main( int argc, char *argv[] ) { int i, numEsclavos; pthread_t pids[MAX_ESCLAVOS];
cardinalidad = atoi(argv[1]); numEsclavos = MAX_ESCLAVOS; longRodaja = cardinalidad / numEsclavos;
// Pedir memoria e inicializar el vector vector = malloc(cardinalidad * sizeof(int)); vectorBis = malloc(cardinalidad * sizeof(int)); for (i=0; i<cardinalidad; i++) vector[i] = random() % MAX_ENTERO; imprimir(vector);
// Inicializar semaforos para sincronizar sem_init (&S2a1, 0, 0); sem_init (&S4a3, 0, 0); sem_init (&S3a1, 0, 0);
// Crear esclavos y esperar a que terminen su trabajo for (i=0; i<numEsclavos; i++) pthread_create (&pids[i], NULL, esclavo, (void *) i); for (i=0; i<numEsclavos; i++) pthread_join (pids[i], NULL);
imprimir(vector); return (0);}
sort 200000 => 8:350sortPar 200000 => 2:100
proPar Opciones de programación pasoMsj-12Entornos de programación paralela en los 90 “Tim Mattson - Intel”
proPar Opciones de programación pasoMsj-13
1 A Pattern Language for Parallel Programming
2 Background and Jargon of Parallel Computing
3 The Finding Concurrency Design Space
4 The Algorithm Structure Design Space
5 The Supporting Structures Design Space
6 The Implementation Mechanisms Design Space
7 A Brief Introduction to OpenMP
8 A Brief Introduction to MPI
9 A Brief Introduction to Concurrent Programming in Java
2005
proPar Opciones de programación pasoMsj-14
1. Diseño específico de un lenguaje: Occam Transputer
2. Extensión de lenguaje existente: Fortran M, CC++, Cilk++
www.netlib.org/fortran-m
www-unix.mcs.anl.gov/dbpp/text/node51.html
www.cilk.com
3. Biblioteca de paso de mensajes sobre C, Fortran, C++
PVM: www.csm.ornl.gov/pvm
MPI: www-unix.mcs.anl.gov/mpi
HPC++: www.extreme.indiana.edu/hpc++/index.html
Paralelización automática: El compilador extraeparalelismo del código secuencial
¿ Sistema Operativo ?
OpenMP
1979 Proyecto Europeo: Inmos SGS-Thomson ICL ... †
Objetivo: µP de altas prestaciones, como elemento básico paraconstruir máquinas paralelas (multicomputadores)
1992: habían vendido 500.000 unidades (µP+1MB => 180.000pts)
Característica relevante: 4 enlaces de comunicación (canales)
T8000
1
2
3
Ejecución eficiente de n procesos que envían/reciben mensajes por canales
P1
P2
P3
proPar Opciones … (TRANSPUTER) pasoMsj-15
cP3 ! dato
cP2 ? dato
proPar Creación de procesos pasoMsj-16
• ¿Cómo podría ser contarPar.c si no hay memoria común?
1 3 2 2
6 2 0 … 0 6 7 … 6 2 5 … 2 1 7 …
+8
esclavo1 esclavo2 esclavo3 esclavo4
maestro6 2 0 … 0 6 7 … 6 2 5 … 2 1 7 …
• El vector lo tiene un proceso “maestro”
• El maestro: reparte “envía” trabajo a los “esclavos” y recoge “recibe” resultados
6 2 0 … 0 6 7 … 6 2 5 … 2 1 7 …
13 2 2
2 tipos distintos de procesos
proPar Creación de procesos pasoMsj-17
• ¿Cómo podría ejecutarse la aplicación?
maestro
esclavo1 esclavo2 esclavoN
Un proceso x núcleo
M E E E
• Dos ejecutables: maestro.exe y esclavo.exe
maestro.c esclavo.c
maestro.exe esclavo.exe
Multiple Program Multiple Data
MPMD
maestro.exe esclavo.exe
• Creación de procesos: estática vs dinámica
¿Arquitecturas distintas?
proPar Creación de procesos (creación dinámica) pasoMsj-18
• MPMD: Multiple Program Multiple Data
---------------------------spawn (“esclavo”, 4, ...)---------------------------
maestro.c
---------------------------contarEnTrozo (......)---------------------------
esclavo.c
maestro esclavo
%pvmpvm>add PC2 .....pvm>spawn maestro
M E E
proPar Creación de procesos (creación estática) pasoMsj-19
• SPMD: Single Program Multiple Data
programafuente
*.exe *.exe *.exe
M E
%mpirun –np 9 sort
%mpirun –p4pg fiConf sort
---------------------------if (miIdProceso == 0) maestro()else esclavo()---------------------------
sort.c
0 1 8
proPar Creación de procesos pasoMsj-20
• A veces, viene bien que el maestro también trabaje
esclavo1 esclavo2 esclavo3
maestro06 2 0 … 0 6 7 … 6 2 5 … 2 1 7 …
0 6 7 … 6 2 5 … 2 1 7 …
1
3 2 2
• Modelo SPMD y creación de procesos estática
proPar Rutinas genéricas de paso de mensajes pasoMsj-21
• Pi.enviar(Pj, &msj, ...) Pj.recibir(Pi, &msj, ...)
---------------------------enviar (esclavo, &rodaja[k], ...)---------------------------
sortM---------------------------recibir (maestro, &miRodaja, ...)---------------------------
sortE
• Máquina• PID_Local
Varias semánticas:
• Bloqueante (Síncrona | Rendezvous)
• No bloqueante (Asíncrona: Capacidad de almacenar)
• Temporizada (Tiempo máximo de bloqueo)
enviar( Pi, &msj, temporización, )
∞0
t
proPar Rutinas genéricas de paso de mensajes pasoMsj-22
• Bloqueante vs NoBloqueante
--------------------enviar...--------------------
--------------------recibir...--------------------
El primero se bloquea
Transferencia sin buffers adicionales
Se sabe que se ha recibido
--------------------enviar...--------------------
--------------------recibir...--------------------
Buffer
Se desacopla env | rec
Gestión de buffers
¿ Dónde ?
¿Se ha recibido? => msjACK
enviar( Pi, &msj, temporización, ...)
proPar Rutinas genéricas de paso de mensajes pasoMsj-23
• recibirDeCualquiera (&msj) | recibir ( -1, &msj)
sortE1 sortEn
sortM---------------------------quien = recibir (-1, &rodaja[k], ...)---------------------------
sortM
• Mensajes etiquetados
PPPPPPPH
enviar (S, &msj, tipoP)
enviar (S, &msj, tipoH)
recibir (-1, &msj, tipoH)
recibir (-1, &msj, -1 )
Cliente Servidor
Cliente
Cliente
proPar Paso de mensajes entre “grupos” pasoMsj-24
• Broadcast (a todos) Multicast (a unos concretos)
---------------------------Para todo esclavo enviar (esclavo, &palabra, ...)---------------------------
cuentaM
Problema: Número de ocurrencias de (un dato)* en array grande
cuentaM
cuentaE1 cuentaEncuentaE2
“Ala”“Ala”
“Ala”
---------------------------bcast (esclavos, &palabra, ...)---------------------------
cuentaM¿Más eficiente?
sortM
sortE1 sortEn
VsortM
sortE1 sortEn
V
proPar Paso de mensajes entre “grupos” pasoMsj-25
• scatter ( esparcir ) y gather ( recoger ) Ej: Ordenación
scatter (V, rodaja, grupo, emisor, )
sortM y sortE
gather (V, rodaja, grupo, receptor, )
sortM y sortE
cuentaM
cuentaE12
3
cuentaE25
cuentaEn1
proPar Paso de mensajes entre “grupos” pasoMsj-26
• reduce (recibir de unos concretos y operar) Ej: Ocurrencias
Total = veces;Para todo esclavo recibir (esclavo, &veces, ...) Total += veces;
cuentaM
reduce (+, &veces, grupo, receptor, ...)
cuentaM y cuentaE
+
máximo, mínimo, *, .....
proPar MPI (Introducción) pasoMsj-27
MPI: Message Passing Interface – 1994 MPI Forum [Nov/92]
“Ejecución de aplicaciones paralelas distribuidas en ordenadores heterogéneos”
maestro
esclavo1 esclavo3esclavo2 esclavo4
Cada uno con su dirIP
• Biblioteca “mpi.h”
MPI_Send,
MPI_Recv,
-------------
M E1 E2 E3 E4
• Implementación
MPICH
LAM/MPI
IBM, …
MPI-2
MPI-3
>= 0 => MPI_SUCCESS, significado concreto
< 0 => un error ( ... MPI_ERR_ARG ...)
proPar MPI (Procesos) pasoMsj-28
int MPI_Comm_size(…, int *numProcesos);
int MPI_Comm_rank(…, int *yo);
int MPI_Finalize();
int MPI_Init( ....... ); /* Inicia MPI */
• Creación estática de procesos (según implementación “mpirun”)
01
3
2
4
MPI_COMM_WORLD
2
5
2
proPar MPI (Procesos) pasoMsj-29
• helloWorld paralelo#include “mpi.h”int main (int argc, char *argv[]) { int yo, numProcesos;
MPI_Init (&argc, &argv); MPI_Comm_size (MPI_COMM_WORLD, &numProcesos); MPI_Comm_rank (MPI_COMM_WORLD, &yo); if (yo == 0) printf (“Creados %d procesos\n”, numProcesos); printf (“Hola, soy el proceso %d\n”, yo); MPI_Finalize();}
% mpirun –np 3 helloWorld
% mpirun –p4pg helloWorld.txt helloWorld
pc1 2 /usuarios/alumnosPropar/propar01/p1/helloWorldpc2 2 /usuarios/alumnosPropar/propar01/p1/helloWorldpc3 1 /usuarios/alumnosPropar/propar01/p1/holaMundo
proPar MPI (Envío y Recepción Simple) pasoMsj-30
• Enviar y recibir arrays de datos simples (int, byte, ...) Bloqueante
int vector[N];----------MPI_Send (vector, … P2, ...)----------
P1
int tabla[M];----------MPI_Recv (tabla, … P1, ...)----------
P2
int MPI_Send(void *buffer, int cuantos, MPI_Datatype tipo,
int destino, int etiqueta, MPI_Comm grupo)
MPI_INT,MPI_FLOAT, …
MPI_COMM_WORLD
0..MPI_TAG_UB
proPar MPI (Envío y Recepción Simple) pasoMsj-31
• Enviar y recibir arrays de datos simples (int, byte, ...) Bloqueante
int MPI_Recv(void *buffer, int cuantos, MPI_Datatype tipo,
int remitente,int etiqueta,MPI_Comm grupo,
MPI_Status *estado)
estado.MPI_SOURCEestado.MPI_TAG
MPI_ANY_SOURCE
MPI_ANY_TAG
int MPI_Get_count( MPI_Status *estado, MPI_Datatype tipo,
int *cuantos)
proPar MPI (Envío y Recepción Simple) pasoMsj-32
• Ejemplo de uso: psendrec.c
#include <stdio.h>#include <unistd.h>
#include “mpi.h"
#define N 3#define VECES 5
void esclavo(void) {...}void maestro(void) {...}
int main( int argc, char *argv[] ) { int yo; MPI_Init (&argc, &argv); MPI_Comm_rank (MPI_COMM_WORLD, &yo); if (yo == 0) maestro(); else esclavo(); MPI_Finalize(); return 0;}
proPar MPI (Envío y Recepción Simple) pasoMsj-33
• Ejemplo de uso: psendrec.c
void maestro (void) {
int i, j, vector[N];
for (i=0; i<VECES; i++) { printf ("M: envia => "); for (j=0; j<N; j++) { vector[j] = i*N+j; printf("%d ", vector[j]); } printf ("\n"); MPI_Send (vector, N, MPI_INT, 1, 1, MPI_COMM_WORLD); }}
esclavo
proPar MPI (Envío y Recepción Simple) pasoMsj-34
• Ejemplo de uso: psendrec.c
void esclavo(void) {
int i, j,tabla[N], n; MPI_Status estado;
sleep(2); for (i=0; i<VECES; i++) { MPI_Recv (tabla, N, MPI_INT, 0, 1, MPI_COMM_WORLD, &estado); MPI_Get_count (&estado, MPI_INT, &n); printf ("E: recibe => "); for (j=0; j<N; j++) printf("%d ", tabla[j]); printf (" de tid = %d eti = %d longi = %d\n", estado.MPI_SOURCE, estado.MPI_TAG, n); }}
maestro
proPar MPI (Envío y Recepción No Tan Simple) pasoMsj-35
int MPI_Iprobe(int origen, int etiqueta, MPI_Comm grupo, int *hayMsj, MPI_Status *estado)
• Enviar y recibir arrays de datos simples No Bloqueante
• Enviar y recibir datos no homogéneos
Crear tipos => Algo tedioso
Hacer otras cosas
NO
int MPI_Recv(void *buffer,… MPI_Status *estado)
SI
proPar MPI (Comunicación colectiva) pasoMsj-36
int MPI_Bcast(void *buffer, int cuantos,
MPI_Datatype tipo, int emisor,
MPI_Comm grupo)
cuenta.0
cuenta.1 cuenta.Ncuenta.2
“Ala”“Ala”
“Ala”
void maestro () { void esclavo () { char palabra[4]; char texto[4]; ---------- ---------- MPI_Bcast ( MPI_Bcast ( palabra, 4, MPI_CHAR, texto, 4, MPI_CHAR, 0, MPI_COMM_WORLD); 0, MPI_COMM_WORLD); ---------- ----------
?tag
Send+Recv
proPar MPI (Comunicación colectiva) pasoMsj-37
int MPI_Scatter(
void *vOrg, int nOrg, MPI_Datatype tOrg,
void *vDst, int nDst, MPI_Datatype tDst,
int emisor, MPI_Comm grupo);
grupoE.1 grupoE.9
grupoM.0
int MPI_Reduce(void *vOrg, void *vDst, int nOrg,
MPI_Datatype tDatoOrg, int operacion,
int receptor, MPI_Comm grupo);
+
MPI_SUM, MPI_PROD, MPI_MIN, MPI_MAX, ....
sendCount
proPar MPI (Comunicación colectiva: Ejemplo) pasoMsj-38
• Ejemplo de uso completo: cuentaPar2.c (modelo SPMD)
#include <stdio.h>
#include “mpi.h"
#define CARDINALIDAD 2000000#define MAX_ENTERO 1000#define NUM_BUSCADO 5
int main( int argc, char *argv[] ) {
int i, numVeces, numVecesTotal, yo; int longRodaja, numProcesos; int *vector;
MPI_Init (&argc, &argv); MPI_Comm_size (MPI_COMM_WORLD, &numProcesos); MPI_Comm_rank (MPI_COMM_WORLD, &yo); --------------------------- MPI_Finalize();}
proPar MPI (Comunicación colectiva: Ejemplo) pasoMsj-39
• Ejemplo de uso completo: cuentaPar2.c
// Pedir memoria vector e inicializarlo si maestrolongRodaja = CARDINALIDAD / numProcesos;if (yo == 0) { vector = malloc (CARDINALIDAD * 4); for (i=0; i<CARDINALIDAD; i++) vector[i] = random() % MAX_ENTERO;} else vector = malloc (longRodaja * 4);
MPI_Scatter (vector, longRodaja, MPI_INT, vector, longRodaja, MPI_INT, 0, MPI_COMM_WORLD);// Todos buscan en su trozonumVeces = 0;for (i=0; i<longRodaja; i++) if (vector[i] == NUM_BUSCADO) numVeces++;MPI_Reduce (&numVeces, &numVecesTotal, 1, MPI_INT, MPI_SUM, 0 , MPI_COMM_WORLD);if (yo == 0) printf (“Numero de veces => %d\n”, numVecesTotal);
proPar MPI (Comunicación colectiva) pasoMsj-40
• Otras llamadas interesantes:
int MPI_Gather(void *vOrg, int nOrg, MPI_Datatype tOrg,
void *vDst, int nDst, MPI_Datatype tDst,
int receptor, MPI_Comm grupo);
int MPI_Barrier(MPI_Comm grupo);
----------MPI_Comm_size (MPI_COMM_WORLD, &numProcesos);----------// Computar todos paso 1
MPI_Barrier (MPI_COMM_WORLD);
// Computar todos paso 2
6
proPar Evaluación de programas paralelos pasoMsj-41
• ¿Cuánto tardará mi programa paralelo TP?
• Medición experimental• Estudio analítico
Codificar, Depurar, Probar, ...
Modelo imperfecto, aproximado
m
e0 e9
cuentaVeces:• V[1.000.000]• 10 esclavos
TP = TCPU + TRED
a. Enviar rodajas TRED
c. Recibir veces TRED
b. Contar veces TCPU
veces = 0;for (i=0; i<N’; i++) if (rodaja[i] == D) veces++;
N’ N
N’ * (#i * Tinst) O (N) | O (N2) | O (NlogN) | O(logN)
proPar Evaluación de programas paralelos pasoMsj-42
#m * (TL + #d * TD)#d
t
TL
TP = TCPU + TRED
N’ * (#i * Tinst)
Ejemplos
T3D+PVM
IBM PS2+MPI
iacluster+MPI 40µs
35µs
3µs
TL
64ns
230ns
63ns
TD[8B]
0,6ns
4,2ns
11ns
Tinst
66666
8333
273
TL
107
55
6
TD
1
1
1
Tinst
Normalizar
TP = TCPU + TREDSolapar tiempos | ocultar latencias
Comunicación asíncrona
#msj,
tamaño(#d),
topología red,
tecnología, ...
proPar Evaluación de programas paralelos pasoMsj-43
• Ejemplo: cuentaVeces, V[1.000.000], 10 esclavos
T1 = 1.000.000 * (#i * Tinst)
T10 = TRED(10Rodajas) + TCPU(100.000) + TRED(10Resultados)
T3D: TL(273) y TD(6)
T10 = 10*(273+100.000*6) + 100.000*#i*1 + 10*(273+6) = 6.005.520 + 100.000#i
S10 = 1.000.000*#i / (6.005.520+100.000#i)
iacluster: TL(66.666) y TD(64)
T10 = ... 66.666 ... 64 + ...*1 + ... 66.666+64 = 65.333.960 + 100.000#i
S10 = 1.000.000*#i / (65.333.960 +100.000#i)
#i S10
50 0,71
100 1,33500 4,34
#i S10
5 0,8
10 1,4500 8,9
proPar Herramientas de depuración y monitorización pasoMsj-44
• Medición de tiempos de ejecución• Depuración
• Monitorización
#include <sys/time.h>
struct timeval t0, tf, tiempo;
/* Inicialización */
gettimeofday (&t0, NULL);
/* ejecucion del programa paralelo */
gettimeofday (&tf, NULL); timersub (&tf, &t0, &tiempo); printf (“Tiempo => %ld:%ld seg:micro\n”, tiempo.tv_sec, tiempo.tv_usec);
Evitar E/S
¿Efecto del optimizador de código?
gcc –O3
proPar Herramientas de depuración y monitorización pasoMsj-45
%mpirun –dbg=ddd –np 2 psendrec
Depurar más de un proceso,
algo más complejo
printf
fflush(stdout)
setbuf(stdout, NULL)
depurar (ddd)
proPar Herramientas de depuración y monitorización pasoMsj-47
• Monitorización (totalview) para MPI, openMP, … www.etnus.com
www.roguewave.com
Top Related