uint64_t adios_transform_worst_case_transformed_group_size(uint64_t group_size, struct adios_file_struct *fd) { uint64_t transformed_group_size = group_size; // The upper bound on how much data /might/ be transformed struct adios_var_struct *cur_var; // Aggregated scaling information from all transforms // The end result upper bound group size is: // GS' = total_constant_factor + GS' * max_linear_factor + min(GS', max_capped_linear_cap) * max_capped_linear_factor uint64_t total_constant_factor = 0; double max_linear_factor = 1; double max_capped_linear_factor = 0; uint64_t max_capped_linear_cap = 0; // Note: the "max capped linear" component is overestimating by combining the highest factor and cap from all transforms // A tighter lower bound could be computed by keeping all capped linear caps/factors and doing some sort of overlap // computation. However, this requires O(n vars) storage and extra logic that isn't worth it, given capped factors are // very rare, and this method gives a tight bound when none are present. for (cur_var = fd->group->vars; cur_var; cur_var = cur_var->next) { if (!cur_var->dimensions) // Scalar var { // Remove the scalar's size from the group size that can be affected by data transforms, and add it as a constant factor // Even if it's a string, we don't know the content yet, so use an empty string to get minimum size (we are computing an upper bound) transformed_group_size -= adios_get_type_size(cur_var->type, ""); total_constant_factor += adios_get_type_size(cur_var->type, ""); } else if (cur_var->transform_type == adios_transform_none) // Non-transformed, non-scalar var { // Do nothing } else // Transformed var { uint64_t constant_factor = 0; double linear_factor = 1; double capped_linear_factor = 0; uint64_t capped_linear_cap = 0; // Get the growth factors for this transform method/spec adios_transform_transformed_size_growth(cur_var, cur_var->transform_spec, &constant_factor, &linear_factor, &capped_linear_factor, &capped_linear_cap); // Combine these growth factors into the maximums for computing the worst case total_constant_factor += constant_factor; max_linear_factor = MAX(max_linear_factor, linear_factor); max_capped_linear_factor = MAX(max_capped_linear_factor, capped_linear_factor); max_capped_linear_cap = MAX(max_capped_linear_cap, capped_linear_cap); } } const uint64_t max_transformed_group_size = total_constant_factor + ceil(max_linear_factor * transformed_group_size) + ceil(max_capped_linear_factor * MIN(transformed_group_size, max_capped_linear_cap)); // Return the maximum worst case for the group size // (which can never be less than the starting group size) return MAX(group_size, max_transformed_group_size); }
adios_datablock * adios_transform_alacrity_pg_reqgroup_completed(adios_transform_read_request *reqgroup, adios_transform_pg_read_request *completed_pg_reqgroup) { //uint64_t raw_size = (uint64_t)completed_pg_reqgroup->raw_var_length; void* raw_buff = completed_pg_reqgroup->subreqs->data; uint64_t orig_size = adios_get_type_size(reqgroup->transinfo->orig_type, ""); int d = 0; for(d = 0; d < reqgroup->transinfo->orig_ndim; d++) orig_size *= (uint64_t)(completed_pg_reqgroup->orig_varblock->count[d]); void* orig_buff = malloc(orig_size); ALPartitionData output_partition; uint64_t numElements = 0; // Decompress into output_partition from compressed_buf memstream_t ms = memstreamInitReturn (raw_buff); // Deserialize the ALPartitionData from memstream ALDeserializePartitionData (&output_partition, &ms); // Decode ALPartitionData into decompresed buffer int rtn = ALDecode (&output_partition, orig_buff, &numElements); if (ALErrorNone != rtn) return NULL; ALPartitionDataDestroy(&output_partition); return adios_datablock_new(reqgroup->transinfo->orig_type, completed_pg_reqgroup->timestep, completed_pg_reqgroup->pg_bounds_sel, orig_buff); }
adios_datablock * adios_transform_szip_pg_reqgroup_completed(adios_transform_read_request *reqgroup, adios_transform_pg_read_request *completed_pg_reqgroup) { uint64_t raw_size = (uint64_t)completed_pg_reqgroup->raw_var_length; void* raw_buff = completed_pg_reqgroup->subreqs->data; uint64_t orig_size = adios_get_type_size(reqgroup->transinfo->orig_type, ""); int d = 0; for(d = 0; d < reqgroup->transinfo->orig_ndim; d++) orig_size *= (uint64_t)(completed_pg_reqgroup->orig_varblock->count[d]); void* orig_buff = malloc(orig_size); int ndims = 1; uint64_t dim[1] = {orig_size / sizeof(double)}; int rtn = decompress_szip_pre_allocated(raw_buff, raw_size, orig_buff, &orig_size, ndims, dim); if(rtn != 0) { return NULL; } return adios_datablock_new(reqgroup->transinfo->orig_type, completed_pg_reqgroup->timestep, completed_pg_reqgroup->pg_bounds_sel, orig_buff); }
// NCSU ALACRITY-ADIOS - Compute the pre-transform size of a variable, in bytes // Precondition: var is a non-scalar that has been transformed (transform_type != none) uint64_t adios_transform_get_pre_transform_var_size(struct adios_var_struct *var) { assert(var->dimensions); assert(var->type != adios_string); assert(var->transform_type != adios_transform_none); return adios_get_type_size(var->pre_transform_type, NULL) * adios_get_dimension_space_size(var, var->pre_transform_dimensions); }
static uint64_t compute_selection_size_in_bytes(const ADIOS_SELECTION *sel, enum ADIOS_DATATYPES datum_type, int timestep, const ADIOS_VARINFO *raw_varinfo, const ADIOS_TRANSINFO *transinfo) { int typesize = adios_get_type_size(datum_type, NULL); int i; switch (sel->type) { case ADIOS_SELECTION_BOUNDINGBOX: { const ADIOS_SELECTION_BOUNDINGBOX_STRUCT *bb = &sel->u.bb; const int ndim = bb->ndim; uint64_t size = typesize; for (i = 0; i < ndim; i++) size *= bb->count[i]; return size; } case ADIOS_SELECTION_POINTS: { const ADIOS_SELECTION_POINTS_STRUCT *pts = &sel->u.points; return pts->ndim * pts->npoints * typesize; } case ADIOS_SELECTION_WRITEBLOCK: { const ADIOS_SELECTION_WRITEBLOCK_STRUCT *wb = &sel->u.block; if (wb->is_sub_pg_selection) { return wb->nelements * typesize; } else { const ADIOS_VARBLOCK *theblock; uint64_t size = typesize; int absolute_idx; if (wb->is_absolute_index) { absolute_idx = wb->index; } else { int timestep_start_idx = 0; for (i = 0; i < timestep; i++) timestep_start_idx += raw_varinfo->nblocks[i]; absolute_idx = timestep_start_idx + wb->index; } theblock = &transinfo->orig_blockinfo[absolute_idx]; for (i = 0; i < transinfo->orig_ndim; i++) size *= theblock->count[i]; return size; } } case ADIOS_SELECTION_AUTO: default: adios_error_at_line(err_invalid_argument, __FILE__, __LINE__, "Unsupported selection type %d in data transform read layer", sel->type); return 0; } }
/* Store a scalar variable's values temporarily while we process the dimensions of the arrays in the same PG */ void store_scalar_dimensions ( struct adios_var_header_struct_v1 * var_header, struct adios_var_payload_struct_v1 * var_payload) { if (var_header->is_dim == adios_flag_yes) { if (var_header->id < MAX_DIMENSION_INDEX) { uint64_t size = adios_get_type_size (var_header->type, var_payload->payload); uint64_t d = 0L; switch (var_header->type) { case adios_byte: d = *(signed char *) var_payload->payload; break; case adios_unsigned_byte: d = *(unsigned char *) var_payload->payload; break; case adios_short: d = *(signed short *) var_payload->payload; break; case adios_unsigned_short: d = *(unsigned short *) var_payload->payload; break; case adios_integer: d = *(signed int *) var_payload->payload; break; case adios_unsigned_integer: d = *(unsigned int *) var_payload->payload; break; case adios_long: d = *(signed long long *) var_payload->payload; break; case adios_unsigned_long: d = *(unsigned long long *) var_payload->payload; break; default: printf (" !!! ERROR !!! The variable %s/%s appears to be used " "as dimension but it has non-integer type.\n", var_header->path, var_header->name); break; } dim_value [var_header->id] = *(unsigned int *) var_payload->payload; } else { printf (" !!! ERROR !!! This tool can only handle scalar variables" " used as dimensions if they appear as the first %d variables. " "Here we encountered a scalar named %s/%s with id=%d\n", MAX_DIMENSION_INDEX, var_header->path, var_header->name, var_header->id); } } }
static uint64_t compute_groupsize(uint64_t base_groupsize, const dataset_xml_spec_t *xml_spec, const dataset_pg_spec_t *pg) { int var, dim; // Compute the number of points contained in this PG uint64_t pg_gridsize = dim_prod(xml_spec->ndim, pg->pg_dim); // Compute the sum of the datatype sizes across all variables defined in this PG uint64_t total_var_datatypes_size = 0; for (var = 0; var < xml_spec->nvar; ++var) total_var_datatypes_size += adios_get_type_size(xml_spec->vartypes[var], NULL); // The final group size is the product of the number of points and the number of bytes per point, plus the base groupsize return base_groupsize + pg_gridsize * total_var_datatypes_size; }
adios_datablock * adios_transform_bzip2_pg_reqgroup_completed(adios_transform_read_request *reqgroup, adios_transform_pg_read_request *completed_pg_reqgroup) { uint64_t compressed_size = (uint64_t)completed_pg_reqgroup->raw_var_length; void* compressed_data = completed_pg_reqgroup->subreqs->data; uint64_t uncompressed_size_meta = *((uint64_t*)reqgroup->transinfo->transform_metadata); char compress_ok = *((char*)(reqgroup->transinfo->transform_metadata + sizeof(uint64_t))); uint64_t uncompressed_size = adios_get_type_size(reqgroup->transinfo->orig_type, ""); int d = 0; for(d = 0; d < reqgroup->transinfo->orig_ndim; d++) { uncompressed_size *= (uint64_t)(completed_pg_reqgroup->orig_varblock->count[d]); } if(uncompressed_size_meta != uncompressed_size) { printf("WARNING: possible wrong data size or corrupted metadata\n"); } void* uncompressed_data = malloc(uncompressed_size); if(!uncompressed_data) { return NULL; } if(compress_ok == 1) // compression is successful { int rtn = decompress_bzip2_pre_allocated(compressed_data, compressed_size, uncompressed_data, &uncompressed_size); if(rtn != 0) { return NULL; } } else // just copy the buffer since data is not compressed { // printf("compression failed before, fall back to memory copy\n"); memcpy(uncompressed_data, compressed_data, compressed_size); } return adios_datablock_new(reqgroup->transinfo->orig_type, completed_pg_reqgroup->timestep, completed_pg_reqgroup->pg_bounds_sel, uncompressed_data); }
// NOTE: varblocks_by_var is actually a 1D array varblocks_by_var[var] of 3D "arrays" varblockdata[ts][pg][point_in_pg] of type xml_spec->vartypes[var] (however, points per PG varies) static void collect_varblocks_by_pg( const dataset_xml_spec_t *xml_spec, const dataset_global_spec_t *global_spec, int num_ts, int num_pgs_per_ts, int ndim, int nvar, const uint64_t pg_dims[num_ts][num_pgs_per_ts][ndim], const void **varblocks_by_var, const void *out_varblocks_by_pg[num_ts][num_pgs_per_ts][nvar]) { int ts, pg, var; // Some maths const uint64_t varblocks_per_ts = nvar * num_pgs_per_ts; // Cache the datatype size for each variable, and create a data pointer that we can advance int var_typesizes[nvar]; const char *varblock_datas[nvar]; for (var = 0; var < nvar; ++var) { var_typesizes[var] = adios_get_type_size(xml_spec->vartypes[var], NULL); varblock_datas[var] = (const char *)varblocks_by_var[var]; } // Iterate over all varblocks (var in pg in timestep), get a pointer to the data buffer for that // varblock, and assign it to the proper place in the output array of PG data buffers for (ts = 0; ts < num_ts; ++ts) { for (pg = 0; pg < num_pgs_per_ts; ++pg) { // Compute the points per varblock in this PG const uint64_t points_per_varblock = dim_prod(ndim, pg_dims[ts][pg]); for (var = 0; var < nvar; ++var) { const int var_typesize = var_typesizes[var]; const uint64_t varblock_size = points_per_varblock * var_typesize; // Get the data for this varblock, and advance the pointer by one varblock const char *data_for_varblock = varblock_datas[var]; varblock_datas[var] += varblock_size; // Finally, assign the pointer out_varblocks_by_pg[ts][pg][var] = data_for_varblock; } } } }
inline static uint64_t adios_patch_data_wb_to_wb(void *dst, uint64_t dst_ragged_offset, const ADIOS_SELECTION_WRITEBLOCK_STRUCT *dst_wb, void *src, uint64_t src_ragged_offset, const ADIOS_SELECTION_WRITEBLOCK_STRUCT *src_wb, const ADIOS_SELECTION_BOUNDINGBOX_STRUCT *vb_bounds, enum ADIOS_DATATYPES datum_type, enum ADIOS_FLAG swap_endianness) { uint64_t copy_elem_offset, copy_nelems; const uint64_t vb_size_in_elements = compute_volume(vb_bounds->ndim, vb_bounds->count); const uint64_t dst_elem_offset = dst_wb->is_sub_pg_selection ? dst_wb->element_offset : 0; const uint64_t dst_nelems = dst_wb->is_sub_pg_selection ? dst_wb->nelements : vb_size_in_elements; const uint64_t src_elem_offset = src_wb->is_sub_pg_selection ? src_wb->element_offset : 0; const uint64_t src_nelems = src_wb->is_sub_pg_selection ? src_wb->nelements : vb_size_in_elements; // Find out how many elements overlap between the two // writeblock selections (due to the potential existence // of sub-PG writeblock selections; if both are whole-PG, // this overlap will be complete) int intersects = intersect_segments( dst_elem_offset, dst_nelems, src_elem_offset, src_nelems, ©_elem_offset, ©_nelems ); // Copy any elements that are common to both selections // (for whole-PG writeblock selections, this will be all of them) if (intersects) { int typesize = adios_get_type_size(datum_type, NULL); void *copy_dst = (char*)dst + (copy_elem_offset - dst_elem_offset) * typesize; void *copy_src = (char*)src + (copy_elem_offset - src_elem_offset) * typesize; memcpy(copy_dst, copy_src, copy_nelems * typesize); if (swap_endianness == adios_flag_yes) change_endianness(copy_dst, copy_nelems * typesize, datum_type); return copy_nelems; } else { return 0; } }
static void test_file_mode_reads_on_var(ADIOS_FILE *fp, const char *bp_filename, const char *varname) { int i; ADIOS_VARINFO *varinfo = adios_inq_var(fp, varname); MPI_Assert(COMM, varinfo); if (varinfo->value != NULL) { //if (rank == 0) fprintf(stderr, "(skipping scalar variable '%s')\n", varname); adios_free_varinfo(varinfo); return; } fprintf(stderr, "[rank %d/%d] Starting file-mode writeblock reads on %s:/%s\n", rank, size, bp_filename, varname); adios_inq_var_blockinfo(fp, varinfo); MPI_Assert(COMM, varinfo->blockinfo); const enum ADIOS_DATATYPES datatype = varinfo->type; const int datatypesize = adios_get_type_size(datatype, NULL); int timestep, timestep_blockidx, blockidx = 0; for (timestep = 0; timestep < varinfo->nsteps; ++timestep) { for (timestep_blockidx = 0; timestep_blockidx < varinfo->nblocks[timestep]; ++timestep_blockidx, ++blockidx) { if (blockidx % size != rank) continue; const ADIOS_VARBLOCK *vb = &varinfo->blockinfo[blockidx]; ADIOS_SELECTION *block_bb = adios_selection_boundingbox(varinfo->ndim, vb->start, vb->count); ADIOS_SELECTION *block_wb = adios_selection_writeblock(timestep_blockidx); ADIOS_SELECTION *block_abs_wb = adios_selection_writeblock(blockidx); block_abs_wb->u.block.is_absolute_index = 1; uint64_t blocksize = datatypesize; for (i = 0; i < varinfo->ndim; ++i) blocksize *= vb->count[i]; void *buf_bb = malloc(blocksize); void *buf_wb = malloc(blocksize); void *buf_abs_wb = malloc(blocksize); memset(buf_bb, 0, blocksize); memset(buf_wb, 1, blocksize); memset(buf_abs_wb, 2, blocksize); MPI_Assert(COMM, buf_bb && buf_wb && buf_abs_wb); adios_schedule_read(fp, block_bb, varname, timestep, 1, buf_bb ); adios_schedule_read(fp, block_wb, varname, timestep, 1, buf_wb ); adios_schedule_read(fp, block_abs_wb, varname, timestep, 1, buf_abs_wb); adios_perform_reads(fp, 1); fprintf(stderr, "[rank %d/%d] Checking file-mode blockidx %d BB vs. WB...\n", rank, size, blockidx); MPI_Assert(COMM, memcmp(buf_bb, buf_wb, blocksize) == 0); fprintf(stderr, "[rank %d/%d] Checking file-mode blockidx %d BB vs. abs-WB...\n", rank, size, blockidx); MPI_Assert(COMM, memcmp(buf_bb, buf_abs_wb, blocksize) == 0); free(buf_bb); free(buf_wb); free(buf_abs_wb); adios_selection_delete(block_bb); adios_selection_delete(block_wb); adios_selection_delete(block_abs_wb); } } adios_free_varinfo(varinfo); fprintf(stderr, "[rank %d/%d] Finished file-mode writeblock reads on %s:/%s\n", rank, size, bp_filename, varname); }
// Whenever we are patching between a point selection and bounding box, we // will always iterate over the point selection, check each points for containment // within the bounding box, and compute byte offsets for the point within the point list // and bounding box, regardless of whether the point selection is on the source or // destination buffer. Therefore, we include a helper function with a boolean flag // to switch the copy direction, and just branch for a few lines during the copy // operation. This simplifies the code a lot, and reduces the LoC in this file (although // this comment makes up for a good bit of that savings). inline static uint64_t adios_patch_data_bb_pts_helper(void *dst, uint64_t dst_ragged_offset, void *src, uint64_t src_ragged_offset, const ADIOS_SELECTION_POINTS_STRUCT *pts, const ADIOS_SELECTION_BOUNDINGBOX_STRUCT *bb, _Bool isDestPoints, enum ADIOS_DATATYPES datum_type, enum ADIOS_FLAG swap_endianness) { const int ndim = pts->ndim; uint64_t i; int j; uint64_t pts_copied = 0; uint64_t byte_offset_in_bb_buffer, byte_offset_in_pt_buffer; const uint64_t *cur_pt; uint64_t *bb_byte_strides = malloc(sizeof(uint64_t) * ndim); uint64_t *pt_relative_to_bb = malloc(sizeof(uint64_t) * ndim); // Compute the strides into the source bounding box array int typelen = adios_get_type_size(datum_type, NULL); uint64_t bb_volume = typelen; for (j = ndim - 1; j >= 0; j--) { bb_byte_strides[j] = bb_volume; bb_volume *= bb->count[j]; } uint64_t dst_byte_ragged_offset = dst_ragged_offset * typelen; uint64_t src_byte_ragged_offset = src_ragged_offset * typelen; // Check that the selection dimensions are compatible assert(pts->ndim == bb->ndim); // Check each point; if it's in the bounding box, perform a copy for (i = 0; i < pts->npoints; i++) { cur_pt = &pts->points[i * ndim]; for (j = 0; j < ndim; j++) { // If the point's coordinate in some dimension is outside the bounding box if (cur_pt[j] < bb->start[j] || cur_pt[j] >= bb->start[j] + bb->count[j]) { break; } } // If the point is within the bounding box if (j == ndim) { vector_sub(ndim, pt_relative_to_bb, cur_pt, bb->start); byte_offset_in_bb_buffer = 0; for (j = 0; j < ndim; j++) byte_offset_in_bb_buffer += pt_relative_to_bb[j] * bb_byte_strides[j]; byte_offset_in_pt_buffer = i * typelen; if (isDestPoints) { assert(byte_offset_in_pt_buffer >= dst_byte_ragged_offset); assert(byte_offset_in_bb_buffer >= src_byte_ragged_offset); memcpy((char*)dst + byte_offset_in_pt_buffer - dst_byte_ragged_offset, (char*)src + byte_offset_in_bb_buffer - src_byte_ragged_offset, typelen); } else { assert(byte_offset_in_bb_buffer >= dst_byte_ragged_offset); assert(byte_offset_in_pt_buffer >= src_byte_ragged_offset); memcpy((char*)dst + byte_offset_in_bb_buffer - dst_byte_ragged_offset, (char*)src + byte_offset_in_pt_buffer - src_byte_ragged_offset, typelen); } pts_copied++; } } free(bb_byte_strides); free(pt_relative_to_bb); return pts_copied; }
void add_var_to_index ( struct adios_index_struct_v1 * index, struct adios_process_group_header_struct_v1 * pg_header, struct adios_var_header_struct_v1 * var_header, struct adios_var_payload_struct_v1 * var_payload) { /* similar to code from adios_internals.c:adios_build_index_v1() */ struct adios_index_var_struct_v1 * v_index; v_index = malloc (sizeof (struct adios_index_var_struct_v1)); v_index->characteristics = malloc ( sizeof (struct adios_index_characteristic_struct_v1) ); v_index->id = var_header->id; v_index->group_name = strdup (pg_header->name); v_index->var_name = (var_header->name ? strdup (var_header->name) : 0L); v_index->var_path = (var_header->path ? strdup (var_header->path) : 0L); v_index->type = var_header->type; v_index->characteristics_count = 1; v_index->characteristics_allocated = 1; v_index->characteristics [0].offset = var_header->characteristics.offset; v_index->characteristics [0].payload_offset = var_header->characteristics.payload_offset; v_index->characteristics [0].file_index = -1; // It works only with single BP files v_index->characteristics [0].time_index = pg_header->time_index; v_index->characteristics [0].value = 0; /* Determine the dimensions from actual values or references of scalars */ process_dimensions (var_header, v_index); // NCSU - Initializing stat related info in index v_index->characteristics [0].bitmap = 0; v_index->characteristics [0].stats = 0; memcpy (&v_index->characteristics[0].transform, &var_header->characteristics.transform, sizeof (struct adios_index_characteristic_transform_struct)); // Save scalar's value if (var_payload->payload) { uint64_t size = adios_get_type_size (var_header->type, var_payload->payload); if (var_header->type == adios_string) { v_index->characteristics [0].value = malloc (size + 1); memcpy (v_index->characteristics [0].value, var_payload->payload, size); ((char *) (v_index->characteristics [0].value)) [size] = 0; } else { v_index->characteristics [0].value = malloc (size); memcpy (v_index->characteristics [0].value, var_payload->payload, size); } } /* FIXME: Missing statistics and transformation statistics */ v_index->next = 0; // this fn will either take ownership for free //printf (" add index var %s/%s\n", v_index->var_path, v_index->var_name); index_append_var_v1 (index, v_index, 1); }