Skip to content

Commit

Permalink
Merge pull request #351 from tokusanya/OptimizeManyBlocksRead
Browse files Browse the repository at this point in the history
Optimize many blocks read
  • Loading branch information
gsjaardema committed Jul 6, 2023
2 parents 8801a11 + 7a953a4 commit 15f91ed
Show file tree
Hide file tree
Showing 16 changed files with 1,301 additions and 14 deletions.
77 changes: 77 additions & 0 deletions packages/seacas/libraries/ioss/src/Ioss_DatabaseIO.C
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,29 @@ namespace {
}
}

template <typename T>
std::vector<size_t> get_all_block_offsets(const std::string& field_name, const std::vector<T*>& entity_container)
{
size_t num_blocks = entity_container.size();

std::vector<size_t> offsets(num_blocks + 1, 0);

for(size_t i=0; i<num_blocks; i++) {
T *entity = entity_container[i];

if(entity->field_exists(field_name)) {
Ioss::Field field = entity->get_field(field_name);
offsets[i+1] = entity->entity_count() * field.raw_storage()->component_count();
}
}

for(size_t i=1; i<=num_blocks; ++i) {
offsets[i] += offsets[i-1];
}

return offsets;
}

template <typename ENTITY>
int64_t zero_copy_not_enabled(const ENTITY *entity, const Ioss::Field &field,
const Ioss::DatabaseIO *db)
Expand Down Expand Up @@ -1338,6 +1361,60 @@ namespace Ioss {
return {xx.first, yy.first, zz.first, xx.second, yy.second, zz.second};
}

std::vector<size_t> DatabaseIO::get_all_block_field_data(const std::string &field_name,
void *data, size_t data_size) const
{
const Ioss::ElementBlockContainer& elem_blocks = get_region()->get_element_blocks();
size_t num_blocks = elem_blocks.size();

std::vector<size_t> offset = get_all_block_offsets(field_name, elem_blocks);

for(size_t i=0; i<num_blocks; i++) {

Ioss::ElementBlock *entity = elem_blocks[i];

if(entity->field_exists(field_name)) {
auto num_to_get_for_block = offset[i+1] - offset[i];
Ioss::Field field = entity->get_field(field_name);
size_t field_byte_size = field.get_basic_size();
size_t block_data_size = num_to_get_for_block * field_byte_size;

if (block_data_size != field.get_size()) {
std::ostringstream errmsg;
fmt::print(errmsg, "ERROR: Field '{}' data size {} on entity {} does not match computed size {}\n\n",
field_name, field.get_size(), entity->name(), block_data_size);
IOSS_ERROR(errmsg);
}


size_t expected_data_size = offset[i+1] * field_byte_size;
if (data_size < expected_data_size) {
std::ostringstream errmsg;
fmt::print(errmsg, "ERROR: Field '{}' data size {} on entity {} is less than expected size {}\n\n",
field_name, data_size, entity->name(), expected_data_size);
IOSS_ERROR(errmsg);
}

size_t block_data_offset = offset[i] * field_byte_size;
auto retval = get_field_internal(entity, field, (char*)data + block_data_offset, block_data_size);

size_t block_component_count = field.raw_storage()->component_count();
if(num_to_get_for_block != retval*block_component_count) {
std::ostringstream errmsg;
fmt::print(errmsg, "ERROR: Data length {} for field {} on block {} is not expected length {}\n\n",
retval*block_component_count, field_name, entity->name(), num_to_get_for_block);
IOSS_ERROR(errmsg);
}

if (retval >= 0) {
field.transform((char*)data + block_data_offset);
}
}
}

return offset;
}

int64_t DatabaseIO::get_zc_field_internal(const Ioss::Region *reg, const Ioss::Field &field,
void **, size_t *) const
{
Expand Down
3 changes: 3 additions & 0 deletions packages/seacas/libraries/ioss/src/Ioss_DatabaseIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,9 @@ namespace Ioss {
}
}

virtual std::vector<size_t> get_all_block_field_data(const std::string &field_name,
void *data, size_t data_size) const;

protected:
DatabaseIO(Region *region, std::string filename, Ioss::DatabaseUsage db_usage,
Ioss_MPI_Comm communicator, const Ioss::PropertyManager &props);
Expand Down
96 changes: 96 additions & 0 deletions packages/seacas/libraries/ioss/src/Ioss_Decomposition.C
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,102 @@ namespace Ioss {
return valid_methods;
}

size_t get_all_block_ioss_element_size(const std::vector<BlockDecompositionData> &blocks)
{
size_t count = 0;

for(const Ioss::BlockDecompositionData& block : blocks) {
// Determine total number of ioss decomp elements
count += (block.importMap.size() + block.localMap.size());
}

return count;
}

size_t get_all_block_ioss_offset_size(const std::vector<BlockDecompositionData> &blocks,
const std::vector<int>& block_field_component_count)
{
size_t count = 0;

for(size_t blk_seq = 0; blk_seq < blocks.size(); blk_seq++) {
const Ioss::BlockDecompositionData& block = blocks[blk_seq];
// Determine total number of ioss decomp entries based on field component count per block.
count += block_field_component_count[blk_seq]*(block.importMap.size() + block.localMap.size());
}

return count;
}

std::vector<size_t> get_all_block_ioss_offset(const std::vector<BlockDecompositionData> &blocks,
const std::vector<int>& block_component_count)
{
std::vector<size_t> ioss_offset(blocks.size()+1, 0);

for(size_t blk_seq = 0; blk_seq < blocks.size(); blk_seq++) {
const Ioss::BlockDecompositionData& block = blocks[blk_seq];

// Determine number of ioss decomp entries based on field component count per block.
ioss_offset [blk_seq+1] = block_component_count[blk_seq]*(block.importMap.size() + block.localMap.size());
}

// Compute offsets
for(size_t i=1; i<=blocks.size(); ++i) {
ioss_offset[i] += ioss_offset[i-1];
}

return ioss_offset;
}

std::vector<size_t> get_all_block_import_offset(const std::vector<BlockDecompositionData> &blocks,
const std::vector<int>& block_component_count)
{
std::vector<size_t> ioss_offset(blocks.size()+1, 0);

for(size_t blk_seq = 0; blk_seq < blocks.size(); blk_seq++) {
const Ioss::BlockDecompositionData& block = blocks[blk_seq];

// Determine number of imported ioss decomp entries based on field component count per block.
ioss_offset [blk_seq+1] = block_component_count[blk_seq]*block.importMap.size();
}

// Compute offsets
for(size_t i=1; i<=blocks.size(); ++i) {
ioss_offset[i] += ioss_offset[i-1];
}

return ioss_offset;
}

std::vector<int>
get_all_block_connectivity_ioss_component_count(const std::vector<BlockDecompositionData> &blocks)
{
std::vector<int> block_connectivity_component_count(blocks.size());

for(size_t blk_seq = 0; blk_seq < blocks.size(); blk_seq++) {
const Ioss::BlockDecompositionData& block = blocks[blk_seq];
block_connectivity_component_count[blk_seq] = block.nodesPerEntity;
}

return block_connectivity_component_count;
}

size_t get_all_block_connectivity_ioss_offset_size(const std::vector<BlockDecompositionData> &blocks)
{
return get_all_block_ioss_offset_size(blocks, get_all_block_connectivity_ioss_component_count(blocks));
}

std::vector<size_t>
get_all_block_connectivity_ioss_offset(const std::vector<BlockDecompositionData> &blocks)
{
return get_all_block_ioss_offset(blocks, get_all_block_connectivity_ioss_component_count(blocks));
}

std::vector<size_t>
get_all_block_connectivity_import_offset(const std::vector<BlockDecompositionData> &blocks)
{
return get_all_block_import_offset(blocks, get_all_block_connectivity_ioss_component_count(blocks));
}

template IOSS_EXPORT Decomposition<int>::Decomposition(const Ioss::PropertyManager &props,
Ioss_MPI_Comm comm);
template IOSS_EXPORT Decomposition<int64_t>::Decomposition(const Ioss::PropertyManager &props,
Expand Down
149 changes: 149 additions & 0 deletions packages/seacas/libraries/ioss/src/Ioss_Decomposition.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#include <string>
#include <vector>

#include <Ioss_Utils.h>
#include <Ioss_ParallelUtils.h>

#if !defined(NO_PARMETIS_SUPPORT)
#include <parmetis.h>
#endif
Expand Down Expand Up @@ -130,6 +133,28 @@ namespace Ioss {
bool distributionFactorConstant{false}; // T if all distribution factors the same value.
};

IOSS_EXPORT size_t get_all_block_ioss_element_size(const std::vector<BlockDecompositionData> &blocks);

IOSS_EXPORT size_t get_all_block_ioss_offset_size(const std::vector<BlockDecompositionData> &blocks,
const std::vector<int>& block_component_count);

IOSS_EXPORT std::vector<size_t> get_all_block_ioss_offset(const std::vector<BlockDecompositionData> &blocks,
const std::vector<int>& block_component_count);

IOSS_EXPORT std::vector<size_t> get_all_block_import_offset(const std::vector<BlockDecompositionData> &blocks,
const std::vector<int>& block_component_count);

IOSS_EXPORT std::vector<int>
get_all_block_connectivity_ioss_component_count(const std::vector<BlockDecompositionData> &blocks);

IOSS_EXPORT size_t get_all_block_connectivity_ioss_offset_size(const std::vector<BlockDecompositionData> &blocks);

IOSS_EXPORT std::vector<size_t>
get_all_block_connectivity_ioss_offset(const std::vector<BlockDecompositionData> &blocks);

IOSS_EXPORT std::vector<size_t>
get_all_block_connectivity_import_offset(const std::vector<BlockDecompositionData> &blocks);

template <typename INT> class Decomposition
{
public:
Expand Down Expand Up @@ -498,6 +523,130 @@ namespace Ioss {
}
}

template <typename T, typename U>
std::vector<size_t> do_communicate_all_block_data(T *file_data, U *ioss_data,
const std::vector<BlockDecompositionData> &blocks,
const std::vector<size_t> &file_offset,
const std::vector<int>& block_component_count) const
{
size_t export_size = 0;
size_t import_size = 0;

for(size_t blk_seq = 0; blk_seq < blocks.size(); blk_seq++) {
const Ioss::BlockDecompositionData& blk = blocks[blk_seq];

size_t comp_count = block_component_count[blk_seq];
export_size += blk.exportMap.size() * comp_count;
import_size += blk.importMap.size() * comp_count;
}

std::vector<U> exports;
exports.reserve(export_size);

Ioss::ParallelUtils util_(m_comm);
int nProc = util_.parallel_size();

for(int proc = 0; proc<nProc; proc++) {
for(size_t blk_seq = 0; blk_seq < blocks.size(); blk_seq++) {
const Ioss::BlockDecompositionData& blk = blocks[blk_seq];
size_t comp_count = block_component_count[blk_seq];
size_t fileDataOffset = file_offset[blk_seq];

for (int n = 0; n<blk.exportCount[proc]; n++) {
int exportIndex = blk.exportIndex[proc] + n;
int i = blk.exportMap[exportIndex];

for (size_t j = 0; j < comp_count; j++) {
size_t fileIndex = fileDataOffset + i * comp_count + j;
exports.push_back(file_data[fileIndex]);
}
}
}
}

std::vector<int64_t> export_count(nProc, 0);
std::vector<int64_t> export_disp(nProc, 0);
std::vector<int64_t> import_count(nProc, 0);
std::vector<int64_t> import_disp(nProc, 0);

for(size_t blk_seq = 0; blk_seq < blocks.size(); blk_seq++) {
const Ioss::BlockDecompositionData& blk = blocks[blk_seq];
size_t comp_count = block_component_count[blk_seq];

int proc = 0;
for (int i : blk.exportCount) {
export_count[proc++] += comp_count*i;
}

proc = 0;
for (int i : blk.importCount) {
import_count[proc++] += comp_count*i;
}
}

std::copy(export_count.begin(), export_count.end(), export_disp.begin());
std::copy(import_count.begin(), import_count.end(), import_disp.begin());

Ioss::Utils::generate_index(export_disp);
Ioss::Utils::generate_index(import_disp);

std::vector<U> imports(import_size);
Ioss::MY_Alltoallv(exports, export_count, export_disp, imports, import_count, import_disp, m_comm);
show_progress("\tCommunication 1 finished");

std::vector<size_t> ioss_offset = Ioss::get_all_block_ioss_offset(blocks, block_component_count);
std::vector<size_t> import_offset = Ioss::get_all_block_import_offset(blocks, block_component_count);

// Map local and imported data to ioss_data.
for(size_t blk_seq = 0; blk_seq < blocks.size(); blk_seq++) {
const Ioss::BlockDecompositionData& block = blocks[blk_seq];
size_t comp_count = block_component_count[blk_seq];

for (size_t i = 0; i < block.localMap.size(); i++) {
for (size_t j = 0; j < comp_count; j++) {
unsigned fileIndex = file_offset[blk_seq] + block.localMap[i] * comp_count + j;
unsigned iossIndex = ioss_offset[blk_seq] + (i + block.localIossOffset) * comp_count + j;
ioss_data[iossIndex] = file_data[fileIndex];
}
}

for (size_t i = 0; i < block.importMap.size(); i++) {
for (size_t j = 0; j < comp_count; j++) {
unsigned importIndex = import_offset[blk_seq] + i * comp_count + j;

size_t dataOffset = ioss_offset[blk_seq];
unsigned iossIndex = dataOffset + block.importMap[i] * comp_count + j;

ioss_data[iossIndex] = imports[importIndex];
}
}
}

return ioss_offset;
}

template <typename T, typename U>
std::vector<size_t> communicate_all_block_data(T *file_data, U *ioss_data,
const std::vector<BlockDecompositionData> &blocks,
const std::vector<size_t> &file_offset,
const std::vector<int>& block_component_count) const
{
show_progress(__func__);
if (m_method == "LINEAR") {
// For "LINEAR" decomposition method, the `file_data` is the
// same as `ioss_data` Transfer all local data from file_data
// to ioss_data...
auto size = file_offset[blocks.size()];
std::copy(file_data, file_data + size, ioss_data);

return Ioss::get_all_block_ioss_offset(blocks, block_component_count);;
}

auto retval = do_communicate_all_block_data(file_data, ioss_data, blocks, file_offset, block_component_count);

return retval;
}

template <typename T>
void communicate_node_data(T *file_data, T *ioss_data, size_t comp_count) const
{
Expand Down
Loading

0 comments on commit 15f91ed

Please sign in to comment.