diff --git a/.github/workflows/Linux.yml b/.github/workflows/Linux.yml index d8a2d30..ed64e16 100644 --- a/.github/workflows/Linux.yml +++ b/.github/workflows/Linux.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: install dependencies run : | @@ -19,13 +19,12 @@ jobs: sudo apt-get install libopenmpi-dev openmpi-common sudo apt-get install libeigen3-dev sudo apt-get install libspdlog-dev - sudo apt-get install flex bison - name: bootstrap run: . bootstrap.sh - name: configure - run: mkdir build && cd build && cmake .. -DBUILD_TESTING=ON -DCOLLECT_STATS=ON -DSEWAS_DISTRIBUTED=ON -DSEWAS_WITH_PARSEC=ON -DVERBOSE=ON && cd - + run: mkdir build && cd build && cmake .. -DBUILD_TESTING=ON -DCOLLECT_STATS=ON -DSEWAS_DISTRIBUTED=ON -DSEWAS_WITH_STARPU=ON -DVERBOSE=ON && cd - - name: build run: cmake --build build --config Release diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 8b42792..19cfb8d 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -11,7 +11,7 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: bootstrap run: .\bootstrap.bat diff --git a/.gitignore b/.gitignore index c223b8d..e844a67 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,13 @@ doc/* .vs/tasks.vs.json /thirdparty/vcpkg/src /thirdparty/vcpkg/build +/thirdparty/parsec/src +/thirdparty/parsec/build +/thirdparty/adios/src +/thirdparty/adios/build +/thirdparty/starpu/src +/thirdparty/starpu/build +/thirdparty/install /out /.vs/SeWaS/v16/.suo /.vs/CMake Overview diff --git a/CMakeLists.txt b/CMakeLists.txt index 761c5c6..814cdea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules" C option(SEWAS_DISTRIBUTED "Build SeWaS for distributed memory platforms (default OFF)" OFF) option(SEWAS_WITH_PARSEC "Use PaRSEC for task-scheduling (default OFF)" OFF) +option(SEWAS_WITH_STARPU "Use StarPU for task-scheduling (default OFF)" OFF) option(VERBOSE "Enable collecting and displaying of traced events at runtime (default OFF)" OFF) option(BUILD_TESTING "Build the testing tree (default OFF)" OFF) option(COLLECT_STATS "Collect statistics during execution (default ON)" ON) @@ -77,10 +78,17 @@ if (DOWNLOAD_MISSING_DEPS) set(TARGET_PLATFORM "${HOST_ARCH}-${SYSTEM_NAME}") + # Ports pinned here to a version older than what the vcpkg commit above ships by + # default, because SEWAS' find_package() calls require compatibility with an older + # version than what is currently in the upstream port tree (e.g. eigen3 defaults to + # a 5.x release, which find_package(Eigen3 3.3.3) rejects as incompatible). + set(VCPKG_OVERLAY_PORTS_DIR ${CMAKE_SOURCE_DIR}/cmake/resources/vcpkg/overlay-ports) + # define helper macro for downloading packages through vpckg macro(_vcpkg_install package) message("[VCPKG] Installing package : ${package}:${TARGET_PLATFORM}") execute_process(COMMAND ${VCPKG_EXE} install ${package}:${TARGET_PLATFORM} + --overlay-ports=${VCPKG_OVERLAY_PORTS_DIR} RESULT_VARIABLE STATUS WORKING_DIRECTORY ${VCPKG_ROOT}) if (STATUS) @@ -122,6 +130,14 @@ if(SEWAS_WITH_PARSEC) add_compile_options(-DSEWAS_WITH_PARSEC) endif() +if(SEWAS_WITH_STARPU) + add_compile_options(-DSEWAS_WITH_STARPU) +endif() + +if(SEWAS_WITH_PARSEC AND SEWAS_WITH_STARPU) + message(FATAL_ERROR "SEWAS_WITH_PARSEC and SEWAS_WITH_STARPU are mutually exclusive.") +endif() + if (VERBOSE) add_compile_options(-DVERBOSE) endif(VERBOSE) @@ -354,6 +370,62 @@ if(SEWAS_WITH_PARSEC) set(SEWAS_LIBRARIES ${SEWAS_LIBRARIES} ${PARSEC_LIBRARIES}) endif(SEWAS_WITH_PARSEC) +# ------------------------------------------------------------------- +# StarPU +# ------------------------------------------------------------------- +if(SEWAS_WITH_STARPU) + if (NOT SEWAS_DISTRIBUTED) + message(FATAL_ERROR "The distributed version of SeWaS relies on StarPU.") + endif(NOT SEWAS_DISTRIBUTED) + + find_package(PkgConfig REQUIRED) + set(STARPU_PC_VERSION "1.4" CACHE STRING "StarPU pkg-config version suffix") + + # Also look under the same install prefix vcpkg-downloaded/built dependencies + # (PaRSEC, ADIOS2, ...) land in, in case a previous DOWNLOAD_MISSING_DEPS run + # already built StarPU there. + set(ENV{PKG_CONFIG_PATH} "${THIRDPARTY_ROOT}/install/lib/pkgconfig:${THIRDPARTY_ROOT}/install/lib64/pkgconfig:$ENV{PKG_CONFIG_PATH}") + pkg_check_modules(STARPU starpumpi-${STARPU_PC_VERSION}) + + if (NOT STARPU_FOUND) + message(WARNING "StarPU not found") + if (DOWNLOAD_MISSING_DEPS) + # StarPU not found; trying to download and build it (autotools-based, + # see cmake/resources/starpu/CMakeLists.txt) + set(STARPU_DOWNLOAD_ROOT ${THIRDPARTY_ROOT}/starpu) + configure_file(${CMAKE_SOURCE_DIR}/cmake/resources/starpu/CMakeLists.txt ${STARPU_DOWNLOAD_ROOT}/build/starpu-download/CMakeLists.txt) + execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${STARPU_DOWNLOAD_ROOT}/build/starpu-download) + if(result) + message(FATAL_ERROR "CMake step for starpu failed: ${result}") + endif() + execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${STARPU_DOWNLOAD_ROOT}/build/starpu-download) + if(result) + message(FATAL_ERROR "Build step for starpu failed: ${result}") + endif() + + pkg_check_modules(STARPU REQUIRED starpumpi-${STARPU_PC_VERSION}) + else(DOWNLOAD_MISSING_DEPS) + message(FATAL_ERROR "StarPU (starpumpi-${STARPU_PC_VERSION}) not found via pkg-config. " + "Install it (e.g. 'apt install libstarpu-dev' on Debian/Ubuntu, or build it " + "via Spack) and make sure its .pc files are on PKG_CONFIG_PATH, or set " + "DOWNLOAD_MISSING_DEPS for enabling automatic download of missing dependencies") + endif(DOWNLOAD_MISSING_DEPS) + endif(NOT STARPU_FOUND) + + message(STATUS "StarPU found") + message(STATUS " STARPU_INCLUDE_DIRS = ${STARPU_INCLUDE_DIRS}") + message(STATUS " STARPU_LIBRARY_DIRS = ${STARPU_LIBRARY_DIRS}") + message(STATUS " STARPU_LIBRARIES = ${STARPU_LIBRARIES}") + + include_directories("${STARPU_INCLUDE_DIRS}") + link_directories("${STARPU_LIBRARY_DIRS}") + set(SEWAS_LIBRARIES ${SEWAS_LIBRARIES} ${STARPU_LIBRARIES}) +endif(SEWAS_WITH_STARPU) + # ------------------------------------------------------------------- # Boost # ------------------------------------------------------------------- @@ -445,6 +517,7 @@ set(SOURCES src/SEWASParameterManager.cxx src/SEWASSequential.cxx src/SEWASPaRSEC.cxx + src/SEWASStarPU.cxx src/Mesh3DPartitioning.cxx src/VisualizationManager.cxx src/MetricsManager.cxx diff --git a/README.md b/README.md index 18acef9..a4cf8d5 100644 --- a/README.md +++ b/README.md @@ -279,49 +279,78 @@ DisplayStress Those visualization tasks interact with [VTK](http://www.vtk.org/) actors to render the scene. -# Building the application -The application has been tested on Debian 9 and CentOS. The following steps are suitable for a Debian-like OS. Our experiments were carried out using Intel compiler 18, but according to our recent experiments using gcc 7.3 there is no significant performance differences between these two compilers. So all the following experiments can be obtained using gcc. +# Building and installing -## Dependencies -+ Boost 1.62 (program-options module) -```sh -$ sudo apt-get install libboost-program-options-dev -``` +SeWaS is a CMake project. Its dependencies (Boost `program_options`, Eigen3, spdlog, and — for +distributed builds — OpenMPI plus PaRSEC or StarPU, depending on which task-based scheduler is +selected) are resolved automatically at configure time through +[vcpkg](https://github.com/microsoft/vcpkg), vendored under `thirdparty/vcpkg`, so there is no dependency +installation step to perform by hand. It has been validated on Linux (Ubuntu/Debian-like, via CI) and +Windows; a C++17 compiler and CMake 3.10.3+ are required either way. -+ OpenMPI 2.0.2 -```sh -$ sudo apt-get install libopenmpi-dev openmpi-common -``` +## 1. System prerequisites -+ PaRSEC 2.0 -```sh -$ git clone https://bitbucket.org/icldistcomp/parsec.git -$ cd parsec -$ cmake .. -DPARSEC_WITH_DEVEL_HEADERS=1 -DPARSEC_GPU_WITH_CUDA=0 -$ make install -``` +Only build tooling that vcpkg itself cannot provide needs to be present on the system beforehand: + ++ Linux: a C++17 compiler (gcc/clang), CMake, and — only when building with `-DSEWAS_WITH_PARSEC=ON`, + since PaRSEC's JDF files are compiled with `parsec-ptgpp` — `flex` and `bison`. `-DSEWAS_WITH_STARPU=ON` + needs no extra tooling beyond that: + ```sh + sudo apt-get install build-essential cmake flex bison + ``` ++ Windows: Visual Studio (with the C++ workload) and CMake. + +## 2. Bootstrap + +Run once per clone, before the first configure. This downloads and builds vcpkg into +`thirdparty/vcpkg` if it isn't already present: -+ Eigen 3.3.3 ```sh -$ sudo apt-get install libeigen3-dev +./bootstrap.sh # Linux/macOS +bootstrap.bat # Windows ``` -+ Intel TBB 4.3 +## 3. Configure + ```sh -$ sudo apt-get install libtbb-dev +mkdir build && cd build +cmake .. -DCMAKE_BUILD_TYPE=Release \ + -DSEWAS_DISTRIBUTED=ON -DSEWAS_WITH_STARPU=ON \ + -DBUILD_TESTING=ON -DCOLLECT_STATS=ON -DVERBOSE=ON ``` - -## SeWaS build + +`SEWAS_DISTRIBUTED` enables MPI-based distributed execution, and `SEWAS_WITH_STARPU`/`SEWAS_WITH_PARSEC` +(mutually exclusive, each requiring it) select the task-based scheduler. Linux CI builds +`SEWAS_DISTRIBUTED`+`SEWAS_WITH_STARPU`; Windows CI builds with both OFF. With `DOWNLOAD_MISSING_DEPS` on +(the default), CMake will download and build any of the above dependencies not already found on the +system — expect the first configure to take a while, since it also builds StarPU (or PaRSEC) from source. + +Other build options (all defined at the top of `CMakeLists.txt` and OFF unless noted) let you tune what +gets compiled in: + +| Option | Effect | +|---|---| +| `VISUALIZE_EXECUTION` (+ `ENABLE_VELOCITY_RENDERING`, `ENABLE_STRESS_RENDERING`, `ENABLE_CLUSTER_RENDERING`) | Real-time VTK rendering of the simulation | +| `ENABLE_IO` | ADIOS2-based output | +| `USE_BLOCKWISE_FDO` (ON), `VECTORIZE_COMPUTATIONS` (ON), `EIGEN_VECTORIZATION` (ON), `BOOST_SIMD_VECTORIZATION` | Control how the finite-difference operator is vectorized | +| `DOWNLOAD_MISSING_DEPS` (ON) | Auto-fetch missing dependencies through vcpkg instead of failing configure | + +## 4. Build + ```sh -$ export SEWAS_ROOT=/path/to/SeismicWaveSimulator -$ cd $SEWAS_ROOT/build -$ cmake ../src -DCMAKE_BUILD_TYPE=Release -$ make +cmake --build . --config Release ``` -At this stage the `build/` directory should contain an executable `sewas` +This produces the `sewas` executable directly inside `build/` — there is no separate install step/prefix; +run it in place (see [User Interface](#user-interface) above) or copy the binary wherever you need it. -/!\ The results presented in our paper are obtained on a cluster of Intel KNL processors. Hence it is mandatory to build the SeWaS application natively on one co-processor for best performances. +## 5. Test (optional) + +With `-DBUILD_TESTING=ON`, the GoogleTest suite can be run via CTest: + +```sh +ctest -C Release --output-on-failure -V +``` # Benchmarks Performance studies have been carried out using two test cases: TestA and TestB. diff --git a/cmake/resources/adios/CMakeLists.txt b/cmake/resources/adios/CMakeLists.txt index 6a3ce9e..c55ad14 100644 --- a/cmake/resources/adios/CMakeLists.txt +++ b/cmake/resources/adios/CMakeLists.txt @@ -7,7 +7,7 @@ include(ExternalProject) if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") ExternalProject_Add(adios GIT_REPOSITORY https://github.com/ornladios/ADIOS2.git - GIT_TAG v2.5.0 + GIT_TAG v2.12.1 SOURCE_DIR "${ADIOS_DOWNLOAD_ROOT}/src" BINARY_DIR "${ADIOS_DOWNLOAD_ROOT}/build" PATCH_COMMAND "" diff --git a/cmake/resources/gtest/CMakeLists.txt b/cmake/resources/gtest/CMakeLists.txt index 8efdbaa..bbbf98e 100644 --- a/cmake/resources/gtest/CMakeLists.txt +++ b/cmake/resources/gtest/CMakeLists.txt @@ -5,7 +5,7 @@ project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG master + GIT_TAG v1.17.0 SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" CONFIGURE_COMMAND "" diff --git a/cmake/resources/parsec/CMakeLists.txt b/cmake/resources/parsec/CMakeLists.txt index eb0a27f..ad3d397 100644 --- a/cmake/resources/parsec/CMakeLists.txt +++ b/cmake/resources/parsec/CMakeLists.txt @@ -5,13 +5,18 @@ project(parsec-download) include(ExternalProject) if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + # Pinned to the last commit before PaRSEC's "Reshape of datacopies" rework + # (8f813a179, first shipped in parsec-3.0.2012-rc1). That change and everything + # built on top of it, all the way through parsec-4.0.2411, breaks cross-rank + # halo exchange for SeWaS's task graph (MPI_ERR_TRUNCATE in the 2+ rank case; + # confirmed by bisection, root cause not yet identified upstream). ExternalProject_Add(parsec - GIT_REPOSITORY https://bitbucket.org/icldistcomp/parsec.git - GIT_TAG 8f72a0ecab1296fc3d90ba7c164695f4a3738950 + GIT_REPOSITORY https://github.com/icldisco/parsec + GIT_TAG 4659c27061ffe2c23b034e09becf7e44e54ef6d8 SOURCE_DIR "${PARSEC_DOWNLOAD_ROOT}/src" BINARY_DIR "${PARSEC_DOWNLOAD_ROOT}/build" - PATCH_COMMAND cd ${PARSEC_DOWNLOAD_ROOT}/src && git apply ${PARSEC_DOWNLOAD_ROOT}/patches/increase_max_inout_deps.patch - CONFIGURE_COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DBUILD_TESTING=OFF -DPARSEC_DIST_WITH_MPI=${SEWAS_DISTRIBUTED} -DPARSEC_WITH_DEVEL_HEADERS=ON -DCMAKE_INSTALL_PREFIX=${THIRDPARTY_ROOT}/install ${PARSEC_DOWNLOAD_ROOT}/src + PATCH_COMMAND cd ${PARSEC_DOWNLOAD_ROOT}/src && git apply ${PARSEC_DOWNLOAD_ROOT}/patches/increase_max_inout_deps.patch && sed -i "s/parsec_profiling_stream_t \\*new )/parsec_profiling_stream_t *new_stream )/" parsec/profiling.h + CONFIGURE_COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DBUILD_TESTING=OFF -DPARSEC_DIST_WITH_MPI=${SEWAS_DISTRIBUTED} -DPARSEC_WITH_DEVEL_HEADERS=ON -DCMAKE_C_FLAGS=-fcommon -DCMAKE_INSTALL_PREFIX=${THIRDPARTY_ROOT}/install ${PARSEC_DOWNLOAD_ROOT}/src BUILD_COMMAND make -j INSTALL_COMMAND make install TEST_COMMAND "" diff --git a/cmake/resources/starpu/CMakeLists.txt b/cmake/resources/starpu/CMakeLists.txt new file mode 100644 index 0000000..571b5ea --- /dev/null +++ b/cmake/resources/starpu/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.10.3) + +project(starpu-download) + +include(ExternalProject) + +if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + # Release tarball (ships a pre-generated `configure`, so no autoreconf/automake/ + # libtool is required at build time). Version/hash pinned to StarPU 1.4.7. + ExternalProject_Add(starpu + URL https://files.inria.fr/starpu/starpu-1.4.7/starpu-1.4.7.tar.gz + URL_HASH SHA256=1eb3df551089153fe6e0b172ad95118434b4a81ea9eaa5a2c38725d0db53b13e + SOURCE_DIR "${STARPU_DOWNLOAD_ROOT}/src" + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND /configure + --prefix=${THIRDPARTY_ROOT}/install + --with-mpicc=${MPI_C_COMPILER} + --with-mpicxx=${MPI_CXX_COMPILER} + --disable-build-tests + --disable-build-examples + --disable-build-doc + --disable-fortran + --disable-cuda + --disable-opencl + BUILD_COMMAND make -j + INSTALL_COMMAND make install + TEST_COMMAND "" + ) +else() + message(FATAL_ERROR "StarPU based version of SeWaS is not yet available on this system: ${CMAKE_SYSTEM_NAME}") +endif() diff --git a/cmake/resources/vcpkg/CMakeLists.txt b/cmake/resources/vcpkg/CMakeLists.txt index eb0e6b6..2303a76 100644 --- a/cmake/resources/vcpkg/CMakeLists.txt +++ b/cmake/resources/vcpkg/CMakeLists.txt @@ -11,7 +11,7 @@ endif() if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") ExternalProject_Add(vcpkg GIT_REPOSITORY https://github.com/microsoft/vcpkg.git - GIT_TAG 941d5464544eb5812b2cbd6e687c3ebc78ed2624 + GIT_TAG 40f3c709db80acf154ac4b17a1f83c564ebd022e SOURCE_DIR "../src" BUILD_IN_SOURCE true CONFIGURE_COMMAND "" @@ -20,13 +20,16 @@ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") TEST_COMMAND "" ) elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + # arm64-linux support is native to vcpkg since well before this pin; the old + # add_aarch64_support.patch/community triplet copy is both unneeded and no + # longer applies (scripts/buildsystems/vcpkg.cmake has since been rewritten + # upstream). ExternalProject_Add(vcpkg GIT_REPOSITORY https://github.com/microsoft/vcpkg.git - GIT_TAG 941d5464544eb5812b2cbd6e687c3ebc78ed2624 + GIT_TAG 40f3c709db80acf154ac4b17a1f83c564ebd022e SOURCE_DIR "../src" BUILD_IN_SOURCE true CONFIGURE_COMMAND "" - PATCH_COMMAND cp ../triplets/arm64-linux.cmake ../src/triplets/community && cd ../src && git apply ../patches/add_aarch64_support.patch BUILD_COMMAND ./bootstrap-vcpkg.sh ${_VCPKG_BOOTSTRAP_OPTIONS} INSTALL_COMMAND "" TEST_COMMAND "" diff --git a/cmake/resources/vcpkg/overlay-ports/eigen3/portfile.cmake b/cmake/resources/vcpkg/overlay-ports/eigen3/portfile.cmake new file mode 100644 index 0000000..b8a9be6 --- /dev/null +++ b/cmake/resources/vcpkg/overlay-ports/eigen3/portfile.cmake @@ -0,0 +1,50 @@ +vcpkg_buildpath_length_warning(37) + +vcpkg_from_gitlab( + GITLAB_URL https://gitlab.com + OUT_SOURCE_PATH SOURCE_PATH + REPO libeigen/eigen + REF ${VERSION} + SHA512 15b540d2fad25de837d7612456ea65b7fcfa25f886c48dcb3de025e079f5f43f45f1c0bd9a8435430d0e2fb9f0a6129719626dd4fd45dc61fc480f97762b2f56 + HEAD_REF master +) + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + -DBUILD_TESTING=OFF + -DEIGEN_BUILD_BLAS=OFF + -DEIGEN_BUILD_BTL=OFF + -DEIGEN_BUILD_CMAKE_PACKAGE=ON + -DEIGEN_BUILD_DEMOS=OFF + -DEIGEN_BUILD_DOC=OFF + -DEIGEN_BUILD_LAPACK=OFF + -DEIGEN_BUILD_PKGCONFIG=ON + -DEIGEN_BUILD_SPBENCH=OFF + OPTIONS_RELEASE + "-DCMAKEPACKAGE_INSTALL_DIR=${CURRENT_PACKAGES_DIR}/share/${PORT}" + "-DPKGCONFIG_INSTALL_DIR=${CURRENT_PACKAGES_DIR}/lib/pkgconfig" + OPTIONS_DEBUG + "-DCMAKEPACKAGE_INSTALL_DIR=${CURRENT_PACKAGES_DIR}/debug/share/${PORT}" + "-DPKGCONFIG_INSTALL_DIR=${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig" +) + +vcpkg_cmake_install() +vcpkg_cmake_config_fixup() + +vcpkg_fixup_pkgconfig() + +# Copy the eigen header files to conventional location for user-wide MSBuild integration +file(GLOB INCLUDES ${CURRENT_PACKAGES_DIR}/include/eigen3/*) +file(COPY ${INCLUDES} DESTINATION ${CURRENT_PACKAGES_DIR}/include) + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include" "${CURRENT_PACKAGES_DIR}/debug/share") + +vcpkg_install_copyright( + FILE_LIST + "${SOURCE_PATH}/COPYING.README" + "${SOURCE_PATH}/COPYING.APACHE" + "${SOURCE_PATH}/COPYING.BSD" + "${SOURCE_PATH}/COPYING.MINPACK" + "${SOURCE_PATH}/COPYING.MPL2" +) diff --git a/cmake/resources/vcpkg/overlay-ports/eigen3/vcpkg.json b/cmake/resources/vcpkg/overlay-ports/eigen3/vcpkg.json new file mode 100644 index 0000000..a43dc8c --- /dev/null +++ b/cmake/resources/vcpkg/overlay-ports/eigen3/vcpkg.json @@ -0,0 +1,18 @@ +{ + "name": "eigen3", + "version": "3.4.1", + "port-version": 1, + "description": "C++ template library for linear algebra: matrices, vectors, numerical solvers, and related algorithms.", + "homepage": "http://eigen.tuxfamily.org", + "license": "MPL-2.0", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ] +} diff --git a/include/CentralFDOperator.hxx b/include/CentralFDOperator.hxx index 45b198a..228cee0 100644 --- a/include/CentralFDOperator.hxx +++ b/include/CentralFDOperator.hxx @@ -204,7 +204,7 @@ public: default: LOG(SWS::LOG_ERROR, "Unknown direction {} requested within CentralFDOperator::apply()", - d); + static_cast(d)); break; } diff --git a/include/ExecutionContext.hxx b/include/ExecutionContext.hxx index 7762d7c..9023f8a 100644 --- a/include/ExecutionContext.hxx +++ b/include/ExecutionContext.hxx @@ -35,6 +35,10 @@ #include "sewas.h" #endif +#ifdef SEWAS_WITH_STARPU +#include "SEWASStarPU.hxx" +#endif + #include "SEWASParameterManager.hxx" class ExecutionContext @@ -63,6 +67,10 @@ public: SEWASPaRSEC::finalize(); #endif +#ifdef SEWAS_WITH_STARPU + SEWASStarPU::finalize(); +#endif + #if SEWAS_DISTRIBUTED MPI_Finalize(); #endif diff --git a/include/LogManager.hxx b/include/LogManager.hxx index 8ad0895..4ccbd04 100644 --- a/include/LogManager.hxx +++ b/include/LogManager.hxx @@ -71,7 +71,7 @@ public: default: logger_->warn("The selected log level ({}) is not supported. Fall back " "to INFO level.", - level); + static_cast(level)); logger_->info(msg...); break; } diff --git a/include/SEWASSequential.hxx b/include/SEWASSequential.hxx index 1dfa1f7..c10b892 100644 --- a/include/SEWASSequential.hxx +++ b/include/SEWASSequential.hxx @@ -131,7 +131,9 @@ private: } break; default: - LOG(SWS::LOG_ERROR, "Unknown location {} requested within SEWASSequential::sendreceive()", l); + LOG(SWS::LOG_ERROR, + "Unknown location {} requested within SEWASSequential::sendreceive()", + static_cast(l)); break; } @@ -183,7 +185,9 @@ private: } break; default: - LOG(SWS::LOG_ERROR, "Unknown location {} requested within SEWASSequential::sendreceive()", l); + LOG(SWS::LOG_ERROR, + "Unknown location {} requested within SEWASSequential::sendreceive()", + static_cast(l)); } return status; diff --git a/include/SEWASStarPU.hxx b/include/SEWASStarPU.hxx new file mode 100644 index 0000000..45d8a36 --- /dev/null +++ b/include/SEWASStarPU.hxx @@ -0,0 +1,119 @@ +/* + SeWaS + Copyright (C) 2018 ANEO + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +==============================================================================*/ + +#pragma once + +#ifdef SEWAS_WITH_STARPU +#include + +#include +#include + +#include "Config.hxx" +#include "SEWASParameterManager.hxx" + +/* SEWASStarPU drives the same two-phase-per-timestep algorithm as + * SEWASSequential (see SEWASSequential.hxx), but submits one StarPU task per + * local tile per phase (parallel across tiles within a node, via + * --nthreads), and performs cross-rank halo exchange with the explicit + * starpu_mpi_isend_detached/irecv_detached API, which -- unlike PaRSEC and + * StarPU's own starpu_mpi_task_insert API -- does not exhibit a cross-rank + * deadlock under this access pattern. Same-rank neighbor tiles are handled + * with a plain memcpy, exactly like SEWASSequential::sendreceive(). */ +class SEWASStarPU +{ +public: + static SEWASStarPU* getInstance(const int nt = 1, const int nxx = 1, const int nyy = 1, const int nzz = 1); + static void releaseInstance(); + + static void init(SEWASParameterManager& pm); + static void finalize(); + + int run(); + +private: + enum DataTransferStages + { + SEND, + RECEIVE + }; + + SEWASStarPU(const int nt, const int nxx, const int nyy, const int nzz); + ~SEWASStarPU(); + + void buildVelocityArenas(); + void buildStressArenas(); + void destroyVelocityArenas(); + void destroyStressArenas(); + + void exchangeVelocityHalo(const SWS::Directions d, const int ts); + void exchangeStressHalo(const SWS::StressFieldComponents sc, const int ts); + + size_t haloHandleIndex(const int lii, const int ljj, const int lkk, const SWS::Locations l) const noexcept; + + starpu_mpi_tag_t makeTag(const bool isStress, + const int comp, + const int ts, + const int ii, + const int jj, + const int kk, + const SWS::Locations l) const noexcept; + + bool neighborCoords(const int ii, + const int jj, + const int kk, + const SWS::Locations l, + int& nii, + int& njj, + int& nkk) const noexcept; + + static SWS::Locations opposite(const SWS::Locations l) noexcept; + + static void initializeFieldsCodelet(void* buffers[], void* cl_arg); + static void phaseAVelocityCodelet(void* buffers[], void* cl_arg); + static void phaseBStressCodelet(void* buffers[], void* cl_arg); + + static SEWASStarPU* pInstance_; + + int world_; + int rank_; + + int nt_; + int nxx_; + int nyy_; + int nzz_; + + int lnxx_; + int lnyy_; + int lnzz_; + + /* Persistent send/receive halo buffers, sized to the local tile grid + * (mirrors SEWASSequential's own arenas, and HaloManager's own sigmaH_/vH_ + * sizing): sigmaH_[u](sc)(lii,ljj,lkk)(l), vH_[u](d)(lii,ljj,lkk)(l). */ + SWS::StressFieldHalo sigmaH_[2]; + SWS::VelocityHalo vH_[2]; + + /* StarPU handles wrapping the buffers above, flattened per (component, + * local tile, location); only used for cross-rank transfers -- same-rank + * neighbors are handled with a plain memcpy and never touch these. */ + std::vector vSendHandles_[SWS::DIM]; + std::vector vRecvHandles_[SWS::DIM]; + std::vector sSendHandles_[SWS::NB_STRESS_FIELD_COMPONENTS]; + std::vector sRecvHandles_[SWS::NB_STRESS_FIELD_COMPONENTS]; +}; +#endif diff --git a/include/Types.hxx b/include/Types.hxx index d15d643..f43a691 100644 --- a/include/Types.hxx +++ b/include/Types.hxx @@ -33,7 +33,9 @@ namespace SWS { using RealType = double; #ifdef SEWAS_WITH_PARSEC -constexpr auto PARSECRealType = parsec_datatype_double_t; +// Not constexpr: under Open MPI, MPI_DOUBLE (and thus parsec_datatype_double_t) +// expands to a pointer cast, which isn't a valid constant expression. +static const auto PARSECRealType = parsec_datatype_double_t; #endif constexpr auto Ordering = Orderings::Y_MAJOR; diff --git a/src/ExecutionContext.cxx b/src/ExecutionContext.cxx index 46e697e..a9e1162 100644 --- a/src/ExecutionContext.cxx +++ b/src/ExecutionContext.cxx @@ -19,6 +19,7 @@ #include "ExecutionContext.hxx" #include "LogManager.hxx" #include "SEWASPaRSEC.hxx" +#include "SEWASStarPU.hxx" int ExecutionContext::init(SEWASParameterManager& pm) @@ -50,5 +51,14 @@ ExecutionContext::init(SEWASParameterManager& pm) LOG(SWS::LOG_INFO, "PaRSEC runtime is started"); #endif +#ifdef SEWAS_WITH_STARPU + /* StarPU initialization */ + LOG(SWS::LOG_INFO, "Starting the StarPU runtime"); + + SEWASStarPU::init(pm); + + LOG(SWS::LOG_INFO, "StarPU runtime is started"); +#endif + return 0; } diff --git a/src/HaloManager.cxx b/src/HaloManager.cxx index e31ef49..11782dd 100644 --- a/src/HaloManager.cxx +++ b/src/HaloManager.cxx @@ -173,7 +173,7 @@ HaloManager::getHaloSize(const SWS::Locations l, const int ii, const int jj, con hs = cx * cy * hnz_; break; default: - LOG(SWS::LOG_ERROR, "Unknown location {} requested within HaloManager::getHaloSize()", l); + LOG(SWS::LOG_ERROR, "Unknown location {} requested within HaloManager::getHaloSize()", static_cast(l)); break; } @@ -268,8 +268,8 @@ HaloManager::extractStressHalo(const SWS::Locations l, // MetricsManager::getInstance()->start("ExtractStressHalo"); LOG(SWS::LOG_TRACE, "[start] Extracting ({},{})-stress halo at time-step {} on tile ({}, {}, {})", - l, - sc, + static_cast(l), + static_cast(sc), ts, ii, jj, @@ -302,8 +302,8 @@ HaloManager::extractStressHalo(const SWS::Locations l, // MetricsManager::getInstance()->stop("ExtractStressHalo"); LOG(SWS::LOG_TRACE, "[stop] Extracting ({},{})-stress halo at time-step {} on tile ({}, {}, {})", - l, - sc, + static_cast(l), + static_cast(sc), ts, ii, jj, @@ -323,8 +323,8 @@ HaloManager::extractVelocityHalo(const SWS::Locations l, // MetricsManager::getInstance()->start("ExtractVelocityHalo"); LOG(SWS::LOG_TRACE, "[start] Extracting ({},{})-velocity halo at time-step {} on tile ({}, {}, {})", - l, - d, + static_cast(l), + static_cast(d), ts, ii, jj, @@ -358,8 +358,8 @@ HaloManager::extractVelocityHalo(const SWS::Locations l, // MetricsManager::getInstance()->stop("ExtractVelocityHalo"); LOG(SWS::LOG_TRACE, "[stop] Extracting ({},{})-velocity halo at time-step {} on tile ({}, {}, {})", - l, - d, + static_cast(l), + static_cast(d), ts, ii, jj, @@ -431,7 +431,9 @@ HaloManager::setExtractOffsets(const SWS::Locations l, kShift = kEnd - hnz_; break; default: - LOG(SWS::LOG_ERROR, "Unknown halo location {} requested within HaloManager::setExtractOffsets()", l); + LOG(SWS::LOG_ERROR, + "Unknown halo location {} requested within HaloManager::setExtractOffsets()", + static_cast(l)); break; } } @@ -499,7 +501,9 @@ HaloManager::setUpdateOffsets(const SWS::Locations l, kShift = kEnd; break; default: - LOG(SWS::LOG_ERROR, "Unknown halo location {} requested within HaloManager::setUpdateOffsets()", l); + LOG(SWS::LOG_ERROR, + "Unknown halo location {} requested within HaloManager::setUpdateOffsets()", + static_cast(l)); break; } } diff --git a/src/IOManager.cxx b/src/IOManager.cxx index 3d6fa1e..1e1be68 100644 --- a/src/IOManager.cxx +++ b/src/IOManager.cxx @@ -65,7 +65,7 @@ IOManager::dumpVelocity(const SWS::Directions d, const int ts, const int ii, con int status = 0; #ifdef ENABLE_IO - LOG(SWS::LOG_DEBUG, "[start] Dumping v({})({},{},{}) at ts={}", d, ii, jj, kk, ts); + LOG(SWS::LOG_DEBUG, "[start] Dumping v({})({},{},{}) at ts={}", static_cast(d), ii, jj, kk, ts); const auto& tile3D = LinearSeismicWaveModel::getInstance()->v(d)(ii, jj, kk); @@ -77,7 +77,7 @@ IOManager::dumpVelocity(const SWS::Directions d, const int ts, const int ii, con status = dumpTile(velocityWriter_, tile3D, tileID); } - LOG(SWS::LOG_DEBUG, "[stop] Dumping v({})({},{},{}) at ts={}", d, ii, jj, kk, ts); + LOG(SWS::LOG_DEBUG, "[stop] Dumping v({})({},{},{}) at ts={}", static_cast(d), ii, jj, kk, ts); #endif return status; @@ -105,7 +105,7 @@ IOManager::dumpStress(const SWS::StressFieldComponents sc, int status = 0; #ifdef ENABLE_IO - LOG(SWS::LOG_DEBUG, "[start] Dumping sigma({})({},{},{}) at ts={}", sc, ii, jj, kk, ts); + LOG(SWS::LOG_DEBUG, "[start] Dumping sigma({})({},{},{}) at ts={}", static_cast(sc), ii, jj, kk, ts); const auto& tile3D = LinearSeismicWaveModel::getInstance()->sigma(sc)(ii, jj, kk); @@ -117,7 +117,7 @@ IOManager::dumpStress(const SWS::StressFieldComponents sc, status = dumpTile(stressWriter_, tile3D, tileID); } - LOG(SWS::LOG_DEBUG, "[stop] Dumping sigma({})({},{},{}) at ts={}", sc, ii, jj, kk, ts); + LOG(SWS::LOG_DEBUG, "[stop] Dumping sigma({})({},{},{}) at ts={}", static_cast(sc), ii, jj, kk, ts); #endif return status; @@ -146,9 +146,9 @@ IOManager::init() int status = 0; #ifdef ENABLE_IO #if SEWAS_DISTRIBUTED - adios_ = std::make_unique(MPI_COMM_WORLD, adios2::DebugON); + adios_ = std::make_unique(MPI_COMM_WORLD); #else - adios_ = std::make_unique(adios2::DebugON); + adios_ = std::make_unique(); #endif processedTasks_[0] = 3 * lnxx_ * lnyy_ * lnzz_; diff --git a/src/LinearSeismicWaveModel.cxx b/src/LinearSeismicWaveModel.cxx index b0914e8..b030a57 100644 --- a/src/LinearSeismicWaveModel.cxx +++ b/src/LinearSeismicWaveModel.cxx @@ -42,6 +42,7 @@ #include "MetricsManager.hxx" #include "SEWASPaRSEC.hxx" #include "SEWASSequential.hxx" +#include "SEWASStarPU.hxx" LinearSeismicWaveModel* LinearSeismicWaveModel::pInstance_ = nullptr; @@ -76,7 +77,7 @@ LinearSeismicWaveModel::releaseInstance() int LinearSeismicWaveModel::propagate() noexcept { -#ifdef SEWAS_WITH_PARSEC +#if defined(SEWAS_WITH_PARSEC) LOG(SWS::LOG_INFO, "Starting the PaRSEC-based runner"); SEWASPaRSEC* sewasPaRSEC = SEWASPaRSEC::getInstance(nt_, pm_.nxx(), pm_.nyy(), pm_.nzz()); @@ -87,6 +88,17 @@ LinearSeismicWaveModel::propagate() noexcept LOG(SWS::LOG_INFO, "Seismic simulation completed"); SEWASPaRSEC::releaseInstance(); +#elif defined(SEWAS_WITH_STARPU) + LOG(SWS::LOG_INFO, "Starting the StarPU-based runner"); + + SEWASStarPU* sewasStarPU = SEWASStarPU::getInstance(nt_, pm_.nxx(), pm_.nyy(), pm_.nzz()); + LOG(SWS::LOG_INFO, "StarPU-based runner started"); + + LOG(SWS::LOG_INFO, "Starting execution of the core seismic simulation"); + sewasStarPU->run(); + LOG(SWS::LOG_INFO, "Seismic simulation completed"); + + SEWASStarPU::releaseInstance(); #else LOG(SWS::LOG_INFO, "Starting the sequential runner"); SEWASSequential* sewasSequential = SEWASSequential::getInstance(nt_, pm_.nxx(), pm_.nyy(), pm_.nzz()); @@ -314,7 +326,7 @@ LinearSeismicWaveModel::computeVelocity(const SWS::Directions& d, default: LOG(SWS::LOG_ERROR, "Unknown spatial direction {} requested within LinearSeismicWaveModel::computeVelocity()", - d); + static_cast(d)); break; } @@ -616,7 +628,7 @@ LinearSeismicWaveModel::computeStress(const SWS::StressFieldComponents& sc, default: LOG(SWS::LOG_ERROR, "Unknown stress component {} requested within LinearSeismicWaveModel::computeStress()", - sc); + static_cast(sc)); break; } @@ -714,7 +726,7 @@ LinearSeismicWaveModel::addVelocitySource(const SWS::Directions& d, default: LOG(SWS::LOG_ERROR, "Unknown spatial direction {} requested within LinearSeismicWaveModel::addVelocitySource()", - d); + static_cast(d)); break; } } diff --git a/src/SEWASPaRSEC.cxx b/src/SEWASPaRSEC.cxx index ba8adae..0fe6848 100644 --- a/src/SEWASPaRSEC.cxx +++ b/src/SEWASPaRSEC.cxx @@ -20,6 +20,8 @@ #ifdef SEWAS_WITH_PARSEC +#include // parsec_arena_datatype_construct + #include "Config.hxx" #include "HaloManager.hxx" #include "LinearSeismicWaveModel.hxx" @@ -158,12 +160,12 @@ SEWASPaRSEC::buildDAG() void SEWASPaRSEC::enqueueDAG() { - int status = parsec_enqueue(pPContext_, (parsec_taskpool_t*)pDAG_); - PARSEC_CHECK_ERROR(status, "parsec_enqueue"); + int status = parsec_context_add_taskpool(pPContext_, (parsec_taskpool_t*)pDAG_); + PARSEC_CHECK_ERROR(status, "parsec_context_add_taskpool"); } void -SEWASPaRSEC::addArena(const short arena_idx, const SWS::Locations l) +SEWASPaRSEC::addArena(const short adt_idx, const SWS::Locations l) { parsec_datatype_t oldtype = SWS::PARSECRealType; parsec_datatype_t newtype; @@ -176,7 +178,7 @@ SEWASPaRSEC::addArena(const short arena_idx, const SWS::Locations l) parsec_type_create_contiguous(asize, oldtype, &newtype); parsec_type_extent(newtype, &lb, &extent); - parsec_arena_construct(pDAG_->arenas[arena_idx], extent, SWS::Alignment, newtype); + parsec_arena_datatype_construct(&pDAG_->arenas_datatypes[adt_idx], extent, SWS::Alignment, newtype); } SEWASPaRSEC::SEWASPaRSEC(const int nt, const int nxx, const int nyy, const int nzz) @@ -195,6 +197,9 @@ SEWASPaRSEC::SEWASPaRSEC(const int nt, const int nxx, const int nyy, const int n buildDAG(); /* Default halo arena */ + /* Macro suffix is _ARENA, not _ADT_IDX: pinned PaRSEC predates the parsec-ptgpp + rename to _ADT_IDX (see cmake/resources/parsec/CMakeLists.txt for why this + specific commit is pinned instead of a later tag). */ addArena(PARSEC_sewas_DEFAULT_ARENA); /* Stress field halo arenas */ diff --git a/src/SEWASStarPU.cxx b/src/SEWASStarPU.cxx new file mode 100644 index 0000000..7eb235d --- /dev/null +++ b/src/SEWASStarPU.cxx @@ -0,0 +1,591 @@ +/* + SeWaS + Copyright (C) 2018 ANEO + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +==============================================================================*/ + +#include "SEWASStarPU.hxx" + +#ifdef SEWAS_WITH_STARPU + +#include +#include + +#include "ExecutionContext.hxx" +#include "HaloManager.hxx" +#include "LinearSeismicWaveModel.hxx" +#include "LogManager.hxx" +#include "Mesh3DPartitioning.hxx" + +namespace { +struct starpu_codelet +makeCodelet(void (*func)(void*[], void*), const char* name) +{ + struct starpu_codelet cl; + memset(&cl, 0, sizeof(cl)); + cl.cpu_funcs[0] = func; + cl.cpu_funcs_name[0] = name; + cl.nbuffers = 0; + return cl; +} + +/* Clamp into StarPU's currently valid priority range: the active scheduling + * policy may support only a single priority level (or a narrower range than + * MinimumCommunicationPriorityEvaluator's raw output), and starpu_task_insert + * gives no other feedback for an out-of-range value. */ +int +clampPriority(const int priority) noexcept +{ + const int minPrio = starpu_sched_get_min_priority(); + const int maxPrio = starpu_sched_get_max_priority(); + return (std::max)(minPrio, (std::min)(maxPrio, priority)); +} +} + +SEWASStarPU* SEWASStarPU::pInstance_ = nullptr; + +SEWASStarPU* +SEWASStarPU::getInstance(const int nt, const int nxx, const int nyy, const int nzz) +{ + if (nullptr == pInstance_) { + pInstance_ = new SEWASStarPU(nt, nxx, nyy, nzz); + } + return pInstance_; +} + +void +SEWASStarPU::releaseInstance() +{ + if (pInstance_) { + delete pInstance_; + pInstance_ = nullptr; + } +} + +void +SEWASStarPU::init(SEWASParameterManager& pm) +{ + struct starpu_conf conf; + starpu_conf_init(&conf); + conf.ncpus = pm.nthreads(); + + int status = starpu_init(&conf); + if (status != 0) { + LOG(SWS::LOG_CRITICAL, "starpu_init failed with status {}", status); + exit(SWS::OBJECT_CREATION_FAILURE); + } + + /* MPI is already initialized by ExecutionContext::init(); StarPU-MPI must not + * re-initialize it -- same ownership model SEWASPaRSEC::init() follows for PaRSEC. */ + status = starpu_mpi_init_comm(&pm.argc(), &pm.argv(), 0, MPI_COMM_WORLD); + if (status != 0) { + LOG(SWS::LOG_CRITICAL, "starpu_mpi_init_comm failed with status {}", status); + exit(SWS::OBJECT_CREATION_FAILURE); + } +} + +void +SEWASStarPU::finalize() +{ + starpu_mpi_shutdown(); + starpu_shutdown(); +} + +size_t +SEWASStarPU::haloHandleIndex(const int lii, const int ljj, const int lkk, const SWS::Locations l) const noexcept +{ + return (((size_t)lii * lnyy_ + ljj) * lnzz_ + lkk) * SWS::NB_LOCATIONS + l; +} + +starpu_mpi_tag_t +SEWASStarPU::makeTag(const bool isStress, + const int comp, + const int ts, + const int ii, + const int jj, + const int kk, + const SWS::Locations l) const noexcept +{ + int64_t t = isStress ? 1 : 0; + t = t * 8 + comp; + t = t * SWS::NB_LOCATIONS + l; + t = t * nxx_ + ii; + t = t * nyy_ + jj; + t = t * nzz_ + kk; + t = t * (nt_ + 1) + ts; + return (starpu_mpi_tag_t)t; +} + +bool +SEWASStarPU::neighborCoords(const int ii, + const int jj, + const int kk, + const SWS::Locations l, + int& nii, + int& njj, + int& nkk) const noexcept +{ + nii = ii; + njj = jj; + nkk = kk; + + switch (l) { + case SWS::LEFT: + if (ii <= 0) return false; + nii = ii - 1; + break; + case SWS::RIGHT: + if (ii >= nxx_ - 1) return false; + nii = ii + 1; + break; + case SWS::BACKWARD: + if (jj <= 0) return false; + njj = jj - 1; + break; + case SWS::FORWARD: + if (jj >= nyy_ - 1) return false; + njj = jj + 1; + break; + case SWS::BOTTOM: + if (kk <= 0) return false; + nkk = kk - 1; + break; + case SWS::TOP: + if (kk >= nzz_ - 1) return false; + nkk = kk + 1; + break; + default: + LOG(SWS::LOG_ERROR, + "Unknown location {} requested within SEWASStarPU::neighborCoords()", + static_cast(l)); + return false; + } + + return true; +} + +SWS::Locations +SEWASStarPU::opposite(const SWS::Locations l) noexcept +{ + switch (l) { + case SWS::LEFT: + return SWS::RIGHT; + case SWS::RIGHT: + return SWS::LEFT; + case SWS::BACKWARD: + return SWS::FORWARD; + case SWS::FORWARD: + return SWS::BACKWARD; + case SWS::BOTTOM: + return SWS::TOP; + case SWS::TOP: + return SWS::BOTTOM; + default: + LOG(SWS::LOG_ERROR, "Unknown location {} requested within SEWASStarPU::opposite()", static_cast(l)); + return SWS::NB_LOCATIONS; + } +} + +void +SEWASStarPU::buildVelocityArenas() +{ + auto* pHaloManager = HaloManager::getInstance(); + + for (auto d : { SWS::X, SWS::Y, SWS::Z }) { + for (auto u : { SEND, RECEIVE }) { + vH_[u](d).resize(lnxx_, lnyy_, lnzz_); + } + + vSendHandles_[d].assign((size_t)lnxx_ * lnyy_ * lnzz_ * SWS::NB_LOCATIONS, nullptr); + vRecvHandles_[d].assign((size_t)lnxx_ * lnyy_ * lnzz_ * SWS::NB_LOCATIONS, nullptr); + + for (int lii = 0; lii < lnxx_; lii++) { + for (int ljj = 0; ljj < lnyy_; ljj++) { + for (int lkk = 0; lkk < lnzz_; lkk++) { + for (auto l : { SWS::LEFT, SWS::RIGHT, SWS::BACKWARD, SWS::FORWARD, SWS::BOTTOM, SWS::TOP }) { + const auto hsize = pHaloManager->getHaloSize(l, lii, ljj, lkk); + + auto* sendBuf = new SWS::RealType[hsize]; + memset(sendBuf, 0, hsize * sizeof(SWS::RealType)); + vH_[SEND](d)(lii, ljj, lkk)(l) = sendBuf; + + auto* recvBuf = new SWS::RealType[hsize]; + memset(recvBuf, 0, hsize * sizeof(SWS::RealType)); + vH_[RECEIVE](d)(lii, ljj, lkk)(l) = recvBuf; + + const auto idx = haloHandleIndex(lii, ljj, lkk, l); + starpu_vector_data_register( + &vSendHandles_[d][idx], STARPU_MAIN_RAM, (uintptr_t)sendBuf, hsize, sizeof(SWS::RealType)); + starpu_vector_data_register( + &vRecvHandles_[d][idx], STARPU_MAIN_RAM, (uintptr_t)recvBuf, hsize, sizeof(SWS::RealType)); + } + } + } + } + } +} + +void +SEWASStarPU::buildStressArenas() +{ + auto* pHaloManager = HaloManager::getInstance(); + + for (auto sc : { SWS::XX, SWS::YY, SWS::ZZ, SWS::XY, SWS::XZ, SWS::YZ }) { + for (auto u : { SEND, RECEIVE }) { + sigmaH_[u](sc).resize(lnxx_, lnyy_, lnzz_); + } + + sSendHandles_[sc].assign((size_t)lnxx_ * lnyy_ * lnzz_ * SWS::NB_LOCATIONS, nullptr); + sRecvHandles_[sc].assign((size_t)lnxx_ * lnyy_ * lnzz_ * SWS::NB_LOCATIONS, nullptr); + + for (int lii = 0; lii < lnxx_; lii++) { + for (int ljj = 0; ljj < lnyy_; ljj++) { + for (int lkk = 0; lkk < lnzz_; lkk++) { + for (auto l : { SWS::LEFT, SWS::RIGHT, SWS::BACKWARD, SWS::FORWARD, SWS::BOTTOM, SWS::TOP }) { + const auto hsize = pHaloManager->getHaloSize(l, lii, ljj, lkk); + + auto* sendBuf = new SWS::RealType[hsize]; + memset(sendBuf, 0, hsize * sizeof(SWS::RealType)); + sigmaH_[SEND](sc)(lii, ljj, lkk)(l) = sendBuf; + + auto* recvBuf = new SWS::RealType[hsize]; + memset(recvBuf, 0, hsize * sizeof(SWS::RealType)); + sigmaH_[RECEIVE](sc)(lii, ljj, lkk)(l) = recvBuf; + + const auto idx = haloHandleIndex(lii, ljj, lkk, l); + starpu_vector_data_register( + &sSendHandles_[sc][idx], STARPU_MAIN_RAM, (uintptr_t)sendBuf, hsize, sizeof(SWS::RealType)); + starpu_vector_data_register( + &sRecvHandles_[sc][idx], STARPU_MAIN_RAM, (uintptr_t)recvBuf, hsize, sizeof(SWS::RealType)); + } + } + } + } + } +} + +void +SEWASStarPU::destroyVelocityArenas() +{ + for (auto d : { SWS::X, SWS::Y, SWS::Z }) { + for (int lii = 0; lii < lnxx_; lii++) { + for (int ljj = 0; ljj < lnyy_; ljj++) { + for (int lkk = 0; lkk < lnzz_; lkk++) { + for (auto l : { SWS::LEFT, SWS::RIGHT, SWS::BACKWARD, SWS::FORWARD, SWS::BOTTOM, SWS::TOP }) { + const auto idx = haloHandleIndex(lii, ljj, lkk, l); + + starpu_data_unregister(vSendHandles_[d][idx]); + starpu_data_unregister(vRecvHandles_[d][idx]); + + delete[] vH_[SEND](d)(lii, ljj, lkk)(l); + delete[] vH_[RECEIVE](d)(lii, ljj, lkk)(l); + } + } + } + } + } +} + +void +SEWASStarPU::destroyStressArenas() +{ + for (auto sc : { SWS::XX, SWS::YY, SWS::ZZ, SWS::XY, SWS::XZ, SWS::YZ }) { + for (int lii = 0; lii < lnxx_; lii++) { + for (int ljj = 0; ljj < lnyy_; ljj++) { + for (int lkk = 0; lkk < lnzz_; lkk++) { + for (auto l : { SWS::LEFT, SWS::RIGHT, SWS::BACKWARD, SWS::FORWARD, SWS::BOTTOM, SWS::TOP }) { + const auto idx = haloHandleIndex(lii, ljj, lkk, l); + + starpu_data_unregister(sSendHandles_[sc][idx]); + starpu_data_unregister(sRecvHandles_[sc][idx]); + + delete[] sigmaH_[SEND](sc)(lii, ljj, lkk)(l); + delete[] sigmaH_[RECEIVE](sc)(lii, ljj, lkk)(l); + } + } + } + } + } +} + +void +SEWASStarPU::exchangeVelocityHalo(const SWS::Directions d, const int ts) +{ + auto* pHaloManager = HaloManager::getInstance(); + auto& vH_S = vH_[SEND]; + auto& vH_R = vH_[RECEIVE]; + + for (int ii = 0; ii < nxx_; ii++) { + for (int jj = 0; jj < nyy_; jj++) { + for (int kk = 0; kk < nzz_; kk++) { + if (Mesh3DPartitioning::rank_of(ii, jj, kk) != rank_) continue; + + const int lii = ii % lnxx_; + const int ljj = jj % lnyy_; + const int lkk = kk % lnzz_; + + for (auto l : { SWS::LEFT, SWS::RIGHT, SWS::BACKWARD, SWS::FORWARD, SWS::BOTTOM, SWS::TOP }) { + int nii, njj, nkk; + if (!neighborCoords(ii, jj, kk, l, nii, njj, nkk)) { + continue; + } + + const int nrank = Mesh3DPartitioning::rank_of(nii, njj, nkk); + const auto hsize = pHaloManager->getHaloSize(l, lii, ljj, lkk); + const auto lOpp = opposite(l); + + if (nrank == rank_) { + const int nlii = nii % lnxx_, nljj = njj % lnyy_, nlkk = nkk % lnzz_; + memcpy(vH_R(d)(nlii, nljj, nlkk)(lOpp), vH_S(d)(lii, ljj, lkk)(l), hsize * sizeof(SWS::RealType)); + } else { + const auto idx = haloHandleIndex(lii, ljj, lkk, l); + + const auto outTag = makeTag(false, d, ts, ii, jj, kk, l); + starpu_mpi_isend_detached(vSendHandles_[d][idx], nrank, outTag, MPI_COMM_WORLD, nullptr, nullptr); + + const auto inTag = makeTag(false, d, ts, nii, njj, nkk, lOpp); + starpu_mpi_irecv_detached(vRecvHandles_[d][idx], nrank, inTag, MPI_COMM_WORLD, nullptr, nullptr); + } + } + } + } + } +} + +void +SEWASStarPU::exchangeStressHalo(const SWS::StressFieldComponents sc, const int ts) +{ + auto* pHaloManager = HaloManager::getInstance(); + auto& sigmaH_S = sigmaH_[SEND]; + auto& sigmaH_R = sigmaH_[RECEIVE]; + + for (int ii = 0; ii < nxx_; ii++) { + for (int jj = 0; jj < nyy_; jj++) { + for (int kk = 0; kk < nzz_; kk++) { + if (Mesh3DPartitioning::rank_of(ii, jj, kk) != rank_) continue; + + const int lii = ii % lnxx_; + const int ljj = jj % lnyy_; + const int lkk = kk % lnzz_; + + for (auto l : { SWS::LEFT, SWS::RIGHT, SWS::BACKWARD, SWS::FORWARD, SWS::BOTTOM, SWS::TOP }) { + int nii, njj, nkk; + if (!neighborCoords(ii, jj, kk, l, nii, njj, nkk)) { + continue; + } + + const int nrank = Mesh3DPartitioning::rank_of(nii, njj, nkk); + const auto hsize = pHaloManager->getHaloSize(l, lii, ljj, lkk); + const auto lOpp = opposite(l); + + if (nrank == rank_) { + const int nlii = nii % lnxx_, nljj = njj % lnyy_, nlkk = nkk % lnzz_; + memcpy( + sigmaH_R(sc)(nlii, nljj, nlkk)(lOpp), sigmaH_S(sc)(lii, ljj, lkk)(l), hsize * sizeof(SWS::RealType)); + } else { + const auto idx = haloHandleIndex(lii, ljj, lkk, l); + + const auto outTag = makeTag(true, sc, ts, ii, jj, kk, l); + starpu_mpi_isend_detached(sSendHandles_[sc][idx], nrank, outTag, MPI_COMM_WORLD, nullptr, nullptr); + + const auto inTag = makeTag(true, sc, ts, nii, njj, nkk, lOpp); + starpu_mpi_irecv_detached(sRecvHandles_[sc][idx], nrank, inTag, MPI_COMM_WORLD, nullptr, nullptr); + } + } + } + } + } +} + +void +SEWASStarPU::initializeFieldsCodelet(void* /*buffers*/[], void* cl_arg) +{ + int ii, jj, kk; + starpu_codelet_unpack_args(cl_arg, &ii, &jj, &kk); + LinearSeismicWaveModel::initializeFieldsWrapper(ii, jj, kk); +} + +void +SEWASStarPU::phaseAVelocityCodelet(void* /*buffers*/[], void* cl_arg) +{ + int ts, ii, jj, kk, lii, ljj, lkk; + starpu_codelet_unpack_args(cl_arg, &ts, &ii, &jj, &kk, &lii, &ljj, &lkk); + + auto& sigmaH_R = pInstance_->sigmaH_[RECEIVE]; + auto& vH_S = pInstance_->vH_[SEND]; + + for (auto l : { SWS::LEFT, SWS::RIGHT, SWS::BACKWARD, SWS::FORWARD, SWS::BOTTOM, SWS::TOP }) { + for (auto sc : { SWS::XX, SWS::YY, SWS::ZZ, SWS::XY, SWS::XZ, SWS::YZ }) { + HaloManager::updateStressWrapper(l, sc, ts - 1, ii, jj, kk, sigmaH_R(sc)(lii, ljj, lkk)(l)); + } + } + + for (auto d : { SWS::X, SWS::Y, SWS::Z }) { + LinearSeismicWaveModel::computeVelocityWrapper(d, ts, ii, jj, kk); + + for (auto l : { SWS::LEFT, SWS::RIGHT, SWS::BACKWARD, SWS::FORWARD, SWS::BOTTOM, SWS::TOP }) { + HaloManager::extractVelocityHaloWrapper(l, d, ts, ii, jj, kk, vH_S(d)(lii, ljj, lkk)(l)); + } + } +} + +void +SEWASStarPU::phaseBStressCodelet(void* /*buffers*/[], void* cl_arg) +{ + int ts, ii, jj, kk, lii, ljj, lkk; + starpu_codelet_unpack_args(cl_arg, &ts, &ii, &jj, &kk, &lii, &ljj, &lkk); + + auto& vH_R = pInstance_->vH_[RECEIVE]; + auto& sigmaH_S = pInstance_->sigmaH_[SEND]; + + for (auto l : { SWS::LEFT, SWS::RIGHT, SWS::BACKWARD, SWS::FORWARD, SWS::BOTTOM, SWS::TOP }) { + for (auto d : { SWS::X, SWS::Y, SWS::Z }) { + HaloManager::updateVelocityWrapper(l, d, ts, ii, jj, kk, vH_R(d)(lii, ljj, lkk)(l)); + } + } + + for (auto sc : { SWS::XX, SWS::YY, SWS::ZZ, SWS::XY, SWS::XZ, SWS::YZ }) { + LinearSeismicWaveModel::computeStressWrapper(sc, ts + 1, ii, jj, kk); + + for (auto l : { SWS::LEFT, SWS::RIGHT, SWS::BACKWARD, SWS::FORWARD, SWS::BOTTOM, SWS::TOP }) { + HaloManager::extractStressHaloWrapper(l, sc, ts + 1, ii, jj, kk, sigmaH_S(sc)(lii, ljj, lkk)(l)); + } + } +} + +int +SEWASStarPU::run() +{ + int status = 0; + + static struct starpu_codelet initCl = makeCodelet(initializeFieldsCodelet, "initializeFieldsCodelet"); + static struct starpu_codelet phaseACl = makeCodelet(phaseAVelocityCodelet, "phaseAVelocityCodelet"); + static struct starpu_codelet phaseBCl = makeCodelet(phaseBStressCodelet, "phaseBStressCodelet"); + + auto* pPriorityManager = Mesh3DPartitioning::getInstance()->getTaskPriorityManager(); + + auto forEachLocalTile = [this](auto&& fn) { + for (int ii = 0; ii < nxx_; ii++) { + for (int jj = 0; jj < nyy_; jj++) { + for (int kk = 0; kk < nzz_; kk++) { + if (Mesh3DPartitioning::rank_of(ii, jj, kk) != rank_) continue; + fn(ii, jj, kk, ii % lnxx_, jj % lnyy_, kk % lnzz_); + } + } + } + }; + + forEachLocalTile([&](int ii, int jj, int kk, int /*lii*/, int /*ljj*/, int /*lkk*/) { + const auto prio = clampPriority(pPriorityManager->getPriority(INITIALIZE_FIELDS, 0, ii, jj, kk)); + starpu_task_insert(&initCl, + STARPU_VALUE, &ii, sizeof(ii), + STARPU_VALUE, &jj, sizeof(jj), + STARPU_VALUE, &kk, sizeof(kk), + STARPU_PRIORITY, (unsigned long long)prio, + 0); + }); + starpu_task_wait_for_all(); + + for (int ts = 2; ts <= nt_ - 2; ts += 2) { + LOG(SWS::LOG_TRACE, "[start] Processing time-step {}", ts); + + forEachLocalTile([&](int ii, int jj, int kk, int lii, int ljj, int lkk) { + /* Bundles UPDATE_STRESS + COMPUTE_VELOCITY + EXTRACT_VELOCITY_HALO into one + * task; take the most urgent of the three sub-steps' priorities. */ + const auto prio = clampPriority((std::max)({ + pPriorityManager->getPriority(UPDATE_STRESS, ts, ii, jj, kk), + pPriorityManager->getPriority(COMPUTE_VELOCITY, ts, ii, jj, kk), + pPriorityManager->getPriority(EXTRACT_VELOCITY_HALO, ts, ii, jj, kk), + })); + starpu_task_insert(&phaseACl, + STARPU_VALUE, &ts, sizeof(ts), + STARPU_VALUE, &ii, sizeof(ii), + STARPU_VALUE, &jj, sizeof(jj), + STARPU_VALUE, &kk, sizeof(kk), + STARPU_VALUE, &lii, sizeof(lii), + STARPU_VALUE, &ljj, sizeof(ljj), + STARPU_VALUE, &lkk, sizeof(lkk), + STARPU_PRIORITY, (unsigned long long)prio, + 0); + }); + starpu_task_wait_for_all(); + + for (auto d : { SWS::X, SWS::Y, SWS::Z }) { + exchangeVelocityHalo(d, ts); + } + starpu_mpi_wait_for_all(MPI_COMM_WORLD); + + forEachLocalTile([&](int ii, int jj, int kk, int lii, int ljj, int lkk) { + /* Bundles UPDATE_VELOCITY + COMPUTE_STRESS + EXTRACT_STRESS_HALO into one + * task; take the most urgent of the three sub-steps' priorities. */ + const auto prio = clampPriority((std::max)({ + pPriorityManager->getPriority(UPDATE_VELOCITY, ts, ii, jj, kk), + pPriorityManager->getPriority(COMPUTE_STRESS, ts, ii, jj, kk), + pPriorityManager->getPriority(EXTRACT_STRESS_HALO, ts, ii, jj, kk), + })); + starpu_task_insert(&phaseBCl, + STARPU_VALUE, &ts, sizeof(ts), + STARPU_VALUE, &ii, sizeof(ii), + STARPU_VALUE, &jj, sizeof(jj), + STARPU_VALUE, &kk, sizeof(kk), + STARPU_VALUE, &lii, sizeof(lii), + STARPU_VALUE, &ljj, sizeof(ljj), + STARPU_VALUE, &lkk, sizeof(lkk), + STARPU_PRIORITY, (unsigned long long)prio, + 0); + }); + starpu_task_wait_for_all(); + + for (auto sc : { SWS::XX, SWS::YY, SWS::ZZ, SWS::XY, SWS::XZ, SWS::YZ }) { + exchangeStressHalo(sc, ts); + } + starpu_mpi_wait_for_all(MPI_COMM_WORLD); + + LOG(SWS::LOG_TRACE, "[stop] Processing time-step {}", ts); + } + + return status; +} + +SEWASStarPU::SEWASStarPU(const int nt, const int nxx, const int nyy, const int nzz) + : nt_(nt) + , nxx_(nxx) + , nyy_(nyy) + , nzz_(nzz) +{ + world_ = ExecutionContext::world(); + rank_ = ExecutionContext::rank(); + + auto* pMesh = Mesh3DPartitioning::getInstance(); + lnxx_ = pMesh->lnxx(); + lnyy_ = pMesh->lnyy(); + lnzz_ = pMesh->lnzz(); + + /* Evaluate task priorities: currently unused by this phase-barrier design (there is + * no cross-phase overlap left to schedule around), kept for parity with SEWASPaRSEC + * and as a hook for future, finer-grained pipelining. */ + pMesh->getTaskPriorityManager()->evaluate(); + + buildVelocityArenas(); + buildStressArenas(); +} + +SEWASStarPU::~SEWASStarPU() +{ + destroyVelocityArenas(); + destroyStressArenas(); +} + +#endif // SEWAS_WITH_STARPU diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bb4cda1..8850177 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -38,6 +38,7 @@ add_executable(ComputeVelocityTest ../src/Mesh3DPartitioning.cxx ../src/SEWASParameterManager.cxx ../src/SEWASPaRSEC.cxx + ../src/SEWASStarPU.cxx ../src/SEWASSequential.cxx ../src/ExecutionContext.cxx ../src/MetricsManager.cxx diff --git a/thirdparty/parsec/patches/increase_max_inout_deps.patch b/thirdparty/parsec/patches/increase_max_inout_deps.patch index 25e5468..2903354 100644 --- a/thirdparty/parsec/patches/increase_max_inout_deps.patch +++ b/thirdparty/parsec/patches/increase_max_inout_deps.patch @@ -1,15 +1,15 @@ diff --git a/parsec/include/parsec/parsec_config_bottom.h b/parsec/include/parsec/parsec_config_bottom.h -index 748c3106b..1b6e0c875 100644 +index 1176e24c0..e654339af 100644 --- a/parsec/include/parsec/parsec_config_bottom.h +++ b/parsec/include/parsec/parsec_config_bottom.h -@@ -105,8 +105,8 @@ typedef int32_t parsec_dependency_t; +@@ -153,8 +153,8 @@ typedef int32_t parsec_dependency_t; #define MAX_LOCAL_COUNT 20 #define MAX_PARAM_COUNT 20 - + -#define MAX_DEP_IN_COUNT 10 -#define MAX_DEP_OUT_COUNT 10 +#define MAX_DEP_IN_COUNT 16 +#define MAX_DEP_OUT_COUNT 16 - + #define MAX_TASK_STRLEN 128 - + diff --git a/thirdparty/vcpkg/patches/add_aarch64_support.patch b/thirdparty/vcpkg/patches/add_aarch64_support.patch deleted file mode 100644 index 65298c4..0000000 --- a/thirdparty/vcpkg/patches/add_aarch64_support.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/scripts/buildsystems/vcpkg.cmake b/scripts/buildsystems/vcpkg.cmake -index 1eebc3b8d..99595c0b8 100644 ---- a/scripts/buildsystems/vcpkg.cmake -+++ b/scripts/buildsystems/vcpkg.cmake -@@ -78,6 +78,8 @@ else() - set(_VCPKG_TARGET_TRIPLET_ARCH x86) - elseif(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64") - set(_VCPKG_TARGET_TRIPLET_ARCH x64) -+ elseif(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "aarch64") -+ set(_VCPKG_TARGET_TRIPLET_ARCH arm64) - else() - if( _CMAKE_IN_TRY_COMPILE ) - message(STATUS "Unable to determine target architecture, continuing without vcpkg.") diff --git a/thirdparty/vcpkg/triplets/arm64-linux.cmake b/thirdparty/vcpkg/triplets/arm64-linux.cmake deleted file mode 100644 index 07452e0..0000000 --- a/thirdparty/vcpkg/triplets/arm64-linux.cmake +++ /dev/null @@ -1,5 +0,0 @@ -set(VCPKG_TARGET_ARCHITECTURE arm64) -set(VCPKG_CRT_LINKAGE dynamic) -set(VCPKG_LIBRARY_LINKAGE static) - -set(VCPKG_CMAKE_SYSTEM_NAME Linux)