Skip to content

Commit

Permalink
New API to allow storing only stats for primary variables (#4328)
Browse files Browse the repository at this point in the history
* Move the decision to write data for derived variables in VariableBase

Co-authored-by: Greg Eisenhauer <eisen@cc.gatech.edu>

* C and C++ bindings for setting the write mode of a variable

* Fortran API for changing the write mode for primary variables

* Python API for changing the write mode for primary variables

* Change the API to StoreStatsOnly instead of SetWriteMode

Co-authored-by: Norbert Podhorszki <pnorbert@ornl.gov>

* Testing in CXX and C for the StatsOnly write mode

* Testing for the Fortran bindings for the StatsOnly write mode

* Testing for the Python bindings for the StatsOnly write mode

---------

Co-authored-by: Greg Eisenhauer <eisen@cc.gatech.edu>
Co-authored-by: Norbert Podhorszki <pnorbert@ornl.gov>
  • Loading branch information
3 people authored Sep 17, 2024
1 parent d975ac0 commit 532747a
Show file tree
Hide file tree
Showing 22 changed files with 410 additions and 8 deletions.
17 changes: 17 additions & 0 deletions bindings/C/adios2/c/adios2_c_variable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,23 @@ adios2_error adios2_set_shape(adios2_variable *variable, const size_t ndims, con
}
}

adios2_error adios2_store_stats_only(adios2_variable *variable, const adios2_bool mode)
{
try
{
adios2::core::VariableBase *variableBase =
reinterpret_cast<adios2::core::VariableBase *>(variable);
variableBase->StoreStatsOnly(mode);

return adios2_error_none;
}
catch (...)
{
return static_cast<adios2_error>(
adios2::helper::ExceptionToError("adios2_set_memory_space"));
}
}

adios2::MemorySpace adios2_ToMemorySpace(const adios2_memory_space Cmem)
{
adios2::MemorySpace mem = adios2::MemorySpace::Detect;
Expand Down
6 changes: 6 additions & 0 deletions bindings/C/adios2/c/adios2_c_variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ extern "C" {
*/
adios2_error adios2_set_shape(adios2_variable *variable, const size_t ndims, const size_t *shape);

/**
* Set the write mode of a variable
* @param false - write data; true - write only stats
*/
adios2_error adios2_store_stats_only(adios2_variable *variable, const adios2_bool mode);

/**
* Sets the memory space for all following Puts/Gets
* to either host (default) or device
Expand Down
6 changes: 6 additions & 0 deletions bindings/CXX11/adios2/cxx11/Variable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ namespace adios2
} \
\
template <> \
void Variable<T>::StoreStatsOnly(const bool mode) \
{ \
m_Variable->StoreStatsOnly(mode); \
} \
\
template <> \
void Variable<T>::SetMemorySpace(const MemorySpace mem) \
{ \
m_Variable->SetMemorySpace(mem); \
Expand Down
6 changes: 6 additions & 0 deletions bindings/CXX11/adios2/cxx11/Variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ class Variable
/** Checks if object is valid, e.g. if( variable ) { //..valid } */
explicit operator bool() const noexcept;

/**
* Set the write mode of a variable
* @param false - write data; true - write only stats
*/
void StoreStatsOnly(const bool mode);

/**
* Sets the memory space for all following Puts/Gets
* to either host (default) or device
Expand Down
7 changes: 7 additions & 0 deletions bindings/Fortran/f2c/adios2_f2c_variable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ void FC_GLOBAL(adios2_variable_steps_f2c,
}
}

void FC_GLOBAL(adios2_store_stats_only_f2c, ADIOS2_SET_WRITE_MODE_F2C)(adios2_variable **variable,
const adios2_bool *mode,
int *ierr)
{
*ierr = static_cast<int>(adios2_store_stats_only(*variable, *mode));
}

void FC_GLOBAL(adios2_set_memory_space_f2c, ADIOS2_SET_MEMORY_SPACE_F2C)(adios2_variable **variable,
const int *mem, int *ierr)
{
Expand Down
9 changes: 9 additions & 0 deletions bindings/Fortran/modules/adios2_variable_mod.f90
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module adios2_variable_mod
external adios2_set_selection_f2c
external adios2_set_shape_f2c
external adios2_set_step_selection_f2c
external adios2_store_stats_only_f2c
external adios2_variable_name_f2c
external adios2_variable_name_length_f2c
external adios2_variable_ndims_f2c
Expand Down Expand Up @@ -131,6 +132,14 @@ subroutine adios2_set_selection(variable, ndims, start_dims, count_dims, &
count_dims, ierr)
end subroutine

subroutine adios2_store_stats_only(variable, mode, ierr)
type(adios2_variable), intent(in) :: variable
logical, intent(in) :: mode
integer, intent(out) :: ierr

call adios2_store_stats_only_f2c(variable%f2c, mode, ierr)
end subroutine

subroutine adios2_set_memory_selection(variable, ndims, &
memory_start_dims, &
memory_count_dims, &
Expand Down
6 changes: 6 additions & 0 deletions bindings/Python/py11Variable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ void Variable::SetShape(const Dims &shape)
m_VariableBase->SetShape(shape);
}

void Variable::StoreStatsOnly(const bool mode)
{
helper::CheckForNullptr(m_VariableBase, "in call to Variable::StoreStatsOnly");
m_VariableBase->StoreStatsOnly(mode);
}

void Variable::SetBlockSelection(const size_t blockID)
{
helper::CheckForNullptr(m_VariableBase, "in call to Variable::SetBlockSelection");
Expand Down
2 changes: 2 additions & 0 deletions bindings/Python/py11Variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class Variable

void SetShape(const Dims &shape);

void StoreStatsOnly(const bool mode);

void SetBlockSelection(const size_t blockID);

void SetSelection(const Box<Dims> &selection);
Expand Down
1 change: 1 addition & 0 deletions bindings/Python/py11glue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ PYBIND11_MODULE(ADIOS2_PYTHON_MODULE_NAME, m)
return opBool;
})
.def("SetShape", &adios2::py11::Variable::SetShape)
.def("StoreStatsOnly", &adios2::py11::Variable::StoreStatsOnly)
.def("SetBlockSelection", &adios2::py11::Variable::SetBlockSelection)
.def("SetSelection", &adios2::py11::Variable::SetSelection)
.def("SetStepSelection", &adios2::py11::Variable::SetStepSelection)
Expand Down
6 changes: 6 additions & 0 deletions python/adios2/variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,9 @@ def remove_operations(self):
Remove operations (operators) assigned to this Variable.
"""
self.impl.RemoveOperations()

def store_stats_only(self, mode):
"""
Select writing mode for variable (write data or just stats)
"""
self.impl.StoreStatsOnly(mode)
2 changes: 2 additions & 0 deletions source/adios2/core/VariableBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ VariableBase::VariableBase(const std::string &name, const DataType type, const s

size_t VariableBase::TotalSize() const noexcept { return helper::GetTotalSize(m_Count); }

void VariableBase::StoreStatsOnly(const bool mode) { m_WriteData = !(mode); }

#if defined(ADIOS2_HAVE_KOKKOS) || defined(ADIOS2_HAVE_GPU_SUPPORT)
ArrayOrdering VariableBase::GetArrayLayout() { return m_ArrayLayout; }

Expand Down
9 changes: 9 additions & 0 deletions source/adios2/core/VariableBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ class VariableBase
* VariableStruct -> from constructor sizeof(struct) */
const size_t m_ElementSize;

/** Write data for the variable (True - default) or only write stats (False) */
bool m_WriteData = true;

/* User requested memory space */
MemorySpace m_MemSpace = MemorySpace::Detect;
#if defined(ADIOS2_HAVE_KOKKOS) || defined(ADIOS2_HAVE_GPU_SUPPORT)
Expand Down Expand Up @@ -128,6 +131,12 @@ class VariableBase
*/
size_t TotalSize() const noexcept;

/**
* Set the write mode of a variable
* @param false - write data; true - write only stats
*/
void StoreStatsOnly(const bool mode);

#if defined(ADIOS2_HAVE_KOKKOS) || defined(ADIOS2_HAVE_GPU_SUPPORT)
/**
* Get the layout used by the user buffers
Expand Down
2 changes: 2 additions & 0 deletions source/adios2/core/VariableDerived.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ VariableDerived::VariableDerived(const std::string &name, adios2::derived::Expre
expr.GetCount(), isConstant),
m_DerivedType(varType), m_NameToType(nameToType), m_Expr(expr)
{
if (varType != DerivedVarType::StoreData)
m_WriteData = false;
}

DerivedVarType VariableDerived::GetDerivedType() { return m_DerivedType; }
Expand Down
9 changes: 1 addition & 8 deletions source/adios2/toolkit/format/bp5/BP5Serializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -751,14 +751,7 @@ void BP5Serializer::Marshal(void *Variable, const char *Name, const DataType Typ
core::VariableDerived *VD = dynamic_cast<core::VariableDerived *>(VB);
#endif

bool WriteData = true;
#ifdef ADIOS2_HAVE_DERIVED_VARIABLE
if (VD)
{
// All other types of Derived types we don't write data
WriteData = (VD->GetDerivedType() == DerivedVarType::StoreData);
}
#endif
bool WriteData = VB->m_WriteData;
BP5MetadataInfoStruct *MBase;

BP5WriterRec Rec = LookupWriterRec(Variable);
Expand Down
1 change: 1 addition & 0 deletions testing/adios2/bindings/C/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ gtest_add_tests_helper(NullWriteRead MPI_ALLOW "" Bindings.C. "")
gtest_add_tests_helper(WriteAggregateReadLocal MPI_ONLY BP Bindings.C. "")
gtest_add_tests_helper(AvailableVariablesAttribites MPI_ONLY BP Bindings.C. "")
gtest_add_tests_helper(MemorySpace MPI_NONE BP Bindings.C. "")
gtest_add_tests_helper(WriteStatsOnly MPI_ALLOW BP Bindings.C. "")
88 changes: 88 additions & 0 deletions testing/adios2/bindings/C/TestBPWriteStatsOnly.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Distributed under the OSI-approved Apache License, Version 2.0. See
* accompanying file Copyright.txt for details.
*
* TestBPWriteStatsOnly.cpp : test the C bindings when only stats are written
*/

#include <adios2_c.h>
#include <gtest/gtest.h>
#include <vector>

class ADIOS2_C_API : public ::testing::Test
{
public:
ADIOS2_C_API() { adiosH = adios2_init_serial(); }

~ADIOS2_C_API() { adios2_finalize(adiosH); }

adios2_adios *adiosH;
};

TEST_F(ADIOS2_C_API, ADIOS2BPWriteStatsOnly)
{
#if ADIOS2_USE_MPI
const char fname[] = "ADIOS2_C_API.ADIOS2BPWriteStatsOnly_MPI.bp";
#else
const char fname[] = "ADIOS2_C_API.ADIOS2BPWriteStatsOnly.bp";
#endif
// write
{
adios2_io *ioH = adios2_declare_io(adiosH, "CWriteStats");
adios2_set_engine(ioH, "BPFile");

size_t shape[2];
shape[0] = 5;
shape[1] = 2;

size_t start[2];
start[0] = 0;
start[1] = 0;

size_t count[2];
count[0] = 5;
count[1] = 2;

int32_t data_I32[10] = {131072, 131073, -131070, 131075, -131068,
131077, -131066, 131079, -131064, 131081};
adios2_define_variable(ioH, "varI32", adios2_type_int32_t, 2, shape, start, count,
adios2_constant_dims_true);
adios2_variable *varI32 = adios2_inquire_variable(ioH, "varI32");
adios2_store_stats_only(varI32, adios2_true);

adios2_engine *engineH = adios2_open(ioH, fname, adios2_mode_write);
adios2_put(engineH, varI32, data_I32, adios2_mode_deferred);
adios2_close(engineH);
}
// read shape
{
adios2_io *ioH = adios2_declare_io(adiosH, "Reader");
adios2_engine *engineH = adios2_open(ioH, fname, adios2_mode_readRandomAccess);
size_t steps;
adios2_steps(&steps, engineH);
EXPECT_EQ(steps, 1);

std::vector<int32_t> inI32(10);
adios2_variable *varI32 = adios2_inquire_variable(ioH, "varI32");

// test that the shape function returns the correct dimensions
size_t cpu_shape[2];
adios2_error e = adios2_variable_shape(cpu_shape, varI32);
EXPECT_EQ(e, adios2_error_none);
EXPECT_EQ(cpu_shape[0], 5);
EXPECT_EQ(cpu_shape[1], 2);

e = adios2_get(engineH, varI32, inI32.data(), adios2_mode_sync);
EXPECT_EQ(e, adios2_error_runtime_error);
adios2_close(engineH);
}
}

int main(int argc, char **argv)
{
int result;
::testing::InitGoogleTest(&argc, argv);
result = RUN_ALL_TESTS();

return result;
}
1 change: 1 addition & 0 deletions testing/adios2/bindings/fortran/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ fortran_add_test_helper(BPReadGlobalsByName MPI_ONLY)
fortran_add_test_helper(BPWriteMemorySelectionRead2D MPI_ONLY)
fortran_add_test_helper(BPWriteMemorySelectionRead3D MPI_ONLY)
fortran_add_test_helper(NullEngine MPI_ONLY)
fortran_add_test_helper(BPWriteStatsOnly MPI_NONE)
fortran_add_test_helper(BPMemorySpace MPI_NONE)
if(ADIOS2_HAVE_GPU_Support)
fortran_add_test_helper(BPMemorySpaceGPU MPI_NONE)
Expand Down
67 changes: 67 additions & 0 deletions testing/adios2/bindings/fortran/TestBPWriteStatsOnly.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
program TestBPWriteStatsOnly
use adios2

implicit none

type(adios2_adios) :: adios
type(adios2_io) :: ioPut, ioGet
type(adios2_engine) :: bpWriter, bpReader
type(adios2_variable) :: var_temperatures, var_temperaturesIn

integer(kind=4), dimension(:, :), allocatable :: temperatures_i4, &
sel_temperatures_i4

integer(kind=8), dimension(2) :: ishape, istart, icount
integer(kind=4) :: ierr
integer :: step_status
integer :: in1, in2

in1 = 5
in2 = 10

icount = (/in1, in2/)
istart = (/0, 0/)
ishape = (/in1, in2/)

allocate (temperatures_i4(in1, in2))
temperatures_i4 = 1

! Start adios2 Writer
call adios2_init(adios, ierr)
call adios2_declare_io(ioPut, adios, 'TestWrite', ierr)

call adios2_define_variable(var_temperatures, ioPut, &
'temperatures_i4', adios2_type_integer4, &
2, ishape, istart, icount, &
adios2_constant_dims, ierr)
call adios2_store_stats_only(var_temperatures, .true., ierr)

call adios2_open(bpWriter, ioPut, 'TestBPWriteStatsOnly_f.bp', adios2_mode_write, &
ierr)
call adios2_put(bpWriter, var_temperatures, temperatures_i4, ierr)
call adios2_close(bpWriter, ierr)
if (allocated(temperatures_i4)) deallocate (temperatures_i4)

call adios2_declare_io(ioGet, adios, 'TestRead', ierr)
call adios2_open(bpReader, ioGet, 'TestBPWriteStatsOnly_f.bp', &
adios2_mode_read, ierr)

call adios2_begin_step(bpReader, adios2_step_mode_read, -1., &
step_status, ierr)
call adios2_inquire_variable(var_temperaturesIn, ioGet, &
'temperatures_i4', ierr)

allocate (sel_temperatures_i4(ishape(1), ishape(2)))
sel_temperatures_i4 = 0

call adios2_get(bpReader, var_temperaturesIn, sel_temperatures_i4, adios2_mode_sync, ierr)
if (ierr == 0) then
write(*,*) 'adios2_get for a variable storing only stats returned without error'
if (allocated(sel_temperatures_i4)) deallocate (sel_temperatures_i4)
call adios2_close(bpReader, ierr)
stop 1
end if
if (allocated(sel_temperatures_i4)) deallocate (sel_temperatures_i4)
call adios2_close(bpReader, ierr)

end program TestBPWriteStatsOnly
1 change: 1 addition & 0 deletions testing/adios2/bindings/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ endfunction()

python_add_test(NAME Bindings.Python.BPWriteReadTypes.Serial SCRIPT TestBPWriteReadTypes_nompi.py)
python_add_test(NAME Bindings.Python.TypeExceptionOnGet.Serial SCRIPT TestGetException_nompi.py)
python_add_test(NAME Bindings.Python.BPWriteStatsOnly.Serial SCRIPT TestBPWriteStatsOnly.py)

if(ADIOS2_HAVE_MPI)
add_python_mpi_test(BPWriteReadTypes)
Expand Down
Loading

0 comments on commit 532747a

Please sign in to comment.