480 likes | 642 Views
proPar Curso 14/15. 4. 4. 2, 3, 2. 2, 2. 5. 4. Computadores Paralelos Programación basada en paso de mensajes Técnicas básicas de programación paralela Compulsiva, Divide y Vencerás, Pipeline, Síncrona, Equilibrado de carga y Terminación Programación basada en memoria común
E N D
proPar Curso 14/15 4 4 2, 3, 2 2, 2 5 4 • Computadores Paralelos • Programación basada en paso de mensajes • Técnicas básicas de programación paralela Compulsiva, Divide y Vencerás, Pipeline, Síncrona, Equilibrado de carga y Terminación • Programación basada en memoria común • Algoritmos y aplicaciones Ordenación, …
Procesamiento Paralelo Temario pasoMsj-2 • PROGRAMACIÓN BASADA EN PASO DE MENSAJES • Recordar concurrencia pthreads: contary ordenar • Un modelo de paso de mensajes • Opciones de programación • Creación de procesos • Rutinas genéricas de paso de mensajes • MPI • Introducción • Procesos • Envío y recepción de mensajes • Comunicación colectiva • Evaluación de programas paralelos • 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 66 4 4 0 T1 T2 T3 T4 1 3 2 2 + 8 const N = 40; objetivo = 6; numCPUs = 4; var vector array[1..N] of integer; ¿ Algoritmo paralelo ?
proPar Recordar concurrencia pthreads pasoMsj-4 int longRodaja, numVecesLocal[MAX_ESCLAVOS], *vector; void *esclavo (void *parametro) { ..... } intmain (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 globales int 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 cuentaPar 400.000.000 1..8 // Recorriéndolo diez veces 5 2 1 6 4 Esclavos 7 8 2,721 1,127 1,113 1,286 0,998 Tiempo 5,480 1,408 2,01 Aceleración 4,86 4,26 5,49 4,92 3,89 1,01 0,97 0,69 Eficiencia 0,70 0,81 0,85 2 Xeon E5520 Quad 2,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 ordenar T4 T1 T2 T3 T1 T3 T1 2 3 8 15 1 4 7 10 5 6 13 14 9 11 12 16 mezclar 1 2 3 4 7 8 10 15 5 6 9 11 12 13 14 16 mezclar 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
proPar Recordar concurrencia pthreads pasoMsj-8 • sortPar.c:Ordenar un vector en memoria [Refinamiento] Va ? 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 2 3 4 Va A B C D 1 3 Vb E F 1 Va G La mezcla es destructiva => vector auxiliar • 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 ------------------------------- intcardinalidad, longRodaja; int *vector, *vectorBis; sem_t S2a1, S4a3, S3a1; void imprimir (int *vector) { int i; printf("Contenidodelvector\n"); printf ("====================\n"); for (i=0; i<cardinalidad; i++) { printf ("%6d ", vector[i]); if ((i%10) == 0) printf ("\n"); } printf ("\n"); } voidmezclar (int i, intlongRodaja, int *vOrg, int *vDst) { intiDst, iTope, j, jTope; iTope = i + longRodaja; j = iTope; jTope = j + longRodaja; for (iDst = i; iDst < jTope; iDst++) { if (i == iTope ) vDst[iDst] = vOrg[j++]; elseif(j == jTope ) vDst[iDst] = vOrg[i++]; elseif(vOrg[i] < vOrg[j]) vDst[iDst] = vOrg[i++]; elsevDst[iDst] = vOrg[j++]; } }
proPar Recordar concurrencia pthreads pasoMsj-10 void *esclavo(void *parametro) { intyo, inicio, fin, i, j, imenor, menor; intunCuarto, unMedio; yo = (int) parametro; inicio = yo * longRodaja; fin = inicio + longRodaja; unMedio = cardinalidad / 2; unCuarto = cardinalidad / 4; // Ordenar por inserciondirecta 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-11 intmain( intargc, char *argv[] ) { int i, numEsclavos; pthread_tpids[MAX_ESCLAVOS]; cardinalidad = atoi(argv[1]); numEsclavos = MAX_ESCLAVOS; longRodaja = cardinalidad / numEsclavos; // Pedir memoria e inicializar elvector 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); // Crearesclavos y esperar a que terminensutrabajo 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:350 sortPar 200000 => 2:100
proPar Opciones de programación pasoMsj-12 Entornos de programación paralela en los 90 “Tim Mattson - Intel”
proPar Opciones de programación pasoMsj-13 2005 1 A PatternLanguageforParallelProgramming 2Background and Jargon of Parallel Computing 3TheFindingConcurrencyDesignSpace 4TheAlgorithmStructureDesignSpace 5TheSupportingStructuresDesignSpace 6TheImplementationMechanismsDesignSpace 7 A BriefIntroductiontoOpenMP 8 A BriefIntroductiontoMPI 9 A BriefIntroductiontoConcurrentProgramming in Java
proPar Opciones de programación pasoMsj-14 • Diseño específico de un lenguaje: Occam Transputer • 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 OpenMP • 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 extrae paralelismo del código secuencial ¿ Sistema Operativo ?
proPar Opciones … (TRANSPUTER) pasoMsj-15 1979 Proyecto Europeo: Inmos SGS-Thomson ICL ... † Objetivo: µP de altas prestaciones, como elemento básico para construir máquinas paralelas (multicomputadores) 1992: habían vendido 500.000 unidades (µP+1MB => 180.000pts) Característica relevante: 4 enlaces de comunicación (canales) 1 0 T800 2 P1 P2 P3 3 Ejecución eficiente de n procesos que envían/reciben mensajes por canales cP3 ! dato cP2 ? dato
proPar Creación de procesos pasoMsj-16 • ¿Cómo podría ser contarPar.c si no hay memoria común? maestro 6 2 0 … 0 6 7 … 6 2 5 … 2 1 7 … 6 2 0 … 0 6 7 … 6 2 5 … 2 1 7 … 1 3 2 2 + 1 3 2 2 8 esclavo1 esclavo2 esclavo3 esclavo4 6 2 0 … 0 6 7 … 6 2 5 … 2 1 7 … 2 tipos distintos de procesos • El vector lo tiene un proceso “maestro” • El maestro: reparte “envía” trabajo a los “esclavos” y • recoge “recibe” resultados
proPar Creación de procesos pasoMsj-17 maestro esclavo1 esclavo2 esclavoN • ¿Cómo podría ejecutarse la aplicación? maestro.c esclavo.c maestro.exe esclavo.exe maestro.exe esclavo.exe Un proceso x núcleo M E E E ¿Arquitecturas distintas? MPMD Multiple Program Multiple Data • Dos ejecutables: maestro.exe y esclavo.exe • Creación de procesos: estática vs dinámica
proPar Creación de procesos (creación dinámica) pasoMsj-18 maestro.c esclavo.c --------------------------- spawn (“esclavo”, 4, ...) --------------------------- --------------------------- contarEnTrozo (......) --------------------------- maestro esclavo • MPMD: Multiple Program Multiple Data %pvm pvm>add PC2 ..... pvm>spawn maestro M E E
proPar Creación de procesos (creación estática) pasoMsj-19 sort.c M E --------------------------- if (miIdProceso == 0) maestro() else esclavo() --------------------------- *.exe *.exe *.exe 0 1 8 • SPMD: Single Program Multiple Data programa fuente %mpirun–np 9sort %mpirun –p4pg fiConf sort
proPar Creación de procesos pasoMsj-20 • A veces, viene bien que el maestro también trabaje maestro0 6 2 0 … 0 6 7 … 6 2 5 … 2 1 7 … 1 3 2 2 esclavo1 esclavo2 esclavo3 0 6 7 … 6 2 5 … 2 1 7 … • Modelo SPMD y creación de procesos estática
proPar Rutinas genéricas de paso de mensajes pasoMsj-21 sortM sortE --------------------------- enviar (esclavo, &rodaja[k], ...) --------------------------- --------------------------- recibir (maestro, &miRodaja, ...) --------------------------- • Máquina • PID_Local enviar( Pi, &msj, temporización, ) 0 t • Pi.enviar(Pj, &msj, ...) Pj.recibir(Pi, &msj, ...) • Varias semánticas: • Bloqueante (Síncrona | Rendezvous) • No bloqueante (Asíncrona: Capacidad de almacenar) • Temporizada (Tiempo máximo de bloqueo)
proPar Rutinas genéricas de paso de mensajes pasoMsj-22 ¿ Dónde ? ---------- ---------- enviar... ---------- ---------- ---------- ---------- recibir... ---------- ---------- ---------- ---------- enviar... ---------- ---------- ---------- ---------- recibir... ---------- ---------- Buffer El primero se bloquea Se desacopla env | rec Transferencia sin buffers adicionales Gestión de buffers Se sabe que se ha recibido ¿Se ha recibido? => msjACK • Bloqueante vs NoBloqueante enviar( Pi, &msj, temporización, ...)
proPar Rutinas genéricas de paso de mensajes pasoMsj-23 sortM sortM --------------------------- quien = recibir (-1, &rodaja[k], ...) --------------------------- sortE1 sortEn Cliente Cliente Servidor Cliente enviar (S, &msj, tipoP) enviar (S, &msj, tipoH) recibir (-1, &msj, tipoH) • recibirDeCualquiera (&msj) | recibir ( -1, &msj) • Mensajes etiquetados H P P P P P P P recibir (-1, &msj, -1 )
proPar Paso de mensajes entre “grupos” pasoMsj-24 cuentaM “Ala” “Ala” “Ala” cuentaE1 cuentaE2 cuentaEn cuentaM cuentaM --------------------------- Para todo esclavo enviar (esclavo, &palabra, ...) --------------------------- --------------------------- bcast (esclavos, &palabra, ...) --------------------------- • Broadcast (a todos) Multicast (a unos concretos) Problema: Número de ocurrencias de (un dato)* en array grande ¿Más eficiente?
proPar Paso de mensajes entre “grupos” pasoMsj-25 sortM sortM V V sortE1 sortE1 sortEn sortEn sortM y sortE sortM y sortE gather (V, rodaja, grupo, receptor, ) scatter (V, rodaja, grupo, emisor, ) • scatter ( esparcir ) y gather ( recoger ) Ej: Ordenación
proPar Paso de mensajes entre “grupos” pasoMsj-26 cuentaM 3 + cuentaE1 cuentaEn 2 1 cuentaE2 5 cuentaM cuentaM y cuentaE Total = veces; Para todo esclavo recibir (esclavo, &veces, ...) Total += veces; reduce (+, &veces, grupo, receptor, ...) máximo, mínimo, *, ..... • reduce (recibir de unos concretos y operar) Ej: Ocurrencias
proPar MPI (Introducción) pasoMsj-27 maestro esclavo1 esclavo2 esclavo3 esclavo4 M E1 E2 E3 E4 MPI: Message Passing Interface – 1994 MPI Forum [Nov/92] “Ejecución de aplicaciones paralelas distribuidas en ordenadores heterogéneos” MPI-2 • Biblioteca “mpi.h” • MPI_Send, • MPI_Recv, • ------------- • Implementación • MPICH • LAM/MPI • IBM, … Cada uno con su dirIP
proPar MPI (Procesos) pasoMsj-28 intMPI_Init( ....... ); /* Inicia MPI */ intMPI_Comm_size(…, int *numProcesos); 5 intMPI_Comm_rank(…, int *yo); 2 0 intMPI_Finalize(); 1 2 3 >= 0 => MPI_SUCCESS, significado concreto < 0 => un error ( ... MPI_ERR_ARG ...) 4 MPI_COMM_WORLD • Creación estática de procesos (según implementación “mpirun”) 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(); } pc12 /usuarios/alumnosPropar/propar01/p1/helloWorld pc22 /usuarios/alumnosPropar/propar01/p1/helloWorld pc3 1 /usuarios/alumnosPropar/propar01/p1/holaMundo % mpirun –np 3 helloWorld % mpirun –p4pg helloWorld.txt helloWorld
proPar MPI (Envío y Recepción Simple) pasoMsj-30 MPI_COMM_WORLD MPI_INT, MPI_FLOAT, … 0..MPI_TAG_UB • Enviar y recibir arrays de datos simples (int, byte, ...) Bloqueante P1 P2 int vector[N]; ---------- MPI_Send (vector, … P2,...) ---------- int tabla[M]; ---------- MPI_Recv (tabla, … P1, ...) ---------- intMPI_Send(void *buffer, int cuantos, MPI_Datatype tipo, int destino, int etiqueta, MPI_Commgrupo)
proPar MPI (Envío y Recepción Simple) pasoMsj-31 estado.MPI_SOURCE estado.MPI_TAG MPI_ANY_TAG intMPI_Get_count( MPI_Status*estado,MPI_Datatype tipo, int *cuantos) MPI_ANY_SOURCE • Enviar y recibir arrays de datos simples (int, byte, ...) Bloqueante intMPI_Recv(void *buffer, int cuantos, MPI_Datatype tipo, int remitente,int etiqueta,MPI_Commgrupo, MPI_Status*estado)
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) {...} intmain( 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 esclavo • 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); } }
proPar MPI (Envío y Recepción Simple) pasoMsj-34 maestro • 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); } }
proPar MPI (Envío y Recepción No Tan Simple) pasoMsj-35 • Enviar y recibir arrays de datos simples No Bloqueante intMPI_Iprobe(int origen, int etiqueta, MPI_Commgrupo, int *hayMsj, MPI_Status*estado) NO SI Hacer otras cosas intMPI_Recv(void *buffer,… MPI_Status*estado) • Enviar y recibir datos no homogéneos Crear tipos => Algo tedioso
proPar MPI (Comunicación colectiva) pasoMsj-36 cuenta.0 cuenta.1 “Ala” “Ala” “Ala” cuenta.2 cuenta.N tag ? Send+Recv intMPI_Bcast(void *buffer, int cuantos, MPI_Datatype tipo, int emisor, MPI_Comm grupo) 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); ---------- ----------
proPar MPI (Comunicación colectiva) pasoMsj-37 grupoM.0 grupoE.1 grupoE.9 MPI_SUM, MPI_PROD, MPI_MIN, MPI_MAX, .... + sendCount intMPI_Scatter( void *vOrg, int nOrg, MPI_Datatype tOrg, void *vDst, int nDst, MPI_Datatype tDst, int emisor, MPI_Comm grupo); intMPI_Reduce(void *vOrg, void *vDst, int nOrg, MPI_Datatype tDatoOrg, int operacion, int receptor, MPI_Comm grupo);
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 maestro longRodaja = 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 trozo numVeces = 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 6 • Otras llamadas interesantes: intMPI_Gather(void *vOrg, int nOrg, MPI_Datatype tOrg, void *vDst, int nDst, MPI_Datatype tDst, int receptor, MPI_Comm grupo); intMPI_Barrier(MPI_Comm grupo); ---------- MPI_Comm_size (MPI_COMM_WORLD, &numProcesos); ---------- // Computar todos paso 1 MPI_Barrier (MPI_COMM_WORLD); // Computar todos paso 2
proPar Evaluación de programas paralelos pasoMsj-41 Codificar, Depurar, Probar, ... Modelo imperfecto, aproximado N’ N • cuentaVeces: • V[1.000.000] • 10 esclavos m TP = TCPU + TRED e0 e9 veces = 0; for (i=0; i<N’; i++) if(rodaja[i] == D) veces++; • Enviar rodajas TRED • Contar veces TCPU • Recibir veces TRED N’ * (#i * Tinst) O (N) • ¿Cuánto tardará mi programa paralelo TP? • Medición experimental • Estudio analítico | O (N2) | O (NlogN) | O(logN)
proPar Evaluación de programas paralelos pasoMsj-42 N’ * (#i * Tinst) #msj, tamaño(#d), topología red, tecnología, ... TP = TCPU + TRED t #m * (TL+ #d * TD) TL #d Ejemplos TL TD[8B] Tinst TL TD Tinst T3D+PVM 3s 63ns 11ns Normalizar 273 6 1 IBM PS2+MPI 35s 230ns 4,2ns 8333 55 1 iacluster+MPI 40s 64ns 0,6ns 66666 107 1 Solapar tiempos | ocultar latencias Comunicación asíncrona TP = TCPU+TRED
proPar Evaluación de programas paralelos pasoMsj-43 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) #i #i S10 S10 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) 5 50 0,71 0,8 10 100 1,33 1,4 500 500 4,34 8,9 • Ejemplo: cuentaVeces, V[1.000.000], 10 esclavos T1= 1.000.000 * (#i * Tinst) T10= TRED(10Rodajas) + TCPU(100.000) + TRED(10Resultados)
proPar Herramientas de depuración y monitorización pasoMsj-44 #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 • Medición de tiempos de ejecución • Depuración • Monitorización ¿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 (ddd) printf fflush(stdout) setbuf(stdout, NULL) Depurar más de un proceso, algo más complejo
proPar Herramientas de depuración y monitorización pasoMsj-46 • Monitorización (XPVM) para PVM
proPar Herramientas de depuración y monitorización pasoMsj-47 • Monitorización (totalview) para MPI, openMP, … www.etnus.com www.roguewave.com
proPar Herramientas de depuración y monitorización pasoMsj-48 • Monitorización VAMPIRwww.vampir.eu FIN