diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 28705e6da..067e33a61 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,24 +57,16 @@ jobs: - name: Install APT Dependencies run: | sudo apt update - sudo apt-get install -y autoconf - sudo apt-get install -y automake - sudo apt-get install -y libtool - sudo apt-get install -y libtool-bin - sudo apt-get install -y mpich - sudo apt-get install -y lcov - sudo apt-get install -y zlib1g-dev - sudo apt-get install -y libsdl2-dev - sudo apt-get install -y hdf5-tools + sudo apt-get install -y docker - name: Build And Install Dependencies - if: steps.spack-cache.outputs.cache-hit != 'true' +# if: steps.spack-cache.outputs.cache-hit != 'true' run: ci/install_deps.sh -# - name: Build + - name: Build and Test # if: steps.hermes-cache.outputs.cache-hit != 'true' -# run: ci/build_hermes.sh -# + run: docker exec /hermes_deps_c bash hermes/ci/build_hermes.sh + # - name: Test # run: bash ci/test_hermes.sh # @@ -86,8 +78,8 @@ jobs: # - name: Multi-node Test # run: pushd ci/cluster && ./multi_node_ci_test.sh -# - name: Generate coverage file -# run: bash ci/coverage.sh + - name: Generate coverage file + run: docker exec /hermes_deps_c bash hermes/ci/coverage.sh "hermes/coverage" "hermes/build" # - name: Coveralls # uses: coverallsapp/github-action@master diff --git a/CMakeLists.txt b/CMakeLists.txt index d6418ba74..ac8660cef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,16 +9,19 @@ option(BUILD_MPI_TESTS "Build tests which depend on MPI" ON) option(BUILD_OpenMP_TESTS "Build tests which depend on OpenMP" ON) option(HERMES_ENABLE_COVERAGE "Check how well tests cover code" OFF) option(HERMES_ENABLE_DOXYGEN "Check how well the code is documented" OFF) +option(HERMES_REMOTE_DEBUG "Enable remote debug mode on hrun" OFF) option(HERMES_ENABLE_POSIX_ADAPTER "Build the Hermes POSIX adapter." ON) -option(HERMES_ENABLE_STDIO_ADAPTER "Build the Hermes stdio adapter." ON) -option(HERMES_ENABLE_MPIIO_ADAPTER "Build the Hermes MPI-IO adapter." ON) +option(HERMES_ENABLE_STDIO_ADAPTER "Build the Hermes stdio adapter." OFF) +option(HERMES_ENABLE_MPIIO_ADAPTER "Build the Hermes MPI-IO adapter." OFF) +option(HERMES_ENABLE_VFD "Build the Hermes HDF5 Virtual File Driver" OFF) option(HERMES_ENABLE_PUBSUB_ADAPTER "Build the Hermes pub/sub adapter." OFF) option(HERMES_ENABLE_KVSTORE "Build the Hermes KVStore adapter." OFF) -option(HERMES_ENABLE_VFD "Build the Hermes HDF5 Virtual File Driver" OFF) option(HERMES_ENABLE_PYTHON "Build the Hermes Python wrapper" ON) +option(HERMES_ENABLE_ADIOS "Build the Hermes Python wrapper" ON) -message("HERMES_ENABLE_PYTHON: ${HERMES_ENABLE_PYTHON}") +option(HERMES_MPICH "Specify that this a MPICH build" OFF) +option(HERMES_OPENMPI "Specify that this a OpenMPI build" OFF) #----------------------------------------------------------------------------- # Compiler Optimization @@ -45,9 +48,35 @@ if(NOT HERMES_EXPORTED_TARGETS) set(HERMES_EXPORTED_TARGETS "hrun-targets") endif() +#----------------------------------------------------------------------------- +# Coverage +#----------------------------------------------------------------------------- +if(HERMES_ENABLE_COVERAGE) + set(COVERAGE_FLAGS "-fprofile-arcs -ftest-coverage --coverage" CACHE STRING + "Flags to the coverage program to perform coverage inspection" + ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${COVERAGE_FLAGS}") + + mark_as_advanced(COVERAGE_FLAGS) + + macro(set_coverage_flags target) + target_link_libraries(${target} gcov) +# set_target_properties(${target} +# PROPERTIES +# COMPILE_FLAGS ${COVERAGE_FLAGS} +# LINK_FLAGS ${COVERAGE_FLAGS} +# ) + endmacro() +endif() +add_custom_target(coverage COMMAND bash ${CMAKE_SOURCE_DIR}/ci/coverage.sh + ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}) + #----------------------------------------------------------------------------- # Find Packages #----------------------------------------------------------------------------- +# This is for compatability with SPACK +SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # HermesShm find_package(HermesShm CONFIG REQUIRED) @@ -61,7 +90,7 @@ message(STATUS "found yaml-cpp at ${yaml-cpp_DIR}") find_package(Catch2 3.0.1 REQUIRED) message(STATUS "found catch2.h at ${Catch2_CXX_INCLUDE_DIRS}") -# MPICH +# MPI if(BUILD_MPI_TESTS) find_package(MPI REQUIRED COMPONENTS C CXX) message(STATUS "found mpi.h at ${MPI_CXX_INCLUDE_DIRS}") @@ -85,6 +114,15 @@ if(PkgConfig) message(STATUS "found pkg config") endif() +# LIBAIO +#find_library(LIBAIO_LIBRARY NAMES aio) +#if(LIBAIO_LIBRARY) +# message(STATUS "found libaio at ${LIBAIO_LIBRARY}") +#else() +# set(LIBAIO_LIBRARY aio) +# message(STATUS "Assuming it was installed with our aio spack") +#endif() + # Zeromq #pkg_check_modules(ZMQ REQUIRED libzmq) #include_directories(${ZMQ_INCLUDE_DIRS}) @@ -105,6 +143,38 @@ endif() include_directories(${Boost_INCLUDE_DIRS}) message("Boost: ${Boost_LIBRARIES}") +# HDF5 +if(HERMES_ENABLE_VFD) + set(HERMES_REQUIRED_HDF5_VERSION 1.14.0) + set(HERMES_REQUIRED_HDF5_COMPONENTS C) + find_package(HDF5 ${HERMES_REQUIRED_HDF5_VERSION} CONFIG NAMES hdf5 + COMPONENTS ${HERMES_REQUIRED_HDF5_COMPONENTS} shared) + if(HDF5_FOUND) + message(STATUS "found HDF5 ${HDF5_VERSION} at ${HDF5_INCLUDE_DIR}") + set(HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES + ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} + ${HDF5_INCLUDE_DIR}) + set(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES + ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES} + ${HDF5_C_SHARED_LIBRARY}) + else() + # Allow for HDF5 autotools builds + find_package(HDF5 ${HERMES_REQUIRED_HDF5_VERSION} MODULE REQUIRED + COMPONENTS ${HERMES_REQUIRED_HDF5_COMPONENTS}) + if(HDF5_FOUND) + set(HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES + ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} + ${HDF5_INCLUDE_DIRS}) + set(HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES + ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES} + ${HDF5_LIBRARIES}) + else() + message(FATAL_ERROR "Could not find HDF5, please set HDF5_DIR (1.13.0) or HDF5_ROOT (1.13.1).") + endif() + endif() +endif() + + #------------------------------------------------------------------------------ # Setup CMake Environment #------------------------------------------------------------------------------ @@ -199,6 +269,11 @@ function(pytest test_type test_name) # COMMAND ${script} ${test_type} ${test_name} ${CMAKE_BINARY_DIR} ${HERMES_USE_ADDRESS_SANITIZER}) endfunction() +function(jarvis_test test_type test_name) + add_test(NAME ${test_name} + COMMAND jarvis pipeline run yaml "${CMAKE_SOURCE_DIR}/test/unit/pipelines/${test_type}/${test_name}.yaml") +endfunction() + enable_testing() add_subdirectory(test) diff --git a/README.md b/README.md index 4bdeec1cc..35adbce84 100644 --- a/README.md +++ b/README.md @@ -53,3 +53,68 @@ make install ## Contributing We follow the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). You can run `make lint` to ensure that your code conforms to the style. This requires the `cpplint` Python module (`pip install cpplint`). Alternatively, you can let the CI build inform you of required style changes. + +## Docker + +Build container with Hermes dependencies: +``` +docker build -t lukemartinlogan/hermes_deps . -f docker/deps.Dockerfile +``` + +Run the container with the Hermes source mounted: +``` +docker run -it --mount src=${PWD},target=/hermes,type=bind \ +--name hermes_deps_c \ +--network host \ +--memory=4G \ +--shm-size=4G \ +-p 4000:4000 \ +-p 4001:4001 \ +lukemartinlogan/hermes_deps +``` + +Build Hermes + Jarvis (in container): +``` +bash /hermes/ci/build_hermes.sh +``` + +``` +docker commit hermes_deps_c lukemartinlogan/hermes_deps +docker push lukemartinlogan/hermes_deps +docker stop /hermes_deps_c +docker rm /hermes_deps_c +``` + +## Remote Debug + +### On personal machine +``` +ares_node=llogan@ares.cs.iit.edu + +local_port=4000 +remote_port=4000 +ssh -L ${local_port}:localhost:${remote_port} -fN ${ares_node} + +local_port=4001 +remote_port=4001 +ssh -L ${local_port}:localhost:${remote_port} -fN ${ares_node} +``` + +On Ares +``` +ares_node=ares-comp-27 + +local_port=4000 +remote_port=4000 +ssh -L ${local_port}:localhost:${remote_port} -fN ${ares_node} + +local_port=4001 +remote_port=4001 +ssh -L ${local_port}:localhost:${remote_port} -fN ${ares_node} +``` + +Find PIDs of processes using ports +``` +lsof -i :4000 +lsof -i :4001 +``` \ No newline at end of file diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index ee640a1ae..7963dd82c 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -62,5 +62,5 @@ install(TARGETS #----------------------------------------------------------------------------- if(HERMES_ENABLE_COVERAGE) set_coverage_flags(test_performance_exec) - set_coverage_flags(test_hermes_api) + set_coverage_flags(hermes_api_bench) endif() diff --git a/benchmark/hermes_api_bench.cc b/benchmark/hermes_api_bench.cc index 19ba38889..f1a8f6644 100644 --- a/benchmark/hermes_api_bench.cc +++ b/benchmark/hermes_api_bench.cc @@ -26,7 +26,7 @@ void GatherTimes(std::string test_name, size_t io_size, MpiTimer &t) { if (t.rank_ == 0) { double max = t.GetSec(); double mbps = io_size / t.GetUsec(); - HIPRINT("{}: Time: {} sec, MBps (or MOps): {}, Count: {}, Nprocs: {}\n", + HILOG(kInfo, "{}: Time: {} sec, MBps (or MOps): {}, Count: {}, Nprocs: {}\n", test_name, max, mbps, io_size, t.nprocs_); } } @@ -41,6 +41,7 @@ void PutTest(int nprocs, int rank, t.Resume(); for (int j = 0; j < repeat; ++j) { for (size_t i = 0; i < blobs_per_rank; ++i) { + // HILOG(kInfo, "On blob {}", i) size_t blob_name_int = rank * blobs_per_rank + i; std::string name = std::to_string(blob_name_int); bkt.AsyncPut(name, blob, ctx); @@ -77,7 +78,11 @@ void GetTest(int nprocs, int rank, void PutGetTest(int nprocs, int rank, int repeat, size_t blobs_per_rank, size_t blob_size) { PutTest(nprocs, rank, repeat, blobs_per_rank, blob_size); + HILOG(kInfo, "Beginning barrier") MPI_Barrier(MPI_COMM_WORLD); + HILOG(kInfo, "Beginning flushing") + HRUN_ADMIN->FlushRoot(DomainId::GetGlobal()); + HILOG(kInfo, "Finished flushing") GetTest(nprocs, rank, repeat, blobs_per_rank, blob_size); } @@ -143,7 +148,6 @@ void CreateBucketTest(int nprocs, int rank, MpiTimer t(MPI_COMM_WORLD); t.Resume(); hapi::Context ctx; - std::unordered_map mdm_; for (size_t i = 0; i < bkts_per_rank; ++i) { int bkt_name_int = rank * bkts_per_rank + i; std::string bkt_name = std::to_string(bkt_name_int); @@ -238,8 +242,7 @@ int main(int argc, char **argv) { MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &nprocs); - TRANSPARENT_HRUN(); - HERMES->ClientInit(); + TRANSPARENT_HERMES(); // Get mode REQUIRE_ARGC_GE(2) diff --git a/benchmark/test_latency.cc b/benchmark/test_latency.cc index a3ecba432..af1636956 100644 --- a/benchmark/test_latency.cc +++ b/benchmark/test_latency.cc @@ -10,7 +10,6 @@ #include "hermes_shm/util/timer.h" #include "hrun/work_orchestrator/affinity.h" #include "hermes/hermes.h" -#include "hrun/work_orchestrator/worker.h" #include "hrun/api/hrun_runtime.h" /** The performance of getting a queue */ @@ -95,7 +94,7 @@ TEST_CASE("TestHshmQueueEmplacePop") { hrun::QueueId qid(0, 3); u32 ops = (1 << 20); std::vector queue_info = { - {16, 16, ops, 0} + {TaskPrio::kAdmin, 16, 16, ops, 0} }; auto queue = hipc::make_uptr( qid, queue_info); @@ -120,7 +119,7 @@ TEST_CASE("TestHshmQueueEmplacePop") { TEST_CASE("TestHshmQueueGetLane") { hrun::QueueId qid(0, 3); std::vector queue_info = { - {16, 16, 256, 0} + {TaskPrio::kAdmin, 16, 16, 256, 0} }; auto queue = hipc::make_uptr( qid, queue_info); @@ -139,9 +138,10 @@ TEST_CASE("TestHshmQueueGetLane") { /** Single-thread performance of getting, emplacing, and popping a queue */ TEST_CASE("TestHshmQueueAllocateEmplacePop") { + TRANSPARENT_HERMES(); hrun::QueueId qid(0, 3); std::vector queue_info = { - {16, 16, 256, 0} + {TaskPrio::kAdmin, 16, 16, 256, 0} }; auto queue = hipc::make_uptr( qid, queue_info); @@ -209,7 +209,7 @@ void TestWorkerIterationLatency(u32 num_queues, u32 num_lanes) { for (u32 i = 0; i < num_queues; ++i) { hrun::QueueId qid(0, i + 1); std::vector queue_info = { - {num_lanes, num_lanes, 256, 0} + {TaskPrio::kAdmin, num_lanes, num_lanes, 256, 0} }; auto queue = hipc::make_uptr( qid, queue_info); @@ -233,7 +233,7 @@ void TestWorkerIterationLatency(u32 num_queues, u32 num_lanes) { task = client.AsyncMdPushEmplace(queues[num_queues - 1].get(), task_node, hrun::DomainId::GetLocal()); - worker.Run(); + worker.Run(false); HRUN_CLIENT->DelTask(task); } t.Pause(); @@ -252,8 +252,7 @@ TEST_CASE("TestWorkerLatency") { /** Time to process a request */ TEST_CASE("TestRoundTripLatency") { - TRANSPARENT_HRUN(); - HERMES->ClientInit(); + TRANSPARENT_HERMES(); hrun::small_message::Client client; HRUN_ADMIN->RegisterTaskLibRoot(hrun::DomainId::GetLocal(), "small_message"); // int count = 25; @@ -264,13 +263,14 @@ TEST_CASE("TestRoundTripLatency") { client.CreateRoot(hrun::DomainId::GetLocal(), "ipc_test"); hshm::Timer t; - int pid = getpid(); - ProcessAffiner::SetCpuAffinity(pid, 8); + // int pid = getpid(); + // ProcessAffiner::SetCpuAffinity(pid, 8); t.Resume(); size_t ops = (1 << 20); // size_t ops = 1024; for (size_t i = 0; i < ops; ++i) { + // client.MdRoot(hrun::DomainId::GetLocal()); client.MdPushRoot(hrun::DomainId::GetLocal()); } t.Pause(); diff --git a/ci/build_hermes.sh b/ci/build_hermes.sh index a13d3c167..4557b6e84 100755 --- a/ci/build_hermes.sh +++ b/ci/build_hermes.sh @@ -1,42 +1,75 @@ #!/bin/bash -# CD into git workspace -cd ${GITHUB_WORKSPACE} +# ARGS: +# SPACK_DIR: the path to spack +# THIS SCRIPT IS EXECUTED BY CONTAINER!!! set -x set -e set -o pipefail -# Set spack env -INSTALL_DIR="${HOME}" -SPACK_DIR=${INSTALL_DIR}/spack -. ${SPACK_DIR}/share/spack/setup-env.sh +# Update jarvis-cd +pushd jarvis-cd +git pull +pip install -e . -r requirements.txt +popd -mkdir -p "${HOME}/install" -mkdir build -cd build +# Update scspkg +pushd scspkg +git pull +pip install -e . -r requirements.txt +popd + +# Load scspkg environment +. /module_load.sh +module use "$(scspkg module dir)" + +# Load hermes_shm +. "${SPACK_DIR}/share/spack/setup-env.sh" +spack module tcl refresh --delete-tree -y spack load hermes_shm +# module use "${SPACK_DIR}/share/spack/modules/linux-ubuntu22.04-zen2" + +# Create Hermes module +scspkg create hermes +scspkg env prepend hermes PATH /hermes/build/bin +scspkg env prepend hermes LIBRARY_PATH /hermes/build/bin +scspkg env prepend hermes LD_LIBRARY_PATH /hermes/build/bin +module load hermes + +# Initialize the Jarvis testing Hermes environment +jarvis init \ +"${HOME}/jarvis-config" \ +"${HOME}/jarvis-priv" \ +"${HOME}/jarvis-shared" +cp /hermes/ci/resource_graph.yaml /jarvis-cd/config/resource_graph.yaml +jarvis env build hermes + +# CD into Hermes directory in container +cd /hermes +git config --global --add safe.directory '*' +git submodule update --init + +# Build Hermes +mkdir -p build +cd build cmake ../ \ -DCMAKE_BUILD_TYPE=Debug \ --DCMAKE_INSTALL_PREFIX="${HOME}/install" +-DCMAKE_INSTALL_PREFIX="$(scspkg pkg root hermes)" \ +-DHERMES_ENABLE_MPIIO_ADAPTER=ON \ +-DHERMES_MPICH=ON \ +-DHERMES_ENABLE_STDIO_ADAPTER=ON \ +-DHERMES_ENABLE_POSIX_ADAPTER=ON \ +-DHERMES_ENABLE_COVERAGE=ON make -j8 make install +# Test Hermes export CXXFLAGS=-Wall ctest -VV -# Set proper flags for cmake to find Hermes -INSTALL_PREFIX="${HOME}/install" -export LIBRARY_PATH="${INSTALL_PREFIX}/lib:${LIBRARY_PATH}" -export LD_LIBRARY_PATH="${INSTALL_PREFIX}/lib:${LD_LIBRARY_PATH}" -export LDFLAGS="-L${INSTALL_PREFIX}/lib:${LDFLAGS}" -export CFLAGS="-I${INSTALL_PREFIX}/include:${CFLAGS}" -export CPATH="${INSTALL_PREFIX}/include:${CPATH}" -export CMAKE_PREFIX_PATH="${INSTALL_PREFIX}:${CMAKE_PREFIX_PATH}" -export CXXFLAGS="-I${INSTALL_PREFIX}/include:${CXXFLAGS}" - # Run make install unit test -cd test/unit/external +cd /hermes/test/unit/external mkdir build cd build cmake ../ diff --git a/ci/coverage.sh b/ci/coverage.sh index 59e8dbd01..a017eca20 100644 --- a/ci/coverage.sh +++ b/ci/coverage.sh @@ -1,7 +1,9 @@ #!/bin/bash -COVERAGE_DIR="${GITHUB_WORKSPACE}/coverage" +COVERAGE_DIR="$1" +BUILD_DIR="$2" mkdir -p "${COVERAGE_DIR}" -cd "${GITHUB_WORKSPACE}/build" +cd "${BUILD_DIR}" +echo $BUILD_DIR lcov -c -d . -o "${COVERAGE_DIR}/tmp.info" lcov --remove "${COVERAGE_DIR}/tmp.info" \ "/usr/*" \ diff --git a/ci/hermes/packages/hermes/package.py b/ci/hermes/packages/hermes/package.py index e295a1843..a21ec63b6 100644 --- a/ci/hermes/packages/hermes/package.py +++ b/ci/hermes/packages/hermes/package.py @@ -7,10 +7,9 @@ class Hermes(CMakePackage): version('master', branch='master', submodules=True) - version('dev', git='https://github.com/lukemartinlogan/hermes.git', - branch='dev', submodules=True) - version('dev-priv', git='https://github.com/lukemartinlogan/hermes.git', - branch='dev', submodules=True) + version('dev', branch='dev', submodules=True) + version('priv', branch='dev', + git='https://github.com/lukemartinlogan/hermes.git', submodules=True) version("1.0.5-beta", sha256="1f3ba51a8beda4bc1314d6541b800de1525f5e233a6f498fcde6dc43562ddcb7") version("1.0.0-beta", sha256="301084cced32aa00532ab4bebd638c31b0512c881ffab20bf5da4b7739defac2") version("0.9.9-beta", sha256="d2e0025a9bd7a3f05d3ab608c727ed15d86ed30cf582549fe996875daf6cb649") @@ -29,33 +28,49 @@ class Hermes(CMakePackage): version("0.4.0-beta", sha256="06020836e203b2f680bea24007dc73760dfb977eb61e442b795b264f0267c16b") version("0.3.0-beta...v0.4.0-beta", sha256="7729b115598277adcab019dee24e5276698fb595066bca758bfa59dc8d51c5a4") + depends_on('hermes_shm@master') + + # Common across hermes_shm and hermes + variant('mpiio', default=True, description='Enable MPI I/O adapter') + variant('stdio', default=True, description='Enable STDIO adapter') + variant('vfd', default=False, description='Enable HDF5 VFD') variant('ares', default=False, description='Enable full libfabric install') variant('only_verbs', default=False, description='Only verbs') - variant('vfd', default=False, description='Enable HDF5 VFD') variant('debug', default=False, description='Build shared libraries') variant('zmq', default=False, description='Build ZeroMQ tests') - depends_on('hermes_shm') depends_on('mochi-thallium~cereal@0.10.1') depends_on('catch2@3.0.1') - depends_on('mpich@3.3.2') + depends_on('mpi') depends_on('cereal') depends_on('yaml-cpp') - depends_on('doxygen@1.9.3') - depends_on('boost@1.7: +context +fiber +filesystem +system +atomic +chrono +serialization +signals +pic') - depends_on('libfabric fabrics=sockets,tcp,udp,rxm,rxd,verbs', + depends_on('libaio') + depends_on('doxygen') # @1.9.3 + depends_on('boost@1.7: +context +fiber +filesystem +system +atomic +chrono +serialization +signals +pic +regex') + depends_on('libfabric fabrics=sockets,tcp,udp,verbs', when='+ares') depends_on('libfabric fabrics=verbs', when='+only_verbs') depends_on('libzmq', '+zmq') depends_on('hdf5@1.14.0', when='+vfd') + depends_on('adios2', when='+adios') def cmake_args(self): - args = ['-DCMAKE_INSTALL_PREFIX={}'.format(self.prefix)] + args = [] if '+debug' in self.spec: args.append('-DCMAKE_BUILD_TYPE=Debug') else: args.append('-DCMAKE_BUILD_TYPE=Release') + if '+mpiio' in self.spec: + args.append('-DHERMES_ENABLE_MPIIO_ADAPTER=ON') + if 'openmpi' in self.spec: + args.append('-DHERMES_OPENMPI=ON') + elif 'mpich' in self.spec: + args.append('-DHERMES_MPICH=ON') + if '+stdio' in self.spec: + args.append('-HERMES_ENABLE_STDIO_ADAPTER=ON') + if '+vfd' in self.spec: + args.append('-HERMES_ENABLE_VFD=ON') return args def set_include(self, env, path): @@ -68,6 +83,7 @@ def set_lib(self, env, path): env.prepend_path('LIBRARY_PATH', path) env.prepend_path('LD_LIBRARY_PATH', path) env.append_flags('LDFLAGS', '-L{}'.format(path)) + env.prepend_path('PYTHONPATH', '{}'.format(path)) def set_flags(self, env): self.set_include(env, '{}/include'.format(self.prefix)) diff --git a/ci/hermes/packages/hermes_shm/package.py b/ci/hermes/packages/hermes_shm/package.py index 9d31d00c6..1749fb515 100644 --- a/ci/hermes/packages/hermes_shm/package.py +++ b/ci/hermes/packages/hermes_shm/package.py @@ -6,27 +6,33 @@ class HermesShm(CMakePackage): url = "https://github.com/lukemartinlogan/hermes_shm/archive/refs/tags/v1.0.0.tar.gz" version('master', branch='master') + version("1.1.0", sha256="080d5361cff22794b670e4544c532926ca8b6d6ec695af25596efe035bfffea5") version("1.0.0", sha256="a79f01d531ce89985ad59a2f62b41d74c2385e48d929e2f4ad895ae34137573b") + variant('mpiio', default=True, description='Enable MPI I/O adapter') + variant('stdio', default=True, description='Enable STDIO adapter') + variant('vfd', default=False, description='Enable HDF5 VFD') variant('ares', default=False, description='Enable full libfabric install') variant('only_verbs', default=False, description='Only verbs') - variant('vfd', default=False, description='Enable HDF5 VFD') variant('debug', default=False, description='Build shared libraries') variant('zmq', default=False, description='Build ZeroMQ tests') + variant('adios', default=False, description='Build Adios tests') depends_on('mochi-thallium~cereal@0.10.1') depends_on('catch2@3.0.1') - depends_on('mpich@3.3.2') + depends_on('mpi') depends_on('cereal') depends_on('yaml-cpp') - depends_on('doxygen@1.9.3') + depends_on('libaio') + depends_on('doxygen') # @1.9.3 depends_on('boost@1.7: +context +fiber +filesystem +system +atomic +chrono +serialization +signals +pic +regex') - depends_on('libfabric fabrics=sockets,tcp,udp,rxm,rxd,verbs', + depends_on('libfabric fabrics=sockets,tcp,udp,verbs', when='+ares') depends_on('libfabric fabrics=verbs', when='+only_verbs') depends_on('libzmq', '+zmq') depends_on('hdf5@1.14.0', when='+vfd') + depends_on('adios2', when='+adios') def cmake_args(self): args = [] @@ -34,6 +40,16 @@ def cmake_args(self): args.append('-DCMAKE_BUILD_TYPE=Debug') else: args.append('-DCMAKE_BUILD_TYPE=Release') + if '+mpiio' in self.spec: + args.append('-DHERMES_ENABLE_MPIIO_ADAPTER=ON') + if 'openmpi' in self.spec: + args.append('-DHERMES_OPENMPI=ON') + elif 'mpich' in self.spec: + args.append('-DHERMES_MPICH=ON') + if '+stdio' in self.spec: + args.append('-HERMES_ENABLE_STDIO_ADAPTER=ON') + if '+vfd' in self.spec: + args.append('-HERMES_ENABLE_VFD=ON') return args def set_include(self, env, path): diff --git a/ci/hermes/packages/libaio/package.py b/ci/hermes/packages/libaio/package.py new file mode 100644 index 000000000..c566ab046 --- /dev/null +++ b/ci/hermes/packages/libaio/package.py @@ -0,0 +1,57 @@ +# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other +# Spack Project Developers. See the top-level COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + + +from spack.package import * + + +class Libaio(MakefilePackage): + """Linux native Asynchronous I/O interface library. + + AIO enables even a single application thread to overlap I/O operations + with other processing, by providing an interface for submitting one or + more I/O requests in one system call (io_submit()) without waiting for + completion, and a separate interface (io_getevents()) to reap completed + I/O operations associated with a given completion group. + """ + + homepage = "http://lse.sourceforge.net/io/aio.html" + url = ( + "https://debian.inf.tu-dresden.de/debian/pool/main/liba/libaio/libaio_0.3.110.orig.tar.gz" + ) + + version("0.3.113", sha256="2c44d1c5fd0d43752287c9ae1eb9c023f04ef848ea8d4aafa46e9aedb678200b") + version("0.3.110", sha256="e019028e631725729376250e32b473012f7cb68e1f7275bfc1bbcdd0f8745f7e") + + conflicts("platform=darwin", msg="libaio is a linux specific library") + + @property + def install_targets(self): + return ["prefix={0}".format(self.spec.prefix), "install"] + + def set_include(self, env, path): + env.append_flags('CFLAGS', '-I{}'.format(path)) + env.append_flags('CXXFLAGS', '-I{}'.format(path)) + env.prepend_path('INCLUDE', '{}'.format(path)) + env.prepend_path('CPATH', '{}'.format(path)) + + def set_lib(self, env, path): + env.prepend_path('LIBRARY_PATH', path) + env.prepend_path('LD_LIBRARY_PATH', path) + env.append_flags('LDFLAGS', '-L{}'.format(path)) + env.prepend_path('PYTHONPATH', '{}'.format(path)) + + def set_flags(self, env): + self.set_include(env, '{}/include'.format(self.prefix)) + self.set_include(env, '{}/include'.format(self.prefix)) + self.set_lib(env, '{}/lib'.format(self.prefix)) + self.set_lib(env, '{}/lib64'.format(self.prefix)) + env.prepend_path('CMAKE_PREFIX_PATH', '{}/cmake'.format(self.prefix)) + + def setup_dependent_environment(self, spack_env, run_env, dependent_spec): + self.set_flags(spack_env) + + def setup_run_environment(self, env): + self.set_flags(env) diff --git a/ci/install_deps.sh b/ci/install_deps.sh index 03958f316..764bfc0a5 100755 --- a/ci/install_deps.sh +++ b/ci/install_deps.sh @@ -1,41 +1,18 @@ #!/bin/bash -# CD into git workspace -cd ${GITHUB_WORKSPACE} - -# This script will build and install them via Spack from source -# because Hermes requires a very specific version and configuration options -# for each package. - set -x set -e set -o pipefail -# Change this especially when your $HOME doesn't have enough disk space. -INSTALL_DIR="${HOME}" -SPACK_DIR=${INSTALL_DIR}/spack -SPACK_VERSION=0.18.1 - -echo "Installing dependencies at ${INSTALL_DIR}" -mkdir -p ${INSTALL_DIR} - -# Load Spack -git clone https://github.com/spack/spack ${SPACK_DIR} -cd ${SPACK_DIR} -git checkout v${SPACK_VERSION} - -# Set spack env -set +x -. ${SPACK_DIR}/share/spack/setup-env.sh -set -x - -# This will allow Spack to skip building some packages that are directly -# available from the system. For example, autoconf, cmake, m4, etc. -# Modify ci/pckages.yaml to skip building compilers or build tools via Spack. -cd ${GITHUB_WORKSPACE} -cp ci/packages.yaml ${SPACK_DIR}/etc/spack/packages.yaml - -# Install hermes_shm (needed for dependencies) -# -spack repo add ci/hermes -spack install hermes_shm +# Pull the Hermes dependencies image +docker pull lukemartinlogan/hermes_deps:latest +docker run -d \ +--mount src=${PWD},target=/hermes,type=bind \ +--name hermes_deps_c \ +--network host \ +--memory=4G \ +--shm-size=4G \ +-p 4000:4000 \ +-p 4001:4001 \ +lukemartinlogan/hermes_deps \ +tail -f /dev/null diff --git a/ci/module_load.sh b/ci/module_load.sh new file mode 100644 index 000000000..46706ff02 --- /dev/null +++ b/ci/module_load.sh @@ -0,0 +1,10 @@ +#!/bin/bash +if ! shopt -q login_shell; then + if [ -d /etc/profile.d ]; then + for i in /etc/profile.d/*.sh; do + if [ -r $i ]; then + . $i + fi + done + fi +fi diff --git a/ci/packages.yaml b/ci/packages.yaml deleted file mode 100644 index 7be206aad..000000000 --- a/ci/packages.yaml +++ /dev/null @@ -1,38 +0,0 @@ -packages: - all: - target: [x86_64] - mpich: - externals: - - spec: mpich@3.3.2 - prefix: /usr - buildable: False - cmake: - externals: - - spec: cmake@3.23.2 - prefix: /usr/local - buildable: False - autoconf: - externals: - - spec: autoconf@2.69 - prefix: /usr - buildable: False - automake: - externals: - - spec: automake@1.16 - prefix: /usr - buildable: False - libtool: - externals: - - spec: libtool@2.4.6 - prefix: /usr - buildable: False - m4: - externals: - - spec: m4@1.4.18 - prefix: /usr - buildable: False - pkg-config: - externals: - - spec: pkg-config@0.29.1 - prefix: /usr - buildable: False diff --git a/ci/resource_graph.yaml b/ci/resource_graph.yaml new file mode 100644 index 000000000..8573ae7e1 --- /dev/null +++ b/ci/resource_graph.yaml @@ -0,0 +1,73 @@ +fs: +- avail: 17179869184 + dev_type: hdd + device: /dev/hdd1 + fs_mount: /hdd + fs_size: 16G + fs_type: ext4 + host: localhost + label: null + model: CT500P1SSD8 + mount: /hdd + parent: /dev/hdd + partlabel: null + partuuid: d4ff55be-ac9f-4bd3-9602-48e8b673fa37 + rota: false + shared: false + size: 17179869184 + tran: nvme + use%: 0% + used: 0G + uuid: 8debe05d-9177-40b5-8bb0-82fc969ce919 +- avail: 17179869184 + dev_type: ssd + device: /dev/ssd1 + fs_mount: /ssd + fs_size: 16G + fs_type: ext4 + host: localhost + label: null + model: CT500P1SSD8 + mount: /ssd + parent: /dev/ssd + partlabel: null + partuuid: d4ff55be-ac9f-4bd3-9602-48e8b673fa37 + rota: false + shared: false + size: 17179869184 + tran: nvme + use%: 0% + used: 0G + uuid: 8debe05d-9177-40b5-8bb0-82fc969ce919 +- avail: 17179869184 + dev_type: nvme + device: /dev/nvme1n1p3 + fs_mount: /nvme + fs_size: 16G + fs_type: ext4 + host: localhost + label: null + model: CT500P1SSD8 + mount: /nvme + parent: /dev/nvme1n1 + partlabel: null + partuuid: d4ff55be-ac9f-4bd3-9602-48e8b673fa37 + rota: false + shared: false + size: 17179869184 + tran: nvme + use%: 0% + used: 0G + uuid: 8debe05d-9177-40b5-8bb0-82fc969ce919 +hosts: +- localhost +net: +- domain: lo + fabric: 127.0.0.0/8 + host: localhost + protocol: FI_PROTO_SOCK_TCP + provider: sockets + shared: false + speed: 1073741824 + type: FI_EP_RDM + version: '2.0' diff --git a/codegen/refresh_methods b/codegen/refresh_methods index cad1bfac4..44b1761c3 100755 --- a/codegen/refresh_methods +++ b/codegen/refresh_methods @@ -29,6 +29,7 @@ def refresh_methods(TASK_ROOT): if TASK_NAME != 'hrun_admin': methods.insert(0, ('kConstruct', -2)) methods.insert(1, ('kDestruct', -1)) + monitor_modes = ['kEstTime', 'kTrainTime', 'kFlushStat'] # Produce the TASK_NAME_methods.h file lines = [] @@ -67,6 +68,20 @@ def refresh_methods(TASK_ROOT): lines += [' }'] lines += ['}'] + ## Create the Monitor method + lines += ['/** Execute a task */', + 'void Monitor(u32 mode, Task *task, RunContext &rctx) override {', + ' switch (task->method_) {'] + for method_enum_name, method_off in methods: + method_name = method_enum_name.replace('k', '', 1) + task_name = method_name + "Task" + lines += [f' case Method::{method_enum_name}: {{', + f' Monitor{method_name}(mode, reinterpret_cast<{task_name} *>(task), rctx);', + f' break;', + f' }}'] + lines += [' }'] + lines += ['}'] + ## Create the Del method lines += ['/** Delete a task */', 'void Del(u32 method, Task *task) override {', @@ -75,7 +90,7 @@ def refresh_methods(TASK_ROOT): method_name = method_enum_name.replace('k', '', 1) task_name = method_name + "Task" lines += [f' case Method::{method_enum_name}: {{', - f' HRUN_CLIENT->DelTask(reinterpret_cast<{task_name} *>(task));', + f' HRUN_CLIENT->DelTask<{task_name}>(reinterpret_cast<{task_name} *>(task));', f' break;', f' }}'] lines += [' }'] diff --git a/config/hermes_server_default.yaml b/config/hermes_server_default.yaml index 9741de8dd..8a25d43f9 100644 --- a/config/hermes_server_default.yaml +++ b/config/hermes_server_default.yaml @@ -76,12 +76,6 @@ devices: is_shared_device: true borg_capacity_thresh: [ 0.0, 1.0 ] -# Define the maximum amount of memory Hermes can use for non-buffering tasks. -# This includes metadata management and memory allocations. -# This memory will not be preallocated, so if you don't know, 0 indicates -# any amount of memory -max_memory: 0g - ### Define properties of the BORG buffer_organizer: # The number of threads used in the background organization of internal Hermes buffers. @@ -140,13 +134,17 @@ system_view_state_update_interval_ms: 1000 ### Runtime orchestration settings work_orchestrator: - # The number of worker threads to spawn - max_workers: 4 + # The max number of dedicated worker threads + max_dworkers: 4 + # The max number of overlapping threads + max_oworkers: 32 + # The max number of total dedicated cores + owork_per_core: 32 ### Queue Manager settings queue_manager: # The default depth of allocated queues - queue_depth: 256 + queue_depth: 100000 # The maximum number of lanes per queue max_lanes: 16 # The maximum number of queues @@ -158,6 +156,7 @@ queue_manager: # The size of the shared memory region to allocate for general data structures shm_size: 0g # The size of the shared memory to allocate for data buffers + data_shm_size: 4g ### Define properties of RPCs rpc: @@ -183,7 +182,7 @@ rpc: port: 8080 # The number of handler threads for each RPC server. - num_threads: 4 + num_threads: 32 ### Task Registry task_registry: [ diff --git a/docker/deps.Dockerfile b/docker/deps.Dockerfile new file mode 100644 index 000000000..e55eb9ca9 --- /dev/null +++ b/docker/deps.Dockerfile @@ -0,0 +1,63 @@ +# Install ubuntu 20.04 +FROM ubuntu:20.04 +LABEL maintainer="llogan@hawk.iit.edu" +LABEL version="0.0" +LABEL description="Hermes Docker image with CI" + +# Disable Prompt During Packages Installation +ARG DEBIAN_FRONTEND=noninteractive + +# Update ubuntu +SHELL ["/bin/bash", "-c"] +RUN apt update && apt install + +# Install some basic packages +RUN apt install -y \ + openssh-server \ + sudo \ + git \ + gcc g++ gfortran make binutils gpg \ + tar zip xz-utils bzip2 \ + perl m4 libncurses5-dev libxml2-dev diffutils \ + pkg-config cmake pkg-config \ + python3 python3-pip doxygen \ + lcov zlib1g-dev hdf5-tools \ + build-essential ca-certificates \ + coreutils curl environment-modules \ + gfortran git gpg lsb-release python3 python3-distutils \ + python3-venv unzip zip \ + bash jq python gdbserver gdb + +# Setup basic environment +ENV USER="root" +ENV HOME="/root" +ENV SPACK_DIR="${HOME}/spack" +ENV SPACK_VERSION="v0.20.2" +ENV HERMES_DEPS_DIR="${HOME}/hermes_deps" +ENV HERMES_DIR="${HOME}/hermes" +COPY ci/module_load.sh /module_load.sh + +# Install Spack +RUN . /module_load.sh && \ + git clone -b ${SPACK_VERSION} https://github.com/spack/spack ${SPACK_DIR} && \ + . "${SPACK_DIR}/share/spack/setup-env.sh" && \ + git clone -b dev https://github.com/lukemartinlogan/hermes.git ${HERMES_DEPS_DIR} && \ + # git clone -b dev https://github.com/HDFGroup/hermes.git ${HERMES_DEPS_DIR} && \ + spack repo add ${HERMES_DEPS_DIR}/ci/hermes && \ + mkdir -p ${HERMES_DIR} && \ + spack external find + +# Install hermes_shm +RUN . /module_load.sh && \ + . "${SPACK_DIR}/share/spack/setup-env.sh" && \ + spack install hermes_shm@master+vfd+mpiio^mpich@3.3.2 + +# Install jarvis-cd +RUN git clone https://github.com/grc-iit/jarvis-cd.git && \ + cd jarvis-cd && \ + pip install -e . -r requirements.txt + +# Install scspkg +RUN git clone https://github.com/grc-iit/scspkg.git && \ + cd scspkg && \ + pip install -e . -r requirements.txt diff --git a/hermes_adapters/CMakeLists.txt b/hermes_adapters/CMakeLists.txt index e335f4d0b..1c37de7a2 100644 --- a/hermes_adapters/CMakeLists.txt +++ b/hermes_adapters/CMakeLists.txt @@ -9,7 +9,7 @@ endif() if (HERMES_ENABLE_MPIIO_ADAPTER) add_subdirectory(mpiio) endif() -if (HERMES_ENABLE_HDF5_ADAPTER) +if (HERMES_ENABLE_VFD) add_subdirectory(vfd) endif() diff --git a/hermes_adapters/filesystem/CMakeLists.txt b/hermes_adapters/filesystem/CMakeLists.txt index d9ea0f618..aa3a82686 100644 --- a/hermes_adapters/filesystem/CMakeLists.txt +++ b/hermes_adapters/filesystem/CMakeLists.txt @@ -7,8 +7,6 @@ include_directories( # Create the metadata manager singleton + FS base class add_library(hermes_fs_base SHARED - ${CMAKE_CURRENT_SOURCE_DIR}/filesystem.cc - ${CMAKE_CURRENT_SOURCE_DIR}/filesystem_mdm.cc ${CMAKE_CURRENT_SOURCE_DIR}/filesystem_mdm_singleton.cc) add_dependencies(hermes_fs_base hermes) diff --git a/hermes_adapters/filesystem/filesystem.cc b/hermes_adapters/filesystem/filesystem.cc deleted file mode 100644 index 9900e263e..000000000 --- a/hermes_adapters/filesystem/filesystem.cc +++ /dev/null @@ -1,566 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "filesystem.h" -#include "hermes_shm/util/singleton.h" -#include "filesystem_mdm.h" -#include "hermes_adapters/mapper/mapper_factory.h" - -#include -#include - -namespace stdfs = std::filesystem; - -namespace hermes::adapter::fs { - -File Filesystem::Open(AdapterStat &stat, const std::string &path) { - File f; - auto mdm = HERMES_FS_METADATA_MANAGER; - if (stat.adapter_mode_ == AdapterMode::kNone) { - stat.adapter_mode_ = mdm->GetAdapterMode(path); - } - io_client_->RealOpen(f, stat, path); - if (!f.status_) { - return f; - } - Open(stat, f, path); - return f; -} - -void Filesystem::Open(AdapterStat &stat, File &f, const std::string &path) { - auto mdm = HERMES_FS_METADATA_MANAGER; - Context ctx; - std::shared_ptr exists = mdm->Find(f); - if (!exists) { - HILOG(kDebug, "File not opened before by adapter") - // Normalize path strings - stat.path_ = stdfs::absolute(path).string(); - auto path_shm = hipc::make_uptr(stat.path_); - // Verify the bucket exists if not in CREATE mode - if (stat.adapter_mode_ == AdapterMode::kScratch && - !stat.hflags_.Any(HERMES_FS_EXISTS) && - !stat.hflags_.Any(HERMES_FS_CREATE)) { - TagId bkt_id = HERMES->GetTagId(stat.path_); - if (bkt_id.IsNull()) { - f.status_ = false; - return; - } - } - // Get or create the bucket - if (stat.hflags_.Any(HERMES_FS_TRUNC)) { - // The file was opened with TRUNCATION - stat.bkt_id_ = HERMES->GetBucket(stat.path_, ctx, 0, HERMES_BUCKET_IS_FILE); - stat.bkt_id_.Clear(); - } else { - // The file was opened regularly - stat.file_size_ = io_client_->GetSize(*path_shm); - stat.bkt_id_ = HERMES->GetBucket(stat.path_, ctx, stat.file_size_, HERMES_BUCKET_IS_FILE); - } - HILOG(kDebug, "File has size: {}", stat.bkt_id_.GetSize()); - // Update file position pointer - if (stat.hflags_.Any(HERMES_FS_APPEND)) { - stat.st_ptr_ = std::numeric_limits::max(); - } - // Update page size - stat.page_size_ = mdm->GetAdapterPageSize(path); - // Allocate internal hermes data - auto stat_ptr = std::make_shared(stat); - FilesystemIoClientState fs_ctx(&mdm->fs_mdm_, (void*)stat_ptr.get()); - io_client_->HermesOpen(f, stat, fs_ctx); - mdm->Create(f, stat_ptr); - } else { - HILOG(kDebug, "File already opened by adapter") - exists->UpdateTime(); - } -} - -size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, - size_t off, size_t total_size, - IoStatus &io_status, FsIoOptions opts) { - (void) f; - hapi::Bucket &bkt = stat.bkt_id_; - std::string filename = bkt.GetName(); - - bool is_append = stat.st_ptr_ == std::numeric_limits::max(); - - HILOG(kDebug, "Write called for filename: {}" - " on offset: {}" - " from position: {}" - " and current file size: {}" - " and adapter mode: {}", - filename, off, stat.st_ptr_, total_size, - AdapterModeConv::str(stat.adapter_mode_)) - if (stat.adapter_mode_ == AdapterMode::kBypass) { - // Bypass mode is handled differently - opts.backend_size_ = total_size; - opts.backend_off_ = off; - Blob blob_wrap((char*)ptr, total_size); - io_client_->WriteBlob(bkt.GetName(), blob_wrap, opts, io_status); - if (!io_status.success_) { - HILOG(kDebug, "Failed to write blob of size {} to backend", - opts.backend_size_) - return 0; - } - if (opts.DoSeek() && !is_append) { - stat.st_ptr_ = off + total_size; - } - return total_size; - } - - // Fragment I/O request into pages - BlobPlacements mapping; - auto mapper = MapperFactory::Get(MapperType::kBalancedMapper); - mapper->map(off, total_size, stat.page_size_, mapping); - size_t data_offset = 0; - - // Perform a PartialPut for each page - Context ctx; - ctx.page_size_ = stat.page_size_; - ctx.flags_.SetBits(HERMES_IS_FILE); - for (const BlobPlacement &p : mapping) { - const Blob page((const char*)ptr + data_offset, p.blob_size_); - if (!is_append) { - std::string blob_name(p.CreateBlobName().str()); - bkt.AsyncPartialPut(blob_name, page, p.blob_off_, ctx); - } else { - bkt.Append(page, stat.page_size_, ctx); - } - data_offset += p.blob_size_; - } - if (opts.DoSeek() && !is_append) { - stat.st_ptr_ = off + total_size; - } - stat.UpdateTime(); - - HILOG(kDebug, "The size of file after write: {}", - GetSize(f, stat)) - return data_offset; -} - -size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, - size_t off, size_t total_size, - IoStatus &io_status, FsIoOptions opts) { - (void) f; - hapi::Bucket &bkt = stat.bkt_id_; - - HILOG(kDebug, "Read called for filename: {}" - " on offset: {}" - " from position: {}" - " and size: {}", - stat.path_, off, stat.st_ptr_, total_size) - - // SEEK_END is not a valid read position - if (off == std::numeric_limits::max()) { - return 0; - } - - // Ensure the amount being read makes sense - if (total_size == 0) { - return 0; - } - - if (stat.adapter_mode_ == AdapterMode::kBypass) { - // Bypass mode is handled differently - opts.backend_size_ = total_size; - opts.backend_off_ = off; - Blob blob_wrap((char*)ptr, total_size); - io_client_->ReadBlob(bkt.GetName(), blob_wrap, opts, io_status); - if (!io_status.success_) { - HILOG(kDebug, "Failed to read blob of size {} from backend", - opts.backend_size_) - return 0; - } - if (opts.DoSeek()) { - stat.st_ptr_ = off + total_size; - } - return total_size; - } - - // Fragment I/O request into pages - BlobPlacements mapping; - auto mapper = MapperFactory::Get(MapperType::kBalancedMapper); - mapper->map(off, total_size, stat.page_size_, mapping); - size_t data_offset = 0; - - // Perform a PartialPut for each page - Context ctx; - ctx.flags_.SetBits(HERMES_IS_FILE); - for (const BlobPlacement &p : mapping) { - Blob page((const char*)ptr + data_offset, p.blob_size_); - std::string blob_name(p.CreateBlobName().str()); - bkt.PartialGet(blob_name, page, p.blob_off_, ctx); - data_offset += p.blob_size_; - } - if (opts.DoSeek()) { - stat.st_ptr_ = off + total_size; - } - stat.UpdateTime(); - return data_offset; -} - -Task* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, - size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, FsIoOptions opts) { - HILOG(kDebug, "Starting an asynchronous write", - opts.backend_size_); - return nullptr; -} - -Task* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, - size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, FsIoOptions opts) { - return nullptr; -} - -size_t Filesystem::Wait(uint64_t req_id) { - return 0; -} - -void Filesystem::Wait(std::vector &req_ids, - std::vector &ret) { - for (auto &req_id : req_ids) { - ret.emplace_back(Wait(req_id)); - } -} - -size_t Filesystem::GetSize(File &f, AdapterStat &stat) { - (void) stat; - if (stat.adapter_mode_ != AdapterMode::kBypass) { - return stat.bkt_id_.GetSize(); - } else { - return stdfs::file_size(stat.path_); - } -} - -off_t Filesystem::Seek(File &f, AdapterStat &stat, - SeekMode whence, off64_t offset) { - auto mdm = HERMES_FS_METADATA_MANAGER; - switch (whence) { - case SeekMode::kSet: { - stat.st_ptr_ = offset; - break; - } - case SeekMode::kCurrent: { - if (stat.st_ptr_ != std::numeric_limits::max()) { - stat.st_ptr_ = (off64_t)stat.st_ptr_ + offset; - offset = stat.st_ptr_; - } else { - stat.st_ptr_ = (off64_t)stat.bkt_id_.GetSize() + offset; - offset = stat.st_ptr_; - } - break; - } - case SeekMode::kEnd: { - if (offset == 0) { - stat.st_ptr_ = std::numeric_limits::max(); - offset = stat.bkt_id_.GetSize(); - } else { - stat.st_ptr_ = (off64_t)stat.bkt_id_.GetSize() + offset; - offset = stat.st_ptr_; - } - break; - } - default: { - HELOG(kError, "Invalid seek mode"); - return -1; - } - } - mdm->Update(f, stat); - return offset; -} - -off_t Filesystem::Tell(File &f, AdapterStat &stat) { - (void) f; - if (stat.st_ptr_ != std::numeric_limits::max()) { - return stat.st_ptr_; - } else { - return stat.bkt_id_.GetSize(); - } -} - -int Filesystem::Sync(File &f, AdapterStat &stat) { - if (HERMES_CLIENT_CONF.flushing_mode_ == FlushingMode::kSync) { - // NOTE(llogan): only for the unit tests - // Please don't enable synchronous flushing - } - return 0; -} - -int Filesystem::Truncate(File &f, AdapterStat &stat, size_t new_size) { - // hapi::Bucket &bkt = stat.bkt_id_; - // TODO(llogan) - return 0; -} - -int Filesystem::Close(File &f, AdapterStat &stat) { - Sync(f, stat); - auto mdm = HERMES_FS_METADATA_MANAGER; - FilesystemIoClientState fs_ctx(&mdm->fs_mdm_, (void*)&stat); - io_client_->HermesClose(f, stat, fs_ctx); - io_client_->RealClose(f, stat); - mdm->Delete(stat.path_, f); - if (stat.amode_ & MPI_MODE_DELETE_ON_CLOSE) { - Remove(stat.path_); - } - if (HERMES_CLIENT_CONF.flushing_mode_ == FlushingMode::kSync) { - // NOTE(llogan): only for the unit tests - // Please don't enable synchronous flushing - // stat.bkt_id_.Destroy(); - } - return 0; -} - -int Filesystem::Remove(const std::string &pathname) { - auto mdm = HERMES_FS_METADATA_MANAGER; - int ret = io_client_->RealRemove(pathname); - // Destroy the bucket. It's created if it doesn't exist - auto bkt = HERMES->GetBucket(pathname); - HILOG(kDebug, "Destroying the bucket: {}", bkt.GetName()); - bkt.Destroy(); - // Destroy all file descriptors - std::list* filesp = mdm->Find(pathname); - if (filesp == nullptr) { - return ret; - } - HILOG(kDebug, "Destroying the file descriptors: {}", pathname); - std::list files = *filesp; - for (File &f : files) { - auto stat = mdm->Find(f); - if (stat == nullptr) { continue; } - auto mdm = HERMES_FS_METADATA_MANAGER; - FilesystemIoClientState fs_ctx(&mdm->fs_mdm_, (void *)&stat); - io_client_->HermesClose(f, *stat, fs_ctx); - io_client_->RealClose(f, *stat); - mdm->Delete(stat->path_, f); - if (stat->adapter_mode_ == AdapterMode::kScratch) { - ret = 0; - } - } - return ret; -} - - -/** - * Variants of Read and Write which do not take an offset as - * input. - * */ - -size_t Filesystem::Write(File &f, AdapterStat &stat, const void *ptr, - size_t total_size, IoStatus &io_status, - FsIoOptions opts) { - off_t off = stat.st_ptr_; - return Write(f, stat, ptr, off, total_size, io_status, opts); -} - -size_t Filesystem::Read(File &f, AdapterStat &stat, void *ptr, - size_t total_size, - IoStatus &io_status, FsIoOptions opts) { - off_t off = stat.st_ptr_; - return Read(f, stat, ptr, off, total_size, io_status, opts); -} - -Task* Filesystem::AWrite(File &f, AdapterStat &stat, const void *ptr, - size_t total_size, size_t req_id, - IoStatus &io_status, FsIoOptions opts) { - off_t off = stat.st_ptr_; - return AWrite(f, stat, ptr, off, total_size, req_id, io_status, opts); -} - -Task* Filesystem::ARead(File &f, AdapterStat &stat, void *ptr, - size_t total_size, size_t req_id, - IoStatus &io_status, FsIoOptions opts) { - off_t off = stat.st_ptr_; - return ARead(f, stat, ptr, off, total_size, req_id, io_status, opts); -} - - -/** - * Variants of the above functions which retrieve the AdapterStat - * data structure internally. - * */ - -size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, - size_t total_size, - IoStatus &io_status, FsIoOptions opts) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return 0; - } - stat_exists = true; - return Write(f, *stat, ptr, total_size, io_status, opts); -} - -size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, - size_t total_size, - IoStatus &io_status, FsIoOptions opts) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return 0; - } - stat_exists = true; - return Read(f, *stat, ptr, total_size, io_status, opts); -} - -size_t Filesystem::Write(File &f, bool &stat_exists, const void *ptr, - size_t off, size_t total_size, - IoStatus &io_status, FsIoOptions opts) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return 0; - } - stat_exists = true; - opts.UnsetSeek(); - return Write(f, *stat, ptr, off, total_size, io_status, opts); -} - -size_t Filesystem::Read(File &f, bool &stat_exists, void *ptr, - size_t off, size_t total_size, - IoStatus &io_status, FsIoOptions opts) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return 0; - } - stat_exists = true; - opts.UnsetSeek(); - return Read(f, *stat, ptr, off, total_size, io_status, opts); -} - -Task* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, - size_t total_size, size_t req_id, - IoStatus &io_status, FsIoOptions opts) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return 0; - } - stat_exists = true; - return AWrite(f, *stat, ptr, total_size, req_id, io_status, opts); -} - -Task* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, - size_t total_size, size_t req_id, - IoStatus &io_status, FsIoOptions opts) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return 0; - } - stat_exists = true; - return ARead(f, *stat, ptr, total_size, req_id, io_status, opts); -} - -Task* Filesystem::AWrite(File &f, bool &stat_exists, const void *ptr, - size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, FsIoOptions opts) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return 0; - } - stat_exists = true; - opts.UnsetSeek(); - return AWrite(f, *stat, ptr, off, total_size, req_id, io_status, opts); -} - -Task* Filesystem::ARead(File &f, bool &stat_exists, void *ptr, - size_t off, size_t total_size, size_t req_id, - IoStatus &io_status, FsIoOptions opts) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return 0; - } - stat_exists = true; - opts.UnsetSeek(); - return ARead(f, *stat, ptr, off, total_size, req_id, io_status, opts); -} - -off_t Filesystem::Seek(File &f, bool &stat_exists, - SeekMode whence, off_t offset) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Seek(f, *stat, whence, offset); -} - -size_t Filesystem::GetSize(File &f, bool &stat_exists) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return -1; - } - stat_exists = true; - return GetSize(f, *stat); -} - -off_t Filesystem::Tell(File &f, bool &stat_exists) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Tell(f, *stat); -} - -int Filesystem::Sync(File &f, bool &stat_exists) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Sync(f, *stat); -} - -int Filesystem::Truncate(File &f, bool &stat_exists, size_t new_size) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Truncate(f, *stat, new_size); -} - -int Filesystem::Close(File &f, bool &stat_exists) { - auto mdm = HERMES_FS_METADATA_MANAGER; - auto stat = mdm->Find(f); - if (!stat) { - stat_exists = false; - return -1; - } - stat_exists = true; - return Close(f, *stat); -} - -} // namespace hermes::adapter::fs diff --git a/hermes_adapters/filesystem/filesystem.h b/hermes_adapters/filesystem/filesystem.h index 73bccb73c..6d3261245 100644 --- a/hermes_adapters/filesystem/filesystem.h +++ b/hermes_adapters/filesystem/filesystem.h @@ -26,11 +26,14 @@ #include "hermes/bucket.h" #include "hermes/hermes.h" +#include "filesystem_mdm.h" #include "filesystem_io_client.h" +#include "hermes_adapters/mapper/mapper_factory.h" +#include "data_stager/factory/binary_stager.h" #include -namespace hermes::adapter::fs { +namespace hermes::adapter { /** The maximum length of a posix path */ static inline const int kMaxPathLen = 4096; @@ -44,60 +47,414 @@ enum class SeekMode { }; /** A class to represent file system */ -class Filesystem { +class Filesystem : public FilesystemIoClient { public: - FilesystemIoClient *io_client_; AdapterType type_; public: /** Constructor */ - explicit Filesystem(FilesystemIoClient *io_client, AdapterType type) - : io_client_(io_client), type_(type) {} + explicit Filesystem(AdapterType type) + : type_(type) {} /** open \a path */ - File Open(AdapterStat &stat, const std::string &path); + File Open(AdapterStat &stat, const std::string &path) { + File f; + auto mdm = HERMES_FS_METADATA_MANAGER; + if (stat.adapter_mode_ == AdapterMode::kNone) { + stat.adapter_mode_ = mdm->GetAdapterMode(path); + } + RealOpen(f, stat, path); + if (!f.status_) { + return f; + } + Open(stat, f, path); + return f; + } /** open \a f File in \a path*/ - void Open(AdapterStat &stat, File &f, const std::string &path); + void Open(AdapterStat &stat, File &f, const std::string &path) { + auto mdm = HERMES_FS_METADATA_MANAGER; + Context ctx; + ctx.flags_.SetBits(HERMES_SHOULD_STAGE); + + std::shared_ptr exists = mdm->Find(f); + if (!exists) { + HILOG(kDebug, "File not opened before by adapter") + // Normalize path strings + stat.path_ = stdfs::absolute(path).string(); + auto path_shm = hipc::make_uptr(stat.path_); + // Verify the bucket exists if not in CREATE mode + if (stat.adapter_mode_ == AdapterMode::kScratch && + !stat.hflags_.Any(HERMES_FS_EXISTS) && + !stat.hflags_.Any(HERMES_FS_CREATE)) { + TagId bkt_id = HERMES->GetTagId(stat.path_); + if (bkt_id.IsNull()) { + f.status_ = false; + return; + } + } + // Update page size + stat.page_size_ = mdm->GetAdapterPageSize(path); + // Bucket parameters + ctx.bkt_params_ = hermes::data_stager::BinaryFileStager::BuildFileParams(stat.page_size_); + // Get or create the bucket + if (stat.hflags_.Any(HERMES_FS_TRUNC)) { + // The file was opened with TRUNCATION + stat.bkt_id_ = HERMES->GetBucket(stat.path_, ctx, 0, HERMES_SHOULD_STAGE); + stat.bkt_id_.Clear(); + } else { + // The file was opened regularly + stat.file_size_ = GetBackendSize(*path_shm); + stat.bkt_id_ = HERMES->GetBucket(stat.path_, ctx, stat.file_size_, HERMES_SHOULD_STAGE); + } + HILOG(kDebug, "BKT vs file size: {} {}", stat.bkt_id_.GetSize(), stat.file_size_); + // Update file position pointer + if (stat.hflags_.Any(HERMES_FS_APPEND)) { + stat.st_ptr_ = std::numeric_limits::max(); + } else { + stat.st_ptr_ = 0; + } + // Allocate internal hermes data + auto stat_ptr = std::make_shared(stat); + FilesystemIoClientState fs_ctx(&mdm->fs_mdm_, (void*)stat_ptr.get()); + HermesOpen(f, stat, fs_ctx); + mdm->Create(f, stat_ptr); + } else { + HILOG(kDebug, "File already opened by adapter") + exists->UpdateTime(); + } + } /** write */ size_t Write(File &f, AdapterStat &stat, const void *ptr, size_t off, size_t total_size, IoStatus &io_status, - FsIoOptions opts = FsIoOptions()); + FsIoOptions opts = FsIoOptions()) { + (void) f; + hapi::Bucket &bkt = stat.bkt_id_; + std::string filename = bkt.GetName(); + bool is_append = stat.st_ptr_ == std::numeric_limits::max(); + + HILOG(kDebug, "Write called for filename: {}" + " on offset: {}" + " from position: {}" + " and size: {}" + " and adapter mode: {}", + filename, off, stat.st_ptr_, total_size, + AdapterModeConv::str(stat.adapter_mode_)) + if (stat.adapter_mode_ == AdapterMode::kBypass) { + // Bypass mode is handled differently + opts.backend_size_ = total_size; + opts.backend_off_ = off; + Blob blob_wrap((char*)ptr, total_size); + WriteBlob(bkt.GetName(), blob_wrap, opts, io_status); + if (!io_status.success_) { + HILOG(kDebug, "Failed to write blob of size {} to backend", + opts.backend_size_) + return 0; + } + if (opts.DoSeek() && !is_append) { + stat.st_ptr_ = off + total_size; + } + return total_size; + } + Context ctx; + ctx.flags_.SetBits(HERMES_SHOULD_STAGE); + + if (is_append) { + // Perform append + const Blob page((const char*)ptr, total_size); + bkt.Append(page, stat.page_size_, ctx); + } else { + // Fragment I/O request into pages + BlobPlacements mapping; + auto mapper = MapperFactory::Get(MapperType::kBalancedMapper); + mapper->map(off, total_size, stat.page_size_, mapping); + size_t data_offset = 0; + + // Perform a PartialPut for each page + for (const BlobPlacement &p : mapping) { + const Blob page((const char*)ptr + data_offset, p.blob_size_); + std::string blob_name(p.CreateBlobName().str()); + bkt.AsyncPartialPut(blob_name, page, p.blob_off_, ctx); + data_offset += p.blob_size_; + } + if (opts.DoSeek()) { + stat.st_ptr_ = off + total_size; + } + } + stat.UpdateTime(); + io_status.size_ = total_size; + UpdateIoStatus(opts, io_status); + + HILOG(kDebug, "The size of file after write: {}", + GetSize(f, stat)) + return total_size; + } + + /** base read function */ + template + size_t BaseRead(File &f, AdapterStat &stat, void *ptr, size_t off, + size_t total_size, size_t req_id, + std::vector>> &tasks, + IoStatus &io_status, FsIoOptions opts = FsIoOptions()) { + (void) f; + hapi::Bucket &bkt = stat.bkt_id_; + + HILOG(kDebug, "Read called for filename: {}" + " on offset: {}" + " from position: {}" + " and size: {}", + stat.path_, off, stat.st_ptr_, total_size) + + // SEEK_END is not a valid read position + if (off == std::numeric_limits::max()) { + io_status.size_ = 0; + UpdateIoStatus(opts, io_status); + return 0; + } + + // Ensure the amount being read makes sense + if (total_size == 0) { + io_status.size_ = 0; + UpdateIoStatus(opts, io_status); + return 0; + } + + if constexpr (!ASYNC) { + if (stat.adapter_mode_ == AdapterMode::kBypass) { + // Bypass mode is handled differently + opts.backend_size_ = total_size; + opts.backend_off_ = off; + Blob blob_wrap((char *) ptr, total_size); + ReadBlob(bkt.GetName(), blob_wrap, opts, io_status); + if (!io_status.success_) { + HILOG(kDebug, "Failed to read blob of size {} from backend", + opts.backend_size_) + return 0; + } + if (opts.DoSeek()) { + stat.st_ptr_ = off + total_size; + } + return total_size; + } + } + + // Fragment I/O request into pages + BlobPlacements mapping; + auto mapper = MapperFactory::Get(MapperType::kBalancedMapper); + mapper->map(off, total_size, stat.page_size_, mapping); + size_t data_offset = 0; + + // Perform a PartialPut for each page + Context ctx; + ctx.flags_.SetBits(HERMES_SHOULD_STAGE); + for (const BlobPlacement &p : mapping) { + Blob page((const char*)ptr + data_offset, p.blob_size_); + std::string blob_name(p.CreateBlobName().str()); + if constexpr (ASYNC) { + LPointer> task = + bkt.AsyncPartialGet(blob_name, page, p.blob_off_, ctx); + tasks.emplace_back(task); + } else { + bkt.PartialGet(blob_name, page, p.blob_off_, ctx); + } + data_offset += page.size(); + if (page.size() != p.blob_size_) { + break; + } + } + if (opts.DoSeek()) { + stat.st_ptr_ = off + data_offset; + } + stat.UpdateTime(); + io_status.size_ = data_offset; + UpdateIoStatus(opts, io_status); + return data_offset; + } /** read */ size_t Read(File &f, AdapterStat &stat, void *ptr, size_t off, size_t total_size, - IoStatus &io_status, FsIoOptions opts = FsIoOptions()); + IoStatus &io_status, FsIoOptions opts = FsIoOptions()) { + std::vector>> tasks; + return BaseRead(f, stat, ptr, off, total_size, 0, tasks, io_status, opts); + } /** write asynchronously */ - Task* AWrite(File &f, AdapterStat &stat, const void *ptr, size_t off, - size_t total_size, size_t req_id, IoStatus &io_status, - FsIoOptions opts = FsIoOptions()); + FsAsyncTask* AWrite(File &f, AdapterStat &stat, const void *ptr, size_t off, + size_t total_size, size_t req_id, IoStatus &io_status, + FsIoOptions opts = FsIoOptions()) { + // Writes are completely async at this time + FsAsyncTask *fstask = new FsAsyncTask(); + Write(f, stat, ptr, off, total_size, io_status, opts); + fstask->io_status_.Copy(io_status); + fstask->opts_ = opts; + return fstask; + } + /** read asynchronously */ - Task* ARead(File &f, AdapterStat &stat, void *ptr, size_t off, - size_t total_size, size_t req_id, IoStatus &io_status, - FsIoOptions opts = FsIoOptions()); + FsAsyncTask* ARead(File &f, AdapterStat &stat, void *ptr, size_t off, + size_t total_size, size_t req_id, + IoStatus &io_status, FsIoOptions opts = FsIoOptions()) { + FsAsyncTask *fstask = new FsAsyncTask(); + BaseRead(f, stat, ptr, off, total_size, req_id, fstask->get_tasks_, io_status, opts); + fstask->io_status_ = io_status; + fstask->opts_ = opts; + return fstask; + } + /** wait for \a req_id request ID */ - size_t Wait(uint64_t req_id); + size_t Wait(FsAsyncTask *fstask) { + for (LPointer> &push_task : fstask->put_tasks_) { + push_task->Wait(); + HRUN_CLIENT->DelTask(push_task); + } + + // Update I/O status for gets + if (!fstask->get_tasks_.empty()) { + size_t get_size = 0; + for (LPointer> &push_task : fstask->get_tasks_) { + push_task->Wait(); + GetBlobTask *task = push_task->get(); + get_size += task->data_size_; + HRUN_CLIENT->DelTask(task); + } + fstask->io_status_.size_ = get_size; + UpdateIoStatus(fstask->opts_, fstask->io_status_); + } + return 0; + } + /** wait for request IDs in \a req_id vector */ - void Wait(std::vector &req_id, std::vector &ret); + void Wait(std::vector &req_ids, std::vector &ret) { + for (auto &req_id : req_ids) { + ret.emplace_back(Wait(req_id)); + } + } + /** seek */ - off_t Seek(File &f, AdapterStat &stat, SeekMode whence, off64_t offset); + size_t Seek(File &f, AdapterStat &stat, SeekMode whence, off64_t offset) { + auto mdm = HERMES_FS_METADATA_MANAGER; + switch (whence) { + case SeekMode::kSet: { + stat.st_ptr_ = offset; + break; + } + case SeekMode::kCurrent: { + if (stat.st_ptr_ != std::numeric_limits::max()) { + stat.st_ptr_ = (off64_t)stat.st_ptr_ + offset; + offset = stat.st_ptr_; + } else { + stat.st_ptr_ = (off64_t)stat.bkt_id_.GetSize() + offset; + offset = stat.st_ptr_; + } + break; + } + case SeekMode::kEnd: { + if (offset == 0) { + stat.st_ptr_ = std::numeric_limits::max(); + offset = stat.bkt_id_.GetSize(); + } else { + stat.st_ptr_ = (off64_t)stat.bkt_id_.GetSize() + offset; + offset = stat.st_ptr_; + } + break; + } + default: { + HELOG(kError, "Invalid seek mode"); + return -1; + } + } + mdm->Update(f, stat); + return offset; + } + /** file size */ - size_t GetSize(File &f, AdapterStat &stat); + size_t GetSize(File &f, AdapterStat &stat) { + (void) stat; + if (stat.adapter_mode_ != AdapterMode::kBypass) { + return stat.bkt_id_.GetSize(); + } else { + return stdfs::file_size(stat.path_); + } + } + /** tell */ - off_t Tell(File &f, AdapterStat &stat); + size_t Tell(File &f, AdapterStat &stat) { + (void) f; + if (stat.st_ptr_ != std::numeric_limits::max()) { + return stat.st_ptr_; + } else { + return stat.bkt_id_.GetSize(); + } + } + /** sync */ - int Sync(File &f, AdapterStat &stat); + int Sync(File &f, AdapterStat &stat) { + if (HERMES_CLIENT_CONF.flushing_mode_ == FlushingMode::kSync) { + // NOTE(llogan): only for the unit tests + // Please don't enable synchronous flushing + HRUN_ADMIN->FlushRoot(DomainId::GetGlobal()); + } + return 0; + } + /** truncate */ - int Truncate(File &f, AdapterStat &stat, size_t new_size); + int Truncate(File &f, AdapterStat &stat, size_t new_size) { + // hapi::Bucket &bkt = stat.bkt_id_; + // TODO(llogan) + return 0; + } + /** close */ - int Close(File &f, AdapterStat &stat); + int Close(File &f, AdapterStat &stat) { + Sync(f, stat); + auto mdm = HERMES_FS_METADATA_MANAGER; + FilesystemIoClientState fs_ctx(&mdm->fs_mdm_, (void*)&stat); + HermesClose(f, stat, fs_ctx); + RealClose(f, stat); + mdm->Delete(stat.path_, f); + if (stat.amode_ & MPI_MODE_DELETE_ON_CLOSE) { + Remove(stat.path_); + } + if (HERMES_CLIENT_CONF.flushing_mode_ == FlushingMode::kSync) { + // NOTE(llogan): only for the unit tests + // Please don't enable synchronous flushing + // stat.bkt_id_.Destroy(); + } + return 0; + } + /** remove */ - int Remove(const std::string &pathname); + int Remove(const std::string &pathname) { + auto mdm = HERMES_FS_METADATA_MANAGER; + int ret = RealRemove(pathname); + // Destroy the bucket + std::string canon_path = stdfs::absolute(pathname).string(); + Bucket bkt = HERMES->GetBucket(canon_path); + bkt.Destroy(); + // Destroy all file descriptors + std::list* filesp = mdm->Find(pathname); + if (filesp == nullptr) { + return ret; + } + HILOG(kDebug, "Destroying the file descriptors: {}", pathname); + std::list files = *filesp; + for (File &f : files) { + std::shared_ptr stat = mdm->Find(f); + if (stat == nullptr) { continue; } + FilesystemIoClientState fs_ctx(&mdm->fs_mdm_, (void *)&stat); + HermesClose(f, *stat, fs_ctx); + RealClose(f, *stat); + mdm->Delete(stat->path_, f); + if (stat->adapter_mode_ == AdapterMode::kScratch) { + ret = 0; + } + } + return ret; + } - /* + /** * I/O APIs which seek based on the internal AdapterStat st_ptr, * instead of taking an offset as input. */ @@ -105,19 +462,35 @@ class Filesystem { public: /** write */ size_t Write(File &f, AdapterStat &stat, const void *ptr, size_t total_size, - IoStatus &io_status, FsIoOptions opts); + IoStatus &io_status, FsIoOptions opts) { + size_t off = stat.st_ptr_; + return Write(f, stat, ptr, off, total_size, io_status, opts); + } + /** read */ size_t Read(File &f, AdapterStat &stat, void *ptr, size_t total_size, - IoStatus &io_status, FsIoOptions opts); + IoStatus &io_status, FsIoOptions opts) { + size_t off = stat.st_ptr_; + return Read(f, stat, ptr, off, total_size, io_status, opts); + } + /** write asynchronously */ - Task* AWrite(File &f, AdapterStat &stat, const void *ptr, - size_t total_size, size_t req_id, IoStatus &io_status, - FsIoOptions opts); + FsAsyncTask* AWrite(File &f, AdapterStat &stat, const void *ptr, + size_t total_size, size_t req_id, IoStatus &io_status, + FsIoOptions opts) { + size_t off = stat.st_ptr_; + return AWrite(f, stat, ptr, off, total_size, req_id, io_status, opts); + } + /** read asynchronously */ - Task* ARead(File &f, AdapterStat &stat, void *ptr, size_t total_size, - size_t req_id, IoStatus &io_status, FsIoOptions opts); + FsAsyncTask* ARead(File &f, AdapterStat &stat, void *ptr, size_t total_size, + size_t req_id, + IoStatus &io_status, FsIoOptions opts) { + size_t off = stat.st_ptr_; + return ARead(f, stat, ptr, off, total_size, req_id, io_status, opts); + } - /* + /** * Locates the AdapterStat data structure internally, and * call the underlying APIs which take AdapterStat as input. */ @@ -125,45 +498,189 @@ class Filesystem { public: /** write */ size_t Write(File &f, bool &stat_exists, const void *ptr, size_t total_size, - IoStatus &io_status, FsIoOptions opts = FsIoOptions()); + IoStatus &io_status, FsIoOptions opts = FsIoOptions()) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return 0; + } + stat_exists = true; + return Write(f, *stat, ptr, total_size, io_status, opts); + } + /** read */ size_t Read(File &f, bool &stat_exists, void *ptr, size_t total_size, - IoStatus &io_status, FsIoOptions opts = FsIoOptions()); + IoStatus &io_status, FsIoOptions opts = FsIoOptions()) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return 0; + } + stat_exists = true; + return Read(f, *stat, ptr, total_size, io_status, opts); + } + /** write \a off offset */ size_t Write(File &f, bool &stat_exists, const void *ptr, size_t off, size_t total_size, IoStatus &io_status, - FsIoOptions opts = FsIoOptions()); + FsIoOptions opts = FsIoOptions()) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return 0; + } + stat_exists = true; + opts.UnsetSeek(); + return Write(f, *stat, ptr, off, total_size, io_status, opts); + } + /** read \a off offset */ size_t Read(File &f, bool &stat_exists, void *ptr, size_t off, size_t total_size, IoStatus &io_status, - FsIoOptions opts = FsIoOptions()); + FsIoOptions opts = FsIoOptions()) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return 0; + } + stat_exists = true; + opts.UnsetSeek(); + return Read(f, *stat, ptr, off, total_size, io_status, opts); + } + /** write asynchronously */ - Task* AWrite(File &f, bool &stat_exists, const void *ptr, - size_t total_size, size_t req_id, IoStatus &io_status, - FsIoOptions opts); + FsAsyncTask* AWrite(File &f, bool &stat_exists, const void *ptr, + size_t total_size, size_t req_id, + std::vector &tasks, + IoStatus &io_status, FsIoOptions opts) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return 0; + } + stat_exists = true; + return AWrite(f, *stat, ptr, total_size, req_id, io_status, opts); + } + /** read asynchronously */ - Task* ARead(File &f, bool &stat_exists, void *ptr, size_t total_size, - size_t req_id, IoStatus &io_status, FsIoOptions opts); + FsAsyncTask* ARead(File &f, bool &stat_exists, void *ptr, size_t total_size, + size_t req_id, IoStatus &io_status, FsIoOptions opts) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return 0; + } + stat_exists = true; + return ARead(f, *stat, ptr, total_size, req_id, io_status, opts); + } + /** write \a off offset asynchronously */ - Task* AWrite(File &f, bool &stat_exists, const void *ptr, size_t off, - size_t total_size, size_t req_id, IoStatus &io_status, - FsIoOptions opts); + FsAsyncTask* AWrite(File &f, bool &stat_exists, const void *ptr, size_t off, + size_t total_size, size_t req_id, IoStatus &io_status, + FsIoOptions opts) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return 0; + } + stat_exists = true; + opts.UnsetSeek(); + return AWrite(f, *stat, ptr, off, total_size, req_id, io_status, opts); + } + /** read \a off offset asynchronously */ - Task* ARead(File &f, bool &stat_exists, void *ptr, size_t off, - size_t total_size, size_t req_id, IoStatus &io_status, - FsIoOptions opts); + FsAsyncTask* ARead(File &f, bool &stat_exists, void *ptr, size_t off, + size_t total_size, size_t req_id, IoStatus &io_status, + FsIoOptions opts) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return 0; + } + stat_exists = true; + opts.UnsetSeek(); + return ARead(f, *stat, ptr, off, total_size, req_id, io_status, opts); + } + /** seek */ - off_t Seek(File &f, bool &stat_exists, SeekMode whence, off_t offset); + size_t Seek(File &f, bool &stat_exists, SeekMode whence, size_t offset) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Seek(f, *stat, whence, offset); + } + /** file sizes */ - size_t GetSize(File &f, bool &stat_exists); + size_t GetSize(File &f, bool &stat_exists) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return GetSize(f, *stat); + } + /** tell */ - off_t Tell(File &f, bool &stat_exists); + size_t Tell(File &f, bool &stat_exists) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Tell(f, *stat); + } + /** sync */ - int Sync(File &f, bool &stat_exists); + int Sync(File &f, bool &stat_exists) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Sync(f, *stat); + } + /** truncate */ - int Truncate(File &f, bool &stat_exists, size_t new_size); + int Truncate(File &f, bool &stat_exists, size_t new_size) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Truncate(f, *stat, new_size); + } + /** close */ - int Close(File &f, bool &stat_exists); + int Close(File &f, bool &stat_exists) { + auto mdm = HERMES_FS_METADATA_MANAGER; + auto stat = mdm->Find(f); + if (!stat) { + stat_exists = false; + return -1; + } + stat_exists = true; + return Close(f, *stat); + } public: /** Whether or not \a path PATH is tracked by Hermes */ @@ -188,6 +705,6 @@ class Filesystem { } }; -} // namespace hermes::adapter::fs +} // namespace hermes::adapter #endif // HERMES_ADAPTER_FILESYSTEM_FILESYSTEM_H_ diff --git a/hermes_adapters/filesystem/filesystem_io_client.h b/hermes_adapters/filesystem/filesystem_io_client.h index dab208fcd..8e504501e 100644 --- a/hermes_adapters/filesystem/filesystem_io_client.h +++ b/hermes_adapters/filesystem/filesystem_io_client.h @@ -23,7 +23,7 @@ namespace stdfs = std::filesystem; -namespace hermes::adapter::fs { +namespace hermes::adapter { /** Put or get data directly from I/O client */ #define HERMES_IO_CLIENT_BYPASS BIT_OPT(uint32_t, 0) @@ -53,12 +53,19 @@ struct IoStatus { mpi_ret_(MPI_SUCCESS), mpi_status_ptr_(&mpi_status_), success_(true) {} -}; -/** A structure to represent Hermes request */ -struct HermesRequest { - std::future return_future; /**< future result of async op. */ - IoStatus io_status; /**< IO status */ + /** Copy constructor */ + void Copy(const IoStatus &other) { + size_ = other.size_; + mpi_ret_ = other.mpi_ret_; + mpi_status_ = other.mpi_status_; + if (other.mpi_status_ptr_ == &other.mpi_status_) { + mpi_status_ptr_ = &mpi_status_; + } else { + mpi_status_ptr_ = other.mpi_status_ptr_; + } + success_ = other.success_; + } }; /** @@ -66,19 +73,18 @@ struct HermesRequest { * For now, nothing additional than the typical FsIoOptions. * */ struct FsIoOptions { - AdapterMode adapter_mode_; /**< Current adapter mode for this obj */ - hapi::PlacementPolicy dpe_; /**< data placement policy */ - bitfield32_t flags_; /**< various I/O flags */ - MPI_Datatype mpi_type_; /**< MPI data type */ - int mpi_count_; /**< The number of types */ - size_t backend_off_; /**< Offset in the backend to begin I/O */ - size_t backend_size_; /**< Size of I/O to perform at backend */ + bitfield32_t flags_; /**< various I/O flags */ + MPI_Datatype mpi_type_; /**< MPI data type */ + int mpi_count_; /**< The number of types */ + int type_size_; /**< The size of type */ + size_t backend_off_; /**< Offset in the backend to begin I/O */ + size_t backend_size_; /**< Size of I/O to perform at backend */ /** Default constructor */ - FsIoOptions() : dpe_(hapi::PlacementPolicy::kNone), - flags_(), + FsIoOptions() : flags_(), mpi_type_(MPI_CHAR), mpi_count_(0), + type_size_(1), backend_off_(0), backend_size_(0) { SetSeek(); @@ -116,13 +122,14 @@ struct FsIoOptions { if (!seek) { opts.UnsetSeek(); } return opts; } +}; - /** Return Io options with \a DPE */ - static FsIoOptions WithDpe(hapi::PlacementPolicy dpe) { - FsIoOptions opts; - opts.dpe_ = dpe; - return opts; - } +/** A structure to represent Hermes request */ +struct FsAsyncTask { + std::vector>> put_tasks_; + std::vector>> get_tasks_; + IoStatus io_status_; + FsIoOptions opts_; }; /** Represents an object in the I/O client (e.g., a file) */ @@ -301,7 +308,7 @@ class FilesystemIoClient { virtual ~FilesystemIoClient() = default; /** Get initial statistics from the backend */ - virtual size_t GetSize(const hipc::charbuf &bkt_name) = 0; + virtual size_t GetBackendSize(const hipc::charbuf &bkt_name) = 0; /** Write blob to backend */ virtual void WriteBlob(const std::string &bkt_name, @@ -348,16 +355,19 @@ class FilesystemIoClient { virtual void HermesClose(File &f, const AdapterStat &stat, FilesystemIoClientState &fs_mdm) = 0; + + /** Updates I/O status after read/write operations */ + virtual void UpdateIoStatus(const FsIoOptions &opts, IoStatus &status) = 0; }; -} // namespace hermes::adapter::fs +} // namespace hermes::adapter namespace std { /** A structure to represent hash */ template <> -struct hash<::hermes::adapter::fs::File> { +struct hash<::hermes::adapter::File> { /** hash creator functor */ - std::size_t operator()(const hermes::adapter::fs::File &key) const { + std::size_t operator()(const hermes::adapter::File &key) const { return key.hash(); } }; diff --git a/hermes_adapters/filesystem/filesystem_mdm.cc b/hermes_adapters/filesystem/filesystem_mdm.cc deleted file mode 100644 index 69da5379d..000000000 --- a/hermes_adapters/filesystem/filesystem_mdm.cc +++ /dev/null @@ -1,80 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "filesystem_mdm.h" -#include "hermes/hermes.h" -#include - -namespace hermes::adapter::fs { - -bool MetadataManager::Create(const File &f, - std::shared_ptr &stat) { - HILOG(kDebug, "Create metadata for file handler") - ScopedRwWriteLock md_lock(lock_, kMDM_Create); - if (path_to_hermes_file_.find(stat->path_) == path_to_hermes_file_.end()) { - path_to_hermes_file_.emplace(stat->path_, std::list()); - } - path_to_hermes_file_[stat->path_].emplace_back(f); - auto ret = hermes_file_to_stat_.emplace(f, std::move(stat)); - return ret.second; -} - -bool MetadataManager::Update(const File &f, const AdapterStat &stat) { - HILOG(kDebug, "Update metadata for file handler") - ScopedRwWriteLock md_lock(lock_, kMDM_Update); - auto iter = hermes_file_to_stat_.find(f); - if (iter != hermes_file_to_stat_.end()) { - *(*iter).second = stat; - return true; - } else { - return false; - } -} - -std::list* MetadataManager::Find(const std::string &path) { - std::string canon_path = stdfs::absolute(path).string(); - ScopedRwReadLock md_lock(lock_, kMDM_Find); - auto iter = path_to_hermes_file_.find(canon_path); - if (iter == path_to_hermes_file_.end()) - return nullptr; - else - return &iter->second; -} - -std::shared_ptr MetadataManager::Find(const File &f) { - ScopedRwReadLock md_lock(lock_, kMDM_Find2); - auto iter = hermes_file_to_stat_.find(f); - if (iter == hermes_file_to_stat_.end()) - return nullptr; - else - return iter->second; -} - -bool MetadataManager::Delete(const std::string &path, const File &f) { - HILOG(kDebug, "Delete metadata for file handler") - ScopedRwWriteLock md_lock(lock_, kMDM_Delete); - auto iter = hermes_file_to_stat_.find(f); - if (iter != hermes_file_to_stat_.end()) { - hermes_file_to_stat_.erase(iter); - auto &list = path_to_hermes_file_[path]; - auto f_iter = std::find(list.begin(), list.end(), f); - path_to_hermes_file_[path].erase(f_iter); - if (list.size() == 0) { - path_to_hermes_file_.erase(path); - } - return true; - } else { - return false; - } -} - -} // namespace hermes::adapter::fs diff --git a/hermes_adapters/filesystem/filesystem_mdm.h b/hermes_adapters/filesystem/filesystem_mdm.h index a4f8a6430..06cf65784 100644 --- a/hermes_adapters/filesystem/filesystem_mdm.h +++ b/hermes_adapters/filesystem/filesystem_mdm.h @@ -16,9 +16,8 @@ #include #include #include "filesystem_io_client.h" -#include "filesystem.h" -namespace hermes::adapter::fs { +namespace hermes::adapter { /** * Metadata manager for POSIX adapter @@ -26,15 +25,15 @@ namespace hermes::adapter::fs { class MetadataManager { private: std::unordered_map> - path_to_hermes_file_; /**< Map to determine if path is buffered. */ + path_to_hermes_file_; /**< Map to determine if path is buffered. */ std::unordered_map> - hermes_file_to_stat_; /**< Map for metadata */ - RwLock lock_; /**< Lock to synchronize MD updates*/ + hermes_file_to_stat_; /**< Map for metadata */ + RwLock lock_; /**< Lock to synchronize MD updates*/ public: - /** map for Hermes request */ - std::unordered_map request_map; - FsIoClientMetadata fs_mdm_; /**< Context needed for I/O clients */ + std::unordered_map + request_map_; /**< Map for async FS requests */ + FsIoClientMetadata fs_mdm_; /**< Context needed for I/O clients */ /** Constructor */ MetadataManager() = default; @@ -65,7 +64,16 @@ class MetadataManager { * @return true, if operation was successful. * false, if operation was unsuccessful. */ - bool Create(const File& f, std::shared_ptr &stat); + bool Create(const File& f, std::shared_ptr &stat) { + HILOG(kDebug, "Create metadata for file handler") + ScopedRwWriteLock md_lock(lock_, kMDM_Create); + if (path_to_hermes_file_.find(stat->path_) == path_to_hermes_file_.end()) { + path_to_hermes_file_.emplace(stat->path_, std::list()); + } + path_to_hermes_file_[stat->path_].emplace_back(f); + auto ret = hermes_file_to_stat_.emplace(f, std::move(stat)); + return ret.second; + } /** * Update existing metadata entry for filesystem adapters. @@ -74,7 +82,17 @@ class MetadataManager { * @return true, if operation was successful. * false, if operation was unsuccessful or entry doesn't exist. */ - bool Update(const File& f, const AdapterStat& stat); + bool Update(const File& f, const AdapterStat& stat) { + HILOG(kDebug, "Update metadata for file handler") + ScopedRwWriteLock md_lock(lock_, kMDM_Update); + auto iter = hermes_file_to_stat_.find(f); + if (iter != hermes_file_to_stat_.end()) { + *(*iter).second = stat; + return true; + } else { + return false; + } + } /** * Delete existing metadata entry for for filesystem adapters. @@ -82,14 +100,38 @@ class MetadataManager { * @return true, if operation was successful. * false, if operation was unsuccessful. */ - bool Delete(const std::string &path, const File& f); + bool Delete(const std::string &path, const File& f) { + HILOG(kDebug, "Delete metadata for file handler") + ScopedRwWriteLock md_lock(lock_, kMDM_Delete); + auto iter = hermes_file_to_stat_.find(f); + if (iter != hermes_file_to_stat_.end()) { + hermes_file_to_stat_.erase(iter); + auto &list = path_to_hermes_file_[path]; + auto f_iter = std::find(list.begin(), list.end(), f); + path_to_hermes_file_[path].erase(f_iter); + if (list.size() == 0) { + path_to_hermes_file_.erase(path); + } + return true; + } else { + return false; + } + } /** * Find the hermes file relating to a path. * @param path the path being checked * @return The hermes file. * */ - std::list* Find(const std::string &path); + std::list* Find(const std::string &path) { + std::string canon_path = stdfs::absolute(path).string(); + ScopedRwReadLock md_lock(lock_, kMDM_Find); + auto iter = path_to_hermes_file_.find(canon_path); + if (iter == path_to_hermes_file_.end()) + return nullptr; + else + return &iter->second; + } /** * Find existing metadata entry for filesystem adapters. @@ -97,16 +139,55 @@ class MetadataManager { * @return The metadata entry if exist. * The bool in pair indicated whether metadata entry exists. */ - std::shared_ptr Find(const File& f); + std::shared_ptr Find(const File& f) { + ScopedRwReadLock md_lock(lock_, kMDM_Find2); + auto iter = hermes_file_to_stat_.find(f); + if (iter == hermes_file_to_stat_.end()) + return nullptr; + else + return iter->second; + } + + /** + * Add a request to the request map. + * */ + void EmplaceTask(uint64_t id, FsAsyncTask* task) { + ScopedRwWriteLock md_lock(lock_, 0); + request_map_.emplace(id, task); + } + + /** + * Find a request in the request map. + * */ + FsAsyncTask* FindTask(uint64_t id) { + ScopedRwReadLock md_lock(lock_, 0); + auto iter = request_map_.find(id); + if (iter == request_map_.end()) { + return nullptr; + } else { + return iter->second; + } + } + + /** + * Delete a request in the request map. + * */ + void DeleteTask(uint64_t id) { + ScopedRwWriteLock md_lock(lock_, 0); + auto iter = request_map_.find(id); + if (iter != request_map_.end()) { + request_map_.erase(iter); + } + } }; -} // namespace hermes::adapter::fs +} // namespace hermes::adapter // Singleton macros #include "hermes_shm/util/singleton.h" #define HERMES_FS_METADATA_MANAGER \ - hshm::Singleton<::hermes::adapter::fs::MetadataManager>::GetInstance() -#define HERMES_FS_METADATA_MANAGER_T hermes::adapter::fs::MetadataManager* + hshm::Singleton<::hermes::adapter::MetadataManager>::GetInstance() +#define HERMES_FS_METADATA_MANAGER_T hermes::adapter::MetadataManager* #endif // HERMES_ADAPTER_METADATA_MANAGER_H diff --git a/hermes_adapters/filesystem/filesystem_mdm_singleton.cc b/hermes_adapters/filesystem/filesystem_mdm_singleton.cc index a729e4b0f..f706821e7 100644 --- a/hermes_adapters/filesystem/filesystem_mdm_singleton.cc +++ b/hermes_adapters/filesystem/filesystem_mdm_singleton.cc @@ -13,4 +13,4 @@ #include "hermes_shm/util/singleton.h" #include "filesystem_mdm.h" -DEFINE_SINGLETON_CC(hermes::adapter::fs::MetadataManager) +DEFINE_SINGLETON_CC(hermes::adapter::MetadataManager) diff --git a/hermes_adapters/mpiio/CMakeLists.txt b/hermes_adapters/mpiio/CMakeLists.txt index b12f78c59..cfd2c664a 100644 --- a/hermes_adapters/mpiio/CMakeLists.txt +++ b/hermes_adapters/mpiio/CMakeLists.txt @@ -5,28 +5,26 @@ include_directories( ${HERMES_IO_CLIENT_DIR} .) -# Create the MPIIO I/O client -add_library(hermes_mpiio_io_client SHARED mpiio_io_client.cc) -add_dependencies(hermes_mpiio_io_client - hermes hermes_fs_base) -target_link_libraries(hermes_mpiio_io_client - hermes hermes_fs_base MPI::MPI_CXX stdc++fs dl) - # Create the MPIIO interceptor +if (HERMES_MPICH) + message(STATUS "Using HERMES_MPICH") + add_definitions(-DHERMES_MPICH) +elseif(HERMES_OPENMPI) + message(STATUS "Using HERMES_OPENMPI") + add_definitions(-DHERMES_OPENMPI) +endif() set(INTERCEPTOR_DEPS - hermes - hermes_mpiio_io_client) + hermes hermes_fs_base) add_library(hermes_mpiio SHARED ${CMAKE_CURRENT_SOURCE_DIR}/mpiio_api.cc) add_dependencies(hermes_mpiio ${INTERCEPTOR_DEPS}) -target_link_libraries(hermes_mpiio ${INTERCEPTOR_DEPS}) +target_link_libraries(hermes_mpiio MPI::MPI_CXX stdc++fs dl ${INTERCEPTOR_DEPS}) #----------------------------------------------------------------------------- # Add Target(s) to CMake Install #----------------------------------------------------------------------------- install( TARGETS - hermes_mpiio_io_client hermes_mpiio EXPORT ${HERMES_EXPORTED_TARGETS} @@ -52,6 +50,5 @@ install( # Add Target(s) to Coverage #----------------------------------------------------------------------------- if(HERMES_ENABLE_COVERAGE) - set_coverage_flags(hermes_mpiio_io_client) - #set_coverage_flags(hermes_mpiio) + set_coverage_flags(hermes_mpiio) endif() \ No newline at end of file diff --git a/hermes_adapters/mpiio/mpiio_api.cc b/hermes_adapters/mpiio/mpiio_api.cc index e9dbb397d..e7b9b4a83 100644 --- a/hermes_adapters/mpiio/mpiio_api.cc +++ b/hermes_adapters/mpiio/mpiio_api.cc @@ -19,18 +19,19 @@ bool mpiio_intercepted = true; #include "mpiio_fs_api.h" #include "hermes_shm/util/singleton.h" -#include "hermes_adapters/interceptor.h" /** * Namespace declarations */ -using hermes::adapter::fs::MetadataManager; -using hermes::adapter::fs::File; -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::MpiioApi; -using hermes::adapter::fs::MpiioFs; -using hermes::adapter::fs::MpiioSeekModeConv; - +using hermes::adapter::MetadataManager; +using hermes::adapter::File; +using hermes::adapter::AdapterStat; +using hermes::adapter::SeekMode; +using hermes::adapter::IoStatus; +using hermes::adapter::FsIoOptions; +using hermes::adapter::MpiioApi; +using hermes::adapter::MpiioFs; +using hermes::adapter::MpiioSeekModeConv; extern "C" { diff --git a/hermes_adapters/mpiio/mpiio_api.h b/hermes_adapters/mpiio/mpiio_api.h index 1328447a4..283050e21 100644 --- a/hermes_adapters/mpiio/mpiio_api.h +++ b/hermes_adapters/mpiio/mpiio_api.h @@ -17,7 +17,9 @@ #include #include "hermes_shm/util/logging.h" #include +#ifdef HERMES_MPICH #include +#endif #include "hermes_adapters/real_api.h" #ifndef MPI_MODE_TRUNCATE @@ -55,7 +57,7 @@ typedef int (*MPI_File_iwrite_shared_t)(MPI_File fh, const void * buf, int count typedef int (*MPI_File_sync_t)(MPI_File fh); } -namespace hermes::adapter::fs { +namespace hermes::adapter { /** Pointers to the real mpiio API */ class MpiioApi : public RealApi { @@ -182,7 +184,7 @@ class MpiioApi : public RealApi { /** Simplify access to the stateless MpiioFs Singleton */ #define HERMES_MPIIO_API \ - hshm::EasySingleton<::hermes::adapter::fs::MpiioApi>::GetInstance() -#define HERMES_MPIIO_API_T hermes::adapter::fs::MpiioApi* + hshm::EasySingleton<::hermes::adapter::MpiioApi>::GetInstance() +#define HERMES_MPIIO_API_T hermes::adapter::MpiioApi* #endif // HERMES_ADAPTER_MPIIO_H diff --git a/hermes_adapters/mpiio/mpiio_fs_api.h b/hermes_adapters/mpiio/mpiio_fs_api.h index 6e98b7b41..a9b79bfe0 100644 --- a/hermes_adapters/mpiio/mpiio_fs_api.h +++ b/hermes_adapters/mpiio/mpiio_fs_api.h @@ -18,9 +18,8 @@ #include "hermes_adapters/filesystem/filesystem.h" #include "hermes_adapters/filesystem/filesystem_mdm.h" #include "mpiio_api.h" -#include "mpiio_io_client.h" -namespace hermes::adapter::fs { +namespace hermes::adapter { /** A class to represent MPI IO seek mode conversion */ class MpiioSeekModeConv { @@ -43,9 +42,21 @@ class MpiioSeekModeConv { /** A class to represent POSIX IO file system */ class MpiioFs : public Filesystem { public: - MpiioFs() - : Filesystem(HERMES_MPIIO_IO_CLIENT, - AdapterType::kMpiio) {} + HERMES_MPIIO_API_T real_api_; /**< pointer to real APIs */ + + MpiioFs() : Filesystem(AdapterType::kMpiio) { + real_api_ = HERMES_MPIIO_API; + } + + /** Initialize I/O opts using count + datatype */ + static size_t IoSizeFromCount(int count, + MPI_Datatype datatype, + FsIoOptions &opts) { + opts.mpi_type_ = datatype; + opts.mpi_count_ = count; + MPI_Type_size(datatype, &opts.type_size_); + return static_cast(count * opts.type_size_); + } inline bool IsMpiFpTracked(MPI_File *fh, std::shared_ptr &stat) { auto mdm = HERMES_FS_METADATA_MANAGER; @@ -62,27 +73,26 @@ class MpiioFs : public Filesystem { int Read(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, MPI_Datatype datatype, MPI_Status *status, FsIoOptions opts) { - opts.mpi_type_ = datatype; IoStatus io_status; io_status.mpi_status_ptr_ = status; - size_t total_size = MpiioIoClient::IoSizeFromCount(count, datatype, opts); + size_t total_size = IoSizeFromCount(count, datatype, opts); Filesystem::Read(f, stat, ptr, offset, total_size, io_status, opts); return io_status.mpi_ret_; } int ARead(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, MPI_Datatype datatype, MPI_Request *request, FsIoOptions opts) { - opts.mpi_type_ = datatype; + auto mdm = HERMES_FS_METADATA_MANAGER; IoStatus io_status; - size_t total_size = MpiioIoClient::IoSizeFromCount(count, datatype, opts); - Filesystem::ARead(f, stat, ptr, offset, total_size, - reinterpret_cast(request), io_status, opts); + size_t total_size = IoSizeFromCount(count, datatype, opts); + FsAsyncTask *fstask = Filesystem::ARead(f, stat, ptr, offset, total_size, + reinterpret_cast(request), io_status, opts); + mdm->EmplaceTask(reinterpret_cast(request), fstask); return io_status.mpi_ret_; } int ReadAll(File &f, AdapterStat &stat, void *ptr, size_t offset, int count, MPI_Datatype datatype, MPI_Status *status, FsIoOptions opts) { - opts.mpi_type_ = datatype; MPI_Barrier(stat.comm_); size_t ret = Read(f, stat, ptr, offset, count, datatype, status, opts); MPI_Barrier(stat.comm_); @@ -104,10 +114,9 @@ class MpiioFs : public Filesystem { int Write(File &f, AdapterStat &stat, const void *ptr, size_t offset, int count, MPI_Datatype datatype, MPI_Status *status, FsIoOptions opts) { - opts.mpi_type_ = datatype; IoStatus io_status; io_status.mpi_status_ptr_ = status; - size_t total_size = MpiioIoClient::IoSizeFromCount(count, datatype, opts); + size_t total_size = IoSizeFromCount(count, datatype, opts); Filesystem::Write(f, stat, ptr, offset, total_size, io_status, opts); return io_status.mpi_ret_; } @@ -115,72 +124,85 @@ class MpiioFs : public Filesystem { int AWrite(File &f, AdapterStat &stat, const void *ptr, size_t offset, int count, MPI_Datatype datatype, MPI_Request *request, FsIoOptions opts) { - opts.mpi_type_ = datatype; + auto mdm = HERMES_FS_METADATA_MANAGER; IoStatus io_status; - size_t total_size = MpiioIoClient::IoSizeFromCount(count, datatype, opts); - Filesystem::AWrite(f, stat, ptr, offset, total_size, - reinterpret_cast(request), io_status, opts); + size_t total_size = IoSizeFromCount(count, datatype, opts); + FsAsyncTask *fstask = Filesystem::AWrite(f, stat, ptr, offset, total_size, + reinterpret_cast(request), io_status, opts); + mdm->EmplaceTask(reinterpret_cast(request), fstask); return io_status.mpi_ret_; } + template + int BaseWriteAll(File &f, AdapterStat &stat, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Status *status, + MPI_Request *request, FsIoOptions opts) { + if constexpr(!ASYNC) { + MPI_Barrier(stat.comm_); + int ret = Write(f, stat, ptr, offset, count, datatype, status, opts); + MPI_Barrier(stat.comm_); + return ret; + } else { + return AWrite(f, stat, ptr, offset, count, datatype, request, opts); + } + } + int WriteAll(File &f, AdapterStat &stat, const void *ptr, size_t offset, int count, MPI_Datatype datatype, MPI_Status *status, FsIoOptions opts) { - opts.mpi_type_ = datatype; - MPI_Barrier(stat.comm_); - int ret = Write(f, stat, ptr, offset, count, datatype, status, opts); - MPI_Barrier(stat.comm_); - return ret; + return BaseWriteAll(f, stat, ptr, offset, count, datatype, status, + nullptr, opts); } - int WriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, - MPI_Datatype datatype, - MPI_Status *status, FsIoOptions opts) { - opts.mpi_type_ = datatype; + int AWriteAll(File &f, AdapterStat &stat, const void *ptr, size_t offset, + int count, MPI_Datatype datatype, MPI_Request *request, + FsIoOptions opts) { + return BaseWriteAll(f, stat, ptr, offset, count, datatype, nullptr, + request, opts); + } + + template + int BaseWriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, + MPI_Datatype datatype, MPI_Status *status, + MPI_Request *request, FsIoOptions opts) { int total; MPI_Scan(&count, &total, 1, MPI_INT, MPI_SUM, stat.comm_); MPI_Offset my_offset = total - count; - size_t ret = - WriteAll(f, stat, ptr, my_offset, count, datatype, status, opts); - return ret; + if constexpr(!ASYNC) { + size_t ret = + WriteAll(f, stat, ptr, my_offset, count, datatype, status, opts); + return ret; + } else { + return AWriteAll(f, stat, ptr, my_offset, count, datatype, request, opts); + } + } + + int WriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, + MPI_Datatype datatype, + MPI_Status *status, FsIoOptions opts) { + return BaseWriteOrdered(f, stat, ptr, count, datatype, status, + nullptr, opts); } int AWriteOrdered(File &f, AdapterStat &stat, const void *ptr, int count, MPI_Datatype datatype, MPI_Request *request, FsIoOptions opts) { HILOG(kDebug, "Starting an asynchronous write") - // TODO(llogan): FIX - /*auto mdm = HERMES_FS_METADATA_MANAGER; - auto pool = HERMES_FS_THREAD_POOL; - Task* hreq = new HermesRequest(); - auto lambda = [](MpiioFs *fs, File &f, AdapterStat &stat, const void *ptr, - int count, MPI_Datatype datatype, MPI_Status *status, - FsIoOptions opts) { - int ret = fs->WriteOrdered(f, stat, ptr, count, datatype, status, opts); - return static_cast(ret); - }; - auto func = std::bind(lambda, this, f, stat, ptr, count, datatype, - &hreq->io_status.mpi_status_, opts); - hreq->return_future = pool->run(func); - mdm->request_map.emplace(reinterpret_cast(request), hreq);*/ - return MPI_SUCCESS; + return BaseWriteOrdered(f, stat, ptr, count, datatype, nullptr, + request, opts); } int Wait(MPI_Request *req, MPI_Status *status) { - // TODO(llogan): FIX - /*auto mdm = HERMES_FS_METADATA_MANAGER; - auto real_api = HERMES_MPIIO_API; - auto iter = mdm->request_map.find(reinterpret_cast(req)); - if (iter != mdm->request_map.end()) { - Task* hreq = iter->second; - hreq->return_future.get(); - memcpy(status, hreq->io_status.mpi_status_ptr_, sizeof(MPI_Status)); - mdm->request_map.erase(iter); - delete (hreq); + auto mdm = HERMES_FS_METADATA_MANAGER; + FsAsyncTask *fstask = mdm->FindTask(reinterpret_cast(req)); + if (fstask) { + Filesystem::Wait(fstask); + memcpy(status, fstask->io_status_.mpi_status_ptr_, sizeof(MPI_Status)); + mdm->DeleteTask(reinterpret_cast(req)); + delete (fstask); return MPI_SUCCESS; } - return real_api->MPI_Wait(req, status);*/ - return 0; + return real_api_->MPI_Wait(req, status); } int WaitAll(int count, MPI_Request *req, MPI_Status *status) { @@ -473,13 +495,214 @@ class MpiioFs : public Filesystem { stat_exists = true; return SeekShared(f, *stat, offset, whence); } + + public: + /** Allocate an fd for the file f */ + void RealOpen(File &f, + AdapterStat &stat, + const std::string &path) override { + if (stat.amode_ & MPI_MODE_CREATE) { + stat.hflags_.SetBits(HERMES_FS_CREATE); + stat.hflags_.SetBits(HERMES_FS_TRUNC); + } + if (stat.amode_ & MPI_MODE_APPEND) { + stat.hflags_.SetBits(HERMES_FS_APPEND); + } + + // NOTE(llogan): Allowing scratch mode to create empty files for MPI to + // satisfy IOR. + f.mpi_status_ = real_api_->MPI_File_open( + stat.comm_, path.c_str(), stat.amode_, stat.info_, &stat.mpi_fh_); + if (f.mpi_status_ != MPI_SUCCESS) { + f.status_ = false; + } + + /*if (stat.hflags_.Any(HERMES_FS_CREATE)) { + if (stat.adapter_mode_ != AdapterMode::kScratch) { + f.mpi_status_ = real_api_->MPI_File_open( + stat.comm_, path.c_str(), stat.amode_, stat.info_, &stat.mpi_fh_); + } + } else { + f.mpi_status_ = real_api_->MPI_File_open( + stat.comm_, path.c_str(), stat.amode_, stat.info_, &stat.mpi_fh_); + } + + if (f.mpi_status_ == MPI_SUCCESS) { + stat.hflags_.SetBits(HERMES_FS_EXISTS); + } + if (f.mpi_status_ != MPI_SUCCESS && + stat.adapter_mode_ != AdapterMode::kScratch) { + f.status_ = false; + }*/ + } + + /** + * Called after real open. Allocates the Hermes representation of + * identifying file information, such as a hermes file descriptor + * and hermes file handler. These are not the same as STDIO file + * descriptor and STDIO file handler. + * */ + void HermesOpen(File &f, + const AdapterStat &stat, + FilesystemIoClientState &fs_mdm) override { + // f.hermes_mpi_fh_ = (MPI_File)fs_mdm.stat_; + f.hermes_mpi_fh_ = stat.mpi_fh_; + } + + /** Synchronize \a file FILE f */ + int RealSync(const File &f, + const AdapterStat &stat) override { + return real_api_->MPI_File_sync(stat.mpi_fh_); + } + + /** Close \a file FILE f */ + int RealClose(const File &f, + AdapterStat &stat) override { + return real_api_->MPI_File_close(&stat.mpi_fh_); + } + + /** + * Called before RealClose. Releases information provisioned during + * the allocation phase. + * */ + void HermesClose(File &f, + const AdapterStat &stat, + FilesystemIoClientState &fs_mdm) override { + (void) f; (void) stat; (void) fs_mdm; + } + + /** Remove \a file FILE f */ + int RealRemove(const std::string &path) override { + return remove(path.c_str()); + } + + /** Get initial statistics from the backend */ + size_t GetBackendSize(const hipc::charbuf &bkt_name) override { + size_t true_size = 0; + std::string filename = bkt_name.str(); + int fd = open(filename.c_str(), O_RDONLY); + if (fd < 0) { return 0; } + struct stat buf; + fstat(fd, &buf); + true_size = buf.st_size; + close(fd); + + HILOG(kDebug, "The size of the file {} on disk is {} bytes", + filename, true_size) + return true_size; + } + + /** Write blob to backend */ + void WriteBlob(const std::string &bkt_name, + const Blob &full_blob, + const FsIoOptions &opts, + IoStatus &status) override { + status.success_ = true; + HILOG(kDebug, + "Write called for: {}" + " on offset: {}" + " and size: {}", + bkt_name, opts.backend_off_, full_blob.size()) + MPI_File fh; + int write_count = 0; + status.mpi_ret_ = real_api_->MPI_File_open(MPI_COMM_SELF, bkt_name.c_str(), + MPI_MODE_RDONLY, + MPI_INFO_NULL, &fh); + if (status.mpi_ret_ != MPI_SUCCESS) { + status.success_ = false; + return; + } + + status.mpi_ret_ = real_api_->MPI_File_seek(fh, opts.backend_off_, + MPI_SEEK_SET); + if (status.mpi_ret_ != MPI_SUCCESS) { + status.success_ = false; + goto ERROR; + } + status.mpi_ret_ = real_api_->MPI_File_write(fh, + full_blob.data(), + opts.mpi_count_, + opts.mpi_type_, + status.mpi_status_ptr_); + MPI_Get_count(status.mpi_status_ptr_, + opts.mpi_type_, &write_count); + if (write_count != opts.mpi_count_) { + status.success_ = false; + HELOG(kError, "writing failed: wrote {} / {}", + write_count, opts.mpi_count_) + } + + ERROR: + real_api_->MPI_File_close(&fh); + status.size_ = full_blob.size(); + UpdateIoStatus(opts, status); + } + + /** Read blob from the backend */ + void ReadBlob(const std::string &bkt_name, + Blob &full_blob, + const FsIoOptions &opts, + IoStatus &status) override { + status.success_ = true; + HILOG(kDebug, + "Reading from: {}" + " on offset: {}" + " and size: {}", + bkt_name, opts.backend_off_, full_blob.size()) + MPI_File fh; + int read_count = 0; + status.mpi_ret_ = real_api_->MPI_File_open(MPI_COMM_SELF, bkt_name.c_str(), + MPI_MODE_RDONLY, MPI_INFO_NULL, + &fh); + if (status.mpi_ret_ != MPI_SUCCESS) { + status.success_ = false; + return; + } + + status.mpi_ret_ = real_api_->MPI_File_seek(fh, opts.backend_off_, + MPI_SEEK_SET); + if (status.mpi_ret_ != MPI_SUCCESS) { + status.success_ = false; + goto ERROR; + } + status.mpi_ret_ = real_api_->MPI_File_read(fh, + full_blob.data(), + opts.mpi_count_, + opts.mpi_type_, + status.mpi_status_ptr_); + MPI_Get_count(status.mpi_status_ptr_, + opts.mpi_type_, &read_count); + if (read_count != opts.mpi_count_) { + status.success_ = false; + HELOG(kError, "reading failed: read {} / {}", + read_count, opts.mpi_count_) + } + + ERROR: + real_api_->MPI_File_close(&fh); + status.size_ = full_blob.size(); + UpdateIoStatus(opts, status); + } + + /** Update the I/O status after a ReadBlob or WriteBlob */ + void UpdateIoStatus(const FsIoOptions &opts, IoStatus &status) override { +#ifdef HERMES_OPENMPI + status.mpi_status_ptr_->_cancelled = 0; + status.mpi_status_ptr_->_ucount = (int) (status.size_ / opts.type_size_); +#elif defined(HERMES_MPICH) + status.mpi_status_ptr_->count_hi_and_cancelled = 0; + status.mpi_status_ptr_->count_lo = (int) (status.size_ / opts.type_size_); +#else +#error "No MPI implementation specified for MPIIO adapter" +#endif + } }; -} // namespace hermes::adapter::fs +} // namespace hermes::adapter /** Simplify access to the stateless StdioFs Singleton */ #define HERMES_MPIIO_FS \ - hshm::EasySingleton<::hermes::adapter::fs::MpiioFs>::GetInstance() -#define HERMES_STDIO_FS_T hermes::adapter::fs::MpiioFs* + hshm::EasySingleton<::hermes::adapter::MpiioFs>::GetInstance() +#define HERMES_STDIO_FS_T hermes::adapter::MpiioFs* #endif // HERMES_ADAPTER_MPIIO_MPIIO_FS_API_H_ diff --git a/hermes_adapters/mpiio/mpiio_io_client.cc b/hermes_adapters/mpiio/mpiio_io_client.cc deleted file mode 100644 index 09d23237f..000000000 --- a/hermes_adapters/mpiio/mpiio_io_client.cc +++ /dev/null @@ -1,221 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "mpiio_io_client.h" - -namespace hermes::adapter::fs { - -/** Allocate an fd for the file f */ -void MpiioIoClient::RealOpen(File &f, - AdapterStat &stat, - const std::string &path) { - if (stat.amode_ & MPI_MODE_CREATE) { - stat.hflags_.SetBits(HERMES_FS_CREATE); - stat.hflags_.SetBits(HERMES_FS_TRUNC); - } - if (stat.amode_ & MPI_MODE_APPEND) { - stat.hflags_.SetBits(HERMES_FS_APPEND); - } - - // NOTE(llogan): Allowing scratch mode to create empty files for MPI to - // satisfy IOR. - f.mpi_status_ = real_api->MPI_File_open( - stat.comm_, path.c_str(), stat.amode_, stat.info_, &stat.mpi_fh_); - if (f.mpi_status_ != MPI_SUCCESS) { - f.status_ = false; - } - - /*if (stat.hflags_.Any(HERMES_FS_CREATE)) { - if (stat.adapter_mode_ != AdapterMode::kScratch) { - f.mpi_status_ = real_api->MPI_File_open( - stat.comm_, path.c_str(), stat.amode_, stat.info_, &stat.mpi_fh_); - } - } else { - f.mpi_status_ = real_api->MPI_File_open( - stat.comm_, path.c_str(), stat.amode_, stat.info_, &stat.mpi_fh_); - } - - if (f.mpi_status_ == MPI_SUCCESS) { - stat.hflags_.SetBits(HERMES_FS_EXISTS); - } - if (f.mpi_status_ != MPI_SUCCESS && - stat.adapter_mode_ != AdapterMode::kScratch) { - f.status_ = false; - }*/ -} - -/** - * Called after real open. Allocates the Hermes representation of - * identifying file information, such as a hermes file descriptor - * and hermes file handler. These are not the same as POSIX file - * descriptor and STDIO file handler. - * */ -void MpiioIoClient::HermesOpen(File &f, - const AdapterStat &stat, - FilesystemIoClientState &fs_mdm) { - // f.hermes_mpi_fh_ = (MPI_File)fs_mdm.stat_; - f.hermes_mpi_fh_ = stat.mpi_fh_; -} - -/** Synchronize \a file FILE f */ -int MpiioIoClient::RealSync(const File &f, - const AdapterStat &stat) { - return real_api->MPI_File_sync(stat.mpi_fh_); -} - -/** Close \a file FILE f */ -int MpiioIoClient::RealClose(const File &f, - AdapterStat &stat) { - return real_api->MPI_File_close(&stat.mpi_fh_); -} - -/** - * Called before RealClose. Releases information provisioned during - * the allocation phase. - * */ -void MpiioIoClient::HermesClose(File &f, - const AdapterStat &stat, - FilesystemIoClientState &fs_mdm) { - (void) f; (void) stat; (void) fs_mdm; -} - -/** Remove \a file FILE f */ -int MpiioIoClient::RealRemove(const std::string &path) { - return remove(path.c_str()); -} - -/** Get initial statistics from the backend */ -size_t MpiioIoClient::GetSize(const hipc::charbuf &bkt_name) { - size_t true_size = 0; - std::string filename = bkt_name.str(); - int fd = open(filename.c_str(), O_RDONLY); - if (fd < 0) { return 0; } - struct stat buf; - fstat(fd, &buf); - true_size = buf.st_size; - close(fd); - - HILOG(kDebug, "The size of the file {} on disk is {} bytes", - filename, true_size) - return true_size; -} - -/** Initialize I/O context using count + datatype */ -size_t MpiioIoClient::IoSizeFromCount(int count, - MPI_Datatype datatype, - FsIoOptions &opts) { - int datatype_size; - opts.mpi_type_ = datatype; - opts.mpi_count_ = count; - MPI_Type_size(datatype, &datatype_size); - return static_cast(count * datatype_size); -} - -/** Write blob to backend */ -void MpiioIoClient::WriteBlob(const std::string &bkt_name, - const Blob &full_blob, - const FsIoOptions &opts, - IoStatus &status) { - status.success_ = true; - HILOG(kDebug, - "Write called for: {}" - " on offset: {}" - " and size: {}", - bkt_name, opts.backend_off_, full_blob.size()) - MPI_File fh; - int write_count = 0; - status.mpi_ret_ = real_api->MPI_File_open(MPI_COMM_SELF, bkt_name.c_str(), - MPI_MODE_RDONLY, - MPI_INFO_NULL, &fh); - if (status.mpi_ret_ != MPI_SUCCESS) { - status.success_ = false; - return; - } - - status.mpi_ret_ = real_api->MPI_File_seek(fh, opts.backend_off_, - MPI_SEEK_SET); - if (status.mpi_ret_ != MPI_SUCCESS) { - status.success_ = false; - goto ERROR; - } - status.mpi_ret_ = real_api->MPI_File_write(fh, - full_blob.data(), - opts.mpi_count_, - opts.mpi_type_, - status.mpi_status_ptr_); - MPI_Get_count(status.mpi_status_ptr_, - opts.mpi_type_, &write_count); - if (write_count != opts.mpi_count_) { - status.success_ = false; - HELOG(kError, "writing failed: wrote {} / {}", - write_count, opts.mpi_count_) - } - -ERROR: - real_api->MPI_File_close(&fh); - status.size_ = full_blob.size(); - UpdateIoStatus(opts.mpi_count_, status); -} - -/** Read blob from the backend */ -void MpiioIoClient::ReadBlob(const std::string &bkt_name, - Blob &full_blob, - const FsIoOptions &opts, - IoStatus &status) { - status.success_ = true; - HILOG(kDebug, - "Reading from: {}" - " on offset: {}" - " and size: {}", - bkt_name, opts.backend_off_, full_blob.size()) - MPI_File fh; - int read_count = 0; - status.mpi_ret_ = real_api->MPI_File_open(MPI_COMM_SELF, bkt_name.c_str(), - MPI_MODE_RDONLY, MPI_INFO_NULL, - &fh); - if (status.mpi_ret_ != MPI_SUCCESS) { - status.success_ = false; - return; - } - - status.mpi_ret_ = real_api->MPI_File_seek(fh, opts.backend_off_, - MPI_SEEK_SET); - if (status.mpi_ret_ != MPI_SUCCESS) { - status.success_ = false; - goto ERROR; - } - status.mpi_ret_ = real_api->MPI_File_read(fh, - full_blob.data(), - opts.mpi_count_, - opts.mpi_type_, - status.mpi_status_ptr_); - MPI_Get_count(status.mpi_status_ptr_, - opts.mpi_type_, &read_count); - if (read_count != opts.mpi_count_) { - status.success_ = false; - HELOG(kError, "reading failed: read {} / {}", - read_count, opts.mpi_count_) - } - -ERROR: - real_api->MPI_File_close(&fh); - status.size_ = full_blob.size(); - UpdateIoStatus(opts.mpi_count_, status); -} - -/** Update the I/O status after a ReadBlob or WriteBlob */ -void MpiioIoClient::UpdateIoStatus(size_t count, IoStatus &status) { - status.mpi_status_ptr_->count_hi_and_cancelled = 0; - status.mpi_status_ptr_->count_lo = count; -} - -} // namespace hermes::adapter::fs diff --git a/hermes_adapters/mpiio/mpiio_io_client.h b/hermes_adapters/mpiio/mpiio_io_client.h deleted file mode 100644 index e9f7dd2b3..000000000 --- a/hermes_adapters/mpiio/mpiio_io_client.h +++ /dev/null @@ -1,108 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_MPIIO_MPIIO_IO_CLIENT_H_ -#define HERMES_ADAPTER_MPIIO_MPIIO_IO_CLIENT_H_ - -#include - -#include "hermes_adapters/filesystem/filesystem_io_client.h" -#include "mpiio_api.h" - -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::FsIoOptions; -using hermes::adapter::fs::IoStatus; -using hermes::adapter::fs::MpiioApi; - -namespace hermes::adapter::fs { - -/** A class to represent STDIO IO file system */ -class MpiioIoClient : public hermes::adapter::fs::FilesystemIoClient { - private: - HERMES_MPIIO_API_T real_api; /**< pointer to real APIs */ - - public: - /** Default constructor */ - MpiioIoClient() { - real_api = HERMES_MPIIO_API; - } - - /** Virtual destructor */ - virtual ~MpiioIoClient() = default; - - public: - /** Allocate an fd for the file f */ - void RealOpen(File &f, - AdapterStat &stat, - const std::string &path) override; - - /** - * Called after real open. Allocates the Hermes representation of - * identifying file information, such as a hermes file descriptor - * and hermes file handler. These are not the same as STDIO file - * descriptor and STDIO file handler. - * */ - void HermesOpen(File &f, - const AdapterStat &stat, - FilesystemIoClientState &fs_mdm) override; - - /** Synchronize \a file FILE f */ - int RealSync(const File &f, - const AdapterStat &stat) override; - - /** Close \a file FILE f */ - int RealClose(const File &f, - AdapterStat &stat) override; - - /** - * Called before RealClose. Releases information provisioned during - * the allocation phase. - * */ - void HermesClose(File &f, - const AdapterStat &stat, - FilesystemIoClientState &fs_mdm) override; - - /** Remove \a file FILE f */ - int RealRemove(const std::string &path) override; - - /** Get initial statistics from the backend */ - size_t GetSize(const hipc::charbuf &bkt_name) override; - - /** Initialize I/O context using count + datatype */ - static size_t IoSizeFromCount(int count, - MPI_Datatype datatype, - FsIoOptions &opts); - - /** Write blob to backend */ - void WriteBlob(const std::string &bkt_name, - const Blob &full_blob, - const FsIoOptions &opts, - IoStatus &status) override; - - /** Read blob from the backend */ - void ReadBlob(const std::string &bkt_name, - Blob &full_blob, - const FsIoOptions &opts, - IoStatus &status) override; - - /** Update the I/O status after a ReadBlob or WriteBlob */ - void UpdateIoStatus(size_t count, IoStatus &status); -}; - -} // namespace hermes::adapter::fs - -/** Simplify access to the stateless StdioIoClient Singleton */ -#define HERMES_MPIIO_IO_CLIENT \ - hshm::EasySingleton<::hermes::adapter::fs::MpiioIoClient>::GetInstance() -#define HERMES_MPIIO_IO_CLIENT_T hermes::adapter::fs::MpiioIoClient* - -#endif // HERMES_ADAPTER_MPIIO_MPIIO_IO_CLIENT_H_ diff --git a/hermes_adapters/posix/CMakeLists.txt b/hermes_adapters/posix/CMakeLists.txt index bcc973f3c..c0e412a99 100644 --- a/hermes_adapters/posix/CMakeLists.txt +++ b/hermes_adapters/posix/CMakeLists.txt @@ -5,29 +5,19 @@ include_directories( ${HERMES_IO_CLIENT_DIR} .) -# Creates the POSIX I/O client -add_library(hermes_posix_io_client SHARED posix_io_client.cc) -add_dependencies(hermes_posix_io_client - hermes hermes_fs_base) -target_link_libraries(hermes_posix_io_client - hermes hermes_fs_base - MPI::MPI_CXX stdc++fs dl) - # Create the POSIX interceptor set(INTERCEPTOR_DEPS - hermes - hermes_posix_io_client) + hermes hermes_fs_base) add_library(hermes_posix SHARED ${CMAKE_CURRENT_SOURCE_DIR}/posix_api.cc) add_dependencies(hermes_posix ${INTERCEPTOR_DEPS}) -target_link_libraries(hermes_posix ${INTERCEPTOR_DEPS}) +target_link_libraries(hermes_posix MPI::MPI_CXX stdc++fs dl ${INTERCEPTOR_DEPS}) #----------------------------------------------------------------------------- # Add Target(s) to CMake Install #----------------------------------------------------------------------------- install( TARGETS - hermes_posix_io_client hermes_posix EXPORT ${HERMES_EXPORTED_TARGETS} @@ -40,7 +30,6 @@ install( # Export all exported targets to the build tree for use by parent project #----------------------------------------------------------------------------- set(HERMES_EXPORTED_LIBS - hermes_posix_io_client hermes_posix ${HERMES_EXPORTED_LIBS}) if(NOT HERMES_EXTERNALLY_CONFIGURED) @@ -69,6 +58,5 @@ install( # Add Target(s) to Coverage #----------------------------------------------------------------------------- if(HERMES_ENABLE_COVERAGE) - set_coverage_flags(hermes_posix_io_client) - #set_coverage_flags(hermes_posix) + set_coverage_flags(hermes_posix) endif() diff --git a/hermes_adapters/posix/posix_api.cc b/hermes_adapters/posix/posix_api.cc index 2360ced2e..a6cc7836f 100644 --- a/hermes_adapters/posix/posix_api.cc +++ b/hermes_adapters/posix/posix_api.cc @@ -21,16 +21,17 @@ bool posix_intercepted = true; #include "hermes/hermes_types.h" #include "hermes_shm/util/singleton.h" -#include "hermes_adapters/interceptor.h" #include "posix_api.h" #include "posix_fs_api.h" #include "hermes_adapters/filesystem/filesystem.h" -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::IoStatus; -using hermes::adapter::fs::File; -using hermes::adapter::fs::SeekMode; +using hermes::adapter::MetadataManager; +using hermes::adapter::SeekMode; +using hermes::adapter::AdapterStat; +using hermes::adapter::File; +using hermes::adapter::IoStatus; +using hermes::adapter::FsIoOptions; namespace stdfs = std::filesystem; diff --git a/hermes_adapters/posix/posix_api.h b/hermes_adapters/posix/posix_api.h index 8bd62f133..9b8e44b66 100644 --- a/hermes_adapters/posix/posix_api.h +++ b/hermes_adapters/posix/posix_api.h @@ -89,8 +89,7 @@ typedef int (*remove_t)(const char *pathname); typedef int (*unlink_t)(const char *pathname); } -namespace hermes::adapter::fs { - +namespace hermes::adapter { /** Used for compatability with older kernel versions */ static int fxstat_to_fstat(int fd, struct stat * stbuf); @@ -225,22 +224,22 @@ class PosixApi : public RealApi { } }; -} // namespace hermes::adapter::fs +} // namespace hermes::adapter // Singleton macros #include "hermes_shm/util/singleton.h" #define HERMES_POSIX_API \ - hshm::EasySingleton<::hermes::adapter::fs::PosixApi>::GetInstance() -#define HERMES_POSIX_API_T hermes::adapter::fs::PosixApi* + hshm::EasySingleton<::hermes::adapter::PosixApi>::GetInstance() +#define HERMES_POSIX_API_T hermes::adapter::PosixApi* -namespace hermes::adapter::fs { +namespace hermes::adapter { /** Used for compatability with older kernel versions */ static int fxstat_to_fstat(int fd, struct stat *stbuf) { #ifdef _STAT_VER return HERMES_POSIX_API->__fxstat(_STAT_VER, fd, stbuf); #endif } -} // namespace hermes::adapter::fs +} // namespace hermes::adapter #endif // HERMES_ADAPTER_POSIX_H diff --git a/hermes_adapters/posix/posix_fs_api.h b/hermes_adapters/posix/posix_fs_api.h index 1aa5f473d..89f20d1db 100644 --- a/hermes_adapters/posix/posix_fs_api.h +++ b/hermes_adapters/posix/posix_fs_api.h @@ -18,15 +18,18 @@ #include "hermes_adapters/filesystem/filesystem.h" #include "hermes_adapters/filesystem/filesystem_mdm.h" #include "posix_api.h" -#include "posix_io_client.h" -namespace hermes::adapter::fs { +namespace hermes::adapter { /** A class to represent POSIX IO file system */ -class PosixFs : public hermes::adapter::fs::Filesystem { +class PosixFs : public hermes::adapter::Filesystem { public: - PosixFs() : hermes::adapter::fs::Filesystem(HERMES_POSIX_IO_CLIENT, - AdapterType::kPosix) {} + HERMES_POSIX_API_T real_api_; /**< pointer to real APIs */ + + public: + PosixFs() : Filesystem(AdapterType::kPosix) { + real_api_ = HERMES_POSIX_API; + } template int Stat(File &f, StatT *buf) { @@ -80,7 +83,7 @@ class PosixFs : public hermes::adapter::fs::Filesystem { if (!HERMES->IsInitialized() || fd < 8192) { return false; } - hermes::adapter::fs::File f; + hermes::adapter::File f; f.hermes_fd_ = fd; stat = HERMES_FS_METADATA_MANAGER->Find(f); return stat != nullptr; @@ -98,16 +101,170 @@ class PosixFs : public hermes::adapter::fs::Filesystem { std::vector filename(kMaxPathLen); snprintf(proclnk.data(), kMaxPathLen - 1, "/proc/self/fd/%d", fd); size_t r = readlink(proclnk.data(), filename.data(), kMaxPathLen); - filename[r] = '\0'; - return std::string(filename.data(), filename.size()); + return std::string(filename.data(), r); + } + + public: + /** Allocate an fd for the file f */ + void RealOpen(File &f, + AdapterStat &stat, + const std::string &path) override { + if (stat.flags_ & O_APPEND) { + stat.hflags_.SetBits(HERMES_FS_APPEND); + } + if (stat.flags_ & O_CREAT || stat.flags_ & O_TMPFILE) { + stat.hflags_.SetBits(HERMES_FS_CREATE); + } + if (stat.flags_ & O_TRUNC) { + stat.hflags_.SetBits(HERMES_FS_TRUNC); + } + + if (stat.hflags_.Any(HERMES_FS_CREATE)) { + if (stat.adapter_mode_ != AdapterMode::kScratch) { + stat.fd_ = real_api_->open(path.c_str(), stat.flags_, stat.st_mode_); + } + } else { + stat.fd_ = real_api_->open(path.c_str(), stat.flags_); + } + + if (stat.fd_ >= 0) { + stat.hflags_.SetBits(HERMES_FS_EXISTS); + } + if (stat.fd_ < 0 && stat.adapter_mode_ != AdapterMode::kScratch) { + f.status_ = false; + } + } + + /** + * Called after real open. Allocates the Hermes representation of + * identifying file information, such as a hermes file descriptor + * and hermes file handler. These are not the same as POSIX file + * descriptor and STDIO file handler. + * */ + void HermesOpen(File &f, + const AdapterStat &stat, + FilesystemIoClientState &fs_mdm) override { + f.hermes_fd_ = fs_mdm.mdm_->AllocateFd(); + } + + /** Synchronize \a file FILE f */ + int RealSync(const File &f, + const AdapterStat &stat) override { + (void) f; + if (stat.adapter_mode_ == AdapterMode::kScratch && + stat.fd_ == -1) { + return 0; + } + return real_api_->fsync(stat.fd_); + } + + /** Close \a file FILE f */ + int RealClose(const File &f, + AdapterStat &stat) override { + (void) f; + if (stat.adapter_mode_ == AdapterMode::kScratch && + stat.fd_ == -1) { + return 0; + } + return real_api_->close(stat.fd_); + } + + /** + * Called before RealClose. Releases information provisioned during + * the allocation phase. + * */ + void HermesClose(File &f, + const AdapterStat &stat, + FilesystemIoClientState &fs_mdm) override { + fs_mdm.mdm_->ReleaseFd(f.hermes_fd_); + } + + /** Remove \a file FILE f */ + int RealRemove(const std::string &path) override { + return real_api_->remove(path.c_str()); + } + + /** Get initial statistics from the backend */ + size_t GetBackendSize(const hipc::charbuf &bkt_name) override { + size_t true_size = 0; + std::string filename = bkt_name.str(); + int fd = real_api_->open(filename.c_str(), O_RDONLY); + if (fd < 0) { return 0; } + struct stat buf; + real_api_->fstat(fd, &buf); + true_size = buf.st_size; + real_api_->close(fd); + + HILOG(kDebug, "The size of the file {} on disk is {}", + filename, true_size) + return true_size; + } + + /** Write blob to backend */ + void WriteBlob(const std::string &bkt_name, + const Blob &full_blob, + const FsIoOptions &opts, + IoStatus &status) override { + (void) opts; + status.success_ = true; + HILOG(kDebug, "Writing to file: {}" + " offset: {}" + " size: {}", + bkt_name, opts.backend_off_, full_blob.size()) + int fd = real_api_->open(bkt_name.c_str(), O_RDWR | O_CREAT); + if (fd < 0) { + status.size_ = 0; + status.success_ = false; + return; + } + status.size_ = real_api_->pwrite(fd, + full_blob.data(), + full_blob.size(), + opts.backend_off_); + if (status.size_ != full_blob.size()) { + status.success_ = false; + } + real_api_->close(fd); + } + + /** Read blob from the backend */ + void ReadBlob(const std::string &bkt_name, + Blob &full_blob, + const FsIoOptions &opts, + IoStatus &status) override { + (void) opts; + status.success_ = true; + HILOG(kDebug, "Reading from file: {}" + " offset: {}" + " size: {}", + bkt_name, opts.backend_off_, full_blob.size()) + int fd = real_api_->open(bkt_name.c_str(), O_RDONLY); + if (fd < 0) { + status.size_ = 0; + status.success_ = false; + return; + } + status.size_ = real_api_->pread(fd, + full_blob.data(), + full_blob.size(), + opts.backend_off_); + if (status.size_ != full_blob.size()) { + status.success_ = false; + } + real_api_->close(fd); + } + + void UpdateIoStatus(const FsIoOptions &opts, IoStatus &status) override { + (void) opts; + (void) status; } }; /** Simplify access to the stateless PosixFs Singleton */ #define HERMES_POSIX_FS \ - hshm::EasySingleton<::hermes::adapter::fs::PosixFs>::GetInstance() -#define HERMES_POSIX_FS_T hermes::adapter::fs::PosixFs* + hshm::EasySingleton<::hermes::adapter::PosixFs>::GetInstance() +#define HERMES_POSIX_FS_T hermes::adapter::PosixFs* -} // namespace hermes::adapter::fs +} // namespace hermes::adapter #endif // HERMES_ADAPTER_POSIX_NATIVE_H_ diff --git a/hermes_adapters/posix/posix_io_client.cc b/hermes_adapters/posix/posix_io_client.cc deleted file mode 100644 index 5fecbaef5..000000000 --- a/hermes_adapters/posix/posix_io_client.cc +++ /dev/null @@ -1,167 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "posix_io_client.h" - -namespace hermes::adapter::fs { - -/** Allocate an fd for the file f */ -void PosixIoClient::RealOpen(File &f, - AdapterStat &stat, - const std::string &path) { - if (stat.flags_ & O_APPEND) { - stat.hflags_.SetBits(HERMES_FS_APPEND); - } - if (stat.flags_ & O_CREAT || stat.flags_ & O_TMPFILE) { - stat.hflags_.SetBits(HERMES_FS_CREATE); - } - if (stat.flags_ & O_TRUNC) { - stat.hflags_.SetBits(HERMES_FS_TRUNC); - } - - if (stat.hflags_.Any(HERMES_FS_CREATE)) { - if (stat.adapter_mode_ != AdapterMode::kScratch) { - stat.fd_ = real_api->open(path.c_str(), stat.flags_, stat.st_mode_); - } - } else { - stat.fd_ = real_api->open(path.c_str(), stat.flags_); - } - - if (stat.fd_ >= 0) { - stat.hflags_.SetBits(HERMES_FS_EXISTS); - } - if (stat.fd_ < 0 && stat.adapter_mode_ != AdapterMode::kScratch) { - f.status_ = false; - } -} - -/** - * Called after real open. Allocates the Hermes representation of - * identifying file information, such as a hermes file descriptor - * and hermes file handler. These are not the same as POSIX file - * descriptor and STDIO file handler. - * */ -void PosixIoClient::HermesOpen(File &f, - const AdapterStat &stat, - FilesystemIoClientState &fs_mdm) { - f.hermes_fd_ = fs_mdm.mdm_->AllocateFd(); -} - -/** Synchronize \a file FILE f */ -int PosixIoClient::RealSync(const File &f, - const AdapterStat &stat) { - (void) f; - if (stat.adapter_mode_ == AdapterMode::kScratch && - stat.fd_ == -1) { - return 0; - } - return real_api->fsync(stat.fd_); -} - -/** Close \a file FILE f */ -int PosixIoClient::RealClose(const File &f, - AdapterStat &stat) { - (void) f; - if (stat.adapter_mode_ == AdapterMode::kScratch && - stat.fd_ == -1) { - return 0; - } - return real_api->close(stat.fd_); -} - -/** - * Called before RealClose. Releases information provisioned during - * the allocation phase. - * */ -void PosixIoClient::HermesClose(File &f, - const AdapterStat &stat, - FilesystemIoClientState &fs_mdm) { - fs_mdm.mdm_->ReleaseFd(f.hermes_fd_); -} - -/** Remo - * ve \a file FILE f */ -int PosixIoClient::RealRemove(const std::string &path) { - return real_api->remove(path.c_str()); -} - -/** Get initial statistics from the backend */ -size_t PosixIoClient::GetSize(const hipc::charbuf &bkt_name) { - size_t true_size = 0; - std::string filename = bkt_name.str(); - int fd = real_api->open(filename.c_str(), O_RDONLY); - if (fd < 0) { return 0; } - struct stat buf; - real_api->fstat(fd, &buf); - true_size = buf.st_size; - real_api->close(fd); - - HILOG(kDebug, "The size of the file {} on disk is {}", - filename, true_size) - return true_size; -} - -/** Write blob to backend */ -void PosixIoClient::WriteBlob(const std::string &bkt_name, - const Blob &full_blob, - const FsIoOptions &opts, - IoStatus &status) { - (void) opts; - status.success_ = true; - HILOG(kDebug, "Writing to file: {}" - " offset: {}" - " size: {}", - bkt_name, opts.backend_off_, full_blob.size()) - int fd = real_api->open(bkt_name.c_str(), O_RDWR | O_CREAT); - if (fd < 0) { - status.size_ = 0; - status.success_ = false; - return; - } - status.size_ = real_api->pwrite(fd, - full_blob.data(), - full_blob.size(), - opts.backend_off_); - if (status.size_ != full_blob.size()) { - status.success_ = false; - } - real_api->close(fd); -} - -/** Read blob from the backend */ -void PosixIoClient::ReadBlob(const std::string &bkt_name, - Blob &full_blob, - const FsIoOptions &opts, - IoStatus &status) { - (void) opts; - status.success_ = true; - HILOG(kDebug, "Reading from file: {}" - " offset: {}" - " size: {}", - bkt_name, opts.backend_off_, full_blob.size()) - int fd = real_api->open(bkt_name.c_str(), O_RDONLY); - if (fd < 0) { - status.size_ = 0; - status.success_ = false; - return; - } - status.size_ = real_api->pread(fd, - full_blob.data(), - full_blob.size(), - opts.backend_off_); - if (status.size_ != full_blob.size()) { - status.success_ = false; - } - real_api->close(fd); -} - -} // namespace hermes::adapter::fs diff --git a/hermes_adapters/posix/posix_io_client.h b/hermes_adapters/posix/posix_io_client.h deleted file mode 100644 index 907443144..000000000 --- a/hermes_adapters/posix/posix_io_client.h +++ /dev/null @@ -1,101 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_POSIX_POSIX_IO_CLIENT_H_ -#define HERMES_ADAPTER_POSIX_POSIX_IO_CLIENT_H_ - -#include - -#include "hermes_adapters/filesystem/filesystem_io_client.h" -#include "posix_api.h" - -using hshm::Singleton; -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::FsIoOptions; -using hermes::adapter::fs::IoStatus; -using hermes::adapter::fs::PosixApi; - -namespace hermes::adapter::fs { - -/** A class to represent POSIX IO file system */ -class PosixIoClient : public hermes::adapter::fs::FilesystemIoClient { - private: - HERMES_POSIX_API_T real_api; /**< pointer to real APIs */ - - public: - /** Default constructor */ - PosixIoClient() { - real_api = HERMES_POSIX_API; - } - - /** Virtual destructor */ - virtual ~PosixIoClient() = default; - - public: - /** Allocate an fd for the file f */ - void RealOpen(File &f, - AdapterStat &stat, - const std::string &path) override; - - /** - * Called after real open. Allocates the Hermes representation of - * identifying file information, such as a hermes file descriptor - * and hermes file handler. These are not the same as POSIX file - * descriptor and STDIO file handler. - * */ - void HermesOpen(File &f, - const AdapterStat &stat, - FilesystemIoClientState &fs_mdm) override; - - /** Synchronize \a file FILE f */ - int RealSync(const File &f, - const AdapterStat &stat) override; - - /** Close \a file FILE f */ - int RealClose(const File &f, - AdapterStat &stat) override; - - /** - * Called before RealClose. Releases information provisioned during - * the allocation phase. - * */ - void HermesClose(File &f, - const AdapterStat &stat, - FilesystemIoClientState &fs_mdm) override; - - /** Remove \a file FILE f */ - int RealRemove(const std::string &path) override; - - /** Get initial statistics from the backend */ - size_t GetSize(const hipc::charbuf &bkt_name) override; - - /** Write blob to backend */ - void WriteBlob(const std::string &bkt_name, - const Blob &full_blob, - const FsIoOptions &opts, - IoStatus &status) override; - - /** Read blob from the backend */ - void ReadBlob(const std::string &bkt_name, - Blob &full_blob, - const FsIoOptions &opts, - IoStatus &status) override; -}; - -} // namespace hermes::adapter::fs - -/** Simplify access to the stateless PosixIoClient Singleton */ -#define HERMES_POSIX_IO_CLIENT \ - hshm::EasySingleton<::hermes::adapter::fs::PosixIoClient>::GetInstance() -#define HERMES_POSIX_IO_CLIENT_T hermes::adapter::fs::PosixIoClient* - -#endif // HERMES_ADAPTER_POSIX_POSIX_IO_CLIENT_H_ diff --git a/hermes_adapters/real_api.h b/hermes_adapters/real_api.h index ca1691bef..9aba4cb40 100644 --- a/hermes_adapters/real_api.h +++ b/hermes_adapters/real_api.h @@ -16,6 +16,10 @@ #include #include +namespace stdfs = std::filesystem; + +#define HERMES_DECL(F) F + #define REQUIRE_API(api_name) \ if (!(api_name)) { \ HELOG(kFatal, "HERMES Adapter failed to map symbol: {}", #api_name); \ diff --git a/hermes_adapters/stdio/CMakeLists.txt b/hermes_adapters/stdio/CMakeLists.txt index a2da0baf1..da729b02c 100644 --- a/hermes_adapters/stdio/CMakeLists.txt +++ b/hermes_adapters/stdio/CMakeLists.txt @@ -5,29 +5,19 @@ include_directories( ${HERMES_IO_CLIENT_DIR} .) -# Creates the STDIO I/O client -add_library(hermes_stdio_io_client SHARED stdio_io_client.cc) -add_dependencies(hermes_stdio_io_client - hermes hermes_fs_base) -target_link_libraries(hermes_stdio_io_client - hermes hermes_fs_base - MPI::MPI_CXX stdc++fs dl) - # Create the STDIO interceptor set(INTERCEPTOR_DEPS - hermes - hermes_stdio_io_client) + hermes hermes_fs_base) add_library(hermes_stdio SHARED ${CMAKE_CURRENT_SOURCE_DIR}/stdio_api.cc) add_dependencies(hermes_stdio ${INTERCEPTOR_DEPS}) -target_link_libraries(hermes_stdio ${INTERCEPTOR_DEPS}) +target_link_libraries(hermes_stdio MPI::MPI_CXX stdc++fs dl ${INTERCEPTOR_DEPS}) #----------------------------------------------------------------------------- # Add Target(s) to CMake Install #----------------------------------------------------------------------------- install( TARGETS - hermes_stdio_io_client hermes_stdio EXPORT ${HERMES_EXPORTED_TARGETS} @@ -40,7 +30,6 @@ install( # Export all exported targets to the build tree for use by parent project #----------------------------------------------------------------------------- set(HERMES_EXPORTED_LIBS - hermes_stdio_io_client hermes_stdio ${HERMES_EXPORTED_LIBS}) if(NOT HERMES_EXTERNALLY_CONFIGURED) @@ -69,6 +58,5 @@ install( # Add Target(s) to Coverage #----------------------------------------------------------------------------- if(HERMES_ENABLE_COVERAGE) - set_coverage_flags(hermes_stdio_io_client) - #set_coverage_flags(hermes_stdio) + set_coverage_flags(hermes_stdio) endif() diff --git a/hermes_adapters/stdio/stdio_api.cc b/hermes_adapters/stdio/stdio_api.cc index b88d7ea03..50db93efa 100644 --- a/hermes_adapters/stdio/stdio_api.cc +++ b/hermes_adapters/stdio/stdio_api.cc @@ -17,12 +17,13 @@ bool stdio_intercepted = true; #include #include "stdio_api.h" #include "stdio_fs_api.h" -#include "hermes_adapters/interceptor.h" -using hermes::adapter::fs::MetadataManager; -using hermes::adapter::fs::SeekMode; -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::File; +using hermes::adapter::MetadataManager; +using hermes::adapter::SeekMode; +using hermes::adapter::AdapterStat; +using hermes::adapter::File; +using hermes::adapter::IoStatus; +using hermes::adapter::FsIoOptions; namespace stdfs = std::filesystem; diff --git a/hermes_adapters/stdio/stdio_api.h b/hermes_adapters/stdio/stdio_api.h index 12de1ad83..92c914675 100644 --- a/hermes_adapters/stdio/stdio_api.h +++ b/hermes_adapters/stdio/stdio_api.h @@ -48,7 +48,7 @@ typedef int (*fsetpos64_t)(FILE * stream, const fpos64_t * pos); typedef long int (*ftell_t)(FILE * fp); } -namespace hermes::adapter::fs { +namespace hermes::adapter { /** Pointers to the real stdio API */ class StdioApi : public RealApi { @@ -161,13 +161,13 @@ class StdioApi : public RealApi { REQUIRE_API(ftell) } }; -} // namespace hermes::adapter::fs +} // namespace hermes::adapter #include "hermes_shm/util/singleton.h" // Singleton macros #define HERMES_STDIO_API \ - hshm::EasySingleton<::hermes::adapter::fs::StdioApi>::GetInstance() -#define HERMES_STDIO_API_T hermes::adapter::fs::StdioApi* + hshm::EasySingleton<::hermes::adapter::StdioApi>::GetInstance() +#define HERMES_STDIO_API_T hermes::adapter::StdioApi* #endif // HERMES_ADAPTER_STDIO_H diff --git a/hermes_adapters/stdio/stdio_fs_api.h b/hermes_adapters/stdio/stdio_fs_api.h index 5fb5531f6..3d2c9b4fb 100644 --- a/hermes_adapters/stdio/stdio_fs_api.h +++ b/hermes_adapters/stdio/stdio_fs_api.h @@ -19,22 +19,25 @@ #include "hermes_adapters/filesystem/filesystem_mdm.h" #include "hermes_adapters/posix/posix_fs_api.h" #include "stdio_api.h" -#include "stdio_io_client.h" -namespace hermes::adapter::fs { +namespace hermes::adapter { /** A class to represent POSIX IO file system */ -class StdioFs : public hermes::adapter::fs::Filesystem { +class StdioFs : public hermes::adapter::Filesystem { public: - StdioFs() : hermes::adapter::fs::Filesystem(HERMES_STDIO_IO_CLIENT, - AdapterType::kStdio) {} + HERMES_STDIO_API_T real_api_; /**< pointer to real APIs */ + + public: + StdioFs() : Filesystem(AdapterType::kStdio) { + real_api_ = HERMES_STDIO_API; + } /** Close an existing stream and then open with new path */ FILE* Reopen(const std::string &user_path, const char *mode, AdapterStat &stat) { - auto real_api = HERMES_STDIO_API; + auto real_api_ = HERMES_STDIO_API; FILE *ret; - ret = real_api->freopen(user_path.c_str(), mode, stat.fh_); + ret = real_api_->freopen(user_path.c_str(), mode, stat.fh_); if (!ret) { return ret; } @@ -48,9 +51,9 @@ class StdioFs : public hermes::adapter::fs::Filesystem { /** fdopen */ FILE* FdOpen(const std::string &mode, std::shared_ptr &stat) { - auto real_api = HERMES_STDIO_API; + auto real_api_ = HERMES_STDIO_API; auto mdm = HERMES_FS_METADATA_MANAGER; - stat->fh_ = real_api->fdopen(stat->fd_, mode.c_str()); + stat->fh_ = real_api_->fdopen(stat->fd_, mode.c_str()); stat->mode_str_ = mode; File f; f.hermes_fh_ = (FILE*)stat.get(); mdm->Create(f, stat); @@ -72,7 +75,7 @@ class StdioFs : public hermes::adapter::fs::Filesystem { if (!fp || !HERMES->IsInitialized()) { return false; } - hermes::adapter::fs::File f; + hermes::adapter::File f; f.hermes_fh_ = fp; stat = HERMES_FS_METADATA_MANAGER->Find(f); return stat != nullptr; @@ -94,13 +97,166 @@ class StdioFs : public hermes::adapter::fs::Filesystem { filename[r] = '\0'; return filename; } + + public: + /** Allocate an fd for the file f */ + void RealOpen(File &f, + AdapterStat &stat, + const std::string &path) override { + if (stat.mode_str_.find('w') != std::string::npos) { + stat.hflags_.SetBits(HERMES_FS_TRUNC); + stat.hflags_.SetBits(HERMES_FS_CREATE); + } + if (stat.mode_str_.find('a') != std::string::npos) { + stat.hflags_.SetBits(HERMES_FS_APPEND); + stat.hflags_.SetBits(HERMES_FS_CREATE); + } + + if (stat.hflags_.Any(HERMES_FS_CREATE)) { + if (stat.adapter_mode_ != AdapterMode::kScratch) { + stat.fh_ = real_api_->fopen(path.c_str(), stat.mode_str_.c_str()); + } + } else { + stat.fh_ = real_api_->fopen(path.c_str(), stat.mode_str_.c_str()); + } + + if (stat.fh_ != nullptr) { + stat.hflags_.SetBits(HERMES_FS_EXISTS); + } + if (stat.fh_ == nullptr && stat.adapter_mode_ != AdapterMode::kScratch) { + f.status_ = false; + } + } + + /** + * Called after real open. Allocates the Hermes representation of + * identifying file information, such as a hermes file descriptor + * and hermes file handler. These are not the same as STDIO file + * descriptor and STDIO file handler. + * */ + void HermesOpen(File &f, + const AdapterStat &stat, + FilesystemIoClientState &fs_mdm) override { + f.hermes_fh_ = (FILE*)fs_mdm.stat_; + } + + /** Synchronize \a file FILE f */ + int RealSync(const File &f, + const AdapterStat &stat) override { + (void) f; + if (stat.adapter_mode_ == AdapterMode::kScratch && + stat.fh_ == nullptr) { + return 0; + } + return real_api_->fflush(stat.fh_); + } + + /** Close \a file FILE f */ + int RealClose(const File &f, + AdapterStat &stat) override { + if (stat.adapter_mode_ == AdapterMode::kScratch && + stat.fh_ == nullptr) { + return 0; + } + return real_api_->fclose(stat.fh_); + } + + /** + * Called before RealClose. Releases information provisioned during + * the allocation phase. + * */ + void HermesClose(File &f, + const AdapterStat &stat, + FilesystemIoClientState &fs_mdm) override { + (void) f; (void) stat; (void) fs_mdm; + } + + /** Remove \a file FILE f */ + int RealRemove(const std::string &path) override { + return remove(path.c_str()); + } + + /** Get initial statistics from the backend */ + size_t GetBackendSize(const hipc::charbuf &bkt_name) override { + size_t true_size = 0; + std::string filename = bkt_name.str(); + int fd = open(filename.c_str(), O_RDONLY); + if (fd < 0) { return 0; } + struct stat buf; + fstat(fd, &buf); + true_size = buf.st_size; + close(fd); + + HILOG(kDebug, "The size of the file {} on disk is {}", + filename, true_size) + return true_size; + } + + /** Write blob to backend */ + void WriteBlob(const std::string &bkt_name, + const Blob &full_blob, + const FsIoOptions &opts, + IoStatus &status) override { + status.success_ = true; + HILOG(kDebug, "Writing to file: {}" + " offset: {}" + " size: {}", + bkt_name, opts.backend_off_, full_blob.size()) + FILE *fh = real_api_->fopen(bkt_name.c_str(), "r+"); + if (fh == nullptr) { + status.size_ = 0; + status.success_ = false; + return; + } + real_api_->fseek(fh, opts.backend_off_, SEEK_SET); + status.size_ = real_api_->fwrite(full_blob.data(), + sizeof(char), + full_blob.size(), + fh); + if (status.size_ != full_blob.size()) { + status.success_ = false; + } + real_api_->fclose(fh); + } + + /** Read blob from the backend */ + void ReadBlob(const std::string &bkt_name, + Blob &full_blob, + const FsIoOptions &opts, + IoStatus &status) override { + status.success_ = true; + HILOG(kDebug, "Reading from file: {}" + " offset: {}" + " size: {}", + bkt_name, opts.backend_off_, full_blob.size()) + FILE *fh = real_api_->fopen(bkt_name.c_str(), "r"); + if (fh == nullptr) { + status.size_ = 0; + status.success_ = false; + return; + } + real_api_->fseek(fh, opts.backend_off_, SEEK_SET); + status.size_ = real_api_->fread(full_blob.data(), + sizeof(char), + full_blob.size(), + fh); + if (status.size_ != full_blob.size()) { + status.success_ = false; + } + real_api_->fclose(fh); + } + + void UpdateIoStatus(const FsIoOptions &opts, IoStatus &status) override { + (void) opts; + (void) status; + } }; /** Simplify access to the stateless StdioFs Singleton */ #define HERMES_STDIO_FS \ - hshm::EasySingleton<::hermes::adapter::fs::StdioFs>::GetInstance() -#define HERMES_STDIO_FS_T hermes::adapter::fs::StdioFs* + hshm::EasySingleton<::hermes::adapter::StdioFs>::GetInstance() +#define HERMES_STDIO_FS_T hermes::adapter::StdioFs* -} // namespace hermes::adapter::fs +} // namespace hermes::adapter #endif // HERMES_ADAPTER_STDIO_NATIVE_H_ diff --git a/hermes_adapters/stdio/stdio_io_client.cc b/hermes_adapters/stdio/stdio_io_client.cc deleted file mode 100644 index 6793115da..000000000 --- a/hermes_adapters/stdio/stdio_io_client.cc +++ /dev/null @@ -1,164 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "stdio_io_client.h" - -namespace hermes::adapter::fs { - -/** Allocate an fd for the file f */ -void StdioIoClient::RealOpen(File &f, - AdapterStat &stat, - const std::string &path) { - if (stat.mode_str_.find('w') != std::string::npos) { - stat.hflags_.SetBits(HERMES_FS_TRUNC); - stat.hflags_.SetBits(HERMES_FS_CREATE); - } - if (stat.mode_str_.find('a') != std::string::npos) { - stat.hflags_.SetBits(HERMES_FS_APPEND); - stat.hflags_.SetBits(HERMES_FS_CREATE); - } - - if (stat.hflags_.Any(HERMES_FS_CREATE)) { - if (stat.adapter_mode_ != AdapterMode::kScratch) { - stat.fh_ = real_api->fopen(path.c_str(), stat.mode_str_.c_str()); - } - } else { - stat.fh_ = real_api->fopen(path.c_str(), stat.mode_str_.c_str()); - } - - if (stat.fh_ != nullptr) { - stat.hflags_.SetBits(HERMES_FS_EXISTS); - } - if (stat.fh_ == nullptr && stat.adapter_mode_ != AdapterMode::kScratch) { - f.status_ = false; - } -} - -/** - * Called after real open. Allocates the Hermes representation of - * identifying file information, such as a hermes file descriptor - * and hermes file handler. These are not the same as POSIX file - * descriptor and STDIO file handler. - * */ -void StdioIoClient::HermesOpen(File &f, - const AdapterStat &stat, - FilesystemIoClientState &fs_mdm) { - f.hermes_fh_ = (FILE*)fs_mdm.stat_; -} - -/** Synchronize \a file FILE f */ -int StdioIoClient::RealSync(const File &f, - const AdapterStat &stat) { - (void) f; - if (stat.adapter_mode_ == AdapterMode::kScratch && - stat.fh_ == nullptr) { - return 0; - } - return real_api->fflush(stat.fh_); -} - -/** Close \a file FILE f */ -int StdioIoClient::RealClose(const File &f, - AdapterStat &stat) { - if (stat.adapter_mode_ == AdapterMode::kScratch && - stat.fh_ == nullptr) { - return 0; - } - return real_api->fclose(stat.fh_); -} - -/** - * Called before RealClose. Releases information provisioned during - * the allocation phase. - * */ -void StdioIoClient::HermesClose(File &f, - const AdapterStat &stat, - FilesystemIoClientState &fs_mdm) { - (void) f; (void) stat; (void) fs_mdm; -} - -/** Remove \a file FILE f */ -int StdioIoClient::RealRemove(const std::string &path) { - return remove(path.c_str()); -} - -/** Get initial statistics from the backend */ -size_t StdioIoClient::GetSize(const hipc::charbuf &bkt_name) { - size_t true_size = 0; - std::string filename = bkt_name.str(); - int fd = open(filename.c_str(), O_RDONLY); - if (fd < 0) { return 0; } - struct stat buf; - fstat(fd, &buf); - true_size = buf.st_size; - close(fd); - - HILOG(kDebug, "The size of the file {} on disk is {}", - filename, true_size) - return true_size; -} - -/** Write blob to backend */ -void StdioIoClient::WriteBlob(const std::string &bkt_name, - const Blob &full_blob, - const FsIoOptions &opts, - IoStatus &status) { - status.success_ = true; - HILOG(kDebug, "Writing to file: {}" - " offset: {}" - " size: {}", - bkt_name, opts.backend_off_, full_blob.size()) - FILE *fh = real_api->fopen(bkt_name.c_str(), "r+"); - if (fh == nullptr) { - status.size_ = 0; - status.success_ = false; - return; - } - real_api->fseek(fh, opts.backend_off_, SEEK_SET); - status.size_ = real_api->fwrite(full_blob.data(), - sizeof(char), - full_blob.size(), - fh); - if (status.size_ != full_blob.size()) { - status.success_ = false; - } - real_api->fclose(fh); -} - -/** Read blob from the backend */ -void StdioIoClient::ReadBlob(const std::string &bkt_name, - Blob &full_blob, - const FsIoOptions &opts, - IoStatus &status) { - status.success_ = true; - HILOG(kDebug, "Reading from file: {}" - " offset: {}" - " size: {}", - bkt_name, opts.backend_off_, full_blob.size()) - FILE *fh = real_api->fopen(bkt_name.c_str(), "r"); - if (fh == nullptr) { - status.size_ = 0; - status.success_ = false; - return; - } - real_api->fseek(fh, opts.backend_off_, SEEK_SET); - status.size_ = real_api->fread(full_blob.data(), - sizeof(char), - full_blob.size(), - fh); - if (status.size_ != full_blob.size()) { - status.success_ = false; - } - real_api->fclose(fh); -} - -} // namespace hermes::adapter::fs diff --git a/hermes_adapters/stdio/stdio_io_client.h b/hermes_adapters/stdio/stdio_io_client.h deleted file mode 100644 index be5d2077c..000000000 --- a/hermes_adapters/stdio/stdio_io_client.h +++ /dev/null @@ -1,100 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HERMES_ADAPTER_STDIO_STDIO_IO_CLIENT_H_ -#define HERMES_ADAPTER_STDIO_STDIO_IO_CLIENT_H_ - -#include - -#include "hermes_adapters/filesystem/filesystem_io_client.h" -#include "stdio_api.h" - -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::FsIoOptions; -using hermes::adapter::fs::IoStatus; -using hermes::adapter::fs::StdioApi; - -namespace hermes::adapter::fs { - -/** A class to represent STDIO IO file system */ -class StdioIoClient : public hermes::adapter::fs::FilesystemIoClient { - private: - HERMES_STDIO_API_T real_api; /**< pointer to real APIs */ - - public: - /** Default constructor */ - StdioIoClient() { - real_api = HERMES_STDIO_API; - } - - /** Virtual destructor */ - virtual ~StdioIoClient() = default; - - public: - /** Allocate an fd for the file f */ - void RealOpen(File &f, - AdapterStat &stat, - const std::string &path) override; - - /** - * Called after real open. Allocates the Hermes representation of - * identifying file information, such as a hermes file descriptor - * and hermes file handler. These are not the same as STDIO file - * descriptor and STDIO file handler. - * */ - void HermesOpen(File &f, - const AdapterStat &stat, - FilesystemIoClientState &fs_mdm) override; - - /** Synchronize \a file FILE f */ - int RealSync(const File &f, - const AdapterStat &stat) override; - - /** Close \a file FILE f */ - int RealClose(const File &f, - AdapterStat &stat) override; - - /** - * Called before RealClose. Releases information provisioned during - * the allocation phase. - * */ - void HermesClose(File &f, - const AdapterStat &stat, - FilesystemIoClientState &fs_mdm) override; - - /** Remove \a file FILE f */ - int RealRemove(const std::string &path) override; - - /** Get initial statistics from the backend */ - size_t GetSize(const hipc::charbuf &bkt_name) override; - - /** Write blob to backend */ - void WriteBlob(const std::string &bkt_name, - const Blob &full_blob, - const FsIoOptions &opts, - IoStatus &status) override; - - /** Read blob from the backend */ - void ReadBlob(const std::string &bkt_name, - Blob &full_blob, - const FsIoOptions &opts, - IoStatus &status) override; -}; - -} // namespace hermes::adapter::fs - -/** Simplify access to the stateless StdioIoClient Singleton */ -#define HERMES_STDIO_IO_CLIENT \ - hshm::EasySingleton<::hermes::adapter::fs::StdioIoClient>::GetInstance() -#define HERMES_STDIO_IO_CLIENT_T hermes::adapter::fs::StdioIoClient* - -#endif // HERMES_ADAPTER_STDIO_STDIO_IO_CLIENT_H_ diff --git a/hermes_adapters/vfd/CMakeLists.txt b/hermes_adapters/vfd/CMakeLists.txt index 6ac9e99cd..dd8d8bbaf 100644 --- a/hermes_adapters/vfd/CMakeLists.txt +++ b/hermes_adapters/vfd/CMakeLists.txt @@ -30,9 +30,9 @@ target_include_directories(hdf5_hermes_vfd SYSTEM PUBLIC ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} ) add_dependencies(hdf5_hermes_vfd - hermes hermes_posix_io_client) + hermes hermes_fs_base) target_link_libraries(hdf5_hermes_vfd - hermes hermes_posix_io_client + hermes hermes_fs_base MPI::MPI_CXX ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES}) @@ -42,8 +42,7 @@ set(HDF5_HERMES_VFD_EXPORTED_LIBS hdf5_hermes_vfd ${HDF5_HERMES_VFD_EXPORTED_LIB # Specify project header files to be installed #----------------------------------------------------------------------------- set(HDF5_HERMES_VFD_HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/H5FDhermes.h - ) + ${CMAKE_CURRENT_SOURCE_DIR}/H5FDhermes.h) #----------------------------------------------------------------------------- # Add file(s) to CMake Install diff --git a/hermes_adapters/vfd/H5FDhermes.cc b/hermes_adapters/vfd/H5FDhermes.cc index 60fff9455..8734f8c45 100644 --- a/hermes_adapters/vfd/H5FDhermes.cc +++ b/hermes_adapters/vfd/H5FDhermes.cc @@ -39,8 +39,7 @@ #include "H5PLextern.h" #include "H5FDhermes.h" /* Hermes file driver */ -#include "hermes_adapters/posix/posix_io_client.h" -#include "posix/posix_fs_api.h" +#include "hermes_adapters/posix/posix_fs_api.h" /** * Make this adapter use Hermes. @@ -60,8 +59,9 @@ hid_t H5FDhermes_err_class_g = H5I_INVALID_HID; #define OP_READ 1 #define OP_WRITE 2 -using hermes::adapter::fs::AdapterStat; -using hermes::adapter::fs::File; +using hermes::adapter::AdapterStat; +using hermes::adapter::File; +using hermes::adapter::IoStatus; /* POSIX I/O mode used as the third parameter to open/_open * when creating a new file (O_CREAT is set). */ @@ -211,7 +211,8 @@ H5FD__hermes_term(void) { /* Reset VFL ID */ H5FD_HERMES_g = H5I_INVALID_HID; - HERMES->Finalize(); + // TODO(llogan): Probably should add back at some point. + // HERMES->Finalize(); return ret_value; } /* end H5FD__hermes_term() */ @@ -515,13 +516,13 @@ static herr_t H5FD__hermes_write(H5FD_t *_file, H5FD_mem_t type, */ H5PL_type_t H5PLget_plugin_type(void) { - TRANSPARENT_HERMES + TRANSPARENT_HERMES(); return H5PL_TYPE_VFD; } const void* H5PLget_plugin_info(void) { - TRANSPARENT_HERMES + TRANSPARENT_HERMES(); return &H5FD_hermes_g; } diff --git a/hrun/config/hrun_server_default.yaml b/hrun/config/hrun_server_default.yaml index f31f30ce0..2a076e135 100644 --- a/hrun/config/hrun_server_default.yaml +++ b/hrun/config/hrun_server_default.yaml @@ -1,12 +1,18 @@ ### Runtime orchestration settings work_orchestrator: - # The number of worker threads to spawn - max_workers: 4 + # The max number of dedicated worker threads + max_dworkers: 4 + # The max number of overlapping threads + max_oworkers: 32 + # The max number of total dedicated cores + owork_per_core: 32 ### Queue Manager settings queue_manager: + # The default depth of process queue + proc_queue_depth: 8192 # The default depth of allocated queues - queue_depth: 256 + queue_depth: 100000 # The maximum number of lanes per queue max_lanes: 16 # The maximum number of queues @@ -18,6 +24,9 @@ queue_manager: # The size of the shared memory region to allocate for general data structures shm_size: 0g # The size of the shared memory to allocate for data buffers + data_shm_size: 4g + # The size of the shared memory to allocate for runtime data buffers + rdata_shm_size: 4g ### Define properties of RPCs rpc: @@ -43,7 +52,7 @@ rpc: port: 8080 # The number of handler threads for each RPC server. - num_threads: 4 + num_threads: 32 ### Task Registry task_registry: [ diff --git a/hrun/include/hrun/api/hrun_client.h b/hrun/include/hrun/api/hrun_client.h index 202259052..d9826a946 100644 --- a/hrun/include/hrun/api/hrun_client.h +++ b/hrun/include/hrun/api/hrun_client.h @@ -72,12 +72,17 @@ class Client : public ConfigurationManager { /** Connect to a Daemon's shared memory */ void LoadSharedMemory(bool server) { // Load shared-memory allocator + config::QueueManagerInfo &qm = server_config_.queue_manager_; auto mem_mngr = HERMES_MEMORY_MANAGER; if (!server) { mem_mngr->AttachBackend(hipc::MemoryBackendType::kPosixShmMmap, - server_config_.queue_manager_.shm_name_); + qm.shm_name_); + mem_mngr->AttachBackend(hipc::MemoryBackendType::kPosixShmMmap, + qm.data_shm_name_); } main_alloc_ = mem_mngr->GetAllocator(main_alloc_id_); + data_alloc_ = mem_mngr->GetAllocator(data_alloc_id_); + rdata_alloc_ = mem_mngr->GetAllocator(rdata_alloc_id_); header_ = main_alloc_->GetCustomHeader(); unique_ = &header_->unique_; node_id_ = header_->node_id_; @@ -102,7 +107,8 @@ class Client : public ConfigurationManager { TaskT* NewEmptyTask(hipc::Pointer &p) { TaskT *task = main_alloc_->NewObj(p, main_alloc_); if (task == nullptr) { - throw std::runtime_error("Could not allocate buffer"); + // throw std::runtime_error("Could not allocate buffer"); + HELOG(kFatal, "Could not allocate buffer (1)"); } return task; } @@ -112,8 +118,9 @@ class Client : public ConfigurationManager { HSHM_ALWAYS_INLINE LPointer NewEmptyTask() { LPointer task = main_alloc_->NewObjLocal(main_alloc_); - if (task.ptr_ == nullptr) { - throw std::runtime_error("Could not allocate buffer"); + if (task.shm_.IsNull()) { + // throw std::runtime_error("Could not allocate buffer"); + HELOG(kFatal, "Could not allocate buffer (2)"); } return task; } @@ -123,8 +130,9 @@ class Client : public ConfigurationManager { HSHM_ALWAYS_INLINE hipc::LPointer AllocateTask() { hipc::LPointer task = main_alloc_->AllocateLocalPtr(sizeof(TaskT)); - if (task.ptr_ == nullptr) { - throw std::runtime_error("Could not allocate buffer"); + if (task.shm_.IsNull()) { + // throw std::runtime_error("Could not allocate buffer"); + HELOG(kFatal, "Could not allocate buffer (3)"); } return task; } @@ -143,8 +151,9 @@ class Client : public ConfigurationManager { LPointer NewTask(const TaskNode &task_node, Args&& ...args) { LPointer ptr = main_alloc_->NewObjLocal( main_alloc_, task_node, std::forward(args)...); - if (ptr.ptr_ == nullptr) { - throw std::runtime_error("Could not allocate buffer"); + if (ptr.shm_.IsNull()) { + // throw std::runtime_error("Could not allocate buffer"); + HELOG(kFatal, "Could not allocate buffer (4)"); } return ptr; } @@ -156,8 +165,9 @@ class Client : public ConfigurationManager { TaskNode task_node = MakeTaskNodeId(); LPointer ptr = main_alloc_->NewObjLocal( main_alloc_, task_node, std::forward(args)...); - if (ptr.ptr_ == nullptr) { - throw std::runtime_error("Could not allocate buffer"); + if (ptr.shm_.IsNull()) { + // throw std::runtime_error("Could not allocate buffer"); + HELOG(kFatal, "Could not allocate buffer (5)"); } return ptr; } @@ -205,51 +215,162 @@ class Client : public ConfigurationManager { exec->Del(task->method_, task); } - /** Get a queue by its ID */ + /** Convert pointer to char* */ + template HSHM_ALWAYS_INLINE - MultiQueue* GetQueue(const QueueId &queue_id) { - return queue_manager_.GetQueue(queue_id); + T* GetMainPointer(const hipc::Pointer &p) { + return main_alloc_->Convert(p); } - /** Detect if a task is local or remote */ + /** Agnostic yield function */ + template HSHM_ALWAYS_INLINE - bool IsRemote(Task *task) { - if (task->domain_id_.IsNode()) { - return task->domain_id_.GetId() != header_->node_id_; - } else if (task->domain_id_.IsGlobal()) { - return true; - } else { - return false; + void Yield() { + if constexpr (THREAD_MODEL == TASK_YIELD_STD) { + HERMES_THREAD_MODEL->Yield(); + } else if constexpr (THREAD_MODEL == TASK_YIELD_ABT) { + ABT_thread_yield(); } } + /** Contextual yield function */ + template + HSHM_ALWAYS_INLINE + void Yield(Task *yield_task) { + yield_task->Yield(); + } + + /** Allocate a buffer */ + HSHM_ALWAYS_INLINE + LPointer AllocateBufferClient(size_t size) { + return AllocateBufferSafe(data_alloc_, size); + } + + /** Allocate a buffer */ + template + HSHM_ALWAYS_INLINE + LPointer AllocateBufferServer(size_t size) { + return AllocateBufferSafe(rdata_alloc_, size); + } + + /** Allocate a buffer */ + template + HSHM_ALWAYS_INLINE + LPointer AllocateBufferServer(size_t size, Task *yield_task) { + return AllocateBufferSafe(rdata_alloc_, size, + yield_task); + } + + private: /** Allocate a buffer */ + template HSHM_ALWAYS_INLINE - LPointer AllocateBuffer(size_t size) { - LPointer p = main_alloc_->AllocateLocalPtr(size); - if (p.ptr_ == nullptr) { - throw std::runtime_error("Could not allocate buffer"); + LPointer AllocateBufferSafe(Allocator *alloc, size_t size) { + HILOG(kDebug, "Heap size for {}/{}: {}", + alloc->GetId().bits_.major_, + alloc->GetId().bits_.minor_, + alloc->GetCurrentlyAllocatedSize()); + LPointer p; + while (true) { + try { + p = alloc->AllocateLocalPtr(size); + } catch (hshm::Error &e) { + p.shm_.SetNull(); + } + if (!p.shm_.IsNull()) { + break; + } + // FlushRoot(DomainId::GetLocal()); + Yield(); + HILOG(kDebug, "{} Waiting to allocate buffer of size {} (1)?", size); } return p; } - /** Convert pointer to char* */ - template + /** Allocate a buffer */ + template HSHM_ALWAYS_INLINE - T* GetPrivatePointer(const hipc::Pointer &p) { - return main_alloc_->Convert(p); + LPointer AllocateBufferSafe(Allocator *alloc, size_t size, + Task *yield_task) { + HILOG(kDebug, "Heap size for {}/{}: {}", + alloc->GetId().bits_.major_, + alloc->GetId().bits_.minor_, + alloc->GetCurrentlyAllocatedSize()); + LPointer p; + while (true) { + try { + p = alloc->AllocateLocalPtr(size); + } catch (hshm::Error &e) { + p.shm_.SetNull(); + } + if (!p.shm_.IsNull()) { + break; + } + // FlushRoot(DomainId::GetLocal()); + Yield(yield_task); + HILOG(kDebug, "{} Waiting to allocate buffer of size {} (1)?", size); + } + return p; } + public: /** Free a buffer */ HSHM_ALWAYS_INLINE void FreeBuffer(hipc::Pointer &p) { - main_alloc_->Free(p); + auto alloc = HERMES_MEMORY_MANAGER->GetAllocator(p.allocator_id_); + alloc->Free(p); + HILOG(kDebug, "Heap size for {}/{}: {}", + alloc->GetId().bits_.major_, + alloc->GetId().bits_.minor_, + alloc->GetCurrentlyAllocatedSize()); } /** Free a buffer */ HSHM_ALWAYS_INLINE void FreeBuffer(LPointer &p) { - main_alloc_->FreeLocalPtr(p); + auto alloc = HERMES_MEMORY_MANAGER->GetAllocator(p.shm_.allocator_id_); + alloc->FreeLocalPtr(p); + HILOG(kDebug, "Heap size for {}/{}: {}", + alloc->GetId().bits_.major_, + alloc->GetId().bits_.minor_, + alloc->GetCurrentlyAllocatedSize()); + } + + /** Convert pointer to char* */ + template + HSHM_ALWAYS_INLINE + T* GetDataPointer(const hipc::Pointer &p) { + auto alloc = HERMES_MEMORY_MANAGER->GetAllocator(p.allocator_id_); + return alloc->Convert(p); + } + + /** Get the queue ID */ + HSHM_ALWAYS_INLINE + QueueId GetQueueId(const TaskStateId &id) { + if (id == HRUN_QM_CLIENT->process_queue_) { + return HRUN_QM_CLIENT->process_queue_; + } else { + return HRUN_QM_CLIENT->admin_queue_; + } + } + + /** Get a queue by its ID */ + HSHM_ALWAYS_INLINE + MultiQueue* GetQueue(const QueueId &queue_id) { + QueueId real_id = GetQueueId(queue_id); + return queue_manager_.GetQueue(real_id); + } + + /** Detect if a task is local or remote */ + HSHM_ALWAYS_INLINE + bool IsRemote(Task *task) { + if (task->domain_id_.IsNode()) { + return task->domain_id_.GetId() != header_->node_id_; + } else if (task->domain_id_.IsGlobal()) { + return true; + } else { + return false; + } } }; diff --git a/hrun/include/hrun/api/hrun_runtime.h b/hrun/include/hrun/api/hrun_runtime.h index d6d949b83..af112d598 100644 --- a/hrun/include/hrun/api/hrun_runtime.h +++ b/hrun/include/hrun/api/hrun_runtime.h @@ -1,196 +1,11 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +// +// Created by lukemartinlogan on 10/24/23. +// -#ifndef HRUN_INCLUDE_HRUN_CLIENT_HRUN_SERVER_H_ -#define HRUN_INCLUDE_HRUN_CLIENT_HRUN_SERVER_H_ +#ifndef HERMES_HRUN_INCLUDE_HRUN_API_HRUN_RUNTIME_H_ +#define HERMES_HRUN_INCLUDE_HRUN_API_HRUN_RUNTIME_H_ -#include "hrun/task_registry/task_registry.h" -#include "hrun/work_orchestrator/work_orchestrator.h" -#include "hrun/queue_manager/queue_manager_runtime.h" -#include "hrun_admin/hrun_admin.h" -#include "remote_queue/remote_queue.h" -#include "hrun_client.h" -#include "manager.h" -#include "hrun/network/rpc.h" -#include "hrun/network/rpc_thallium.h" +#include "hrun_runtime_.h" +#include "hrun/work_orchestrator/worker.h" -// Singleton macros -#define HRUN_RUNTIME hshm::Singleton::GetInstance() -#define HRUN_RUNTIME_T hrun::Runtime* -#define HRUN_REMOTE_QUEUE (&HRUN_RUNTIME->remote_queue_) -#define HRUN_THALLIUM (&HRUN_RUNTIME->thallium_) -#define HRUN_RPC (&HRUN_RUNTIME->rpc_) - -namespace hrun { - -class Runtime : public ConfigurationManager { - public: - int data_; - TaskRegistry task_registry_; - WorkOrchestrator work_orchestrator_; - QueueManagerRuntime queue_manager_; - remote_queue::Client remote_queue_; - RpcContext rpc_; - ThalliumRpc thallium_; - bool remote_created_ = false; - - public: - /** Default constructor */ - Runtime() = default; - - /** Create the server-side API */ - Runtime* Create(std::string server_config_path = "") { - hshm::ScopedMutex lock(lock_, 1); - if (is_initialized_) { - return this; - } - mode_ = HrunMode::kServer; - is_being_initialized_ = true; - ServerInit(std::move(server_config_path)); - is_initialized_ = true; - is_being_initialized_ = false; - return this; - } - - private: - /** Initialize */ - void ServerInit(std::string server_config_path) { - LoadServerConfig(server_config_path); - InitSharedMemory(); - rpc_.ServerInit(&server_config_); - thallium_.ServerInit(&rpc_); - header_->node_id_ = rpc_.node_id_; - header_->unique_ = 0; - header_->num_nodes_ = server_config_.rpc_.host_names_.size(); - task_registry_.ServerInit(&server_config_, rpc_.node_id_, header_->unique_); - // Queue manager + client must be initialized before Work Orchestrator - queue_manager_.ServerInit(main_alloc_, - rpc_.node_id_, - &server_config_, - header_->queue_manager_); - HRUN_CLIENT->Create(server_config_path, "", true); - HERMES_THREAD_MODEL->SetThreadModel(hshm::ThreadType::kPthread); - work_orchestrator_.ServerInit(&server_config_, queue_manager_); - hipc::mptr admin_task; - - // Create the admin library - HRUN_CLIENT->MakeTaskStateId(); - admin_task = hipc::make_mptr(); - task_registry_.RegisterTaskLib("hrun_admin"); - task_registry_.CreateTaskState( - "hrun_admin", - "hrun_admin", - HRUN_QM_CLIENT->admin_task_state_, - admin_task.get()); - - // Create the process queue - HRUN_CLIENT->MakeTaskStateId(); - admin_task = hipc::make_mptr(); - task_registry_.RegisterTaskLib("proc_queue"); - task_registry_.CreateTaskState( - "proc_queue", - "proc_queue", - HRUN_QM_CLIENT->process_queue_, - admin_task.get()); - - // Create the work orchestrator queue scheduling library - TaskStateId queue_sched_id = HRUN_CLIENT->MakeTaskStateId(); - admin_task = hipc::make_mptr(); - task_registry_.RegisterTaskLib("worch_queue_round_robin"); - task_registry_.CreateTaskState( - "worch_queue_round_robin", - "worch_queue_round_robin", - queue_sched_id, - admin_task.get()); - - // Create the work orchestrator process scheduling library - TaskStateId proc_sched_id = HRUN_CLIENT->MakeTaskStateId(); - admin_task = hipc::make_mptr(); - task_registry_.RegisterTaskLib("worch_proc_round_robin"); - task_registry_.CreateTaskState( - "worch_proc_round_robin", - "worch_proc_round_robin", - proc_sched_id, - admin_task.get()); - - // Set the work orchestrator queue scheduler - HRUN_ADMIN->SetWorkOrchQueuePolicyRoot(hrun::DomainId::GetLocal(), queue_sched_id); - HRUN_ADMIN->SetWorkOrchProcPolicyRoot(hrun::DomainId::GetLocal(), proc_sched_id); - - // Create the remote queue library - task_registry_.RegisterTaskLib("remote_queue"); - remote_queue_.CreateRoot(DomainId::GetLocal(), "remote_queue", - HRUN_CLIENT->MakeTaskStateId()); - remote_created_ = true; - } - - public: - /** Initialize shared-memory between daemon and client */ - void InitSharedMemory() { - // Create shared-memory allocator - auto mem_mngr = HERMES_MEMORY_MANAGER; - if (server_config_.queue_manager_.shm_size_ == 0) { - server_config_.queue_manager_.shm_size_ = - hipc::MemoryManager::GetDefaultBackendSize(); - } - mem_mngr->CreateBackend( - server_config_.queue_manager_.shm_size_, - server_config_.queue_manager_.shm_name_); - main_alloc_ = - mem_mngr->CreateAllocator( - server_config_.queue_manager_.shm_name_, - main_alloc_id_, - sizeof(HrunShm)); - header_ = main_alloc_->GetCustomHeader(); - } - - /** Finalize Hermes explicitly */ - void Finalize() {} - - /** Run the Hermes core Daemon */ - void RunDaemon() { - thallium_.RunDaemon(); - HILOG(kInfo, "Daemon is running") -// while (HRUN_WORK_ORCHESTRATOR->IsRuntimeAlive()) { -// // Scheduler callbacks? -// HERMES_THREAD_MODEL->SleepForUs(1000); -// } - HILOG(kInfo, "Finishing up last requests") - HRUN_WORK_ORCHESTRATOR->Join(); - HILOG(kInfo, "Daemon is exiting") - } - - /** Stop the Hermes core Daemon */ - void StopDaemon() { - HRUN_WORK_ORCHESTRATOR->FinalizeRuntime(); - } - - /** Get the set of DomainIds */ - std::vector ResolveDomainId(const DomainId &domain_id) { - std::vector ids; - if (domain_id.IsGlobal()) { - ids.reserve(rpc_.hosts_.size()); - for (HostInfo &host_info : rpc_.hosts_) { - ids.push_back(DomainId::GetNode(host_info.node_id_)); - } - } else if (domain_id.IsNode()) { - ids.reserve(1); - ids.push_back(domain_id); - } - // TODO(llogan): handle named domain ID sets - return ids; - } -}; - -} // namespace hrun - -#endif // HRUN_INCLUDE_HRUN_CLIENT_HRUN_SERVER_H_ +#endif // HERMES_HRUN_INCLUDE_HRUN_API_HRUN_RUNTIME_H_ diff --git a/hrun/include/hrun/api/hrun_runtime_.h b/hrun/include/hrun/api/hrun_runtime_.h new file mode 100644 index 000000000..5f957d648 --- /dev/null +++ b/hrun/include/hrun/api/hrun_runtime_.h @@ -0,0 +1,76 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HRUN_INCLUDE_HRUN_CLIENT_HRUN_SERVER_H_ +#define HRUN_INCLUDE_HRUN_CLIENT_HRUN_SERVER_H_ + +#include "hrun/task_registry/task_registry.h" +#include "hrun/work_orchestrator/work_orchestrator.h" +#include "hrun/queue_manager/queue_manager_runtime.h" +#include "hrun_admin/hrun_admin.h" +#include "remote_queue/remote_queue.h" +#include "hrun_client.h" +#include "manager.h" +#include "hrun/network/rpc.h" +#include "hrun/network/rpc_thallium.h" + +// Singleton macros +#define HRUN_RUNTIME hshm::Singleton::GetInstance() +#define HRUN_RUNTIME_T hrun::Runtime* +#define HRUN_REMOTE_QUEUE (&HRUN_RUNTIME->remote_queue_) +#define HRUN_THALLIUM (&HRUN_RUNTIME->thallium_) +#define HRUN_RPC (&HRUN_RUNTIME->rpc_) + +namespace hrun { + +class Runtime : public ConfigurationManager { + public: + int data_; + TaskRegistry task_registry_; + WorkOrchestrator work_orchestrator_; + QueueManagerRuntime queue_manager_; + remote_queue::Client remote_queue_; + RpcContext rpc_; + ThalliumRpc thallium_; + bool remote_created_ = false; + + public: + /** Default constructor */ + Runtime() = default; + + /** Create the server-side API */ + Runtime* Create(std::string server_config_path = ""); + + private: + /** Initialize */ + void ServerInit(std::string server_config_path); + + public: + /** Initialize shared-memory between daemon and client */ + void InitSharedMemory(); + + /** Finalize Hermes explicitly */ + void Finalize(); + + /** Run the Hermes core Daemon */ + void RunDaemon(); + + /** Stop the Hermes core Daemon */ + void StopDaemon(); + + /** Get the set of DomainIds */ + std::vector ResolveDomainId(const DomainId &domain_id); +}; + +} // namespace hrun + +#endif // HRUN_INCLUDE_HRUN_CLIENT_HRUN_SERVER_H_ diff --git a/hrun/include/hrun/api/manager.h b/hrun/include/hrun/api/manager.h index 0f2ee22c9..70be6a0d0 100644 --- a/hrun/include/hrun/api/manager.h +++ b/hrun/include/hrun/api/manager.h @@ -38,7 +38,13 @@ class ConfigurationManager { ServerConfig server_config_; static inline const hipc::allocator_id_t main_alloc_id_ = hipc::allocator_id_t(0, 1); + static inline const hipc::allocator_id_t data_alloc_id_ = + hipc::allocator_id_t(1, 1); + static inline const hipc::allocator_id_t rdata_alloc_id_ = + hipc::allocator_id_t(2, 1); hipc::Allocator *main_alloc_; + hipc::Allocator *data_alloc_; + hipc::Allocator *rdata_alloc_; bool is_being_initialized_; bool is_initialized_; bool is_terminated_; diff --git a/hrun/include/hrun/config/config_server.h b/hrun/include/hrun/config/config_server.h index e72183548..a520ed822 100644 --- a/hrun/include/hrun/config/config_server.h +++ b/hrun/include/hrun/config/config_server.h @@ -22,8 +22,12 @@ namespace hrun::config { * Work orchestrator information defined in server config * */ struct WorkOrchestratorInfo { - /** Maximum number of workers to spawn */ - size_t max_workers_; + /** Maximum number of dedicated workers */ + size_t max_dworkers_; + /** Maximum number of overlapping workers */ + size_t max_oworkers_; + /** Overlapped workers per core */ + size_t owork_per_core_; }; /** @@ -32,6 +36,8 @@ struct WorkOrchestratorInfo { struct QueueManagerInfo { /** Maximum depth of IPC queues */ u32 queue_depth_; + /** Maximum depth of process queue */ + u32 proc_queue_depth_; /** Maximum number of lanes per IPC queue */ u32 max_lanes_; /** Maximum number of allocatable IPC queues */ @@ -42,6 +48,14 @@ struct QueueManagerInfo { std::string shm_name_; /** Shared memory region size */ size_t shm_size_; + /** Shared memory data region name */ + std::string data_shm_name_; + /** Shared memory runtime data region name */ + std::string rdata_shm_name_; + /** Client data shared memory region size */ + size_t data_shm_size_; + /** Runtime data shared memory region size */ + size_t rdata_shm_size_; }; /** diff --git a/hrun/include/hrun/config/config_server_default.h b/hrun/include/hrun/config/config_server_default.h index f8e5c5334..acc3f0300 100644 --- a/hrun/include/hrun/config/config_server_default.h +++ b/hrun/include/hrun/config/config_server_default.h @@ -3,13 +3,19 @@ const inline char* kHrunServerDefaultConfigStr = "### Runtime orchestration settings\n" "work_orchestrator:\n" -" # The number of worker threads to spawn\n" -" max_workers: 4\n" +" # The max number of dedicated worker threads\n" +" max_dworkers: 4\n" +" # The max number of overlapping threads\n" +" max_oworkers: 32\n" +" # The max number of total dedicated cores\n" +" owork_per_core: 32\n" "\n" "### Queue Manager settings\n" "queue_manager:\n" +" # The default depth of process queue\n" +" proc_queue_depth: 8192\n" " # The default depth of allocated queues\n" -" queue_depth: 256\n" +" queue_depth: 100000\n" " # The maximum number of lanes per queue\n" " max_lanes: 16\n" " # The maximum number of queues\n" @@ -21,6 +27,9 @@ const inline char* kHrunServerDefaultConfigStr = " # The size of the shared memory region to allocate for general data structures\n" " shm_size: 0g\n" " # The size of the shared memory to allocate for data buffers\n" +" data_shm_size: 4g\n" +" # The size of the shared memory to allocate for runtime data buffers\n" +" rdata_shm_size: 4g\n" "\n" "### Define properties of RPCs\n" "rpc:\n" @@ -46,7 +55,7 @@ const inline char* kHrunServerDefaultConfigStr = " port: 8080\n" "\n" " # The number of handler threads for each RPC server.\n" -" num_threads: 4\n" +" num_threads: 32\n" "\n" "### Task Registry\n" "task_registry: [\n" diff --git a/hrun/include/hrun/hrun_types.h b/hrun/include/hrun/hrun_types.h index 2e0952d9d..7ac5251fc 100644 --- a/hrun/include/hrun/hrun_types.h +++ b/hrun/include/hrun/hrun_types.h @@ -13,6 +13,14 @@ #ifndef HRUN_INCLUDE_HRUN_HRUN_TYPES_H_ #define HRUN_INCLUDE_HRUN_HRUN_TYPES_H_ +#include +#include +#include +#include +#include +#include +#include + #include #include #include diff --git a/hrun/include/hrun/network/local_serialize.h b/hrun/include/hrun/network/local_serialize.h index f0a870be9..2f950ac5a 100644 --- a/hrun/include/hrun/network/local_serialize.h +++ b/hrun/include/hrun/network/local_serialize.h @@ -26,6 +26,16 @@ class LocalSerialize { LocalSerialize(DataT &data) : data_(data) { data_.resize(0); } + LocalSerialize(DataT &data, bool) : data_(data) {} + + /** left shift operator */ + template + HSHM_ALWAYS_INLINE + LocalSerialize& operator<<(const UniqueId &obj) { + (*this) << obj.unique_; + (*this) << obj.node_id_; + return *this; + } /** left shift operator */ template @@ -36,10 +46,13 @@ class LocalSerialize { size_t off = data_.size(); data_.resize(off + size); memcpy(data_.data() + off, &obj, size); - } else if constexpr (std::is_same::value || std::is_same::value) { - size_t size = obj.size(); + } else if constexpr (std::is_same::value || + std::is_same::value) { + size_t size = sizeof(size_t) + obj.size(); size_t off = data_.size(); data_.resize(off + size); + memcpy(data_.data() + off, &size, sizeof(size_t)); + off += sizeof(size_t); memcpy(data_.data() + off, obj.data(), size); } else { throw std::runtime_error("Cannot serialize object"); @@ -59,6 +72,15 @@ class LocalDeserialize { cur_off_ = 0; } + /** right shift operator */ + template + HSHM_ALWAYS_INLINE + LocalDeserialize& operator<<(const UniqueId &obj) { + (*this) >> obj.unique_; + (*this) >> obj.node_id_; + return *this; + } + /** right shift operator */ template HSHM_ALWAYS_INLINE @@ -69,8 +91,11 @@ class LocalDeserialize { size = sizeof(T); memcpy(&obj, data_.data() + off, size); } else if constexpr (std::is_same::value || std::is_same::value) { - size = obj.size(); - memcpy(obj.data(), data_.data() + off, size); + memcpy(&size, data_.data() + off, sizeof(size_t)); + size_t str_size = size - sizeof(size_t); + off += sizeof(size_t); + obj.resize(str_size); + memcpy(obj.data(), data_.data() + off, str_size); } else { throw std::runtime_error("Cannot serialize object"); } diff --git a/hrun/include/hrun/network/rpc_thallium.h b/hrun/include/hrun/network/rpc_thallium.h index 58873283e..6c4be4ec8 100644 --- a/hrun/include/hrun/network/rpc_thallium.h +++ b/hrun/include/hrun/network/rpc_thallium.h @@ -126,7 +126,6 @@ class ThalliumRpc { std::string server_name = GetServerName(node_id); tl::remote_procedure remote_proc = client_engine_->define(func_name); tl::endpoint server = client_engine_->lookup(server_name); - HILOG(kDebug, "Found the server: {}={}", node_id, server_name) if constexpr(!ASYNC) { if constexpr (std::is_same::value) { remote_proc.disable_response(); @@ -195,6 +194,7 @@ class ThalliumRpc { tl::bulk bulk = client_engine_->expose(segments, flag); if constexpr (!ASYNC) { if constexpr (std::is_same_v) { + remote_proc.disable_response(); remote_proc.on(server)(bulk, std::forward(args)...); } else { return remote_proc.on(server)(bulk, std::forward(args)...); @@ -291,7 +291,7 @@ class ThalliumRpc { return req.received(); } - /** Wait for thallium to complete */ + /** Wait for async thallium to complete */ template RetT Wait(thallium::async_response &req) { if constexpr(std::is_same_v) { @@ -300,6 +300,11 @@ class ThalliumRpc { return req.wait(); } } + + /** Check if async thallium complete */ + bool IsComplete(thallium::async_response &req) { + return req.received(); + } }; } // namespace hermes diff --git a/hrun/include/hrun/network/serialize.h b/hrun/include/hrun/network/serialize.h index d775de7c8..1bd7c9d37 100644 --- a/hrun/include/hrun/network/serialize.h +++ b/hrun/include/hrun/network/serialize.h @@ -16,13 +16,6 @@ #include "hrun/hrun_types.h" #include "hrun/task_registry/task.h" #include -#include -#include -#include -#include -#include -#include -#include namespace hrun { diff --git a/hrun/include/hrun/queue_manager/queue.h b/hrun/include/hrun/queue_manager/queue.h index 09fd3213a..0dcf40a06 100644 --- a/hrun/include/hrun/queue_manager/queue.h +++ b/hrun/include/hrun/queue_manager/queue.h @@ -29,58 +29,76 @@ #define QUEUE_UNORDERED BIT_OPT(u32, 4) /** Requests in this queue are long-running */ #define QUEUE_LONG_RUNNING BIT_OPT(u32, 5) +/** Requests in this queue should not be scheduled on a traditional worker */ +#define QUEUE_DISABLED BIT_OPT(u32, 6) +/** This queue is tethered to another queue */ +#define QUEUE_TETHERED BIT_OPT(u32, 7) namespace hrun { /** Prioritization info needed to be set by client */ struct PriorityInfo { + u32 prio_; /**< Priority ID */ u32 max_lanes_; /**< Maximum number of lanes in the queue */ u32 num_lanes_; /**< Current number of lanes in use */ u32 depth_; /**< The maximum depth of individual lanes */ bitfield32_t flags_; /**< Scheduling hints for the queue */ + u32 tether_; /**< Lanes should be pinned to the same workers as the tether */ /** Default constructor */ PriorityInfo() = default; /** Emplace constructor */ - PriorityInfo(u32 num_lanes, u32 max_lanes, u32 depth, u32 flags) { + PriorityInfo(u32 prio, u32 num_lanes, u32 max_lanes, + u32 depth, u32 flags, u32 tether = 0) { + prio_ = prio; max_lanes_ = max_lanes; num_lanes_ = num_lanes; depth_ = depth; flags_ = bitfield32_t(flags); + tether_ = tether; } /** Emplace constructor */ - PriorityInfo(u32 num_lanes, u32 max_lanes, u32 depth, bitfield32_t flags) { + PriorityInfo(u32 prio, u32 num_lanes, u32 max_lanes, u32 depth, + bitfield32_t flags, u32 tether = 0) { + prio_ = prio; max_lanes_ = max_lanes; num_lanes_ = num_lanes; depth_ = depth; flags_ = flags; + tether_ = tether; } /** Copy constructor */ PriorityInfo(const PriorityInfo &priority) { + prio_ = priority.prio_; max_lanes_ = priority.max_lanes_; num_lanes_ = priority.num_lanes_; depth_ = priority.depth_; flags_ = priority.flags_; + tether_ = priority.tether_; } /** Move constructor */ PriorityInfo(PriorityInfo &&priority) noexcept { + prio_ = priority.prio_; max_lanes_ = priority.max_lanes_; num_lanes_ = priority.num_lanes_; depth_ = priority.depth_; flags_ = priority.flags_; + tether_ = priority.tether_; } /** Copy assignment operator */ PriorityInfo& operator=(const PriorityInfo &priority) { if (this != &priority) { + prio_ = priority.prio_; max_lanes_ = priority.max_lanes_; num_lanes_ = priority.num_lanes_; depth_ = priority.depth_; flags_ = priority.flags_; + tether_ = priority.tether_; } return *this; } @@ -88,10 +106,12 @@ struct PriorityInfo { /** Move assignment operator */ PriorityInfo& operator=(PriorityInfo &&priority) noexcept { if (this != &priority) { + prio_ = priority.prio_; max_lanes_ = priority.max_lanes_; num_lanes_ = priority.num_lanes_; depth_ = priority.depth_; flags_ = priority.flags_; + tether_ = priority.tether_; } return *this; } @@ -99,10 +119,12 @@ struct PriorityInfo { /** Serialize Priority Info */ template void serialize(Ar &ar) { + ar & prio_; ar & max_lanes_; ar & num_lanes_; ar & depth_; ar & flags_; + ar & tether_; } }; diff --git a/hrun/include/hrun/queue_manager/queue_manager_runtime.h b/hrun/include/hrun/queue_manager/queue_manager_runtime.h index f60f55b6c..ffe08ce28 100644 --- a/hrun/include/hrun/queue_manager/queue_manager_runtime.h +++ b/hrun/include/hrun/queue_manager/queue_manager_runtime.h @@ -41,7 +41,7 @@ class QueueManagerRuntime : public QueueManager { void ServerInit(hipc::Allocator *alloc, u32 node_id, ServerConfig *config, QueueManagerShm &shm) { config_ = config; Init(node_id); - QueueManagerInfo &qm = config_->queue_manager_; + config::QueueManagerInfo &qm = config_->queue_manager_; // Initialize ticket queue (ticket 0 is for admin queue) max_queues_ = qm.max_queues_; max_lanes_ = qm.max_lanes_; @@ -55,14 +55,31 @@ class QueueManagerRuntime : public QueueManager { queue_map_->resize(max_queues_); // Create the admin queue MultiQueue *queue; + std::vector queue_info{ + {TaskPrio::kAdmin, 1, 1, qm.queue_depth_, QUEUE_UNORDERED}, + {TaskPrio::kLongRunning, 1, 1, qm.queue_depth_, QUEUE_LONG_RUNNING}, + {TaskPrio::kLowLatency, qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY}, + {TaskPrio::kLongRunningTether, qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, + QUEUE_LONG_RUNNING | QUEUE_TETHERED, TaskPrio::kLowLatency}, + {TaskPrio::kHighLatency, qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY} + }; queue = CreateQueue(admin_queue_, { - {1, 1, qm.queue_depth_, QUEUE_UNORDERED} + {TaskPrio::kAdmin, 1, 1, qm.queue_depth_, QUEUE_UNORDERED}, + {TaskPrio::kLongRunning, 1, 1, qm.queue_depth_, QUEUE_LONG_RUNNING}, + {TaskPrio::kLowLatency, qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY}, + {TaskPrio::kLongRunningTether, qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, + QUEUE_LONG_RUNNING | QUEUE_TETHERED, TaskPrio::kLowLatency}, + {TaskPrio::kHighLatency, qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY} }); queue->flags_.SetBits(QUEUE_READY); + u32 depth = qm.proc_queue_depth_; queue = CreateQueue(process_queue_, { - {1, 1, qm.queue_depth_, QUEUE_UNORDERED}, - {1, 1, qm.queue_depth_, QUEUE_LONG_RUNNING}, - {qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY} + {TaskPrio::kAdmin, 1, 1, depth, QUEUE_UNORDERED}, + {TaskPrio::kLongRunning, 1, 1, depth, QUEUE_LONG_RUNNING}, + {TaskPrio::kLowLatency, qm.max_lanes_, qm.max_lanes_, depth, QUEUE_LOW_LATENCY}, + {TaskPrio::kLongRunningTether, qm.max_lanes_, qm.max_lanes_, depth, + QUEUE_LONG_RUNNING | QUEUE_TETHERED, TaskPrio::kLowLatency}, + {TaskPrio::kHighLatency, qm.max_lanes_, qm.max_lanes_, depth, QUEUE_LOW_LATENCY} }); queue->flags_.SetBits(QUEUE_READY); } diff --git a/hrun/include/hrun/queue_manager/queues/hshm_queue.h b/hrun/include/hrun/queue_manager/queues/hshm_queue.h index 94e921527..11db153a1 100644 --- a/hrun/include/hrun/queue_manager/queues/hshm_queue.h +++ b/hrun/include/hrun/queue_manager/queues/hshm_queue.h @@ -6,14 +6,14 @@ #define HRUN_INCLUDE_HRUN_QUEUE_MANAGER_HSHM_QUEUE_H_ #include "hrun/queue_manager/queue.h" +#include "mpsc_queue.h" namespace hrun { /** The data stored in a lane */ struct LaneData { - hipc::Pointer p_; - bool complete_; - ABT_thread thread_; + hipc::Pointer p_; /**< Pointer to SHM request */ + bool complete_; /**< Whether request is complete */ LaneData() = default; @@ -24,13 +24,14 @@ struct LaneData { }; /** Represents a lane tasks can be stored */ -typedef hipc::mpsc_queue Lane; +typedef hrun::mpsc_queue Lane; /** Prioritization of different lanes in the queue */ struct LaneGroup : public PriorityInfo { u32 prio_; /**< The priority of the lane group */ u32 num_scheduled_; /**< The number of lanes currently scheduled on workers */ hipc::ShmArchive> lanes_; /**< The lanes of the queue */ + u32 tether_; /**< Lanes should be pinned to the same workers as the tether's prio group */ /** Default constructor */ HSHM_ALWAYS_INLINE @@ -39,34 +40,43 @@ struct LaneGroup : public PriorityInfo { /** Set priority info */ HSHM_ALWAYS_INLINE LaneGroup(const PriorityInfo &priority) { + prio_ = priority.prio_; max_lanes_ = priority.max_lanes_; num_lanes_ = priority.num_lanes_; num_scheduled_ = 0; depth_ = priority.depth_; flags_ = priority.flags_; - // prio_ is set externally + tether_ = priority.tether_; } /** Copy constructor. Should never actually be called. */ HSHM_ALWAYS_INLINE LaneGroup(const LaneGroup &priority) { + prio_ = priority.prio_; max_lanes_ = priority.max_lanes_; num_lanes_ = priority.num_lanes_; num_scheduled_ = priority.num_scheduled_; depth_ = priority.depth_; flags_ = priority.flags_; - // prio_ is set externally + tether_ = priority.tether_; } /** Move constructor. Should never actually be called. */ HSHM_ALWAYS_INLINE LaneGroup(LaneGroup &&priority) noexcept { + prio_ = priority.prio_; max_lanes_ = priority.max_lanes_; num_lanes_ = priority.num_lanes_; num_scheduled_ = priority.num_scheduled_; depth_ = priority.depth_; flags_ = priority.flags_; - // prio_ is set externally + tether_ = priority.tether_; + } + + /** Check if this group is tethered */ + HSHM_ALWAYS_INLINE + bool IsTethered() { + return flags_.Any(QUEUE_TETHERED); } /** Check if this group is long-running or ADMIN */ @@ -75,6 +85,12 @@ struct LaneGroup : public PriorityInfo { return flags_.Any(QUEUE_LONG_RUNNING) || prio_ == 0; } + /** Check if this group is long-running or ADMIN */ + HSHM_ALWAYS_INLINE + bool IsLowLatency() { + return flags_.Any(QUEUE_LOW_LATENCY); + } + /** Get lane */ Lane& GetLane(u32 lane_id) { return (*lanes_)[lane_id]; @@ -110,18 +126,15 @@ struct MultiQueueT : public hipc::ShmContainer { const std::vector &prios) { shm_init_container(alloc); id_ = id; - HSHM_MAKE_AR0(groups_, GetAllocator()); - groups_->reserve(prios.size()); - for (u32 prio = 0; prio < prios.size(); ++prio) { - const PriorityInfo &prio_info = prios[prio]; - groups_->emplace_back(prio_info); - LaneGroup &lane_group = (*groups_)[prio]; + HSHM_MAKE_AR(groups_, GetAllocator(), prios.size()); + for (const PriorityInfo &prio_info : prios) { + groups_->replace(groups_->begin() + prio_info.prio_, prio_info); + LaneGroup &lane_group = (*groups_)[prio_info.prio_]; // Initialize lanes HSHM_MAKE_AR0(lane_group.lanes_, GetAllocator()); lane_group.lanes_->reserve(prio_info.max_lanes_); - lane_group.prio_ = prio; for (u32 lane_id = 0; lane_id < lane_group.num_lanes_; ++lane_id) { - lane_group.lanes_->emplace_back(lane_group.depth_); + lane_group.lanes_->emplace_back(lane_group.depth_, id_); Lane &lane = lane_group.lanes_->back(); lane.flags_ = prio_info.flags_; } @@ -226,10 +239,20 @@ struct MultiQueueT : public hipc::ShmContainer { /** Emplace a SHM pointer to a task */ HSHM_ALWAYS_INLINE - bool Emplace(u32 prio, u32 lane_hash, hipc::Pointer &p, bool complete = false) { + bool Emplace(u32 prio, u32 lane_hash, + hipc::Pointer &p, bool complete = false) { return Emplace(prio, lane_hash, LaneData(p, complete)); } + /** + * Emplace a SHM pointer to a task if the queue utilization is less than 50% + * */ + HSHM_ALWAYS_INLINE + bool EmplaceFrac(u32 prio, u32 lane_hash, + hipc::Pointer &p, bool complete = false) { + return EmplaceFrac(prio, lane_hash, LaneData(p, complete)); + } + /** Emplace a SHM pointer to a task */ bool Emplace(u32 prio, u32 lane_hash, const LaneData &data) { if (IsEmplacePlugged()) { @@ -242,6 +265,23 @@ struct MultiQueueT : public hipc::ShmContainer { return !ret.IsNull(); } + /** + * Emplace a SHM pointer to a task if the queue utilization is less than 50% + * */ + bool EmplaceFrac(u32 prio, u32 lane_hash, const LaneData &data) { + if (IsEmplacePlugged()) { + WaitForEmplacePlug(); + } + LaneGroup &lane_group = GetGroup(prio); + u32 lane_id = lane_hash % lane_group.num_lanes_; + Lane &lane = GetLane(lane_group, lane_id); + if (lane.GetSize() * 2 > lane.GetDepth()) { + return false; + } + hshm::qtok_t ret = lane.emplace(data); + return !ret.IsNull(); + } + /** * Change the number of active lanes * This assumes that PlugForResize and UnplugForResize are called externally. diff --git a/hrun/include/hrun/queue_manager/queues/mpsc_queue.h b/hrun/include/hrun/queue_manager/queues/mpsc_queue.h new file mode 100644 index 000000000..46dee8a76 --- /dev/null +++ b/hrun/include/hrun/queue_manager/queues/mpsc_queue.h @@ -0,0 +1,312 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HRUN_INCLUDE_HRUN_DATA_STRUCTURES_IPC_mpsc_queue_H_ +#define HRUN_INCLUDE_HRUN_DATA_STRUCTURES_IPC_mpsc_queue_H_ + +#include "hermes_shm/data_structures/ipc/internal/shm_internal.h" +#include "hermes_shm/thread/lock.h" +#include "hermes_shm/data_structures/ipc/vector.h" +#include "hermes_shm/data_structures/ipc/pair.h" +#include "hermes_shm/types/qtok.h" +#include "hrun/hrun_types.h" + +namespace hrun { + +/** Forward declaration of mpsc_queue */ +template +class mpsc_queue; + +/** + * MACROS used to simplify the mpsc_queue namespace + * Used as inputs to the SHM_CONTAINER_TEMPLATE + * */ +#define CLASS_NAME mpsc_queue +#define TYPED_CLASS mpsc_queue +#define TYPED_HEADER ShmHeader> + +using hipc::ShmContainer; +using hipc::pair; +using hshm::_qtok_t; +using hshm::qtok_t; +using hipc::vector; +using hipc::ShmArchive; +using hipc::Allocator; +using hshm::bitfield32_t; +using hshm::make_argpack; + +/** + * A queue optimized for multiple producers (emplace) with a single + * consumer (pop). + * */ +template +class mpsc_queue : public ShmContainer { + public: + SHM_CONTAINER_TEMPLATE((CLASS_NAME), (TYPED_CLASS)) + ShmArchive>> queue_; + std::atomic<_qtok_t> tail_; + std::atomic<_qtok_t> head_; + bitfield32_t flags_; + QueueId id_; + u32 worker_id_; + + public: + /**==================================== + * Default Constructor + * ===================================*/ + + /** SHM constructor. Default. */ + explicit mpsc_queue(Allocator *alloc, + size_t depth = 1024, + QueueId id = QueueId::GetNull()) { + shm_init_container(alloc); + HSHM_MAKE_AR(queue_, GetAllocator(), depth); + flags_.Clear(); + id_ = id; + SetNull(); + } + + /**==================================== + * Copy Constructors + * ===================================*/ + + /** SHM copy constructor */ + explicit mpsc_queue(Allocator *alloc, + const mpsc_queue &other) { + shm_init_container(alloc); + SetNull(); + shm_strong_copy_construct_and_op(other); + } + + /** SHM copy assignment operator */ + mpsc_queue& operator=(const mpsc_queue &other) { + if (this != &other) { + shm_destroy(); + shm_strong_copy_construct_and_op(other); + } + return *this; + } + + /** SHM copy constructor + operator main */ + void shm_strong_copy_construct_and_op(const mpsc_queue &other) { + head_ = other.head_.load(); + tail_ = other.tail_.load(); + (*queue_) = (*other.queue_); + } + + /**==================================== + * Move Constructors + * ===================================*/ + + /** SHM move constructor. */ + mpsc_queue(Allocator *alloc, + mpsc_queue &&other) noexcept { + shm_init_container(alloc); + if (GetAllocator() == other.GetAllocator()) { + head_ = other.head_.load(); + tail_ = other.tail_.load(); + (*queue_) = std::move(*other.queue_); + other.SetNull(); + } else { + shm_strong_copy_construct_and_op(other); + other.shm_destroy(); + } + } + + /** SHM move assignment operator. */ + mpsc_queue& operator=(mpsc_queue &&other) noexcept { + if (this != &other) { + shm_destroy(); + if (GetAllocator() == other.GetAllocator()) { + head_ = other.head_.load(); + tail_ = other.tail_.load(); + (*queue_) = std::move(*other.queue_); + other.SetNull(); + } else { + shm_strong_copy_construct_and_op(other); + other.shm_destroy(); + } + } + return *this; + } + + /**==================================== + * Destructor + * ===================================*/ + + /** SHM destructor. */ + void shm_destroy_main() { + (*queue_).shm_destroy(); + } + + /** Check if the list is empty */ + bool IsNull() const { + return (*queue_).IsNull(); + } + + /** Sets this list as empty */ + void SetNull() { + head_ = 0; + tail_ = 0; + } + + /**==================================== + * MPSC Queue Methods + * ===================================*/ + + /** Construct an element at \a pos position in the list */ + template + qtok_t emplace(Args&&... args) { + // Allocate a slot in the queue + // The slot is marked NULL, so pop won't do anything if context switch + _qtok_t head = head_.load(); + _qtok_t tail = tail_.fetch_add(1); + size_t size = tail - head + 1; + vector> &queue = (*queue_); + + // Check if there's space in the queue. + if (size > queue.size()) { + HILOG(kDebug, "Queue {}/{} is full, waiting for space", + id_, queue_->size()); + while (true) { + head = head_.load(); + size = tail - head + 1; + if (size <= (*queue_).size()) { + break; + } + HERMES_THREAD_MODEL->Yield(); + } + HILOG(kDebug, "Queue {}/{} got scheduled", id_, queue_->size()); + } + + // Emplace into queue at our slot + uint32_t idx = tail % queue.size(); + auto iter = queue.begin() + idx; + queue.replace(iter, + hshm::PiecewiseConstruct(), + make_argpack(), + make_argpack(std::forward(args)...)); + + // Let pop know that the data is fully prepared + pair &entry = (*iter); + entry.GetFirst().SetBits(1); + return qtok_t(tail); + } + + public: + /** Consumer pops the head object */ + qtok_t pop(T &val) { + // Don't pop if there's no entries + _qtok_t head = head_.load(); + _qtok_t tail = tail_.load(); + if (head >= tail) { + return qtok_t::GetNull(); + } + + // Pop the element, but only if it's marked valid + _qtok_t idx = head % (*queue_).size(); + hipc::pair &entry = (*queue_)[idx]; + if (entry.GetFirst().Any(1)) { + val = std::move(entry.GetSecond()); + entry.GetFirst().Clear(); + head_.fetch_add(1); + return qtok_t(head); + } else { + return qtok_t::GetNull(); + } + } + + /** Consumer pops the head object */ + qtok_t pop() { + // Don't pop if there's no entries + _qtok_t head = head_.load(); + _qtok_t tail = tail_.load(); + if (head >= tail) { + return qtok_t::GetNull(); + } + + // Pop the element, but only if it's marked valid + _qtok_t idx = head % (*queue_).size(); + hipc::pair &entry = (*queue_)[idx]; + if (entry.GetFirst().Any(1)) { + entry.GetFirst().Clear(); + head_.fetch_add(1); + return qtok_t(head); + } else { + return qtok_t::GetNull(); + } + } + + /** Consumer peeks an object */ + qtok_t peek(T *&val, int off = 0) { + // Don't pop if there's no entries + _qtok_t head = head_.load() + off; + _qtok_t tail = tail_.load(); + if (head >= tail) { + return qtok_t::GetNull(); + } + + // Pop the element, but only if it's marked valid + _qtok_t idx = (head) % (*queue_).size(); + hipc::pair &entry = (*queue_)[idx]; + if (entry.GetFirst().Any(1)) { + val = &entry.GetSecond(); + return qtok_t(head); + } else { + return qtok_t::GetNull(); + } + } + + /** Consumer peeks an object */ + qtok_t peek(pair *&val, int off = 0) { + // Don't pop if there's no entries + _qtok_t head = head_.load() + off; + _qtok_t tail = tail_.load(); + if (head >= tail) { + return qtok_t::GetNull(); + } + + // Pop the element, but only if it's marked valid + _qtok_t idx = (head) % (*queue_).size(); + hipc::pair &entry = (*queue_)[idx]; + if (entry.GetFirst().Any(1)) { + val = &entry; + return qtok_t(head); + } else { + return qtok_t::GetNull(); + } + } + + /** Current size of queue */ + size_t GetSize() { + size_t tail = tail_.load(); + size_t head = head_.load(); + if (tail <= head) { + return 0; + } else { + return tail - head; + } + } + + /** Max depth of queue */ + size_t GetDepth() { + return (*queue_).size(); + } +}; + +} // namespace hshm::ipc + +#undef CLASS_NAME +#undef TYPED_CLASS +#undef TYPED_HEADER + +#endif // HRUN_INCLUDE_HRUN_DATA_STRUCTURES_IPC_mpsc_queue_H_ diff --git a/hrun/include/hrun/task_registry/task.h b/hrun/include/hrun/task_registry/task.h index 6a6a3d451..c8723a1eb 100644 --- a/hrun/include/hrun/task_registry/task.h +++ b/hrun/include/hrun/task_registry/task.h @@ -53,14 +53,14 @@ class TaskLib; #define TASK_DATA_OWNER BIT_OPT(u32, 14) /** This task uses co-routine wait */ #define TASK_COROUTINE BIT_OPT(u32, 15) -/** This task uses argobot wait */ -#define TASK_PREEMPTIVE BIT_OPT(u32, 17) /** This task can be scheduled on any lane */ #define TASK_LANE_ANY BIT_OPT(u32, 18) /** This task should be scheduled on all lanes */ #define TASK_LANE_ALL BIT_OPT(u32, 19) /** This task flushes the runtime */ #define TASK_FLUSH BIT_OPT(u32, 20) +/** This task is considered a root task */ +#define TASK_IS_ROOT BIT_OPT(u32, 21) /** This task is apart of remote debugging */ #define TASK_REMOTE_DEBUG_MARK BIT_OPT(u32, 31) @@ -189,9 +189,10 @@ static inline std::ostream &operator<<(std::ostream &os, const TaskNode &obj) { #define TF_SRL_ASYM (TF_SRL_ASYM_START | TF_SRL_ASYM_END) /** This task uses replication */ #define TF_REPLICA BIT_OPT(u32, 31) -/** This task uses duplication */ /** This task is intended to be used only locally */ #define TF_LOCAL BIT_OPT(u32, 5) +/** This task supports monitoring of all sub-methods */ +#define TF_MONITOR BIT_OPT(u32, 6) /** All tasks inherit this to easily check if a class is a task using SFINAE */ class IsTask {}; @@ -219,6 +220,7 @@ struct TaskFlags : public IsTask { TASK_FLAG_T SRL_SYM_START = FLAGS & TF_SRL_SYM_START; TASK_FLAG_T SRL_SYM_END = FLAGS & TF_SRL_SYM_END; TASK_FLAG_T REPLICA = FLAGS & TF_REPLICA; + TASK_FLAG_T MONITOR = FLAGS & TF_MONITOR; }; /** The type of a compile-time task flag */ @@ -227,32 +229,32 @@ struct TaskFlags : public IsTask { /** Prioritization of tasks */ class TaskPrio { public: - TASK_PRIO_T kAdmin = 0; - TASK_PRIO_T kLongRunning = 1; - TASK_PRIO_T kLowLatency = 2; + TASK_PRIO_T kAdmin = 0; /**< Admin task lane */ + TASK_PRIO_T kLongRunning = 1; /**< Long-running task lane */ + TASK_PRIO_T kLowLatency = 2; /**< Low latency task lane */ + TASK_PRIO_T kLongRunningTether = 3; /**< Tethered to low latency workers */ + TASK_PRIO_T kHighLatency = 4; /**< High latency task lane */ }; - /** Used to indicate the amount of work remaining to do when flushing */ struct WorkPending { bool flushing_; - std::atomic pending_; + std::atomic count_; /** Default constructor */ WorkPending() - : flushing_(false), pending_(0) {} + : flushing_(false), count_(0) {} /** Copy constructor */ WorkPending(const WorkPending &other) - : flushing_(other.flushing_), pending_(other.pending_.load()) {} + : flushing_(other.flushing_), count_(other.count_.load()) {} }; /** Context passed to the Run method of a task */ struct RunContext { - u32 lane_id_; /**< The lane id of the task */ + u32 lane_id_; /**< The lane id of the task */ bctx::transfer_t jmp_; /**< Current execution state of the task (runtime) */ - size_t stack_size_ = KILOBYTES(64); /**< The size of the stack for the task (runtime) */ - void *stack_ptr_; /**< The pointer to the stack (runtime) */ + void *stack_ptr_; /**< The pointer to the stack (runtime) */ TaskLib *exec_; WorkPending *flush_; @@ -390,11 +392,6 @@ struct Task : public hipc::ShmContainer { task_flags_.UnsetBits(TASK_COROUTINE); } - /** Set this task as blocking */ - HSHM_ALWAYS_INLINE bool IsPreemptive() { - return task_flags_.Any(TASK_PREEMPTIVE); - } - /** This task should be dispersed across all lanes */ HSHM_ALWAYS_INLINE bool IsLaneAll() { return task_flags_.Any(TASK_LANE_ALL); @@ -405,6 +402,21 @@ struct Task : public hipc::ShmContainer { task_flags_.UnsetBits(TASK_LANE_ALL); } + /** This task is a root task */ + HSHM_ALWAYS_INLINE bool IsRoot() { + return task_flags_.Any(TASK_IS_ROOT); + } + + /** Set this task as a root task */ + HSHM_ALWAYS_INLINE void SetRoot() { + task_flags_.SetBits(TASK_IS_ROOT); + } + + /** Unset this task a sa root task */ + HSHM_ALWAYS_INLINE void UnsetRoot() { + task_flags_.UnsetBits(TASK_IS_ROOT); + } + /** Set period in nanoseconds */ HSHM_ALWAYS_INLINE void SetPeriodNs(double ns) { period_ns_ = ns; @@ -437,15 +449,14 @@ struct Task : public hipc::ShmContainer { /** Determine if time has elapsed */ HSHM_ALWAYS_INLINE bool ShouldRun(hshm::Timepoint &cur_time, bool flushing) { - if (!IsStarted() || flushing) { - start_ = cur_time; + if (!IsLongRunning()) { return true; } - if (IsLongRunning()) { - return start_.GetNsecFromStart(cur_time) >= period_ns_; - } else { + if (!IsStarted() || flushing) { + start_ = cur_time; return true; } + return start_.GetNsecFromStart(cur_time) >= period_ns_; } /** Mark this task as having been run */ diff --git a/hrun/include/hrun/task_registry/task_lib.h b/hrun/include/hrun/task_registry/task_lib.h index 663fe42b5..ebadd7938 100644 --- a/hrun/include/hrun/task_registry/task_lib.h +++ b/hrun/include/hrun/task_registry/task_lib.h @@ -23,6 +23,14 @@ namespace hrun { typedef LPointer TaskPointer; +/** Monitoring modes */ +class MonitorMode { + public: + TASK_METHOD_T kEstTime = 0; + TASK_METHOD_T kTrainTime = 1; + TASK_METHOD_T kFlushStat = 2; +}; + /** * Represents a custom operation to perform. * Tasks are independent of Hermes. @@ -37,9 +45,10 @@ class TaskLib { TaskLib() : id_(TaskStateId::GetNull()) {} /** Emplace Constructor */ - void Init(const TaskStateId &id, const std::string &name) { + void Init(const TaskStateId &id, const QueueId &queue_id, + const std::string &name) { id_ = id; - queue_id_ = QueueId(id); + queue_id_ = queue_id; name_ = name; } @@ -49,6 +58,9 @@ class TaskLib { /** Run a method of the task */ virtual void Run(u32 method, Task *task, RunContext &rctx) = 0; + /** Monitor a method of the task */ + virtual void Monitor(u32 mode, Task *task, RunContext &rctx) = 0; + /** Delete a task */ virtual void Del(u32 method, Task *task) = 0; @@ -91,9 +103,11 @@ class TaskLibClient { public: /** Init from existing ID */ - void Init(const TaskStateId &id) { + void Init(const TaskStateId &id, + const QueueId &queue_id) { id_ = id; - queue_id_ = QueueId(id_); + // queue_id_ = QueueId(id_); + queue_id_ = queue_id; } }; @@ -112,13 +126,13 @@ typedef const char* (*get_task_lib_name_t)(void); void* alloc_state(hrun::Admin::CreateTaskStateTask *task, const char *state_name) {\ hrun::TaskState *exec = reinterpret_cast(\ new TYPE_UNWRAP(TRAIT_CLASS)());\ - exec->Init(task->id_, state_name);\ + exec->Init(task->id_, HRUN_CLIENT->GetQueueId(task->id_), state_name);\ return exec;\ }\ void* create_state(hrun::Admin::CreateTaskStateTask *task, const char *state_name) {\ hrun::TaskState *exec = reinterpret_cast(\ new TYPE_UNWRAP(TRAIT_CLASS)());\ - exec->Init(task->id_, state_name);\ + exec->Init(task->id_, HRUN_CLIENT->GetQueueId(task->id_), state_name);\ RunContext rctx(0);\ exec->Run(hrun::TaskMethod::kConstruct, task, rctx);\ return exec;\ diff --git a/hrun/include/hrun/task_registry/task_registry.h b/hrun/include/hrun/task_registry/task_registry.h index 60bf7844b..fc3808ed4 100644 --- a/hrun/include/hrun/task_registry/task_registry.h +++ b/hrun/include/hrun/task_registry/task_registry.h @@ -220,7 +220,7 @@ class TaskRegistry { Admin::CreateTaskStateTask *task) { // Ensure state_id is not NULL if (state_id.IsNull()) { - HILOG(kError, "The task state ID cannot be null"); + HELOG(kError, "The task state ID cannot be null"); task->SetModuleComplete(); return nullptr; } diff --git a/hrun/include/hrun/work_orchestrator/affinity.h b/hrun/include/hrun/work_orchestrator/affinity.h index 55f54fc1f..7e6106308 100644 --- a/hrun/include/hrun/work_orchestrator/affinity.h +++ b/hrun/include/hrun/work_orchestrator/affinity.h @@ -14,6 +14,11 @@ #define HRUN_INCLUDE_HRUN_WORK_ORCHESTRATOR_AFFINITY_H_ #include +#include +#include +#include +#include +#include class ProcessAffiner { public: @@ -30,6 +35,146 @@ class ProcessAffiner { // HELOG(kError, "Failed to set CPU affinity for process {}", pid); } } + + private: + int n_cpu_; + std::vector cpus_; + std::vector ignore_pids_; + + public: + ProcessAffiner() { + n_cpu_ = get_nprocs_conf(); + cpus_.resize(n_cpu_); + Clear(); + } + + inline bool isdigit(char digit) { + return ('0' <= digit && digit <= '9'); + } + + inline int GetNumCPU() { + return n_cpu_; + } + + inline void SetCpu(int cpu) { + CPU_SET(cpu, cpus_.data()); + } + + inline void SetCpus(int off, int len) { + for (int i = 0; i < len; ++i) { + SetCpu(off + i); + } + } + + inline void SetCpus(const std::vector &cpu_ids) { + for (int cpu_id : cpu_ids) { + SetCpu(cpu_id); + } + } + + inline void ClearCpu(int cpu) { + CPU_CLR(cpu, cpus_.data()); + } + + void IgnorePids(const std::vector &pids) { + ignore_pids_ = pids; + } + + inline void ClearCpus(int off, int len) { + for (int i = 0; i < len; ++i) { + ClearCpu(off + i); + } + } + + inline void Clear() { + for (cpu_set_t &cpu : cpus_) { + CPU_ZERO(&cpu); + } + } + + int AffineAll(void) { + DIR *procdir; + struct dirent *entry; + size_t count = 0; + + // Open /proc directory. + procdir = opendir("/proc"); + if (!procdir) { + perror("opendir failed"); + return 0; + } + + // Iterate through all files and folders of /proc. + while ((entry = readdir(procdir))) { + // Skip anything that is not a PID folder. + if (!is_pid_folder(entry)) { + continue; + } + // Get the PID of the running process + int proc_pid = atoi(entry->d_name); + if (std::find(ignore_pids_.begin(), ignore_pids_.end(), proc_pid) != + ignore_pids_.end()) { + continue; + } + // Set the affinity of all running process to this mask + count += Affine(proc_pid); + } + closedir(procdir); + return count; + } + int Affine(std::vector &&pids) { + return Affine(pids); + } + int Affine(std::vector &pids) { + // Set the affinity of all running process to this mask + size_t count = 0; + for (pid_t &pid : pids) { + count += Affine(pid); + } + return count; + } + int Affine(int pid) { + return SetAffinitySafe(pid, n_cpu_, cpus_.data()); + } + + void PrintAffinity(int pid) { + PrintAffinity("", pid); + } + void PrintAffinity(std::string prefix, int pid) { + std::vector cpus(n_cpu_); + sched_getaffinity(pid, n_cpu_, cpus.data()); + PrintAffinity(prefix, pid, cpus.data()); + } + + void PrintAffinity(std::string prefix, int pid, cpu_set_t *cpus) { + std::string affinity = ""; + for (int i = 0; i < n_cpu_; ++i) { + if (CPU_ISSET(i, cpus)) { + affinity += std::to_string(i) + ", "; + } + } + printf("%s: CPU affinity[pid=%d]: %s\n", prefix.c_str(), + pid, affinity.c_str()); + } + + private: + int SetAffinitySafe(int pid, int n_cpu, cpu_set_t *cpus) { + int ret = sched_setaffinity(pid, n_cpu, cpus); + if (ret == -1) { + return 0; + } + return 1; + } + + // Helper function to check if a struct dirent from /proc is a PID folder. + int is_pid_folder(const struct dirent *entry) { + const char *p; + for (p = entry->d_name; *p; p++) { + if (!isdigit(*p)) + return false; + } + return true; + } }; #endif // HRUN_INCLUDE_HRUN_WORK_ORCHESTRATOR_AFFINITY_H_ diff --git a/hrun/include/hrun/work_orchestrator/scheduler.h b/hrun/include/hrun/work_orchestrator/scheduler.h index 25bdca4c8..29aa7b625 100644 --- a/hrun/include/hrun/work_orchestrator/scheduler.h +++ b/hrun/include/hrun/work_orchestrator/scheduler.h @@ -43,7 +43,7 @@ struct ScheduleTask : public Task, TaskFlags { task_state_ = state_id; method_ = SchedulerMethod::kSchedule; task_flags_.SetBits(TASK_LONG_RUNNING | TASK_REMOTE_DEBUG_MARK); - SetPeriodSec(1); + SetPeriodMs(250); domain_id_ = domain_id; // Custom params diff --git a/hrun/include/hrun/work_orchestrator/work_orchestrator.h b/hrun/include/hrun/work_orchestrator/work_orchestrator.h index 33d2182e1..71443b693 100644 --- a/hrun/include/hrun/work_orchestrator/work_orchestrator.h +++ b/hrun/include/hrun/work_orchestrator/work_orchestrator.h @@ -14,18 +14,21 @@ #define HRUN_INCLUDE_HRUN_WORK_ORCHESTRATOR_WORK_ORCHESTRATOR_H_ #include "hrun/hrun_types.h" -#include "hrun/api/hrun_runtime.h" #include "hrun/queue_manager/queue_manager_runtime.h" -#include "worker.h" #include "hrun/network/rpc_thallium.h" #include namespace hrun { +class Worker; + class WorkOrchestrator { public: ServerConfig *config_; /**< The server configuration */ - std::vector workers_; /**< Workers execute tasks */ + std::vector> workers_; /**< Workers execute tasks */ + std::vector dworkers_; /**< Core-dedicated workers */ + std::vector oworkers_; /**< Undedicated workers */ + Worker* admin_worker_; /**< Constantly polled admin worker */ std::atomic stop_runtime_; /**< Begin killing the runtime */ std::atomic kill_requested_; /**< Kill flushing threads eventually */ ABT_xstream xstream_; @@ -38,70 +41,40 @@ class WorkOrchestrator { ~WorkOrchestrator() = default; /** Create thread pool */ - void ServerInit(ServerConfig *config, QueueManager &qm) { - config_ = config; + void ServerInit(ServerConfig *config, QueueManager &qm); - // Initialize argobots - ABT_init(0, nullptr); + /** Finalize thread pool */ + void Join(); - // Create argobots xstream - int ret = ABT_xstream_create(ABT_SCHED_NULL, &xstream_); - if (ret != ABT_SUCCESS) { - HELOG(kFatal, "Could not create argobots xstream"); - } + /** Get worker with this id */ + Worker& GetWorker(u32 worker_id); - // Spawn workers on the stream - size_t num_workers = config_->wo_.max_workers_; - workers_.reserve(num_workers); - for (u32 worker_id = 0; worker_id < num_workers; ++worker_id) { - workers_.emplace_back(worker_id, xstream_); - } - stop_runtime_ = false; - kill_requested_ = false; - - // Schedule admin queue on worker 0 - MultiQueue *admin_queue = qm.GetQueue(qm.admin_queue_); - LaneGroup *admin_group = &admin_queue->GetGroup(0); - for (u32 lane_id = 0; lane_id < admin_group->num_lanes_; ++lane_id) { - Worker &worker = workers_[0]; - worker.PollQueues({WorkEntry(0, lane_id, admin_queue)}); - } - admin_group->num_scheduled_ = admin_group->num_lanes_; + /** Get the number of workers */ + size_t GetNumWorkers(); - HILOG(kInfo, "Started {} workers", num_workers); - } + /** Get all PIDs of active workers */ + std::vector GetWorkerPids(); - /** Get worker with this id */ - Worker& GetWorker(u32 worker_id) { - return workers_[worker_id]; - } + /** Get the complement of worker cores */ + std::vector GetWorkerCoresComplement(); - /** Get the number of workers */ - size_t GetNumWorkers() { - return workers_.size(); - } + /** Begin dedicating core s*/ + void DedicateCores(); /** Begin finalizing the runtime */ + HSHM_ALWAYS_INLINE void FinalizeRuntime() { stop_runtime_.store(true); } - /** Finalize thread pool */ - void Join() { - kill_requested_.store(true); - for (Worker &worker : workers_) { - worker.thread_->join(); - ABT_xstream_join(xstream_); - ABT_xstream_free(&xstream_); - } - } - /** Whether threads should still be executing */ + HSHM_ALWAYS_INLINE bool IsAlive() { return !kill_requested_.load(); } /** Whether runtime should still be executing */ + HSHM_ALWAYS_INLINE bool IsRuntimeAlive() { return !stop_runtime_.load(); } diff --git a/hrun/include/hrun/work_orchestrator/worker.h b/hrun/include/hrun/work_orchestrator/worker.h index 92e29aeb6..9070713ad 100644 --- a/hrun/include/hrun/work_orchestrator/worker.h +++ b/hrun/include/hrun/work_orchestrator/worker.h @@ -15,6 +15,9 @@ #include "hrun/hrun_types.h" #include "hrun/queue_manager/queue_manager_runtime.h" +#include "hrun/task_registry/task_registry.h" +#include "hrun/work_orchestrator/work_orchestrator.h" +#include "hrun/api/hrun_runtime_.h" #include #include #include "affinity.h" @@ -24,6 +27,8 @@ static inline pid_t GetLinuxTid() { return syscall(SYS_gettid); } +#define DEBUG + namespace hrun { #define WORKER_CONTINUOUS_POLLING BIT_OPT(u32, 0) @@ -139,39 +144,53 @@ class Worker { public: u32 id_; /**< Unique identifier of this worker */ std::unique_ptr thread_; /**< The worker thread handle */ + ABT_thread tl_thread_; /**< The worker argobots thread handle */ int pthread_id_; /**< The worker pthread handle */ - // ABT_thread tl_thread_; - int pid_; /**< The worker process id */ + std::atomic pid_; /**< The worker process id */ + int affinity_; /**< The worker CPU affinity */ u32 numa_node_; // TODO(llogan): track NUMA affinity + ABT_xstream xstream_; std::vector work_queue_; /**< The set of queues to poll */ - /** A set of queues to begin polling in a worker */ + /**< A set of queues to begin polling in a worker */ hshm::spsc_queue> poll_queues_; - /** A set of queues to stop polling in a worker */ + /**< A set of queues to stop polling in a worker */ hshm::spsc_queue> relinquish_queues_; - size_t sleep_us_; /** Time the worker should sleep after a run */ - u32 retries_; /** The number of times to repeat the internal run loop before sleeping */ - bitfield32_t flags_; /** Worker metadata flags */ + size_t sleep_us_; /**< Time the worker should sleep after a run */ + u32 retries_; /**< The number of times to repeat the internal run loop before sleeping */ + bitfield32_t flags_; /**< Worker metadata flags */ std::unordered_map - group_map_; /** Determine if a task can be executed right now */ - hshm::charbuf group_; /** The current group */ - WorkPending flush_; /** Info needed for flushing ops */ - + group_map_; /**< Determine if a task can be executed right now */ + hshm::charbuf group_; /**< The current group */ + WorkPending flush_; /**< Info needed for flushing ops */ + hshm::Timepoint now_; /**< The current timepoint */ + hshm::spsc_queue stacks_; /**< Cache of stacks for tasks */ + int num_stacks_ = 256; /**< Number of stacks */ + int stack_size_ = KILOBYTES(64); public: + /**=============================================================== + * Initialize Worker and Change Utilization + * =============================================================== */ + /** Constructor */ - Worker(u32 id, ABT_xstream &xstream) { + Worker(u32 id, int cpu_id, ABT_xstream &xstream) { poll_queues_.Resize(1024); relinquish_queues_.Resize(1024); id_ = id; sleep_us_ = 0; - EnableContinuousPolling(); retries_ = 1; pid_ = 0; + affinity_ = cpu_id; thread_ = std::make_unique(&Worker::Loop, this); pthread_id_ = thread_->native_handle(); // TODO(llogan): implement reserve for group group_.resize(512); group_.resize(0); + xstream_ = xstream; + stacks_.Resize(num_stacks_); + for (int i = 0; i < 16; ++i) { + stacks_.emplace(malloc(stack_size_)); + } /* int ret = ABT_thread_create_on_xstream(xstream, [](void *args) { ((Worker*)args)->Loop(); }, this, ABT_THREAD_ATTR_NULL, &tl_thread_); @@ -195,13 +214,22 @@ class Worker { group_.resize(0); } - /** - * Tell worker to poll a set of queues - * */ + /** Tell worker to poll a set of queues */ void PollQueues(const std::vector &queues) { poll_queues_.emplace(queues); } + /** Actually poll the queues from within the worker */ + void _PollQueues() { + std::vector work_queue; + while (!poll_queues_.pop(work_queue).IsNull()) { + for (const WorkEntry &entry : work_queue) { + // HILOG(kDebug, "Scheduled queue {} (lane {})", entry.queue_->id_, entry.lane_); + work_queue_.emplace_back(entry); + } + } + } + /** * Tell worker to start relinquishing some of its queues * This function must be called from a single thread (outside of worker) @@ -210,6 +238,17 @@ class Worker { relinquish_queues_.emplace(queues); } + /** Actually relinquish the queues from within the worker */ + void _RelinquishQueues() { + std::vector work_queue; + while (!poll_queues_.pop(work_queue).IsNull()) { + for (auto &entry : work_queue) { + work_queue_.erase(std::find(work_queue_.begin(), + work_queue_.end(), entry)); + } + } + } + /** Check if worker is still stealing queues */ bool IsRelinquishingQueues() { return relinquish_queues_.size() > 0; @@ -232,13 +271,24 @@ class Worker { flags_.UnsetBits(WORKER_CONTINUOUS_POLLING); } + /** Check if continuously polling */ + bool IsContinuousPolling() { + return flags_.Any(WORKER_CONTINUOUS_POLLING); + } + /** Set the CPU affinity of this worker */ void SetCpuAffinity(int cpu_id) { - ProcessAffiner::SetCpuAffinity(pid_, cpu_id); + HILOG(kInfo, "Affining worker {} (pid={}) to {}", id_, pid_, cpu_id); + affinity_ = cpu_id; + ProcessAffiner::SetCpuAffinity(pid_, affinity_); } - /** The work loop */ - void Loop(); + /** Make maximum priority process */ + void MakeDedicated() { + int policy = SCHED_FIFO; + struct sched_param param = { .sched_priority = 1 }; + sched_setscheduler(0, policy, ¶m); + } /** Worker yields for a period of time */ void Yield() { @@ -252,36 +302,234 @@ class Worker { } } - /** Worker merges the set of queues to poll */ - void _PollQueues() { - std::vector work_queue; - while (!poll_queues_.pop(work_queue).IsNull()) { - for (const WorkEntry &entry : work_queue) { - // HILOG(kDebug, "Scheduled queue {} (lane {})", entry.queue_->id_, entry.lane_); - work_queue_.emplace_back(entry); + /**=============================================================== + * Run tasks + * =============================================================== */ + + /** Worker loop iteration */ + void Loop() { + pid_ = GetLinuxTid(); + SetCpuAffinity(affinity_); + if (IsContinuousPolling()) { + MakeDedicated(); + } + WorkOrchestrator *orchestrator = HRUN_WORK_ORCHESTRATOR; + now_.Now(); + while (orchestrator->IsAlive()) { + try { + bool flushing = flush_.flushing_; + Run(flushing); + if (flushing) { + flush_.flushing_ = false; + } + } catch (hshm::Error &e) { + HELOG(kError, "(node {}) Worker {} caught an error: {}", HRUN_CLIENT->node_id_, id_, e.what()); + } catch (std::exception &e) { + HELOG(kError, "(node {}) Worker {} caught an exception: {}", HRUN_CLIENT->node_id_, id_, e.what()); + } catch (...) { + HELOG(kError, "(node {}) Worker {} caught an unknown exception", HRUN_CLIENT->node_id_, id_); + } + if (!IsContinuousPolling()) { + Yield(); } } + Run(true); } - /** Relinquish queues. Called from wihtin Worker */ - void _RelinquishQueues() { - std::vector work_queue; - while (!poll_queues_.pop(work_queue).IsNull()) { - for (auto &entry : work_queue) { - work_queue_.erase(std::find(work_queue_.begin(), - work_queue_.end(), entry)); + /** Run a single iteration over all queues */ + void Run(bool flushing) { + if (poll_queues_.size() > 0) { + _PollQueues(); + } + if (relinquish_queues_.size() > 0) { + _RelinquishQueues(); + } + if (!IsContinuousPolling()) { + now_.Now(); + for (WorkEntry &work_entry : work_queue_) { + work_entry.cur_time_ = now_; + PollGrouped(work_entry, flushing); + } + } else { + for (WorkEntry &work_entry : work_queue_) { + PollGrouped(work_entry, flushing); } } } - /** - * Poll work queue - * - * @return true if work was found, false otherwise - * */ - void Run(); + /** Print all queues */ + void PrintQueues(bool no_long_run = false) { + for (std::unique_ptr &worker : HRUN_WORK_ORCHESTRATOR->workers_) { + for (WorkEntry &work_entry : worker->work_queue_) { + Lane *&lane = work_entry.lane_; + LaneData *entry; + int off = 0; + while (!lane->peek(entry, off).IsNull()) { + Task *task = HRUN_CLIENT->GetMainPointer(entry->p_); + TaskState *exec = HRUN_TASK_REGISTRY->GetTaskState(task->task_state_); + bool is_remote = task->domain_id_.IsRemote(HRUN_RPC->GetNumHosts(), + HRUN_CLIENT->node_id_); + if (no_long_run && task->IsLongRunning()) { + off += 1; + continue; + } + HILOG(kInfo, + "(node {}, worker {}) Task {} state {}, method {}, is remote: {}, long_running: {}", + HRUN_CLIENT->node_id_, + worker->id_, + task->task_node_, + exec->name_, + task->method_, + is_remote, + task->IsLongRunning()); + off += 1; + } + } + } + } + + /** Allocate a stack for a task */ + void* AllocateStack() { + void *stack; + if (!stacks_.pop(stack).IsNull()) { + return stack; + } + return malloc(stack_size_); + } + + /** Free a stack */ + void FreeStack(void *stack) { + if(!stacks_.emplace(stack).IsNull()) { + return; + } + stacks_.Resize(stacks_.size() + num_stacks_); + } + /** Run an iteration over a particular queue */ HSHM_ALWAYS_INLINE + void PollGrouped(WorkEntry &work_entry, bool flushing) { + int off = 0; + Lane *&lane = work_entry.lane_; + Task *task; + LaneData *entry; + while (!lane->peek(entry, off).IsNull()) { + // Get the task message + if (entry->complete_) { + PopTask(lane, off); + continue; + } + task = HRUN_CLIENT->GetMainPointer(entry->p_); + RunContext &rctx = task->ctx_; + rctx.lane_id_ = work_entry.lane_id_; + rctx.flush_ = &flush_; + // Get the task state + TaskState *exec = HRUN_TASK_REGISTRY->GetTaskState(task->task_state_); + rctx.exec_ = exec; + if (!exec) { + bool was_end = HRUN_TASK_REGISTRY->task_states_.find(task->task_state_) == + HRUN_TASK_REGISTRY->task_states_.end(); + HELOG(kWarning, "(node {}) Could not find the task state: {}", + HRUN_CLIENT->node_id_, task->task_state_); + off += 1; + // PrintQueues(); + // entry->complete_ = true; + // EndTask(lane, exec, task, off); + continue; + } + // Get task properties + bool is_remote = task->domain_id_.IsRemote(HRUN_RPC->GetNumHosts(), HRUN_CLIENT->node_id_); +// #define HERMES_REMOTE_DEBUG +#ifdef HERMES_REMOTE_DEBUG + if (task->task_state_ != HRUN_QM_CLIENT->admin_task_state_ && + !task->task_flags_.Any(TASK_REMOTE_DEBUG_MARK) && + task->method_ != TaskMethod::kConstruct && + HRUN_RUNTIME->remote_created_) { + is_remote = true; + } +#endif + bool group_avail = CheckTaskGroup(task, exec, work_entry.lane_id_, task->task_node_, is_remote); + bool should_run = task->ShouldRun(work_entry.cur_time_, flushing); + // Verify tasks + if (flushing && !task->IsFlush()) { + if (task->IsLongRunning()) { + exec->Monitor(MonitorMode::kFlushStat, task, rctx); + } else { + flush_.count_ += 1; + } + } + // Attempt to run the task if it's ready and runnable + if (!task->IsRunDisabled() && group_avail && should_run) { + // Execute or schedule task + if (is_remote) { + auto ids = HRUN_RUNTIME->ResolveDomainId(task->domain_id_); + HRUN_REMOTE_QUEUE->Disperse(task, exec, ids); + task->SetDisableRun(); + } else if (task->IsLaneAll()) { + HRUN_REMOTE_QUEUE->DisperseLocal(task, exec, work_entry.queue_, work_entry.group_); + task->SetDisableRun(); + } else if (task->IsCoroutine()) { + if (!task->IsStarted()) { + rctx.stack_ptr_ = AllocateStack(); + if (rctx.stack_ptr_ == nullptr) { + HELOG(kFatal, "The stack pointer of size {} is NULL", + stack_size_, rctx.stack_ptr_); + } + rctx.jmp_.fctx = bctx::make_fcontext( + (char*)rctx.stack_ptr_ + stack_size_, + stack_size_, &Worker::RunCoroutine); + task->SetStarted(); + } + rctx.jmp_ = bctx::jump_fcontext(rctx.jmp_.fctx, task); + if (!task->IsStarted()) { + rctx.jmp_.fctx = bctx::make_fcontext( + (char*)rctx.stack_ptr_ + stack_size_, + stack_size_, &Worker::RunCoroutine); + task->SetStarted(); + } + } else { + try { + exec->Run(task->method_, task, rctx); + } catch (std::exception &e) { + HELOG(kError, "(node {}) Worker {} caught an exception: {}", HRUN_CLIENT->node_id_, id_, e.what()); + } catch (...) { + HELOG(kError, "(node {}) Worker {} caught an unknown exception", HRUN_CLIENT->node_id_, id_); + + } + task->SetStarted(); + } + task->DidRun(work_entry.cur_time_); + } + // Cleanup on task completion + if (task->IsModuleComplete()) { + entry->complete_ = true; + if (task->IsCoroutine() && !is_remote && !task->IsLaneAll()) { + FreeStack(rctx.stack_ptr_); + } + RemoveTaskGroup(task, exec, work_entry.lane_id_, is_remote); + EndTask(lane, exec, task, off); + } else { + off += 1; + } + } + } + + /** Run a coroutine */ + static void RunCoroutine(bctx::transfer_t t) { + Task *task = reinterpret_cast(t.data); + RunContext &rctx = task->ctx_; + TaskState *&exec = rctx.exec_; + rctx.jmp_ = t; + exec->Run(task->method_, task, rctx); + task->UnsetStarted(); + task->Yield(); + } + + /**=============================================================== + * Task Ordering and Completion + * =============================================================== */ + + /** Check if two tasks can execute concurrently */ + // HSHM_ALWAYS_INLINE bool CheckTaskGroup(Task *task, TaskState *exec, u32 lane_id, TaskNode node, const bool &is_remote) { @@ -295,40 +543,33 @@ class Worker { return true; } -#ifdef DEBUG - // TODO(llogan): remove - std::stringstream ss; - for (int i = 0; i < group_.size(); ++i) { - ss << std::to_string((int)group_[i]); - } -#endif - // Ensure that concurrent requests are not serialized - LocalSerialize srl(group_); + LocalSerialize srl(group_, false); srl << lane_id; auto it = group_map_.find(group_); if (it == group_map_.end()) { node.node_depth_ = 1; group_map_.emplace(group_, node); -// HILOG(kDebug, "(node {}) Increasing depth of group to {} worker={}", -// HRUN_CLIENT->node_id_, node.node_depth_, id_); +// HILOG(kDebug, "(node {}) Increasing depth of group {} to {} (worker={})", +// HRUN_CLIENT->node_id_, std::hash{}(group_), node.node_depth_, id_); return true; } TaskNode &node_cmp = it->second; if (node_cmp.root_ == node.root_) { node_cmp.node_depth_ += 1; -// HILOG(kDebug, "(node {}) Increasing depth of group to {} worker={}", -// HRUN_CLIENT->node_id_, node_cmp.node_depth_, id_); +// HILOG(kDebug, "(node {}) Increasing depth of group {} to {} (worker={})", +// HRUN_CLIENT->node_id_, std::hash{}(group_), node.node_depth_, id_); return true; } return false; } + /** No longer serialize tasks of the same group */ HSHM_ALWAYS_INLINE void RemoveTaskGroup(Task *task, TaskState *exec, u32 lane_id, const bool &is_remote) { - if (is_remote) { + if (is_remote || task->IsLaneAll()) { return; } int ret = exec->GetGroup(task->method_, task, group_); @@ -338,21 +579,14 @@ class Worker { return; } -#ifdef DEBUG - // TODO(llogan): remove - std::stringstream ss; - for (int i = 0; i < group_.size(); ++i) { - ss << std::to_string((int)group_[i]); - } -#endif // Ensure that concurrent requests are not serialized - LocalSerialize srl(group_); + LocalSerialize srl(group_, false); srl << lane_id; TaskNode &node_cmp = group_map_[group_]; if (node_cmp.node_depth_ == 0) { HELOG(kFatal, "(node {}) Group {} depth is already 0 (task_node={} worker={})", - HRUN_CLIENT->node_id_, task->task_node_, id_); + HRUN_CLIENT->node_id_, std::hash{}(group_), task->task_node_, id_); } node_cmp.node_depth_ -= 1; // HILOG(kDebug, "(node {}) Decreasing depth of to {} (task_node={} worker={})", @@ -362,16 +596,18 @@ class Worker { } } + /** Free a task when it is no longer needed */ HSHM_ALWAYS_INLINE void EndTask(Lane *lane, TaskState *exec, Task *task, int &off) { PopTask(lane, off); if (exec && task->IsFireAndForget()) { - HRUN_CLIENT->DelTask(exec, task); + exec->Del(task->method_, task); } else { task->SetComplete(); } } + /** Pop a task if it's the first entry of the queue */ HSHM_ALWAYS_INLINE void PopTask(Lane *lane, int &off) { if (off == 0) { @@ -380,10 +616,6 @@ class Worker { off += 1; } } - - void PollGrouped(WorkEntry &entry); - static void RunCoroutine(bctx::transfer_t t); - static void RunPreemptive(void *data); }; } // namespace hrun diff --git a/hrun/src/CMakeLists.txt b/hrun/src/CMakeLists.txt index c7e819a91..5c9ee288e 100644 --- a/hrun/src/CMakeLists.txt +++ b/hrun/src/CMakeLists.txt @@ -21,11 +21,13 @@ target_link_libraries(hrun_client # Build Hrun Runtime Library #------------------------------------------------------------------------------ add_library(hrun_runtime - worker.cc + work_orchestrator.cc hrun_runtime.cc) add_dependencies(hrun_runtime ${Hermes_CLIENT_DEPS}) target_link_libraries(hrun_runtime thallium ${Hermes_CLIENT_LIBRARIES}) - +if (HERMES_REMOTE_DEBUG) + target_compile_definitions(hrun_runtime PUBLIC -DHERMES_REMOTE_DEBUG) +endif() #------------------------------------------------------------------------------ # Build Hrun Runtime Start Function #------------------------------------------------------------------------------ diff --git a/hrun/src/config_server.cc b/hrun/src/config_server.cc index 5cb7a478c..aa5a6f775 100644 --- a/hrun/src/config_server.cc +++ b/hrun/src/config_server.cc @@ -23,8 +23,14 @@ namespace hrun::config { /** parse work orchestrator info from YAML config */ void ServerConfig::ParseWorkOrchestrator(YAML::Node yaml_conf) { - if (yaml_conf["max_workers"]) { - wo_.max_workers_ = yaml_conf["max_workers"].as(); + if (yaml_conf["max_dworkers"]) { + wo_.max_dworkers_ = yaml_conf["max_dworkers"].as(); + } + if (yaml_conf["max_oworkers"]) { + wo_.max_oworkers_ = yaml_conf["max_oworkers"].as(); + } + if (yaml_conf["owork_per_core"]) { + wo_.owork_per_core_ = yaml_conf["owork_per_core"].as(); } } @@ -33,6 +39,10 @@ void ServerConfig::ParseQueueManager(YAML::Node yaml_conf) { if (yaml_conf["queue_depth"]) { queue_manager_.queue_depth_ = yaml_conf["queue_depth"].as(); } + if (yaml_conf["proc_queue_depth"]) { + queue_manager_.proc_queue_depth_ = + yaml_conf["proc_queue_depth"].as(); + } if (yaml_conf["max_lanes"]) { queue_manager_.max_lanes_ = yaml_conf["max_lanes"].as(); } @@ -43,12 +53,25 @@ void ServerConfig::ParseQueueManager(YAML::Node yaml_conf) { queue_manager_.shm_allocator_ = yaml_conf["shm_allocator"].as(); } if (yaml_conf["shm_name"]) { - queue_manager_.shm_name_ = yaml_conf["shm_name"].as(); + queue_manager_.shm_name_ = + hshm::ConfigParse::ExpandPath(yaml_conf["shm_name"].as()); + queue_manager_.data_shm_name_ = + hshm::ConfigParse::ExpandPath(queue_manager_.shm_name_ + "_data"); + queue_manager_.rdata_shm_name_ = + hshm::ConfigParse::ExpandPath(queue_manager_.shm_name_ + "_rdata"); } if (yaml_conf["shm_size"]) { queue_manager_.shm_size_ = hshm::ConfigParse::ParseSize( yaml_conf["shm_size"].as()); } + if (yaml_conf["data_shm_size"]) { + queue_manager_.data_shm_size_ = hshm::ConfigParse::ParseSize( + yaml_conf["data_shm_size"].as()); + } + if (yaml_conf["rdata_shm_size"]) { + queue_manager_.rdata_shm_size_ = hshm::ConfigParse::ParseSize( + yaml_conf["rdata_shm_size"].as()); + } } /** parse RPC information from YAML config */ diff --git a/hrun/src/hrun_runtime.cc b/hrun/src/hrun_runtime.cc index 6484ff3df..8af7cc93d 100644 --- a/hrun/src/hrun_runtime.cc +++ b/hrun/src/hrun_runtime.cc @@ -13,5 +13,173 @@ #include "hermes_shm/util/singleton.h" #include "hrun/api/hrun_runtime.h" +namespace hrun { + +/** Create the server-side API */ +Runtime* Runtime::Create(std::string server_config_path) { + hshm::ScopedMutex lock(lock_, 1); + if (is_initialized_) { + return this; + } + mode_ = HrunMode::kServer; + is_being_initialized_ = true; + ServerInit(std::move(server_config_path)); + is_initialized_ = true; + is_being_initialized_ = false; + return this; +} + +/** Initialize */ +void Runtime::ServerInit(std::string server_config_path) { + LoadServerConfig(server_config_path); + HILOG(kInfo, "Initializing shared memory") + InitSharedMemory(); + HILOG(kInfo, "Initializing RPC") + rpc_.ServerInit(&server_config_); + HILOG(kInfo, "Initializing thallium") + thallium_.ServerInit(&rpc_); + HILOG(kInfo, "Initializing queues + workers") + header_->node_id_ = rpc_.node_id_; + header_->unique_ = 0; + header_->num_nodes_ = server_config_.rpc_.host_names_.size(); + task_registry_.ServerInit(&server_config_, rpc_.node_id_, header_->unique_); + // Queue manager + client must be initialized before Work Orchestrator + queue_manager_.ServerInit(main_alloc_, + rpc_.node_id_, + &server_config_, + header_->queue_manager_); + HRUN_CLIENT->Create(server_config_path, "", true); + HERMES_THREAD_MODEL->SetThreadModel(hshm::ThreadType::kPthread); + work_orchestrator_.ServerInit(&server_config_, queue_manager_); + hipc::mptr admin_task; + + // Create the admin library + HRUN_CLIENT->MakeTaskStateId(); + admin_task = hipc::make_mptr(); + task_registry_.RegisterTaskLib("hrun_admin"); + task_registry_.CreateTaskState( + "hrun_admin", + "hrun_admin", + HRUN_QM_CLIENT->admin_task_state_, + admin_task.get()); + + // Create the process queue + HRUN_CLIENT->MakeTaskStateId(); + admin_task = hipc::make_mptr(); + task_registry_.RegisterTaskLib("proc_queue"); + task_registry_.CreateTaskState( + "proc_queue", + "proc_queue", + HRUN_QM_CLIENT->process_queue_, + admin_task.get()); + + // Create the work orchestrator queue scheduling library + TaskStateId queue_sched_id = HRUN_CLIENT->MakeTaskStateId(); + admin_task = hipc::make_mptr(); + task_registry_.RegisterTaskLib("worch_queue_round_robin"); + task_registry_.CreateTaskState( + "worch_queue_round_robin", + "worch_queue_round_robin", + queue_sched_id, + admin_task.get()); + + // Create the work orchestrator process scheduling library + TaskStateId proc_sched_id = HRUN_CLIENT->MakeTaskStateId(); + admin_task = hipc::make_mptr(); + task_registry_.RegisterTaskLib("worch_proc_round_robin"); + task_registry_.CreateTaskState( + "worch_proc_round_robin", + "worch_proc_round_robin", + proc_sched_id, + admin_task.get()); + + // Set the work orchestrator queue scheduler + HRUN_ADMIN->SetWorkOrchQueuePolicyRoot(hrun::DomainId::GetLocal(), queue_sched_id); + HRUN_ADMIN->SetWorkOrchProcPolicyRoot(hrun::DomainId::GetLocal(), proc_sched_id); + + // Create the remote queue library + task_registry_.RegisterTaskLib("remote_queue"); + remote_queue_.CreateRoot(DomainId::GetLocal(), "remote_queue", + HRUN_CLIENT->MakeTaskStateId()); + remote_created_ = true; +} + +/** Initialize shared-memory between daemon and client */ +void Runtime::InitSharedMemory() { + // Create shared-memory allocator + config::QueueManagerInfo &qm = server_config_.queue_manager_; + auto mem_mngr = HERMES_MEMORY_MANAGER; + if (qm.shm_size_ == 0) { + qm.shm_size_ = + hipc::MemoryManager::GetDefaultBackendSize(); + } + // Create general allocator + mem_mngr->CreateBackend( + qm.shm_size_, + qm.shm_name_); + main_alloc_ = + mem_mngr->CreateAllocator( + qm.shm_name_, + main_alloc_id_, + sizeof(HrunShm)); + header_ = main_alloc_->GetCustomHeader(); + // Create separate data allocator + mem_mngr->CreateBackend( + qm.data_shm_size_, + qm.data_shm_name_); + data_alloc_ = + mem_mngr->CreateAllocator( + qm.data_shm_name_, + data_alloc_id_, 0); + // Create separate runtime data allocator + mem_mngr->CreateBackend( + qm.rdata_shm_size_, + qm.rdata_shm_name_); + rdata_alloc_ = + mem_mngr->CreateAllocator( + qm.rdata_shm_name_, + rdata_alloc_id_, 0); +} + +/** Finalize Hermes explicitly */ +void Runtime::Finalize() {} + +/** Run the Hermes core Daemon */ +void Runtime::RunDaemon() { + thallium_.RunDaemon(); + HILOG(kInfo, "Daemon is running") +// while (HRUN_WORK_ORCHESTRATOR->IsRuntimeAlive()) { +// // Scheduler callbacks? +// HERMES_THREAD_MODEL->SleepForUs(1000); +// } + HILOG(kInfo, "Finishing up last requests") + HRUN_WORK_ORCHESTRATOR->Join(); + HILOG(kInfo, "Daemon is exiting") +} + +/** Stop the Hermes core Daemon */ +void Runtime::StopDaemon() { + HRUN_WORK_ORCHESTRATOR->FinalizeRuntime(); +} + +/** Get the set of DomainIds */ +std::vector +Runtime::ResolveDomainId(const DomainId &domain_id) { + std::vector ids; + if (domain_id.IsGlobal()) { + ids.reserve(rpc_.hosts_.size()); + for (HostInfo &host_info : rpc_.hosts_) { + ids.push_back(DomainId::GetNode(host_info.node_id_)); + } + } else if (domain_id.IsNode()) { + ids.reserve(1); + ids.push_back(domain_id); + } + // TODO(llogan): handle named domain ID sets + return ids; +} + +} // namespace hrun + /** Runtime singleton */ DEFINE_SINGLETON_CC(hrun::Runtime) \ No newline at end of file diff --git a/hrun/src/hrun_stop_runtime.cc b/hrun/src/hrun_stop_runtime.cc index 079533cab..f5cb33d02 100644 --- a/hrun/src/hrun_stop_runtime.cc +++ b/hrun/src/hrun_stop_runtime.cc @@ -14,5 +14,5 @@ int main() { TRANSPARENT_HRUN(); - HRUN_ADMIN->AsyncStopRuntimeRoot(hrun::DomainId::GetLocal()); + HRUN_ADMIN->StopRuntimeRoot(hrun::DomainId::GetLocal()); } \ No newline at end of file diff --git a/hrun/src/work_orchestrator.cc b/hrun/src/work_orchestrator.cc new file mode 100644 index 000000000..60764b184 --- /dev/null +++ b/hrun/src/work_orchestrator.cc @@ -0,0 +1,140 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "hrun/work_orchestrator/work_orchestrator.h" +#include "hrun/work_orchestrator/worker.h" + +namespace hrun { + +void WorkOrchestrator::ServerInit(ServerConfig *config, QueueManager &qm) { + config_ = config; + + // Initialize argobots + ABT_init(0, nullptr); + + // Create argobots xstream + int ret = ABT_xstream_create(ABT_SCHED_NULL, &xstream_); + if (ret != ABT_SUCCESS) { + HELOG(kFatal, "Could not create argobots xstream"); + } + + // Spawn workers on the stream + size_t num_workers = config_->wo_.max_dworkers_ + config->wo_.max_oworkers_ + 1; + workers_.reserve(num_workers); + int worker_id = 0; + // Spawn admin worker + workers_.emplace_back(std::make_unique(worker_id, 0, xstream_)); + admin_worker_ = workers_.back().get(); + ++worker_id; + // Spawn dedicated workers (dworkers) + u32 num_dworkers = config_->wo_.max_dworkers_; + for (; worker_id < num_dworkers; ++worker_id) { + int cpu_id = worker_id; + workers_.emplace_back(std::make_unique(worker_id, cpu_id, xstream_)); + Worker &worker = *workers_.back(); + worker.EnableContinuousPolling(); + dworkers_.emplace_back(&worker); + } + // Spawn overlapped workers (oworkers) + for (; worker_id < num_workers; ++worker_id) { + int cpu_id = (int)(num_dworkers + (worker_id - num_dworkers) / config->wo_.owork_per_core_); + workers_.emplace_back(std::make_unique(worker_id, cpu_id, xstream_)); + Worker &worker = *workers_.back(); + worker.DisableContinuousPolling(); + oworkers_.emplace_back(&worker); + } + stop_runtime_ = false; + kill_requested_ = false; + + // Wait for pids to become non-zero + while (true) { + bool all_pids_nonzero = true; + for (std::unique_ptr &worker : workers_) { + if (worker->pid_ == 0) { + all_pids_nonzero = false; + break; + } + } + if (all_pids_nonzero) { + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + + // Schedule admin queue on first overlapping worker + MultiQueue *admin_queue = qm.GetQueue(qm.admin_queue_); + LaneGroup *admin_group = &admin_queue->GetGroup(0); + for (u32 lane_id = 0; lane_id < admin_group->num_lanes_; ++lane_id) { + admin_worker_->PollQueues({WorkEntry(0, lane_id, admin_queue)}); + } + admin_group->num_scheduled_ = admin_group->num_lanes_; + + // Dedicate CPU cores to this runtime + DedicateCores(); + + HILOG(kInfo, "Started {} workers", num_workers); +} + +void WorkOrchestrator::Join() { + kill_requested_.store(true); + for (std::unique_ptr &worker : workers_) { + worker->thread_->join(); + ABT_xstream_join(xstream_); + ABT_xstream_free(&xstream_); + } +} + +/** Get worker with this id */ +Worker& WorkOrchestrator::GetWorker(u32 worker_id) { + return *workers_[worker_id]; +} + +/** Get the number of workers */ +size_t WorkOrchestrator::GetNumWorkers() { + return workers_.size(); +} + +/** Get all PIDs of active workers */ +std::vector WorkOrchestrator::GetWorkerPids() { + std::vector pids; + pids.reserve(workers_.size()); + for (std::unique_ptr &worker : workers_) { + pids.push_back(worker->pid_); + } + return pids; +} + +/** Get the complement of worker cores */ +std::vector WorkOrchestrator::GetWorkerCoresComplement() { + std::vector cores; + cores.reserve(HERMES_SYSTEM_INFO->ncpu_); + for (int i = 0; i < HERMES_SYSTEM_INFO->ncpu_; ++i) { + cores.push_back(i); + } + for (std::unique_ptr &worker : workers_) { + cores.erase(std::remove(cores.begin(), cores.end(), worker->affinity_), cores.end()); + } + return cores; +} + +/** Dedicate cores */ +void WorkOrchestrator::DedicateCores() { + ProcessAffiner affiner; + std::vector worker_pids = GetWorkerPids(); + std::vector cpu_ids = GetWorkerCoresComplement(); + affiner.IgnorePids(worker_pids); + affiner.SetCpus(cpu_ids); + int count = affiner.AffineAll(); + // HILOG(kInfo, "Affining {} processes to {} cores", count, cpu_ids.size()); +} + +} // namespace hrun diff --git a/hrun/src/worker.cc b/hrun/src/worker.cc deleted file mode 100644 index 1d3a63224..000000000 --- a/hrun/src/worker.cc +++ /dev/null @@ -1,203 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "hrun/api/hrun_runtime.h" -#include "hrun/work_orchestrator/worker.h" -#include "hrun/work_orchestrator/work_orchestrator.h" - -namespace hrun { - -void Worker::Loop() { - pid_ = GetLinuxTid(); - WorkOrchestrator *orchestrator = HRUN_WORK_ORCHESTRATOR; - while (orchestrator->IsAlive()) { - try { - flush_.pending_ = 0; - Run(); - if (flush_.flushing_ && flush_.pending_ == 0) { - flush_.flushing_ = false; - } - } catch (hshm::Error &e) { - HELOG(kFatal, "(node {}) Worker {} caught an error: {}", HRUN_CLIENT->node_id_, id_, e.what()); - } - // Yield(); - } - Run(); -} - -void Worker::Run() { - if (poll_queues_.size() > 0) { - _PollQueues(); - } - if (relinquish_queues_.size() > 0) { - _RelinquishQueues(); - } - hshm::Timepoint now; - now.Now(); - for (WorkEntry &work_entry : work_queue_) { -// if (!work_entry.lane_->flags_.Any(QUEUE_LOW_LATENCY)) { -// work_entry.count_ += 1; -// if (work_entry.count_ % 4096 != 0) { -// continue; -// } -// } - work_entry.cur_time_ = now; - PollGrouped(work_entry); - } -} - -void Worker::PollGrouped(WorkEntry &work_entry) { - int off = 0; - Lane *&lane = work_entry.lane_; - Task *task; - LaneData *entry; - for (int i = 0; i < 1024; ++i) { - // Get the task message - if (lane->peek(entry, off).IsNull()) { - return; - } - if (entry->complete_) { - PopTask(lane, off); - continue; - } - task = HRUN_CLIENT->GetPrivatePointer(entry->p_); - RunContext &rctx = task->ctx_; - rctx.lane_id_ = work_entry.lane_id_; - rctx.flush_ = &flush_; - // Get the task state - TaskState *exec = HRUN_TASK_REGISTRY->GetTaskState(task->task_state_); - rctx.exec_ = exec; - if (!exec) { - for (std::pair entries : HRUN_TASK_REGISTRY->task_state_ids_) { - HILOG(kInfo, "Task state: {} id: {} ptr: {} equal: {}", - entries.first, entries.second, - (size_t)HRUN_TASK_REGISTRY->task_states_[entries.second], - entries.second == task->task_state_); - } - bool was_end = HRUN_TASK_REGISTRY->task_states_.find(task->task_state_) == - HRUN_TASK_REGISTRY->task_states_.end(); - HILOG(kInfo, "Was end: {}", was_end); - HELOG(kFatal, "(node {}) Could not find the task state: {}", - HRUN_CLIENT->node_id_, task->task_state_); - entry->complete_ = true; - EndTask(lane, exec, task, off); - continue; - } - // Attempt to run the task if it's ready and runnable - bool is_remote = task->domain_id_.IsRemote(HRUN_RPC->GetNumHosts(), HRUN_CLIENT->node_id_); - if (!task->IsRunDisabled() && - CheckTaskGroup(task, exec, work_entry.lane_id_, task->task_node_, is_remote) && - task->ShouldRun(work_entry.cur_time_, flush_.flushing_)) { -#ifdef REMOTE_DEBUG - if (task->task_state_ != HRUN_QM_CLIENT->admin_task_state_ && - !task->task_flags_.Any(TASK_REMOTE_DEBUG_MARK) && - task->method_ != TaskMethod::kConstruct && - HRUN_RUNTIME->remote_created_) { - is_remote = true; - } - task->task_flags_.SetBits(TASK_REMOTE_DEBUG_MARK); -#endif - // Execute or schedule task - if (is_remote) { - auto ids = HRUN_RUNTIME->ResolveDomainId(task->domain_id_); - HRUN_REMOTE_QUEUE->Disperse(task, exec, ids); - task->SetDisableRun(); - task->SetUnordered(); - task->UnsetCoroutine(); - } else if (task->IsLaneAll()) { - HRUN_REMOTE_QUEUE->DisperseLocal(task, exec, work_entry.queue_, work_entry.group_); - task->SetDisableRun(); - task->SetUnordered(); - task->UnsetCoroutine(); - task->UnsetLaneAll(); - } else if (task->IsCoroutine()) { - if (!task->IsStarted()) { - rctx.stack_ptr_ = malloc(rctx.stack_size_); - if (rctx.stack_ptr_ == nullptr) { - HILOG(kFatal, "The stack pointer of size {} is NULL", - rctx.stack_size_, rctx.stack_ptr_); - } - rctx.jmp_.fctx = bctx::make_fcontext( - (char*)rctx.stack_ptr_ + rctx.stack_size_, - rctx.stack_size_, &RunCoroutine); - task->SetStarted(); - } - rctx.jmp_ = bctx::jump_fcontext(rctx.jmp_.fctx, task); - if (!task->IsStarted()) { - rctx.jmp_.fctx = bctx::make_fcontext( - (char*)rctx.stack_ptr_ + rctx.stack_size_, - rctx.stack_size_, &RunCoroutine); - task->SetStarted(); - } - } else if (task->IsPreemptive()) { - task->SetDisableRun(); - entry->thread_ = HRUN_WORK_ORCHESTRATOR->SpawnAsyncThread(&Worker::RunPreemptive, task); - } else { - task->SetStarted(); - exec->Run(task->method_, task, rctx); - } - task->DidRun(work_entry.cur_time_); - if (!task->IsModuleComplete() && !task->IsFlush()) { - flush_.pending_ += 1; - } - } - // Cleanup on task completion - if (task->IsModuleComplete()) { -// HILOG(kDebug, "(node {}) Ending task: task_node={} task_state={} lane={} queue={} worker={}", -// HRUN_CLIENT->node_id_, task->task_node_, task->task_state_, lane_id, queue->id_, id_); - entry->complete_ = true; - if (task->IsCoroutine()) { - free(rctx.stack_ptr_); - } else if (task->IsPreemptive()) { - ABT_thread_join(entry->thread_); - } - RemoveTaskGroup(task, exec, work_entry.lane_id_, is_remote); - EndTask(lane, exec, task, off); - } else { - off += 1; - } - } -} - -void Worker::RunCoroutine(bctx::transfer_t t) { - Task *task = reinterpret_cast(t.data); - RunContext &rctx = task->ctx_; - TaskState *&exec = rctx.exec_; - rctx.jmp_ = t; - exec->Run(task->method_, task, rctx); - task->UnsetStarted(); - if (task->IsLongRunning()) { - rctx.flush_->pending_ -= 1; - } - task->Yield(); -} - -void Worker::RunPreemptive(void *data) { - Task *task = reinterpret_cast(data); - TaskState *exec = HRUN_TASK_REGISTRY->GetTaskState(task->task_state_); - RunContext &real_rctx = task->ctx_; - RunContext rctx(0); - do { - hshm::Timepoint now; - now.Now(); - if (task->ShouldRun(now, real_rctx.flush_->flushing_)) { - exec->Run(task->method_, task, rctx); - task->DidRun(now); - } - if (task->IsLongRunning()) { - real_rctx.flush_->pending_ -= 1; - } - task->Yield(); - } while(!task->IsModuleComplete()); -} - -} // namespace hrun \ No newline at end of file diff --git a/hrun/tasks_required/TASK_NAME/include/TASK_NAME/TASK_NAME.h b/hrun/tasks_required/TASK_NAME/include/TASK_NAME/TASK_NAME.h index e2f541956..0db31c06e 100644 --- a/hrun/tasks_required/TASK_NAME/include/TASK_NAME/TASK_NAME.h +++ b/hrun/tasks_required/TASK_NAME/include/TASK_NAME/TASK_NAME.h @@ -34,11 +34,7 @@ class Client : public TaskLibClient { const std::string &state_name) { id_ = TaskStateId::GetNull(); QueueManagerInfo &qm = HRUN_CLIENT->server_config_.queue_manager_; - std::vector queue_info = { - {1, 1, qm.queue_depth_, 0}, - {1, 1, qm.queue_depth_, QUEUE_LONG_RUNNING}, - {qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY} - }; + std::vector queue_info; return HRUN_ADMIN->AsyncCreateTaskState( task_node, domain_id, state_name, id_, queue_info); } @@ -49,8 +45,7 @@ class Client : public TaskLibClient { LPointer task = AsyncCreateRoot(std::forward(args)...); task->Wait(); - id_ = task->id_; - queue_id_ = QueueId(id_); + Init(id_, HRUN_ADMIN->queue_id_); HRUN_CLIENT->DelTask(task); } diff --git a/hrun/tasks_required/TASK_NAME/include/TASK_NAME/TASK_NAME_lib_exec.h b/hrun/tasks_required/TASK_NAME/include/TASK_NAME/TASK_NAME_lib_exec.h index 0f75fae53..1c36daccd 100644 --- a/hrun/tasks_required/TASK_NAME/include/TASK_NAME/TASK_NAME_lib_exec.h +++ b/hrun/tasks_required/TASK_NAME/include/TASK_NAME/TASK_NAME_lib_exec.h @@ -18,19 +18,36 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kConstruct: { + MonitorConstruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestruct: { + MonitorDestruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kCustom: { + MonitorCustom(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kConstruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kCustom: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } diff --git a/hrun/tasks_required/TASK_NAME/src/TASK_NAME.cc b/hrun/tasks_required/TASK_NAME/src/TASK_NAME.cc index 43c5aec9f..d7ec8f891 100644 --- a/hrun/tasks_required/TASK_NAME/src/TASK_NAME.cc +++ b/hrun/tasks_required/TASK_NAME/src/TASK_NAME.cc @@ -20,18 +20,26 @@ class Server : public TaskLib { public: Server() = default; + /** Construct TASK_NAME */ void Construct(ConstructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } + /** Destroy TASK_NAME */ void Destruct(DestructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } + /** A custom method */ void Custom(CustomTask *task, RunContext &rctx) { task->SetModuleComplete(); } - + void MonitorCustom(u32 mode, CustomTask *task, RunContext &rctx) { + } public: #include "TASK_NAME/TASK_NAME_lib_exec.h" }; diff --git a/hrun/tasks_required/hrun_admin/include/hrun_admin/hrun_admin.h b/hrun/tasks_required/hrun_admin/include/hrun_admin/hrun_admin.h index 0762ba70f..5af7801de 100644 --- a/hrun/tasks_required/hrun_admin/include/hrun_admin/hrun_admin.h +++ b/hrun/tasks_required/hrun_admin/include/hrun_admin/hrun_admin.h @@ -177,6 +177,10 @@ class Client : public TaskLibClient { task, task_node, domain_id); } HRUN_TASK_NODE_ADMIN_ROOT(StopRuntime); + void StopRuntimeRoot(const DomainId &domain_id) { + FlushRoot(domain_id); + AsyncStopRuntimeRoot(domain_id); + } /** Set work orchestrator queue policy */ void AsyncSetWorkOrchQueuePolicyConstruct(SetWorkOrchQueuePolicyTask *task, diff --git a/hrun/tasks_required/hrun_admin/include/hrun_admin/hrun_admin_lib_exec.h b/hrun/tasks_required/hrun_admin/include/hrun_admin/hrun_admin_lib_exec.h index 22f34312c..d456cd369 100644 --- a/hrun/tasks_required/hrun_admin/include/hrun_admin/hrun_admin_lib_exec.h +++ b/hrun/tasks_required/hrun_admin/include/hrun_admin/hrun_admin_lib_exec.h @@ -46,47 +46,92 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kCreateTaskState: { + MonitorCreateTaskState(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestroyTaskState: { + MonitorDestroyTaskState(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kRegisterTaskLib: { + MonitorRegisterTaskLib(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestroyTaskLib: { + MonitorDestroyTaskLib(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetOrCreateTaskStateId: { + MonitorGetOrCreateTaskStateId(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetTaskStateId: { + MonitorGetTaskStateId(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kStopRuntime: { + MonitorStopRuntime(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kSetWorkOrchQueuePolicy: { + MonitorSetWorkOrchQueuePolicy(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kSetWorkOrchProcPolicy: { + MonitorSetWorkOrchProcPolicy(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kFlush: { + MonitorFlush(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kCreateTaskState: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestroyTaskState: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kRegisterTaskLib: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestroyTaskLib: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetOrCreateTaskStateId: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetTaskStateId: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kStopRuntime: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kSetWorkOrchQueuePolicy: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kSetWorkOrchProcPolicy: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kFlush: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } diff --git a/hrun/tasks_required/hrun_admin/include/hrun_admin/hrun_admin_tasks.h b/hrun/tasks_required/hrun_admin/include/hrun_admin/hrun_admin_tasks.h index 4dd5e24ab..48e208849 100644 --- a/hrun/tasks_required/hrun_admin/include/hrun_admin/hrun_admin_tasks.h +++ b/hrun/tasks_required/hrun_admin/include/hrun_admin/hrun_admin_tasks.h @@ -464,7 +464,9 @@ struct FlushTask : public Task, TaskFlags { /** Create group */ HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { - return TASK_UNORDERED; + hrun::LocalSerialize srl(group); + srl << task_state_; + return 0; } }; diff --git a/hrun/tasks_required/hrun_admin/src/hrun_admin.cc b/hrun/tasks_required/hrun_admin/src/hrun_admin.cc index 6d28bcccb..dc10f74ce 100644 --- a/hrun/tasks_required/hrun_admin/src/hrun_admin.cc +++ b/hrun/tasks_required/hrun_admin/src/hrun_admin.cc @@ -24,24 +24,34 @@ class Server : public TaskLib { public: Server() : queue_sched_(nullptr), proc_sched_(nullptr) {} + /** Register a task library dynamically */ void RegisterTaskLib(RegisterTaskLibTask *task, RunContext &rctx) { std::string lib_name = task->lib_name_->str(); HRUN_TASK_REGISTRY->RegisterTaskLib(lib_name); task->SetModuleComplete(); } + void MonitorRegisterTaskLib(u32 mode, RegisterTaskLibTask *task, RunContext &rctx) { + } + /** Destroy a task library */ void DestroyTaskLib(DestroyTaskLibTask *task, RunContext &rctx) { std::string lib_name = task->lib_name_->str(); HRUN_TASK_REGISTRY->DestroyTaskLib(lib_name); task->SetModuleComplete(); } + void MonitorDestroyTaskLib(u32 mode, DestroyTaskLibTask *task, RunContext &rctx) { + } + /** Get a task state ID if it exists, and create otherwise */ void GetOrCreateTaskStateId(GetOrCreateTaskStateIdTask *task, RunContext &rctx) { std::string state_name = task->state_name_->str(); task->id_ = HRUN_TASK_REGISTRY->GetOrCreateTaskStateId(state_name); task->SetModuleComplete(); } + void MonitorGetOrCreateTaskStateId(u32 mode, GetOrCreateTaskStateIdTask *task, RunContext &rctx) { + } + /** Create a task state */ void CreateTaskState(CreateTaskStateTask *task, RunContext &rctx) { std::string lib_name = task->lib_name_->str(); std::string state_name = task->state_name_->str(); @@ -78,9 +88,9 @@ class Server : public TaskLib { return; } // Create the task queue for the state - QueueId qid(task->id_); - MultiQueue *queue = HRUN_QM_RUNTIME->CreateQueue( - qid, task->queue_info_->vec()); + // QueueId qid(task->id_); + // MultiQueue *queue = HRUN_QM_RUNTIME->CreateQueue( + // qid, task->queue_info_->vec()); // Allocate the task state task->method_ = Method::kConstruct; HRUN_TASK_REGISTRY->CreateTaskState( @@ -88,28 +98,41 @@ class Server : public TaskLib { state_name.c_str(), task->id_, task); - queue->flags_.SetBits(QUEUE_READY); + // queue->flags_.SetBits(QUEUE_READY); + task->method_ = Method::kCreateTaskState; task->SetModuleComplete(); } + void MonitorCreateTaskState(u32 mode, CreateTaskStateTask *task, RunContext &rctx) { + } + /** Get task state id, fail if DNE */ void GetTaskStateId(GetTaskStateIdTask *task, RunContext &rctx) { std::string state_name = task->state_name_->str(); task->id_ = HRUN_TASK_REGISTRY->GetTaskStateId(state_name); task->SetModuleComplete(); } + void MonitorGetTaskStateId(u32 mode, GetTaskStateIdTask *task, RunContext &rctx) { + } + /** Destroy a task state */ void DestroyTaskState(DestroyTaskStateTask *task, RunContext &rctx) { HRUN_TASK_REGISTRY->DestroyTaskState(task->id_); task->SetModuleComplete(); } + void MonitorDestroyTaskState(u32 mode, DestroyTaskStateTask *task, RunContext &rctx) { + } + /** Stop this runtime */ void StopRuntime(StopRuntimeTask *task, RunContext &rctx) { HILOG(kInfo, "Stopping (server mode)"); HRUN_WORK_ORCHESTRATOR->FinalizeRuntime(); HRUN_THALLIUM->StopThisDaemon(); task->SetModuleComplete(); } + void MonitorStopRuntime(u32 mode, StopRuntimeTask *task, RunContext &rctx) { + } + /** Set work orchestrator policy */ void SetWorkOrchQueuePolicy(SetWorkOrchQueuePolicyTask *task, RunContext &rctx) { if (queue_sched_) { queue_sched_->SetModuleComplete(); @@ -124,7 +147,10 @@ class Server : public TaskLib { queue->Emplace(0, 0, queue_sched.shm_); task->SetModuleComplete(); } + void MonitorSetWorkOrchQueuePolicy(u32 mode, SetWorkOrchQueuePolicyTask *task, RunContext &rctx) { + } + /** Set work orchestration policy */ void SetWorkOrchProcPolicy(SetWorkOrchProcPolicyTask *task, RunContext &rctx) { if (proc_sched_) { proc_sched_->SetModuleComplete(); @@ -139,29 +165,35 @@ class Server : public TaskLib { queue->Emplace(0, 0, proc_sched.shm_); task->SetModuleComplete(); } + void MonitorSetWorkOrchProcPolicy(u32 mode, SetWorkOrchProcPolicyTask *task, RunContext &rctx) { + } + /** Flush the runtime */ void Flush(FlushTask *task, RunContext &rctx) { HILOG(kDebug, "Beginning to flush runtime"); - for (Worker &worker : HRUN_WORK_ORCHESTRATOR->workers_) { - worker.flush_.flushing_ = true; - } while (true) { + // Make all workers flush locally int count = 0; - for (Worker &worker : HRUN_WORK_ORCHESTRATOR->workers_) { - if (worker.flush_.flushing_) { - count += 1; - break; + for (int i = 0; i < 2; ++i) { + for (std::unique_ptr + &worker : HRUN_WORK_ORCHESTRATOR->workers_) { + worker->flush_.count_ = 0; + worker->flush_.flushing_ = true; + while (worker->flush_.flushing_) { + task->Yield(); + } + count += worker->flush_.count_; } } - if (count) { - task->Yield(); - } else { + if (!count) { break; } } HILOG(kDebug, "Flushing completed"); task->SetModuleComplete(); } + void MonitorFlush(u32 mode, FlushTask *task, RunContext &rctx) { + } public: #include "hrun_admin/hrun_admin_lib_exec.h" diff --git a/hrun/tasks_required/proc_queue/include/proc_queue/proc_queue.h b/hrun/tasks_required/proc_queue/include/proc_queue/proc_queue.h index 1db95bc66..c7e049ba7 100644 --- a/hrun/tasks_required/proc_queue/include/proc_queue/proc_queue.h +++ b/hrun/tasks_required/proc_queue/include/proc_queue/proc_queue.h @@ -36,11 +36,7 @@ class Client : public TaskLibClient { const std::string &state_name) { id_ = TaskStateId::GetNull(); QueueManagerInfo &qm = HRUN_CLIENT->server_config_.queue_manager_; - std::vector queue_info = { - {1, 1, qm.queue_depth_, 0}, - {1, 1, qm.queue_depth_, QUEUE_LONG_RUNNING}, - {qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY} - }; + std::vector queue_info; return HRUN_ADMIN->AsyncCreateTaskState( task_node, domain_id, state_name, id_, queue_info); } @@ -51,8 +47,7 @@ class Client : public TaskLibClient { LPointer task = AsyncCreateRoot(std::forward(args)...); task->Wait(); - id_ = task->id_; - queue_id_ = QueueId(id_); + Init(id_, HRUN_ADMIN->queue_id_); HRUN_CLIENT->DelTask(task); } diff --git a/hrun/tasks_required/proc_queue/include/proc_queue/proc_queue_lib_exec.h b/hrun/tasks_required/proc_queue/include/proc_queue/proc_queue_lib_exec.h index 7033c12e5..22ec8470f 100644 --- a/hrun/tasks_required/proc_queue/include/proc_queue/proc_queue_lib_exec.h +++ b/hrun/tasks_required/proc_queue/include/proc_queue/proc_queue_lib_exec.h @@ -18,19 +18,36 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kConstruct: { + MonitorConstruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestruct: { + MonitorDestruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kPush: { + MonitorPush(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kConstruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kPush: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } diff --git a/hrun/tasks_required/proc_queue/include/proc_queue/proc_queue_tasks.h b/hrun/tasks_required/proc_queue/include/proc_queue/proc_queue_tasks.h index 94a8406a8..2c8270b1d 100644 --- a/hrun/tasks_required/proc_queue/include/proc_queue/proc_queue_tasks.h +++ b/hrun/tasks_required/proc_queue/include/proc_queue/proc_queue_tasks.h @@ -81,6 +81,9 @@ class PushTaskPhase { TASK_METHOD_T kWaitSchedule = 1; }; +#define HERMES_PT_IS_FIRE_FORGET BIT_OPT(u32, 0) +#define HERMES_PT_MARKED BIT_OPT(u32, 1) + /** * Push a task into the per-process queue * */ @@ -89,6 +92,7 @@ struct TypedPushTask : public Task, TaskFlags { IN LPointer sub_cli_; /**< Pointer to the subtask (client + SHM) */ TEMP LPointer sub_run_; /**< Pointer to the subtask (runtime) */ TEMP int phase_ = PushTaskPhase::kSchedule; + TEMP bool is_fire_forget_ = false; /** SHM default constructor */ HSHM_ALWAYS_INLINE explicit @@ -105,11 +109,19 @@ struct TypedPushTask : public Task, TaskFlags { hshm::NodeThreadId tid; task_node_ = task_node; lane_hash_ = tid.bits_.tid_ + tid.bits_.pid_; - prio_ = TaskPrio::kLowLatency; task_state_ = state_id; method_ = Method::kPush; task_flags_.SetBits(TASK_DATA_OWNER | TASK_LOW_LATENCY | TASK_REMOTE_DEBUG_MARK); domain_id_ = domain_id; + if (subtask->IsFlush()) { + task_flags_.SetBits(TASK_FLUSH); + } + if (subtask->IsLongRunning()) { + task_flags_.SetBits(TASK_LONG_RUNNING); + prio_ = TaskPrio::kLongRunning; + } else { + prio_ = TaskPrio::kLowLatency; + } // Custom params sub_cli_ = subtask; @@ -119,8 +131,6 @@ struct TypedPushTask : public Task, TaskFlags { ~TypedPushTask() { if (!IsFireAndForget()) { HRUN_CLIENT->DelTask(sub_cli_); - } else { - HRUN_CLIENT->DelTask(sub_run_); } } diff --git a/hrun/tasks_required/proc_queue/src/proc_queue.cc b/hrun/tasks_required/proc_queue/src/proc_queue.cc index 95a6c3260..d576e6dc8 100644 --- a/hrun/tasks_required/proc_queue/src/proc_queue.cc +++ b/hrun/tasks_required/proc_queue/src/proc_queue.cc @@ -20,39 +20,58 @@ class Server : public TaskLib { public: Server() = default; + /** Construct proc queue */ void Construct(ConstructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } + /** Destroy proc queue */ void Destruct(DestructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } + /** Push a task onto the process queue */ void Push(PushTask *task, RunContext &rctx) { switch (task->phase_) { case PushTaskPhase::kSchedule: { task->sub_run_.shm_ = task->sub_cli_.shm_; - task->sub_run_.ptr_ = HRUN_CLIENT->GetPrivatePointer(task->sub_cli_.shm_); + task->sub_run_.ptr_ = HRUN_CLIENT->GetMainPointer(task->sub_cli_.shm_); Task *&ptr = task->sub_run_.ptr_; // HILOG(kDebug, "Scheduling task {} on state {} tid {}", // ptr->task_node_, ptr->task_state_, GetLinuxTid()); if (ptr->IsFireAndForget()) { ptr->UnsetFireAndForget(); + task->is_fire_forget_ = true; + } + if (ptr->task_node_.IsRoot() || task->task_node_.IsRoot()) { + ptr->SetRoot(); } MultiQueue *real_queue = HRUN_CLIENT->GetQueue(QueueId(ptr->task_state_)); - real_queue->Emplace(ptr->prio_, ptr->lane_hash_, task->sub_run_.shm_); - task->phase_ = PushTaskPhase::kWaitSchedule; + bool ret = real_queue->EmplaceFrac( + ptr->prio_, ptr->lane_hash_, task->sub_run_.shm_); + if (ret) { + task->phase_ = PushTaskPhase::kWaitSchedule; + } } case PushTaskPhase::kWaitSchedule: { Task *&ptr = task->sub_run_.ptr_; if (!ptr->IsComplete()) { return; } - // TODO(llogan): handle fire & forget tasks gracefully + if (task->is_fire_forget_) { + TaskState *exec = HRUN_TASK_REGISTRY->GetTaskState(ptr->task_state_); + exec->Del(ptr->method_, ptr); + } task->SetModuleComplete(); } } } + void MonitorPush(u32 mode, PushTask *task, RunContext &rctx) { + } public: #include "proc_queue/proc_queue_lib_exec.h" diff --git a/hrun/tasks_required/remote_queue/include/remote_queue/remote_queue.h b/hrun/tasks_required/remote_queue/include/remote_queue/remote_queue.h index 07f4493b7..21dd89ddf 100644 --- a/hrun/tasks_required/remote_queue/include/remote_queue/remote_queue.h +++ b/hrun/tasks_required/remote_queue/include/remote_queue/remote_queue.h @@ -32,12 +32,7 @@ class Client : public TaskLibClient { const TaskStateId &state_id) { id_ = state_id; QueueManagerInfo &qm = HRUN_CLIENT->server_config_.queue_manager_; - std::vector queue_info = { - {1, 1, qm.queue_depth_, 0}, - {1, 1, qm.queue_depth_, QUEUE_LONG_RUNNING}, - // {qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY} - {1, 1, qm.queue_depth_, QUEUE_LOW_LATENCY} - }; + std::vector queue_info; return HRUN_ADMIN->AsyncCreateTaskState( task_node, domain_id, state_name, id_, queue_info); } @@ -48,8 +43,7 @@ class Client : public TaskLibClient { LPointer task = AsyncCreateRoot(std::forward(args)...); task->Wait(); - id_ = task->id_; - queue_id_ = QueueId(id_); + Init(id_, HRUN_ADMIN->queue_id_); HRUN_CLIENT->DelTask(task); } @@ -65,8 +59,7 @@ class Client : public TaskLibClient { TaskState *exec, std::vector &domain_ids) { // Serialize task + create the wait task - HILOG(kDebug, "Beginning dispersion for (task_node={}, task_state={}, method={})", - orig_task->task_node_ + 1, orig_task->task_state_, orig_task->method_) + orig_task->UnsetStarted(); BinaryOutputArchive ar(DomainId::GetNode(HRUN_CLIENT->node_id_)); std::vector xfer = exec->SaveStart(orig_task->method_, ar, orig_task); @@ -76,8 +69,11 @@ class Client : public TaskLibClient { LPointer push_task = HRUN_CLIENT->NewTask( orig_task->task_node_ + 1, DomainId::GetLocal(), id_, domain_ids, orig_task, exec, orig_task->method_, xfer); + if (orig_task->IsRoot()) { + push_task->SetRoot(); + } MultiQueue *queue = HRUN_CLIENT->GetQueue(queue_id_); - queue->Emplace(TaskPrio::kLowLatency, orig_task->lane_hash_, push_task.shm_); + queue->Emplace(push_task->prio_, 0, push_task.shm_); } /** Disperse a task among each lane of this node */ @@ -85,8 +81,6 @@ class Client : public TaskLibClient { void DisperseLocal(Task *orig_task, TaskState *exec, MultiQueue *orig_queue, LaneGroup *lane_group) { // Duplicate task -// HILOG(kDebug, "Beginning duplication for (task_node={}, task_state={}, method={})", -// orig_task->task_node_ + 1, orig_task->task_state_, orig_task->method_); std::vector> dups(lane_group->num_lanes_); exec->Dup(orig_task->method_, orig_task, dups); for (size_t i = 0; i < dups.size(); ++i) { @@ -103,7 +97,7 @@ class Client : public TaskLibClient { orig_task->task_node_ + 1, id_, orig_task, exec, orig_task->method_, dups); MultiQueue *queue = HRUN_CLIENT->GetQueue(queue_id_); - queue->Emplace(TaskPrio::kLowLatency, orig_task->lane_hash_, dup_task.shm_); + queue->Emplace(dup_task->prio_, 0, dup_task.shm_); } /** Spawn task to accept new connections */ diff --git a/hrun/tasks_required/remote_queue/include/remote_queue/remote_queue_lib_exec.h b/hrun/tasks_required/remote_queue/include/remote_queue/remote_queue_lib_exec.h index aa55b5fdb..3ae6cca60 100644 --- a/hrun/tasks_required/remote_queue/include/remote_queue/remote_queue_lib_exec.h +++ b/hrun/tasks_required/remote_queue/include/remote_queue/remote_queue_lib_exec.h @@ -22,23 +22,44 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kConstruct: { + MonitorConstruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestruct: { + MonitorDestruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kPush: { + MonitorPush(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDup: { + MonitorDup(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kConstruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kPush: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDup: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } diff --git a/hrun/tasks_required/remote_queue/include/remote_queue/remote_queue_tasks.h b/hrun/tasks_required/remote_queue/include/remote_queue/remote_queue_tasks.h index 673ce7c88..643fadf43 100644 --- a/hrun/tasks_required/remote_queue/include/remote_queue/remote_queue_tasks.h +++ b/hrun/tasks_required/remote_queue/include/remote_queue/remote_queue_tasks.h @@ -88,7 +88,10 @@ struct PushTask : public Task, TaskFlags { IN TaskState *exec_; IN u32 exec_method_; IN std::vector xfer_; - TEMP std::string params_; + TEMP bool started_ = false; + TEMP void *server_; + TEMP std::atomic rep_; + TEMP u32 num_reps_; /** SHM default constructor */ HSHM_ALWAYS_INLINE explicit @@ -108,11 +111,21 @@ struct PushTask : public Task, TaskFlags { // Initialize task task_node_ = task_node; lane_hash_ = 0; - prio_ = TaskPrio::kLowLatency; task_state_ = state_id; method_ = Method::kPush; - task_flags_.SetBits(TASK_LOW_LATENCY | TASK_PREEMPTIVE | TASK_REMOTE_DEBUG_MARK | TASK_FIRE_AND_FORGET); + // task_flags_.SetBits(TASK_LOW_LATENCY | TASK_PREEMPTIVE | TASK_REMOTE_DEBUG_MARK | TASK_FIRE_AND_FORGET); + // task_flags_.SetBits(TASK_LOW_LATENCY | TASK_COROUTINE | TASK_REMOTE_DEBUG_MARK | TASK_FIRE_AND_FORGET); + task_flags_.SetBits(TASK_LOW_LATENCY | TASK_REMOTE_DEBUG_MARK | TASK_FIRE_AND_FORGET); domain_id_ = domain_id; + if (orig_task->IsFlush()) { + task_flags_.SetBits(TASK_FLUSH); + } + if (orig_task->IsLongRunning()) { + task_flags_.SetBits(TASK_LONG_RUNNING); + prio_ = TaskPrio::kLongRunning; + } else { + prio_ = TaskPrio::kLowLatency; + } // Custom params domain_ids_ = std::move(domain_ids); @@ -125,6 +138,10 @@ struct PushTask : public Task, TaskFlags { /** Create group */ HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { +// hrun::LocalSerialize srl(group); +// srl << task_state_.unique_; +// srl << task_state_.node_id_; +// return 0; return TASK_UNORDERED; } }; @@ -154,11 +171,20 @@ struct DupTask : public Task, TaskFlags { // Initialize task task_node_ = task_node; lane_hash_ = 0; - prio_ = TaskPrio::kLowLatency; + task_state_ = state_id; method_ = Method::kDup; task_flags_.SetBits(TASK_LOW_LATENCY | TASK_REMOTE_DEBUG_MARK | TASK_FIRE_AND_FORGET | TASK_COROUTINE); domain_id_ = DomainId::GetLocal(); + if (orig_task->IsFlush()) { + task_flags_.SetBits(TASK_FLUSH); + } + if (orig_task->IsLongRunning()) { + task_flags_.SetBits(TASK_LONG_RUNNING); + prio_ = TaskPrio::kLongRunning; + } else { + prio_ = TaskPrio::kLowLatency; + } // Custom params orig_task_ = orig_task; diff --git a/hrun/tasks_required/remote_queue/src/remote_queue.cc b/hrun/tasks_required/remote_queue/src/remote_queue.cc index 049783c6d..b9a440f6b 100644 --- a/hrun/tasks_required/remote_queue/src/remote_queue.cc +++ b/hrun/tasks_required/remote_queue/src/remote_queue.cc @@ -23,234 +23,355 @@ SERIALIZE_ENUM(hrun::IoType); namespace hrun::remote_queue { +class Server; + +struct AbtWorkerEntry { + int id_; + Server *server_; + ABT_thread thread_; + PushTask *task_; + RunContext *rctx_; + + AbtWorkerEntry() = default; + + AbtWorkerEntry(int id, Server *server) + : id_(id), server_(server), task_(nullptr), rctx_(nullptr) {} +}; + +struct WaitTask { + u32 method_; + Task *task_; + DomainId ret_domain_; + TaskState *exec_; + size_t task_addr_; + int replica_; + LPointer data_; + bool complete_; +}; + +struct AckTask { + PushTask *task_; + int replica_; + std::string ret_; +}; + class Server : public TaskLib { public: - hrun::remote_queue::Client client_; + hipc::uptr> push_; + hipc::uptr> wait_; + hipc::uptr> ack_; public: Server() = default; /** Construct remote queue */ + void CreateThreads() { + AbtWorkerEntry *entry; + entry = new AbtWorkerEntry(0, this); + entry->thread_ = HRUN_WORK_ORCHESTRATOR->SpawnAsyncThread( + &Server::RunPreemptive, entry); + + entry = new AbtWorkerEntry(1, this); + entry->thread_ = HRUN_WORK_ORCHESTRATOR->SpawnAsyncThread( + &Server::RunWaitPreemptive, entry); + +// entry = new AbtWorkerEntry(2, this); +// entry->thread_ = HRUN_WORK_ORCHESTRATOR->SpawnAsyncThread( +// &Server::RunAckPreemptive, entry); + } void Construct(ConstructTask *task, RunContext &rctx) { HILOG(kInfo, "(node {}) Constructing remote queue (task_node={}, task_state={}, method={})", HRUN_CLIENT->node_id_, task->task_node_, task->task_state_, task->method_); - HRUN_THALLIUM->RegisterRpc("RpcPushSmall", [this](const tl::request &req, - TaskStateId state_id, - u32 method, - std::string ¶ms) { - this->RpcPushSmall(req, state_id, method, params); + size_t max = HRUN_RPC->num_threads_; + push_ = hipc::make_uptr>( + HRUN_CLIENT->server_config_.queue_manager_.queue_depth_); + wait_ = hipc::make_uptr>( + HRUN_CLIENT->server_config_.queue_manager_.queue_depth_); +// ack_ = hipc::make_uptr>( +// HRUN_CLIENT->server_config_.queue_manager_.queue_depth_); + CreateThreads(); + HRUN_THALLIUM->RegisterRpc("RpcPushSmall", [this]( + const tl::request &req, + TaskStateId state_id, + u32 method, + size_t task_addr, + int replica, + const DomainId &domain_id, + std::string ¶ms) { + this->RpcPushSmall(req, state_id, method, + task_addr, replica, domain_id, params); }); - HRUN_THALLIUM->RegisterRpc("RpcPushBulk", [this](const tl::request &req, - const tl::bulk &bulk, - TaskStateId state_id, - u32 method, - std::string ¶ms, - size_t data_size, - IoType io_type) { - this->RpcPushBulk(req, state_id, method, params, bulk, data_size, io_type); + HRUN_THALLIUM->RegisterRpc("RpcPushBulk", [this]( + const tl::request &req, + const tl::bulk &bulk, + TaskStateId state_id, + u32 method, + size_t task_addr, + int replica, + const DomainId &domain_id, + std::string ¶ms, + size_t data_size, + IoType io_type) { + this->RpcPushBulk(req, state_id, method, + task_addr, replica, domain_id, + params, bulk, data_size, io_type); + }); + HRUN_THALLIUM->RegisterRpc("RpcClientHandlePushReplicaOutput", [this]( + const tl::request &req, + size_t task_addr, + int replica, + std::string &ret) { + this->RpcClientHandlePushReplicaOutput(req, task_addr, replica, ret); }); task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } /** Destroy remote queue */ void Destruct(DestructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } - /** Handle output from replica PUSH */ - static void ClientHandlePushReplicaOutput(int replica, std::string &ret, PushTask *task) { - std::vector xfer(1); - xfer[0].data_ = ret.data(); - xfer[0].data_size_ = ret.size(); - HILOG(kDebug, "Wait got {} bytes of data (task_node={}, task_state={}, method={})", - xfer[0].data_size_, - task->orig_task_->task_node_, - task->orig_task_->task_state_, - task->orig_task_->method_); - BinaryInputArchive ar(xfer); - task->exec_->LoadEnd(replica, task->exec_method_, ar, task->orig_task_); + /** Push operation called on client */ + void Push(PushTask *task, RunContext &rctx) { + if (!task->started_) { + task->started_ = true; + task->rep_ = 0; + task->num_reps_ = task->domain_ids_.size(); + HILOG(kDebug, "push task emplaced: task={}, orig_task={}", + (size_t)task, (size_t)task->orig_task_) + push_->emplace(task); + } + if (task->rep_.load() == task->num_reps_) { + ClientHandlePushReplicaEnd(task); + } + // HILOG(kDebug, "Continuing task {}", task->task_node_) + } + void MonitorPush(u32 mode, PushTask *task, RunContext &rctx) { } - /** Handle finalization of PUSH replicate */ - static void ClientHandlePushReplicaEnd(PushTask *task) { - task->exec_->ReplicateEnd(task->orig_task_->method_, task->orig_task_); - HILOG(kDebug, "Completing task (task_node={}, task_state={}, method={})", - task->orig_task_->task_node_, - task->orig_task_->task_state_, - task->orig_task_->method_); - if (!task->orig_task_->IsLongRunning()) { - task->orig_task_->SetModuleComplete(); - } else { - task->orig_task_->UnsetStarted(); - task->orig_task_->UnsetDisableRun(); + /** Duplicate operations */ + void Dup(DupTask *task, RunContext &ctx) { + Task *orig_task = task->orig_task_; + if (!orig_task->IsFireAndForget()) { + for (size_t i = 0; i < task->dups_.size(); ++i) { + LPointer &dup = task->dups_[i]; + dup->Wait(task); + task->exec_->DupEnd(dup->method_, i, task->orig_task_, dup.ptr_); + HRUN_CLIENT->DelTask(task->exec_, dup.ptr_); + } + task->exec_->ReplicateEnd(task->exec_method_, task->orig_task_); + if (!orig_task->IsLongRunning()) { + orig_task->SetModuleComplete(); + } else { + orig_task->UnsetStarted(); + } } task->SetModuleComplete(); } + void MonitorDup(u32 mode, DupTask *task, RunContext &rctx) { + } - /** Push for small message */ - void ClientSmallPush(std::vector &xfer, PushTask *task) { - task->params_ = std::string((char *) xfer[0].data_, xfer[0].data_size_); - for (int replica = 0; replica < task->domain_ids_.size(); ++replica) { - DomainId domain_id = task->domain_ids_[replica]; - HILOG(kDebug, "(SM) Transferring {} bytes of data (task_node={}, task_state={}, method={}, from={}, to={})", - task->params_.size(), - task->orig_task_->task_node_, - task->orig_task_->task_state_, - task->orig_task_->method_, - HRUN_CLIENT->node_id_, - domain_id.id_); - std::string ret = HRUN_THALLIUM->SyncCall(domain_id.id_, - "RpcPushSmall", - task->exec_->id_, - task->exec_method_, - task->params_); - HILOG(kDebug, "(SM) Finished {} bytes of data (task_node={}, task_state={}, method={}, from={}, to={})", - task->params_.size(), - task->orig_task_->task_node_, - task->orig_task_->task_state_, - task->orig_task_->method_, - HRUN_CLIENT->node_id_, - domain_id.id_); - ClientHandlePushReplicaOutput(replica, ret, task); + private: + /** An ABT thread to run a PUSH task */ + static void RunPreemptive(void *data) { + AbtWorkerEntry *entry = (AbtWorkerEntry *) data; + Server *server = entry->server_; + WorkOrchestrator *orchestrator = HRUN_WORK_ORCHESTRATOR; + while (orchestrator->IsAlive()) { + PushTask *task; + while (!server->push_->pop(task).IsNull()) { + HILOG(kDebug, "push task started: task={}, orig_task={}", (size_t)task, (size_t)task->orig_task_) + server->PushPreemptive(task); + } + ABT_thread_yield(); + } + } + + /** PUSH using thallium */ + void PushPreemptive(PushTask *task) { + std::vector xfer = task->xfer_; + std::vector domain_ids = task->domain_ids_; + try { + switch (xfer.size()) { + case 1: { + SyncClientSmallPush(xfer, domain_ids, task); + break; + } + case 2: { + SyncClientIoPush(xfer, domain_ids, task); + break; + } + default: { + HELOG(kFatal, + "The task {}/{} does not support remote calls", + task->task_state_, + task->method_); + } + } + } catch (hshm::Error &e) { + HELOG(kError, "(node {}) Worker {} caught an error: {}", HRUN_CLIENT->node_id_, id_, e.what()); + } catch (std::exception &e) { + HELOG(kError, "(node {}) Worker {} caught an exception: {}", HRUN_CLIENT->node_id_, id_, e.what()); + } catch (...) { + HELOG(kError, "(node {}) Worker {} caught an unknown exception", HRUN_CLIENT->node_id_, id_); + } + } + + /** Sync Push for small message */ + void SyncClientSmallPush(std::vector &xfer, + std::vector &domain_ids, + PushTask *task) { + TaskStateId state_id = task->exec_->id_; + int method = task->exec_method_; + std::string params = std::string((char *) xfer[0].data_, xfer[0].data_size_); + for (int replica = 0; replica < domain_ids.size(); ++replica) { + DomainId my_domain = DomainId::GetNode(HRUN_CLIENT->node_id_); + DomainId domain_id = domain_ids[replica]; + HRUN_THALLIUM->SyncCall(domain_id.id_, + "RpcPushSmall", + state_id, + method, + (size_t) task, + replica, + my_domain, + params); } } - /** Push for I/O message */ - void ClientIoPush(std::vector &xfer, PushTask *task) { - task->params_ = std::string((char *) xfer[1].data_, xfer[1].data_size_); + /** Sync Push for I/O message */ + void SyncClientIoPush(std::vector &xfer, + std::vector &domain_ids, + PushTask *task) { + std::string params = std::string((char *) xfer[1].data_, xfer[1].data_size_); IoType io_type = IoType::kRead; if (xfer[0].flags_.Any(DT_RECEIVER_READ)) { io_type = IoType::kWrite; } - for (int replica = 0; replica < task->domain_ids_.size(); ++replica) { - DomainId domain_id = task->domain_ids_[replica]; + TaskStateId state_id = task->exec_->id_; + int method = task->exec_method_; + for (int replica = 0; replica < domain_ids.size(); ++replica) { + DomainId my_domain = DomainId::GetNode(HRUN_CLIENT->node_id_); + DomainId domain_id = domain_ids[replica]; char *data = (char*)xfer[0].data_; size_t data_size = xfer[0].data_size_; - HILOG(kDebug, "(IO) Transferring {} bytes of data (task_node={}, task_state={}, method={}, from={}, to={}, type={})", - data_size, - task->orig_task_->task_node_, - task->orig_task_->task_state_, - task->orig_task_->method_, - HRUN_CLIENT->node_id_, - domain_id.id_, - static_cast(io_type)); - std::string ret = HRUN_THALLIUM->SyncIoCall(domain_id.id_, - "RpcPushBulk", - io_type, - data, - data_size, - task->exec_->id_, - task->exec_method_, - task->params_, - data_size, - io_type); - HILOG(kDebug, "(IO) Finished transferring {} bytes of data (task_node={}, task_state={}, method={}, from={}, to={}, type={})", - data_size, - task->orig_task_->task_node_, - task->orig_task_->task_state_, - task->orig_task_->method_, - HRUN_CLIENT->node_id_, - domain_id.id_, - static_cast(io_type)); - ClientHandlePushReplicaOutput(replica, ret, task); - } - } - - /** Push operation called on client */ - void Push(PushTask *task, RunContext &rctx) { - std::vector &xfer = task->xfer_; - switch (xfer.size()) { - case 1: { - ClientSmallPush(xfer, task); - break; - } - case 2: { - ClientIoPush(xfer, task); - break; - } - default: { - HELOG(kFatal, "The task {}/{} does not support remote calls", task->task_state_, task->method_); + if (data_size > 0) { + HRUN_THALLIUM->SyncIoCall(domain_id.id_, + "RpcPushBulk", + io_type, + data, + data_size, + state_id, + method, + (size_t) task, + replica, + my_domain, + params, + data_size, + io_type); + } else { + HELOG(kFatal, "(IO) Thallium can't handle 0-sized I/O") } } - ClientHandlePushReplicaEnd(task); + // task->rep_ = task->num_reps_; } - /** Duplicate operations */ - void Dup(DupTask *task, RunContext &ctx) { - for (size_t i = 0; i < task->dups_.size(); ++i) { - LPointer &dup = task->dups_[i]; - dup->Wait(task); - task->exec_->DupEnd(dup->method_, i, task->orig_task_, dup.ptr_); - HRUN_CLIENT->DelTask(dup); - } - task->exec_->ReplicateEnd(task->exec_method_, task->orig_task_); - task->orig_task_->SetModuleComplete(); - task->SetModuleComplete(); - } - - private: /** The RPC for processing a small message */ void RpcPushSmall(const tl::request &req, TaskStateId state_id, u32 method, + size_t task_addr, + int replica, + const DomainId &ret_domain, std::string ¶ms) { + // Create the input data transfer object - std::vector xfer(1); - xfer[0].data_ = params.data(); - xfer[0].data_size_ = params.size(); - HILOG(kDebug, "Received small message of size {} " - "(task_state={}, method={})", xfer[0].data_size_, state_id, method); - - // Process the message - TaskState *exec; - Task *orig_task; - RpcExec(req, state_id, method, params, xfer, orig_task, exec); - RpcComplete(req, method, orig_task, exec, state_id); + try { + std::vector xfer(1); + xfer[0].data_ = params.data(); + xfer[0].data_size_ = params.size(); + HILOG(kDebug, "(node {}) Received small message of size {} " + "(task_state={}, method={})", + HRUN_CLIENT->node_id_, + xfer[0].data_size_, state_id, method); + + // Process the message + TaskState *exec; + Task *orig_task; + LPointer data; + data.ptr_ = nullptr; + RpcExec(req, state_id, method, task_addr, replica, ret_domain, + xfer, data, orig_task, exec); + } catch (hshm::Error &e) { + HELOG(kError, "(node {}) Worker {} caught an error: {}", HRUN_CLIENT->node_id_, id_, e.what()); + } catch (std::exception &e) { + HELOG(kError, "(node {}) Worker {} caught an exception: {}", HRUN_CLIENT->node_id_, id_, e.what()); + } catch (...) { + HELOG(kError, "(node {}) Worker {} caught an unknown exception", HRUN_CLIENT->node_id_, id_); + } + req.respond(0); } /** The RPC for processing a message with data */ void RpcPushBulk(const tl::request &req, TaskStateId state_id, u32 method, + size_t task_addr, + int replica, + const DomainId &ret_domain, std::string ¶ms, const tl::bulk &bulk, size_t data_size, IoType io_type) { - hshm::charbuf data(data_size); + LPointer data; + data.ptr_ = nullptr; + try { + data = HRUN_CLIENT->AllocateBufferServer(data_size); - // Create the input data transfer object - std::vector xfer(2); - xfer[0].data_ = data.data(); - xfer[0].data_size_ = data.size(); - xfer[1].data_ = params.data(); - xfer[1].data_size_ = params.size(); - - HILOG(kDebug, "Received large message of size {} " - "(task_state={}, method={})", xfer[0].data_size_, state_id, method); - - // Process the message - if (io_type == IoType::kWrite) { - HRUN_THALLIUM->IoCallServer(req, bulk, io_type, data.data(), data_size); - HILOG(kDebug, "(node {}) Write blob integer: {}", HRUN_CLIENT->node_id_, (int)data[0]) - } - TaskState *exec; - Task *orig_task; - RpcExec(req, state_id, method, params, xfer, orig_task, exec); - if (io_type == IoType::kRead) { - HILOG(kDebug, "(node {}) Read blob integer: {}", HRUN_CLIENT->node_id_, (int)data[0]) - HRUN_THALLIUM->IoCallServer(req, bulk, io_type, data.data(), data_size); - } + // Create the input data transfer object + std::vector xfer(2); + xfer[0].data_ = data.ptr_; + xfer[0].data_size_ = data_size; + xfer[1].data_ = params.data(); + xfer[1].data_size_ = params.size(); - // Return - RpcComplete(req, method, orig_task, exec, state_id); + HILOG(kDebug, "(node {}) Received large message of size {} " + "(task_state={}, method={})", + HRUN_CLIENT->node_id_, xfer[0].data_size_, state_id, method); + + // Process the message + if (io_type == IoType::kWrite) { + HRUN_THALLIUM->IoCallServer(req, bulk, io_type, data.ptr_, data_size); + } + TaskState *exec; + Task *orig_task; + RpcExec(req, state_id, method, task_addr, replica, ret_domain, + xfer, data, orig_task, exec); + if (io_type == IoType::kRead) { + HRUN_THALLIUM->IoCallServer(req, bulk, io_type, data.ptr_, data_size); + } + } catch (hshm::Error &e) { + HELOG(kError, "(node {}) Worker {} caught an error: {}", HRUN_CLIENT->node_id_, id_, e.what()); + } catch (std::exception &e) { + HELOG(kError, "(node {}) Worker {} caught an exception: {}", HRUN_CLIENT->node_id_, id_, e.what()); + } catch (...) { + HELOG(kError, "(node {}) Worker {} caught an unknown exception", HRUN_CLIENT->node_id_, id_); + } + req.respond(0); } /** Push operation called at the remote server */ void RpcExec(const tl::request &req, const TaskStateId &state_id, u32 method, - std::string ¶ms, + size_t task_addr, + int replica, + const DomainId &ret_domain, std::vector &xfer, + LPointer &data, Task *&orig_task, TaskState *&exec) { size_t data_size = xfer[0].data_size_; BinaryInputArchive ar(xfer); @@ -260,12 +381,7 @@ class Server : public TaskLib { if (exec == nullptr) { HELOG(kFatal, "(node {}) Could not find the task state {}", HRUN_CLIENT->node_id_, state_id); - req.respond(std::string()); return; - } else { - HILOG(kDebug, "(node {}) Found task state {}", - HRUN_CLIENT->node_id_, - state_id); } TaskPointer task_ptr = exec->LoadStart(method, ar); orig_task = task_ptr.ptr_; @@ -279,6 +395,8 @@ class Server : public TaskLib { orig_task->UnsetStarted(); orig_task->UnsetDataOwner(); orig_task->UnsetLongRunning(); + orig_task->UnsetRoot(); + orig_task->task_flags_.SetBits(TASK_REMOTE_DEBUG_MARK); // Execute task MultiQueue *queue = HRUN_CLIENT->GetQueue(QueueId(state_id)); @@ -293,29 +411,162 @@ class Server : public TaskLib { method, data_size, orig_task->lane_hash_); - orig_task->Wait(); + + // Spawn wait event handler for task completion + WaitTask wait_task; + wait_task.method_ = method; + wait_task.ret_domain_ = ret_domain; + wait_task.task_ = orig_task; + wait_task.exec_ = exec; + wait_task.task_addr_ = task_addr; + wait_task.replica_ = replica; + wait_task.data_ = data; + wait_task.complete_ = false; + wait_->emplace(wait_task); + +// HILOG(kDebug, +// "(node {}) Waiting task (task_node={}, task_state={}/{}, state_name={}, method={}, size={}, lane_hash={})", +// HRUN_CLIENT->node_id_, +// orig_task->task_node_, +// orig_task->task_state_, +// state_id, +// exec->name_, +// method, +// data_size, +// orig_task->lane_hash_); + } + + /** An ABT thread to run a WAIT task */ + static void RunWaitPreemptive(void *data) { + AbtWorkerEntry *entry = (AbtWorkerEntry *) data; + Server *server = entry->server_; + WorkOrchestrator *orchestrator = HRUN_WORK_ORCHESTRATOR; + while (orchestrator->IsAlive()) { + WaitTask *wait_task; + int i = 0; + while (!server->wait_->peek(wait_task, i).IsNull()) { + Task *orig_task = wait_task->task_; + if (!wait_task->complete_ && orig_task->IsComplete()) { + server->RpcComplete(wait_task->method_, + orig_task, + wait_task->exec_, + wait_task->task_addr_, + wait_task->replica_, + wait_task->ret_domain_, + wait_task->data_); + wait_task->complete_ = true; + } + if (i == 0 && wait_task->complete_) { + server->wait_->pop(); + continue; + } + ++i; + } + ABT_thread_yield(); + } } - void RpcComplete(const tl::request &req, - u32 method, Task *orig_task, - TaskState *exec, TaskStateId state_id) { + /** Complete a wait task */ + void RpcComplete(u32 method, Task *orig_task, + TaskState *exec, + size_t task_addr, int replica, + const DomainId &ret_domain, + LPointer &data) { + if (data.ptr_ != nullptr) { + HRUN_CLIENT->FreeBuffer(data); + } BinaryOutputArchive ar(DomainId::GetNode(HRUN_CLIENT->node_id_)); std::vector out_xfer = exec->SaveEnd(method, ar, orig_task); - HILOG(kDebug, "(node {}) Returning {} bytes of data (task_node={}, task_state={}/{}, method={})", - HRUN_CLIENT->node_id_, - out_xfer[0].data_size_, - orig_task->task_node_, - orig_task->task_state_, - state_id, - method); - HRUN_CLIENT->DelTask(exec, orig_task); + std::string ret; if (out_xfer.size() > 0 && out_xfer[0].data_size_ > 0) { - req.respond(std::string((char *) out_xfer[0].data_, out_xfer[0].data_size_)); + ret = std::string((char *) out_xfer[0].data_, out_xfer[0].data_size_); + } + HRUN_THALLIUM->SyncCall(ret_domain.id_, + "RpcClientHandlePushReplicaOutput", + task_addr, + replica, + ret); + exec->Del(orig_task->method_, orig_task); + } + + /** Handle return of RpcComplete */ + void RpcClientHandlePushReplicaOutput(const tl::request &req, + size_t task_addr, + int replica, + std::string &ret) { +// AckTask ack_task; +// ack_task.task_ = (PushTask *) task_addr; +// ack_task.replica_ = replica; +// ack_task.ret_ = std::move(ret); +// ack_->emplace(ack_task); +// req.respond(0); + ClientHandlePushReplicaOutput(replica, ret, (PushTask *) task_addr); + req.respond(0); + } + + /** An ABT thread to run a PUSH task */ +// static void RunAckPreemptive(void *data) { +// AbtWorkerEntry *entry = (AbtWorkerEntry *) data; +// Server *server = entry->server_; +// WorkOrchestrator *orchestrator = HRUN_WORK_ORCHESTRATOR; +// while (orchestrator->IsAlive()) { +// AckTask ack_task; +// while (!server->ack_->pop(ack_task).IsNull()) { +// server->ClientHandlePushReplicaOutput( +// ack_task.replica_, ack_task.ret_, ack_task.task_); +// } +// ABT_thread_yield(); +// } +// } + + /** Handle output from replica PUSH */ + void ClientHandlePushReplicaOutput(int replica, + std::string &ret, + PushTask *task) { + try { + std::vector xfer(1); + xfer[0].data_ = ret.data(); + xfer[0].data_size_ = ret.size(); + BinaryInputArchive ar(xfer); + task->exec_->LoadEnd(replica, task->exec_method_, ar, task->orig_task_); + HILOG(kDebug, "Handled replica output for task " + "(task_node={}, task_state={}, method={}, " + "rep={}, num_reps={})", + task->orig_task_->task_node_, + task->orig_task_->task_state_, + task->orig_task_->method_, + task->rep_.load() + 1, + task->num_reps_); + task->rep_ += 1; + } catch (hshm::Error &e) { + HELOG(kError, "(node {}) Caught an error: {}", + HRUN_CLIENT->node_id_, e.what()); + } catch (std::exception &e) { + HELOG(kError, "(node {}) Caught an exception: {}", + HRUN_CLIENT->node_id_, e.what()); + } catch (...) { + HELOG(kError, "(node {}) Caught an unknown exception", + HRUN_CLIENT->node_id_); + } + } + + /** Handle finalization of PUSH replicate */ + void ClientHandlePushReplicaEnd(PushTask *task) { + task->exec_->ReplicateEnd(task->orig_task_->method_, task->orig_task_); + HILOG(kDebug, "Completing task (task_node={}, task_state={}, method={})", + task->orig_task_->task_node_, + task->orig_task_->task_state_, + task->orig_task_->method_); + if (!task->orig_task_->IsLongRunning()) { + task->orig_task_->SetModuleComplete(); } else { - req.respond(std::string()); + task->orig_task_->UnsetStarted(); + task->orig_task_->UnsetDisableRun(); } + task->SetModuleComplete(); } + public: #include "remote_queue/remote_queue_lib_exec.h" }; diff --git a/hrun/tasks_required/small_message/include/small_message/small_message.h b/hrun/tasks_required/small_message/include/small_message/small_message.h index f66d120f2..bd40553b1 100644 --- a/hrun/tasks_required/small_message/include/small_message/small_message.h +++ b/hrun/tasks_required/small_message/include/small_message/small_message.h @@ -25,14 +25,10 @@ class Client : public TaskLibClient { const std::string &state_name) { id_ = TaskStateId::GetNull(); QueueManagerInfo &qm = HRUN_CLIENT->server_config_.queue_manager_; - std::vector queue_info = { - {1, 1, qm.queue_depth_, 0}, - {1, 1, qm.queue_depth_, QUEUE_LONG_RUNNING}, - {qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY} - }; + std::vector queue_info; id_ = HRUN_ADMIN->CreateTaskStateRoot( domain_id, state_name, id_, queue_info); - queue_id_ = QueueId(id_); + Init(id_, HRUN_ADMIN->queue_id_); } /** Destroy state + queue */ diff --git a/hrun/tasks_required/small_message/include/small_message/small_message_lib_exec.h b/hrun/tasks_required/small_message/include/small_message/small_message_lib_exec.h index 692bcd8f5..a8d6b2724 100644 --- a/hrun/tasks_required/small_message/include/small_message/small_message_lib_exec.h +++ b/hrun/tasks_required/small_message/include/small_message/small_message_lib_exec.h @@ -26,27 +26,52 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kConstruct: { + MonitorConstruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestruct: { + MonitorDestruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kMd: { + MonitorMd(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kIo: { + MonitorIo(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kMdPush: { + MonitorMdPush(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kConstruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kMd: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kIo: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kMdPush: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } diff --git a/hrun/tasks_required/small_message/src/small_message.cc b/hrun/tasks_required/small_message/src/small_message.cc index 30d737b28..410e987f2 100644 --- a/hrun/tasks_required/small_message/src/small_message.cc +++ b/hrun/tasks_required/small_message/src/small_message.cc @@ -21,24 +21,37 @@ class Server : public TaskLib { int count_ = 0; public: + /** Construct small_message */ void Construct(ConstructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } + /** Destroy small_message */ void Destruct(DestructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } + /** A metadata operation */ void Md(MdTask *task, RunContext &rctx) { task->ret_[0] = 1; task->SetModuleComplete(); } + void MonitorMd(u32 mode, MdTask *task, RunContext &rctx) { + } + /** A metadata operation + push task */ void MdPush(MdPushTask *task, RunContext &rctx) { task->ret_[0] = 1; task->SetModuleComplete(); } + void MonitorMdPush(u32 mode, MdPushTask *task, RunContext &rctx) { + } + /** An I/O task */ void Io(IoTask *task, RunContext &rctx) { task->ret_ = 1; for (int i = 0; i < 256; ++i) { @@ -49,6 +62,8 @@ class Server : public TaskLib { } task->SetModuleComplete(); } + void MonitorIo(u32 mode, IoTask *task, RunContext &rctx) { + } public: #include "small_message/small_message_lib_exec.h" diff --git a/hrun/tasks_required/worch_proc_round_robin/include/worch_proc_round_robin/worch_proc_round_robin.h b/hrun/tasks_required/worch_proc_round_robin/include/worch_proc_round_robin/worch_proc_round_robin.h index f57feabaa..7dc764877 100644 --- a/hrun/tasks_required/worch_proc_round_robin/include/worch_proc_round_robin/worch_proc_round_robin.h +++ b/hrun/tasks_required/worch_proc_round_robin/include/worch_proc_round_robin/worch_proc_round_robin.h @@ -24,9 +24,7 @@ class Client : public TaskLibClient { void CreateRoot(const DomainId &domain_id, const std::string &state_name) { id_ = TaskStateId::GetNull(); - std::vector queue_info = { - {1, 1, 4, 0}, - }; + std::vector queue_info; id_ = HRUN_ADMIN->CreateTaskStateRoot( domain_id, state_name, id_, queue_info); } diff --git a/hrun/tasks_required/worch_proc_round_robin/include/worch_proc_round_robin/worch_proc_round_robin_lib_exec.h b/hrun/tasks_required/worch_proc_round_robin/include/worch_proc_round_robin/worch_proc_round_robin_lib_exec.h index b859d2bf8..230d25e3b 100644 --- a/hrun/tasks_required/worch_proc_round_robin/include/worch_proc_round_robin/worch_proc_round_robin_lib_exec.h +++ b/hrun/tasks_required/worch_proc_round_robin/include/worch_proc_round_robin/worch_proc_round_robin_lib_exec.h @@ -18,19 +18,36 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kConstruct: { + MonitorConstruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestruct: { + MonitorDestruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kSchedule: { + MonitorSchedule(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kConstruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kSchedule: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } diff --git a/hrun/tasks_required/worch_proc_round_robin/src/worch_proc_round_robin.cc b/hrun/tasks_required/worch_proc_round_robin/src/worch_proc_round_robin.cc index 0c8be3c24..44e8a9e5d 100644 --- a/hrun/tasks_required/worch_proc_round_robin/src/worch_proc_round_robin.cc +++ b/hrun/tasks_required/worch_proc_round_robin/src/worch_proc_round_robin.cc @@ -18,20 +18,25 @@ namespace hrun::worch_proc_round_robin { class Server : public TaskLib { public: + /** Construct the work orchestrator process scheduler */ void Construct(ConstructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } + /** Destroy the work orchestrator process queue */ void Destruct(DestructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } + /** Schedule running processes */ void Schedule(ScheduleTask *task, RunContext &rctx) { - int rr = 0; - for (Worker &worker : HRUN_WORK_ORCHESTRATOR->workers_) { - worker.SetCpuAffinity(rr % HERMES_SYSTEM_INFO->ncpu_); - ++rr; - } + HRUN_WORK_ORCHESTRATOR->DedicateCores(); + } + void MonitorSchedule(u32 mode, ScheduleTask *task, RunContext &rctx) { } #include "worch_proc_round_robin/worch_proc_round_robin_lib_exec.h" diff --git a/hrun/tasks_required/worch_queue_round_robin/include/worch_queue_round_robin/worch_queue_round_robin.h b/hrun/tasks_required/worch_queue_round_robin/include/worch_queue_round_robin/worch_queue_round_robin.h index 539f96fb3..cdffb5318 100644 --- a/hrun/tasks_required/worch_queue_round_robin/include/worch_queue_round_robin/worch_queue_round_robin.h +++ b/hrun/tasks_required/worch_queue_round_robin/include/worch_queue_round_robin/worch_queue_round_robin.h @@ -24,11 +24,10 @@ class Client : public TaskLibClient { void CreateRoot(const DomainId &domain_id, const std::string &state_name) { id_ = TaskStateId::GetNull(); - std::vector queue_info = { - {1, 1, 4, 0}, - }; + std::vector queue_info; id_ = HRUN_ADMIN->CreateTaskStateRoot( domain_id, state_name, id_, queue_info); + Init(id_, HRUN_ADMIN->queue_id_); } /** Destroy task state */ diff --git a/hrun/tasks_required/worch_queue_round_robin/include/worch_queue_round_robin/worch_queue_round_robin_lib_exec.h b/hrun/tasks_required/worch_queue_round_robin/include/worch_queue_round_robin/worch_queue_round_robin_lib_exec.h index 4f4c3237d..14418939b 100644 --- a/hrun/tasks_required/worch_queue_round_robin/include/worch_queue_round_robin/worch_queue_round_robin_lib_exec.h +++ b/hrun/tasks_required/worch_queue_round_robin/include/worch_queue_round_robin/worch_queue_round_robin_lib_exec.h @@ -18,19 +18,36 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kConstruct: { + MonitorConstruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestruct: { + MonitorDestruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kSchedule: { + MonitorSchedule(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kConstruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kSchedule: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } diff --git a/hrun/tasks_required/worch_queue_round_robin/src/worch_queue_round_robin.cc b/hrun/tasks_required/worch_queue_round_robin/src/worch_queue_round_robin.cc index 15596232f..2dbd435e8 100644 --- a/hrun/tasks_required/worch_queue_round_robin/src/worch_queue_round_robin.cc +++ b/hrun/tasks_required/worch_queue_round_robin/src/worch_queue_round_robin.cc @@ -18,18 +18,27 @@ namespace hrun::worch_queue_round_robin { class Server : public TaskLib { public: - u32 count_; + u32 count_lowlat_; + u32 count_highlat_; public: + /** Construct work orchestrator queue scheduler */ void Construct(ConstructTask *task, RunContext &rctx) { - count_ = 0; + count_lowlat_ = 0; + count_highlat_ = 0; task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } + /** Destroy work orchestrator queue scheduler */ void Destruct(DestructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } + /** Schedule work orchestrator queues */ void Schedule(ScheduleTask *task, RunContext &rctx) { // Check if any new queues need to be scheduled for (MultiQueue &queue : *HRUN_QM_RUNTIME->queue_map_) { @@ -37,27 +46,45 @@ class Server : public TaskLib { continue; } for (LaneGroup &lane_group : *queue.groups_) { - // NOTE(llogan): Assumes a minimum of two workers, admin on worker 0. - if (lane_group.IsLowPriority()) { - for (u32 lane_id = lane_group.num_scheduled_; lane_id < lane_group.num_lanes_; ++lane_id) { - // HILOG(kDebug, "Scheduling the queue {} (lane {})", queue.id_, lane_id); - Worker &worker = HRUN_WORK_ORCHESTRATOR->workers_[0]; + u32 num_lanes = lane_group.num_lanes_; + if (lane_group.IsTethered()) { + LaneGroup &tether_group = queue.GetGroup(lane_group.tether_); + num_lanes = tether_group.num_scheduled_; + } + for (u32 lane_id = lane_group.num_scheduled_; lane_id < num_lanes; ++lane_id) { + Lane &lane = lane_group.GetLane(lane_id); + if (lane_group.IsTethered()) { + LaneGroup &tether_group = queue.GetGroup(lane_group.tether_); + Lane &tether_lane = tether_group.GetLane(lane_id); + Worker &worker = *HRUN_WORK_ORCHESTRATOR->workers_[tether_lane.worker_id_]; worker.PollQueues({WorkEntry(lane_group.prio_, lane_id, &queue)}); - } - lane_group.num_scheduled_ = lane_group.num_lanes_; - } else { - for (u32 lane_id = lane_group.num_scheduled_; lane_id < lane_group.num_lanes_; ++lane_id) { - // HILOG(kDebug, "Scheduling the queue {} (lane {})", queue.id_, lane_id); - u32 worker_id = (count_ % (HRUN_WORK_ORCHESTRATOR->workers_.size() - 1)) + 1; - Worker &worker = HRUN_WORK_ORCHESTRATOR->workers_[worker_id]; + lane.worker_id_ = worker.id_; + HILOG(kInfo, "(node {}) Scheduling the queue {} (prio {}, lane {}, worker {})", + HRUN_CLIENT->node_id_, queue.id_, lane_group.prio_, lane_id, worker.id_); + } else if (lane_group.IsLowLatency()) { + u32 worker_off = count_lowlat_ % HRUN_WORK_ORCHESTRATOR->dworkers_.size(); + count_lowlat_ += 1; + Worker &worker = *HRUN_WORK_ORCHESTRATOR->dworkers_[worker_off]; + worker.PollQueues({WorkEntry(lane_group.prio_, lane_id, &queue)}); + lane.worker_id_ = worker.id_; + HILOG(kInfo, "(node {}) Scheduling the queue {} (prio {}, lane {}, worker {})", + HRUN_CLIENT->node_id_, queue.id_, lane_group.prio_, lane_id, worker.id_); + } else { + u32 worker_off = count_highlat_ % HRUN_WORK_ORCHESTRATOR->oworkers_.size(); + count_highlat_ += 1; + Worker &worker = *HRUN_WORK_ORCHESTRATOR->oworkers_[worker_off]; worker.PollQueues({WorkEntry(lane_group.prio_, lane_id, &queue)}); - count_ += 1; + HILOG(kInfo, "(node {}) Scheduling the queue {} (prio {}, lane {}, worker {})", + HRUN_CLIENT->node_id_, queue.id_, lane_group.prio_, lane_id, worker_off); + lane.worker_id_ = worker.id_; } - lane_group.num_scheduled_ = lane_group.num_lanes_; } + lane_group.num_scheduled_ = num_lanes; } } } + void MonitorSchedule(u32 mode, ScheduleTask *task, RunContext &rctx) { + } #include "worch_queue_round_robin/worch_queue_round_robin_lib_exec.h" }; diff --git a/include/hermes/bucket.h b/include/hermes/bucket.h index 690c29826..2cf1dcc7d 100644 --- a/include/hermes/bucket.h +++ b/include/hermes/bucket.h @@ -23,8 +23,6 @@ namespace hermes { using hermes::blob_mdm::PutBlobTask; using hermes::blob_mdm::GetBlobTask; -#define HERMES_BUCKET_IS_FILE BIT_OPT(u32, 1) - class Bucket { public: mdm::Client *mdm_; @@ -73,7 +71,7 @@ class Bucket { bkt_mdm_ = &HERMES_CONF->bkt_mdm_; id_ = bkt_mdm_->GetOrCreateTagRoot( hshm::charbuf(bkt_name), true, - std::vector(), backend_size, flags); + std::vector(), backend_size, flags, ctx); name_ = bkt_name; } @@ -228,7 +226,7 @@ class Bucket { bitfield32_t flags, task_flags( TASK_FIRE_AND_FORGET | TASK_DATA_OWNER | TASK_LOW_LATENCY); // Copy data to shared memory - LPointer p = HRUN_CLIENT->AllocateBuffer(blob.size()); + LPointer p = HRUN_CLIENT->AllocateBufferClient(blob.size()); char *data = p.ptr_; memcpy(data, blob.data(), blob.size()); // Put to shared memory @@ -380,7 +378,7 @@ class Bucket { * Append \a blob_name Blob into the bucket (fully asynchronous) * */ void Append(const Blob &blob, size_t page_size, Context &ctx) { - LPointer p = HRUN_CLIENT->AllocateBuffer(blob.size()); + LPointer p = HRUN_CLIENT->AllocateBufferClient(blob.size()); char *data = p.ptr_; memcpy(data, blob.data(), blob.size()); bkt_mdm_->AppendBlobRoot( @@ -447,7 +445,7 @@ class Bucket { } // Get from shared memory size_t data_size = blob.size(); - LPointer data_p = HRUN_CLIENT->AllocateBuffer(data_size); + LPointer data_p = HRUN_CLIENT->AllocateBufferClient(blob.size()); LPointer> push_task; push_task = blob_mdm_->AsyncGetBlobRoot(id_, hshm::to_charbuf(blob_name), blob_id, blob_off, @@ -465,7 +463,6 @@ class Bucket { size_t blob_off, Context &ctx) { // TODO(llogan): intercept mmap to avoid copy - // TODO(llogan): make GetBlobSize work with blob_name size_t data_size = blob.size(); if (blob.size() == 0) { data_size = blob_mdm_->GetBlobSizeRoot( @@ -479,8 +476,9 @@ class Bucket { push_task->Wait(); GetBlobTask *task = push_task->get(); blob_id = task->blob_id_; - char *data = HRUN_CLIENT->GetPrivatePointer(task->data_); - memcpy(blob.data(), data, data_size); + char *data = HRUN_CLIENT->GetDataPointer(task->data_); + memcpy(blob.data(), data, task->data_size_); + blob.resize(task->data_size_); HRUN_CLIENT->FreeBuffer(task->data_); HRUN_CLIENT->DelTask(push_task); return blob_id; @@ -614,7 +612,6 @@ class Bucket { * Delete \a blob_id blob * */ void DestroyBlob(const BlobId &blob_id, Context &ctx) { - // TODO(llogan): Make apart of bkt_mdm_ instead blob_mdm_->DestroyBlobRoot(id_, blob_id); } diff --git a/include/hermes/config_manager.h b/include/hermes/config_manager.h index 1cf44a040..a2d67cea5 100644 --- a/include/hermes/config_manager.h +++ b/include/hermes/config_manager.h @@ -62,7 +62,11 @@ class ConfigurationManager { is_initialized_ = true; } - void LoadClientConfig(std::string &config_path) { + void ServerInit() { + ClientInit(); + } + + void LoadClientConfig(std::string config_path) { // Load hermes config if (config_path.empty()) { config_path = GetEnvSafe(Constant::kHermesClientConf); @@ -71,7 +75,7 @@ class ConfigurationManager { client_config_.LoadFromFile(config_path); } - void LoadServerConfig(std::string &config_path) { + void LoadServerConfig(std::string config_path) { // Load hermes config if (config_path.empty()) { config_path = GetEnvSafe(Constant::kHermesServerConf); diff --git a/include/hermes/config_server_default.h b/include/hermes/config_server_default.h index 75ce716a1..203508ef0 100644 --- a/include/hermes/config_server_default.h +++ b/include/hermes/config_server_default.h @@ -79,12 +79,6 @@ const inline char* kHermesServerDefaultConfigStr = " is_shared_device: true\n" " borg_capacity_thresh: [ 0.0, 1.0 ]\n" "\n" -"# Define the maximum amount of memory Hermes can use for non-buffering tasks.\n" -"# This includes metadata management and memory allocations.\n" -"# This memory will not be preallocated, so if you don\'t know, 0 indicates\n" -"# any amount of memory\n" -"max_memory: 0g\n" -"\n" "### Define properties of the BORG\n" "buffer_organizer:\n" " # The number of threads used in the background organization of internal Hermes buffers.\n" @@ -143,13 +137,17 @@ const inline char* kHermesServerDefaultConfigStr = "\n" "### Runtime orchestration settings\n" "work_orchestrator:\n" -" # The number of worker threads to spawn\n" -" max_workers: 4\n" +" # The max number of dedicated worker threads\n" +" max_dworkers: 4\n" +" # The max number of overlapping threads\n" +" max_oworkers: 32\n" +" # The max number of total dedicated cores\n" +" owork_per_core: 32\n" "\n" "### Queue Manager settings\n" "queue_manager:\n" " # The default depth of allocated queues\n" -" queue_depth: 256\n" +" queue_depth: 100000\n" " # The maximum number of lanes per queue\n" " max_lanes: 16\n" " # The maximum number of queues\n" @@ -161,6 +159,7 @@ const inline char* kHermesServerDefaultConfigStr = " # The size of the shared memory region to allocate for general data structures\n" " shm_size: 0g\n" " # The size of the shared memory to allocate for data buffers\n" +" data_shm_size: 4g\n" "\n" "### Define properties of RPCs\n" "rpc:\n" @@ -186,7 +185,7 @@ const inline char* kHermesServerDefaultConfigStr = " port: 8080\n" "\n" " # The number of handler threads for each RPC server.\n" -" num_threads: 4\n" +" num_threads: 32\n" "\n" "### Task Registry\n" "task_registry: [\n" diff --git a/include/hermes/dpe/minimize_io_time.h b/include/hermes/dpe/minimize_io_time.h index 7c09b6c96..2cb6259ec 100644 --- a/include/hermes/dpe/minimize_io_time.h +++ b/include/hermes/dpe/minimize_io_time.h @@ -42,7 +42,9 @@ class MinimizeIoTime : public Dpe { // NOTE(llogan): We skip targets that are too high of priority or // targets that can't fit the ENTIRE blob size_t rem_cap = target.GetRemCap(); + // TODO(llogan): add back if (target.score_ > score || rem_cap < blob_size) { + // if (rem_cap < blob_size) { // TODO(llogan): add other considerations of this Dpe continue; } diff --git a/include/hermes/hermes.h b/include/hermes/hermes.h index 7cf45ffea..9aba19bfc 100644 --- a/include/hermes/hermes.h +++ b/include/hermes/hermes.h @@ -30,6 +30,11 @@ class Hermes { HERMES_CONF->ClientInit(); } + /** Init hermes server */ + void ServerInit() { + HERMES_CONF->ServerInit(); + } + /** Check if initialized */ bool IsInitialized() { return HERMES_CONF->is_initialized_; diff --git a/include/hermes/hermes_types.h b/include/hermes/hermes_types.h index 822540252..de8fd8cbe 100644 --- a/include/hermes/hermes_types.h +++ b/include/hermes/hermes_types.h @@ -119,12 +119,12 @@ struct Context { /** The blob's score */ float blob_score_; - /** Page size to use for FS reads / writes*/ - size_t page_size_; - /** Flags */ bitfield32_t flags_; + /** Custom bucket parameters */ + std::string bkt_params_; + /** The node id the blob will be accessed from */ u32 node_id_; @@ -305,6 +305,7 @@ struct BlobInfo { blob_size_ = other.blob_size_; max_blob_size_ = other.max_blob_size_; score_ = other.score_; + user_score_ = other.user_score_; access_freq_ = other.access_freq_.load(); last_access_ = other.last_access_; mod_count_ = other.mod_count_.load(); @@ -322,6 +323,13 @@ struct BlobInfo { last_access_.Now(); access_freq_.fetch_add(1); } + + /** Get name as std::string */ + std::vector GetName() { + std::vector data(name_.size()); + memcpy(data.data(), name_.data(), name_.size()); + return data; + } }; /** Data structure used to store Bucket information */ @@ -332,12 +340,20 @@ struct TagInfo { std::list traits_; size_t internal_size_; size_t page_size_; + bitfield32_t flags_; bool owner_; /** Serialization */ template void serialize(Ar &ar) { - ar(tag_id_, name_, internal_size_, page_size_, owner_); + ar(tag_id_, name_, internal_size_, page_size_, owner_, flags_); + } + + /** Get std::string of name */ + std::vector GetName() { + std::vector data(name_.size()); + memcpy(data.data(), name_.data(), name_.size()); + return data; } }; diff --git a/include/hermes/score_histogram.h b/include/hermes/score_histogram.h index 4775e39a6..d7db6e0b8 100644 --- a/include/hermes/score_histogram.h +++ b/include/hermes/score_histogram.h @@ -20,7 +20,7 @@ namespace hermes { struct HistEntry { - std::atomic x_; + std::atomic x_; /** Default constructor */ HistEntry() : x_(0) {} @@ -87,16 +87,25 @@ class Histogram { histogram_.resize(num_bins); } + /** Get the bin score belongs to */ + u32 GetBin(float score) { + u32 bin = score * histogram_.size(); + if (bin >= histogram_.size()) { + bin = histogram_.size() - 1; + } + return bin; + } + /** Increment histogram */ void Increment(float score) { - int bin = (int)(1.0/score - 1.0); + u32 bin = GetBin(score); histogram_[bin].increment(); count_.fetch_add(1); } /** Decrement histogram */ void Decrement(float score) { - int bin = (int)(1.0/score - 1.0); + u32 bin = GetBin(score); histogram_[bin].x_.fetch_sub(1); count_.fetch_sub(1); } @@ -104,15 +113,55 @@ class Histogram { /** * Determine if a blob should be elevated (1), * stationary (0), or demoted (-1) + * + * @input score a number between 0 and 1 + * @return Percentile (a number between 0 and 100) * */ - u16 GetPercentile(float score) { - int bin = (int)(1.0/score - 1.0); + template + u32 GetPercentileBase(float score) { + if (score == 0) { + return 0; + } + if (count_ == 0) { + return 100; + } + u32 bin = GetBin(score); u32 count = 0; - for (u32 i = 0; i <= bin; ++i) { - count += histogram_[i].x_.load(); + if (LESS_THAN_EQUAL) { + for (u32 i = 0; i <= bin; ++i) { + count += histogram_[i].x_.load(); + } + } else { + for (u32 i = 0; i < bin; ++i) { + count += histogram_[i].x_.load(); + } } return count * 100 / count_; } + u32 GetPercentile(float score) { + return GetPercentileBase(score); + } + u32 GetPercentileLT(float score) { + return GetPercentileBase(score); + } + + /** + * Get quantile. + * @input percentile is a number between 0 and 100 + * */ + float GetQuantile(u32 percentile) { + u32 count = 0; + if (count_ == 0) { + return 0.0; + } + for (u32 i = 0; i < histogram_.size(); ++i) { + count += histogram_[i].x_.load(); + if (count * 100 / count_ >= percentile && count > 0) { + return (i + 1) / histogram_.size(); + } + } + return 0.0; + } }; } // namespace hermes diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4bcda8599..d08551468 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ #------------------------------------------------------------------------------ -# Build Small Message Task Library +# Build Hermes #------------------------------------------------------------------------------ add_library(hermes SHARED hermes_config_manager.cc) @@ -7,7 +7,7 @@ add_dependencies(hermes ${Hermes_RUNTIME_DEPS}) target_link_libraries(hermes ${Hermes_RUNTIME_LIBRARIES}) #------------------------------------------------------------------------------ -# Install Small Message Task Library +# Install Hermes Library #------------------------------------------------------------------------------ install( TARGETS diff --git a/tasks/bdev/include/bdev/bdev.h b/tasks/bdev/include/bdev/bdev.h index d795f6127..2d6f826cf 100644 --- a/tasks/bdev/include/bdev/bdev.h +++ b/tasks/bdev/include/bdev/bdev.h @@ -16,11 +16,14 @@ namespace hermes::bdev { class Client : public TaskLibClient { public: DomainId domain_id_; - MonitorTask *monitor_task_; + StatBdevTask *monitor_task_; size_t max_cap_; /**< maximum capacity of the target */ double bandwidth_; /**< the bandwidth of the device */ double latency_; /**< the latency of the device */ float score_; /**< Relative importance of this tier */ + float bw_score_; /**< Relative importance of this tier */ + f32 borg_min_thresh_; /**< Capacity percentage too low */ + f32 borg_max_thresh_; /**< Capacity percentage too high */ public: Client() : score_(0) {} @@ -31,6 +34,8 @@ class Client : public TaskLibClient { bandwidth_ = dev_info.bandwidth_; latency_ = dev_info.latency_; score_ = 0; + borg_min_thresh_ = dev_info.borg_min_thresh_; + borg_max_thresh_ = dev_info.borg_max_thresh_; } /** Async create task state */ @@ -44,11 +49,7 @@ class Client : public TaskLibClient { id_ = TaskStateId::GetNull(); CopyDevInfo(dev_info); QueueManagerInfo &qm = HRUN_CLIENT->server_config_.queue_manager_; - std::vector queue_info = { - {1, 1, qm.queue_depth_, 0}, - {1, 1, qm.queue_depth_, QUEUE_LONG_RUNNING}, - {4, 4, qm.queue_depth_, QUEUE_LOW_LATENCY} - }; + std::vector queue_info; return HRUN_ADMIN->AsyncCreateTaskState( task_node, domain_id, state_name, lib_name, id_, queue_info, dev_info); @@ -56,8 +57,8 @@ class Client : public TaskLibClient { void AsyncCreateComplete(ConstructTask *task) { if (task->IsModuleComplete()) { id_ = task->id_; - queue_id_ = QueueId(id_); - monitor_task_ = AsyncMonitor(task->task_node_ + 1, 100).ptr_; + Init(id_, HRUN_ADMIN->queue_id_); + monitor_task_ = AsyncStatBdev(task->task_node_ + 1, 100).ptr_; HRUN_CLIENT->DelTask(task); } } @@ -80,13 +81,13 @@ class Client : public TaskLibClient { /** BDEV monitoring task */ HSHM_ALWAYS_INLINE - void AsyncMonitorConstruct(MonitorTask *task, + void AsyncStatBdevConstruct(StatBdevTask *task, const TaskNode &task_node, size_t freq_ms) { - HRUN_CLIENT->ConstructTask( + HRUN_CLIENT->ConstructTask( task, task_node, domain_id_, id_, freq_ms, max_cap_); } - HRUN_TASK_NODE_PUSH_ROOT(Monitor); + HRUN_TASK_NODE_PUSH_ROOT(StatBdev); /** Get bdev remaining capacity */ HSHM_ALWAYS_INLINE @@ -153,19 +154,25 @@ class Client : public TaskLibClient { class Server { public: ssize_t rem_cap_; /**< Remaining capacity */ - // Histogram score_hist_; /**< Score distribution */ + Histogram score_hist_; /**< Score distribution */ public: + /** Update the blob score in this tier */ void UpdateScore(UpdateScoreTask *task, RunContext &ctx) { -// if (task->old_score_ >= 0) { -// score_hist_.Decrement(task->old_score_); -// } -// score_hist_.Increment(task->new_score_); + if (task->old_score_ >= 0) { + score_hist_.Decrement(task->old_score_); + } + score_hist_.Increment(task->new_score_); + } + void MonitorUpdateScore(u32 mode, UpdateScoreTask *task, RunContext &ctx) { } - void Monitor(MonitorTask *task, RunContext &ctx) { + /** Stat capacity and scores */ + void StatBdev(StatBdevTask *task, RunContext &ctx) { task->rem_cap_ = rem_cap_; -// task->score_hist_ = score_hist_; + task->score_hist_ = score_hist_; + } + void MonitorStatBdev(u32 mode, StatBdevTask *task, RunContext &ctx) { } }; @@ -177,6 +184,7 @@ typedef bdev::Client TargetInfo; struct TargetStats { public: TargetId tgt_id_; + u32 node_id_; size_t rem_cap_; /**< Current remaining capacity */ size_t max_cap_; /**< maximum capacity of the target */ double bandwidth_; /**< the bandwidth of the device */ @@ -187,7 +195,7 @@ struct TargetStats { /** Serialize */ template void serialize(Ar &ar) { - ar(tgt_id_, max_cap_, bandwidth_, + ar(tgt_id_, node_id_, max_cap_, bandwidth_, latency_, score_, rem_cap_); } }; diff --git a/tasks/bdev/include/bdev/bdev_lib_exec.h b/tasks/bdev/include/bdev/bdev_lib_exec.h index 15d5d239c..fbc3e2177 100644 --- a/tasks/bdev/include/bdev/bdev_lib_exec.h +++ b/tasks/bdev/include/bdev/bdev_lib_exec.h @@ -28,8 +28,8 @@ void Run(u32 method, Task *task, RunContext &rctx) override { Free(reinterpret_cast(task), rctx); break; } - case Method::kMonitor: { - Monitor(reinterpret_cast(task), rctx); + case Method::kStatBdev: { + StatBdev(reinterpret_cast(task), rctx); break; } case Method::kUpdateScore: { @@ -38,39 +38,76 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kConstruct: { + MonitorConstruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestruct: { + MonitorDestruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kWrite: { + MonitorWrite(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kRead: { + MonitorRead(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kAllocate: { + MonitorAllocate(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kFree: { + MonitorFree(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kStatBdev: { + MonitorStatBdev(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kUpdateScore: { + MonitorUpdateScore(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kConstruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kWrite: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kRead: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kAllocate: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kFree: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } - case Method::kMonitor: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + case Method::kStatBdev: { + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kUpdateScore: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } @@ -102,8 +139,8 @@ void Dup(u32 method, Task *orig_task, std::vector> &dups) overrid hrun::CALL_DUPLICATE(reinterpret_cast(orig_task), dups); break; } - case Method::kMonitor: { - hrun::CALL_DUPLICATE(reinterpret_cast(orig_task), dups); + case Method::kStatBdev: { + hrun::CALL_DUPLICATE(reinterpret_cast(orig_task), dups); break; } case Method::kUpdateScore: { @@ -139,8 +176,8 @@ void DupEnd(u32 method, u32 replica, Task *orig_task, Task *dup_task) override { hrun::CALL_DUPLICATE_END(replica, reinterpret_cast(orig_task), reinterpret_cast(dup_task)); break; } - case Method::kMonitor: { - hrun::CALL_DUPLICATE_END(replica, reinterpret_cast(orig_task), reinterpret_cast(dup_task)); + case Method::kStatBdev: { + hrun::CALL_DUPLICATE_END(replica, reinterpret_cast(orig_task), reinterpret_cast(dup_task)); break; } case Method::kUpdateScore: { @@ -176,8 +213,8 @@ void ReplicateStart(u32 method, u32 count, Task *task) override { hrun::CALL_REPLICA_START(count, reinterpret_cast(task)); break; } - case Method::kMonitor: { - hrun::CALL_REPLICA_START(count, reinterpret_cast(task)); + case Method::kStatBdev: { + hrun::CALL_REPLICA_START(count, reinterpret_cast(task)); break; } case Method::kUpdateScore: { @@ -213,8 +250,8 @@ void ReplicateEnd(u32 method, Task *task) override { hrun::CALL_REPLICA_END(reinterpret_cast(task)); break; } - case Method::kMonitor: { - hrun::CALL_REPLICA_END(reinterpret_cast(task)); + case Method::kStatBdev: { + hrun::CALL_REPLICA_END(reinterpret_cast(task)); break; } case Method::kUpdateScore: { @@ -250,8 +287,8 @@ std::vector SaveStart(u32 method, BinaryOutputArchive &ar, T ar << *reinterpret_cast(task); break; } - case Method::kMonitor: { - ar << *reinterpret_cast(task); + case Method::kStatBdev: { + ar << *reinterpret_cast(task); break; } case Method::kUpdateScore: { @@ -295,9 +332,9 @@ TaskPointer LoadStart(u32 method, BinaryInputArchive &ar) override { ar >> *reinterpret_cast(task_ptr.ptr_); break; } - case Method::kMonitor: { - task_ptr.ptr_ = HRUN_CLIENT->NewEmptyTask(task_ptr.shm_); - ar >> *reinterpret_cast(task_ptr.ptr_); + case Method::kStatBdev: { + task_ptr.ptr_ = HRUN_CLIENT->NewEmptyTask(task_ptr.shm_); + ar >> *reinterpret_cast(task_ptr.ptr_); break; } case Method::kUpdateScore: { @@ -335,8 +372,8 @@ std::vector SaveEnd(u32 method, BinaryOutputArchive &ar, Ta ar << *reinterpret_cast(task); break; } - case Method::kMonitor: { - ar << *reinterpret_cast(task); + case Method::kStatBdev: { + ar << *reinterpret_cast(task); break; } case Method::kUpdateScore: { @@ -373,8 +410,8 @@ void LoadEnd(u32 replica, u32 method, BinaryInputArchive &ar, Task *task) ar.Deserialize(replica, *reinterpret_cast(task)); break; } - case Method::kMonitor: { - ar.Deserialize(replica, *reinterpret_cast(task)); + case Method::kStatBdev: { + ar.Deserialize(replica, *reinterpret_cast(task)); break; } case Method::kUpdateScore: { @@ -404,8 +441,8 @@ u32 GetGroup(u32 method, Task *task, hshm::charbuf &group) override { case Method::kFree: { return reinterpret_cast(task)->GetGroup(group); } - case Method::kMonitor: { - return reinterpret_cast(task)->GetGroup(group); + case Method::kStatBdev: { + return reinterpret_cast(task)->GetGroup(group); } case Method::kUpdateScore: { return reinterpret_cast(task)->GetGroup(group); diff --git a/tasks/bdev/include/bdev/bdev_methods.h b/tasks/bdev/include/bdev/bdev_methods.h index e1098d44f..48fbc21e4 100644 --- a/tasks/bdev/include/bdev/bdev_methods.h +++ b/tasks/bdev/include/bdev/bdev_methods.h @@ -7,7 +7,7 @@ struct Method : public TaskMethod { TASK_METHOD_T kRead = kLast + 1; TASK_METHOD_T kAllocate = kLast + 2; TASK_METHOD_T kFree = kLast + 3; - TASK_METHOD_T kMonitor = kLast + 4; + TASK_METHOD_T kStatBdev = kLast + 4; TASK_METHOD_T kUpdateScore = kLast + 5; }; diff --git a/tasks/bdev/include/bdev/bdev_methods.yaml b/tasks/bdev/include/bdev/bdev_methods.yaml index 8291c8091..acf8ea882 100644 --- a/tasks/bdev/include/bdev/bdev_methods.yaml +++ b/tasks/bdev/include/bdev/bdev_methods.yaml @@ -2,6 +2,6 @@ kWrite: 0 kRead: 1 kAllocate: 2 kFree: 3 -kMonitor: 4 +kStatBdev: 4 kUpdateScore: 5 kLast: 6 \ No newline at end of file diff --git a/tasks/bdev/include/bdev/bdev_namespace.h b/tasks/bdev/include/bdev/bdev_namespace.h index f77fd7c99..0c8e72426 100644 --- a/tasks/bdev/include/bdev/bdev_namespace.h +++ b/tasks/bdev/include/bdev/bdev_namespace.h @@ -17,7 +17,7 @@ using ::hermes::bdev::AllocateTask; using ::hermes::bdev::FreeTask; using ::hermes::bdev::ReadTask; using ::hermes::bdev::WriteTask; -using ::hermes::bdev::MonitorTask; +using ::hermes::bdev::StatBdevTask; using ::hermes::bdev::UpdateScoreTask; /** Create admin requests */ diff --git a/tasks/bdev/include/bdev/bdev_tasks.h b/tasks/bdev/include/bdev/bdev_tasks.h index 8338b1413..952b3d3d4 100644 --- a/tasks/bdev/include/bdev/bdev_tasks.h +++ b/tasks/bdev/include/bdev/bdev_tasks.h @@ -5,6 +5,7 @@ #ifndef HRUN_TASKS_BDEV_INCLUDE_BDEV_BDEV_TASKS_H_ #define HRUN_TASKS_BDEV_INCLUDE_BDEV_BDEV_TASKS_H_ +// #include #include "hrun/api/hrun_client.h" #include "hrun/task_registry/task_lib.h" #include "hrun_admin/hrun_admin.h" @@ -60,7 +61,7 @@ struct DestructTask : public DestroyTaskStateTask { const TaskNode &task_node, TaskStateId &state_id, const DomainId &domain_id) - : DestroyTaskStateTask(alloc, task_node, domain_id, state_id) {} + : DestroyTaskStateTask(alloc, task_node, domain_id, state_id) {} /** Create group */ HSHM_ALWAYS_INLINE @@ -85,12 +86,12 @@ struct AllocateTask : public Task, TaskFlags { /** Emplace constructor */ HSHM_ALWAYS_INLINE explicit AllocateTask(hipc::Allocator *alloc, - const TaskNode &task_node, - const DomainId &domain_id, - const TaskStateId &state_id, - size_t size, - float score, - std::vector *buffers) : Task(alloc) { + const TaskNode &task_node, + const DomainId &domain_id, + const TaskStateId &state_id, + size_t size, + float score, + std::vector *buffers) : Task(alloc) { // Initialize task task_node_ = task_node; lane_hash_ = 0; @@ -164,6 +165,8 @@ struct WriteTask : public Task, TaskFlags { IN const char *buf_; /**< Data in memory */ IN size_t disk_off_; /**< Offset on disk */ IN size_t size_; /**< Size in buf */ + TEMP int phase_ = 0; + // TEMP io_context_t ctx_ = 0; /** SHM default constructor */ HSHM_ALWAYS_INLINE explicit @@ -179,13 +182,19 @@ struct WriteTask : public Task, TaskFlags { size_t disk_off, size_t size) : Task(alloc) { // Initialize task + static int counter = 0; task_node_ = task_node; - lane_hash_ = 0; - prio_ = TaskPrio::kLowLatency; + lane_hash_ = ++counter; + if (size < KILOBYTES(8)) { + prio_ = TaskPrio::kLowLatency; + } else { + prio_ = TaskPrio::kHighLatency; + } task_state_ = state_id; method_ = Method::kWrite; task_flags_.SetBits(TASK_UNORDERED | TASK_REMOTE_DEBUG_MARK); domain_id_ = domain_id; + counter += 1; // Free params buf_ = buf; @@ -207,6 +216,8 @@ struct ReadTask : public Task, TaskFlags { IN char *buf_; /**< Data in memory */ IN size_t disk_off_; /**< Offset on disk */ IN size_t size_; /**< Size in disk buf */ + TEMP int phase_ = 0; + // TEMP io_context_t ctx_ = 0; /** SHM default constructor */ HSHM_ALWAYS_INLINE explicit @@ -221,10 +232,16 @@ struct ReadTask : public Task, TaskFlags { char *buf, size_t disk_off, size_t size) : Task(alloc) { + static int counter = 0; // Initialize task task_node_ = task_node; - lane_hash_ = 0; - prio_ = TaskPrio::kLowLatency; + lane_hash_ = counter; + ++counter; + if (size < KILOBYTES(8)) { + prio_ = TaskPrio::kLowLatency; + } else { + prio_ = TaskPrio::kHighLatency; + } task_state_ = state_id; method_ = Method::kRead; task_flags_.SetBits(TASK_UNORDERED | TASK_REMOTE_DEBUG_MARK); @@ -244,34 +261,35 @@ struct ReadTask : public Task, TaskFlags { }; /** A task to monitor bdev statistics */ -struct MonitorTask : public Task, TaskFlags { +struct StatBdevTask : public Task, TaskFlags { OUT size_t rem_cap_; /**< Remaining capacity of the target */ - // OUT Histogram score_hist_; /**< Score distribution */ + OUT Histogram score_hist_; /**< Score distribution */ /** SHM default constructor */ HSHM_ALWAYS_INLINE explicit - MonitorTask(hipc::Allocator *alloc) : Task(alloc) {} + StatBdevTask(hipc::Allocator *alloc) : Task(alloc) {} /** Emplace constructor */ HSHM_ALWAYS_INLINE explicit - MonitorTask(hipc::Allocator *alloc, - const TaskNode &task_node, - const DomainId &domain_id, - const TaskStateId &state_id, - size_t freq_ms, - size_t rem_cap) : Task(alloc) { + StatBdevTask(hipc::Allocator *alloc, + const TaskNode &task_node, + const DomainId &domain_id, + const TaskStateId &state_id, + size_t freq_ms, + size_t rem_cap) : Task(alloc) { // Initialize task task_node_ = task_node; lane_hash_ = 0; prio_ = TaskPrio::kLongRunning; task_state_ = state_id; - method_ = Method::kMonitor; + method_ = Method::kStatBdev; task_flags_.SetBits(TASK_LONG_RUNNING | TASK_REMOTE_DEBUG_MARK); SetPeriodMs(freq_ms); domain_id_ = domain_id; // Custom rem_cap_ = rem_cap; + score_hist_.Resize(10); } /** Create group */ @@ -293,10 +311,10 @@ struct UpdateScoreTask : public Task, TaskFlags { /** Emplace constructor */ HSHM_ALWAYS_INLINE explicit UpdateScoreTask(hipc::Allocator *alloc, - const TaskNode &task_node, - const DomainId &domain_id, - const TaskStateId &state_id, - float old_score, float new_score) : Task(alloc) { + const TaskNode &task_node, + const DomainId &domain_id, + const TaskStateId &state_id, + float old_score, float new_score) : Task(alloc) { // Initialize task task_node_ = task_node; lane_hash_ = 0; diff --git a/tasks/data_stager/include/data_stager/data_stager.h b/tasks/data_stager/include/data_stager/data_stager.h index dd7fdbc7c..ec524856c 100644 --- a/tasks/data_stager/include/data_stager/data_stager.h +++ b/tasks/data_stager/include/data_stager/data_stager.h @@ -26,11 +26,7 @@ class Client : public TaskLibClient { const TaskStateId &blob_mdm) { id_ = TaskStateId::GetNull(); QueueManagerInfo &qm = HRUN_CLIENT->server_config_.queue_manager_; - std::vector queue_info = { - {1, 1, qm.queue_depth_, 0}, - {1, 1, qm.queue_depth_, QUEUE_LONG_RUNNING}, - {qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY} - }; + std::vector queue_info; return HRUN_ADMIN->AsyncCreateTaskState( task_node, domain_id, state_name, id_, queue_info, blob_mdm); } @@ -42,7 +38,7 @@ class Client : public TaskLibClient { AsyncCreateRoot(std::forward(args)...); task->Wait(); id_ = task->id_; - queue_id_ = QueueId(id_); + Init(id_, HRUN_ADMIN->queue_id_); HRUN_CLIENT->DelTask(task); } @@ -57,15 +53,17 @@ class Client : public TaskLibClient { void AsyncRegisterStagerConstruct(RegisterStagerTask *task, const TaskNode &task_node, const BucketId &bkt_id, - const hshm::charbuf &url) { + const hshm::charbuf &path, + const hshm::charbuf ¶ms) { HRUN_CLIENT->ConstructTask( - task, task_node, id_, bkt_id, url); + task, task_node, id_, bkt_id, path, params); } HSHM_ALWAYS_INLINE void RegisterStagerRoot(const BucketId &bkt_id, - const hshm::charbuf &url) { + const hshm::charbuf &path, + const hshm::charbuf params) { LPointer> task = - AsyncRegisterStagerRoot(bkt_id, url); + AsyncRegisterStagerRoot(bkt_id, path, params); task.ptr_->Wait(); } HRUN_TASK_NODE_PUSH_ROOT(RegisterStager); diff --git a/tasks/data_stager/include/data_stager/data_stager_lib_exec.h b/tasks/data_stager/include/data_stager/data_stager_lib_exec.h index df65d48be..5e955f05e 100644 --- a/tasks/data_stager/include/data_stager/data_stager_lib_exec.h +++ b/tasks/data_stager/include/data_stager/data_stager_lib_exec.h @@ -30,31 +30,60 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kConstruct: { + MonitorConstruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestruct: { + MonitorDestruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kRegisterStager: { + MonitorRegisterStager(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kUnregisterStager: { + MonitorUnregisterStager(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kStageIn: { + MonitorStageIn(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kStageOut: { + MonitorStageOut(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kConstruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kRegisterStager: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kUnregisterStager: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kStageIn: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kStageOut: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } diff --git a/tasks/data_stager/include/data_stager/data_stager_tasks.h b/tasks/data_stager/include/data_stager/data_stager_tasks.h index a9bcb44f9..8a2bdd03c 100644 --- a/tasks/data_stager/include/data_stager/data_stager_tasks.h +++ b/tasks/data_stager/include/data_stager/data_stager_tasks.h @@ -93,7 +93,8 @@ struct DestructTask : public DestroyTaskStateTask { * */ struct RegisterStagerTask : public Task, TaskFlags { hermes::BucketId bkt_id_; - hipc::ShmArchive url_; + hipc::ShmArchive tag_name_; + hipc::ShmArchive params_; /** SHM default constructor */ HSHM_ALWAYS_INLINE explicit @@ -105,7 +106,8 @@ struct RegisterStagerTask : public Task, TaskFlags { const TaskNode &task_node, const TaskStateId &state_id, hermes::BucketId bkt_id, - const hshm::charbuf &url) : Task(alloc) { + const hshm::charbuf &tag_name, + const hshm::charbuf ¶ms) : Task(alloc) { // Initialize task task_node_ = task_node; lane_hash_ = bkt_id.hash_; @@ -117,13 +119,15 @@ struct RegisterStagerTask : public Task, TaskFlags { // Custom params bkt_id_ = bkt_id; - HSHM_MAKE_AR(url_, alloc, url); + HSHM_MAKE_AR(tag_name_, alloc, tag_name); + HSHM_MAKE_AR(params_, alloc, params); } /** Destructor */ HSHM_ALWAYS_INLINE ~RegisterStagerTask() { - HSHM_DESTROY_AR(url_) + HSHM_DESTROY_AR(tag_name_) + HSHM_DESTROY_AR(params_) } /** Duplicate message */ @@ -139,7 +143,7 @@ struct RegisterStagerTask : public Task, TaskFlags { template void SerializeStart(Ar &ar) { task_serialize(ar); - ar(bkt_id_, url_); + ar(bkt_id_, tag_name_, params_); } /** (De)serialize message return */ diff --git a/tasks/data_stager/include/data_stager/factory/abstract_stager.h b/tasks/data_stager/include/data_stager/factory/abstract_stager.h index 2c5dca484..02483101c 100644 --- a/tasks/data_stager/include/data_stager/factory/abstract_stager.h +++ b/tasks/data_stager/include/data_stager/factory/abstract_stager.h @@ -11,7 +11,8 @@ namespace hermes::data_stager { class AbstractStager { public: - std::string url_; + std::string path_; + std::string params_; AbstractStager() = default; ~AbstractStager() = default; diff --git a/tasks/data_stager/include/data_stager/factory/binary_stager.h b/tasks/data_stager/include/data_stager/factory/binary_stager.h index cea23d787..2b40d15db 100644 --- a/tasks/data_stager/include/data_stager/factory/binary_stager.h +++ b/tasks/data_stager/include/data_stager/factory/binary_stager.h @@ -12,7 +12,6 @@ namespace hermes::data_stager { class BinaryFileStager : public AbstractStager { public: - int fd_; size_t page_size_; std::string path_; @@ -21,37 +20,33 @@ class BinaryFileStager : public AbstractStager { BinaryFileStager() = default; /** Destructor */ - ~BinaryFileStager() { - HERMES_POSIX_API->close(fd_); - } + ~BinaryFileStager() {} - /** Build file url */ - static hshm::charbuf BuildFileUrl(const std::string &path, size_t page_size) { - std::stringstream ss; - ss << "file://" << path << ":" << page_size; - return hshm::charbuf(ss.str()); + /** Build context for staging */ + static Context BuildContext(size_t page_size) { + Context ctx; + ctx.flags_.SetBits(HERMES_SHOULD_STAGE); + ctx.bkt_params_ = BuildFileParams(page_size); + return ctx; } - /** Parse file url */ - static void ParseFileUrl(const std::string &url, std::string &path, size_t &page_size) { - // Parse url - std::string protocol, action; - std::vector tokens; - Client::GetUrlProtocolAndAction(url, protocol, action, tokens); - // file://[path]:[page_size] - if (protocol == "file") { - path = tokens[0]; - page_size = std::stoul(tokens[1]); - } + /** Build serialized file parameter pack */ + static std::string BuildFileParams(size_t page_size) { + std::string params; + hrun::LocalSerialize srl(params); + srl << std::string("file"); + srl << page_size; + return params; } /** Create the data stager payload */ void RegisterStager(RegisterStagerTask *task, RunContext &rctx) override { - ParseFileUrl(task->url_->str(), path_, page_size_); - fd_ = HERMES_POSIX_API->open(path_.c_str(), O_RDWR); - if (fd_ < 0) { - HELOG(kError, "Failed to open file {}", path_); - } + std::string params = task->params_->str(); + std::string protocol; + hrun::LocalDeserialize srl(params); + srl >> protocol; + srl >> page_size_; + path_ = task->tag_name_->str(); } /** Stage data in from remote source */ @@ -59,23 +54,34 @@ class BinaryFileStager : public AbstractStager { adapter::BlobPlacement plcmnt; plcmnt.DecodeBlobName(*task->blob_name_, page_size_); HILOG(kDebug, "Attempting to stage {} bytes from the backend file {} at offset {}", - page_size_, url_, plcmnt.bucket_off_); - LPointer blob = HRUN_CLIENT->AllocateBuffer(page_size_); - ssize_t real_size = HERMES_POSIX_API->pread(fd_, + page_size_, path_, plcmnt.bucket_off_); + LPointer blob = HRUN_CLIENT->AllocateBufferServer(page_size_); + int fd = HERMES_POSIX_API->open(path_.c_str(), O_CREAT | O_RDWR, 0666); + if (fd < 0) { + HELOG(kError, "Failed to open file {}", path_); + HRUN_CLIENT->FreeBuffer(blob); + return; + } + ssize_t real_size = HERMES_POSIX_API->pread(fd, blob.ptr_, page_size_, (off_t)plcmnt.bucket_off_); + HERMES_POSIX_API->close(fd); if (real_size < 0) { HELOG(kError, "Failed to stage in {} bytes from {}", - page_size_, url_); + page_size_, path_); + HRUN_CLIENT->FreeBuffer(blob); + return; + } else if (real_size == 0) { + HRUN_CLIENT->FreeBuffer(blob); return; } - // memcpy(blob.ptr_ + plcmnt.blob_off_, blob.ptr_, real_size); HILOG(kDebug, "Staged {} bytes from the backend file {}", - real_size, url_); + real_size, path_); HILOG(kDebug, "Submitting put blob {} ({}) to blob mdm ({})", task->blob_name_->str(), task->bkt_id_, blob_mdm.id_) hapi::Context ctx; + ctx.flags_.SetBits(HERMES_SHOULD_STAGE); LPointer put_task = blob_mdm.AsyncPutBlob(task->task_node_ + 1, task->bkt_id_, @@ -92,18 +98,24 @@ class BinaryFileStager : public AbstractStager { adapter::BlobPlacement plcmnt; plcmnt.DecodeBlobName(*task->blob_name_, page_size_); HILOG(kDebug, "Attempting to stage {} bytes to the backend file {} at offset {}", - page_size_, url_, plcmnt.bucket_off_); - char *data = HRUN_CLIENT->GetPrivatePointer(task->data_); - ssize_t real_size = HERMES_POSIX_API->pwrite(fd_, + page_size_, path_, plcmnt.bucket_off_); + char *data = HRUN_CLIENT->GetDataPointer(task->data_); + int fd = HERMES_POSIX_API->open(path_.c_str(), O_CREAT | O_RDWR, 0666); + if (fd < 0) { + HELOG(kError, "Failed to open file {}", path_); + return; + } + ssize_t real_size = HERMES_POSIX_API->pwrite(fd, data, task->data_size_, (off_t)plcmnt.bucket_off_); + HERMES_POSIX_API->close(fd); if (real_size < 0) { HELOG(kError, "Failed to stage out {} bytes from {}", - task->data_size_, url_); + task->data_size_, path_); } HILOG(kDebug, "Staged out {} bytes to the backend file {}", - real_size, url_); + real_size, path_); } }; diff --git a/tasks/data_stager/include/data_stager/factory/stager_factory.h b/tasks/data_stager/include/data_stager/factory/stager_factory.h index 341b55964..ba37e5282 100644 --- a/tasks/data_stager/include/data_stager/factory/stager_factory.h +++ b/tasks/data_stager/include/data_stager/factory/stager_factory.h @@ -13,16 +13,22 @@ namespace hermes::data_stager { class StagerFactory { public: - static std::unique_ptr Get(const std::string &url) { + static std::unique_ptr Get(const std::string &path, + const std::string ¶ms) { + std::string protocol; + hrun::LocalDeserialize srl(params); + srl >> protocol; + std::unique_ptr stager; - if (url.find("file://") == 0) { + if (protocol == "file") { stager = std::make_unique(); - } else if (url.find("parquet://")) { - } else if (url.find("hdf5://")) { + } else if (protocol == "parquet") { + } else if (protocol == "hdf5") { } else { throw std::runtime_error("Unknown stager type"); } - stager->url_ = url; + stager->path_ = path; + stager->params_ = params; return stager; } }; diff --git a/tasks/data_stager/src/data_stager.cc b/tasks/data_stager/src/data_stager.cc index 55dc298b9..08275d05a 100644 --- a/tasks/data_stager/src/data_stager.cc +++ b/tasks/data_stager/src/data_stager.cc @@ -20,39 +20,58 @@ class Server : public TaskLib { public: Server() = default; + /** Construct data stager */ void Construct(ConstructTask *task, RunContext &rctx) { task->Deserialize(); url_map_.resize(HRUN_QM_RUNTIME->max_lanes_); - blob_mdm_.Init(task->blob_mdm_); + blob_mdm_.Init(task->blob_mdm_, HRUN_ADMIN->queue_id_); HILOG(kInfo, "(node {}) BLOB MDM: {}", HRUN_CLIENT->node_id_, blob_mdm_.id_); task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } + /** Destroy data stager */ void Destruct(DestructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } + /** Register a stager */ void RegisterStager(RegisterStagerTask *task, RunContext &rctx) { - std::string url = task->url_->str(); - std::unique_ptr stager = StagerFactory::Get(url); + std::string tag_name = task->tag_name_->str(); + std::string params = task->params_->str(); + HILOG(kDebug, "Registering stager {}: {}", task->bkt_id_, tag_name); + std::unique_ptr stager = StagerFactory::Get(tag_name, params); stager->RegisterStager(task, rctx); url_map_[rctx.lane_id_].emplace(task->bkt_id_, std::move(stager)); task->SetModuleComplete(); } + void MonitorRegisterStager(u32 mode, RegisterStagerTask *task, RunContext &rctx) { + } + /** Unregister stager */ void UnregisterStager(UnregisterStagerTask *task, RunContext &rctx) { + HILOG(kDebug, "Unregistering stager {}", task->bkt_id_); if (url_map_[rctx.lane_id_].find(task->bkt_id_) == url_map_[rctx.lane_id_].end()) { + task->SetModuleComplete(); return; } url_map_[rctx.lane_id_].erase(task->bkt_id_); task->SetModuleComplete(); } + void MonitorUnregisterStager(u32 mode, UnregisterStagerTask *task, RunContext &rctx) { + } + /** Stage in data */ void StageIn(StageInTask *task, RunContext &rctx) { + // HILOG(kDebug, "Beginning stage in"); std::unordered_map>::iterator it = url_map_[rctx.lane_id_].find(task->bkt_id_); if (it == url_map_[rctx.lane_id_].end()) { - HELOG(kError, "Could not find stager for bucket: {}", task->bkt_id_); + // + // HELOG(kError, "Could not find stager for bucket: {}", task->bkt_id_); // TODO(llogan): Probably should add back... // task->SetModuleComplete(); return; @@ -61,7 +80,10 @@ class Server : public TaskLib { stager->StageIn(blob_mdm_, task, rctx); task->SetModuleComplete(); } + void MonitorStageIn(u32 mode, StageInTask *task, RunContext &rctx) { + } + /** Stage out data */ void StageOut(StageOutTask *task, RunContext &rctx) { std::unordered_map>::iterator it = url_map_[rctx.lane_id_].find(task->bkt_id_); @@ -74,6 +96,9 @@ class Server : public TaskLib { stager->StageOut(blob_mdm_, task, rctx); task->SetModuleComplete(); } + void MonitorStageOut(u32 mode, StageOutTask *task, RunContext &rctx) { + } + public: #include "data_stager/data_stager_lib_exec.h" }; diff --git a/tasks/hermes_blob_mdm/include/hermes_blob_mdm/hermes_blob_mdm.h b/tasks/hermes_blob_mdm/include/hermes_blob_mdm/hermes_blob_mdm.h index 9c04cefdb..3cb367c9d 100644 --- a/tasks/hermes_blob_mdm/include/hermes_blob_mdm/hermes_blob_mdm.h +++ b/tasks/hermes_blob_mdm/include/hermes_blob_mdm/hermes_blob_mdm.h @@ -19,24 +19,14 @@ class Client : public TaskLibClient { /** Destructor */ ~Client() = default; - /** Initialize directly using TaskStateId */ - void Init(const TaskStateId &id) { - id_ = id; - queue_id_ = QueueId(id_); - } - /** Create a hermes_blob_mdm */ HSHM_ALWAYS_INLINE - LPointer AsyncCreate(const TaskNode &task_node, - const DomainId &domain_id, - const std::string &state_name) { + LPointer AsyncCreate(const TaskNode &task_node, + const DomainId &domain_id, + const std::string &state_name) { id_ = TaskStateId::GetNull(); QueueManagerInfo &qm = HRUN_CLIENT->server_config_.queue_manager_; - std::vector queue_info = { - {1, 1, qm.queue_depth_, 0}, - {1, 1, qm.queue_depth_, QUEUE_LONG_RUNNING}, - {qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY} - }; + std::vector queue_info; return HRUN_ADMIN->AsyncCreateTaskState( task_node, domain_id, state_name, id_, queue_info); } @@ -81,7 +71,7 @@ class Client : public TaskLibClient { const TaskStateId &stager_mdm, const TaskStateId &op_mdm) { LPointer> push_task = - AsyncSetBucketMdmRoot(domain_id, blob_mdm, stager_mdm, op_mdm); + AsyncSetBucketMdmRoot(domain_id, blob_mdm, stager_mdm, op_mdm); push_task->Wait(); HRUN_CLIENT->DelTask(push_task); } @@ -94,14 +84,14 @@ class Client : public TaskLibClient { const TaskNode &task_node, TagId tag_id, const hshm::charbuf &blob_name) { - u32 hash = std::hash{}(blob_name); + u32 hash = HashBlobName(tag_id, blob_name); HRUN_CLIENT->ConstructTask( task, task_node, DomainId::GetNode(HASH_TO_NODE_ID(hash)), id_, tag_id, blob_name); } BlobId GetOrCreateBlobIdRoot(TagId tag_id, const hshm::charbuf &blob_name) { LPointer> push_task = - AsyncGetOrCreateBlobIdRoot(tag_id, blob_name); + AsyncGetOrCreateBlobIdRoot(tag_id, blob_name); push_task->Wait(); GetOrCreateBlobIdTask *task = push_task->get(); BlobId blob_id = task->blob_id_; @@ -164,7 +154,7 @@ class Client : public TaskLibClient { Context ctx = Context(), u32 flags = 0) { LPointer> push_task = - AsyncGetBlobRoot(tag_id, hshm::charbuf(""), blob_id, off, data_size, data, ctx, flags); + AsyncGetBlobRoot(tag_id, hshm::charbuf(""), blob_id, off, data_size, data, ctx, flags); push_task->Wait(); GetBlobTask *task = push_task->get(); data = task->data_; @@ -187,11 +177,12 @@ class Client : public TaskLibClient { const BlobId &blob_id, float score, u32 node_id, - bool user_score) { + bool user_score, + u32 task_flags = TASK_LOW_LATENCY | TASK_FIRE_AND_FORGET) { // HILOG(kDebug, "Beginning REORGANIZE (task_node={})", task_node); HRUN_CLIENT->ConstructTask( task, task_node, DomainId::GetNode(blob_id.node_id_), id_, - tag_id, blob_id, score, node_id, user_score); + tag_id, blob_id, score, node_id, user_score, task_flags); } HRUN_TASK_NODE_PUSH_ROOT(ReorganizeBlob); @@ -214,7 +205,7 @@ class Client : public TaskLibClient { const BlobId &blob_id, const TagId &tag) { LPointer> push_task = - AsyncTagBlobRoot(tag_id, blob_id, tag); + AsyncTagBlobRoot(tag_id, blob_id, tag); push_task->Wait(); HRUN_CLIENT->DelTask(push_task); } @@ -236,7 +227,7 @@ class Client : public TaskLibClient { const BlobId &blob_id, const TagId &tag) { LPointer> push_task = - AsyncBlobHasTagRoot(tag_id, blob_id, tag); + AsyncBlobHasTagRoot(tag_id, blob_id, tag); push_task->Wait(); BlobHasTagTask *task = push_task->get(); bool has_tag = task->has_tag_; @@ -252,7 +243,7 @@ class Client : public TaskLibClient { const TaskNode &task_node, const TagId &tag_id, const hshm::charbuf &blob_name) { - u32 hash = std::hash{}(blob_name); + u32 hash = HashBlobName(tag_id, blob_name); HRUN_CLIENT->ConstructTask( task, task_node, DomainId::GetNode(HASH_TO_NODE_ID(hash)), id_, tag_id, blob_name); @@ -260,7 +251,7 @@ class Client : public TaskLibClient { BlobId GetBlobIdRoot(const TagId &tag_id, const hshm::charbuf &blob_name) { LPointer> push_task = - AsyncGetBlobIdRoot(tag_id, blob_name); + AsyncGetBlobIdRoot(tag_id, blob_name); push_task->Wait(); GetBlobIdTask *task = push_task->get(); BlobId blob_id = task->blob_id_; @@ -283,7 +274,7 @@ class Client : public TaskLibClient { std::string GetBlobNameRoot(const TagId &tag_id, const BlobId &blob_id) { LPointer> push_task = - AsyncGetBlobNameRoot(tag_id, blob_id); + AsyncGetBlobNameRoot(tag_id, blob_id); push_task->Wait(); GetBlobNameTask *task = push_task->get(); std::string blob_name = task->blob_name_->str(); @@ -309,7 +300,7 @@ class Client : public TaskLibClient { const hshm::charbuf &blob_name, const BlobId &blob_id) { LPointer> push_task = - AsyncGetBlobSizeRoot(tag_id, blob_name, blob_id); + AsyncGetBlobSizeRoot(tag_id, blob_name, blob_id); push_task->Wait(); GetBlobSizeTask *task = push_task->get(); size_t size = task->size_; @@ -332,7 +323,7 @@ class Client : public TaskLibClient { float GetBlobScoreRoot(const TagId &tag_id, const BlobId &blob_id) { LPointer> push_task = - AsyncGetBlobScoreRoot(tag_id, blob_id); + AsyncGetBlobScoreRoot(tag_id, blob_id); push_task->Wait(); GetBlobScoreTask *task = push_task->get(); float score = task->score_; @@ -381,7 +372,7 @@ class Client : public TaskLibClient { const BlobId &blob_id, const hshm::charbuf &new_blob_name) { LPointer> push_task = - AsyncRenameBlobRoot(tag_id, blob_id, new_blob_name); + AsyncRenameBlobRoot(tag_id, blob_id, new_blob_name); push_task->Wait(); HRUN_CLIENT->DelTask(push_task); } @@ -403,7 +394,7 @@ class Client : public TaskLibClient { const BlobId &blob_id, size_t new_size) { LPointer> push_task = - AsyncTruncateBlobRoot(tag_id, blob_id, new_size); + AsyncTruncateBlobRoot(tag_id, blob_id, new_size); push_task->Wait(); HRUN_CLIENT->DelTask(push_task); } @@ -415,15 +406,17 @@ class Client : public TaskLibClient { void AsyncDestroyBlobConstruct(DestroyBlobTask *task, const TaskNode &task_node, const TagId &tag_id, - const BlobId &blob_id) { + const BlobId &blob_id, + bool update_size = true) { HRUN_CLIENT->ConstructTask( task, task_node, DomainId::GetNode(blob_id.node_id_), - id_, tag_id, blob_id); + id_, tag_id, blob_id, update_size); } void DestroyBlobRoot(const TagId &tag_id, - const BlobId &blob_id) { + const BlobId &blob_id, + bool update_size = true) { LPointer> push_task = - AsyncDestroyBlobRoot(tag_id, blob_id); + AsyncDestroyBlobRoot(tag_id, blob_id, update_size); push_task->Wait(); HRUN_CLIENT->DelTask(push_task); } @@ -431,9 +424,10 @@ class Client : public TaskLibClient { /** Initialize automatic flushing */ void AsyncFlushDataConstruct(FlushDataTask *task, - const TaskNode &task_node) { + const TaskNode &task_node, + size_t period_ms) { HRUN_CLIENT->ConstructTask( - task, task_node, id_); + task, task_node, id_, period_ms); } HRUN_TASK_NODE_PUSH_ROOT(FlushData); @@ -441,13 +435,13 @@ class Client : public TaskLibClient { * Get all blob metadata * */ void AsyncPollBlobMetadataConstruct(PollBlobMetadataTask *task, - const TaskNode &task_node) { + const TaskNode &task_node) { HRUN_CLIENT->ConstructTask( task, task_node, id_); } std::vector PollBlobMetadataRoot() { LPointer> push_task = - AsyncPollBlobMetadataRoot(); + AsyncPollBlobMetadataRoot(); push_task->Wait(); PollBlobMetadataTask *task = push_task->get(); std::vector blob_mdms = @@ -467,7 +461,7 @@ class Client : public TaskLibClient { } std::vector PollTargetMetadataRoot() { LPointer> push_task = - AsyncPollTargetMetadataRoot(); + AsyncPollTargetMetadataRoot(); push_task->Wait(); PollTargetMetadataTask *task = push_task->get(); std::vector target_mdms = @@ -480,4 +474,4 @@ class Client : public TaskLibClient { } // namespace hrun -#endif // HRUN_hermes_blob_mdm_H_ +#endif // HRUN_hermes_blob_mdm_H_ \ No newline at end of file diff --git a/tasks/hermes_blob_mdm/include/hermes_blob_mdm/hermes_blob_mdm_lib_exec.h b/tasks/hermes_blob_mdm/include/hermes_blob_mdm/hermes_blob_mdm_lib_exec.h index 9b702250e..88abb5f58 100644 --- a/tasks/hermes_blob_mdm/include/hermes_blob_mdm/hermes_blob_mdm_lib_exec.h +++ b/tasks/hermes_blob_mdm/include/hermes_blob_mdm/hermes_blob_mdm_lib_exec.h @@ -86,87 +86,172 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kConstruct: { + MonitorConstruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestruct: { + MonitorDestruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kPutBlob: { + MonitorPutBlob(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetBlob: { + MonitorGetBlob(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kTruncateBlob: { + MonitorTruncateBlob(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestroyBlob: { + MonitorDestroyBlob(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kTagBlob: { + MonitorTagBlob(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kBlobHasTag: { + MonitorBlobHasTag(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetBlobId: { + MonitorGetBlobId(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetOrCreateBlobId: { + MonitorGetOrCreateBlobId(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetBlobName: { + MonitorGetBlobName(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetBlobSize: { + MonitorGetBlobSize(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetBlobScore: { + MonitorGetBlobScore(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetBlobBuffers: { + MonitorGetBlobBuffers(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kRenameBlob: { + MonitorRenameBlob(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kReorganizeBlob: { + MonitorReorganizeBlob(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kSetBucketMdm: { + MonitorSetBucketMdm(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kFlushData: { + MonitorFlushData(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kPollBlobMetadata: { + MonitorPollBlobMetadata(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kPollTargetMetadata: { + MonitorPollTargetMetadata(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kConstruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kPutBlob: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetBlob: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kTruncateBlob: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestroyBlob: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kTagBlob: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kBlobHasTag: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetBlobId: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetOrCreateBlobId: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetBlobName: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetBlobSize: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetBlobScore: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetBlobBuffers: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kRenameBlob: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kReorganizeBlob: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kSetBucketMdm: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kFlushData: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kPollBlobMetadata: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kPollTargetMetadata: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } diff --git a/tasks/hermes_blob_mdm/include/hermes_blob_mdm/hermes_blob_mdm_tasks.h b/tasks/hermes_blob_mdm/include/hermes_blob_mdm/hermes_blob_mdm_tasks.h index 332c9768b..f3307a772 100644 --- a/tasks/hermes_blob_mdm/include/hermes_blob_mdm/hermes_blob_mdm_tasks.h +++ b/tasks/hermes_blob_mdm/include/hermes_blob_mdm/hermes_blob_mdm_tasks.h @@ -23,6 +23,12 @@ using hrun::Task; using hrun::TaskFlags; using hrun::DataTransfer; +static inline u32 HashBlobName(const TagId &tag_id, const hshm::charbuf &blob_name) { + u32 h2 = std::hash{}(tag_id); + u32 h1 = std::hash{}(blob_name); + return std::hash{}(h1 ^ h2); +} + /** Phases of the construct task */ using hrun::Admin::CreateTaskStatePhase; class ConstructTaskPhase : public CreateTaskStatePhase { @@ -172,7 +178,7 @@ struct GetOrCreateBlobIdTask : public Task, TaskFlags { const hshm::charbuf &blob_name) : Task(alloc) { // Initialize task task_node_ = task_node; - lane_hash_ = std::hash{}(blob_name); + lane_hash_ = HashBlobName(tag_id, blob_name); prio_ = TaskPrio::kLowLatency; task_state_ = state_id; method_ = Method::kGetOrCreateBlobId; @@ -222,7 +228,7 @@ class PutBlobPhase { #define HERMES_BLOB_REPLACE BIT_OPT(u32, 0) #define HERMES_BLOB_APPEND BIT_OPT(u32, 1) #define HERMES_DID_STAGE_IN BIT_OPT(u32, 2) -#define HERMES_IS_FILE BIT_OPT(u32, 3) +#define HERMES_SHOULD_STAGE BIT_OPT(u32, 3) #define HERMES_BLOB_DID_CREATE BIT_OPT(u32, 4) #define HERMES_GET_BLOB_ID BIT_OPT(u32, 5) #define HERMES_HAS_DERIVED BIT_OPT(u32, 6) @@ -270,7 +276,7 @@ struct PutBlobTask : public Task, TaskFlags lane_hash_ = blob_id.hash_; domain_id_ = domain_id; } else { - lane_hash_ = std::hash{}(blob_name); + lane_hash_ = HashBlobName(tag_id, blob_name); domain_id_ = DomainId::GetNode(HASH_TO_NODE_ID(lane_hash_)); } @@ -283,12 +289,14 @@ struct PutBlobTask : public Task, TaskFlags data_ = data; score_ = score; flags_ = bitfield32_t(flags | ctx.flags_.bits_); + // HILOG(kInfo, "Creating PUT {} of size {}", task_node_, data_size_); } /** Destructor */ ~PutBlobTask() { HSHM_DESTROY_AR(blob_name_); if (IsDataOwner()) { + // HILOG(kInfo, "Actually freeing PUT {} of size {}", task_node_, data_size_); HRUN_CLIENT->FreeBuffer(data_); } } @@ -326,8 +334,8 @@ struct PutBlobTask : public Task, TaskFlags HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -346,11 +354,8 @@ struct GetBlobTask : public Task, TaskFlags INOUT BlobId blob_id_; IN size_t blob_off_; IN hipc::Pointer data_; - INOUT ssize_t data_size_; + INOUT size_t data_size_; IN bitfield32_t flags_; - TEMP int phase_ = GetBlobPhase::kStart; - TEMP hipc::ShmArchive> bdev_reads_; - TEMP PutBlobTask *stage_task_ = nullptr; /** SHM default constructor */ HSHM_ALWAYS_INLINE explicit @@ -366,7 +371,7 @@ struct GetBlobTask : public Task, TaskFlags const hshm::charbuf &blob_name, const BlobId &blob_id, size_t off, - ssize_t data_size, + size_t data_size, hipc::Pointer &data, const Context &ctx, u32 flags) : Task(alloc) { @@ -375,12 +380,12 @@ struct GetBlobTask : public Task, TaskFlags prio_ = TaskPrio::kLowLatency; task_state_ = state_id; method_ = Method::kGetBlob; - task_flags_.SetBits(TASK_LOW_LATENCY); + task_flags_.SetBits(TASK_LOW_LATENCY | TASK_COROUTINE); if (!blob_id.IsNull()) { lane_hash_ = blob_id.hash_; domain_id_ = domain_id; } else { - lane_hash_ = std::hash{}(blob_name); + lane_hash_ = HashBlobName(tag_id, blob_name); domain_id_ = DomainId::GetNode(HASH_TO_NODE_ID(lane_hash_)); } @@ -390,7 +395,7 @@ struct GetBlobTask : public Task, TaskFlags blob_off_ = off; data_size_ = data_size; data_ = data; - flags_ = bitfield32_t(flags); + flags_ = bitfield32_t(flags | ctx.flags_.bits_); HSHM_MAKE_AR(blob_name_, alloc, blob_name); } @@ -398,7 +403,7 @@ struct GetBlobTask : public Task, TaskFlags template HSHM_ALWAYS_INLINE void Get(T &obj) { - char *data = HRUN_CLIENT->GetPrivatePointer(data_); + char *data = HRUN_CLIENT->GetDataPointer(data_); std::stringstream ss(std::string(data, data_size_)); cereal::BinaryInputArchive ar(ss); ar >> obj; @@ -444,14 +449,15 @@ struct GetBlobTask : public Task, TaskFlags if (flags_.Any(HERMES_GET_BLOB_ID)) { ar(blob_id_); } + ar(data_size_); } /** Create group */ HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -506,8 +512,8 @@ struct TagBlobTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -567,8 +573,8 @@ struct BlobHasTagTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -595,7 +601,7 @@ struct GetBlobIdTask : public Task, TaskFlags { const hshm::charbuf &blob_name) : Task(alloc) { // Initialize task task_node_ = task_node; - lane_hash_ = std::hash{}(blob_name); + lane_hash_ = HashBlobName(tag_id, blob_name); prio_ = TaskPrio::kLowLatency; task_state_ = state_id; method_ = Method::kGetBlobId; @@ -629,8 +635,8 @@ struct GetBlobIdTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -692,8 +698,8 @@ struct GetBlobNameTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -728,7 +734,7 @@ struct GetBlobSizeTask : public Task, TaskFlags { lane_hash_ = blob_id.hash_; domain_id_ = domain_id; } else { - lane_hash_ = std::hash{}(blob_name); + lane_hash_ = HashBlobName(tag_id, blob_name); domain_id_ = DomainId::GetNode(HASH_TO_NODE_ID(lane_hash_)); } @@ -760,8 +766,8 @@ struct GetBlobSizeTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -815,8 +821,8 @@ struct GetBlobScoreTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -876,8 +882,8 @@ struct GetBlobBuffersTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -941,8 +947,8 @@ struct RenameBlobTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -997,8 +1003,8 @@ struct TruncateBlobTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -1013,6 +1019,7 @@ struct DestroyBlobPhase { struct DestroyBlobTask : public Task, TaskFlags { IN TagId tag_id_; IN BlobId blob_id_; + IN bool update_size_; TEMP int phase_ = DestroyBlobPhase::kFreeBuffers; TEMP hipc::ShmArchive> free_tasks_; @@ -1027,7 +1034,8 @@ struct DestroyBlobTask : public Task, TaskFlags { const DomainId &domain_id, const TaskStateId &state_id, const TagId &tag_id, - const BlobId &blob_id) : Task(alloc) { + const BlobId &blob_id, + bool update_size = true) : Task(alloc) { // Initialize task task_node_ = task_node; lane_hash_ = blob_id.hash_; @@ -1040,13 +1048,14 @@ struct DestroyBlobTask : public Task, TaskFlags { // Custom params tag_id_ = tag_id; blob_id_ = blob_id; + update_size_ = update_size; } /** (De)serialize message call */ template void SerializeStart(Ar &ar) { task_serialize(ar); - ar(tag_id_, blob_id_); + ar(tag_id_, blob_id_, update_size_); } /** (De)serialize message return */ @@ -1058,8 +1067,8 @@ struct DestroyBlobTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -1098,14 +1107,15 @@ struct ReorganizeBlobTask : public Task, TaskFlags { const BlobId &blob_id, float score, u32 node_id, - bool is_user_score) : Task(alloc) { + bool is_user_score, + u32 task_flags = TASK_LOW_LATENCY | TASK_FIRE_AND_FORGET) : Task(alloc) { // Initialize task task_node_ = task_node; lane_hash_ = blob_id.hash_; prio_ = TaskPrio::kLowLatency; task_state_ = state_id; method_ = Method::kReorganizeBlob; - task_flags_.SetBits(TASK_LOW_LATENCY | TASK_FIRE_AND_FORGET); + task_flags_.SetBits(task_flags); domain_id_ = domain_id; // Custom params @@ -1132,8 +1142,8 @@ struct ReorganizeBlobTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -1148,11 +1158,12 @@ struct FlushDataTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE explicit FlushDataTask(hipc::Allocator *alloc, const TaskNode &task_node, - const TaskStateId &state_id) : Task(alloc) { + const TaskStateId &state_id, + size_t period_ms) : Task(alloc) { // Initialize task task_node_ = task_node; lane_hash_ = 0; - prio_ = TaskPrio::kLowLatency; + prio_ = TaskPrio::kLongRunningTether; task_state_ = state_id; method_ = Method::kFlushData; task_flags_.SetBits( @@ -1161,7 +1172,7 @@ struct FlushDataTask : public Task, TaskFlags { TASK_LONG_RUNNING | TASK_COROUTINE | TASK_REMOTE_DEBUG_MARK); - SetPeriodSec(2); // TODO(llogan): don't hardcode this + SetPeriodMs((double)period_ms); domain_id_ = DomainId::GetLocal(); } @@ -1199,13 +1210,15 @@ struct FlushDataTask : public Task, TaskFlags { }; /** A task to collect blob metadata */ -struct PollBlobMetadataTask : public Task, TaskFlags { - OUT hipc::ShmArchive my_blob_mdms_; +struct PollBlobMetadataTask : public Task, TaskFlags { + TEMP hipc::ShmArchive my_blob_mdm_; TEMP hipc::ShmArchive> blob_mdms_; /** SHM default constructor */ HSHM_ALWAYS_INLINE explicit - PollBlobMetadataTask(hipc::Allocator *alloc) : Task(alloc) {} + PollBlobMetadataTask(hipc::Allocator *alloc) : Task(alloc) { + HSHM_MAKE_AR0(blob_mdms_, alloc) + } /** Emplace constructor */ HSHM_ALWAYS_INLINE explicit @@ -1222,8 +1235,8 @@ struct PollBlobMetadataTask : public Task, TaskFlags { domain_id_ = DomainId::GetGlobal(); // Custom params - HSHM_MAKE_AR0(my_blob_mdms_, alloc) HSHM_MAKE_AR0(blob_mdms_, alloc) + HSHM_MAKE_AR0(my_blob_mdm_, alloc) } /** Serialize blob info */ @@ -1231,7 +1244,7 @@ struct PollBlobMetadataTask : public Task, TaskFlags { std::stringstream ss; cereal::BinaryOutputArchive ar(ss); ar << blob_info; - (*my_blob_mdms_) = ss.str(); + (*my_blob_mdm_) = ss.str(); } /** Deserialize blob info */ @@ -1257,39 +1270,46 @@ struct PollBlobMetadataTask : public Task, TaskFlags { /** Deserialize final query output */ std::vector DeserializeBlobMetadata() { std::vector blob_mdms; - DeserializeBlobMetadata(my_blob_mdms_->str(), blob_mdms); + DeserializeBlobMetadata((*my_blob_mdm_).str(), blob_mdms); return blob_mdms; } /** Destructor */ ~PollBlobMetadataTask() { - HSHM_DESTROY_AR(my_blob_mdms_) HSHM_DESTROY_AR(blob_mdms_) + HSHM_DESTROY_AR(my_blob_mdm_) } /** Duplicate message */ void Dup(hipc::Allocator *alloc, PollBlobMetadataTask &other) { task_dup(other); HSHM_MAKE_AR(blob_mdms_, alloc, *other.blob_mdms_) - HSHM_MAKE_AR(my_blob_mdms_, alloc, *other.my_blob_mdms_) + HSHM_MAKE_AR(my_blob_mdm_, alloc, *other.my_blob_mdm_) } /** Process duplicate message output */ void DupEnd(u32 replica, PollBlobMetadataTask &dup_task) { - (*blob_mdms_)[replica] = (*dup_task.my_blob_mdms_); + (*blob_mdms_)[replica] = (*dup_task.my_blob_mdm_); } /** (De)serialize message call */ template void SerializeStart(Ar &ar) { task_serialize(ar); - ar(my_blob_mdms_); + ar(my_blob_mdm_); } /** (De)serialize message return */ template - void SerializeEnd(u32 replica, Ar &ar) { - ar((*blob_mdms_)[replica]); + void SaveEnd(Ar &ar) { + ar(my_blob_mdm_); + } + + /** (De)serialize message return */ + template + void LoadEnd(u32 replica, Ar &ar) { + ar(my_blob_mdm_); + DupEnd(replica, *this); } /** Begin replication */ @@ -1311,13 +1331,15 @@ struct PollBlobMetadataTask : public Task, TaskFlags { }; /** A task to collect blob metadata */ -struct PollTargetMetadataTask : public Task, TaskFlags { +struct PollTargetMetadataTask : public Task, TaskFlags { OUT hipc::ShmArchive my_target_mdms_; TEMP hipc::ShmArchive> target_mdms_; /** SHM default constructor */ HSHM_ALWAYS_INLINE explicit - PollTargetMetadataTask(hipc::Allocator *alloc) : Task(alloc) {} + PollTargetMetadataTask(hipc::Allocator *alloc) : Task(alloc) { + HSHM_MAKE_AR0(target_mdms_, alloc) + } /** Emplace constructor */ HSHM_ALWAYS_INLINE explicit @@ -1380,11 +1402,7 @@ struct PollTargetMetadataTask : public Task, TaskFlags } /** Duplicate message */ - void Dup(hipc::Allocator *alloc, PollTargetMetadataTask &other) { - task_dup(other); - HSHM_MAKE_AR(target_mdms_, alloc, *other.target_mdms_) - HSHM_MAKE_AR(my_target_mdms_, alloc, *other.my_target_mdms_) - } + void Dup(hipc::Allocator *alloc, PollTargetMetadataTask &other) {} /** Process duplicate message output */ void DupEnd(u32 replica, PollTargetMetadataTask &dup_task) { @@ -1400,8 +1418,15 @@ struct PollTargetMetadataTask : public Task, TaskFlags /** (De)serialize message return */ template - void SerializeEnd(u32 replica, Ar &ar) { - ar((*target_mdms_)[replica]); + void SaveEnd(Ar &ar) { + ar(my_target_mdms_); + } + + /** (De)serialize message return */ + template + void LoadEnd(u32 replica, Ar &ar) { + ar(my_target_mdms_); + DupEnd(replica, *this); } /** Begin replication */ diff --git a/tasks/hermes_blob_mdm/src/hermes_blob_mdm.cc b/tasks/hermes_blob_mdm/src/hermes_blob_mdm.cc index 984fc3d16..1a742d4c9 100644 --- a/tasks/hermes_blob_mdm/src/hermes_blob_mdm.cc +++ b/tasks/hermes_blob_mdm/src/hermes_blob_mdm.cc @@ -46,6 +46,7 @@ class Server : public TaskLib { * ===================================*/ std::vector target_tasks_; std::vector targets_; + bdev::Client *fallback_target_; std::unordered_map target_map_; Client blob_mdm_; bucket_mdm::Client bkt_mdm_; @@ -56,6 +57,7 @@ class Server : public TaskLib { public: Server() = default; + /** Construct blob mdm and it targets */ void Construct(ConstructTask *task, RunContext &rctx) { id_alloc_ = 0; node_id_ = HRUN_CLIENT->node_id_; @@ -77,7 +79,7 @@ class Server : public TaskLib { bdev::ConstructTask *create_task = client.AsyncCreate( task->task_node_ + 1, DomainId::GetLocal(), - "hermes_" + dev.dev_name_, + "hermes_" + dev.dev_name_ + "/" + std::to_string(HRUN_CLIENT->node_id_), dev_type, dev).ptr_; target_tasks_.emplace_back(create_task); @@ -87,24 +89,43 @@ class Server : public TaskLib { tgt_task->Wait(task); bdev::Client &client = targets_[i]; client.AsyncCreateComplete(tgt_task); + } + std::sort(targets_.begin(), targets_.end(), + [](const bdev::Client &a, const bdev::Client &b) { + return a.bandwidth_ > b.bandwidth_; + }); + float bw_max = targets_.front().bandwidth_; + float bw_min = targets_.back().bandwidth_; + for (bdev::Client &client : targets_) { + client.bw_score_ = (client.bandwidth_ - bw_min) / (bw_max - bw_min); + client.score_ = client.bw_score_; + } + for (bdev::Client &client : targets_) { target_map_.emplace(client.id_, &client); + HILOG(kInfo, "(node {}) Target {} has bw {} and score {}", HRUN_CLIENT->node_id_, + client.id_, client.bandwidth_, client.bw_score_); } - blob_mdm_.Init(id_); + fallback_target_ = &targets_.back(); + blob_mdm_.Init(id_, HRUN_ADMIN->queue_id_); HILOG(kInfo, "(node {}) Created Blob MDM", HRUN_CLIENT->node_id_); task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } + /** Destroy blob mdm */ void Destruct(DestructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } private: /** Get the globally unique blob name */ const hshm::charbuf GetBlobNameWithBucket(TagId tag_id, const hshm::charbuf &blob_name) { hshm::charbuf new_name(sizeof(TagId) + blob_name.size()); hrun::LocalSerialize srl(new_name); - srl << tag_id.node_id_; - srl << tag_id.unique_; + srl << tag_id; srl << blob_name; return new_name; } @@ -115,31 +136,58 @@ class Server : public TaskLib { * */ void SetBucketMdm(SetBucketMdmTask *task, RunContext &rctx) { if (bkt_mdm_.id_.IsNull()) { - bkt_mdm_.Init(task->bkt_mdm_); - stager_mdm_.Init(task->stager_mdm_); - op_mdm_.Init(task->op_mdm_); - // TODO(llogan): Add back - flush_task_ = blob_mdm_.AsyncFlushData(task->task_node_ + 1); + bkt_mdm_.Init(task->bkt_mdm_, HRUN_ADMIN->queue_id_); + stager_mdm_.Init(task->stager_mdm_, HRUN_ADMIN->queue_id_); + op_mdm_.Init(task->op_mdm_, HRUN_ADMIN->queue_id_); + flush_task_ = blob_mdm_.AsyncFlushData( + task->task_node_ + 1, HERMES_SERVER_CONF.borg_.flush_period_); } task->SetModuleComplete(); } + void MonitorSetBucketMdm(u32 mode, SetBucketMdmTask *task, RunContext &rctx) { + } /** New score */ - float MakeScore(BlobInfo &blob_info, hshm::Timepoint &now) { - float freq_score = blob_info.access_freq_ / 5; - float access_score = (float)(1 - (blob_info.last_access_.GetSecFromStart(now) / 5)); - if (freq_score > 1) { - freq_score = 1; + float NormalizeScore(float score) { + if (score > 1) { + return 1; } - if (access_score > 1) { - access_score = 1; + if (score < 0) { + return 0; } - float data_score = std::max(freq_score, access_score); + return score; + } + float MakeScore(BlobInfo &blob_info, hshm::Timepoint &now) { + ServerConfig &server = HERMES_CONF->server_config_; + // Frequency score: how many times blob accessed? + float freq_min = server.borg_.freq_min_; + float freq_diff = server.borg_.freq_max_ - freq_min; + float freq_score = NormalizeScore((blob_info.access_freq_ - freq_min) / freq_diff); + // Temporal score: how recently the blob was accessed? + float time_diff = blob_info.last_access_.GetSecFromStart(now); + float rec_min = server.borg_.recency_min_; + float rec_max = server.borg_.recency_max_; + float rec_diff = rec_max - rec_min; + float temporal_score = NormalizeScore((time_diff - rec_min) / rec_diff); + temporal_score = 1 - temporal_score; + // Access score: was the blob accessed recently or frequently? + float access_score = std::max(freq_score, temporal_score); float user_score = blob_info.user_score_; + // Final scores if (!blob_info.flags_.Any(HERMES_USER_SCORE_STATIONARY)) { - user_score *= data_score; + return user_score * access_score; + } else { + return std::max(access_score, user_score); + } + } + const bdev::Client& FindNearestTarget(float score) { + for (const bdev::Client &cmp_tgt: targets_) { + if (cmp_tgt.score_ > score + .05) { + continue; + } + return cmp_tgt; } - return std::max(data_score, user_score); + return targets_.back(); } /** Check if blob should be reorganized */ @@ -147,22 +195,58 @@ class Server : public TaskLib { bool ShouldReorganize(BlobInfo &blob_info, float score, TaskNode &task_node) { -// for (BufferInfo &buf : blob_info.buffers_) { -// TargetInfo &target = *target_map_[buf.tid_]; -// Histogram &hist = target.monitor_task_->score_hist_; -// if constexpr(UPDATE_SCORE) { -// target.AsyncUpdateScore(task_node + 1, -// blob_info.score_, score); -// } -// u32 percentile = hist.GetPercentile(score); -// size_t rem_cap = target.monitor_task_->rem_cap_; -// size_t max_cap = target.max_cap_; -// if (rem_cap < max_cap / 10) { -// if (percentile < 10 || percentile > 90) { -// return true; -// } -// } -// } + ServerConfig &server = HERMES_CONF->server_config_; + for (BufferInfo &buf : blob_info.buffers_) { + TargetInfo &target = *target_map_[buf.tid_]; + Histogram &hist = target.monitor_task_->score_hist_; + u32 percentile = hist.GetPercentile(score); + u32 precentile_lt = hist.GetPercentileLT(score); + size_t rem_cap = target.monitor_task_->rem_cap_; + size_t max_cap = target.max_cap_; + float borg_cap_min = target.borg_min_thresh_; + float borg_cap_max = target.borg_max_thresh_; + // float min_score = hist.GetQuantile(0); + // Update the target score + target.score_ = target.bw_score_; + // Update blob score + if constexpr(UPDATE_SCORE) { + u32 bin_orig = hist.GetBin(blob_info.score_); + u32 bin_new = hist.GetBin(score); + if (bin_orig != bin_new) { + target.AsyncUpdateScore(task_node + 1, + blob_info.score_, score); + } + } + // Determine if the blob should be reorganized + // Get the target with minimum difference in score to this blob + if (abs(target.score_ - score) < .1) { + continue; + } + const bdev::Client &cmp_tgt = FindNearestTarget(score); + if (cmp_tgt.id_ == target.id_) { + continue; + } + if (cmp_tgt.score_ <= target.score_) { + // Demote if we have sufficiently low capacity + if (rem_cap < max_cap * borg_cap_min) { + HILOG(kInfo, "Demoting blob {} of score {} from tgt={} tgt_score={} to tgt={} tgt_score={}", + blob_info.blob_id_, blob_info.score_, + target.id_, target.score_, + cmp_tgt.id_, cmp_tgt.score_); + return true; + } + } else { + // Promote if the guy above us has sufficiently high capacity + float cmp_rem_cap = cmp_tgt.monitor_task_->rem_cap_; + if (cmp_rem_cap > blob_info.blob_size_) { + HILOG(kInfo, "Promoting blob {} of score {} from tgt={} tgt_score={} to tgt={} tgt_score={}", + blob_info.blob_id_, blob_info.score_, + target.id_, target.score_, + cmp_tgt.id_, cmp_tgt.score_); + return true; + } + } + } return false; } @@ -170,34 +254,45 @@ class Server : public TaskLib { * Long-running task to stage out data periodically and * reorganize blobs * */ + struct FlushInfo { + BlobInfo *blob_info_; + LPointer stage_task_; + size_t mod_count_; + }; void FlushData(FlushDataTask *task, RunContext &rctx) { hshm::Timepoint now; now.Now(); // Get the blob info data structure BLOB_MAP_T &blob_map = blob_map_[rctx.lane_id_]; + std::vector stage_tasks; + stage_tasks.reserve(256); for (auto &it : blob_map) { BlobInfo &blob_info = it.second; // Update blob scores - // TODO(llogan): Add back -// float new_score = MakeScore(blob_info, now); -// if (ShouldReorganize(blob_info, new_score, task->task_node_)) { -// blob_mdm_.AsyncReorganizeBlob(task->task_node_ + 1, -// blob_info.tag_id_, -// blob_info.blob_id_, -// new_score, 0, false); -// } -// blob_info.access_freq_ = 0; -// blob_info.score_ = new_score; + float new_score = MakeScore(blob_info, now); + blob_info.score_ = new_score; + if (ShouldReorganize(blob_info, new_score, task->task_node_)) { + LPointer reorg_task = + blob_mdm_.AsyncReorganizeBlob(task->task_node_ + 1, + blob_info.tag_id_, + blob_info.blob_id_, + new_score, 0, false, + TASK_LOW_LATENCY); + reorg_task->Wait(task); + HRUN_CLIENT->DelTask(reorg_task); + } + blob_info.access_freq_ = 0; // Flush data + FlushInfo flush_info; + flush_info.blob_info_ = &blob_info; + flush_info.mod_count_ = blob_info.mod_count_; if (blob_info.last_flush_ > 0 && - blob_info.mod_count_ > blob_info.last_flush_) { + flush_info.mod_count_ > blob_info.last_flush_) { HILOG(kDebug, "Flushing blob {} (mod_count={}, last_flush={})", - blob_info.blob_id_, blob_info.mod_count_, blob_info.last_flush_); - blob_info.last_flush_ = 1; - blob_info.mod_count_ = 0; - blob_info.UpdateWriteStats(); - LPointer data = HRUN_CLIENT->AllocateBuffer(blob_info.blob_size_); + blob_info.blob_id_, flush_info.mod_count_, blob_info.last_flush_); + LPointer data = HRUN_CLIENT->AllocateBufferServer( + blob_info.blob_size_, task); LPointer get_blob = blob_mdm_.AsyncGetBlob(task->task_node_ + 1, blob_info.tag_id_, @@ -206,11 +301,35 @@ class Server : public TaskLib { 0, blob_info.blob_size_, data.shm_); get_blob->Wait(task); - stager_mdm_.AsyncStageOut(task->task_node_ + 1, - blob_info.tag_id_, - blob_info.name_, - data.shm_, blob_info.blob_size_, - TASK_DATA_OWNER | TASK_FIRE_AND_FORGET); + HRUN_CLIENT->DelTask(get_blob); + flush_info.stage_task_ = + stager_mdm_.AsyncStageOut(task->task_node_ + 1, + blob_info.tag_id_, + blob_info.name_, + data.shm_, blob_info.blob_size_, + TASK_DATA_OWNER); + stage_tasks.emplace_back(flush_info); + } + if (stage_tasks.size() == 256) { + break; + } + } + + for (FlushInfo &flush_info : stage_tasks) { + BlobInfo &blob_info = *flush_info.blob_info_; + flush_info.stage_task_->Wait(task); + blob_info.last_flush_ = flush_info.mod_count_; + HRUN_CLIENT->DelTask(flush_info.stage_task_); + } + } + void MonitorFlushData(u32 mode, FlushDataTask *task, RunContext &rctx) { + BLOB_MAP_T &blob_map = blob_map_[rctx.lane_id_]; + for (auto &it : blob_map) { + BlobInfo &blob_info = it.second; + if (blob_info.last_flush_ > 0 && + blob_info.mod_count_ > blob_info.last_flush_) { + rctx.flush_->count_ += 1; + return; } } } @@ -225,38 +344,33 @@ class Server : public TaskLib { task->blob_id_ = GetOrCreateBlobId(task->tag_id_, task->lane_hash_, blob_name, rctx, task->flags_); } - HILOG(kDebug, "Beginning PUT for {}", blob_name.str()); + HILOG(kDebug, "Beginning PUT for (hash: {})", + std::hash{}(blob_name)); BLOB_MAP_T &blob_map = blob_map_[rctx.lane_id_]; BlobInfo &blob_info = blob_map[task->blob_id_]; - - // Update the blob info - if (task->flags_.Any(HERMES_BLOB_DID_CREATE)) { - blob_info.name_ = std::move(blob_name); - blob_info.blob_id_ = task->blob_id_; - blob_info.tag_id_ = task->tag_id_; - blob_info.blob_size_ = 0; - blob_info.max_blob_size_ = 0; - blob_info.score_ = task->score_; - blob_info.mod_count_ = 0; - blob_info.access_freq_ = 0; - blob_info.last_flush_ = 0; - blob_info.UpdateWriteStats(); - if (task->flags_.Any(HERMES_IS_FILE)) { - blob_info.mod_count_ = 1; - blob_info.last_flush_ = 1; - LPointer stage_task = - stager_mdm_.AsyncStageIn(task->task_node_ + 1, - task->tag_id_, - blob_info.name_, - task->score_, 0); - stage_task->Wait(task); - HRUN_CLIENT->DelTask(stage_task); - } - } else { - // Modify existing blob - blob_info.UpdateWriteStats(); + blob_info.score_ = task->score_; + blob_info.user_score_ = task->score_; + + // Stage Blob + if (task->flags_.Any(HERMES_SHOULD_STAGE) && blob_info.last_flush_ == 0) { + HILOG(kDebug, "This file has not yet been flushed"); + blob_info.last_flush_ = 1; + LPointer stage_task = + stager_mdm_.AsyncStageIn(task->task_node_ + 1, + task->tag_id_, + blob_info.name_, + task->score_, 0); + stage_task->Wait(task); + blob_info.mod_count_ = 1; + HRUN_CLIENT->DelTask(stage_task); + } + if (task->flags_.Any(HERMES_SHOULD_STAGE)) { + HILOG(kDebug, "This is marked as a file: {} {}", + blob_info.mod_count_, blob_info.last_flush_); } + ssize_t bkt_size_diff = 0; if (task->flags_.Any(HERMES_BLOB_REPLACE)) { + bkt_size_diff -= blob_info.blob_size_; PutBlobFreeBuffersPhase(blob_info, task, rctx); } @@ -266,19 +380,25 @@ class Server : public TaskLib { if (needed_space > blob_info.max_blob_size_) { size_diff = needed_space - blob_info.max_blob_size_; } - blob_info.blob_size_ += size_diff; - HILOG(kDebug, "The size diff is {} bytes", size_diff) + size_t min_blob_size = task->blob_off_ + task->data_size_; + if (min_blob_size > blob_info.blob_size_) { + blob_info.blob_size_ = task->blob_off_ + task->data_size_; + } + bkt_size_diff += (ssize_t)size_diff; + HILOG(kDebug, "The size diff is {} bytes (bkt diff {})", size_diff, bkt_size_diff) // Use DPE std::vector schema_vec; if (size_diff > 0) { Context ctx; auto *dpe = DpeFactory::Get(ctx.dpe_); + ctx.blob_score_ = task->score_; dpe->Placement({size_diff}, targets_, ctx, schema_vec); } // Allocate blob buffers for (PlacementSchema &schema : schema_vec) { + schema.plcmnts_.emplace_back(0, fallback_target_->id_); for (size_t sub_idx = 0; sub_idx < schema.plcmnts_.size(); ++sub_idx) { SubPlacement &placement = schema.plcmnts_[sub_idx]; TargetInfo &bdev = *target_map_[placement.tid_]; @@ -288,12 +408,16 @@ class Server : public TaskLib { placement.size_, blob_info.buffers_); alloc_task->Wait(task); +// HILOG(kInfo, "(node {}) Placing {}/{} bytes in target {} of bw {}", +// HRUN_CLIENT->node_id_, +// alloc_task->alloc_size_, task->data_size_, +// placement.tid_, bdev.bandwidth_) if (alloc_task->alloc_size_ < alloc_task->size_) { - // SubPlacement &next_placement = schema.plcmnts_[sub_idx + 1]; - // size_t diff = alloc_task->size_ - alloc_task->alloc_size_; - // next_placement.size_ += diff; - HELOG(kFatal, "Ran outta space in this tier -- will fix soon") + SubPlacement &next_placement = schema.plcmnts_[sub_idx + 1]; + size_t diff = alloc_task->size_ - alloc_task->alloc_size_; + next_placement.size_ += diff; } + // bdev.monitor_task_->rem_cap_ -= alloc_task->alloc_size_; HRUN_CLIENT->DelTask(alloc_task); } } @@ -301,18 +425,26 @@ class Server : public TaskLib { // Place blob in buffers std::vector> write_tasks; write_tasks.reserve(blob_info.buffers_.size()); - size_t blob_off = 0, buf_off = 0; - char *blob_buf = HRUN_CLIENT->GetPrivatePointer(task->data_); + size_t blob_off = task->blob_off_, buf_off = 0; + size_t buf_left = 0, buf_right = 0; + size_t blob_right = task->blob_off_ + task->data_size_; + char *blob_buf = HRUN_CLIENT->GetDataPointer(task->data_); HILOG(kDebug, "Number of buffers {}", blob_info.buffers_.size()); + bool found_left = false; for (BufferInfo &buf : blob_info.buffers_) { - size_t blob_left = blob_off; - size_t blob_right = blob_off + buf.t_size_; - if (blob_left <= task->blob_off_ && task->blob_off_ < blob_right) { - size_t rel_off = task->blob_off_ - blob_off; + buf_right = buf_left + buf.t_size_; + if (blob_off >= blob_right) { + break; + } + if (buf_left <= blob_off && blob_off < buf_right) { + found_left = true; + } + if (found_left) { + size_t rel_off = blob_off - buf_left; size_t tgt_off = buf.t_off_ + rel_off; size_t buf_size = buf.t_size_ - rel_off; - if (blob_off + buf_size > task->blob_off_ + task->data_size_) { - buf_size = task->blob_off_ + task->data_size_ - blob_off; + if (buf_right > blob_right) { + buf_size = blob_right - (buf_left + rel_off); } HILOG(kDebug, "Writing {} bytes at off {} from target {}", buf_size, tgt_off, buf.tid_) TargetInfo &target = *target_map_[buf.tid_]; @@ -322,8 +454,9 @@ class Server : public TaskLib { tgt_off, buf_size); write_tasks.emplace_back(write_task); buf_off += buf_size; + blob_off = buf_right; } - blob_off += buf.t_size_; + buf_left += buf.t_size_; } blob_info.max_blob_size_ = blob_off; @@ -334,14 +467,21 @@ class Server : public TaskLib { } // Update information - int update_mode = bucket_mdm::UpdateSizeMode::kAdd; - if (task->flags_.Any(HERMES_IS_FILE)) { - update_mode = bucket_mdm::UpdateSizeMode::kCap; - } - bkt_mdm_.AsyncUpdateSize(task->task_node_ + 1, - task->tag_id_, - task->blob_off_ + task->data_size_, - update_mode); + if (task->flags_.Any(HERMES_SHOULD_STAGE)) { + // TODO(llogan): Move to data stager + adapter::BlobPlacement p; + std::string blob_name_str = task->blob_name_->str(); + p.DecodeBlobName(blob_name_str, 1 << 20); + bkt_mdm_.AsyncUpdateSize(task->task_node_ + 1, + task->tag_id_, + p.bucket_off_ + task->blob_off_ + task->data_size_, + bucket_mdm::UpdateSizeMode::kCap); + } else { + bkt_mdm_.AsyncUpdateSize(task->task_node_ + 1, + task->tag_id_, + bkt_size_diff, + bucket_mdm::UpdateSizeMode::kAdd); + } if (task->flags_.Any(HERMES_BLOB_DID_CREATE)) { bkt_mdm_.AsyncTagAddBlob(task->task_node_ + 1, task->tag_id_, @@ -358,17 +498,20 @@ class Server : public TaskLib { // Free data HILOG(kDebug, "Completing PUT for {}", blob_name.str()); + blob_info.UpdateWriteStats(); task->SetModuleComplete(); } + void MonitorPutBlob(u32 mode, PutBlobTask *task, RunContext &rctx) { + } /** Release buffers */ void PutBlobFreeBuffersPhase(BlobInfo &blob_info, PutBlobTask *task, RunContext &rctx) { for (BufferInfo &buf : blob_info.buffers_) { TargetInfo &target = *target_map_[buf.tid_]; std::vector buf_vec = {buf}; -// target.AsyncFree(task->task_node_ + 1, -// blob_info.score_, -// std::move(buf_vec), true); + target.AsyncFree(task->task_node_ + 1, + blob_info.score_, + std::move(buf_vec), true); } blob_info.buffers_.clear(); blob_info.max_blob_size_ = 0; @@ -377,17 +520,6 @@ class Server : public TaskLib { /** Get a blob's data */ void GetBlob(GetBlobTask *task, RunContext &rctx) { - switch (task->phase_) { - case GetBlobPhase::kStart: { - GetBlobGetPhase(task, rctx); - } - case GetBlobPhase::kWait: { - GetBlobWaitPhase(task, rctx); - } - } - } - - void GetBlobGetPhase(GetBlobTask *task, RunContext &rctx) { if (task->blob_id_.IsNull()) { hshm::charbuf blob_name = hshm::to_charbuf(*task->blob_name_); task->blob_id_ = GetOrCreateBlobId(task->tag_id_, task->lane_hash_, @@ -395,23 +527,45 @@ class Server : public TaskLib { } BLOB_MAP_T &blob_map = blob_map_[rctx.lane_id_]; BlobInfo &blob_info = blob_map[task->blob_id_]; - HSHM_MAKE_AR0(task->bdev_reads_, nullptr); - std::vector &read_tasks = *task->bdev_reads_; + + // Stage Blob + if (task->flags_.Any(HERMES_SHOULD_STAGE) && blob_info.last_flush_ == 0) { + // TODO(llogan): Don't hardcore score = 1 + blob_info.last_flush_ = 1; + LPointer stage_task = + stager_mdm_.AsyncStageIn(task->task_node_ + 1, + task->tag_id_, + blob_info.name_, + 1, 0); + stage_task->Wait(task); + HRUN_CLIENT->DelTask(stage_task); + } + + // Read blob from buffers + std::vector read_tasks; read_tasks.reserve(blob_info.buffers_.size()); HILOG(kDebug, "Getting blob {} of size {} starting at offset {} (total_blob_size={}, buffers={})", task->blob_id_, task->data_size_, task->blob_off_, blob_info.blob_size_, blob_info.buffers_.size()); - size_t blob_off = 0, buf_off = 0; - hipc::mptr blob_data_mptr(task->data_); - char *blob_buf = blob_data_mptr.get(); + size_t blob_off = task->blob_off_; + size_t buf_left = 0, buf_right = 0; + size_t buf_off = 0; + size_t blob_right = task->blob_off_ + task->data_size_; + bool found_left = false; + char *blob_buf = HRUN_CLIENT->GetDataPointer(task->data_); for (BufferInfo &buf : blob_info.buffers_) { - size_t blob_left = blob_off; - size_t blob_right = blob_off + buf.t_size_; - if (blob_left <= task->blob_off_ && task->blob_off_ < blob_right) { - size_t rel_off = task->blob_off_ - blob_off; + buf_right = buf_left + buf.t_size_; + if (blob_off >= blob_right) { + break; + } + if (buf_left <= blob_off && blob_off < buf_right) { + found_left = true; + } + if (found_left) { + size_t rel_off = blob_off - buf_left; size_t tgt_off = buf.t_off_ + rel_off; size_t buf_size = buf.t_size_ - rel_off; - if (blob_off + buf_size > task->blob_off_ + task->data_size_) { - buf_size = task->blob_off_ + task->data_size_ - blob_off; + if (buf_right > blob_right) { + buf_size = blob_right - (buf_left + rel_off); } HILOG(kDebug, "Loading {} bytes at off {} from target {}", buf_size, tgt_off, buf.tid_) TargetInfo &target = *target_map_[buf.tid_]; @@ -420,26 +574,19 @@ class Server : public TaskLib { tgt_off, buf_size).ptr_; read_tasks.emplace_back(read_task); buf_off += buf_size; + blob_off = buf_right; } - blob_off += buf.t_size_; - } - task->phase_ = GetBlobPhase::kWait; - } - - void GetBlobWaitPhase(GetBlobTask *task, RunContext &rctx) { - std::vector &read_tasks = *task->bdev_reads_; - for (bdev::ReadTask *&read_task : read_tasks) { - if (!read_task->IsComplete()) { - return; - } + buf_left += buf.t_size_; } for (bdev::ReadTask *&read_task : read_tasks) { + read_task->Wait(task); HRUN_CLIENT->DelTask(read_task); } - HSHM_DESTROY_AR(task->bdev_reads_); - HILOG(kDebug, "GetBlobTask complete"); + task->data_size_ = buf_off; task->SetModuleComplete(); } + void MonitorGetBlob(u32 mode, GetBlobTask *task, RunContext &rctx) { + } /** * Tag a blob @@ -455,6 +602,8 @@ class Server : public TaskLib { blob.tags_.push_back(task->tag_); task->SetModuleComplete(); } + void MonitorTagBlob(u32 mode, TagBlobTask *task, RunContext &rctx) { + } /** * Check if blob has a tag @@ -472,6 +621,8 @@ class Server : public TaskLib { task->tag_) != blob.tags_.end(); task->SetModuleComplete(); } + void MonitorBlobHasTag(u32 mode, BlobHasTagTask *task, RunContext &rctx) { + } /** * Create \a blob_id BLOB ID @@ -488,6 +639,16 @@ class Server : public TaskLib { flags.SetBits(HERMES_BLOB_DID_CREATE); BLOB_MAP_T &blob_map = blob_map_[rctx.lane_id_]; blob_map.emplace(blob_id, BlobInfo()); + BlobInfo &blob_info = blob_map[blob_id]; + blob_info.name_ = blob_name; + blob_info.blob_id_ = blob_id; + blob_info.tag_id_ = tag_id; + blob_info.blob_size_ = 0; + blob_info.max_blob_size_ = 0; + blob_info.score_ = 1; + blob_info.mod_count_ = 0; + blob_info.access_freq_ = 0; + blob_info.last_flush_ = 0; return blob_id; } return it->second; @@ -498,6 +659,8 @@ class Server : public TaskLib { task->blob_id_ = GetOrCreateBlobId(task->tag_id_, task->lane_hash_, blob_name, rctx, flags); task->SetModuleComplete(); } + void MonitorGetOrCreateBlobId(u32 mode, GetOrCreateBlobIdTask *task, RunContext &rctx) { + } /** * Get \a blob_name BLOB from \a bkt_id bucket @@ -518,6 +681,8 @@ class Server : public TaskLib { HILOG(kDebug, "Found blob {} / {} in {}", task->blob_id_, blob_name.str(), task->tag_id_); task->SetModuleComplete(); } + void MonitorGetBlobId(u32 mode, GetBlobIdTask *task, RunContext &rctx) { + } /** * Get \a blob_name BLOB name from \a blob_id BLOB id @@ -533,6 +698,8 @@ class Server : public TaskLib { (*task->blob_name_) = blob.name_; task->SetModuleComplete(); } + void MonitorGetBlobName(u32 mode, GetBlobNameTask *task, RunContext &rctx) { + } /** * Get \a score from \a blob_id BLOB id @@ -555,6 +722,8 @@ class Server : public TaskLib { task->size_ = blob.blob_size_; task->SetModuleComplete(); } + void MonitorGetBlobSize(u32 mode, GetBlobSizeTask *task, RunContext &rctx) { + } /** * Get \a score from \a blob_id BLOB id @@ -570,6 +739,8 @@ class Server : public TaskLib { task->score_ = blob.score_; task->SetModuleComplete(); } + void MonitorGetBlobScore(u32 mode, GetBlobScoreTask *task, RunContext &rctx) { + } /** * Get \a blob_id blob's buffers @@ -585,6 +756,8 @@ class Server : public TaskLib { (*task->buffers_) = blob.buffers_; task->SetModuleComplete(); } + void MonitorGetBlobBuffers(u32 mode, GetBlobBuffersTask *task, RunContext &rctx) { + } /** * Rename \a blob_id blob to \a new_blob_name new blob name @@ -604,6 +777,8 @@ class Server : public TaskLib { blob.name_ = hshm::to_charbuf(*task->new_blob_name_); task->SetModuleComplete(); } + void MonitorRenameBlob(u32 mode, RenameBlobTask *task, RunContext &rctx) { + } /** * Truncate a blob to a new size @@ -619,6 +794,8 @@ class Server : public TaskLib { // TODO(llogan): truncate blob task->SetModuleComplete(); } + void MonitorTruncateBlob(u32 mode, TruncateBlobTask *task, RunContext &rctx) { + } /** * Destroy \a blob_id blob in \a bkt_id bucket @@ -660,16 +837,20 @@ class Server : public TaskLib { } BLOB_MAP_T &blob_map = blob_map_[rctx.lane_id_]; BlobInfo &blob_info = blob_map[task->blob_id_]; - bkt_mdm_.AsyncUpdateSize(task->task_node_ + 1, - task->tag_id_, - -(ssize_t)blob_info.blob_size_, - bucket_mdm::UpdateSizeMode::kAdd); + if (task->update_size_) { + bkt_mdm_.AsyncUpdateSize(task->task_node_ + 1, + task->tag_id_, + -(ssize_t) blob_info.blob_size_, + bucket_mdm::UpdateSizeMode::kAdd); + } HSHM_DESTROY_AR(task->free_tasks_); blob_map.erase(task->blob_id_); task->SetModuleComplete(); } } } + void MonitorDestroyBlob(u32 mode, DestroyBlobTask *task, RunContext &rctx) { + } /** * Reorganize \a blob_id blob in \a bkt_id bucket @@ -686,16 +867,16 @@ class Server : public TaskLib { BlobInfo &blob_info = it->second; if (task->is_user_score_) { blob_info.user_score_ = task->score_; - blob_info.score_ = std::max(blob_info.user_score_, - blob_info.score_); + blob_info.score_ = blob_info.user_score_; } else { blob_info.score_ = task->score_; } - if (!ShouldReorganize(blob_info, task->score_, task->task_node_)) { - task->SetModuleComplete(); - return; - } - task->data_ = HRUN_CLIENT->AllocateBuffer(blob_info.blob_size_).shm_; +// if (!ShouldReorganize(blob_info, task->score_, task->task_node_)) { +// task->SetModuleComplete(); +// return; +// } + task->data_ = HRUN_CLIENT->AllocateBufferServer( + blob_info.blob_size_, task).shm_; task->data_size_ = blob_info.blob_size_; task->get_task_ = blob_mdm_.AsyncGetBlob(task->task_node_ + 1, task->tag_id_, @@ -715,17 +896,20 @@ class Server : public TaskLib { task->phase_ = ReorganizeBlobPhase::kPut; } case ReorganizeBlobPhase::kPut: { - task->put_task_ = blob_mdm_.AsyncPutBlob(task->task_node_ + 1, - task->tag_id_, hshm::charbuf(""), - task->blob_id_, 0, - task->data_size_, - task->data_, - task->score_, - HERMES_BLOB_REPLACE).ptr_; + task->put_task_ = blob_mdm_.AsyncPutBlob( + task->task_node_ + 1, + task->tag_id_, hshm::charbuf(""), + task->blob_id_, 0, + task->data_size_, + task->data_, + task->score_, + HERMES_BLOB_REPLACE | TASK_FIRE_AND_FORGET | TASK_DATA_OWNER).ptr_; task->SetModuleComplete(); } } } + void MonitorReorganizeBlob(u32 mode, ReorganizeBlobTask *task, RunContext &rctx) { + } /** * Get all metadata about a blob @@ -742,6 +926,8 @@ class Server : public TaskLib { task->SerializeBlobMetadata(blob_mdms); task->SetModuleComplete(); } + void MonitorPollBlobMetadata(u32 mode, PollBlobMetadataTask *task, RunContext &rctx) { + } /** * Get all metadata about a blob @@ -757,6 +943,7 @@ class Server : public TaskLib { } TargetStats stats; stats.tgt_id_ = bdev_client.id_; + stats.node_id_ = HRUN_CLIENT->node_id_; stats.rem_cap_ = bdev_client.monitor_task_->rem_cap_; stats.max_cap_ = bdev_client.max_cap_; stats.bandwidth_ = bdev_client.bandwidth_; @@ -767,6 +954,8 @@ class Server : public TaskLib { task->SerializeTargetMetadata(target_mdms); task->SetModuleComplete(); } + void MonitorPollTargetMetadata(u32 mode, PollTargetMetadataTask *task, RunContext &rctx) { + } public: #include "hermes_blob_mdm/hermes_blob_mdm_lib_exec.h" diff --git a/tasks/hermes_bucket_mdm/include/hermes_bucket_mdm/hermes_bucket_mdm.h b/tasks/hermes_bucket_mdm/include/hermes_bucket_mdm/hermes_bucket_mdm.h index ad6d66e52..f462d2218 100644 --- a/tasks/hermes_bucket_mdm/include/hermes_bucket_mdm/hermes_bucket_mdm.h +++ b/tasks/hermes_bucket_mdm/include/hermes_bucket_mdm/hermes_bucket_mdm.h @@ -24,14 +24,10 @@ class Client : public TaskLibClient { const std::string &state_name) { id_ = TaskStateId::GetNull(); QueueManagerInfo &qm = HRUN_CLIENT->server_config_.queue_manager_; - std::vector queue_info = { - {1, 1, qm.queue_depth_, 0}, - {1, 1, qm.queue_depth_, QUEUE_LONG_RUNNING}, - {qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY} - }; + std::vector queue_info; id_ = HRUN_ADMIN->CreateTaskStateRoot( domain_id, state_name, id_, queue_info); - queue_id_ = QueueId(id_); + Init(id_, HRUN_ADMIN->queue_id_); } /** Destroy task state + queue */ @@ -68,7 +64,7 @@ class Client : public TaskLibClient { void AsyncUpdateSizeConstruct(UpdateSizeTask *task, const TaskNode &task_node, TagId tag_id, - size_t update, + ssize_t update, int mode) { HRUN_CLIENT->ConstructTask( task, task_node, DomainId::GetNode(tag_id.node_id_), id_, @@ -125,21 +121,22 @@ class Client : public TaskLibClient { bool blob_owner, const std::vector &traits, size_t backend_size, - u32 flags) { + u32 flags, + const Context &ctx = Context()) { HILOG(kDebug, "Creating a tag {}", tag_name.str()); - u32 hash = std::hash{}(tag_name); HRUN_CLIENT->ConstructTask( - task, task_node, DomainId::GetNode(HASH_TO_NODE_ID(hash)), id_, - tag_name, blob_owner, traits, backend_size, flags); + task, task_node, id_, + tag_name, blob_owner, traits, backend_size, flags, ctx); } HSHM_ALWAYS_INLINE TagId GetOrCreateTagRoot(const hshm::charbuf &tag_name, bool blob_owner, const std::vector &traits, size_t backend_size, - u32 flags) { + u32 flags, + const Context &ctx = Context()) { LPointer> push_task = - AsyncGetOrCreateTagRoot(tag_name, blob_owner, traits, backend_size, flags); + AsyncGetOrCreateTagRoot(tag_name, blob_owner, traits, backend_size, flags, ctx); push_task->Wait(); GetOrCreateTagTask *task = push_task->get(); TagId tag_id = task->tag_id_; diff --git a/tasks/hermes_bucket_mdm/include/hermes_bucket_mdm/hermes_bucket_mdm_lib_exec.h b/tasks/hermes_bucket_mdm/include/hermes_bucket_mdm/hermes_bucket_mdm_lib_exec.h index 323022042..c8fa1e36c 100644 --- a/tasks/hermes_bucket_mdm/include/hermes_bucket_mdm/hermes_bucket_mdm_lib_exec.h +++ b/tasks/hermes_bucket_mdm/include/hermes_bucket_mdm/hermes_bucket_mdm_lib_exec.h @@ -74,75 +74,148 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kConstruct: { + MonitorConstruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestruct: { + MonitorDestruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetOrCreateTag: { + MonitorGetOrCreateTag(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetTagId: { + MonitorGetTagId(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetTagName: { + MonitorGetTagName(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kRenameTag: { + MonitorRenameTag(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestroyTag: { + MonitorDestroyTag(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kTagAddBlob: { + MonitorTagAddBlob(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kTagRemoveBlob: { + MonitorTagRemoveBlob(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kTagClearBlobs: { + MonitorTagClearBlobs(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kUpdateSize: { + MonitorUpdateSize(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kAppendBlobSchema: { + MonitorAppendBlobSchema(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kAppendBlob: { + MonitorAppendBlob(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetSize: { + MonitorGetSize(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kSetBlobMdm: { + MonitorSetBlobMdm(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kGetContainedBlobIds: { + MonitorGetContainedBlobIds(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kPollTagMetadata: { + MonitorPollTagMetadata(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kConstruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetOrCreateTag: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetTagId: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetTagName: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kRenameTag: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestroyTag: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kTagAddBlob: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kTagRemoveBlob: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kTagClearBlobs: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kUpdateSize: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kAppendBlobSchema: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kAppendBlob: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetSize: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kSetBlobMdm: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kGetContainedBlobIds: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kPollTagMetadata: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } diff --git a/tasks/hermes_bucket_mdm/include/hermes_bucket_mdm/hermes_bucket_mdm_tasks.h b/tasks/hermes_bucket_mdm/include/hermes_bucket_mdm/hermes_bucket_mdm_tasks.h index 24eaf2dad..489ecadd0 100644 --- a/tasks/hermes_bucket_mdm/include/hermes_bucket_mdm/hermes_bucket_mdm_tasks.h +++ b/tasks/hermes_bucket_mdm/include/hermes_bucket_mdm/hermes_bucket_mdm_tasks.h @@ -15,12 +15,14 @@ #include "hrun/api/hrun_client.h" #include "hrun/hrun_namespace.h" #include "proc_queue/proc_queue.h" +#include "data_stager/data_stager.h" namespace hermes::bucket_mdm { #include "hermes_bucket_mdm_methods.h" #include "hrun/hrun_namespace.h" + /** * A task to create hermes_bucket_mdm * */ @@ -190,8 +192,8 @@ struct UpdateSizeTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << task_state_; + srl << lane_hash_; return 0; } }; @@ -275,8 +277,8 @@ struct AppendBlobSchemaTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -338,8 +340,8 @@ struct AppendBlobTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << std::string("blob_op"); + srl << tag_id_; return 0; } }; @@ -347,6 +349,7 @@ struct AppendBlobTask : public Task, TaskFlags { /** A task to get or create a tag */ struct GetOrCreateTagTask : public Task, TaskFlags { IN hipc::ShmArchive tag_name_; + IN hipc::ShmArchive params_; IN bool blob_owner_; IN hipc::ShmArchive> traits_; IN size_t backend_size_; @@ -361,13 +364,13 @@ struct GetOrCreateTagTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE explicit GetOrCreateTagTask(hipc::Allocator *alloc, const TaskNode &task_node, - const DomainId &domain_id, const TaskStateId &state_id, const hshm::charbuf &tag_name, bool blob_owner, const std::vector &traits, size_t backend_size, - u32 flags) : Task(alloc) { + u32 flags, + const Context &ctx) : Task(alloc) { // Initialize task task_node_ = task_node; lane_hash_ = std::hash{}(tag_name); @@ -375,27 +378,29 @@ struct GetOrCreateTagTask : public Task, TaskFlags { task_state_ = state_id; method_ = Method::kGetOrCreateTag; task_flags_.SetBits(TASK_LOW_LATENCY); - domain_id_ = domain_id; + domain_id_ = DomainId::GetNode(HASH_TO_NODE_ID(lane_hash_)); // Custom params blob_owner_ = blob_owner; backend_size_ = backend_size; HSHM_MAKE_AR(tag_name_, alloc, tag_name) HSHM_MAKE_AR(traits_, alloc, traits) - flags_ = bitfield32_t(flags); + HSHM_MAKE_AR(params_, alloc, ctx.bkt_params_) + flags_ = bitfield32_t(flags | ctx.flags_.bits_); } /** Destructor */ ~GetOrCreateTagTask() { HSHM_DESTROY_AR(tag_name_) HSHM_DESTROY_AR(traits_) + HSHM_DESTROY_AR(params_) } /** (De)serialize message call */ template void SerializeStart(Ar &ar) { task_serialize(ar); - ar(tag_name_, blob_owner_, traits_, backend_size_, flags_); + ar(tag_name_, blob_owner_, traits_, backend_size_, flags_, params_); } /** (De)serialize message return */ @@ -407,8 +412,9 @@ struct GetOrCreateTagTask : public Task, TaskFlags { /** Create group */ HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { - group.resize(tag_name_->size()); - memcpy(group.data(), tag_name_->data(), tag_name_->size()); + hrun::LocalSerialize srl(group); + srl << task_state_; + srl << lane_hash_; return 0; } }; @@ -463,8 +469,9 @@ struct GetTagIdTask : public Task, TaskFlags { /** Create group */ HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { - group.resize(tag_name_->size()); - memcpy(group.data(), tag_name_->data(), tag_name_->size()); + hrun::LocalSerialize srl(group); + srl << task_state_; + srl << lane_hash_; return 0; } }; @@ -520,8 +527,8 @@ struct GetTagNameTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << task_state_; + srl << lane_hash_; return 0; } }; @@ -579,8 +586,8 @@ struct RenameTagTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << task_state_; + srl << lane_hash_; return 0; } }; @@ -607,7 +614,7 @@ struct DestroyTagTask : public Task, TaskFlags { const TaskNode &task_node, const DomainId &domain_id, const TaskStateId &state_id, - TagId tag_id) : Task(alloc) { + const TagId &tag_id) : Task(alloc) { // Initialize task task_node_ = task_node; lane_hash_ = tag_id.hash_; @@ -636,8 +643,8 @@ struct DestroyTagTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << task_state_; + srl << lane_hash_; return 0; } }; @@ -688,8 +695,8 @@ struct TagAddBlobTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << task_state_; + srl << lane_hash_; return 0; } }; @@ -740,8 +747,8 @@ struct TagRemoveBlobTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << task_state_; + srl << lane_hash_; return 0; } }; @@ -798,8 +805,8 @@ struct TagClearBlobsTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << task_state_; + srl << lane_hash_; return 0; } }; @@ -850,8 +857,8 @@ struct GetSizeTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << task_state_; + srl << lane_hash_; return 0; } }; @@ -908,20 +915,22 @@ struct GetContainedBlobIdsTask : public Task, TaskFlags { HSHM_ALWAYS_INLINE u32 GetGroup(hshm::charbuf &group) { hrun::LocalSerialize srl(group); - srl << tag_id_.unique_; - srl << tag_id_.node_id_; + srl << task_state_; + srl << lane_hash_; return 0; } }; /** A task to collect blob metadata */ -struct PollTagMetadataTask : public Task, TaskFlags { +struct PollTagMetadataTask : public Task, TaskFlags { OUT hipc::ShmArchive my_tag_mdms_; TEMP hipc::ShmArchive> tag_mdms_; /** SHM default constructor */ HSHM_ALWAYS_INLINE explicit - PollTagMetadataTask(hipc::Allocator *alloc) : Task(alloc) {} + PollTagMetadataTask(hipc::Allocator *alloc) : Task(alloc) { + HSHM_MAKE_AR0(tag_mdms_, alloc) + } /** Emplace constructor */ HSHM_ALWAYS_INLINE explicit @@ -1004,8 +1013,15 @@ struct PollTagMetadataTask : public Task, TaskFlags { /** (De)serialize message return */ template - void SerializeEnd(u32 replica, Ar &ar) { - ar((*tag_mdms_)[replica]); + void SaveEnd(Ar &ar) { + ar(my_tag_mdms_); + } + + /** (De)serialize message return */ + template + void LoadEnd(u32 replica, Ar &ar) { + ar(my_tag_mdms_); + DupEnd(replica, *this); } /** Begin replication */ diff --git a/tasks/hermes_bucket_mdm/src/hermes_bucket_mdm.cc b/tasks/hermes_bucket_mdm/src/hermes_bucket_mdm.cc index c0fe118c5..9c81cacca 100644 --- a/tasks/hermes_bucket_mdm/src/hermes_bucket_mdm.cc +++ b/tasks/hermes_bucket_mdm/src/hermes_bucket_mdm.cc @@ -29,27 +29,35 @@ class Server : public TaskLib { public: Server() = default; + /** Construct bucket mdm */ void Construct(ConstructTask *task, RunContext &rctx) { id_alloc_ = 0; node_id_ = HRUN_CLIENT->node_id_; - bkt_mdm_.Init(id_); + bkt_mdm_.Init(id_, HRUN_ADMIN->queue_id_); tag_id_map_.resize(HRUN_QM_RUNTIME->max_lanes_); tag_map_.resize(HRUN_QM_RUNTIME->max_lanes_); task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } + /** Destroy bucket mdm */ void Destruct(DestructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } /** * Set the Blob MDM * */ void SetBlobMdm(SetBlobMdmTask *task, RunContext &rctx) { - blob_mdm_.Init(task->blob_mdm_); - stager_mdm_.Init(task->stager_mdm_); + blob_mdm_.Init(task->blob_mdm_, HRUN_ADMIN->queue_id_); + stager_mdm_.Init(task->stager_mdm_, HRUN_ADMIN->queue_id_); task->SetModuleComplete(); } + void MonitorSetBlobMdm(u32 mode, SetBlobMdmTask *task, RunContext &rctx) { + } /** Update the size of the bucket */ void UpdateSize(UpdateSizeTask *task, RunContext &rctx) { @@ -66,6 +74,8 @@ class Server : public TaskLib { tag_info.internal_size_ = (size_t) internal_size; task->SetModuleComplete(); } + void MonitorUpdateSize(u32 mode, UpdateSizeTask *task, RunContext &rctx) { + } /** * Create the PartialPuts for append operations. @@ -94,7 +104,7 @@ class Server : public TaskLib { } append_info.emplace_back(); AppendInfo &append = append_info.back(); - append.blob_name_ = hshm::charbuf(std::to_string(cur_page)); + append.blob_name_ = adapter::BlobPlacement::CreateBlobName(cur_page); append.data_size_ = update_size; append.blob_off_ = cur_page_off; append.blob_id_task_ = blob_mdm_.AsyncGetOrCreateBlobId(task->task_node_ + 1, @@ -124,6 +134,8 @@ class Server : public TaskLib { } } } + void MonitorAppendBlobSchema(u32 mode, AppendBlobSchemaTask *task, RunContext &rctx) { + } /** * Append data to a bucket. Assumes that the blobs in the bucket @@ -149,10 +161,16 @@ class Server : public TaskLib { size_t buf_off = 0; HILOG(kDebug, "(node {}) Got blob schema of size {} for tag {} (task_node={})", HRUN_CLIENT->node_id_, append_info.size(), task->tag_id_, task->task_node_) + TAG_MAP_T &tag_map = tag_map_[rctx.lane_id_]; + TagInfo &tag_info = tag_map[task->tag_id_]; for (AppendInfo &append : append_info) { HILOG(kDebug, "(node {}) Spawning blob {} of size {} for tag {} (task_node={} blob_mdm={})", HRUN_CLIENT->node_id_, append.blob_name_.str(), append.data_size_, task->tag_id_, task->task_node_, blob_mdm_.id_); + Context ctx; + if (tag_info.flags_.Any(HERMES_SHOULD_STAGE)) { + ctx.flags_.SetBits(HERMES_SHOULD_STAGE); + } append.put_task_ = blob_mdm_.AsyncPutBlob(task->task_node_ + 1, task->tag_id_, append.blob_name_, @@ -161,7 +179,7 @@ class Server : public TaskLib { append.data_size_, task->data_ + buf_off, task->score_, 0, - Context(), 0).ptr_; + ctx, 0).ptr_; HILOG(kDebug, "(node {}) Finished spawning blob {} of size {} for tag {} (task_node={} blob_mdm={})", HRUN_CLIENT->node_id_, append.blob_name_.str(), append.data_size_, task->tag_id_, task->task_node_, blob_mdm_.id_); @@ -187,6 +205,8 @@ class Server : public TaskLib { } } } + void MonitorAppendBlob(u32 mode, AppendBlobTask *task, RunContext &rctx) { + } /** Get or create a tag */ void GetOrCreateTag(GetOrCreateTagTask *task, RunContext &rctx) { @@ -216,10 +236,12 @@ class Server : public TaskLib { tag_info.tag_id_ = tag_id; tag_info.owner_ = task->blob_owner_; tag_info.internal_size_ = task->backend_size_; - if (task->flags_.Any(HERMES_IS_FILE)) { + if (task->flags_.Any(HERMES_SHOULD_STAGE)) { stager_mdm_.AsyncRegisterStager(task->task_node_ + 1, tag_id, - hshm::charbuf(task->tag_name_->str())); + hshm::charbuf(task->tag_name_->str()), + hshm::charbuf(task->params_->str())); + tag_info.flags_.SetBits(HERMES_SHOULD_STAGE); } } else { if (tag_name.size()) { @@ -235,6 +257,8 @@ class Server : public TaskLib { // task->did_create_ = did_create; task->SetModuleComplete(); } + void MonitorGetOrCreateTag(u32 mode, GetOrCreateTagTask *task, RunContext &rctx) { + } /** Get tag ID */ void GetTagId(GetTagIdTask *task, RunContext &rctx) { @@ -249,6 +273,8 @@ class Server : public TaskLib { task->tag_id_ = it->second; task->SetModuleComplete(); } + void MonitorGetTagId(u32 mode, GetTagIdTask *task, RunContext &rctx) { + } /** Get tag name */ void GetTagName(GetTagNameTask *task, RunContext &rctx) { @@ -261,6 +287,8 @@ class Server : public TaskLib { (*task->tag_name_) = it->second.name_; task->SetModuleComplete(); } + void MonitorGetTagName(u32 mode, GetTagNameTask *task, RunContext &rctx) { + } /** Rename tag */ void RenameTag(RenameTagTask *task, RunContext &rctx) { @@ -273,6 +301,8 @@ class Server : public TaskLib { (*task->tag_name_) = (*task->tag_name_); task->SetModuleComplete(); } + void MonitorRenameTag(u32 mode, RenameTagTask *task, RunContext &rctx) { + } /** Destroy tag */ void DestroyTag(DestroyTagTask *task, RunContext &rctx) { @@ -287,11 +317,13 @@ class Server : public TaskLib { blob_tasks.reserve(tag.blobs_.size()); for (BlobId &blob_id : tag.blobs_) { blob_mdm::DestroyBlobTask *blob_task = - blob_mdm_.AsyncDestroyBlob(task->task_node_ + 1, task->tag_id_, blob_id).ptr_; + blob_mdm_.AsyncDestroyBlob(task->task_node_ + 1, + task->tag_id_, blob_id, false).ptr_; blob_tasks.emplace_back(blob_task); } stager_mdm_.AsyncUnregisterStager(task->task_node_ + 1, task->tag_id_); + HILOG(kInfo, "Destroying the tag: {}", tag.name_.str()); task->phase_ = DestroyTagPhase::kWaitDestroyBlobs; return; } @@ -308,10 +340,13 @@ class Server : public TaskLib { HSHM_DESTROY_AR(task->destroy_blob_tasks_); TAG_MAP_T &tag_map = tag_map_[rctx.lane_id_]; tag_map.erase(task->tag_id_); + HILOG(kInfo, "Finished destroying the tag"); task->SetModuleComplete(); } } } + void MonitorDestroyTag(u32 mode, DestroyTagTask *task, RunContext &rctx) { + } /** Add a blob to a tag */ void TagAddBlob(TagAddBlobTask *task, RunContext &rctx) { @@ -325,6 +360,8 @@ class Server : public TaskLib { tag.blobs_.emplace_back(task->blob_id_); task->SetModuleComplete(); } + void MonitorTagAddBlob(u32 mode, TagAddBlobTask *task, RunContext &rctx) { + } /** Remove a blob from a tag */ void TagRemoveBlob(TagRemoveBlobTask *task, RunContext &rctx) { @@ -339,6 +376,8 @@ class Server : public TaskLib { tag.blobs_.erase(blob_it); task->SetModuleComplete(); } + void MonitorTagRemoveBlob(u32 mode, TagRemoveBlobTask *task, RunContext &rctx) { + } /** Clear blobs from a tag */ void TagClearBlobs(TagClearBlobsTask *task, RunContext &rctx) { @@ -349,10 +388,17 @@ class Server : public TaskLib { return; } TagInfo &tag = it->second; + if (tag.owner_) { + for (BlobId &blob_id : tag.blobs_) { + blob_mdm_.AsyncDestroyBlob(task->task_node_ + 1, task->tag_id_, blob_id); + } + } tag.blobs_.clear(); tag.internal_size_ = 0; task->SetModuleComplete(); } + void MonitorTagClearBlobs(u32 mode, TagClearBlobsTask *task, RunContext &rctx) { + } /** Get size of the bucket */ void GetSize(GetSizeTask *task, RunContext &rctx) { @@ -367,6 +413,8 @@ class Server : public TaskLib { task->size_ = tag.internal_size_; task->SetModuleComplete(); } + void MonitorGetSize(u32 mode, GetSizeTask *task, RunContext &rctx) { + } /** Get contained blob IDs */ void GetContainedBlobIds(GetContainedBlobIdsTask *task, RunContext &rctx) { @@ -384,6 +432,8 @@ class Server : public TaskLib { } task->SetModuleComplete(); } + void MonitorGetContainedBlobIds(u32 mode, GetContainedBlobIdsTask *task, RunContext &rctx) { + } /** * Get all metadata about a blob @@ -400,6 +450,8 @@ class Server : public TaskLib { task->SerializeTagMetadata(tag_mdms); task->SetModuleComplete(); } + void MonitorPollTagMetadata(u32 mode, PollTagMetadataTask *task, RunContext &rctx) { + } public: #include "hermes_bucket_mdm/hermes_bucket_mdm_lib_exec.h" diff --git a/tasks/hermes_data_op/include/hermes_data_op/hermes_data_op.h b/tasks/hermes_data_op/include/hermes_data_op/hermes_data_op.h index 54c583f2d..78bc2e82a 100644 --- a/tasks/hermes_data_op/include/hermes_data_op/hermes_data_op.h +++ b/tasks/hermes_data_op/include/hermes_data_op/hermes_data_op.h @@ -28,11 +28,7 @@ class Client : public TaskLibClient { TaskStateId &blob_mdm_id) { id_ = TaskStateId::GetNull(); QueueManagerInfo &qm = HRUN_CLIENT->server_config_.queue_manager_; - std::vector queue_info = { - {1, 1, qm.queue_depth_, 0}, - {1, 1, qm.queue_depth_, QUEUE_LONG_RUNNING}, - {qm.max_lanes_, qm.max_lanes_, qm.queue_depth_, QUEUE_LOW_LATENCY} - }; + std::vector queue_info; return HRUN_ADMIN->AsyncCreateTaskState( task_node, domain_id, state_name, id_, queue_info, bkt_mdm_id, blob_mdm_id); @@ -45,7 +41,7 @@ class Client : public TaskLibClient { AsyncCreateRoot(std::forward(args)...); task->Wait(); id_ = task->id_; - queue_id_ = QueueId(id_); + Init(id_, HRUN_ADMIN->queue_id_); HRUN_CLIENT->DelTask(task); } diff --git a/tasks/hermes_data_op/include/hermes_data_op/hermes_data_op_lib_exec.h b/tasks/hermes_data_op/include/hermes_data_op/hermes_data_op_lib_exec.h index 51413ffc1..84c49c886 100644 --- a/tasks/hermes_data_op/include/hermes_data_op/hermes_data_op_lib_exec.h +++ b/tasks/hermes_data_op/include/hermes_data_op/hermes_data_op_lib_exec.h @@ -26,27 +26,52 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kConstruct: { + MonitorConstruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestruct: { + MonitorDestruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kRegisterOp: { + MonitorRegisterOp(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kRegisterData: { + MonitorRegisterData(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kRunOp: { + MonitorRunOp(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kConstruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kRegisterOp: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kRegisterData: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kRunOp: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } diff --git a/tasks/hermes_data_op/include/hermes_data_op/hermes_data_op_tasks.h b/tasks/hermes_data_op/include/hermes_data_op/hermes_data_op_tasks.h index a76101f59..5d5419bb3 100644 --- a/tasks/hermes_data_op/include/hermes_data_op/hermes_data_op_tasks.h +++ b/tasks/hermes_data_op/include/hermes_data_op/hermes_data_op_tasks.h @@ -290,10 +290,12 @@ struct RunOpTask : public Task, TaskFlags { // Initialize task task_node_ = task_node; lane_hash_ = 0; - prio_ = TaskPrio::kLowLatency; + prio_ = TaskPrio::kLongRunning; task_state_ = state_id; method_ = Method::kRunOp; - task_flags_.SetBits(TASK_LONG_RUNNING | TASK_COROUTINE | TASK_LANE_ALL); + task_flags_.SetBits( + TASK_LONG_RUNNING | TASK_COROUTINE | TASK_LANE_ALL | + TASK_REMOTE_DEBUG_MARK); SetPeriodSec(1); // TODO(llogan): don't hardcode this domain_id_ = DomainId::GetLocal(); } diff --git a/tasks/hermes_data_op/src/hermes_data_op.cc b/tasks/hermes_data_op/src/hermes_data_op.cc index 72d9f3db7..8dfdf9a13 100644 --- a/tasks/hermes_data_op/src/hermes_data_op.cc +++ b/tasks/hermes_data_op/src/hermes_data_op.cc @@ -31,22 +31,29 @@ class Server : public TaskLib { public: Server() = default; + /** Construct data operator table */ void Construct(ConstructTask *task, RunContext &rctx) { task->Deserialize(); - bkt_mdm_.Init(task->bkt_mdm_); - blob_mdm_.Init(task->blob_mdm_); - client_.Init(id_); + bkt_mdm_.Init(task->bkt_mdm_, HRUN_ADMIN->queue_id_); + blob_mdm_.Init(task->blob_mdm_, HRUN_ADMIN->queue_id_); + client_.Init(id_, HRUN_ADMIN->queue_id_); op_id_map_["min"] = 0; op_id_map_["max"] = 1; op_graphs_.resize(HRUN_QM_RUNTIME->max_lanes_); run_task_ = client_.AsyncRunOp(task->task_node_ + 1); task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } + /** Destroy data operators */ void Destruct(DestructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } + /** Registor operators */ void RegisterOp(RegisterOpTask *task, RunContext &rctx) { // Load OpGraph op_graphs_[rctx.lane_id_].push_back(task->GetOpGraph()); @@ -99,7 +106,10 @@ class Server : public TaskLib { // Store the operator to perform task->SetModuleComplete(); } + void MonitorRegisterOp(u32 mode, RegisterOpTask *task, RunContext &rctx) { + } + /** Inform that data is ready for operators */ void RegisterData(RegisterDataTask *task, RunContext &rctx) { if (!op_data_lock_.TryLock(0)) { return; @@ -110,7 +120,10 @@ class Server : public TaskLib { op_data_lock_.Unlock(); task->SetModuleComplete(); } + void MonitorRegisterData(u32 mode, RegisterDataTask *task, RunContext &rctx) { + } + /** Run the operator */ void RunOp(RunOpTask *task, RunContext &rctx) { for (OpGraph &op_graph : op_graphs_[rctx.lane_id_]) { for (Op &op : op_graph.ops_) { @@ -125,7 +138,10 @@ class Server : public TaskLib { } } } + void MonitorRunOp(u32 mode, RunOpTask *task, RunContext &rctx) { + } + /** Get pending data needed for the operator */ std::list GetPendingData(Op &op) { std::list pending; if (!op_data_lock_.TryLock(0)) { @@ -151,6 +167,7 @@ class Server : public TaskLib { return pending; } + /** Get the minimum of data */ void RunMin(RunOpTask *task, Op &op) { // Get the pending data from Hermes std::list op_data = GetPendingData(op); @@ -165,7 +182,8 @@ class Server : public TaskLib { std::vector in_tasks; for (OpData &data : op_data) { // Get the input data - LPointer data_ptr = HRUN_CLIENT->AllocateBuffer(data.size_); + LPointer data_ptr = + HRUN_CLIENT->AllocateBufferServer(data.size_, task); LPointer in_task = blob_mdm_.AsyncGetBlob(task->task_node_ + 1, data.bkt_id_, @@ -184,7 +202,8 @@ class Server : public TaskLib { in_task->Wait(task); // Calaculate the minimum - LPointer min_lptr = HRUN_CLIENT->AllocateBuffer(sizeof(float)); + LPointer min_lptr = + HRUN_CLIENT->AllocateBufferServer(sizeof(float), task); float *min_ptr = (float*)min_lptr.ptr_; *min_ptr = std::numeric_limits::max(); for (size_t i = 0; i < in_task->data_size_; i += sizeof(float)) { @@ -199,9 +218,12 @@ class Server : public TaskLib { BlobId::GetNull(), 0, sizeof(float), min_lptr.shm_, 0, 0); + HRUN_CLIENT->FreeBuffer(in_task->data_); + HRUN_CLIENT->DelTask(in_task); } } + /** Get the maximum of data */ void RunMax(RunOpTask *task, Op &op) { } diff --git a/tasks/hermes_mdm/include/hermes_mdm/hermes_mdm.h b/tasks/hermes_mdm/include/hermes_mdm/hermes_mdm.h index 0420c3629..283670594 100644 --- a/tasks/hermes_mdm/include/hermes_mdm/hermes_mdm.h +++ b/tasks/hermes_mdm/include/hermes_mdm/hermes_mdm.h @@ -23,12 +23,10 @@ class Client : public TaskLibClient { void CreateRoot(const DomainId &domain_id, const std::string &state_name) { id_ = TaskStateId::GetNull(); - std::vector queue_info = { - {1, 1, 1, 0}, - }; + std::vector queue_info; id_ = HRUN_ADMIN->CreateTaskStateRoot( domain_id, state_name, id_, queue_info); - queue_id_ = QueueId(id_); + Init(id_, HRUN_ADMIN->queue_id_); } /** Destroy task state + queue */ diff --git a/tasks/hermes_mdm/include/hermes_mdm/hermes_mdm_lib_exec.h b/tasks/hermes_mdm/include/hermes_mdm/hermes_mdm_lib_exec.h index 17c627803..d6159d960 100644 --- a/tasks/hermes_mdm/include/hermes_mdm/hermes_mdm_lib_exec.h +++ b/tasks/hermes_mdm/include/hermes_mdm/hermes_mdm_lib_exec.h @@ -14,15 +14,28 @@ void Run(u32 method, Task *task, RunContext &rctx) override { } } } +/** Execute a task */ +void Monitor(u32 mode, Task *task, RunContext &rctx) override { + switch (task->method_) { + case Method::kConstruct: { + MonitorConstruct(mode, reinterpret_cast(task), rctx); + break; + } + case Method::kDestruct: { + MonitorDestruct(mode, reinterpret_cast(task), rctx); + break; + } + } +} /** Delete a task */ void Del(u32 method, Task *task) override { switch (method) { case Method::kConstruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } case Method::kDestruct: { - HRUN_CLIENT->DelTask(reinterpret_cast(task)); + HRUN_CLIENT->DelTask(reinterpret_cast(task)); break; } } diff --git a/tasks/hermes_mdm/src/hermes_mdm.cc b/tasks/hermes_mdm/src/hermes_mdm.cc index 60351b68c..35f629c85 100644 --- a/tasks/hermes_mdm/src/hermes_mdm.cc +++ b/tasks/hermes_mdm/src/hermes_mdm.cc @@ -18,13 +18,14 @@ class Server : public TaskLib { /**==================================== * Configuration * ===================================*/ - u32 node_id_; - blob_mdm::Client blob_mdm_; - bucket_mdm::Client bkt_mdm_; + u32 node_id_; + blob_mdm::Client blob_mdm_; + bucket_mdm::Client bkt_mdm_; public: Server() = default; + /** Construct hermes MDM */ void Construct(ConstructTask *task, RunContext &rctx) { HILOG(kDebug, "ConstructTaskPhase::kLoadConfig") std::string config_path = task->server_config_path_->str(); @@ -32,10 +33,15 @@ class Server : public TaskLib { node_id_ = HRUN_CLIENT->node_id_; task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } + /** Destory hermes MDM */ void Destruct(DestructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } public: #include "hermes_mdm/hermes_mdm_lib_exec.h" diff --git a/tasks/posix_bdev/src/posix_bdev.cc b/tasks/posix_bdev/src/posix_bdev.cc index b6e3f3a64..3a73f8e02 100644 --- a/tasks/posix_bdev/src/posix_bdev.cc +++ b/tasks/posix_bdev/src/posix_bdev.cc @@ -11,28 +11,30 @@ #include #include #include +// #include namespace hermes::posix_bdev { - class Server : public TaskLib, public bdev::Server { +class Server : public TaskLib, public bdev::Server { public: SlabAllocator alloc_; int fd_; std::string path_; public: + /** Construct posix BDEV */ void Construct(ConstructTask *task, RunContext &rctx) { DeviceInfo &dev_info = task->info_; rem_cap_ = dev_info.capacity_; alloc_.Init(id_, dev_info.capacity_, dev_info.slab_sizes_); - // score_hist_.Resize(10); + score_hist_.Resize(10); std::string text = dev_info.mount_dir_ + "/" + "slab_" + dev_info.dev_name_; auto canon = stdfs::weakly_canonical(text).string(); dev_info.mount_point_ = canon; path_ = canon; fd_ = open(dev_info.mount_point_.c_str(), - O_TRUNC | O_CREAT | O_RDWR, 0666); + O_TRUNC | O_CREAT | O_RDWR, 0666); if (fd_ < 0) { HELOG(kError, "Failed to open file: {}", dev_info.mount_point_); } @@ -40,44 +42,143 @@ namespace hermes::posix_bdev { dev_info.dev_name_, dev_info.mount_point_, dev_info.capacity_); task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } + /** Destroy posix bdev */ void Destruct(DestructTask *task, RunContext &rctx) { task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } + /** Allocate space from bdev */ void Allocate(AllocateTask *task, RunContext &rctx) { alloc_.Allocate(task->size_, *task->buffers_, task->alloc_size_); HILOG(kDebug, "Allocated {}/{} bytes ({})", task->alloc_size_, task->size_, path_); rem_cap_ -= task->alloc_size_; - // score_hist_.Increment(task->score_); + score_hist_.Increment(task->score_); task->SetModuleComplete(); } + void MonitorAllocate(u32 mode, AllocateTask *task, RunContext &rctx) { + } + /** Free space from bdev */ void Free(FreeTask *task, RunContext &rctx) { rem_cap_ += alloc_.Free(task->buffers_); - // score_hist_.Decrement(task->score_); + score_hist_.Decrement(task->score_); task->SetModuleComplete(); } + void MonitorFree(u32 mode, FreeTask *task, RunContext &rctx) { + } + /** Write to bdev */ void Write(WriteTask *task, RunContext &rctx) { HILOG(kDebug, "Writing {} bytes to {}", task->size_, path_); +#ifdef HERMES_LIBAIO + switch (task->phase_) { + case 0: { + int ret = io_setup(1, &task->ctx_); + if (ret < 0) { + perror("io_setup"); + HELOG(kError, "Libaio failed for write (1)"); + task->SetModuleComplete(); + return; + } + struct iocb xfer_iocb; + struct iocb *iocb_list[1]; + io_prep_pwrite(&xfer_iocb, fd_, (void*)task->buf_, task->size_, task->disk_off_); + xfer_iocb.data = (void*) task->buf_; + iocb_list[0] = &xfer_iocb; + ret = io_submit(task->ctx_, 1, iocb_list); + if (ret != 1) { + perror("io_submit"); + HELOG(kError, "Libaio failed for write (2)"); + task->SetModuleComplete(); + return; + } + task->phase_ = 1; + } + case 1: { + struct io_event events[1]; + struct timespec timeout{0, 0}; + int ret = io_getevents(task->ctx_, 1, 1, events, &timeout); + if (ret == -EAGAIN) { + return; + } else if (ret < 0) { + perror("io_getevents"); + HELOG(kError, "Libaio failed for write (3)"); + task->SetModuleComplete(); + return; + } + io_destroy(task->ctx_); + } + } +#else ssize_t count = pwrite(fd_, task->buf_, task->size_, (off_t)task->disk_off_); if (count != task->size_) { HELOG(kError, "BORG: wrote {} bytes, but expected {}: {}", count, task->size_, strerror(errno)); } +#endif task->SetModuleComplete(); } + void MonitorWrite(u32 mode, WriteTask *task, RunContext &rctx) { + } + /** Read from bdev */ void Read(ReadTask *task, RunContext &rctx) { HILOG(kDebug, "Reading {} bytes from {}", task->size_, path_); +#ifdef HERMES_LIBAIO + switch (task->phase_) { + case 0: { + int ret = io_setup(1, &task->ctx_); + if (ret < 0) { + perror("io_setup"); + HELOG(kError, "Libaio failed for write (1)"); + task->SetModuleComplete(); + return; + } + struct iocb xfer_iocb; + struct iocb *iocb_list[1]; + io_prep_pread(&xfer_iocb, fd_, (void*)task->buf_, task->size_, task->disk_off_); + xfer_iocb.data = (void*) task->buf_; + iocb_list[0] = &xfer_iocb; + ret = io_submit(task->ctx_, 1, iocb_list); + if (ret != 1) { + perror("io_submit"); + HELOG(kError, "Libaio failed for write (2)"); + task->SetModuleComplete(); + return; + } + task->phase_ = 1; + } + case 1: { + struct io_event events[1]; + struct timespec timeout{0, 0}; + int ret = io_getevents(task->ctx_, 1, 1, events, &timeout); + if (ret == -EAGAIN) { + return; + } else if (ret < 0) { + perror("io_getevents"); + HELOG(kError, "Libaio failed for write (3)"); + task->SetModuleComplete(); + return; + } + io_destroy(task->ctx_); + } + } +#else ssize_t count = pread(fd_, task->buf_, task->size_, (off_t)task->disk_off_); if (count != task->size_) { HELOG(kError, "BORG: read {} bytes, but expected {}", count, task->size_); } +#endif task->SetModuleComplete(); } + void MonitorRead(u32 mode, ReadTask *task, RunContext &rctx) { + } public: #include "bdev/bdev_lib_exec.h" }; diff --git a/tasks/ram_bdev/src/ram_bdev.cc b/tasks/ram_bdev/src/ram_bdev.cc index f95dd9f41..392decba3 100644 --- a/tasks/ram_bdev/src/ram_bdev.cc +++ b/tasks/ram_bdev/src/ram_bdev.cc @@ -15,48 +15,66 @@ class Server : public TaskLib, public bdev::Server { char *mem_ptr_; public: + /** Construct ram bdev */ void Construct(ConstructTask *task, RunContext &rctx) { DeviceInfo &dev_info = task->info_; rem_cap_ = dev_info.capacity_; alloc_.Init(id_, dev_info.capacity_, dev_info.slab_sizes_); mem_ptr_ = (char*)malloc(dev_info.capacity_); - // score_hist_.Resize(10); + score_hist_.Resize(10); HILOG(kDebug, "Created {} at {} of size {}", dev_info.dev_name_, dev_info.mount_point_, dev_info.capacity_); task->SetModuleComplete(); } + void MonitorConstruct(u32 mode, ConstructTask *task, RunContext &rctx) { + } + /** Destroy ram bdev */ void Destruct(DestructTask *task, RunContext &rctx) { free(mem_ptr_); task->SetModuleComplete(); } + void MonitorDestruct(u32 mode, DestructTask *task, RunContext &rctx) { + } + /** Allocate space from bdev */ void Allocate(AllocateTask *task, RunContext &rctx) { HILOG(kDebug, "Allocating {} bytes (RAM)", task->size_); alloc_.Allocate(task->size_, *task->buffers_, task->alloc_size_); rem_cap_ -= task->alloc_size_; - // score_hist_.Increment(task->score_); + score_hist_.Increment(task->score_); HILOG(kDebug, "Allocated {} bytes (RAM)", task->alloc_size_); task->SetModuleComplete(); } + void MonitorAllocate(u32 mode, AllocateTask *task, RunContext &rctx) { + } + /** Free space to bdev */ void Free(FreeTask *task, RunContext &rctx) { rem_cap_ += alloc_.Free(task->buffers_); - // score_hist_.Decrement(task->score_); + score_hist_.Decrement(task->score_); task->SetModuleComplete(); } + void MonitorFree(u32 mode, FreeTask *task, RunContext &rctx) { + } + /** Write to bdev */ void Write(WriteTask *task, RunContext &rctx) { HILOG(kDebug, "Writing {} bytes to RAM", task->size_); memcpy(mem_ptr_ + task->disk_off_, task->buf_, task->size_); task->SetModuleComplete(); } + void MonitorWrite(u32 mode, WriteTask *task, RunContext &rctx) { + } + /** Read from bdev */ void Read(ReadTask *task, RunContext &rctx) { HILOG(kDebug, "Reading {} bytes from RAM", task->size_); memcpy(task->buf_, mem_ptr_ + task->disk_off_, task->size_); task->SetModuleComplete(); } + void MonitorRead(u32 mode, ReadTask *task, RunContext &rctx) { + } public: #include "bdev/bdev_lib_exec.h" }; diff --git a/test/unit/external/CMakeLists.txt b/test/unit/external/CMakeLists.txt index 5e9284ba1..a9fb9a944 100644 --- a/test/unit/external/CMakeLists.txt +++ b/test/unit/external/CMakeLists.txt @@ -1,15 +1,12 @@ cmake_minimum_required(VERSION 3.10) project(hermes) -include_directories(/home/lukemartinlogan/Documents/Projects/PhD/hermes/test/unit) set(CMAKE_CXX_STANDARD 17) find_package(Hermes REQUIRED) find_package(MPI REQUIRED COMPONENTS C CXX) include_directories(${Hermes_INCLUDE_DIRS}) add_executable(test_hermes_external_compile - ../../main_mpi.cc - ../hermes/test_init.cc - ../hermes/test_bucket.cc + external.cc ) target_link_libraries(test_hermes_external_compile ${Hermes_LIBRARIES} Catch2::Catch2 MPI::MPI_CXX) diff --git a/test/unit/hermes_adapters/catch_config.h b/test/unit/external/external.cc similarity index 66% rename from test/unit/hermes_adapters/catch_config.h rename to test/unit/external/external.cc index 1317e1e50..910d0eb08 100644 --- a/test/unit/hermes_adapters/catch_config.h +++ b/test/unit/external/external.cc @@ -10,33 +10,35 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_CATCH_CONFIG_H -#define HERMES_CATCH_CONFIG_H - #define CATCH_CONFIG_RUNNER -#include - #include +#include +#include +#include +#include "hermes/hermes.h" namespace cl = Catch::Clara; - cl::Parser define_options(); -int init(int* argc, char*** argv); -int finalize(); - -int main(int argc, char* argv[]) { +int main(int argc, char **argv) { + int rc; + MPI_Init(&argc, &argv); Catch::Session session; - auto cli = session.cli() | define_options(); - int returnCode = init(&argc, &argv); - if (returnCode != 0) return returnCode; + auto cli = session.cli(); session.cli(cli); - returnCode = session.applyCommandLine(argc, argv); - if (returnCode != 0) return returnCode; - int test_return_code = session.run(); - returnCode = finalize(); - if (returnCode != 0) return returnCode; - return test_return_code; + rc = session.applyCommandLine(argc, argv); + if (rc != 0) return rc; + rc = session.run(); + if (rc != 0) return rc; + MPI_Finalize(); + return rc; } -#endif +TEST_CASE("TestHermesConnect") { + int rank, nprocs; + MPI_Barrier(MPI_COMM_WORLD); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nprocs); + HERMES->ClientInit(); + MPI_Barrier(MPI_COMM_WORLD); +} diff --git a/test/unit/hermes/CMakeLists.txt b/test/unit/hermes/CMakeLists.txt index a0ab24237..0e16a098f 100644 --- a/test/unit/hermes/CMakeLists.txt +++ b/test/unit/hermes/CMakeLists.txt @@ -16,6 +16,7 @@ add_dependencies(test_hermes_exec ${Hermes_CLIENT_DEPS} hermes) target_link_libraries(test_hermes_exec ${Hermes_CLIENT_LIBRARIES} hermes Catch2::Catch2 MPI::MPI_CXX) +jarvis_test(hermes test_hermes) #------------------------------------------------------------------------------ # Test Cases @@ -40,5 +41,5 @@ install(TARGETS # Coverage #----------------------------------------------------------------------------- if(HERMES_ENABLE_COVERAGE) - set_coverage_flags(test_messages) + set_coverage_flags(test_hermes_exec) endif() diff --git a/test/unit/hermes/config/hermes_server.yaml b/test/unit/hermes/config/hermes_server.yaml index d7b3dcf3f..14cf03b81 100644 --- a/test/unit/hermes/config/hermes_server.yaml +++ b/test/unit/hermes/config/hermes_server.yaml @@ -49,7 +49,7 @@ rpc: protocol: "ofi+sockets" domain: "" port: 8080 - num_threads: 4 + num_threads: 32 ### Define properties of the BORG buffer_organizer: @@ -90,17 +90,19 @@ system_view_state_update_interval_ms: 1000 ### Runtime orchestration settings work_orchestrator: - # The number of worker threads to spawn - max_workers: 4 + max_dworkers: 4 + max_oworkers: 32 + owork_per_core: 32 ### Queue Manager settings queue_manager: - queue_depth: 256 + queue_depth: 100000 max_lanes: 16 max_queues: 1024 shm_allocator: kScalablePageAllocator shm_name: "hrun_shm" shm_size: 0g + data_shm_size: 4g ### Task Registry task_registry: [ diff --git a/test/unit/hermes/test_bucket.cc b/test/unit/hermes/test_bucket.cc index 39731f052..6f5a60ce6 100644 --- a/test/unit/hermes/test_bucket.cc +++ b/test/unit/hermes/test_bucket.cc @@ -93,6 +93,33 @@ TEST_CASE("TestHermesPut") { MPI_Barrier(MPI_COMM_WORLD); } +TEST_CASE("TestHermesAsyncPut") { + int rank, nprocs; + MPI_Barrier(MPI_COMM_WORLD); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nprocs); + + // Initialize Hermes on all nodes + HERMES->ClientInit(); + + // Create a bucket + hermes::Context ctx; + hermes::Bucket bkt("hello"); + + size_t count_per_proc = 256; + size_t off = rank * count_per_proc; + size_t proc_count = off + count_per_proc; + for (size_t i = off; i < proc_count; ++i) { + HILOG(kInfo, "Iteration: {}", i); + // Put a blob + hermes::Blob blob(MEGABYTES(1)); + memset(blob.data(), i % 256, blob.size()); + bkt.AsyncPut(std::to_string(i), blob, ctx); + } + MPI_Barrier(MPI_COMM_WORLD); + HRUN_ADMIN->FlushRoot(DomainId::GetGlobal()); +} + TEST_CASE("TestHermesPutGet") { int rank, nprocs; MPI_Barrier(MPI_COMM_WORLD); @@ -108,14 +135,14 @@ TEST_CASE("TestHermesPutGet") { hermes::Bucket bkt("hello"); HILOG(kInfo, "BUCKET LOADED!!!") - size_t count_per_proc = 4; + size_t count_per_proc = 16; size_t off = rank * count_per_proc; size_t proc_count = off + count_per_proc; for (int rep = 0; rep < 4; ++rep) { for (size_t i = off; i < proc_count; ++i) { HILOG(kInfo, "Iteration: {} with blob name {}", i, std::to_string(i)); // Put a blob - hermes::Blob blob(KILOBYTES(4)); + hermes::Blob blob(MEGABYTES(1)); memset(blob.data(), i % 256, blob.size()); hermes::BlobId blob_id = bkt.Put(std::to_string(i), blob, ctx); HILOG(kInfo, "(iteration {}) Using BlobID: {}", i, blob_id); @@ -125,6 +152,7 @@ TEST_CASE("TestHermesPutGet") { REQUIRE(blob.size() == blob2.size()); REQUIRE(blob == blob2); } + sleep(5); } } @@ -465,11 +493,8 @@ TEST_CASE("TestHermesDataStager") { // Create a stageable bucket using hermes::data_stager::BinaryFileStager; - hermes::Context ctx; - ctx.flags_.SetBits(HERMES_IS_FILE); - hshm::charbuf url = - BinaryFileStager::BuildFileUrl(path, page_size); - hermes::Bucket bkt(url.str(), file_size, HERMES_IS_FILE); + hermes::Context ctx = BinaryFileStager::BuildContext(page_size); + hermes::Bucket bkt(path, ctx, file_size); // Put a few blobs in the bucket for (size_t i = off; i < proc_count; ++i) { @@ -495,6 +520,8 @@ TEST_CASE("TestHermesDataStager") { MPI_Barrier(MPI_COMM_WORLD); // Verify staging happened + HRUN_ADMIN->FlushRoot(DomainId::GetGlobal()); + HILOG(kInfo, "Flushing finished") } TEST_CASE("TestHermesDataOp") { @@ -507,7 +534,6 @@ TEST_CASE("TestHermesDataOp") { HERMES->ClientInit(); // Create a bucket that supports derived quantities - using hermes::data_stager::BinaryFileStager; hermes::Context ctx; ctx.flags_.SetBits(HERMES_HAS_DERIVED); std::string url = "data_bkt"; @@ -522,10 +548,12 @@ TEST_CASE("TestHermesDataOp") { op_graph.ops_.emplace_back(op); HERMES->RegisterOp(op_graph); - size_t count_per_proc = 16; + size_t count_per_proc = 256; size_t off = rank * count_per_proc; size_t proc_count = off + count_per_proc; - size_t page_size = KILOBYTES(4); + size_t page_size = MEGABYTES(1); + + HILOG(kInfo, "GENERATING VALUES BETWEEN 5 and 261"); // Put a few blobs in the bucket for (size_t i = off; i < proc_count; ++i) { @@ -543,25 +571,20 @@ TEST_CASE("TestHermesDataOp") { } MPI_Barrier(MPI_COMM_WORLD); - // HRUN_ADMIN->FlushRoot(DomainId::GetGlobal()); + HRUN_ADMIN->FlushRoot(DomainId::GetGlobal()); // Verify derived operator happens hermes::Bucket bkt_min("data_bkt_min", 0, 0); - size_t size; - do { - size = bkt_min.GetSize(); - if (size != sizeof(float) * count_per_proc * nprocs) { - HILOG(kInfo, "Waiting for derived data"); - sleep(1); - } else { - break; - } - } while (true); + HRUN_ADMIN->FlushRoot(DomainId::GetGlobal()); + size_t size = bkt_min.GetSize(); + REQUIRE(size == sizeof(float) * count_per_proc * nprocs); hermes::Blob blob2; bkt_min.Get(std::to_string(0), blob2, ctx); float min = *(float *)blob2.data(); REQUIRE(size == sizeof(float) * count_per_proc * nprocs); REQUIRE(min == 5); + + HILOG(kInfo, "MINIMUM VALUE QUERY FROM EMPRESS: {}", min); } TEST_CASE("TestHermesCollectMetadata") { @@ -590,7 +613,108 @@ TEST_CASE("TestHermesCollectMetadata") { // Get contained blob ids hermes::MetadataTable table = HERMES->CollectMetadataSnapshot(); REQUIRE(table.blob_info_.size() == 1024 * nprocs); - REQUIRE(table.bkt_info_.size() == 1); - REQUIRE(table.target_info_.size() >= 4); + REQUIRE(table.bkt_info_.size() == nprocs); + // REQUIRE(table.target_info_.size() >= 4); + MPI_Barrier(MPI_COMM_WORLD); +} + +/* +TEST_CASE("TestHermesDataPlacement") { + int rank, nprocs; + MPI_Barrier(MPI_COMM_WORLD); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nprocs); + + // Initialize Hermes on all nodes + HERMES->ClientInit(); + + // Create a bucket + hermes::Context ctx; + hermes::Bucket bkt("hello"); + + size_t count_per_proc = 16; + size_t off = rank * count_per_proc; + size_t proc_count = off + count_per_proc; + + // Put a few blobs in the bucket + HILOG(kInfo, "Initially placing blobs") + for (size_t i = off; i < proc_count; ++i) { + HILOG(kInfo, "Iteration: {}", i); + hermes::Blob blob(MEGABYTES(1)); + memset(blob.data(), i % 256, blob.size()); + bkt.AsyncPut(std::to_string(i), blob, ctx); + } + MPI_Barrier(MPI_COMM_WORLD); + sleep(20); + + while (true) { + // Demote half of blobs + HILOG(kInfo, "Demoting blobs") + for (size_t i = off; i < proc_count; ++i) { + HILOG(kInfo, "Iteration: {}", i); + hermes::BlobId blob_id = bkt.GetBlobId(std::to_string(i)); + bkt.ReorganizeBlob(blob_id, .5, 0, ctx); + } + MPI_Barrier(MPI_COMM_WORLD); + sleep(20); + + // Promote half of blobs + HILOG(kInfo, "Promoting blobs") + for (size_t i = off; i < proc_count; ++i) { + HILOG(kInfo, "Iteration: {}", i); + hermes::BlobId blob_id = bkt.GetBlobId(std::to_string(i)); + bkt.ReorganizeBlob(blob_id, 1, 0, ctx); + } + MPI_Barrier(MPI_COMM_WORLD); + sleep(20); + } +} + +TEST_CASE("TestHermesDataPlacementFancy") { + int rank, nprocs; + MPI_Barrier(MPI_COMM_WORLD); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nprocs); + + // Initialize Hermes on all nodes + HERMES->ClientInit(); + + // Create a bucket + hermes::Context ctx; + hermes::Bucket bkt("hello"); + + size_t count_per_proc = 16; + size_t off = rank * count_per_proc; + size_t proc_count = off + count_per_proc; + + // Put a few blobs in the bucket + HILOG(kInfo, "Initially placing blobs") + for (size_t i = off; i < proc_count; ++i) { + HILOG(kInfo, "Iteration: {}", i); + hermes::Blob blob(MEGABYTES(1)); + memset(blob.data(), i % 256, blob.size()); + bkt.AsyncPut(std::to_string(i), blob, ctx); + } MPI_Barrier(MPI_COMM_WORLD); + sleep(20); + + std::vector scores = { + 1.0, .5, .01, 0 + }; + int count = 0; + + while (true) { + int score_id = count % scores.size(); + // Demote half of blobs + HILOG(kInfo, "Demoting blobs") + for (size_t i = off; i < proc_count; ++i) { + HILOG(kInfo, "Iteration: {}", i); + hermes::BlobId blob_id = bkt.GetBlobId(std::to_string(i)); + bkt.ReorganizeBlob(blob_id, scores[score_id], 0, ctx); + } + MPI_Barrier(MPI_COMM_WORLD); + sleep(5); + count += 1; + } } +*/ diff --git a/test/unit/hermes_adapters/CMakeLists.txt b/test/unit/hermes_adapters/CMakeLists.txt index 72962ce60..a16722b6c 100644 --- a/test/unit/hermes_adapters/CMakeLists.txt +++ b/test/unit/hermes_adapters/CMakeLists.txt @@ -1,5 +1,4 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHERMES_PRELOAD -DHERMES_RPC_THALLIUM") -set(ADAPTER_COMMON ${CMAKE_CURRENT_SOURCE_DIR}/catch_config.h) set(HERMES_ADAPTER_TEST_DIR ${HERMES_ADAPTER_DIR}/test) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/test/unit/hermes_adapters/adapter_test_utils.h b/test/unit/hermes_adapters/adapter_test_utils.h index bfdfe9f7d..e2f76d4fe 100644 --- a/test/unit/hermes_adapters/adapter_test_utils.h +++ b/test/unit/hermes_adapters/adapter_test_utils.h @@ -17,45 +17,8 @@ #include #include -bool FilesystemSupportsTmpfile() { - bool result = false; - -#if O_TMPFILE - // NOTE(chogan): Even if O_TMPFILE is defined, the underlying filesystem might - // not support it. - int tmp_fd = open("/tmp", O_WRONLY | O_TMPFILE, 0600); - if (tmp_fd > 0) { - result = true; - close(tmp_fd); - } -#endif - - return result; -} - -size_t GetRandomOffset(size_t i, unsigned int offset_seed, size_t stride, - size_t total_size) { - return abs((int)(((i * rand_r(&offset_seed)) % stride) % total_size)); -} - -std::string GenRandom(const int len) { - std::string tmp_s; - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - - srand(100); - - tmp_s.reserve(len); - - for (int i = 0; i < len; ++i) { - tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)]; - } - - tmp_s[len - 1] = '\n'; - - return tmp_s; -} +#define CATCH_CONFIG_RUNNER +#include +namespace cl = Catch::Clara; #endif // HERMES_ADAPTER_TEST_UTILS_H diff --git a/test/unit/hermes_adapters/binary_file_tests.h b/test/unit/hermes_adapters/binary_file_tests.h new file mode 100644 index 000000000..829d4dc40 --- /dev/null +++ b/test/unit/hermes_adapters/binary_file_tests.h @@ -0,0 +1,77 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_TEST_UNIT_HERMES_ADAPTERS_BINARY_FILE_TESTS_H_ +#define HERMES_TEST_UNIT_HERMES_ADAPTERS_BINARY_FILE_TESTS_H_ + +#include "filesystem_tests.h" + +namespace hermes::adapter::test { + +class BinaryFileTests : public FilesystemTests { + public: + std::vector GenerateData() override { + return GenRandom(total_size_, 200); + } + + void CreateFile(const std::string &path, + std::vector &data) override { + int fd = open(path.c_str(), O_CREAT | O_TRUNC | O_RDWR, 0666); + if (fd == -1) { + HELOG(kFatal, "Failed to open file: {}", path); + } + int ret = write(fd, data.data(), data.size()); + if (ret != data.size()) { + return; + } + close(fd); + REQUIRE(stdfs::file_size(path) == data.size()); + HILOG(kInfo, "Created file {}", path); + } + + void CompareFiles(FileInfo &info) override { + size_t cmp_size = stdfs::file_size(info.cmp_); + size_t hermes_size = stdfs::file_size(info.hermes_); + REQUIRE(cmp_size == hermes_size); + std::vector d1(cmp_size, '0'); + std::vector d2(hermes_size, '1'); + LoadFile(info.cmp_, d1); + LoadFile(info.hermes_, d2); + CompareBuffers(d1, d2); + } + + private: + void LoadFile(const std::string &path, std::vector &data) { + FILE* fh = fopen(path.c_str(), "r"); + if (fh == nullptr) { + HELOG(kFatal, "Failed to open file: {}", path); + } + REQUIRE(fh != nullptr); + size_t load_size = fread(data.data(), 1, data.size(), fh); + REQUIRE(load_size == data.size()); + int status = fclose(fh); + REQUIRE(status == 0); + } + + void CompareBuffers(const std::vector &d1, + const std::vector &d2) { + size_t char_mismatch = 0; + for (size_t pos = 0; pos < d1.size(); ++pos) { + if (d1[pos] != d2[pos]) char_mismatch++; + } + REQUIRE(char_mismatch == 0); + } +}; + +} // namespace hermes::adapter::test + +#endif // HERMES_TEST_UNIT_HERMES_ADAPTERS_BINARY_FILE_TESTS_H_ diff --git a/test/unit/hermes_adapters/filesystem_tests.h b/test/unit/hermes_adapters/filesystem_tests.h new file mode 100644 index 000000000..12f0aa10c --- /dev/null +++ b/test/unit/hermes_adapters/filesystem_tests.h @@ -0,0 +1,297 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_TEST_UNIT_HERMES_ADAPTERS_FILESYSTEM_TESTS_H_ +#define HERMES_TEST_UNIT_HERMES_ADAPTERS_FILESYSTEM_TESTS_H_ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "hermes_shm/util/singleton.h" +#include "hermes/hermes.h" + +#define CATCH_CONFIG_RUNNER +#include +#include + +namespace hermes::adapter::test { + +/** Pre-create the Hermes file */ +#define TEST_DO_CREATE BIT_OPT(u32, 0) +/** Allow this file to be buffered with Hermes */ +#define TEST_WITH_HERMES BIT_OPT(u32, 1) +/** Make this file shared across processes */ +#define TEST_FILE_SHARED BIT_OPT(u32, 2) + +struct FileInfo { + std::string hermes_; /** The file produced by Hermes */ + std::string cmp_; /** The file to verify against */ + bitfield32_t flags_; /** Various flags */ +}; + +template +class FilesystemTests { + public: + bool supports_tmpfile; + std::vector write_data_; + std::vector read_data_; + std::list files_; + int pid_; + std::string pid_str_; + + std::string filename_ = "test.dat"; + std::string dir_ = "/tmp/test_hermes"; + size_t request_size_ = KILOBYTES(64); + size_t num_iterations_ = 64; + size_t total_size_; // The size of the EXISTING file + int rank_ = 0; + int comm_size_ = 1; + + public: + cl::Parser DefineOptions() { + return cl::Opt(filename_, "filename")["-f"]["--filename"]( + "Filename used for performing I/O") | + cl::Opt(dir_, "dir")["-d"]["--directory"]( + "Directory used for performing I/O") | + cl::Opt(request_size_, "request_size")["-s"]["--request_size"]( + "Request size used for performing I/O"); + } + + int Init(int argc, char **argv) { + MPI_Init(&argc, &argv); + MPI_Comm_rank(MPI_COMM_WORLD, &rank_); + MPI_Comm_size(MPI_COMM_WORLD, &comm_size_); + Catch::Session session; + auto cli = session.cli() | DefineOptions(); + session.cli(cli); + int rc = session.applyCommandLine(argc, argv); + if (rc != 0) return rc; + +#if HERMES_INTERCEPT == 1 + TRANSPARENT_HERMES(); + setenv("HERMES_FLUSH_MODE", "kSync", 1); + HERMES_CLIENT_CONF.flushing_mode_ = hermes::FlushingMode::kSync; +#endif + + total_size_ = request_size_ * num_iterations_; + write_data_ = GenRandom(request_size_); + read_data_ = std::vector(request_size_, 'r'); + supports_tmpfile = FilesystemSupportsTmpfile(); + pid_ = getpid(); + pid_str_ = std::to_string(pid_); + RegisterFiles(); + + rc = session.run(); + MPI_Finalize(); + return rc; + } + + void RegisterPath(const std::string &basename, + u32 flags, + FileInfo &info) { + info.hermes_ = dir_ + "/" + filename_ + "_" + basename + "_"; + info.cmp_ = info.hermes_ + "cmp_"; + info.flags_.SetBits(flags | TEST_WITH_HERMES); + if (!info.flags_.Any(TEST_FILE_SHARED)) { + info.hermes_ += pid_str_; + info.cmp_ += pid_str_; + } + files_.push_back(info); + } + + void RegisterTmpPath(FileInfo &info) { + info.hermes_ = "/tmp"; + info.cmp_ = "/tmp"; + info.flags_.SetBits(0); + files_.push_back(info); + } + + void IgnoreAllFiles() { + for (const FileInfo &info : files_) { + HERMES_CLIENT_CONF.SetAdapterPathTracking(info.hermes_, false); + HERMES_CLIENT_CONF.SetAdapterPathTracking(info.cmp_, false); + } + } + + void TrackAllFiles() { + for (const FileInfo &info : files_) { + HERMES_CLIENT_CONF.SetAdapterPathTracking( + info.hermes_, info.flags_.Any(TEST_WITH_HERMES)); + } + } + + void RemoveAllFiles() { + for (const FileInfo &info : files_) { + if (info.flags_.Any(TEST_WITH_HERMES)) { + RemoveFile(info.hermes_); + RemoveFile(info.cmp_); + HILOG(kInfo, "Removing files: {} {}", info.hermes_, info.cmp_); + } + } + } + + void CreateFiles() { + std::vector data = GenerateData(); + for (const FileInfo &info : files_) { + if (!info.flags_.Any(TEST_WITH_HERMES)) { + continue; + } + if (info.flags_.Any(TEST_DO_CREATE)) { + if (info.flags_.Any(TEST_FILE_SHARED) && rank_ != 0) { + continue; + } + CreateFile(info.cmp_, data); + CreateFile(info.hermes_, data); + } + } + } + + void Flush() { +#if HERMES_INTERCEPT == 1 + // HERMES->Clear(); + HRUN_ADMIN->FlushRoot(DomainId::GetGlobal()); +#endif + } + + void Pretest() { + MPI_Barrier(MPI_COMM_WORLD); + IgnoreAllFiles(); + RemoveAllFiles(); + MPI_Barrier(MPI_COMM_WORLD); + CreateFiles(); + TrackAllFiles(); + MPI_Barrier(MPI_COMM_WORLD); + } + + void Posttest(bool compare_data = true) { + MPI_Barrier(MPI_COMM_WORLD); + Flush(); + IgnoreAllFiles(); + if (compare_data) { + for (FileInfo &info : files_) { + if (!info.flags_.Any(TEST_WITH_HERMES)) { + continue; + } + if (stdfs::exists(info.hermes_) && stdfs::exists(info.cmp_)) { + CompareFiles(info); + } + } + } + /* Delete the files from both Hermes and the backend. */ + MPI_Barrier(MPI_COMM_WORLD); + TrackAllFiles(); + RemoveAllFiles(); + Flush(); + MPI_Barrier(MPI_COMM_WORLD); + } + + virtual void RegisterFiles() = 0; + virtual void CreateFile(const std::string &path, std::vector &data) = 0; + virtual std::vector GenerateData() = 0; + virtual void CompareFiles(FileInfo &info) = 0; + + static size_t GetRandomOffset( + size_t i, unsigned int offset_seed, + size_t stride, size_t total_size) { + return abs((int)(((i * rand_r(&offset_seed)) % stride) % total_size)); + } + + std::vector GenRandom(const size_t len, int seed = 100) { + auto tmp_s = std::vector(len); + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + srand(seed); + for (int i = 0; i < len; ++i) + tmp_s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; + return tmp_s; + } + + static inline u32 RotateLeft(const u32 x, int k) { + u32 result = (x << k) | (x >> (32 - k)); + + return result; + } + + u32 GenNextRandom() { + static u32 random_state[4] = {111, 222, 333, 444}; + const u32 random = random_state[0] + random_state[3]; + + const u32 t = random_state[1] << 9; + + random_state[2] ^= random_state[0]; + random_state[3] ^= random_state[1]; + random_state[1] ^= random_state[2]; + random_state[0] ^= random_state[3]; + + random_state[2] ^= t; + + random_state[3] = RotateLeft(random_state[3], 11); + + return random; + } + + /** + * Return a random float in the range [0.0f, 1.0f] + * */ + f32 GenRandom0to1() { + u32 random_u32 = GenNextRandom(); + + f32 result = (random_u32 >> 8) * 0x1.0p-24f; + + return result; + } + + private: + void RemoveFile(const std::string &path) { + stdfs::remove(path); + if (stdfs::exists(path)) { + HELOG(kFatal, "Failed to remove: {}", path) + } +#ifdef HERMES_INTERCEPT + hermes::Bucket bkt = HERMES->GetBucket(path); + bkt.Destroy(); +#endif + } + + bool FilesystemSupportsTmpfile() { + bool result = false; + +#if O_TMPFILE + // NOTE(chogan): Even if O_TMPFILE is defined, the underlying filesystem + // might not support it. + int tmp_fd = open("/tmp", O_WRONLY | O_TMPFILE, 0600); + if (tmp_fd > 0) { + result = true; + close(tmp_fd); + } +#endif + + return result; + } +}; + +} // namespace hermes::adapter::test + +#endif // HERMES_TEST_UNIT_HERMES_ADAPTERS_FILESYSTEM_TESTS_H_ diff --git a/test/unit/hermes_adapters/mpiio/CMakeLists.txt b/test/unit/hermes_adapters/mpiio/CMakeLists.txt index 7fafaf3f0..cca4d820e 100644 --- a/test/unit/hermes_adapters/mpiio/CMakeLists.txt +++ b/test/unit/hermes_adapters/mpiio/CMakeLists.txt @@ -1,12 +1,27 @@ -add_executable(mpiio_adapter_test mpiio_adapter_test.cpp ${ADAPTER_COMMON}) -# pytest(mpiio test_mpiio_basic) +# MPI adapter tests without hermes +add_executable(mpiio_adapter_test + mpiio_adapter_test.cc + mpiio_adapter_basic_test.cc) +target_link_libraries(mpiio_adapter_test + hermes) +add_dependencies(mpiio_adapter_test + hermes) +target_compile_definitions(mpiio_adapter_test PUBLIC + HERMES_MPI_TESTS=true) +jarvis_test(mpiio test_mpiio_basic) -add_executable(hermes_mpiio_adapter_test mpiio_adapter_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_mpiio_adapter_test hermes_mpiio) -add_dependencies(hermes_mpiio_adapter_test hermes_mpiio) -set_target_properties(hermes_mpiio_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -pytest(mpiio test_hermes_mpiio_basic_sync) -pytest(mpiio test_hermes_mpiio_basic_async) +# MPI adapter tests with hermes +add_executable(hermes_mpiio_adapter_test + mpiio_adapter_test.cc + mpiio_adapter_basic_test.cc) +target_link_libraries(hermes_mpiio_adapter_test + hermes_mpiio) +add_dependencies(hermes_mpiio_adapter_test + hermes_mpiio) +target_compile_definitions(hermes_mpiio_adapter_test PUBLIC + HERMES_INTERCEPT=1 HERMES_MPI_TESTS=true) +jarvis_test(mpiio test_hermes_mpiio_basic_sync) +jarvis_test(mpiio test_hermes_mpiio_basic_async) set(MPIIO_TESTS mpiio_adapter_test diff --git a/test/unit/hermes_adapters/mpiio/mpiio_adapter_basic_test.cc b/test/unit/hermes_adapters/mpiio/mpiio_adapter_basic_test.cc new file mode 100644 index 000000000..918ae11ac --- /dev/null +++ b/test/unit/hermes_adapters/mpiio/mpiio_adapter_basic_test.cc @@ -0,0 +1,1114 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "mpiio_adapter_test.h" + +TEST_CASE("Open", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[coordination=independent]" + "[synchronicity=sync]" + "[operation=single_open]" + "[repetition=1][file=1]") { + TESTER->Pretest(); + SECTION("open non-existant file") { + TESTER->test_open(TESTER->new_file_, MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + TESTER->test_open(TESTER->new_file_, MPI_MODE_RDWR | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + } + + SECTION("opening existing file write-only") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_WRONLY | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + SECTION("opening existing file and read/write") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDWR | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("open existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDONLY | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("append write existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_APPEND | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + TESTER->test_open(TESTER->existing_file_, MPI_MODE_APPEND, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + TESTER->test_open(TESTER->existing_file_, + MPI_MODE_WRONLY | MPI_MODE_APPEND, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_open(TESTER->existing_file_, + MPI_MODE_RDONLY | MPI_MODE_APPEND, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDWR | MPI_MODE_APPEND, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("append write and read new file") { + TESTER->test_open(TESTER->existing_file_, + MPI_MODE_RDWR | MPI_MODE_APPEND | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("delete on close mode") { + TESTER->test_open( + TESTER->new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::exists(TESTER->new_file_.hermes_)); + TESTER->test_close(); + REQUIRE(!stdfs::exists(TESTER->new_file_.hermes_)); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + TESTER->Posttest(); +} + +TEST_CASE("OpenCollective", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[coordination=collective]" + "[synchronicity=sync]" + "[operation=single_open]" + "[repetition=1][file=1]") { + TESTER->Pretest(); + SECTION("open on non-existant shared file") { + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_RDONLY | MPI_MODE_EXCL, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_RDONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + TESTER->test_open(TESTER->shared_new_file_, MPI_MODE_RDWR | MPI_MODE_EXCL, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_RDWR | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("open on shared existing file") { + TESTER->test_open(TESTER->shared_existing_file_, + MPI_MODE_WRONLY | MPI_MODE_EXCL, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_open(TESTER->shared_existing_file_, + MPI_MODE_RDWR | MPI_MODE_EXCL, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_open(TESTER->shared_existing_file_, + MPI_MODE_RDONLY | MPI_MODE_EXCL, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + TESTER->test_open(TESTER->shared_existing_file_, MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_open(TESTER->shared_existing_file_, MPI_MODE_RDWR, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("append write/read on shared existing file") { + TESTER->test_open(TESTER->shared_existing_file_, + MPI_MODE_RDWR | MPI_MODE_APPEND, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("append write and read on shared new file") { + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_RDWR | MPI_MODE_APPEND | MPI_MODE_CREATE, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("delete on close mode on new file") { + TESTER->test_open( + TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(!stdfs::exists(TESTER->shared_new_file_.hermes_)); + } + TESTER->Posttest(); +} + +TEST_CASE("SingleWrite", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_write]" + "[synchronicity=sync]" + "[coordination=independent]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + bool check_bytes = true; + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("write to new file") { + TESTER->test_open(TESTER->new_file_, MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + + SECTION("write to new file with allocate") { + TESTER->test_open(TESTER->new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_preallocate(TESTER->request_size_ * TESTER->comm_size_); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->request_size_ * TESTER->rank_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + MPI_Barrier(MPI_COMM_WORLD); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + (size_t)TESTER->size_written_orig_ * TESTER->comm_size_); + } + + SECTION("append to existing file") { + auto existing_size = stdfs::file_size(TESTER->existing_file_.hermes_); + TESTER->test_open(TESTER->existing_file_, + MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->existing_file_.hermes_) == + existing_size + TESTER->size_written_orig_); + } + + SECTION("append to new file") { + TESTER->test_open(TESTER->new_file_, + MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + + SECTION("write_at to existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_write_at(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR, + TESTER->rank_ * TESTER->request_size_); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("write_at to new file") { + TESTER->test_open(TESTER->new_file_, MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_write_at(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR, + 0); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + + SECTION("delete on close mode on new file") { + TESTER->test_open( + TESTER->new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + REQUIRE(stdfs::exists(TESTER->new_file_.hermes_)); + TESTER->test_close(); + REQUIRE(!stdfs::exists(TESTER->new_file_.hermes_)); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("delete on close mode on existing file") { + auto original_size = stdfs::file_size(TESTER->existing_file_.hermes_); + TESTER->test_open(TESTER->existing_file_, + MPI_MODE_WRONLY | MPI_MODE_EXCL | + MPI_MODE_DELETE_ON_CLOSE, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + REQUIRE(stdfs::exists(TESTER->existing_file_.hermes_)); + auto new_size = + original_size > (size_t)TESTER->size_written_orig_ * TESTER->comm_size_ + ? original_size + : TESTER->size_written_orig_ * TESTER->comm_size_; + REQUIRE(stdfs::file_size(TESTER->existing_file_.hermes_) == + (size_t)new_size); + TESTER->test_close(); + REQUIRE(!stdfs::exists(TESTER->existing_file_.hermes_)); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + check_bytes = false; + } + TESTER->Posttest(check_bytes); +} + +TEST_CASE("SingleWriteCollective", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_write]" + "[synchronicity=sync]" + "[coordination=collective]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + bool check_bytes = true; + SECTION("write to existing file") { + TESTER->test_open(TESTER->shared_existing_file_, MPI_MODE_RDWR, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("write to new file") { + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->shared_new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + + // TODO(chogan): This test fails intermittently. Needs diagnosis. + // https://github.com/HDFGroup/hermes/issues/209 + SECTION("write to new file using shared ptr") { + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write_shared(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->shared_new_file_.hermes_) == + (size_t)TESTER->size_written_orig_ * TESTER->comm_size_); + } + + SECTION("write to new file with allocate") { + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_preallocate(TESTER->request_size_ * TESTER->comm_size_); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->request_size_ * TESTER->rank_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + MPI_Barrier(MPI_COMM_WORLD); + REQUIRE(stdfs::file_size(TESTER->shared_new_file_.hermes_) == + (size_t)TESTER->size_written_orig_ * TESTER->comm_size_); + } + + SECTION("write_at_all to existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_write_at_all(TESTER->write_data_.data(), TESTER->request_size_, + MPI_CHAR, TESTER->rank_ * TESTER->request_size_); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("write_at_all to new file") { + TESTER->test_open(TESTER->new_file_, MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_write_at_all(TESTER->write_data_.data(), + TESTER->request_size_, + MPI_CHAR, 0); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + + SECTION("append to existing file") { + auto existing_size = stdfs::file_size(TESTER->existing_file_.hermes_); + TESTER->test_open(TESTER->shared_existing_file_, + MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_write_all(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->shared_existing_file_.hermes_) == + existing_size + TESTER->size_written_orig_); + } + + SECTION("append to new file") { + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_write_all(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->shared_new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + + SECTION("write_ordered to existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_write_ordered(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("write_ordered to new file") { + TESTER->test_open(TESTER->new_file_, MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_write_ordered(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + SECTION("delete on close mode on new file") { + TESTER->test_open( + TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + REQUIRE(stdfs::exists(TESTER->shared_new_file_.hermes_)); + MPI_Barrier(MPI_COMM_WORLD); + TESTER->test_close(); + REQUIRE(!stdfs::exists(TESTER->shared_new_file_.hermes_)); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("delete on close mode on existing file") { + auto original_size = stdfs::file_size( + TESTER->shared_existing_file_.hermes_); + TESTER->test_open(TESTER->shared_existing_file_, + MPI_MODE_WRONLY | MPI_MODE_EXCL | + MPI_MODE_DELETE_ON_CLOSE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + REQUIRE(stdfs::exists(TESTER->shared_existing_file_.hermes_)); + auto new_size = + original_size > (size_t)TESTER->size_written_orig_ * TESTER->comm_size_ + ? original_size + : TESTER->size_written_orig_ * TESTER->comm_size_; + REQUIRE(stdfs::file_size(TESTER->shared_existing_file_.hermes_) == + (size_t)new_size); + TESTER->test_close(); + REQUIRE(!stdfs::exists(TESTER->shared_existing_file_.hermes_)); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + check_bytes = false; + } + TESTER->Posttest(check_bytes); +} + +TEST_CASE("SingleAsyncWrite", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_write]" + "[coordination=independent]" + "[synchronicity=async]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + bool check_bytes = true; + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iwrite(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("write to new file") { + TESTER->test_open(TESTER->new_file_, MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iwrite(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + + SECTION("write to new file using shared ptr") { + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iwrite_shared(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->shared_new_file_.hermes_) == + (size_t)TESTER->size_written_orig_ * TESTER->comm_size_); + } + + SECTION("write to new file with allocate") { + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_preallocate(TESTER->request_size_ * TESTER->comm_size_); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->request_size_ * TESTER->rank_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + MPI_Barrier(MPI_COMM_WORLD); + REQUIRE(stdfs::file_size(TESTER->shared_new_file_.hermes_) == + (size_t)TESTER->size_written_orig_ * TESTER->comm_size_); + } + + SECTION("append to existing file") { + auto existing_size = stdfs::file_size(TESTER->existing_file_.hermes_); + TESTER->test_open(TESTER->existing_file_, + MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_iwrite(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->existing_file_.hermes_) == + existing_size + TESTER->size_written_orig_); + } + + SECTION("append to new file") { + TESTER->test_open(TESTER->new_file_, + MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_iwrite(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + + SECTION("write_at to existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_iwrite_at(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR, + TESTER->rank_ * TESTER->request_size_); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("write_at to new file") { + TESTER->test_open(TESTER->new_file_, MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_iwrite_at(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR, + 0); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + + SECTION("delete on close mode on new file") { + TESTER->test_open( + TESTER->new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iwrite(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + REQUIRE(stdfs::exists(TESTER->new_file_.hermes_)); + TESTER->test_close(); + REQUIRE(!stdfs::exists(TESTER->new_file_.hermes_)); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("delete on close mode on existing file") { + TESTER->test_open(TESTER->existing_file_, + MPI_MODE_WRONLY | MPI_MODE_EXCL | + MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iwrite(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + REQUIRE(stdfs::exists(TESTER->existing_file_.hermes_)); + TESTER->test_close(); + REQUIRE(!stdfs::exists(TESTER->existing_file_.hermes_)); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + check_bytes = false; + } + TESTER->Posttest(check_bytes); +} + +TEST_CASE("SingleAsyncWriteCollective", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_write]" + "[synchronicity=async]" + "[coordination=collective]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + bool check_bytes = true; + SECTION("write to existing file") { + TESTER->test_open(TESTER->shared_existing_file_, MPI_MODE_RDWR, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iwrite(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("write to new file") { + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iwrite(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->shared_new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + + SECTION("write to new file using shared ptr") { + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iwrite_shared(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->shared_new_file_.hermes_) == + (size_t)TESTER->size_written_orig_ * TESTER->comm_size_); + } + + SECTION("write to new file with allocate") { + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_preallocate(TESTER->request_size_ * TESTER->comm_size_); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->request_size_ * TESTER->rank_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iwrite(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + MPI_Barrier(MPI_COMM_WORLD); + REQUIRE(stdfs::file_size(TESTER->shared_new_file_.hermes_) == + (size_t)TESTER->size_written_orig_ * TESTER->comm_size_); + } + + SECTION("write_at_all to existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDWR, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_iwrite_at_all(TESTER->write_data_.data(), + TESTER->request_size_, + MPI_CHAR, TESTER->rank_ * TESTER->request_size_); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("write_at_all to new file") { + TESTER->test_open(TESTER->new_file_, MPI_MODE_WRONLY | MPI_MODE_CREATE, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_iwrite_at_all(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR, 0); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + SECTION("append to existing file") { + auto existing_size = stdfs::file_size(TESTER->existing_file_.hermes_); + TESTER->test_open(TESTER->shared_existing_file_, + MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_iwrite_all(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->shared_existing_file_.hermes_) == + existing_size + TESTER->size_written_orig_); + } + + SECTION("append to new file") { + TESTER->test_open(TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_iwrite_all(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + REQUIRE(stdfs::file_size(TESTER->shared_new_file_.hermes_) == + (size_t)TESTER->size_written_orig_); + } + SECTION("delete on close mode on new file") { + TESTER->test_open( + TESTER->shared_new_file_, + MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iwrite(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + REQUIRE(stdfs::exists(TESTER->shared_new_file_.hermes_)); + TESTER->test_close(); + REQUIRE(!stdfs::exists(TESTER->shared_new_file_.hermes_)); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("delete on close mode on existing file") { + auto original_size = stdfs::file_size( + TESTER->shared_existing_file_.hermes_); + TESTER->test_open(TESTER->shared_existing_file_, + MPI_MODE_WRONLY | MPI_MODE_EXCL | + MPI_MODE_DELETE_ON_CLOSE, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iwrite(TESTER->write_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_written_orig_ == TESTER->request_size_); + REQUIRE(stdfs::exists(TESTER->shared_existing_file_.hermes_)); + auto new_size = + original_size > (size_t)TESTER->size_written_orig_ * TESTER->comm_size_ + ? original_size + : TESTER->size_written_orig_ * TESTER->comm_size_; + REQUIRE(stdfs::file_size(TESTER->shared_existing_file_.hermes_) == + (size_t)new_size); + TESTER->test_close(); + REQUIRE(!stdfs::exists(TESTER->shared_existing_file_.hermes_)); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + check_bytes = false; + } + TESTER->Posttest(check_bytes); +} + +TEST_CASE("SingleRead", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_read]" + "[synchronicity=sync]" + "[coordination=independent]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + SECTION("read from non-existing file") { + TESTER->test_open(TESTER->new_file_, MPI_MODE_RDONLY | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + } + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_read(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("read from existing file using shared ptr") { + TESTER->test_open(TESTER->shared_existing_file_, MPI_MODE_RDONLY, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_read_shared(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("read at the end of existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(0, MPI_SEEK_END); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + MPI_Offset offset; + MPI_File_get_position(TESTER->fh_orig_, &offset); + REQUIRE(offset == + (long long)(TESTER->request_size_ * TESTER->num_iterations_)); + TESTER->test_read(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE(TESTER->size_read_orig_ == 0); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("read_at from existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_read_at(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR, + TESTER->rank_ * TESTER->request_size_); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + TESTER->Posttest(); +} + +TEST_CASE("SingleReadCollective", "[process=" + + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_read]" + "[synchronicity=sync]" + "[coordination=collective]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + SECTION("read from non-existing file") { + TESTER->test_open(TESTER->shared_new_file_, MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + } + + SECTION("read from existing file") { + TESTER->test_open(TESTER->shared_existing_file_, MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_read_all(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("read from existing file using shared ptr") { + TESTER->test_open(TESTER->shared_existing_file_, MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_read_shared(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("read_at_all from existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_read_at_all(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR, + TESTER->rank_ * TESTER->request_size_); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("read_ordered from existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_read_ordered(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + TESTER->Posttest(); +} + +TEST_CASE("SingleAsyncRead", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_read]" + "[synchronicity=async]" + "[coordination=independent]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + SECTION("read from non-existing file") { + TESTER->test_open(TESTER->new_file_, MPI_MODE_RDONLY | MPI_MODE_EXCL, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + } + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iread(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("read from existing file using shared ptr") { + TESTER->test_open(TESTER->shared_existing_file_, MPI_MODE_RDONLY, + MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iread_shared(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("read at the end of existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(0, MPI_SEEK_END); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + MPI_Offset offset; + MPI_File_get_position(TESTER->fh_orig_, &offset); + REQUIRE(offset == + (long long)(TESTER->request_size_ * TESTER->num_iterations_)); + TESTER->test_iread(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE(TESTER->size_read_orig_ == 0); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("read_at from existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_iread_at(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR, + TESTER->rank_ * TESTER->request_size_); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + TESTER->Posttest(); +} + +// TODO(chogan): This test fails sporadically. +// https://github.com/HDFGroup/hermes/issues/413 +TEST_CASE("SingleAsyncReadCollective", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_read]" + "[synchronicity=async]" + "[coordination=collective]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + SECTION("read from non-existing file") { + TESTER->test_open(TESTER->shared_new_file_, MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ != MPI_SUCCESS); + } + + SECTION("read from existing file") { + TESTER->test_open(TESTER->shared_existing_file_, MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek(TESTER->rank_ * TESTER->request_size_, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iread_all(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("read from existing file using shared ptr") { + TESTER->test_open(TESTER->shared_existing_file_, MPI_MODE_RDONLY, + MPI_COMM_WORLD); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_seek_shared(0, MPI_SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_iread_shared(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + + SECTION("read_at_all from existing file") { + TESTER->test_open(TESTER->existing_file_, MPI_MODE_RDONLY, MPI_COMM_SELF); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + TESTER->test_iread_at_all(TESTER->read_data_.data(), + TESTER->request_size_, MPI_CHAR, + TESTER->rank_ * TESTER->request_size_); + REQUIRE((size_t)TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == MPI_SUCCESS); + } + TESTER->Posttest(); +} diff --git a/test/unit/hermes_adapters/mpiio/mpiio_adapter_basic_test.cpp b/test/unit/hermes_adapters/mpiio/mpiio_adapter_basic_test.cpp deleted file mode 100644 index 9035bd5d4..000000000 --- a/test/unit/hermes_adapters/mpiio/mpiio_adapter_basic_test.cpp +++ /dev/null @@ -1,1044 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -TEST_CASE("Open", "[process=" + std::to_string(info.comm_size) + - "]" - "[coordination=independent]" - "[synchronicity=sync]" - "[operation=single_open]" - "[repetition=1][file=1]") { - pretest(); - SECTION("open non-existant file") { - test::test_open(info.new_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.new_file.c_str(), MPI_MODE_RDWR | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - } - - SECTION("opening existing file write-only") { - test::test_open(info.existing_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - SECTION("opening existing file and read/write") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("open existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("append write existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_APPEND | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.existing_file.c_str(), MPI_MODE_APPEND, MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.existing_file.c_str(), - MPI_MODE_RDONLY | MPI_MODE_APPEND, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR | MPI_MODE_APPEND, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("append write and read new file") { - test::test_open(info.existing_file.c_str(), - MPI_MODE_RDWR | MPI_MODE_APPEND | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("delete on close mode") { - test::test_open( - info.new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::exists(info.new_file.c_str())); - test::test_close(); - REQUIRE(!stdfs::exists(info.new_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - posttest(); -} - -TEST_CASE("OpenCollective", "[process=" + std::to_string(info.comm_size) + - "]" - "[coordination=collective]" - "[synchronicity=sync]" - "[operation=single_open]" - "[repetition=1][file=1]") { - pretest(); - SECTION("open on non-existant shared file") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_RDONLY | MPI_MODE_EXCL, MPI_COMM_WORLD); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_RDONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.shared_new_file.c_str(), MPI_MODE_RDWR | MPI_MODE_EXCL, - MPI_COMM_WORLD); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_RDWR | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("open on shared existing file") { - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_EXCL, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_RDWR | MPI_MODE_EXCL, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_RDONLY | MPI_MODE_EXCL, MPI_COMM_WORLD); - REQUIRE(test::status_orig != MPI_SUCCESS); - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDWR, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("append write/read on shared existing file") { - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_RDWR | MPI_MODE_APPEND, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("append write and read on shared new file") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_RDWR | MPI_MODE_APPEND | MPI_MODE_CREATE, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("delete on close mode on new file") { - test::test_open( - info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(!stdfs::exists(info.shared_new_file.c_str())); - } - posttest(); -} - -TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[synchronicity=sync]" - "[coordination=independent]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - bool check_bytes = true; - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("write to new file with allocate") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_preallocate(args.request_size * info.comm_size); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(args.request_size * info.rank, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - MPI_Barrier(MPI_COMM_WORLD); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("append to existing file") { - auto existing_size = stdfs::file_size(info.existing_file); - test::test_open(info.existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.existing_file) == - existing_size + test::size_written_orig); - } - - SECTION("append to new file") { - test::test_open(info.new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("write_at to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_at(info.write_data.c_str(), args.request_size, MPI_CHAR, - info.rank * args.request_size); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write_at to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_at(info.write_data.c_str(), args.request_size, MPI_CHAR, - 0); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("delete on close mode on new file") { - test::test_open( - info.new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.new_file.c_str())); - test::test_close(); - REQUIRE(!stdfs::exists(info.new_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("delete on close mode on existing file") { - auto original_size = stdfs::file_size(info.existing_file); - test::test_open(info.existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_EXCL | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.existing_file.c_str())); - auto new_size = - original_size > (size_t)test::size_written_orig * info.comm_size - ? original_size - : test::size_written_orig * info.comm_size; - REQUIRE(stdfs::file_size(info.existing_file) == (size_t)new_size); - test::test_close(); - REQUIRE(!stdfs::exists(info.existing_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - check_bytes = false; - } - posttest(check_bytes); -} - -TEST_CASE("SingleWriteCollective", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[synchronicity=sync]" - "[coordination=collective]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - bool check_bytes = true; - SECTION("write to existing file") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDWR, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write to new file") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig); - } - - // TODO(chogan): This test fails intermittently. Needs diagnosis. - // https://github.com/HDFGroup/hermes/issues/209 - SECTION("write to new file using shared ptr") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write_shared(info.write_data.c_str(), args.request_size, - MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("write to new file with allocate") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_preallocate(args.request_size * info.comm_size); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(args.request_size * info.rank, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - MPI_Barrier(MPI_COMM_WORLD); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("write_at_all to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_at_all(info.write_data.c_str(), args.request_size, - MPI_CHAR, info.rank * args.request_size); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write_at_all to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_at_all(info.write_data.c_str(), args.request_size, - MPI_CHAR, 0); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("append to existing file") { - auto existing_size = stdfs::file_size(info.existing_file); - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_all(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_existing_file) == - existing_size + test::size_written_orig); - } - - SECTION("append to new file") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_all(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig); - } - - SECTION("write_ordered to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_ordered(info.write_data.c_str(), args.request_size, - MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write_ordered to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_write_ordered(info.write_data.c_str(), args.request_size, - MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - SECTION("delete on close mode on new file") { - test::test_open( - info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.shared_new_file.c_str())); - MPI_Barrier(MPI_COMM_WORLD); - test::test_close(); - REQUIRE(!stdfs::exists(info.shared_new_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("delete on close mode on existing file") { - auto original_size = stdfs::file_size(info.shared_existing_file); - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_EXCL | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.shared_existing_file.c_str())); - auto new_size = - original_size > (size_t)test::size_written_orig * info.comm_size - ? original_size - : test::size_written_orig * info.comm_size; - REQUIRE(stdfs::file_size(info.shared_existing_file) == (size_t)new_size); - test::test_close(); - REQUIRE(!stdfs::exists(info.shared_existing_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - check_bytes = false; - } - posttest(check_bytes); -} - -TEST_CASE("SingleAsyncWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[coordination=independent]" - "[synchronicity=async]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - bool check_bytes = true; - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("write to new file using shared ptr") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite_shared(info.write_data.c_str(), args.request_size, - MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("write to new file with allocate") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_preallocate(args.request_size * info.comm_size); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(args.request_size * info.rank, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - MPI_Barrier(MPI_COMM_WORLD); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("append to existing file") { - auto existing_size = stdfs::file_size(info.existing_file); - test::test_open(info.existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.existing_file) == - existing_size + test::size_written_orig); - } - - SECTION("append to new file") { - test::test_open(info.new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("write_at to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite_at(info.write_data.c_str(), args.request_size, MPI_CHAR, - info.rank * args.request_size); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write_at to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite_at(info.write_data.c_str(), args.request_size, MPI_CHAR, - 0); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - - SECTION("delete on close mode on new file") { - test::test_open( - info.new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.new_file.c_str())); - test::test_close(); - REQUIRE(!stdfs::exists(info.new_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("delete on close mode on existing file") { - test::test_open(info.existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_EXCL | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.existing_file.c_str())); - test::test_close(); - REQUIRE(!stdfs::exists(info.existing_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - check_bytes = false; - } - posttest(check_bytes); -} - -TEST_CASE("SingleAsyncWriteCollective", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[synchronicity=async]" - "[coordination=collective]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - bool check_bytes = true; - SECTION("write to existing file") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDWR, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write to new file") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig); - } - - SECTION("write to new file using shared ptr") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite_shared(info.write_data.c_str(), args.request_size, - MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("write to new file with allocate") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_preallocate(args.request_size * info.comm_size); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(args.request_size * info.rank, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - MPI_Barrier(MPI_COMM_WORLD); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig * info.comm_size); - } - - SECTION("write_at_all to existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDWR, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite_at_all(info.write_data.c_str(), args.request_size, - MPI_CHAR, info.rank * args.request_size); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("write_at_all to new file") { - test::test_open(info.new_file.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite_at_all(info.write_data.c_str(), args.request_size, - MPI_CHAR, 0); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.new_file) == (size_t)test::size_written_orig); - } - SECTION("append to existing file") { - auto existing_size = stdfs::file_size(info.existing_file); - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_APPEND | MPI_MODE_EXCL, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite_all(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_existing_file) == - existing_size + test::size_written_orig); - } - - SECTION("append to new file") { - test::test_open(info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iwrite_all(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - REQUIRE(stdfs::file_size(info.shared_new_file) == - (size_t)test::size_written_orig); - } - SECTION("delete on close mode on new file") { - test::test_open( - info.shared_new_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.shared_new_file.c_str())); - test::test_close(); - REQUIRE(!stdfs::exists(info.shared_new_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("delete on close mode on existing file") { - auto original_size = stdfs::file_size(info.shared_existing_file); - test::test_open(info.shared_existing_file.c_str(), - MPI_MODE_WRONLY | MPI_MODE_EXCL | MPI_MODE_DELETE_ON_CLOSE, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iwrite(info.write_data.c_str(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_written_orig == args.request_size); - REQUIRE(stdfs::exists(info.shared_existing_file.c_str())); - auto new_size = - original_size > (size_t)test::size_written_orig * info.comm_size - ? original_size - : test::size_written_orig * info.comm_size; - REQUIRE(stdfs::file_size(info.shared_existing_file) == (size_t)new_size); - test::test_close(); - REQUIRE(!stdfs::exists(info.shared_existing_file.c_str())); - REQUIRE(test::status_orig == MPI_SUCCESS); - check_bytes = false; - } - posttest(check_bytes); -} - -TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[synchronicity=sync]" - "[coordination=independent]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read from non-existing file") { - test::test_open(info.new_file.c_str(), MPI_MODE_RDONLY | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - } - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_read(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read from existing file using shared ptr") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_read_shared(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read at the end of existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_END); - REQUIRE(test::status_orig == MPI_SUCCESS); - MPI_Offset offset; - MPI_File_get_position(test::fh_orig, &offset); - REQUIRE(offset == (long long)(args.request_size * info.num_iterations)); - test::test_read(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE(test::size_read_orig == 0); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read_at from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_read_at(info.read_data.data(), args.request_size, MPI_CHAR, - info.rank * args.request_size); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - posttest(); -} - -TEST_CASE("SingleReadCollective", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[synchronicity=sync]" - "[coordination=collective]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read from non-existing file") { - test::test_open(info.shared_new_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig != MPI_SUCCESS); - } - - SECTION("read from existing file") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_read_all(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read from existing file using shared ptr") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_read_shared(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read_at_all from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_read_at_all(info.read_data.data(), args.request_size, MPI_CHAR, - info.rank * args.request_size); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read_ordered from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_read_ordered(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - posttest(); -} - -TEST_CASE("SingleAsyncRead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[synchronicity=async]" - "[coordination=independent]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read from non-existing file") { - test::test_open(info.new_file.c_str(), MPI_MODE_RDONLY | MPI_MODE_EXCL, - MPI_COMM_SELF); - REQUIRE(test::status_orig != MPI_SUCCESS); - } - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iread(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read from existing file using shared ptr") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iread_shared(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read at the end of existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(0, MPI_SEEK_END); - REQUIRE(test::status_orig == MPI_SUCCESS); - MPI_Offset offset; - MPI_File_get_position(test::fh_orig, &offset); - REQUIRE(offset == (long long)(args.request_size * info.num_iterations)); - test::test_iread(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE(test::size_read_orig == 0); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read_at from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iread_at(info.read_data.data(), args.request_size, MPI_CHAR, - info.rank * args.request_size); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - posttest(); -} - -// TODO(chogan): This test fails sporadically. -// https://github.com/HDFGroup/hermes/issues/413 -TEST_CASE("SingleAsyncReadCollective", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[synchronicity=async]" - "[coordination=collective]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read from non-existing file") { - test::test_open(info.shared_new_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig != MPI_SUCCESS); - } - - SECTION("read from existing file") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek(info.rank * args.request_size, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iread_all(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read from existing file using shared ptr") { - test::test_open(info.shared_existing_file.c_str(), MPI_MODE_RDONLY, - MPI_COMM_WORLD); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_seek_shared(0, MPI_SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_iread_shared(info.read_data.data(), args.request_size, MPI_CHAR); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - - SECTION("read_at_all from existing file") { - test::test_open(info.existing_file.c_str(), MPI_MODE_RDONLY, MPI_COMM_SELF); - REQUIRE(test::status_orig == MPI_SUCCESS); - test::test_iread_at_all(info.read_data.data(), args.request_size, MPI_CHAR, - info.rank * args.request_size); - REQUIRE((size_t)test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == MPI_SUCCESS); - } - posttest(); -} diff --git a/test/unit/hermes_adapters/mpiio/mpiio_adapter_test.cc b/test/unit/hermes_adapters/mpiio/mpiio_adapter_test.cc new file mode 100644 index 000000000..bebec2019 --- /dev/null +++ b/test/unit/hermes_adapters/mpiio/mpiio_adapter_test.cc @@ -0,0 +1,17 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "mpiio_adapter_test.h" + +int main(int argc, char **argv) { + TESTER->Init(argc, argv); +} diff --git a/test/unit/hermes_adapters/mpiio/mpiio_adapter_test.cpp b/test/unit/hermes_adapters/mpiio/mpiio_adapter_test.cpp deleted file mode 100644 index 8c94d3cdb..000000000 --- a/test/unit/hermes_adapters/mpiio/mpiio_adapter_test.cpp +++ /dev/null @@ -1,685 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -#include -#include - -#include "adapter_test_utils.h" -#include "catch_config.h" -#if HERMES_INTERCEPT == 1 -#include "hermes_adapters/filesystem/filesystem.h" -#endif - -#include "adapter_test_utils.h" - -namespace stdfs = std::filesystem; - -namespace hermes::adapter::mpiio::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp/test_hermes"; - size_t request_size = 65536; -}; -struct Info { - bool debug = false; - int rank = 0; - int comm_size = 1; - std::string write_data; - std::string read_data; - std::string new_file; - std::string existing_file; - std::string shared_new_file; - std::string shared_existing_file; - std::string new_file_cmp; - std::string existing_file_cmp; - std::string shared_new_file_cmp; - std::string shared_existing_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 5; - size_t total_size; - size_t stride_size = 512; - unsigned int temporal_interval_ms = 1; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; - size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::mpiio::test -hermes::adapter::mpiio::test::Arguments args; -hermes::adapter::mpiio::test::Info info; - -int init(int* argc, char*** argv) { -#if HERMES_INTERCEPT == 1 - setenv("HERMES_FLUSH_MODE", "kSync", 1); - HERMES_CLIENT_CONF.flushing_mode_ = hermes::FlushingMode::kSync; -#endif - MPI_Init(argc, argv); - info.write_data = GenRandom(args.request_size); - info.read_data = std::string(args.request_size, 'r'); - MPI_Comm_rank(MPI_COMM_WORLD, &info.rank); - MPI_Comm_size(MPI_COMM_WORLD, &info.comm_size); - if (info.debug && info.rank == 0) { - printf("ready for attach\n"); - fflush(stdout); - sleep(30); - } - MPI_Barrier(MPI_COMM_WORLD); - return 0; -} -int finalize() { - MPI_Finalize(); - return 0; -} - -const char* kUser = "USER"; - -int pretest() { - stdfs::path fullpath = args.directory; - fullpath /= args.filename + "_" + std::string(getenv(kUser)); - info.new_file = fullpath.string() + "_new_" + std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext_" + std::to_string(getpid()); - info.new_file_cmp = - fullpath.string() + "_new_cmp" + "_" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp" + "_" + std::to_string(getpid()); - info.shared_new_file = - fullpath.string() + "_shared_new_" + std::to_string(info.comm_size); - info.shared_existing_file = - fullpath.string() + "_shared_ext_" + std::to_string(info.comm_size); - info.shared_new_file_cmp = - fullpath.string() + "_shared_new_cmp_" + std::to_string(info.comm_size); - info.shared_existing_file_cmp = - fullpath.string() + "_shared_ext_cmp_" + std::to_string(info.comm_size); - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + info.existing_file + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - MPI_Barrier(MPI_COMM_WORLD); - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - } - MPI_Barrier(MPI_COMM_WORLD); - if (info.rank == 0) { - if (stdfs::exists(info.shared_new_file)) - stdfs::remove(info.shared_new_file); - if (stdfs::exists(info.shared_existing_file)) - stdfs::remove(info.shared_existing_file); - if (!stdfs::exists(info.shared_existing_file)) { - std::string cmd = - "cp " + info.existing_file + " " + info.shared_existing_file; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.shared_existing_file) == - args.request_size * info.num_iterations); - } - if (stdfs::exists(info.shared_new_file_cmp)) - stdfs::remove(info.shared_new_file_cmp); - if (stdfs::exists(info.shared_existing_file_cmp)) - stdfs::remove(info.shared_existing_file_cmp); - if (!stdfs::exists(info.shared_existing_file_cmp)) { - std::string cmd = - "cp " + info.existing_file + " " + info.shared_existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.shared_existing_file_cmp) == - args.request_size * info.num_iterations); - } - } - MPI_Barrier(MPI_COMM_WORLD); - REQUIRE(info.total_size > 0); -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking( - info.shared_new_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking( - info.shared_existing_file_cmp, false); -#endif - return 0; -} - -void Clear() { -#if HERMES_INTERCEPT == 1 - HERMES->Clear(); -#endif -} - -int posttest(bool compare_data = true) { -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, false); -#endif - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - /* Clean up. */ - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - Clear(); - -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file_cmp, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file_cmp, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, true); -#endif - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -namespace test { -MPI_File fh_orig; -MPI_File fh_cmp; -int status_orig; -int size_read_orig; -int size_written_orig; - -void test_read_data(size_t size_read, size_t count, int type_size, - char* read_data, char* ptr) { - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < count * type_size; ++i) { - if (read_data[i] != ptr[i]) { - unmatching_chars = i; - break; - } - } - REQUIRE(unmatching_chars == 0); - } -} - -void test_open(const char* path, int mode, MPI_Comm comm) { - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else if (strcmp(path, info.existing_file.c_str()) == 0) { - cmp_path = info.existing_file_cmp; - } else if (strcmp(path, info.shared_new_file.c_str()) == 0) { - cmp_path = info.shared_new_file_cmp; - } else { - cmp_path = info.shared_existing_file_cmp; - } - status_orig = MPI_File_open(comm, path, mode, MPI_INFO_NULL, &fh_orig); - auto status_cmp = - MPI_File_open(comm, cmp_path.c_str(), mode, MPI_INFO_NULL, &fh_cmp); - bool is_same = (status_orig != MPI_SUCCESS && status_cmp != MPI_SUCCESS) || - (status_orig == MPI_SUCCESS && status_cmp == MPI_SUCCESS); - REQUIRE(is_same); -} -void test_close() { - status_orig = MPI_File_close(&fh_orig); - int status = MPI_File_close(&fh_cmp); - REQUIRE(status == status_orig); -} - -void test_preallocate(MPI_Offset size) { - status_orig = MPI_File_preallocate(fh_orig, size); - int status = MPI_File_preallocate(fh_cmp, size); - REQUIRE(status == status_orig); -} - -void test_write(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = MPI_File_write(fh_orig, ptr, count, datatype, &stat_orig); - int size_written; - auto ret_cmp = MPI_File_write(fh_cmp, ptr, count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_written_orig); - MPI_Get_count(&stat_cmp, datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_iwrite(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = MPI_File_iwrite(fh_orig, ptr, count, datatype, &request[0]); - int size_written; - auto ret_cmp = MPI_File_iwrite(fh_cmp, ptr, count, datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_written_orig); - MPI_Get_count(&stat[1], datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_write_shared(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_write_shared(fh_orig, ptr, count, datatype, &stat_orig); - int size_written; - auto ret_cmp = MPI_File_write_shared(fh_cmp, ptr, count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_written_orig); - MPI_Get_count(&stat_cmp, datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_iwrite_shared(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iwrite_shared(fh_orig, ptr, count, datatype, &request[0]); - int size_written; - auto ret_cmp = - MPI_File_iwrite_shared(fh_cmp, ptr, count, datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_written_orig); - MPI_Get_count(&stat[1], datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_write_all(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = MPI_File_write_all(fh_orig, ptr, count, datatype, &stat_orig); - int size_written; - auto ret_cmp = MPI_File_write_all(fh_cmp, ptr, count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_written_orig); - MPI_Get_count(&stat_cmp, datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_iwrite_all(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iwrite_all(fh_orig, ptr, count, datatype, &request[0]); - int size_written; - auto ret_cmp = MPI_File_iwrite_all(fh_cmp, ptr, count, datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_written_orig); - MPI_Get_count(&stat[1], datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_write_at(const void* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_write_at(fh_orig, offset, ptr, count, datatype, &stat_orig); - int size_written; - auto ret_cmp = - MPI_File_write_at(fh_cmp, offset, ptr, count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_written_orig); - MPI_Get_count(&stat_cmp, datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_iwrite_at(const void* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iwrite_at(fh_orig, offset, ptr, count, datatype, &request[0]); - int size_written; - auto ret_cmp = - MPI_File_iwrite_at(fh_cmp, offset, ptr, count, datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_written_orig); - MPI_Get_count(&stat[0], datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_write_at_all(const void* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_write_at_all(fh_orig, offset, ptr, count, datatype, &stat_orig); - int size_written; - auto ret_cmp = - MPI_File_write_at_all(fh_cmp, offset, ptr, count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_written_orig); - MPI_Get_count(&stat_cmp, datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_iwrite_at_all(const void* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = MPI_File_iwrite_at_all(fh_orig, offset, ptr, count, datatype, - &request[0]); - int size_written; - auto ret_cmp = - MPI_File_iwrite_at_all(fh_cmp, offset, ptr, count, datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_written_orig); - MPI_Get_count(&stat[1], datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_write_ordered(const void* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_write_ordered(fh_orig, ptr, count, datatype, &stat_orig); - int size_written; - auto ret_cmp = - MPI_File_write_ordered(fh_cmp, ptr, count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_written_orig); - MPI_Get_count(&stat_cmp, datatype, &size_written); - REQUIRE(size_written == size_written_orig); -} - -void test_read(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = MPI_File_read(fh_orig, ptr, count, datatype, &stat_orig); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = - MPI_File_read(fh_cmp, read_data.data(), count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_read_orig); - MPI_Get_count(&stat_cmp, datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_iread(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = MPI_File_iread(fh_orig, ptr, count, datatype, &request[0]); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = - MPI_File_iread(fh_cmp, read_data.data(), count, datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_read_orig); - MPI_Get_count(&stat[1], datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_read_shared(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_read_shared(fh_orig, ptr, count, datatype, &stat_orig); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_read_shared(fh_cmp, read_data.data(), count, datatype, - &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_read_orig); - MPI_Get_count(&stat_cmp, datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_iread_shared(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iread_shared(fh_orig, ptr, count, datatype, &request[0]); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_iread_shared(fh_cmp, read_data.data(), count, - datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_read_orig); - MPI_Get_count(&stat[1], datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_read_all(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = MPI_File_read_all(fh_orig, ptr, count, datatype, &stat_orig); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = - MPI_File_read_all(fh_cmp, read_data.data(), count, datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_read_orig); - MPI_Get_count(&stat_cmp, datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_iread_all(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iread_all(fh_orig, ptr, count, datatype, &request[0]); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_iread_all(fh_cmp, read_data.data(), count, datatype, - &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_read_orig); - MPI_Get_count(&stat[1], datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_read_ordered(char* ptr, size_t count, MPI_Datatype datatype) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_read_ordered(fh_orig, ptr, count, datatype, &stat_orig); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_read_ordered(fh_cmp, read_data.data(), count, - datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_read_orig); - MPI_Get_count(&stat_cmp, datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_read_at(char* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_read_at(fh_orig, offset, ptr, count, datatype, &stat_orig); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_read_at(fh_cmp, offset, read_data.data(), count, - datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_read_orig); - MPI_Get_count(&stat_cmp, datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_iread_at(char* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iread_at(fh_orig, offset, ptr, count, datatype, &request[0]); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_iread_at(fh_cmp, offset, read_data.data(), count, - datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_read_orig); - MPI_Get_count(&stat[1], datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_read_at_all(char* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat_orig, stat_cmp; - auto ret_orig = - MPI_File_read_at_all(fh_orig, offset, ptr, count, datatype, &stat_orig); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_read_at_all(fh_cmp, offset, read_data.data(), count, - datatype, &stat_cmp); - REQUIRE(ret_orig == ret_cmp); - MPI_Get_count(&stat_orig, datatype, &size_read_orig); - MPI_Get_count(&stat_cmp, datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_iread_at_all(char* ptr, size_t count, MPI_Datatype datatype, - MPI_Offset offset) { - MPI_Status stat[2]; - MPI_Request request[2]; - auto ret_orig = - MPI_File_iread_at_all(fh_orig, offset, ptr, count, datatype, &request[0]); - int type_size; - MPI_Type_size(datatype, &type_size); - std::vector read_data(count * type_size, 'r'); - int size_read; - auto ret_cmp = MPI_File_iread_at_all(fh_cmp, offset, read_data.data(), count, - datatype, &request[1]); - REQUIRE(ret_orig == ret_cmp); - MPI_Waitall(2, request, stat); - MPI_Get_count(&stat[0], datatype, &size_read_orig); - MPI_Get_count(&stat[1], datatype, &size_read); - REQUIRE(size_read == size_read_orig); - test_read_data(size_read, count, type_size, - reinterpret_cast(read_data.data()), ptr); -} - -void test_seek(MPI_Offset offset, int whence) { - status_orig = MPI_File_seek(fh_orig, offset, whence); - int status = MPI_File_seek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} - -void test_seek_shared(MPI_Offset offset, int whence) { - status_orig = MPI_File_seek_shared(fh_orig, offset, whence); - int status = MPI_File_seek_shared(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -#include "mpiio_adapter_basic_test.cpp" diff --git a/test/unit/hermes_adapters/mpiio/mpiio_adapter_test.h b/test/unit/hermes_adapters/mpiio/mpiio_adapter_test.h new file mode 100644 index 000000000..a8512e4d0 --- /dev/null +++ b/test/unit/hermes_adapters/mpiio/mpiio_adapter_test.h @@ -0,0 +1,496 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_TEST_UNIT_HERMES_ADAPTERS_POSIX_POSIX_ADAPTER_BASE_TEST_H_ +#define HERMES_TEST_UNIT_HERMES_ADAPTERS_POSIX_POSIX_ADAPTER_BASE_TEST_H_ + +#include "binary_file_tests.h" + +namespace hermes::adapter::test { +template +class MpiioTest : public BinaryFileTests { + public: + FileInfo new_file_; + FileInfo existing_file_; + FileInfo shared_new_file_; + FileInfo shared_existing_file_; + FileInfo tmp_file_; + unsigned int offset_seed_ = 1; + unsigned int rs_seed_ = 1; + unsigned int temporal_interval_seed_ = 5; + size_t stride_size_ = 1024; + unsigned int temporal_interval_ms_ = 1; + size_t small_min_ = 1; + size_t small_max_ = 4 * 1024; + size_t medium_min_ = 4 * 1024 + 1; + size_t medium_max_ = 256 * 1024; + size_t large_min_ = 256 * 1024 + 1; + size_t large_max_ = 3 * 1024 * 1024; + + MPI_File fh_orig_; + MPI_File fh_cmp_; + int status_orig_; + int size_read_orig_; + int size_written_orig_; + + public: + void RegisterFiles() override { + RegisterPath("new", 0, new_file_); + RegisterPath("ext", TEST_DO_CREATE, existing_file_); + if constexpr(WITH_MPI) { + RegisterPath("shared_new", TEST_FILE_SHARED, shared_new_file_); + RegisterPath("shared_ext", TEST_DO_CREATE | TEST_FILE_SHARED, + shared_existing_file_); + } + RegisterTmpPath(tmp_file_); + } + + void test_read_data(size_t size_read, size_t count, int type_size, + char* read_data, char* ptr) { + if (size_read > 0) { + size_t unmatching_chars = 0; + for (size_t i = 0; i < count * type_size; ++i) { + if (read_data[i] != ptr[i]) { + unmatching_chars = i; + break; + } + } + REQUIRE(unmatching_chars == 0); + } + } + + void test_open(FileInfo &info, int mode, MPI_Comm comm) { + status_orig_ = MPI_File_open(comm, info.hermes_.c_str(), + mode, MPI_INFO_NULL, &fh_orig_); + auto status_cmp = + MPI_File_open(comm, info.cmp_.c_str(), mode, MPI_INFO_NULL, &fh_cmp_); + bool is_same = (status_orig_ != MPI_SUCCESS && status_cmp != MPI_SUCCESS) || + (status_orig_ == MPI_SUCCESS && status_cmp == MPI_SUCCESS); + REQUIRE(is_same); + } + void test_close() { + status_orig_ = MPI_File_close(&fh_orig_); + int status = MPI_File_close(&fh_cmp_); + REQUIRE(status == status_orig_); + } + + void test_preallocate(MPI_Offset size) { + status_orig_ = MPI_File_preallocate(fh_orig_, size); + int status = MPI_File_preallocate(fh_cmp_, size); + REQUIRE(status == status_orig_); + } + + void test_write(const void* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = MPI_File_write(fh_orig_, ptr, count, datatype, &stat_orig); + int size_written; + auto ret_cmp = MPI_File_write(fh_cmp_, ptr, count, datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_written_orig_); + MPI_Get_count(&stat_cmp, datatype, &size_written); + REQUIRE(size_written == size_written_orig_); + } + + void test_iwrite(const void* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = MPI_File_iwrite(fh_orig_, ptr, count, + datatype, &request[0]); + int size_written; + auto ret_cmp = MPI_File_iwrite(fh_cmp_, ptr, count, + datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_written_orig_); + MPI_Get_count(&stat[1], datatype, &size_written); + REQUIRE(size_written == size_written_orig_); + } + + void test_write_shared(const void* ptr, size_t count, + MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_write_shared(fh_orig_, ptr, count, datatype, &stat_orig); + int size_written; + auto ret_cmp = MPI_File_write_shared(fh_cmp_, ptr, count, + datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_written_orig_); + MPI_Get_count(&stat_cmp, datatype, &size_written); + REQUIRE(size_written == size_written_orig_); + } + + void test_iwrite_shared(const void* ptr, size_t count, + MPI_Datatype datatype) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iwrite_shared(fh_orig_, ptr, count, datatype, &request[0]); + int size_written; + auto ret_cmp = + MPI_File_iwrite_shared(fh_cmp_, ptr, count, datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_written_orig_); + MPI_Get_count(&stat[1], datatype, &size_written); + REQUIRE(size_written == size_written_orig_); + } + + void test_write_all(const void* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = MPI_File_write_all(fh_orig_, ptr, count, + datatype, &stat_orig); + int size_written; + auto ret_cmp = MPI_File_write_all(fh_cmp_, ptr, count, + datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_written_orig_); + MPI_Get_count(&stat_cmp, datatype, &size_written); + REQUIRE(size_written == size_written_orig_); + } + + void test_iwrite_all(const void* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iwrite_all(fh_orig_, ptr, count, datatype, &request[0]); + int size_written; + auto ret_cmp = MPI_File_iwrite_all(fh_cmp_, ptr, count, + datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_written_orig_); + MPI_Get_count(&stat[1], datatype, &size_written); + REQUIRE(size_written == size_written_orig_); + } + + void test_write_at(const void* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_write_at(fh_orig_, offset, ptr, count, datatype, &stat_orig); + int size_written; + auto ret_cmp = + MPI_File_write_at(fh_cmp_, offset, ptr, count, datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_written_orig_); + MPI_Get_count(&stat_cmp, datatype, &size_written); + REQUIRE(size_written == size_written_orig_); + } + + void test_iwrite_at(const void* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iwrite_at(fh_orig_, offset, ptr, count, datatype, &request[0]); + int size_written; + auto ret_cmp = + MPI_File_iwrite_at(fh_cmp_, offset, ptr, count, datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_written_orig_); + MPI_Get_count(&stat[0], datatype, &size_written); + REQUIRE(size_written == size_written_orig_); + } + + void test_write_at_all(const void* ptr, size_t count, + MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_write_at_all(fh_orig_, offset, ptr, count, + datatype, &stat_orig); + int size_written; + auto ret_cmp = + MPI_File_write_at_all(fh_cmp_, offset, ptr, count, + datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_written_orig_); + MPI_Get_count(&stat_cmp, datatype, &size_written); + REQUIRE(size_written == size_written_orig_); + } + + void test_iwrite_at_all(const void* ptr, size_t count, + MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = MPI_File_iwrite_at_all(fh_orig_, offset, ptr, + count, datatype, + &request[0]); + int size_written; + auto ret_cmp = + MPI_File_iwrite_at_all(fh_cmp_, offset, ptr, count, + datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_written_orig_); + MPI_Get_count(&stat[1], datatype, &size_written); + REQUIRE(size_written == size_written_orig_); + } + + void test_write_ordered(const void* ptr, size_t count, + MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_write_ordered(fh_orig_, ptr, count, datatype, &stat_orig); + int size_written; + auto ret_cmp = + MPI_File_write_ordered(fh_cmp_, ptr, count, datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_written_orig_); + MPI_Get_count(&stat_cmp, datatype, &size_written); + REQUIRE(size_written == size_written_orig_); + } + + void test_read(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = MPI_File_read(fh_orig_, ptr, count, + datatype, &stat_orig); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = + MPI_File_read(fh_cmp_, read_data.data(), count, + datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_read_orig_); + MPI_Get_count(&stat_cmp, datatype, &size_read); + REQUIRE(size_read == size_read_orig_); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); + } + + void test_iread(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = MPI_File_iread(fh_orig_, ptr, count, + datatype, &request[0]); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = + MPI_File_iread(fh_cmp_, read_data.data(), count, + datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_read_orig_); + MPI_Get_count(&stat[1], datatype, &size_read); + REQUIRE(size_read == size_read_orig_); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); + } + + void test_read_shared(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_read_shared(fh_orig_, ptr, count, datatype, &stat_orig); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_read_shared(fh_cmp_, read_data.data(), + count, datatype, + &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_read_orig_); + MPI_Get_count(&stat_cmp, datatype, &size_read); + REQUIRE(size_read == size_read_orig_); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); + } + + void test_iread_shared(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iread_shared(fh_orig_, ptr, count, datatype, &request[0]); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_iread_shared(fh_cmp_, + read_data.data(), count, + datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_read_orig_); + MPI_Get_count(&stat[1], datatype, &size_read); + REQUIRE(size_read == size_read_orig_); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); + } + + void test_read_all(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = MPI_File_read_all(fh_orig_, ptr, count, + datatype, &stat_orig); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = + MPI_File_read_all(fh_cmp_, read_data.data(), count, + datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_read_orig_); + MPI_Get_count(&stat_cmp, datatype, &size_read); + REQUIRE(size_read == size_read_orig_); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); + } + + void test_iread_all(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iread_all(fh_orig_, ptr, count, datatype, &request[0]); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_iread_all(fh_cmp_, read_data.data(), + count, datatype, + &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_read_orig_); + MPI_Get_count(&stat[1], datatype, &size_read); + REQUIRE(size_read == size_read_orig_); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); + } + + void test_read_ordered(char* ptr, size_t count, MPI_Datatype datatype) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_read_ordered(fh_orig_, ptr, count, datatype, &stat_orig); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_read_ordered(fh_cmp_, read_data.data(), count, + datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_read_orig_); + MPI_Get_count(&stat_cmp, datatype, &size_read); + REQUIRE(size_read == size_read_orig_); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); + } + + void test_read_at(char* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_read_at(fh_orig_, offset, ptr, count, datatype, &stat_orig); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_read_at(fh_cmp_, offset, read_data.data(), count, + datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_read_orig_); + MPI_Get_count(&stat_cmp, datatype, &size_read); + REQUIRE(size_read == size_read_orig_); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); + } + + void test_iread_at(char* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iread_at(fh_orig_, offset, ptr, count, datatype, &request[0]); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_iread_at(fh_cmp_, offset, read_data.data(), count, + datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_read_orig_); + MPI_Get_count(&stat[1], datatype, &size_read); + REQUIRE(size_read == size_read_orig_); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); + } + + void test_read_at_all(char* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat_orig, stat_cmp; + auto ret_orig = + MPI_File_read_at_all(fh_orig_, offset, ptr, count, + datatype, &stat_orig); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_read_at_all(fh_cmp_, offset, + read_data.data(), count, + datatype, &stat_cmp); + REQUIRE(ret_orig == ret_cmp); + MPI_Get_count(&stat_orig, datatype, &size_read_orig_); + MPI_Get_count(&stat_cmp, datatype, &size_read); + REQUIRE(size_read == size_read_orig_); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); + } + + void test_iread_at_all(char* ptr, size_t count, MPI_Datatype datatype, + MPI_Offset offset) { + MPI_Status stat[2]; + MPI_Request request[2]; + auto ret_orig = + MPI_File_iread_at_all(fh_orig_, offset, ptr, count, + datatype, &request[0]); + int type_size; + MPI_Type_size(datatype, &type_size); + std::vector read_data(count * type_size, 'r'); + int size_read; + auto ret_cmp = MPI_File_iread_at_all(fh_cmp_, offset, + read_data.data(), count, + datatype, &request[1]); + REQUIRE(ret_orig == ret_cmp); + MPI_Waitall(2, request, stat); + MPI_Get_count(&stat[0], datatype, &size_read_orig_); + MPI_Get_count(&stat[1], datatype, &size_read); + REQUIRE(size_read == size_read_orig_); + test_read_data(size_read, count, type_size, + reinterpret_cast(read_data.data()), ptr); + } + + void test_seek(MPI_Offset offset, int whence) { + status_orig_ = MPI_File_seek(fh_orig_, offset, whence); + int status = MPI_File_seek(fh_cmp_, offset, whence); + REQUIRE(status == status_orig_); + } + + void test_seek_shared(MPI_Offset offset, int whence) { + status_orig_ = MPI_File_seek_shared(fh_orig_, offset, whence); + int status = MPI_File_seek_shared(fh_cmp_, offset, whence); + REQUIRE(status == status_orig_); + } +}; + +} // namespace hermes::adapter::test + +#define TESTER \ + hshm::EasySingleton>::GetInstance() + +#endif // HERMES_TEST_UNIT_HERMES_ADAPTERS_POSIX_POSIX_ADAPTER_BASE_TEST_H_ diff --git a/test/unit/hermes_adapters/mpiio/tests.py b/test/unit/hermes_adapters/mpiio/tests.py deleted file mode 100644 index 26c575672..000000000 --- a/test/unit/hermes_adapters/mpiio/tests.py +++ /dev/null @@ -1,35 +0,0 @@ -from py_hermes_ci.test_manager import TestManager -from jarvis_util import * - - -class MpiioTestManager(TestManager): - def spawn_all_nodes(self): - return self.spawn_info() - - def set_paths(self): - self.MPIIO_CMD = f"{self.CMAKE_BINARY_DIR}/bin/mpiio_adapter_test" - self.HERMES_MPIIO_CMD = f"{self.CMAKE_BINARY_DIR}/bin/hermes_mpiio_adapter_test" - - self.disable_testing = False - - def test_hermes_mpiio_basic_sync(self): - mpiio_cmd = f"{self.HERMES_MPIIO_CMD} " \ - f"[synchronicity=sync] " \ - f"--reporter compact -d yes" - spawn_info = self.spawn_info(nprocs=2, - hermes_conf='hermes_server') - self.start_daemon(spawn_info) - node = Exec(mpiio_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_mpiio_basic_async(self): - mpiio_cmd = f"{self.HERMES_MPIIO_CMD} " \ - f"[synchronicity=async] " \ - f"--reporter compact -d yes" - spawn_info = self.spawn_info(nprocs=2, - hermes_conf='hermes_server') - self.start_daemon(spawn_info) - node = Exec(mpiio_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code \ No newline at end of file diff --git a/test/unit/hermes_adapters/posix/CMakeLists.txt b/test/unit/hermes_adapters/posix/CMakeLists.txt index 3f6775206..f2b8c28cf 100644 --- a/test/unit/hermes_adapters/posix/CMakeLists.txt +++ b/test/unit/hermes_adapters/posix/CMakeLists.txt @@ -5,32 +5,65 @@ include_directories(${CMAKE_SOURCE_DIR}/src) # Posix Adapter tests #------------------------------------------------------------------------------ -add_executable(posix_adapter_test posix_adapter_test.cpp ${ADAPTER_COMMON}) -add_dependencies(posix_adapter_test hermes) -target_link_libraries(posix_adapter_test hermes) -pytest(posix test_posix_basic) +add_executable(posix_adapter_test + posix_adapter_test.cc + posix_adapter_basic_test.cc + posix_adapter_rs_test.cc) +add_dependencies(posix_adapter_test + hermes) +target_link_libraries(posix_adapter_test + hermes) +target_compile_definitions(posix_adapter_test PUBLIC + HERMES_MPI_TESTS=false) +jarvis_test(posix test_posix_basic) -add_executable(posix_adapter_mpi_test posix_adapter_mpi_test.cpp ${ADAPTER_COMMON}) -pytest(posix test_posix_basic_mpi) +add_executable(hermes_posix_adapter_test + posix_adapter_test.cc + posix_adapter_basic_test.cc + posix_adapter_rs_test.cc) +add_dependencies(hermes_posix_adapter_test + hermes_posix) +target_link_libraries(hermes_posix_adapter_test + hermes_posix) +target_compile_definitions(hermes_posix_adapter_test PUBLIC + HERMES_INTERCEPT=1 HERMES_MPI_TESTS=false) +jarvis_test(posix test_hermes_posix_basic_small) +jarvis_test(posix test_hermes_posix_basic_large) -add_executable(hermes_posix_adapter_test posix_adapter_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_posix_adapter_test hermes_posix) -add_dependencies(hermes_posix_adapter_test hermes_posix) -set_target_properties(hermes_posix_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -pytest(posix test_hermes_posix_basic_small) -pytest(posix test_hermes_posix_basic_large) +add_executable(posix_adapter_mpi_test + posix_adapter_test.cc + posix_adapter_basic_test.cc + posix_adapter_rs_test.cc + # posix_adapter_shared_test.cc +) +add_dependencies(posix_adapter_mpi_test + hermes) +target_link_libraries(posix_adapter_mpi_test + hermes Catch2::Catch2 MPI::MPI_CXX) +target_compile_definitions(posix_adapter_mpi_test PUBLIC + HERMES_MPI_TESTS=true) +jarvis_test(posix test_posix_basic_mpi) -add_executable(hermes_posix_adapter_mpi_test posix_adapter_mpi_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_posix_adapter_mpi_test hermes_posix) -add_dependencies(hermes_posix_adapter_mpi_test hermes_posix) -set_target_properties(hermes_posix_adapter_mpi_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -pytest(posix test_hermes_posix_basic_mpi_small) -pytest(posix test_hermes_posix_basic_mpi_large) +add_executable(hermes_posix_adapter_mpi_test + posix_adapter_test.cc + posix_adapter_basic_test.cc + posix_adapter_rs_test.cc + # posix_adapter_shared_test.cc +) +add_dependencies(hermes_posix_adapter_mpi_test + hermes_posix) +target_link_libraries(hermes_posix_adapter_mpi_test + hermes_posix Catch2::Catch2 MPI::MPI_C MPI::MPI_CXX) +target_compile_definitions(hermes_posix_adapter_mpi_test PUBLIC + HERMES_INTERCEPT=1 HERMES_MPI_TESTS=true) +jarvis_test(posix test_hermes_posix_basic_mpi_small) +jarvis_test(posix test_hermes_posix_basic_mpi_large) include_directories(${CMAKE_SOURCE_DIR}/adapter) add_executable(posix_simple_io_mpi posix_simple_io_mpi.cc) add_dependencies(posix_simple_io_mpi hermes_posix) -target_link_libraries(posix_simple_io_mpi hermes_posix) +target_link_libraries(posix_simple_io_mpi + hermes_posix Catch2::Catch2 MPI::MPI_CXX) add_executable(hermes_posix_simple_io_omp posix_simple_io_omp.cc) add_dependencies(hermes_posix_simple_io_omp hermes_posix) @@ -41,9 +74,11 @@ add_executable(posix_simple_io_omp posix_simple_io_omp.cc) target_link_libraries(posix_simple_io_omp ${HermesShm_LIBRARIES} Catch2::Catch2 OpenMP::OpenMP_CXX) -pytest(posix test_hermes_posix_simple_io_omp_default) -pytest(posix test_hermes_posix_simple_io_omp_scratch) -pytest(posix test_hermes_posix_simple_io_omp_preload) +jarvis_test(posix test_posix_simple_io_omp) +jarvis_test(posix test_hermes_posix_simple_io_omp) +#pytest(posix test_hermes_posix_simple_io_omp_default) +#pytest(posix test_hermes_posix_simple_io_omp_scratch) +#pytest(posix test_hermes_posix_simple_io_omp_preload) set(POSIX_TESTS posix_adapter_test @@ -55,8 +90,8 @@ set(POSIX_TESTS ) foreach(program ${POSIX_TESTS}) - target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_DIR}) - target_include_directories(${program} PRIVATE ${HERMES_ADAPTER_TEST_DIR}) + target_include_directories(${program} PUBLIC ${HERMES_ADAPTER_DIR}) + target_include_directories(${program} PUBLIC ${HERMES_ADAPTER_TEST_DIR}) target_link_libraries(${program} Catch2::Catch2 -lstdc++fs -lc MPI::MPI_CXX OpenMP::OpenMP_CXX) endforeach() diff --git a/test/unit/hermes_adapters/posix/posix_adapter_basic_test.cc b/test/unit/hermes_adapters/posix/posix_adapter_basic_test.cc new file mode 100644 index 000000000..943323dae --- /dev/null +++ b/test/unit/hermes_adapters/posix/posix_adapter_basic_test.cc @@ -0,0 +1,1529 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Distributed under BSD 3-Clause license. * +* Copyright by The HDF Group. * +* Copyright by the Illinois Institute of Technology. * +* All rights reserved. * +* * +* This file is part of Hermes. The full Hermes copyright notice, including * +* terms governing use, modification, and redistribution, is contained in * +* the COPYING file, which can be found at the top directory. If you do not * +* have access to the file, you may request a copy from help@hdfgroup.org. * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include "posix_adapter_test.h" + +TEST_CASE("Open", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_open]" + "[repetition=1][file=1]") { + TESTER->Pretest(); + SECTION("open non-existant file") { + TESTER->test_open(TESTER->new_file_, O_WRONLY); + REQUIRE(TESTER->fh_orig_ == -1); + TESTER->test_open(TESTER->new_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ == -1); + TESTER->test_open(TESTER->new_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ == -1); + } + + SECTION("truncate existing file and write-only") { + TESTER->test_open(TESTER->existing_file_, O_WRONLY | O_TRUNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("truncate existing file and read/write") { + TESTER->test_open(TESTER->existing_file_, O_RDWR | O_TRUNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("open existing file") { + TESTER->test_open(TESTER->existing_file_, O_WRONLY); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("append write existing file") { + TESTER->test_open(TESTER->existing_file_, O_APPEND); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("create a new file") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + stdfs::remove(TESTER->new_file_.hermes_); + + TESTER->test_open(TESTER->new_file_, O_RDONLY | O_CREAT, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + stdfs::remove(TESTER->new_file_.hermes_); + + TESTER->test_open(TESTER->new_file_, O_RDWR | O_CREAT, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("create a existing file") { + TESTER->test_open(TESTER->existing_file_, O_WRONLY | O_CREAT, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDONLY | O_CREAT, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDWR | O_CREAT, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + + TESTER->test_open(TESTER->existing_file_, O_WRONLY | O_CREAT | O_EXCL, + 0600); + REQUIRE(TESTER->fh_orig_ == -1); + TESTER->test_open(TESTER->existing_file_, O_RDONLY | O_CREAT | O_EXCL, + 0600); + REQUIRE(TESTER->fh_orig_ == -1); + TESTER->test_open(TESTER->existing_file_, O_RDWR | O_CREAT | O_EXCL, + 0600); + REQUIRE(TESTER->fh_orig_ == -1); + } + SECTION("Async I/O") { + TESTER->test_open(TESTER->existing_file_, O_WRONLY | O_ASYNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDONLY | O_ASYNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDWR | O_ASYNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_APPEND | O_ASYNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + + TESTER->test_open(TESTER->existing_file_, O_WRONLY | O_NONBLOCK); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDONLY | O_NONBLOCK); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDWR | O_NONBLOCK); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_APPEND | O_NONBLOCK); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + + TESTER->test_open(TESTER->existing_file_, O_WRONLY | O_NDELAY); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDONLY | O_NDELAY); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDWR | O_NDELAY); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_APPEND | O_NDELAY); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("Async I/O") { + TESTER->test_open(TESTER->existing_file_, O_WRONLY | O_DIRECT); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDONLY | O_DIRECT); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDWR | O_DIRECT); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_APPEND | O_DIRECT); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("Write Synchronize") { + /* File synchronicity */ + TESTER->test_open(TESTER->existing_file_, O_WRONLY | O_DSYNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDONLY | O_DSYNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDWR | O_DSYNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_APPEND | O_DSYNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + + /* Write synchronicity */ + TESTER->test_open(TESTER->existing_file_, O_WRONLY | O_SYNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDONLY | O_SYNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDWR | O_SYNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_APPEND | O_SYNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("Temporary file") { + if (TESTER->supports_tmpfile) { + TESTER->test_open(TESTER->tmp_file_, O_WRONLY | O_TMPFILE, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->existing_file_, O_RDONLY | O_TMPFILE, 0600); + REQUIRE(TESTER->fh_orig_ == -1); + TESTER->test_open(TESTER->existing_file_, O_RDWR | O_TMPFILE, 0600); + REQUIRE(TESTER->fh_orig_ == -1); + TESTER->test_open(TESTER->existing_file_, O_APPEND | O_TMPFILE, 0600); + REQUIRE(TESTER->fh_orig_ == -1); + + TESTER->test_open(TESTER->existing_file_, O_WRONLY | O_TMPFILE, 0600); + REQUIRE(TESTER->fh_orig_ == -1); + TESTER->test_open(TESTER->existing_file_, O_RDONLY | O_TMPFILE, 0600); + REQUIRE(TESTER->fh_orig_ == -1); + TESTER->test_open(TESTER->existing_file_, O_RDWR | O_TMPFILE, 0600); + REQUIRE(TESTER->fh_orig_ == -1); + } + } + TESTER->Posttest(); +} + +// TEST_CASE("Remove") { +// TESTER->test_open(TESTER->existing_file_, O_WRONLY | O_TRUNC); +// TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); +// stdfs::remove(TESTER->existing_file_.hermes_); +// hermes::Bucket bkt = HERMES->GetBucket(TESTER->existing_file_.hermes_); +// bkt.Destroy(); +// } + +TEST_CASE("SingleWrite", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_write]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + int status = TESTER->status_orig_; + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("write to new file") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + int size = stdfs::file_size(TESTER->new_file_.hermes_); + int orig_size = TESTER->size_written_orig_; + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->size_written_orig_); + } + + SECTION("write to existing file with truncate") { + TESTER->test_open(TESTER->existing_file_, O_WRONLY | O_TRUNC); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->existing_file_.hermes_) == + TESTER->size_written_orig_); + } + + SECTION("write to existing file at the end") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_seek(0, SEEK_END); + REQUIRE(((size_t)TESTER->status_orig_) == + TESTER->request_size_ * TESTER->num_iterations_); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->existing_file_.hermes_) == + TESTER->size_written_orig_ + + TESTER->request_size_ * TESTER->num_iterations_); + } + + SECTION("append to existing file") { + auto existing_size = stdfs::file_size(TESTER->existing_file_.hermes_); + TESTER->test_open(TESTER->existing_file_, O_RDWR | O_APPEND); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->existing_file_.hermes_) == + existing_size + TESTER->size_written_orig_); + } + + SECTION("append to new file") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->size_written_orig_); + } + TESTER->Posttest(); +} + +TEST_CASE("SingleRead", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_read]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + SECTION("read from non-existing file") { + TESTER->test_open(TESTER->new_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ == -1); + } + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_seek(0, SEEK_CUR); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_read(TESTER->read_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("read at the end of existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_seek(0, SEEK_END); + REQUIRE(((size_t)TESTER->status_orig_) == + TESTER->request_size_ * TESTER->num_iterations_); + TESTER->test_read(TESTER->read_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == 0); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedWriteSequential", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("write to new file") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->request_size_); + } + + SECTION("write to new file always at start") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->num_iterations_ * TESTER->request_size_); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequential", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_read(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + + for (size_t i = 0; i < 1; ++i) { + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->is_scase_ = true; + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadRandom", "[process=" + + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + + "][pattern=random][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + TESTER->test_read(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateRandom", "[process=" + + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=random][file=1]") { + TESTER->Pretest(); + SECTION("update into existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->request_size_ - 1); + TESTER->test_seek(offset, SEEK_SET); // 630978 + REQUIRE(((size_t)TESTER->status_orig_) == offset); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + fsync(TESTER->fh_orig_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideFixed", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = (i * TESTER->stride_size_) % TESTER->total_size_; + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + TESTER->test_read(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixed", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = (i * TESTER->stride_size_) % TESTER->total_size_; + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + TESTER->test_read(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideDynamic", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + TESTER->test_read(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamic", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + TESTER->test_read(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedWriteRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + + SECTION("write to new file always at the start") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + size_t biggest_size_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->offset_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + if (biggest_size_written < request_size) + biggest_size_written = request_size; + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + biggest_size_written); + } + + SECTION("write to new file") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + size_t total_size_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->offset_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + total_size_written += TESTER->size_written_orig_; + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == total_size_written); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequentialRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = (TESTER->request_size_ + + (rand_r(&TESTER->offset_seed_) % TESTER->request_size_)) % + (TESTER->total_size_ - current_offset); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + current_offset += TESTER->size_read_orig_; + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_open(TESTER->existing_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ != -1); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->offset_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadRandomRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-variable]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + + "][pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + (TESTER->request_size_ + + (rand_r(&TESTER->rs_seed_) % TESTER->request_size_)) % + (TESTER->total_size_ - offset); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->rs_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = (i * TESTER->stride_size_) % TESTER->total_size_; + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + (TESTER->request_size_ + + (rand_r(&TESTER->rs_seed_) % TESTER->request_size_)) % + (TESTER->total_size_ - offset); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = (i * TESTER->stride_size_) % TESTER->total_size_; + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->rs_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->rs_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->rs_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideNegative", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + size_t prev_offset = TESTER->total_size_ + 1; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto stride_offset = TESTER->total_size_ - i * TESTER->stride_size_; + REQUIRE(prev_offset > stride_offset); + prev_offset = stride_offset; + size_t offset = (stride_offset) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + TESTER->test_read(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegative", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + TESTER->total_size_ - ((i * TESTER->stride_size_) % + TESTER->total_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + TESTER->test_write(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = (TESTER->total_size_ - i * TESTER->stride_size_) % + (TESTER->total_size_ - 2 * TESTER->request_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + (TESTER->request_size_ + (rand_r(&TESTER->rs_seed_) % + TESTER->request_size_)) % + (TESTER->total_size_ - offset); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + TESTER->total_size_ - ((i * TESTER->stride_size_) % + TESTER->total_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->request_size_ + (rand_r(&TESTER->rs_seed_) % + TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStride2D", "[process=" + + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + TESTER->test_read(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStride2D", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + TESTER->test_write(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStride2DRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - 2 * TESTER->request_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + (TESTER->request_size_ + (rand_r(&TESTER->rs_seed_) % + TESTER->request_size_)) % + (TESTER->total_size_ - offset); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - 2 * TESTER->request_size_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->request_size_ + (rand_r(&TESTER->rs_seed_) % + TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +/** +* Temporal Fixed + */ + +TEST_CASE("BatchedWriteTemporalFixed", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1][temporal=fixed]") { + TESTER->Pretest(); + + SECTION("write to new file") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->request_size_); + } + + SECTION("write to new file always at start") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->num_iterations_ * TESTER->request_size_); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequentialTemporalFixed", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1][temporal=fixed]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_read(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_seek(0, SEEK_SET); + TESTER->test_read(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedWriteTemporalVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1][temporal=variable]") { + TESTER->Pretest(); + + SECTION("write to existing file") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->temporal_interval_ms_ = + rand_r(&TESTER->temporal_interval_seed_) % + TESTER->temporal_interval_ms_ + 1; + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->request_size_); + } + + SECTION("write to new file always at start") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->temporal_interval_ms_ = + rand_r(&TESTER->temporal_interval_seed_) % + TESTER->temporal_interval_ms_ + 1; + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->num_iterations_ * TESTER->request_size_); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequentialTemporalVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1][temporal=variable]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->temporal_interval_ms_ = + rand_r(&TESTER->temporal_interval_seed_) % + TESTER->temporal_interval_ms_ + 1; + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_read(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_open(TESTER->existing_file_, O_WRONLY); + REQUIRE(TESTER->fh_orig_ != -1); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->temporal_interval_ms_ = + rand_r(&TESTER->temporal_interval_seed_) % + TESTER->temporal_interval_ms_ + 1; + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedMixedSequential", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_mixed]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("read after write on new file") { + TESTER->test_open(TESTER->new_file_, O_RDWR | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + size_t last_offset = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_seek(last_offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == last_offset); + TESTER->test_read(TESTER->read_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + last_offset += TESTER->request_size_; + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("write and read alternative existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + if (i % 2 == 0) { + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } else { + TESTER->test_read(TESTER->read_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("update after read existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + size_t last_offset = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_read(TESTER->read_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_seek(last_offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == last_offset); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + last_offset += TESTER->request_size_; + } + + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("read all after write all on new file in single open") { + TESTER->test_open(TESTER->new_file_, O_RDWR | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_read(TESTER->read_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("read all after write all on new file in different open") { + TESTER->test_open(TESTER->new_file_, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->new_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_read(TESTER->read_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("SingleMixed", "[process=" + std::to_string(TESTER->comm_size_) + + "][operation=single_mixed]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + SECTION("read after write from new file") { + TESTER->test_open(TESTER->new_file_, O_RDWR | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_read(TESTER->read_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("update after read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_read(TESTER->read_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("read after write from new file different opens") { + TESTER->test_open(TESTER->new_file_, O_RDWR | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_open(TESTER->new_file_, O_RDWR); + TESTER->test_read(TESTER->read_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("fstat") { + TESTER->Pretest(); + + SECTION("fstat on new file") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT | O_EXCL, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + TESTER->test_write(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + + struct stat buf = {}; + int result = fstat(TESTER->fh_orig_, &buf); + REQUIRE(result == 0); + REQUIRE(buf.st_size == (off_t)TESTER->size_written_orig_); + + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + + TESTER->Posttest(); +} diff --git a/test/unit/hermes_adapters/posix/posix_adapter_basic_test.cpp b/test/unit/hermes_adapters/posix/posix_adapter_basic_test.cpp deleted file mode 100644 index df4950dbc..000000000 --- a/test/unit/hermes_adapters/posix/posix_adapter_basic_test.cpp +++ /dev/null @@ -1,1480 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* Distributed under BSD 3-Clause license. * -* Copyright by The HDF Group. * -* Copyright by the Illinois Institute of Technology. * -* All rights reserved. * -* * -* This file is part of Hermes. The full Hermes copyright notice, including * -* terms governing use, modification, and redistribution, is contained in * -* the COPYING file, which can be found at the top directory. If you do not * -* have access to the file, you may request a copy from help@hdfgroup.org. * -* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include - -TEST_CASE("Open", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_open]" - "[repetition=1][file=1]") { - pretest(); - SECTION("open non-existant file") { - test::test_open(info.new_file.c_str(), O_WRONLY); - REQUIRE(test::fh_orig == -1); - test::test_open(info.new_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig == -1); - test::test_open(info.new_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig == -1); - } - - SECTION("truncate existing file and write-only") { - test::test_open(info.existing_file.c_str(), O_WRONLY | O_TRUNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("truncate existing file and read/write") { - test::test_open(info.existing_file.c_str(), O_RDWR | O_TRUNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("open existing file") { - test::test_open(info.existing_file.c_str(), O_WRONLY); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("append write existing file") { - test::test_open(info.existing_file.c_str(), O_APPEND); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("create a new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - stdfs::remove(info.new_file); - - test::test_open(info.new_file.c_str(), O_RDONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - stdfs::remove(info.new_file); - - test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("create a existing file") { - test::test_open(info.existing_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - - test::test_open(info.existing_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, - 0600); - REQUIRE(test::fh_orig == -1); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_CREAT | O_EXCL, - 0600); - REQUIRE(test::fh_orig == -1); - test::test_open(info.existing_file.c_str(), O_RDWR | O_CREAT | O_EXCL, - 0600); - REQUIRE(test::fh_orig == -1); - } - SECTION("Async I/O") { - test::test_open(info.existing_file.c_str(), O_WRONLY | O_ASYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_ASYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_ASYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_APPEND | O_ASYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - - test::test_open(info.existing_file.c_str(), O_WRONLY | O_NONBLOCK); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_NONBLOCK); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_NONBLOCK); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_APPEND | O_NONBLOCK); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - - test::test_open(info.existing_file.c_str(), O_WRONLY | O_NDELAY); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_NDELAY); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_NDELAY); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_APPEND | O_NDELAY); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("Async I/O") { - test::test_open(info.existing_file.c_str(), O_WRONLY | O_DIRECT); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_DIRECT); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_DIRECT); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_APPEND | O_DIRECT); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("Write Synchronize") { - /* File synchronicity */ - test::test_open(info.existing_file.c_str(), O_WRONLY | O_DSYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_DSYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_DSYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_APPEND | O_DSYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - - /* Write synchronicity */ - test::test_open(info.existing_file.c_str(), O_WRONLY | O_SYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_SYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_RDWR | O_SYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.existing_file.c_str(), O_APPEND | O_SYNC); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("Temporary file") { - if (info.supports_tmpfile) { - test::test_open("/tmp", O_WRONLY | O_TMPFILE, 0600); - REQUIRE(test::fh_orig != -1); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.new_file.c_str(), O_RDONLY | O_TMPFILE, 0600); - REQUIRE(test::fh_orig == -1); - test::test_open(info.new_file.c_str(), O_RDWR | O_TMPFILE, 0600); - REQUIRE(test::fh_orig == -1); - test::test_open(info.new_file.c_str(), O_APPEND | O_TMPFILE, 0600); - REQUIRE(test::fh_orig == -1); - - test::test_open(info.existing_file.c_str(), O_WRONLY | O_TMPFILE, 0600); - REQUIRE(test::fh_orig == -1); - test::test_open(info.existing_file.c_str(), O_RDONLY | O_TMPFILE, 0600); - REQUIRE(test::fh_orig == -1); - test::test_open(info.existing_file.c_str(), O_RDWR | O_TMPFILE, 0600); - REQUIRE(test::fh_orig == -1); - } - } - posttest(); -} - -TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == test::size_written_orig); - } - - - SECTION("write to existing file with truncate") { - test::test_open(info.existing_file.c_str(), O_WRONLY | O_TRUNC); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.existing_file) == test::size_written_orig); - } - - SECTION("write to existing file at the end") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - test::test_seek(0, SEEK_END); - REQUIRE(((size_t)test::status_orig) == - args.request_size * info.num_iterations); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.existing_file) == - test::size_written_orig + args.request_size * info.num_iterations); - } - - SECTION("append to existing file") { - auto existing_size = stdfs::file_size(info.existing_file); - test::test_open(info.existing_file.c_str(), O_RDWR | O_APPEND); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.existing_file) == - existing_size + test::size_written_orig); - } - - SECTION("append to new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == test::size_written_orig); - } - posttest(); -} - -TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read from non-existing file") { - test::test_open(info.new_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig == -1); - } - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - test::test_seek(0, SEEK_CUR); - REQUIRE(test::status_orig == 0); - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("read at the end of existing file") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - test::test_seek(0, SEEK_END); - REQUIRE(((size_t)test::status_orig) == - args.request_size * info.num_iterations); - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == 0); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedWriteSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == args.request_size); - } - - SECTION("write to new file always at start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedReadSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < 1; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::is_scase_ = true; - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - SECTION("update into existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size - 1); - test::test_seek(offset, SEEK_SET); // 630978 - REQUIRE(((size_t)test::status_orig) == offset); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - fsync(test::fh_orig); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (i * info.stride_size) % info.total_size; - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (i * info.stride_size) % info.total_size; - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamic", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamic", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedWriteRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - - SECTION("write to new file always at the start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - size_t biggest_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.offset_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_size_written < request_size) - biggest_size_written = request_size; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_size_written); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - size_t total_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - args.request_size + (rand_r(&info.offset_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_size_written += test::size_written_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_size_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = (args.request_size + - (rand_r(&info.offset_seed) % args.request_size)) % - (info.total_size - current_offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.offset_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (i * info.stride_size) % info.total_size; - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (i * info.stride_size) % info.total_size; - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegative", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t prev_offset = info.total_size + 1; - for (size_t i = 0; i < info.num_iterations; ++i) { - auto stride_offset = info.total_size - i * info.stride_size; - REQUIRE(prev_offset > stride_offset); - prev_offset = stride_offset; - size_t offset = (stride_offset) % (info.total_size - args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegative", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - info.total_size - ((i * info.stride_size) % info.total_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_write(data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (info.total_size - i * info.stride_size) % - (info.total_size - 2 * args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - info.total_size - ((i * info.stride_size) % info.total_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2D", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2D", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - test::test_write(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - 2 * args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - 2 * args.request_size); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -/** -* Temporal Fixed - */ - -TEST_CASE("BatchedWriteTemporalFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=fixed]") { - pretest(); - - SECTION("write to existing file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == args.request_size); - } - - SECTION("write to new file always at start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialTemporalFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=fixed]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_WRONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedWriteTemporalVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=variable]") { - pretest(); - - SECTION("write to existing file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == args.request_size); - } - - SECTION("write to new file always at start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialTemporalVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=variable]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_read(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_WRONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedMixedSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_mixed]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read after write on new file") { - test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - size_t last_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_seek(last_offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == last_offset); - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - last_offset += args.request_size; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("write and read alternative existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - if (i % 2 == 0) { - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } else { - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("update after read existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t last_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_seek(last_offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == last_offset); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - last_offset += args.request_size; - } - - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("read all after write all on new file in single open") { - test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("read all after write all on new file in different open") { - test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.new_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("SingleMixed", "[process=" + std::to_string(info.comm_size) + - "][operation=single_mixed]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read after write from new file") { - test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("update after read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - - test::test_close(); - REQUIRE(test::status_orig == 0); - } - SECTION("read after write from new file different opens") { - test::test_open(info.new_file.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - test::test_open(info.new_file.c_str(), O_RDWR); - test::test_read(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("fstat") { - pretest(); - - SECTION("fstat on new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600); - REQUIRE(test::fh_orig != -1); - test::test_write(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - - struct stat buf = {}; - int result = fstat(test::fh_orig, &buf); - REQUIRE(result == 0); - REQUIRE(buf.st_size == (off_t)test::size_written_orig); - - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - posttest(); -} diff --git a/test/unit/hermes_adapters/posix/posix_adapter_mpi_test.cpp b/test/unit/hermes_adapters/posix/posix_adapter_mpi_test.cpp deleted file mode 100644 index 501b5e07f..000000000 --- a/test/unit/hermes_adapters/posix/posix_adapter_mpi_test.cpp +++ /dev/null @@ -1,412 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include -#include - -#include "catch_config.h" - -#include "adapter_test_utils.h" - -#if HERMES_INTERCEPT == 1 -#include "hermes_adapters/posix/posix_api.h" -#include "hermes_adapters/posix/posix_fs_api.h" -#endif - -namespace stdfs = std::filesystem; - -namespace hermes::adapter::fs::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp/test_hermes"; - size_t request_size = 65536; -}; -struct Info { - bool debug = false; - bool supports_tmpfile; - int rank = 0; - int comm_size = 1; - std::vector write_data; - std::vector read_data; - std::string new_file; - std::string existing_file; - std::string shared_new_file; - std::string existing_shared_file; - std::string new_file_cmp; - std::string existing_file_cmp; - std::string existing_shared_file_cmp; - std::string shared_new_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 1; - size_t total_size; - size_t stride_size = 4 * 1024; - unsigned int temporal_interval_ms = 5; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 512 * 1024; - size_t large_min = 512 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::fs::test - -hermes::adapter::fs::test::Arguments args; -hermes::adapter::fs::test::Info info; -std::vector gen_random(const int len) { - std::vector tmp_s(len); - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - - srand((unsigned)time(NULL) * getpid()); - - tmp_s.reserve(len); - - for (int i = 0; i < len; ++i) - tmp_s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; - - return tmp_s; -} - -int init(int* argc, char*** argv) { -#if HERMES_INTERCEPT == 1 - setenv("HERMES_FLUSH_MODE", "kSync", 1); - HERMES_CLIENT_CONF.flushing_mode_ = hermes::FlushingMode::kSync; -#endif - MPI_Init(argc, argv); - info.write_data = gen_random(args.request_size); - info.read_data = std::vector(args.request_size, 'r'); - info.supports_tmpfile = FilesystemSupportsTmpfile(); - MPI_Comm_rank(MPI_COMM_WORLD, &info.rank); - MPI_Comm_size(MPI_COMM_WORLD, &info.comm_size); - if (info.debug && info.rank == 0) { - printf("%d ready for attach\n", info.comm_size); - fflush(stdout); - sleep(30); - } - MPI_Barrier(MPI_COMM_WORLD); - return 0; -} - -int finalize() { - MPI_Finalize(); - return 0; -} - -int pretest() { - REQUIRE(info.comm_size > 1); - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new_" + std::to_string(info.rank) + - "_of_" + std::to_string(info.comm_size) + "_" + - std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext_" + std::to_string(info.rank) + - "_of_" + std::to_string(info.comm_size) + "_" + - std::to_string(getpid()); - info.new_file_cmp = - fullpath.string() + "_new_cmp_" + std::to_string(info.rank) + "_of_" + - std::to_string(info.comm_size) + "_" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp_" + std::to_string(info.rank) + "_of_" + - std::to_string(info.comm_size) + "_" + std::to_string(getpid()); - info.existing_shared_file = - fullpath.string() + "_shared_ext_" + std::to_string(info.comm_size); - info.existing_shared_file_cmp = - fullpath.string() + "_shared_ext_cmp_" + std::to_string(info.comm_size); - info.shared_new_file = - fullpath.string() + "_shared_new_" + std::to_string(info.comm_size); - info.shared_new_file_cmp = - fullpath.string() + "_shared_new_cmp_" + std::to_string(info.comm_size); - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - if (stdfs::exists(info.existing_shared_file)) - stdfs::remove(info.existing_shared_file); - if (stdfs::exists(info.existing_shared_file_cmp)) - stdfs::remove(info.existing_shared_file_cmp); - if (stdfs::exists(info.shared_new_file)) stdfs::remove(info.shared_new_file); - if (stdfs::exists(info.shared_new_file_cmp)) - stdfs::remove(info.shared_new_file_cmp); - stdfs::path temp_fullpath = "/tmp"; - temp_fullpath /= args.filename; - std::string temp_ext_file = - temp_fullpath.string() + "_temp_" + std::to_string(info.rank) + "_of_" + - std::to_string(info.comm_size) + "_" + std::to_string(getpid()); - if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); - if (!stdfs::exists(temp_ext_file)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + temp_ext_file + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(temp_ext_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(temp_ext_file); - } - if (info.rank == 0 && !stdfs::exists(info.existing_shared_file)) { - std::string cmd = "cp " + temp_ext_file + " " + info.existing_shared_file; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_shared_file) == - args.request_size * info.num_iterations); - } - if (info.rank == 0 && !stdfs::exists(info.existing_shared_file_cmp)) { - std::string cmd = - "cp " + temp_ext_file + " " + info.existing_shared_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_shared_file_cmp) == - args.request_size * info.num_iterations); - } - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "cp " + temp_ext_file + " " + info.existing_file; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - } - if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); - REQUIRE(info.total_size > 0); - MPI_Barrier(MPI_COMM_WORLD); -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking( - info.existing_shared_file_cmp, false); -#endif - return 0; -} - -void Clear() { -#if HERMES_INTERCEPT == 1 - HERMES->Clear(); -#endif -} - -int posttest(bool compare_data = true) { -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking( - info.existing_shared_file, false); -#endif - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_shared_file) && - stdfs::exists(info.existing_shared_file_cmp)) { - size_t size = stdfs::file_size(info.existing_shared_file); - if (size != stdfs::file_size(info.existing_shared_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_shared_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_shared_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_shared_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - /* Clean up. */ - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - MPI_Barrier(MPI_COMM_WORLD); - if (info.rank == 0) { - if (stdfs::exists(info.existing_shared_file)) - stdfs::remove(info.existing_shared_file); - if (stdfs::exists(info.existing_shared_file_cmp)) - stdfs::remove(info.existing_shared_file_cmp); - } - Clear(); - - #if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file_cmp, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file_cmp, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking( - info.existing_shared_file, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking( - info.existing_shared_file_cmp, true); - #endif - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -namespace test { -int fh_orig; -int fh_cmp; -int status_orig; -size_t size_read_orig; -size_t size_written_orig; -bool is_scase_ = false; -void test_open(const char* path, int flags, ...) { - int mode = 0; - if (flags & O_CREAT || flags & O_TMPFILE) { - va_list arg; - va_start(arg, flags); - mode = va_arg(arg, int); - va_end(arg); - } - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else if (strcmp(path, info.shared_new_file.c_str()) == 0) { - cmp_path = info.shared_new_file_cmp; - } else if (strcmp(path, "/tmp") == 0) { - cmp_path = "/tmp"; - } else { - cmp_path = info.existing_file_cmp; - } - if (flags & O_CREAT || flags & O_TMPFILE) { - fh_orig = open(path, flags, mode); - fh_cmp = open(cmp_path.c_str(), flags, mode); - } else { - fh_orig = open(path, flags); - fh_cmp = open(cmp_path.c_str(), flags); - } - bool is_same = - (fh_cmp != -1 && fh_orig != -1) || (fh_cmp == -1 && fh_orig == -1); - REQUIRE(is_same); -} -void test_close() { - status_orig = close(fh_orig); - int status = close(fh_cmp); - REQUIRE(status == status_orig); -} -void test_write(const void* ptr, size_t size) { - size_written_orig = write(fh_orig, ptr, size); - size_t size_written = write(fh_cmp, ptr, size); - REQUIRE(size_written == size_written_orig); -} -void test_read(char* ptr, size_t size) { - size_read_orig = read(fh_orig, ptr, size); - std::vector read_data(size, 'r'); - size_t size_read = read(fh_cmp, read_data.data(), size); - REQUIRE(size_read == size_read_orig); - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < size; ++i) { - if (read_data[i] != ptr[i]) { - unmatching_chars = i; - break; - } - } - REQUIRE(unmatching_chars == 0); - } -} -void test_seek(long offset, int whence) { - status_orig = lseek(fh_orig, offset, whence); - int status = lseek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -#include "posix_adapter_basic_test.cpp" -#include "posix_adapter_rs_test.cpp" -// TODO(chogan): Disabling until issue #302 is fixed -// #include "posix_adapter_shared_test.cpp" diff --git a/test/unit/hermes_adapters/posix/posix_adapter_rs_test.cc b/test/unit/hermes_adapters/posix/posix_adapter_rs_test.cc new file mode 100644 index 000000000..a0c66c0e9 --- /dev/null +++ b/test/unit/hermes_adapters/posix/posix_adapter_rs_test.cc @@ -0,0 +1,1294 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "posix_adapter_test.h" + +TEST_CASE("BatchedWriteRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("write to new file always at the start") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + size_t biggest_size_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + if (biggest_size_written < request_size) + biggest_size_written = request_size; + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_.c_str()) == + biggest_size_written); + } + + SECTION("write to new file") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + size_t total_size_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + total_size_written += TESTER->size_written_orig_; + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_.c_str()) == + total_size_written); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequentialRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + TESTER->small_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_open(TESTER->existing_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ != -1); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->small_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadRandomRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-small]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + + "][pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->small_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->small_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + (i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->small_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + (i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->small_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_ - TESTER->small_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_ - TESTER->small_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = (TESTER->total_size_ - i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->total_size_ - ((i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->small_max_)); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStride2DRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->small_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->small_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} +/** + * Medium RS + **/ + +TEST_CASE("BatchedWriteRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("write to new file always at the start") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + size_t biggest_size_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + if (biggest_size_written < request_size) + biggest_size_written = request_size; + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_.c_str()) == + biggest_size_written); + } + + SECTION("write to new file") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + size_t total_size_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + total_size_written += TESTER->size_written_orig_; + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_.c_str()) == + total_size_written); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequentialRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + (TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_)) % + (TESTER->total_size_ - current_offset); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + current_offset += TESTER->size_read_orig_; + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_open(TESTER->existing_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ != -1); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadRandomRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-medium]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + + "][pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + (i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + (i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = (TESTER->total_size_ - i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->total_size_ - ((i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->medium_max_)); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStride2DRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} +/** + * Large RS + **/ + +TEST_CASE("BatchedWriteRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("write to new file always at the start") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + size_t biggest_size_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->large_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + if (biggest_size_written < request_size) + biggest_size_written = request_size; + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_.c_str()) == + biggest_size_written); + } + + SECTION("write to new file") { + TESTER->test_open(TESTER->new_file_, O_WRONLY | O_CREAT, 0600); + REQUIRE(TESTER->fh_orig_ != -1); + size_t total_size_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + TESTER->large_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + total_size_written += TESTER->size_written_orig_; + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_.c_str()) == + total_size_written); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequentialRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ != -1); + std::string data(TESTER->request_size_, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + (TESTER->large_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_)) % + (TESTER->total_size_ - current_offset); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + current_offset += TESTER->size_read_orig_; + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_open(TESTER->existing_file_, O_RDONLY); + REQUIRE(TESTER->fh_orig_ != -1); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_seek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->large_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadRandomRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-large]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + + "][pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + (TESTER->large_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_)) % + (TESTER->total_size_ - TESTER->status_orig_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + (i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->large_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = + (i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_ - TESTER->large_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_ - TESTER->large_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = (TESTER->total_size_ - i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + (TESTER->large_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_)) % + (TESTER->total_size_ - TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t offset = TESTER->total_size_ - ((i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->large_max_)); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStride2DRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("read from existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_read(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("write to existing file") { + TESTER->test_open(TESTER->existing_file_, O_RDWR); + REQUIRE(TESTER->fh_orig_ != -1); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_seek(offset, SEEK_SET); + REQUIRE(((size_t)TESTER->status_orig_) == offset); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_write(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_close(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} diff --git a/test/unit/hermes_adapters/posix/posix_adapter_rs_test.cpp b/test/unit/hermes_adapters/posix/posix_adapter_rs_test.cpp deleted file mode 100644 index d52d4438d..000000000 --- a/test/unit/hermes_adapters/posix/posix_adapter_rs_test.cpp +++ /dev/null @@ -1,1239 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -TEST_CASE("BatchedWriteRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at the start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - size_t biggest_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_size_written < request_size) - biggest_size_written = request_size; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_size_written); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - size_t total_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_size_written += test::size_written_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_size_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - (i * info.stride_size) % (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - (i * info.stride_size) % (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (info.total_size - i * info.stride_size) % - (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = info.total_size - ((i * info.stride_size) % - (info.total_size - info.small_max)); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.small_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} -/** - * Medium RS - **/ - -TEST_CASE("BatchedWriteRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at the start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - size_t biggest_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_size_written < request_size) - biggest_size_written = request_size; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_size_written); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - size_t total_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_size_written += test::size_written_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_size_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - (info.medium_min + (rand_r(&info.rs_seed) % info.medium_max)) % - (info.total_size - current_offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - (i * info.stride_size) % (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - (i * info.stride_size) % (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (info.total_size - i * info.stride_size) % - (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = info.total_size - ((i * info.stride_size) % - (info.total_size - info.medium_max)); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.medium_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} -/** - * Large RS - **/ - -TEST_CASE("BatchedWriteRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at the start") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - size_t biggest_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_size_written < request_size) - biggest_size_written = request_size; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_size_written); - } - - SECTION("write to new file") { - test::test_open(info.new_file.c_str(), O_WRONLY | O_CREAT, 0600); - REQUIRE(test::fh_orig != -1); - size_t total_size_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_size_written += test::size_written_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_size_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % - (info.total_size - current_offset); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_open(info.existing_file.c_str(), O_RDONLY); - REQUIRE(test::fh_orig != -1); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_seek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % - (info.total_size - test::status_orig); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - rand_r(&info.offset_seed) % (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - (i * info.stride_size) % (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = - (i * info.stride_size) % (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = (info.total_size - i * info.stride_size) % - (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % - (info.total_size - info.large_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t offset = info.total_size - ((i * info.stride_size) % - (info.total_size - info.large_max)); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_read(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_open(info.existing_file.c_str(), O_RDWR); - REQUIRE(test::fh_orig != -1); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - size_t offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.large_max); - test::test_seek(offset, SEEK_SET); - REQUIRE(((size_t)test::status_orig) == offset); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_write(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_close(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} diff --git a/test/unit/hermes_adapters/posix/posix_adapter_shared_test.cpp b/test/unit/hermes_adapters/posix/posix_adapter_shared_test.cc similarity index 72% rename from test/unit/hermes_adapters/posix/posix_adapter_shared_test.cpp rename to test/unit/hermes_adapters/posix/posix_adapter_shared_test.cc index 0b64d299e..9ce490641 100644 --- a/test/unit/hermes_adapters/posix/posix_adapter_shared_test.cpp +++ b/test/unit/hermes_adapters/posix/posix_adapter_shared_test.cc @@ -10,18 +10,20 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -TEST_CASE("SharedFile", "[process=" + std::to_string(info.comm_size) + +#include "posix_adapter_test.h" + +TEST_CASE("SharedFile", "[process=" + std::to_string(TESTER->comm_size_) + "]" "[operation=batched_write]" "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + + std::to_string(TESTER->num_iterations_) + "]" "[mode=shared]" "[pattern=sequential][file=1]") { - pretest(); - REQUIRE(info.comm_size == 2); + TESTER->Pretest(); + REQUIRE(TESTER->comm_size_ == 2); SECTION("producer-consumer") { - bool producer = info.rank % 2 == 0; + bool producer = TESTER->rank_ % 2 == 0; struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; @@ -29,16 +31,17 @@ TEST_CASE("SharedFile", "[process=" + std::to_string(info.comm_size) + lock.l_len = 0; lock.l_pid = getpid(); if (producer) { - int fd = open(info.shared_new_file.c_str(), O_RDWR | O_CREAT, 0666); + int fd = open(TESTER->shared_new_file_.hermes_.c_str(), + O_RDWR | O_CREAT, 0666); REQUIRE(fd != -1); MPI_Barrier(MPI_COMM_WORLD); int status = -1; - for (size_t i = 0; i < info.num_iterations; ++i) { + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { status = fcntl(fd, F_SETLKW, &lock); REQUIRE(status != -1); size_t write_bytes = - write(fd, info.write_data.data(), args.request_size); - REQUIRE(write_bytes == args.request_size); + write(fd, TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(write_bytes == TESTER->request_size_); lock.l_type = F_UNLCK; status = fcntl(fd, F_SETLK, &lock); REQUIRE(status != -1); @@ -47,11 +50,11 @@ TEST_CASE("SharedFile", "[process=" + std::to_string(info.comm_size) + REQUIRE(status != -1); } else { MPI_Barrier(MPI_COMM_WORLD); - int fd = open(info.shared_new_file.c_str(), O_RDONLY); + int fd = open(TESTER->shared_new_file_.hermes_.c_str(), O_RDONLY); REQUIRE(fd != -1); int status = -1; size_t bytes_read = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { lock.l_type = F_RDLCK; status = fcntl(fd, F_SETLKW, &lock); REQUIRE(status != -1); @@ -59,10 +62,10 @@ TEST_CASE("SharedFile", "[process=" + std::to_string(info.comm_size) + size_t cur_offset = lseek(fd, bytes_read, SEEK_SET); REQUIRE(cur_offset == bytes_read); if (file_size > bytes_read) { - size_t read_size = args.request_size < file_size - bytes_read - ? args.request_size + size_t read_size = TESTER->request_size_ < file_size - bytes_read + ? TESTER->request_size_ : file_size - bytes_read; - size_t read_bytes = read(fd, info.read_data.data(), read_size); + size_t read_bytes = read(fd, TESTER->read_data_.data(), read_size); REQUIRE(read_bytes == read_size); bytes_read += read_bytes; } @@ -74,5 +77,5 @@ TEST_CASE("SharedFile", "[process=" + std::to_string(info.comm_size) + REQUIRE(status != -1); } } - posttest(); + TESTER->Posttest(); } diff --git a/test/unit/hermes_adapters/posix/posix_adapter_test.cc b/test/unit/hermes_adapters/posix/posix_adapter_test.cc new file mode 100644 index 000000000..a4bd24213 --- /dev/null +++ b/test/unit/hermes_adapters/posix/posix_adapter_test.cc @@ -0,0 +1,17 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "posix_adapter_test.h" + +int main(int argc, char **argv) { + TESTER->Init(argc, argv); +} diff --git a/test/unit/hermes_adapters/posix/posix_adapter_test.cpp b/test/unit/hermes_adapters/posix/posix_adapter_test.cpp deleted file mode 100644 index 0c5e1350d..000000000 --- a/test/unit/hermes_adapters/posix/posix_adapter_test.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include -#include -#include "hermes/hermes.h" -#include - -#include "catch_config.h" -#include "hermes_adapters/posix/posix_api.h" - -#if HERMES_INTERCEPT == 1 -#include "hermes_adapters/posix/posix_fs_api.h" -#endif - -#include "adapter_test_utils.h" - -namespace stdfs = std::filesystem; - -namespace hermes::adapter::fs::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp/test_hermes"; - size_t request_size = 65536; -}; -struct Info { - int rank = 0; - int comm_size = 1; - bool supports_tmpfile; - std::vector write_data; - std::vector read_data; - std::string new_file; // Tracked by Hermes - std::string existing_file; // Tracked by Hermes - std::string new_file_cmp; // NOT tracked by Hermes - std::string existing_file_cmp; // NOT tracekd by Hermes - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 5; - size_t total_size; // The size of the EXISTING file - size_t stride_size = 1024; - unsigned int temporal_interval_ms = 1; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; - size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::fs::test -hermes::adapter::fs::test::Arguments args; -hermes::adapter::fs::test::Info info; -std::vector gen_random(const int len) { - auto tmp_s = std::vector(len); - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - - srand(100); - for (int i = 0; i < len; ++i) - tmp_s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; - return tmp_s; -} - -int init(int* argc, char*** argv) { -#if HERMES_INTERCEPT == 1 - setenv("HERMES_FLUSH_MODE", "kSync", 1); - HERMES_CLIENT_CONF.flushing_mode_ = hermes::FlushingMode::kSync; -#endif - MPI_Init(argc, argv); - info.write_data = gen_random(args.request_size); - info.read_data = std::vector(args.request_size, 'r'); - info.supports_tmpfile = FilesystemSupportsTmpfile(); - return 0; -} - -int finalize() { - MPI_Finalize(); - return 0; -} - -void IgnoreAllFiles() { -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, false); -#endif -} - -void TrackFiles() { -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, true); -#endif -} - -void RemoveFile(const std::string &path) { - stdfs::remove(path); - if (stdfs::exists(path)) { - HELOG(kFatal, "Failed to remove: {}", path) - } -} - -void RemoveFiles() { - RemoveFile(info.new_file); - RemoveFile(info.new_file_cmp); - RemoveFile(info.existing_file); - RemoveFile(info.existing_file_cmp); -} - -int pretest() { - // Initialize path names - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new_" + std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext_" + std::to_string(getpid()); - info.new_file_cmp = - fullpath.string() + "_new_cmp" + "_" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp" + "_" + std::to_string(getpid()); - - // Ignore all files - IgnoreAllFiles(); - - // Remove existing files from the FS - RemoveFiles(); - - // Create the file which is untracked by Hermes - if (true) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + info.existing_file_cmp + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file_cmp); - } - - // Create the file that is being tracks by Hermes - if (true) { - std::string cmd = "cp " + info.existing_file_cmp + " " + info.existing_file; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - auto check = stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations; - if (!check) { - HELOG(kFatal, "File sizes weren't equivalent after copy") - } - REQUIRE(check); - } - REQUIRE(info.total_size > 0); - - // Begin tracking the Hermes files - TrackFiles(); - return 0; -} - -void Clear() { -#if HERMES_INTERCEPT == 1 - HERMES->Clear(); -#endif -} - -int posttest(bool compare_data = true) { - IgnoreAllFiles(); - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - // Verify the NEW file is the same in Hermes + the backend - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, 'r'); - std::vector d2(size, 'w'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), sizeof(unsigned char), size, fh1); - REQUIRE(read_d1 == size); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), sizeof(unsigned char), size, fh2); - REQUIRE(read_d2 == size); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) { - char_mismatch = pos; - break; - } - } - if (char_mismatch != 0) { - std::cout << "The files " << info.existing_file - << " and " << info.existing_file_cmp - << " had mismatched characters" << std::endl; - } - REQUIRE(char_mismatch == 0); - } - } - /* Delete the files from both Hermes and the backend. */ - TrackFiles(); - RemoveFiles(); - Clear(); - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -namespace test { -int fh_orig; -int fh_cmp; -int status_orig; -size_t size_read_orig; -size_t size_written_orig; -bool is_scase_ = false; -void test_open(const char* path, int flags, ...) { - int mode = 0; - if (flags & O_CREAT || flags & O_TMPFILE) { - va_list arg; - va_start(arg, flags); - mode = va_arg(arg, int); - va_end(arg); - } - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else if (strcmp(path, "/tmp") == 0) { - cmp_path = "/tmp"; - } else { - cmp_path = info.existing_file_cmp; - } - if (flags & O_CREAT || flags & O_TMPFILE) { - fh_orig = open(path, flags, mode); - fh_cmp = open(cmp_path.c_str(), flags, mode); - } else { - fh_orig = open(path, flags); - fh_cmp = open(cmp_path.c_str(), flags); - } - bool is_same = - (fh_cmp != -1 && fh_orig != -1) || (fh_cmp == -1 && fh_orig == -1); - REQUIRE(is_same); -} -void test_close() { - status_orig = close(fh_orig); - int status = close(fh_cmp); - REQUIRE(status == status_orig); -} -void test_write(const void* ptr, size_t size) { - size_written_orig = write(fh_orig, ptr, size); - size_t size_written = write(fh_cmp, ptr, size); - REQUIRE(size_written == size_written_orig); -} -void test_read(char* ptr, size_t size) { - size_read_orig = read(fh_orig, ptr, size); - std::vector read_data(size, 'r'); - size_t size_read = read(fh_cmp, read_data.data(), size); - REQUIRE(size_read == size_read_orig); - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < size; ++i) { - if (read_data[i] != ptr[i]) { - unmatching_chars = i; - break; - } - } - if (unmatching_chars != 0) { - std::cerr << "There were unmatching chars" << std::endl; - } - REQUIRE(unmatching_chars == 0); - } -} -void test_seek(long offset, int whence) { - status_orig = lseek(fh_orig, offset, whence); - int status = lseek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -#include "posix_adapter_basic_test.cpp" -#include "posix_adapter_rs_test.cpp" diff --git a/test/unit/hermes_adapters/posix/posix_adapter_test.h b/test/unit/hermes_adapters/posix/posix_adapter_test.h new file mode 100644 index 000000000..cf4625d7a --- /dev/null +++ b/test/unit/hermes_adapters/posix/posix_adapter_test.h @@ -0,0 +1,129 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_TEST_UNIT_HERMES_ADAPTERS_POSIX_POSIX_ADAPTER_BASE_TEST_H_ +#define HERMES_TEST_UNIT_HERMES_ADAPTERS_POSIX_POSIX_ADAPTER_BASE_TEST_H_ + +#include "binary_file_tests.h" + +namespace hermes::adapter::test { +template +class PosixTest : public BinaryFileTests { + public: + FileInfo new_file_; + FileInfo existing_file_; + FileInfo shared_new_file_; + FileInfo shared_existing_file_; + FileInfo tmp_file_; + unsigned int offset_seed_ = 1; + unsigned int rs_seed_ = 1; + unsigned int temporal_interval_seed_ = 5; + size_t stride_size_ = 1024; + unsigned int temporal_interval_ms_ = 1; + size_t small_min_ = 1; + size_t small_max_ = 4 * 1024; + size_t medium_min_ = 4 * 1024 + 1; + size_t medium_max_ = 256 * 1024; + size_t large_min_ = 256 * 1024 + 1; + size_t large_max_ = 3 * 1024 * 1024; + + int fh_orig_; + int fh_cmp_; + int status_orig_; + size_t size_read_orig_; + size_t size_written_orig_; + bool is_scase_ = false; + + public: + void RegisterFiles() override { + RegisterPath("new", 0, new_file_); + RegisterPath("ext", TEST_DO_CREATE, existing_file_); + if constexpr(WITH_MPI) { + RegisterPath("shared_new", TEST_FILE_SHARED, shared_new_file_); + RegisterPath("shared_ext", TEST_DO_CREATE | TEST_FILE_SHARED, + shared_existing_file_); + } + RegisterTmpPath(tmp_file_); + } + + void test_open(FileInfo &info, int flags, ...) { + int mode = 0; + if (flags & O_CREAT || flags & O_TMPFILE) { + va_list arg; + va_start(arg, flags); + mode = va_arg(arg, int); + va_end(arg); + } + std::string cmp_path; + if (flags & O_CREAT || flags & O_TMPFILE) { + fh_orig_ = open(info.hermes_.c_str(), flags, mode); + fh_cmp_ = open(info.cmp_.c_str(), flags, mode); + } else { + fh_orig_ = open(info.hermes_.c_str(), flags); + fh_cmp_ = open(info.cmp_.c_str(), flags); + } + bool is_same = + (fh_cmp_ != -1 && fh_orig_ != -1) || (fh_cmp_ == -1 && fh_orig_ == -1); + REQUIRE(is_same); + } + + void test_close() { + status_orig_ = close(fh_orig_); + int status = close(fh_cmp_); + REQUIRE(status == status_orig_); + } + + void test_write(const void* ptr, size_t size) { + size_written_orig_ = write(fh_orig_, ptr, size); + size_t size_written = write(fh_cmp_, ptr, size); + REQUIRE(size_written == size_written_orig_); + } + + void test_read(char* ptr, size_t size) { + size_read_orig_ = read(fh_orig_, ptr, size); + std::vector read_data(size, 'r'); + size_t size_read = read(fh_cmp_, read_data.data(), size); + REQUIRE(size_read == size_read_orig_); + if (size_read > 0) { + size_t unmatching_chars = 0; + for (size_t i = 0; i < size; ++i) { + if (read_data[i] != ptr[i]) { + unmatching_chars = i; + break; + } + } + if (unmatching_chars != 0) { + std::cerr << "There were unmatching chars" << std::endl; + } + REQUIRE(unmatching_chars == 0); + } + } + + void test_seek(long offset, int whence) { + status_orig_ = lseek(fh_orig_, offset, whence); + int status = lseek(fh_cmp_, offset, whence); + REQUIRE(status == status_orig_); + } +}; + +} // namespace hermes::adapter::test + +#if defined(HERMES_MPI_TESTS) +#define TESTER \ + hshm::EasySingleton< \ + hermes::adapter::test::PosixTest>::GetInstance() +#else +#define TESTER \ + hshm::EasySingleton>::GetInstance() +#endif + +#endif // HERMES_TEST_UNIT_HERMES_ADAPTERS_POSIX_POSIX_ADAPTER_BASE_TEST_H_ diff --git a/test/unit/hermes_adapters/posix/posix_simple_io_omp.cc b/test/unit/hermes_adapters/posix/posix_simple_io_omp.cc index f470be1a5..f16efd36e 100644 --- a/test/unit/hermes_adapters/posix/posix_simple_io_omp.cc +++ b/test/unit/hermes_adapters/posix/posix_simple_io_omp.cc @@ -24,7 +24,7 @@ #include #include "basic_test.h" -static const int kNumProcs = 1; +static const int kNumProcs = 8; void TestThread(char *path, int do_read, @@ -34,7 +34,7 @@ void TestThread(char *path, int rank = omp_get_thread_num(); size_t size = count * block_size; size_t total_size = size * kNumProcs; - int off = (rank * size) + block_off * block_size; + size_t off = (rank * size) + block_off * block_size; { std::stringstream ss; @@ -56,7 +56,7 @@ void TestThread(char *path, std::cout << "Failed to open the file" << std::endl; exit(1); } - lseek(fd, off, SEEK_SET); + lseek64(fd, off, SEEK_SET); if (do_read) { struct stat st; @@ -77,6 +77,7 @@ void TestThread(char *path, #pragma omp barrier for (int i = 0; i < count; ++i) { + HILOG(kInfo, "ITERATION: {} / {}", i, count); char nonce = i + 1; if (!do_read) { memset(buf.data(), nonce, block_size); diff --git a/test/unit/hermes_adapters/posix/tests.py b/test/unit/hermes_adapters/posix/tests.py deleted file mode 100644 index b29b4300f..000000000 --- a/test/unit/hermes_adapters/posix/tests.py +++ /dev/null @@ -1,110 +0,0 @@ -from py_hermes_ci.test_manager import TestManager -from jarvis_util import * - - -class PosixTestManager(TestManager): - def spawn_all_nodes(self): - return self.spawn_info() - - def set_paths(self): - self.POSIX_CMD = f"{self.CMAKE_BINARY_DIR}/bin/posix_adapter_test" - self.HERMES_POSIX_CMD = f"{self.CMAKE_BINARY_DIR}/bin/hermes_posix_adapter_test" - self.POSIX_MPI_CMD = f"{self.CMAKE_BINARY_DIR}/bin/posix_adapter_mpi_test" - self.HERMES_POSIX_MPI_CMD = f"{self.CMAKE_BINARY_DIR}/bin/hermes_posix_adapter_mpi_test" - self.POSIX_SIMPLE_IO_CMD = f"{self.CMAKE_BINARY_DIR}/bin/posix_simple_io_omp" - self.HERMES_POSIX_SIMPLE_IO_CMD = f"{self.CMAKE_BINARY_DIR}/bin/hermes_posix_simple_io_omp" - - self.disable_testing = False - - def test_posix_basic(self): - return - posix_cmd = f"{self.POSIX_CMD}" - node = Exec(posix_cmd) - return node.exit_code - - def test_hermes_posix_basic_small(self): - posix_cmd = f"{self.HERMES_POSIX_CMD} " \ - f"~[request_size=range-small] " \ - f"--reporter compact -d yes" - - spawn_info = self.spawn_info(nprocs=1, - hermes_conf='hermes_server') - self.start_daemon(spawn_info) - node = Exec(posix_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_posix_basic_large(self): - posix_cmd = f"{self.HERMES_POSIX_CMD} " \ - f"[request_size=range-large] " \ - f"--reporter compact -d yes" - spawn_info = self.spawn_info(nprocs=1, - hermes_conf='hermes_server') - self.start_daemon(spawn_info) - node = Exec(posix_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_posix_basic_mpi(self): - return - posix_cmd = f"{self.POSIX_MPI_CMD}" - spawn_info = self.spawn_info(nprocs=2) - node = Exec(posix_cmd, spawn_info) - return node.exit_code - - def test_hermes_posix_basic_mpi_small(self): - posix_cmd = f"{self.HERMES_POSIX_MPI_CMD} " \ - f"~[request_size=range-large] " \ - f"--reporter compact -d yes" - spawn_info = self.spawn_info(nprocs=2, - hermes_conf='hermes_server') - self.start_daemon(spawn_info) - node = Exec(posix_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_posix_basic_mpi_large(self): - posix_cmd = f"{self.HERMES_POSIX_MPI_CMD} " \ - f"[request_size=range-large] " \ - f"--reporter compact -d yes" - spawn_info = self.spawn_info(nprocs=2, - hermes_conf='hermes_server') - self.start_daemon(spawn_info) - node = Exec(posix_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_posix_simple_io_omp_default(self): - posix_cmd = f"{self.HERMES_POSIX_SIMPLE_IO_CMD} " \ - f"/tmp/test_hermes/hi.txt 0 1024 8 0" - spawn_info = self.spawn_info(nprocs=2, - hermes_conf='hermes_server', - hermes_mode='kDefault') - self.start_daemon(spawn_info) - node = Exec(posix_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_posix_simple_io_omp_scratch(self): - posix_cmd = f"{self.HERMES_POSIX_SIMPLE_IO_CMD} " \ - f"/tmp/test_hermes/hi.txt 0 1024 8 0" - spawn_info = self.spawn_info(nprocs=2, - hermes_conf='hermes_server', - hermes_mode='kScratch') - self.start_daemon(spawn_info) - node = Exec(posix_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_posix_simple_io_omp_preload(self): - return - posix_cmd = f"{self.POSIX_SIMPLE_IO_CMD} " \ - f"/tmp/test_hermes/hi.txt 0 1024 8 0" - spawn_info = self.spawn_info(nprocs=2, - hermes_conf='hermes_server', - hermes_mode='kScratch', - api='posix') - self.start_daemon(spawn_info) - node = Exec(posix_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code diff --git a/test/unit/hermes_adapters/stdio/CMakeLists.txt b/test/unit/hermes_adapters/stdio/CMakeLists.txt index d14367619..8bc02b7b4 100644 --- a/test/unit/hermes_adapters/stdio/CMakeLists.txt +++ b/test/unit/hermes_adapters/stdio/CMakeLists.txt @@ -5,57 +5,109 @@ include_directories( #------------------------------------------------------------------------------ # STDIO Adapter Internal tests #------------------------------------------------------------------------------ -add_executable(stdio_adapter_mapper_test stdio_adapter_mapper_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(stdio_adapter_mapper_test stdc++fs hermes_stdio) -add_dependencies(stdio_adapter_mapper_test hermes_stdio) -pytest(stdio test_hermes_stdio_mapper) +add_executable(hermes_stdio_adapter_mapper_test + stdio_adapter_test.cc + stdio_adapter_mapper_test.cc) +add_dependencies(hermes_stdio_adapter_mapper_test + hermes_stdio) +target_link_libraries(hermes_stdio_adapter_mapper_test + hermes_stdio) +target_compile_definitions(hermes_stdio_adapter_mapper_test PUBLIC + HERMES_INTERCEPT=1 HERMES_MPI_TESTS=false) +jarvis_test(stdio test_hermes_stdio_mapper) #------------------------------------------------------------------------------ # STDIO Adapter End to End tests #------------------------------------------------------------------------------ -add_executable(stdio_adapter_test stdio_adapter_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(stdio_adapter_test hermes) -pytest(stdio test_stdio_basic) +# Non-Hermes, None-MPI STDIO basic +add_executable(stdio_adapter_test + stdio_adapter_test.cc + stdio_adapter_basic_test.cc + stdio_adapter_func_test.cc + stdio_adapter_rs_test.cc) +add_dependencies(stdio_adapter_test + hermes) +target_link_libraries(stdio_adapter_test + hermes) +target_compile_definitions(stdio_adapter_test PUBLIC + HERMES_MPI_TESTS=false) +jarvis_test(stdio test_stdio_basic) -add_executable(stdio_adapter_mpi_test stdio_adapter_mpi_test.cpp ${ADAPTER_COMMON}) -# pytest(stdio test_stdio_basic_mpi 2 "") +# Hermes, None-MPI STDIO basic +add_executable(hermes_stdio_adapter_test + stdio_adapter_test.cc + stdio_adapter_basic_test.cc + stdio_adapter_rs_test.cc) +add_dependencies(hermes_stdio_adapter_test + hermes_stdio) +target_link_libraries(hermes_stdio_adapter_test + hermes_stdio) +target_compile_definitions(hermes_stdio_adapter_test PUBLIC + HERMES_INTERCEPT=1 HERMES_MPI_TESTS=false) +jarvis_test(stdio test_hermes_stdio_basic_small) +jarvis_test(stdio test_hermes_stdio_basic_large) -add_executable(hermes_stdio_adapter_test stdio_adapter_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_stdio_adapter_test hermes_stdio) -add_dependencies(hermes_stdio_adapter_test hermes_stdio) -set_target_properties(hermes_stdio_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -pytest(stdio test_hermes_stdio_basic_small) -pytest(stdio test_hermes_stdio_basic_large) +# Non-Hermes, MPI STDIO basic +add_executable(stdio_adapter_mpi_test + stdio_adapter_test.cc + stdio_adapter_basic_test.cc + stdio_adapter_rs_test.cc + stdio_adapter_shared_test.cc) +add_dependencies(stdio_adapter_mpi_test + hermes) +target_link_libraries(stdio_adapter_mpi_test + hermes) +target_compile_definitions(stdio_adapter_mpi_test PUBLIC + HERMES_MPI_TESTS=true) +jarvis_test(stdio test_stdio_basic_mpi) -add_executable(hermes_stdio_low_buf_adapter_test stdio_adapter_low_buffer_space_test.cpp ${ADAPTER_COMMON}) +# Hermes, MPI STDIO basic +add_executable(hermes_stdio_adapter_mpi_test + stdio_adapter_test.cc + stdio_adapter_basic_test.cc + stdio_adapter_rs_test.cc + stdio_adapter_shared_test.cc) +target_link_libraries(hermes_stdio_adapter_mpi_test + hermes_stdio) +add_dependencies(hermes_stdio_adapter_mpi_test + hermes_stdio) +target_compile_definitions(hermes_stdio_adapter_mpi_test PUBLIC + HERMES_INTERCEPT=1 HERMES_MPI_TESTS=true) +jarvis_test(stdio test_hermes_stdio_basic_mpi_small) +jarvis_test(stdio test_hermes_stdio_basic_mpi_large) + +# Hermes, Low buffer space +add_executable(hermes_stdio_low_buf_adapter_test + stdio_adapter_test.cc + stdio_adapter_low_buffer_space_test.cc) target_link_libraries(hermes_stdio_low_buf_adapter_test hermes_stdio) add_dependencies(hermes_stdio_low_buf_adapter_test hermes_stdio) -set_target_properties(hermes_stdio_low_buf_adapter_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -pytest(stdio test_hermes_stdio_low_buf) - -add_executable(hermes_stdio_adapter_mode_test stdio_adapter_mode_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_stdio_adapter_mode_test hermes_stdio) -add_dependencies(hermes_stdio_adapter_mode_test hermes_stdio) -set_target_properties(hermes_stdio_adapter_mode_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -pytest(stdio test_hermes_stdio_bypass) -pytest(stdio test_hermes_stdio_default) -pytest(stdio test_hermes_stdio_scratch) +target_compile_definitions(hermes_stdio_low_buf_adapter_test PUBLIC + HERMES_INTERCEPT=1 HERMES_MPI_TESTS=false) +jarvis_test(stdio test_hermes_stdio_low_buf) -add_executable(hermes_stdio_adapter_mpi_test stdio_adapter_mpi_test.cpp ${ADAPTER_COMMON}) -target_link_libraries(hermes_stdio_adapter_mpi_test hermes_stdio) -add_dependencies(hermes_stdio_adapter_mpi_test hermes_stdio) -set_target_properties(hermes_stdio_adapter_mpi_test PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") -pytest(stdio test_hermes_stdio_mpi_small) -pytest(stdio test_hermes_stdio_mpi_large) +# Hermes, Adapter mode +add_executable(hermes_stdio_adapter_mode_test + stdio_adapter_test.cc + stdio_adapter_mode_test.cc) +target_link_libraries(hermes_stdio_adapter_mode_test + hermes_stdio) +add_dependencies(hermes_stdio_adapter_mode_test + hermes_stdio) +target_compile_definitions(hermes_stdio_adapter_mode_test PUBLIC + HERMES_INTERCEPT=1 HERMES_MPI_TESTS=false) +jarvis_test(stdio test_hermes_stdio_adapter_bypass) +jarvis_test(stdio test_hermes_stdio_adapter_default) +jarvis_test(stdio test_hermes_stdio_adapter_scratch) set(STDIO_TESTS - stdio_adapter_mapper_test - stdio_adapter_test - hermes_stdio_adapter_test - hermes_stdio_low_buf_adapter_test - hermes_stdio_adapter_mode_test - stdio_adapter_mpi_test - hermes_stdio_adapter_mpi_test + stdio_adapter_test + hermes_stdio_adapter_test + hermes_stdio_low_buf_adapter_test + hermes_stdio_adapter_mapper_test + hermes_stdio_adapter_mode_test + stdio_adapter_mpi_test + hermes_stdio_adapter_mpi_test ) foreach(program ${STDIO_TESTS}) diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_basic_test.cc b/test/unit/hermes_adapters/stdio/stdio_adapter_basic_test.cc new file mode 100644 index 000000000..ca2f300d0 --- /dev/null +++ b/test/unit/hermes_adapters/stdio/stdio_adapter_basic_test.cc @@ -0,0 +1,1377 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "stdio_adapter_test.h" + +TEST_CASE("Open", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_open]" + "[repetition=1][file=1]") { + TESTER->Pretest(); + SECTION("open non-existant file") { + TESTER->test_fopen(TESTER->new_file_, "r"); + REQUIRE(TESTER->fh_orig_ == nullptr); + TESTER->test_fopen(TESTER->new_file_, "r+"); + REQUIRE(TESTER->fh_orig_ == nullptr); + } + + SECTION("truncate existing file and write-only") { + TESTER->test_fopen(TESTER->existing_file_, "w"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("truncate existing file and read/write") { + TESTER->test_fopen(TESTER->existing_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("open existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fopen(TESTER->existing_file_, "r"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("append write existing file") { + TESTER->test_fopen(TESTER->existing_file_, "a"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("append write and read existing file") { + TESTER->test_fopen(TESTER->existing_file_, "a+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("SingleWrite", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_write]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fwrite(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("write to new file") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->size_written_orig_); + } + + SECTION("write to existing file with truncate") { + TESTER->test_fopen(TESTER->existing_file_, "w"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fwrite(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->existing_file_.hermes_) == + TESTER->size_written_orig_); + } + + SECTION("write to existing file at the end") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fseek(0, SEEK_END); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == TESTER->request_size_ * TESTER->num_iterations_); + TESTER->test_fwrite(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->existing_file_.hermes_) == + TESTER->size_written_orig_ + offset); + } + + SECTION("append to existing file") { + auto existing_size = stdfs::file_size(TESTER->existing_file_.hermes_); + TESTER->test_fopen(TESTER->existing_file_, "a+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fwrite(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->existing_file_.hermes_) == + existing_size + TESTER->size_written_orig_); + } + + SECTION("append to new file") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fwrite(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->size_written_orig_); + } + TESTER->Posttest(); +} + +TEST_CASE("SingleRead", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_read]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + SECTION("read from non-existing file") { + TESTER->test_fopen(TESTER->new_file_, "r"); + REQUIRE(TESTER->fh_orig_ == nullptr); + } + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + TESTER->test_fread(TESTER->read_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("read at the end of existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r"); + REQUIRE(TESTER->fh_orig_ != nullptr); + TESTER->test_fseek(0, SEEK_END); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == TESTER->request_size_ * TESTER->num_iterations_); + TESTER->test_fread(TESTER->read_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == 0); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedWriteSequential", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("write to new file always at beginning") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + TESTER->test_fwrite(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->request_size_); + } + + SECTION("write to new file sequentially") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fwrite(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->num_iterations_ * TESTER->request_size_); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequential", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_fopen(TESTER->existing_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadRandom", "[process=" + + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + + "][pattern=random][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateRandom", "[process=" + + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_update]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=random][file=1]") { + TESTER->Pretest(); + SECTION("update into existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + fflush(TESTER->fh_orig_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideFixed", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = (i * TESTER->stride_size_) % TESTER->total_size_; + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixed", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_update]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + + SECTION("update from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = (i * TESTER->stride_size_) % TESTER->total_size_; + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideDynamic", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamic", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_update]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("update from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->GetRandomOffset(i, TESTER->offset_seed_, + TESTER->stride_size_, + TESTER->total_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedWriteRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + + SECTION("write to new file always at the start") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t biggest_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->offset_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + if (biggest_written < request_size) biggest_written = request_size; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == biggest_written); + } + + SECTION("write to new file") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t total_test_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->offset_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + total_test_written += TESTER->size_written_orig_; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + total_test_written); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequentialRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = (TESTER->request_size_ + + (rand_r(&TESTER->offset_seed_) % TESTER->request_size_)) % + (TESTER->total_size_ - current_offset); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + current_offset += TESTER->size_read_orig_; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_fopen(TESTER->existing_file_, "r"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->offset_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadRandomRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-variable]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + + "][pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + (TESTER->request_size_ + + (rand_r(&TESTER->rs_seed_) % TESTER->request_size_)) % + (TESTER->total_size_ - offset); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_update]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->rs_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = (i * TESTER->stride_size_) % TESTER->total_size_; + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + (TESTER->request_size_ + + (rand_r(&TESTER->rs_seed_) % TESTER->request_size_)) % + (TESTER->total_size_ - offset); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_update]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = (i * TESTER->stride_size_) % TESTER->total_size_; + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->rs_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->GetRandomOffset(i, TESTER->offset_seed_, + TESTER->stride_size_, + TESTER->total_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->rs_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_update]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->GetRandomOffset(i, TESTER->offset_seed_, + TESTER->stride_size_, + TESTER->total_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->request_size_ + + (rand_r(&TESTER->rs_seed_) % TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideNegative", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + size_t prev_offset = TESTER->total_size_ + 1; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto stride_offset = TESTER->total_size_ - i * TESTER->stride_size_; + REQUIRE(prev_offset > stride_offset); + prev_offset = stride_offset; + auto offset = (stride_offset) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegative", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_update]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + TESTER->total_size_ - TESTER->request_size_ - + ((i * TESTER->stride_size_) % TESTER->total_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = (TESTER->total_size_ - i * TESTER->stride_size_) % + (TESTER->total_size_ - 2 * TESTER->request_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + (TESTER->request_size_ + (rand_r(&TESTER->rs_seed_) % + TESTER->request_size_)) % + (TESTER->total_size_ - offset); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_update]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + TESTER->total_size_ - ((i * TESTER->stride_size_) % + TESTER->total_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->request_size_ + (rand_r(&TESTER->rs_seed_) % + TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStride2D", "[process=" + + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStride2D", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_update]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->request_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStride2DRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "" + "[operation=batched_read]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - 2 * TESTER->request_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + (TESTER->request_size_ + (rand_r(&TESTER->rs_seed_) % + TESTER->request_size_)) % + (TESTER->total_size_ - offset); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_update]" + "[request_size=type-variable][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - 2 * TESTER->request_size_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->request_size_ + (rand_r(&TESTER->rs_seed_) % + TESTER->request_size_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.c_str(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +/** + * Temporal Fixed + */ + +TEST_CASE("BatchedWriteTemporalFixed", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1][temporal=fixed]") { + TESTER->Pretest(); + + SECTION("write to existing file always at start") { + TESTER->test_fopen(TESTER->existing_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->existing_file_.hermes_) == + TESTER->request_size_); + } + + SECTION("write to new file always at start") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->request_size_); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequentialTemporalFixed", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1][temporal=fixed]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + TESTER->test_fread(TESTER->read_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedWriteTemporalVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1][temporal=variable]") { + TESTER->Pretest(); + + SECTION("write to existing file always at start") { + TESTER->test_fopen(TESTER->existing_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->temporal_interval_ms_ = + rand_r(&TESTER->temporal_interval_seed_) % + TESTER->temporal_interval_ms_ + 1; + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->existing_file_.hermes_) == + TESTER->request_size_); + } + + SECTION("write to new file") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->temporal_interval_ms_ = + rand_r(&TESTER->temporal_interval_seed_) % + TESTER->temporal_interval_ms_ + 1; + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->num_iterations_ * TESTER->request_size_); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequentialTemporalVariable", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1][temporal=variable]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->temporal_interval_ms_ = + rand_r(&TESTER->temporal_interval_seed_) % + TESTER->temporal_interval_ms_ + 1; + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->temporal_interval_ms_ = + rand_r(&TESTER->temporal_interval_seed_) % + TESTER->temporal_interval_ms_ + 1; + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + TESTER->test_fread(TESTER->read_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedMixedSequential", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_mixed]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("read after write on new file") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t last_offset = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_fseek(last_offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fread(TESTER->read_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + last_offset += TESTER->request_size_; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("write and read alternative existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + if (i % 2 == 0) { + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } else { + TESTER->test_fread(TESTER->read_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("update after read existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t last_offset = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fread(TESTER->read_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_fseek(last_offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + last_offset += TESTER->request_size_; + } + + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("read all after write all on new file in single open") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fread(TESTER->read_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("read all after write all on new file in different open") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fopen(TESTER->new_file_, "r"); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fread(TESTER->read_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("SingleMixed", "[process=" + std::to_string(TESTER->comm_size_) + + "][operation=single_mixed]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); + SECTION("read after write from new file") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fread(TESTER->read_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("update after read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + TESTER->test_fread(TESTER->read_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + SECTION("read after write from new file different opens") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + TESTER->test_fwrite(TESTER->write_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + TESTER->test_fopen(TESTER->new_file_, "r+"); + TESTER->test_fread(TESTER->read_data_.data(), + TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_basic_test.cpp b/test/unit/hermes_adapters/stdio/stdio_adapter_basic_test.cpp deleted file mode 100644 index b53ec4d0e..000000000 --- a/test/unit/hermes_adapters/stdio/stdio_adapter_basic_test.cpp +++ /dev/null @@ -1,1309 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -TEST_CASE("Open", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_open]" - "[repetition=1][file=1]") { - pretest(); - SECTION("open non-existant file") { - test::test_fopen(info.new_file.c_str(), "r"); - REQUIRE(test::fh_orig == nullptr); - test::test_fopen(info.new_file.c_str(), "r+"); - REQUIRE(test::fh_orig == nullptr); - } - - SECTION("truncate existing file and write-only") { - test::test_fopen(info.existing_file.c_str(), "w"); - REQUIRE(test::fh_orig != nullptr); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("truncate existing file and read/write") { - test::test_fopen(info.existing_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("open existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("append write existing file") { - test::test_fopen(info.existing_file.c_str(), "a"); - REQUIRE(test::fh_orig != nullptr); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("append write and read existing file") { - test::test_fopen(info.existing_file.c_str(), "a+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("write to new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == test::size_written_orig); - } - - SECTION("write to existing file with truncate") { - test::test_fopen(info.existing_file.c_str(), "w"); - REQUIRE(test::fh_orig != nullptr); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.existing_file) == test::size_written_orig); - } - - SECTION("write to existing file at the end") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fseek(0, SEEK_END); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == args.request_size * info.num_iterations); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.existing_file) == - test::size_written_orig + offset); - } - - SECTION("append to existing file") { - auto existing_size = stdfs::file_size(info.existing_file); - test::test_fopen(info.existing_file.c_str(), "a+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.existing_file) == - existing_size + test::size_written_orig); - } - - SECTION("append to new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == test::size_written_orig); - } - posttest(); -} - -TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read from non-existing file") { - test::test_fopen(info.new_file.c_str(), "r"); - REQUIRE(test::fh_orig == nullptr); - } - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("read at the end of existing file") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - test::test_fseek(0, SEEK_END); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == args.request_size * info.num_iterations); - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == 0); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedWriteSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at beginning") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == args.request_size); - } - - SECTION("write to new file sequentially") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedReadSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - SECTION("update into existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - fflush(test::fh_orig); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % info.total_size; - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("update from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % info.total_size; - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamic", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamic", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("update from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedWriteRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - - SECTION("write to new file always at the start") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t biggest_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - args.request_size + (rand_r(&info.offset_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_written < request_size) biggest_written = request_size; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_written); - } - - SECTION("write to new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t total_test_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - args.request_size + (rand_r(&info.offset_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_test_written += test::size_written_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_test_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = (args.request_size + - (rand_r(&info.offset_seed) % args.request_size)) % - (info.total_size - current_offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - args.request_size + (rand_r(&info.offset_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % info.total_size; - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % info.total_size; - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegative", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t prev_offset = info.total_size + 1; - for (size_t i = 0; i < info.num_iterations; ++i) { - auto stride_offset = info.total_size - i * info.stride_size; - REQUIRE(prev_offset > stride_offset); - prev_offset = stride_offset; - auto offset = (stride_offset) % (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegative", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - info.total_size - args.request_size - - ((i * info.stride_size) % info.total_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (info.total_size - i * info.stride_size) % - (info.total_size - 2 * args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - info.total_size - ((i * info.stride_size) % info.total_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2D", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2D", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "" - "[operation=batched_read]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - 2 * args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - (args.request_size + (rand_r(&info.rs_seed) % args.request_size)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_update]" - "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - 2 * args.request_size); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - args.request_size + (rand_r(&info.rs_seed) % args.request_size); - std::string data(request_size, '1'); - test::test_fwrite(data.c_str(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -/** - * Temporal Fixed - */ - -TEST_CASE("BatchedWriteTemporalFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=fixed]") { - pretest(); - - SECTION("write to existing file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == args.request_size); - } - - SECTION("write to new file always at start") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialTemporalFixed", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=fixed]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedWriteTemporalVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=variable]") { - pretest(); - - SECTION("write to existing file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == args.request_size); - } - - SECTION("write to new file always at start") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialTemporalVariable", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1][temporal=variable]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - info.temporal_interval_ms = - rand_r(&info.temporal_interval_seed) % info.temporal_interval_ms + 1; - usleep(info.temporal_interval_ms * 1000); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedMixedSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_mixed]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read after write on new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t last_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fseek(last_offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - last_offset += args.request_size; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("write and read alternative existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - if (i % 2 == 0) { - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } else { - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("update after read existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t last_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_fseek(last_offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - last_offset += args.request_size; - } - - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("read all after write all on new file in single open") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("read all after write all on new file in different open") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - test::test_fopen(info.new_file.c_str(), "r"); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("SingleMixed", "[process=" + std::to_string(info.comm_size) + - "][operation=single_mixed]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - pretest(); - SECTION("read after write from new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("update after read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - SECTION("read after write from new file different opens") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - test::test_fwrite(info.write_data.data(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - test::test_fopen(info.new_file.c_str(), "r+"); - test::test_fread(info.read_data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_func_test.cpp b/test/unit/hermes_adapters/stdio/stdio_adapter_func_test.cc similarity index 50% rename from test/unit/hermes_adapters/stdio/stdio_adapter_func_test.cpp rename to test/unit/hermes_adapters/stdio/stdio_adapter_func_test.cc index b3dda30a5..597dcf244 100644 --- a/test/unit/hermes_adapters/stdio/stdio_adapter_func_test.cpp +++ b/test/unit/hermes_adapters/stdio/stdio_adapter_func_test.cc @@ -10,48 +10,50 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -TEST_CASE("FFlush", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fflush]" - "[repetition=1][file=1]") { - pretest(); +#include "stdio_adapter_test.h" + +TEST_CASE("FFlush", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_fflush]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("Flushing contents of file in different modes") { - FILE* fd = fopen(info.existing_file.c_str(), "w"); + FILE* fd = fopen(TESTER->existing_file_.hermes_.c_str(), "w"); REQUIRE(fd != nullptr); int status = fflush(fd); REQUIRE(status == 0); status = fclose(fd); REQUIRE(status == 0); - fd = fopen(info.existing_file.c_str(), "w+"); + fd = fopen(TESTER->existing_file_.hermes_.c_str(), "w+"); REQUIRE(fd != nullptr); status = fflush(fd); REQUIRE(status == 0); status = fclose(fd); REQUIRE(status == 0); - fd = fopen(info.existing_file.c_str(), "r+"); + fd = fopen(TESTER->existing_file_.hermes_.c_str(), "r+"); REQUIRE(fd != nullptr); status = fflush(fd); REQUIRE(status == 0); status = fclose(fd); REQUIRE(status == 0); - fd = fopen(info.existing_file.c_str(), "r"); + fd = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fd != nullptr); status = fflush(fd); REQUIRE(status == 0); status = fclose(fd); REQUIRE(status == 0); - fd = fopen(info.existing_file.c_str(), "a"); + fd = fopen(TESTER->existing_file_.hermes_.c_str(), "a"); REQUIRE(fd != nullptr); status = fflush(fd); REQUIRE(status == 0); status = fclose(fd); REQUIRE(status == 0); - fd = fopen(info.existing_file.c_str(), "a+"); + fd = fopen(TESTER->existing_file_.hermes_.c_str(), "a+"); REQUIRE(fd != nullptr); status = fflush(fd); REQUIRE(status == 0); @@ -62,23 +64,24 @@ TEST_CASE("FFlush", "[process=" + std::to_string(info.comm_size) + int status = fflush(nullptr); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("Fdopen", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fdopen]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("Fdopen", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_fdopen]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("Associate a FILE ptr with read mode") { - int fd = open(info.existing_file.c_str(), O_RDWR); + int fd = open(TESTER->existing_file_.hermes_.c_str(), O_RDWR); REQUIRE(fd != -1); FILE* fh = fdopen(fd, "r"); REQUIRE(fh != nullptr); size_t read_size = - fread(info.read_data.data(), sizeof(char), args.request_size, fh); - REQUIRE(read_size == args.request_size); + fread(TESTER->read_data_.data(), + sizeof(char), TESTER->request_size_, fh); + REQUIRE(read_size == TESTER->request_size_); int status = fclose(fh); REQUIRE(status == 0); @@ -89,14 +92,15 @@ TEST_CASE("Fdopen", "[process=" + std::to_string(info.comm_size) + REQUIRE(status == -1); } SECTION("Associate a FILE ptr with write mode") { - int fd = open(info.existing_file.c_str(), O_RDWR); + int fd = open(TESTER->existing_file_.hermes_.c_str(), O_RDWR); REQUIRE(fd != -1); FILE* fh = fdopen(fd, "w"); REQUIRE(fh != nullptr); size_t write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fh); - REQUIRE(write_size == args.request_size); + fwrite(TESTER->write_data_.data(), + sizeof(char), TESTER->request_size_, fh); + REQUIRE(write_size == TESTER->request_size_); int status = fclose(fh); REQUIRE(status == 0); @@ -104,14 +108,15 @@ TEST_CASE("Fdopen", "[process=" + std::to_string(info.comm_size) + REQUIRE(status == -1); } SECTION("Associate a FILE ptr with read plus mode") { - int fd = open(info.existing_file.c_str(), O_RDWR); + int fd = open(TESTER->existing_file_.hermes_.c_str(), O_RDWR); REQUIRE(fd != -1); FILE* fh = fdopen(fd, "r"); REQUIRE(fh != nullptr); size_t read_size = - fread(info.read_data.data(), sizeof(char), args.request_size, fh); - REQUIRE(read_size == args.request_size); + fread(TESTER->read_data_.data(), + sizeof(char), TESTER->request_size_, fh); + REQUIRE(read_size == TESTER->request_size_); int status = fclose(fh); REQUIRE(status == 0); @@ -122,14 +127,15 @@ TEST_CASE("Fdopen", "[process=" + std::to_string(info.comm_size) + REQUIRE(status == -1); } SECTION("Associate a FILE ptr with write plus mode") { - int fd = open(info.existing_file.c_str(), O_RDWR); + int fd = open(TESTER->existing_file_.hermes_.c_str(), O_RDWR); REQUIRE(fd != -1); FILE* fh = fdopen(fd, "w+"); REQUIRE(fh != nullptr); size_t write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fh); - REQUIRE(write_size == args.request_size); + fwrite(TESTER->write_data_.data(), + sizeof(char), TESTER->request_size_, fh); + REQUIRE(write_size == TESTER->request_size_); int status = fclose(fh); REQUIRE(status == 0); @@ -140,14 +146,15 @@ TEST_CASE("Fdopen", "[process=" + std::to_string(info.comm_size) + REQUIRE(status == -1); } SECTION("Associate a FILE ptr with append mode") { - int fd = open(info.existing_file.c_str(), O_RDWR | O_APPEND); + int fd = open(TESTER->existing_file_.hermes_.c_str(), O_RDWR | O_APPEND); REQUIRE(fd != -1); FILE* fh = fdopen(fd, "a"); REQUIRE(fh != nullptr); size_t write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fh); - REQUIRE(write_size == args.request_size); + fwrite(TESTER->write_data_.data(), + sizeof(char), TESTER->request_size_, fh); + REQUIRE(write_size == TESTER->request_size_); int status = fclose(fh); REQUIRE(status == 0); @@ -158,14 +165,15 @@ TEST_CASE("Fdopen", "[process=" + std::to_string(info.comm_size) + REQUIRE(status == -1); } SECTION("Associate a FILE ptr with append plus mode") { - int fd = open(info.existing_file.c_str(), O_RDWR | O_APPEND); + int fd = open(TESTER->existing_file_.hermes_.c_str(), O_RDWR | O_APPEND); REQUIRE(fd != -1); FILE* fh = fdopen(fd, "a+"); REQUIRE(fh != nullptr); size_t write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fh); - REQUIRE(write_size == args.request_size); + fwrite(TESTER->write_data_.data(), + sizeof(char), TESTER->request_size_, fh); + REQUIRE(write_size == TESTER->request_size_); int status = fclose(fh); REQUIRE(status == 0); @@ -176,14 +184,15 @@ TEST_CASE("Fdopen", "[process=" + std::to_string(info.comm_size) + REQUIRE(status == -1); } SECTION("Associate a FILE ptr with read mode twice") { - int fd = open(info.existing_file.c_str(), O_RDWR); + int fd = open(TESTER->existing_file_.hermes_.c_str(), O_RDWR); REQUIRE(fd != -1); FILE* fh = fdopen(fd, "r"); REQUIRE(fh != nullptr); size_t read_size = - fread(info.read_data.data(), sizeof(char), args.request_size, fh); - REQUIRE(read_size == args.request_size); + fread(TESTER->read_data_.data(), + sizeof(char), TESTER->request_size_, fh); + REQUIRE(read_size == TESTER->request_size_); int status = fclose(fh); REQUIRE(status == 0); @@ -192,14 +201,15 @@ TEST_CASE("Fdopen", "[process=" + std::to_string(info.comm_size) + REQUIRE(status == -1); } SECTION("Associate a FILE ptr with read mode twice after one closes") { - int fd = open(info.existing_file.c_str(), O_RDWR); + int fd = open(TESTER->existing_file_.hermes_.c_str(), O_RDWR); REQUIRE(fd != -1); FILE* fh = fdopen(fd, "r"); REQUIRE(fh != nullptr); size_t read_size = - fread(info.read_data.data(), sizeof(char), args.request_size, fh); - REQUIRE(read_size == args.request_size); + fread(TESTER->read_data_.data(), + sizeof(char), TESTER->request_size_, fh); + REQUIRE(read_size == TESTER->request_size_); int status = fcntl(fd, F_GETFD); REQUIRE(fd != -1); @@ -213,144 +223,148 @@ TEST_CASE("Fdopen", "[process=" + std::to_string(info.comm_size) + status = close(fd); REQUIRE(status == -1); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("Freopen", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_freopen]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("Freopen", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_freopen]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("change different modes") { - FILE* fhr = fopen(info.existing_file.c_str(), "r"); + FILE* fhr = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fhr != nullptr); - FILE* fhw = freopen(info.existing_file.c_str(), "w", fhr); + FILE* fhw = freopen(TESTER->existing_file_.hermes_.c_str(), "w", fhr); REQUIRE(fhw != nullptr); size_t write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhw); - REQUIRE(write_size == args.request_size); + fwrite(TESTER->write_data_.data(), + sizeof(char), TESTER->request_size_, fhw); + REQUIRE(write_size == TESTER->request_size_); - FILE* fhwp = freopen(info.existing_file.c_str(), "w+", fhw); + FILE* fhwp = freopen(TESTER->existing_file_.hermes_.c_str(), "w+", fhw); REQUIRE(fhwp != nullptr); write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhwp); - REQUIRE(write_size == args.request_size); + fwrite(TESTER->write_data_.data(), + sizeof(char), TESTER->request_size_, fhwp); + REQUIRE(write_size == TESTER->request_size_); - FILE* fha = freopen(info.existing_file.c_str(), "a", fhwp); + FILE* fha = freopen(TESTER->existing_file_.hermes_.c_str(), "a", fhwp); REQUIRE(fha != nullptr); write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhwp); - REQUIRE(write_size == args.request_size); + fwrite(TESTER->write_data_.data(), + sizeof(char), TESTER->request_size_, fhwp); + REQUIRE(write_size == TESTER->request_size_); - FILE* fhap = freopen(info.existing_file.c_str(), "a+", fha); + FILE* fhap = freopen(TESTER->existing_file_.hermes_.c_str(), "a+", fha); REQUIRE(fhap != nullptr); write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhap); - REQUIRE(write_size == args.request_size); + fwrite(TESTER->write_data_.data(), + sizeof(char), TESTER->request_size_, fhap); + REQUIRE(write_size == TESTER->request_size_); int status = fclose(fhap); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("fgetc", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_fgetc]" - "[repetition=" + - std::to_string(info.num_iterations) + "][file=1]") { - pretest(); +TEST_CASE("fgetc", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_fgetc]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + "][file=1]") { + TESTER->Pretest(); SECTION("iterate and get all characters") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); size_t total_chars = 0; int c = '0'; do { c = fgetc(fh); total_chars++; - if (total_chars >= info.num_iterations) break; + if (total_chars >= TESTER->num_iterations_) break; } while (c != EOF); - REQUIRE(total_chars == info.num_iterations); + REQUIRE(total_chars == TESTER->num_iterations_); int status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("getc", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_getc]" - "[repetition=" + - std::to_string(info.num_iterations) + "][file=1]") { - pretest(); +TEST_CASE("getc", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_getc]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + "][file=1]") { + TESTER->Pretest(); SECTION("iterate and get all characters") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); size_t total_chars = 0; int c = '0'; do { c = getc(fh); total_chars++; - if (total_chars >= info.num_iterations) break; + if (total_chars >= TESTER->num_iterations_) break; } while (c != EOF); - REQUIRE(total_chars == info.num_iterations); + REQUIRE(total_chars == TESTER->num_iterations_); int status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("getw", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_getw]" - "[repetition=" + - std::to_string(info.num_iterations) + "][file=1]") { - pretest(); +TEST_CASE("getw", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_getw]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + "][file=1]") { + TESTER->Pretest(); SECTION("iterate and get all characters") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); size_t total_chars = 0; int c = '0'; do { c = getw(fh); total_chars++; - if (total_chars >= info.num_iterations) break; + if (total_chars >= TESTER->num_iterations_) break; } while (c != EOF); - REQUIRE(total_chars == info.num_iterations); + REQUIRE(total_chars == TESTER->num_iterations_); int status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("fgets", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fgets]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("fgets", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_fgets]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("iterate and get all characters") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); - auto ret_str = fgets(info.read_data.data(), args.request_size, fh); + auto ret_str = fgets(TESTER->read_data_.data(), TESTER->request_size_, fh); REQUIRE(ret_str != NULL); - REQUIRE(strlen(ret_str) == args.request_size - 1); + REQUIRE(strlen(ret_str) == TESTER->request_size_ - 1); int status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("fputc", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_fputc]" - "[repetition=" + - std::to_string(info.num_iterations) + "][file=1]") { - pretest(); +TEST_CASE("fputc", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_fputc]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + "][file=1]") { + TESTER->Pretest(); SECTION("iterate and get all characters") { - FILE* fh = fopen(info.new_file.c_str(), "w+"); + FILE* fh = fopen(TESTER->new_file_.hermes_.c_str(), "w+"); REQUIRE(fh != nullptr); - size_t total_chars = info.num_iterations; + size_t total_chars = TESTER->num_iterations_; char c = 'w'; for (size_t i = 0; i < total_chars; ++i) { int ret_char = fputc(c, fh); @@ -359,19 +373,19 @@ TEST_CASE("fputc", "[process=" + std::to_string(info.comm_size) + int status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("putc", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_putc]" - "[repetition=" + - std::to_string(info.num_iterations) + "][file=1]") { - pretest(); +TEST_CASE("putc", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_putc]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + "][file=1]") { + TESTER->Pretest(); SECTION("iterate and get all characters") { - FILE* fh = fopen(info.new_file.c_str(), "w+"); + FILE* fh = fopen(TESTER->new_file_.hermes_.c_str(), "w+"); REQUIRE(fh != nullptr); - size_t total_chars = info.num_iterations; + size_t total_chars = TESTER->num_iterations_; char c = 'w'; for (size_t i = 0; i < total_chars; ++i) { int ret_char = putc(c, fh); @@ -380,18 +394,18 @@ TEST_CASE("putc", "[process=" + std::to_string(info.comm_size) + int status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("putw", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_putw]" - "[repetition=" + - std::to_string(info.num_iterations) + "][file=1]") { - pretest(); +TEST_CASE("putw", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_putw]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + "][file=1]") { + TESTER->Pretest(); SECTION("iterate and get all characters") { - FILE* fh = fopen(info.new_file.c_str(), "w+"); + FILE* fh = fopen(TESTER->new_file_.hermes_.c_str(), "w+"); REQUIRE(fh != nullptr); - size_t total_chars = info.num_iterations; + size_t total_chars = TESTER->num_iterations_; int c = 'w'; for (size_t i = 0; i < total_chars; ++i) { int ret = putw(c, fh); @@ -400,32 +414,32 @@ TEST_CASE("putw", "[process=" + std::to_string(info.comm_size) + int status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("fputs", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fputs]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("fputs", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_fputs]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("iterate and get all characters") { - FILE* fh = fopen(info.existing_file.c_str(), "w+"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "w+"); REQUIRE(fh != nullptr); - int status = fputs(info.write_data.c_str(), fh); + int status = fputs(TESTER->write_data_.data(), fh); REQUIRE(status != -1); status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("fseek", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fseek]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("fseek", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_fseek]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); int status = fseek(fh, 0, SEEK_SET); REQUIRE(status == 0); @@ -440,26 +454,26 @@ TEST_CASE("fseek", "[process=" + std::to_string(info.comm_size) + status = fseek(fh, 0, SEEK_END); REQUIRE(status == 0); offset = ftell(fh); - REQUIRE(offset == info.total_size); + REQUIRE(offset == TESTER->total_size_); status = fseek(fh, 0, SEEK_CUR); REQUIRE(status == 0); offset = ftell(fh); - REQUIRE(offset == info.total_size); + REQUIRE(offset == TESTER->total_size_); status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("fseeko", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fseeko]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("fseeko", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_fseeko]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); int status = fseeko(fh, 0, SEEK_SET); REQUIRE(status == 0); @@ -474,26 +488,26 @@ TEST_CASE("fseeko", "[process=" + std::to_string(info.comm_size) + status = fseeko(fh, 0, SEEK_END); REQUIRE(status == 0); offset = ftell(fh); - REQUIRE(offset == info.total_size); + REQUIRE(offset == TESTER->total_size_); status = fseeko(fh, 0, SEEK_CUR); REQUIRE(status == 0); offset = ftell(fh); - REQUIRE(offset == info.total_size); + REQUIRE(offset == TESTER->total_size_); status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("fseeko64", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fseeko64]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("fseeko64", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_fseeko64]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); int status = fseeko64(fh, 0, SEEK_SET); REQUIRE(status == 0); @@ -508,26 +522,26 @@ TEST_CASE("fseeko64", "[process=" + std::to_string(info.comm_size) + status = fseeko64(fh, 0, SEEK_END); REQUIRE(status == 0); offset = ftell(fh); - REQUIRE(offset == info.total_size); + REQUIRE(offset == TESTER->total_size_); status = fseeko64(fh, 0, SEEK_CUR); REQUIRE(status == 0); offset = ftell(fh); - REQUIRE(offset == info.total_size); + REQUIRE(offset == TESTER->total_size_); status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("rewind", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_rewind]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("rewind", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_rewind]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); int status = fseeko(fh, 0, SEEK_SET); REQUIRE(status == 0); @@ -540,7 +554,7 @@ TEST_CASE("rewind", "[process=" + std::to_string(info.comm_size) + status = fseeko(fh, 0, SEEK_END); REQUIRE(status == 0); offset = ftell(fh); - REQUIRE(offset == info.total_size); + REQUIRE(offset == TESTER->total_size_); rewind(fh); offset = ftell(fh); REQUIRE(offset == 0); @@ -548,16 +562,16 @@ TEST_CASE("rewind", "[process=" + std::to_string(info.comm_size) + status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("fsetpos", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fsetpos]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("fsetpos", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_fsetpos]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); fpos_t position; fgetpos(fh, &position); @@ -568,25 +582,25 @@ TEST_CASE("fsetpos", "[process=" + std::to_string(info.comm_size) + size_t offset = ftell(fh); REQUIRE(offset == 0); - position.__pos = info.total_size; + position.__pos = TESTER->total_size_; status = fsetpos(fh, &position); REQUIRE(status == 0); offset = ftell(fh); - REQUIRE(offset == info.total_size); + REQUIRE(offset == TESTER->total_size_); status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("fsetpos64", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fsetpos64]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("fsetpos64", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_fsetpos64]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); fpos64_t position; fgetpos64(fh, &position); @@ -597,25 +611,25 @@ TEST_CASE("fsetpos64", "[process=" + std::to_string(info.comm_size) + size_t offset = ftell(fh); REQUIRE(offset == 0); - position.__pos = info.total_size; + position.__pos = TESTER->total_size_; status = fsetpos64(fh, &position); REQUIRE(status == 0); offset = ftell(fh); - REQUIRE(offset == info.total_size); + REQUIRE(offset == TESTER->total_size_); status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("fgetpos", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fgetpos]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("fgetpos", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_fgetpos]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); fpos_t position; @@ -627,21 +641,21 @@ TEST_CASE("fgetpos", "[process=" + std::to_string(info.comm_size) + status = fseek(fh, 0, SEEK_END); REQUIRE(status == 0); status = fgetpos(fh, &position); - REQUIRE(position.__pos == (long int)info.total_size); + REQUIRE(position.__pos == (long int)TESTER->total_size_); status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("fgetpos64", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_fgetpos64]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("fgetpos64", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_fgetpos64]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("test all seek modes") { - FILE* fh = fopen(info.existing_file.c_str(), "r"); + FILE* fh = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); fpos64_t position; @@ -653,119 +667,123 @@ TEST_CASE("fgetpos64", "[process=" + std::to_string(info.comm_size) + status = fseek(fh, 0, SEEK_END); REQUIRE(status == 0); status = fgetpos64(fh, &position); - REQUIRE(position.__pos == (long int)info.total_size); + REQUIRE(position.__pos == (long int)TESTER->total_size_); status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("Open64", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_open]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("Open64", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_open]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("open non-existant file") { - FILE* fh = fopen64(info.new_file.c_str(), "r"); + FILE* fh = fopen64(TESTER->new_file_.hermes_.c_str(), "r"); REQUIRE(fh == nullptr); - fh = fopen64(info.new_file.c_str(), "r+"); + fh = fopen64(TESTER->new_file_.hermes_.c_str(), "r+"); REQUIRE(fh == nullptr); } SECTION("truncate existing file and write-only") { - FILE* fh = fopen64(info.existing_file.c_str(), "w"); + FILE* fh = fopen64(TESTER->existing_file_.hermes_.c_str(), "w"); REQUIRE(fh != nullptr); int status = fclose(fh); REQUIRE(status == 0); } SECTION("truncate existing file and read/write") { - FILE* fh = fopen64(info.existing_file.c_str(), "w+"); + FILE* fh = fopen64(TESTER->existing_file_.hermes_.c_str(), "w+"); REQUIRE(fh != nullptr); int status = fclose(fh); REQUIRE(status == 0); } SECTION("open existing file") { - FILE* fh = fopen64(info.existing_file.c_str(), "r+"); + FILE* fh = fopen64(TESTER->existing_file_.hermes_.c_str(), "r+"); REQUIRE(fh != nullptr); int status = fclose(fh); REQUIRE(status == 0); - fh = fopen64(info.existing_file.c_str(), "r"); + fh = fopen64(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh != nullptr); status = fclose(fh); REQUIRE(status == 0); } SECTION("append write existing file") { - FILE* fh = fopen64(info.existing_file.c_str(), "a"); + FILE* fh = fopen64(TESTER->existing_file_.hermes_.c_str(), "a"); REQUIRE(fh != nullptr); int status = fclose(fh); REQUIRE(status == 0); } SECTION("append write and read existing file") { - FILE* fh = fopen64(info.existing_file.c_str(), "a+"); + FILE* fh = fopen64(TESTER->existing_file_.hermes_.c_str(), "a+"); REQUIRE(fh != nullptr); int status = fclose(fh); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("Freopen64", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_freopen]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("Freopen64", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_freopen]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("change different modes") { - FILE* fhr = fopen(info.existing_file.c_str(), "r"); + FILE* fhr = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fhr != nullptr); - FILE* fhw = freopen64(info.existing_file.c_str(), "w", fhr); + FILE* fhw = freopen64(TESTER->existing_file_.hermes_.c_str(), "w", fhr); REQUIRE(fhw != nullptr); size_t write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhw); - REQUIRE(write_size == args.request_size); + fwrite(TESTER->write_data_.data(), + sizeof(char), TESTER->request_size_, fhw); + REQUIRE(write_size == TESTER->request_size_); - FILE* fhwp = freopen64(info.existing_file.c_str(), "w+", fhw); + FILE* fhwp = freopen64(TESTER->existing_file_.hermes_.c_str(), "w+", fhw); REQUIRE(fhwp != nullptr); write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhwp); - REQUIRE(write_size == args.request_size); + fwrite(TESTER->write_data_.data(), + sizeof(char), TESTER->request_size_, fhwp); + REQUIRE(write_size == TESTER->request_size_); - FILE* fha = freopen64(info.existing_file.c_str(), "a", fhwp); + FILE* fha = freopen64(TESTER->existing_file_.hermes_.c_str(), "a", fhwp); REQUIRE(fha != nullptr); write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhwp); - REQUIRE(write_size == args.request_size); + fwrite(TESTER->write_data_.data(), + sizeof(char), TESTER->request_size_, fhwp); + REQUIRE(write_size == TESTER->request_size_); - FILE* fhap = freopen64(info.existing_file.c_str(), "a+", fha); + FILE* fhap = freopen64(TESTER->existing_file_.hermes_.c_str(), "a+", fha); REQUIRE(fhap != nullptr); write_size = - fwrite(info.write_data.c_str(), sizeof(char), args.request_size, fhap); - REQUIRE(write_size == args.request_size); + fwrite(TESTER->write_data_.data(), + sizeof(char), TESTER->request_size_, fhap); + REQUIRE(write_size == TESTER->request_size_); int status = fclose(fhap); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } -TEST_CASE("MultiOpen", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=multi_open]" - "[repetition=1][file=1]") { - pretest(); +TEST_CASE("MultiOpen", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=multi_open]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("Open same file twice and then close both fps") { - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); + FILE* fh1 = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh1 != nullptr); - FILE* fh2 = fopen(info.existing_file.c_str(), "r"); + FILE* fh2 = fopen(TESTER->existing_file_.hermes_.c_str(), "r"); REQUIRE(fh2 != nullptr); int status = fclose(fh1); REQUIRE(status == 0); status = fclose(fh2); REQUIRE(status == 0); } - posttest(false); + TESTER->Posttest(false); } diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_low_buffer_space_test.cc b/test/unit/hermes_adapters/stdio/stdio_adapter_low_buffer_space_test.cc new file mode 100644 index 000000000..c471a338e --- /dev/null +++ b/test/unit/hermes_adapters/stdio/stdio_adapter_low_buffer_space_test.cc @@ -0,0 +1,49 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "stdio_adapter_test.h" + +TEST_CASE("LowBufferSpace", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("write to new file one big write") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + auto write_size = TESTER->request_size_ * (TESTER->num_iterations_ + 1); + TESTER->write_data_ = TESTER->GenRandom(write_size); + TESTER->test_fwrite(TESTER->write_data_.data(), write_size); + REQUIRE(TESTER->size_written_orig_ == write_size); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == write_size); + } + SECTION("write to new file multiple write") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i <= TESTER->num_iterations_; ++i) { + TESTER->test_fwrite(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->request_size_ * (TESTER->num_iterations_ + 1)); + } + TESTER->Posttest(); +} diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_low_buffer_space_test.cpp b/test/unit/hermes_adapters/stdio/stdio_adapter_low_buffer_space_test.cpp deleted file mode 100644 index 337c81f86..000000000 --- a/test/unit/hermes_adapters/stdio/stdio_adapter_low_buffer_space_test.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include -#include - -#include "adapter_test_utils.h" -#include "catch_config.h" -#if HERMES_INTERCEPT == 1 -#include "hermes_adapters/stdio/stdio_api.h" -#include "hermes_adapters/stdio/stdio_fs_api.h" -#endif - -namespace stdfs = std::filesystem; - -namespace hermes::adapter::stdio::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp/test_hermes"; - size_t request_size = 65536; -}; -struct Info { - int rank = 0; - int comm_size = 1; - std::string write_data; - std::string read_data; - std::string new_file; - std::string existing_file; - std::string new_file_cmp; - std::string existing_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 5; - size_t total_size; - size_t stride_size = 512; - unsigned int temporal_interval_ms = 1; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; - size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::stdio::test -hermes::adapter::stdio::test::Arguments args; -hermes::adapter::stdio::test::Info info; - -int init(int* argc, char*** argv) { -#if HERMES_INTERCEPT == 1 - setenv("HERMES_FLUSH_MODE", "kSync", 1); - HERMES_CLIENT_CONF.flushing_mode_ = hermes::FlushingMode::kSync; -#endif - MPI_Init(argc, argv); - info.write_data = GenRandom(args.request_size); - info.read_data = std::string(args.request_size, 'r'); - return 0; -} -int finalize() { - MPI_Finalize(); - return 0; -} - -int pretest() { - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new_" + std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext_" + std::to_string(getpid()); - info.new_file_cmp = - fullpath.string() + "_new_cmp" + "_" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp" + "_" + std::to_string(getpid()); - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + info.existing_file + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - } - REQUIRE(info.total_size > 0); -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file_cmp, false); -#endif - return 0; -} - -void Clear() { -#if HERMES_INTERCEPT == 1 - HERMES->Clear(); -#endif -} - -int posttest(bool compare_data = true) { -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, false); -#endif - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) { - char_mismatch = pos; - break; - } - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - /* Clean up. */ - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - Clear(); - -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file_cmp, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file_cmp, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, true); -#endif - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -namespace test { -FILE* fh_orig; -FILE* fh_cmp; -int status_orig; -size_t size_read_orig; -size_t size_written_orig; -void test_fopen(const char* path, const char* mode) { - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else { - cmp_path = info.existing_file_cmp; - } - fh_orig = fopen(path, mode); - fh_cmp = fopen(cmp_path.c_str(), mode); - bool is_same = (fh_cmp != nullptr && fh_orig != nullptr) || - (fh_cmp == nullptr && fh_orig == nullptr); - REQUIRE(is_same); -} -void test_fclose() { - status_orig = fclose(fh_orig); - int status = fclose(fh_cmp); - REQUIRE(status == status_orig); -} -void test_fwrite(const void* ptr, size_t size) { - size_written_orig = fwrite(ptr, sizeof(char), size, fh_orig); - size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp); - REQUIRE(size_written == size_written_orig); -} -void test_fread(char* ptr, size_t size) { - size_read_orig = fread(ptr, sizeof(char), size, fh_orig); - std::vector read_data(size, 'r'); - size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp); - REQUIRE(size_read == size_read_orig); - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < size; ++i) { - if (read_data[i] != ptr[i]) { - unmatching_chars = i; - break; - } - } - REQUIRE(unmatching_chars == 0); - } -} -void test_fseek(long offset, int whence) { - status_orig = fseek(fh_orig, offset, whence); - int status = fseek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -TEST_CASE("BatchedWriteSequential", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file one big write") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - auto write_size = args.request_size * (info.num_iterations + 1); - info.write_data = GenRandom(write_size); - test::test_fwrite(info.write_data.c_str(), write_size); - REQUIRE(test::size_written_orig == write_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == write_size); - } - SECTION("write to new file multiple write") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i <= info.num_iterations; ++i) { - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - REQUIRE(test::size_written_orig == args.request_size); - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - args.request_size * (info.num_iterations + 1)); - } - posttest(); -} diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_mapper_test.cpp b/test/unit/hermes_adapters/stdio/stdio_adapter_mapper_test.cc similarity index 50% rename from test/unit/hermes_adapters/stdio/stdio_adapter_mapper_test.cpp rename to test/unit/hermes_adapters/stdio/stdio_adapter_mapper_test.cc index 5214074fe..0ca1337c7 100644 --- a/test/unit/hermes_adapters/stdio/stdio_adapter_mapper_test.cpp +++ b/test/unit/hermes_adapters/stdio/stdio_adapter_mapper_test.cc @@ -10,118 +10,26 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include - -#include "catch_config.h" -#include "hermes/hermes_types.h" -#include "hermes_adapters/adapter_constants.h" +#include "stdio_adapter_test.h" +#include "hermes_adapters/mapper/mapper_factory.h" #include "hermes_adapters/mapper/mapper_factory.h" -#include "hermes_adapters/stdio/stdio_fs_api.h" +#include "hermes_adapters/adapter_constants.h" -using hermes::adapter::BlobPlacements; using hermes::adapter::MapperFactory; -using hermes::adapter::MapperType; +using hermes::adapter::BlobPlacements; using hermes::adapter::kMapperType; -using hermes::adapter::fs::MetadataManager; -namespace stdfs = std::filesystem; - -namespace hermes::adapter::stdio::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp/test_hermes"; - size_t request_size = 65536; - size_t num_iterations = 1024; -}; -struct Info { - int rank = 0; - int comm_size = 1; - std::string new_file; - std::string existing_file; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - size_t total_size; - size_t stride_size = 1024; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; - size_t large_min = 256 * 1024 + 1, large_max = 4 * 1024 * 1024; -}; -} // namespace hermes::adapter::stdio::test -hermes::adapter::stdio::test::Arguments args; -hermes::adapter::stdio::test::Info info; - -int init(int* argc, char*** argv) { -#if HERMES_INTERCEPT == 1 - setenv("HERMES_FLUSH_MODE", "kSync", 1); - HERMES_CLIENT_CONF.flushing_mode_ = hermes::FlushingMode::kSync; -#endif - MPI_Init(argc, argv); - - return 0; -} -int finalize() { - MPI_Finalize(); - - return 0; -} - -int pretest() { - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new"; - info.existing_file = fullpath.string() + "_ext"; - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "dd if=/dev/zero of=" + info.existing_file + - " bs=1 count=0 seek=" + - std::to_string(args.request_size * args.num_iterations) + - " > /dev/null 2>&1"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * args.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - REQUIRE(info.total_size > 0); - return 0; -} - -void Clear() { -#if HERMES_INTERCEPT == 1 - HERMES->Clear(); -#endif -} - -int posttest() { - Clear(); - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O") | - cl::Opt(args.num_iterations, "iterations")["-n"]["--iterations"]( - "Number of iterations of requests"); -} - -TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[request_size=type-fixed][repetition=1]" - "[pattern=sequential][file=1]") { - pretest(); +TEST_CASE("SingleWrite", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_write]" + "[request_size=type-fixed][repetition=1]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); const size_t kPageSize = MEGABYTES(1); SECTION("Map a one request") { - auto mapper = MapperFactory().Get(kMapperType); - size_t total_size = args.request_size; - FILE* fp = fopen(info.new_file.c_str(), "w+"); + auto mapper = hermes::adapter::MapperFactory().Get(kMapperType); + size_t total_size = TESTER->request_size_; + FILE* fp = fopen(TESTER->new_file_.hermes_.c_str(), "w+"); REQUIRE(fp != nullptr); size_t offset = 0; REQUIRE(kPageSize > total_size + offset); @@ -136,8 +44,8 @@ TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + } SECTION("Map a one big request") { auto mapper = MapperFactory().Get(kMapperType); - size_t total_size = args.request_size * args.num_iterations; - FILE* fp = fopen(info.new_file.c_str(), "w+"); + size_t total_size = TESTER->request_size_ * TESTER->num_iterations_; + FILE* fp = fopen(TESTER->new_file_.hermes_.c_str(), "w+"); REQUIRE(fp != nullptr); size_t offset = 0; BlobPlacements mapping; @@ -156,8 +64,8 @@ TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + } SECTION("Map a one large unaligned request") { auto mapper = MapperFactory().Get(kMapperType); - size_t total_size = args.request_size * args.num_iterations; - FILE* fp = fopen(info.new_file.c_str(), "w+"); + size_t total_size = TESTER->request_size_ * TESTER->num_iterations_; + FILE* fp = fopen(TESTER->new_file_.hermes_.c_str(), "w+"); REQUIRE(fp != nullptr); size_t offset = 1; BlobPlacements mapping; @@ -191,8 +99,8 @@ TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + } SECTION("Map a one small unaligned request") { auto mapper = MapperFactory().Get(kMapperType); - size_t total_size = args.request_size; - FILE* fp = fopen(info.new_file.c_str(), "w+"); + size_t total_size = TESTER->request_size_; + FILE* fp = fopen(TESTER->new_file_.hermes_.c_str(), "w+"); REQUIRE(fp != nullptr); size_t offset = 1; REQUIRE(kPageSize > total_size + offset); @@ -205,5 +113,5 @@ TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + int status = fclose(fp); REQUIRE(status == 0); } - posttest(); + TESTER->Posttest(); } diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_mode_test.cc b/test/unit/hermes_adapters/stdio/stdio_adapter_mode_test.cc new file mode 100644 index 000000000..b36ccc197 --- /dev/null +++ b/test/unit/hermes_adapters/stdio/stdio_adapter_mode_test.cc @@ -0,0 +1,99 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "stdio_adapter_test.h" + +TEST_CASE("BatchedWriteSequentialPersistent", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[hermes_mode=persistent]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + HERMES_CLIENT_CONF.SetBaseAdapterMode(hermes::adapter::AdapterMode::kDefault); + REQUIRE(HERMES_CLIENT_CONF.GetBaseAdapterMode() == + hermes::adapter::AdapterMode::kDefault); + TESTER->Pretest(); + SECTION("write to new file always at end") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fwrite(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->num_iterations_ * TESTER->request_size_); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedWriteSequentialBypass", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[hermes_mode=bypass]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + HERMES_CLIENT_CONF.SetBaseAdapterMode(hermes::adapter::AdapterMode::kBypass); + REQUIRE(HERMES_CLIENT_CONF.GetBaseAdapterMode() == + hermes::adapter::AdapterMode::kBypass); + TESTER->Pretest(); + SECTION("write to new file always at end") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fwrite(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == + TESTER->num_iterations_ * TESTER->request_size_); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedWriteSequentialScratch", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[hermes_mode=scratch]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + HERMES_CLIENT_CONF.SetBaseAdapterMode(hermes::adapter::AdapterMode::kScratch); + REQUIRE(HERMES_CLIENT_CONF.GetBaseAdapterMode() == + hermes::adapter::AdapterMode::kScratch); + TESTER->Pretest(); + SECTION("write to new file always at end") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fwrite(TESTER->write_data_.data(), TESTER->request_size_); + REQUIRE(TESTER->size_written_orig_ == TESTER->request_size_); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::exists(TESTER->new_file_.hermes_) == 0); + } + TESTER->Posttest(false); +} diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_mode_test.cpp b/test/unit/hermes_adapters/stdio/stdio_adapter_mode_test.cpp deleted file mode 100644 index 78926c123..000000000 --- a/test/unit/hermes_adapters/stdio/stdio_adapter_mode_test.cpp +++ /dev/null @@ -1,363 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include -#include - -#include -#include - -#if HERMES_INTERCEPT == 1 -#include "hermes_adapters/stdio/stdio_api.h" -#endif - -#include "adapter_test_utils.h" -#include "hermes_adapters/adapter_types.h" -#include "hermes/hermes.h" - -namespace stdfs = std::filesystem; -using hermes::adapter::AdapterMode; - -namespace hermes::adapter::stdio::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp/test_hermes"; - size_t request_size = 65536; -}; -struct Info { - int rank = 0; - int comm_size = 1; - std::string write_data; - std::string read_data; - std::string new_file; - std::string existing_file; - std::string new_file_cmp; - std::string existing_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 5; - size_t total_size; - size_t stride_size = 512; - unsigned int temporal_interval_ms = 1; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; - size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::stdio::test -hermes::adapter::stdio::test::Arguments args; -hermes::adapter::stdio::test::Info info; - -int init(int* argc, char*** argv) { -#if HERMES_INTERCEPT == 1 - setenv("HERMES_FLUSH_MODE", "kSync", 1); - HERMES_CLIENT_CONF.flushing_mode_ = hermes::FlushingMode::kSync; -#endif - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new" + std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext" + std::to_string(getpid()); - info.new_file_cmp = fullpath.string() + "_new_cmp" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp" + std::to_string(getpid()); - char* set_path = getenv("SET_PATH"); - if (set_path && strcmp(set_path, "1") == 0) { - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, false); - } - MPI_Init(argc, argv); - info.write_data = GenRandom(args.request_size); - info.read_data = std::string(args.request_size, 'r'); - return 0; -} -int finalize() { - MPI_Finalize(); - return 0; -} - -void IgnoreAllFiles() { -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, false); -#endif -} - -void TrackFiles() { -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, true); -#endif -} - -void RemoveFile(const std::string &path) { - stdfs::remove(path); - if (stdfs::exists(path)) { - HELOG(kFatal, "Failed to remove: {}", path) - } -} - -void RemoveFiles() { - RemoveFile(info.new_file); - RemoveFile(info.new_file_cmp); - RemoveFile(info.existing_file); - RemoveFile(info.existing_file_cmp); -} - -void Clear() { -#if HERMES_INTERCEPT == 1 - HERMES->Clear(); -#endif -} - -int pretest() { - IgnoreAllFiles(); - RemoveFiles(); - - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + info.existing_file + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - } - REQUIRE(info.total_size > 0); - - TrackFiles(); - return 0; -} - -int posttest(bool compare_data = true) { - IgnoreAllFiles(); - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - /* Clean up. */ - TrackFiles(); - RemoveFiles(); - Clear(); - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -namespace test { -FILE* fh_orig; -FILE* fh_cmp; -int status_orig; -size_t size_read_orig; -size_t size_written_orig; -void test_fopen(const char* path, const char* mode) { - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else { - cmp_path = info.existing_file_cmp; - } - fh_orig = fopen(path, mode); - fh_cmp = fopen(cmp_path.c_str(), mode); - bool is_same = (fh_cmp != nullptr && fh_orig != nullptr) || - (fh_cmp == nullptr && fh_orig == nullptr); - REQUIRE(is_same); -} -void test_fclose() { - status_orig = fclose(fh_orig); - int status = fclose(fh_cmp); - REQUIRE(status == status_orig); -} -void test_fwrite(const void* ptr, size_t size) { - size_written_orig = fwrite(ptr, sizeof(char), size, fh_orig); - size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp); - REQUIRE(size_written == size_written_orig); -} -void test_fread(char* ptr, size_t size) { - size_read_orig = fread(ptr, sizeof(char), size, fh_orig); - std::vector read_data(size, 'r'); - size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp); - REQUIRE(size_read == size_read_orig); - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < size; ++i) { - if (read_data[i] != ptr[i]) { - unmatching_chars = i; - break; - } - } - REQUIRE(unmatching_chars == 0); - } -} -void test_fseek(long offset, int whence) { - status_orig = fseek(fh_orig, offset, whence); - int status = fseek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -TEST_CASE("BatchedWriteSequentialPersistent", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[hermes_mode=persistent]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - HERMES_CLIENT_CONF.SetBaseAdapterMode(AdapterMode::kDefault); - REQUIRE(HERMES_CLIENT_CONF.GetBaseAdapterMode() == AdapterMode::kDefault); - pretest(); - SECTION("write to new file always at end") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedWriteSequentialBypass", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[hermes_mode=bypass]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - HERMES_CLIENT_CONF.SetBaseAdapterMode(AdapterMode::kBypass); - REQUIRE(HERMES_CLIENT_CONF.GetBaseAdapterMode() == AdapterMode::kBypass); - pretest(); - SECTION("write to new file always at end") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == - info.num_iterations * args.request_size); - } - posttest(); -} - -TEST_CASE("BatchedWriteSequentialScratch", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[hermes_mode=scratch]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - HERMES_CLIENT_CONF.SetBaseAdapterMode(AdapterMode::kScratch); - REQUIRE(HERMES_CLIENT_CONF.GetBaseAdapterMode() == AdapterMode::kScratch); - pretest(); - SECTION("write to new file always at end") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fwrite(info.write_data.c_str(), args.request_size); - REQUIRE(test::size_written_orig == args.request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - IgnoreAllFiles(); - REQUIRE(stdfs::exists(info.new_file) == 0); - TrackFiles(); - } - posttest(false); -} diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_mpi_test.cpp b/test/unit/hermes_adapters/stdio/stdio_adapter_mpi_test.cpp deleted file mode 100644 index 0a4970665..000000000 --- a/test/unit/hermes_adapters/stdio/stdio_adapter_mpi_test.cpp +++ /dev/null @@ -1,362 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include -#include -#include - -#include -#include -#if HERMES_INTERCEPT == 1 -#include "hermes_adapters/stdio/stdio_api.h" -#include "hermes_adapters/stdio/stdio_fs_api.h" -#endif - -namespace stdfs = std::filesystem; - -namespace hermes::adapter::stdio::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp/test_hermes"; - size_t request_size = 65536; -}; -struct Info { - bool debug = false; - int rank = 0; - int comm_size = 1; - std::string write_data; - std::string read_data; - std::string new_file; - std::string existing_file; - std::string existing_shared_file; - std::string new_file_cmp; - std::string existing_file_cmp; - std::string existing_shared_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 1; - size_t total_size; - size_t stride_size = 4 * 1024; - unsigned int temporal_interval_ms = 5; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 512 * 1024; - size_t large_min = 512 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::stdio::test - -hermes::adapter::stdio::test::Arguments args; -hermes::adapter::stdio::test::Info info; - -int init(int* argc, char*** argv) { -#if HERMES_INTERCEPT == 1 - setenv("HERMES_FLUSH_MODE", "kSync", 1); - HERMES_CLIENT_CONF.flushing_mode_ = hermes::FlushingMode::kSync; -#endif - MPI_Init(argc, argv); - info.write_data = GenRandom(args.request_size); - info.read_data = std::string(args.request_size, 'r'); - MPI_Comm_rank(MPI_COMM_WORLD, &info.rank); - MPI_Comm_size(MPI_COMM_WORLD, &info.comm_size); - if (info.debug && info.rank == 0) { - printf("%d ready for attach\n", info.comm_size); - fflush(stdout); - sleep(30); - } - MPI_Barrier(MPI_COMM_WORLD); - return 0; -} -int finalize() { - MPI_Finalize(); - return 0; -} - -namespace test { -FILE* fh_orig; -FILE* fh_cmp; -int status_orig; -size_t size_read_orig; -size_t size_written_orig; -void test_fopen(const char* path, const char* mode) { - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else if (strcmp(path, info.existing_file.c_str()) == 0) { - cmp_path = info.existing_file_cmp; - } else { - cmp_path = info.existing_shared_file_cmp; - } - fh_orig = fopen(path, mode); - fh_cmp = fopen(cmp_path.c_str(), mode); - bool is_same = (fh_cmp != nullptr && fh_orig != nullptr) || - (fh_cmp == nullptr && fh_orig == nullptr); - REQUIRE(is_same); -} -void test_fclose() { - status_orig = fclose(fh_orig); - int status = fclose(fh_cmp); - REQUIRE(status == status_orig); -} -void test_fwrite(const void* ptr, size_t size) { - size_written_orig = fwrite(ptr, sizeof(char), size, fh_orig); - size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp); - REQUIRE(size_written == size_written_orig); -} -void test_fread(char* ptr, size_t size) { - size_read_orig = fread(ptr, sizeof(char), size, fh_orig); - std::vector read_data(size, 'r'); - size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp); - REQUIRE(size_read == size_read_orig); - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < size; ++i) { - if (read_data[i] != ptr[i]) unmatching_chars++; - } - REQUIRE(unmatching_chars == 0); - } -} -void test_fseek(long offset, int whence) { - status_orig = fseek(fh_orig, offset, whence); - int status = fseek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -int pretest() { - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new_" + std::to_string(info.rank) + - "_of_" + std::to_string(info.comm_size) + "_" + - std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext_" + std::to_string(info.rank) + - "_of_" + std::to_string(info.comm_size) + "_" + - std::to_string(getpid()); - info.new_file_cmp = - fullpath.string() + "_new_cmp_" + std::to_string(info.rank) + "_of_" + - std::to_string(info.comm_size) + "_" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp_" + std::to_string(info.rank) + "_of_" + - std::to_string(info.comm_size) + "_" + std::to_string(getpid()); - info.existing_shared_file = - fullpath.string() + "_ext_" + std::to_string(info.comm_size); - info.existing_shared_file_cmp = - fullpath.string() + "_ext_cmp_" + std::to_string(info.comm_size); - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - if (stdfs::exists(info.existing_shared_file)) - stdfs::remove(info.existing_shared_file); - if (stdfs::exists(info.existing_shared_file_cmp)) - stdfs::remove(info.existing_shared_file_cmp); - stdfs::path temp_fullpath = "/tmp"; - temp_fullpath /= args.filename; - std::string temp_ext_file = - temp_fullpath.string() + "_temp_" + std::to_string(info.rank) + "_of_" + - std::to_string(info.comm_size) + "_" + std::to_string(getpid()); - if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); - if (!stdfs::exists(temp_ext_file)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + temp_ext_file + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(temp_ext_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(temp_ext_file); - } - if (info.rank == 0 && !stdfs::exists(info.existing_shared_file)) { - std::string cmd = "cp " + temp_ext_file + " " + info.existing_shared_file; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_shared_file) == - args.request_size * info.num_iterations); - } - if (info.rank == 0 && !stdfs::exists(info.existing_shared_file_cmp)) { - std::string cmd = - "cp " + temp_ext_file + " " + info.existing_shared_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_shared_file_cmp) == - args.request_size * info.num_iterations); - } - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "cp " + temp_ext_file + " " + info.existing_file; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - } - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - } - if (stdfs::exists(temp_ext_file)) stdfs::remove(temp_ext_file); - REQUIRE(info.total_size > 0); - MPI_Barrier(MPI_COMM_WORLD); -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking( - info.existing_shared_file_cmp, false); -#endif - return 0; -} - -void Clear() { -#if HERMES_INTERCEPT == 1 - HERMES->Clear(); -#endif -} - -int posttest(bool compare_data = true) { -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking( - info.existing_shared_file, false); -#endif - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_shared_file) && - stdfs::exists(info.existing_shared_file_cmp)) { - size_t size = stdfs::file_size(info.existing_shared_file); - if (size != stdfs::file_size(info.existing_shared_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_shared_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_shared_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_shared_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) char_mismatch++; - } - REQUIRE(char_mismatch == 0); - } - } - /* Clean up. */ - if (stdfs::exists(info.new_file)) stdfs::remove(info.new_file); - if (stdfs::exists(info.existing_file)) stdfs::remove(info.existing_file); - if (stdfs::exists(info.new_file_cmp)) stdfs::remove(info.new_file_cmp); - if (stdfs::exists(info.existing_file_cmp)) - stdfs::remove(info.existing_file_cmp); - MPI_Barrier(MPI_COMM_WORLD); - if (info.rank == 0) { - if (stdfs::exists(info.existing_shared_file)) - stdfs::remove(info.existing_shared_file); - if (stdfs::exists(info.existing_shared_file_cmp)) - stdfs::remove(info.existing_shared_file_cmp); - } - Clear(); - -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file_cmp, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file_cmp, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking( - info.existing_shared_file, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking( - info.existing_shared_file_cmp, true); -#endif - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -#include "stdio_adapter_basic_test.cpp" -#include "stdio_adapter_func_test.cpp" -#include "stdio_adapter_rs_test.cpp" -// #include "stdio_adapter_shared_test.cpp" diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_rs_test.cc b/test/unit/hermes_adapters/stdio/stdio_adapter_rs_test.cc new file mode 100644 index 000000000..179924ea4 --- /dev/null +++ b/test/unit/hermes_adapters/stdio/stdio_adapter_rs_test.cc @@ -0,0 +1,1287 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include "stdio_adapter_test.h" + +TEST_CASE("BatchedWriteRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("write to new file always at the start") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t biggest_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + if (biggest_written < request_size) biggest_written = request_size; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == biggest_written); + } + + SECTION("write to new file") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t total_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + total_written += TESTER->size_written_orig_; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == total_written); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequentialRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + current_offset += TESTER->size_read_orig_; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_fopen(TESTER->existing_file_, "r"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadRandomRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-small]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + + "][pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->small_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = (i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = (i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_ - TESTER->small_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_ - TESTER->small_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = (TESTER->total_size_ - i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->total_size_ - ((i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->small_max_)); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStride2DRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSRangeSmall", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-small][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->small_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->small_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->small_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} +/** + * Medium RS + **/ + +TEST_CASE("BatchedWriteRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("write to new file always at the start") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t biggest_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + if (biggest_written < request_size) biggest_written = request_size; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == biggest_written); + } + + SECTION("write to new file") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t total_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + total_written += TESTER->size_written_orig_; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequentialRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + (TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_)) % + (TESTER->total_size_ - current_offset); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + current_offset += TESTER->size_read_orig_; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_fopen(TESTER->existing_file_, "r"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadRandomRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-medium]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + + "][pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + (i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + (i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = (TESTER->total_size_ - i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->total_size_ - ((i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->medium_max_)); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStride2DRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSRangeMedium", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-medium][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->medium_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->medium_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->medium_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} +/** + * Large RS + **/ + +TEST_CASE("BatchedWriteRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("write to new file always at the start") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t biggest_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + if (biggest_written < request_size) biggest_written = request_size; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("write to new file") { + TESTER->test_fopen(TESTER->new_file_, "w+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t total_written = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + total_written += TESTER->size_written_orig_; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + REQUIRE(stdfs::file_size(TESTER->new_file_.hermes_) == total_written); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadSequentialRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + size_t current_offset = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = + (TESTER->large_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_)) % + (TESTER->total_size_ - current_offset); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + current_offset += TESTER->size_read_orig_; + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + + SECTION("read from existing file always at start") { + TESTER->test_fopen(TESTER->existing_file_, "r"); + REQUIRE(TESTER->fh_orig_ != nullptr); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fseek(0, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t offset = ftell(TESTER->fh_orig_); + REQUIRE(offset == 0); + size_t request_size = + TESTER->large_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadRandomRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-large]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + + "][pattern=random][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + (TESTER->large_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_)) % + (TESTER->total_size_ - offset); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateRandomRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=random][file=1]") { + TESTER->Pretest(); + + SECTION("write into existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = + rand_r(&TESTER->offset_seed_) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::vector data = TESTER->GenRandom(request_size); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideFixedRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = (i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->large_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideFixedRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_fixed][file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = (i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideDynamicRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, TESTER->stride_size_, + TESTER->total_size_ - TESTER->large_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideDynamicRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_dynamic][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->GetRandomOffset( + i, TESTER->offset_seed_, + TESTER->stride_size_, + TESTER->total_size_ - TESTER->large_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStrideNegativeRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = (TESTER->total_size_ - i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + (TESTER->large_min_ + + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_)) % + (TESTER->total_size_ - TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStrideNegativeRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_negative][file=1]") { + TESTER->Pretest(); + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + auto offset = TESTER->total_size_ - ((i * TESTER->stride_size_) % + (TESTER->total_size_ - TESTER->large_max_)); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedReadStride2DRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("read from existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_fread(data.data(), request_size); + REQUIRE(TESTER->size_read_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} + +TEST_CASE("BatchedUpdateStride2DRSRangeLarge", + "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "" + "[operation=batched_write]" + "[request_size=range-large][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=stride_2d][file=1]") { + TESTER->Pretest(); + size_t rows = sqrt(TESTER->total_size_); + size_t cols = rows; + REQUIRE(rows * cols == TESTER->total_size_); + size_t cell_size = 128; + size_t cell_stride = rows * cols / cell_size / TESTER->num_iterations_; + SECTION("write to existing file") { + TESTER->test_fopen(TESTER->existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + size_t prev_cell_col = 0, prev_cell_row = 0; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t current_cell_col = (prev_cell_col + cell_stride) % cols; + size_t current_cell_row = prev_cell_col + cell_stride > cols + ? prev_cell_row + 1 + : prev_cell_row; + prev_cell_row = current_cell_row; + auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % + (TESTER->total_size_ - TESTER->large_max_); + TESTER->test_fseek(offset, SEEK_SET); + REQUIRE(TESTER->status_orig_ == 0); + size_t request_size = + TESTER->large_min_ + (rand_r(&TESTER->rs_seed_) % TESTER->large_max_); + std::string data(request_size, '1'); + TESTER->test_fwrite(data.data(), request_size); + REQUIRE(TESTER->size_written_orig_ == request_size); + } + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); + } + TESTER->Posttest(); +} diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_rs_test.cpp b/test/unit/hermes_adapters/stdio/stdio_adapter_rs_test.cpp deleted file mode 100644 index b6a4ea629..000000000 --- a/test/unit/hermes_adapters/stdio/stdio_adapter_rs_test.cpp +++ /dev/null @@ -1,1247 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -TEST_CASE("BatchedWriteRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at the start") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t biggest_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_written < request_size) biggest_written = request_size; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_written); - } - - SECTION("write to new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t total_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_written += test::size_written_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (info.total_size - i * info.stride_size) % - (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = info.total_size - ((i * info.stride_size) % - (info.total_size - info.small_max)); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSRangeSmall", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-small][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.small_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.small_min + (rand_r(&info.rs_seed) % info.small_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} -/** - * Medium RS - **/ - -TEST_CASE("BatchedWriteRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at the start") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t biggest_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_written < request_size) biggest_written = request_size; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == biggest_written); - } - - SECTION("write to new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t total_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_written += test::size_written_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - (info.medium_min + (rand_r(&info.rs_seed) % info.medium_max)) % - (info.total_size - current_offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - (i * info.stride_size) % (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - (i * info.stride_size) % (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (info.total_size - i * info.stride_size) % - (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = info.total_size - ((i * info.stride_size) % - (info.total_size - info.medium_max)); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSRangeMedium", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-medium][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.medium_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.medium_min + (rand_r(&info.rs_seed) % info.medium_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} -/** - * Large RS - **/ - -TEST_CASE("BatchedWriteRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("write to new file always at the start") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t biggest_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - if (biggest_written < request_size) biggest_written = request_size; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("write to new file") { - test::test_fopen(info.new_file.c_str(), "w+"); - REQUIRE(test::fh_orig != nullptr); - size_t total_written = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - total_written += test::size_written_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - REQUIRE(stdfs::file_size(info.new_file) == total_written); - } - posttest(); -} - -TEST_CASE("BatchedReadSequentialRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=sequential][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - size_t current_offset = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = - (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % - (info.total_size - current_offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - current_offset += test::size_read_orig; - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - - SECTION("read from existing file always at start") { - test::test_fopen(info.existing_file.c_str(), "r"); - REQUIRE(test::fh_orig != nullptr); - - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fseek(0, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t offset = ftell(test::fh_orig); - REQUIRE(offset == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadRandomRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % - (info.total_size - offset); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateRandomRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - pretest(); - - SECTION("write into existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = - rand_r(&info.offset_seed) % (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data = GenRandom(request_size); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideFixedRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideFixedRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_fixed][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (i * info.stride_size) % (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideDynamicRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideDynamicRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_dynamic][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = GetRandomOffset(i, info.offset_seed, info.stride_size, - info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStrideNegativeRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = (info.total_size - i * info.stride_size) % - (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - (info.large_min + (rand_r(&info.rs_seed) % info.large_max)) % - (info.total_size - info.large_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStrideNegativeRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_negative][file=1]") { - pretest(); - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - for (size_t i = 0; i < info.num_iterations; ++i) { - auto offset = info.total_size - ((i * info.stride_size) % - (info.total_size - info.large_max)); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedReadStride2DRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("read from existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fread(data.data(), request_size); - REQUIRE(test::size_read_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} - -TEST_CASE("BatchedUpdateStride2DRSRangeLarge", - "[process=" + std::to_string(info.comm_size) + - "]" - "" - "[operation=batched_write]" - "[request_size=range-large][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=stride_2d][file=1]") { - pretest(); - size_t rows = sqrt(info.total_size); - size_t cols = rows; - REQUIRE(rows * cols == info.total_size); - size_t cell_size = 128; - size_t cell_stride = rows * cols / cell_size / info.num_iterations; - SECTION("write to existing file") { - test::test_fopen(info.existing_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - size_t prev_cell_col = 0, prev_cell_row = 0; - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t current_cell_col = (prev_cell_col + cell_stride) % cols; - size_t current_cell_row = prev_cell_col + cell_stride > cols - ? prev_cell_row + 1 - : prev_cell_row; - prev_cell_row = current_cell_row; - auto offset = (current_cell_col * cell_stride + prev_cell_row * cols) % - (info.total_size - info.large_max); - test::test_fseek(offset, SEEK_SET); - REQUIRE(test::status_orig == 0); - size_t request_size = - info.large_min + (rand_r(&info.rs_seed) % info.large_max); - std::string data(request_size, '1'); - test::test_fwrite(data.data(), request_size); - REQUIRE(test::size_written_orig == request_size); - } - test::test_fclose(); - REQUIRE(test::status_orig == 0); - } - posttest(); -} diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_shared_test.cpp b/test/unit/hermes_adapters/stdio/stdio_adapter_shared_test.cc similarity index 51% rename from test/unit/hermes_adapters/stdio/stdio_adapter_shared_test.cpp rename to test/unit/hermes_adapters/stdio/stdio_adapter_shared_test.cc index 5a9f437e3..5d06c6dd0 100644 --- a/test/unit/hermes_adapters/stdio/stdio_adapter_shared_test.cpp +++ b/test/unit/hermes_adapters/stdio/stdio_adapter_shared_test.cc @@ -10,26 +10,28 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -TEST_CASE("SharedSTDIORead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[mode=shared]" - "[pattern=sequential][file=1]") { - pretest(); +#include "stdio_adapter_test.h" + +TEST_CASE("SharedSTDIORead", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[mode=shared]" + "[pattern=sequential][file=1]") { + TESTER->Pretest(); SECTION("read from existing file") { - test::test_fopen(info.existing_shared_file.c_str(), "r+"); - REQUIRE(test::fh_orig != nullptr); - std::string data(args.request_size, '1'); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::test_fread(data.data(), args.request_size); - REQUIRE(test::size_read_orig == args.request_size); + TESTER->test_fopen(TESTER->shared_existing_file_, "r+"); + REQUIRE(TESTER->fh_orig_ != nullptr); + std::string data(TESTER->request_size_, '1'); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->test_fread(data.data(), TESTER->request_size_); + REQUIRE(TESTER->size_read_orig_ == TESTER->request_size_); } - test::test_fclose(); - REQUIRE(test::status_orig == 0); + TESTER->test_fclose(); + REQUIRE(TESTER->status_orig_ == 0); } - posttest(); + TESTER->Posttest(); } diff --git a/hermes_adapters/interceptor.h b/test/unit/hermes_adapters/stdio/stdio_adapter_test.cc similarity index 69% rename from hermes_adapters/interceptor.h rename to test/unit/hermes_adapters/stdio/stdio_adapter_test.cc index ba62e256a..a1a264f6f 100644 --- a/hermes_adapters/interceptor.h +++ b/test/unit/hermes_adapters/stdio/stdio_adapter_test.cc @@ -10,21 +10,9 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef HERMES_ADAPTER_UTILS_H_ -#define HERMES_ADAPTER_UTILS_H_ +#include "stdio_adapter_test.h" -#include "hermes/hermes.h" -#include "hermes_adapters/filesystem/filesystem_mdm.h" +int main(int argc, char **argv) { + TESTER->Init(argc, argv); +} -namespace stdfs = std::filesystem; - -namespace hermes::adapter { - -#define HERMES_DECL(F) F - -/** The maximum length of a POSIX path */ -static inline const int kMaxPathLen = 4096; - -} // namespace hermes::adapter - -#endif // HERMES_ADAPTER_UTILS_H_ diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_test.cpp b/test/unit/hermes_adapters/stdio/stdio_adapter_test.cpp deleted file mode 100644 index 92c690771..000000000 --- a/test/unit/hermes_adapters/stdio/stdio_adapter_test.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Distributed under BSD 3-Clause license. * - * Copyright by The HDF Group. * - * Copyright by the Illinois Institute of Technology. * - * All rights reserved. * - * * - * This file is part of Hermes. The full Hermes copyright notice, including * - * terms governing use, modification, and redistribution, is contained in * - * the COPYING file, which can be found at the top directory. If you do not * - * have access to the file, you may request a copy from help@hdfgroup.org. * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include -#include -#include - -#include -#include - -#include "adapter_test_utils.h" -#include "catch_config.h" -#include "hermes_adapters/stdio/stdio_api.h" -#if HERMES_INTERCEPT == 1 -#include "hermes_adapters/stdio/stdio_fs_api.h" -#endif - -#include "hermes_shm/util/logging.h" -#include "adapter_test_utils.h" - -namespace stdfs = std::filesystem; - -namespace hermes::adapter::stdio::test { -struct Arguments { - std::string filename = "test.dat"; - std::string directory = "/tmp/test_hermes"; - size_t request_size = 65536; -}; -struct Info { - int rank = 0; - int comm_size = 1; - std::string write_data; - std::string read_data; - std::string new_file; - std::string existing_file; - std::string new_file_cmp; - std::string existing_file_cmp; - size_t num_iterations = 64; - unsigned int offset_seed = 1; - unsigned int rs_seed = 1; - unsigned int temporal_interval_seed = 5; - size_t total_size; - size_t stride_size = 512; - unsigned int temporal_interval_ms = 1; - size_t small_min = 1, small_max = 4 * 1024; - size_t medium_min = 4 * 1024 + 1, medium_max = 256 * 1024; - size_t large_min = 256 * 1024 + 1, large_max = 3 * 1024 * 1024; -}; -} // namespace hermes::adapter::stdio::test - -hermes::adapter::stdio::test::Arguments args; -hermes::adapter::stdio::test::Info info; - -int init(int* argc, char*** argv) { -#if HERMES_INTERCEPT == 1 - setenv("HERMES_FLUSH_MODE", "kSync", 1); - HERMES_CLIENT_CONF.flushing_mode_ = hermes::FlushingMode::kSync; -#endif - MPI_Init(argc, argv); - info.write_data = GenRandom(args.request_size); - info.read_data = std::string(args.request_size, 'r'); - return 0; -} - -int finalize() { - MPI_Finalize(); - return 0; -} - -void IgnoreAllFiles() { -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, false); -#endif -} - -void TrackFiles() { -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, true); -#endif -} - -void RemoveFile(const std::string &path) { - stdfs::remove(path); - if (stdfs::exists(path)) { - HELOG(kFatal, "Failed to remove: {}", path) - } -} - -void RemoveFiles() { - RemoveFile(info.new_file); - RemoveFile(info.new_file_cmp); - RemoveFile(info.existing_file); - RemoveFile(info.existing_file_cmp); -} - -void Clear() { -#if HERMES_INTERCEPT == 1 - HERMES->Clear(); -#endif -} - -int pretest() { - // Create path names - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - info.new_file = fullpath.string() + "_new_" + std::to_string(getpid()); - info.existing_file = fullpath.string() + "_ext_" + std::to_string(getpid()); - info.new_file_cmp = - fullpath.string() + "_new_cmp" + "_" + std::to_string(getpid()); - info.existing_file_cmp = - fullpath.string() + "_ext_cmp" + "_" + std::to_string(getpid()); - - // Temporarily ignore all files - IgnoreAllFiles(); - - // Remove all files - RemoveFiles(); - - // Create the file NOT buffered by Hermes - if (!stdfs::exists(info.existing_file_cmp)) { - std::string cmd = "{ tr -dc '[:alnum:]' < /dev/urandom | head -c " + - std::to_string(args.request_size * info.num_iterations) + - "; } > " + info.existing_file_cmp + " 2> /dev/null"; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file_cmp) == - args.request_size * info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file_cmp); - } - - // Create the file that IS buffered by Hermes - if (!stdfs::exists(info.existing_file)) { - std::string cmd = "cp " + info.existing_file_cmp + " " + info.existing_file; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(stdfs::file_size(info.existing_file) == - args.request_size * info.num_iterations); - } - - REQUIRE(info.total_size > 0); - - // Begin interception - TrackFiles(); - return 0; -} - -int posttest(bool compare_data = true) { - IgnoreAllFiles(); - if (compare_data && stdfs::exists(info.new_file) && - stdfs::exists(info.new_file_cmp)) { - size_t size = stdfs::file_size(info.new_file); - REQUIRE(size == stdfs::file_size(info.new_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.new_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.new_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) { - char_mismatch++; - } - } - REQUIRE(char_mismatch == 0); - } - } - if (compare_data && stdfs::exists(info.existing_file) && - stdfs::exists(info.existing_file_cmp)) { - size_t size = stdfs::file_size(info.existing_file); - if (size != stdfs::file_size(info.existing_file_cmp)) sleep(1); - REQUIRE(size == stdfs::file_size(info.existing_file_cmp)); - if (size > 0) { - std::vector d1(size, '0'); - std::vector d2(size, '1'); - - FILE* fh1 = fopen(info.existing_file.c_str(), "r"); - REQUIRE(fh1 != nullptr); - size_t read_d1 = fread(d1.data(), size, sizeof(unsigned char), fh1); - REQUIRE(read_d1 == sizeof(unsigned char)); - int status = fclose(fh1); - REQUIRE(status == 0); - - FILE* fh2 = fopen(info.existing_file_cmp.c_str(), "r"); - REQUIRE(fh2 != nullptr); - size_t read_d2 = fread(d2.data(), size, sizeof(unsigned char), fh2); - REQUIRE(read_d2 == sizeof(unsigned char)); - status = fclose(fh2); - REQUIRE(status == 0); - size_t char_mismatch = 0; - for (size_t pos = 0; pos < size; ++pos) { - if (d1[pos] != d2[pos]) { - char_mismatch++; - } - } - REQUIRE(char_mismatch == 0); - } - } - /* Delete the files from both Hermes and the backend. */ - TrackFiles(); - RemoveFiles(); - Clear(); - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -namespace test { -FILE* fh_orig; -FILE* fh_cmp; -int status_orig; -size_t size_read_orig; -size_t size_written_orig; -void test_fopen(const char* path, const char* mode) { - std::string cmp_path; - if (strcmp(path, info.new_file.c_str()) == 0) { - cmp_path = info.new_file_cmp; - } else { - cmp_path = info.existing_file_cmp; - } - fh_orig = fopen(path, mode); - fh_cmp = fopen(cmp_path.c_str(), mode); - bool is_same = (fh_cmp != nullptr && fh_orig != nullptr) || - (fh_cmp == nullptr && fh_orig == nullptr); - REQUIRE(is_same); -} -void test_fclose() { - status_orig = fclose(fh_orig); - int status = fclose(fh_cmp); - REQUIRE(status == status_orig); -} -void test_fwrite(const void* ptr, size_t size) { - size_written_orig = fwrite(ptr, sizeof(char), size, fh_orig); - size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp); - REQUIRE(size_written == size_written_orig); -} -void test_fread(char* ptr, size_t size) { - size_read_orig = fread(ptr, sizeof(char), size, fh_orig); - std::vector read_data(size, 'r'); - size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp); - REQUIRE(size_read == size_read_orig); - if (size_read > 0) { - size_t unmatching_chars = 0; - for (size_t i = 0; i < size; ++i) { - if (read_data[i] != ptr[i]) { - unmatching_chars = i; - break; - } - } - REQUIRE(unmatching_chars == 0); - } -} -void test_fseek(long offset, int whence) { - status_orig = fseek(fh_orig, offset, whence); - int status = fseek(fh_cmp, offset, whence); - REQUIRE(status == status_orig); -} -} // namespace test - -#include "stdio_adapter_basic_test.cpp" -#include "stdio_adapter_func_test.cpp" -#include "stdio_adapter_rs_test.cpp" diff --git a/test/unit/hermes_adapters/stdio/stdio_adapter_test.h b/test/unit/hermes_adapters/stdio/stdio_adapter_test.h new file mode 100644 index 000000000..f31bff7f4 --- /dev/null +++ b/test/unit/hermes_adapters/stdio/stdio_adapter_test.h @@ -0,0 +1,108 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_TEST_UNIT_HERMES_ADAPTERS_STDIO_STDIO_ADAPTER_TEST_H_ +#define HERMES_TEST_UNIT_HERMES_ADAPTERS_STDIO_STDIO_ADAPTER_TEST_H_ + +#include "binary_file_tests.h" + +namespace hermes::adapter::test { +template +class StdioTest : public BinaryFileTests { + public: + FileInfo new_file_; + FileInfo existing_file_; + FileInfo shared_new_file_; + FileInfo shared_existing_file_; + FileInfo tmp_file_; + unsigned int offset_seed_ = 1; + unsigned int rs_seed_ = 1; + unsigned int temporal_interval_seed_ = 5; + size_t stride_size_ = 512; + unsigned int temporal_interval_ms_ = 1; + size_t small_min_ = 1; + size_t small_max_ = 4 * 1024; + size_t medium_min_ = 4 * 1024 + 1; + size_t medium_max_ = 256 * 1024; + size_t large_min_ = 256 * 1024 + 1; + size_t large_max_ = 3 * 1024 * 1024; + + FILE* fh_orig_; + FILE* fh_cmp_; + int status_orig_; + size_t size_read_orig_; + size_t size_written_orig_; + + public: + void RegisterFiles() override { + RegisterPath("new", 0, new_file_); + RegisterPath("ext", TEST_DO_CREATE, existing_file_); + if constexpr(WITH_MPI) { + RegisterPath("shared_new", TEST_FILE_SHARED, shared_new_file_); + RegisterPath("shared_ext", TEST_DO_CREATE | TEST_FILE_SHARED, + shared_existing_file_); + } + RegisterTmpPath(tmp_file_); + } + + void test_fopen(FileInfo &info, const char* mode) { + fh_orig_ = fopen(info.hermes_.c_str(), mode); + fh_cmp_ = fopen(info.cmp_.c_str(), mode); + bool is_same = (fh_cmp_ != nullptr && fh_orig_ != nullptr) || + (fh_cmp_ == nullptr && fh_orig_ == nullptr); + REQUIRE(is_same); + } + void test_fclose() { + status_orig_ = fclose(fh_orig_); + int status = fclose(fh_cmp_); + REQUIRE(status == status_orig_); + } + void test_fwrite(const void* ptr, size_t size) { + size_written_orig_ = fwrite(ptr, sizeof(char), size, fh_orig_); + size_t size_written = fwrite(ptr, sizeof(char), size, fh_cmp_); + REQUIRE(size_written == size_written_orig_); + } + void test_fread(char* ptr, size_t size) { + size_read_orig_ = fread(ptr, sizeof(char), size, fh_orig_); + std::vector read_data(size, 'r'); + size_t size_read = fread(read_data.data(), sizeof(char), size, fh_cmp_); + REQUIRE(size_read == size_read_orig_); + if (size_read > 0) { + size_t unmatching_chars = 0; + for (size_t i = 0; i < size; ++i) { + if (read_data[i] != ptr[i]) { + unmatching_chars = i; + break; + } + } + REQUIRE(unmatching_chars == 0); + } + } + void test_fseek(long offset, int whence) { + status_orig_ = fseek(fh_orig_, offset, whence); + int status = fseek(fh_cmp_, offset, whence); + REQUIRE(status == status_orig_); + } +}; + +} // namespace hermes::adapter::test + +#if defined(HERMES_MPI_TESTS) +#define TESTER \ + hshm::EasySingleton< \ + hermes::adapter::test::StdioTest>::GetInstance() +#else +#define TESTER \ + hshm::EasySingleton>::GetInstance() +#endif + +#endif // HERMES_TEST_UNIT_HERMES_ADAPTERS_STDIO_STDIO_ADAPTER_TEST_H_ diff --git a/test/unit/hermes_adapters/stdio/tests.py b/test/unit/hermes_adapters/stdio/tests.py deleted file mode 100644 index bbcf12ce8..000000000 --- a/test/unit/hermes_adapters/stdio/tests.py +++ /dev/null @@ -1,120 +0,0 @@ -from py_hermes_ci.test_manager import TestManager -from jarvis_util import * - - -class StdioTestManager(TestManager): - def spawn_all_nodes(self): - return self.spawn_info() - - def set_paths(self): - self.STDIO_CMD = f"{self.CMAKE_BINARY_DIR}/bin/stdio_adapter_test" - self.HERMES_STDIO_CMD = f"{self.CMAKE_BINARY_DIR}/bin/hermes_stdio_adapter_test" - self.STDIO_MPI_CMD = f"{self.CMAKE_BINARY_DIR}/bin/stdio_adapter_mpi_test" - self.HERMES_STDIO_MPI_CMD = f"{self.CMAKE_BINARY_DIR}/bin/hermes_stdio_adapter_mpi_test" - self.STDIO_SIMPLE_IO_CMD = f"{self.CMAKE_BINARY_DIR}/bin/stdio_simple_io" - self.HERMES_STDIO_SIMPLE_IO_CMD = f"{self.CMAKE_BINARY_DIR}/bin/hermes_stdio_simple_io" - - self.HERMES_STDIO_MAPPER_CMD = f"{self.CMAKE_BINARY_DIR}/bin/stdio_adapter_mapper_test" - self.HERMES_STDIO_LOW_BUF_CMD = f"{self.CMAKE_BINARY_DIR}/bin/hermes_stdio_low_buf_adapter_test" - self.HERMES_STDIO_MODE_CMD = f"{self.CMAKE_BINARY_DIR}/bin/hermes_stdio_adapter_mode_test" - - self.disable_testing = False - - def test_stdio_basic(self): - return - stdio_cmd = f"{self.STDIO_CMD}" - node = Exec(stdio_cmd) - return node.exit_code - - def test_hermes_stdio_mapper(self): - stdio_cmd = f"{self.HERMES_STDIO_MAPPER_CMD} " - spawn_info = self.spawn_info(nprocs=1, - hermes_conf='hermes_server') - self.start_daemon(spawn_info) - node = Exec(stdio_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_stdio_basic_small(self): - stdio_cmd = f"{self.HERMES_STDIO_CMD} " \ - f"~[request_size=range-large] " \ - f"--reporter compact -d yes" - spawn_info = self.spawn_info(nprocs=1, - hermes_conf='hermes_server') - self.start_daemon(spawn_info) - node = Exec(stdio_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_stdio_basic_large(self): - stdio_cmd = f"{self.HERMES_STDIO_CMD} " \ - f"[request_size=range-large] " \ - f"--reporter compact -d yes" - spawn_info = self.spawn_info(nprocs=1, - hermes_conf='hermes_server') - self.start_daemon(spawn_info) - node = Exec(stdio_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_stdio_mpi_small(self): - stdio_cmd = f"{self.HERMES_STDIO_MPI_CMD} " \ - f"~[request_size=range-large] " \ - f"--reporter compact -d yes" - spawn_info = self.spawn_info(nprocs=2, - hermes_conf='hermes_server') - self.start_daemon(spawn_info) - node = Exec(stdio_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_stdio_mpi_large(self): - stdio_cmd = f"{self.HERMES_STDIO_MPI_CMD} " \ - f"[request_size=range-large] " \ - f"--reporter compact -d yes" - spawn_info = self.spawn_info(nprocs=2, - hermes_conf='hermes_server') - self.start_daemon(spawn_info) - node = Exec(stdio_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_stdio_low_buf(self): - stdio_cmd = f"{self.HERMES_STDIO_LOW_BUF_CMD} " - spawn_info = self.spawn_info(nprocs=1, - hermes_conf='hermes_server') - self.start_daemon(spawn_info) - node = Exec(stdio_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_stdio_bypass(self): - stdio_cmd = f"{self.HERMES_STDIO_MODE_CMD} [hermes_mode=bypass]" - spawn_info = self.spawn_info(nprocs=1, - hermes_conf='hermes_server', - hermes_mode='kBypass') - self.start_daemon(spawn_info) - node = Exec(stdio_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_stdio_default(self): - stdio_cmd = f"{self.HERMES_STDIO_MODE_CMD} [hermes_mode=persistent]" - spawn_info = self.spawn_info(nprocs=1, - hermes_conf='hermes_server', - hermes_mode='kDefault') - self.start_daemon(spawn_info) - node = Exec(stdio_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_stdio_scratch(self): - stdio_cmd = f"{self.HERMES_STDIO_MODE_CMD} [hermes_mode=scratch]" - spawn_info = self.spawn_info(nprocs=1, - hermes_conf='hermes_server', - hermes_mode='kScratch') - self.start_daemon(spawn_info) - node = Exec(stdio_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - diff --git a/test/unit/hermes_adapters/vfd/CMakeLists.txt b/test/unit/hermes_adapters/vfd/CMakeLists.txt index 6d40c8625..030843d1e 100644 --- a/test/unit/hermes_adapters/vfd/CMakeLists.txt +++ b/test/unit/hermes_adapters/vfd/CMakeLists.txt @@ -4,14 +4,16 @@ set(hermes_vfd_tests hermes_vfd_adapter_test ) -add_executable(hermes_vfd_adapter_test ${CMAKE_CURRENT_SOURCE_DIR}/hermes_vfd_test.cc) +add_executable(hermes_vfd_adapter_test + ${CMAKE_CURRENT_SOURCE_DIR}/hermes_vfd_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/hermes_vfd_basic_test.cc) target_include_directories(hermes_vfd_adapter_test PRIVATE ${HERMES_VFD_DIR}) target_include_directories(hermes_vfd_adapter_test PRIVATE ${HERMES_ADAPTER_TEST_DIR}) target_include_directories(hermes_vfd_adapter_test SYSTEM PRIVATE ${HDF5_HERMES_VFD_EXT_INCLUDE_DEPENDENCIES} ) -set_target_properties(hermes_vfd_adapter_test - PROPERTIES COMPILE_FLAGS "-DHERMES_INTERCEPT=1") +target_compile_definitions(hermes_vfd_adapter_test PUBLIC + HERMES_INTERCEPT=1 HERMES_MPI_TESTS=true) add_dependencies(hermes_vfd_adapter_test hermes) target_link_libraries(hermes_vfd_adapter_test hermes @@ -20,5 +22,5 @@ target_link_libraries(hermes_vfd_adapter_test stdc++fs ${HDF5_HERMES_VFD_EXT_LIB_DEPENDENCIES}) -pytest(vfd test_hermes_vfd_default) -pytest(vfd test_hermes_vfd_scratch) \ No newline at end of file +jarvis_test(vfd test_hermes_vfd_basic) +jarvis_test(vfd test_hermes_vfd_scratch) \ No newline at end of file diff --git a/test/unit/hermes_adapters/vfd/hermes_vfd_basic_test.cc b/test/unit/hermes_adapters/vfd/hermes_vfd_basic_test.cc index f0c2eca7f..bde7cba2b 100644 --- a/test/unit/hermes_adapters/vfd/hermes_vfd_basic_test.cc +++ b/test/unit/hermes_adapters/vfd/hermes_vfd_basic_test.cc @@ -10,11 +10,12 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -using hermes::adapter::vfd::test::MuteHdf5Errors; +#include "hermes_vfd_test.h" +using hermes::adapter::test::MuteHdf5Errors; /** Returns a number in the range [1, upper_bound] */ static inline size_t Random1ToUpperBound(size_t upper_bound) { - size_t result = ((size_t)GenNextRandom() % upper_bound) + 1; + size_t result = ((size_t)TESTER->GenNextRandom() % upper_bound) + 1; return result; } @@ -27,693 +28,717 @@ static inline std::string RandomDatasetName(size_t upper_bound) { return result; } -TEST_CASE("H5FOpen", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_open]" - "[repetition=1][file=1]") { - Pretest(); +TEST_CASE("H5FOpen", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_open]" + "[repetition=1][file=1]") { + TESTER->Pretest(); SECTION("open non-existent file") { MuteHdf5Errors mute; - test::TestOpen(info.new_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid == H5I_INVALID_HID); - test::TestOpen(info.new_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid == H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_RDONLY); + REQUIRE(TESTER->hermes_hid_ == H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ == H5I_INVALID_HID); } SECTION("truncate existing file") { - test::TestOpen(info.existing_file, H5F_ACC_TRUNC, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_TRUNC, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("open existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDONLY); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("create existing file exclusively") { MuteHdf5Errors mute; - test::TestOpen(info.existing_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid == H5I_INVALID_HID); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ == H5I_INVALID_HID); } - Posttest(); + TESTER->Posttest(); } -TEST_CASE("SingleWrite", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_write]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - Pretest(); +TEST_CASE("SingleWrite", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_write]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); SECTION("overwrite dataset in existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWritePartial1d("0", info.write_data.data(), 0, - info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + TESTER->TestWritePartial1d("0", TESTER->write_data_.data(), 0, + TESTER->request_size_); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("write to new file") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWriteDataset("0", info.write_data); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + TESTER->TestWriteDataset("0", TESTER->write_data_); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("write to existing file with truncate") { - test::TestOpen(info.existing_file, H5F_ACC_TRUNC, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWriteDataset("0", info.write_data); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_TRUNC, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + TESTER->TestWriteDataset("0", TESTER->write_data_); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("add dataset to existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWriteDataset(std::to_string(info.num_iterations), - info.write_data); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + TESTER->TestWriteDataset(std::to_string(TESTER->num_iterations_), + TESTER->write_data_); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } -TEST_CASE("SingleRead", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=single_read]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - Pretest(); +TEST_CASE("SingleRead", "[process=" + std::to_string(TESTER->comm_size_) + + "]" + "[operation=single_read]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); SECTION("read from non-existing file") { MuteHdf5Errors mute; - test::TestOpen(info.new_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid == H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_RDONLY); + REQUIRE(TESTER->hermes_hid_ == H5I_INVALID_HID); } SECTION("read first dataset from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestRead("0", info.read_data, 0, info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDONLY); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + TESTER->TestRead("0", TESTER->read_data_, 0, + TESTER->request_size_); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("read last dataset of existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestRead(std::to_string(info.num_iterations - 1), info.read_data, 0, - info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - Posttest(); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDONLY); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + TESTER->TestRead(std::to_string(TESTER->num_iterations_ - 1), + TESTER->read_data_, 0, + TESTER->request_size_); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); + } + TESTER->Posttest(); } TEST_CASE("BatchedWriteSequential", - "[process=" + std::to_string(info.comm_size) + + "[process=" + std::to_string(TESTER->comm_size_) + "]" "[operation=batched_write]" "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + + std::to_string(TESTER->num_iterations_) + "]" "[pattern=sequential][file=1]") { - Pretest(); + TESTER->Pretest(); SECTION("write to new file") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestWriteDataset(std::to_string(i), info.write_data); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->TestWriteDataset(std::to_string(i), TESTER->write_data_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("overwrite first dataset") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - test::TestWriteDataset("0", info.write_data); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestWritePartial1d("0", info.write_data.data(), 0, - info.nelems_per_dataset); + TESTER->TestWriteDataset("0", TESTER->write_data_); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->TestWritePartial1d("0", TESTER->write_data_.data(), 0, + TESTER->request_size_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } TEST_CASE("BatchedReadSequential", - "[process=" + std::to_string(info.comm_size) + + "[process=" + std::to_string(TESTER->comm_size_) + "]" "[operation=batched_read]" "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + + std::to_string(TESTER->num_iterations_) + "]" "[pattern=sequential][file=1]") { - Pretest(); + TESTER->Pretest(); SECTION("read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - std::vector buf(info.nelems_per_dataset, 0.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestRead(std::to_string(i), buf, 0, info.nelems_per_dataset); + std::vector buf(TESTER->request_size_, 0.0f); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->TestRead(std::to_string(i), buf, 0, + TESTER->request_size_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("read from existing file always at start") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestRead("0", info.read_data, 0, info.nelems_per_dataset); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->TestRead("0", TESTER->read_data_, 0, + TESTER->request_size_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } -TEST_CASE("BatchedReadRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_read]" - "[request_size=type-fixed]" - "[repetition=" + - std::to_string(info.num_iterations) + - "][pattern=random][file=1]") { - Pretest(); +TEST_CASE("BatchedReadRandom", "[process=" + + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_read]" + "[request_size=type-fixed]" + "[repetition=" + + std::to_string(TESTER->num_iterations_) + + "][pattern=random][file=1]") { + TESTER->Pretest(); SECTION("read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - std::vector buf(info.nelems_per_dataset, 0.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - u32 dataset = GenNextRandom() % info.num_iterations; - test::TestRead(std::to_string(dataset), buf, 0, info.nelems_per_dataset); + std::vector buf(TESTER->request_size_, 0.0f); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + u32 dataset = TESTER->GenNextRandom() % TESTER->num_iterations_; + TESTER->TestRead(std::to_string(dataset), buf, 0, TESTER->request_size_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } -TEST_CASE("BatchedUpdateRandom", "[process=" + std::to_string(info.comm_size) + - "]" - "[operation=batched_write]" - "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + - "]" - "[pattern=random][file=1]") { - Pretest(); +TEST_CASE("BatchedUpdateRandom", "[process=" + + std::to_string(TESTER->comm_size_) + + "]" + "[operation=batched_write]" + "[request_size=type-fixed][repetition=" + + std::to_string(TESTER->num_iterations_) + + "]" + "[pattern=random][file=1]") { + TESTER->Pretest(); SECTION("update entire dataset in existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - u32 dataset = GenNextRandom() % info.num_iterations; - test::TestWritePartial1d(std::to_string(dataset), info.write_data.data(), - 0, info.nelems_per_dataset); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + u32 dataset = TESTER->GenNextRandom() % TESTER->num_iterations_; + TESTER->TestWritePartial1d(std::to_string(dataset), + TESTER->write_data_.data(), + 0, TESTER->request_size_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("update partial dataset in existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { - u32 dataset = GenNextRandom() % info.num_iterations; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + u32 dataset = TESTER->GenNextRandom() % TESTER->num_iterations_; // NOTE(chogan): Subtract 1 from size so we're always writing at least 1 // element - hsize_t offset = GenNextRandom() % (info.write_data.size() - 1); - hsize_t elements_to_write = info.write_data.size() - offset; - test::TestWritePartial1d(std::to_string(dataset), info.write_data.data(), - offset, elements_to_write); + hsize_t offset = TESTER->GenNextRandom() % + (TESTER->write_data_.size() - 1); + hsize_t elements_to_write = TESTER->write_data_.size() - offset; + TESTER->TestWritePartial1d(std::to_string(dataset), + TESTER->write_data_.data(), + offset, elements_to_write); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } TEST_CASE("BatchedWriteRSVariable", - "[process=" + std::to_string(info.comm_size) + + "[process=" + std::to_string(TESTER->comm_size_) + "]" "[operation=batched_write]" "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + + std::to_string(TESTER->num_iterations_) + "]" "[pattern=sequential][file=1]") { - Pretest(); + TESTER->Pretest(); SECTION("write to new file always at the start") { MuteHdf5Errors mute; - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = Random1ToUpperBound(TESTER->request_size_); std::vector data(request_size, 2.0f); - test::TestWritePartial1d(std::to_string(i), data.data(), 0, request_size); + TESTER->TestWritePartial1d(std::to_string(i), data.data(), + 0, request_size); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } TEST_CASE("BatchedReadSequentialRSVariable", - "[process=" + std::to_string(info.comm_size) + + "[process=" + std::to_string(TESTER->comm_size_) + "]" "[operation=batched_read]" "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + + std::to_string(TESTER->num_iterations_) + "]" "[pattern=sequential][file=1]") { - Pretest(); + TESTER->Pretest(); SECTION("read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDONLY); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); - size_t starting_element = info.nelems_per_dataset - request_size; + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = Random1ToUpperBound(TESTER->request_size_); + size_t starting_element = TESTER->request_size_ - request_size; std::vector data(request_size, 1.5f); - test::TestRead(std::to_string(i), data, starting_element, request_size); + TESTER->TestRead(std::to_string(i), data, + starting_element, request_size); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("read from existing file always at start") { - test::TestOpen(info.existing_file, H5F_ACC_RDONLY); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDONLY); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { - size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + size_t request_size = Random1ToUpperBound(TESTER->request_size_); std::vector data(request_size, 3.0f); - test::TestRead(std::to_string(i), data, 0, request_size); + TESTER->TestRead(std::to_string(i), data, 0, request_size); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } TEST_CASE("BatchedReadRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + + "[process=" + std::to_string(TESTER->comm_size_) + "]" "[operation=batched_read]" "[request_size=type-variable]" "[repetition=" + - std::to_string(info.num_iterations) + + std::to_string(TESTER->num_iterations_) + "][pattern=random][file=1]") { - Pretest(); + TESTER->Pretest(); SECTION("read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - std::vector data(info.nelems_per_dataset, 5.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = RandomDatasetName(info.num_iterations); - size_t starting_element = Random1ToUpperBound(info.nelems_per_dataset); + std::vector data(TESTER->request_size_, 5.0f); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + std::string dset_name = RandomDatasetName(TESTER->num_iterations_); + size_t starting_element = Random1ToUpperBound(TESTER->request_size_); size_t request_elements = - Random1ToUpperBound(info.nelems_per_dataset - starting_element); + Random1ToUpperBound(TESTER->request_size_ - starting_element); std::vector data(request_elements, 3.8f); - test::TestRead(dset_name, data, starting_element, request_elements); + TESTER->TestRead(dset_name, data, starting_element, request_elements); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } TEST_CASE("BatchedUpdateRandomRSVariable", - "[process=" + std::to_string(info.comm_size) + + "[process=" + std::to_string(TESTER->comm_size_) + "]" "[operation=batched_write]" "[request_size=type-variable][repetition=" + - std::to_string(info.num_iterations) + + std::to_string(TESTER->num_iterations_) + "]" "[pattern=random][file=1]") { - Pretest(); + TESTER->Pretest(); SECTION("write to existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - std::vector data(info.nelems_per_dataset, 8.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = RandomDatasetName(info.num_iterations); - size_t request_size = Random1ToUpperBound(info.nelems_per_dataset); - test::TestWritePartial1d(dset_name, data.data(), 0, request_size); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + + std::vector data(TESTER->request_size_, 8.0f); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + std::string dset_name = RandomDatasetName(TESTER->num_iterations_); + size_t request_size = Random1ToUpperBound(TESTER->request_size_); + TESTER->TestWritePartial1d(dset_name, data.data(), 0, request_size); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } TEST_CASE("BatchedWriteTemporalFixed", - "[process=" + std::to_string(info.comm_size) + + "[process=" + std::to_string(TESTER->comm_size_) + "]" "[operation=batched_write]" "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + + std::to_string(TESTER->num_iterations_) + "]" "[pattern=sequential][file=1][temporal=fixed]") { - Pretest(); + TESTER->Pretest(); SECTION("write to existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::TestWritePartial1d(std::to_string(i), info.write_data.data(), 0, - info.nelems_per_dataset); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->TestWritePartial1d(std::to_string(i), + TESTER->write_data_.data(), 0, + TESTER->request_size_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("write to new file always at start") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { - usleep(info.temporal_interval_ms * 1000); - test::TestWriteDataset(std::to_string(i), info.write_data); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + usleep(TESTER->temporal_interval_ms_ * 1000); + TESTER->TestWriteDataset(std::to_string(i), TESTER->write_data_); } - test::TestClose(); + TESTER->TestClose(); } - Posttest(); + TESTER->Posttest(); } TEST_CASE("BatchedWriteTemporalVariable", - "[process=" + std::to_string(info.comm_size) + + "[process=" + std::to_string(TESTER->comm_size_) + "]" "[operation=batched_write]" "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + + std::to_string(TESTER->num_iterations_) + "]" "[pattern=sequential][file=1][temporal=variable]") { - Pretest(); + TESTER->Pretest(); SECTION("write to existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { size_t sleep_interval_ms = - GenNextRandom() % (info.temporal_interval_ms + 2); + TESTER->GenNextRandom() % (TESTER->temporal_interval_ms_ + 2); usleep(sleep_interval_ms * 1000); - test::TestWritePartial1d(std::to_string(i), info.write_data.data(), 0, - info.nelems_per_dataset); + TESTER->TestWritePartial1d(std::to_string(i), + TESTER->write_data_.data(), 0, + TESTER->request_size_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("write to new file always at start") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { size_t sleep_interval_ms = - GenNextRandom() % (info.temporal_interval_ms + 2); + TESTER->GenNextRandom() % (TESTER->temporal_interval_ms_ + 2); usleep(sleep_interval_ms * 1000); - test::TestWriteDataset(std::to_string(i), info.write_data); + TESTER->TestWriteDataset(std::to_string(i), TESTER->write_data_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } TEST_CASE("BatchedMixedSequential", - "[process=" + std::to_string(info.comm_size) + + "[process=" + std::to_string(TESTER->comm_size_) + "]" "[operation=batched_mixed]" "[request_size=type-fixed][repetition=" + - std::to_string(info.num_iterations) + + std::to_string(TESTER->num_iterations_) + "]" "[pattern=sequential][file=1]") { - Pretest(); + TESTER->Pretest(); SECTION("read after write on new file") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { std::string dset_name = std::to_string(i); - test::TestWriteDataset(dset_name, info.write_data); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); + TESTER->TestWriteDataset(dset_name, TESTER->write_data_); + TESTER->TestRead(dset_name, TESTER->read_data_, + 0, TESTER->request_size_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("alternate write and read existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { std::string dset_name = std::to_string(i); if (i % 2 == 0) { - test::TestWritePartial1d(dset_name, info.write_data.data(), 0, - info.nelems_per_dataset); + TESTER->TestWritePartial1d(dset_name, TESTER->write_data_.data(), + 0, TESTER->request_size_); } else { - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); + TESTER->TestRead(dset_name, TESTER->read_data_, + 0, TESTER->request_size_); } } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("update after read existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { std::string dset_name = std::to_string(i); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - test::TestWritePartial1d(dset_name, info.write_data.data(), 0, - info.nelems_per_dataset); + TESTER->TestRead(dset_name, TESTER->read_data_, + 0, TESTER->request_size_); + TESTER->TestWritePartial1d(dset_name, TESTER->write_data_.data(), 0, + TESTER->request_size_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("read all after write all on new file in single open") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { std::string dset_name = std::to_string(i); - test::TestWriteDataset(dset_name, info.write_data); + TESTER->TestWriteDataset(dset_name, TESTER->write_data_); } - for (size_t i = 0; i < info.num_iterations; ++i) { + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { std::string dset_name = std::to_string(i); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); + TESTER->TestRead(dset_name, TESTER->read_data_, + 0, TESTER->request_size_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("read all after write all on new file in different open") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestWriteDataset(std::to_string(i), info.write_data); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->TestWriteDataset(std::to_string(i), TESTER->write_data_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); - test::TestOpen(info.new_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestRead(std::to_string(i), info.read_data, 0, - info.nelems_per_dataset); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->TestRead(std::to_string(i), TESTER->read_data_, 0, + TESTER->request_size_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } -TEST_CASE("SingleMixed", "[process=" + std::to_string(info.comm_size) + - "][operation=single_mixed]" - "[request_size=type-fixed][repetition=1]" - "[file=1]") { - Pretest(); +TEST_CASE("SingleMixed", "[process=" + std::to_string(TESTER->comm_size_) + + "][operation=single_mixed]" + "[request_size=type-fixed][repetition=1]" + "[file=1]") { + TESTER->Pretest(); SECTION("read after write from new file") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); std::string dset_name("0"); - test::TestWriteDataset(dset_name, info.write_data); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestWriteDataset(dset_name, TESTER->write_data_); + TESTER->TestRead(dset_name, TESTER->read_data_, + 0, TESTER->request_size_); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("update after read from existing file") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); std::string dset_name("0"); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - test::TestWritePartial1d(dset_name, info.write_data.data(), 0, - info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestRead(dset_name, TESTER->read_data_, + 0, TESTER->request_size_); + TESTER->TestWritePartial1d(dset_name, TESTER->write_data_.data(), 0, + TESTER->request_size_); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("read after write from new file different opens") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); std::string dset_name("0"); - test::TestWriteDataset(dset_name, info.write_data); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestWriteDataset(dset_name, TESTER->write_data_); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); - test::TestOpen(info.new_file, H5F_ACC_RDWR); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_RDWR); + TESTER->TestRead(dset_name, TESTER->read_data_, + 0, TESTER->request_size_); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } TEST_CASE("CompactDatasets") { - Pretest(); + TESTER->Pretest(); SECTION("create many and read randomly") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); size_t num_elements = KILOBYTES(32) / sizeof(f32); - for (size_t i = 0; i < info.num_iterations; ++i) { + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { std::vector data(num_elements); for (size_t i = 0; i < data.size(); ++i) { - data[i] = GenRandom0to1(); + data[i] = TESTER->GenRandom0to1(); } - test::TestMakeCompactDataset(std::to_string(i), data); + TESTER->TestMakeCompactDataset(std::to_string(i), data); } std::vector read_buf(num_elements, 0.0f); - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = RandomDatasetName(info.num_iterations); - test::TestRead(dset_name, read_buf, 0, num_elements); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + std::string dset_name = RandomDatasetName(TESTER->num_iterations_); + TESTER->TestRead(dset_name, read_buf, 0, num_elements); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } - Posttest(); + TESTER->Posttest(); } TEST_CASE("PartialUpdateToLastPage") { - Pretest(); + TESTER->Pretest(); SECTION("beginning of last page") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWritePartial1d(std::to_string(info.num_iterations - 1), - info.write_data.data(), 0, - info.nelems_per_dataset / 2); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + TESTER->TestWritePartial1d( + std::to_string(TESTER->num_iterations_ - 1), + TESTER->write_data_.data(), 0, + TESTER->request_size_ / 2); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("in middle of last page") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWritePartial1d(std::to_string(info.num_iterations - 1), - info.write_data.data(), - info.nelems_per_dataset / 4, - info.nelems_per_dataset / 2); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + TESTER->TestWritePartial1d( + std::to_string(TESTER->num_iterations_ - 1), + TESTER->write_data_.data(), + TESTER->request_size_ / 4, + TESTER->request_size_ / 2); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); } SECTION("at end of last page") { - test::TestOpen(info.existing_file, H5F_ACC_RDWR); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); - test::TestWritePartial1d(std::to_string(info.num_iterations - 1), - info.write_data.data(), - info.nelems_per_dataset / 2, - info.nelems_per_dataset / 2); - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); - } - - Posttest(); + TESTER->TestOpen(TESTER->existing_file_, H5F_ACC_RDWR); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); + TESTER->TestWritePartial1d( + std::to_string(TESTER->num_iterations_ - 1), + TESTER->write_data_.data(), + TESTER->request_size_ / 2, + TESTER->request_size_ / 2); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); + } + + TESTER->Posttest(); } -TEST_CASE("ScratchMode", "[scratch]") { - Pretest(); +TEST_CASE("ScratchMode", "[mode=scratch]") { + TESTER->Pretest(); SECTION("created files shouldn't persist") { - test::TestOpen(info.new_file, H5F_ACC_EXCL, true); - REQUIRE(test::hermes_hid != H5I_INVALID_HID); + TESTER->TestOpen(TESTER->new_file_, H5F_ACC_EXCL, true); + REQUIRE(TESTER->hermes_hid_ != H5I_INVALID_HID); - for (size_t i = 0; i < info.num_iterations; ++i) { - test::TestWriteDataset(std::to_string(i), info.write_data); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + TESTER->TestWriteDataset(std::to_string(i), TESTER->write_data_); } - for (size_t i = 0; i < info.num_iterations; ++i) { - std::string dset_name = RandomDatasetName(info.num_iterations); - test::TestRead(dset_name, info.read_data, 0, info.nelems_per_dataset); + for (size_t i = 0; i < TESTER->num_iterations_; ++i) { + std::string dset_name = RandomDatasetName(TESTER->num_iterations_); + TESTER->TestRead(dset_name, TESTER->read_data_, + 0, TESTER->request_size_); } - test::TestClose(); - REQUIRE(test::hermes_herr >= 0); + TESTER->TestClose(); + REQUIRE(TESTER->hermes_herr_ >= 0); if (HERMES_CLIENT_CONF.GetBaseAdapterMode() == hermes::adapter::AdapterMode::kScratch) { - REQUIRE(!stdfs::exists(info.new_file)); + REQUIRE(!stdfs::exists(TESTER->new_file_.hermes_)); } } - Posttest(); + TESTER->Posttest(); } diff --git a/test/unit/hermes_adapters/vfd/hermes_vfd_test.cc b/test/unit/hermes_adapters/vfd/hermes_vfd_test.cc index ce2711315..3e9da19f1 100644 --- a/test/unit/hermes_adapters/vfd/hermes_vfd_test.cc +++ b/test/unit/hermes_adapters/vfd/hermes_vfd_test.cc @@ -10,595 +10,8 @@ * have access to the file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include -#include -#include -#include -#include +#include "hermes_vfd_test.h" -#include -#include - -#include -#include - -#include "hermes/hermes.h" -#include "hermes_types.h" -#include "adapter_test_utils.h" -#include "catch_config.h" - -using hermes::f32; -using hermes::u32; -namespace stdfs = std::filesystem; - -namespace hermes::adapter::vfd::test { - -/** - A structure to represent test arguments -*/ -struct Arguments { - std::string filename = "test"; /**< test file name */ - std::string directory = "/tmp/test_hermes"; /**< test directory name */ - size_t request_size = 65536; /**< test request size */ -}; - -/** - A structure to represent test information -*/ -struct TestInfo { - static inline const int element_size = sizeof(f32); /**< test element size */ - - // int rank = 0; - int comm_size = 1; /**< communicator size */ - std::vector write_data; /**< test data for writing */ - std::vector read_data; /**< test data for reading */ - std::string new_file; /**< new file name */ - std::string existing_file; /**< existing file name */ - std::string new_file_cmp; /**< new file name to compare */ - std::string existing_file_cmp; /**< existing file name to compare */ - std::string hdf5_extension = ".h5"; /**< HDF5 file extention to use */ - size_t num_iterations = 64; /**< number of iterations */ - // int offset_seed = 1; - // unsigned int rs_seed = 1; - // unsigned int temporal_interval_seed = 5; - size_t total_size; /**< total size */ - // size_t stride_size = 512; - unsigned int temporal_interval_ms = 1; /**< interval in milliseconds */ - // size_t small_min = 1; - // size_t small_max = KILOBYTES(4); - // size_t medium_min = KILOBYTES(4) + 1; - // size_t medium_max = KILOBYTES(256); - // size_t large_min = KILOBYTES(256) + 1; - // size_t large_max = MEGABYTES(3); - size_t nelems_per_dataset; /**< number of elements per dataset */ -}; - -/** - * Temporarily disable printing of the HDF5 error stack. - * - * Some tests intentionally trigger HDF5 errors, and in those cases we don't - * want to clutter the output with HDF5 error messages. - */ -class MuteHdf5Errors { - H5E_auto2_t old_func; /**< error handler callback function */ - void *old_client_data; /**< pointer to client data for old_func */ - - public: - MuteHdf5Errors() { - // Save old error handler - H5Eget_auto(H5E_DEFAULT, &old_func, &old_client_data); - - // Turn off error stack printing - H5Eset_auto(H5E_DEFAULT, NULL, NULL); - } - - ~MuteHdf5Errors() { - // Restore previous error handler - H5Eset_auto(H5E_DEFAULT, old_func, old_client_data); - } -}; - -/** - * HDF5 identifiers required for reads and writes. - */ -struct RwIds { - hid_t dset_id; /**< dataset ID */ - hid_t dspace_id; /**< data space ID */ - hid_t mspace_id; /**< memory space ID */ -}; - -/** - * The I/O API for this adapter layer. - * - * Ideally we would have a high level Adapter I/O API that each adapter inherits - * from so that the adapter tests can reuse more code. This is a step in that - * direction. - */ -struct Hdf5Api { - /** - * A file access property list representing the sec2 (POSIX) VFD. - */ - hid_t sec2_fapl; - - Hdf5Api() : sec2_fapl(H5I_INVALID_HID) { - sec2_fapl = H5Pcreate(H5P_FILE_ACCESS); - REQUIRE(sec2_fapl != H5I_INVALID_HID); - REQUIRE(H5Pset_fapl_sec2(sec2_fapl) >= 0); - } - - ~Hdf5Api() { - REQUIRE(H5Pclose(sec2_fapl) >= 0); - sec2_fapl = H5I_INVALID_HID; - } - - /** - * Open an existing file using the default VFD. Since the tests are run with - * HDF5_DRIVER=hermes, the default VFD will be the Hermes VFD. - */ - hid_t Open(const std::string &fname, unsigned flags) { - hid_t result = H5Fopen(fname.c_str(), flags, H5P_DEFAULT); - - return result; - } - - /** - * Open an existing file using the POSIX VFD. This will bypass Hermes. - */ - hid_t OpenPosix(const std::string &fname, unsigned flags) { - hid_t result = H5Fopen(fname.c_str(), flags, sec2_fapl); - - return result; - } - - /** - * Create a file using the default VFD. - */ - hid_t Create(const std::string &fname, unsigned flags) { - hid_t result = H5Fcreate(fname.c_str(), flags, H5P_DEFAULT, H5P_DEFAULT); - - return result; - } - - /** - * Create a file using the POSIX VFD. - */ - hid_t CreatePosix(const std::string &fname, unsigned flags) { - hid_t result = H5Fcreate(fname.c_str(), flags, H5P_DEFAULT, sec2_fapl); - - return result; - } - - /** - * Boilerplate necessary before calling H5Dread or H5Dwrite. - */ - RwIds RwPreamble(hid_t hid, const std::string &dset_name, hsize_t offset, - hsize_t nelems, hsize_t stride = 1) { - hid_t dset_id = H5Dopen2(hid, dset_name.c_str(), H5P_DEFAULT); - - hid_t memspace_id = H5Screate_simple(1, &nelems, NULL); - REQUIRE(memspace_id != H5I_INVALID_HID); - - if (dset_id == H5I_INVALID_HID) { - dset_id = H5Dcreate2(hid, dset_name.c_str(), H5T_NATIVE_FLOAT, - memspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - } - - REQUIRE(dset_id != H5I_INVALID_HID); - hid_t dspace_id = H5Dget_space(dset_id); - REQUIRE(dspace_id != H5I_INVALID_HID); - herr_t status = H5Sselect_hyperslab(dspace_id, H5S_SELECT_SET, &offset, - &stride, &nelems, NULL); - REQUIRE(status >= 0); - - RwIds result = {dset_id, dspace_id, memspace_id}; - - return result; - } - - /** - * Cleanup code required after H5Dread and H5Dwrite. - */ - void RwCleanup(RwIds *ids) { - REQUIRE(H5Sclose(ids->mspace_id) >= 0); - REQUIRE(H5Sclose(ids->dspace_id) >= 0); - REQUIRE(H5Dclose(ids->dset_id) >= 0); - } - - /** - * Reads @p nelems elements from the object represented by @p hid into @p buf, - * starting at element @p offset. - */ - void Read(hid_t hid, const std::string &dset_name, std::vector &buf, - hsize_t offset, hsize_t nelems) { - RwIds ids = RwPreamble(hid, dset_name, offset, nelems); - herr_t status = H5Dread(ids.dset_id, H5T_NATIVE_FLOAT, ids.mspace_id, - ids.dspace_id, H5P_DEFAULT, buf.data()); - REQUIRE(status >= 0); - - RwCleanup(&ids); - } - /** - Create a 1-dimensional dataset using \a data vector. - */ - void MakeDataset(hid_t hid, const std::string &dset_name, - const std::vector &data, bool compact = false) { - MakeDataset(hid, dset_name, data.data(), data.size(), compact); - } - - /** - * Create a 1-dimensional dataset named @p dset_name in object @p hid with @p - * nelems elements from the array @p data. - */ - void MakeDataset(hid_t hid, const std::string &dset_name, const f32 *data, - hsize_t nelems, bool compact = false) { - hid_t dcpl = H5P_DEFAULT; - herr_t status = 0; - - if (compact) { - REQUIRE(nelems * sizeof(f32) <= KILOBYTES(64)); - dcpl = H5Pcreate(H5P_DATASET_CREATE); - REQUIRE(dcpl != H5I_INVALID_HID); - status = H5Pset_layout(dcpl, H5D_COMPACT); - REQUIRE(status >= 0); - } - - hid_t memspace_id = H5Screate_simple(1, &nelems, NULL); - REQUIRE(memspace_id != H5I_INVALID_HID); - - hid_t dset_id = H5Dcreate2(hid, dset_name.c_str(), H5T_NATIVE_FLOAT, - memspace_id, H5P_DEFAULT, dcpl, H5P_DEFAULT); - REQUIRE(dset_id != H5I_INVALID_HID); - - hid_t dspace_id = H5Dget_space(dset_id); - REQUIRE(dspace_id != H5I_INVALID_HID); - - status = H5Dwrite(dset_id, H5T_NATIVE_FLOAT, memspace_id, - dspace_id, H5P_DEFAULT, data); - REQUIRE(status >= 0); - REQUIRE(H5Sclose(memspace_id) >= 0); - REQUIRE(H5Sclose(dspace_id) >= 0); - REQUIRE(H5Dclose(dset_id) >= 0); - - if (compact) { - REQUIRE(H5Pclose(dcpl) >= 0); - } - } - - /** - * Write @p nelems elements to the dataset @p dset_name in file @p hid - * starting at element @p offset. The dataset will be created if it doesn't - * already exist. - */ - void WritePartial1d(hid_t hid, const std::string &dset_name, - const f32 *data, hsize_t offset, hsize_t nelems) { - RwIds ids = RwPreamble(hid, dset_name, offset, nelems); - herr_t status = H5Dwrite(ids.dset_id, H5T_NATIVE_FLOAT, ids.mspace_id, - ids.dspace_id, H5P_DEFAULT, data); - REQUIRE(status >= 0); - - RwCleanup(&ids); - } - /** - Close HDF5 file. - */ - herr_t Close(hid_t id) { - herr_t result = H5Fclose(id); - - return result; - } -}; - -// xoshiro128+ random number generation. 2x speedup over std::mt19937: -// https://prng.di.unimi.it/xoshiro128plus.c - -static inline u32 RotateLeft(const u32 x, int k) { - u32 result = (x << k) | (x >> (32 - k)); - - return result; -} - -static u32 random_state[4] = {111, 222, 333, 444}; - -u32 GenNextRandom() { - const u32 random = random_state[0] + random_state[3]; - - const u32 t = random_state[1] << 9; - - random_state[2] ^= random_state[0]; - random_state[3] ^= random_state[1]; - random_state[1] ^= random_state[2]; - random_state[0] ^= random_state[3]; - - random_state[2] ^= t; - - random_state[3] = RotateLeft(random_state[3], 11); - - return random; -} - -/** - * Return a random float in the range [0.0f, 1.0f] - */ -f32 GenRandom0to1() { - u32 random_u32 = GenNextRandom(); - - f32 result = (random_u32 >> 8) * 0x1.0p-24f; - - return result; +int main(int argc, char **argv) { + TESTER->Init(argc, argv); } - -/** - * Create an HDF5 file called @p fname with @p num_datasets datasets, each with - * @p num_dataset_elems elements. - */ -void GenHdf5File(std::string fname, size_t num_dataset_elems, - size_t num_datasets) { - std::vector data(num_dataset_elems * num_datasets); - - for (size_t i = 0; i < data.size(); ++i) { - data[i] = GenRandom0to1(); - } - - Hdf5Api api; - f32 *at = data.data(); - - hid_t file_id = api.CreatePosix(fname, H5F_ACC_TRUNC); - REQUIRE(file_id != H5I_INVALID_HID); - - for (size_t i = 0; i < num_datasets; ++i) { - api.MakeDataset(file_id, std::to_string(i), at, num_dataset_elems); - at += num_dataset_elems; - } - - REQUIRE(api.Close(file_id) > -1); -} - -} // namespace hermes::adapter::vfd::test - -hermes::adapter::vfd::test::Arguments args; -hermes::adapter::vfd::test::TestInfo info; - -using hermes::adapter::vfd::test::GenHdf5File; -using hermes::adapter::vfd::test::GenNextRandom; -using hermes::adapter::vfd::test::GenRandom0to1; - -void IgnoreAllFiles() { -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file_cmp, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, false); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, false); -#endif -} - -void TrackFiles() { -#if HERMES_INTERCEPT == 1 - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.new_file, true); - HERMES_CLIENT_CONF.SetAdapterPathTracking(info.existing_file, true); -#endif -} - -void RemoveFile(const std::string &path) { - stdfs::remove(path); - if (stdfs::exists(path)) { - HELOG(kFatal, "Failed to remove: {}", path) - } -} - -void RemoveFiles() { - RemoveFile(info.new_file); - RemoveFile(info.new_file_cmp); - RemoveFile(info.existing_file); - RemoveFile(info.existing_file_cmp); -} - -/** - * Called in the Catch2 main function (see catch_config.h) before any tests are - * run. Initialize sizes, filenames, and read/write buffers. - */ -int init(int* argc, char*** argv) { -#if HERMES_INTERCEPT == 1 - setenv("HERMES_FLUSH_MODE", "kSync", 1); - TRANSPARENT_HERMES - HERMES_CLIENT_CONF.flushing_mode_ = hermes::FlushingMode::kSync; -#endif - MPI_Init(argc, argv); - - if (args.request_size % info.element_size != 0) { - HELOG(kFatal, "request_size must be a multiple of: {}", info.element_size) - } - info.nelems_per_dataset = args.request_size / info.element_size; - - info.write_data.resize(info.nelems_per_dataset); - for (size_t i = 0; i < info.write_data.size(); ++i) { - info.write_data[i] = GenRandom0to1(); - } - info.read_data.resize(info.nelems_per_dataset); - for (size_t i = 0; i < info.read_data.size(); ++i) { - info.read_data[i] = 0.0f; - } - - stdfs::path fullpath = args.directory; - fullpath /= args.filename; - std::string suffix = std::to_string(getpid()) + info.hdf5_extension; - info.new_file = fullpath.string() + "_new_" + suffix; - info.existing_file = fullpath.string() + "_ext_" + suffix; - info.new_file_cmp = fullpath.string() + "_new_cmp_" + suffix; - info.existing_file_cmp = fullpath.string() + "_ext_cmp_" + suffix; - IgnoreAllFiles(); - RemoveFiles(); - return 0; -} - -/** - * Called from catch_config.h after all tests are run. - */ -int finalize() { - MPI_Finalize(); - return 0; -} - -/** - * Called before each individual test. - * - * Generates files for tests that operate on existing files. - */ -int Pretest() { - IgnoreAllFiles(); - RemoveFiles(); - - GenHdf5File(info.existing_file, info.nelems_per_dataset, info.num_iterations); - info.total_size = stdfs::file_size(info.existing_file); - std::string cmd = "cp " + info.existing_file + " " + info.existing_file_cmp; - int status = system(cmd.c_str()); - REQUIRE(status != -1); - REQUIRE(info.total_size > 0); - - TrackFiles(); - return 0; -} - -/** - * Use h5diff to ensure that the resulting files from the Hermes VFD and the - * POSIX VFD are the same. - */ -void CheckResults(const std::string &file1, const std::string &file2) { - if (stdfs::exists(file1) && stdfs::exists(file2)) { - std::string h5diff_cmd = "h5diff " + file1 + " " + file2; - int status = system(h5diff_cmd.c_str()); - if (status != 0) { - HELOG(kError, "Failing h5diff command: {}", h5diff_cmd) - } - REQUIRE(status == 0); - } -} - -/** - * Called after each individual test. - */ -int Posttest() { - if (HERMES_CLIENT_CONF.GetBaseAdapterMode() - != hermes::adapter::AdapterMode::kScratch) { - // NOTE(chogan): This is necessary so that h5diff doesn't use the Hermes VFD - // in CheckResults. We don't need to reset LD_PRELOAD because it only has an - // effect when an application first starts. - unsetenv("HDF5_DRIVER"); - // CheckResults(info.new_file, info.new_file_cmp); - // CheckResults(info.existing_file, info.existing_file_cmp); - setenv("HDF5_DRIVER", "hdf5_hermes_vfd", 1); - } - - RemoveFiles(); -#if HERMES_INTERCEPT == 1 - HERMES->Clear(); -#endif - - return 0; -} - -cl::Parser define_options() { - return cl::Opt(args.filename, "filename")["-f"]["--filename"]( - "Filename used for performing I/O") | - cl::Opt(args.directory, "dir")["-d"]["--directory"]( - "Directory used for performing I/O") | - cl::Opt(args.request_size, "request_size")["-s"]["--request_size"]( - "Request size used for performing I/O"); -} - -using hermes::adapter::vfd::test::Hdf5Api; - -/** - * The functions in this namespace perform operations on 2 files: the "main" - * file, which is the one going through the Hermes VFD, and a comparison file - * (with a "_cmp" suffix) which goes through the POSIX VFD. The idea is to - * perfrom each test on 2 files (Hermes VFD and POSIX VFD) and then compare the - * results at the end with h5diff. In persistent mode, the file produced by the - * Hermes VFD should be exactly the same as the one produced by the POSIX VFD. - */ -namespace test { - -hid_t hermes_hid; /**< Hermes handle ID */ -hid_t sec2_hid; /**< POSIX driver handle ID */ -herr_t hermes_herr; /**< Hermes error return value */ -/** - Test creating and opening a new file. -*/ -void TestOpen(const std::string &path, unsigned flags, bool create = false) { - Hdf5Api api; - - std::string cmp_path; - if (path == info.new_file) { - cmp_path = info.new_file_cmp; - } else { - cmp_path = info.existing_file_cmp; - } - - if (create) { - hermes_hid = api.Create(path, flags); - sec2_hid = api.CreatePosix(cmp_path, flags); - } else { - hermes_hid = api.Open(path, flags); - sec2_hid = api.OpenPosix(cmp_path, flags); - } - bool is_same = - (sec2_hid != H5I_INVALID_HID && hermes_hid != H5I_INVALID_HID) || - (sec2_hid == H5I_INVALID_HID && hermes_hid == H5I_INVALID_HID); - - REQUIRE(is_same); -} -/** - Test Close() calls. -*/ -void TestClose() { - Hdf5Api api; - hermes_herr = api.Close(hermes_hid); - herr_t status = api.Close(sec2_hid); - REQUIRE(status == hermes_herr); -} - -/** - Test writing partial 1-D dataset. -*/ -void TestWritePartial1d(const std::string &dset_name, const f32 *data, - hsize_t offset, hsize_t nelems) { - Hdf5Api api; - api.WritePartial1d(test::hermes_hid, dset_name, data, offset, nelems); - api.WritePartial1d(test::sec2_hid, dset_name, data, offset, nelems); -} - -/** - Test making dataset. -*/ -void TestWriteDataset(const std::string &dset_name, - const std::vector &data) { - Hdf5Api api; - api.MakeDataset(test::hermes_hid, dset_name, data); - api.MakeDataset(test::sec2_hid, dset_name, data); -} - - -/** - Test making compact dataset. -*/ -void TestMakeCompactDataset(const std::string &dset_name, - const std::vector &data) { - Hdf5Api api; - api.MakeDataset(test::hermes_hid, dset_name, data, true); - api.MakeDataset(test::sec2_hid, dset_name, data, true); -} - -/** - Test reading dataset. -*/ -void TestRead(const std::string &dset_name, std::vector &buf, - hsize_t offset, hsize_t nelems) { - Hdf5Api api; - api.Read(test::hermes_hid, dset_name, buf, offset, nelems); - std::vector sec2_read_buf(nelems, 0.0f); - api.Read(test::sec2_hid, dset_name, sec2_read_buf, offset, nelems); - - REQUIRE(std::equal(buf.begin(), buf.begin() + nelems, sec2_read_buf.begin())); -} -} // namespace test - -#include "hermes_vfd_basic_test.cc" diff --git a/test/unit/hermes_adapters/vfd/hermes_vfd_test.h b/test/unit/hermes_adapters/vfd/hermes_vfd_test.h new file mode 100644 index 000000000..4742a4164 --- /dev/null +++ b/test/unit/hermes_adapters/vfd/hermes_vfd_test.h @@ -0,0 +1,409 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Distributed under BSD 3-Clause license. * + * Copyright by The HDF Group. * + * Copyright by the Illinois Institute of Technology. * + * All rights reserved. * + * * + * This file is part of Hermes. The full Hermes copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the top directory. If you do not * + * have access to the file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef HERMES_TEST_UNIT_HERMES_ADAPTERS_HDF5_VFD_TESTS_H_ +#define HERMES_TEST_UNIT_HERMES_ADAPTERS_HDF5_VFD_TESTS_H_ + +#include "filesystem_tests.h" +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "hermes_shm/util/singleton.h" +#include "hermes/hermes.h" + +#define CATCH_CONFIG_RUNNER +#include +#include + +namespace hermes::adapter::test { + +/** + * Temporarily disable printing of the HDF5 error stack. + * + * Some tests intentionally trigger HDF5 errors, and in those cases we don't + * want to clutter the output with HDF5 error messages. + */ +class MuteHdf5Errors { + H5E_auto2_t old_func; /**< error handler callback function */ + void *old_client_data; /**< pointer to client data for old_func */ + + public: + MuteHdf5Errors() { + // Save old error handler + H5Eget_auto(H5E_DEFAULT, &old_func, &old_client_data); + + // Turn off error stack printing + H5Eset_auto(H5E_DEFAULT, NULL, NULL); + } + + ~MuteHdf5Errors() { + // Restore previous error handler + H5Eset_auto(H5E_DEFAULT, old_func, old_client_data); + } +}; + +/** + * HDF5 identifiers required for reads and writes. + */ +struct RwIds { + hid_t dset_id; /**< dataset ID */ + hid_t dspace_id; /**< data space ID */ + hid_t mspace_id; /**< memory space ID */ +}; + +/** + * The I/O API for this adapter layer. + * + * Ideally we would have a high level Adapter I/O API that each adapter inherits + * from so that the adapter tests can reuse more code. This is a step in that + * direction. + */ +struct Hdf5Api { + /** + * A file access property list representing the sec2 (POSIX) VFD. + */ + hid_t sec2_fapl; + + Hdf5Api() : sec2_fapl(H5I_INVALID_HID) { + sec2_fapl = H5Pcreate(H5P_FILE_ACCESS); + REQUIRE(sec2_fapl != H5I_INVALID_HID); + REQUIRE(H5Pset_fapl_sec2(sec2_fapl) >= 0); + } + + ~Hdf5Api() { + REQUIRE(H5Pclose(sec2_fapl) >= 0); + sec2_fapl = H5I_INVALID_HID; + } + + /** + * Open an existing file using the default VFD. Since the tests are run with + * HDF5_DRIVER=hermes, the default VFD will be the Hermes VFD. + */ + hid_t Open(const std::string &fname, unsigned flags) { + hid_t result = H5Fopen(fname.c_str(), flags, H5P_DEFAULT); + + return result; + } + + /** + * Open an existing file using the POSIX VFD. This will bypass Hermes. + */ + hid_t OpenPosix(const std::string &fname, unsigned flags) { + hid_t result = H5Fopen(fname.c_str(), flags, sec2_fapl); + + return result; + } + + /** + * Create a file using the default VFD. + */ + hid_t Create(const std::string &fname, unsigned flags) { + hid_t result = H5Fcreate(fname.c_str(), flags, H5P_DEFAULT, H5P_DEFAULT); + + return result; + } + + /** + * Create a file using the POSIX VFD. + */ + hid_t CreatePosix(const std::string &fname, unsigned flags) { + hid_t result = H5Fcreate(fname.c_str(), flags, H5P_DEFAULT, sec2_fapl); + + return result; + } + + /** + * Boilerplate necessary before calling H5Dread or H5Dwrite. + */ + RwIds RwPreamble(hid_t hid, const std::string &dset_name, hsize_t offset, + hsize_t nelems, hsize_t stride = 1) { + hid_t dset_id = H5Dopen2(hid, dset_name.c_str(), H5P_DEFAULT); + + hid_t memspace_id = H5Screate_simple(1, &nelems, NULL); + REQUIRE(memspace_id != H5I_INVALID_HID); + + if (dset_id == H5I_INVALID_HID) { + dset_id = H5Dcreate2(hid, dset_name.c_str(), H5T_NATIVE_FLOAT, + memspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + + REQUIRE(dset_id != H5I_INVALID_HID); + hid_t dspace_id = H5Dget_space(dset_id); + REQUIRE(dspace_id != H5I_INVALID_HID); + herr_t status = H5Sselect_hyperslab(dspace_id, H5S_SELECT_SET, &offset, + &stride, &nelems, NULL); + REQUIRE(status >= 0); + + RwIds result = {dset_id, dspace_id, memspace_id}; + + return result; + } + + /** + * Cleanup code required after H5Dread and H5Dwrite. + */ + void RwCleanup(RwIds *ids) { + REQUIRE(H5Sclose(ids->mspace_id) >= 0); + REQUIRE(H5Sclose(ids->dspace_id) >= 0); + REQUIRE(H5Dclose(ids->dset_id) >= 0); + } + + /** + * Reads @p nelems elements from the object represented by @p hid into @p buf, + * starting at element @p offset. + */ + void Read(hid_t hid, const std::string &dset_name, std::vector &buf, + hsize_t offset, hsize_t nelems) { + RwIds ids = RwPreamble(hid, dset_name, offset, nelems); + herr_t status = H5Dread(ids.dset_id, H5T_NATIVE_FLOAT, ids.mspace_id, + ids.dspace_id, H5P_DEFAULT, buf.data()); + REQUIRE(status >= 0); + + RwCleanup(&ids); + } + /** + Create a 1-dimensional dataset using \a data vector. + */ + void MakeDataset(hid_t hid, const std::string &dset_name, + const std::vector &data, bool compact = false) { + MakeDataset(hid, dset_name, data.data(), data.size(), compact); + } + + /** + * Create a 1-dimensional dataset named @p dset_name in object @p hid with @p + * nelems elements from the array @p data. + */ + void MakeDataset(hid_t hid, const std::string &dset_name, const f32 *data, + hsize_t nelems, bool compact = false) { + hid_t dcpl = H5P_DEFAULT; + herr_t status = 0; + + if (compact) { + REQUIRE(nelems * sizeof(f32) <= KILOBYTES(64)); + dcpl = H5Pcreate(H5P_DATASET_CREATE); + REQUIRE(dcpl != H5I_INVALID_HID); + status = H5Pset_layout(dcpl, H5D_COMPACT); + REQUIRE(status >= 0); + } + + hid_t memspace_id = H5Screate_simple(1, &nelems, NULL); + REQUIRE(memspace_id != H5I_INVALID_HID); + + hid_t dset_id = H5Dcreate2(hid, dset_name.c_str(), H5T_NATIVE_FLOAT, + memspace_id, H5P_DEFAULT, dcpl, H5P_DEFAULT); + REQUIRE(dset_id != H5I_INVALID_HID); + + hid_t dspace_id = H5Dget_space(dset_id); + REQUIRE(dspace_id != H5I_INVALID_HID); + + status = H5Dwrite(dset_id, H5T_NATIVE_FLOAT, memspace_id, + dspace_id, H5P_DEFAULT, data); + REQUIRE(status >= 0); + REQUIRE(H5Sclose(memspace_id) >= 0); + REQUIRE(H5Sclose(dspace_id) >= 0); + REQUIRE(H5Dclose(dset_id) >= 0); + + if (compact) { + REQUIRE(H5Pclose(dcpl) >= 0); + } + } + + /** + * Write @p nelems elements to the dataset @p dset_name in file @p hid + * starting at element @p offset. The dataset will be created if it doesn't + * already exist. + */ + void WritePartial1d(hid_t hid, const std::string &dset_name, + const f32 *data, hsize_t offset, hsize_t nelems) { + RwIds ids = RwPreamble(hid, dset_name, offset, nelems); + herr_t status = H5Dwrite(ids.dset_id, H5T_NATIVE_FLOAT, ids.mspace_id, + ids.dspace_id, H5P_DEFAULT, data); + REQUIRE(status >= 0); + + RwCleanup(&ids); + } + /** + Close HDF5 file. + */ + herr_t Close(hid_t id) { + herr_t result = H5Fclose(id); + + return result; + } +}; + +template +class Hdf5VfdTests : public FilesystemTests { + public: + FileInfo new_file_; + FileInfo existing_file_; + FileInfo shared_new_file_; + FileInfo shared_existing_file_; + // int offset_seed = 1; + // unsigned int rs_seed = 1; + // unsigned int temporal_interval_seed = 5; + // size_t stride_size = 512; + unsigned int temporal_interval_ms_ = 1; /**< interval in milliseconds */ + // size_t small_min = 1; + // size_t small_max = KILOBYTES(4); + // size_t medium_min = KILOBYTES(4) + 1; + // size_t medium_max = KILOBYTES(256); + // size_t large_min = KILOBYTES(256) + 1; + // size_t large_max = MEGABYTES(3); + + hid_t hermes_hid_; /**< Hermes handle ID */ + hid_t sec2_hid_; /**< POSIX driver handle ID */ + herr_t hermes_herr_; /**< Hermes error return value */ + + public: + void RegisterFiles() override { + RegisterPath("new", 0, new_file_); + RegisterPath("ext", TEST_DO_CREATE, existing_file_); + if constexpr(WITH_MPI) { + RegisterPath("shared_new", TEST_FILE_SHARED, shared_new_file_); + RegisterPath("shared_ext", TEST_DO_CREATE | TEST_FILE_SHARED, + shared_existing_file_); + } + } + + void CompareFiles(FileInfo &info) override { + const char *driver = getenv("HDF5_DRIVER"); + if (driver != nullptr) { + unsetenv("HDF5_DRIVER"); + } + std::string h5diff_cmd = "h5diff " + info.hermes_ + " " + info.cmp_; + int status = system(h5diff_cmd.c_str()); + if (status != 0) { + HELOG(kError, "Failing h5diff command: {}", h5diff_cmd) + } + if (driver != nullptr) { + setenv("HDF5_DRIVER", driver, 1); + } + REQUIRE(status == 0); + } + + std::vector GenerateData() override { + std::vector data(request_size_ * num_iterations_); + for (size_t i = 0; i < data.size(); ++i) { + data[i] = GenRandom0to1(); + } + return data; + } + + /** + * Create an HDF5 file called @p fname with @p num_datasets datasets, each with + * @p num_dataset_elems elements. + * */ + void CreateFile(const std::string &path, + std::vector &data) override { + Hdf5Api api; + f32 *at = (f32*)data.data(); + hid_t file_id = api.CreatePosix(path, H5F_ACC_TRUNC); + REQUIRE(file_id != H5I_INVALID_HID); + for (size_t i = 0; i < num_iterations_; ++i) { + api.MakeDataset(file_id, std::to_string(i), at, request_size_); + at += request_size_; + } + REQUIRE(api.Close(file_id) > -1); + } + + public: + /** + * Test creating and opening a new file. + * */ + void TestOpen(FileInfo &info, unsigned flags, bool create = false) { + Hdf5Api api; + if (create) { + hermes_hid_ = api.Create(info.hermes_, flags); + sec2_hid_ = api.CreatePosix(info.cmp_, flags); + } else { + hermes_hid_ = api.Open(info.hermes_, flags); + sec2_hid_ = api.OpenPosix(info.cmp_, flags); + } + bool is_same = + (sec2_hid_ != H5I_INVALID_HID && hermes_hid_ != H5I_INVALID_HID) || + (sec2_hid_ == H5I_INVALID_HID && hermes_hid_ == H5I_INVALID_HID); + + REQUIRE(is_same); + } + /** + * @return Test Close() calls + * */ + void TestClose() { + Hdf5Api api; + hermes_herr_ = api.Close(hermes_hid_); + herr_t status = api.Close(sec2_hid_); + REQUIRE(status == hermes_herr_); + } + + /** + * Test writing partial 1-D dataset. + * */ + void TestWritePartial1d(const std::string &dset_name, const f32 *data, + hsize_t offset, hsize_t nelems) { + Hdf5Api api; + api.WritePartial1d(hermes_hid_, dset_name, data, offset, nelems); + api.WritePartial1d(sec2_hid_, dset_name, data, offset, nelems); + } + + /** + * Test making dataset. + * */ + void TestWriteDataset(const std::string &dset_name, + const std::vector &data) { + Hdf5Api api; + api.MakeDataset(hermes_hid_, dset_name, data); + api.MakeDataset(sec2_hid_, dset_name, data); + } + + + /** + * Test making compact dataset. + * */ + void TestMakeCompactDataset(const std::string &dset_name, + const std::vector &data) { + Hdf5Api api; + api.MakeDataset(hermes_hid_, dset_name, data, true); + api.MakeDataset(sec2_hid_, dset_name, data, true); + } + + /** + * Test reading dataset. + * */ + void TestRead(const std::string &dset_name, std::vector &buf, + hsize_t offset, hsize_t nelems) { + Hdf5Api api; + api.Read(hermes_hid_, dset_name, buf, offset, nelems); + std::vector sec2_read_buf(nelems, 0.0f); + api.Read(sec2_hid_, dset_name, sec2_read_buf, offset, nelems); + REQUIRE(std::equal(buf.begin(), buf.begin() + nelems, + sec2_read_buf.begin())); + } +}; + +} // namespace hermes::adapter::test + +#define TESTER \ + hshm::EasySingleton>::GetInstance() + +#endif // HERMES_TEST_UNIT_HERMES_ADAPTERS_HDF5_VFD_TESTS_H_ diff --git a/test/unit/hermes_adapters/vfd/tests.py b/test/unit/hermes_adapters/vfd/tests.py deleted file mode 100644 index 132a1a545..000000000 --- a/test/unit/hermes_adapters/vfd/tests.py +++ /dev/null @@ -1,39 +0,0 @@ -from py_hermes_ci.test_manager import TestManager -from jarvis_util import * - - -class VfdTestManager(TestManager): - def spawn_all_nodes(self): - return self.spawn_info() - - def set_paths(self): - self.VFD_CMD = f"{self.CMAKE_BINARY_DIR}/bin/vfd_adapter_test" - self.HERMES_VFD_CMD = f"{self.CMAKE_BINARY_DIR}/bin/hermes_vfd_adapter_test" - self.disable_testing = False - - def test_vfd_basic(self): - vfd_cmd = f"{self.VFD_CMD}" - node = Exec(vfd_cmd) - return node.exit_code - - def test_hermes_vfd_default(self): - vfd_cmd = f"{self.HERMES_VFD_CMD} SingleWrite" - spawn_info = self.spawn_info(nprocs=1, - hermes_conf='hermes_server', - hermes_mode='kDefault', - api='vfd') - self.start_daemon(spawn_info) - node = Exec(vfd_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code - - def test_hermes_vfd_scratch(self): - vfd_cmd = f"{self.HERMES_VFD_CMD} [scratch]" - spawn_info = self.spawn_info(nprocs=1, - hermes_conf='hermes_server', - hermes_mode='kScratch', - api='vfd') - self.start_daemon(spawn_info) - node = Exec(vfd_cmd, spawn_info) - self.stop_daemon(spawn_info) - return node.exit_code \ No newline at end of file diff --git a/test/unit/ipc/CMakeLists.txt b/test/unit/ipc/CMakeLists.txt index d6eff102a..d62f05703 100644 --- a/test/unit/ipc/CMakeLists.txt +++ b/test/unit/ipc/CMakeLists.txt @@ -42,5 +42,5 @@ install(TARGETS # Coverage #----------------------------------------------------------------------------- if(HERMES_ENABLE_COVERAGE) - set_coverage_flags(test_messages) + set_coverage_flags(test_ipc_exec) endif() diff --git a/test/unit/pipelines/hermes/test_hermes.yaml b/test/unit/pipelines/hermes/test_hermes.yaml new file mode 100644 index 000000000..4050a8f22 --- /dev/null +++ b/test/unit/pipelines/hermes/test_hermes.yaml @@ -0,0 +1,10 @@ +name: hermes_unit_hermes_mpiio_basic_large +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + ram: 16m + sleep: 5 + - pkg_type: hermes_unit_tests + pkg_name: hermes_unit_tests + TEST_CASE: hermes diff --git a/test/unit/pipelines/mpiio/test_hermes_mpiio_basic_async.yaml b/test/unit/pipelines/mpiio/test_hermes_mpiio_basic_async.yaml new file mode 100644 index 000000000..2e3635c6c --- /dev/null +++ b/test/unit/pipelines/mpiio/test_hermes_mpiio_basic_async.yaml @@ -0,0 +1,11 @@ +name: hermes_unit_hermes_mpiio_basic_large +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 5 + - pkg_type: hermes_mpiio_tests + pkg_name: hermes_mpiio_tests + test_file: mpiio_basic + hermes: true + size: large diff --git a/test/unit/pipelines/mpiio/test_hermes_mpiio_basic_sync.yaml b/test/unit/pipelines/mpiio/test_hermes_mpiio_basic_sync.yaml new file mode 100644 index 000000000..ba639d2ff --- /dev/null +++ b/test/unit/pipelines/mpiio/test_hermes_mpiio_basic_sync.yaml @@ -0,0 +1,11 @@ +name: hermes_unit_hermes_mpiio_basic_async +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_mpiio_tests + pkg_name: hermes_mpiio_tests + test_file: mpiio_basic + hermes: true + sync: async \ No newline at end of file diff --git a/test/unit/pipelines/mpiio/test_mpiio_basic.yaml b/test/unit/pipelines/mpiio/test_mpiio_basic.yaml new file mode 100644 index 000000000..576f92ab2 --- /dev/null +++ b/test/unit/pipelines/mpiio/test_mpiio_basic.yaml @@ -0,0 +1,7 @@ +name: hermes_unit_mpiio_basic +env: hermes +pkgs: + - pkg_type: hermes_mpiio_tests + pkg_name: hermes_mpiio_tests + test_file: mpiio_basic + hermes: false \ No newline at end of file diff --git a/test/unit/pipelines/posix/test_hermes_posix_basic_large.yaml b/test/unit/pipelines/posix/test_hermes_posix_basic_large.yaml new file mode 100644 index 000000000..8b95a425f --- /dev/null +++ b/test/unit/pipelines/posix/test_hermes_posix_basic_large.yaml @@ -0,0 +1,11 @@ +name: hermes_unit_hermes_posix_basic_large +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 5 + - pkg_type: hermes_posix_tests + pkg_name: hermes_posix_tests + test_file: posix_basic + hermes: true + size: large diff --git a/test/unit/pipelines/posix/test_hermes_posix_basic_mpi_large.yaml b/test/unit/pipelines/posix/test_hermes_posix_basic_mpi_large.yaml new file mode 100644 index 000000000..51a6f4d46 --- /dev/null +++ b/test/unit/pipelines/posix/test_hermes_posix_basic_mpi_large.yaml @@ -0,0 +1,11 @@ +name: hermes_unit_hermes_posix_basic_mpi_large +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_posix_tests + pkg_name: hermes_posix_tests + test_file: posix_basic_mpi + hermes: true + size: large \ No newline at end of file diff --git a/test/unit/pipelines/posix/test_hermes_posix_basic_mpi_small.yaml b/test/unit/pipelines/posix/test_hermes_posix_basic_mpi_small.yaml new file mode 100644 index 000000000..a461c79f2 --- /dev/null +++ b/test/unit/pipelines/posix/test_hermes_posix_basic_mpi_small.yaml @@ -0,0 +1,11 @@ +name: hermes_unit_hermes_posix_basic_mpi_small +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_posix_tests + pkg_name: hermes_posix_tests + test_file: posix_basic_mpi + hermes: true + size: small \ No newline at end of file diff --git a/test/unit/pipelines/posix/test_hermes_posix_basic_small.yaml b/test/unit/pipelines/posix/test_hermes_posix_basic_small.yaml new file mode 100644 index 000000000..26f6b0f63 --- /dev/null +++ b/test/unit/pipelines/posix/test_hermes_posix_basic_small.yaml @@ -0,0 +1,11 @@ +name: hermes_unit_hermes_posix_basic_small +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_posix_tests + pkg_name: hermes_posix_tests + test_file: posix_basic + hermes: true + size: small \ No newline at end of file diff --git a/test/unit/pipelines/posix/test_hermes_posix_simple_io_omp.yaml b/test/unit/pipelines/posix/test_hermes_posix_simple_io_omp.yaml new file mode 100644 index 000000000..6a41a707b --- /dev/null +++ b/test/unit/pipelines/posix/test_hermes_posix_simple_io_omp.yaml @@ -0,0 +1,10 @@ +name: hermes_unit_hermes_posix_simple_io_omp +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_posix_tests + pkg_name: hermes_posix_tests + test_file: posix_simple_io_omp + hermes: true \ No newline at end of file diff --git a/test/unit/pipelines/posix/test_posix_basic.yaml b/test/unit/pipelines/posix/test_posix_basic.yaml new file mode 100644 index 000000000..eb9bb1a41 --- /dev/null +++ b/test/unit/pipelines/posix/test_posix_basic.yaml @@ -0,0 +1,7 @@ +name: hermes_unit_posix_basic +env: hermes +pkgs: + - pkg_type: hermes_posix_tests + pkg_name: hermes_posix_tests + test_file: posix_basic + hermes: false \ No newline at end of file diff --git a/test/unit/pipelines/posix/test_posix_basic_mpi.yaml b/test/unit/pipelines/posix/test_posix_basic_mpi.yaml new file mode 100644 index 000000000..99bcd3db4 --- /dev/null +++ b/test/unit/pipelines/posix/test_posix_basic_mpi.yaml @@ -0,0 +1,7 @@ +name: hermes_unit_posix_basic_mpi +env: hermes +pkgs: + - pkg_type: hermes_posix_tests + pkg_name: hermes_posix_tests + test_file: posix_basic_mpi + hermes: false \ No newline at end of file diff --git a/test/unit/pipelines/posix/test_posix_simple_io_omp.yaml b/test/unit/pipelines/posix/test_posix_simple_io_omp.yaml new file mode 100644 index 000000000..09a34ff39 --- /dev/null +++ b/test/unit/pipelines/posix/test_posix_simple_io_omp.yaml @@ -0,0 +1,7 @@ +name: hermes_unit_posix_simple_io_omp +env: hermes +pkgs: + - pkg_type: hermes_posix_tests + pkg_name: hermes_posix_tests + test_file: posix_simple_io_omp + hermes: false \ No newline at end of file diff --git a/test/unit/pipelines/stdio/test_hermes_stdio_adapter_bypass.yaml b/test/unit/pipelines/stdio/test_hermes_stdio_adapter_bypass.yaml new file mode 100644 index 000000000..f70b30757 --- /dev/null +++ b/test/unit/pipelines/stdio/test_hermes_stdio_adapter_bypass.yaml @@ -0,0 +1,12 @@ +name: hermes_unit_hermes_stdio_basic_small +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_stdio_tests + pkg_name: hermes_stdio_tests + test_file: stdio_adapter_mode + test_case: BatchedWriteSequentialBypass + hermes: true + size: small \ No newline at end of file diff --git a/test/unit/pipelines/stdio/test_hermes_stdio_adapter_default.yaml b/test/unit/pipelines/stdio/test_hermes_stdio_adapter_default.yaml new file mode 100644 index 000000000..e8b56d196 --- /dev/null +++ b/test/unit/pipelines/stdio/test_hermes_stdio_adapter_default.yaml @@ -0,0 +1,12 @@ +name: hermes_unit_hermes_stdio_basic_small +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_stdio_tests + pkg_name: hermes_stdio_tests + test_file: stdio_adapter_mode + test_case: BatchedWriteSequentialPersistent + hermes: true + size: small \ No newline at end of file diff --git a/test/unit/pipelines/stdio/test_hermes_stdio_adapter_scratch.yaml b/test/unit/pipelines/stdio/test_hermes_stdio_adapter_scratch.yaml new file mode 100644 index 000000000..c4fa8f3a3 --- /dev/null +++ b/test/unit/pipelines/stdio/test_hermes_stdio_adapter_scratch.yaml @@ -0,0 +1,12 @@ +name: hermes_unit_hermes_stdio_basic_small +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_stdio_tests + pkg_name: hermes_stdio_tests + test_file: stdio_adapter_mode + test_case: BatchedWriteSequentialScratch + hermes: true + size: small \ No newline at end of file diff --git a/test/unit/pipelines/stdio/test_hermes_stdio_basic_large.yaml b/test/unit/pipelines/stdio/test_hermes_stdio_basic_large.yaml new file mode 100644 index 000000000..c4972f1b1 --- /dev/null +++ b/test/unit/pipelines/stdio/test_hermes_stdio_basic_large.yaml @@ -0,0 +1,11 @@ +name: hermes_unit_hermes_stdio_basic_large +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_stdio_tests + pkg_name: hermes_stdio_tests + test_file: stdio_basic + hermes: true + size: large diff --git a/test/unit/pipelines/stdio/test_hermes_stdio_basic_mpi_large.yaml b/test/unit/pipelines/stdio/test_hermes_stdio_basic_mpi_large.yaml new file mode 100644 index 000000000..126926539 --- /dev/null +++ b/test/unit/pipelines/stdio/test_hermes_stdio_basic_mpi_large.yaml @@ -0,0 +1,11 @@ +name: hermes_unit_hermes_stdio_basic_mpi_large +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_stdio_tests + pkg_name: hermes_stdio_tests + test_file: stdio_basic_mpi + hermes: true + size: large diff --git a/test/unit/pipelines/stdio/test_hermes_stdio_basic_mpi_small.yaml b/test/unit/pipelines/stdio/test_hermes_stdio_basic_mpi_small.yaml new file mode 100644 index 000000000..24fce5ea9 --- /dev/null +++ b/test/unit/pipelines/stdio/test_hermes_stdio_basic_mpi_small.yaml @@ -0,0 +1,11 @@ +name: hermes_unit_hermes_stdio_basic_mpi_small +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_stdio_tests + pkg_name: hermes_stdio_tests + test_file: stdio_basic_mpi + hermes: true + size: small \ No newline at end of file diff --git a/test/unit/pipelines/stdio/test_hermes_stdio_basic_small.yaml b/test/unit/pipelines/stdio/test_hermes_stdio_basic_small.yaml new file mode 100644 index 000000000..ae626a913 --- /dev/null +++ b/test/unit/pipelines/stdio/test_hermes_stdio_basic_small.yaml @@ -0,0 +1,11 @@ +name: hermes_unit_hermes_stdio_basic_small +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_stdio_tests + pkg_name: hermes_stdio_tests + test_file: stdio_basic + hermes: true + size: small \ No newline at end of file diff --git a/test/unit/pipelines/stdio/test_hermes_stdio_low_buf.yaml b/test/unit/pipelines/stdio/test_hermes_stdio_low_buf.yaml new file mode 100644 index 000000000..47036fbb5 --- /dev/null +++ b/test/unit/pipelines/stdio/test_hermes_stdio_low_buf.yaml @@ -0,0 +1,10 @@ +name: hermes_unit_hermes_stdio_basic_small +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_stdio_tests + pkg_name: hermes_stdio_tests + test_file: stdio_low_buf + hermes: true \ No newline at end of file diff --git a/test/unit/pipelines/stdio/test_hermes_stdio_mapper.yaml b/test/unit/pipelines/stdio/test_hermes_stdio_mapper.yaml new file mode 100644 index 000000000..27259caa9 --- /dev/null +++ b/test/unit/pipelines/stdio/test_hermes_stdio_mapper.yaml @@ -0,0 +1,10 @@ +name: hermes_unit_hermes_stdio_basic_small +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 2 + - pkg_type: hermes_stdio_tests + pkg_name: hermes_stdio_tests + test_file: stdio_mapper + hermes: true \ No newline at end of file diff --git a/test/unit/pipelines/stdio/test_stdio_basic.yaml b/test/unit/pipelines/stdio/test_stdio_basic.yaml new file mode 100644 index 000000000..b4ad4fbc9 --- /dev/null +++ b/test/unit/pipelines/stdio/test_stdio_basic.yaml @@ -0,0 +1,7 @@ +name: hermes_unit_stdio_basic +env: hermes +pkgs: + - pkg_type: hermes_stdio_tests + pkg_name: hermes_stdio_tests + test_file: stdio_basic + hermes: false \ No newline at end of file diff --git a/test/unit/pipelines/stdio/test_stdio_basic_mpi.yaml b/test/unit/pipelines/stdio/test_stdio_basic_mpi.yaml new file mode 100644 index 000000000..751697a15 --- /dev/null +++ b/test/unit/pipelines/stdio/test_stdio_basic_mpi.yaml @@ -0,0 +1,7 @@ +name: hermes_unit_stdio_basic_mpi +env: hermes +pkgs: + - pkg_type: hermes_stdio_tests + pkg_name: hermes_stdio_tests + test_file: stdio_basic_mpi + hermes: false \ No newline at end of file diff --git a/test/unit/pipelines/test_borg.yaml b/test/unit/pipelines/test_borg.yaml new file mode 100644 index 000000000..7b60e026f --- /dev/null +++ b/test/unit/pipelines/test_borg.yaml @@ -0,0 +1,15 @@ +name: hermes_unit_ior +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + recency_max: 1 + ram: 10m + sleep: 5 + do_dbg: true + dbg_port: 4000 + - pkg_type: hermes_unit_tests + pkg_name: hermes_unit_tests + TEST_CASE: TestHermesPutGet + do_dbg: true + dbg_port: 4001 diff --git a/test/unit/pipelines/test_ior.yaml b/test/unit/pipelines/test_ior.yaml new file mode 100644 index 000000000..bb91795c8 --- /dev/null +++ b/test/unit/pipelines/test_ior.yaml @@ -0,0 +1,18 @@ +name: hermes_unit_ior +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + include: /tmp/test_hermes + sleep: 5 + ram: 1g + - pkg_type: hermes_api + pkg_name: hermes_api + mpi: true + - pkg_type: ior + pkg_name: ior + api: mpiio + out: /tmp/test_hermes/ior.bin + xfer: 1m + block: 32g + nprocs: 4 \ No newline at end of file diff --git a/test/unit/pipelines/vfd/test_hermes_vfd_basic.yaml b/test/unit/pipelines/vfd/test_hermes_vfd_basic.yaml new file mode 100644 index 000000000..5ddd84d05 --- /dev/null +++ b/test/unit/pipelines/vfd/test_hermes_vfd_basic.yaml @@ -0,0 +1,14 @@ +name: hermes_unit_hermes_vfd_basic +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 5 + - pkg_type: hermes_api + pkg_name: hermes_api + vfd: true + - pkg_type: hermes_vfd_tests + pkg_name: hermes_vfd_tests + test_file: vfd_basic + hermes: true + mode: default diff --git a/test/unit/pipelines/vfd/test_hermes_vfd_scratch.yaml b/test/unit/pipelines/vfd/test_hermes_vfd_scratch.yaml new file mode 100644 index 000000000..69cdcccc8 --- /dev/null +++ b/test/unit/pipelines/vfd/test_hermes_vfd_scratch.yaml @@ -0,0 +1,11 @@ +name: hermes_unit_hermes_vfd_basic +env: hermes +pkgs: + - pkg_type: hermes_run + pkg_name: hermes_run + sleep: 5 + - pkg_type: hermes_vfd_tests + pkg_name: hermes_vfd_tests + test_file: vfd_basic + hermes: true + mode: scratch diff --git a/wrapper/python/cpp/py_hermes.cpp b/wrapper/python/cpp/py_hermes.cpp index 51efeabd0..128d1630d 100644 --- a/wrapper/python/cpp/py_hermes.cpp +++ b/wrapper/python/cpp/py_hermes.cpp @@ -22,6 +22,7 @@ using hermes::BlobId; using hermes::BucketId; using hermes::TagId; using hermes::TargetId; +using hermes::BufferInfo; using hermes::BlobInfo; using hermes::TargetStats; using hermes::TagInfo; @@ -54,6 +55,15 @@ void BindUniqueId(py::module &m, const std::string &name) { .def_readonly("unique", &UniqueT::unique_); } +void BindBufferInfo(py::module &m) { + py::class_(m, "BufferInfo") + .def(py::init<>()) + .def_readwrite("tid", &BufferInfo::tid_) + .def_readwrite("t_slab", &BufferInfo::t_slab_) + .def_readwrite("t_off", &BufferInfo::t_off_) + .def_readwrite("t_size", &BufferInfo::t_size_); +} + void BindBlobInfo(py::module &m) { py::class_(m, "BlobInfo") .def(py::init<>()) @@ -61,7 +71,7 @@ void BindBlobInfo(py::module &m) { .def("UpdateReadStats", &BlobInfo::UpdateReadStats) .def_readonly("tag_id", &BlobInfo::tag_id_) .def_readonly("blob_id", &BlobInfo::blob_id_) - .def_readonly("name", &BlobInfo::name_) + .def("get_name", &BlobInfo::GetName) .def_readonly("buffers", &BlobInfo::buffers_) .def_readonly("tags", &BlobInfo::tags_) .def_readonly("blob_size", &BlobInfo::blob_size_) @@ -76,6 +86,7 @@ void BindTargetStats(py::module &m) { py::class_(m, "TargetStats") .def(py::init<>()) .def_readonly("tgt_id", &TargetStats::tgt_id_) + .def_readonly("node_id", &TargetStats::node_id_) .def_readonly("rem_cap", &TargetStats::rem_cap_) .def_readonly("max_cap", &TargetStats::max_cap_) .def_readonly("bandwidth", &TargetStats::bandwidth_) @@ -87,7 +98,7 @@ void BindTagInfo(py::module &m) { py::class_(m, "TagInfo") .def(py::init<>()) .def_readonly("tag_id", &TagInfo::tag_id_) - .def_readonly("name", &TagInfo::name_) + .def("get_name", &TagInfo::GetName) .def_readonly("blobs", &TagInfo::blobs_) .def_readonly("traits", &TagInfo::traits_) .def_readonly("internal_size", &TagInfo::internal_size_) @@ -118,8 +129,10 @@ PYBIND11_MODULE(py_hermes, m) { BindUniqueId(m, "BucketId"); BindUniqueId(m, "TagId"); BindUniqueId(m, "TargetId"); + BindBufferInfo(m); BindBlobInfo(m); BindTargetStats(m); + BindTagInfo(m); BindMetadataTable(m); BindHermes(m); } diff --git a/wrapper/python/py_hermes_mdm/py_hermes_mdm/py_hermes_mdm.py b/wrapper/python/py_hermes_mdm/py_hermes_mdm/py_hermes_mdm.py new file mode 100644 index 000000000..b4fb6afda --- /dev/null +++ b/wrapper/python/py_hermes_mdm/py_hermes_mdm/py_hermes_mdm.py @@ -0,0 +1,71 @@ + +from py_hermes import Hermes, TRANSPARENT_HERMES +class MetadataSnapshot: + def __init__(self): + TRANSPARENT_HERMES() + self.hermes = Hermes() + self.blob_info = [] + self.target_info = [] + self.tag_info = [] + + @staticmethod + def unique(id): + return f'{id.node_id}.{id.unique}' + + def collect(self): + mdm = self.hermes.CollectMetadataSnapshot() + tag_to_blob = {} + tid_to_tgt = {} + for target in mdm.target_info: + target_info = { + 'name': None, + 'id': self.unique(target.tgt_id), + 'node_id': int(target.node_id), + 'rem_cap': target.rem_cap, + 'max_cap': target.max_cap, + 'bandwidth': target.bandwidth, + 'latency': target.latency, + 'score': target.score, + } + self.target_info.append(target_info) + tid_to_tgt[target_info['id']] = target_info + self.target_info.sort(reverse=True, key=lambda x: x['bandwidth']) + for i, target in enumerate(self.target_info): + target['name'] = f'Tier {i}' + for blob in mdm.blob_info: + blob_info = { + 'name': str(blob.get_name()), + 'id': self.unique(blob.blob_id), + 'mdm_node': int(blob.blob_id.node_id), + 'tag_id': self.unique(blob.tag_id), + 'score': float(blob.score), + 'access_frequency': 0, + 'buffer_info': [] + } + for buf in blob.buffers: + buf_info = { + 'target_id': self.unique(buf.tid), + 'node_id': 0, + 'size': int(buf.t_size) + } + buf_info['node_id'] = tid_to_tgt[buf_info['target_id']]['node_id'] + blob_info['buffer_info'].append(buf_info) + self.blob_info.append(blob_info) + if blob_info['tag_id'] not in tag_to_blob: + tag_to_blob[blob_info['tag_id']] = [] + tag_to_blob[blob_info['tag_id']].append(blob_info['id']) + for tag in mdm.bkt_info: + tag_info = { + 'id': self.unique(tag.tag_id), + 'mdm_node': int(tag.tag_id.node_id), + 'name': str(tag.get_name()), + # 'blobs': [self.unique(blob.blob_id) for blob in tag.blobs] + 'blobs': [] + } + if tag_info['id'] in tag_to_blob: + tag_info['blobs'] = tag_to_blob[tag_info['id']] + self.tag_info.append(tag_info) + +# mdm = MetadataSnapshot() +# mdm.collect() +# print('Done')