Tipos derivados MPI
MPI describe los mensajes por tipos, no por bytes (sistemas heterogéneos). Un tipo derivado es una lista de (tipo básico, desplazamiento) que describe la data en memoria. Sirve para:
- enviar data no contigua de un tipo (una columna, una submatriz) o de varios tipos (structs);
- no hacer una llamada por elemento (múltiples latencias) ni copiar a arrays contiguos.
| Constructor | Firma | Uso |
|---|---|---|
| contiguous | MPI_Type_contiguous(count, old, &new) | una fila (rowtype), un punto 3D |
| vector | MPI_Type_vector(count, blocklength, stride, old, &new) | columna, bloque de columnas, submatriz |
| indexed | MPI_Type_indexed(count, blocklens[], displs[], old, &new) | bloques de largo variable (triangular) |
| struct | MPI_Type_create_struct(count, blocklens[], displs[], types[], &new) | tipos mezclados |
vector: count bloques de blocklength elementos; de inicio a inicio de cada bloque hay stride elementos.
Tipos derivados MPI: ¿qué celdas se envían?
Matriz en memoria row-major. Naranja = elementos del mensaje (el número pequeño es su orden en el mensaje); verde = dónde aterrizan en el receptor.
MPI_Type_vector(10, 1, 10, MPI_FLOAT, &coltype);MPI_Type_commit(&coltype);MPI_Send(&A[0][col], 1, coltype, 1, 0, MPI_COMM_WORLD); // col = 6MPI_Recv(&A[0][col], 1, coltype, 0, 0, MPI_COMM_WORLD, &status);
struct: el anillo de ejemplo08
Sección titulada «struct: el anillo de ejemplo08»struct buff { int i; float f; } snd_buf, rcv_buf, sum;int array_of_blocklengths[2];MPI_Aint array_of_displacements[2], first_var_address, second_var_address;MPI_Datatype array_of_types[2], send_recv_type;
array_of_blocklengths[0] = 1;array_of_blocklengths[1] = 1;MPI_Get_address(&snd_buf.i, &first_var_address);MPI_Get_address(&snd_buf.f, &second_var_address);array_of_displacements[0] = (MPI_Aint) 0;array_of_displacements[1] = MPI_Aint_diff(second_var_address, first_var_address);array_of_types[0] = MPI_INT;array_of_types[1] = MPI_FLOAT;
MPI_Type_create_struct(2, array_of_blocklengths, array_of_displacements, array_of_types, &send_recv_type);MPI_Type_commit(&send_recv_type);
for (i = 0; i < size; i++) { // p vueltas al anillo MPI_Issend(&snd_buf, 1, send_recv_type, right, 17, MPI_COMM_WORLD, &request); MPI_Recv(&rcv_buf, 1, send_recv_type, left, 17, MPI_COMM_WORLD, &status); MPI_Wait(&request, &status); snd_buf = rcv_buf; sum.i += rcv_buf.i; sum.f += rcv_buf.f;}MPI_Type_free(&send_recv_type);Por qué los desplazamientos no son la suma de sizeof
Sección titulada «Por qué los desplazamientos no son la suma de sizeof»El compilador alinea cada campo a un múltiplo de su tamaño e inserta relleno (padding). Con class A2 { int a; double b; char c; }, imprimir &obj, &obj.a, &obj.b y &obj.c muestra que b empieza en el byte 8, no en el 4. Por eso ejemplo08 calcula los desplazamientos con MPI_Get_address + MPI_Aint_diff.
¿Por qué MPI_Get_address? Padding y alineación en structs
Cada campo se alinea a un múltiplo de su tamaño ⇒ el compilador inserta relleno. Los desplazamientos reales no son la suma de los sizeof.
| campo | tipo MPI | relleno antes | desplazamiento real | dirección (&obj + d) | suma de sizeof |
|---|---|---|---|---|---|
| int a | MPI_INT | 0 B | 0 | 0x7ffd5a3c1b20 | 0 ✓ |
| double b | MPI_DOUBLE | 4 B | 8 | 0x7ffd5a3c1b28 | 4 ✖ |
| char c | MPI_CHAR | 0 B | 16 | 0x7ffd5a3c1b30 | 12 ✖ |
int bl[3] = {1, 1, 1};
MPI_Aint d[3], base;
MPI_Datatype ty[3] = {MPI_INT, MPI_DOUBLE, MPI_CHAR};
MPI_Get_address(&obj, &base);
MPI_Get_address(&obj.a, &d[0]); d[0] = MPI_Aint_diff(d[0], base); // = 0
MPI_Get_address(&obj.b, &d[1]); d[1] = MPI_Aint_diff(d[1], base); // = 8
MPI_Get_address(&obj.c, &d[2]); d[2] = MPI_Aint_diff(d[2], base); // = 16
MPI_Type_create_struct(3, bl, d, ty, &tipo);
MPI_Type_commit(&tipo);sizeof, MPI leería bytes equivocados. Por eso se usan MPI_Get_address + MPI_Aint_diff. Ordenar los campos de mayor a menor tamaño reduce el relleno.Alineación típica en x86-64 (char 1, int/float 4, double 8). Imprimir &obj, &obj.a, &obj.b, &obj.c muestra exactamente estos saltos.
indexed: la diagonal de miejemplo.cpp
Sección titulada «indexed: la diagonal de miejemplo.cpp»MPI_Type_indexed(count, blocklens[], displs[], …) generaliza a vector: cada bloque tiene su propio largo y desplazamiento. En miejemplo.cpp se envía la diagonal de una matriz con bloques de largo 1 en i*M + i = 35. Elige el preset «miejemplo — diagonal» en el visualizador de arriba.
Pack/Unpack y Sendrecv
Sección titulada «Pack/Unpack y Sendrecv»MPI_Pack/MPI_Unpack(tipoMPI_PACKED): empaquetar variables en un buffer de bytes. Muy dinámico (estructura que cambia en ejecución, uso único), pero con costo de copia. Si la misma estructura se envía en un bucle, convieneMPI_Type_create_struct.MPI_Sendrecv(&sbuf, scnt, stype, dest, stag, &rbuf, rcnt, rtype, src, rtag, comm, &status): envío y recibo en una llamada — MPI evita el bloqueo mutuo de un anillo.
Ejercicio (ejemplo04_contiguous.cpp)
Sección titulada «Ejercicio (ejemplo04_contiguous.cpp)»Complete el anillo que suma dos enteros {i, j} por proceso usando MPI_Type_contiguous y comunicación no bloqueada (como en PD3).
Ver solución
MPI_Datatype pairtype;MPI_Type_contiguous(2, MPI_INT, &pairtype); // struct {int i; int j;} = 2 ints contiguosMPI_Type_commit(&pairtype);sum.i = 0; sum.j = 0; snd_buf.i = my_rank; snd_buf.j = 10 * my_rank;for (i = 0; i < size; i++) { MPI_Issend(&snd_buf, 1, pairtype, right, 17, MPI_COMM_WORLD, &request); MPI_Recv(&rcv_buf, 1, pairtype, left, 17, MPI_COMM_WORLD, &status); MPI_Wait(&request, &status); snd_buf = rcv_buf; sum.i += rcv_buf.i; sum.j += rcv_buf.j;}printf("PE%i:\tSum = %i\t%i\n", my_rank, sum.i, sum.j);MPI_Type_free(&pairtype);Cada proceso imprime y . Como ambos campos son int y no hay padding, contiguous basta; con tipos mezclados (int + float) se necesita create_struct.
Autoevaluación
0/4 correctas · 0 respondidasfloat A[8][5]:MPI_Type_vector(2, 3, 6, MPI_DOUBLE, &t) enviado desde A () manda…Fuente ·U3.4 Paralelismo Distribuido-tiposMPI.pdf · U3.4 Comunicacion-tiposMPI-codigo/ejemplo01–08 · U3.4 Comunicacion-tiposMPI-codigo/miejemplo.cpp · U3.4 Comunicacion-tiposMPI-codigo/test.cpp · practica_3_ofi/ejercicio02_col.cpp