ompi_datatype_t* create_vector_type( const ompi_datatype_t* data, int count, int length, int stride ) { ompi_datatype_t* vector; ompi_datatype_create_vector( count, length, stride, data, &vector ); ompi_datatype_commit( &vector ); return vector; }
/** * Data-type functions. */ ompi_datatype_t* create_inversed_vector( const ompi_datatype_t* type, int length ) { ompi_datatype_t* type1; ompi_datatype_create_vector( length, 1, 2, type, &type1 ); ompi_datatype_commit( &type1 ); return type1; }
ompi_datatype_t* test_create_blacs_type2( const ompi_datatype_t* base_type ) { ompi_datatype_t *pdt; ompi_datatype_create_vector( 7, 1, 2, base_type, &pdt ); ompi_datatype_commit( &pdt ); if( outputFlags & DUMP_DATA_AFTER_COMMIT ) { ompi_datatype_dump( pdt ); } return pdt; }
ompi_datatype_t* test_create_twice_two_doubles( void ) { ompi_datatype_t* pdt; ompi_datatype_create_vector( 2, 2, 5, &ompi_mpi_double.dt, &pdt ); ompi_datatype_commit( &pdt ); if( outputFlags & DUMP_DATA_AFTER_COMMIT ) { ompi_datatype_dump( pdt ); } return pdt; }
static ompi_datatype_t* __ompi_datatype_create_from_args( int32_t* i, MPI_Aint* a, ompi_datatype_t** d, int32_t type ) { ompi_datatype_t* datatype = NULL; switch(type){ /******************************************************************/ case MPI_COMBINER_DUP: /* should we duplicate d[0]? */ /* ompi_datatype_set_args( datatype, 0, NULL, 0, NULL, 1, d[0], MPI_COMBINER_DUP ); */ assert(0); /* shouldn't happen */ break; /******************************************************************/ case MPI_COMBINER_CONTIGUOUS: ompi_datatype_create_contiguous( i[0], d[0], &datatype ); ompi_datatype_set_args( datatype, 1, (const int **) &i, 0, NULL, 1, d, MPI_COMBINER_CONTIGUOUS ); break; /******************************************************************/ case MPI_COMBINER_VECTOR: ompi_datatype_create_vector( i[0], i[1], i[2], d[0], &datatype ); { const int* a_i[3] = {&i[0], &i[1], &i[2]}; ompi_datatype_set_args( datatype, 3, a_i, 0, NULL, 1, d, MPI_COMBINER_VECTOR ); } break; /******************************************************************/ case MPI_COMBINER_HVECTOR_INTEGER: case MPI_COMBINER_HVECTOR: ompi_datatype_create_hvector( i[0], i[1], a[0], d[0], &datatype ); { const int* a_i[2] = {&i[0], &i[1]}; ompi_datatype_set_args( datatype, 2, a_i, 1, a, 1, d, MPI_COMBINER_HVECTOR ); } break; /******************************************************************/ case MPI_COMBINER_INDEXED: /* TO CHECK */ ompi_datatype_create_indexed( i[0], &(i[1]), &(i[1+i[0]]), d[0], &datatype ); { const int* a_i[3] = {&i[0], &i[1], &(i[1+i[0]])}; ompi_datatype_set_args( datatype, 2 * i[0] + 1, a_i, 0, NULL, 1, d, MPI_COMBINER_INDEXED ); } break; /******************************************************************/ case MPI_COMBINER_HINDEXED_INTEGER: case MPI_COMBINER_HINDEXED: ompi_datatype_create_hindexed( i[0], &(i[1]), a, d[0], &datatype ); { const int* a_i[2] = {&i[0], &i[1]}; ompi_datatype_set_args( datatype, i[0] + 1, a_i, i[0], a, 1, d, MPI_COMBINER_HINDEXED ); } break; /******************************************************************/ case MPI_COMBINER_INDEXED_BLOCK: ompi_datatype_create_indexed_block( i[0], i[1], &(i[2]), d[0], &datatype ); { const int* a_i[3] = {&i[0], &i[1], &i[2]}; ompi_datatype_set_args( datatype, i[0] + 2, a_i, 0, NULL, 1, d, MPI_COMBINER_INDEXED_BLOCK ); } break; /******************************************************************/ case MPI_COMBINER_STRUCT_INTEGER: case MPI_COMBINER_STRUCT: ompi_datatype_create_struct( i[0], &(i[1]), a, d, &datatype ); { const int* a_i[2] = {&i[0], &i[1]}; ompi_datatype_set_args( datatype, i[0] + 1, a_i, i[0], a, i[0], d, MPI_COMBINER_STRUCT ); } break; /******************************************************************/ case MPI_COMBINER_SUBARRAY: ompi_datatype_create_subarray( i[0], &i[1 + 0 * i[0]], &i[1 + 1 * i[0]], &i[1 + 2 * i[0]], i[1 + 3 * i[0]], d[0], &datatype ); { const int* a_i[5] = {&i[0], &i[1 + 0 * i[0]], &i[1 + 1 * i[0]], &i[1 + 2 * i[0]], &i[1 + 3 * i[0]]}; ompi_datatype_set_args( datatype, 3 * i[0] + 2, a_i, 0, NULL, 1, d, MPI_COMBINER_SUBARRAY); } break; /******************************************************************/ case MPI_COMBINER_DARRAY: ompi_datatype_create_darray( i[0] /* size */, i[1] /* rank */, i[2] /* ndims */, &i[3 + 0 * i[0]], &i[3 + 1 * i[0]], &i[3 + 2 * i[0]], &i[3 + 3 * i[0]], i[3 + 4 * i[0]], d[0], &datatype ); { const int* a_i[8] = {&i[0], &i[1], &i[2], &i[3 + 0 * i[0]], &i[3 + 1 * i[0]], &i[3 + 2 * i[0]], &i[3 + 3 * i[0]], &i[3 + 4 * i[0]]}; ompi_datatype_set_args( datatype, 4 * i[0] + 4,a_i, 0, NULL, 1, d, MPI_COMBINER_DARRAY); } break; /******************************************************************/ case MPI_COMBINER_F90_REAL: case MPI_COMBINER_F90_COMPLEX: /*pArgs->i[0] = i[0][0]; pArgs->i[1] = i[1][0]; */ break; /******************************************************************/ case MPI_COMBINER_F90_INTEGER: /*pArgs->i[0] = i[0][0];*/ break; /******************************************************************/ case MPI_COMBINER_RESIZED: ompi_datatype_create_resized(d[0], a[0], a[1], &datatype); ompi_datatype_set_args( datatype, 0, NULL, 2, a, 1, d, MPI_COMBINER_RESIZED ); break; /******************************************************************/ case MPI_COMBINER_HINDEXED_BLOCK: ompi_datatype_create_hindexed_block( i[0], i[1], a, d[0], &datatype ); { const int* a_i[2] = {&i[0], &i[1]}; ompi_datatype_set_args( datatype, 2 + i[0], a_i, i[0], a, 1, d, MPI_COMBINER_HINDEXED_BLOCK ); } break; /******************************************************************/ default: break; } return datatype; }
int32_t ompi_datatype_create_subarray(int ndims, int const* size_array, int const* subsize_array, int const* start_array, int order, const ompi_datatype_t* oldtype, ompi_datatype_t** newtype) { MPI_Datatype last_type; int32_t i, step, end_loop; MPI_Aint size, displ, extent; /** * If the oldtype contains the original MPI_LB and MPI_UB markers then we * are forced to follow the MPI standard suggestion and reset these 2 * markers (MPI 3.0 page 96 line 37). Otherwise we can simply resize the * datatype. */ ompi_datatype_type_extent( oldtype, &extent ); /* If the ndims is zero then return the NULL datatype */ if( ndims < 2 ) { if( 0 == ndims ) { *newtype = &ompi_mpi_datatype_null.dt; return MPI_SUCCESS; } ompi_datatype_create_contiguous( subsize_array[0], oldtype, &last_type ); size = size_array[0]; displ = start_array[0]; goto replace_subarray_type; } if( MPI_ORDER_C == order ) { i = ndims - 1; step = -1; end_loop = -1; } else { i = 0; step = 1; end_loop = ndims; } /* As we know that the ndims is at least 1 we can start by creating the * first dimension data outside the loop, such that we dont have to create * a duplicate of the oldtype just to be able to free it. */ ompi_datatype_create_vector( subsize_array[i+step], subsize_array[i], size_array[i], oldtype, newtype ); last_type = *newtype; size = (MPI_Aint)size_array[i] * (MPI_Aint)size_array[i+step]; displ = (MPI_Aint)start_array[i] + (MPI_Aint)start_array[i+step] * (MPI_Aint)size_array[i]; for( i += 2 * step; i != end_loop; i += step ) { ompi_datatype_create_hvector( subsize_array[i], 1, size * extent, last_type, newtype ); ompi_datatype_destroy( &last_type ); displ += size * start_array[i]; size *= size_array[i]; last_type = *newtype; } replace_subarray_type: /** * We need to shift the content (useful data) of the datatype, so * we need to force the displacement to be moved. Therefore, we * cannot use resize as it will only set the soft lb and ub * markers without moving the data. Instead, we have to create a * new data, and insert the last_Type with the correct * displacement. */ *newtype = ompi_datatype_create( last_type->super.desc.used ); ompi_datatype_add( *newtype, last_type, 1, displ * extent, size * extent); ompi_datatype_destroy( &last_type ); return OMPI_SUCCESS; }
int32_t ompi_datatype_create_subarray(int ndims, int const* size_array, int const* subsize_array, int const* start_array, int order, const ompi_datatype_t* oldtype, ompi_datatype_t** newtype) { MPI_Datatype last_type; int32_t i, step, end_loop; MPI_Aint size, displ, extent; /** * If the oldtype contains the original MPI_LB and MPI_UB markers then we * are forced to follow the MPI standard suggestion and reset these 2 * markers (MPI 3.0 page 96 line 37). Otherwise we can simply resize the * datatype. */ ompi_datatype_type_extent( oldtype, &extent ); /* If the ndims is zero then return the NULL datatype */ if( ndims < 2 ) { if( 0 == ndims ) { *newtype = &ompi_mpi_datatype_null.dt; return MPI_SUCCESS; } ompi_datatype_create_contiguous( subsize_array[0], oldtype, &last_type ); size = size_array[0]; displ = start_array[0]; goto replace_subarray_type; } if( MPI_ORDER_C == order ) { i = ndims - 1; step = -1; end_loop = -1; } else { i = 0; step = 1; end_loop = ndims; } /* As we know that the ndims is at least 1 we can start by creating the * first dimension data outside the loop, such that we dont have to create * a duplicate of the oldtype just to be able to free it. */ ompi_datatype_create_vector( subsize_array[i+step], subsize_array[i], size_array[i], oldtype, newtype ); last_type = *newtype; size = (MPI_Aint)size_array[i] * (MPI_Aint)size_array[i+step]; displ = (MPI_Aint)start_array[i] + (MPI_Aint)start_array[i+step] * (MPI_Aint)size_array[i]; for( i += 2 * step; i != end_loop; i += step ) { ompi_datatype_create_hvector( subsize_array[i], 1, size * extent, last_type, newtype ); ompi_datatype_destroy( &last_type ); displ += size * start_array[i]; size *= size_array[i]; last_type = *newtype; } replace_subarray_type: /* * Resized will only set the soft lb and ub markers without moving the real * data inside. Thus, in case the original data contains the hard markers * (MPI_LB or MPI_UB) we must force the displacement of the data upward to * the right position AND set the hard markers LB and UB. * * NTH: ompi_datatype_create_resized() does not do enough for the general * pack/unpack functions to work correctly. Until this is fixed always use * ompi_datatype_create_struct(). Once this is fixed remove 1 || below. To * verify that the regression is fixed run the subarray test in the Open MPI * ibm testsuite. */ if(1 || oldtype->super.flags & (OPAL_DATATYPE_FLAG_USER_LB | OPAL_DATATYPE_FLAG_USER_UB) ) { MPI_Aint displs[3]; MPI_Datatype types[3]; int blength[3] = { 1, 1, 1 }; displs[0] = 0; displs[1] = displ * extent; displs[2] = size * extent; types[0] = MPI_LB; types[1] = last_type; types[2] = MPI_UB; ompi_datatype_create_struct( 3, blength, displs, types, newtype ); } else { ompi_datatype_create_resized(last_type, displ * extent, size * extent, newtype); } ompi_datatype_destroy( &last_type ); return OMPI_SUCCESS; }
int main( int argc, char* argv[] ) { ddt_segment_t* segments; int *send_buffer, *recv_buffer; int i, seg_count, errors; int show_only_first_error = 1; ompi_datatype_t* datatype = MPI_DATATYPE_NULL; #define NELT (300) send_buffer = malloc(NELT*sizeof(int)); recv_buffer = malloc(NELT*sizeof(int)); for (i = 0; i < NELT; ++i) { send_buffer[i] = i; recv_buffer[i] = 0xdeadbeef; } opal_init_util (NULL, NULL); ompi_datatype_init(); ompi_datatype_create_vector(NELT/2, 1, 2, MPI_INT, &datatype); ompi_datatype_commit(&datatype); #if (OPAL_ENABLE_DEBUG == 1) && (OPAL_C_HAVE_VISIBILITY == 0) opal_unpack_debug = false; opal_pack_debug = false; opal_position_debug = false; #endif /* OPAL_ENABLE_DEBUG */ create_segments( datatype, 1, fragment_size, &segments, &seg_count ); /* shuffle the segments */ shuffle_segments( segments, seg_count ); /* pack the data */ pack_segments( datatype, 1, fragment_size, segments, seg_count, send_buffer ); /* unpack the data back in the user space (recv buffer) */ unpack_segments( datatype, 1, fragment_size, segments, seg_count, recv_buffer ); /* And now check the data */ for( errors = i = 0; i < NELT; i++ ) { int expected = ((i % 2) ? (int)0xdeadbeef : i); if (recv_buffer[i] != expected) { if( (show_only_first_error && (0 == errors)) || !show_only_first_error ) { printf("error at index %4d: 0x%08x != 0x%08x\n", i, recv_buffer[i], expected); } errors++; } } printf( "Found %d errors\n", errors ); free(send_buffer); free(recv_buffer); for( i = 0; i < seg_count; i++ ) { free( segments[i].buffer ); } free(segments); ompi_datatype_finalize(); opal_finalize_util (); return (0 == errors ? 0 : -1); }
int32_t ompi_datatype_create_subarray(int ndims, int const* size_array, int const* subsize_array, int const* start_array, int order, const ompi_datatype_t* oldtype, ompi_datatype_t** newtype) { MPI_Datatype last_type; int32_t i, step, end_loop; MPI_Aint size, displ, extent; ompi_datatype_type_extent( oldtype, &extent ); /* If the ndims is zero then return the NULL datatype */ if( ndims < 2 ) { if( 0 == ndims ) { *newtype = &ompi_mpi_datatype_null.dt; return MPI_SUCCESS; } ompi_datatype_create_contiguous( subsize_array[0], oldtype, &last_type ); size = size_array[0]; displ = start_array[0]; goto replace_subarray_type; } if( MPI_ORDER_C == order ) { i = ndims - 1; step = -1; end_loop = -1; } else { i = 0; step = 1; end_loop = ndims; } /* As we know that the ndims is at least 1 we can start by creating the * first dimension data outside the loop, such that we dont have to create * a duplicate of the oldtype just to be able to free it. */ ompi_datatype_create_vector( subsize_array[i+step], subsize_array[i], size_array[i], oldtype, newtype ); last_type = *newtype; size = size_array[i] * size_array[i+step]; displ = start_array[i] + start_array[i+step] * size_array[i]; for( i += 2 * step; i != end_loop; i += step ) { ompi_datatype_create_hvector( subsize_array[i], 1, size * extent, last_type, newtype ); ompi_datatype_destroy( &last_type ); displ += size * start_array[i]; size *= size_array[i]; last_type = *newtype; } replace_subarray_type: /** * We cannot use resized here. Resized will only set the soft lb and ub markers * without moving the real data inside. What we need is to force the displacement * of the data upward to the right position AND set the LB and UB. A type * struct is the function we need. */ { MPI_Aint displs[3]; MPI_Datatype types[3]; int blength[3] = { 1, 1, 1 }; displs[0] = 0; displs[1] = displ * extent; displs[2] = size * extent; types[0] = MPI_LB; types[1] = last_type; types[2] = MPI_UB; ompi_datatype_create_struct( 3, blength, displs, types, newtype ); } ompi_datatype_destroy( &last_type ); return OMPI_SUCCESS; }
int main(int argc, char *argv[]) { opal_init_util(&argc, &argv); ompi_datatype_init(); /* Simple contiguous data: MPI_INT32_T */ { int32_t send_data[2] = {1234, 5678}; int32_t recv_data[2] = {-1, -1}; if( verbose ) { printf("send data %08x %08x \n", send_data[0], send_data[1]); printf("data "); dump_hex(&send_data, sizeof(int32_t) * 2); printf("\n"); } (void)pack_unpack_datatype( send_data, &ompi_mpi_int32_t.dt, 2, recv_data, check_contiguous, (void*)&ompi_mpi_int32_t.dt ); if( verbose ) { printf("recv "); dump_hex(&recv_data, sizeof(int32_t) * 2); printf("\n"); printf("recv data %08x %08x \n", recv_data[0], recv_data[1]); } if( (send_data[0] != recv_data[0]) || (send_data[1] != recv_data[1]) ) { printf("Error during external32 pack/unack for contiguous types (MPI_INT32_T)\n"); exit(-1); } } /* Simple contiguous data: MPI_INT16_T */ { int16_t send_data[2] = {1234, 5678}; int16_t recv_data[2] = {-1, -1}; if( verbose ) { printf("send data %08x %08x \n", send_data[0], send_data[1]); printf("data "); dump_hex(&send_data, sizeof(int16_t) * 2); printf("\n"); } (void)pack_unpack_datatype( send_data, &ompi_mpi_int16_t.dt, 2, recv_data, check_contiguous, (void*)&ompi_mpi_int16_t.dt ); if( verbose ) { printf("recv "); dump_hex(&recv_data, sizeof(int16_t) * 2); printf("\n"); printf("recv data %08x %08x \n", recv_data[0], recv_data[1]); } if( (send_data[0] != recv_data[0]) || (send_data[1] != recv_data[1]) ) { printf("Error during external32 pack/unack for contiguous types\n"); exit(-1); } } /* Vector datatype */ printf("\n\nVector datatype\n\n"); { int count=2, blocklength=1, stride=2; int send_data[3] = {1234, 0, 5678}; int recv_data[3] = {-1, -1, -1}; ompi_datatype_t *ddt; ompi_datatype_create_vector ( count, blocklength, stride, &ompi_mpi_int.dt, &ddt ); { const int* a_i[3] = {&count, &blocklength, &stride}; ompi_datatype_t *type = &ompi_mpi_int.dt; ompi_datatype_set_args( ddt, 3, a_i, 0, NULL, 1, &type, MPI_COMBINER_VECTOR ); } ompi_datatype_commit(&ddt); if( verbose ) { printf("send data %08x %x08x %08x \n", send_data[0], send_data[1], send_data[2]); printf("data "); dump_hex(&send_data, sizeof(int32_t) * 3); printf("\n"); } (void)pack_unpack_datatype( send_data, ddt, 1, recv_data, check_vector, (void*)&ompi_mpi_int32_t.dt ); if( verbose ) { printf("recv "); dump_hex(&recv_data, sizeof(int32_t) * 3); printf("\n"); printf("recv data %08x %08x %08x \n", recv_data[0], recv_data[1], recv_data[2]); } ompi_datatype_destroy(&ddt); if( (send_data[0] != recv_data[0]) || (send_data[2] != recv_data[2]) ) { printf("Error during external32 pack/unack for vector types (MPI_INT32_T)\n"); exit(-1); } } ompi_datatype_finalize(); return 0; }
static int unpack_ooo(void) { ompi_datatype_t * t1; ompi_datatype_t * t2; ompi_datatype_t * type[2]; ompi_datatype_t * newtype; MPI_Aint disp[2]; int len[2], rc; rc = ompi_datatype_create_vector(2, 1, 2, MPI_INT, &t1); if (OMPI_SUCCESS != rc) { fprintf(stderr, "could not create vector t1\n"); return 1; } rc = ompi_datatype_commit (&t1); if (OMPI_SUCCESS != rc) { fprintf(stderr, "could not commit vector t1\n"); return 1; } rc = ompi_datatype_create_vector(2, 1, 2, MPI_DOUBLE, &t2); if (OMPI_SUCCESS != rc) { fprintf(stderr, "could not create vector t2\n"); return 1; } rc = ompi_datatype_commit (&t2); if (OMPI_SUCCESS != rc) { fprintf(stderr, "could not commit vector t2\n"); return 1; } /* * btl=0x7f7823672580 bytes_received=992 data_offset=0 * btl=0x7f7823260420 bytes_received=1325 data_offset=992 * btl=0x7f7823672580 bytes_received=992 data_offset=2317 * btl=0x7f7823672580 bytes_received=992 data_offset=3309 * btl=0x7f7823672580 bytes_received=992 data_offset=4301 * btl=0x7f7823672580 bytes_received=992 data_offset=5293 * btl=0x7f7823672580 bytes_received=992 data_offset=6285 * btl=0x7f7823672580 bytes_received=667 data_offset=7277 */ size_t test1[9][2] = { {992, 0}, {1325, 992}, {992, 2317}, {992, 3309}, {992, 4301}, {992, 5293}, {992, 6285}, {667, 7277}, {0, -1}, }; /* * btl=0x7f80bc545580 bytes_received=992 data_offset=0 * btl=0x7f80bc545580 bytes_received=992 data_offset=2317 * btl=0x7f80bc545580 bytes_received=992 data_offset=3309 * btl=0x7f80bc545580 bytes_received=992 data_offset=4301 * btl=0x7f80bc545580 bytes_received=992 data_offset=5293 * btl=0x7f80bc545580 bytes_received=992 data_offset=6285 * btl=0x7f80bc133420 bytes_received=1325 data_offset=992 * btl=0x7f80bc545580 bytes_received=667 data_offset=7277 */ size_t test2[9][2] = { {992, 0}, {992, 2317}, {992, 3309}, {992, 4301}, {992, 5293}, {992, 6285}, {1325, 992}, {667, 7277}, {0, -1}, }; /* trimmed version of test2 */ size_t test3[9][2] = { {992, 0}, {4960, 2317}, {1325, 992}, {667, 7277}, {0, -1}, }; /* an other test case */ size_t test4[9][2] = { {992, 0}, {992, 2976}, {992, 1984}, {992, 992}, {3976, 3968}, {0, -1}, }; disp[0] = (long)(&foo.i[0]) - (long)&foo; disp[1] = (long)(&foo.d[0]) - (long)&foo; type[0] = t1; type[1] = t2; len[0] = 1; len[1] = 1; rc = ompi_datatype_create_struct(2, len, disp, type, &newtype); if (OMPI_SUCCESS != rc) { fprintf(stderr, "could not create struct\n"); return 1; } rc = ompi_datatype_commit (&newtype); if (OMPI_SUCCESS != rc) { fprintf(stderr, "could not create struct\n"); return 1; } pbar = (struct pfoo_t *)malloc (N * sizeof(struct pfoo_t)); if (NULL == pbar) { fprintf(stderr, "could not malloc pbar\n"); return 1; } bar = (struct foo_t *)malloc (N * sizeof(struct foo_t)); if (NULL == bar) { fprintf(stderr, "could not malloc bar\n"); return 1; } if (0 != testcase(newtype, test1)) { printf ("test1 failed\n"); return 2; } if (0 != testcase(newtype, test2)) { printf ("test2 failed\n"); return 2; } if (0 != testcase(newtype, test3)) { printf ("test3 failed\n"); return 2; } if (0 != testcase(newtype, test4)) { printf ("test4 failed\n"); return 2; } /* test the automatic destruction pf the data */ ompi_datatype_destroy( &newtype ); assert( newtype == NULL ); return rc; }