static inline int __ompi_datatype_pack_description( ompi_datatype_t* datatype, void** packed_buffer, int* next_index ) { int i, *position = (int*)*packed_buffer; ompi_datatype_args_t* args = (ompi_datatype_args_t*)datatype->args; char* next_packed = (char*)*packed_buffer; if( ompi_datatype_is_predefined(datatype) ) { position[0] = MPI_COMBINER_NAMED; position[1] = datatype->id; /* On the OMPI - layer, copy the ompi_datatype.id */ next_packed += (2 * sizeof(int)); *packed_buffer = next_packed; return OMPI_SUCCESS; } /* For duplicated datatype we don't have to store all the information */ if( MPI_COMBINER_DUP == args->create_type ) { ompi_datatype_t* temp_data = args->d[0]; return __ompi_datatype_pack_description(temp_data, packed_buffer, next_index ); } position[0] = args->create_type; position[1] = args->ci; position[2] = args->ca; position[3] = args->cd; next_packed += (4 * sizeof(int)); /* Spoiler: We will access the data in this storage structure, and thus we * need to align it to the expected boundaries (special thanks to Sparc64). * The simplest way is to ensure that prior to each type that must be 64 * bits aligned, we have a pointer that is 64 bits aligned. That will minimize * the memory requirements in all cases where no displacements are stored. */ if( 0 < args->ca ) { /* description of the displacements must be 64 bits aligned */ OMPI_DATATYPE_ALIGN_PTR(next_packed, char*); memcpy( next_packed, args->a, sizeof(OPAL_PTRDIFF_TYPE) * args->ca ); next_packed += sizeof(OPAL_PTRDIFF_TYPE) * args->ca; } position = (int*)next_packed; next_packed += sizeof(int) * args->cd; /* copy the aray of counts (32 bits aligned) */ memcpy( next_packed, args->i, sizeof(int) * args->ci ); next_packed += args->ci * sizeof(int); /* copy the rest of the data */ for( i = 0; i < args->cd; i++ ) { ompi_datatype_t* temp_data = args->d[i]; if( ompi_datatype_is_predefined(temp_data) ) { position[i] = temp_data->id; /* On the OMPI - layer, copy the ompi_datatype.id */ } else { position[i] = *next_index; (*next_index)++; __ompi_datatype_pack_description( temp_data, (void**)&next_packed, next_index ); } } *packed_buffer = next_packed; return OMPI_SUCCESS; }
int ompi_datatype_get_pack_description( ompi_datatype_t* datatype, const void** packed_buffer ) { ompi_datatype_args_t* args = (ompi_datatype_args_t*)datatype->args; int next_index = OMPI_DATATYPE_MAX_PREDEFINED; void *packed_description = datatype->packed_description; void* recursive_buffer; if (NULL == packed_description) { if (opal_atomic_cmpset (&datatype->packed_description, NULL, (void *) 1)) { if( ompi_datatype_is_predefined(datatype) ) { packed_description = malloc(2 * sizeof(int)); } else if( NULL == args ) { return OMPI_ERROR; } else { packed_description = malloc(args->total_pack_size); } recursive_buffer = packed_description; __ompi_datatype_pack_description( datatype, &recursive_buffer, &next_index ); if (!ompi_datatype_is_predefined(datatype)) { args->total_pack_size = (uintptr_t)((char*)recursive_buffer - (char *) packed_description); } opal_atomic_wmb (); datatype->packed_description = packed_description; } else { /* another thread beat us to it */ packed_description = datatype->packed_description; } } if ((void *) 1 == packed_description) { struct timespec interval = {.tv_sec = 0, .tv_nsec = 1000}; /* wait until the packed description is updated */ while ((void *) 1 == datatype->packed_description) { nanosleep (&interval, NULL); } packed_description = datatype->packed_description; } *packed_buffer = (const void *) packed_description; return OMPI_SUCCESS; } size_t ompi_datatype_pack_description_length( ompi_datatype_t* datatype ) { void *packed_description = datatype->packed_description; if( ompi_datatype_is_predefined(datatype) ) { return 2 * sizeof(int); } if( NULL == packed_description || (void *) 1 == packed_description) { const void* buf; int rc; rc = ompi_datatype_get_pack_description(datatype, &buf); if( OMPI_SUCCESS != rc ) { return 0; } } assert( NULL != (ompi_datatype_args_t*)datatype->args ); assert( NULL != (ompi_datatype_args_t*)datatype->packed_description ); return ((ompi_datatype_args_t*)datatype->args)->total_pack_size; }
int ompi_datatype_get_pack_description( ompi_datatype_t* datatype, const void** packed_buffer ) { ompi_datatype_args_t* args = (ompi_datatype_args_t*)datatype->args; int next_index = OMPI_DATATYPE_MAX_PREDEFINED; void *packed_description = (void *) datatype->packed_description; void* recursive_buffer; if (NULL == packed_description) { void *_tmp_ptr = NULL; if (opal_atomic_compare_exchange_strong_ptr (&datatype->packed_description, (intptr_t *) &_tmp_ptr, 1)) { if( ompi_datatype_is_predefined(datatype) ) { packed_description = malloc(2 * sizeof(int)); } else if( NULL == args ) { return OMPI_ERROR; } else { packed_description = malloc(args->total_pack_size); } recursive_buffer = packed_description; __ompi_datatype_pack_description( datatype, &recursive_buffer, &next_index ); if (!ompi_datatype_is_predefined(datatype)) { /* If the precomputed size is not large enough we're already in troubles, we * have overwritten outside of the allocated buffer. Raise the alarm ! * If not reassess the size of the packed buffer necessary for holding the * datatype description. */ assert(args->total_pack_size >= (uintptr_t)((char*)recursive_buffer - (char *) packed_description)); args->total_pack_size = (uintptr_t)((char*)recursive_buffer - (char *) packed_description); } opal_atomic_wmb (); datatype->packed_description = (intptr_t) packed_description; } else { /* another thread beat us to it */ packed_description = (void *) datatype->packed_description; } } if ((void *) 1 == packed_description) { struct timespec interval = {.tv_sec = 0, .tv_nsec = 1000}; /* wait until the packed description is updated */ while (1 == datatype->packed_description) { nanosleep (&interval, NULL); } packed_description = (void *) datatype->packed_description; } *packed_buffer = (const void *) packed_description; return OMPI_SUCCESS; } size_t ompi_datatype_pack_description_length( ompi_datatype_t* datatype ) { void *packed_description = (void *) datatype->packed_description; if( ompi_datatype_is_predefined(datatype) ) { return 2 * sizeof(int); } if( NULL == packed_description || (void *) 1 == packed_description) { const void* buf; int rc; rc = ompi_datatype_get_pack_description(datatype, &buf); if( OMPI_SUCCESS != rc ) { return 0; } } assert( NULL != (ompi_datatype_args_t*)datatype->args ); assert( NULL != (ompi_datatype_args_t*)datatype->packed_description ); return ((ompi_datatype_args_t*)datatype->args)->total_pack_size; }