Ir al contenido

Comunicación colectiva

Propiedades: todos los procesos del comunicador participan (cada llamada colectiva debe incluirlos a todos); no interfiere con punto a punto; el buffer se reutiliza cuando el proceso termina la llamada. La librería optimiza la comunicación (árboles).

RutinaQué hace
MPI_Barrier(comm)sincroniza: nadie sigue hasta que todos llegan. Casi nunca hace falta (útil para debugging/medir tiempos)
MPI_Bcast(&buf, count, type, root, comm)root → todos
MPI_Scatter(&sbuf, scnt, stype, &rbuf, rcnt, rtype, root, comm)root reparte trozos de scnt elementos por proceso, en orden de rank
MPI_Gather(&sbuf, scnt, stype, &rbuf, rcnt, rtype, root, comm)inverso de Scatter: root junta en orden de rank
MPI_Allgather(...) (sin root)Gather + Bcast: todos obtienen todo
MPI_Reduce(&sbuf, &rbuf, count, type, op, root, comm)combina con op (MPI_SUM, MPI_MAX, MPI_MIN, MPI_PROD…) en root
MPI_Allreduce(&sbuf, &rbuf, count, type, op, comm)Reduce + resultado en todos

Colectivas MPI: lineal vs árbol

Cada paso = mensajes simultáneos; costo del paso = α + β·(mensaje más grande). La raíz es P0.

paso 0/3
P0P1P2P3P4P5P6P7
Pasos (arbol)3
T simulado (arbol)0.003 s
Pasos (lineal)7
T (lineal)0.00701 s
log₂ p3
Lineal: O(p(α+mβ))O(p(\alpha+m\beta))  ·  Árbol: O(log⁡p (α+mβ))O(\log p\,(\alpha+m\beta))
El árbol reduce el término de latencia de αp a α log p; en Scatter/Gather el término βm no cambia (el volumen total de datos es el mismo).
session2/ejemplo01-bcast-reduce.cpp
if (rank == 0) data = 5;
// 1. el maestro envía data a todos
MPI_Bcast(&data, 1, MPI_INT, 0, MPI_COMM_WORLD);
data *= rank; // 2. cada uno modifica
MPI_Reduce(&data, &resultado, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
// 3. resultado (solo en el maestro) = 5·(0+1+…+(p−1))
if (rank == 0) cout << "resultado: " << resultado << endl;

El mismo ejemplo03-PI-reduce.cpp se midió con N = 10² … 10⁶ iteraciones. Es la mejor evidencia de por qué la escalabilidad depende de N.

π con MPI_Reduce: tiempos medidos (np = 1 … 128)

Datos reales del benchmark de ejemplo03-PI-reduce.cpp para 5 tamaños N. ¿Cuándo conviene paralelizar?

05101520110100npSpeedup T(1)/T(np)
N = 10³N = 10⁴N = 10⁵N = 10⁶
Carrera de tiempos para N =
np=1
15.8 ms
np=2
12.7 ms
np=4
6.64 ms
np=8
4.39 ms
np=16
1.84 ms
np=32
1.3 ms
np=64
0.951 ms ★
np=128
1.11 ms
Para N = 10⁶ el mínimo está en np = 64 (S = 16.7). Con N pequeño el costo de MPI_Bcast/MPI_Reduce (latencia ~α log p) supera al cómputo O(N/p): más procesos = más lento. Con N grande el punto óptimo se desplaza a más procesos — la misma lección que N-Body y la isoeficiencia.

Array de 1000 números aleatorios 0–100. Reparta con MPI_Scatter, cada proceso calcula su promedio, junte los promedios con MPI_Gather y el maestro calcula el promedio global. ¿Es correcto promediar los promedios? ¿Qué colectiva sería mejor?

Ver solución

Es correcto solo si todos los trozos tienen el mismo tamaño (1000 divisible por pp); si no, hay que ponderar por el tamaño de cada trozo. Mejor aún: cada proceso calcula su suma local y se hace un único MPI_Reduce(MPI_SUM); el maestro divide entre 1000. Evita juntar pp valores en un array y el costo es O(log⁡p)O(\log p) en árbol.

Autoevaluación

0/4 correctas · 0 respondidas
1. ¿Qué colectiva deja el resultado de la reducción en TODOS los procesos?
2. MPI_Allgather equivale a…
3. En Scatter con 40 elementos y 4 procesos, sendcnt =
4. Bcast en árbol vs lineal: pasos con p=16p=16

Fuente ·U3.2 Paralelismo Distribuido-MPI.pdf · session2/*.cpp · session2/pi-reduce/ejemplo03-PI-reduce.cpp · session2/pi-reduce/ej03_res.txt, ej03.plt · 05_Particionamiento.md §2