ADIOS_VARINFO* adios_read_flexpath_inq_var(const ADIOS_FILE * adiosfile, const char* varname) { fp_log("FUNC", "entering flexpath_inq_var\n"); flexpath_reader_file *fp = (flexpath_reader_file*)adiosfile->fh; ADIOS_VARINFO *v = malloc(sizeof(ADIOS_VARINFO)); if(!v) { adios_error(err_no_memory, "Cannot allocate buffer in adios_read_datatap_inq_var()"); return NULL; } memset(v, 0, sizeof(ADIOS_VARINFO)); flexpath_var *fpvar = find_fp_var(fp->var_list, varname); if(fpvar) { v = convert_var_info(fpvar, v, varname, adiosfile); fp_log("FUNC", "leaving flexpath_inq_var\n"); return v; } else { adios_error(err_invalid_varname, "Cannot find var %s\n", varname); return NULL; } }
static int group_msg_handler(CManager cm, void *vevent, void *client_data, attr_list attrs) { EVtake_event_buffer(fp_read_data->fp_cm, vevent); evgroup *msg = (evgroup*)vevent; ADIOS_FILE *adiosfile = client_data; flexpath_reader_file * fp = (flexpath_reader_file*)adiosfile->fh; fp->gp = msg; int i; for(i = 0; i<msg->num_vars; i++){ global_var *gblvar = &msg->vars[i]; flexpath_var *fpvar = find_fp_var(fp->var_list, gblvar->name); if(fpvar){ offset_struct *offset = &gblvar->offsets[0]; uint64_t *local_dimensions = offset->local_dimensions; uint64_t *local_offsets = offset->local_offsets; uint64_t *global_dimensions = offset->global_dimensions; fpvar->num_dims = offset->offsets_per_rank; fpvar->global_dims = malloc(sizeof(uint64_t)*fpvar->num_dims); memcpy(fpvar->global_dims, global_dimensions, sizeof(uint64_t)*fpvar->num_dims); }else{ adios_error(err_corrupted_variable, "Mismatch between global variables and variables specified %s.", gblvar->name); return err_corrupted_variable; } } CMCondition_signal(fp_read_data->fp_cm, msg->condition); return 0; }
ADIOS_FILE* adios_read_flexpath_open_file(const char * fname, MPI_Comm comm) { adios_error (err_operation_not_supported, "FLEXPATH staging method does not support file mode for reading. " "Use adios_read_open() to open a staged dataset.\n"); return NULL; }
ADIOS_VARINFO* convert_var_info(flexpath_var * fpvar, ADIOS_VARINFO * v, const char* varname, const ADIOS_FILE *adiosfile) { int i; flexpath_reader_file *fp = (flexpath_reader_file*)adiosfile->fh; v->type = fpvar->type; v->ndim = fpvar->num_dims; // needs to change. Has to get information from write. v->nsteps = 1; v->nblocks = malloc(sizeof(int)*v->nsteps); v->sum_nblocks = 1; v->nblocks[0] = 1; v->statistics = NULL; v->blockinfo = NULL; if(v->ndim == 0){ int value_size = fpvar->type_size; v->value = malloc(value_size); if(!v->value) { adios_error(err_no_memory, "Cannot allocate buffer in adios_read_datatap_inq_var()"); return NULL; } flexpath_var_chunk * chunk = &fpvar->chunks[0]; memcpy(v->value, chunk->data, value_size); v->global = 0; }else{ // arrays v->dims = (uint64_t*)malloc(v->ndim * sizeof(uint64_t)); if(!v->dims) { adios_error(err_no_memory, "Cannot allocate buffer in adios_read_datatap_inq_var()"); return NULL; } // broken. fix. int cpysize = fpvar->num_dims*sizeof(uint64_t); if(fpvar->global_dims){ v->global = 1; memcpy(v->dims, fpvar->global_dims, cpysize); } else{ v->global = 0; } } return v; }
ADIOS_QUERY* common_query_combine(ADIOS_QUERY* q1, enum ADIOS_CLAUSE_OP_MODE operator, ADIOS_QUERY* q2) { // combine selection sel3 = q1.fastbitSelection & q2.fastbitSelection //create a new query (q1.cond :op: q2.cond, sel3); //ADIOS_QUERY* result = (ADIOS_QUERY*)malloc(sizeof(ADIOS_QUERY)); if ((q1 == NULL) || (q2 == NULL)) { log_error("Error: detected NULL query when combining.\n"); adios_error (err_incompatible_queries, "Query combine: NULL passed as query.\n"); return NULL; } if (isCompatible(q1, q2) != 0) { adios_error (err_incompatible_queries, "Query combine: the two queries' selections are not compatible.\n"); return NULL; } ADIOS_QUERY* result = (ADIOS_QUERY*)calloc(1, sizeof(ADIOS_QUERY)); initialize(result); result->condition = malloc(strlen(q1->condition)+strlen(q2->condition)+10); if (operator == ADIOS_QUERY_OP_AND) { sprintf(result->condition, "(%s and %s)", q1->condition, q2->condition); } else { sprintf(result->condition, "(%s or %s)", q1->condition, q2->condition); } q1->hasParent = 1; q2->hasParent = 1; result->left = q1; result->right = q2; result->combineOp = operator; result->rawDataSize = q1->rawDataSize; //initialize(result); return result; }
// Note: from_steps and nsteps are ignored in the absolute writeblock case static void populate_read_request_for_local_selection( const ADIOS_VARINFO *raw_varinfo, const ADIOS_TRANSINFO *transinfo, const ADIOS_SELECTION *sel, int from_steps, int nsteps, adios_transform_read_request *readreq) { int timestep, timestep_blockidx, blockidx; if (sel->type == ADIOS_SELECTION_WRITEBLOCK) { const ADIOS_SELECTION_WRITEBLOCK_STRUCT *wb = &sel->u.block; if (wb->is_absolute_index) { // For an absolute writeblock, at most one PG is touched (0 if erroneous blockidx) blockidx = wb->index; // Convert blockidx to timestep and timestep_blockidx int valid_blockidx = compute_relative_blockidx_from_absolute_blockidx(raw_varinfo, blockidx, ×tep, ×tep_blockidx); if (valid_blockidx) { generate_read_request_for_pg(raw_varinfo, transinfo, sel, timestep, timestep_blockidx, blockidx, readreq); } else { adios_error(err_invalid_timestep, "Writeblock selection with invalid absolute index %d passed to adios_schedule_read, caught in ADIOS transforms layer", wb->index); } } else { // For a relative writeblock, one PG may be touched per timestep in the user's timestep range timestep_blockidx = wb->index; for (timestep = from_steps; timestep < from_steps + nsteps; timestep++) { // Convert timestep (loop iterator variable) and timestep_blockidx to blockidx int valid_blockidx = compute_absolute_blockidx_from_relative_blockidx(raw_varinfo, timestep, timestep_blockidx, &blockidx); if (valid_blockidx) { generate_read_request_for_pg(raw_varinfo, transinfo, sel, timestep, timestep_blockidx, blockidx, readreq); } else { adios_error(err_invalid_timestep, "Writeblock selection with index %d passed to adios_schedule_read is invalid in timestep %d, caught in ADIOS transforms layer", wb->index, timestep); } } } } else { adios_error_at_line(err_operation_not_supported, __FILE__, __LINE__, "Internal error: unsupported selection type %d in populate_read_request_for_local_selection", sel->type); } }
int adios_read_flexpath_get_attr_byid (const ADIOS_FILE *adiosfile, int attrid, enum ADIOS_DATATYPES *type, int *size, void **data) { // log_debug( "debug: adios_read_flexpath_get_attr_byid\n"); // TODO: borrowed from dimes adios_error(err_invalid_read_method, "adios_read_flexpath_get_attr_byid is not implemented."); *size = 0; *type = adios_unknown; *data = 0; return adios_errno; }
int adios_read_flexpath_get_attr (int *gp, const char *attrname, enum ADIOS_DATATYPES *type, int *size, void **data) { //log_debug( "debug: adios_read_flexpath_get_attr\n"); // TODO: borrowed from dimes adios_error(err_invalid_read_method, "adios_read_flexpath_get_attr is not implemented."); *size = 0; *type = adios_unknown; *data = 0; return adios_errno; }
int adios_get_absolute_writeblock_index(const ADIOS_VARINFO *varinfo, int timestep_relative_idx, int timestep) { int i; int absolute_idx = timestep_relative_idx; assert(varinfo->blockinfo); if (timestep < 0 || timestep >= varinfo->nsteps) { adios_error(err_invalid_timestep, "Timestep %d out of range (min 0, max %d) (at %s:%s)", timestep, varinfo->nsteps, __FILE__, __LINE__); return -1; } if (timestep_relative_idx < 0 || timestep_relative_idx >= varinfo->nblocks[timestep]) { adios_error(err_invalid_argument, "Writeblock %d out of range for timestep %d (min 0, max %d) (at %s:%s)", timestep_relative_idx, timestep, varinfo->nsteps, __FILE__, __LINE__); return -1; } for (i = 0; i < timestep; i++) absolute_idx += varinfo->nblocks[i]; return absolute_idx; }
ADIOS_VARINFO* adios_read_flexpath_inq_var_byid (const ADIOS_FILE * adiosfile, int varid) { fp_log("FUNC", "entering flexpath_inq_var_byid\n"); flexpath_reader_file *fp = (flexpath_reader_file*)adiosfile->fh; if(varid >= 0 && varid < adiosfile->nvars) { ADIOS_VARINFO *v = adios_read_flexpath_inq_var(adiosfile, adiosfile->var_namelist[varid]); fp_log("FUNC", "leaving flexpath_inq_var_byid\n"); return v; } else { adios_error(err_invalid_varid, "FLEXPATH method: Cannot find var %d\n", varid); return NULL; } }
int adios_get_timing_value (int64_t fd_p, int64_t index, double* value) { struct adios_file_struct * fd = (struct adios_file_struct *) fd_p; if (!fd) { adios_error (err_invalid_file_pointer, "Invalid handle passed to adios_get_timing_value\n"); return 1; } *value = fd->timing_obj->times[index]; return 0; }
ADIOS_SELECTION * adios_selection_intersect_pts_pts(const ADIOS_SELECTION_POINTS_STRUCT *pts1, const ADIOS_SELECTION_POINTS_STRUCT *pts2) { const int ndim = pts1->ndim; const uint64_t max_new_npts = pts1->npoints > pts2->npoints ? pts1->npoints : pts2->npoints; uint64_t *new_pts = malloc(max_new_npts * ndim * sizeof(uint64_t)); int k; uint64_t *new_pts_ptr = new_pts; uint64_t *pts1_ptr, *pts2_ptr; const uint64_t * const pts1_end_ptr = pts1->points + pts1->npoints * ndim; const uint64_t * const pts2_end_ptr = pts2->points + pts2->npoints * ndim; uint64_t new_npts = 0; assert(pts1->ndim == pts2->ndim); if (!new_pts) { adios_error(err_no_memory, "Cannot allocate memory for POINTS-POINTS selection intersection"); return NULL; } // Check every pair of points for equality; whenever a shared point is found, output // it into the new point list for (pts1_ptr = pts1->points; pts1_ptr < pts1_end_ptr; pts1_ptr += ndim) { for (pts2_ptr = pts2->points; pts2_ptr < pts2_end_ptr; pts2_ptr += ndim) { // Check each dimension component of the pair of points for equality for (k = 0; k < ndim; k++) if (pts1_ptr[k] != pts2_ptr[k]) break; // Check whether any component was unequal; if so, skip this pair; otherwise, // output the shared point if (k != ndim) { continue; } else { memcpy(new_pts_ptr, pts1_ptr, ndim * sizeof(uint64_t)); new_pts_ptr += ndim; new_npts++; } } } if (new_npts == 0) { free(new_pts); return NULL; } else { new_pts = (uint64_t*)realloc(new_pts, new_npts * sizeof(uint64_t)); return common_read_selection_points(ndim, new_npts, new_pts); } }
adios_transform_read_request * adios_transform_generate_read_reqgroup(const ADIOS_VARINFO *raw_varinfo, const ADIOS_TRANSINFO* transinfo, const ADIOS_FILE *fp, const ADIOS_SELECTION *sel, int from_steps, int nsteps, const char *param, void *data) { // Declares adios_transform_read_request *new_readreq; int blockidx, timestep, timestep_blockidx; int start_blockidx, end_blockidx; enum ADIOS_FLAG swap_endianness = (fp->endianness == get_system_endianness()) ? adios_flag_no : adios_flag_yes; // In streaming mode, ignore the user's from_steps/nsteps arguments if (fp->is_streaming) { from_steps = 0; nsteps = 1; } // Precondition checking assert(is_transform_type_valid(transinfo->transform_type)); assert(from_steps >= 0 && from_steps + nsteps <= raw_varinfo->nsteps); if (sel->type != ADIOS_SELECTION_BOUNDINGBOX && sel->type != ADIOS_SELECTION_POINTS && sel->type != ADIOS_SELECTION_WRITEBLOCK) { adios_error(err_operation_not_supported, "Only bounding box, point , and writeblock selections are currently supported for reads on transformed variables."); } // Retrieve blockinfos, if they haven't been done retrieved if (!raw_varinfo->blockinfo) common_read_inq_var_blockinfo_raw(fp, (ADIOS_VARINFO*)raw_varinfo); if (!transinfo->orig_blockinfo) common_read_inq_trans_blockinfo(fp, raw_varinfo, (ADIOS_TRANSINFO*)transinfo); // Allocate a new, empty request group new_readreq = adios_transform_read_request_new(fp, raw_varinfo, transinfo, sel, from_steps, nsteps, param, data, swap_endianness); if (is_global_selection(sel)) { populate_read_request_for_global_selection(raw_varinfo, transinfo, sel, from_steps, nsteps, new_readreq); } else { populate_read_request_for_local_selection(raw_varinfo, transinfo, sel, from_steps, nsteps, new_readreq); } // If this read request does not intersect any PGs, then clear the new read request and return NULL if (new_readreq->num_pg_reqgroups == 0) { adios_transform_read_request_free(&new_readreq); new_readreq = NULL; } return new_readreq; }
int adios_get_timing_name (int64_t fd_p, int64_t index, char* name) { struct adios_file_struct * fd = (struct adios_file_struct *) fd_p; if (!fd) { adios_error (err_invalid_file_pointer, "Invalid handle passed to adios_get_timing_name\n"); return 1; } strcpy (name, fd->timing_obj->names[index]); //*name = fd->timing_obj->names[index]; return 0; }
ADIOS_SELECTION * adios_selection_intersect_bb_pts(const ADIOS_SELECTION_BOUNDINGBOX_STRUCT *bb1, const ADIOS_SELECTION_POINTS_STRUCT *pts2) { const int ndim = bb1->ndim; const uint64_t max_new_npts = pts2->npoints; uint64_t *new_pts = malloc(max_new_npts * ndim * sizeof(uint64_t)); int j; uint64_t *new_pts_ptr = new_pts; uint64_t *pts2_ptr; const uint64_t * const pts2_end_ptr = pts2->points + pts2->npoints * ndim; uint64_t new_npts = 0; assert(bb1->ndim == pts2->ndim); if (!new_pts) { adios_error(err_no_memory, "Cannot allocate memory for BOUNDINGBOX-POINTS selection intersection"); return NULL; } // Check every pair of points for equality; whenever a shared point is found, output // it into the new point list for (pts2_ptr = pts2->points; pts2_ptr < pts2_end_ptr; pts2_ptr += ndim) { // Check each dimension component of the point for containment in the bounding box for (j = 0; j < ndim; j++) if (pts2_ptr[j] < bb1->start[j] || pts2_ptr[j] >= bb1->start[j] + bb1->count[j]) break; // Check whether any component was out of bounds; if so, skip this point; otherwise, // output the point if (j != ndim) { continue; } else { memcpy(new_pts_ptr, pts2_ptr, ndim * sizeof(uint64_t)); new_pts_ptr += ndim; new_npts++; } } if (new_npts == 0) { free(new_pts); return NULL; } else { new_pts = (uint64_t*)realloc(new_pts, new_npts * ndim * sizeof(uint64_t)); return common_read_selection_points(ndim, new_npts, new_pts); } }
int adios_set_buffer_size () { //if (!adios_buffer_size_max) // not called before if (adios_buffer_size_max < adios_buffer_size_requested) // not called before { long pagesize; long pages; pagesize = sysconf (_SC_PAGE_SIZE); pages = adios_get_avphys_pages (); if (adios_buffer_alloc_percentage) { adios_buffer_size_max = (pages * pagesize / 100.0) * adios_buffer_size_requested; } else { if (pagesize * pages >= adios_buffer_size_requested) { // sufficient memory, do nothing adios_buffer_size_max = adios_buffer_size_requested; } else { adios_error (err_no_memory, "adios_allocate_buffer (): insufficient memory: " "%llu requested, %llu available. Using " "available.\n", adios_buffer_size_requested, (uint64_t)(((uint64_t) pagesize) * pages)); adios_buffer_size_max = (uint64_t)((uint64_t) pagesize) * pages; } } adios_buffer_size_remaining = adios_buffer_size_max; return 1; } else { log_debug ("adios_allocate_buffer already called. No changes made.\n"); return 1; } }
int adios_method_buffer_free (uint64_t size) { if (size + adios_buffer_size_remaining > adios_buffer_size_max) { adios_error (err_invalid_buffer, "ERROR: attempt to return more bytes to buffer " "pool than were originally available\n"); adios_buffer_size_remaining = adios_buffer_size_max; return 0; } else { adios_buffer_size_remaining += size; return 1; } }
// // One-on-one global intersection functions // ADIOS_SELECTION * adios_selection_intersect_bb_bb(const ADIOS_SELECTION_BOUNDINGBOX_STRUCT *bb1, const ADIOS_SELECTION_BOUNDINGBOX_STRUCT *bb2) { const int ndim = bb1->ndim; uint64_t *new_start = malloc(ndim * sizeof(uint64_t)); uint64_t *new_count = malloc(ndim * sizeof(uint64_t)); assert(bb1->ndim == bb2->ndim); if (!new_start || !new_count) { adios_error(err_no_memory, "Cannot allocate memory for BOUNDINGBOX-BOUNDINGBOX selection intersection"); return NULL; } if (intersect_bb(bb1, bb2, new_start, NULL, NULL, new_count)) { return common_read_selection_boundingbox(ndim, new_start, new_count); } else { free(new_start); free(new_count); return NULL; } }
/* * Gathers basic MPI information; sets up reader CM. */ int adios_read_flexpath_init_method (MPI_Comm comm, PairStruct* params) { setenv("CMSelfFormats", "1", 1); fp_read_data = malloc(sizeof(flexpath_read_data)); if(!fp_read_data) { adios_error(err_no_memory, "Cannot allocate memory for flexpath."); return -1; } memset(fp_read_data, 0, sizeof(flexpath_read_data)); fp_read_data->CM_TRANSPORT = attr_atom_from_string("CM_TRANSPORT"); attr_list listen_list = NULL; char * transport = NULL; transport = getenv("CMTransport"); // setup MPI stuffs fp_read_data->fp_comm = comm; MPI_Comm_size(fp_read_data->fp_comm, &(fp_read_data->fp_comm_size)); MPI_Comm_rank(fp_read_data->fp_comm, &(fp_read_data->fp_comm_rank)); fp_read_data->fp_cm = CManager_create(); if(transport == NULL){ if(CMlisten(fp_read_data->fp_cm) == 0) { fprintf(stderr, "Flexpath ERROR: reader %d unable to initialize connection manager.\n", fp_read_data->fp_comm_rank); } }else{ listen_list = create_attr_list(); add_attr(listen_list, fp_read_data->CM_TRANSPORT, Attr_String, (attr_value)strdup(transport)); CMlisten_specific(fp_read_data->fp_cm, listen_list); } int forked = CMfork_comm_thread(fp_read_data->fp_cm); if(!forked) { fprintf(stderr, "reader %d failed to fork comm_thread.\n", fp_read_data->fp_comm_rank); /*log_debug( "forked\n");*/ } return 0; }
int adios_read_icee_advance_step(ADIOS_FILE *adiosfile, int last, float timeout_sec) { log_debug("%s\n", __FUNCTION__); adios_errno = 0; icee_fileinfo_rec_ptr_t fp = (icee_fileinfo_rec_ptr_t) adiosfile->fh; icee_fileinfo_rec_ptr_t next = NULL; float waited_sec = 0.0; while (waited_sec <= timeout_sec) { next = fp->next; if (next != NULL) break; usleep(0.1*1E6); waited_sec += 0.1; } if (next != NULL) { icee_llist_ptr_t head = NULL; head = icee_llist_search(icee_filelist, icee_fileinfo_checkname, (const void*) fp->fname); assert(head != NULL); head->item = next; adiosfile->fh = (uint64_t) next; icee_fileinfo_free(fp); } else adios_error (err_step_notready, "No more data yet\n"); return adios_errno; }
int adios_get_timing_internal_count (int64_t fd_p, int64_t * tc) { struct adios_file_struct * fd = (struct adios_file_struct *) fd_p; if (!fd) { adios_error (err_invalid_file_pointer, "Invalid handle passed to adios_get_timing_count\n"); return 1; } if (! fd->timing_obj) { *tc = 0; } else { *tc = fd->timing_obj->internal_count; } return 0; }
/* * Takes a datablock and applies its data to a given output buffer (described * by a given output buffer selection), then frees the given datablock. * * If *output_buffer is non-NULL, copies the pertinent data from datablock->data * into *output_buffer, assuming *output_buffer is shaped like output_sel. * * If *output_buffer is NULL, allocates a minimum-size buffer to contain the * data for the *intersection* of datablock->bounds and output_sel and returns * it via *output_buffer. * * If out_inter_sel != NULL, returns a selection representing the intersection * of datablock->bounds and output_sel (i.e., the portion of data that was * actually copied) via *out_inter_sel. Otherwise, leaves this argument untouched. * * This function can handle any combination of datablock bounding selection and * output buffer bounding selection: * - If both datablock and buffer selections are global (BB, points), performs * a straightforward data patching based on the geometry * - If both datablock and buffer selections are local (writeblock), performs * a straghtforward memcpy as appropriate * - If the buffer is global but the datablock is local, promotes the datablock * to a bounding box using blockinfo (note: the variable is guaranteed to be * a global array in this case because the user supplied a global selection) * - If the buffer is local but the datablock is global, promotes the buffer * to a bounding box using blockinfo (note: the variable may or may not be * a global array in this case; however, even if it is not, both the datablock * and the buffer will be constructed relative to (0,0,...,0), so it will do * the right thing). * * @return the number of elements patched into the output buffer (0 indicates * no data in the given datablock was pertinent to the given output * buffer selection) */ static uint64_t apply_datablock_to_buffer_and_free( 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, enum ADIOS_FLAG swap_endianness) { uint64_t used_count = 0; ADIOS_SELECTION *inter_sel = NULL; assert(raw_varinfo && transinfo && datablock && output_buffer && output_sel); // Check preconditions if (datablock->bounds->type != ADIOS_SELECTION_BOUNDINGBOX && datablock->bounds->type != ADIOS_SELECTION_POINTS && datablock->bounds->type != ADIOS_SELECTION_WRITEBLOCK) { adios_error(err_operation_not_supported, "Only results of bounding box, points, or writeblock selection types " "are currently accepted from transform plugins (received selection type %d)\n", datablock->bounds->type); return 0; } if (output_sel->type != ADIOS_SELECTION_BOUNDINGBOX && output_sel->type != ADIOS_SELECTION_POINTS && output_sel->type != ADIOS_SELECTION_WRITEBLOCK) { adios_error_at_line(err_operation_not_supported, __FILE__, __LINE__, "Internal error: only bounding box, points, or writeblock selection types " "are currently supported in apply_datablock_to_buffer_and_free (received selection type %d)\n", datablock->bounds->type); return 0; } // Invoke the appropriate helper function depending // on whether at least one of datablock->bounds or // output_sel is global if (!is_global_selection(datablock->bounds) && !is_global_selection(output_sel)) { used_count = apply_datablock_to_buffer_local_selections( raw_varinfo, transinfo, datablock, output_buffer, output_sel, &inter_sel, (out_inter_sel ? 1 : 0), swap_endianness); } else { used_count = apply_datablock_to_buffer_nonlocal_selections( raw_varinfo, transinfo, datablock, output_buffer, output_sel, &inter_sel, (out_inter_sel ? 1 : 0), swap_endianness); } // Clean up the returned intersection if it is not wanted by the caller if (inter_sel) { if (out_inter_sel) { *out_inter_sel = inter_sel; } else { // TODO: Deep delete the selection (delete points list, start/count arrays, etc.) a2sel_free(inter_sel); } } // Free the datablock adios_datablock_free(&datablock, 1); return used_count; }
static int raw_handler(CManager cm, void *vevent, int len, void *client_data, attr_list attrs) { ADIOS_FILE *adiosfile = client_data; flexpath_reader_file *fp = (flexpath_reader_file*)adiosfile->fh; double data_end = dgettimeofday(); if(fp->time_in == 0.00) fp->time_in = data_end; // used for perf measurements only int condition; int writer_rank; int flush_id; double data_start; get_double_attr(attrs, attr_atom_from_string("fp_starttime"), &data_start); get_int_attr(attrs, attr_atom_from_string("fp_dst_condition"), &condition); get_int_attr(attrs, attr_atom_from_string(FP_RANK_ATTR_NAME), &writer_rank); get_int_attr(attrs, attr_atom_from_string("fp_flush_id"), &flush_id); double format_start = dgettimeofday(); FMContext context = CMget_FMcontext(cm); void *base_data = FMheader_skip(context, vevent); FMFormat format = FMformat_from_ID(context, vevent); // copy //FMfree_struct_desc_list call FMStructDescList struct_list = FMcopy_struct_list(format_list_of_FMFormat(format)); FMField *f = struct_list[0].field_list; #if 0 uint64_t packet_size = calc_ffspacket_size(f, attrs, base_data); fp->data_read += packet_size; #endif /* setting up initial vars from the format list that comes along with the message. Message contains both an FFS description and the data. */ if(fp->num_vars == 0){ int var_count = 0; fp->var_list = setup_flexpath_vars(f, &var_count); adiosfile->var_namelist = malloc(var_count * sizeof(char *)); int i = 0; while(f->field_name != NULL) { adiosfile->var_namelist[i++] = strdup(f->field_name); f++; } adiosfile->nvars = var_count; fp->num_vars = var_count; } f = struct_list[0].field_list; char *curr_offset = NULL; while(f->field_name){ char atom_name[200] = ""; flexpath_var *var = find_fp_var(fp->var_list, f->field_name); if(!var){ adios_error(err_file_open_error, "file not opened correctly. var does not match format.\n"); return err_file_open_error; } int num_dims = get_ndims_attr(f->field_name, attrs); var->num_dims = num_dims; flexpath_var_chunk *curr_chunk = &var->chunks[0]; // has the var been scheduled? if(var->sel){ if(var->sel->type == ADIOS_SELECTION_WRITEBLOCK){ if(num_dims == 0){ // writeblock selection for scalar if(var->sel->u.block.index == writer_rank){ void *tmp_data = get_FMfieldAddr_by_name(f, f->field_name, base_data); memcpy(var->chunks[0].user_buf, tmp_data, f->field_size); } } else { // writeblock selection for arrays /* if(var->num_dims == 0){ */ /* var->global_dims = malloc(sizeof(uint64_t)*num_dims); */ /* } */ if(var->sel->u.block.index == writer_rank){ var->array_size = var->type_size; int i; for(i=0; i<num_dims; i++){ char *dim; atom_name[0] ='\0'; strcat(atom_name, FP_DIM_ATTR_NAME); strcat(atom_name, "_"); strcat(atom_name, f->field_name); strcat(atom_name, "_"); char dim_num[10] = ""; sprintf(dim_num, "%d", i+1); strcat(atom_name, dim_num); get_string_attr(attrs, attr_atom_from_string(atom_name), &dim); FMField *temp_field = find_field_by_name(dim, f); if(!temp_field){ adios_error(err_corrupted_variable, "Could not find fieldname: %s\n", dim); } else{ int *temp_data = get_FMfieldAddr_by_name(temp_field, temp_field->field_name, base_data); uint64_t dim = (uint64_t)(*temp_data); var->array_size = var->array_size * dim; } } void *arrays_data = get_FMPtrField_by_name(f, f->field_name, base_data, 1); memcpy(var->chunks[0].user_buf, arrays_data, var->array_size); } } } else if(var->sel->type == ADIOS_SELECTION_BOUNDINGBOX){ if(num_dims == 0){ // scalars; throw error adios_error(err_offset_required, "Only scalars can be scheduled with write_block selection.\n"); } else{ // arrays int i; global_var *gv = find_gbl_var(fp->gp->vars, var->varname, fp->gp->num_vars); array_displacements * disp = find_displacement(var->displ, writer_rank, var->num_displ); if(disp){ // does this writer hold a chunk we've asked for, for this var? uint64_t *temp = gv->offsets[0].local_dimensions; int offsets_per_rank = gv->offsets[0].offsets_per_rank; uint64_t *writer_sizes = &temp[offsets_per_rank * writer_rank]; uint64_t *sel_start = disp->start; uint64_t *sel_count = disp->count; char *writer_array = (char*)get_FMPtrField_by_name(f, f->field_name, base_data, 1); char *reader_array = (char*)var->chunks[0].user_buf; uint64_t reader_start_pos = disp->pos; var->start_position += copyarray(writer_sizes, sel_start, sel_count, disp->ndims, f->field_size, 0, writer_array, reader_array+reader_start_pos); } } } } else { //var has not been scheduled; if(num_dims == 0){ // only worry about scalars flexpath_var_chunk *chunk = &var->chunks[0]; if(!chunk->has_data){ void *tmp_data = get_FMfieldAddr_by_name(f, f->field_name, base_data); chunk->data = malloc(f->field_size); memcpy(chunk->data, tmp_data, f->field_size); chunk->has_data = 1; } } } f++; } if(condition == -1){ fp->completed_requests++; if(fp->completed_requests == fp->pending_requests){ pthread_mutex_lock(&fp->data_mutex); pthread_cond_signal(&fp->data_condition); pthread_mutex_unlock(&fp->data_mutex); } } else{ CMCondition_signal(fp_read_data->fp_cm, condition); } free_fmstructdesclist(struct_list); return 0; }
int adios_read_flexpath_inq_var_trans_blockinfo(const ADIOS_FILE *gp, const ADIOS_VARINFO *vi, ADIOS_TRANSINFO *ti) { adios_error(err_operation_not_supported, "Flexpath does not yet support transforms: trans_blockinfo.\n"); return (int64_t)0; }
void adios_read_flexpath_reset_dimension_order (const ADIOS_FILE *adiosfile, int is_fortran) { //log_debug( "debug: adios_read_flexpath_reset_dimension_order\n"); adios_error(err_invalid_read_method, "adios_read_flexpath_reset_dimension_order is not implemented."); }
int adios_read_icee_schedule_read_byid(const ADIOS_FILE *adiosfile, const ADIOS_SELECTION *sel, int varid, int from_steps, int nsteps, void *data) { int i; icee_fileinfo_rec_ptr_t fp = (icee_fileinfo_rec_ptr_t) adiosfile->fh; log_debug("%s (%d:%s)\n", __FUNCTION__, varid, fp->fname); //assert((varid < fp->nvars) || (fp->nvars == 0)); if (nsteps != 1) { adios_error (err_invalid_timestep, "Only one step can be read from a stream at a time. " "You requested % steps in adios_schedule_read()\n", nsteps); return err_invalid_timestep; } icee_varinfo_rec_ptr_t vp = NULL; vp = icee_varinfo_search_byname(fp->varinfo, adiosfile->var_namelist[varid]); if (adios_verbose_level > 5) icee_varinfo_print(vp); if (!vp) { adios_error(err_invalid_varid, "Invalid variable id: %d\n", varid); return adios_errno; } while (fp->merge_count != fp->nchunks) { log_debug("Waiting the rest of blocks (%d/%d)\n", fp->merge_count, fp->nchunks); usleep(0.1*1E6); } if (sel==0) memcpy(data, vp->data, vp->varlen); else switch(sel->type) { case ADIOS_SELECTION_WRITEBLOCK: { //DUMP("fp->rank: %d", fp->rank); //DUMP("u.block.index: %d", sel->u.block.index); if (fp->comm_rank != sel->u.block.index) adios_error(err_unspecified, "Block id missmatch. " "Not yet supported by ICEE\n"); // Possible memory overwrite memcpy(data, vp->data, vp->varlen); break; } case ADIOS_SELECTION_BOUNDINGBOX: { if (vp->ndims != sel->u.bb.ndim) adios_error(err_invalid_dimension, "Dimension mismatch\n"); log_debug("Merging operation (total nvars: %d).\n", fp->nchunks); if (adios_verbose_level > 5) icee_sel_bb_print(sel); while (vp != NULL) { icee_matrix_t m_sel; icee_matrix_t m_var; icee_matrix_view_t v_sel; icee_matrix_view_t v_var; uint64_t start[10]; int64_t count[10]; // should be signed to check validity uint64_t s_offsets[10], v_offsets[10]; int i; if (adios_verbose_level > 5) icee_varinfo_print(vp); mat_init(&m_sel, vp->typesize, vp->ndims, sel->u.bb.count, data); mat_init(&m_var, vp->typesize, vp->ndims, vp->ldims, vp->data); for (i=0; i<vp->ndims; i++) start[i] = MYMAX(sel->u.bb.start[i], vp->offsets[i]); for (i=0; i<vp->ndims; i++) { count[i] = MYMIN(sel->u.bb.start[i]+sel->u.bb.count[i], vp->offsets[i]+vp->ldims[i]) - start[i]; } for (i=0; i<vp->ndims; i++) { if (count[i] <= 0) { log_debug("No ROI. Skip\n"); goto next; } } for (i=0; i<vp->ndims; i++) s_offsets[i] = start[i] - sel->u.bb.start[i]; for (i=0; i<vp->ndims; i++) v_offsets[i] = start[i] - vp->offsets[i]; view_init (&v_sel, &m_sel, count, s_offsets); view_init (&v_var, &m_var, count, v_offsets); view_copy (&v_sel, &v_var); next: vp = icee_varinfo_search_byname(vp->next, adiosfile->var_namelist[varid]); } break; } case ADIOS_SELECTION_AUTO: { // Possible memory overwrite memcpy(data, vp->data, vp->varlen); break; } case ADIOS_SELECTION_POINTS: { adios_error(err_operation_not_supported, "ADIOS_SELECTION_POINTS not yet supported by ICEE.\n"); break; } } return adios_errno; }
/* Copy data between two views. Dimension and size should match */ void view_copy (icee_matrix_view_t *dest, icee_matrix_view_t *src) { assert(dest->mat->ndims == src->mat->ndims); int i; for (i=0; i<dest->mat->ndims; i++) assert(dest->vdims[i] == src->vdims[i]); // Contiguous merging if ((dest->leastcontiguousdim == 0) && (src->leastcontiguousdim == 0)) { int s, d; d = dest->offsets[0] * dest->mat->accumdims[0]; s = src->offsets[0] * src->mat->accumdims[0]; memcpy(dest->mat->data + d * dest->mat->typesize, src->mat->data + s * dest->mat->typesize, dest->vdims[0] * dest->mat->accumdims[0] * dest->mat->typesize); return; } // Non-contiguous merging switch (dest->mat->ndims) { case 1: { int s, d; d = dest->offsets[0]; s = src->offsets[0]; memcpy(dest->mat->data + d * dest->mat->typesize, src->mat->data + s * dest->mat->typesize, dest->vdims[0] * dest->mat->typesize); break; } case 2: { int i, s, d; for (i=0; i<dest->vdims[0]; i++) { d = (i + dest->offsets[0]) * dest->mat->accumdims[0] + dest->offsets[1]; s = (i + src->offsets[0]) * src->mat->accumdims[0] + src->offsets[1]; memcpy(dest->mat->data + d * dest->mat->typesize, src->mat->data + s * dest->mat->typesize, dest->vdims[1] * dest->mat->typesize); } break; } case 3: { int i, j, s, d; for (i=0; i<dest->vdims[0]; i++) { for (j=0; j<dest->vdims[1]; j++) { d = (i + dest->offsets[0]) * dest->mat->accumdims[0] + (j + dest->offsets[1]) * dest->mat->accumdims[1] + dest->offsets[2]; s = (i + src->offsets[0]) * src->mat->accumdims[0] + (j + src->offsets[1]) * src->mat->accumdims[1] + src->offsets[2]; memcpy(dest->mat->data + d * dest->mat->typesize, src->mat->data + s * dest->mat->typesize, dest->vdims[2] * dest->mat->typesize); } } break; } default: adios_error(err_expected_read_size_mismatch, "The variable dimension is out of the range. ", "Not yet supported by ICEE\n"); break; } }
/* * Takes a datablock containing data potentially applicable to the given read * request group, identifies that data (if any), and returns it as an * ADIOS_VARCHUNK. Additionally, free the datablock. */ static ADIOS_VARCHUNK * apply_datablock_to_chunk_and_free(adios_datablock *datablock, adios_transform_read_request *reqgroup) { assert(datablock); assert(reqgroup); assert(reqgroup->orig_sel); if (reqgroup->orig_sel->type != ADIOS_SELECTION_BOUNDINGBOX && reqgroup->orig_sel->type != ADIOS_SELECTION_POINTS && reqgroup->orig_sel->type != ADIOS_SELECTION_WRITEBLOCK) { adios_error(err_operation_not_supported, "Only read selections of bounding box, points, or writeblock selection types " "are currently allowed (received selection type %d) " "(NOTE: this should have been caught earlier in the code)\n", reqgroup->orig_sel->type); } if (datablock->bounds->type != ADIOS_SELECTION_BOUNDINGBOX && datablock->bounds->type != ADIOS_SELECTION_POINTS && datablock->bounds->type != ADIOS_SELECTION_WRITEBLOCK) { adios_error(err_operation_not_supported, "Only results of bounding box, points, or writeblock selection types " "are currently accepted from transform plugins (received selection type %d)\n", datablock->bounds->type); abort(); } // Special check due to limitations of ADIOS_VARCHUNK return: // If the output is a writeblock selection, AND the input is not, AND // the variable is a local array, AND we are required to return a chunk // at a time, we must warn the user about potentially unexpected output. // Because our results would necessarily be a global-selection-based chunk // (subvolume, etc.), which has no information about what PG it came from, // if the user submitted multiple writeblock selections over a local array // variable at once, there would be no way to determine which writeblock // a varchunk with a bounding box selection corresponds to. // // Potential solutions are: submit only one writeblock per schedule/check/perform // cycle, use blocking reads, use a global array file, or use a different data // transform. if (reqgroup->orig_sel->type == ADIOS_SELECTION_WRITEBLOCK && datablock->bounds->type != ADIOS_SELECTION_WRITEBLOCK && !reqgroup->transinfo->orig_global && adios_transform_read_request_get_mode(reqgroup) == PARTIAL_RESULT_MODE) { static int warning_printed = 0; if (!warning_printed) { const char *transform_name = adios_transform_plugin_primary_xml_alias(reqgroup->transinfo->transform_type); if (!transform_name) transform_name = "<name unknown>"; log_warn("Results for a chunked read using a writeblock selection over a %s-transformed " "variable will return correct results, but in the form of ADIOS_VARCHUNKs with " "non-writeblock selections, so it may be difficult to determine which VARCHUNK " "goes with which writeblock selection if multiple have been submitted at once. " "To avoid this warning, either use blocking reads, use a global array file, or " "select a use data transform. This warning will only be printed once per run.", transform_name); warning_printed = 1; } return NULL; } ADIOS_SELECTION *chunk_sel = NULL; void *chunk_data = NULL; uint64_t used_count = apply_datablock_to_buffer_and_free( reqgroup->raw_varinfo, reqgroup->transinfo, datablock, &chunk_data, reqgroup->orig_sel, &chunk_sel, // chunk_data == NULL -> allocate fitted buffer, chunk_sel == NULL -> return intersection selection reqgroup->swap_endianness); if (used_count) { assert(chunk_data && chunk_sel); // Bind the output buffer to the chunk struct ADIOS_VARCHUNK *chunk = (ADIOS_VARCHUNK *)malloc(sizeof(ADIOS_VARCHUNK)); *chunk = (ADIOS_VARCHUNK) { .varid = reqgroup->raw_varinfo->varid, .data = chunk_data, .type = datablock->elem_type, .sel = chunk_sel, .from_steps = datablock->timestep, .nsteps = 1, }; return chunk; } else { return NULL; } }
/* * Sets up local data structure for series of reads on an adios file * - create evpath graph and structures * -- create evpath control stone (outgoing) * -- create evpath data stone (incoming) * -- rank 0 dumps contact info to file * -- create connections using contact info from file */ ADIOS_FILE* adios_read_flexpath_open(const char * fname, MPI_Comm comm, enum ADIOS_LOCKMODE lock_mode, float timeout_sec) { fp_log("FUNC", "entering flexpath_open\n"); ADIOS_FILE *adiosfile = malloc(sizeof(ADIOS_FILE)); if(!adiosfile){ adios_error (err_no_memory, "Cannot allocate memory for file info.\n"); return NULL; } flexpath_reader_file *fp = new_flexpath_reader_file(fname); adios_errno = 0; fp->stone = EValloc_stone(fp_read_data->fp_cm); fp->comm = comm; MPI_Comm_size(fp->comm, &(fp->size)); MPI_Comm_rank(fp->comm, &(fp->rank)); EVassoc_terminal_action(fp_read_data->fp_cm, fp->stone, op_format_list, op_msg_handler, adiosfile); EVassoc_terminal_action(fp_read_data->fp_cm, fp->stone, update_step_msg_format_list, update_step_msg_handler, adiosfile); EVassoc_terminal_action(fp_read_data->fp_cm, fp->stone, evgroup_format_list, group_msg_handler, adiosfile); EVassoc_raw_terminal_action(fp_read_data->fp_cm, fp->stone, raw_handler, adiosfile); /* Gather the contact info from the other readers and write it to a file. Create a ready file so that the writer knows it can parse this file. */ double setup_start = dgettimeofday(); char writer_ready_filename[200]; char writer_info_filename[200]; char reader_ready_filename[200]; char reader_info_filename[200]; sprintf(reader_ready_filename, "%s_%s", fname, READER_READY_FILE); sprintf(reader_info_filename, "%s_%s", fname, READER_CONTACT_FILE); sprintf(writer_ready_filename, "%s_%s", fname, WRITER_READY_FILE); sprintf(writer_info_filename, "%s_%s", fname, WRITER_CONTACT_FILE); char *string_list; char data_contact_info[CONTACT_LENGTH]; string_list = attr_list_to_string(CMget_contact_list(fp_read_data->fp_cm)); sprintf(&data_contact_info[0], "%d:%s", fp->stone, string_list); free(string_list); char * recvbuf; if(fp->rank == 0){ recvbuf = (char*)malloc(sizeof(char)*CONTACT_LENGTH*(fp->size)); } MPI_Gather(data_contact_info, CONTACT_LENGTH, MPI_CHAR, recvbuf, CONTACT_LENGTH, MPI_CHAR, 0, fp->comm); if(fp->rank == 0){ // print our own contact information FILE * fp_out = fopen(reader_info_filename, "w"); int i; if(!fp_out){ adios_error(err_file_open_error, "File for contact info could not be opened for writing.\n"); exit(1); } for(i=0; i<fp->size; i++) { fprintf(fp_out,"%s\n", &recvbuf[i*CONTACT_LENGTH]); } fclose(fp_out); free(recvbuf); FILE * read_ready = fopen(reader_ready_filename, "w"); fprintf(read_ready, "ready"); fclose(read_ready); } MPI_Barrier(fp->comm); FILE * fp_in = fopen(writer_ready_filename,"r"); while(!fp_in) { //CMsleep(fp_read_data->fp_cm, 1); fp_in = fopen(writer_ready_filename, "r"); } fclose(fp_in); fp_in = fopen(writer_info_filename, "r"); while(!fp_in){ //CMsleep(fp_read_data->fp_cm, 1); fp_in = fopen(writer_info_filename, "r"); } char in_contact[CONTACT_LENGTH] = ""; //fp->bridges = malloc(sizeof(bridge_info)); int num_bridges = 0; int their_stone; // change to read all numbers, dont create stones, turn bridge array into linked list while(fscanf(fp_in, "%d:%s", &their_stone, in_contact) != EOF){ //fprintf(stderr, "writer contact: %d:%s\n", their_stone, in_contact); fp->bridges = realloc(fp->bridges, sizeof(bridge_info) * (num_bridges+1)); fp->bridges[num_bridges].their_num = their_stone; fp->bridges[num_bridges].contact = strdup(in_contact); fp->bridges[num_bridges].created = 0; fp->bridges[num_bridges].step = 0; fp->bridges[num_bridges].opened = 0; fp->bridges[num_bridges].scheduled = 0; num_bridges++; } fclose(fp_in); fp->num_bridges = num_bridges; // clean up of writer's files MPI_Barrier(fp->comm); if(fp->rank == 0){ unlink(writer_info_filename); unlink(writer_ready_filename); } adiosfile->fh = (uint64_t)fp; adiosfile->current_step = 0; /* Init with a writer to get initial scalar data so we can handle inq_var calls and also populate the ADIOS_FILE struct. */ double bridge_start = MPI_Wtime(); if(fp->size < num_bridges){ int mystart = (num_bridges/fp->size) * fp->rank; int myend = (num_bridges/fp->size) * (fp->rank+1); fp->writer_coordinator = mystart; int z; for(z=mystart; z<myend; z++){ build_bridge(&fp->bridges[z]); } } else{ int writer_rank = fp->rank % num_bridges; build_bridge(&fp->bridges[writer_rank]); fp->writer_coordinator = writer_rank; } // requesting initial data. send_open_msg(fp, fp->writer_coordinator); fp->data_read = 0; send_flush_msg(fp, fp->writer_coordinator, DATA, 1); send_flush_msg(fp, fp->writer_coordinator, EVGROUP, 1); fp->data_read = 0; // this has to change. Writer needs to have some way of // taking the attributes out of the xml document // and sending them over ffs encoded. Not yet implemented. // the rest of this info for adiosfile gets filled in raw_handler. adiosfile->nattrs = 0; adiosfile->attr_namelist = NULL; // first step is at least one, otherwise raw_handler will not execute. // in reality, writer might be further along, so we might have to make // the writer explitly send across messages each time it calls close, to // indicate which timesteps are available. adiosfile->last_step = 1; adiosfile->path = strdup(fname); // verifies these two fields. It's not BP, so no BP version. // It's a stream, so how can the file size be known? adiosfile->version = -1; adiosfile->file_size = 0; adios_errno = err_no_error; fp_log("FUNC", "leaving flexpath_open\n"); return adiosfile; }
int adios_read_flexpath_schedule_read_byid(const ADIOS_FILE *adiosfile, const ADIOS_SELECTION *sel, int varid, int from_steps, int nsteps, void *data) { fp_log("FUNC", "entering schedule_read_byid\n"); flexpath_reader_file * fp = (flexpath_reader_file*)adiosfile->fh; flexpath_var * var = fp->var_list; while(var){ if(var->id == varid) break; else var=var->next; } if(!var){ adios_error(err_invalid_varid, "Invalid variable id: %d\n", varid); return err_invalid_varid; } //store the user allocated buffer. flexpath_var_chunk *chunk = &var->chunks[0]; chunk->user_buf = data; var->start_position = 0; if(nsteps != 1){ adios_error (err_invalid_timestep, "Only one step can be read from a stream at a time. " "You requested % steps in adios_schedule_read()\n", nsteps); return err_invalid_timestep; } // this is done so that the user can do multiple schedule_read/perform_reads // within before doing release/advance step. Might need a better way to // manage the ADIOS selections. if(var->sel){ free_selection(var->sel); } var->sel = copy_selection(sel); switch(var->sel->type) { case ADIOS_SELECTION_WRITEBLOCK: { int writer_index = var->sel->u.block.index; if(writer_index > fp->num_bridges){ adios_error(err_out_of_bound, "No process exists on the writer side matching the index.\n"); return err_out_of_bound; } send_var_message(fp, writer_index, var->varname); break; } case ADIOS_SELECTION_BOUNDINGBOX: { free_displacements(var->displ, var->num_displ); var->displ = NULL; int j=0; int need_count = 0; array_displacements * all_disp = NULL; uint64_t pos = 0; double sched_start = MPI_Wtime(); for(j=0; j<fp->num_bridges; j++) { int destination=0; if(need_writer(fp, j, var->sel, fp->gp, var->varname)==1){ uint64_t _pos = 0; need_count++; destination = j; global_var *gvar = find_gbl_var(fp->gp->vars, var->varname, fp->gp->num_vars); // TODO: memory leak here. have to free these at some point. array_displacements *displ = get_writer_displacements(j, var->sel, gvar, &_pos); displ->pos = pos; _pos *= (uint64_t)var->type_size; pos += _pos; all_disp = realloc(all_disp, sizeof(array_displacements)*need_count); all_disp[need_count-1] = *displ; send_var_message(fp, j, var->varname); } } double sched_end = MPI_Wtime(); var->displ = all_disp; var->num_displ = need_count; break; } case ADIOS_SELECTION_AUTO: { adios_error(err_operation_not_supported, "ADIOS_SELECTION_AUTO not yet supported by flexpath."); break; } case ADIOS_SELECTION_POINTS: { adios_error(err_operation_not_supported, "ADIOS_SELECTION_POINTS not yet supported by flexpath."); break; } } fp_log("FUNC", "entering schedule_read_byid\n"); return 0; }