Skip to content

Commit 6d62da2

Browse files
authored
Merge pull request #597 from E3SM-Project/dqwu/adios_decomp_enhancement
Storing large decomposition maps in ADIOS BP files can significantly increase disk usage. This PR introduces a build-time configuration option for the ADIOS type, allowing users to conserve disk space by excluding decomposition data from BP files. Also see PR #589 (on maint branch)
2 parents e97dd82 + 7d276c1 commit 6d62da2

File tree

8 files changed

+205
-3
lines changed

8 files changed

+205
-3
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ option (WITH_NETCDF "Require the use of NetCDF" ON)
5353
option (WITH_ADIOS2 "Require the use of ADIOS 2.x" OFF)
5454
option (WITH_HDF5 "Require the use of HDF5" OFF)
5555
option (ADIOS_BP2NC_TEST "Enable testing of BP to NetCDF conversion" OFF)
56+
option (ADIOS_NO_DECOMPS "Save no decomposition data to ADIOS BP files" OFF)
5657
#===== Testing Options =====
5758
option (PIO_ENABLE_TESTS "Enable the testing builds" OFF)
5859
option (PIO_ENABLE_LARGE_TESTS "Enable large (file, processes) tests" OFF)

ctest/CTestEnvironment-anlgce.cmake

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ if (DEFINED ENV{ENABLE_ADIOS_BP2NC_TEST})
8686
set (CTEST_CONFIGURE_OPTIONS "${CTEST_CONFIGURE_OPTIONS} -DADIOS_BP2NC_TEST=ON")
8787
endif ()
8888

89+
# If ENABLE_ADIOS_NO_DECOMPS environment variable is set, then save no decomposition data to ADIOS BP files
90+
if (DEFINED ENV{ENABLE_ADIOS_NO_DECOMPS})
91+
set (CTEST_CONFIGURE_OPTIONS "${CTEST_CONFIGURE_OPTIONS} -DADIOS_NO_DECOMPS=ON")
92+
endif ()
93+
8994
# If ENABLE_TESTS environment variable is set, then enable the testing builds
9095
if (DEFINED ENV{ENABLE_TESTS})
9196
set (CTEST_CONFIGURE_OPTIONS "${CTEST_CONFIGURE_OPTIONS} -DPIO_ENABLE_TESTS=ON")

ctest/CTestScript-Test.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ ctest_test(INCLUDE "pio_unit_test|^init|pio_file\
3232
elseif (DEFINED ENV{ADIOS_READ_CTEST})
3333
ctest_test(INCLUDE "pio_unit_test|^init|pio_file\
3434
|ncdf_simple_tests\
35-
|pio_decomp_tests_|pio_decomp_frame_tests_|pio_decomp_extra_dims_\
35+
|pio_decomp_tests_np|pio_decomp_extra_dims_\
3636
|pio_iosystem_tests|examplePio|example1|darray_no_async|test_adios")
3737
elseif (DEFINED ENV{HDF5_CTEST})
3838
ctest_test(INCLUDE "test_hdf5")

src/clib/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,12 @@ if (ADIOS_BP2NC_TEST)
317317
PUBLIC _ADIOS_BP2NC_TEST)
318318
endif ()
319319

320+
if (ADIOS_NO_DECOMPS)
321+
message(STATUS "No decomposition data will be saved to ADIOS BP files to reduce disk usage")
322+
target_compile_definitions (pioc
323+
PUBLIC _SPIO_ADIOS_NO_DECOMPS)
324+
endif ()
325+
320326
if (PIO_ENABLE_API_TRACING)
321327
message(STATUS "Enabling API tracing")
322328
set(ENABLE_API_TRACING 1)

src/clib/pio.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,10 @@ typedef struct file_desc_t
10841084
struct spio_hmap *cache_darray_info;
10851085

10861086
char io_name_reader[PIO_MAX_NAME + 1]; /* Name of io object, for ADIOS read */
1087+
size_t adios_reader_num_decomp_blocks; /* Number of decomposition blocks, for ADIOS read */
1088+
1089+
/* Indicates whether the decomposition maps (for ADIOS write) need to be stored in BP files. Default is true. */
1090+
bool store_adios_decomp;
10871091
#endif /* _ADIOS2 */
10881092

10891093
#ifdef _HDF5

src/clib/pio_darray.cpp

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,11 @@ static int MPI_BigAdios_Gatherv(const void *sendbuf, int sendcount, MPI_Datatype
842842
static int needs_to_write_decomp(file_desc_t *file, int ioid)
843843
{
844844
assert(file != NULL);
845+
846+
/* No need to write the decomposition maps to ADIOS BP files. */
847+
if (!file->store_adios_decomp)
848+
return 0;
849+
845850
int ret = 1; // Yes
846851
for (int i = 0; i < file->n_written_ioids; i++)
847852
{
@@ -2756,6 +2761,8 @@ static int PIOc_read_darray_adios(file_desc_t *file, int fndims, io_desc_t *iode
27562761
decomp_info_buff = (const int *) file->cache_darray_info->get(file->cache_darray_info, decomp_name);
27572762
if (decomp_info_buff == NULL)
27582763
{
2764+
if (file->store_adios_decomp)
2765+
{
27592766
/* We should search decomposition array from the step 0 if the decomp info is not in the cache, so we close and open the bp file */
27602767
/* Should not reopen opened file at step 0 */
27612768
if ((file->engineH != NULL && current_adios_step != 0) ||
@@ -2871,7 +2878,8 @@ static int PIOc_read_darray_adios(file_desc_t *file, int fndims, io_desc_t *iode
28712878
pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid);
28722879
}
28732880

2874-
int32_t decomp_blocks_size = decomp_blocks->nblocks;
2881+
size_t decomp_blocks_size = decomp_blocks->nblocks;
2882+
assert(decomp_blocks_size == file->adios_reader_num_decomp_blocks);
28752883

28762884
/* Free memory */
28772885
for (size_t i = 0; i < decomp_blocks->nblocks; i++)
@@ -3044,6 +3052,55 @@ static int PIOc_read_darray_adios(file_desc_t *file, int fndims, io_desc_t *iode
30443052
"Cannot determine block for the decomposition map (ADIOS read and write must use the same decomposition map)",
30453053
pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid);
30463054
}
3055+
} /* End if (file->store_adios_decomp) */
3056+
else
3057+
{
3058+
/* In case the write decomposition map is not available for verification,
3059+
* we simply use the anticipated block and start/end indices to read data. */
3060+
iosystem_desc_t *ios = file->iosystem; /* Pointer to io system information. */
3061+
assert(ios != NULL);
3062+
3063+
/* Determine the maximum number of compute tasks assigned to each block. */
3064+
size_t decomp_blocks_size = file->adios_reader_num_decomp_blocks;
3065+
assert(decomp_blocks_size > 0);
3066+
int max_comptasks_per_block = ios->num_comptasks / decomp_blocks_size;
3067+
if (ios->num_comptasks % decomp_blocks_size != 0)
3068+
max_comptasks_per_block++;
3069+
assert(max_comptasks_per_block >= 1);
3070+
3071+
/* Calculate the most probable target block we try to find. */
3072+
int guess_block = ios->comp_rank / max_comptasks_per_block;
3073+
assert(guess_block >= 0 && guess_block < decomp_blocks_size);
3074+
3075+
target_block = guess_block;
3076+
3077+
/* Store the length of the decomposition map on each computation task. */
3078+
int task_maplen[ios->num_comptasks];
3079+
3080+
/* Gather map lengths from all computation tasks and fill the task_maplen array on all tasks. */
3081+
int mpierr = MPI_SUCCESS;
3082+
if ((mpierr = MPI_Allgather(&iodesc->maplen, 1, MPI_INT, task_maplen, 1, MPI_INT, ios->comp_comm)))
3083+
return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__);
3084+
assert(task_maplen[file->all_rank] == iodesc->maplen);
3085+
3086+
start_idx_in_target_block = 0;
3087+
for (int proc = 0; proc < ios->num_comptasks; proc++)
3088+
{
3089+
int proc_block = proc / max_comptasks_per_block;
3090+
if (proc_block == target_block && proc < file->all_rank)
3091+
{
3092+
/* Handle the special case where the map length is 0 or 1.
3093+
* The ADIOS writer always ensures that the map length is
3094+
* at least 2 by padding if the original length is 0 or 1. */
3095+
if (task_maplen[proc] > 1)
3096+
start_idx_in_target_block += task_maplen[proc];
3097+
else
3098+
start_idx_in_target_block += 2;
3099+
}
3100+
}
3101+
3102+
end_idx_in_target_block = start_idx_in_target_block + iodesc->maplen - 1;
3103+
}
30473104

30483105
/* Add to cache */
30493106
int *buff = (int*)calloc(3, sizeof(int));

src/clib/pioc_support.cpp

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2961,6 +2961,14 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char *
29612961
file->num_adiostasks = ios->num_adiostasks;
29622962
file->adios_io_process = ios->adios_io_process;
29632963

2964+
file->adios_reader_num_decomp_blocks = 0;
2965+
2966+
#ifdef _SPIO_ADIOS_NO_DECOMPS
2967+
file->store_adios_decomp = false;
2968+
#else
2969+
file->store_adios_decomp = true;
2970+
#endif
2971+
29642972
/* Create a new ADIOS group */
29652973
char declare_name[PIO_MAX_NAME];
29662974
snprintf(declare_name, PIO_MAX_NAME, "%s%lu", file->filename, get_adios2_io_cnt());
@@ -3073,7 +3081,35 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char *
30733081
"Putting (ADIOS) variable (name=/__pio__/info/nproc) failed (adios2_error=%s) for file (%s)",
30743082
convert_adios2_error_to_string(adiosErr), pio_get_fname_from_file(file));
30753083
}
3076-
(file->num_written_blocks)++;
3084+
3085+
variableH = adios2_inquire_variable(file->ioH, "/__pio__/info/decomp_stored");
3086+
if (variableH == NULL)
3087+
{
3088+
variableH = adios2_define_variable(file->ioH,
3089+
"/__pio__/info/decomp_stored", adios2_type_int32_t,
3090+
0, NULL, NULL, NULL,
3091+
adios2_constant_dims_true);
3092+
if (variableH == NULL)
3093+
{
3094+
spio_ltimer_stop(file->io_fstats->wr_timer_name);
3095+
spio_ltimer_stop(file->io_fstats->tot_timer_name);
3096+
return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__,
3097+
"Defining (ADIOS) variable (name=/__pio__/info/decomp_stored) failed for file (%s)",
3098+
pio_get_fname_from_file(file));
3099+
}
3100+
}
3101+
3102+
int info_decomp_stored = (file->store_adios_decomp)? 1 : 0;
3103+
adiosErr = adios2_put(file->engineH, variableH, &info_decomp_stored, adios2_mode_sync);
3104+
if (adiosErr != adios2_error_none)
3105+
{
3106+
spio_ltimer_stop(file->io_fstats->wr_timer_name);
3107+
spio_ltimer_stop(file->io_fstats->tot_timer_name);
3108+
return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__,
3109+
"Putting (ADIOS) variable (name=/__pio__/info/decomp_stored) failed (adios2_error=%s) for file (%s)",
3110+
convert_adios2_error_to_string(adiosErr), pio_get_fname_from_file(file));
3111+
}
3112+
file->num_written_blocks += 2;
30773113
}
30783114

30793115
/* Write the number and list of processes in block merges */
@@ -3537,6 +3573,8 @@ static int adios_get_step_info(file_desc_t *file, int, size_t, size_t);
35373573
static int adios_get_dim_ids(file_desc_t *file, int);
35383574
static int adios_get_nc_op_tag(file_desc_t *file, int);
35393575
static int adios_get_attr(file_desc_t *file, int current_var_cnt, char *const *attr_names, size_t);
3576+
static int adios_get_num_decomp_blocks(file_desc_t *file);
3577+
static int adios_get_decomp_storage_info(file_desc_t *file);
35403578
static size_t adios_read_vars_vars(file_desc_t *file, size_t var_size, char *const *var_names);
35413579
static size_t adios_read_vars_attrs(file_desc_t *file, size_t attr_size, char *const *attr_names);
35423580

@@ -4113,6 +4151,62 @@ static int adios_get_step_info(file_desc_t *file, int varid, size_t adios_step,
41134151
return 0;
41144152
}
41154153

4154+
static int adios_get_num_decomp_blocks(file_desc_t *file)
4155+
{
4156+
adios2_variable *variableH = adios2_inquire_variable(file->ioH, "/__pio__/info/block_list");
4157+
if (variableH == NULL)
4158+
{
4159+
return pio_err(NULL, file, PIO_EADIOS2ERR, __FILE__, __LINE__,
4160+
"Getting number of decomposition blocks in file (%s, ncid=%d) using ADIOS iotype failed. "
4161+
"/__pio__/info/block_list is missing",
4162+
pio_get_fname_from_file(file), file->pio_ncid);
4163+
}
4164+
4165+
adios2_varinfo *info_block_list = adios2_inquire_blockinfo(file->engineH, variableH, 0);
4166+
if (info_block_list == NULL)
4167+
{
4168+
return pio_err(NULL, file, PIO_EADIOS2ERR, __FILE__, __LINE__,
4169+
"Getting number of decomposition blocks (%s, ncid=%d) using ADIOS iotype failed. "
4170+
"The low level (ADIOS) I/O library call failed to get the list of blocks for a variable in a given step (NULL pointer returned)",
4171+
pio_get_fname_from_file(file), file->pio_ncid);
4172+
}
4173+
4174+
file->adios_reader_num_decomp_blocks = info_block_list->nblocks;
4175+
4176+
/* Free adios2_varinfo structure (this ADIOS2 API returns void) */
4177+
adios2_free_blockinfo(info_block_list);
4178+
4179+
return PIO_NOERR;
4180+
}
4181+
4182+
static int adios_get_decomp_storage_info(file_desc_t *file)
4183+
{
4184+
adios2_variable *variableH = adios2_inquire_variable(file->ioH, "/__pio__/info/decomp_stored");
4185+
4186+
/* Maintains backward compatibility with earlier generated BP files where decomposition storage
4187+
* information is absent. */
4188+
if (variableH == NULL)
4189+
{
4190+
file->store_adios_decomp = true;
4191+
return PIO_NOERR;
4192+
}
4193+
4194+
int info_decomp_stored = -1;
4195+
adios2_error adiosErr = adios2_get(file->engineH, variableH, &info_decomp_stored, adios2_mode_sync);
4196+
if (adiosErr != adios2_error_none)
4197+
{
4198+
return pio_err(NULL, file, PIO_EADIOS2ERR, __FILE__, __LINE__,
4199+
"Getting decomposition storage info in file (%s, ncid=%d) using ADIOS iotype failed. "
4200+
"The low level (ADIOS) I/O library call failed to get data associated with a variable from an engine (adios2_error=%s)",
4201+
pio_get_fname_from_file(file), file->pio_ncid, convert_adios2_error_to_string(adiosErr));
4202+
}
4203+
assert(info_decomp_stored == 0 || info_decomp_stored == 1);
4204+
4205+
file->store_adios_decomp = (info_decomp_stored == 0)? false : true;
4206+
4207+
return PIO_NOERR;
4208+
}
4209+
41164210
static size_t adios_read_vars_attrs(file_desc_t *file, size_t attr_size, char *const *attr_names)
41174211
{
41184212
size_t current_var_cnt = 0;
@@ -4604,6 +4698,10 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f
46044698
file->cache_block_sizes = spio_hash(10000);
46054699
file->cache_darray_info = spio_hash(10000);
46064700

4701+
file->adios_reader_num_decomp_blocks = 0;
4702+
4703+
file->store_adios_decomp = true;
4704+
46074705
while (step < nsteps && adios2_begin_step(file->engineH, adios2_step_mode_read, -1.0, &status) == adios2_error_none)
46084706
{
46094707
file->begin_step_called = 1;
@@ -4669,6 +4767,12 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f
46694767
adios_get_step_info(file, var_id, step, nsteps);
46704768
}
46714769

4770+
if (step == 0)
4771+
{
4772+
adios_get_num_decomp_blocks(file);
4773+
adios_get_decomp_storage_info(file);
4774+
}
4775+
46724776
adiosErr = adios2_end_step(file->engineH);
46734777
if (adiosErr != adios2_error_none)
46744778
{

tools/adios2pio-nm/adios2pio-nm-lib.cxx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2184,6 +2184,7 @@ int ConvertBPFile(const string &infilepath, const string &outfilename,
21842184
string err_msg = "No errors";
21852185
int ncid = -1;
21862186
int n_bp_writers;
2187+
int decomp_stored_flag = -1;
21872188
int ret = PIO_NOERR;
21882189
int iosysid;
21892190

@@ -2252,6 +2253,26 @@ int ConvertBPFile(const string &infilepath, const string &outfilename,
22522253
return BP2PIO_ERROR;
22532254
}
22542255

2256+
/* Get the value of /__pio__/info/decomp_stored flag */
2257+
adios2::Variable<int> bpDecompStored = bpIO[0].InquireVariable<int>("/__pio__/info/decomp_stored");
2258+
if (bpDecompStored)
2259+
{
2260+
bpReader[0].Get(bpDecompStored, &decomp_stored_flag, adios2::Mode::Sync);
2261+
assert(decomp_stored_flag == 0 || decomp_stored_flag == 1);
2262+
}
2263+
else
2264+
{
2265+
/* Maintains backward compatibility with earlier generated BP files where decomposition storage
2266+
* information is absent. */
2267+
decomp_stored_flag = 1;
2268+
}
2269+
2270+
if (decomp_stored_flag == 0)
2271+
{
2272+
if (w_mpirank == 0)
2273+
fprintf(stdout, "WARNING: Skipping conversion of distributed array variables due to missing decomposition data for BP file : \"%s\"\n", infilepath.c_str());
2274+
}
2275+
22552276
uint64_t time_step = 0;
22562277
std::vector<int> block_procs;
22572278
adios2::Variable<int> blockProcs = bpIO[0].InquireVariable<int>("/__pio__/info/block_nprocs");
@@ -2408,6 +2429,9 @@ int ConvertBPFile(const string &infilepath, const string &outfilename,
24082429
}
24092430
else if (var.op == "darray")
24102431
{
2432+
/* Convert distributed array variables only when decomposition maps are available. */
2433+
if (decomp_stored_flag == 1)
2434+
{
24112435
/* Variable was written with pio_write_darray() with a decomposition */
24122436
if (debug_out)
24132437
{
@@ -2418,6 +2442,7 @@ int ConvertBPFile(const string &infilepath, const string &outfilename,
24182442
iosysid, file0, adios_new, time_step,
24192443
comm, mpirank, nproc, block_procs, local_proc_blocks,
24202444
block_list, processed_attrs, decomp_cache);
2445+
}
24212446
}
24222447
}
24232448

0 commit comments

Comments
 (0)