// take all provided params from other and apply to self // NOTE: this requires that "other" is of the same derived type as this bool BaseBlock::merge(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { bool some_param_changed = false; BlockDescriptor::all_params_list_t::const_iterator end_it = block_data.mAllParams.end(); for (BlockDescriptor::all_params_list_t::const_iterator it = block_data.mAllParams.begin(); it != end_it; ++it) { const Param* other_paramp = other.getParamFromHandle(it->mParamHandle); ParamDescriptor::merge_func_t merge_func = it->mMergeFunc; if (merge_func) { Param* paramp = getParamFromHandle(it->mParamHandle); some_param_changed |= merge_func(*paramp, *other_paramp, overwrite); } } return some_param_changed; }
//---------------------------------------------------------------------------- // // radix-k merge // // did: decomposition id // its: pointers to input/ouput items, results in first number of output items // hdrs: pointers to input headers (optional, pass NULL if unnecessary) // nr: number of rounds // kv: k vector, radix for each round // cc: pointer to communicate object // assign: pointer to assignment object // merge_func: pointer to merging function // create_func: pointer to function that creates item // destroy_func: pointer to function that destroys item // type_func: pointer to function that creates MPI datatype for item // // side effects: allocates output items and array of pointers to them, if // not reducing in-place // // returns: number of output items // int Merge::MergeBlocks(int did, char **its, int **hdrs, int nr, int *kv, Comm *cc, Assignment *assign, void (*merge_func)(char **, int *, int, int *), char * (*create_func)(int *), void (*destroy_func)(void *), void (*type_func)(void*, MPI_Datatype*, int *)) { int rank, groupsize; // MPI usual int gid; // global id of current item block int p; // process rank MPI_Datatype dtype; // data type int ng; // number of groups this process owns int nb = assign->NumBlks(); // number of blocks this process owns vector<char *> my_its(its, its + nb); // copy of its vector<bool> done(nb, false); // done items vector<int> root_gids; // distinct gids of root blocks // init assert(nr > 0 && nr <= DIY_MAX_R); // sanity MPI_Comm_rank(comm, &rank); MPI_Comm_size(comm, &groupsize); // for all rounds for (int r = 0; r < nr; r++){ int n_recv = 0; // number of received blocks by root int partners[kv[r]]; // gids of partners in a group root_gids.clear(); root_gids.reserve(kv[r]); // all my current blocks must participate in a round (send or receive) for (int b = 0; b < nb; b++) { if (!done[b]) { // blocks that survived to this round gid = DIY_Gid(did, b); bool root = GetPartners(kv, r, gid, partners); if (!root) { // nonroots post sends of headers and items p = assign->Gid2Proc(partners[kv[r] - 1]); if (hdrs) type_func(my_its[b], &dtype, hdrs[b]); else type_func(my_its[b], &dtype, NULL); // tag is source block gid if (hdrs && dtype_absolute_address) cc->SendItem((char *)MPI_BOTTOM, hdrs[b], p, gid, &dtype); else if (hdrs && !dtype_absolute_address) cc->SendItem((char *)my_its[b], hdrs[b], p, gid, &dtype); else if (!hdrs && dtype_absolute_address) cc->SendItem((char *)MPI_BOTTOM, NULL, p, gid, &dtype); else cc->SendItem((char *)my_its[b], NULL, p, gid, &dtype); MPI_Type_free(&dtype); done[b] = true; // nonroot blocks are done after they have been sent } else { // root posts receives of headers root_gids.push_back(partners[kv[r] - 1]); for (int k = 0; k < kv[r] - 1; k++) { // receive the others p = assign->Gid2Proc(partners[k]); cc->StartRecvItem(p, hdrs); n_recv++; } } } // blocks that survived to this round } // all my current blocks // finish receiving all items char *recv_its[n_recv]; // received items int recv_gids[n_recv]; // (source) gids of the received items int recv_procs[n_recv]; // source proc of each received item cc->FinishRecvItemsMerge(recv_its, recv_gids, recv_procs, create_func, type_func); // merge each group ng = (int)root_gids.size(); // number of groups this process owns for (int j = 0; j < ng; j++) { vector<char *>reduce_its; // items ready for reduction in a group vector<int>reduce_gids; // gids for reduce_its reduce_its.reserve(kv[r]); reduce_gids.reserve(kv[r]); int lid = assign->Gid2Lid(root_gids[j]); reduce_its.push_back(my_its[lid]); reduce_gids.push_back(root_gids[j]); GetPartners(kv, r, root_gids[j], partners); for (int i = 0; i < n_recv; i++) { // collect items for this group if (find(partners, partners + kv[r], recv_gids[i]) != partners + kv[r]) { reduce_its.push_back(recv_its[i]); reduce_gids.push_back(recv_gids[i]); } } // header from root block of merge is used if (hdrs) merge_func(&reduce_its[0], &reduce_gids[0], kv[r], hdrs[lid]); else merge_func(&reduce_its[0], &reduce_gids[0], kv[r], NULL); my_its[lid] = reduce_its[0]; } // cleanup if (ng) { for (int i = 0; i < n_recv; i++) destroy_func(recv_its[i]); } } // for all rounds // move results to the front, swapping them rather than copying so that user // can free all items without having duplicated pointers that get freed // multiple times for (int i = 0; i < ng; i++) { char *temp = its[i]; its[i] = my_its[assign->Gid2Lid(root_gids[i])]; its[assign->Gid2Lid(root_gids[i])] = temp; } return ng; }