// Note: assumes one or more of datablock->bounds or output_sel is local static uint64_t apply_datablock_to_buffer_nonlocal_selections( const ADIOS_VARINFO *raw_varinfo, const ADIOS_TRANSINFO *transinfo, adios_datablock *datablock, void **output_buffer, const ADIOS_SELECTION *output_sel, ADIOS_SELECTION **out_inter_sel, int want_out_inter_sel, enum ADIOS_FLAG swap_endianness) { int may_have_intersection = 1; uint64_t used_count = 0; const ADIOS_SELECTION *global_output_buffer_sel = output_sel; const ADIOS_SELECTION *global_datablock_bounds = datablock->bounds; // Promote output buffer selection and/or datablock selection to global if needed if (!is_global_selection(global_output_buffer_sel)) global_output_buffer_sel = create_writeblock_bounds(&global_output_buffer_sel->u.block, datablock->timestep, raw_varinfo, transinfo); if (!is_global_selection(global_datablock_bounds)) global_datablock_bounds = create_writeblock_bounds(&global_datablock_bounds->u.block, datablock->timestep, raw_varinfo, transinfo); // Compute the intersection explicitly if it is requested, or // if we need to allocate a fitting output buffer if (want_out_inter_sel || !*output_buffer) { *out_inter_sel = adios_selection_intersect_global(global_datablock_bounds, global_output_buffer_sel); may_have_intersection = (*out_inter_sel ? 1 : 0); } // We can stop immediately if it is known there is no intersection if (may_have_intersection) { // Allocate the output buffer if needed (inter_sel is populated by previous if statement) if (!*output_buffer) { const uint64_t chunk_buffer_size = compute_selection_size_in_bytes(*out_inter_sel, datablock->elem_type, datablock->timestep, raw_varinfo, transinfo); *output_buffer = malloc(chunk_buffer_size); // Refitting the output selection to the intersection region, since we // just allocated a buffer for that smaller region if (global_output_buffer_sel != output_sel) a2sel_free((ADIOS_SELECTION *)global_output_buffer_sel); output_sel = *out_inter_sel; global_output_buffer_sel = *out_inter_sel; } // Perform the actual data patching, now that everything is in the global space used_count = adios_patch_data_to_global( *output_buffer, (uint64_t)0, global_output_buffer_sel, datablock->data, datablock->ragged_offset, global_datablock_bounds, datablock->elem_type, swap_endianness); } // Clean up if (global_output_buffer_sel != output_sel) a2sel_free((ADIOS_SELECTION *)global_output_buffer_sel); if (global_datablock_bounds != datablock->bounds) a2sel_free((ADIOS_SELECTION *)global_datablock_bounds); return used_count; }
/* * Takes a datablock and applies its data to the user buffer for the given * read request group, then frees the given datablock. Assumes there is, in * fact, a user buffer (i.e., it is not NULL). * * Assumes that the datablock selection is of type bounding box. * * NOTE: also frees the data buffer within the datablock * * @return non-zero if some data in the datablock intersected the read * request's selection, and was applied; returns 0 otherwise. */ static int apply_datablock_to_result_and_free(adios_datablock *datablock, adios_transform_read_request *reqgroup) { assert(datablock); assert(reqgroup); assert(reqgroup->orig_sel); assert(reqgroup->orig_data); void *output_buffer; if (is_global_selection(reqgroup->orig_sel)) { // All timestep results have the same size in bytes, so offset the // output pointer by however many timesteps precede this timestep const int timestep_within_request = datablock->timestep - reqgroup->from_steps; output_buffer = (char*)reqgroup->orig_data + timestep_within_request * reqgroup->orig_sel_timestep_size; } else if (reqgroup->orig_sel->type == ADIOS_SELECTION_WRITEBLOCK) { // For writeblock selections, computing the output buffer position for // the current timestep is a bit trickier, since varblocks may be // different sizes in different timesteps const ADIOS_SELECTION_WRITEBLOCK_STRUCT *orig_sel_wb = &reqgroup->orig_sel->u.block; // Compute the offset into the output buffer at which the current timestep's output should go // For absolute writeblocks, it's always 0, since there is only 1 timestep involved. For // timestep-relative writeblock selections, we add the size of the writeblock (i.e. varblock) // for all previous timesteps in the user's read request. uint64_t output_buffer_offset = 0; if (!orig_sel_wb->is_absolute_index) { int timestep; for (timestep = reqgroup->from_steps; timestep < datablock->timestep; timestep++) { // Compute the size of the writeblock at this timestep and add it to our offset output_buffer_offset += compute_selection_size_in_bytes(reqgroup->orig_sel, reqgroup->transinfo->orig_type, timestep, reqgroup->raw_varinfo, reqgroup->transinfo); } } // Offset the output pointer by the computed amount output_buffer = (char*)reqgroup->orig_data + output_buffer_offset; } else { adios_error_at_line(err_unspecified, __FILE__, __LINE__, "Internal error: unexpected selection type %d, this should not be possible here\n", reqgroup->orig_sel->type); } // Now that we have the output buffer pointer, actually perform the patch operation const uint64_t used_count = apply_datablock_to_buffer_and_free( reqgroup->raw_varinfo, reqgroup->transinfo, datablock, &output_buffer, reqgroup->orig_sel, NULL /* don't need the intersection */, reqgroup->swap_endianness); return used_count != 0; }
static uint64_t apply_datablock_to_buffer_local_selections( const ADIOS_VARINFO *raw_varinfo, const ADIOS_TRANSINFO *transinfo, adios_datablock *datablock, void **output_buffer, const ADIOS_SELECTION *output_sel, ADIOS_SELECTION **out_inter_sel, int want_out_inter_sel, enum ADIOS_FLAG swap_endianness) { int may_have_intersection = 1; // For writeblock selections, we can use adios_patch_data_to_local, // but first we must determine the bounding box of the writeblock selection const ADIOS_SELECTION *vb_bounds_sel = create_writeblock_bounds(&output_sel->u.block, datablock->timestep, raw_varinfo, transinfo); // Compute the intersection explicitly if it is requested, or // if we need to allocate a fitting output buffer if (want_out_inter_sel || !*output_buffer) { *out_inter_sel = adios_selection_intersect_local(datablock->bounds, output_sel, datablock->timestep, raw_varinfo, transinfo); may_have_intersection = (*out_inter_sel ? 1 : 0); } // Allocate the output buffer if needed (inter_sel is populated by previous if statement) if (!*output_buffer) { const uint64_t chunk_buffer_size = compute_selection_size_in_bytes(*out_inter_sel, datablock->elem_type, datablock->timestep, raw_varinfo, transinfo); *output_buffer = malloc(chunk_buffer_size); // Refitting the output selection to the intersection region, since we // just allocated a buffer for that smaller region output_sel = *out_inter_sel; } // Invoke adios_patch_data_to_local to perform the actual patching const uint64_t used_count = adios_patch_data_to_local( *output_buffer, (uint64_t)0, output_sel, datablock->data, datablock->ragged_offset, datablock->bounds, &vb_bounds_sel->u.bb, datablock->elem_type, swap_endianness); // Clean up common_read_selection_delete((ADIOS_SELECTION *)vb_bounds_sel); return used_count; }