├── .clang-format ├── .clang-tidy ├── .github └── workflows │ ├── build-with-IntelMPI.yml │ ├── build-with-mpich.yml │ └── build-with-openmpi.yml ├── .gitignore ├── CMakeLists.txt ├── COPYING ├── README.md ├── cmake ├── PVS-Studio.cmake ├── PVS-Studio.cmake.LICENSE └── mplConfig.cmake ├── doc ├── CMakeLists.txt ├── doxygen │ ├── Doxyfile.in │ ├── README.md │ ├── data_types.md │ └── style.css └── sphinx │ ├── _static │ └── custom.css │ ├── auxiliary.rst │ ├── cmake_integration.rst │ ├── communicator.rst │ ├── conf.py.in │ ├── constants.rst │ ├── data_types.rst │ ├── design.rst │ ├── environmental_management.rst │ ├── error.rst │ ├── examples │ ├── arrays.rst │ ├── blocking.rst │ ├── blocking_vector.rst │ ├── collective.rst │ ├── communicator.rst │ ├── custom_initialization.rst │ ├── distributed_grid.rst │ ├── distributed_grid_scatter_gather.rst │ ├── file.rst │ ├── gather.rst │ ├── gatherv.rst │ ├── heat_equation_Jacobi_method.rst │ ├── heat_equation_successive_over-relaxation.rst │ ├── hello_world.rst │ ├── index.rst │ ├── iterators.rst │ ├── layouts.rst │ ├── matrix_gather.rst │ ├── nonblocking.rst │ ├── nonblocking_mult.rst │ ├── parallel_sort.rst │ ├── probe.rst │ ├── process_creation.rst │ ├── reduce.rst │ ├── standard_types.rst │ ├── stl_container.rst │ ├── struct.rst │ ├── subarray.rst │ └── vibrating_string.rst │ ├── file.rst │ ├── file_error_handling.cc │ ├── grid.rst │ ├── group.rst │ ├── index.rst │ ├── info.rst │ ├── installation.rst │ ├── interoperability.rst │ ├── layouts.rst │ ├── reduction_operations.rst │ └── tags.rst ├── docs ├── .nojekyll ├── html │ ├── _images │ │ ├── graphviz-57432295888f3b1be18dc2ff4389e53d44c4c869.png │ │ ├── graphviz-57432295888f3b1be18dc2ff4389e53d44c4c869.png.map │ │ ├── graphviz-610b9e33bc07bb04b4607643a1f9f6ac5fc1da80.png │ │ ├── graphviz-610b9e33bc07bb04b4607643a1f9f6ac5fc1da80.png.map │ │ ├── graphviz-684df2bb1f5f269b07d535b765e98e0faed34052.png │ │ ├── graphviz-684df2bb1f5f269b07d535b765e98e0faed34052.png.map │ │ ├── graphviz-7106b06e7ffc5ab56026f5ac8ff442871e53c310.png │ │ ├── graphviz-7106b06e7ffc5ab56026f5ac8ff442871e53c310.png.map │ │ ├── graphviz-75a1f18eb87795bf7a08712374e54c8d1b2bd278.png │ │ ├── graphviz-75a1f18eb87795bf7a08712374e54c8d1b2bd278.png.map │ │ ├── graphviz-ac4fbb3880ee103a7ca5c201fb2dee5b4a532839.png │ │ ├── graphviz-ac4fbb3880ee103a7ca5c201fb2dee5b4a532839.png.map │ │ ├── graphviz-b254f1bb6c2aa092534cd14c8d6efccda1b3235f.png │ │ ├── graphviz-b254f1bb6c2aa092534cd14c8d6efccda1b3235f.png.map │ │ ├── graphviz-b4b2d9f87128e4daea95a129e33a37e63efa7c98.png │ │ ├── graphviz-b4b2d9f87128e4daea95a129e33a37e63efa7c98.png.map │ │ ├── graphviz-d91f2fdebe3b7e20ff1761bf5a36baed7437423b.png │ │ ├── graphviz-d91f2fdebe3b7e20ff1761bf5a36baed7437423b.png.map │ │ ├── graphviz-ead1119f5dbe0a448886914d18fd0cadedecdab1.png │ │ ├── graphviz-ead1119f5dbe0a448886914d18fd0cadedecdab1.png.map │ │ ├── graphviz-f85f742f79de3c705c79ddaf4b344515c9beb90a.png │ │ └── graphviz-f85f742f79de3c705c79ddaf4b344515c9beb90a.png.map │ ├── _sources │ │ ├── auxiliary.rst.txt │ │ ├── cmake_integration.rst.txt │ │ ├── communicator.rst.txt │ │ ├── constants.rst.txt │ │ ├── data_types.rst.txt │ │ ├── design.rst.txt │ │ ├── environmental_management.rst.txt │ │ ├── error.rst.txt │ │ ├── examples │ │ │ ├── arrays.rst.txt │ │ │ ├── blocking.rst.txt │ │ │ ├── blocking_vector.rst.txt │ │ │ ├── collective.rst.txt │ │ │ ├── communicator.rst.txt │ │ │ ├── custom_initialization.rst.txt │ │ │ ├── distributed_grid.rst.txt │ │ │ ├── distributed_grid_scatter_gather.rst.txt │ │ │ ├── file.rst.txt │ │ │ ├── gather.rst.txt │ │ │ ├── gatherv.rst.txt │ │ │ ├── heat_equation_Jacobi_method.rst.txt │ │ │ ├── heat_equation_successive_over-relaxation.rst.txt │ │ │ ├── hello_world.rst.txt │ │ │ ├── index.rst.txt │ │ │ ├── iterators.rst.txt │ │ │ ├── layouts.rst.txt │ │ │ ├── matrix_gather.rst.txt │ │ │ ├── nonblocking.rst.txt │ │ │ ├── nonblocking_mult.rst.txt │ │ │ ├── parallel_sort.rst.txt │ │ │ ├── probe.rst.txt │ │ │ ├── process_creation.rst.txt │ │ │ ├── reduce.rst.txt │ │ │ ├── standard_types.rst.txt │ │ │ ├── stl_container.rst.txt │ │ │ ├── struct.rst.txt │ │ │ ├── subarray.rst.txt │ │ │ └── vibrating_string.rst.txt │ │ ├── file.rst.txt │ │ ├── grid.rst.txt │ │ ├── group.rst.txt │ │ ├── index.rst.txt │ │ ├── info.rst.txt │ │ ├── installation.rst.txt │ │ ├── interoperability.rst.txt │ │ ├── layouts.rst.txt │ │ ├── reduction_operations.rst.txt │ │ └── tags.rst.txt │ ├── _sphinx_design_static │ │ ├── design-tabs.js │ │ └── sphinx-design.min.css │ ├── _static │ │ ├── basic.css │ │ ├── check-solid.svg │ │ ├── clipboard.min.js │ │ ├── copy-button.svg │ │ ├── copybutton.css │ │ ├── copybutton.js │ │ ├── copybutton_funcs.js │ │ ├── custom.css │ │ ├── debug.css │ │ ├── design-tabs.js │ │ ├── doctools.js │ │ ├── documentation_options.js │ │ ├── file.png │ │ ├── graphviz.css │ │ ├── language_data.js │ │ ├── minus.png │ │ ├── plus.png │ │ ├── pygments.css │ │ ├── scripts │ │ │ ├── furo-extensions.js │ │ │ ├── furo.js │ │ │ ├── furo.js.LICENSE.txt │ │ │ └── furo.js.map │ │ ├── searchtools.js │ │ ├── skeleton.css │ │ ├── sphinx-design.min.css │ │ ├── sphinx_highlight.js │ │ └── styles │ │ │ ├── furo-extensions.css │ │ │ ├── furo-extensions.css.map │ │ │ ├── furo.css │ │ │ └── furo.css.map │ ├── auxiliary.html │ ├── cmake_integration.html │ ├── communicator.html │ ├── constants.html │ ├── data_types.html │ ├── design.html │ ├── environmental_management.html │ ├── error.html │ ├── examples │ │ ├── arrays.html │ │ ├── blocking.html │ │ ├── blocking_vector.html │ │ ├── collective.html │ │ ├── communicator.html │ │ ├── custom_initialization.html │ │ ├── distributed_grid.html │ │ ├── distributed_grid_scatter_gather.html │ │ ├── file.html │ │ ├── gather.html │ │ ├── gatherv.html │ │ ├── heat_equation_Jacobi_method.html │ │ ├── heat_equation_successive_over-relaxation.html │ │ ├── hello_world.html │ │ ├── index.html │ │ ├── iterators.html │ │ ├── layouts.html │ │ ├── matrix_gather.html │ │ ├── nonblocking.html │ │ ├── nonblocking_mult.html │ │ ├── parallel_sort.html │ │ ├── probe.html │ │ ├── process_creation.html │ │ ├── reduce.html │ │ ├── standard_types.html │ │ ├── stl_container.html │ │ ├── struct.html │ │ ├── subarray.html │ │ └── vibrating_string.html │ ├── file.html │ ├── genindex.html │ ├── grid.html │ ├── group.html │ ├── index.html │ ├── info.html │ ├── installation.html │ ├── interoperability.html │ ├── layouts.html │ ├── objects.inv │ ├── reduction_operations.html │ ├── search.html │ ├── searchindex.js │ └── tags.html └── mpl_parallel_2018.pdf ├── examples ├── CMakeLists.txt ├── arrays.cc ├── blocking.cc ├── blocking_vector.cc ├── collective.cc ├── communicator.cc ├── custom_initialization.cc ├── distributed_grid.cc ├── distributed_grid_scatter_gather.cc ├── file.cc ├── gather.cc ├── gatherv.cc ├── heat_equation_Jacobi_method.cc ├── heat_equation_successive_over-relaxation.cc ├── hello_world.cc ├── intercommunicator.cc ├── iterators.cc ├── layouts.cc ├── matrix_gather.cc ├── nonblocking.cc ├── nonblocking_mult.cc ├── parallel_sort_mpi.c ├── parallel_sort_mpl.cc ├── probe.cc ├── process_creation.cc ├── process_creation_client.cc ├── process_creation_multiple.cc ├── reduce_lcm.cc ├── reduce_min_loc.cc ├── standard_types.cc ├── stl_container.cc ├── struct.cc ├── subarray.cc ├── vibrating_string_mpi.c └── vibrating_string_mpl.cc ├── mpl ├── cartesian_communicator.hpp ├── comm_group.hpp ├── command_line.hpp ├── datatype.hpp ├── displacements.hpp ├── distributed_graph_communicator.hpp ├── distributed_grid.hpp ├── environment.hpp ├── error.hpp ├── file.hpp ├── flat_memory.hpp ├── graph_communicator.hpp ├── info.hpp ├── layout.hpp ├── message.hpp ├── mpl.hpp ├── operator.hpp ├── ranks.hpp ├── request.hpp ├── status.hpp ├── tag.hpp ├── topology_communicator.hpp ├── utility.hpp └── vector.hpp └── test ├── CMakeLists.txt ├── test_cartesian_communicator.cc ├── test_communicator.cc ├── test_communicator_allgather.cc ├── test_communicator_allgatherv.cc ├── test_communicator_allreduce.cc ├── test_communicator_alltoall.cc ├── test_communicator_alltoallv.cc ├── test_communicator_barrier.cc ├── test_communicator_bcast.cc ├── test_communicator_exscan.cc ├── test_communicator_gather.cc ├── test_communicator_gatherv.cc ├── test_communicator_init_send_init_recv.cc ├── test_communicator_isend_irecv.cc ├── test_communicator_mprobe_mrecv.cc ├── test_communicator_probe.cc ├── test_communicator_reduce.cc ├── test_communicator_reduce_scatter.cc ├── test_communicator_reduce_scatter_block.cc ├── test_communicator_scan.cc ├── test_communicator_scatter.cc ├── test_communicator_scatterv.cc ├── test_communicator_send_recv.cc ├── test_communicator_sendrecv.cc ├── test_displacements.cc ├── test_dist_graph_communicator.cc ├── test_file.cc ├── test_graph_communicator.cc ├── test_group.cc ├── test_helper.hpp ├── test_info.cc ├── test_initialization.cc ├── test_inter_communicator.cc └── test_mpi_communicator.cc /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Google 3 | AccessModifierOffset: -2 4 | AllowShortBlocksOnASingleLine: false 5 | AllowShortCaseLabelsOnASingleLine: false 6 | AllowShortFunctionsOnASingleLine: false 7 | AllowShortIfStatementsOnASingleLine: false 8 | AllowShortLoopsOnASingleLine: false 9 | ColumnLimit: 96 10 | MaxEmptyLinesToKeep: 2 11 | NamespaceIndentation: All 12 | RequiresClausePosition: OwnLine 13 | IndentRequiresClause: false 14 | SpaceAfterTemplateKeyword: false 15 | SortIncludes: false 16 | SortUsingDeclarations: false 17 | CommentPragmas: '^/' 18 | Standard: c++20 19 | ... 20 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | # Generated from CLion Inspection settings 2 | --- 3 | Checks: '-*, 4 | bugprone-*, 5 | -bugprone-easily-swappable-parameters, 6 | cppcoreguidelines-*, 7 | -cppcoreguidelines-avoid-magic-numbers 8 | -cppcoreguidelines-pro-bounds-pointer-arithmetic, 9 | -cppcoreguidelines-pro-type-reinterpret-cast, 10 | hicpp-*, 11 | -hicpp-braces-around-statements, 12 | -hicpp-modernize-use-emplace, 13 | modernize-*, 14 | -modernize-use-emplace, 15 | -modernize-use-trailing-return-type, 16 | mpi-*, 17 | misc-*, 18 | -misc-confusable-identifiers, 19 | -misc-coroutine-hostile-raii, 20 | -misc-header-include-cycle, 21 | -misc-include-cleaner, 22 | -misc-no-recursion, 23 | -misc-non-private-member-variables-in-classes, 24 | openmp-use-default-none, 25 | performance-*, 26 | -performance-enum-size, 27 | portability-*, 28 | -portability-restrict-system-includes, 29 | readability-*, 30 | -readability-function-size, 31 | -readability-identifier-length, 32 | -readability-magic-numbers, 33 | -readability-suspicious-call-argument, 34 | -readability-uppercase-literal-suffix, 35 | -readability-math-missing-parentheses, 36 | -readability-avoid-nested-conditional-operator, 37 | -readability-const-return-type, 38 | -readability-braces-around-statements, 39 | -readability-avoid-return-with-void-value, 40 | -readability-avoid-unconditional-preprocessor-if, 41 | -readability-function-cognitive-complexity, 42 | -readability-identifier-naming, 43 | -*-avoid-magic-numbers, 44 | -*-uppercase-literal-suffix, 45 | -*-pro-bounds-pointer-arithmetic, 46 | -*-misplaced-const, 47 | -*-pro-bounds-constant-array-index' 48 | -------------------------------------------------------------------------------- /.github/workflows/build-with-IntelMPI.yml: -------------------------------------------------------------------------------- 1 | name: build-with-IntelMPI 2 | run-name: Build MPL with IntelMPI 3 | on: [push, pull_request, workflow_dispatch] 4 | jobs: 5 | compile-mpl: 6 | runs-on: ubuntu-24.04 7 | steps: 8 | - name: Check out repository code 9 | uses: actions/checkout@v4 10 | - name: Install build dependencies 11 | run: | 12 | sudo apt install cmake ninja-build g++ libboost-test-dev 13 | wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null 14 | echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list 15 | sudo apt update 16 | sudo apt install intel-oneapi-mpi-devel 17 | - name: Build mpl 18 | run: | 19 | mkdir build 20 | cd build 21 | . /opt/intel/oneapi/setvars.sh 22 | cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DMPL_BUILD_EXAMPLES=ON .. 23 | cmake -G Ninja -DCMAKE_INSTALL_PREFIX="$HOME/mpl" -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DMPL_BUILD_EXAMPLES=ON .. 24 | cmake --build . -j 25 | cmake --build . --target install 26 | - name: Test mpl 27 | run: | 28 | cd build 29 | . /opt/intel/oneapi/setvars.sh 30 | ctest --output-on-failure 31 | - run: echo "This job's status is ${{ job.status }}." 32 | -------------------------------------------------------------------------------- /.github/workflows/build-with-mpich.yml: -------------------------------------------------------------------------------- 1 | name: build-with-mpich 2 | run-name: Build MPL with MPICH 3 | on: [push, pull_request, workflow_dispatch] 4 | jobs: 5 | compile-mpl: 6 | runs-on: ubuntu-22.04 7 | steps: 8 | - name: Check out repository code 9 | uses: actions/checkout@v4 10 | - name: Install build dependencies 11 | run: | 12 | sudo apt install libmpich-dev cmake ninja-build g++ libboost-test-dev 13 | mpichversion 14 | - name: Build mpl 15 | run: | 16 | mkdir build 17 | cd build 18 | cmake -G Ninja -DCMAKE_INSTALL_PREFIX="$HOME/mpl" -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DMPL_BUILD_EXAMPLES=ON .. 19 | cmake --build . -j 20 | cmake --build . --target install 21 | - name: Test mpl 22 | run: | 23 | cd build 24 | ctest --output-on-failure 25 | - run: echo "This job's status is ${{ job.status }}." 26 | -------------------------------------------------------------------------------- /.github/workflows/build-with-openmpi.yml: -------------------------------------------------------------------------------- 1 | name: build-with-openmpi 2 | run-name: Build MPL with OpenMPI 3 | on: [push, pull_request, workflow_dispatch] 4 | jobs: 5 | compile-mpl: 6 | runs-on: ubuntu-24.04 7 | steps: 8 | - name: Check out repository code 9 | uses: actions/checkout@v4 10 | - name: Install build dependencies 11 | run: | 12 | sudo apt install libopenmpi-dev cmake ninja-build g++ libboost-test-dev 13 | ompi_info 14 | - name: Build mpl 15 | run: | 16 | mkdir build 17 | cd build 18 | cmake -G Ninja -DCMAKE_INSTALL_PREFIX="$HOME/mpl" -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -DMPL_BUILD_EXAMPLES=ON .. 19 | cmake --build . -j 20 | cmake --build . --target install 21 | - name: Test mpl 22 | run: | 23 | cd build 24 | ctest --output-on-failure 25 | - run: echo "This job's status is ${{ job.status }}." 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *build*/ 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 3.21 required for PROJECT_IS_TOP_LEVEL, 3.10 required for mpi targets, 3.5 required for boost targets 2 | cmake_minimum_required(VERSION 3.21) 3 | 4 | project(mpl VERSION 0.4.0 LANGUAGES CXX C) 5 | 6 | if(NOT DEFINED CACHE{BUILD_TESTING}) 7 | set(BUILD_TESTING OFF CACHE BOOL "") 8 | endif() 9 | include(CTest) 10 | include(GNUInstallDirs) 11 | include(CMakePackageConfigHelpers) 12 | 13 | # project requires c++17 to build 14 | set(CMAKE_CXX_STANDARD 17) 15 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 16 | set(CMAKE_CXX_EXTENSIONS OFF) 17 | 18 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 19 | 20 | find_package(MPI 3.1 REQUIRED C CXX) 21 | 22 | add_library(mpl INTERFACE) 23 | target_include_directories(mpl 24 | INTERFACE 25 | $ 26 | $) 27 | 28 | # convention for allowing use as a subdirectory 29 | add_library(mpl::mpl ALIAS mpl) 30 | target_link_libraries(mpl INTERFACE MPI::MPI_CXX) 31 | 32 | option(MPL_BUILD_EXAMPLES "build the mpl examples" ${PROJECT_IS_TOP_LEVEL}) 33 | if(MPL_BUILD_EXAMPLES) 34 | add_subdirectory(examples) 35 | endif() 36 | if(BUILD_TESTING) 37 | add_subdirectory(test) 38 | endif() 39 | 40 | option(MPL_INSTALL "Generate and install MPL target" ${PROJECT_IS_TOP_LEVEL}) 41 | if(MPL_INSTALL) 42 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/mplConfig.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/mpl) 43 | 44 | install(DIRECTORY mpl DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 45 | 46 | install(TARGETS mpl EXPORT mplTargets) 47 | export(EXPORT mplTargets 48 | NAMESPACE mpl:: 49 | FILE mplTargets.cmake) 50 | install(EXPORT mplTargets 51 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/mpl 52 | NAMESPACE mpl:: 53 | FILE mplTargets.cmake) 54 | endif() 55 | 56 | option(MPL_BUILD_DOCUMENTATION "build the mpl documentation using Doxygen and Sphinx" OFF) 57 | add_subdirectory(doc) 58 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2015, Heiko Bauke 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 | OF THE POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /cmake/mplConfig.cmake: -------------------------------------------------------------------------------- 1 | include(CMakeFindDependencyMacro) 2 | 3 | find_dependency(Threads) 4 | find_dependency(MPI) 5 | 6 | 7 | include(${CMAKE_CURRENT_LIST_DIR}/mplTargets.cmake) 8 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(doxygen_source_dir ${CMAKE_CURRENT_SOURCE_DIR}/doxygen) 2 | set(doxygen_binary_dir ${CMAKE_CURRENT_BINARY_DIR}/doxygen) 3 | 4 | set(sphinx_source_dir ${CMAKE_CURRENT_SOURCE_DIR}/sphinx) 5 | set(sphinx_binary_dir ${CMAKE_CURRENT_BINARY_DIR}/sphinx) 6 | 7 | configure_file(${doxygen_source_dir}/Doxyfile.in ${doxygen_binary_dir}/Doxyfile @ONLY) 8 | configure_file(${sphinx_source_dir}/conf.py.in ${sphinx_binary_dir}/conf.py @ONLY) 9 | 10 | set(documentation_sources 11 | sphinx/auxiliary.rst 12 | sphinx/cmake_integration.rst 13 | sphinx/communicator.rst 14 | sphinx/conf.py.in 15 | sphinx/constants.rst 16 | sphinx/data_types.rst 17 | sphinx/design.rst 18 | sphinx/environmental_management.rst 19 | sphinx/error.rst 20 | sphinx/examples/arrays.rst 21 | sphinx/examples/blocking.rst 22 | sphinx/examples/blocking_vector.rst 23 | sphinx/examples/collective.rst 24 | sphinx/examples/communicator.rst 25 | sphinx/examples/distributed_grid.rst 26 | sphinx/examples/distributed_grid_scatter_gather.rst 27 | sphinx/examples/gather.rst 28 | sphinx/examples/gatherv.rst 29 | sphinx/examples/heat_equation_Jacobi_method.rst 30 | sphinx/examples/heat_equation_successive_over-relaxation.rst 31 | sphinx/examples/hello_world.rst 32 | sphinx/examples/index.rst 33 | sphinx/examples/iterators.rst 34 | sphinx/examples/layouts.rst 35 | sphinx/examples/matrix_gather.rst 36 | sphinx/examples/nonblocking_mult.rst 37 | sphinx/examples/nonblocking.rst 38 | sphinx/examples/parallel_sort.rst 39 | sphinx/examples/probe.rst 40 | sphinx/examples/reduce.rst 41 | sphinx/examples/standard_types.rst 42 | sphinx/examples/stl_container.rst 43 | sphinx/examples/struct.rst 44 | sphinx/examples/subarray.rst 45 | sphinx/examples/vibrating_string.rst 46 | sphinx/grid.rst 47 | sphinx/group.rst 48 | sphinx/index.rst 49 | sphinx/info.rst 50 | sphinx/installation.rst 51 | sphinx/interoperability.rst 52 | sphinx/layouts.rst 53 | sphinx/reduction_operations.rst 54 | sphinx/tags.rst 55 | sphinx/_static/custom.css) 56 | 57 | add_custom_command(OUTPUT ${doxygen_binary_dir}/xml/index.xml 58 | COMMAND doxygen Doxyfile 59 | WORKING_DIRECTORY ${doxygen_binary_dir} 60 | COMMENT "Generating API documentation with Doxygen" 61 | VERBATIM) 62 | 63 | add_custom_command(OUTPUT ${sphinx_binary_dir}/html/index.html 64 | DEPENDS 65 | ${doxygen_binary_dir}/xml/index.xml 66 | ${documentation_sources} 67 | COMMAND sphinx-build -b html -j auto -c ${sphinx_binary_dir} ${sphinx_source_dir} ${sphinx_binary_dir}/html 68 | WORKING_DIRECTORY ${sphinx_binary_dir} 69 | COMMENT "Generating API documentation with Sphinx & Breathe" 70 | VERBATIM) 71 | 72 | if(MPL_BUILD_DOCUMENTATION) 73 | add_custom_target(documentation ALL DEPENDS ${sphinx_binary_dir}/html/index.html) 74 | else() 75 | add_custom_target(documentation DEPENDS ${sphinx_binary_dir}/html/index.html) 76 | endif() 77 | 78 | # Documentation installation (Sphinx output only). 79 | include(GNUInstallDirs) 80 | install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/sphinx/html/ DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT documentation PATTERN ".*" EXCLUDE) 81 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/sphinx/html) 82 | 83 | set(documentation_output_dirs ${doxygen_binary_dir}/html ${doxygen_binary_dir}/xml ${sphinx_binary_dir}/html) 84 | 85 | # Remove documentation via global clean target. 86 | set_property(TARGET documentation APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${documentation_output_dirs}) 87 | # Custom target to remove documentation only. 88 | add_custom_target(documentation_clean COMMAND ${CMAKE_COMMAND} -E rm -rf ${documentation_output_dirs}) 89 | -------------------------------------------------------------------------------- /doc/doxygen/data_types.md: -------------------------------------------------------------------------------- 1 | # Data types 2 | \anchor data_types 3 | 4 | With MPL processes can send and receive messages containing data of 5 | different data types. MPL requires some knowledge about the internal 6 | representation of this data. MPL supports 7 | 8 | * all standard integer types, signed as well as unsigned, such as `int`, 9 | `unsigned int` etc., 10 | 11 | * the character types `char`, `signed char`, `unsigned char` as well as 12 | the wide character types `wchar_t`, `char8_t` (if compiler supports 13 | C++-20 features), `char16_t` and `char32_t`, 14 | 15 | * the floating point types `float`, `double` and `long double`, 16 | 17 | * the complex types `std::complex`, `std::complex` and 18 | `std::complex`, 19 | 20 | * the Boolean type `bool`, 21 | 22 | * the type `std::byte` and 23 | 24 | * enumeration types. 25 | 26 | MPL would not be very limited if it would only support these elementary 27 | data types. However, MPL comes also with some support for user-defined 28 | data types. To be able to exchange data of custom types via a message 29 | passing library. The message passing library must have some knowledge 30 | about the internal representation of user-defined data types. Because 31 | C++ has very limited type introspection capabilities, this knowledge 32 | cannot be obtained automatically by the message passing library. Usually 33 | information about the internal structure of user-defined types 34 | (structures and classes) has to be exposed explicitly to the message 35 | passing library. Therefore, MPL supports message exchange of data where 36 | information about the internal representation can be obtained 37 | automatically and introduces a mechanism to expose the internal 38 | representation of custom types to MPL if this is not possible. 39 | 40 | The data types, where MPL can infer their internal representation, C 41 | arrays of constant size and the template classes 42 | `std::array`, `std::pair` and `std::tuple` of the C++ Standard Template 43 | Library. The only limitation is, that the C arrays as well as the 44 | mentioned STL template classes hold data elements of types that can be 45 | sent or received by MPL, e.g., the elementary types mentioned above. 46 | This rule can be applied recursively, which allows one to build quite 47 | complex data structures. This means, for example, one can send and 48 | receive data of type std::pair, because `int` and 49 | `double` can be sent or received. But also 50 | `std::array, 8>`, which represents 8 pairs of 51 | `int` and `double`, can be used in a message. 52 | 53 | User-defined data structures usually come as structures or classes. 54 | Provided that these classes hold only non-static non-const data members 55 | of types, which MPL is able to send or receive, it is possible to expose 56 | these data members to MPL via template specialization of the class 57 | `struct_builder` such that messages containing objects of these classes 58 | can be exchanged. Template specialization of the class struct_builder is 59 | illustrated in the example program [`example_struct.cc`](struct_8cc-example.html). 60 | The specialized template has to derived from `base_struct_builder` and 61 | the internal data representation of the user-defined class is exposed 62 | to MPL in the constructor. 63 | -------------------------------------------------------------------------------- /doc/sphinx/_static/custom.css: -------------------------------------------------------------------------------- 1 | dl.function { 2 | margin-bottom: 1.25em; 3 | } 4 | 5 | p.breathe-sectiondef-title.rubric { 6 | font-size: x-large; 7 | font-weight: bolder; 8 | line-height: inherit; 9 | text-transform: none; 10 | } 11 | 12 | dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list > dt { 13 | font-size: var(--font-size--normal); 14 | font-weight: bolder; 15 | text-transform: none 16 | } 17 | -------------------------------------------------------------------------------- /doc/sphinx/auxiliary.rst: -------------------------------------------------------------------------------- 1 | Auxiliary functions and classes 2 | =============================== 3 | 4 | Integer types 5 | ------------- 6 | 7 | .. doxygentypedef:: mpl::size_t 8 | .. doxygentypedef:: mpl::ssize_t 9 | 10 | 11 | Ranks 12 | ----- 13 | 14 | .. doxygenclass:: mpl::ranks 15 | 16 | 17 | Types for probing messages 18 | -------------------------- 19 | 20 | The following types are used in the context of probing messages. See section :doc:`examples/probe` for an example. 21 | 22 | .. doxygentypedef:: mpl::message_t 23 | .. doxygenclass:: mpl::status_t 24 | .. doxygenstruct:: mpl::mprobe_status 25 | 26 | 27 | Memory displacements 28 | -------------------- 29 | 30 | The ``mpl::displacements`` class is used in the context of various collective communication operations that send and/or receive an amount of data that varies over the set of participating processes. 31 | 32 | .. doxygenclass:: mpl::displacements 33 | 34 | 35 | Requests 36 | -------- 37 | 38 | Test status enum 39 | ^^^^^^^^^^^^^^^^ 40 | 41 | .. doxygenenum:: mpl::test_result 42 | 43 | 44 | Non-blocking communication requests 45 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 46 | 47 | .. doxygenclass:: mpl::irequest 48 | .. doxygenclass:: mpl::irequest_pool 49 | 50 | 51 | Persistent communication requests 52 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 53 | 54 | .. doxygenclass:: mpl::prequest 55 | .. doxygenclass:: mpl::prequest_pool 56 | 57 | 58 | Command-line arguments 59 | ---------------------- 60 | 61 | .. doxygenclass:: mpl::command_line 62 | 63 | .. doxygenclass:: mpl::command_lines 64 | -------------------------------------------------------------------------------- /doc/sphinx/cmake_integration.rst: -------------------------------------------------------------------------------- 1 | CMake integration 2 | ================= 3 | 4 | MPL provides supporting files for CMake integration. These are also installed during the installation step. CMake integration is realized via the ``mpl`` CMake package, which provides the library target ``mpl::mpl``. The following example ``CMakeLists.txt`` file illustrates the usage of the ``mpl`` CMake package for creating an MPL application. First, the ``mpl`` package is loaded via the ``find_package`` function. Then, all targets with MPL dependency must be linked against ``mpl::mpl``. In this way, CMake adds all necessary compiler flags and linker flags that are required for building an MPL application. 5 | 6 | .. code-block:: CMake 7 | 8 | # MPI CMake module available since version 3.10 9 | cmake_minimum_required(VERSION 3.10) 10 | 11 | project(hello_mpl) 12 | 13 | # project requires c++17 to build 14 | set(CMAKE_CXX_STANDARD 17) 15 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 16 | set(CMAKE_CXX_EXTENSIONS OFF) 17 | 18 | # find the MPL library and its dependencies, e.g., an MPI library 19 | find_package(mpl REQUIRED) 20 | 21 | # create executable and link against mpl and its dependencies 22 | add_executable(hello_world hello_world.cc) 23 | target_link_libraries(hello_world PRIVATE mpl::mpl) 24 | 25 | When using ``find_package``, CMake searches in a set of platform-dependent standard directories for the requested CMake package. CMake may fail to find the MPL CMake package when MPL was installed in a custom directory. If MPL was installed in a custom directory, add the installation directory (given via ``CMAKE_INSTALL_PREFIX`` during MPL configuration see :ref:`Installation`) to the ``CMAKE_PREFIX_PATH`` variable during the configuration of the MPL application, e.g.: 26 | 27 | .. code:: shell 28 | 29 | user@host:~/hello_mpl/build$ cmake -DCMAKE_PREFIX_PATH:PATH=/path/to/mpl .. 30 | -------------------------------------------------------------------------------- /doc/sphinx/communicator.rst: -------------------------------------------------------------------------------- 1 | Communicators 2 | ============= 3 | 4 | A communicator consists of a group of processed and defines a communication context that partitions the communication space. A message sent in one context cannot be received in another context. Furthermore, where permitted, collective operations are independent of pending point-to-point operations. 5 | 6 | MPL defines several kinds of communicators: 7 | 8 | - standard communicators, 9 | 10 | - communicators with a process topology (Cartesian communicators, graph communicators, distributed graph communicators) and 11 | 12 | - inter-communicators. 13 | 14 | An inter-communicator identifies two distinct groups of processes linked with a communication context. 15 | 16 | 17 | Standard communicators 18 | ---------------------- 19 | 20 | .. doxygenclass:: mpl::communicator 21 | 22 | 23 | Standard communicators for MPI interoperability 24 | ----------------------------------------------- 25 | 26 | .. doxygenclass:: mpl::mpi_communicator 27 | 28 | 29 | Cartesian communicators 30 | ----------------------- 31 | 32 | .. doxygenclass:: mpl::cartesian_communicator 33 | 34 | 35 | Auxiliary functions and classes for cartesian communicators 36 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 37 | 38 | For constructing communicators with a cartesian process topology the following utility function can be used. 39 | 40 | .. doxygenfunction:: mpl::dims_create 41 | 42 | .. doxygenstruct:: mpl::shift_ranks 43 | 44 | 45 | Graph communicators 46 | ------------------- 47 | 48 | .. doxygenclass:: mpl::graph_communicator 49 | 50 | 51 | Distributed graph communicators 52 | ------------------------------- 53 | 54 | .. doxygenclass:: mpl::distributed_graph_communicator 55 | 56 | 57 | Inter-communicators 58 | ------------------- 59 | 60 | .. doxygenclass:: mpl::inter_communicator 61 | 62 | 63 | Inter-communicators for MPI interoperability 64 | ----------------------------------------------- 65 | 66 | .. doxygenclass:: mpl::mpi_inter_communicator 67 | -------------------------------------------------------------------------------- /doc/sphinx/constants.rst: -------------------------------------------------------------------------------- 1 | Constants 2 | ========= 3 | 4 | MPL defines the following global constants: 5 | 6 | .. doxygenvariable:: mpl::proc_null 7 | 8 | .. doxygenvariable:: mpl::undefined 9 | 10 | .. doxygenvariable:: mpl::root 11 | 12 | .. doxygenvariable:: mpl::absolute 13 | 14 | .. doxygenvariable:: mpl::bsend_overhead 15 | -------------------------------------------------------------------------------- /doc/sphinx/design.rst: -------------------------------------------------------------------------------- 1 | .. _Design: 2 | 3 | Library design principles 4 | ========================= 5 | 6 | MPL is designed on the basis of the following design principles: 7 | 8 | Resource management 9 | ------------------- 10 | 11 | In a typical MPI program, a number of resources, e.g., communicators, 12 | custom data types etc., must be management. Allocation and deallocation 13 | of such resources must be done manually by explicitly calling the 14 | respective allocation and deallocation function. This is error-prone, 15 | may lead to resource leaks and requires a lot of boilerplate code. 16 | 17 | Therefore, MPL applies the principle of "resource acquisition is 18 | initialization" (RAII) and wraps all resources in custom class types. 19 | Resources are allocated in a constructor and automatically dealocated 20 | when a resource object goes out of scope by the destructor. In contrast 21 | to MPI handles, all resource classes have a value-semantics. This means, 22 | when a resource object is copies in to another one, then a new resource 23 | is created and the two resource objects manage different independent 24 | resources. 25 | 26 | 27 | Custom data types 28 | ----------------- 29 | 30 | Custom data types are one of the most versatile features of MPI. With 31 | custom data types, it is possible to write very well-structured 32 | code by hiding details of the complex communication pattern in 33 | well-designed custom data types. Therefore, MPL makes it easy to 34 | create and use custom data types. These are called layouts in MPL. 35 | 36 | The size argument of MPI communication functions is usually redundant. 37 | The information that it provides can be incorporated into the 38 | data type argument with a custom data type. Therefore, MPL communication 39 | functions do not require a size argument. All information about the 40 | amount and memory layout of exchanged data is provided by data layout 41 | arguments. 42 | 43 | 44 | Avoid programming errors by strong typing 45 | ----------------------------------------- 46 | 47 | It is a common error in MPI programs to pass logically inconsistent 48 | arguments to an MPI function. For example, one might pass a pointer 49 | to ``double`` as a buffer argument and pass ``MPI_FLOAT`` as the 50 | data type argument. The classic MPI api does not protect one from such 51 | kind of errors, i.e., no compiler error is caused. 52 | 53 | MPL leverages the strong type system of C++ to detect such kinds of 54 | programming mistakes at compile time, i.e., to make such programming 55 | errors impossible. For example, buffer arguments expect pointers of a 56 | specific type, rather than untyped pointers to ``void``, and MPL 57 | infers internally the right MPI data type on the basis of the pointer 58 | type. 59 | -------------------------------------------------------------------------------- /doc/sphinx/environmental_management.rst: -------------------------------------------------------------------------------- 1 | Environmental management 2 | ======================== 3 | 4 | MPL provides various functions for querying characteristics of the computational environment. 5 | 6 | 7 | Current processor name 8 | ---------------------- 9 | 10 | .. doxygenfunction:: mpl::environment::processor_name 11 | 12 | 13 | Predefined communicators 14 | ------------------------ 15 | 16 | .. doxygenfunction:: mpl::environment::comm_world 17 | .. doxygenfunction:: mpl::environment::comm_self 18 | 19 | 20 | Threading support 21 | ----------------- 22 | 23 | .. doxygenfunction:: mpl::environment::is_thread_main 24 | .. doxygenfunction:: mpl::environment::threading_mode 25 | .. doxygenenum:: mpl::threading_modes 26 | 27 | 28 | Time 29 | ---- 30 | 31 | .. doxygenfunction:: mpl::environment::wtime_is_global 32 | .. doxygenfunction:: mpl::environment::wtime 33 | .. doxygenfunction:: mpl::environment::wtick 34 | 35 | 36 | Management of buffers for buffered send operations 37 | -------------------------------------------------- 38 | 39 | .. doxygenfunction:: mpl::environment::buffer_attach 40 | .. doxygenfunction:: mpl::environment::buffer_detach 41 | .. doxygenclass:: mpl::bsend_buffer 42 | -------------------------------------------------------------------------------- /doc/sphinx/error.rst: -------------------------------------------------------------------------------- 1 | Error handling 2 | ============== 3 | 4 | MPL performs some consistency checks when the macro ``MPL_DEBUG`` has been defined. In case of an error, an exception may be thrown with an object having one of the following types. 5 | 6 | .. doxygenclass:: mpl::error 7 | .. doxygenclass:: mpl::invalid_rank 8 | .. doxygenclass:: mpl::invalid_tag 9 | .. doxygenclass:: mpl::invalid_size 10 | .. doxygenclass:: mpl::invalid_count 11 | .. doxygenclass:: mpl::invalid_layout 12 | .. doxygenclass:: mpl::invalid_dim 13 | .. doxygenclass:: mpl::invalid_datatype_bound 14 | .. doxygenclass:: mpl::invalid_argument 15 | -------------------------------------------------------------------------------- /doc/sphinx/examples/arrays.rst: -------------------------------------------------------------------------------- 1 | Arrays 2 | ====== 3 | 4 | Sends and receives arrays (C arrays and ``std::array``) of fixed size, which must be known at compile time. The types of the array elements must be suited for communication. These rules may be applied recursively. 5 | 6 | .. literalinclude:: ../../../examples/arrays.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/blocking.rst: -------------------------------------------------------------------------------- 1 | Blocking send and receive 2 | ========================= 3 | 4 | Demonstrates various blocking send and receive modes of standard data types. 5 | 6 | .. literalinclude:: ../../../examples/blocking.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/blocking_vector.rst: -------------------------------------------------------------------------------- 1 | Blocking send and receive of vectors 2 | ==================================== 3 | 4 | Demonstrates blocking send and receive of a vector of standard data types. 5 | 6 | .. literalinclude:: ../../../examples/blocking_vector.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/collective.rst: -------------------------------------------------------------------------------- 1 | Collective communication 2 | ======================== 3 | 4 | Demonstrates various modes of collective communication. 5 | 6 | .. literalinclude:: ../../../examples/collective.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/communicator.rst: -------------------------------------------------------------------------------- 1 | Communicator management 2 | ======================= 3 | 4 | Demonstrates some basic communicator management. 5 | 6 | .. literalinclude:: ../../../examples/communicator.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/custom_initialization.rst: -------------------------------------------------------------------------------- 1 | Custom initialization of the MPI environment 2 | ============================================ 3 | 4 | MPL initializes the MPI environment automatically internally. This example program shows how to write a custom MPI initializer when more control over the initialization of the MPI environment is needed. This can be useful, when combining MPL with other MPI-based libraries. 5 | 6 | .. literalinclude:: ../../../examples/custom_initialization.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/distributed_grid.rst: -------------------------------------------------------------------------------- 1 | Distributed grid 2 | ================ 3 | 4 | Data type ``mpl::distributed_grid`` in action. 5 | 6 | .. literalinclude:: ../../../examples/distributed_grid.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/distributed_grid_scatter_gather.rst: -------------------------------------------------------------------------------- 1 | Distributed grid collective operations 2 | ====================================== 3 | 4 | Scatter and gather operations with data type ``mpl::distributed_grid``. 5 | 6 | .. literalinclude:: ../../../examples/distributed_grid_scatter_gather.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/file.rst: -------------------------------------------------------------------------------- 1 | File i/o 2 | ======== 3 | 4 | Simple program performing basic file-based i/o operations. 5 | 6 | .. literalinclude:: ../../../examples/file.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/gather.rst: -------------------------------------------------------------------------------- 1 | Gather operations 2 | ================= 3 | 4 | Gathers data to a single process. 5 | 6 | .. literalinclude:: ../../../examples/gather.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/gatherv.rst: -------------------------------------------------------------------------------- 1 | Variable gather operations 2 | ========================== 3 | 4 | Gathers data if varying size to a single process. 5 | 6 | .. literalinclude:: ../../../examples/gather.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/heat_equation_Jacobi_method.rst: -------------------------------------------------------------------------------- 1 | Heat equation Jacobi solver 2 | =========================== 3 | 4 | Solves the two-dimensional time-independent heat equation with fixed temperatures at the border via Jacobi iterations. Implementation uses ``mpl::distributed_grid``. 5 | 6 | .. literalinclude:: ../../../examples/heat_equation_Jacobi_method.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/heat_equation_successive_over-relaxation.rst: -------------------------------------------------------------------------------- 1 | Heat equation successive over-relaxation 2 | ======================================== 3 | 4 | Solves the two-dimensional time-independent heat equation with fixed temperatures at the border via successive over-relaxation. Implementation uses ``mpl::distributed_grid``. 5 | 6 | .. literalinclude:: ../../../examples/heat_equation_successive_over-relaxation.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/hello_world.rst: -------------------------------------------------------------------------------- 1 | Hello world 2 | =========== 3 | 4 | Simple hello-world program. Initializes the message passing environment and determines the number of processes and rank. 5 | 6 | .. literalinclude:: ../../../examples/hello_world.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/index.rst: -------------------------------------------------------------------------------- 1 | Examples 2 | ======== 3 | 4 | .. toctree:: 5 | 6 | hello_world 7 | standard_types 8 | struct 9 | arrays 10 | stl_container 11 | iterators 12 | blocking 13 | blocking_vector 14 | nonblocking 15 | nonblocking_mult 16 | probe 17 | communicator 18 | collective 19 | gather 20 | gatherv 21 | matrix_gather 22 | reduce 23 | layouts 24 | subarray 25 | custom_initialization 26 | parallel_sort 27 | vibrating_string 28 | distributed_grid 29 | distributed_grid_scatter_gather 30 | heat_equation_Jacobi_method 31 | heat_equation_successive_over-relaxation 32 | process_creation 33 | file 34 | -------------------------------------------------------------------------------- /doc/sphinx/examples/iterators.rst: -------------------------------------------------------------------------------- 1 | Iterators 2 | ========= 3 | 4 | Sends and receives containers (``std::vector``, ``std::list``, etc.) given by their iterators. The types of the array elements must be suited for communication. On the receiving side, there must be sufficient preallocated memory, i.e., sending and receiving containers must be of the same size. Furthermore, tracking the address of a dereferenced iterator must result a non-const pointer on the receiving side. 5 | 6 | .. literalinclude:: ../../../examples/iterators.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/layouts.rst: -------------------------------------------------------------------------------- 1 | Layouts 2 | ======= 3 | 4 | Construction and usage of various data layouts. 5 | 6 | .. literalinclude:: ../../../examples/layouts.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/matrix_gather.rst: -------------------------------------------------------------------------------- 1 | Matrix gather 2 | ============= 3 | 4 | Demonstrates gathering of a distributed matrix as it may used in domain partitioning applications. 5 | 6 | .. literalinclude:: ../../../examples/matrix_gather.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/nonblocking.rst: -------------------------------------------------------------------------------- 1 | Non-blocking send and receive 2 | ============================= 3 | 4 | Demonstrates non-blocking send and receive of standard data types and vectors of standard data types and different waiting methods. 5 | 6 | .. literalinclude:: ../../../examples/nonblocking.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/nonblocking_mult.rst: -------------------------------------------------------------------------------- 1 | Gather via non-blocking send and receive 2 | ======================================== 3 | 4 | Utilizes non-blocking send and receive of standard data types to implement a gather operation. 5 | 6 | .. literalinclude:: ../../../examples/nonblocking_mult.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/parallel_sort.rst: -------------------------------------------------------------------------------- 1 | Parallel sorting 2 | ================ 3 | 4 | Parallel sort algorithm, MPI version. 5 | 6 | .. literalinclude:: ../../../examples/parallel_sort_mpi.c 7 | :language: c 8 | 9 | 10 | Parallel sort algorithm, MPL version. 11 | 12 | .. literalinclude:: ../../../examples/parallel_sort_mpl.cc 13 | :language: c++ 14 | -------------------------------------------------------------------------------- /doc/sphinx/examples/probe.rst: -------------------------------------------------------------------------------- 1 | Probing messages 2 | ================ 3 | 4 | Demonstrates how to probe data and to receive a message of unknown size. 5 | 6 | .. literalinclude:: ../../../examples/probe.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/process_creation.rst: -------------------------------------------------------------------------------- 1 | Process creation 2 | ================ 3 | 4 | The following two programs illustrate dynamic creation of new processes and establishing a communication channel in the form of inter-communicator. 5 | 6 | .. literalinclude:: ../../../examples/process_creation.cc 7 | :language: c++ 8 | 9 | .. literalinclude:: ../../../examples/process_creation_multiple.cc 10 | :language: c++ 11 | 12 | 13 | The corresponding source of the spawned process is given as shown below: 14 | 15 | .. literalinclude:: ../../../examples/process_creation_client.cc 16 | :language: c++ 17 | -------------------------------------------------------------------------------- /doc/sphinx/examples/reduce.rst: -------------------------------------------------------------------------------- 1 | Reduction operations 2 | ===================== 3 | 4 | Demonstrates use of custom reduction functions. 5 | 6 | .. literalinclude:: ../../../examples/reduce_lcm.cc 7 | :language: c++ 8 | 9 | 10 | Demonstrates use of reduction functions for std::pair to determine a minimum as its location. 11 | 12 | .. literalinclude:: ../../../examples/reduce_min_loc.cc 13 | :language: c++ 14 | -------------------------------------------------------------------------------- /doc/sphinx/examples/standard_types.rst: -------------------------------------------------------------------------------- 1 | Standard types 2 | ============== 3 | 4 | Sends and receives data of various standard types. 5 | 6 | .. literalinclude:: ../../../examples/standard_types.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/stl_container.rst: -------------------------------------------------------------------------------- 1 | STL containers 2 | ============== 3 | 4 | Sends and receives STL containers. 5 | 6 | .. literalinclude:: ../../../examples/stl_container.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/struct.rst: -------------------------------------------------------------------------------- 1 | Using structs 2 | ============= 3 | 4 | Demonstrates how to use ``class mpl::struct_builder`` to enable communication using structures and classes. Class members must be of fixed size (no dynamic memory allocation). All types of the class members must be suited for communication. These rules may be applied recursively. 5 | 6 | .. literalinclude:: ../../../examples/struct.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/subarray.rst: -------------------------------------------------------------------------------- 1 | Subarray layouts 2 | ================ 3 | 4 | Construction and usage of subarray layouts. 5 | 6 | .. literalinclude:: ../../../examples/subarray.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /doc/sphinx/examples/vibrating_string.rst: -------------------------------------------------------------------------------- 1 | Vibrating string 2 | ================ 3 | 4 | Solves the one-dimensional wave equation via finite differences, MPI version. 5 | 6 | .. literalinclude:: ../../../examples/vibrating_string_mpi.c 7 | :language: c 8 | 9 | 10 | Solves the one-dimensional wave equation via finite differences, MPL version. 11 | 12 | .. literalinclude:: ../../../examples/vibrating_string_mpl.cc 13 | :language: c++ 14 | -------------------------------------------------------------------------------- /doc/sphinx/file.rst: -------------------------------------------------------------------------------- 1 | File 2 | ==== 3 | 4 | Overview 5 | -------- 6 | 7 | Parallel file operations are implemented via the ``mpl::file`` class. It offers various read and write modalities (collective and non-collective, blocking and non-blocking etc.) by closely following the MPI standard. See the `MPI standard `_ for a detailed description of the semantics of the various i/o operations. 8 | 9 | 10 | Class documentation 11 | ------------------- 12 | 13 | File class 14 | ^^^^^^^^^^ 15 | 16 | .. doxygenclass:: mpl::file 17 | 18 | 19 | File access mode operations 20 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 21 | 22 | .. doxygenfunction:: mpl::operator|(file::access_mode, file::access_mode) 23 | .. doxygenfunction:: mpl::operator|=(file::access_mode &, file::access_mode) 24 | .. doxygenfunction:: mpl::operator&(file::access_mode, file::access_mode) 25 | .. doxygenfunction:: mpl::operator&=(file::access_mode &, file::access_mode) 26 | 27 | 28 | Error handling 29 | ^^^^^^^^^^^^^^ 30 | 31 | Methods of ``mpl::file`` class may throw an exception of the type ``mpl::io_failure`` in the case of run-time i/o failures. Thus, file operations should be wrapped into a ``try`` block and possible exceptions should be caught in a matching ``catch`` clause as demonstrated in the following example: 32 | 33 | .. literalinclude:: file_error_handling.cc 34 | :language: c++ 35 | -------------------------------------------------------------------------------- /doc/sphinx/file_error_handling.cc: -------------------------------------------------------------------------------- 1 | try { 2 | mpl::file file; 3 | file.open(comm_world, "file_name.bin", 4 | mpl::file::access_mode::create | mpl::file::access_mode::read_write); 5 | // further file operations 6 | file.close(); 7 | } catch (mpl::io_failure &error) { 8 | // catch and handle i/o failures 9 | std::cerr << error.what() << '\n'; 10 | } 11 | -------------------------------------------------------------------------------- /doc/sphinx/grid.rst: -------------------------------------------------------------------------------- 1 | Grids 2 | ===== 3 | 4 | Global and local grids are two data structures included into MPL to facilitate the implementation of domain decomposition mathods on regular rectangular multidimensional grids. See sections :doc:`examples/distributed_grid`, :doc:`examples/distributed_grid_scatter_gather`, :doc:`examples/heat_equation_Jacobi_method` and :doc:`examples/heat_equation_successive_over-relaxation` for examples. 5 | 6 | 7 | Distributed grids 8 | ----------------- 9 | 10 | .. doxygenclass:: mpl::distributed_grid 11 | 12 | 13 | Local grids 14 | ----------- 15 | 16 | .. doxygenclass:: mpl::local_grid 17 | -------------------------------------------------------------------------------- /doc/sphinx/group.rst: -------------------------------------------------------------------------------- 1 | Group 2 | ===== 3 | 4 | Overview 5 | -------- 6 | 7 | A group is an ordered set of process identifiers. Each process in a group is associated with an integer rank. Ranks are contiguous and start from zero. Groups are represented by ``mpl::group`` objects. A group is used within a communicator to describe the participants in a communication “universe” and to rank such participants. 8 | 9 | 10 | Class documentation 11 | ------------------- 12 | 13 | .. doxygenclass:: mpl::group 14 | -------------------------------------------------------------------------------- /doc/sphinx/info.rst: -------------------------------------------------------------------------------- 1 | Info objects 2 | ============ 3 | 4 | Overview 5 | -------- 6 | 7 | Info objects store key-value pairs of string type. The semantics of these key-value pairs is defined by the MPI standard and by the employed MPI implementation. See the MPI standard and the documentation of your MPI implementation for details. Info objects are used by some MPL to pass the key-value pairs to the underlying MPI implementation to improve performance or resource utilization. 8 | 9 | 10 | Class documentation 11 | ------------------- 12 | 13 | .. doxygenclass:: mpl::info 14 | 15 | .. doxygenclass:: mpl::infos 16 | -------------------------------------------------------------------------------- /doc/sphinx/interoperability.rst: -------------------------------------------------------------------------------- 1 | .. _Design: 2 | 3 | MPL-MPI interoperability 4 | ======================== 5 | 6 | The MPL library is written on the basis of the MPI standard. Though, 7 | MPL hides most MPI specifics as an internal implementation detail. 8 | MPL allows to write complex message passing programs without calling 9 | any MPI function explicitly. 10 | 11 | In some situations, however, it might be desirable to mix MPL and MPI. 12 | Therefore, MPL provides some limited interoperability features. 13 | 14 | 15 | Getting MPI handles from MPL objects 16 | ------------------------------------ 17 | 18 | The MPL classes ``group``, ``communicator`` , ``inter_communicator`` 19 | (and all other communicator classes), ``file`` and ``layout`` (and all 20 | other data layout types) have a ``native handle`` method, which provides 21 | a copy of the object's underlying MPI handle, e.g., an ``MPI_Comm`` 22 | handle. These handles can be used in calls to plain MPI functions. 23 | A handle returned by a ``native handle`` method must not be freed 24 | manually, as it is managed by the MPL object. 25 | 26 | 27 | Using MPI communicators in MPL 28 | ------------------------------ 29 | 30 | The MPL class ``mpi_communicator`` provides a way to use an MPI 31 | communicator in MPL. The constructor of ``mpi_communicator`` 32 | requires a MPI communicator of type ``MPI_Comm`` as its argument and 33 | the constructed object will utilize this MPI communicator in all 34 | successive communication operations. This MPI communicator is *not* 35 | freed by the ``mpi_communicator`` destructor. 36 | 37 | 38 | Custom initialization and deinitialization of the MPI environment 39 | ----------------------------------------------------------------- 40 | 41 | MPL entirely hides the initialization and deinitialization of the MPI 42 | environment. With MPL, there is not need to call ``MPI_Init`` or 43 | ``MPI_Finalize`` (or some equivalent function) manually. This is a 44 | direct consequence of how MPL manages some internal resources. The 45 | deallocation of some resources (by calling the appropriate MPI 46 | functions) must be postponed until programm shutdown, i.e., *after* 47 | exiting from ``main``. 48 | 49 | Hiding the initialization and deinitialization of the MPI environment 50 | is convenient but can become a limiting factor when mixing MPI and MPL 51 | or when come custom initialization of the MPI environment is needed. 52 | 53 | In order to write your custom initialization and deinitialization code 54 | wrapp the calls to ``MPI_Init`` and ``MPI_Finalize`` into the 55 | constructor and the destructor of a custom class, e.g.: 56 | 57 | .. code-block:: 58 | 59 | class my_mpi_environment { 60 | public: 61 | my_mpi_environment(int *argc, char ***argv) { 62 | MPI_Init(argc, argv); 63 | } 64 | 65 | ~my_mpi_environment() { 66 | MPI_Finalize(); 67 | } 68 | }; 69 | 70 | Then create a static object of this class on function scope (e.g., in 71 | the scope of ``main``) and call this function before any MPL function. 72 | When MPL tries to initialize the MPI environment, it is checked if it 73 | has already been initialized before. In this case, MPL will also not 74 | deinitialize at program shutdown. In stead the MPI environment will 75 | be finalized by the provided custom destructor of the class sketched 76 | above. 77 | -------------------------------------------------------------------------------- /doc/sphinx/layouts.rst: -------------------------------------------------------------------------------- 1 | Data layouts 2 | ============ 3 | 4 | Overview 5 | -------- 6 | 7 | MPL message exchange methods come in several overloaded variants with signatures of different complexity. The most simple overloads allow to send or receive one object only, e.g., a single integer. As sending and receiving single data items would be too limiting for a message passing library, MPL introduces the concept of data layouts. Data layouts specify the memory layout of a set of objects to be sent or received (similar to derived data types in MPI). The layout may be continuous, a strided vector etc. The layouts on the sending and on the receiving sides need not to be identical but compatible, e.g., represent the same number of elements with the same types on both communication ends. See section :doc:`examples/layouts` for some usage examples of layouts. 8 | 9 | The MPL layout classes wrap MPI generalized data types into a flexible RAII interface and inherit their semantics. See the MPI Standard for details. 10 | 11 | 12 | Class documentation 13 | ------------------- 14 | 15 | Data layout base class 16 | ^^^^^^^^^^^^^^^^^^^^^^ 17 | 18 | .. doxygenclass:: mpl::layout 19 | :allow-dot-graphs: 20 | 21 | 22 | Null layout 23 | ^^^^^^^^^^^ 24 | 25 | .. doxygenclass:: mpl::null_layout 26 | :allow-dot-graphs: 27 | 28 | 29 | Empty layout 30 | ^^^^^^^^^^^^ 31 | 32 | .. doxygenclass:: mpl::empty_layout 33 | :allow-dot-graphs: 34 | 35 | 36 | Contiguous layout 37 | ^^^^^^^^^^^^^^^^^ 38 | 39 | .. doxygenclass:: mpl::contiguous_layout 40 | :allow-dot-graphs: 41 | 42 | 43 | Vector layout 44 | ^^^^^^^^^^^^^ 45 | 46 | .. doxygenclass:: mpl::vector_layout 47 | :allow-dot-graphs: 48 | 49 | 50 | Strided vector layout 51 | ^^^^^^^^^^^^^^^^^^^^^ 52 | 53 | .. doxygenclass:: mpl::strided_vector_layout 54 | :allow-dot-graphs: 55 | 56 | 57 | Indexed layout 58 | ^^^^^^^^^^^^^^ 59 | 60 | .. doxygenclass:: mpl::indexed_layout 61 | :allow-dot-graphs: 62 | 63 | 64 | Heterogeneous indexed layout 65 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 66 | 67 | .. doxygenclass:: mpl::hindexed_layout 68 | :allow-dot-graphs: 69 | 70 | 71 | Indexed block layout 72 | ^^^^^^^^^^^^^^^^^^^^ 73 | 74 | .. doxygenclass:: mpl::indexed_block_layout 75 | 76 | 77 | Heterogeneous indexed block layout 78 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 79 | 80 | .. doxygenclass:: mpl::hindexed_block_layout 81 | 82 | 83 | Iterator layout 84 | ^^^^^^^^^^^^^^^ 85 | 86 | .. doxygenclass:: mpl::iterator_layout 87 | 88 | 89 | Subarray layout 90 | ^^^^^^^^^^^^^^^ 91 | 92 | .. doxygenclass:: mpl::subarray_layout 93 | 94 | 95 | Helper functions and classes 96 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 97 | 98 | .. doxygenenum:: mpl::array_orders 99 | 100 | 101 | Heterogeneous layout 102 | ^^^^^^^^^^^^^^^^^^^^ 103 | 104 | .. doxygenclass:: mpl::heterogeneous_layout 105 | 106 | 107 | Helper functions and classes 108 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 109 | 110 | .. doxygenclass:: mpl::absolute_data 111 | .. doxygenclass:: mpl::absolute_data< const T * > 112 | .. doxygenclass:: mpl::absolute_data< T * > 113 | .. doxygenfunction:: mpl::make_absolute(const T *x, const layout &l) 114 | .. doxygenfunction:: mpl::make_absolute(T *x, const layout &l) 115 | 116 | 117 | Layouts 118 | ^^^^^^^ 119 | 120 | .. doxygenclass:: mpl::layouts 121 | 122 | 123 | Contiguous layouts 124 | ^^^^^^^^^^^^^^^^^^ 125 | 126 | .. doxygenclass:: mpl::contiguous_layouts 127 | -------------------------------------------------------------------------------- /doc/sphinx/reduction_operations.rst: -------------------------------------------------------------------------------- 1 | Reduction operations 2 | ==================== 3 | 4 | Overview 5 | -------- 6 | 7 | MPL supports various communication operations that perform a reduction operation over all processes within a communicator. The reduction operation is passed as an argument to the communicator class method that realizes to communication operation. The reduction operation can be given by a user-defined two-arguments functor class, a lambda function, e.g., 8 | 9 | .. code:: c++ 10 | 11 | comm.reduce([](auto a, auto b) { return a + b; }, ...); 12 | 13 | or by any of the template classes as documented below. 14 | 15 | 16 | Class documentation 17 | ------------------- 18 | 19 | Maximum 20 | ^^^^^^^ 21 | 22 | Perform the reduction operation 23 | 24 | .. math:: 25 | 26 | y = \max (x_1, x_2) 27 | 28 | .. doxygenstruct:: mpl::max 29 | 30 | 31 | Minimum 32 | ^^^^^^^ 33 | 34 | Perform the reduction operation 35 | 36 | .. math:: 37 | 38 | y = \min (x_1, x_2) 39 | 40 | .. doxygenstruct:: mpl::min 41 | 42 | 43 | Addition 44 | ^^^^^^^^ 45 | 46 | Perform the reduction operation 47 | 48 | .. math:: 49 | 50 | y = x_1 + x_2 51 | 52 | .. doxygenstruct:: mpl::plus 53 | 54 | 55 | Multiplication 56 | ^^^^^^^^^^^^^^ 57 | 58 | Perform the reduction operation 59 | 60 | .. math:: 61 | 62 | y = x_1 \cdot x_2 63 | 64 | .. doxygenstruct:: mpl::multiplies 65 | 66 | 67 | Logical conjunction 68 | ^^^^^^^^^^^^^^^^^^^ 69 | 70 | Perform the reduction operation 71 | 72 | .. math:: 73 | 74 | y = x_1 \land x_2 75 | 76 | .. doxygenstruct:: mpl::logical_and 77 | 78 | 79 | Logical disjunction 80 | ^^^^^^^^^^^^^^^^^^^ 81 | 82 | Perform the reduction operation 83 | 84 | .. math:: 85 | 86 | y = x_1 \lor x_2 87 | 88 | .. doxygenstruct:: mpl::logical_or 89 | 90 | 91 | Exclusive disjunction 92 | ^^^^^^^^^^^^^^^^^^^^^ 93 | 94 | Perform the reduction operation 95 | 96 | .. math:: 97 | 98 | y = x_1 \oplus x_2 99 | 100 | .. doxygenstruct:: mpl::logical_xor 101 | 102 | 103 | Bitwise and 104 | ^^^^^^^^^^^ 105 | 106 | Perform for integer arguments the bitwise reduction operation 107 | 108 | .. math:: 109 | 110 | y = x_1 \land x_2 111 | 112 | .. doxygenstruct:: mpl::bit_and 113 | 114 | 115 | Bitwise or 116 | ^^^^^^^^^^ 117 | 118 | Perform for integer arguments the bitwise reduction operation 119 | 120 | .. math:: 121 | 122 | y = x_1 \lor x_2 123 | 124 | .. doxygenstruct:: mpl::bit_or 125 | 126 | 127 | Bitwise exclusive-or 128 | ^^^^^^^^^^^^^^^^^^^^ 129 | 130 | Perform for integer arguments the bitwise reduction operation 131 | 132 | .. math:: 133 | 134 | y = x_1 \oplus x_2 135 | 136 | .. doxygenstruct:: mpl::bit_xor 137 | 138 | 139 | Operator traits 140 | ^^^^^^^^^^^^^^^ 141 | 142 | The application of some reduction operations can be performed more efficiently by exploiting the commutativity properties of the employed reduction operation. Partial template specializations of the class ``mpl::op_traits`` provide information about the commutativity properties of the reduction operation. Users may provide further user-defined specializations of ``mpl::op_traits`` for user-defined operators. 143 | 144 | .. doxygenstruct:: mpl::op_traits 145 | .. doxygenstruct:: mpl::op_traits< max< T > > 146 | .. doxygenstruct:: mpl::op_traits< min< T > > 147 | .. doxygenstruct:: mpl::op_traits< plus< T > > 148 | .. doxygenstruct:: mpl::op_traits< multiplies< T > > 149 | .. doxygenstruct:: mpl::op_traits< logical_and< T > > 150 | .. doxygenstruct:: mpl::op_traits< logical_or< T > > 151 | .. doxygenstruct:: mpl::op_traits< logical_xor< T > > 152 | .. doxygenstruct:: mpl::op_traits< bit_and< T > > 153 | .. doxygenstruct:: mpl::op_traits< bit_or< T > > 154 | .. doxygenstruct:: mpl::op_traits< bit_xor< T > > 155 | -------------------------------------------------------------------------------- /doc/sphinx/tags.rst: -------------------------------------------------------------------------------- 1 | Tags 2 | ==== 3 | 4 | Overview 5 | -------- 6 | 7 | A integer-valued message tag must be specified in some communication operations. The class ``mpl::tag_t`` wraps such tag into a custom class. This tag can be used by the program to distinguish different types of messages. 8 | 9 | 10 | Class documentation 11 | ------------------- 12 | 13 | .. doxygenclass:: mpl::tag_t 14 | 15 | .. doxygenvariable:: mpl::any_source 16 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/.nojekyll -------------------------------------------------------------------------------- /docs/html/_images/graphviz-57432295888f3b1be18dc2ff4389e53d44c4c869.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_images/graphviz-57432295888f3b1be18dc2ff4389e53d44c4c869.png -------------------------------------------------------------------------------- /docs/html/_images/graphviz-57432295888f3b1be18dc2ff4389e53d44c4c869.png.map: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/html/_images/graphviz-610b9e33bc07bb04b4607643a1f9f6ac5fc1da80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_images/graphviz-610b9e33bc07bb04b4607643a1f9f6ac5fc1da80.png -------------------------------------------------------------------------------- /docs/html/_images/graphviz-610b9e33bc07bb04b4607643a1f9f6ac5fc1da80.png.map: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/html/_images/graphviz-684df2bb1f5f269b07d535b765e98e0faed34052.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_images/graphviz-684df2bb1f5f269b07d535b765e98e0faed34052.png -------------------------------------------------------------------------------- /docs/html/_images/graphviz-684df2bb1f5f269b07d535b765e98e0faed34052.png.map: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/html/_images/graphviz-7106b06e7ffc5ab56026f5ac8ff442871e53c310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_images/graphviz-7106b06e7ffc5ab56026f5ac8ff442871e53c310.png -------------------------------------------------------------------------------- /docs/html/_images/graphviz-7106b06e7ffc5ab56026f5ac8ff442871e53c310.png.map: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/html/_images/graphviz-75a1f18eb87795bf7a08712374e54c8d1b2bd278.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_images/graphviz-75a1f18eb87795bf7a08712374e54c8d1b2bd278.png -------------------------------------------------------------------------------- /docs/html/_images/graphviz-75a1f18eb87795bf7a08712374e54c8d1b2bd278.png.map: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/html/_images/graphviz-ac4fbb3880ee103a7ca5c201fb2dee5b4a532839.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_images/graphviz-ac4fbb3880ee103a7ca5c201fb2dee5b4a532839.png -------------------------------------------------------------------------------- /docs/html/_images/graphviz-ac4fbb3880ee103a7ca5c201fb2dee5b4a532839.png.map: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/html/_images/graphviz-b254f1bb6c2aa092534cd14c8d6efccda1b3235f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_images/graphviz-b254f1bb6c2aa092534cd14c8d6efccda1b3235f.png -------------------------------------------------------------------------------- /docs/html/_images/graphviz-b254f1bb6c2aa092534cd14c8d6efccda1b3235f.png.map: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/html/_images/graphviz-b4b2d9f87128e4daea95a129e33a37e63efa7c98.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_images/graphviz-b4b2d9f87128e4daea95a129e33a37e63efa7c98.png -------------------------------------------------------------------------------- /docs/html/_images/graphviz-b4b2d9f87128e4daea95a129e33a37e63efa7c98.png.map: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/html/_images/graphviz-d91f2fdebe3b7e20ff1761bf5a36baed7437423b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_images/graphviz-d91f2fdebe3b7e20ff1761bf5a36baed7437423b.png -------------------------------------------------------------------------------- /docs/html/_images/graphviz-d91f2fdebe3b7e20ff1761bf5a36baed7437423b.png.map: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/html/_images/graphviz-ead1119f5dbe0a448886914d18fd0cadedecdab1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_images/graphviz-ead1119f5dbe0a448886914d18fd0cadedecdab1.png -------------------------------------------------------------------------------- /docs/html/_images/graphviz-ead1119f5dbe0a448886914d18fd0cadedecdab1.png.map: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /docs/html/_images/graphviz-f85f742f79de3c705c79ddaf4b344515c9beb90a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_images/graphviz-f85f742f79de3c705c79ddaf4b344515c9beb90a.png -------------------------------------------------------------------------------- /docs/html/_images/graphviz-f85f742f79de3c705c79ddaf4b344515c9beb90a.png.map: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/html/_sources/auxiliary.rst.txt: -------------------------------------------------------------------------------- 1 | Auxiliary functions and classes 2 | =============================== 3 | 4 | Integer types 5 | ------------- 6 | 7 | .. doxygentypedef:: mpl::size_t 8 | .. doxygentypedef:: mpl::ssize_t 9 | 10 | 11 | Ranks 12 | ----- 13 | 14 | .. doxygenclass:: mpl::ranks 15 | 16 | 17 | Types for probing messages 18 | -------------------------- 19 | 20 | The following types are used in the context of probing messages. See section :doc:`examples/probe` for an example. 21 | 22 | .. doxygentypedef:: mpl::message_t 23 | .. doxygenclass:: mpl::status_t 24 | .. doxygenstruct:: mpl::mprobe_status 25 | 26 | 27 | Memory displacements 28 | -------------------- 29 | 30 | The ``mpl::displacements`` class is used in the context of various collective communication operations that send and/or receive an amount of data that varies over the set of participating processes. 31 | 32 | .. doxygenclass:: mpl::displacements 33 | 34 | 35 | Requests 36 | -------- 37 | 38 | Test status enum 39 | ^^^^^^^^^^^^^^^^ 40 | 41 | .. doxygenenum:: mpl::test_result 42 | 43 | 44 | Non-blocking communication requests 45 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 46 | 47 | .. doxygenclass:: mpl::irequest 48 | .. doxygenclass:: mpl::irequest_pool 49 | 50 | 51 | Persistent communication requests 52 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 53 | 54 | .. doxygenclass:: mpl::prequest 55 | .. doxygenclass:: mpl::prequest_pool 56 | 57 | 58 | Command-line arguments 59 | ---------------------- 60 | 61 | .. doxygenclass:: mpl::command_line 62 | 63 | .. doxygenclass:: mpl::command_lines 64 | -------------------------------------------------------------------------------- /docs/html/_sources/cmake_integration.rst.txt: -------------------------------------------------------------------------------- 1 | CMake integration 2 | ================= 3 | 4 | MPL provides supporting files for CMake integration. These are also installed during the installation step. CMake integration is realized via the ``mpl`` CMake package, which provides the library target ``mpl::mpl``. The following example ``CMakeLists.txt`` file illustrates the usage of the ``mpl`` CMake package for creating an MPL application. First, the ``mpl`` package is loaded via the ``find_package`` function. Then, all targets with MPL dependency must be linked against ``mpl::mpl``. In this way, CMake adds all necessary compiler flags and linker flags that are required for building an MPL application. 5 | 6 | .. code-block:: CMake 7 | 8 | # MPI CMake module available since version 3.10 9 | cmake_minimum_required(VERSION 3.10) 10 | 11 | project(hello_mpl) 12 | 13 | # project requires c++17 to build 14 | set(CMAKE_CXX_STANDARD 17) 15 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 16 | set(CMAKE_CXX_EXTENSIONS OFF) 17 | 18 | # find the MPL library and its dependencies, e.g., an MPI library 19 | find_package(mpl REQUIRED) 20 | 21 | # create executable and link against mpl and its dependencies 22 | add_executable(hello_world hello_world.cc) 23 | target_link_libraries(hello_world PRIVATE mpl::mpl) 24 | 25 | When using ``find_package``, CMake searches in a set of platform-dependent standard directories for the requested CMake package. CMake may fail to find the MPL CMake package when MPL was installed in a custom directory. If MPL was installed in a custom directory, add the installation directory (given via ``CMAKE_INSTALL_PREFIX`` during MPL configuration see :ref:`Installation`) to the ``CMAKE_PREFIX_PATH`` variable during the configuration of the MPL application, e.g.: 26 | 27 | .. code:: shell 28 | 29 | user@host:~/hello_mpl/build$ cmake -DCMAKE_PREFIX_PATH:PATH=/path/to/mpl .. 30 | -------------------------------------------------------------------------------- /docs/html/_sources/communicator.rst.txt: -------------------------------------------------------------------------------- 1 | Communicators 2 | ============= 3 | 4 | A communicator consists of a group of processed and defines a communication context that partitions the communication space. A message sent in one context cannot be received in another context. Furthermore, where permitted, collective operations are independent of pending point-to-point operations. 5 | 6 | MPL defines several kinds of communicators: 7 | 8 | - standard communicators, 9 | 10 | - communicators with a process topology (Cartesian communicators, graph communicators, distributed graph communicators) and 11 | 12 | - inter-communicators. 13 | 14 | An inter-communicator identifies two distinct groups of processes linked with a communication context. 15 | 16 | 17 | Standard communicators 18 | ---------------------- 19 | 20 | .. doxygenclass:: mpl::communicator 21 | 22 | 23 | Standard communicators for MPI interoperability 24 | ----------------------------------------------- 25 | 26 | .. doxygenclass:: mpl::mpi_communicator 27 | 28 | 29 | Cartesian communicators 30 | ----------------------- 31 | 32 | .. doxygenclass:: mpl::cartesian_communicator 33 | 34 | 35 | Auxiliary functions and classes for cartesian communicators 36 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 37 | 38 | For constructing communicators with a cartesian process topology the following utility function can be used. 39 | 40 | .. doxygenfunction:: mpl::dims_create 41 | 42 | .. doxygenstruct:: mpl::shift_ranks 43 | 44 | 45 | Graph communicators 46 | ------------------- 47 | 48 | .. doxygenclass:: mpl::graph_communicator 49 | 50 | 51 | Distributed graph communicators 52 | ------------------------------- 53 | 54 | .. doxygenclass:: mpl::distributed_graph_communicator 55 | 56 | 57 | Inter-communicators 58 | ------------------- 59 | 60 | .. doxygenclass:: mpl::inter_communicator 61 | 62 | 63 | Inter-communicators for MPI interoperability 64 | ----------------------------------------------- 65 | 66 | .. doxygenclass:: mpl::mpi_inter_communicator 67 | -------------------------------------------------------------------------------- /docs/html/_sources/constants.rst.txt: -------------------------------------------------------------------------------- 1 | Constants 2 | ========= 3 | 4 | MPL defines the following global constants: 5 | 6 | .. doxygenvariable:: mpl::proc_null 7 | 8 | .. doxygenvariable:: mpl::undefined 9 | 10 | .. doxygenvariable:: mpl::root 11 | 12 | .. doxygenvariable:: mpl::absolute 13 | 14 | .. doxygenvariable:: mpl::bsend_overhead 15 | -------------------------------------------------------------------------------- /docs/html/_sources/design.rst.txt: -------------------------------------------------------------------------------- 1 | .. _Design: 2 | 3 | Library design principles 4 | ========================= 5 | 6 | MPL is designed on the basis of the following design principles: 7 | 8 | Resource management 9 | ------------------- 10 | 11 | In a typical MPI program, a number of resources, e.g., communicators, 12 | custom data types etc., must be management. Allocation and deallocation 13 | of such resources must be done manually by explicitly calling the 14 | respective allocation and deallocation function. This is error-prone, 15 | may lead to resource leaks and requires a lot of boilerplate code. 16 | 17 | Therefore, MPL applies the principle of "resource acquisition is 18 | initialization" (RAII) and wraps all resources in custom class types. 19 | Resources are allocated in a constructor and automatically dealocated 20 | when a resource object goes out of scope by the destructor. In contrast 21 | to MPI handles, all resource classes have a value-semantics. This means, 22 | when a resource object is copies in to another one, then a new resource 23 | is created and the two resource objects manage different independent 24 | resources. 25 | 26 | 27 | Custom data types 28 | ----------------- 29 | 30 | Custom data types are one of the most versatile features of MPI. With 31 | custom data types, it is possible to write very well-structured 32 | code by hiding details of the complex communication pattern in 33 | well-designed custom data types. Therefore, MPL makes it easy to 34 | create and use custom data types. These are called layouts in MPL. 35 | 36 | The size argument of MPI communication functions is usually redundant. 37 | The information that it provides can be incorporated into the 38 | data type argument with a custom data type. Therefore, MPL communication 39 | functions do not require a size argument. All information about the 40 | amount and memory layout of exchanged data is provided by data layout 41 | arguments. 42 | 43 | 44 | Avoid programming errors by strong typing 45 | ----------------------------------------- 46 | 47 | It is a common error in MPI programs to pass logically inconsistent 48 | arguments to an MPI function. For example, one might pass a pointer 49 | to ``double`` as a buffer argument and pass ``MPI_FLOAT`` as the 50 | data type argument. The classic MPI api does not protect one from such 51 | kind of errors, i.e., no compiler error is caused. 52 | 53 | MPL leverages the strong type system of C++ to detect such kinds of 54 | programming mistakes at compile time, i.e., to make such programming 55 | errors impossible. For example, buffer arguments expect pointers of a 56 | specific type, rather than untyped pointers to ``void``, and MPL 57 | infers internally the right MPI data type on the basis of the pointer 58 | type. 59 | -------------------------------------------------------------------------------- /docs/html/_sources/environmental_management.rst.txt: -------------------------------------------------------------------------------- 1 | Environmental management 2 | ======================== 3 | 4 | MPL provides various functions for querying characteristics of the computational environment. 5 | 6 | 7 | Current processor name 8 | ---------------------- 9 | 10 | .. doxygenfunction:: mpl::environment::processor_name 11 | 12 | 13 | Predefined communicators 14 | ------------------------ 15 | 16 | .. doxygenfunction:: mpl::environment::comm_world 17 | .. doxygenfunction:: mpl::environment::comm_self 18 | 19 | 20 | Threading support 21 | ----------------- 22 | 23 | .. doxygenfunction:: mpl::environment::is_thread_main 24 | .. doxygenfunction:: mpl::environment::threading_mode 25 | .. doxygenenum:: mpl::threading_modes 26 | 27 | 28 | Time 29 | ---- 30 | 31 | .. doxygenfunction:: mpl::environment::wtime_is_global 32 | .. doxygenfunction:: mpl::environment::wtime 33 | .. doxygenfunction:: mpl::environment::wtick 34 | 35 | 36 | Management of buffers for buffered send operations 37 | -------------------------------------------------- 38 | 39 | .. doxygenfunction:: mpl::environment::buffer_attach 40 | .. doxygenfunction:: mpl::environment::buffer_detach 41 | .. doxygenclass:: mpl::bsend_buffer 42 | -------------------------------------------------------------------------------- /docs/html/_sources/error.rst.txt: -------------------------------------------------------------------------------- 1 | Error handling 2 | ============== 3 | 4 | MPL performs some consistency checks when the macro ``MPL_DEBUG`` has been defined. In case of an error, an exception may be thrown with an object having one of the following types. 5 | 6 | .. doxygenclass:: mpl::error 7 | .. doxygenclass:: mpl::invalid_rank 8 | .. doxygenclass:: mpl::invalid_tag 9 | .. doxygenclass:: mpl::invalid_size 10 | .. doxygenclass:: mpl::invalid_count 11 | .. doxygenclass:: mpl::invalid_layout 12 | .. doxygenclass:: mpl::invalid_dim 13 | .. doxygenclass:: mpl::invalid_datatype_bound 14 | .. doxygenclass:: mpl::invalid_argument 15 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/arrays.rst.txt: -------------------------------------------------------------------------------- 1 | Arrays 2 | ====== 3 | 4 | Sends and receives arrays (C arrays and ``std::array``) of fixed size, which must be known at compile time. The types of the array elements must be suited for communication. These rules may be applied recursively. 5 | 6 | .. literalinclude:: ../../../examples/arrays.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/blocking.rst.txt: -------------------------------------------------------------------------------- 1 | Blocking send and receive 2 | ========================= 3 | 4 | Demonstrates various blocking send and receive modes of standard data types. 5 | 6 | .. literalinclude:: ../../../examples/blocking.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/blocking_vector.rst.txt: -------------------------------------------------------------------------------- 1 | Blocking send and receive of vectors 2 | ==================================== 3 | 4 | Demonstrates blocking send and receive of a vector of standard data types. 5 | 6 | .. literalinclude:: ../../../examples/blocking_vector.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/collective.rst.txt: -------------------------------------------------------------------------------- 1 | Collective communication 2 | ======================== 3 | 4 | Demonstrates various modes of collective communication. 5 | 6 | .. literalinclude:: ../../../examples/collective.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/communicator.rst.txt: -------------------------------------------------------------------------------- 1 | Communicator management 2 | ======================= 3 | 4 | Demonstrates some basic communicator management. 5 | 6 | .. literalinclude:: ../../../examples/communicator.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/custom_initialization.rst.txt: -------------------------------------------------------------------------------- 1 | Custom initialization of the MPI environment 2 | ============================================ 3 | 4 | MPL initializes the MPI environment automatically internally. This example program shows how to write a custom MPI initializer when more control over the initialization of the MPI environment is needed. This can be useful, when combining MPL with other MPI-based libraries. 5 | 6 | .. literalinclude:: ../../../examples/custom_initialization.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/distributed_grid.rst.txt: -------------------------------------------------------------------------------- 1 | Distributed grid 2 | ================ 3 | 4 | Data type ``mpl::distributed_grid`` in action. 5 | 6 | .. literalinclude:: ../../../examples/distributed_grid.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/distributed_grid_scatter_gather.rst.txt: -------------------------------------------------------------------------------- 1 | Distributed grid collective operations 2 | ====================================== 3 | 4 | Scatter and gather operations with data type ``mpl::distributed_grid``. 5 | 6 | .. literalinclude:: ../../../examples/distributed_grid_scatter_gather.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/file.rst.txt: -------------------------------------------------------------------------------- 1 | File i/o 2 | ======== 3 | 4 | Simple program performing basic file-based i/o operations. 5 | 6 | .. literalinclude:: ../../../examples/file.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/gather.rst.txt: -------------------------------------------------------------------------------- 1 | Gather operations 2 | ================= 3 | 4 | Gathers data to a single process. 5 | 6 | .. literalinclude:: ../../../examples/gather.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/gatherv.rst.txt: -------------------------------------------------------------------------------- 1 | Variable gather operations 2 | ========================== 3 | 4 | Gathers data if varying size to a single process. 5 | 6 | .. literalinclude:: ../../../examples/gather.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/heat_equation_Jacobi_method.rst.txt: -------------------------------------------------------------------------------- 1 | Heat equation Jacobi solver 2 | =========================== 3 | 4 | Solves the two-dimensional time-independent heat equation with fixed temperatures at the border via Jacobi iterations. Implementation uses ``mpl::distributed_grid``. 5 | 6 | .. literalinclude:: ../../../examples/heat_equation_Jacobi_method.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/heat_equation_successive_over-relaxation.rst.txt: -------------------------------------------------------------------------------- 1 | Heat equation successive over-relaxation 2 | ======================================== 3 | 4 | Solves the two-dimensional time-independent heat equation with fixed temperatures at the border via successive over-relaxation. Implementation uses ``mpl::distributed_grid``. 5 | 6 | .. literalinclude:: ../../../examples/heat_equation_successive_over-relaxation.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/hello_world.rst.txt: -------------------------------------------------------------------------------- 1 | Hello world 2 | =========== 3 | 4 | Simple hello-world program. Initializes the message passing environment and determines the number of processes and rank. 5 | 6 | .. literalinclude:: ../../../examples/hello_world.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/index.rst.txt: -------------------------------------------------------------------------------- 1 | Examples 2 | ======== 3 | 4 | .. toctree:: 5 | 6 | hello_world 7 | standard_types 8 | struct 9 | arrays 10 | stl_container 11 | iterators 12 | blocking 13 | blocking_vector 14 | nonblocking 15 | nonblocking_mult 16 | probe 17 | communicator 18 | collective 19 | gather 20 | gatherv 21 | matrix_gather 22 | reduce 23 | layouts 24 | subarray 25 | custom_initialization 26 | parallel_sort 27 | vibrating_string 28 | distributed_grid 29 | distributed_grid_scatter_gather 30 | heat_equation_Jacobi_method 31 | heat_equation_successive_over-relaxation 32 | process_creation 33 | file 34 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/iterators.rst.txt: -------------------------------------------------------------------------------- 1 | Iterators 2 | ========= 3 | 4 | Sends and receives containers (``std::vector``, ``std::list``, etc.) given by their iterators. The types of the array elements must be suited for communication. On the receiving side, there must be sufficient preallocated memory, i.e., sending and receiving containers must be of the same size. Furthermore, tracking the address of a dereferenced iterator must result a non-const pointer on the receiving side. 5 | 6 | .. literalinclude:: ../../../examples/iterators.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/layouts.rst.txt: -------------------------------------------------------------------------------- 1 | Layouts 2 | ======= 3 | 4 | Construction and usage of various data layouts. 5 | 6 | .. literalinclude:: ../../../examples/layouts.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/matrix_gather.rst.txt: -------------------------------------------------------------------------------- 1 | Matrix gather 2 | ============= 3 | 4 | Demonstrates gathering of a distributed matrix as it may used in domain partitioning applications. 5 | 6 | .. literalinclude:: ../../../examples/matrix_gather.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/nonblocking.rst.txt: -------------------------------------------------------------------------------- 1 | Non-blocking send and receive 2 | ============================= 3 | 4 | Demonstrates non-blocking send and receive of standard data types and vectors of standard data types and different waiting methods. 5 | 6 | .. literalinclude:: ../../../examples/nonblocking.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/nonblocking_mult.rst.txt: -------------------------------------------------------------------------------- 1 | Gather via non-blocking send and receive 2 | ======================================== 3 | 4 | Utilizes non-blocking send and receive of standard data types to implement a gather operation. 5 | 6 | .. literalinclude:: ../../../examples/nonblocking_mult.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/parallel_sort.rst.txt: -------------------------------------------------------------------------------- 1 | Parallel sorting 2 | ================ 3 | 4 | Parallel sort algorithm, MPI version. 5 | 6 | .. literalinclude:: ../../../examples/parallel_sort_mpi.c 7 | :language: c 8 | 9 | 10 | Parallel sort algorithm, MPL version. 11 | 12 | .. literalinclude:: ../../../examples/parallel_sort_mpl.cc 13 | :language: c++ 14 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/probe.rst.txt: -------------------------------------------------------------------------------- 1 | Probing messages 2 | ================ 3 | 4 | Demonstrates how to probe data and to receive a message of unknown size. 5 | 6 | .. literalinclude:: ../../../examples/probe.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/process_creation.rst.txt: -------------------------------------------------------------------------------- 1 | Process creation 2 | ================ 3 | 4 | The following two programs illustrate dynamic creation of new processes and establishing a communication channel in the form of inter-communicator. 5 | 6 | .. literalinclude:: ../../../examples/process_creation.cc 7 | :language: c++ 8 | 9 | .. literalinclude:: ../../../examples/process_creation_multiple.cc 10 | :language: c++ 11 | 12 | 13 | The corresponding source of the spawned process is given as shown below: 14 | 15 | .. literalinclude:: ../../../examples/process_creation_client.cc 16 | :language: c++ 17 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/reduce.rst.txt: -------------------------------------------------------------------------------- 1 | Reduction operations 2 | ===================== 3 | 4 | Demonstrates use of custom reduction functions. 5 | 6 | .. literalinclude:: ../../../examples/reduce_lcm.cc 7 | :language: c++ 8 | 9 | 10 | Demonstrates use of reduction functions for std::pair to determine a minimum as its location. 11 | 12 | .. literalinclude:: ../../../examples/reduce_min_loc.cc 13 | :language: c++ 14 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/standard_types.rst.txt: -------------------------------------------------------------------------------- 1 | Standard types 2 | ============== 3 | 4 | Sends and receives data of various standard types. 5 | 6 | .. literalinclude:: ../../../examples/standard_types.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/stl_container.rst.txt: -------------------------------------------------------------------------------- 1 | STL containers 2 | ============== 3 | 4 | Sends and receives STL containers. 5 | 6 | .. literalinclude:: ../../../examples/stl_container.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/struct.rst.txt: -------------------------------------------------------------------------------- 1 | Using structs 2 | ============= 3 | 4 | Demonstrates how to use ``class mpl::struct_builder`` to enable communication using structures and classes. Class members must be of fixed size (no dynamic memory allocation). All types of the class members must be suited for communication. These rules may be applied recursively. 5 | 6 | .. literalinclude:: ../../../examples/struct.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/subarray.rst.txt: -------------------------------------------------------------------------------- 1 | Subarray layouts 2 | ================ 3 | 4 | Construction and usage of subarray layouts. 5 | 6 | .. literalinclude:: ../../../examples/subarray.cc 7 | :language: c++ 8 | -------------------------------------------------------------------------------- /docs/html/_sources/examples/vibrating_string.rst.txt: -------------------------------------------------------------------------------- 1 | Vibrating string 2 | ================ 3 | 4 | Solves the one-dimensional wave equation via finite differences, MPI version. 5 | 6 | .. literalinclude:: ../../../examples/vibrating_string_mpi.c 7 | :language: c 8 | 9 | 10 | Solves the one-dimensional wave equation via finite differences, MPL version. 11 | 12 | .. literalinclude:: ../../../examples/vibrating_string_mpl.cc 13 | :language: c++ 14 | -------------------------------------------------------------------------------- /docs/html/_sources/file.rst.txt: -------------------------------------------------------------------------------- 1 | File 2 | ==== 3 | 4 | Overview 5 | -------- 6 | 7 | Parallel file operations are implemented via the ``mpl::file`` class. It offers various read and write modalities (collective and non-collective, blocking and non-blocking etc.) by closely following the MPI standard. See the `MPI standard `_ for a detailed description of the semantics of the various i/o operations. 8 | 9 | 10 | Class documentation 11 | ------------------- 12 | 13 | File class 14 | ^^^^^^^^^^ 15 | 16 | .. doxygenclass:: mpl::file 17 | 18 | 19 | File access mode operations 20 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 21 | 22 | .. doxygenfunction:: mpl::operator|(file::access_mode, file::access_mode) 23 | .. doxygenfunction:: mpl::operator|=(file::access_mode &, file::access_mode) 24 | .. doxygenfunction:: mpl::operator&(file::access_mode, file::access_mode) 25 | .. doxygenfunction:: mpl::operator&=(file::access_mode &, file::access_mode) 26 | 27 | 28 | Error handling 29 | ^^^^^^^^^^^^^^ 30 | 31 | Methods of ``mpl::file`` class may throw an exception of the type ``mpl::io_failure`` in the case of run-time i/o failures. Thus, file operations should be wrapped into a ``try`` block and possible exceptions should be caught in a matching ``catch`` clause as demonstrated in the following example: 32 | 33 | .. literalinclude:: file_error_handling.cc 34 | :language: c++ 35 | -------------------------------------------------------------------------------- /docs/html/_sources/grid.rst.txt: -------------------------------------------------------------------------------- 1 | Grids 2 | ===== 3 | 4 | Global and local grids are two data structures included into MPL to facilitate the implementation of domain decomposition mathods on regular rectangular multidimensional grids. See sections :doc:`examples/distributed_grid`, :doc:`examples/distributed_grid_scatter_gather`, :doc:`examples/heat_equation_Jacobi_method` and :doc:`examples/heat_equation_successive_over-relaxation` for examples. 5 | 6 | 7 | Distributed grids 8 | ----------------- 9 | 10 | .. doxygenclass:: mpl::distributed_grid 11 | 12 | 13 | Local grids 14 | ----------- 15 | 16 | .. doxygenclass:: mpl::local_grid 17 | -------------------------------------------------------------------------------- /docs/html/_sources/group.rst.txt: -------------------------------------------------------------------------------- 1 | Group 2 | ===== 3 | 4 | Overview 5 | -------- 6 | 7 | A group is an ordered set of process identifiers. Each process in a group is associated with an integer rank. Ranks are contiguous and start from zero. Groups are represented by ``mpl::group`` objects. A group is used within a communicator to describe the participants in a communication “universe” and to rank such participants. 8 | 9 | 10 | Class documentation 11 | ------------------- 12 | 13 | .. doxygenclass:: mpl::group 14 | -------------------------------------------------------------------------------- /docs/html/_sources/info.rst.txt: -------------------------------------------------------------------------------- 1 | Info objects 2 | ============ 3 | 4 | Overview 5 | -------- 6 | 7 | Info objects store key-value pairs of string type. The semantics of these key-value pairs is defined by the MPI standard and by the employed MPI implementation. See the MPI standard and the documentation of your MPI implementation for details. Info objects are used by some MPL to pass the key-value pairs to the underlying MPI implementation to improve performance or resource utilization. 8 | 9 | 10 | Class documentation 11 | ------------------- 12 | 13 | .. doxygenclass:: mpl::info 14 | 15 | .. doxygenclass:: mpl::infos 16 | -------------------------------------------------------------------------------- /docs/html/_sources/interoperability.rst.txt: -------------------------------------------------------------------------------- 1 | .. _Design: 2 | 3 | MPL-MPI interoperability 4 | ======================== 5 | 6 | The MPL library is written on the basis of the MPI standard. Though, 7 | MPL hides most MPI specifics as an internal implementation detail. 8 | MPL allows to write complex message passing programs without calling 9 | any MPI function explicitly. 10 | 11 | In some situations, however, it might be desirable to mix MPL and MPI. 12 | Therefore, MPL provides some limited interoperability features. 13 | 14 | 15 | Getting MPI handles from MPL objects 16 | ------------------------------------ 17 | 18 | The MPL classes ``group``, ``communicator`` , ``inter_communicator`` 19 | (and all other communicator classes), ``file`` and ``layout`` (and all 20 | other data layout types) have a ``native handle`` method, which provides 21 | a copy of the object's underlying MPI handle, e.g., an ``MPI_Comm`` 22 | handle. These handles can be used in calls to plain MPI functions. 23 | A handle returned by a ``native handle`` method must not be freed 24 | manually, as it is managed by the MPL object. 25 | 26 | 27 | Using MPI communicators in MPL 28 | ------------------------------ 29 | 30 | The MPL class ``mpi_communicator`` provides a way to use an MPI 31 | communicator in MPL. The constructor of ``mpi_communicator`` 32 | requires a MPI communicator of type ``MPI_Comm`` as its argument and 33 | the constructed object will utilize this MPI communicator in all 34 | successive communication operations. This MPI communicator is *not* 35 | freed by the ``mpi_communicator`` destructor. 36 | 37 | 38 | Custom initialization and deinitialization of the MPI environment 39 | ----------------------------------------------------------------- 40 | 41 | MPL entirely hides the initialization and deinitialization of the MPI 42 | environment. With MPL, there is not need to call ``MPI_Init`` or 43 | ``MPI_Finalize`` (or some equivalent function) manually. This is a 44 | direct consequence of how MPL manages some internal resources. The 45 | deallocation of some resources (by calling the appropriate MPI 46 | functions) must be postponed until programm shutdown, i.e., *after* 47 | exiting from ``main``. 48 | 49 | Hiding the initialization and deinitialization of the MPI environment 50 | is convenient but can become a limiting factor when mixing MPI and MPL 51 | or when come custom initialization of the MPI environment is needed. 52 | 53 | In order to write your custom initialization and deinitialization code 54 | wrapp the calls to ``MPI_Init`` and ``MPI_Finalize`` into the 55 | constructor and the destructor of a custom class, e.g.: 56 | 57 | .. code-block:: 58 | 59 | class my_mpi_environment { 60 | public: 61 | my_mpi_environment(int *argc, char ***argv) { 62 | MPI_Init(argc, argv); 63 | } 64 | 65 | ~my_mpi_environment() { 66 | MPI_Finalize(); 67 | } 68 | }; 69 | 70 | Then create a static object of this class on function scope (e.g., in 71 | the scope of ``main``) and call this function before any MPL function. 72 | When MPL tries to initialize the MPI environment, it is checked if it 73 | has already been initialized before. In this case, MPL will also not 74 | deinitialize at program shutdown. In stead the MPI environment will 75 | be finalized by the provided custom destructor of the class sketched 76 | above. 77 | -------------------------------------------------------------------------------- /docs/html/_sources/layouts.rst.txt: -------------------------------------------------------------------------------- 1 | Data layouts 2 | ============ 3 | 4 | Overview 5 | -------- 6 | 7 | MPL message exchange methods come in several overloaded variants with signatures of different complexity. The most simple overloads allow to send or receive one object only, e.g., a single integer. As sending and receiving single data items would be too limiting for a message passing library, MPL introduces the concept of data layouts. Data layouts specify the memory layout of a set of objects to be sent or received (similar to derived data types in MPI). The layout may be continuous, a strided vector etc. The layouts on the sending and on the receiving sides need not to be identical but compatible, e.g., represent the same number of elements with the same types on both communication ends. See section :doc:`examples/layouts` for some usage examples of layouts. 8 | 9 | The MPL layout classes wrap MPI generalized data types into a flexible RAII interface and inherit their semantics. See the MPI Standard for details. 10 | 11 | 12 | Class documentation 13 | ------------------- 14 | 15 | Data layout base class 16 | ^^^^^^^^^^^^^^^^^^^^^^ 17 | 18 | .. doxygenclass:: mpl::layout 19 | :allow-dot-graphs: 20 | 21 | 22 | Null layout 23 | ^^^^^^^^^^^ 24 | 25 | .. doxygenclass:: mpl::null_layout 26 | :allow-dot-graphs: 27 | 28 | 29 | Empty layout 30 | ^^^^^^^^^^^^ 31 | 32 | .. doxygenclass:: mpl::empty_layout 33 | :allow-dot-graphs: 34 | 35 | 36 | Contiguous layout 37 | ^^^^^^^^^^^^^^^^^ 38 | 39 | .. doxygenclass:: mpl::contiguous_layout 40 | :allow-dot-graphs: 41 | 42 | 43 | Vector layout 44 | ^^^^^^^^^^^^^ 45 | 46 | .. doxygenclass:: mpl::vector_layout 47 | :allow-dot-graphs: 48 | 49 | 50 | Strided vector layout 51 | ^^^^^^^^^^^^^^^^^^^^^ 52 | 53 | .. doxygenclass:: mpl::strided_vector_layout 54 | :allow-dot-graphs: 55 | 56 | 57 | Indexed layout 58 | ^^^^^^^^^^^^^^ 59 | 60 | .. doxygenclass:: mpl::indexed_layout 61 | :allow-dot-graphs: 62 | 63 | 64 | Heterogeneous indexed layout 65 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 66 | 67 | .. doxygenclass:: mpl::hindexed_layout 68 | :allow-dot-graphs: 69 | 70 | 71 | Indexed block layout 72 | ^^^^^^^^^^^^^^^^^^^^ 73 | 74 | .. doxygenclass:: mpl::indexed_block_layout 75 | 76 | 77 | Heterogeneous indexed block layout 78 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 79 | 80 | .. doxygenclass:: mpl::hindexed_block_layout 81 | 82 | 83 | Iterator layout 84 | ^^^^^^^^^^^^^^^ 85 | 86 | .. doxygenclass:: mpl::iterator_layout 87 | 88 | 89 | Subarray layout 90 | ^^^^^^^^^^^^^^^ 91 | 92 | .. doxygenclass:: mpl::subarray_layout 93 | 94 | 95 | Helper functions and classes 96 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 97 | 98 | .. doxygenenum:: mpl::array_orders 99 | 100 | 101 | Heterogeneous layout 102 | ^^^^^^^^^^^^^^^^^^^^ 103 | 104 | .. doxygenclass:: mpl::heterogeneous_layout 105 | 106 | 107 | Helper functions and classes 108 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 109 | 110 | .. doxygenclass:: mpl::absolute_data 111 | .. doxygenclass:: mpl::absolute_data< const T * > 112 | .. doxygenclass:: mpl::absolute_data< T * > 113 | .. doxygenfunction:: mpl::make_absolute(const T *x, const layout &l) 114 | .. doxygenfunction:: mpl::make_absolute(T *x, const layout &l) 115 | 116 | 117 | Layouts 118 | ^^^^^^^ 119 | 120 | .. doxygenclass:: mpl::layouts 121 | 122 | 123 | Contiguous layouts 124 | ^^^^^^^^^^^^^^^^^^ 125 | 126 | .. doxygenclass:: mpl::contiguous_layouts 127 | -------------------------------------------------------------------------------- /docs/html/_sources/tags.rst.txt: -------------------------------------------------------------------------------- 1 | Tags 2 | ==== 3 | 4 | Overview 5 | -------- 6 | 7 | A integer-valued message tag must be specified in some communication operations. The class ``mpl::tag_t`` wraps such tag into a custom class. This tag can be used by the program to distinguish different types of messages. 8 | 9 | 10 | Class documentation 11 | ------------------- 12 | 13 | .. doxygenclass:: mpl::tag_t 14 | 15 | .. doxygenvariable:: mpl::any_source 16 | -------------------------------------------------------------------------------- /docs/html/_sphinx_design_static/design-tabs.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | // Extra JS capability for selected tabs to be synced 4 | // The selection is stored in local storage so that it persists across page loads. 5 | 6 | /** 7 | * @type {Record} 8 | */ 9 | let sd_id_to_elements = {}; 10 | const storageKeyPrefix = "sphinx-design-tab-id-"; 11 | 12 | /** 13 | * Create a key for a tab element. 14 | * @param {HTMLElement} el - The tab element. 15 | * @returns {[string, string, string] | null} - The key. 16 | * 17 | */ 18 | function create_key(el) { 19 | let syncId = el.getAttribute("data-sync-id"); 20 | let syncGroup = el.getAttribute("data-sync-group"); 21 | if (!syncId || !syncGroup) return null; 22 | return [syncGroup, syncId, syncGroup + "--" + syncId]; 23 | } 24 | 25 | /** 26 | * Initialize the tab selection. 27 | * 28 | */ 29 | function ready() { 30 | // Find all tabs with sync data 31 | 32 | /** @type {string[]} */ 33 | let groups = []; 34 | 35 | document.querySelectorAll(".sd-tab-label").forEach((label) => { 36 | if (label instanceof HTMLElement) { 37 | let data = create_key(label); 38 | if (data) { 39 | let [group, id, key] = data; 40 | 41 | // add click event listener 42 | // @ts-ignore 43 | label.onclick = onSDLabelClick; 44 | 45 | // store map of key to elements 46 | if (!sd_id_to_elements[key]) { 47 | sd_id_to_elements[key] = []; 48 | } 49 | sd_id_to_elements[key].push(label); 50 | 51 | if (groups.indexOf(group) === -1) { 52 | groups.push(group); 53 | // Check if a specific tab has been selected via URL parameter 54 | const tabParam = new URLSearchParams(window.location.search).get( 55 | group 56 | ); 57 | if (tabParam) { 58 | console.log( 59 | "sphinx-design: Selecting tab id for group '" + 60 | group + 61 | "' from URL parameter: " + 62 | tabParam 63 | ); 64 | window.sessionStorage.setItem(storageKeyPrefix + group, tabParam); 65 | } 66 | } 67 | 68 | // Check is a specific tab has been selected previously 69 | let previousId = window.sessionStorage.getItem( 70 | storageKeyPrefix + group 71 | ); 72 | if (previousId === id) { 73 | // console.log( 74 | // "sphinx-design: Selecting tab from session storage: " + id 75 | // ); 76 | // @ts-ignore 77 | label.previousElementSibling.checked = true; 78 | } 79 | } 80 | } 81 | }); 82 | } 83 | 84 | /** 85 | * Activate other tabs with the same sync id. 86 | * 87 | * @this {HTMLElement} - The element that was clicked. 88 | */ 89 | function onSDLabelClick() { 90 | let data = create_key(this); 91 | if (!data) return; 92 | let [group, id, key] = data; 93 | for (const label of sd_id_to_elements[key]) { 94 | if (label === this) continue; 95 | // @ts-ignore 96 | label.previousElementSibling.checked = true; 97 | } 98 | window.sessionStorage.setItem(storageKeyPrefix + group, id); 99 | } 100 | 101 | document.addEventListener("DOMContentLoaded", ready, false); 102 | -------------------------------------------------------------------------------- /docs/html/_static/check-solid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/html/_static/copy-button.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/html/_static/copybutton.css: -------------------------------------------------------------------------------- 1 | /* Copy buttons */ 2 | button.copybtn { 3 | position: absolute; 4 | display: flex; 5 | top: .3em; 6 | right: .3em; 7 | width: 1.7em; 8 | height: 1.7em; 9 | opacity: 0; 10 | transition: opacity 0.3s, border .3s, background-color .3s; 11 | user-select: none; 12 | padding: 0; 13 | border: none; 14 | outline: none; 15 | border-radius: 0.4em; 16 | /* The colors that GitHub uses */ 17 | border: #1b1f2426 1px solid; 18 | background-color: #f6f8fa; 19 | color: #57606a; 20 | } 21 | 22 | button.copybtn.success { 23 | border-color: #22863a; 24 | color: #22863a; 25 | } 26 | 27 | button.copybtn svg { 28 | stroke: currentColor; 29 | width: 1.5em; 30 | height: 1.5em; 31 | padding: 0.1em; 32 | } 33 | 34 | div.highlight { 35 | position: relative; 36 | } 37 | 38 | /* Show the copybutton */ 39 | .highlight:hover button.copybtn, button.copybtn.success { 40 | opacity: 1; 41 | } 42 | 43 | .highlight button.copybtn:hover { 44 | background-color: rgb(235, 235, 235); 45 | } 46 | 47 | .highlight button.copybtn:active { 48 | background-color: rgb(187, 187, 187); 49 | } 50 | 51 | /** 52 | * A minimal CSS-only tooltip copied from: 53 | * https://codepen.io/mildrenben/pen/rVBrpK 54 | * 55 | * To use, write HTML like the following: 56 | * 57 | *

Short

58 | */ 59 | .o-tooltip--left { 60 | position: relative; 61 | } 62 | 63 | .o-tooltip--left:after { 64 | opacity: 0; 65 | visibility: hidden; 66 | position: absolute; 67 | content: attr(data-tooltip); 68 | padding: .2em; 69 | font-size: .8em; 70 | left: -.2em; 71 | background: grey; 72 | color: white; 73 | white-space: nowrap; 74 | z-index: 2; 75 | border-radius: 2px; 76 | transform: translateX(-102%) translateY(0); 77 | transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); 78 | } 79 | 80 | .o-tooltip--left:hover:after { 81 | display: block; 82 | opacity: 1; 83 | visibility: visible; 84 | transform: translateX(-100%) translateY(0); 85 | transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); 86 | transition-delay: .5s; 87 | } 88 | 89 | /* By default the copy button shouldn't show up when printing a page */ 90 | @media print { 91 | button.copybtn { 92 | display: none; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /docs/html/_static/copybutton_funcs.js: -------------------------------------------------------------------------------- 1 | function escapeRegExp(string) { 2 | return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string 3 | } 4 | 5 | /** 6 | * Removes excluded text from a Node. 7 | * 8 | * @param {Node} target Node to filter. 9 | * @param {string} exclude CSS selector of nodes to exclude. 10 | * @returns {DOMString} Text from `target` with text removed. 11 | */ 12 | export function filterText(target, exclude) { 13 | const clone = target.cloneNode(true); // clone as to not modify the live DOM 14 | if (exclude) { 15 | // remove excluded nodes 16 | clone.querySelectorAll(exclude).forEach(node => node.remove()); 17 | } 18 | return clone.innerText; 19 | } 20 | 21 | // Callback when a copy button is clicked. Will be passed the node that was clicked 22 | // should then grab the text and replace pieces of text that shouldn't be used in output 23 | export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { 24 | var regexp; 25 | var match; 26 | 27 | // Do we check for line continuation characters and "HERE-documents"? 28 | var useLineCont = !!lineContinuationChar 29 | var useHereDoc = !!hereDocDelim 30 | 31 | // create regexp to capture prompt and remaining line 32 | if (isRegexp) { 33 | regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') 34 | } else { 35 | regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') 36 | } 37 | 38 | const outputLines = []; 39 | var promptFound = false; 40 | var gotLineCont = false; 41 | var gotHereDoc = false; 42 | const lineGotPrompt = []; 43 | for (const line of textContent.split('\n')) { 44 | match = line.match(regexp) 45 | if (match || gotLineCont || gotHereDoc) { 46 | promptFound = regexp.test(line) 47 | lineGotPrompt.push(promptFound) 48 | if (removePrompts && promptFound) { 49 | outputLines.push(match[2]) 50 | } else { 51 | outputLines.push(line) 52 | } 53 | gotLineCont = line.endsWith(lineContinuationChar) & useLineCont 54 | if (line.includes(hereDocDelim) & useHereDoc) 55 | gotHereDoc = !gotHereDoc 56 | } else if (!onlyCopyPromptLines) { 57 | outputLines.push(line) 58 | } else if (copyEmptyLines && line.trim() === '') { 59 | outputLines.push(line) 60 | } 61 | } 62 | 63 | // If no lines with the prompt were found then just use original lines 64 | if (lineGotPrompt.some(v => v === true)) { 65 | textContent = outputLines.join('\n'); 66 | } 67 | 68 | // Remove a trailing newline to avoid auto-running when pasting 69 | if (textContent.endsWith("\n")) { 70 | textContent = textContent.slice(0, -1) 71 | } 72 | return textContent 73 | } 74 | -------------------------------------------------------------------------------- /docs/html/_static/custom.css: -------------------------------------------------------------------------------- 1 | dl.function { 2 | margin-bottom: 1.25em; 3 | } 4 | 5 | p.breathe-sectiondef-title.rubric { 6 | font-size: x-large; 7 | font-weight: bolder; 8 | line-height: inherit; 9 | text-transform: none; 10 | } 11 | 12 | dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) .field-list > dt { 13 | font-size: var(--font-size--normal); 14 | font-weight: bolder; 15 | text-transform: none 16 | } 17 | -------------------------------------------------------------------------------- /docs/html/_static/debug.css: -------------------------------------------------------------------------------- 1 | /* 2 | This CSS file should be overridden by the theme authors. It's 3 | meant for debugging and developing the skeleton that this theme provides. 4 | */ 5 | body { 6 | font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, 7 | "Apple Color Emoji", "Segoe UI Emoji"; 8 | background: lavender; 9 | } 10 | .sb-announcement { 11 | background: rgb(131, 131, 131); 12 | } 13 | .sb-announcement__inner { 14 | background: black; 15 | color: white; 16 | } 17 | .sb-header { 18 | background: lightskyblue; 19 | } 20 | .sb-header__inner { 21 | background: royalblue; 22 | color: white; 23 | } 24 | .sb-header-secondary { 25 | background: lightcyan; 26 | } 27 | .sb-header-secondary__inner { 28 | background: cornflowerblue; 29 | color: white; 30 | } 31 | .sb-sidebar-primary { 32 | background: lightgreen; 33 | } 34 | .sb-main { 35 | background: blanchedalmond; 36 | } 37 | .sb-main__inner { 38 | background: antiquewhite; 39 | } 40 | .sb-header-article { 41 | background: lightsteelblue; 42 | } 43 | .sb-article-container { 44 | background: snow; 45 | } 46 | .sb-article-main { 47 | background: white; 48 | } 49 | .sb-footer-article { 50 | background: lightpink; 51 | } 52 | .sb-sidebar-secondary { 53 | background: lightgoldenrodyellow; 54 | } 55 | .sb-footer-content { 56 | background: plum; 57 | } 58 | .sb-footer-content__inner { 59 | background: palevioletred; 60 | } 61 | .sb-footer { 62 | background: pink; 63 | } 64 | .sb-footer__inner { 65 | background: salmon; 66 | } 67 | .sb-article { 68 | background: white; 69 | } 70 | -------------------------------------------------------------------------------- /docs/html/_static/design-tabs.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | // Extra JS capability for selected tabs to be synced 4 | // The selection is stored in local storage so that it persists across page loads. 5 | 6 | /** 7 | * @type {Record} 8 | */ 9 | let sd_id_to_elements = {}; 10 | const storageKeyPrefix = "sphinx-design-tab-id-"; 11 | 12 | /** 13 | * Create a key for a tab element. 14 | * @param {HTMLElement} el - The tab element. 15 | * @returns {[string, string, string] | null} - The key. 16 | * 17 | */ 18 | function create_key(el) { 19 | let syncId = el.getAttribute("data-sync-id"); 20 | let syncGroup = el.getAttribute("data-sync-group"); 21 | if (!syncId || !syncGroup) return null; 22 | return [syncGroup, syncId, syncGroup + "--" + syncId]; 23 | } 24 | 25 | /** 26 | * Initialize the tab selection. 27 | * 28 | */ 29 | function ready() { 30 | // Find all tabs with sync data 31 | 32 | /** @type {string[]} */ 33 | let groups = []; 34 | 35 | document.querySelectorAll(".sd-tab-label").forEach((label) => { 36 | if (label instanceof HTMLElement) { 37 | let data = create_key(label); 38 | if (data) { 39 | let [group, id, key] = data; 40 | 41 | // add click event listener 42 | // @ts-ignore 43 | label.onclick = onSDLabelClick; 44 | 45 | // store map of key to elements 46 | if (!sd_id_to_elements[key]) { 47 | sd_id_to_elements[key] = []; 48 | } 49 | sd_id_to_elements[key].push(label); 50 | 51 | if (groups.indexOf(group) === -1) { 52 | groups.push(group); 53 | // Check if a specific tab has been selected via URL parameter 54 | const tabParam = new URLSearchParams(window.location.search).get( 55 | group 56 | ); 57 | if (tabParam) { 58 | console.log( 59 | "sphinx-design: Selecting tab id for group '" + 60 | group + 61 | "' from URL parameter: " + 62 | tabParam 63 | ); 64 | window.sessionStorage.setItem(storageKeyPrefix + group, tabParam); 65 | } 66 | } 67 | 68 | // Check is a specific tab has been selected previously 69 | let previousId = window.sessionStorage.getItem( 70 | storageKeyPrefix + group 71 | ); 72 | if (previousId === id) { 73 | // console.log( 74 | // "sphinx-design: Selecting tab from session storage: " + id 75 | // ); 76 | // @ts-ignore 77 | label.previousElementSibling.checked = true; 78 | } 79 | } 80 | } 81 | }); 82 | } 83 | 84 | /** 85 | * Activate other tabs with the same sync id. 86 | * 87 | * @this {HTMLElement} - The element that was clicked. 88 | */ 89 | function onSDLabelClick() { 90 | let data = create_key(this); 91 | if (!data) return; 92 | let [group, id, key] = data; 93 | for (const label of sd_id_to_elements[key]) { 94 | if (label === this) continue; 95 | // @ts-ignore 96 | label.previousElementSibling.checked = true; 97 | } 98 | window.sessionStorage.setItem(storageKeyPrefix + group, id); 99 | } 100 | 101 | document.addEventListener("DOMContentLoaded", ready, false); 102 | -------------------------------------------------------------------------------- /docs/html/_static/documentation_options.js: -------------------------------------------------------------------------------- 1 | const DOCUMENTATION_OPTIONS = { 2 | VERSION: '0.4.0', 3 | LANGUAGE: 'en', 4 | COLLAPSE_INDEX: false, 5 | BUILDER: 'html', 6 | FILE_SUFFIX: '.html', 7 | LINK_SUFFIX: '.html', 8 | HAS_SOURCE: true, 9 | SOURCELINK_SUFFIX: '.txt', 10 | NAVIGATION_WITH_KEYS: true, 11 | SHOW_SEARCH_SUMMARY: true, 12 | ENABLE_SEARCH_SHORTCUTS: true, 13 | }; -------------------------------------------------------------------------------- /docs/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_static/file.png -------------------------------------------------------------------------------- /docs/html/_static/graphviz.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Sphinx stylesheet -- graphviz extension. 3 | */ 4 | 5 | img.graphviz { 6 | border: 0; 7 | max-width: 100%; 8 | } 9 | 10 | object.graphviz { 11 | max-width: 100%; 12 | } 13 | -------------------------------------------------------------------------------- /docs/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_static/minus.png -------------------------------------------------------------------------------- /docs/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_static/plus.png -------------------------------------------------------------------------------- /docs/html/_static/scripts/furo-extensions.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/_static/scripts/furo-extensions.js -------------------------------------------------------------------------------- /docs/html/_static/scripts/furo.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * gumshoejs v5.1.2 (patched by @pradyunsg) 3 | * A simple, framework-agnostic scrollspy script. 4 | * (c) 2019 Chris Ferdinandi 5 | * MIT License 6 | * http://github.com/cferdinandi/gumshoe 7 | */ 8 | -------------------------------------------------------------------------------- /docs/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/html/objects.inv -------------------------------------------------------------------------------- /docs/mpl_parallel_2018.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rabauke/mpl/80c3305d90e2e3927cee7a8710fd93606d2c8667/docs/mpl_parallel_2018.pdf -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | function(add_mpl_executable TARGET_NAME SOURCES) 2 | add_executable(${TARGET_NAME} ${SOURCES}) 3 | target_compile_options(${TARGET_NAME} PRIVATE 4 | $<$: 5 | -Wall -Wextra -Wpedantic> 6 | $<$,$>: 7 | -Wall -Wextra -Wpedantic -Wno-c++98-compat> 8 | $<$: 9 | -Wall> 10 | $<$: 11 | /permissive- /W4 /WX>) 12 | target_link_libraries(${TARGET_NAME} PRIVATE mpl::mpl) 13 | # add MPL_Debug definition if building in debug mode 14 | target_compile_definitions(${TARGET_NAME} PRIVATE 15 | $<$:MPL_DEBUG>) 16 | endfunction() 17 | 18 | 19 | add_mpl_executable(arrays arrays.cc) 20 | add_mpl_executable(blocking blocking.cc) 21 | add_mpl_executable(blocking_vector blocking_vector.cc) 22 | add_mpl_executable(collective collective.cc) 23 | add_mpl_executable(communicator communicator.cc) 24 | add_mpl_executable(distributed_grid distributed_grid.cc) 25 | add_mpl_executable(distributed_grid_scatter_gather distributed_grid_scatter_gather.cc) 26 | add_mpl_executable(gather gather.cc) 27 | add_mpl_executable(gatherv gatherv.cc) 28 | add_mpl_executable(heat_equation_Jacobi_method heat_equation_Jacobi_method.cc) 29 | add_mpl_executable(heat_equation_successive_over-relaxation heat_equation_successive_over-relaxation.cc) 30 | add_mpl_executable(hello_world hello_world.cc) 31 | add_mpl_executable(custom_initialization custom_initialization.cc) 32 | add_mpl_executable(iterators iterators.cc) 33 | add_mpl_executable(layouts layouts.cc) 34 | add_mpl_executable(matrix_gather matrix_gather.cc) 35 | add_mpl_executable(nonblocking nonblocking.cc) 36 | add_mpl_executable(nonblocking_mult nonblocking_mult.cc) 37 | add_mpl_executable(probe probe.cc) 38 | add_mpl_executable(reduce_lcm reduce_lcm.cc) 39 | add_mpl_executable(reduce_min_loc reduce_min_loc.cc) 40 | add_mpl_executable(stl_container stl_container.cc) 41 | add_mpl_executable(struct struct.cc) 42 | add_mpl_executable(subarray subarray.cc) 43 | add_mpl_executable(vibrating_string_mpl vibrating_string_mpl.cc) 44 | add_mpl_executable(standard_types standard_types.cc) 45 | add_mpl_executable(parallel_sort_mpl parallel_sort_mpl.cc) 46 | add_mpl_executable(intercommunicator intercommunicator.cc) 47 | add_mpl_executable(process_creation process_creation.cc) 48 | add_mpl_executable(process_creation_multiple process_creation_multiple.cc) 49 | add_mpl_executable(process_creation_client process_creation_client.cc) 50 | add_mpl_executable(file file.cc) 51 | 52 | # c only examples 53 | add_executable(vibrating_string_mpi vibrating_string_mpi.c) 54 | target_link_libraries(vibrating_string_mpi PUBLIC m MPI::MPI_C) 55 | add_executable(parallel_sort_mpi parallel_sort_mpi.c) 56 | target_link_libraries(parallel_sort_mpi PUBLIC MPI::MPI_C) 57 | 58 | find_program(PVS_STUDIO pvs-studio) 59 | 60 | if (PVS_STUDIO) 61 | include(../cmake/PVS-Studio.cmake) 62 | pvs_studio_add_target(TARGET PVS-Studio_analyze # ALL 63 | OUTPUT FORMAT errorfile 64 | RECURSIVE ANALYZE 65 | arrays blocking blocking_vector collective communicator distributed_grid 66 | distributed_grid_scatter_gather gather gatherv 67 | heat_equation_Jacobi_method heat_equation_successive_over-relaxation 68 | hello_world iterators layouts matrix_gather nonblocking nonblocking_mult probe reduce_lcm 69 | reduce_min_loc standard_types struct vibrating_string_mpi vibrating_string_mpl parallel_sort_mpl 70 | parallel_sort_mpi 71 | MODE GA:1,2,3 OP LOG target.err) 72 | endif () 73 | -------------------------------------------------------------------------------- /examples/arrays.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | int main() { 8 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 9 | // run the program with two or more processes 10 | if (comm_world.size() < 2) 11 | comm_world.abort(EXIT_FAILURE); 12 | // send / receive a single array 13 | { 14 | const int n{10}; 15 | double arr[n]; 16 | if (comm_world.rank() == 0) { 17 | std::iota(arr, arr + n, 1); 18 | comm_world.send(arr, 1); 19 | } 20 | if (comm_world.rank() == 1) { 21 | comm_world.recv(arr, 0); 22 | for (int j{0}; j < n; ++j) 23 | std::cout << "arr[" << j << "] = " << arr[j] << '\n'; 24 | } 25 | } 26 | // send / receive a single two-dimensional array 27 | { 28 | const int n_0{2}, n_1{3}; 29 | double arr[n_0][n_1]; 30 | if (comm_world.rank() == 0) { 31 | for (int j_1{0}; j_1 < n_1; ++j_1) 32 | for (int j_0{0}; j_0 < n_0; ++j_0) 33 | arr[j_0][j_1] = (j_0 + 1) + 100 * (j_1 + 1); 34 | comm_world.send(arr, 1); 35 | } 36 | if (comm_world.rank() == 1) { 37 | comm_world.recv(arr, 0); 38 | for (int j_1{0}; j_1 < n_1; ++j_1) { 39 | for (int j_0{0}; j_0 < n_0; ++j_0) 40 | std::cout << "arr[" << j_0 << ", " << j_1 << "] = " << arr[j_0][j_1] << '\n'; 41 | } 42 | } 43 | } 44 | return EXIT_SUCCESS; 45 | } 46 | -------------------------------------------------------------------------------- /examples/blocking.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | int main() { 7 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 8 | // run the program with two or more processes 9 | if (comm_world.size() < 2) 10 | return EXIT_FAILURE; 11 | // process 0 sends 12 | enum class tag_enum : short { tag = 1 }; 13 | if (comm_world.rank() == 0) { 14 | // see MPI Standard for the semantics of standard send, buffered send, 15 | // synchronous send and ready send 16 | double x{1.23456}; 17 | comm_world.send(x, 1, tag_enum::tag); // send x to rank 1 via standard send 18 | ++x; 19 | { 20 | // create a buffer for buffered send, 21 | // memory will be freed on leaving the scope 22 | int size{comm_world.bsend_size()}; 23 | mpl::bsend_buffer buff{size}; 24 | comm_world.bsend(x, 1); // send x to rank 1 via buffered send 25 | } 26 | ++x; 27 | comm_world.ssend(x, 1); // send x to rank 1 via synchronous send 28 | ++x; 29 | comm_world.rsend(x, 1); // send x to rank 1 via ready send 30 | } 31 | // process 1 receives 32 | if (comm_world.rank() == 1) { 33 | double x; 34 | comm_world.recv(x, 0, tag_enum::tag); // receive x from rank 0 35 | std::cout << "x = " << x << '\n'; 36 | comm_world.recv(x, 0); // receive x from rank 0 37 | std::cout << "x = " << x << '\n'; 38 | comm_world.recv(x, 0); // receive x from rank 0 39 | std::cout << "x = " << x << '\n'; 40 | comm_world.recv(x, 0); // receive x from rank 0 41 | std::cout << "x = " << x << '\n'; 42 | } 43 | return EXIT_SUCCESS; 44 | } 45 | -------------------------------------------------------------------------------- /examples/blocking_vector.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | template 10 | void print_range(const char *const str, I i_1, I i_2) { 11 | std::cout << str; 12 | while (i_1 != i_2) { 13 | std::cout << (*i_1); 14 | ++i_1; 15 | std::cout << ((i_1 != i_2) ? ' ' : '\n'); 16 | } 17 | } 18 | 19 | 20 | int main() { 21 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 22 | // run the program with two or more processes 23 | if (comm_world.size() < 2) 24 | return EXIT_FAILURE; 25 | const int n{12}; 26 | std::vector v(n); // vector of n elements lying contiguously in memory 27 | mpl::contiguous_layout l(n); // corresponding memory layout 28 | // process 0 sends 29 | if (comm_world.rank() == 0) { 30 | // see MPI Standard for the semantics of standard send, buffered send, 31 | // synchronous send and ready sendG 32 | std::iota(v.begin(), v.end(), 0); // fill vector with some data 33 | auto add_one{[](int x) { return x + 1; }}; 34 | comm_world.send(v.data(), l, 1); // send vector to rank 1 via standard send 35 | std::transform(v.begin(), v.end(), v.begin(), add_one); // update data 36 | { 37 | // create a buffer for buffered send, 38 | // memory will be freed on leaving the scope 39 | const int size{comm_world.bsend_size(l)}; 40 | mpl::bsend_buffer buff{size}; 41 | comm_world.bsend(v.data(), l, 1); // send x to rank 1 via buffered send 42 | } 43 | std::transform(v.begin(), v.end(), v.begin(), add_one); // update data 44 | comm_world.ssend(v.data(), l, 1); // send x to rank 1 via synchronous send 45 | std::transform(v.begin(), v.end(), v.begin(), add_one); // update data 46 | comm_world.rsend(v.data(), l, 1); // send x to rank 1 via ready send 47 | } 48 | // process 1 receives 49 | if (comm_world.rank() == 1) { 50 | comm_world.recv(v.data(), l, 0); // receive vector from rank 0 51 | print_range("v = ", v.begin(), v.end()); 52 | comm_world.recv(v.data(), l, 0); // receive vector from rank 0 53 | print_range("v = ", v.begin(), v.end()); 54 | comm_world.recv(v.data(), l, 0); // receive vector from rank 0 55 | print_range("v = ", v.begin(), v.end()); 56 | comm_world.recv(v.data(), l, 0); // receive vector from rank 0 57 | print_range("v = ", v.begin(), v.end()); 58 | } 59 | return EXIT_SUCCESS; 60 | } 61 | -------------------------------------------------------------------------------- /examples/communicator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | int main() { 7 | // check communicator properties of comm_world 8 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 9 | std::cout << "comm_world rank: " << comm_world.rank() << "\tsize: " << comm_world.size() 10 | << std::endl; 11 | comm_world.barrier(); 12 | // split comm_world into 3 disjoint communicators 13 | // and carry out some collective communication 14 | mpl::communicator comm_3{mpl::communicator::split, comm_world, comm_world.rank() % 3}; 15 | int key; 16 | if (comm_3.rank() == 0) 17 | key = comm_world.rank() % 3; 18 | comm_3.bcast(0, key); 19 | std::cout << "comm_3 rank: " << comm_3.rank() << "\tsize: " << comm_3.size() 20 | << "\tkey: " << key << std::endl; 21 | comm_world.barrier(); 22 | // split comm_world into a communicator which contains all processes 23 | // except rank 0 of comm_world and carry out some collective communication 24 | mpl::communicator comm_without_0(mpl::communicator::split, comm_world, 25 | comm_world.rank() == 0 ? mpl::undefined : 1); 26 | if (comm_world.rank() != 0) { 27 | double data{1}; 28 | comm_without_0.allreduce(mpl::plus(), data); 29 | std::cout << "sum: " << data << std::endl; 30 | } 31 | comm_world.barrier(); 32 | std::cout << "comm_world rank: " << comm_world.rank() 33 | << "\tcomm valid: " << (comm_without_0.is_valid() ? "yes" : "no") << std::endl; 34 | return EXIT_SUCCESS; 35 | } 36 | -------------------------------------------------------------------------------- /examples/custom_initialization.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | // a custom initializer 8 | class my_initializer final { 9 | private: 10 | explicit my_initializer(int *argc, char **argv[]) { 11 | // initialize MPI by calling MPI_Init or MPI_Init_thread 12 | MPI_Init(argc, argv); 13 | } 14 | 15 | ~my_initializer() { 16 | // finalize MPI 17 | MPI_Finalize(); 18 | } 19 | 20 | public: 21 | static void init(int *argc, char **argv[]) { 22 | // variable must be static 23 | static const my_initializer init{argc, argv}; 24 | } 25 | }; 26 | 27 | 28 | int main(int argc, char *argv[]) { 29 | // custom initialization of the MPI environment before any MPL call 30 | my_initializer::init(&argc, &argv); 31 | 32 | // do some MPL operations 33 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 34 | std::cout << "Hello world! I am running on \"" << mpl::environment::processor_name() 35 | << "\". My rank is " << comm_world.rank() << " out of " << comm_world.size() 36 | << " processes.\n"; 37 | if (comm_world.size() >= 2) { 38 | if (comm_world.rank() == 0) { 39 | const std::string message{"Hello world!"}; 40 | comm_world.send(message, 1); 41 | } else if (comm_world.rank() == 1) { 42 | std::string message; 43 | comm_world.recv(message, 0); 44 | std::cout << "got: \"" << message << "\"\n"; 45 | } 46 | } 47 | 48 | // exit the program and implicitly deinitialize MPL first and MPI afterward 49 | return EXIT_SUCCESS; 50 | } 51 | -------------------------------------------------------------------------------- /examples/distributed_grid.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | template 7 | void update_overlap(const mpl::cartesian_communicator &cartesian_communicator, 8 | mpl::distributed_grid &grid, mpl::tag_t tag = mpl::tag_t()) { 9 | for (std::size_t i{0}; i < dim; ++i) { 10 | // send to left 11 | auto [source_l, destination_l] = cartesian_communicator.shift(i, -1); 12 | cartesian_communicator.sendrecv(grid.data(), grid.left_border_layout(i), destination_l, tag, 13 | grid.data(), grid.right_mirror_layout(i), source_l, tag); 14 | // send to right 15 | auto [source_r, destination_r] = cartesian_communicator.shift(i, +1); 16 | cartesian_communicator.sendrecv(grid.data(), grid.right_border_layout(i), destination_r, 17 | tag, grid.data(), grid.left_mirror_layout(i), source_r, 18 | tag); 19 | } 20 | } 21 | 22 | 23 | int main() { 24 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 25 | { 26 | // build a one-dimensional Cartesian communicator 27 | // Cartesian is non-cyclic 28 | mpl::cartesian_communicator::dimensions size{mpl::cartesian_communicator::non_periodic}; 29 | mpl::cartesian_communicator comm_c{comm_world, mpl::dims_create(comm_world.size(), size)}; 30 | // create a distributed grid of 31 total grid points and 2 shadow grid points 31 | // to mirror data between adjacent processes 32 | mpl::distributed_grid<1, int> grid{comm_c, {{31, 2}}}; 33 | // fill local grid including shadow grid points 34 | for (auto i{grid.obegin(0)}, i_end{grid.oend(0)}; i < i_end; ++i) 35 | grid(i) = comm_c.rank(); 36 | // get shadow data from adjacent processes 37 | update_overlap(comm_c, grid); 38 | // print local grid including shadow grid points 39 | for (int k{0}; k < comm_c.size(); ++k) { 40 | if (k == comm_c.rank()) { 41 | for (auto i{grid.obegin(0)}, i_end{grid.oend(0)}; i < i_end; ++i) 42 | std::cout << grid(i); 43 | std::cout << std::endl; 44 | } 45 | comm_c.barrier(); // barrier may avoid overlapping output 46 | } 47 | } 48 | { 49 | // build a two-dimensional Cartesian communicator 50 | // Cartesian is cyclic along 1st dimension, non-cyclic along 2nd dimension 51 | mpl::cartesian_communicator::dimensions size{mpl::cartesian_communicator::periodic, 52 | mpl::cartesian_communicator::non_periodic}; 53 | mpl::cartesian_communicator comm_c{comm_world, mpl::dims_create(comm_world.size(), size)}; 54 | // create a distributed grid of 11x13 total grid points and 2 respectively 1 55 | // shadow grid points to mirror data between adjacent processes 56 | mpl::distributed_grid<2, int> grid{comm_c, {{11, 2}, {13, 1}}}; 57 | // fill local grid including shadow grid points 58 | for (auto j{grid.obegin(1)}, j_end{grid.oend(1)}; j < j_end; ++j) 59 | for (auto i{grid.obegin(0)}, i_end{grid.oend(0)}; i < i_end; ++i) 60 | grid(i, j) = comm_c.rank(); 61 | // get shadow data from adjacent processes 62 | update_overlap(comm_c, grid); 63 | // print local grid including shadow grid points 64 | for (int k{0}; k < comm_c.size(); ++k) { 65 | if (k == comm_c.rank()) { 66 | std::cout << std::endl; 67 | for (auto j{grid.obegin(1)}, j_end{grid.oend(1)}; j < j_end; ++j) { 68 | for (auto i{grid.obegin(0)}, i_end{grid.oend(0)}; i < i_end; ++i) 69 | std::cout << grid(i, j); 70 | std::cout << std::endl; 71 | } 72 | } 73 | comm_c.barrier(); // barrier may avoid overlapping output 74 | } 75 | } 76 | return EXIT_SUCCESS; 77 | } 78 | -------------------------------------------------------------------------------- /examples/distributed_grid_scatter_gather.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | template 7 | void scatter(const mpl::cartesian_communicator &communicator, int root, 8 | const mpl::local_grid &local_grid, 9 | mpl::distributed_grid &distributed_grid) { 10 | communicator.scatterv(root, local_grid.data(), local_grid.sub_layouts(), 11 | distributed_grid.data(), distributed_grid.interior_layout()); 12 | } 13 | 14 | 15 | template 16 | void scatter(const mpl::cartesian_communicator &communicator, int root, 17 | mpl::distributed_grid &distributed_grid) { 18 | communicator.scatterv(root, distributed_grid.data(), distributed_grid.interior_layout()); 19 | } 20 | 21 | 22 | template 23 | void gather(const mpl::cartesian_communicator &communicator, int root, 24 | const mpl::distributed_grid &distributed_grid, 25 | mpl::local_grid &local_grid) { 26 | communicator.gatherv(root, distributed_grid.data(), distributed_grid.interior_layout(), 27 | local_grid.data(), local_grid.sub_layouts()); 28 | } 29 | 30 | 31 | template 32 | void gather(const mpl::cartesian_communicator &communicator, int root, 33 | const mpl::distributed_grid &distributed_grid) { 34 | communicator.gatherv(root, distributed_grid.data(), distributed_grid.interior_layout()); 35 | } 36 | 37 | 38 | int main() { 39 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 40 | mpl::cartesian_communicator::dimensions size{mpl::cartesian_communicator::periodic, 41 | mpl::cartesian_communicator::non_periodic}; 42 | const int nx{21}, ny{13}; 43 | mpl::cartesian_communicator comm_c{comm_world, mpl::dims_create(comm_world.size(), size)}; 44 | mpl::distributed_grid<2, int> grid{comm_c, {{nx, 1}, {ny, 1}}}; 45 | const int c_rank{comm_c.rank()}; 46 | const int c_size{comm_c.size()}; 47 | for (auto j{grid.obegin(1)}, j_end{grid.oend(1)}; j < j_end; ++j) 48 | for (auto i{grid.obegin(0)}, i_end{grid.oend(0)}; i < i_end; ++i) 49 | grid(i, j) = c_rank + 1; 50 | if (comm_world.rank() == 0) { 51 | mpl::local_grid<2, int> local_grid(comm_c, {nx, ny}); 52 | for (auto j{local_grid.begin(1)}, j_end{local_grid.end(1)}; j < j_end; ++j) 53 | for (auto i{local_grid.begin(0)}, i_end{local_grid.end(0)}; i < i_end; ++i) 54 | local_grid(i, j) = 0; 55 | scatter(comm_c, 0, local_grid, grid); 56 | } else 57 | scatter(comm_c, 0, grid); 58 | for (int i{0}; i < c_size; ++i) { 59 | if (i == c_rank) { 60 | std::cout << std::endl; 61 | for (auto j{grid.obegin(1)}, j_end{grid.oend(1)}; j < j_end; ++j) { 62 | for (auto i{grid.obegin(0)}, i_end{grid.oend(0)}; i < i_end; ++i) 63 | std::cout << grid(i, j); 64 | std::cout << std::endl; 65 | } 66 | } 67 | comm_c.barrier(); 68 | } 69 | for (auto j{grid.obegin(1)}, j_end{grid.oend(1)}; j < j_end; ++j) 70 | for (auto i{grid.obegin(0)}, i_end{grid.oend(0)}; i < i_end; ++i) 71 | grid(i, j) = c_rank; 72 | if (comm_world.rank() == 0) { 73 | mpl::local_grid<2, int> local_grid{comm_c, {nx, ny}}; 74 | gather(comm_c, 0, grid, local_grid); 75 | std::cout << std::endl; 76 | for (auto j{local_grid.begin(1)}, j_end{local_grid.end(1)}; j < j_end; ++j) { 77 | for (auto i{grid.begin(0)}, i_end{local_grid.end(0)}; i < i_end; ++i) 78 | std::cout << local_grid(i, j); 79 | std::cout << std::endl; 80 | } 81 | } else 82 | gather(comm_c, 0, grid); 83 | return EXIT_SUCCESS; 84 | } 85 | -------------------------------------------------------------------------------- /examples/file.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | // include MPL header file 7 | #include 8 | 9 | 10 | int main() { 11 | // get a reference to communicator "world" 12 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 13 | // generate some data 14 | using value_type = std::array; 15 | std::vector vec; 16 | for (std::uint8_t i{0}; i < 16; ++i) 17 | vec.push_back( 18 | {static_cast(i + 1), static_cast(comm_world.rank() + 1)}); 19 | // write data into file 20 | try { 21 | // wrap i/o operations in try-catch block, i/o operations may throw 22 | mpl::file file; 23 | // opening a file is collective over all processes within the employed communicator 24 | file.open(comm_world, "test.bin", 25 | mpl::file::access_mode::create | mpl::file::access_mode::read_write); 26 | // set file view 27 | file.set_view("native"); 28 | // write data 29 | mpl::vector_layout write_layout(vec.size()); 30 | file.write_at_all(vec.size() * comm_world.rank(), vec.data(), write_layout); 31 | // close file 32 | file.close(); 33 | } catch (mpl::error &error) { 34 | std::cerr << error.what() << '\n'; 35 | } 36 | return EXIT_SUCCESS; 37 | } 38 | -------------------------------------------------------------------------------- /examples/gather.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | int main() { 8 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 9 | const auto c_rank{comm_world.rank()}; 10 | const auto c_size{comm_world.size()}; 11 | // gather a single int from all ranks to rank root=0 12 | { 13 | int root{0}; 14 | int x{c_rank + 1}; 15 | std::vector y(c_rank == root ? c_size : 0); 16 | comm_world.gather(root, x, y.data()); 17 | if (c_rank == root) { 18 | for (int i{0}; i < c_size; ++i) 19 | std::cout << y[i] << ' '; 20 | std::cout << "\n"; 21 | } 22 | } 23 | // gather a single int from all ranks to rank root=0 24 | // root and non-root rank use different function overloads of gather 25 | { 26 | const int root{0}; 27 | int x{-(c_rank + 1)}; 28 | if (c_rank == root) { 29 | std::vector y(c_size); 30 | comm_world.gather(root, x, y.data()); 31 | for (int i{0}; i < c_size; ++i) 32 | std::cout << y[i] << ' '; 33 | std::cout << "\n"; 34 | } else 35 | comm_world.gather(root, x); 36 | } 37 | // gather several ints from all ranks to rank root=0 38 | { 39 | const int root{0}, n{3}; 40 | std::vector x(n, c_rank + 1); 41 | std::vector y(c_rank == root ? n * c_size : 0); 42 | mpl::contiguous_layout l(n); 43 | comm_world.gather(root, x.data(), l, y.data(), l); 44 | if (c_rank == root) { 45 | for (int i{0}; i < c_size * n; ++i) 46 | std::cout << y[i] << ' '; 47 | std::cout << "\n"; 48 | } 49 | } 50 | return EXIT_SUCCESS; 51 | } 52 | -------------------------------------------------------------------------------- /examples/gatherv.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | int main() { 8 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 9 | const auto c_rank{comm_world.rank()}; 10 | const auto c_size{comm_world.size()}; 11 | // fill vector with C_rank+1 elements, each having the value C_rank+1 12 | std::vector x(c_rank + 1, c_rank + 1); 13 | mpl::contiguous_layout l(c_rank + 1); 14 | // root rank will send and receive in gather operation 15 | if (c_rank == 0) { 16 | // messages of varying size will be received 17 | // need to specify appropriate memory layouts to define how many elements 18 | // will be received and where to store them 19 | mpl::layouts ls; 20 | for (int i{0}; i < c_size; ++i) 21 | // define layout for message to be received from rank i 22 | ls.push_back(mpl::indexed_layout({{ 23 | i + 1, // number of int elements 24 | (i * i + i) / 2 // position of the first element in receive buffer 25 | }})); 26 | std::vector y((c_size * c_size + c_size) / 2); // receive buffer 27 | comm_world.gatherv(0, x.data(), l, y.data(), ls); // receive data 28 | // print data 29 | for (const auto &f : y) 30 | std::cout << f << '\n'; 31 | } else 32 | // non-root ranks just send 33 | comm_world.gatherv(0, x.data(), l); 34 | return EXIT_SUCCESS; 35 | } 36 | -------------------------------------------------------------------------------- /examples/hello_world.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | // include MPL header file 4 | #include 5 | 6 | 7 | int main() { 8 | // get a reference to communicator "world" 9 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 10 | // each process prints a message containing the processor name, the rank 11 | // in communicator world and the size of communicator world 12 | // output may depend on MPI implementation 13 | std::cout << "Hello world! I am running on \"" << mpl::environment::processor_name() 14 | << "\". My rank is " << comm_world.rank() << " out of " << comm_world.size() 15 | << " processes.\n"; 16 | // if there are two or more processes send a message from process 0 to process 1 17 | if (comm_world.size() >= 2) { 18 | if (comm_world.rank() == 0) { 19 | std::string message{"Hello world!"}; 20 | comm_world.send(message, 1); // send message to rank 1 21 | } else if (comm_world.rank() == 1) { 22 | std::string message; 23 | comm_world.recv(message, 0); // receive message from rank 0 24 | std::cout << "got: \"" << message << "\"\n"; 25 | } 26 | } 27 | return EXIT_SUCCESS; 28 | } 29 | -------------------------------------------------------------------------------- /examples/intercommunicator.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | int main() { 8 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 9 | // split communicator comm_world into two groups consisting of processes with odd and even 10 | // rank in comm_world 11 | const int world_rank{comm_world.rank()}; 12 | const int my_group{world_rank % 2}; 13 | mpl::communicator local_communicator{mpl::communicator::split, comm_world, my_group}; 14 | const int local_leader{0}; 15 | const int remote_leader{my_group == 0 ? 1 : 0}; 16 | // comm_world is used as the communicator that can communicate with processes in the local 17 | // group as well as in the remote group 18 | mpl::inter_communicator icom{local_communicator, local_leader, comm_world, remote_leader}; 19 | // gather data from all processes in the remote group 20 | const int send_data{world_rank}; // as an example, send rank in comm_world 21 | std::vector recv_data(icom.remote_size()); 22 | // will receive a set of odd or even numbers 23 | icom.allgather(send_data, recv_data.data()); 24 | // output communicator characteristics and received data 25 | std::stringstream stream; 26 | stream << "inter communicator size: " << icom.size() << ";\t" 27 | << "inter communicator rank: " << icom.rank() << ";\t" 28 | << "inter communicator remote size: " << icom.remote_size() << ";\t" 29 | << "gathered data: "; 30 | for (auto &val : recv_data) 31 | stream << val << ' '; 32 | stream << '\n'; 33 | std::cout << stream.str(); 34 | return EXIT_SUCCESS; 35 | } 36 | -------------------------------------------------------------------------------- /examples/iterators.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | int main() { 12 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 13 | // run the program with two or more processes 14 | if (comm_world.size() < 2) 15 | comm_world.abort(EXIT_FAILURE); 16 | // send / receive a single vector 17 | { 18 | const int n{10}; 19 | std::vector l(n); 20 | if (comm_world.rank() == 0) { 21 | std::iota(begin(l), end(l), 1); 22 | comm_world.send(begin(l), end(l), 1); 23 | } 24 | if (comm_world.rank() == 1) { 25 | comm_world.recv(begin(l), end(l), 0); 26 | std::for_each(begin(l), end(l), [](double x) { std::cout << x << '\n'; }); 27 | } 28 | } 29 | // send / receive a single list 30 | { 31 | const int n{10}; 32 | std::list l(n); 33 | if (comm_world.rank() == 0) { 34 | std::iota(begin(l), end(l), 1); 35 | comm_world.send(begin(l), end(l), 1); 36 | } 37 | if (comm_world.rank() == 1) { 38 | comm_world.recv(begin(l), end(l), 0); 39 | std::for_each(begin(l), end(l), [](double x) { std::cout << x << '\n'; }); 40 | } 41 | } 42 | // send a set / receive an array 43 | { 44 | const int n{10}; 45 | if (comm_world.rank() == 0) { 46 | std::set s; 47 | for (int i{1}; i <= n; ++i) 48 | s.insert(i); 49 | comm_world.send(s.begin(), s.end(), 1); 50 | } 51 | if (comm_world.rank() == 1) { 52 | std::array l; 53 | comm_world.recv(begin(l), end(l), 0); 54 | std::for_each(begin(l), end(l), [](double x) { std::cout << x << '\n'; }); 55 | } 56 | } 57 | return EXIT_SUCCESS; 58 | } 59 | -------------------------------------------------------------------------------- /examples/nonblocking_mult.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | int main() { 8 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 9 | double x{1.23456 + comm_world.rank()}; 10 | mpl::irequest r_send(comm_world.isend(x, 0)); // nonblocking send to rank 0 11 | // rank 0 receives data from all ranks 12 | if (comm_world.rank() == 0) { 13 | std::vector v(comm_world.size()); 14 | mpl::irequest_pool r_pool; 15 | for (int i{0}; i < comm_world.size(); ++i) 16 | r_pool.push(comm_world.irecv(v[i], i)); 17 | r_pool.waitall(); // wait to finish all receive operations 18 | for (int i{0}; i < comm_world.size(); ++i) 19 | std::cout << i << '\t' << v[i] << '\n'; 20 | } 21 | r_send.wait(); // wait to finish send operation 22 | return EXIT_SUCCESS; 23 | } 24 | -------------------------------------------------------------------------------- /examples/parallel_sort_mpl.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | static std::random_device rd; 9 | static std::mt19937_64 mt(rd()); 10 | 11 | 12 | double get_random() { 13 | std::uniform_real_distribution dist(0, 1); 14 | return dist(mt); 15 | } 16 | 17 | 18 | void fill_random(std::vector &v) { 19 | std::generate(std::begin(v), std::end(v), get_random); 20 | } 21 | 22 | 23 | // parallel sort algorithm for distributed memory computers 24 | // 25 | // algorithm works as follows: 26 | // 1) each process draws (size-1) random samples from its local data 27 | // 2) all processes gather local random samples => size*(size-1) samples 28 | // 3) size*(size-1) samples are sorted locally 29 | // 4) pick (size-1) pivot elements from the globally sorted sample 30 | // 5) partition local data with respect to the pivot elements into size bins 31 | // 6) redistribute data such that data in bin i goes to process with rank i 32 | // 7) sort redistributed data locally 33 | // 34 | // Note that the amount of data at each process changes during the algorithm. 35 | // In worst case, a single process may hold finally all data. 36 | // 37 | template 38 | void parallel_sort(std::vector &v) { 39 | auto &comm_world{mpl::environment::comm_world()}; 40 | const int rank{comm_world.rank()}; 41 | const int size{comm_world.size()}; 42 | std::vector local_pivots, pivots(size * (size - 1)); 43 | std::sample(begin(v), end(v), std::back_inserter(local_pivots), size - 1, mt); 44 | comm_world.allgather(local_pivots.data(), mpl::vector_layout(size - 1), pivots.data(), 45 | mpl::vector_layout(size - 1)); 46 | std::sort(begin(pivots), end(pivots)); 47 | local_pivots.clear(); 48 | for (std::size_t i{1}; i < static_cast(size); ++i) 49 | local_pivots.push_back(pivots[i * (size - 1)]); 50 | swap(local_pivots, pivots); 51 | std::vector::iterator> pivot_pos; 52 | pivot_pos.push_back(begin(v)); 53 | for (T p : pivots) 54 | pivot_pos.push_back(std::partition(pivot_pos.back(), end(v), [p](T x) { return x < p; })); 55 | pivot_pos.push_back(end(v)); 56 | std::vector local_block_sizes, block_sizes(size * size); 57 | for (std::size_t i{0}; i < pivot_pos.size() - 1; ++i) 58 | local_block_sizes.push_back( 59 | static_cast(std::distance(pivot_pos[i], pivot_pos[i + 1]))); 60 | comm_world.allgather(local_block_sizes.data(), mpl::vector_layout(size), 61 | block_sizes.data(), mpl::vector_layout(size)); 62 | mpl::layouts send_layouts, recv_layouts; 63 | int send_pos{0}, recv_pos{0}; 64 | for (int i{0}; i < size; ++i) { 65 | send_layouts.push_back(mpl::indexed_layout({{block_sizes[rank * size + i], send_pos}})); 66 | send_pos += block_sizes[rank * size + i]; 67 | recv_layouts.push_back(mpl::indexed_layout({{block_sizes[rank + size * i], recv_pos}})); 68 | recv_pos += block_sizes[rank + size * i]; 69 | } 70 | std::vector v_2(recv_pos); 71 | comm_world.alltoallv(v.data(), send_layouts, v_2.data(), recv_layouts); 72 | std::sort(begin(v_2), end(v_2)); 73 | swap(v, v_2); 74 | } 75 | 76 | 77 | int main() { 78 | const auto &comm_world{mpl::environment::comm_world()}; 79 | const int size{comm_world.size()}; 80 | 81 | const std::size_t N{100000000 / static_cast(size)}; 82 | std::vector v(N); 83 | fill_random(v); 84 | parallel_sort(v); 85 | return EXIT_SUCCESS; 86 | } 87 | -------------------------------------------------------------------------------- /examples/probe.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | template 9 | void print_range(const char *const str, I i_1, I i_2) { 10 | std::cout << str; 11 | while (i_1 != i_2) { 12 | std::cout << (*i_1); 13 | ++i_1; 14 | std::cout << ((i_1 != i_2) ? ' ' : '\n'); 15 | } 16 | } 17 | 18 | 19 | int main() { 20 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 21 | // run the program with two or more processes 22 | if (comm_world.size() < 2) 23 | return EXIT_FAILURE; 24 | if (comm_world.rank() == 0) { 25 | // send a message of n elements to rank 1 26 | enum class tag { send = 29 }; 27 | const int n{12}; 28 | std::vector v(n); 29 | mpl::contiguous_layout l(n); 30 | std::iota(v.begin(), v.end(), 0); 31 | comm_world.send(v.data(), l, 1, tag::send); 32 | } 33 | if (comm_world.rank() == 1) { 34 | // receive a message of an a priori unknown number of elements from rank 0 35 | // first probe for a message from some arbitrary rank with any tag 36 | mpl::status_t s(comm_world.probe(mpl::any_source, mpl::tag_t::any())); 37 | // decode the number of elements, the source and the tag 38 | const int n{s.get_count()}, source{s.source()}; 39 | const mpl::tag_t tag(s.tag()); 40 | std::cerr << "source : " << s.source() << '\n' 41 | << "tag : " << s.tag() << '\n' 42 | << "error : " << s.error() << '\n' 43 | << "count : " << n << '\n'; 44 | // reserve sufficient amount of memory to receive the message 45 | std::vector v(n); 46 | mpl::contiguous_layout l(n); 47 | // finally, receive the message 48 | comm_world.recv(v.data(), l, source, tag); 49 | print_range("v = ", v.begin(), v.end()); 50 | } 51 | return EXIT_SUCCESS; 52 | } 53 | -------------------------------------------------------------------------------- /examples/process_creation.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | // include MPL header file 4 | #include 5 | 6 | 7 | int main() { 8 | using namespace std::string_literals; 9 | // get a reference to communicator "world" 10 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 11 | // spawn 2 new processes 12 | mpl::info info; 13 | info.set("host", "localhost"); 14 | auto inter_comm{comm_world.spawn(0, 2, {"./process_creation_client"s}, info)}; 15 | // broadcast a message to the created processes 16 | double message; 17 | if (comm_world.rank() == 0) { 18 | // root rank 19 | message = 1.23; 20 | inter_comm.bcast(mpl::root, message); 21 | } else 22 | // non-root ranks 23 | inter_comm.bcast(mpl::proc_null, message); 24 | 25 | return EXIT_SUCCESS; 26 | } 27 | -------------------------------------------------------------------------------- /examples/process_creation_client.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | // include MPL header file 4 | #include 5 | 6 | 7 | int main(int argc, char *argv[]) { 8 | using namespace std::string_literals; 9 | 10 | // get a reference to communicator "world" 11 | [[maybe_unused]] const mpl::communicator &comm_world{mpl::environment::comm_world()}; 12 | // get the parent inter-communicator 13 | auto &inter_comm{mpl::inter_communicator::parent()}; 14 | std::cout << "Hello world! I am running on \"" << mpl::environment::processor_name() 15 | << "\". My rank is " << inter_comm.rank() << " out of " << inter_comm.size() 16 | << " processes.\n"; 17 | std::cout << "commandline arguments: "; 18 | for (int i{0}; i < argc; ++i) 19 | std::cout << argv[i] << ' '; 20 | std::cout << std::endl; 21 | double message; 22 | inter_comm.bcast(0, message); 23 | std::cout << "got: " << message << '\n'; 24 | return EXIT_SUCCESS; 25 | } 26 | -------------------------------------------------------------------------------- /examples/process_creation_multiple.cc: -------------------------------------------------------------------------------- 1 | #include 2 | // include MPL header file 3 | #include 4 | 5 | 6 | int main() { 7 | using namespace std::string_literals; 8 | // get a reference to communicator "world" 9 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 10 | // spawn 2 new processes 11 | mpl::info info; 12 | info.set("host", "localhost"); 13 | auto inter_comm{ 14 | comm_world.spawn_multiple(0, 15 | {{"./process_creation_client"s, "arg1"s}, 16 | {"./process_creation_client"s, "arg1"s, "arg2"s}, 17 | {"./process_creation_client"s, "arg1"s, "arg2"s, "arg3"s}}, 18 | {info, info, info})}; 19 | // broadcast a message to the created processes 20 | double message; 21 | if (comm_world.rank() == 0) { 22 | // root rank 23 | message = 1.23; 24 | inter_comm.bcast(mpl::root, message); 25 | } else 26 | // non-root ranks 27 | inter_comm.bcast(mpl::proc_null, message); 28 | 29 | return EXIT_SUCCESS; 30 | } 31 | -------------------------------------------------------------------------------- /examples/reduce_lcm.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | // calculate the least common multiple of two arguments 11 | template 12 | class lcm { 13 | // helper: calculate greatest common divisor 14 | T gcd(T a, T b) { 15 | constexpr T zero{}; 16 | if (a < zero) 17 | a = -a; 18 | if (b < zero) 19 | b = -b; 20 | while (b > zero) { 21 | const T t{a % b}; 22 | a = b; 23 | b = t; 24 | } 25 | return a; 26 | } 27 | 28 | public: 29 | T operator()(T a, T b) { 30 | constexpr T zero{}; 31 | const T t{(a / gcd(a, b)) * b}; 32 | if (t < zero) 33 | return -t; 34 | return t; 35 | } 36 | }; 37 | 38 | 39 | int main() { 40 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 41 | // generate data 42 | std::mt19937_64 g(std::time(nullptr) * comm_world.rank()); // random seed 43 | std::uniform_int_distribution uniform{1, 12}; 44 | const int n{8}; 45 | // populate vector with random data 46 | std::vector v(n); 47 | std::generate(v.begin(), v.end(), [&g, &uniform]() { return uniform(g); }); 48 | // calculate the least common multiple and send result to rank 0 49 | mpl::contiguous_layout layout(n); 50 | if (comm_world.rank() == 0) { 51 | std::vector result(n); 52 | // calculate the least common multiple 53 | comm_world.reduce(lcm(), 0, v.data(), result.data(), layout); 54 | // to check the result display data from all ranks 55 | std::cout << "Arguments:\n"; 56 | for (int r{0}; r < comm_world.size(); ++r) { 57 | if (r > 0) 58 | comm_world.recv(v.data(), layout, r); 59 | for (auto i : v) 60 | std::cout << i << '\t'; 61 | std::cout << '\n'; 62 | } 63 | // display results of global reduction 64 | std::cout << "\nResults:\n"; 65 | for (auto i : result) 66 | std::cout << i << '\t'; 67 | std::cout << '\n'; 68 | } else { 69 | // calculate the least common multiple 70 | comm_world.reduce(lcm(), 0, v.data(), layout); 71 | // send data to rank 0 for display 72 | comm_world.send(v.data(), layout, 0); 73 | } 74 | return EXIT_SUCCESS; 75 | } 76 | -------------------------------------------------------------------------------- /examples/reduce_min_loc.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | // data type to store the data and the position of the global minimum 12 | using pair_t = std::pair; 13 | 14 | 15 | int main() { 16 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 17 | // generate data 18 | std::mt19937_64 g(std::time(nullptr) * comm_world.rank()); // random seed 19 | std::uniform_real_distribution<> uniform; 20 | const int n{8}; 21 | // populate vector with random data 22 | std::vector v(n); 23 | std::generate(v.begin(), v.end(), [&comm_world, &g, &uniform]() { 24 | return std::make_pair(uniform(g), comm_world.rank()); 25 | }); 26 | // calculate minimum and its location and send result to rank root 27 | const int root{0}; 28 | mpl::contiguous_layout layout(n); 29 | if (comm_world.rank() == root) { 30 | std::vector result(n); 31 | // calculate minimum 32 | comm_world.reduce(mpl::min(), root, v.data(), result.data(), layout); 33 | // display data from all ranks 34 | std::cout << "arguments:\n"; 35 | for (int r{0}; r < comm_world.size(); ++r) { 36 | if (r > 0) 37 | comm_world.recv(v.data(), layout, r); 38 | for (auto i : v) 39 | std::cout << std::fixed << std::setprecision(5) << i.first << ' ' << i.second << '\t'; 40 | std::cout << '\n'; 41 | } 42 | // display results of global reduction 43 | std::cout << "\nresults:\n"; 44 | for (const pair_t &i : result) 45 | std::cout << std::fixed << std::setprecision(5) << i.first << ' ' << i.second << '\t'; 46 | std::cout << '\n'; 47 | } else { 48 | // calculate minimum and its location and send result to rank 0 49 | comm_world.reduce(mpl::min(), root, v.data(), layout); 50 | // send data to rank 0 for display 51 | comm_world.send(v.data(), layout, root); 52 | } 53 | return EXIT_SUCCESS; 54 | } 55 | -------------------------------------------------------------------------------- /examples/struct.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | // some structures 9 | struct structure { 10 | double d{0}; 11 | int i[9]{0, 0, 0, 0, 0, 0, 0, 0, 0}; 12 | }; 13 | 14 | 15 | // print elements of structure 16 | template 17 | std::basic_ostream &operator<<(std::basic_ostream &out, const structure &s) { 18 | out << '(' << s.d << ",[" << s.i[0]; 19 | for (std::size_t i{1}; i < std::size(s.i); ++i) 20 | out << ',' << s.i[i]; 21 | return out << "])"; 22 | } 23 | 24 | 25 | struct structure_2 { 26 | double d{0}; 27 | structure str; 28 | }; 29 | 30 | 31 | // print elements of structure2 32 | template 33 | std::basic_ostream &operator<<(std::basic_ostream &out, const structure_2 &s) { 34 | return out << '(' << s.d << "," << s.str << ")"; 35 | } 36 | 37 | 38 | // specialize trait template class struct_builder 39 | // for the structures defined above 40 | namespace mpl { 41 | 42 | template<> 43 | class struct_builder : public base_struct_builder { 44 | struct_layout layout; 45 | 46 | public: 47 | struct_builder() { 48 | structure str; 49 | layout.register_struct(str); 50 | // register each element of struct structure 51 | layout.register_element(str.d); 52 | layout.register_element(str.i); 53 | // finalize 54 | define_struct(layout); 55 | } 56 | }; 57 | 58 | } // namespace mpl 59 | 60 | 61 | // MPL_REFLECTION is a convenient macro which creates the required 62 | // specialization of the struct_builder template automatically. Just 63 | // pass the class name and the public members as arguments to the 64 | // macro. MPL_REFLECTION is limited to 120 class members. 65 | MPL_REFLECTION(structure_2, d, str) 66 | 67 | 68 | int main() { 69 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 70 | // run the program with two or more processes 71 | if (comm_world.size() < 2) 72 | comm_world.abort(EXIT_FAILURE); 73 | // send / receive a single structure 74 | structure str; 75 | if (comm_world.rank() == 0) { 76 | str.d = 1; 77 | std::iota(str.i, str.i + 9, 1); 78 | comm_world.send(str, 1); 79 | } 80 | if (comm_world.rank() == 1) { 81 | comm_world.recv(str, 0); 82 | std::cout << str << '\n'; 83 | } 84 | // send / receive a single structure containing another structure 85 | structure_2 str2; 86 | if (comm_world.rank() == 0) { 87 | str2.d = 1; 88 | str2.str.d = 1; 89 | std::iota(str2.str.i, str2.str.i + 9, 1); 90 | comm_world.send(str2, 1); 91 | } 92 | if (comm_world.rank() == 1) { 93 | comm_world.recv(str2, 0); 94 | std::cout << str2 << '\n'; 95 | } 96 | // send / receive a vector of structures 97 | const int field_size{8}; 98 | std::vector str_field(field_size); 99 | mpl::contiguous_layout str_field_layout(field_size); 100 | if (comm_world.rank() == 0) { 101 | // populate vector of structures 102 | for (int k{0}; k < field_size; ++k) { 103 | str_field[k].d = k + 1; 104 | std::iota(str_field[k].i, str_field[k].i + 9, 1 + k); 105 | } 106 | // send vector of structures 107 | comm_world.send(str_field.data(), str_field_layout, 1); 108 | } 109 | if (comm_world.rank() == 1) { 110 | // receive vector of structures 111 | comm_world.recv(str_field.data(), str_field_layout, 0); 112 | for (int k{0}; k < field_size; ++k) 113 | std::cout << str_field[k] << '\n'; 114 | } 115 | 116 | return EXIT_SUCCESS; 117 | } 118 | -------------------------------------------------------------------------------- /examples/subarray.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | int main() { 8 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 9 | // run the program with two or more processes 10 | if (comm_world.size() < 2) 11 | return EXIT_FAILURE; 12 | // test layout for a subarray 13 | // layouts on sending and receiving side may differ but must be compatible 14 | const int n_0{20}, n_1{8}; // size of two-dimensional array 15 | const int s_0{11}, s_1{3}; // size of two-dimensional subarray 16 | // process 0 sends 17 | if (comm_world.rank() == 0) { 18 | // C order matrix with two-dimensional C arrays 19 | double a[n_1][n_0]; 20 | for (int i_1{0}; i_1 < n_1; ++i_1) 21 | for (int i_0{0}; i_0 < n_0; ++i_0) 22 | a[i_1][i_0] = i_0 + 0.01 * i_1; 23 | mpl::subarray_layout subarray{{ 24 | {n_1, s_1, 2}, // 2nd dimension: size of array, size of subarray, start of subarray 25 | {n_0, s_0, 4} // 1st dimension: size of array, size of subarray, start of subarray 26 | }}; 27 | comm_world.send(&a[0][0], subarray, 1); 28 | } 29 | // process 1 receives 30 | if (comm_world.rank() == 1) { 31 | double a[s_1][s_0]; 32 | mpl::contiguous_layout array{s_0 * s_1}; 33 | comm_world.recv(&a[0][0], array, 0); 34 | for (int i_1{0}; i_1 < s_1; ++i_1) { 35 | for (int i_0{0}; i_0 < s_0; ++i_0) 36 | std::cout << std::fixed << std::setprecision(2) << a[i_1][i_0] << " "; 37 | std::cout << '\n'; 38 | } 39 | } 40 | return EXIT_SUCCESS; 41 | } 42 | -------------------------------------------------------------------------------- /mpl/command_line.hpp: -------------------------------------------------------------------------------- 1 | #if !(defined MPL_COMMANDLINE_HPP) 2 | 3 | #define MPL_COMMANDLINE_HPP 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | namespace mpl { 12 | 13 | /// Represents a set of command-line arguments. 14 | /// \see class \c communicator::spawn 15 | class command_line : private std::vector { 16 | using base = std::vector; 17 | 18 | public: 19 | using base::size_type; 20 | using base::value_type; 21 | using base::iterator; 22 | using base::const_iterator; 23 | 24 | /// Constructs an empty set of command-line arguments. 25 | explicit command_line() = default; 26 | 27 | /// Constructs set of command-line arguments from a braces expression of strings. 28 | /// \param init list of initial values 29 | command_line(std::initializer_list init) : base(init) { 30 | } 31 | 32 | /// Constructs set of command-line arguments from another set. 33 | /// \param other the other set to copy from 34 | command_line(const command_line &other) = default; 35 | 36 | /// Move-constructs set of command-line arguments from another set. 37 | /// \param other the other set to move from 38 | command_line(command_line &&other) noexcept : base(std::move(other)) { 39 | } 40 | 41 | using base::operator=; 42 | using base::begin; 43 | using base::end; 44 | using base::cbegin; 45 | using base::cend; 46 | using base::operator[]; 47 | using base::size; 48 | using base::push_back; 49 | }; 50 | 51 | /// Represents a list of command-line argument sets. 52 | /// \see class \c communicator::spawn_multiple 53 | class command_lines : private std::vector { 54 | using base = std::vector; 55 | 56 | public: 57 | using base::size_type; 58 | using base::value_type; 59 | using base::iterator; 60 | using base::const_iterator; 61 | 62 | /// Constructs an empty list of command-line argument sets. 63 | command_lines() = default; 64 | 65 | /// Constructs list of command-line argument sets from a braces expression of strings. 66 | /// \param init list of initial values 67 | command_lines(std::initializer_list init) : base(init) { 68 | } 69 | 70 | /// Constructs list of command-line argument sets from another list. 71 | /// \param other the other list to copy from 72 | command_lines(const command_lines &other) = default; 73 | 74 | /// Move-constructs list of command-line argument sets from another list. 75 | /// \param other the other list to move from 76 | command_lines(command_lines &&other) noexcept : base(std::move(other)) { 77 | } 78 | 79 | using base::operator=; 80 | using base::begin; 81 | using base::end; 82 | using base::cbegin; 83 | using base::cend; 84 | using base::operator[]; 85 | using base::size; 86 | using base::push_back; 87 | }; 88 | 89 | } // namespace mpl 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /mpl/displacements.hpp: -------------------------------------------------------------------------------- 1 | #if !(defined MPL_DISPLACEMENTS_HPP) 2 | 3 | #define MPL_DISPLACEMENTS_HPP 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace mpl { 11 | 12 | /// Set of %displacements indicates the beginning of data buffers in various collective 13 | /// communication operations. 14 | /// \note Individual %displacements are always given in bytes. 15 | class displacements : private std::vector { 16 | using base = std::vector; 17 | 18 | public: 19 | using size_type = base::size_type; 20 | using value_type = base::value_type; 21 | using base::iterator; 22 | using base::const_iterator; 23 | 24 | /// Constructs a set of displacements with displacement zero. 25 | /// \param n number of displacements 26 | explicit displacements(size_type n = 0) : base(n, 0) { 27 | } 28 | 29 | /// Constructs a set of displacements with given displacements. 30 | /// \param init initial displacements 31 | explicit displacements(std::initializer_list init) : base(init) { 32 | } 33 | 34 | /// Copy constructor. 35 | /// \param other the other set of displacements to copy from 36 | displacements(const displacements &other) = default; 37 | /// Move constructor. 38 | /// \param other the other set of displacements to move from 39 | displacements(displacements &&other) = default; 40 | 41 | using base::operator=; 42 | using base::begin; 43 | using base::end; 44 | using base::cbegin; 45 | using base::cend; 46 | using base::operator[]; 47 | using base::size; 48 | using base::push_back; 49 | using base::resize; 50 | 51 | /// Get raw displacement data. 52 | /// \return pointer to the array of displacements 53 | const MPI_Aint *operator()() const { 54 | return base::data(); 55 | } 56 | }; 57 | 58 | } // namespace mpl 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /mpl/error.hpp: -------------------------------------------------------------------------------- 1 | #if !(defined MPL_ERROR_HPP) 2 | 3 | #define MPL_ERROR_HPP 4 | 5 | #include 6 | 7 | 8 | namespace mpl { 9 | 10 | /// Base class for all MPL exception classes that will be thrown in case of run-time errors. 11 | class error : public ::std::exception { 12 | private: 13 | const char *const messsage_; 14 | 15 | public: 16 | /// \param message error message that will be returned by #what method 17 | explicit error(const char *const message = "unknown") : messsage_{message} { 18 | } 19 | 20 | /// \return character pointer to error message 21 | [[nodiscard]] const char *what() const noexcept override { 22 | return messsage_; 23 | } 24 | }; 25 | 26 | /// Will be thrown in case of invalid rank argument. 27 | class invalid_rank : public error { 28 | public: 29 | invalid_rank() : error{"invalid rank"} { 30 | } 31 | }; 32 | 33 | /// Will be thrown in case of invalid tag argument. 34 | class invalid_tag : public error { 35 | public: 36 | invalid_tag() : error{"invalid tag"} { 37 | } 38 | }; 39 | 40 | /// Will be thrown in case of invalid size argument. 41 | class invalid_size : public error { 42 | public: 43 | invalid_size() : error{"invalid size"} { 44 | } 45 | }; 46 | 47 | /// Will be thrown in case of invalid count argument. 48 | class invalid_count : public error { 49 | public: 50 | invalid_count() : error{"invalid count"} { 51 | } 52 | }; 53 | 54 | /// Will be thrown in case of invalid count argument. 55 | class invalid_displacement : public error { 56 | public: 57 | invalid_displacement() : error{"invalid displacement"} { 58 | } 59 | }; 60 | 61 | /// Will be thrown in case of invalid layout argument. 62 | class invalid_layout : public error { 63 | public: 64 | invalid_layout() : error{"invalid layout"} { 65 | } 66 | }; 67 | 68 | /// Will be thrown in case of invalid dimension. 69 | class invalid_dim : public error { 70 | public: 71 | invalid_dim() : error{"invalid dimension"} { 72 | } 73 | }; 74 | 75 | /// Will be thrown when an error occurs while manipulating layouts. 76 | class invalid_datatype_bound : public error { 77 | public: 78 | invalid_datatype_bound() : error{"invalid datatype bound"} { 79 | } 80 | }; 81 | 82 | /// Will be thrown in case of invalid arguments. 83 | class invalid_argument : public error { 84 | public: 85 | invalid_argument() : error{"invalid argument"} { 86 | } 87 | }; 88 | 89 | /// Will be thrown in case of file-related io errors. 90 | class io_failure : public error { 91 | char message_[MPI_MAX_ERROR_STRING + 1]{}; 92 | 93 | public: 94 | explicit io_failure(int code) { 95 | int len{0}; 96 | MPI_Error_string(code, message_, &len); 97 | message_[len] = '\0'; 98 | } 99 | 100 | /// \return character pointer to error message 101 | [[nodiscard]] const char *what() const noexcept override { 102 | return message_; 103 | } 104 | }; 105 | 106 | } // namespace mpl 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /mpl/message.hpp: -------------------------------------------------------------------------------- 1 | #if !(defined MPL_MESSAGE_HPP) 2 | 3 | #define MPL_MESSAGE_HPP 4 | 5 | #include 6 | 7 | 8 | namespace mpl { 9 | 10 | /// Status of a received message. 11 | using message_t = MPI_Message; 12 | 13 | } // namespace mpl 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /mpl/mpl.hpp: -------------------------------------------------------------------------------- 1 | #if !(defined MPL_HPP) 2 | 3 | #define MPL_HPP 4 | 5 | #include 6 | #include 7 | 8 | 9 | namespace mpl { 10 | 11 | /// Wildcard value to indicate in a receive operation, e.g., \c communicator::recv, that any 12 | /// source is acceptable. 13 | /// \see \c tag_t::any 14 | constexpr int any_source = MPI_ANY_SOURCE; 15 | 16 | /// Special value that can be used instead of a rank wherever a source or a destination 17 | /// argument is required in a call to indicate that the communication shall have no effect. 18 | constexpr int proc_null = MPI_PROC_NULL; 19 | 20 | /// Special value that is used to indicate an invalid return value or function 21 | /// parameter in some functions. 22 | constexpr int undefined = MPI_UNDEFINED; 23 | 24 | /// Special value to indicate the root process in some inter-communicator collective 25 | /// operations. 26 | constexpr int root = MPI_ROOT; 27 | 28 | /// Special constant to indicate the start of the address range of message buffers. 29 | /// \anchor absolute 30 | constexpr void *absolute = MPI_BOTTOM; 31 | 32 | /// Special constant representing an upper bound on the additional space consumed when 33 | /// buffering messages. 34 | /// \see \c communicator::bsend 35 | /// \anchor bsend_overhead 36 | constexpr int bsend_overhead = MPI_BSEND_OVERHEAD; 37 | 38 | /// Unsigned integer type used for array indexing and address arithmetic. 39 | using size_t = std::size_t; 40 | 41 | /// Signed integer type used for array indexing and address arithmetic. 42 | using ssize_t = std::ptrdiff_t; 43 | 44 | } // namespace mpl 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /mpl/ranks.hpp: -------------------------------------------------------------------------------- 1 | #if !(defined MPL_RANKS_HPP) 2 | 3 | #define MPL_RANKS_HPP 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace mpl { 11 | 12 | /// Represents a collection of ranks. 13 | /// \see class \c group 14 | class ranks : private std::vector { 15 | using base = std::vector; 16 | 17 | public: 18 | using base::size_type; 19 | using base::value_type; 20 | using base::iterator; 21 | using base::const_iterator; 22 | 23 | /// Constructs collection of ranks with all ranks having value zero. 24 | /// \param n initial size of the collection 25 | explicit ranks(size_type n = 0) : base(n, 0) { 26 | } 27 | 28 | /// Constructs collection of ranks from a braces expression of integers. 29 | /// \param init list of initial values 30 | ranks(std::initializer_list init) : base(init) { 31 | } 32 | 33 | /// Constructs collection of ranks from another collection. 34 | /// \param other the other collection to copy from 35 | ranks(const ranks &other) = default; 36 | 37 | /// Move-constructs collection of ranks from another collection. 38 | /// \param other the other collection to move from 39 | ranks(ranks &&other) noexcept : base(std::move(other)) { 40 | } 41 | 42 | using base::operator=; 43 | using base::begin; 44 | using base::end; 45 | using base::cbegin; 46 | using base::cend; 47 | using base::operator[]; 48 | using base::size; 49 | using base::push_back; 50 | 51 | /// Gives access to internal data. 52 | /// \return pointer to constant array 53 | [[nodiscard]] const int *operator()() const { 54 | return base::data(); 55 | } 56 | 57 | /// Gives access to internal data. 58 | /// \return pointer to array 59 | [[nodiscard]] int *operator()() { 60 | return base::data(); 61 | } 62 | }; 63 | 64 | } // namespace mpl 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /mpl/status.hpp: -------------------------------------------------------------------------------- 1 | #if !(defined MPL_STATUS_HPP) 2 | 3 | #define MPL_STATUS_HPP 4 | 5 | #include 6 | 7 | 8 | namespace mpl { 9 | 10 | namespace impl { 11 | 12 | class base_communicator; 13 | 14 | template 15 | class base_request; 16 | 17 | template 18 | class request_pool; 19 | 20 | } // namespace impl 21 | 22 | //-------------------------------------------------------------------------------------------- 23 | 24 | /// Class that represents the status of a received message. 25 | class status_t : private MPI_Status { 26 | public: 27 | /// \return source of the message 28 | [[nodiscard]] int source() const { 29 | return MPI_Status::MPI_SOURCE; 30 | } 31 | 32 | /// \return tag value of the message 33 | [[nodiscard]] mpl::tag_t tag() const { 34 | return mpl::tag_t(MPI_Status::MPI_TAG); 35 | } 36 | 37 | /// \return error code associated with the message 38 | [[nodiscard]] int error() const { 39 | return MPI_Status::MPI_ERROR; 40 | } 41 | 42 | /// \return true if associated request has been canceled 43 | [[nodiscard]] bool is_cancelled() const { 44 | int result; 45 | MPI_Test_cancelled(static_cast(this), &result); 46 | return result != 0; 47 | } 48 | 49 | /// \return true if associated request has been canceled 50 | [[nodiscard]] bool is_canceled() const { 51 | return is_cancelled(); 52 | } 53 | 54 | /// \tparam T received data type 55 | /// \return number of top level elements of type \c T received in associated message 56 | template 57 | [[nodiscard]] int get_count() const { 58 | int result; 59 | MPI_Get_count(static_cast(this), 60 | detail::datatype_traits::get_datatype(), &result); 61 | return result; 62 | } 63 | 64 | /// \tparam T received data type 65 | /// \param l layout used in associated message 66 | /// \return number of top level elements of type \c T received in associated message 67 | template 68 | [[nodiscard]] int get_count(const layout &l) const { 69 | int result; 70 | MPI_Get_count(static_cast(this), 71 | detail::datatype_traits>::get_datatype(l), &result); 72 | return result; 73 | } 74 | 75 | /// default constructor initializes source and tag with wildcards given by 76 | /// \ref any_source and \c tag_t::any and no error 77 | status_t() : MPI_Status{} { 78 | MPI_Status::MPI_SOURCE = MPI_ANY_SOURCE; 79 | MPI_Status::MPI_TAG = MPI_ANY_TAG; 80 | MPI_Status::MPI_ERROR = MPI_SUCCESS; 81 | } 82 | 83 | friend class impl::base_communicator; 84 | template 85 | friend class impl::base_request; 86 | template 87 | friend class impl::request_pool; 88 | friend class file; 89 | }; 90 | 91 | static_assert(sizeof(MPI_Status) == sizeof(status_t)); 92 | 93 | } // namespace mpl 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /mpl/tag.hpp: -------------------------------------------------------------------------------- 1 | #if !(defined MPL_TAG_HPP) 2 | 3 | #define MPL_TAG_HPP 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace mpl { 11 | 12 | /// Class for representing tag parameters in communication operations. 13 | class tag_t { 14 | private: 15 | int t{0}; 16 | 17 | public: 18 | /// Copy-constructor. 19 | /// \param t tag value 20 | tag_t(const tag_t &t) = default; 21 | 22 | /// Initializes tag from an integer value. 23 | /// \param t tag value 24 | explicit tag_t(int t = 0) : t{t} { 25 | } 26 | 27 | /// Initializes tag from an enum value. The enum's underlying type must be convertible to 28 | /// int without loss of precession (narrowing). 29 | /// \param t tag value 30 | template 31 | tag_t(T t) : t{static_cast(t)} { 32 | static_assert(detail::is_valid_tag_v, 33 | "not an enumeration type or underlying enumeration type too large"); 34 | } 35 | 36 | /// Copy-assignmnet operator. 37 | /// \param t tag value 38 | tag_t &operator=(const tag_t &t) = default; 39 | 40 | /// \return tag value as integer 41 | explicit operator int() const { 42 | return t; 43 | } 44 | 45 | /// \return tag with the largest value when converted to int 46 | static inline tag_t up(); 47 | 48 | /// \return wildcard tag to be used in receive operations, e.g., \c communicator::recv, to 49 | /// indicate acceptance of a message with any tag value 50 | /// \see \c any_source 51 | static inline tag_t any(); 52 | }; 53 | 54 | /// \param t1 first tag to compare 55 | /// \param t2 second tag to compare 56 | /// \return true if both tags are convertible to the same int value 57 | inline bool operator==(tag_t t1, tag_t t2) { 58 | return static_cast(t1) == static_cast(t2); 59 | } 60 | 61 | /// \param t1 first tag to compare 62 | /// \param t2 second tag to compare 63 | /// \return true if both tags are not convertible to the same int value 64 | inline bool operator!=(tag_t t1, tag_t t2) { 65 | return static_cast(t1) != static_cast(t2); 66 | } 67 | 68 | /// Write tag into output stream in numerical representation. 69 | /// \param os output stream 70 | /// \param t tag to write into stream 71 | /// \return output stream 72 | template 73 | std::basic_ostream &operator<<(std::basic_ostream &os, 74 | tag_t t) { 75 | return os << static_cast(t); 76 | } 77 | 78 | /// Read tag given in numerical representation from input stream. 79 | /// \param is input stream 80 | /// \param t tag to read from stream 81 | /// \return input stream 82 | template 83 | std::basic_istream &operator>>(std::basic_istream &is, 84 | tag_t &t) { 85 | int t_; 86 | is >> t_; 87 | if (is) 88 | t = tag_t(t_); 89 | return is; 90 | } 91 | 92 | } // namespace mpl 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /mpl/vector.hpp: -------------------------------------------------------------------------------- 1 | #if !(defined MPL_VECTOR_HPP) 2 | 3 | #define MPL_VECTOR_HPP 4 | 5 | #include 6 | #include 7 | 8 | 9 | namespace mpl::detail { 10 | 11 | struct uninitialized {}; 12 | 13 | template 14 | class vector { 15 | public: 16 | using value_type = T; 17 | using pointer = T *; 18 | using const_pointer = const T *; 19 | using reference = T &; 20 | using const_reference = const T &; 21 | using iterator = T *; 22 | using const_iterator = const T *; 23 | using size_type = std::size_t; 24 | 25 | private: 26 | size_type size_{0}; 27 | T *data_{nullptr}; 28 | 29 | public: 30 | explicit vector(size_type size) 31 | : size_{size}, data_{static_cast(operator new(size_ * sizeof(T)))} { 32 | for (size_type i{0}; i < size; ++i) 33 | new (&data_[i]) value_type(); 34 | } 35 | 36 | explicit vector(size_type size, uninitialized) 37 | : size_{size}, 38 | data_{static_cast(operator new(size_ * sizeof(T), 39 | std::align_val_t{alignof(T)}))} { 40 | if (not std::is_trivially_copyable::value) 41 | for (size_type i{0}; i < size; ++i) 42 | new (&data_[i]) value_type(); 43 | } 44 | 45 | template 46 | explicit vector(size_type size, IterT iter) 47 | : size_{size}, 48 | data_{static_cast(operator new(size_ * sizeof(T), 49 | std::align_val_t{alignof(T)}))} { 50 | for (size_type i{0}; i < size; ++i) { 51 | new (&data_[i]) value_type(*iter); 52 | ++iter; 53 | } 54 | } 55 | 56 | vector(const vector &) = delete; 57 | vector &operator=(const vector &) = delete; 58 | 59 | [[nodiscard]] size_type size() const { 60 | return size_; 61 | } 62 | 63 | [[nodiscard]] bool empty() const { 64 | return size_ == 0; 65 | } 66 | 67 | pointer data() { 68 | return data_; 69 | } 70 | 71 | const_pointer data() const { 72 | return data_; 73 | } 74 | 75 | reference operator[](size_type i) { 76 | return data_[i]; 77 | } 78 | const_reference operator[](size_type i) const { 79 | return data_[i]; 80 | } 81 | 82 | iterator begin() { 83 | return data_; 84 | } 85 | 86 | const_iterator begin() const { 87 | return data_; 88 | } 89 | 90 | iterator end() { 91 | return data_ + size_; 92 | } 93 | 94 | const_iterator end() const { 95 | return data_ + size_; 96 | } 97 | 98 | ~vector() { 99 | for (auto &val : *this) 100 | val.~T(); 101 | operator delete(data_); 102 | } 103 | }; 104 | 105 | } // namespace mpl::detail 106 | 107 | #endif // MPL_VECTOR_HPP 108 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(POLICY CMP0167) 2 | # The FindBoost module is removed. Boost 1.70.0 and later provide a 3 | # BoostConfig.cmake package configuration file. 4 | find_package(Boost 1.70.0 COMPONENTS unit_test_framework CONFIG REQUIRED) 5 | else() 6 | # Use build-in FindBoost module. 7 | find_package(Boost COMPONENTS unit_test_framework REQUIRED) 8 | endif() 9 | 10 | function(add_test_executable TARGET_NAME SOURCES) 11 | add_executable(${TARGET_NAME} ${SOURCES}) 12 | target_compile_options(${TARGET_NAME} PRIVATE 13 | $<$: 14 | -Wall -Wextra -Wpedantic> 15 | $<$,$>: 16 | -Wall -Wextra -Wpedantic -Wno-c++98-compat> 17 | $<$: 18 | -Wall> 19 | $<$: 20 | /permissive- /W4 /WX>) 21 | target_link_libraries(${TARGET_NAME} PRIVATE mpl::mpl Boost::unit_test_framework) 22 | add_test(NAME ${TARGET_NAME} COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} ${MPIEXEC_PREFLAGS} ./${TARGET_NAME} ${MPIEXEC_POSTFLAGS}) 23 | endfunction() 24 | 25 | add_test_executable(test_group test_group.cc) 26 | add_test_executable(test_communicator test_communicator.cc) 27 | add_test_executable(test_initialization test_initialization.cc) 28 | add_test_executable(test_cartesian_communicator test_cartesian_communicator.cc) 29 | add_test_executable(test_graph_communicator test_graph_communicator.cc) 30 | add_test_executable(test_dist_graph_communicator test_dist_graph_communicator.cc) 31 | add_test_executable(test_communicator_send_recv test_communicator_send_recv.cc) 32 | add_test_executable(test_communicator_isend_irecv test_communicator_isend_irecv.cc test_helper.hpp) 33 | add_test_executable(test_communicator_init_send_init_recv test_communicator_init_send_init_recv.cc test_helper.hpp) 34 | add_test_executable(test_communicator_sendrecv test_communicator_sendrecv.cc test_helper.hpp) 35 | add_test_executable(test_communicator_probe test_communicator_probe.cc test_helper.hpp) 36 | add_test_executable(test_communicator_mprobe_mrecv test_communicator_mprobe_mrecv.cc test_helper.hpp) 37 | add_test_executable(test_communicator_barrier test_communicator_barrier.cc) 38 | add_test_executable(test_communicator_bcast test_communicator_bcast.cc) 39 | add_test_executable(test_communicator_gather test_communicator_gather.cc) 40 | add_test_executable(test_communicator_gatherv test_communicator_gatherv.cc) 41 | add_test_executable(test_communicator_allgather test_communicator_allgather.cc) 42 | add_test_executable(test_communicator_allgatherv test_communicator_allgatherv.cc) 43 | add_test_executable(test_communicator_scatter test_communicator_scatter.cc) 44 | add_test_executable(test_communicator_scatterv test_communicator_scatterv.cc) 45 | add_test_executable(test_communicator_alltoall test_communicator_alltoall.cc) 46 | add_test_executable(test_communicator_alltoallv test_communicator_alltoallv.cc) 47 | add_test_executable(test_communicator_reduce test_communicator_reduce.cc) 48 | add_test_executable(test_communicator_allreduce test_communicator_allreduce.cc) 49 | add_test_executable(test_communicator_reduce_scatter_block test_communicator_reduce_scatter_block.cc) 50 | add_test_executable(test_communicator_reduce_scatter test_communicator_reduce_scatter.cc) 51 | add_test_executable(test_communicator_scan test_communicator_scan.cc) 52 | add_test_executable(test_communicator_exscan test_communicator_exscan.cc) 53 | add_test_executable(test_displacements test_displacements.cc) 54 | add_test_executable(test_inter_communicator test_inter_communicator.cc) 55 | add_test_executable(test_info test_info.cc) 56 | add_test_executable(test_file test_file.cc) 57 | add_test_executable(test_mpi_communicator test_mpi_communicator.cc) 58 | -------------------------------------------------------------------------------- /test/test_communicator_allgather.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE communicator_allgather 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | template 11 | bool allgather_test(const T &val) { 12 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 13 | std::vector v(comm_world.size()); 14 | comm_world.allgather(val, v.data()); 15 | return std::all_of(v.begin(), v.end(), [&val](const auto &x) { return x == val; }); 16 | } 17 | 18 | 19 | template 20 | bool iallgather_test(const T &val) { 21 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 22 | std::vector v(comm_world.size()); 23 | auto r{comm_world.iallgather(val, v.data())}; 24 | r.wait(); 25 | return std::all_of(v.begin(), v.end(), [&val](const auto &x) { return x == val; }); 26 | } 27 | 28 | 29 | BOOST_AUTO_TEST_CASE(allgather) { 30 | BOOST_TEST(allgather_test(1.0)); 31 | BOOST_TEST(allgather_test(std::array{1, 2, 3, 4})); 32 | 33 | BOOST_TEST(iallgather_test(1.0)); 34 | BOOST_TEST(iallgather_test(std::array{1, 2, 3, 4})); 35 | } 36 | -------------------------------------------------------------------------------- /test/test_communicator_barrier.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE communicator_barrier 2 | 3 | #include 4 | #include 5 | 6 | 7 | bool barrier_test() { 8 | const mpl::communicator &comm_world = mpl::environment::comm_world(); 9 | comm_world.barrier(); 10 | return true; 11 | } 12 | 13 | 14 | bool ibarrier_test() { 15 | const mpl::communicator &comm_world = mpl::environment::comm_world(); 16 | auto r{comm_world.ibarrier()}; 17 | r.wait(); 18 | return true; 19 | } 20 | 21 | 22 | BOOST_AUTO_TEST_CASE(barrier) { 23 | BOOST_TEST(barrier_test()); 24 | BOOST_TEST(ibarrier_test()); 25 | } 26 | -------------------------------------------------------------------------------- /test/test_communicator_bcast.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE communicator_bcast 2 | 3 | #include 4 | #include 5 | 6 | 7 | template 8 | bool bcast_test(const T &val) { 9 | const mpl::communicator &comm_world = mpl::environment::comm_world(); 10 | T x{}; 11 | if (comm_world.rank() == 0) 12 | x = val; 13 | comm_world.bcast(0, x); 14 | return x == val; 15 | } 16 | 17 | 18 | template 19 | bool bcast_test(const std::vector &send, const std::vector &expected, 20 | const mpl::layout &l) { 21 | const mpl::communicator &comm_world = mpl::environment::comm_world(); 22 | std::vector x(send.size(), {}); 23 | if (comm_world.rank() == 0) 24 | x = send; 25 | comm_world.bcast(0, x.data(), l); 26 | if (comm_world.rank() == 0) 27 | return x == send; 28 | else 29 | return x == expected; 30 | } 31 | 32 | 33 | template 34 | bool ibcast_test(const T &val) { 35 | const mpl::communicator &comm_world = mpl::environment::comm_world(); 36 | T x{}; 37 | if (comm_world.rank() == 0) 38 | x = val; 39 | auto r{comm_world.ibcast(0, x)}; 40 | r.wait(); 41 | return x == val; 42 | } 43 | 44 | 45 | template 46 | bool ibcast_test(const std::vector &send, const std::vector &expected, 47 | const mpl::layout &l) { 48 | const mpl::communicator &comm_world = mpl::environment::comm_world(); 49 | std::vector x(send.size(), {}); 50 | if (comm_world.rank() == 0) 51 | x = send; 52 | auto r{comm_world.ibcast(0, x.data(), l)}; 53 | r.wait(); 54 | if (comm_world.rank() == 0) 55 | return x == send; 56 | else 57 | return x == expected; 58 | } 59 | 60 | 61 | BOOST_AUTO_TEST_CASE(bcast) { 62 | BOOST_TEST(bcast_test(1.0)); 63 | BOOST_TEST(bcast_test(std::array{1, 2, 3, 4})); 64 | BOOST_TEST(bcast_test(std::vector{1, 2, 3, 4, 5, 6}, std::vector{0, 2, 3, 0, 5, 0}, 65 | mpl::indexed_layout{{{2, 1}, {1, 4}}})); 66 | 67 | BOOST_TEST(ibcast_test(1.0)); 68 | BOOST_TEST(ibcast_test(std::array{1, 2, 3, 4})); 69 | BOOST_TEST(ibcast_test(std::vector{1, 2, 3, 4, 5, 6}, std::vector{0, 2, 3, 0, 5, 0}, 70 | mpl::indexed_layout{{{2, 1}, {1, 4}}})); 71 | } 72 | -------------------------------------------------------------------------------- /test/test_communicator_gather.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE communicator_gather 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | template 9 | bool gather_test(const T &val) { 10 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 11 | if (comm_world.rank() == 0) { 12 | std::vector v(comm_world.size()); 13 | comm_world.gather(0, val, v.data()); 14 | std::vector v_expected; 15 | for (int i{0}; i < comm_world.size(); ++i) 16 | v_expected.push_back(val); 17 | return v == v_expected; 18 | } else { 19 | comm_world.gather(0, val); 20 | return true; 21 | } 22 | } 23 | 24 | 25 | template 26 | bool gather_test(const std::vector &send, const std::vector &expected, 27 | const mpl::layout &l) { 28 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 29 | if (comm_world.rank() == 0) { 30 | std::vector v(comm_world.size() * send.size()); 31 | comm_world.gather(0, send.data(), l, v.data(), l); 32 | std::vector v_expected; 33 | for (int i{0}; i < comm_world.size(); ++i) 34 | std::copy(expected.begin(), expected.end(), std::back_inserter(v_expected)); 35 | return v == v_expected; 36 | } else { 37 | comm_world.gather(0, send.data(), l); 38 | return true; 39 | } 40 | } 41 | 42 | 43 | template 44 | bool igather_test(const T &val) { 45 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 46 | if (comm_world.rank() == 0) { 47 | std::vector v(comm_world.size()); 48 | auto r{comm_world.igather(0, val, v.data())}; 49 | std::vector v_expected; 50 | for (int i{0}; i < comm_world.size(); ++i) 51 | v_expected.push_back(val); 52 | r.wait(); 53 | return v == v_expected; 54 | } else { 55 | auto r{comm_world.igather(0, val)}; 56 | r.wait(); 57 | return true; 58 | } 59 | } 60 | 61 | 62 | template 63 | bool igather_test(const std::vector &send, const std::vector &expected, 64 | const mpl::layout &l) { 65 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 66 | if (comm_world.rank() == 0) { 67 | std::vector v(comm_world.size() * send.size()); 68 | auto r{comm_world.igather(0, send.data(), l, v.data(), l)}; 69 | std::vector v_expected; 70 | for (int i{0}; i < comm_world.size(); ++i) 71 | std::copy(expected.begin(), expected.end(), std::back_inserter(v_expected)); 72 | r.wait(); 73 | return v == v_expected; 74 | } else { 75 | auto r{comm_world.igather(0, send.data(), l)}; 76 | r.wait(); 77 | return true; 78 | } 79 | } 80 | 81 | 82 | BOOST_AUTO_TEST_CASE(gather) { 83 | BOOST_TEST(gather_test(1.0)); 84 | BOOST_TEST(gather_test(std::array{1, 2, 3, 4})); 85 | { 86 | const std::vector send{1, 2, 3, 4, 5, 6}; 87 | const std::vector expected{0, 2, 3, 0, 5, 0}; 88 | mpl::indexed_layout l{{{2, 1}, {1, 4}}}; 89 | l.resize(0, 6); 90 | BOOST_TEST(gather_test(send, expected, l)); 91 | } 92 | 93 | BOOST_TEST(igather_test(1.0)); 94 | BOOST_TEST(igather_test(std::array{1, 2, 3, 4})); 95 | { 96 | const std::vector send{1, 2, 3, 4, 5, 6}; 97 | const std::vector expected{0, 2, 3, 0, 5, 0}; 98 | mpl::indexed_layout l{{{2, 1}, {1, 4}}}; 99 | l.resize(0, 6); 100 | BOOST_TEST(igather_test(send, expected, l)); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /test/test_communicator_reduce_scatter.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE communicator_reduce_scatter 2 | 3 | #include 4 | #include 5 | #include "test_helper.hpp" 6 | 7 | 8 | template 9 | bool reduce_scatter_test(F f, const T &val) { 10 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 11 | T x{val}; 12 | std::vector v_x; 13 | mpl::contiguous_layouts l; 14 | for (int i{0}; i < comm_world.size(); ++i) { 15 | const int block_size{i + 1}; 16 | for (int j{0}; j < block_size; ++j) 17 | v_x.push_back(x); 18 | l.push_back(mpl::contiguous_layout(block_size)); 19 | ++x; 20 | } 21 | const int block_size{comm_world.rank() + 1}; 22 | std::vector v_y(block_size); 23 | comm_world.reduce_scatter(f, v_x.data(), v_y.data(), l); 24 | x = val; 25 | for (int i{0}; i < comm_world.rank(); ++i) 26 | ++x; 27 | T expected{x}; 28 | for (int i{1}; i < comm_world.size(); ++i) 29 | expected = f(expected, x); 30 | std::vector v_expected(block_size, expected); 31 | return v_y == v_expected; 32 | } 33 | 34 | 35 | template 36 | bool ireduce_scatter_test(F f, const T &val) { 37 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 38 | T x{val}; 39 | std::vector v_x; 40 | mpl::contiguous_layouts l; 41 | for (int i{0}; i < comm_world.size(); ++i) { 42 | const int block_size{i + 1}; 43 | for (int j{0}; j < block_size; ++j) 44 | v_x.push_back(x); 45 | l.push_back(mpl::contiguous_layout(block_size)); 46 | ++x; 47 | } 48 | const int block_size{comm_world.rank() + 1}; 49 | std::vector v_y(block_size); 50 | auto r{comm_world.ireduce_scatter(f, v_x.data(), v_y.data(), l)}; 51 | x = val; 52 | for (int i{0}; i < comm_world.rank(); ++i) 53 | ++x; 54 | T expected{x}; 55 | for (int i{1}; i < comm_world.size(); ++i) 56 | expected = f(expected, x); 57 | std::vector v_expected(block_size, expected); 58 | r.wait(); 59 | return v_y == v_expected; 60 | } 61 | 62 | 63 | BOOST_AUTO_TEST_CASE(reduce_scatter) { 64 | BOOST_TEST(reduce_scatter_test(add(), 1.0)); 65 | BOOST_TEST(reduce_scatter_test(add(), tuple{1, 2.0})); 66 | BOOST_TEST(reduce_scatter_test(mpl::plus(), 1.0)); 67 | BOOST_TEST(reduce_scatter_test(mpl::plus(), tuple{1, 2.0})); 68 | BOOST_TEST(reduce_scatter_test([](auto a, auto b) { return a + b; }, 1.0)); 69 | BOOST_TEST(reduce_scatter_test([](auto a, auto b) { return a + b; }, tuple{1, 2.0})); 70 | 71 | BOOST_TEST(ireduce_scatter_test(add(), 1.0)); 72 | BOOST_TEST(ireduce_scatter_test(add(), tuple{1, 2.0})); 73 | BOOST_TEST(ireduce_scatter_test(mpl::plus(), 1.0)); 74 | BOOST_TEST(ireduce_scatter_test(mpl::plus(), tuple{1, 2.0})); 75 | BOOST_TEST(ireduce_scatter_test([](auto a, auto b) { return a + b; }, 1.0)); 76 | BOOST_TEST(ireduce_scatter_test([](auto a, auto b) { return a + b; }, tuple{1, 2.0})); 77 | } 78 | -------------------------------------------------------------------------------- /test/test_communicator_scatter.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE communicator_scatter 2 | 3 | #include 4 | #include 5 | 6 | 7 | template 8 | bool scatter_test(const T &val) { 9 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 10 | T recv; 11 | if (comm_world.rank() == 0) { 12 | std::vector v(comm_world.size(), val); 13 | comm_world.scatter(0, v.data(), recv); 14 | } else { 15 | comm_world.scatter(0, recv); 16 | } 17 | return recv == val; 18 | } 19 | 20 | 21 | template 22 | bool scatter_test(const std::vector &send, const std::vector &expected, 23 | const mpl::layout &l) { 24 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 25 | std::vector recv(send.size()); 26 | if (comm_world.rank() == 0) { 27 | std::vector v_send; 28 | for (int i{0}; i < comm_world.size(); ++i) 29 | std::copy(send.begin(), send.end(), std::back_inserter(v_send)); 30 | comm_world.scatter(0, v_send.data(), l, recv.data(), l); 31 | } else { 32 | comm_world.scatter(0, recv.data(), l); 33 | } 34 | return recv == expected; 35 | } 36 | 37 | 38 | template 39 | bool iscatter_test(const T &val) { 40 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 41 | T recv; 42 | if (comm_world.rank() == 0) { 43 | std::vector v(comm_world.size(), val); 44 | auto r{comm_world.iscatter(0, v.data(), recv)}; 45 | r.wait(); 46 | } else { 47 | auto r{comm_world.iscatter(0, recv)}; 48 | r.wait(); 49 | } 50 | return recv == val; 51 | } 52 | 53 | 54 | template 55 | bool iscatter_test(const std::vector &send, const std::vector &expected, 56 | const mpl::layout &l) { 57 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 58 | std::vector recv(send.size()); 59 | if (comm_world.rank() == 0) { 60 | std::vector v_send; 61 | for (int i{0}; i < comm_world.size(); ++i) 62 | std::copy(send.begin(), send.end(), std::back_inserter(v_send)); 63 | auto r{comm_world.iscatter(0, v_send.data(), l, recv.data(), l)}; 64 | r.wait(); 65 | } else { 66 | auto r{comm_world.iscatter(0, recv.data(), l)}; 67 | r.wait(); 68 | } 69 | return recv == expected; 70 | } 71 | 72 | 73 | BOOST_AUTO_TEST_CASE(scatter) { 74 | BOOST_TEST(scatter_test(1.0)); 75 | BOOST_TEST(scatter_test(std::array{1, 2, 3, 4})); 76 | { 77 | const std::vector send{1, 2, 3, 4, 5, 6}; 78 | const std::vector expected{0, 2, 3, 0, 5, 0}; 79 | mpl::indexed_layout l{{{2, 1}, {1, 4}}}; 80 | l.resize(0, 6); 81 | BOOST_TEST(scatter_test(send, expected, l)); 82 | } 83 | 84 | BOOST_TEST(iscatter_test(1.0)); 85 | BOOST_TEST(iscatter_test(std::array{1, 2, 3, 4})); 86 | { 87 | const std::vector send{1, 2, 3, 4, 5, 6}; 88 | const std::vector expected{0, 2, 3, 0, 5, 0}; 89 | mpl::indexed_layout l{{{2, 1}, {1, 4}}}; 90 | l.resize(0, 6); 91 | BOOST_TEST(iscatter_test(send, expected, l)); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /test/test_displacements.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE displacements 2 | 3 | #include 4 | #include 5 | 6 | 7 | BOOST_AUTO_TEST_CASE(displacements) { 8 | mpl::displacements displacements_1(10); 9 | mpl::displacements displacements_2{1, 2, 3}; 10 | displacements_2.push_back(10); 11 | BOOST_TEST(displacements_1.size() == 10); 12 | BOOST_TEST(displacements_2.size() == 4); 13 | } 14 | -------------------------------------------------------------------------------- /test/test_dist_graph_communicator.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE dist_graph_communicator 2 | 3 | #include 4 | #include 5 | 6 | 7 | bool dist_graph_communicator_test() { 8 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 9 | const int size{comm_world.size()}; 10 | const int rank{comm_world.rank()}; 11 | mpl::distributed_graph_communicator::neighbours_set sources; 12 | mpl::distributed_graph_communicator::neighbours_set destination; 13 | if (rank == 0) { 14 | for (int i{1}; i < size; ++i) { 15 | sources.add(i); 16 | destination.add({i, 0}); 17 | } 18 | } else { 19 | sources.add(0); 20 | destination.add({0, 0}); 21 | } 22 | mpl::distributed_graph_communicator comm_g(comm_world, sources, destination); 23 | if (rank == 0) { 24 | if (comm_g.in_degree() != comm_g.size() - 1) 25 | return false; 26 | if (comm_g.out_degree() != comm_g.size() - 1) 27 | return false; 28 | } else { 29 | if (comm_g.in_degree() != 1) 30 | return false; 31 | if (comm_g.out_degree() != 1) 32 | return false; 33 | } 34 | return true; 35 | } 36 | 37 | 38 | BOOST_AUTO_TEST_CASE(dist_graph_communicator) { 39 | BOOST_TEST(dist_graph_communicator_test()); 40 | } 41 | -------------------------------------------------------------------------------- /test/test_graph_communicator.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE graph_communicator 2 | 3 | #include 4 | #include 5 | 6 | 7 | bool graph_communicator_test() { 8 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 9 | const int size{comm_world.size()}; 10 | mpl::graph_communicator::edge_set es; 11 | for (int i{1}; i < size; ++i) { 12 | es.add({0, i}); 13 | es.add({i, 0}); 14 | } 15 | mpl::graph_communicator comm_g(comm_world, es); 16 | if (comm_g.degree(0) != comm_g.size() - 1) 17 | return false; 18 | const auto nl_0{comm_g.neighbors(0)}; 19 | if (nl_0.size() != comm_g.size() - 1) 20 | return false; 21 | const auto nl_1{comm_g.neighbors(1)}; 22 | if (nl_1.size() != 1) 23 | return false; 24 | return true; 25 | } 26 | 27 | 28 | bool graph_communicator_test_2() { 29 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 30 | const int size{comm_world.size()}; 31 | const int rank{comm_world.rank()}; 32 | if (size >= 4) { 33 | mpl::communicator communicator_4{mpl::communicator::split, comm_world, rank < 4 ? 0 : rank}; 34 | if (communicator_4.size() < 4) 35 | return true; 36 | mpl::graph_communicator::edge_set es{{0, 1}, {0, 3}, {1, 0}, {2, 3}, {3, 0}, {3, 2}}; 37 | mpl::graph_communicator comm_g(communicator_4, es); 38 | if (comm_g.degree(0) != 2) 39 | return false; 40 | if (comm_g.degree(1) != 1) 41 | return false; 42 | if (comm_g.degree(2) != 1) 43 | return false; 44 | if (comm_g.degree(3) != 2) 45 | return false; 46 | if (comm_g.neighbors(0) != mpl::graph_communicator::node_list{1, 3}) 47 | return false; 48 | if (comm_g.neighbors(1) != mpl::graph_communicator::node_list{0}) 49 | return false; 50 | if (comm_g.neighbors(2) != mpl::graph_communicator::node_list{3}) 51 | return false; 52 | if (comm_g.neighbors(3) != mpl::graph_communicator::node_list{0, 2}) 53 | return false; 54 | } 55 | return true; 56 | } 57 | 58 | 59 | BOOST_AUTO_TEST_CASE(graph_communicator) { 60 | BOOST_TEST(graph_communicator_test()); 61 | BOOST_TEST(graph_communicator_test_2()); 62 | } 63 | -------------------------------------------------------------------------------- /test/test_group.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE group 2 | 3 | #include 4 | #include 5 | 6 | 7 | BOOST_AUTO_TEST_CASE(group) { 8 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 9 | const mpl::communicator &comm_self{mpl::environment::comm_self()}; 10 | 11 | mpl::group group_world{comm_world}; 12 | mpl::group group_self{comm_self}; 13 | 14 | BOOST_TEST((group_world.size() == comm_world.size())); 15 | BOOST_TEST((group_world.rank() == comm_world.rank())); 16 | BOOST_TEST((group_self.size() == comm_self.size())); 17 | 18 | mpl::group group_world_copy{group_world}; 19 | BOOST_TEST((group_world == group_world_copy)); 20 | 21 | if (comm_world.size() > 1) 22 | BOOST_TEST((group_world != group_self)); 23 | else 24 | BOOST_TEST((group_world == group_self)); 25 | if (comm_world.size() > 1) 26 | BOOST_TEST((group_world.compare(group_self) == mpl::group::unequal)); 27 | else 28 | BOOST_TEST((group_world.compare(group_self) == mpl::group::identical)); 29 | 30 | BOOST_TEST((group_self.translate(0, group_world) == group_world.rank())); 31 | 32 | mpl::group group_union(mpl::group::Union, group_world, group_self); 33 | mpl::group group_intersection(mpl::group::intersection, group_world, group_self); 34 | mpl::group group_difference(mpl::group::difference, group_world, group_self); 35 | mpl::group group_with_0(mpl::group::include, group_world, {0}); 36 | mpl::group group_without_0(mpl::group::exclude, group_world, {0}); 37 | 38 | BOOST_TEST((group_union.size() == group_world.size())); 39 | BOOST_TEST((group_intersection.size() == 1)); 40 | BOOST_TEST((group_difference.size() == group_world.size() - 1)); 41 | BOOST_TEST((group_with_0.size() == 1)); 42 | BOOST_TEST((group_without_0.size() == group_world.size() - 1)); 43 | } 44 | -------------------------------------------------------------------------------- /test/test_helper.hpp: -------------------------------------------------------------------------------- 1 | #if !(defined MPL_TEST_HELPER_HPP) 2 | #define MPL_TEST_HELPER_HPP 3 | 4 | #include 5 | #include 6 | 7 | 8 | template 9 | struct has_size : std::false_type {}; 10 | 11 | template 12 | struct has_size> : std::true_type {}; 13 | 14 | 15 | template 16 | struct has_resize : std::false_type {}; 17 | 18 | template 19 | struct has_resize> : std::true_type {}; 20 | 21 | 22 | template 23 | struct has_begin_end : std::false_type {}; 24 | 25 | template 26 | struct has_begin_end< 27 | T, std::void_t>> 28 | : std::true_type {}; 29 | 30 | 31 | struct tuple { 32 | int a{0}; 33 | double b{0}; 34 | tuple &operator++() { 35 | ++a; 36 | ++b; 37 | return *this; 38 | } 39 | }; 40 | 41 | inline bool operator==(const tuple &t1, const tuple &t2) { 42 | return t1.a == t2.a and t1.b == t2.b; 43 | } 44 | 45 | inline tuple operator+(const tuple &t1, const tuple &t2) { 46 | return tuple{t1.a + t2.a, t1.b + t2.b}; 47 | } 48 | 49 | MPL_REFLECTION(tuple, a, b) 50 | 51 | 52 | template 53 | class add { 54 | public: 55 | T operator()(const T &a, const T &b) const { 56 | return a + b; 57 | } 58 | }; 59 | 60 | 61 | enum class use_non_root_overload { no, yes }; 62 | 63 | #endif // MPL_TEST_HELPER_HPP 64 | -------------------------------------------------------------------------------- /test/test_info.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE info 2 | 3 | #include 4 | #include 5 | 6 | 7 | BOOST_AUTO_TEST_CASE(info) { 8 | [[maybe_unused]] const mpl::communicator &comm_world{mpl::environment::comm_world()}; 9 | 10 | mpl::info info_1; 11 | BOOST_TEST(info_1.size() == 0); 12 | info_1.set("Douglas Adams", "The Hitchhiker's Guide to the Galaxy"); 13 | info_1.set("Isaac Asimov", "Nightfall"); 14 | BOOST_TEST(info_1.size() == 2); 15 | BOOST_TEST(info_1.value("Isaac Asimov").value() == "Nightfall"); 16 | 17 | mpl::info info_2{info_1}; 18 | BOOST_TEST(info_1.size() == 2); 19 | BOOST_TEST(info_2.value("Isaac Asimov").value() == "Nightfall"); 20 | 21 | BOOST_TEST(not info_2.value("no such thing")); 22 | } 23 | -------------------------------------------------------------------------------- /test/test_initialization.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE communicator 2 | 3 | #include 4 | #include 5 | 6 | 7 | class my_mpi_environment { 8 | public: 9 | my_mpi_environment(int *argc, char ***argv) { 10 | MPI_Init(argc, argv); 11 | } 12 | 13 | ~my_mpi_environment() { 14 | MPI_Finalize(); 15 | } 16 | }; 17 | 18 | 19 | // test manual external initialization and finalization of the MPI environment 20 | bool initialization_test() { 21 | // Create a static my_mpi_environment object on block scope before any call to MPL. The 22 | // object will initialize the MPI environment in its constructor. The object's destructor 23 | // finalizes the MPI environment. The object will be destroyed after all MPL singletons have 24 | // been freed because static objects on block scope are destroyed in reverse order compared to 25 | // creation order. 26 | const static my_mpi_environment environment{nullptr, nullptr}; 27 | 28 | // Perform some MPI operations. 29 | int size{0}; 30 | MPI_Comm_size(MPI_COMM_WORLD, &size); 31 | BOOST_CHECK_GT(size, 0); 32 | // Do some MPL stuff. 33 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 34 | return comm_world.is_valid(); 35 | } 36 | 37 | 38 | BOOST_AUTO_TEST_CASE(initialization) { 39 | BOOST_TEST(initialization_test()); 40 | } 41 | -------------------------------------------------------------------------------- /test/test_inter_communicator.cc: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE inter_communicator 2 | 3 | #include 4 | #include 5 | 6 | 7 | // test inter-communicator creation 8 | BOOST_AUTO_TEST_CASE(inter_communicator_create) { 9 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 10 | // split communicator comm_world into two groups consisting of processes with odd and even 11 | // rank in comm_world 12 | const int world_rank{comm_world.rank()}; 13 | const int world_size{comm_world.size()}; 14 | const int my_group{world_rank % 2}; 15 | mpl::communicator local_communicator{mpl::communicator::split, comm_world, my_group}; 16 | const int local_leader{0}; 17 | const int remote_leader{my_group == 0 ? 1 : 0}; 18 | // comm_world is used as the communicator that can communicate with processes in the local 19 | // group as well as in the remote group 20 | mpl::inter_communicator inter_com{local_communicator, local_leader, comm_world, 21 | remote_leader}; 22 | BOOST_TEST((inter_com.size() + inter_com.remote_size() == world_size)); 23 | if (my_group == 0) { 24 | BOOST_TEST((inter_com.size() == (world_size + 1) / 2)); 25 | BOOST_TEST((inter_com.remote_size() == world_size / 2)); 26 | } else { 27 | BOOST_TEST((inter_com.remote_size() == (world_size + 1) / 2)); 28 | BOOST_TEST((inter_com.size() == world_size / 2)); 29 | } 30 | } 31 | 32 | 33 | // test inter-communicator merge 34 | BOOST_AUTO_TEST_CASE(inter_communicator_merge) { 35 | const mpl::communicator &comm_world{mpl::environment::comm_world()}; 36 | // split communicator comm_world into two groups consisting of processes with odd and even 37 | // rank in comm_world 38 | const int world_rank{comm_world.rank()}; 39 | const int my_group{world_rank % 2}; 40 | mpl::communicator local_communicator{mpl::communicator::split, comm_world, my_group}; 41 | const int local_leader{0}; 42 | const int remote_leader{my_group == 0 ? 1 : 0}; 43 | // comm_world is used as the communicator that can communicate with processes in the local 44 | // group as well as in the remote group 45 | mpl::inter_communicator inter_comm{local_communicator, local_leader, comm_world, 46 | remote_leader}; 47 | mpl::communicator com{inter_comm, mpl::communicator::order_low}; 48 | const auto communicator_equality{com.compare(comm_world)}; 49 | BOOST_TEST((communicator_equality == mpl::communicator::congruent or 50 | communicator_equality == mpl::communicator::similar)); 51 | } 52 | --------------------------------------------------------------------------------