// The if statements impose a total order on the selection types, and call this function // with arguments swapped if they are out of this order. This simplifies the above helper // functions. ADIOS_SELECTION * adios_selection_intersect_global(const ADIOS_SELECTION *s1, const ADIOS_SELECTION *s2) { if (!is_global_selection(s1) || !is_global_selection(s2)) { adios_error_at_line(err_invalid_argument, __FILE__, __LINE__, "Internal error: adios_selection_intersect_global called on non-global selection(s)"); return NULL; } switch (s1->type) { case ADIOS_SELECTION_BOUNDINGBOX: { const ADIOS_SELECTION_BOUNDINGBOX_STRUCT *bb1 = &s1->u.bb; return adios_selection_intersect_bb(bb1, s2); } case ADIOS_SELECTION_POINTS: { const ADIOS_SELECTION_POINTS_STRUCT *pts1 = &s1->u.points; if (s1->type == ADIOS_SELECTION_BOUNDINGBOX) { return adios_selection_intersect_global(s2, s1); } else { return adios_selection_intersect_pts(pts1, s2); } } default: adios_error_at_line(err_invalid_argument, __FILE__, __LINE__, "Unknown selection type %d", s1->type); return NULL; } }
// 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; }
static int generate_read_request_for_pg( const ADIOS_VARINFO *raw_varinfo, const ADIOS_TRANSINFO *transinfo, const ADIOS_SELECTION *sel, int timestep, int timestep_blockidx, int blockidx, adios_transform_read_request *readreq) { const ADIOS_SELECTION *pg_bounds_sel; ADIOS_SELECTION *pg_intersection_sel; ADIOS_SELECTION *pg_writeblock_sel; const ADIOS_VARBLOCK *raw_vb = &raw_varinfo->blockinfo[blockidx]; const ADIOS_VARBLOCK *orig_vb = &transinfo->orig_blockinfo[blockidx]; pg_bounds_sel = create_pg_bounds_from_varblock(transinfo->orig_ndim, orig_vb); pg_writeblock_sel = a2sel_writeblock(blockidx); pg_writeblock_sel->u.block.is_absolute_index = 1; // Find the intersection, if any if (is_global_selection(sel)) { pg_intersection_sel = adios_selection_intersect_global(pg_bounds_sel, sel); } else if (sel->type == ADIOS_SELECTION_WRITEBLOCK) { pg_intersection_sel = adios_selection_intersect_local(pg_writeblock_sel, sel, timestep, raw_varinfo, transinfo); } else { abort(); // Should never be called with other types of selections } a2sel_free(pg_writeblock_sel); // If there is an intersection, generate a corresponding PG read request if (pg_intersection_sel) { // Make a PG read request group, and fill it with some subrequests, and link it into the read reqgroup adios_transform_pg_read_request *new_pg_readreq; new_pg_readreq = adios_transform_pg_read_request_new(timestep, timestep_blockidx, blockidx, transinfo->orig_ndim, raw_varinfo->ndim, orig_vb, raw_vb, pg_intersection_sel, pg_bounds_sel, transinfo->transform_metadatas[blockidx].content, (uint16_t)transinfo->transform_metadatas[blockidx].length); adios_transform_generate_read_subrequests(readreq, new_pg_readreq); adios_transform_pg_read_request_append(readreq, new_pg_readreq); // Don't free pg_bounds_sel or pg_intersection_sel, since they are now // held by the adios_transform_pg_read_request struct return 1; } else { // Cleanup a2sel_free((ADIOS_SELECTION *)pg_bounds_sel); // OK to delete, because this function only frees the outer struct, not the arrays within return 0; } }
ADIOS_PG_INTERSECTIONS * adios_find_intersecting_pgs(const ADIOS_FILE *fp, int varid, const ADIOS_SELECTION *sel, const int from_step, const int nsteps) { // Declares adios_transform_read_request *new_reqgroup; int blockidx, timestep, timestep_blockidx; int curblocks, start_blockidx, end_blockidx; int intersects; ADIOS_VARBLOCK *raw_vb, *vb; enum ADIOS_FLAG swap_endianness = (fp->endianness == get_system_endianness()) ? adios_flag_no : adios_flag_yes; int to_steps = from_step + nsteps; // As long as we don't free/destroy it, using the infocache from the file will have no effect on future // operations using the file (except possibly speeding them up, so "constness" is still respected adios_infocache *infocache = common_read_get_file_infocache((ADIOS_FILE*)fp); ADIOS_PG_INTERSECTIONS *resulting_intersections = (ADIOS_PG_INTERSECTIONS *)calloc(1, sizeof(ADIOS_PG_INTERSECTIONS)); resulting_intersections->npg = 0; int intersection_capacity = INITIAL_INTERSECTION_CAPACITY; resulting_intersections->intersections = (ADIOS_PG_INTERSECTION *)calloc(intersection_capacity, sizeof(ADIOS_PG_INTERSECTION)); // Precondition checking if (sel->type != ADIOS_SELECTION_BOUNDINGBOX && sel->type != ADIOS_SELECTION_POINTS) { adios_error(err_operation_not_supported, "Only bounding box and point selections are currently supported during read on transformed variables."); } // Still respecting constness, since we're going to undo this const data_view_t old_view = adios_read_set_data_view((ADIOS_FILE*)fp, LOGICAL_DATA_VIEW); // Temporarily go to logical data view const ADIOS_VARINFO *varinfo = adios_infocache_inq_varinfo(fp, infocache, varid); assert(from_step >= 0 && to_steps <= varinfo->nsteps); // Compute the blockidx range, given the timesteps compute_blockidx_range(varinfo, from_step, to_steps, &start_blockidx, &end_blockidx); // Retrieve blockinfos, if they haven't been done retrieved if (!varinfo->blockinfo) common_read_inq_var_blockinfo(fp, (ADIOS_VARINFO *)varinfo); // Undoing view set (returning to const state) adios_read_set_data_view((ADIOS_FILE*)fp, old_view); // Reset the data view to whatever it was before // Assemble read requests for each varblock blockidx = start_blockidx; timestep = from_step; timestep_blockidx = 0; while (blockidx != end_blockidx) { //for (blockidx = startblock_idx; blockidx != endblock_idx; blockidx++) { ADIOS_SELECTION *pg_bounds_sel; ADIOS_SELECTION *pg_intersection_sel; vb = &varinfo->blockinfo[blockidx]; pg_bounds_sel = create_pg_bounds(varinfo->ndim, vb); // Find the intersection, if any pg_intersection_sel = adios_selection_intersect_global(pg_bounds_sel, sel); if (pg_intersection_sel) { // Expand the PG intersection array, if needed if (resulting_intersections->npg == intersection_capacity) { intersection_capacity *= 2; resulting_intersections->intersections = (ADIOS_PG_INTERSECTION *)realloc(resulting_intersections->intersections, intersection_capacity * sizeof(ADIOS_PG_INTERSECTION)); if (!resulting_intersections->intersections) { adios_error (err_no_memory, "Cannot allocate buffer for PG intersection results in adios_find_intersecting_pgs (required %llu bytes)\n", intersection_capacity * sizeof(ADIOS_PG_INTERSECTION)); return NULL; } } ADIOS_PG_INTERSECTION *intersection = &resulting_intersections->intersections[resulting_intersections->npg]; intersection->timestep = timestep; intersection->blockidx = blockidx; intersection->blockidx_in_timestep = timestep_blockidx; intersection->intersection_sel = pg_intersection_sel; intersection->pg_bounds_sel = pg_bounds_sel; resulting_intersections->npg++; } else { // Cleanup common_read_selection_delete(pg_bounds_sel); // OK to delete, because this function only frees the outer struct, not the arrays within } // Increment block indexes blockidx++; timestep_blockidx++; if (timestep_blockidx == varinfo->nblocks[timestep]) { timestep_blockidx = 0; timestep++; } } return resulting_intersections; }