├── .gitignore ├── AUTHORS ├── CHANGELOG.md ├── COPYING ├── COPYING.LESSER ├── Makefile.am ├── README.md ├── bootstrap ├── configure.ac ├── docs └── fig │ └── logo.png ├── m4 ├── ax_append_flag.m4 ├── ax_boost_base.m4 ├── ax_check_compile_flag.m4 ├── ax_check_cpus.m4 ├── ax_check_link_flag.m4 ├── ax_check_mpi.m4 ├── ax_cxx_compile_stdcxx.m4 ├── ax_cxx_compile_stdcxx_11.m4 ├── ax_cxx_compile_stdcxx_17.m4 ├── ax_var_pop.m4 ├── ax_var_push.m4 ├── flags.m4 ├── lx_find_mpi.m4 ├── modes.m4 └── ovni.m4 ├── src ├── c │ ├── Allgather.cpp │ ├── Allgatherv.cpp │ ├── Allreduce.cpp │ ├── Alltoall.cpp │ ├── Alltoallv.cpp │ ├── Alltoallw.cpp │ ├── Barrier.cpp │ ├── Bcast.cpp │ ├── Bsend.cpp │ ├── Exscan.cpp │ ├── Gather.cpp │ ├── Gatherv.cpp │ ├── InitFinalize.cpp │ ├── Recv.cpp │ ├── Reduce.cpp │ ├── Reducescatter.cpp │ ├── Reducescatterblock.cpp │ ├── Rsend.cpp │ ├── Scan.cpp │ ├── Scatter.cpp │ ├── Scatterv.cpp │ ├── Send.cpp │ ├── Ssend.cpp │ ├── Utils.cpp │ └── Wait.cpp ├── common │ ├── ALPI.hpp │ ├── Allocator.cpp │ ├── Allocator.hpp │ ├── CompletionManager.hpp │ ├── Declarations.hpp │ ├── Environment.cpp │ ├── Environment.hpp │ ├── Interface.hpp │ ├── Operation.cpp │ ├── Operation.hpp │ ├── OperationManager.hpp │ ├── Symbol.hpp │ ├── TaskContext.hpp │ ├── TaskingModel.cpp │ ├── TaskingModel.hpp │ ├── Ticket.hpp │ ├── TicketManager.hpp │ ├── TicketManagerCapacityCtrl.hpp │ ├── TicketManagerInternals.hpp │ ├── instrument │ │ ├── Instrument.cpp │ │ ├── Instrument.hpp │ │ └── OvniInstrument.hpp │ ├── polling │ │ ├── Polling.hpp │ │ ├── PollingPeriodCtrl.cpp │ │ ├── PollingPeriodCtrl.hpp │ │ └── SlowStartPollingPeriodCtrl.hpp │ └── util │ │ ├── ArrayView.hpp │ │ ├── BoostLockFreeQueue.hpp │ │ ├── Clock.hpp │ │ ├── EnvironmentVariable.hpp │ │ ├── ErrorHandler.hpp │ │ ├── FixedSizeStack.hpp │ │ ├── MultiLockFreeQueue.hpp │ │ ├── SpinLock.hpp │ │ ├── SpinWait.hpp │ │ ├── StringSupport.hpp │ │ └── Utils.hpp └── include │ ├── TAMPI.h │ ├── TAMPI_Decl.h │ ├── TAMPI_Wrappers.h │ └── TAMPIf.h └── tests ├── Makefile ├── Utils.hpp ├── omp ├── CollectiveNonBlk.cpp ├── MultiPrimitiveNonBlk.cpp └── PrimitiveNonBlk.cpp ├── oss ├── CollectiveBlk.cpp ├── CollectiveNonBlk.cpp ├── DoNotExecute.cpp ├── DoNotExecutef.F90 ├── HugeBlkTasks.cpp ├── HugeTasksf.F90 ├── InitAuto.cpp ├── InitAutoTaskAware.cpp ├── InitExplicit.cpp ├── InitExplicitTaskAware.cpp ├── MultiPrimitiveBlk.cpp ├── MultiPrimitiveNonBlk.cpp ├── PrimitiveBlk.cpp ├── PrimitiveNonBlk.cpp ├── ThreadDisableTaskAwareness.cpp └── ThreadTaskAwareness.cpp └── run-tests.sh /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile.in 2 | aclocal.m4 3 | ar-lib 4 | autom4te.cache/ 5 | build/ 6 | compile 7 | config.guess 8 | config.h.in 9 | config.h.in~ 10 | config.sub 11 | configure 12 | depcomp 13 | doc/html 14 | doc/latex 15 | install-sh 16 | ltmain.sh 17 | m4/libtool.m4 18 | m4/ltoptions.m4 19 | m4/ltsugar.m4 20 | m4/ltversion.m4 21 | m4/lt~obsolete.m4 22 | missing 23 | setup_env.sh 24 | tests/*.test 25 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Jorge Bellón Castro 2 | Vicenç Beltran Querol 3 | Víctor López Herrero 4 | Josep M. Pérez Cáncer 5 | Kevin Sala Penadés 6 | Xavier Teruel García 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Task-Aware MPI Release Notes 2 | All notable changes to this project will be documented in this file. 3 | 4 | 5 | ## Version 4.0, Fri Nov 15, 2024 6 | The 4.0 release introduces TAMPI-OPT, a newly optimized version of the library that ensures only a single thread accesses the MPI interface through delegation techniques. This approach gives access comparable to the highest MPI performance of single-threaded scenarios. Moreover, it introduces several bug fixes and usability and code improvements. Due to the new optimizations, some features have been ultimately dropped, while others will remain unsupported temporarily. For a detailed list check the bullet points below. 7 | 8 | ### General 9 | - Major library optimizations by serializing communications 10 | - Bump required MPI standard to 3.0 or later 11 | - Add support to adjust the completion polling task period dynamically 12 | - Improved collective operations constructors 13 | - Improve allocations of Operations through a scalable allocator 14 | - Improved ALPI symbol handling 15 | - Other bug fixes and code/performance improvements 16 | 17 | ### Unsupported Features 18 | - Temporarily dropped support for Fortran. 19 | - Temporarily dropped support for request-based MPI operations: `MPI_Wait`, `MPI_Waitall`, `TAMPI_Iwait`, `TAMPI_Iwaitall`. 20 | - Dropped support for `MPI_Sendrecv` and `MPI_Sendrecv_replace`. Every point-to-point and collective operation is **supported**. 21 | 22 | 23 | ## Version 3.0.1, Thu Dec 7, 2023 24 | The 3.0.1 release introduces bug fixes. 25 | 26 | ### General 27 | - Fix memory order in an atomic store 28 | - Update README with information regarding the [OpenMP-V](https://github.com/bsc-pm/llvm) runtime 29 | 30 | 31 | ## Version 3.0, Fri Nov 17, 2023 32 | The 3.0 release introduces the use of the generic ALPI tasking interface, bug fixes, and improved usability and programmability. This version also extends the ovni instrumentation to show more information regarding the TAMPI behavior in Paraver traces. 33 | 34 | ### General 35 | - Rely on the [ALPI](https://gitlab.bsc.es/alpi/alpi) tasking interface (OmpSs-2 2023.11 or later) 36 | - Drop support for the Nanos6-specific tasking interface 37 | - Drop support for older versions than OmpSs-2 2023.11 38 | - Remove deprecated `TAMPI_POLLING_FREQUENCY` environment variable 39 | - Stop using PMPI interfaces for testing internal requests (e.g., `PMPI_Test`) 40 | - Do not assume the default MPI threading level is `MPI_THREAD_SINGLE` 41 | - Load first occurrence of the ALPI tasking interface symbols (`RTLD_DEFAULT`) 42 | - Add opt-in mechanism to explicitly initialize TAMPI independently from MPI 43 | - Add opt-in mechanism to disable task-awareness for specific threads 44 | - Refactor and simplify symbol loading 45 | 46 | ### Instrumentation 47 | - Instrument library subsystems with ovni; see the [ovni documentation](https://ovni.readthedocs.io) for more information 48 | - Improve ovni library discovery 49 | 50 | ### Building 51 | - Add `--enable-debug` configure option replacing `--enable-debug-mode` 52 | - Add `--enable-asan` option to enable address sanitizer flags 53 | - Deprecate `--enable-debug-mode` option, which will be removed in next versions 54 | 55 | ### Testing 56 | - Improve testing scripts and Makefiles 57 | - Fix CPU binding on SLURM-based tests 58 | - Add testing option `--skip-omp` to skip the execution of OpenMP tests 59 | 60 | 61 | ## Version 2.0, Fri May 26, 2023 62 | The 2.0 release introduces several performance improvements, important bug fixes, and improved usability and programmability. Several environment variables that users can set to change default behavior have been updated. This version also introduces support for the ovni instrumentation to obtain Paraver execution traces. 63 | 64 | ### General 65 | - Introduce `TAMPI_POLLING_PERIOD` replacing `TAMPI_POLLING_FREQUENCY` 66 | - Deprecate `TAMPI_POLLING_FREQUENCY` and will be removed in next versions 67 | - Drop support for OmpSs-2 2020.06; now requiring OmpSs-2 2020.11 or later 68 | - Leverage C++17 standard, which may require newer GCC (such as GCC 7 or later) 69 | - Extend README with a Frequently Asked Questions (FAQ) section 70 | 71 | ### Performance 72 | - Set default polling period (`TAMPI_POLLING_PERIOD`) to 100us, which can improve applications' performance 73 | - Fix and improve implementation of custom spinlocks 74 | - Remove use of std::function due to its dynamic memory allocations 75 | 76 | ### Fixes and Code Improvements 77 | - Reduce code duplication between C/C++ and Fortran support 78 | - Fix Fortran interfaces 79 | - Fix and improve testing infrastructure and test codes 80 | - Compile all libraries with -fPIC 81 | 82 | ### Instrumentation 83 | - Add [ovni](https://github.com/bsc-pm/ovni) instrumentation to generate Paraver traces for multi-node executions 84 | - Enable ovni instrumentation when `TAMPI_INSTRUMENT=ovni` environment variable 85 | - Drop support for Nanos6-specific instrumentation; use ovni instead 86 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 2 | # 3 | # Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 4 | 5 | ACLOCAL_AMFLAGS = -I m4 6 | 7 | AM_CPPFLAGS = \ 8 | $(BOOST_CPPFLAGS) -DBOOST_ENABLE_ASSERT_DEBUG_HANDLER \ 9 | -I$(top_srcdir)/src \ 10 | -I$(top_srcdir)/src/common \ 11 | -I$(top_srcdir)/src/include \ 12 | -include "config.h" \ 13 | $(ovni_CPPFLAGS) \ 14 | $(tampi_CPPFLAGS) \ 15 | $(asan_CPPFLAGS) 16 | 17 | AM_CXXFLAGS = $(MPI_CXXFLAGS) $(tampi_CXXFLAGS) $(asan_CXXFLAGS) 18 | 19 | AM_LDFLAGS = $(ovni_LIBS) $(asan_LDFLAGS) -ldl $(MPI_CXXLDFLAGS) 20 | LIBS = 21 | 22 | include_HEADERS = \ 23 | src/include/TAMPI.h \ 24 | src/include/TAMPI_Decl.h \ 25 | src/include/TAMPI_Wrappers.h \ 26 | src/include/TAMPIf.h 27 | 28 | pkginclude_HEADERS = # This library does not provide any additional header 29 | 30 | c_api_sources = \ 31 | src/c/Allgather.cpp \ 32 | src/c/Allgatherv.cpp \ 33 | src/c/Allreduce.cpp \ 34 | src/c/Alltoall.cpp \ 35 | src/c/Alltoallv.cpp \ 36 | src/c/Alltoallw.cpp \ 37 | src/c/Barrier.cpp \ 38 | src/c/Bcast.cpp \ 39 | src/c/Bsend.cpp \ 40 | src/c/Exscan.cpp \ 41 | src/c/Gather.cpp \ 42 | src/c/Gatherv.cpp \ 43 | src/c/InitFinalize.cpp \ 44 | src/c/Wait.cpp \ 45 | src/c/Recv.cpp \ 46 | src/c/Reduce.cpp \ 47 | src/c/Reducescatter.cpp \ 48 | src/c/Reducescatterblock.cpp \ 49 | src/c/Rsend.cpp \ 50 | src/c/Scan.cpp \ 51 | src/c/Scatter.cpp \ 52 | src/c/Scatterv.cpp \ 53 | src/c/Send.cpp \ 54 | src/c/Ssend.cpp \ 55 | src/c/Utils.cpp 56 | 57 | common_sources = \ 58 | src/common/Allocator.cpp \ 59 | src/common/Environment.cpp \ 60 | src/common/Operation.cpp \ 61 | src/common/TaskingModel.cpp \ 62 | src/common/instrument/Instrument.cpp \ 63 | src/common/polling/PollingPeriodCtrl.cpp 64 | 65 | noinst_HEADERS = \ 66 | src/common/Allocator.hpp \ 67 | src/common/ALPI.hpp \ 68 | src/common/Declarations.hpp \ 69 | src/common/CompletionManager.hpp \ 70 | src/common/Environment.hpp \ 71 | src/common/Interface.hpp \ 72 | src/common/Operation.hpp \ 73 | src/common/OperationManager.hpp \ 74 | src/common/Symbol.hpp \ 75 | src/common/TaskContext.hpp \ 76 | src/common/TaskingModel.hpp \ 77 | src/common/Ticket.hpp \ 78 | src/common/TicketManager.hpp \ 79 | src/common/TicketManagerCapacityCtrl.hpp \ 80 | src/common/TicketManagerInternals.hpp \ 81 | src/common/instrument/Instrument.hpp \ 82 | src/common/instrument/OvniInstrument.hpp \ 83 | src/common/polling/Polling.hpp \ 84 | src/common/polling/PollingPeriodCtrl.hpp \ 85 | src/common/polling/SlowStartPollingPeriodCtrl.hpp \ 86 | src/common/util/ArrayView.hpp \ 87 | src/common/util/BoostLockFreeQueue.hpp \ 88 | src/common/util/Clock.hpp \ 89 | src/common/util/EnvironmentVariable.hpp \ 90 | src/common/util/ErrorHandler.hpp \ 91 | src/common/util/FixedSizeStack.hpp \ 92 | src/common/util/MultiLockFreeQueue.hpp \ 93 | src/common/util/SpinLock.hpp \ 94 | src/common/util/SpinWait.hpp \ 95 | src/common/util/StringSupport.hpp \ 96 | src/common/util/Utils.hpp 97 | 98 | lib_LTLIBRARIES = libtampi.la libtampi-c.la libtampi-fortran.la 99 | 100 | libtampi_la_CPPFLAGS = $(AM_CPPFLAGS) 101 | libtampi_la_SOURCES = $(common_sources) $(c_api_sources) 102 | 103 | libtampi_c_la_CPPFLAGS = $(AM_CPPFLAGS) -DDISABLE_FORTRAN_LANG 104 | libtampi_c_la_SOURCES = $(common_sources) $(c_api_sources) 105 | 106 | libtampi_fortran_la_CPPFLAGS = $(AM_CPPFLAGS) -DDISABLE_C_LANG 107 | libtampi_fortran_la_SOURCES = $(common_sources) 108 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | autoreconf -fiv 4 | 5 | # Patch ltmain.sh 6 | if [[ -f ltmain.sh ]] ; then 7 | echo -n "Patching ltmain.sh... " 8 | 9 | # (A) Apply some of the patches that Debian introduces to ltmain.sh in order to not link against 10 | # all the dependencies of our libraries. Thus, reducing the over-linking produced by libtool. 11 | 12 | # Concatenate dependency_libs only if link_all_deplibs != no 13 | case="link) libs=\"\$deplibs %DEPLIBS% \$dependency_libs\" ;;" 14 | newcase="link) libs=\"\$deplibs %DEPLIBS%\"\n" 15 | newcase+="\t\ttest \"X\$link_all_deplibs\" != Xno \&\& libs=\"\$libs \$dependency_libs\" ;;" 16 | script_1="s/$case/$newcase/" 17 | 18 | # In the step of checking convenience libraries, iterate dependency_libs only if libdir is empty 19 | # The objective here is to move 3 lines down (elif -> fi) until the end of the debplib loop. 20 | script_2=" 21 | # Match only from '# It is a libtool convenience library' until the end of the next loop 22 | /# It is a libtool convenience library/,/done/ { 23 | 24 | # If the elif block is found, move it to the hold buffer 25 | /elif/ { 26 | # Append the next two lines to the pattern buffer 27 | N 28 | N 29 | # Exchange pattern and hold buffers to keep the 3 lines 30 | x 31 | # Delele the current pattern buffer which should be blank 32 | d 33 | } 34 | 35 | # If the end of the loop is found, append the contents of the hold buffer 36 | /done/ { 37 | # First, we switch buffers to check if the hold buffer contains our code 38 | x 39 | # If the hold buffer contained elif, it means that the elif block was prior to the loop 40 | /elif/ { 41 | # Restore the initial pattern 42 | x 43 | # Append the hold buffer to the pattern space 44 | G 45 | } 46 | # If the hold buffer was empty, the elif block was not prior and the patch is not needed 47 | /^$/ { 48 | # Switch buffers again to restore the initial pattern 49 | x 50 | } 51 | } 52 | }" 53 | 54 | # (B) Libtool has a weird 'feature' in which places all the linker options '-Wl,option' at the 55 | # end of the command line. Some options, like '--as-needed', need to be placed before the 56 | # library list to have any effect. 57 | 58 | parse_flags=" -Wl,*--as-needed*)\n" 59 | parse_flags+=" deplibs=\"\$deplibs \$wl--as-needed\"\n" 60 | parse_flags+=" ;;\n" 61 | parse_flags+=" -Wl,*--no-as-needed*)\n" 62 | parse_flags+=" deplibs=\"\$deplibs \$wl--no-as-needed\"\n" 63 | parse_flags+=" ;;\n" 64 | 65 | iter_flags=" -Wl,--as-needed)\n" 66 | iter_flags+=" if test \"\$linkmode,\$pass\" = \"prog,link\"; then\n" 67 | iter_flags+=" compile_deplibs=\"\$deplib \$compile_deplibs\"\n" 68 | iter_flags+=" finalize_deplibs=\"\$deplib \$finalize_deplibs\"\n" 69 | iter_flags+=" else\n" 70 | iter_flags+=" deplibs=\"\$deplib \$deplibs\"\n" 71 | iter_flags+=" fi\n" 72 | iter_flags+=" continue\n" 73 | iter_flags+=" ;;\n" 74 | script_3=" 75 | # Match only from within the func_mode_link() function 76 | /func_mode_link\s*\(\)/,/^}/ { 77 | 78 | # Prepend parsing of -Wl,--as-nedded / -Wl,--no-as-needed 79 | /-Wl,\*)/ { 80 | s/.*/$parse_flags&/ 81 | } 82 | 83 | # Place flags before the library list 84 | # We are looking for the loop where -pthread is parsed from \$deplib 85 | /case \$deplib in/ { 86 | n 87 | /-pthread/ { 88 | s/.*/$iter_flags&/ 89 | } 90 | } 91 | }" 92 | 93 | # Apply scripts 94 | sed -i -e "$script_1" -e "$script_2" -e "$script_3" ltmain.sh 95 | 96 | echo "DONE" 97 | fi 98 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | # This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 5 | # 6 | # Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 7 | 8 | AC_PREREQ([2.69]) 9 | AC_INIT([tampi], [4.0], [pm-tools@bsc.es]) 10 | 11 | AC_CONFIG_MACRO_DIR([m4]) 12 | AC_CONFIG_SRCDIR([src]) 13 | AC_CONFIG_HEADERS([config.h]) 14 | 15 | AC_LANG([C++]) 16 | 17 | # Prepare compilation flags before AC_PROG_CXX 18 | AX_COMPILE_FLAGS 19 | 20 | # Look for a valid C++ compiler 21 | AC_PROG_CXX 22 | 23 | # Retrieve compiler version 24 | AX_CHECK_CXX_VERSION 25 | 26 | # AM_PROG_AR must be called before LT_INIT or a warning ensues 27 | AM_PROG_AR 28 | 29 | # Automake initialization 30 | AM_INIT_AUTOMAKE([foreign -Wall dist-bzip2 -Wno-portability subdir-objects silent-rules]) 31 | AM_SILENT_RULES([yes]) 32 | 33 | # Checks header files 34 | AC_CHECK_HEADERS([unistd.h]) 35 | 36 | # Find and check the MPI library 37 | LX_FIND_MPI 38 | AX_CHECK_MPI 39 | 40 | # Check the Boost library 41 | AX_BOOST_BASE([1.59], [], [ AC_MSG_ERROR([Boost library not found])]) 42 | 43 | # Check the ovni instrumentation library 44 | AC_CHECK_OVNI 45 | 46 | # Check that the compiler supports C++17 47 | AX_CXX_COMPILE_STDCXX_17([noext], [mandatory]) 48 | 49 | # Enable/disable blocking and non-blocking modes 50 | AX_CHECK_TAMPI_MODES 51 | 52 | # Check the CPU count of the system 53 | AX_CHECK_CPUS 54 | 55 | # Compile both static and dynamic libraries. All objects should be compiled 56 | # enabling the position independent code (PIC) mode 57 | LT_INIT([shared static pic-only]) 58 | 59 | AC_CONFIG_FILES([Makefile]) 60 | AC_OUTPUT 61 | 62 | echo "" 63 | echo "" 64 | echo "Configuration summary:" 65 | echo " Compiler version... ${CXX_VERSION}" 66 | echo "" 67 | echo " Installation prefix... ${prefix}" 68 | echo "" 69 | echo " TAMPI blocking mode... ${ac_blocking_mode}" 70 | echo " TAMPI non-blocking mode... ${ac_nonblocking_mode}" 71 | echo "" 72 | echo " CXXFLAGS... ${tampi_CXXFLAGS} ${asan_CXXFLAGS} ${CXXFLAGS}" 73 | echo " CPPFLAGS... ${tampi_CPPFLAGS} ${asan_CPPFLAGS} ${CPPFLAGS}" 74 | echo " LDFLAGS... ${asan_LDFLAGS} ${LDFLAGS}" 75 | echo "" 76 | echo " MPI CXXFLAGS... ${MPI_CXXFLAGS}" 77 | echo " MPI LDFLAGS... ${MPI_CXXLDFLAGS}" 78 | echo "" 79 | echo " Boost CPPFLAGS... ${BOOST_CPPFLAGS}" 80 | echo "" 81 | echo " Ovni is enabled... ${ac_use_ovni}" 82 | 83 | if test x"${ac_use_ovni}" = x"yes" ; then 84 | echo " Ovni CPPFLAGS... ${ovni_CPPFLAGS}" 85 | echo " Ovni LIBS... ${ovni_LIBS}" 86 | fi 87 | echo "" 88 | -------------------------------------------------------------------------------- /docs/fig/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsc-pm/tampi/a5c93bf8ab045b71ad4a8d5e2c991ce774db5cbc/docs/fig/logo.png -------------------------------------------------------------------------------- /m4/ax_append_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_append_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # FLAG is appended to the FLAGS-VARIABLE shell variable, with a space 12 | # added in between. 13 | # 14 | # If FLAGS-VARIABLE is not specified, the current language's flags (e.g. 15 | # CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains 16 | # FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly 17 | # FLAG. 18 | # 19 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. 20 | # 21 | # LICENSE 22 | # 23 | # Copyright (c) 2008 Guido U. Draheim 24 | # Copyright (c) 2011 Maarten Bosmans 25 | # 26 | # This program is free software: you can redistribute it and/or modify it 27 | # under the terms of the GNU General Public License as published by the 28 | # Free Software Foundation, either version 3 of the License, or (at your 29 | # option) any later version. 30 | # 31 | # This program is distributed in the hope that it will be useful, but 32 | # WITHOUT ANY WARRANTY; without even the implied warranty of 33 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 34 | # Public License for more details. 35 | # 36 | # You should have received a copy of the GNU General Public License along 37 | # with this program. If not, see . 38 | # 39 | # As a special exception, the respective Autoconf Macro's copyright owner 40 | # gives unlimited permission to copy, distribute and modify the configure 41 | # scripts that are the output of Autoconf when processing the Macro. You 42 | # need not follow the terms of the GNU General Public License when using 43 | # or distributing such scripts, even though portions of the text of the 44 | # Macro appear in them. The GNU General Public License (GPL) does govern 45 | # all other use of the material that constitutes the Autoconf Macro. 46 | # 47 | # This special exception to the GPL applies to versions of the Autoconf 48 | # Macro released by the Autoconf Archive. When you make and distribute a 49 | # modified version of the Autoconf Macro, you may extend this special 50 | # exception to the GPL to apply to your modified version as well. 51 | 52 | #serial 6 53 | 54 | # AS_VAR_APPEND compatibility for autoconf < 2.64 55 | m4_ifndef([AS_VAR_APPEND], 56 | AC_DEFUN([AS_VAR_APPEND], $1=$$1$2)) 57 | 58 | AC_DEFUN([AX_APPEND_FLAG], 59 | [dnl 60 | dnl AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF 61 | AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) 62 | AS_VAR_SET_IF(FLAGS,[ 63 | AS_CASE([" AS_VAR_GET(FLAGS) "], 64 | [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], 65 | [ 66 | AS_VAR_APPEND(FLAGS,[" $1"]) 67 | AC_RUN_LOG([: FLAGS="$FLAGS"]) 68 | ]) 69 | ], 70 | [ 71 | AS_VAR_SET(FLAGS,[$1]) 72 | AC_RUN_LOG([: FLAGS="$FLAGS"]) 73 | ]) 74 | AS_VAR_POPDEF([FLAGS])dnl 75 | ])dnl AX_APPEND_FLAG 76 | -------------------------------------------------------------------------------- /m4/ax_check_compile_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check whether the given FLAG works with the current language's compiler 12 | # or gives an error. (Warnings, however, are ignored) 13 | # 14 | # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on 15 | # success/failure. 16 | # 17 | # If EXTRA-FLAGS is defined, it is added to the current language's default 18 | # flags (e.g. CFLAGS) when the check is done. The check is thus made with 19 | # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to 20 | # force the compiler to issue an error when a bad flag is given. 21 | # 22 | # INPUT gives an alternative input source to AC_COMPILE_IFELSE. 23 | # 24 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this 25 | # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. 26 | # 27 | # LICENSE 28 | # 29 | # Copyright (c) 2008 Guido U. Draheim 30 | # Copyright (c) 2011 Maarten Bosmans 31 | # 32 | # This program is free software: you can redistribute it and/or modify it 33 | # under the terms of the GNU General Public License as published by the 34 | # Free Software Foundation, either version 3 of the License, or (at your 35 | # option) any later version. 36 | # 37 | # This program is distributed in the hope that it will be useful, but 38 | # WITHOUT ANY WARRANTY; without even the implied warranty of 39 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 40 | # Public License for more details. 41 | # 42 | # You should have received a copy of the GNU General Public License along 43 | # with this program. If not, see . 44 | # 45 | # As a special exception, the respective Autoconf Macro's copyright owner 46 | # gives unlimited permission to copy, distribute and modify the configure 47 | # scripts that are the output of Autoconf when processing the Macro. You 48 | # need not follow the terms of the GNU General Public License when using 49 | # or distributing such scripts, even though portions of the text of the 50 | # Macro appear in them. The GNU General Public License (GPL) does govern 51 | # all other use of the material that constitutes the Autoconf Macro. 52 | # 53 | # This special exception to the GPL applies to versions of the Autoconf 54 | # Macro released by the Autoconf Archive. When you make and distribute a 55 | # modified version of the Autoconf Macro, you may extend this special 56 | # exception to the GPL to apply to your modified version as well. 57 | 58 | #serial 3 59 | 60 | AC_DEFUN([AX_CHECK_COMPILE_FLAG], 61 | [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX 62 | AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl 63 | AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ 64 | ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS 65 | _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" 66 | AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], 67 | [AS_VAR_SET(CACHEVAR,[yes])], 68 | [AS_VAR_SET(CACHEVAR,[no])]) 69 | _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) 70 | AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], 71 | [m4_default([$2], :)], 72 | [m4_default([$3], :)]) 73 | AS_VAR_POPDEF([CACHEVAR])dnl 74 | ])dnl AX_CHECK_COMPILE_FLAGS 75 | -------------------------------------------------------------------------------- /m4/ax_check_cpus.m4: -------------------------------------------------------------------------------- 1 | # 2 | # SYNOPSIS 3 | # 4 | # AX_CHECK_CPUS 5 | # 6 | # AX_CHECK_CPUS 7 | # 8 | 9 | AC_DEFUN([AX_CHECK_CPUS], [ 10 | AC_MSG_CHECKING([the maximum number of CPUs in the system]) 11 | numcpus=$(nproc --all) 12 | AS_IF([numcpus=$(nproc --all 2> /dev/null)],[], 13 | [numcpus=$(grep -c processor /proc/cpuinfo 2> /dev/null)],[], 14 | [numcpus=$(sysctl -n hw.ncpu 2> /dev/null)],[], 15 | [numcpus=64]) 16 | AC_SUBST([numcpus]) 17 | AC_MSG_RESULT([${numcpus}]) 18 | 19 | AC_DEFINE_UNQUOTED([MAX_SYSTEM_CPUS], [$numcpus], [Maximum number of CPUs in the system]) 20 | ]) 21 | -------------------------------------------------------------------------------- /m4/ax_check_link_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check whether the given FLAG works with the linker or gives an error. 12 | # (Warnings, however, are ignored) 13 | # 14 | # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on 15 | # success/failure. 16 | # 17 | # If EXTRA-FLAGS is defined, it is added to the linker's default flags 18 | # when the check is done. The check is thus made with the flags: "LDFLAGS 19 | # EXTRA-FLAGS FLAG". This can for example be used to force the linker to 20 | # issue an error when a bad flag is given. 21 | # 22 | # INPUT gives an alternative input source to AC_LINK_IFELSE. 23 | # 24 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this 25 | # macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. 26 | # 27 | # LICENSE 28 | # 29 | # Copyright (c) 2008 Guido U. Draheim 30 | # Copyright (c) 2011 Maarten Bosmans 31 | # 32 | # This program is free software: you can redistribute it and/or modify it 33 | # under the terms of the GNU General Public License as published by the 34 | # Free Software Foundation, either version 3 of the License, or (at your 35 | # option) any later version. 36 | # 37 | # This program is distributed in the hope that it will be useful, but 38 | # WITHOUT ANY WARRANTY; without even the implied warranty of 39 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 40 | # Public License for more details. 41 | # 42 | # You should have received a copy of the GNU General Public License along 43 | # with this program. If not, see . 44 | # 45 | # As a special exception, the respective Autoconf Macro's copyright owner 46 | # gives unlimited permission to copy, distribute and modify the configure 47 | # scripts that are the output of Autoconf when processing the Macro. You 48 | # need not follow the terms of the GNU General Public License when using 49 | # or distributing such scripts, even though portions of the text of the 50 | # Macro appear in them. The GNU General Public License (GPL) does govern 51 | # all other use of the material that constitutes the Autoconf Macro. 52 | # 53 | # This special exception to the GPL applies to versions of the Autoconf 54 | # Macro released by the Autoconf Archive. When you make and distribute a 55 | # modified version of the Autoconf Macro, you may extend this special 56 | # exception to the GPL to apply to your modified version as well. 57 | 58 | #serial 4 59 | 60 | AC_DEFUN([AX_CHECK_LINK_FLAG], 61 | [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF 62 | AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl 63 | AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ 64 | ax_check_save_flags=$LDFLAGS 65 | LDFLAGS="$LDFLAGS $4 $1" 66 | AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], 67 | [AS_VAR_SET(CACHEVAR,[yes])], 68 | [AS_VAR_SET(CACHEVAR,[no])]) 69 | LDFLAGS=$ax_check_save_flags]) 70 | AS_VAR_IF(CACHEVAR,yes, 71 | [m4_default([$2], :)], 72 | [m4_default([$3], :)]) 73 | AS_VAR_POPDEF([CACHEVAR])dnl 74 | ])dnl AX_CHECK_LINK_FLAGS 75 | -------------------------------------------------------------------------------- /m4/ax_cxx_compile_stdcxx_11.m4: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html 3 | # ============================================================================= 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check for baseline language coverage in the compiler for the C++11 12 | # standard; if necessary, add switches to CXX and CXXCPP to enable 13 | # support. 14 | # 15 | # This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX 16 | # macro with the version set to C++11. The two optional arguments are 17 | # forwarded literally as the second and third argument respectively. 18 | # Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for 19 | # more information. If you want to use this macro, you also need to 20 | # download the ax_cxx_compile_stdcxx.m4 file. 21 | # 22 | # LICENSE 23 | # 24 | # Copyright (c) 2008 Benjamin Kosnik 25 | # Copyright (c) 2012 Zack Weinberg 26 | # Copyright (c) 2013 Roy Stogner 27 | # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov 28 | # Copyright (c) 2015 Paul Norman 29 | # Copyright (c) 2015 Moritz Klammler 30 | # 31 | # Copying and distribution of this file, with or without modification, are 32 | # permitted in any medium without royalty provided the copyright notice 33 | # and this notice are preserved. This file is offered as-is, without any 34 | # warranty. 35 | 36 | #serial 18 37 | 38 | AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX]) 39 | AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])]) 40 | -------------------------------------------------------------------------------- /m4/ax_cxx_compile_stdcxx_17.m4: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_17.html 3 | # ============================================================================= 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CXX_COMPILE_STDCXX_17([ext|noext], [mandatory|optional]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check for baseline language coverage in the compiler for the C++17 12 | # standard; if necessary, add switches to CXX and CXXCPP to enable 13 | # support. 14 | # 15 | # This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX 16 | # macro with the version set to C++17. The two optional arguments are 17 | # forwarded literally as the second and third argument respectively. 18 | # Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for 19 | # more information. If you want to use this macro, you also need to 20 | # download the ax_cxx_compile_stdcxx.m4 file. 21 | # 22 | # LICENSE 23 | # 24 | # Copyright (c) 2015 Moritz Klammler 25 | # Copyright (c) 2016 Krzesimir Nowak 26 | # 27 | # Copying and distribution of this file, with or without modification, are 28 | # permitted in any medium without royalty provided the copyright notice 29 | # and this notice are preserved. This file is offered as-is, without any 30 | # warranty. 31 | 32 | #serial 2 33 | 34 | AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX]) 35 | AC_DEFUN([AX_CXX_COMPILE_STDCXX_17], [AX_CXX_COMPILE_STDCXX([17], [$1], [$2])]) 36 | -------------------------------------------------------------------------------- /m4/ax_var_pop.m4: -------------------------------------------------------------------------------- 1 | # 2 | # SYNOPSIS 3 | # 4 | # AX_VAR_POPVALUE(VARIABLE) 5 | # Restores a variable's previous value 6 | # 7 | # DESCRIPTION 8 | # 9 | # Compile, link and running tests usually require the programmer to 10 | # provide additional flags. However, it is strongly recommended not 11 | # to override flags defined by the user through the configure command. 12 | # AX_VAR_PUSHVALUE and AX_VAR_POPVALUE are clean way to temporarily 13 | # store a variable's value and restore it later, using a stack-like 14 | # behaviour. 15 | # This macro supports nesting. 16 | # 17 | # Example: 18 | # AX_VAR_PUSHVALUE([CXXFLAGS],["my test flags"]) 19 | # perform some checks with CXXFLAGS... 20 | # CXXFLAGS value will be "my test flags" 21 | # AX_VAR_POPVALUE([CXXFLAGS]) 22 | # CXXFLAGS is restored to its original value 23 | # 24 | # LICENSE 25 | # 26 | # Copyright (c) 2015 Jorge Bellon 27 | # 28 | # This program is free software: you can redistribute it and/or modify it 29 | # under the terms of the GNU General Public License as published by the 30 | # Free Software Foundation, either version 3 of the License, or (at your 31 | # option) any later version. 32 | # 33 | # This program is distributed in the hope that it will be useful, but 34 | # WITHOUT ANY WARRANTY; without even the implied warranty of 35 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 36 | # Public License for more details. 37 | # 38 | # You should have received a copy of the GNU General Public License along 39 | # with this program. If not, see . 40 | # 41 | # As a special exception, the respective Autoconf Macro's copyright owner 42 | # gives unlimited permission to copy, distribute and modify the configure 43 | # scripts that are the output of Autoconf when processing the Macro. You 44 | # need not follow the terms of the GNU General Public License when using 45 | # or distributing such scripts, even though portions of the text of the 46 | # Macro appear in them. The GNU General Public License (GPL) does govern 47 | # all other use of the material that constitutes the Autoconf Macro. 48 | # 49 | # This special exception to the GPL applies to versions of the Autoconf 50 | # Macro released by the Autoconf Archive. When you make and distribute a 51 | # modified version of the Autoconf Macro, you may extend this special 52 | # exception to the GPL to apply to your modified version as well. 53 | # 54 | 55 | AC_DEFUN([AX_VAR_POPVALUE],[ 56 | AS_VAR_PUSHDEF([variable],[$1]) dnl 57 | AS_VAR_PUSHDEF([backup],[save_$1_]$1_counter) dnl 58 | 59 | AS_VAR_SET(variable,$backup) dnl 60 | 61 | decrement([$1_counter]) 62 | AS_VAR_POPDEF([variable]) dnl 63 | AS_VAR_POPDEF([backup]) dnl 64 | ])dnl AX_VAR_PUSHVALUE 65 | 66 | # ------------------------- 67 | # Auxiliary macro 68 | # ------------------------- 69 | # decrement(counter_name) 70 | # 71 | # Decrement the value of a named counter. 72 | # Throws an error if counter not defined 73 | # or value reaches zero. 74 | # ------------------------- 75 | m4_define([decrement],[dnl 76 | m4_ifdef([$1],dnl 77 | [m4_if(m4_eval($1 > 0), 78 | [1],m4_define([$1],m4_decr($1)),dnl 79 | [m4_fatal([Missing call to AX_VAR_PUSHVALUE with var $1])]dnl 80 | )],dnl 81 | [m4_fatal([Missing call to AX_VAR_PUSHVALUE with var $1])])dnl 82 | ])dnl 83 | -------------------------------------------------------------------------------- /m4/ax_var_push.m4: -------------------------------------------------------------------------------- 1 | # 2 | # SYNOPSIS 3 | # 4 | # AX_VAR_PUSHVALUE(VARIABLE, [VALUE]) 5 | # Stores a copy of variable_name's value and assigns it to 'value' 6 | # If no value is given, its original value is kept. 7 | # 8 | # DESCRIPTION 9 | # 10 | # Compile, link and running tests usually require the programmer to 11 | # provide additional flags. However, it is strongly recommended not 12 | # to override flags defined by the user through the configure command. 13 | # AX_VAR_PUSHVALUE and AX_VAR_POPVALUE are clean way to temporarily 14 | # store a variable's value and restore it later, using a stack-like 15 | # behaviour. 16 | # This macro supports nesting. 17 | # 18 | # Example: 19 | # AX_VAR_PUSHVALUE([CXXFLAGS],["my test flags"]) 20 | # perform some checks with CXXFLAGS... 21 | # CXXFLAGS value will be "my test flags" 22 | # AX_VAR_POPVALUE([CXXFLAGS]) 23 | # CXXFLAGS is restored to its original value 24 | # 25 | # LICENSE 26 | # 27 | # Copyright (c) 2015 Jorge Bellon 28 | # 29 | # This program is free software: you can redistribute it and/or modify it 30 | # under the terms of the GNU General Public License as published by the 31 | # Free Software Foundation, either version 3 of the License, or (at your 32 | # option) any later version. 33 | # 34 | # This program is distributed in the hope that it will be useful, but 35 | # WITHOUT ANY WARRANTY; without even the implied warranty of 36 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 37 | # Public License for more details. 38 | # 39 | # You should have received a copy of the GNU General Public License along 40 | # with this program. If not, see . 41 | # 42 | # As a special exception, the respective Autoconf Macro's copyright owner 43 | # gives unlimited permission to copy, distribute and modify the configure 44 | # scripts that are the output of Autoconf when processing the Macro. You 45 | # need not follow the terms of the GNU General Public License when using 46 | # or distributing such scripts, even though portions of the text of the 47 | # Macro appear in them. The GNU General Public License (GPL) does govern 48 | # all other use of the material that constitutes the Autoconf Macro. 49 | # 50 | # This special exception to the GPL applies to versions of the Autoconf 51 | # Macro released by the Autoconf Archive. When you make and distribute a 52 | # modified version of the Autoconf Macro, you may extend this special 53 | # exception to the GPL to apply to your modified version as well. 54 | # 55 | 56 | AC_DEFUN([AX_VAR_PUSHVALUE],[ 57 | increment([$1_counter]) 58 | 59 | AS_VAR_PUSHDEF([variable],[$1]) dnl 60 | AS_VAR_PUSHDEF([backup],[save_$1_]$1_counter) dnl 61 | 62 | AS_VAR_SET(backup,$variable) dnl 63 | AS_VAR_SET(variable,["]m4_default($2,$variable)["]) dnl 64 | 65 | AS_VAR_POPDEF([variable]) dnl 66 | AS_VAR_POPDEF([backup]) dnl 67 | ])dnl AX_PUSH_VAR 68 | 69 | # ------------------------- 70 | # Auxiliary macro 71 | # ------------------------- 72 | # increment(counter_name) 73 | # 74 | # Increment the value of a named counter. 75 | # Initialize to 1 if not defined 76 | # ------------------------- 77 | m4_define([increment],[dnl 78 | m4_ifdef([$1],dnl 79 | [m4_define([$1],m4_incr($1))],dnl 80 | [m4_define([$1],[1])]dnl 81 | )dnl 82 | ])dnl 83 | -------------------------------------------------------------------------------- /m4/flags.m4: -------------------------------------------------------------------------------- 1 | # 2 | # SYNOPSIS 3 | # 4 | # AX_CHECK_CXX_VERSION 5 | # 6 | # AX_COMPILE_FLAGS 7 | # 8 | 9 | AC_DEFUN([AX_CHECK_CXX_VERSION], [ 10 | AC_MSG_CHECKING([the ${CXX} version]) 11 | if test x"$CXX" != x"" ; then 12 | CXX_VERSION=$(${CXX} --version | head -1) 13 | fi 14 | AC_MSG_RESULT([$CXX_VERSION]) 15 | AC_SUBST([CXX_VERSION]) 16 | ]) 17 | 18 | AC_DEFUN([AX_COMPILE_FLAGS], [ 19 | # Disable debug and address sanitizer by default 20 | ac_enable_debug=no 21 | ac_enable_asan=no 22 | 23 | AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug], 24 | [Adds compiler debug flags and enables additional internal debugging mechanisms @<:@default=disabled@:>@])], 25 | [ ac_enable_debug=$enableval ]) 26 | 27 | AC_ARG_ENABLE([debug-mode], [AS_HELP_STRING([--enable-debug-mode], 28 | [Deprecated option to enable debug; use --enable-debug instead @<:@default=disabled@:>@])], 29 | [ 30 | AC_MSG_WARN([Option --enable-debug-mode is deprecated; use --enable-debug instead]) 31 | ac_enable_debug=$enableval 32 | ]) 33 | 34 | AC_ARG_ENABLE([asan], [AS_HELP_STRING([--enable-asan], 35 | [Enables address sanitizing @<:@default=disabled@:>@])], 36 | [ ac_enable_asan=$enableval ]) 37 | 38 | if test x"${ac_enable_debug}" = x"yes" ; then 39 | # Use debug flags 40 | tampi_CPPFLAGS="" 41 | tampi_CXXFLAGS="-Wall -Wextra -Wshadow -fvisibility=hidden -O0 -g3" 42 | else 43 | # Use optimized flags 44 | tampi_CPPFLAGS="-DNDEBUG" 45 | tampi_CXXFLAGS="-Wall -Wextra -Wshadow -fvisibility=hidden -O3" 46 | fi 47 | 48 | if test x"${ac_enable_asan}" = x"yes" ; then 49 | if test x"${ac_enable_debug}" = x"no" ; then 50 | AC_MSG_WARN([Enabling address sanitizer without enabling debug is not recommended]) 51 | fi 52 | 53 | # Enable address sanitizer flags 54 | ac_asan_flags="-fsanitize=address -fno-omit-frame-pointer" 55 | asan_CPPFLAGS="${ac_asan_flags}" 56 | asan_CXXFLAGS="${ac_asan_flags}" 57 | asan_LDFLAGS="${ac_asan_flags}" 58 | else 59 | asan_CPPFLAGS="" 60 | asan_CXXFLAGS="" 61 | asan_LDFLAGS="" 62 | fi 63 | 64 | AC_SUBST(tampi_CPPFLAGS) 65 | AC_SUBST(tampi_CXXFLAGS) 66 | 67 | AC_SUBST(asan_CPPFLAGS) 68 | AC_SUBST(asan_CXXFLAGS) 69 | AC_SUBST(asan_LDFLAGS) 70 | 71 | # Disable autoconf default compilation flags 72 | : ${CPPFLAGS=""} 73 | : ${CXXFLAGS=""} 74 | : ${CFLAGS=""} 75 | : ${LDFLAGS=""} 76 | ]) 77 | -------------------------------------------------------------------------------- /m4/modes.m4: -------------------------------------------------------------------------------- 1 | # 2 | # SYNOPSIS 3 | # 4 | # AX_CHECK_TAMPI_MODES 5 | # 6 | 7 | AC_DEFUN([AX_CHECK_TAMPI_MODES], [ 8 | AC_MSG_CHECKING([whether the blocking mode of TAMPI is enabled]) 9 | AC_ARG_ENABLE( 10 | [blocking-mode], 11 | [AS_HELP_STRING([--disable-blocking-mode], [do not compile the blocking mode of TAMPI @<:@default=enabled@:>@])], 12 | [ 13 | case "${enableval}" in 14 | yes) 15 | AC_MSG_RESULT([yes]) 16 | ac_blocking_mode=yes 17 | ;; 18 | no) 19 | AC_MSG_RESULT([no]) 20 | ac_blocking_mode=no 21 | ;; 22 | *) 23 | AC_MSG_ERROR([bad value ${enableval} for --disable-blocking-mode]) 24 | ;; 25 | esac 26 | ], 27 | [ 28 | AC_MSG_RESULT([yes]) 29 | ac_blocking_mode=yes 30 | ] 31 | ) 32 | if test x"${ac_blocking_mode}" = x"no" ; then 33 | AC_DEFINE([DISABLE_BLOCKING_MODE], 1, [Compile the blocking mode of TAMPI]) 34 | fi 35 | 36 | AC_MSG_CHECKING([whether the non-blocking mode of TAMPI is enabled]) 37 | AC_ARG_ENABLE( 38 | [nonblocking-mode], 39 | [AS_HELP_STRING([--disable-nonblocking-mode], [do not compile the non-blocking mode of TAMPI @<:@default=enabled@:>@])], 40 | [ 41 | case "${enableval}" in 42 | yes) 43 | AC_MSG_RESULT([yes]) 44 | ac_nonblocking_mode=yes 45 | ;; 46 | no) 47 | AC_MSG_RESULT([no]) 48 | ac_nonblocking_mode=no 49 | ;; 50 | *) 51 | AC_MSG_ERROR([bad value ${enableval} for --disable-nonblocking-mode]) 52 | ;; 53 | esac 54 | ], 55 | [ 56 | AC_MSG_RESULT([yes]) 57 | ac_nonblocking_mode=yes 58 | ] 59 | ) 60 | if test x"${ac_nonblocking_mode}" = x"no" ; then 61 | AC_DEFINE([DISABLE_NONBLOCKING_MODE], 1, [Compile the non-blocking mode of TAMPI]) 62 | fi 63 | 64 | if test x"${ac_blocking_mode}" = x"no" -a x"${ac_nonblocking_mode}" = x"no" ; then 65 | AC_MSG_ERROR([At least one of the TAMPI modes should be enabled]) 66 | fi 67 | ]) 68 | -------------------------------------------------------------------------------- /m4/ovni.m4: -------------------------------------------------------------------------------- 1 | # This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 2 | # 3 | # Copyright (C) 2022-2023 Barcelona Supercomputing Center (BSC) 4 | 5 | AC_DEFUN([AC_CHECK_OVNI], 6 | [ 7 | AC_ARG_WITH( 8 | [ovni], 9 | [AS_HELP_STRING([--with-ovni@<:@=DIR@:>@], [enable ovni and specify the ovni library installation prefix])], 10 | [ac_use_ovni_prefix="${withval}"], 11 | [ac_use_ovni_prefix="no"] 12 | ) 13 | 14 | ovni_LIBS="" 15 | ovni_CPPFLAGS="" 16 | ac_use_ovni=no 17 | 18 | AC_MSG_CHECKING([for the ovni installation]) 19 | if test x"${ac_use_ovni_prefix}" = x"no" ; then 20 | AC_MSG_RESULT([not enabled]) 21 | elif test x"${ac_use_ovni_prefix}" = x"" ; then 22 | AC_MSG_RESULT([invalid prefix]) 23 | AC_MSG_ERROR([ovni prefix specified but empty]) 24 | elif test x"${ac_use_ovni_prefix}" = x"yes" ; then 25 | AC_MSG_RESULT([enabled with no prefix]) 26 | 27 | # Check ovni header and library without adding any prefix 28 | AC_CHECK_HEADERS([ovni.h], [], [AC_MSG_ERROR([ovni ovni.h header file not found])]) 29 | AC_CHECK_LIB([ovni], [ovni_proc_init], 30 | [ac_use_ovni=yes], 31 | [AC_MSG_ERROR([libovni library not found])], 32 | [${LIBS}] 33 | ) 34 | 35 | ovni_LIBS="-lovni" 36 | else 37 | AC_MSG_RESULT([${ac_use_ovni_prefix}]) 38 | 39 | ac_save_CPPFLAGS="${CPPFLAGS}" 40 | ac_save_LIBS="${LIBS}" 41 | 42 | # Check ovni header 43 | ovni_CPPFLAGS="-I${ac_use_ovni_prefix}/include" 44 | CPPFLAGS="${ac_save_CPPFLAGS} ${ovni_CPPFLAGS}" 45 | 46 | AC_CHECK_HEADERS([ovni.h], [], [AC_MSG_ERROR([ovni ovni.h header file not found])]) 47 | 48 | # Check ovni library in lib and lib64 subdirectories 49 | for libsubdir in lib lib64 ; do 50 | # Avoid the cached results of previous AC_CHECK_LIB 51 | AS_UNSET(ac_cv_lib_ovni_ovni_proc_init) 52 | 53 | LIBS="${ac_save_LIBS} -L${ac_use_ovni_prefix}/${libsubdir}" 54 | 55 | AC_CHECK_LIB([ovni], [ovni_proc_init], [ac_use_ovni=yes], [], [${ac_save_LIBS}]) 56 | 57 | # Stop searching if found 58 | if test x"${ac_use_ovni}" = x"yes" ; then 59 | ac_use_ovni_libsubdir="${libsubdir}" 60 | break 61 | fi 62 | done 63 | 64 | if test x"${ac_use_ovni}" != x"yes" ; then 65 | AC_MSG_ERROR([libovni library not found]) 66 | fi 67 | 68 | ovni_LIBS="-lovni -L${ac_use_ovni_prefix}/${ac_use_ovni_libsubdir}" 69 | ovni_LIBS="${ovni_LIBS} -Wl,--enable-new-dtags -Wl,-rpath=${ac_use_ovni_prefix}/${ac_use_ovni_libsubdir}" 70 | 71 | CPPFLAGS="${ac_save_CPPFLAGS}" 72 | LIBS="${ac_save_LIBS}" 73 | fi 74 | 75 | AM_CONDITIONAL(HAVE_OVNI, test x"${ac_use_ovni}" = x"yes") 76 | if test x"${ac_use_ovni}" = x"yes" ; then 77 | AC_DEFINE([HAVE_OVNI], [1], [Define if ovni is enabled]) 78 | fi 79 | 80 | AC_SUBST([ovni_LIBS]) 81 | AC_SUBST([ovni_CPPFLAGS]) 82 | ] 83 | ) 84 | -------------------------------------------------------------------------------- /src/c/Allgather.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 21 | void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm) 22 | { 23 | if (Environment::isBlockingEnabledForCurrentThread()) { 24 | OperationManager::process(ALLGATHER, BLK, comm, sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype); 25 | return MPI_SUCCESS; 26 | } else { 27 | static Symbol::mpi_allgather_t> symbol(__func__); 28 | return symbol(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm); 29 | } 30 | } 31 | 32 | int TAMPI_Iallgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 33 | void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm) 34 | { 35 | if (Environment::isNonBlockingEnabled()) { 36 | OperationManager::process(ALLGATHER, NONBLK, comm, sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype); 37 | return MPI_SUCCESS; 38 | } else { 39 | ErrorHandler::fail(__func__, " not enabled"); 40 | return MPI_ERR_UNSUPPORTED_OPERATION; 41 | } 42 | } 43 | 44 | } // extern C 45 | 46 | #pragma GCC visibility pop 47 | -------------------------------------------------------------------------------- /src/c/Allgatherv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Allgatherv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, 21 | void* recvbuf, const int recvcounts[], const int displs[], 22 | MPI_Datatype recvtype, MPI_Comm comm) 23 | { 24 | if (Environment::isBlockingEnabledForCurrentThread()) { 25 | OperationManager::process(ALLGATHERV, BLK, comm, sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype); 26 | return MPI_SUCCESS; 27 | } else { 28 | static Symbol::mpi_allgatherv_t> symbol(__func__); 29 | return symbol(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, comm); 30 | } 31 | } 32 | 33 | int TAMPI_Iallgatherv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, 34 | void* recvbuf, const int recvcounts[], const int displs[], 35 | MPI_Datatype recvtype, MPI_Comm comm) 36 | { 37 | if (Environment::isNonBlockingEnabled()) { 38 | OperationManager::process(ALLGATHERV, NONBLK, comm, sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype); 39 | return MPI_SUCCESS; 40 | } else { 41 | ErrorHandler::fail(__func__, " not enabled"); 42 | return MPI_ERR_UNSUPPORTED_OPERATION; 43 | } 44 | } 45 | 46 | } // extern C 47 | 48 | #pragma GCC visibility pop 49 | -------------------------------------------------------------------------------- /src/c/Allreduce.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) 21 | { 22 | if (Environment::isBlockingEnabledForCurrentThread()) { 23 | OperationManager::process(ALLREDUCE, BLK, comm, sendbuf, count, datatype, recvbuf, count, datatype, op); 24 | return MPI_SUCCESS; 25 | } else { 26 | static Symbol::mpi_allreduce_t> symbol(__func__); 27 | return symbol(sendbuf, recvbuf, count, datatype, op, comm); 28 | } 29 | } 30 | 31 | int TAMPI_Iallreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) 32 | { 33 | if (Environment::isNonBlockingEnabled()) { 34 | OperationManager::process(ALLREDUCE, NONBLK, comm, sendbuf, count, datatype, recvbuf, count, datatype, op); 35 | return MPI_SUCCESS; 36 | } else { 37 | ErrorHandler::fail(__func__, " not enabled"); 38 | return MPI_ERR_UNSUPPORTED_OPERATION; 39 | } 40 | } 41 | 42 | } // extern C 43 | 44 | #pragma GCC visibility pop 45 | -------------------------------------------------------------------------------- /src/c/Alltoall.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Alltoall(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 21 | void *recvbuf, int recvcount, MPI_Datatype recvtype, 22 | MPI_Comm comm) 23 | { 24 | if (Environment::isBlockingEnabledForCurrentThread()) { 25 | OperationManager::process(ALLTOALL, BLK, comm, sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype); 26 | return MPI_SUCCESS; 27 | } else { 28 | static Symbol::mpi_alltoall_t> symbol(__func__); 29 | return symbol(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm); 30 | } 31 | } 32 | 33 | int TAMPI_Ialltoall(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 34 | void *recvbuf, int recvcount, MPI_Datatype recvtype, 35 | MPI_Comm comm) 36 | { 37 | if (Environment::isNonBlockingEnabled()) { 38 | OperationManager::process(ALLTOALL, NONBLK, comm, sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype); 39 | return MPI_SUCCESS; 40 | } else { 41 | ErrorHandler::fail(__func__, " not enabled"); 42 | return MPI_ERR_UNSUPPORTED_OPERATION; 43 | } 44 | } 45 | 46 | } // extern C 47 | 48 | #pragma GCC visibility pop 49 | -------------------------------------------------------------------------------- /src/c/Alltoallv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Alltoallv(const void *sendbuf, const int sendcounts[], const int sdispls[], MPI_Datatype sendtype, 21 | void *recvbuf, const int recvcounts[], const int rdispls[], MPI_Datatype recvtype, MPI_Comm comm) 22 | { 23 | if (Environment::isBlockingEnabledForCurrentThread()) { 24 | OperationManager::process(ALLTOALLV, BLK, comm, sendbuf, sendcounts, sdispls, sendtype, recvbuf, recvcounts, rdispls, recvtype); 25 | return MPI_SUCCESS; 26 | } else { 27 | static Symbol::mpi_alltoallv_t> symbol(__func__); 28 | return symbol(sendbuf, sendcounts, sdispls, sendtype, recvbuf, recvcounts, rdispls, recvtype, comm); 29 | } 30 | } 31 | 32 | int TAMPI_Ialltoallv(const void *sendbuf, const int sendcounts[], const int sdispls[], MPI_Datatype sendtype, 33 | void *recvbuf, const int recvcounts[], const int rdispls[], MPI_Datatype recvtype, MPI_Comm comm) 34 | { 35 | if (Environment::isNonBlockingEnabled()) { 36 | OperationManager::process(ALLTOALLV, NONBLK, comm, sendbuf, sendcounts, sdispls, sendtype, recvbuf, recvcounts, rdispls, recvtype); 37 | return MPI_SUCCESS; 38 | } else { 39 | ErrorHandler::fail(__func__, " not enabled"); 40 | return MPI_ERR_UNSUPPORTED_OPERATION; 41 | } 42 | } 43 | 44 | } // extern C 45 | 46 | #pragma GCC visibility pop 47 | -------------------------------------------------------------------------------- /src/c/Alltoallw.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Alltoallw(const void *sendbuf, const int sendcounts[], const int sdispls[], const MPI_Datatype sendtypes[], 21 | void *recvbuf, const int recvcounts[], const int rdispls[], const MPI_Datatype recvtypes[], MPI_Comm comm) 22 | { 23 | if (Environment::isBlockingEnabledForCurrentThread()) { 24 | OperationManager::process(ALLTOALLW, BLK, comm, sendbuf, sendcounts, sdispls, sendtypes, recvbuf, recvcounts, rdispls, recvtypes); 25 | return MPI_SUCCESS; 26 | } else { 27 | ErrorHandler::fail("TAMPI: ", __func__, " not supported"); 28 | return MPI_ERR_UNSUPPORTED_OPERATION; 29 | } 30 | } 31 | 32 | int TAMPI_Ialltoallw(const void *sendbuf, const int sendcounts[], const int sdispls[], const MPI_Datatype sendtypes[], 33 | void *recvbuf, const int recvcounts[], const int rdispls[], const MPI_Datatype recvtypes[], MPI_Comm comm) 34 | { 35 | if (Environment::isNonBlockingEnabled()) { 36 | OperationManager::process(ALLTOALLW, NONBLK, comm, sendbuf, sendcounts, sdispls, sendtypes, recvbuf, recvcounts, rdispls, recvtypes); 37 | return MPI_SUCCESS; 38 | } else { 39 | ErrorHandler::fail(__func__, " not enabled"); 40 | return MPI_ERR_UNSUPPORTED_OPERATION; 41 | } 42 | } 43 | 44 | } // extern C 45 | 46 | #pragma GCC visibility pop 47 | -------------------------------------------------------------------------------- /src/c/Barrier.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Barrier(MPI_Comm comm) 21 | { 22 | if (Environment::isBlockingEnabledForCurrentThread()) { 23 | OperationManager::process(BARRIER, BLK, comm, nullptr, 0, MPI_DATATYPE_NULL, nullptr, 0, MPI_DATATYPE_NULL); 24 | return MPI_SUCCESS; 25 | } else { 26 | static Symbol::mpi_barrier_t> symbol(__func__); 27 | return symbol(comm); 28 | } 29 | } 30 | 31 | int TAMPI_Ibarrier(MPI_Comm comm) 32 | { 33 | if (Environment::isNonBlockingEnabled()) { 34 | OperationManager::process(BARRIER, NONBLK, comm, nullptr, 0, MPI_DATATYPE_NULL, nullptr, 0, MPI_DATATYPE_NULL); 35 | return MPI_SUCCESS; 36 | } else { 37 | ErrorHandler::fail(__func__, " not enabled"); 38 | return MPI_ERR_UNSUPPORTED_OPERATION; 39 | } 40 | } 41 | 42 | } // extern C 43 | 44 | #pragma GCC visibility pop 45 | -------------------------------------------------------------------------------- /src/c/Bcast.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm) 21 | { 22 | if (Environment::isBlockingEnabledForCurrentThread()) { 23 | OperationManager::process(BCAST, BLK, comm, nullptr, 0, MPI_DATATYPE_NULL, buffer, count, datatype, MPI_OP_NULL, root); 24 | return MPI_SUCCESS; 25 | } else { 26 | static Symbol::mpi_bcast_t> symbol(__func__); 27 | return symbol(buffer, count, datatype, root, comm); 28 | } 29 | } 30 | 31 | int TAMPI_Ibcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm) 32 | { 33 | if (Environment::isNonBlockingEnabled()) { 34 | OperationManager::process(BCAST, NONBLK, comm, nullptr, 0, MPI_DATATYPE_NULL, buffer, count, datatype, MPI_OP_NULL, root); 35 | return MPI_SUCCESS; 36 | } else { 37 | ErrorHandler::fail(__func__, " not enabled"); 38 | return MPI_ERR_UNSUPPORTED_OPERATION; 39 | } 40 | } 41 | 42 | } // extern C 43 | 44 | #pragma GCC visibility pop 45 | -------------------------------------------------------------------------------- /src/c/Bsend.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Bsend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) 21 | { 22 | if (Environment::isBlockingEnabledForCurrentThread()) { 23 | OperationManager::process(BSEND, BLK, buf, count, datatype, dest, tag, comm); 24 | return MPI_SUCCESS; 25 | } else { 26 | static Symbol::mpi_bsend_t> symbol(__func__); 27 | return symbol(buf, count, datatype, dest, tag, comm); 28 | } 29 | } 30 | 31 | int TAMPI_Ibsend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) 32 | { 33 | if (Environment::isNonBlockingEnabled()) { 34 | OperationManager::process(BSEND, NONBLK, buf, count, datatype, dest, tag, comm); 35 | return MPI_SUCCESS; 36 | } else { 37 | ErrorHandler::fail(__func__, " not enabled"); 38 | return MPI_ERR_UNSUPPORTED_OPERATION; 39 | } 40 | } 41 | 42 | } // extern C 43 | 44 | #pragma GCC visibility pop 45 | -------------------------------------------------------------------------------- /src/c/Exscan.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "Interface.hpp" 12 | #include "OperationManager.hpp" 13 | #include "Symbol.hpp" 14 | 15 | using namespace tampi; 16 | 17 | #pragma GCC visibility push(default) 18 | 19 | extern "C" { 20 | 21 | int MPI_Exscan(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) 22 | { 23 | if (Environment::isBlockingEnabledForCurrentThread()) { 24 | OperationManager::process(EXSCAN, BLK, comm, sendbuf, count, datatype, recvbuf, 0, MPI_DATATYPE_NULL, op); 25 | return MPI_SUCCESS; 26 | } else { 27 | static Symbol::mpi_exscan_t> symbol(__func__); 28 | return symbol(sendbuf, recvbuf, count, datatype, op, comm); 29 | } 30 | } 31 | 32 | int TAMPI_Iexscan(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) 33 | { 34 | if (Environment::isNonBlockingEnabled()) { 35 | OperationManager::process(EXSCAN, NONBLK, comm, sendbuf, count, datatype, recvbuf, 0, MPI_DATATYPE_NULL, op); 36 | return MPI_SUCCESS; 37 | } else { 38 | ErrorHandler::fail(__func__, " not enabled"); 39 | return MPI_ERR_UNSUPPORTED_OPERATION; 40 | } 41 | } 42 | 43 | } // extern C 44 | 45 | #pragma GCC visibility pop 46 | -------------------------------------------------------------------------------- /src/c/Gather.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Gather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 21 | void *recvbuf, int recvcount, MPI_Datatype recvtype, 22 | int root, MPI_Comm comm) 23 | { 24 | if (Environment::isBlockingEnabledForCurrentThread()) { 25 | OperationManager::process(GATHER, BLK, comm, sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, MPI_OP_NULL, root); 26 | return MPI_SUCCESS; 27 | } else { 28 | static Symbol::mpi_gather_t> symbol(__func__); 29 | return symbol(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root, comm); 30 | } 31 | } 32 | 33 | int TAMPI_Igather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 34 | void *recvbuf, int recvcount, MPI_Datatype recvtype, 35 | int root, MPI_Comm comm) 36 | { 37 | if (Environment::isNonBlockingEnabled()) { 38 | OperationManager::process(GATHER, NONBLK, comm, sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, MPI_OP_NULL, root); 39 | return MPI_SUCCESS; 40 | } else { 41 | ErrorHandler::fail(__func__, " not enabled"); 42 | return MPI_ERR_UNSUPPORTED_OPERATION; 43 | } 44 | } 45 | 46 | } // extern C 47 | 48 | #pragma GCC visibility pop 49 | -------------------------------------------------------------------------------- /src/c/Gatherv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "Interface.hpp" 12 | #include "OperationManager.hpp" 13 | #include "Symbol.hpp" 14 | 15 | using namespace tampi; 16 | 17 | #pragma GCC visibility push(default) 18 | 19 | extern "C" { 20 | 21 | int MPI_Gatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 22 | void *recvbuf, const int recvcounts[], const int displs[], 23 | MPI_Datatype recvtype, int root, MPI_Comm comm) 24 | { 25 | if (Environment::isBlockingEnabledForCurrentThread()) { 26 | OperationManager::process(GATHERV, BLK, comm, sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, MPI_OP_NULL, root); 27 | return MPI_SUCCESS; 28 | } else { 29 | static Symbol::mpi_gatherv_t> symbol(__func__); 30 | return symbol(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, root, comm); 31 | } 32 | } 33 | 34 | int TAMPI_Igatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 35 | void *recvbuf, const int recvcounts[], const int displs[], 36 | MPI_Datatype recvtype, int root, MPI_Comm comm) 37 | { 38 | if (Environment::isNonBlockingEnabled()) { 39 | OperationManager::process(GATHERV, NONBLK, comm, sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, MPI_OP_NULL, root); 40 | return MPI_SUCCESS; 41 | } else { 42 | ErrorHandler::fail(__func__, " not enabled"); 43 | return MPI_ERR_UNSUPPORTED_OPERATION; 44 | } 45 | } 46 | 47 | } // extern C 48 | 49 | #pragma GCC visibility pop 50 | -------------------------------------------------------------------------------- /src/c/InitFinalize.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "TAMPI_Decl.h" 10 | 11 | #include "Declarations.hpp" 12 | #include "Environment.hpp" 13 | #include "Interface.hpp" 14 | #include "Symbol.hpp" 15 | #include "util/ErrorHandler.hpp" 16 | 17 | using namespace tampi; 18 | 19 | #pragma GCC visibility push(default) 20 | 21 | extern "C" { 22 | 23 | int MPI_Init(int *argc, char ***argv) 24 | { 25 | static Symbol::mpi_init_t> symbol(__func__); 26 | 27 | // Call MPI_Init 28 | int err = symbol(argc, argv); 29 | if (err != MPI_SUCCESS) 30 | return err; 31 | 32 | // Retrieve the default thread level 33 | int provided; 34 | err = MPI_Query_thread(&provided); 35 | if (err != MPI_SUCCESS) 36 | return err; 37 | 38 | // Prepare the MPI environment 39 | Environment::preinitialize(provided); 40 | 41 | // Attempt to auto initialize the library; no mode is enabled 42 | Environment::initialize(provided, &provided, /* auto */ true); 43 | 44 | return MPI_SUCCESS; 45 | } 46 | 47 | int MPI_Init_thread(int *argc, char ***argv, int required, int *provided) 48 | { 49 | static Symbol::mpi_init_thread_t> symbol(__func__); 50 | 51 | // When TAMPI is in explicit initialization mode, the MPI_Init_thread acts 52 | // as the standard call and does not support MPI_TASK_MULTIPLE. In such 53 | // case, MPI_Init_thread must be called with MPI_THREAD_MULTIPLE, and then, 54 | // TAMPI_Init can be called with MPI_TASK_MULTIPLE 55 | if (!Environment::isAutoInitializeEnabled() && required == MPI_TASK_MULTIPLE) 56 | ErrorHandler::fail("The MPI_TASK_MULTIPLE must be passed to TAMPI_Init"); 57 | 58 | // Assuming that MPI does not provide MPI_TASK_MULTIPLE 59 | int irequired = required; 60 | if (required == MPI_TASK_MULTIPLE) 61 | irequired = MPI_THREAD_MULTIPLE; 62 | 63 | // Call MPI_Init_thread 64 | int err = symbol(argc, argv, irequired, provided); 65 | if (err != MPI_SUCCESS) 66 | return err; 67 | 68 | // Prepare the MPI enviornment 69 | Environment::preinitialize(*provided); 70 | 71 | // Attempt to auto initialize the library 72 | Environment::initialize(required, provided, /* auto */ true); 73 | 74 | return MPI_SUCCESS; 75 | } 76 | 77 | int MPI_Finalize(void) 78 | { 79 | static Symbol::mpi_finalize_t> symbol(__func__); 80 | 81 | // Call MPI_Finalize 82 | int err = symbol(); 83 | if (err != MPI_SUCCESS) 84 | return err; 85 | 86 | // Attempt to finalize the library 87 | Environment::finalize(/* auto */ true); 88 | 89 | return MPI_SUCCESS; 90 | } 91 | 92 | int TAMPI_Init(int required, int *provided) 93 | { 94 | // Explicitly initialize the library 95 | Environment::initialize(required, provided, /* auto */ false); 96 | 97 | return MPI_SUCCESS; 98 | } 99 | 100 | int TAMPI_Finalize(void) 101 | { 102 | // Explicitly finalize the library 103 | Environment::finalize(/* auto */ false); 104 | 105 | return MPI_SUCCESS; 106 | } 107 | 108 | } // extern C 109 | 110 | #pragma GCC visibility pop 111 | -------------------------------------------------------------------------------- /src/c/Recv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status) 21 | { 22 | if (Environment::isBlockingEnabledForCurrentThread()) { 23 | OperationManager::process(RECV, BLK, buf, count, datatype, source, tag, comm, status); 24 | return MPI_SUCCESS; 25 | } else { 26 | static Symbol::mpi_recv_t> symbol(__func__); 27 | return symbol(buf, count, datatype, source, tag, comm, status); 28 | } 29 | } 30 | 31 | int TAMPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status) 32 | { 33 | if (Environment::isNonBlockingEnabled()) { 34 | OperationManager::process(RECV, NONBLK, buf, count, datatype, source, tag, comm, status); 35 | return MPI_SUCCESS; 36 | } else { 37 | ErrorHandler::fail(__func__, " not enabled"); 38 | return MPI_ERR_UNSUPPORTED_OPERATION; 39 | } 40 | } 41 | 42 | } // extern C 43 | 44 | #pragma GCC visibility pop 45 | -------------------------------------------------------------------------------- /src/c/Reduce.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Reduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm) 21 | { 22 | if (Environment::isBlockingEnabledForCurrentThread()) { 23 | OperationManager::process(REDUCE, BLK, comm, sendbuf, count, datatype, recvbuf, count, datatype, op, root); 24 | return MPI_SUCCESS; 25 | } else { 26 | static Symbol::mpi_reduce_t> symbol(__func__); 27 | return symbol(sendbuf, recvbuf, count, datatype, op, root, comm); 28 | } 29 | } 30 | 31 | int TAMPI_Ireduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm) 32 | { 33 | if (Environment::isNonBlockingEnabled()) { 34 | OperationManager::process(REDUCE, NONBLK, comm, sendbuf, count, datatype, recvbuf, count, datatype, op, root); 35 | return MPI_SUCCESS; 36 | } else { 37 | ErrorHandler::fail(__func__, " not enabled"); 38 | return MPI_ERR_UNSUPPORTED_OPERATION; 39 | } 40 | } 41 | 42 | } // extern C 43 | 44 | #pragma GCC visibility pop 45 | -------------------------------------------------------------------------------- /src/c/Reducescatter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Reduce_scatter(const void *sendbuf, void *recvbuf, const int recvcounts[], MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) 21 | { 22 | if (Environment::isBlockingEnabledForCurrentThread()) { 23 | OperationManager::process(REDUCESCATTER, BLK, comm, sendbuf, 0, datatype, recvbuf, recvcounts, nullptr, MPI_DATATYPE_NULL, op); 24 | return MPI_SUCCESS; 25 | } else { 26 | static Symbol::mpi_reduce_scatter_t> symbol(__func__); 27 | return symbol(sendbuf, recvbuf, recvcounts, datatype, op, comm); 28 | } 29 | } 30 | 31 | int TAMPI_Ireduce_scatter(const void *sendbuf, void *recvbuf, const int recvcounts[], MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) 32 | { 33 | if (Environment::isNonBlockingEnabled()) { 34 | OperationManager::process(REDUCESCATTER, NONBLK, comm, sendbuf, 0, datatype, recvbuf, recvcounts, nullptr, MPI_DATATYPE_NULL, op); 35 | return MPI_SUCCESS; 36 | } else { 37 | ErrorHandler::fail(__func__, " not enabled"); 38 | return MPI_ERR_UNSUPPORTED_OPERATION; 39 | } 40 | } 41 | 42 | } // extern C 43 | 44 | #pragma GCC visibility pop 45 | -------------------------------------------------------------------------------- /src/c/Reducescatterblock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Reduce_scatter_block(const void *sendbuf, void *recvbuf, int recvcount, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) 21 | { 22 | if (Environment::isBlockingEnabledForCurrentThread()) { 23 | OperationManager::process(REDUCESCATTERBLOCK, BLK, comm, sendbuf, 0, datatype, recvbuf, recvcount, MPI_DATATYPE_NULL, op); 24 | return MPI_SUCCESS; 25 | } else { 26 | static Symbol::mpi_reduce_scatter_block_t> symbol(__func__); 27 | return symbol(sendbuf, recvbuf, recvcount, datatype, op, comm); 28 | } 29 | } 30 | 31 | int TAMPI_Ireduce_scatter_block(const void *sendbuf, void *recvbuf, int recvcount, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) 32 | { 33 | if (Environment::isNonBlockingEnabled()) { 34 | OperationManager::process(REDUCESCATTERBLOCK, NONBLK, comm, sendbuf, 0, datatype, recvbuf, recvcount, MPI_DATATYPE_NULL, op); 35 | return MPI_SUCCESS; 36 | } else { 37 | ErrorHandler::fail(__func__, " not enabled"); 38 | return MPI_ERR_UNSUPPORTED_OPERATION; 39 | } 40 | } 41 | 42 | } // extern C 43 | 44 | #pragma GCC visibility pop 45 | -------------------------------------------------------------------------------- /src/c/Rsend.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Rsend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) 21 | { 22 | if (Environment::isBlockingEnabledForCurrentThread()) { 23 | OperationManager::process(RSEND, BLK, buf, count, datatype, dest, tag, comm); 24 | return MPI_SUCCESS; 25 | } else { 26 | static Symbol::mpi_rsend_t> symbol(__func__); 27 | return symbol(buf, count, datatype, dest, tag, comm); 28 | } 29 | } 30 | 31 | int TAMPI_Irsend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) 32 | { 33 | if (Environment::isNonBlockingEnabled()) { 34 | OperationManager::process(RSEND, NONBLK, buf, count, datatype, dest, tag, comm); 35 | return MPI_SUCCESS; 36 | } else { 37 | ErrorHandler::fail(__func__, " not enabled"); 38 | return MPI_ERR_UNSUPPORTED_OPERATION; 39 | } 40 | } 41 | 42 | } // extern C 43 | 44 | #pragma GCC visibility pop 45 | -------------------------------------------------------------------------------- /src/c/Scan.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Scan(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) 21 | { 22 | if (Environment::isBlockingEnabledForCurrentThread()) { 23 | OperationManager::process(SCAN, BLK, comm, sendbuf, count, datatype, recvbuf, 0, MPI_DATATYPE_NULL, op); 24 | return MPI_SUCCESS; 25 | } else { 26 | static Symbol::mpi_scan_t> symbol(__func__); 27 | return symbol(sendbuf, recvbuf, count, datatype, op, comm); 28 | } 29 | } 30 | 31 | int TAMPI_Iscan(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) 32 | { 33 | if (Environment::isNonBlockingEnabled()) { 34 | OperationManager::process(SCAN, NONBLK, comm, sendbuf, count, datatype, recvbuf, 0, MPI_DATATYPE_NULL, op); 35 | return MPI_SUCCESS; 36 | } else { 37 | ErrorHandler::fail(__func__, " not enabled"); 38 | return MPI_ERR_UNSUPPORTED_OPERATION; 39 | } 40 | } 41 | 42 | } // extern C 43 | 44 | #pragma GCC visibility pop 45 | -------------------------------------------------------------------------------- /src/c/Scatter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Scatter(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 21 | void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm) 22 | { 23 | if (Environment::isBlockingEnabledForCurrentThread()) { 24 | OperationManager::process(SCATTER, BLK, comm, sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, MPI_OP_NULL, root); 25 | return MPI_SUCCESS; 26 | } else { 27 | static Symbol::mpi_scatter_t> symbol(__func__); 28 | return symbol(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root, comm); 29 | } 30 | } 31 | 32 | int TAMPI_Iscatter(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 33 | void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm) 34 | { 35 | if (Environment::isNonBlockingEnabled()) { 36 | OperationManager::process(SCATTER, NONBLK, comm, sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, MPI_OP_NULL, root); 37 | return MPI_SUCCESS; 38 | } else { 39 | ErrorHandler::fail(__func__, " not enabled"); 40 | return MPI_ERR_UNSUPPORTED_OPERATION; 41 | } 42 | } 43 | 44 | } // extern C 45 | 46 | #pragma GCC visibility pop 47 | -------------------------------------------------------------------------------- /src/c/Scatterv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Scatterv(const void* sendbuf, const int sendcounts[], const int displs[], MPI_Datatype sendtype, 21 | void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm) 22 | { 23 | if (Environment::isBlockingEnabledForCurrentThread()) { 24 | OperationManager::process(SCATTERV, BLK, comm, sendbuf, sendcounts, displs, sendtype, recvbuf, recvcount, recvtype, MPI_OP_NULL, root); 25 | return MPI_SUCCESS; 26 | } else { 27 | static Symbol::mpi_scatterv_t> symbol(__func__); 28 | return symbol(sendbuf, sendcounts, displs, sendtype, recvbuf, recvcount, recvtype, root, comm); 29 | } 30 | } 31 | 32 | int TAMPI_Iscatterv(const void* sendbuf, const int sendcounts[], const int displs[], MPI_Datatype sendtype, 33 | void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm) 34 | { 35 | if (Environment::isNonBlockingEnabled()) { 36 | OperationManager::process(SCATTERV, NONBLK, comm, sendbuf, sendcounts, displs, sendtype, recvbuf, recvcount, recvtype, MPI_OP_NULL, root); 37 | return MPI_SUCCESS; 38 | } else { 39 | ErrorHandler::fail(__func__, " not enabled"); 40 | return MPI_ERR_UNSUPPORTED_OPERATION; 41 | } 42 | } 43 | 44 | } // extern C 45 | 46 | #pragma GCC visibility pop 47 | -------------------------------------------------------------------------------- /src/c/Send.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) 21 | { 22 | if (Environment::isBlockingEnabledForCurrentThread()) { 23 | OperationManager::process(SEND, BLK, buf, count, datatype, dest, tag, comm); 24 | return MPI_SUCCESS; 25 | } else { 26 | static Symbol::mpi_send_t> symbol(__func__); 27 | return symbol(buf, count, datatype, dest, tag, comm); 28 | } 29 | } 30 | 31 | int TAMPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) 32 | { 33 | if (Environment::isNonBlockingEnabled()) { 34 | OperationManager::process(SEND, NONBLK, buf, count, datatype, dest, tag, comm); 35 | return MPI_SUCCESS; 36 | } else { 37 | ErrorHandler::fail(__func__, " not enabled"); 38 | return MPI_ERR_UNSUPPORTED_OPERATION; 39 | } 40 | } 41 | 42 | } // extern C 43 | 44 | #pragma GCC visibility pop 45 | -------------------------------------------------------------------------------- /src/c/Ssend.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "OperationManager.hpp" 12 | #include "Symbol.hpp" 13 | 14 | using namespace tampi; 15 | 16 | #pragma GCC visibility push(default) 17 | 18 | extern "C" { 19 | 20 | int MPI_Ssend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) 21 | { 22 | if (Environment::isBlockingEnabledForCurrentThread()) { 23 | OperationManager::process(SSEND, BLK, buf, count, datatype, dest, tag, comm); 24 | return MPI_SUCCESS; 25 | } else { 26 | static Symbol::mpi_ssend_t> symbol(__func__); 27 | return symbol(buf, count, datatype, dest, tag, comm); 28 | } 29 | } 30 | 31 | int TAMPI_Issend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) 32 | { 33 | if (Environment::isNonBlockingEnabled()) { 34 | OperationManager::process(SSEND, NONBLK, buf, count, datatype, dest, tag, comm); 35 | return MPI_SUCCESS; 36 | } else { 37 | ErrorHandler::fail(__func__, " not enabled"); 38 | return MPI_ERR_UNSUPPORTED_OPERATION; 39 | } 40 | } 41 | 42 | } // extern C 43 | 44 | #pragma GCC visibility pop 45 | -------------------------------------------------------------------------------- /src/c/Utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "TAMPI_Decl.h" 10 | 11 | #include "Declarations.hpp" 12 | #include "Environment.hpp" 13 | #include "Interface.hpp" 14 | #include "Symbol.hpp" 15 | 16 | using namespace tampi; 17 | 18 | #pragma GCC visibility push(default) 19 | 20 | extern "C" { 21 | 22 | int MPI_Query_thread(int *provided) 23 | { 24 | assert(provided != nullptr); 25 | 26 | int blocking = 0; 27 | int err = Environment::getProperty(TAMPI_PROPERTY_BLOCKING_MODE, &blocking); 28 | if (err) 29 | return MPI_ERR_ARG; 30 | 31 | if (blocking) { 32 | *provided = MPI_TASK_MULTIPLE; 33 | } else { 34 | static Symbol::mpi_query_thread_t> symbol(__func__); 35 | return symbol(provided); 36 | } 37 | return MPI_SUCCESS; 38 | } 39 | 40 | int TAMPI_Blocking_enabled(int *flag) 41 | { 42 | assert(flag != nullptr); 43 | 44 | int err = Environment::getProperty(TAMPI_PROPERTY_BLOCKING_MODE, flag); 45 | if (err) 46 | return MPI_ERR_ARG; 47 | 48 | return MPI_SUCCESS; 49 | } 50 | 51 | int TAMPI_Nonblocking_enabled(int *flag) 52 | { 53 | assert(flag != nullptr); 54 | 55 | int err = Environment::getProperty(TAMPI_PROPERTY_NONBLOCKING_MODE, flag); 56 | if (err) 57 | return MPI_ERR_ARG; 58 | 59 | return MPI_SUCCESS; 60 | } 61 | 62 | int TAMPI_Property_get(int property, int *value) 63 | { 64 | assert(value != nullptr); 65 | 66 | int err = Environment::getProperty(property, value); 67 | if (err) 68 | return MPI_ERR_ARG; 69 | 70 | return MPI_SUCCESS; 71 | } 72 | 73 | int TAMPI_Property_set(int property, int value) 74 | { 75 | int err = Environment::setProperty(property, value); 76 | if (err) 77 | return MPI_ERR_ARG; 78 | 79 | return MPI_SUCCESS; 80 | } 81 | 82 | } // extern C 83 | 84 | #pragma GCC visibility pop 85 | -------------------------------------------------------------------------------- /src/c/Wait.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Declarations.hpp" 10 | #include "Environment.hpp" 11 | #include "Symbol.hpp" 12 | 13 | using namespace tampi; 14 | 15 | #pragma GCC visibility push(default) 16 | 17 | extern "C" { 18 | 19 | int MPI_Wait(MPI_Request *request, MPI_Status *status) 20 | { 21 | if (Environment::isBlockingEnabledForCurrentThread()) { 22 | ErrorHandler::fail(__func__, " with task-aware behavior not supported"); 23 | return MPI_ERR_UNSUPPORTED_OPERATION; 24 | } else { 25 | static Symbol::mpi_wait_t> symbol(__func__); 26 | return symbol(request, status); 27 | } 28 | } 29 | 30 | int MPI_Waitall(int count, MPI_Request array_of_requests[], MPI_Status array_of_statuses[]) 31 | { 32 | if (Environment::isBlockingEnabledForCurrentThread()) { 33 | ErrorHandler::fail(__func__, " with task-aware behavior not supported"); 34 | return MPI_ERR_UNSUPPORTED_OPERATION; 35 | } else { 36 | static Symbol::mpi_waitall_t> symbol(__func__); 37 | return symbol(count, array_of_requests, array_of_statuses); 38 | } 39 | } 40 | 41 | int TAMPI_Iwait(MPI_Request *, MPI_Status *) 42 | { 43 | ErrorHandler::fail(__func__, " not supported"); 44 | return MPI_ERR_UNSUPPORTED_OPERATION; 45 | } 46 | 47 | int TAMPI_Iwaitall(int, MPI_Request [], MPI_Status []) 48 | { 49 | ErrorHandler::fail("TAMPI: ", __func__, " not supported"); 50 | return MPI_ERR_UNSUPPORTED_OPERATION; 51 | } 52 | 53 | } // extern C 54 | 55 | #pragma GCC visibility pop 56 | -------------------------------------------------------------------------------- /src/common/Allocator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include "Allocator.hpp" 8 | #include "Declarations.hpp" 9 | #include "Operation.hpp" 10 | 11 | 12 | namespace tampi { 13 | 14 | void Allocator::initialize() 15 | { 16 | ObjAllocator>::_instance = 17 | new ObjAllocator>(OperationCapacity); 18 | ObjAllocator>::_instance = 19 | new ObjAllocator>(CollOperationCapacity); 20 | } 21 | 22 | void Allocator::finalize() 23 | { 24 | delete ObjAllocator>::_instance; 25 | delete ObjAllocator>::_instance; 26 | ObjAllocator>::_instance = nullptr; 27 | ObjAllocator>::_instance = nullptr; 28 | } 29 | 30 | } // namespace tampi 31 | -------------------------------------------------------------------------------- /src/common/CompletionManager.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef COMPLETION_MANAGER_HPP 8 | #define COMPLETION_MANAGER_HPP 9 | 10 | #include 11 | 12 | #include 13 | 14 | // Support for BOOST 1.67 15 | #if BOOST_VERSION == 106700 16 | #include 17 | #endif 18 | 19 | #include 20 | 21 | #include "TaskContext.hpp" 22 | #include "instrument/Instrument.hpp" 23 | #include "util/EnvironmentVariable.hpp" 24 | #include "util/ErrorHandler.hpp" 25 | 26 | 27 | namespace tampi { 28 | 29 | class CompletionManager { 30 | private: 31 | static constexpr size_t Size = 32*1024; 32 | 33 | typedef boost::lockfree::spsc_queue > queue_t; 34 | 35 | static EnvironmentVariable _enabled; 36 | 37 | static queue_t _queue; 38 | 39 | public: 40 | CompletionManager() = delete; 41 | CompletionManager(const CompletionManager &) = delete; 42 | const CompletionManager& operator= (const CompletionManager &) = delete; 43 | 44 | static void transfer(const TaskContext *contexts, size_t count) 45 | { 46 | size_t pushed = _queue.push(contexts, count); 47 | if (pushed != count) 48 | ErrorHandler::fail("Failed to push task contexts"); 49 | } 50 | 51 | static size_t process() 52 | { 53 | if (!_queue.read_available()) 54 | return 0; 55 | 56 | Instrument::Guard instrGuard; 57 | 58 | // Complete all task contexts 59 | return _queue.consume_all( 60 | [&](TaskContext &context) { 61 | context.completeEvents(1, true); 62 | }); 63 | } 64 | 65 | static bool isEnabled() 66 | { 67 | return _enabled; 68 | } 69 | }; 70 | 71 | } // namespace tampi 72 | 73 | #endif // COMPLETION_MANAGER_HPP 74 | -------------------------------------------------------------------------------- /src/common/Environment.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | 9 | #include "Environment.hpp" 10 | #include "polling/Polling.hpp" 11 | #include "util/ErrorHandler.hpp" 12 | 13 | 14 | namespace tampi { 15 | 16 | Environment::State Environment::_state; 17 | thread_local bool Environment::State::threadTaskAwareness = true; 18 | 19 | TaskingModel::PollingInstance *Polling::_pollingInstance; 20 | TaskingModel::PollingInstance *Polling::_completionPollingInstance; 21 | PollingPeriodCtrl Polling::_periodCtrl("TAMPI_POLLING_PERIOD"); 22 | PollingPeriodCtrl Polling::_completionPeriodCtrl("TAMPI_POLLING_TASK_COMPLETION_PERIOD"); 23 | 24 | EnvironmentVariable CompletionManager::_enabled("TAMPI_POLLING_TASK_COMPLETION", true); 25 | CompletionManager::queue_t CompletionManager::_queue; 26 | 27 | std::mutex ErrorHandler::_lock; 28 | 29 | } // namespace tampi 30 | 31 | #if !defined(NDEBUG) 32 | namespace boost { 33 | void assertion_failed_msg(char const * expr, char const * msg, char const * function, char const * file, long line) 34 | { 35 | fprintf(stderr, "%s:%ld %s Boost assertion failure: %s when evaluating %s\n", file, line, function, msg, expr); 36 | abort(); 37 | } 38 | 39 | void assertion_failed(char const * expr, char const * function, char const * file, long line) 40 | { 41 | fprintf(stderr, "%s:%ld %s Boost assertion failure when evaluating %s\n", file, line, function, expr); 42 | abort(); 43 | } 44 | } 45 | #endif 46 | -------------------------------------------------------------------------------- /src/common/Operation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include "Interface.hpp" 8 | #include "Operation.hpp" 9 | 10 | namespace tampi { 11 | 12 | template <> 13 | Operation::request_t Operation::issue() 14 | { 15 | int err = MPI_SUCCESS; 16 | request_t request = Interface::REQUEST_NULL; 17 | 18 | switch (_code) { 19 | case SEND: 20 | err = Interface::mpi_isend(_buffer, _count, _datatype, _rank, _tag, _comm, &request); 21 | break; 22 | case BSEND: 23 | err = Interface::mpi_ibsend(_buffer, _count, _datatype, _rank, _tag, _comm, &request); 24 | break; 25 | case RSEND: 26 | err = Interface::mpi_irsend(_buffer, _count, _datatype, _rank, _tag, _comm, &request); 27 | break; 28 | case SSEND: 29 | err = Interface::mpi_issend(_buffer, _count, _datatype, _rank, _tag, _comm, &request); 30 | break; 31 | case RECV: 32 | err = Interface::mpi_irecv(_buffer, _count, _datatype, _rank, _tag, _comm, &request); 33 | break; 34 | default: 35 | ErrorHandler::fail("Invalid operation ", _code); 36 | break; 37 | } 38 | 39 | if (err != MPI_SUCCESS) 40 | ErrorHandler::fail("Operation with code ", _code, " failed"); 41 | 42 | return request; 43 | } 44 | 45 | template <> 46 | Operation::request_t CollOperation::issue() 47 | { 48 | int err = MPI_SUCCESS; 49 | request_t request = Interface::REQUEST_NULL; 50 | 51 | switch (_code) { 52 | case ALLGATHER: 53 | err = Interface::mpi_iallgather(_sendbuf, _sendcount, _sendtype, _recvbuf, _recvcount, _recvtype, _comm, &request); 54 | break; 55 | case ALLGATHERV: 56 | err = Interface::mpi_iallgatherv(_sendbuf, _sendcount, _sendtype, _recvbuf, _recvcounts, _recvdispls, _recvtype, _comm, &request); 57 | break; 58 | case ALLREDUCE: 59 | err = Interface::mpi_iallreduce(_sendbuf, _recvbuf, _sendcount, _sendtype, _op, _comm, &request); 60 | break; 61 | case ALLTOALL: 62 | err = Interface::mpi_ialltoall(_sendbuf, _sendcount, _sendtype, _recvbuf, _recvcount, _recvtype, _comm, &request); 63 | break; 64 | case ALLTOALLV: 65 | err = Interface::mpi_ialltoallv(_sendbuf, _sendcounts, _senddispls, _sendtype, _recvbuf, _recvcounts, _recvdispls, _recvtype, _comm, &request); 66 | break; 67 | case ALLTOALLW: 68 | err = Interface::mpi_ialltoallw(_sendbuf, _sendcounts, _senddispls, _sendtypes, _recvbuf, _recvcounts, _recvdispls, _recvtypes, _comm, &request); 69 | break; 70 | case BARRIER: 71 | err = Interface::mpi_ibarrier(_comm, &request); 72 | break; 73 | case BCAST: 74 | err = Interface::mpi_ibcast(_recvbuf, _recvcount, _recvtype, _rank, _comm, &request); 75 | break; 76 | case EXSCAN: 77 | err = Interface::mpi_iexscan(_sendbuf, _recvbuf, _sendcount, _sendtype, _op, _comm, &request); 78 | break; 79 | case GATHER: 80 | err = Interface::mpi_igather(_sendbuf, _sendcount, _sendtype, _recvbuf, _recvcount, _recvtype, _rank, _comm, &request); 81 | break; 82 | case GATHERV: 83 | err = Interface::mpi_igatherv(_sendbuf, _sendcount, _sendtype, _recvbuf, _recvcounts, _recvdispls, _recvtype, _rank, _comm, &request); 84 | break; 85 | case REDUCE: 86 | err = Interface::mpi_ireduce(_sendbuf, _recvbuf, _sendcount, _sendtype, _op, _rank, _comm, &request); 87 | break; 88 | case REDUCESCATTER: 89 | err = Interface::mpi_ireduce_scatter(_sendbuf, _recvbuf, _recvcounts, _sendtype, _op, _comm, &request); 90 | break; 91 | case REDUCESCATTERBLOCK: 92 | err = Interface::mpi_ireduce_scatter_block(_sendbuf, _recvbuf, _recvcount, _sendtype, _op, _comm, &request); 93 | break; 94 | case SCAN: 95 | err = Interface::mpi_iscan(_sendbuf, _recvbuf, _sendcount, _sendtype, _op, _comm, &request); 96 | break; 97 | case SCATTER: 98 | err = Interface::mpi_iscatter(_sendbuf, _sendcount, _sendtype, _recvbuf, _recvcount, _recvtype, _rank, _comm, &request); 99 | break; 100 | case SCATTERV: 101 | err = Interface::mpi_iscatterv(_sendbuf, _sendcounts, _senddispls, _sendtype, _recvbuf, _recvcount, _recvtype, _rank, _comm, &request); 102 | break; 103 | default: 104 | ErrorHandler::fail("Invalid large operation ", _code); 105 | break; 106 | } 107 | 108 | if (err != MPI_SUCCESS) 109 | ErrorHandler::fail("Operation with code", _code, " failed"); 110 | 111 | return request; 112 | } 113 | 114 | template <> 115 | Types::request_t Operation::issue() 116 | { 117 | ErrorHandler::fail("Fortran not supported"); 118 | return Interface::REQUEST_NULL; 119 | } 120 | 121 | template <> 122 | Types::request_t CollOperation::issue() 123 | { 124 | ErrorHandler::fail("Fortran not supported"); 125 | return Interface::REQUEST_NULL; 126 | } 127 | 128 | } // namespace tampi 129 | -------------------------------------------------------------------------------- /src/common/OperationManager.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef OPERATION_MANAGER_HPP 8 | #define OPERATION_MANAGER_HPP 9 | 10 | #include 11 | #include 12 | 13 | #include "Allocator.hpp" 14 | #include "Operation.hpp" 15 | #include "Interface.hpp" 16 | #include "Ticket.hpp" 17 | #include "TicketManager.hpp" 18 | #include "instrument/Instrument.hpp" 19 | #include "util/ArrayView.hpp" 20 | #include "util/ErrorHandler.hpp" 21 | 22 | namespace tampi { 23 | 24 | //! Class that manages the operations generated by user tasks. It is responsible 25 | //! for creating the operation and delegating its processing to the polling task 26 | template typename Op> 27 | class OperationManager { 28 | private: 29 | typedef typename Types::request_t request_t; 30 | typedef typename Types::status_t status_t; 31 | typedef typename Types::status_ptr_t status_ptr_t; 32 | typedef tampi::TicketManager TicketManager; 33 | typedef tampi::Ticket Ticket; 34 | 35 | public: 36 | //! \brief Process a task-aware operation generated by a user task 37 | //! 38 | //! The operation is contructed and delegated to the polling task through 39 | //! the ticket manager. An operation can be blocking (pausing the calling 40 | //! task) or non-blocking (registering an external event on the calling 41 | //! task). The type of the operation is determined by the Op parameter of 42 | //! the class 43 | //! 44 | //! Once the underlying MPI operation is issued and finished, the status is 45 | //! saved in the specified location (if any), and the task is resumed or the 46 | //! external event is fulfilled 47 | //! 48 | //! \param code The code of the operation: send, recv, etc 49 | //! \param nature The nature of the operation: blocking or non-blocking 50 | //! \param args The rest of arguments to construct the operation 51 | template 52 | static void process(OpCode code, OpNature nature, Args &&... args) 53 | { 54 | Instrument::Guard instrGuard1; 55 | 56 | // Construct a task context 57 | TaskContext taskContext(nature == BLK); 58 | taskContext.bindEvents(1); 59 | 60 | // Allocate and construct the operation 61 | Op *operation = Allocator::alloc>( 62 | taskContext.getTaskHandle(), code, nature, 63 | std::forward(args)...); 64 | 65 | // Delegate the processing of the operation 66 | TicketManager &manager = TicketManager::get(); 67 | manager.addOperation(operation); 68 | 69 | // Wait the operation if it is blocking 70 | if (taskContext.isBlocking()) { 71 | Instrument::Guard instrGuard2; 72 | taskContext.waitEventsCompletion(); 73 | } 74 | } 75 | }; 76 | 77 | } // namespace tampi 78 | 79 | #endif // OPERATION_MANAGER_HPP 80 | -------------------------------------------------------------------------------- /src/common/Symbol.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef SYMBOL_HPP 8 | #define SYMBOL_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "util/ErrorHandler.hpp" 15 | 16 | namespace tampi { 17 | 18 | //! \brief Utility class to store function prototypes 19 | template 20 | class SymbolDecl { 21 | public: 22 | //! The return type of the function 23 | typedef Ret ReturnTy; 24 | 25 | //! The complete function prototype 26 | typedef Ret SymbolTy(Params...); 27 | }; 28 | 29 | //! \brief The attributes when loading symbols with Symbol::load 30 | enum class SymbolAttr { 31 | //! The default behavior when loading symbols. The default 32 | //! policy loads the next occurence of the symbol (RTLD_NEXT) 33 | //! and the loading is mandatory 34 | Next = 0, 35 | //! Load the first occurence of the symbol (RTLD_DEFAULT) 36 | First, 37 | }; 38 | 39 | //! Class that allows the dynamic loading of symbols at run-time 40 | template 41 | class Symbol { 42 | protected: 43 | using SymbolTy = typename SymbolDecl::SymbolTy; 44 | using ReturnTy = typename SymbolDecl::ReturnTy; 45 | 46 | //! The symbol name 47 | std::string_view _name; 48 | 49 | //! The loaded symbol or nullptr 50 | SymbolTy *_symbol; 51 | 52 | public: 53 | Symbol(std::string_view name, bool preload = true) : 54 | _name(name), _symbol(nullptr) 55 | { 56 | if (preload) 57 | load(); 58 | } 59 | 60 | //! \brief Load the symbol if not already loaded 61 | //! 62 | //! \param attr The attribute to load the symbol 63 | //! \param mandatory Whether the symbol is mandatory 64 | bool load(SymbolAttr attr = SymbolAttr::Next, bool mandatory = true) 65 | { 66 | // Do nothing if it was already loaded 67 | if (_symbol != nullptr) 68 | return true; 69 | 70 | void *handle = (attr == SymbolAttr::Next) ? RTLD_NEXT : RTLD_DEFAULT; 71 | 72 | _symbol = (SymbolTy *) dlsym(handle, _name.data()); 73 | if (_symbol == nullptr && mandatory) 74 | ErrorHandler::fail("Could not find symbol ", _name); 75 | 76 | return (_symbol != nullptr); 77 | } 78 | 79 | //! \brief Indicate whether the symbol is loaded 80 | bool hasSymbol() const 81 | { 82 | return (_symbol != nullptr); 83 | } 84 | 85 | //! \brief Execute the function 86 | template 87 | ReturnTy operator()(Params &&... params) const 88 | { 89 | assert(_symbol != nullptr); 90 | return (*_symbol)(std::forward(params)...); 91 | } 92 | }; 93 | 94 | } // namespace tampi 95 | 96 | #endif // SYMBOL_HPP 97 | -------------------------------------------------------------------------------- /src/common/TaskContext.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef TASK_CONTEXT_HPP 8 | #define TASK_CONTEXT_HPP 9 | 10 | #include 11 | 12 | #include "TaskingModel.hpp" 13 | 14 | namespace tampi { 15 | 16 | //! Class that represents the context of a task and provides 17 | //! several functions to bind events to the task, either in 18 | //! a blocking or non-blocking manner 19 | class TaskContext { 20 | private: 21 | //! Indicate whether the task is using the blocking mode 22 | bool _blocking; 23 | 24 | //! The task handle 25 | TaskingModel::task_handle_t _taskHandle; 26 | 27 | public: 28 | //! \brief Construct a task context 29 | TaskContext() : 30 | _blocking(false), 31 | _taskHandle(nullptr) 32 | { 33 | } 34 | 35 | //! \brief Construct a task context 36 | //! 37 | //! \param blocking Whether the task is using the blocking mode 38 | TaskContext(bool blocking) : 39 | _blocking(blocking), 40 | _taskHandle(nullptr) 41 | { 42 | _taskHandle = TaskingModel::getCurrentTask(); 43 | assert(_taskHandle != nullptr); 44 | } 45 | 46 | //! \brief Construct a task context 47 | //! 48 | //! \param blocking Whether the task is using the blocking mode 49 | //! \param taskHandle The task handle 50 | TaskContext(bool blocking, TaskingModel::task_handle_t taskHandle) : 51 | _blocking(blocking), 52 | _taskHandle(taskHandle) 53 | { 54 | assert(taskHandle != nullptr); 55 | } 56 | 57 | //! \brief Get the task handle 58 | TaskingModel::task_handle_t getTaskHandle() const 59 | { 60 | return _taskHandle; 61 | } 62 | 63 | //! \brief Bind some events to the task 64 | //! 65 | //! \param num The number of events to bind 66 | void bindEvents(int num) 67 | { 68 | assert(num > 0); 69 | if (!_blocking) { 70 | TaskingModel::increaseCurrentTaskEvents(_taskHandle, num); 71 | } 72 | } 73 | 74 | //! \brief Complete some events of the task 75 | //! 76 | //! \param num The number of events to complete 77 | //! \param allCompleted Whether these are the last events to complete 78 | void completeEvents(int num, bool allCompleted) 79 | { 80 | assert(num > 0); 81 | if (!_blocking) { 82 | TaskingModel::decreaseTaskEvents(_taskHandle, num); 83 | } else if (allCompleted) { 84 | // Unblock the task when all its events completed 85 | TaskingModel::unblockTask(_taskHandle); 86 | } 87 | } 88 | 89 | //! \brief Wait until all its events finished 90 | //! 91 | //! This function blocks the current task until its events 92 | //! have been completed. Note this call is only allowed when 93 | //! the task is using the blocking mode 94 | void waitEventsCompletion() 95 | { 96 | assert(_blocking); 97 | TaskingModel::blockCurrentTask(_taskHandle); 98 | } 99 | 100 | //! \brief Indicate whether the task is using the blocking mode 101 | bool isBlocking() const 102 | { 103 | return _blocking; 104 | } 105 | }; 106 | 107 | } // namespace tampi 108 | 109 | #endif // TASK_CONTEXT_HPP 110 | 111 | -------------------------------------------------------------------------------- /src/common/TaskingModel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include "Symbol.hpp" 8 | #include "TaskingModel.hpp" 9 | #include "util/ErrorHandler.hpp" 10 | 11 | namespace tampi { 12 | 13 | void TaskingModel::initialize(bool requireTaskBlockingAPI, bool requireTaskEventsAPI) 14 | { 15 | // Avoid loading symbols if no mode is required 16 | if (!requireTaskBlockingAPI && !requireTaskEventsAPI) 17 | return; 18 | 19 | // Find the first occurrence of the desired symbol 20 | const SymbolAttr attr = SymbolAttr::First; 21 | 22 | _alpi_error_string.load(attr); 23 | _alpi_version_check.load(attr); 24 | _alpi_version_get.load(attr); 25 | _alpi_task_self.load(attr); 26 | _alpi_task_spawn.load(attr); 27 | _alpi_task_waitfor_ns.load(attr); 28 | _alpi_cpu_count.load(attr); 29 | _alpi_cpu_logical_id.load(attr); 30 | _alpi_cpu_system_id.load(attr); 31 | 32 | // Load the task blocking API functions if needed 33 | if (requireTaskBlockingAPI) { 34 | _alpi_task_block.load(attr); 35 | _alpi_task_unblock.load(attr); 36 | } 37 | 38 | // Load the task events API functions if needed 39 | if (requireTaskEventsAPI) { 40 | _alpi_task_events_increase.load(attr); 41 | _alpi_task_events_decrease.load(attr); 42 | } 43 | 44 | int expected[2] = { ALPI_VERSION_MAJOR, ALPI_VERSION_MINOR }; 45 | int provided[2] = { false, false }; 46 | 47 | _alpi_version_get(&provided[0], &provided[1]); 48 | 49 | int err = _alpi_version_check.callNative(expected[0], expected[1]); 50 | if (err == ALPI_ERR_VERSION) 51 | ErrorHandler::fail("Incompatible ALPI tasking interface versions:\n", 52 | "\tExpected: ", expected[0], ".", expected[1], "\n", 53 | "\tProvided: ", provided[0], ".", provided[1]); 54 | else if (err) 55 | _alpi_version_check.processFailure(err); 56 | } 57 | 58 | ALPISymbol 59 | TaskingModel::_alpi_error_string("alpi_error_string", nullptr); 60 | 61 | ALPISymbol 62 | TaskingModel::_alpi_version_check("alpi_version_check", &_alpi_error_string); 63 | 64 | ALPISymbol 65 | TaskingModel::_alpi_version_get("alpi_version_get", &_alpi_error_string); 66 | 67 | ALPISymbol 68 | TaskingModel::_alpi_task_self("alpi_task_self", &_alpi_error_string); 69 | 70 | ALPISymbol 71 | TaskingModel::_alpi_task_block("alpi_task_block", &_alpi_error_string); 72 | 73 | ALPISymbol 74 | TaskingModel::_alpi_task_unblock("alpi_task_unblock", &_alpi_error_string); 75 | 76 | ALPISymbol 77 | TaskingModel::_alpi_task_events_increase("alpi_task_events_increase", &_alpi_error_string); 78 | 79 | ALPISymbol 80 | TaskingModel::_alpi_task_events_decrease("alpi_task_events_decrease", &_alpi_error_string); 81 | 82 | ALPISymbol 83 | TaskingModel::_alpi_task_waitfor_ns("alpi_task_waitfor_ns", &_alpi_error_string); 84 | 85 | ALPISymbol 86 | TaskingModel::_alpi_task_spawn("alpi_task_spawn", &_alpi_error_string); 87 | 88 | ALPISymbol 89 | TaskingModel::_alpi_cpu_count("alpi_cpu_count", &_alpi_error_string); 90 | 91 | ALPISymbol 92 | TaskingModel::_alpi_cpu_logical_id("alpi_cpu_logical_id", &_alpi_error_string); 93 | 94 | ALPISymbol 95 | TaskingModel::_alpi_cpu_system_id("alpi_cpu_system_id", &_alpi_error_string); 96 | 97 | } // namespace tampi 98 | -------------------------------------------------------------------------------- /src/common/Ticket.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef TICKET_HPP 8 | #define TICKET_HPP 9 | 10 | #include 11 | 12 | #include "Interface.hpp" 13 | #include "Operation.hpp" 14 | #include "TaskContext.hpp" 15 | 16 | namespace tampi { 17 | 18 | //! Class that tracks a pending operation issued by a task 19 | template 20 | class Ticket { 21 | private: 22 | typedef typename Types::status_t status_t; 23 | typedef typename Types::status_ptr_t status_ptr_t; 24 | 25 | //! The context of the owner task 26 | TaskContext _taskContext; 27 | 28 | //! A pointer to the location where to save the statuses 29 | status_ptr_t _firstStatus; 30 | 31 | public: 32 | //! \brief Construct an empty ticket 33 | Ticket() : 34 | _taskContext(), 35 | _firstStatus(nullptr) 36 | { 37 | } 38 | 39 | //! \brief Construct a ticket 40 | //! 41 | //! \param firstStatus A pointer to the location where to save 42 | //! the statuses or STATUS_IGNORE 43 | //! \param blocking Whether the TAMPI operation is blocking 44 | Ticket(status_ptr_t firstStatus, bool blocking) : 45 | _taskContext(blocking), 46 | _firstStatus(firstStatus) 47 | { 48 | } 49 | 50 | Ticket(const Operation &operation) : 51 | _taskContext(operation._nature == BLK, operation._task), 52 | _firstStatus(operation._status) 53 | { 54 | } 55 | 56 | Ticket(const CollOperation &operation) : 57 | _taskContext(operation._nature == BLK, operation._task), 58 | _firstStatus(Interface::STATUS_IGNORE) 59 | { 60 | } 61 | 62 | //! \brief Add pending operation to the ticket 63 | //! 64 | //! \param num The number of pending operations to add 65 | void addPendingOperation(int num = 1) 66 | { 67 | _taskContext.bindEvents(num); 68 | } 69 | 70 | //! \brief Mark the ticket as completed 71 | void complete() 72 | { 73 | _taskContext.completeEvents(1, true); 74 | } 75 | 76 | //! \brief Get the task context 77 | const TaskContext &getTaskContext() const 78 | { 79 | return _taskContext; 80 | } 81 | 82 | //! \brief Wait until all operations complete 83 | //! 84 | //! This function blocks the current task until all operations 85 | //! complete. Note this is only valid for tickets of blocking 86 | //! TAMPI operations 87 | void wait() 88 | { 89 | _taskContext.waitEventsCompletion(); 90 | } 91 | 92 | //! \brief Indicate whether the statuses should be ignored 93 | //! 94 | //! \returns Whether ignore the statuses 95 | bool ignoreStatus() const 96 | { 97 | return (_firstStatus == Interface::STATUS_IGNORE 98 | || _firstStatus == Interface::STATUSES_IGNORE); 99 | } 100 | 101 | //! \brief Store the status of a request 102 | //! 103 | //! \param status The status to be stored 104 | //! \param statusPosition The local position in the array of statuses 105 | void storeStatus(const status_t& status, int statusPosition) 106 | { 107 | assert(_firstStatus != nullptr); 108 | assert(statusPosition >= 0); 109 | 110 | status_t *outStatus = (status_t *) _firstStatus; 111 | outStatus += statusPosition; 112 | std::copy(&status, &status + 1, outStatus); 113 | } 114 | }; 115 | 116 | } // namespace tampi 117 | 118 | #endif // TICKET_HPP 119 | 120 | -------------------------------------------------------------------------------- /src/common/TicketManagerCapacityCtrl.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef TICKET_MANAGER_CAPACITY_CTRL_HPP 8 | #define TICKET_MANAGER_CAPACITY_CTRL_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "util/Clock.hpp" 16 | #include "util/EnvironmentVariable.hpp" 17 | 18 | namespace tampi { 19 | 20 | //! Class that controls the capacity of the ticket manager capacity 21 | class TicketManagerCapacityCtrl { 22 | private: 23 | //! Hard limit of in-flight requests 24 | static constexpr uint64_t CapacityLimit = 32*1024; 25 | 26 | //! The minimum and maximum capacity 27 | uint64_t _capacityMin; 28 | uint64_t _capacityMax; 29 | 30 | //! Indicate whether the capacity is dynamic 31 | bool _dynamic; 32 | 33 | //! The current capacity 34 | uint64_t _capacity; 35 | 36 | //! The maximum time (in ms) which a saturation epoch may take 37 | uint64_t _timeout; 38 | 39 | //! Indicate whether there is a saturation epoch currently 40 | bool _saturation; 41 | 42 | //! The timestamp (in ms) when the saturation epoch began (if any) 43 | double _saturationBegin; 44 | 45 | public: 46 | TicketManagerCapacityCtrl() : 47 | _capacityMin(128), 48 | _capacityMax(CapacityLimit), 49 | _dynamic(true), 50 | _capacity(_capacityMin), 51 | _timeout(10), 52 | _saturation(false) 53 | { 54 | EnvironmentVariable policy("TAMPI_CAPACITY"); 55 | EnvironmentVariable timeout("TAMPI_CAPACITY_TIMEOUT"); 56 | 57 | if (policy.isPresent()) { 58 | auto [min, max] = parseCapacities(policy.get()); 59 | if (min > max) 60 | ErrorHandler::fail("Minimum capacity cannot be greater than maximum"); 61 | 62 | _capacityMin = std::min(min, CapacityLimit); 63 | _capacityMax = std::min(max, CapacityLimit); 64 | _capacity = _capacityMin; 65 | _dynamic = (_capacityMin != _capacityMax); 66 | } 67 | 68 | if (timeout.isPresent()) 69 | _timeout = timeout.get(); 70 | } 71 | 72 | inline int get() const 73 | { 74 | return _capacity; 75 | } 76 | 77 | constexpr static inline int max() 78 | { 79 | return CapacityLimit; 80 | } 81 | 82 | //! \brief Evaluate whether the capacity must be modified 83 | //! 84 | //! This function decides which should be capacity of the ticket manager, 85 | //! which is the maximum number of in-flight requests. To this end, the 86 | //! function considers the current number of pending requests and the 87 | //! number of completed requests since the last evaluation. This function 88 | //! should be called just before returning from the polling body. 89 | //! 90 | //! \param pending The number of pending requests 91 | //! \param completed The number of completed requests 92 | inline void evaluate(uint64_t pending, uint64_t completed) 93 | { 94 | // Nothing to do if the maximum capacity was reached 95 | if (_capacity == _capacityMax) 96 | return; 97 | 98 | // The saturation protocol should be enabled while we are in the maximum 99 | // capacity and we find no completed requests. Once this condition persists 100 | // for more than a timeout period (in ms), we need to increase the capacity. 101 | // Otherwise, we could end up in a communication deadlock 102 | if (pending == _capacity && completed == 0) { 103 | if (!_saturation) { 104 | // Enable saturation protocol 105 | _saturation = true; 106 | _saturationBegin = Clock::now_ms(); 107 | } else if (Clock::now_ms() - _saturationBegin > _timeout) { 108 | // The saturation grace period expired. Double the capacity and 109 | // disable the saturation protocol 110 | _saturation = false; 111 | _capacity = std::min(_capacity * 2, _capacityMax); 112 | ErrorHandler::warn("Increasing capacity to ", _capacity); 113 | } 114 | } else { 115 | // Disable saturation protocol 116 | _saturation = false; 117 | } 118 | } 119 | 120 | //! \brief Parse the capacity policy string 121 | //! 122 | //! \param policy The policy string 123 | //! 124 | //! \returns a pair with the minimum and maximum capacities 125 | static inline std::pair parseCapacities( 126 | const std::string &policy 127 | ) { 128 | std::string component; 129 | std::vector components; 130 | std::stringstream stream(policy); 131 | while (std::getline(stream, component, ':')) 132 | components.push_back(component); 133 | 134 | if (components.size() < 1 || components.size() > 2) 135 | ErrorHandler::fail("TAMPI_CAPACITY has format '[:]'"); 136 | 137 | uint64_t min, max; 138 | std::istringstream(components[0]) >> min; 139 | if (components.size() > 1) 140 | std::istringstream(components[1]) >> max; 141 | else 142 | max = min; 143 | 144 | return { min, max }; 145 | } 146 | }; 147 | 148 | } // namespace tampi 149 | 150 | #endif // TICKET_MANAGER_CAPACITY_CTRL_HPP 151 | -------------------------------------------------------------------------------- /src/common/instrument/Instrument.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2022-2023 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifdef HAVE_CONFIG_H 8 | #include 9 | #endif 10 | 11 | #include "Instrument.hpp" 12 | #include "util/ErrorHandler.hpp" 13 | 14 | #ifdef HAVE_OVNI 15 | #include "OvniInstrument.hpp" 16 | #endif 17 | 18 | namespace tampi { 19 | 20 | EnvironmentVariable Instrument::_instrument("TAMPI_INSTRUMENT", "none"); 21 | InstrumentBackendInterface *Instrument::_backend = nullptr; 22 | 23 | void Instrument::initialize(int rank, int nranks) 24 | { 25 | if (_instrument.get() == "ovni") { 26 | #ifdef HAVE_OVNI 27 | _backend = new OvniInstrumentBackend(); 28 | #else 29 | ErrorHandler::fail("TAMPI was not configured with ovni support"); 30 | #endif 31 | } else if (_instrument.get() != "none") { 32 | ErrorHandler::fail(_instrument.get(), " instrumentation not supported"); 33 | } 34 | 35 | if (_backend) 36 | _backend->initialize(rank, nranks); 37 | } 38 | 39 | } // namespace tampi 40 | -------------------------------------------------------------------------------- /src/common/instrument/Instrument.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2021-2023 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef INSTRUMENT_HPP 8 | #define INSTRUMENT_HPP 9 | 10 | #include "util/EnvironmentVariable.hpp" 11 | 12 | namespace tampi { 13 | 14 | //! The instrumentation points 15 | enum InstrumentPoint { 16 | AddQueues = 0, 17 | CheckGlobalRequestArray, 18 | CompletedRequest, 19 | CreateTicket, 20 | IssueNonBlockingOp, 21 | LibraryInterface, 22 | LibraryPolling, 23 | TestAllRequests, 24 | TestRequest, 25 | TestSomeRequests, 26 | TransferQueues, 27 | WaitTicket, 28 | NumInstrumentPoints, 29 | }; 30 | 31 | //! The instrumentation backend interface 32 | class InstrumentBackendInterface { 33 | public: 34 | virtual void initialize(int rank, int nranks) = 0; 35 | virtual void finalize() = 0; 36 | virtual void enter(InstrumentPoint point) = 0; 37 | virtual void exit(InstrumentPoint point) = 0; 38 | }; 39 | 40 | class Instrument { 41 | private: 42 | //! Envar controlling whether the instrumentation should be enabled. The 43 | //! envar is called TAMPI_INSTRUMENT and the default value is "none". The 44 | //! accepted values are: 45 | //! - "none": No instrumentation is enabled 46 | //! - "ovni": Ovni instrumentation is enabled to generate Paraver traces 47 | static EnvironmentVariable _instrument; 48 | 49 | //! Reference to the instrumentation backend; null if no instrumentation 50 | static InstrumentBackendInterface *_backend; 51 | 52 | public: 53 | //! \brief Initialize the instrumentation 54 | static void initialize(int rank, int nranks); 55 | 56 | //! \brief Finalize the instrumentation 57 | static void finalize() 58 | { 59 | if (_backend) 60 | _backend->finalize(); 61 | } 62 | 63 | //! \brief Enter into a state at an instrument point 64 | template 65 | static void enter() 66 | { 67 | if (_backend) 68 | _backend->enter(Point); 69 | } 70 | 71 | //! \brief Exit from a state at an instrument point 72 | template 73 | static void exit() 74 | { 75 | if (_backend) 76 | _backend->exit(Point); 77 | } 78 | 79 | //! \brief Guard class to perform automatic scope instrumentation 80 | //! 81 | //! Guard objects instrument the enter and exit points of a specific 82 | //! instrumentation point at construction and destruction, respectively 83 | template 84 | struct Guard { 85 | //! \brief Enter the instrumentation point at construction 86 | Guard() 87 | { 88 | Instrument::enter(); 89 | } 90 | 91 | //! \brief Exit the instrumentation point at destruction 92 | ~Guard() 93 | { 94 | Instrument::exit(); 95 | } 96 | }; 97 | }; 98 | 99 | } // namespace tampi 100 | 101 | #endif // INSTRUMENT_HPP 102 | -------------------------------------------------------------------------------- /src/common/instrument/OvniInstrument.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2022-2023 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef OVNI_INSTRUMENT_HPP 8 | #define OVNI_INSTRUMENT_HPP 9 | 10 | #include 11 | 12 | #include "Instrument.hpp" 13 | 14 | namespace tampi { 15 | 16 | class OvniInstrumentBackend : public InstrumentBackendInterface { 17 | private: 18 | //! If the thread has performed the initialization or not 19 | static inline thread_local bool _threadInit = false; 20 | 21 | //! The state is composed by the enter and exit ovni MCV, which are three 22 | //! characters that specify the event model, category and value 23 | struct StateInfo { 24 | const char *enterMCV; 25 | const char *exitMCV; 26 | }; 27 | 28 | //! The table storing subsystem states information with the enter and 29 | //! exit event model-category-value. The model for TAMPI events is 'T' 30 | static constexpr StateInfo Subsystems[NumInstrumentPoints] = { 31 | [AddQueues] = { "TQa", "TQA" }, 32 | [CheckGlobalRequestArray] = { "TGc", "TGC" }, 33 | [CompletedRequest] = { "TRc", "TRC" }, 34 | [CreateTicket] = { "TTc", "TTC" }, 35 | [IssueNonBlockingOp] = { "TCi", "TCI" }, 36 | [LibraryInterface] = { "TLi", "TLI" }, 37 | [LibraryPolling] = { "TLp", "TLP" }, 38 | [TestAllRequests] = { "TRa", "TRA" }, 39 | [TestRequest] = { "TRt", "TRT" }, 40 | [TestSomeRequests] = { "TRs", "TRS" }, 41 | [TransferQueues] = { "TQt", "TQT" }, 42 | [WaitTicket] = { "TTw", "TTW" }, 43 | }; 44 | 45 | //! Emit an ovni event given the event model-category-value 46 | static void emitEvent(const char *mcv) 47 | { 48 | if (!_threadInit) { 49 | ovni_thread_require("tampi", "1.0.0"); 50 | _threadInit = true; 51 | } 52 | 53 | struct ovni_ev ev = {}; 54 | ovni_ev_set_clock(&ev, ovni_clock_now()); 55 | ovni_ev_set_mcv(&ev, mcv); 56 | ovni_ev_emit(&ev); 57 | } 58 | 59 | public: 60 | //! \brief Initialize the ovni instrumentation 61 | void initialize(int rank, int nranks) override 62 | { 63 | ovni_proc_set_rank(rank, nranks); 64 | } 65 | 66 | //! \brief Finalize the ovni instrumentation 67 | void finalize() override 68 | { 69 | } 70 | 71 | //! \brief Enter into a subsystem state at an instrument point 72 | void enter(InstrumentPoint point) override 73 | { 74 | emitEvent(Subsystems[point].enterMCV); 75 | } 76 | 77 | //! \brief Exit from a subsystem state at an instrument point 78 | void exit(InstrumentPoint point) override 79 | { 80 | emitEvent(Subsystems[point].exitMCV); 81 | } 82 | }; 83 | 84 | } // namespace tampi 85 | 86 | #endif // OVNI_INSTRUMENT_HPP 87 | -------------------------------------------------------------------------------- /src/common/polling/Polling.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef POLLING_HPP 8 | #define POLLING_HPP 9 | 10 | #include 11 | 12 | #include "PollingPeriodCtrl.hpp" 13 | #include "TaskingModel.hpp" 14 | #include "TicketManager.hpp" 15 | #include "instrument/Instrument.hpp" 16 | 17 | namespace tampi { 18 | 19 | //! Class that represents the polling features 20 | class Polling { 21 | private: 22 | //! The polling instance of the task that periodically checks the in-flight 23 | //! MPI requests 24 | static TaskingModel::PollingInstance *_pollingInstance; 25 | 26 | //! The controller of the polling period 27 | static PollingPeriodCtrl _periodCtrl; 28 | 29 | //! The polling instance of the task that processes completions 30 | static TaskingModel::PollingInstance *_completionPollingInstance; 31 | 32 | //! The controller of the completion polling period 33 | static PollingPeriodCtrl _completionPeriodCtrl; 34 | 35 | public: 36 | Polling() = delete; 37 | Polling(const Polling &) = delete; 38 | const Polling& operator= (const Polling &) = delete; 39 | 40 | //! \brief Initialize the polling features 41 | static void initialize() 42 | { 43 | _pollingInstance = TaskingModel::registerPolling("TAMPI", Polling::polling, nullptr); 44 | 45 | if (CompletionManager::isEnabled()) 46 | _completionPollingInstance = TaskingModel::registerPolling( 47 | "TAMPI Comp", Polling::completions, nullptr); 48 | } 49 | 50 | //! \brief Finalize the polling features 51 | static void finalize() 52 | { 53 | TaskingModel::unregisterPolling(_pollingInstance); 54 | 55 | if (CompletionManager::isEnabled()) 56 | TaskingModel::unregisterPolling(_completionPollingInstance); 57 | } 58 | 59 | private: 60 | //! \brief Polling function that checks the in-flight requests 61 | //! 62 | //! This function is periodically called by the tasking runtime system 63 | //! and should check for the in-flight MPI requests posted from both C 64 | //! and Fortran languages (if needed) 65 | //! 66 | //! \param args An opaque pointer to the arguments 67 | //! \param prevWaitUs The actual wait time in microseconds 68 | //! 69 | //! \returns How many microseconds should the task wait in the next call 70 | static uint64_t polling(void *, uint64_t) 71 | { 72 | size_t pending = 0; 73 | size_t completed = 0; 74 | 75 | Instrument::Guard instrGuard; 76 | 77 | #ifndef DISABLE_C_LANG 78 | TicketManager &cManager = TicketManager::get(); 79 | completed += cManager.checkRequests(pending); 80 | #endif 81 | #ifndef DISABLE_FORTRAN_LANG 82 | TicketManager &fortranManager = TicketManager::get(); 83 | completed += fortranManager.checkRequests(pending); 84 | #endif 85 | return _periodCtrl.getPeriod(completed, pending); 86 | } 87 | 88 | //! \brief Polling function that checks the completions 89 | //! 90 | //! This function is periodically called by the tasking runtime system 91 | //! and should notify it about any completion. This function is only 92 | //! executed when the completion polling task is enabled 93 | //! 94 | //! \param args An opaque pointer to the arguments 95 | //! \param prevWaitUs The actual wait time in microseconds 96 | //! 97 | //! \returns How many microseconds should the task wait in the next call 98 | static uint64_t completions(void *, uint64_t) 99 | { 100 | size_t completed = CompletionManager::process(); 101 | 102 | return _completionPeriodCtrl.getPeriod(completed, 0); 103 | } 104 | }; 105 | 106 | } // namespace tampi 107 | 108 | #endif // POLLING_HPP 109 | -------------------------------------------------------------------------------- /src/common/polling/PollingPeriodCtrl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include "PollingPeriodCtrl.hpp" 8 | #include "SlowStartPollingPeriodCtrl.hpp" 9 | #include "util/ErrorHandler.hpp" 10 | #include "util/StringSupport.hpp" 11 | 12 | 13 | namespace tampi { 14 | 15 | PollingPeriodCtrl::PollingPeriodCtrl(const std::string &envar) : 16 | _envar(envar, std::to_string(DefaultPeriodUs)), 17 | _minPeriod(0), 18 | _maxPeriod(0), 19 | _dynamic(false), 20 | _policy(""), 21 | _dynamicCtrl(nullptr) 22 | { 23 | bool present[3]; 24 | if (!StringSupport::parse(_envar.get(), present, _minPeriod, _maxPeriod, _policy, ':')) 25 | ErrorHandler::fail("Invalid format TAMPI_POLLING_PERIOD=minperiod[:maxperiod[:policy]]"); 26 | 27 | if (!present[0]) 28 | _minPeriod = DefaultPeriodUs; 29 | if (!present[1]) 30 | _maxPeriod = _minPeriod; 31 | if (!present[2]) 32 | _policy = DefaultPolicy; 33 | 34 | if (_minPeriod > _maxPeriod) 35 | ErrorHandler::fail("TAMPI_POLLING_PERIOD has a minperiod greater than maxperiod"); 36 | 37 | if (_maxPeriod != _minPeriod) { 38 | _dynamic = true; 39 | 40 | if (_policy == "slowstart" || _policy == "default") 41 | _dynamicCtrl = new SlowStartPollingPeriodCtrl(_minPeriod, _maxPeriod); 42 | else 43 | ErrorHandler::fail("TAMPI_POLLING_PERIOD has an invalid policy '", _policy, "'"); 44 | } 45 | } 46 | 47 | PollingPeriodCtrl::~PollingPeriodCtrl() 48 | { 49 | if (_dynamicCtrl) 50 | delete _dynamicCtrl; 51 | } 52 | 53 | } // namespace tampi 54 | -------------------------------------------------------------------------------- /src/common/polling/PollingPeriodCtrl.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef POLLING_PERIOD_CTRL_HPP 8 | #define POLLING_PERIOD_CTRL_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "util/EnvironmentVariable.hpp" 15 | 16 | 17 | namespace tampi { 18 | 19 | //! Virtual class for dynamic polling period controllers. Policies should 20 | //! inherit from this class 21 | struct DynamicPollingPeriodCtrlImpl { 22 | virtual ~DynamicPollingPeriodCtrlImpl() 23 | { 24 | } 25 | 26 | //! Run one step of the policy after having checked the TAMPI requests 27 | //! 28 | //! \param completedUnits The number of completed requests/operations 29 | //! \param pendingUnits The number of pending requests/operations 30 | //! 31 | //! \returns The next polling period in microseconds 32 | virtual uint64_t run(uint64_t completedUnits, uint64_t pendingUnits) = 0; 33 | }; 34 | 35 | //! Class that controls the polling period depending on the policies specified 36 | //! by the user 37 | class PollingPeriodCtrl { 38 | //! The default period and policy 39 | constexpr static uint64_t DefaultPeriodUs = 100; 40 | constexpr static const char *DefaultPolicy = "slowstart"; 41 | 42 | //! The envar specifying the polling period 43 | EnvironmentVariable _envar; 44 | 45 | //! The minimum period for polling tasks 46 | uint64_t _minPeriod; 47 | 48 | //! The maximum period for polling tasks 49 | uint64_t _maxPeriod; 50 | 51 | //! Whether the polling period is dynamic or static 52 | bool _dynamic; 53 | 54 | //! Policy for dynamic polling 55 | std::string _policy; 56 | 57 | //! Dynamic period controller 58 | DynamicPollingPeriodCtrlImpl *_dynamicCtrl; 59 | 60 | public: 61 | //! \brief Create the period controller 62 | //! 63 | //! The controller reads the TAMPI_POLLING_PERIOD envar to determine the period 64 | //! in which TAMPI will check its MPI requests. If the envar is not defined, 65 | //! the period is 100us as a default value 66 | //! 67 | //! \param envar The envar specifying the polling period 68 | PollingPeriodCtrl(const std::string &envar); 69 | 70 | ~PollingPeriodCtrl(); 71 | 72 | //! \brief Run the polling policy and retrieve the next polling period 73 | //! 74 | //! \param completed The number of completed requests/operations 75 | //! \param pending The number of pending requests/operations 76 | //! 77 | //! \returns The next polling period in microseconds 78 | inline uint64_t getPeriod(size_t completed, size_t pending) 79 | { 80 | if (!_dynamic) 81 | return _maxPeriod; 82 | 83 | assert(_dynamicCtrl != nullptr); 84 | return _dynamicCtrl->run(completed, pending); 85 | } 86 | }; 87 | 88 | } // namespace tampi 89 | 90 | #endif // POLLING_PERIOD_CTRL_HPP 91 | -------------------------------------------------------------------------------- /src/common/polling/SlowStartPollingPeriodCtrl.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef SLOW_START_POLLING_PERIOD_CTRL_HPP 8 | #define SLOW_START_POLLING_PERIOD_CTRL_HPP 9 | 10 | #include 11 | 12 | #include "PollingPeriodCtrl.hpp" 13 | 14 | 15 | namespace tampi { 16 | 17 | //! Class implementing a Slow Start-based policy for controlling the 18 | //! dynamic polling period 19 | class SlowStartPollingPeriodCtrl : public DynamicPollingPeriodCtrlImpl { 20 | //! The number of consecutive misses before increasing period 21 | static constexpr int64_t Tolerance = 50; 22 | 23 | //! The factor used to compute the base period after a period increase 24 | static constexpr double Penalty = 2.0; 25 | 26 | //! The minimum base period after a period increase. A slow start phase 27 | //! cannot start from a lower value 28 | static constexpr double MinBase = 10.0; 29 | 30 | //! The minimum and maximum periods 31 | const double _minPeriod; 32 | const double _maxPeriod; 33 | 34 | //! The current period 35 | double _period; 36 | 37 | //! The current period decreasing factor. This factor must start at 2.0 38 | //! and can decrease to 1.5 39 | double _factor; 40 | 41 | //! The current number of consecutive missing 42 | int64_t _misses; 43 | 44 | public: 45 | inline SlowStartPollingPeriodCtrl(uint64_t periodMin, uint64_t periodMax) : 46 | _minPeriod(periodMin), _maxPeriod(periodMax), _period(periodMax), 47 | _factor(2.0), _misses(0) 48 | { 49 | } 50 | 51 | //! Run one step of the policy after having checked the TAMPI requests 52 | //! 53 | //! \param completedUnits The number of completed requests/operations 54 | //! \param pendingUnits The number of pending requests/operations 55 | //! 56 | //! \returns The next polling period in microseconds 57 | inline uint64_t run(uint64_t completedUnits, uint64_t) override 58 | { 59 | // Tolerate some misses before increasing the period 60 | if (completedUnits == 0 && ++_misses < Tolerance) 61 | return _period; 62 | 63 | // Reset the misses counter 64 | _misses = 0; 65 | 66 | if (completedUnits == 0) { 67 | // New miss detected. Reset the period to a higher value by applying a 68 | // penality. Recompute the factor depending on the new base period 69 | _period = std::max(std::min(_period * Penalty, _maxPeriod), MinBase); 70 | _factor = (1.5 * _maxPeriod + 0.5 * _period) / _maxPeriod; 71 | } else { 72 | // Decrease the current period applying the factor 73 | _period = std::max(_period / _factor, _minPeriod); 74 | } 75 | 76 | assert(_factor >= 1.5 && _factor <= 2.0); 77 | assert(_period <= _maxPeriod && _period >= _minPeriod); 78 | 79 | return _period; 80 | } 81 | }; 82 | 83 | } // namespace tampi 84 | 85 | #endif // SLOW_START_POLLING_PERIOD_CTRL_HPP 86 | -------------------------------------------------------------------------------- /src/common/util/ArrayView.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2023 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef ARRAY_VIEW_HPP 8 | #define ARRAY_VIEW_HPP 9 | 10 | #include 11 | #include 12 | 13 | 14 | namespace tampi { 15 | 16 | //! Class that encapsulates an array previously allocated 17 | //! and that his storage should be kept valid during the 18 | //! lifetime of this object 19 | template 20 | class ArrayView { 21 | private: 22 | //! The begin of the array 23 | T* _begin; 24 | 25 | //! The end of the array (not included) 26 | T* _end; 27 | 28 | public: 29 | //! \brief Construct an arrayview 30 | //! 31 | //! \param begin A pointer to the first element 32 | //! \param length The length of the arrayview 33 | ArrayView(T *begin, int length) : 34 | _begin(begin), 35 | _end(begin + static_cast(length)) 36 | { 37 | assert(length >= 0); 38 | } 39 | 40 | //! \brief Construct an arrayview 41 | //! 42 | //! \param begin A pointer to the first element 43 | //! \param length The length of the arrayview 44 | ArrayView(T *begin, size_t length) : 45 | _begin(begin), 46 | _end(begin + length) 47 | { 48 | } 49 | 50 | //! \brief Get the number of elements in the arrayview 51 | //! 52 | //! \returns The number of elements 53 | int size() const 54 | { 55 | return std::distance(begin(), end()); 56 | } 57 | 58 | //! \brief Indicate whether the arrayview is empty 59 | //! 60 | //! \returns Whether it is empty 61 | bool empty() const 62 | { 63 | return begin() == end(); 64 | } 65 | 66 | //! \brief Get a pointer to the first element 67 | //! 68 | //! \returns A pointer to the first element 69 | T* begin() 70 | { 71 | return _begin; 72 | } 73 | 74 | //! \brief Get a pointer to the first element 75 | //! 76 | //! \returns A pointer to the first element 77 | const T* begin() const 78 | { 79 | return _begin; 80 | } 81 | 82 | //! \brief Get a pointer to the end of the array 83 | //! 84 | //! This function returns a pointer to the end of the 85 | //! array, which is not a valid element. Accessing it 86 | //! results in undefined behavior 87 | //! 88 | //! \returns A pointer to the end 89 | T* end() 90 | { 91 | return _end; 92 | } 93 | 94 | //! \brief Get a pointer to the end of the array 95 | //! 96 | //! This function returns a pointer to the end of the 97 | //! array, which is not a valid element. Accessing it 98 | //! results in undefined behavior 99 | //! 100 | //! \returns A pointer to the end 101 | const T* end() const 102 | { 103 | return _end; 104 | } 105 | 106 | //! \brief Get the elements at a given position 107 | //! 108 | //! \param position The position of the element 109 | //! 110 | //! \returns The element 111 | T& operator[](size_t position) 112 | { 113 | return _begin[position]; 114 | } 115 | 116 | //! \brief Get the elements at a given position 117 | //! 118 | //! \param position The position of the element 119 | //! 120 | //! \returns The element 121 | const T& operator[](size_t position) const 122 | { 123 | return _begin[position]; 124 | } 125 | 126 | //! \brief Get a pointer to the underlying array data 127 | //! 128 | //! \returns A pointer to the array data 129 | T* data() 130 | { 131 | return _begin; 132 | } 133 | 134 | //! \brief Get a pointer to the underlying array data 135 | //! 136 | //! \returns A pointer to the array data 137 | const T* data() const 138 | { 139 | return _begin; 140 | } 141 | 142 | //! \brief Get a reverse iterator to the begin 143 | //! 144 | //! \returns A reverse iterator to the begin 145 | std::reverse_iterator rbegin() 146 | { 147 | return std::reverse_iterator(end()); 148 | } 149 | 150 | //! \brief Get a reverse iterator to the begin 151 | //! 152 | //! \returns A reverse iterator to the begin 153 | std::reverse_iterator rbegin() const 154 | { 155 | return std::reverse_iterator(end()); 156 | } 157 | 158 | //! \brief Get a reverse iterator to the end 159 | //! 160 | //! \returns A reverse iterator to the end 161 | std::reverse_iterator rend() 162 | { 163 | return std::reverse_iterator(begin()); 164 | } 165 | 166 | //! \brief Get a reverse iterator to the end 167 | //! 168 | //! \returns A reverse iterator to the end 169 | std::reverse_iterator rend() const 170 | { 171 | return std::reverse_iterator(begin()); 172 | } 173 | }; 174 | 175 | template 176 | struct reverse_adaptor { 177 | T& iterable; 178 | 179 | auto begin() -> decltype(iterable.rbegin()) 180 | { 181 | return iterable.rbegin(); 182 | } 183 | 184 | auto end() -> decltype(iterable.rend()) 185 | { 186 | return iterable.rend(); 187 | } 188 | 189 | auto rbegin() -> decltype(iterable.begin()) 190 | { 191 | return iterable.begin(); 192 | } 193 | 194 | auto rend() -> decltype(iterable.end()) 195 | { 196 | return iterable.end(); 197 | } 198 | }; 199 | 200 | template 201 | reverse_adaptor reverse(T&& iterable) 202 | { 203 | return {iterable}; 204 | } 205 | 206 | } // namespace tampi 207 | 208 | #endif // ARRAY_VIEW_HPP 209 | -------------------------------------------------------------------------------- /src/common/util/BoostLockFreeQueue.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef BOOST_LOCK_FREE_QUEUE_HPP 8 | #define BOOST_LOCK_FREE_QUEUE_HPP 9 | 10 | #include 11 | 12 | // Support for BOOST 1.67 13 | #if BOOST_VERSION == 106700 14 | #include 15 | #endif 16 | 17 | #include 18 | 19 | #include "EnvironmentVariable.hpp" 20 | #include "ErrorHandler.hpp" 21 | #include "SpinLock.hpp" 22 | #include "SpinWait.hpp" 23 | 24 | 25 | namespace tampi { 26 | 27 | //! Class that provides the functionality of a lock free queue 28 | template 29 | class BoostLockFreeQueue { 30 | private: 31 | typedef boost::lockfree::spsc_queue > queue_t; 32 | 33 | //! Indicate whether the queue will have multiple producers. The producer 34 | //! side needs mutual exclusion if there are multiple producers 35 | const bool _multipleProducers; 36 | 37 | //! Envar indicating whether the execution should abort if the queue is full 38 | const EnvironmentVariable _fullFailure; 39 | 40 | //! Spinlock to add elements in the queue 41 | alignas(CacheAlignment) SpinLock _adderMutex; 42 | 43 | //! Single producer single consumer queue 44 | alignas(CacheAlignment) queue_t _queue; 45 | 46 | public: 47 | BoostLockFreeQueue(bool multipleProducers = true) : 48 | _multipleProducers(multipleProducers), 49 | _fullFailure("TAMPI_QUEUES_FULL_FAILURE", false), 50 | _adderMutex(), 51 | _queue() 52 | { 53 | } 54 | 55 | //! \brief Push an element to the queue 56 | //! 57 | //! \param element The element to add 58 | void push(const T &element) 59 | { 60 | // Acquire the producer mutex if needed 61 | if (_multipleProducers) 62 | _adderMutex.lock(); 63 | 64 | if (_fullFailure) 65 | pushOrFail(&element, 1); 66 | else 67 | pushCont(&element, 1); 68 | 69 | // Release the producer mutex if needed 70 | if (_multipleProducers) 71 | _adderMutex.unlock(); 72 | } 73 | 74 | //! \brief Push elements to the queue 75 | //! 76 | //! \param elements The elements to add 77 | //! \param count The number of elements to add 78 | void push(const T elements[], size_t count) 79 | { 80 | // Acquire the producer mutex if needed 81 | if (_multipleProducers) 82 | _adderMutex.lock(); 83 | 84 | if (_fullFailure) 85 | pushOrFail(elements, count); 86 | else 87 | pushCont(elements, count); 88 | 89 | // Release the producer mutex if needed 90 | if (_multipleProducers) 91 | _adderMutex.unlock(); 92 | } 93 | 94 | //! \brief Pop multiple elements from the queue 95 | //! 96 | //! \param elements The array to store the retrieved elements 97 | //! \param count The maximum number of elements to retrieve 98 | //! 99 | //! \returns The number of elements retrieved 100 | size_t pop(T elements[], size_t count) 101 | { 102 | assert(elements != nullptr); 103 | return _queue.pop(elements, count); 104 | } 105 | 106 | private: 107 | //! \brief Push elements to the queue or fail if full 108 | //! 109 | //! \param elements The elements to add 110 | //! \param count The number of elements to add 111 | void pushOrFail(const T elements[], size_t count) 112 | { 113 | if (_queue.push(elements, count) != count) 114 | ErrorHandler::fail("BoostLockFreeQueue is full"); 115 | } 116 | 117 | //! \brief Push elements to the queue unconditionally 118 | //! 119 | //! \param elements The elements to add 120 | //! \param count The number of elements to add 121 | void pushCont(const T elements[], size_t count) 122 | { 123 | size_t pushed = _queue.push(elements, count); 124 | if (pushed == count) 125 | return; 126 | 127 | do { 128 | SpinWait::wait(); 129 | pushed += _queue.push(&elements[pushed], count - pushed); 130 | } while (pushed < count); 131 | 132 | SpinWait::release(); 133 | } 134 | }; 135 | 136 | } // namespace tampi 137 | 138 | #endif // BOOST_LOCK_FREE_QUEUE_HPP 139 | -------------------------------------------------------------------------------- /src/common/util/Clock.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef CLOCK_HPP 8 | #define CLOCK_HPP 9 | 10 | #include 11 | 12 | #ifdef CLOCK_MONOTONIC_COARSE 13 | #define CLK_SRC_FAST CLOCK_MONOTONIC_COARSE 14 | #else 15 | #define CLK_SRC_FAST CLOCK_MONOTONIC 16 | #endif 17 | 18 | namespace tampi { 19 | 20 | //! Class that provides clock features 21 | class Clock { 22 | public: 23 | static inline double now_ms() 24 | { 25 | struct timespec tp; 26 | clock_gettime(CLK_SRC_FAST, &tp); 27 | return (double)(tp.tv_sec) * 1.0e3 + (double)(tp.tv_nsec) * 1.0e-6; 28 | } 29 | }; 30 | 31 | } // namespace tampi 32 | 33 | #endif // CLOCK_HPP 34 | -------------------------------------------------------------------------------- /src/common/util/EnvironmentVariable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2020-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef ENVIRONMENT_VARIABLE_HPP 8 | #define ENVIRONMENT_VARIABLE_HPP 9 | 10 | #include 11 | #include 12 | 13 | #include "ErrorHandler.hpp" 14 | #include "StringSupport.hpp" 15 | 16 | 17 | namespace tampi { 18 | 19 | //! Class that represents an environment variable 20 | template 21 | class EnvironmentVariable { 22 | private: 23 | //! The environment variable value 24 | T _value; 25 | 26 | //! Indicate whether the environment variable is defined 27 | bool _isPresent; 28 | 29 | //! The environment variable name 30 | std::string _name; 31 | 32 | public: 33 | //! \brief Construct an environment variable 34 | //! 35 | //! \param name The name of the environment variable 36 | //! \param defaultValue An optional value to assign if the environment variable has not been defined 37 | EnvironmentVariable(std::string const &name, T defaultValue = T()) : 38 | _value(defaultValue), 39 | _isPresent(false), 40 | _name(name) 41 | { 42 | char const *valueString = getenv(name.c_str()); 43 | if (valueString != nullptr) { 44 | _isPresent = StringSupport::parse(valueString, _value); 45 | if (!_isPresent) 46 | ErrorHandler::warn("Invalid value for ", name, "; defaulting to ", defaultValue); 47 | } 48 | } 49 | 50 | //! \brief Indicate if the enviornment variable has actually been defined 51 | //! 52 | //! \returns Whether the enviornment variable is defined 53 | bool isPresent() const 54 | { 55 | return _isPresent; 56 | } 57 | 58 | //! \brief Retrieve the current value 59 | //! 60 | //! \returns The current value 61 | T get() const 62 | { 63 | return _value; 64 | } 65 | 66 | //! \brief Retrieve the current value 67 | //! 68 | //! \returns The current value 69 | operator T() const 70 | { 71 | return _value; 72 | } 73 | 74 | //! \brief Overwrite the value 75 | //! 76 | //! This method does not alter the actual enviornment variable, it only 77 | //! modifies the value stored in the object 78 | //! 79 | //! \param value The new value 80 | //! \param makePresent Mark it as if it had been originally defined 81 | void set(T value, bool makePresent = false) 82 | { 83 | _value = value; 84 | _isPresent |= makePresent; 85 | } 86 | }; 87 | 88 | } // namespace tampi 89 | 90 | #endif // ENVIRONMENT_VARIABLE_HPP 91 | -------------------------------------------------------------------------------- /src/common/util/ErrorHandler.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2019-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef ERROR_HANDLER_HPP 8 | #define ERROR_HANDLER_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | namespace tampi { 20 | 21 | //! Class providing the functionality of error handling 22 | class ErrorHandler { 23 | private: 24 | static std::mutex _lock; 25 | 26 | template 27 | static void emitReasonParts(std::ostringstream &oss, T const &firstReasonPart, TS... reasonParts) 28 | { 29 | oss << firstReasonPart; 30 | emitReasonParts(oss, reasonParts...); 31 | } 32 | 33 | static void emitReasonParts(__attribute__((unused)) std::ostringstream &oss) 34 | { 35 | } 36 | 37 | static void safeEmitPart(__attribute__((unused)) char *buffer, __attribute__((unused)) size_t size, char part) 38 | { 39 | write(2, &part, 1); 40 | } 41 | 42 | static void safeEmitPart(char *buffer, size_t size, int part) 43 | { 44 | int length = snprintf(buffer, size, "%i", part); 45 | write(2, buffer, length); 46 | } 47 | 48 | static void safeEmitPart(char *buffer, size_t size, long part) 49 | { 50 | int length = snprintf(buffer, size, "%li", part); 51 | write(2, buffer, length); 52 | } 53 | 54 | static void safeEmitPart(__attribute__((unused)) char *buffer, __attribute__((unused)) size_t size, char const *part) 55 | { 56 | write(2, part, strlen(part)); 57 | } 58 | 59 | static void safeEmitPart(char *buffer, size_t size, float part) 60 | { 61 | int length = snprintf(buffer, size, "%f", part); 62 | write(2, buffer, length); 63 | } 64 | 65 | static void safeEmitPart(char *buffer, size_t size, double part) 66 | { 67 | int length = snprintf(buffer, size, "%f", part); 68 | write(2, buffer, length); 69 | } 70 | 71 | template 72 | static void safeEmitReasonParts(char *buffer, size_t size, T const &firstReasonPart, TS... reasonParts) 73 | { 74 | safeEmitPart(buffer, size, firstReasonPart); 75 | safeEmitReasonParts(buffer, size, reasonParts...); 76 | } 77 | 78 | static void safeEmitReasonParts(__attribute__((unused)) char *buffer, __attribute__((unused)) size_t size) 79 | { 80 | } 81 | 82 | public: 83 | //! \brief Print an error message and abort the execution 84 | //! 85 | //! \param reasonParts The reason of the failure 86 | template 87 | static void fail(TS... reasonParts) 88 | { 89 | std::ostringstream oss; 90 | oss << "Error: "; 91 | emitReasonParts(oss, reasonParts...); 92 | oss << std::endl; 93 | 94 | { 95 | std::lock_guard guard(_lock); 96 | std::cerr << oss.str(); 97 | } 98 | 99 | #ifndef NDEBUG 100 | abort(); 101 | #else 102 | exit(1); 103 | #endif 104 | } 105 | 106 | //! \brief Print an error message and abort the execution if failed 107 | //! 108 | //! \param failure Whether the condition failed 109 | //! \param reasonParts The reason of the failure 110 | template 111 | static void failIf(bool failure, TS... reasonParts) 112 | { 113 | if (__builtin_expect(!failure, 1)) 114 | return; 115 | 116 | fail(reasonParts...); 117 | } 118 | 119 | //! \brief Print a warning message 120 | //! 121 | //! \param reasonParts The reason of the warning 122 | template 123 | static void warn(TS... reasonParts) 124 | { 125 | std::ostringstream oss; 126 | oss << "Warning: "; 127 | emitReasonParts(oss, reasonParts...); 128 | oss << std::endl; 129 | 130 | { 131 | std::lock_guard guard(_lock); 132 | std::cerr << oss.str(); 133 | } 134 | } 135 | 136 | //! \brief Print a warning message if failed 137 | //! 138 | //! \param failure Whether the condition failed 139 | //! \param reasonParts The reason of the warning 140 | template 141 | static void warnIf(bool failure, TS... reasonParts) 142 | { 143 | if (__builtin_expect(!failure, 1)) 144 | return; 145 | 146 | warn(reasonParts...); 147 | } 148 | }; 149 | 150 | } // namespace tampi 151 | 152 | #endif // ERROR_HANDLER_HPP 153 | -------------------------------------------------------------------------------- /src/common/util/FixedSizeStack.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef FIXED_SIZE_STACK_HPP 8 | #define FIXED_SIZE_STACK_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | namespace tampi { 17 | 18 | //! Class that implements a stack with a fixed capacity 19 | template 20 | class FixedSizeStack { 21 | private: 22 | //! The array of elements 23 | std::array _array; 24 | 25 | //! The current size of the stack 26 | size_t _size; 27 | 28 | public: 29 | //! \brief Constructs an empty stack 30 | FixedSizeStack() : 31 | _array(), 32 | _size(0) 33 | { 34 | } 35 | 36 | //! \brief Checks whether the stack is empty 37 | bool empty() const 38 | { 39 | return _size == 0; 40 | } 41 | 42 | //! \brief Gets the stack size 43 | size_t size() const 44 | { 45 | return _size; 46 | } 47 | 48 | //! \brief Gets the stack capacity 49 | constexpr size_t capacity() const 50 | { 51 | return Capacity; 52 | } 53 | 54 | //! \brief Pushes an element to the stack 55 | //! 56 | //! \param element The element to push 57 | void push(const T &element) 58 | { 59 | assert(_size < Capacity); 60 | _array[_size] = element; 61 | ++_size; 62 | } 63 | 64 | //! \brief Pushes multiple elements to the stack 65 | //! 66 | //! The operation assumes there is enough space to push all the elements 67 | //! 68 | //! \param elements The pointer to the elements to push 69 | //! \param n The number of elements to push 70 | void push(const T *elements, size_t n) 71 | { 72 | assert(_size + n <= Capacity); 73 | std::copy(elements, elements + n, _array.begin() + _size); 74 | _size += n; 75 | } 76 | 77 | //! \brief Pops an element from the stack 78 | //! 79 | //! The operation assumes there is at least an element in the stack 80 | //! 81 | //! \param element The place where to store the retrieved element 82 | bool pop(T &element) 83 | { 84 | if (_size == 0) 85 | return false; 86 | 87 | --_size; 88 | element = _array[_size]; 89 | return true; 90 | } 91 | }; 92 | 93 | } // namespace tampi 94 | 95 | #endif // FIXED_SIZE_STACK_HPP 96 | -------------------------------------------------------------------------------- /src/common/util/SpinLock.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef SPIN_LOCK_HPP 8 | #define SPIN_LOCK_HPP 9 | 10 | #include 11 | 12 | #include "SpinWait.hpp" 13 | #include "Utils.hpp" 14 | 15 | 16 | namespace tampi { 17 | 18 | //! Class that implements a ticket array spinlock that focuses on 19 | //! avoiding the overhead when there are many threads trying to 20 | //! acquire the lock at the same time 21 | class SpinLock { 22 | private: 23 | static constexpr size_t Size = MaxSystemCPUs; 24 | 25 | alignas(CacheAlignment) PaddedArray, Size> _buffer; 26 | alignas(CacheAlignment) std::atomic _head; 27 | alignas(CacheAlignment) size_t _next; 28 | 29 | public: 30 | SpinLock() : 31 | _head(0), 32 | _next(0) 33 | { 34 | for (size_t i = 0; i < Size; ++i) 35 | std::atomic_init(&_buffer[i], (size_t) 0); 36 | } 37 | 38 | //! \brief Aquire the spinlock 39 | void lock() 40 | { 41 | const size_t head = _head.fetch_add(1, std::memory_order_relaxed); 42 | const size_t idx = head % Size; 43 | while (_buffer[idx].load(std::memory_order_relaxed) != head) { 44 | SpinWait::wait(); 45 | } 46 | SpinWait::release(); 47 | 48 | std::atomic_thread_fence(std::memory_order_acquire); 49 | } 50 | 51 | //! \brief Try to acquire the spinlock 52 | //! 53 | //! \returns Whether the spinlock was acquired 54 | bool try_lock() 55 | { 56 | size_t head = _head.load(std::memory_order_relaxed); 57 | const size_t idx = head % Size; 58 | if (_buffer[idx].load(std::memory_order_relaxed) != head) 59 | return false; 60 | 61 | return std::atomic_compare_exchange_strong_explicit( 62 | &_head, &head, head + 1, 63 | std::memory_order_acquire, 64 | std::memory_order_relaxed); 65 | } 66 | 67 | //! \brief Release the spinlock 68 | void unlock() 69 | { 70 | const size_t idx = ++_next % Size; 71 | _buffer[idx].store(_next, std::memory_order_release); 72 | } 73 | }; 74 | 75 | } // namespace tampi 76 | 77 | #endif // SPIN_LOCK_HPP 78 | -------------------------------------------------------------------------------- /src/common/util/SpinWait.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING file. 3 | 4 | Copyright (C) 2022-2023 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef SPIN_WAIT_HPP 8 | #define SPIN_WAIT_HPP 9 | 10 | #if defined(__powerpc__) || defined(__powerpc64__) || defined(__PPC__) || defined(__PPC64__) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) 11 | #define POWER9_ARCH 12 | #endif 13 | 14 | #if defined(__i386__) || defined(__x86_64__) 15 | #define X86_ARCH 16 | #endif 17 | 18 | #if defined(__arm__) || defined(__aarch64__) 19 | #define ARM_ARCH 20 | #endif 21 | 22 | #if defined(__SSE2__) 23 | #include 24 | #define SSE2_ARCH_FEATURE 25 | #endif 26 | 27 | #if defined(POWER9_ARCH) 28 | /* Macros for adjusting thread priority (hardware multi-threading) */ 29 | #define HMT_very_low() asm volatile("or 31,31,31 # very low priority") 30 | #define HMT_low() asm volatile("or 1,1,1 # low priority") 31 | #define HMT_medium_low() asm volatile("or 6,6,6 # medium low priority") 32 | #define HMT_medium() asm volatile("or 2,2,2 # medium priority") 33 | #define HMT_medium_high() asm volatile("or 5,5,5 # medium high priority") 34 | #define HMT_high() asm volatile("or 3,3,3 # high priority") 35 | #define HMT_barrier() asm volatile("" : : : "memory") 36 | #endif 37 | 38 | namespace tampi { 39 | 40 | struct SpinWait { 41 | static void wait() 42 | { 43 | #if defined(SSE2_ARCH_FEATURE) 44 | _mm_pause(); 45 | #elif defined(POWER9_ARCH) 46 | HMT_low(); 47 | #elif defined(X86_ARCH) 48 | asm volatile("pause" ::: "memory"); 49 | #elif defined(ARM_ARCH) 50 | __asm__ __volatile__ ("yield"); 51 | #else 52 | #pragma message ("No 'pause' instruction/intrisic found for this architecture ") 53 | #endif 54 | } 55 | 56 | static void release() 57 | { 58 | #if defined(POWER9_ARCH) 59 | HMT_medium(); 60 | #endif 61 | } 62 | }; 63 | 64 | } // namespace tampi 65 | 66 | #endif // SPIN_WAIT_HPP 67 | -------------------------------------------------------------------------------- /src/common/util/Utils.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef UTILS_HPP 8 | #define UTILS_HPP 9 | 10 | #ifdef HAVE_CONFIG_H 11 | #include 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #ifndef CACHELINE_SIZE 22 | #define CACHELINE_SIZE 64 23 | #endif 24 | 25 | #ifndef MAX_SYSTEM_CPUS 26 | #define MAX_SYSTEM_CPUS 64 27 | #endif 28 | 29 | 30 | namespace tampi { 31 | 32 | //! Cache alignment is the size of two cache lines to avoid 33 | //! false sharing between objects 34 | constexpr size_t CacheAlignment = CACHELINE_SIZE * 2; 35 | 36 | //! The maximum number of CPUs in the system 37 | constexpr size_t MaxSystemCPUs = MAX_SYSTEM_CPUS; 38 | 39 | //! Class that provides padding for a type 40 | template 41 | class Padded { 42 | //! \brief Computes the neareast integer multiple of a given value 43 | //! 44 | //! \param x The value to round 45 | //! \param y The value which the result should be multiple of 46 | //! 47 | //! \returns The nearest multiple integer 48 | static constexpr size_t roundup(size_t const x, size_t const y) 49 | { 50 | return (((x + (y - 1)) / y) * y); 51 | } 52 | 53 | //! The actual object 54 | T _value; 55 | 56 | //! The extra space 57 | uint8_t _padding[roundup(sizeof(T), Size) - sizeof(T)]; 58 | 59 | public: 60 | Padded() {} 61 | 62 | Padded(T value) : _value(value) {} 63 | 64 | template 65 | Padded(Args&&... args) : _value(std::forward(args)...) {} 66 | 67 | //! \brief Get a reference to the object 68 | T &get() 69 | { 70 | return _value; 71 | } 72 | 73 | //! \brief Get a const reference to the object 74 | const T &get() const 75 | { 76 | return _value; 77 | } 78 | }; 79 | 80 | //! Class that provides a padded array 81 | template 82 | class PaddedArray { 83 | //! The array of objects 84 | Padded _data[Capacity]; 85 | 86 | public: 87 | PaddedArray() 88 | { 89 | assert((uintptr_t) _data % CacheAlignment == 0); 90 | } 91 | 92 | T &operator[](size_t i) 93 | { 94 | assert(i < Capacity); 95 | return _data[i].get(); 96 | } 97 | 98 | const T &operator[](size_t i) const 99 | { 100 | assert(i < Capacity); 101 | return _data[i].get(); 102 | } 103 | }; 104 | 105 | //! Class providing uninitialized array memory for a type 106 | template 107 | class Uninitialized { 108 | typename std::aligned_storage::type _data[N]; 109 | 110 | public: 111 | T *get() 112 | { 113 | return reinterpret_cast(&_data); 114 | } 115 | 116 | operator T *() 117 | { 118 | return get(); 119 | } 120 | 121 | T &operator[](size_t idx) 122 | { 123 | return *(get() + idx); 124 | } 125 | 126 | const T &operator[](size_t idx) const 127 | { 128 | return *(get() + idx); 129 | } 130 | }; 131 | 132 | //! Class that provides memory allocation utilities 133 | class Memory { 134 | public: 135 | //! \brief Allocate aligned memory for several objects 136 | //! 137 | //! The operation only allocates memory; it does not construct the objects 138 | //! 139 | //! \param n The number of objects (of type T) to allocate 140 | //! 141 | //! \returns The pointer to the objects 142 | template 143 | static T *alignedAlloc(size_t n) 144 | { 145 | void *ptr = mmap(NULL, sizeof(T) * n, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, 0, 0); 146 | if (ptr == MAP_FAILED) 147 | ErrorHandler::fail("Failed to allocate aligned memory"); 148 | if ((uintptr_t) ptr % CacheAlignment != 0) 149 | ErrorHandler::fail("Aligned memory is not aligned to ", CacheAlignment); 150 | return (T *) ptr; 151 | } 152 | 153 | //! \brief Free aligned memory holding several objects 154 | //! 155 | //! The operation only frees memory; it does not destroy any object. The 156 | //! memory must have been allocated by the 'alignedAlloc' function 157 | //! 158 | //! \param data The pointer to the objects (of type T) 159 | //! \param n The number of objects 160 | template 161 | static void alignedFree(T *data, size_t n) 162 | { 163 | munmap(data, sizeof(T) * n); 164 | } 165 | }; 166 | 167 | } // namespace tampi 168 | 169 | #endif // UTILS_HPP 170 | -------------------------------------------------------------------------------- /src/include/TAMPI.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2019 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef TAMPI_H 8 | #define TAMPI_H 9 | 10 | #include 11 | 12 | #include "TAMPI_Decl.h" 13 | #include "TAMPI_Wrappers.h" 14 | 15 | #endif /* TAMPI_H */ 16 | -------------------------------------------------------------------------------- /src/include/TAMPI_Decl.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef TAMPI_DECL_H 8 | #define TAMPI_DECL_H 9 | 10 | #include 11 | 12 | #pragma GCC visibility push(default) 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | //! Constant defining the major version of the current interface 19 | #define TAMPI_VERSION_MAJOR 4 20 | 21 | //! Constant defining the minor version of the current interface 22 | #define TAMPI_VERSION_MINOR 0 23 | 24 | //! The MPI thread level that enables the task-aware blocking mode 25 | #define MPI_TASK_MULTIPLE (MPI_THREAD_MULTIPLE + 1) 26 | 27 | //! The TAMPI_PROPERTY_BLOCKING_MODE is the property to obtain whether the task- 28 | //! aware blocking mode is enabled. This property can only be consulted; setting 29 | //! its value is invalid 30 | #define TAMPI_PROPERTY_BLOCKING_MODE 0x1 31 | 32 | //! The TAMPI_PROPERTY_NONBLOCKING_MODE is the property to obtain whether the 33 | //! task-aware non-blocking mode is enabled. This property can only consulted; 34 | //! setting its value is invalid 35 | #define TAMPI_PROPERTY_NONBLOCKING_MODE 0x2 36 | 37 | //! The TAMPI_PROPERTY_AUTO_INIT enables/disables the automatic initialization 38 | //! and finalization of TAMPI when MPI_Init, MPI_Init_thread and MPI_Finalized 39 | //! are called. The property value is treated as a boolean that enables or 40 | //! disables the automatic initialization. Changing this property is only valid 41 | //! before MPI_Init is called. By default, the TAMPI is automatically initialized 42 | //! and finalizes when MPI does 43 | #define TAMPI_PROPERTY_AUTO_INIT 0x3 44 | 45 | //! The TAMPI_PROPERTY_THREAD_TASKAWARE enables/disables the task-awareness for 46 | //! the calling thread. The task-awareness is the interception of blocking MPI 47 | //! calls and the pause/resume of communication tasks. This property is per 48 | //! thread and only considered when the MPI_TASK_MULTIPLE is enabled. It is user 49 | //! responsibility to enable and disable it whenever it is necessary. When a 50 | //! thread encounters a blocking MPI call, it will check this thread-local value 51 | //! to decide whether the communication must be task-aware or not. By default, 52 | //! all threads have their task-awareness enabled 53 | #define TAMPI_PROPERTY_THREAD_TASKAWARE 0x4 54 | 55 | //! Functions to get and set library properties 56 | int TAMPI_Property_get(int property, int *value); 57 | int TAMPI_Property_set(int property, int value); 58 | 59 | //! Functions to initialize and finalize explicitly 60 | int TAMPI_Init(int required, int *provided); 61 | int TAMPI_Finalize(void); 62 | 63 | //! Functions to know which TAMPI modes are enabled 64 | int TAMPI_Blocking_enabled(int *flag); 65 | int TAMPI_Nonblocking_enabled(int *flag); 66 | 67 | //! Functions to asycnhronously wait communications from tasks 68 | int TAMPI_Iwait(MPI_Request *request, MPI_Status *status); 69 | int TAMPI_Iwaitall(int count, MPI_Request requests[], MPI_Status statuses[]); 70 | 71 | //! Fortran prototypes of previous C/C++ functions 72 | void tampi_property_get_(MPI_Fint *property, MPI_Fint *value, MPI_Fint *err); 73 | void tampi_property_set_(MPI_Fint *property, MPI_Fint *value, MPI_Fint *err); 74 | void tampi_init_(MPI_Fint *required, MPI_Fint *provided, MPI_Fint *err); 75 | void tampi_finalize_(MPI_Fint *err); 76 | void tampi_blocking_enabled_(MPI_Fint *flag, MPI_Fint *err); 77 | void tampi_nonblocking_enabled_(MPI_Fint *flag, MPI_Fint *err); 78 | void tampi_iwait_(MPI_Fint *request, MPI_Fint *status, MPI_Fint *err); 79 | void tampi_iwaitall_(MPI_Fint *count, MPI_Fint requests[], MPI_Fint *statuses, MPI_Fint *err); 80 | 81 | #ifdef __cplusplus 82 | } 83 | #endif 84 | 85 | #pragma GCC visibility pop 86 | 87 | #endif /* TAMPI_DECL_H */ 88 | -------------------------------------------------------------------------------- /src/include/TAMPI_Wrappers.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #ifndef TAMPI_WRAPPERS_H 8 | #define TAMPI_WRAPPERS_H 9 | 10 | #include 11 | 12 | #include "TAMPI_Decl.h" 13 | 14 | #pragma GCC visibility push(default) 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | int TAMPI_Ibsend(const void *buf, int count, MPI_Datatype datatype, 21 | int dest, int tag, MPI_Comm comm); 22 | 23 | int TAMPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, 24 | int tag, MPI_Comm comm, MPI_Status *status); 25 | 26 | int TAMPI_Irsend(const void *buf, int count, MPI_Datatype datatype, 27 | int source, int tag, MPI_Comm comm); 28 | 29 | int TAMPI_Isend(const void *buf, int count, MPI_Datatype datatype, 30 | int dest, int tag, MPI_Comm comm); 31 | 32 | int TAMPI_Issend(const void *buf, int count, MPI_Datatype datatype, 33 | int source, int tag, MPI_Comm comm); 34 | 35 | int TAMPI_Iallgather(const void *sendbuf, int sendcount, 36 | MPI_Datatype sendtype, void *recvbuf, int recvcount, 37 | MPI_Datatype recvtype, MPI_Comm comm); 38 | 39 | int TAMPI_Iallgatherv(const void *sendbuf, int sendcount, 40 | MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], 41 | const int displs[], MPI_Datatype recvtype, MPI_Comm comm); 42 | 43 | int TAMPI_Iallreduce(const void *sendbuf, void *recvbuf, int count, 44 | MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); 45 | 46 | int TAMPI_Ialltoall(const void *sendbuf, int sendcount, 47 | MPI_Datatype sendtype, void *recvbuf, int recvcount, 48 | MPI_Datatype recvtype, MPI_Comm comm); 49 | 50 | int TAMPI_Ialltoallv(const void *sendbuf, const int sendcounts[], 51 | const int sdispls[], MPI_Datatype sendtype, void *recvbuf, 52 | const int recvcounts[], const int rdispls[], 53 | MPI_Datatype recvtype, MPI_Comm comm); 54 | 55 | int TAMPI_Ialltoallw(const void *sendbuf, const int sendcounts[], 56 | const int sdispls[], const MPI_Datatype sendtypes[], 57 | void *recvbuf, const int recvcounts[], const int rdispls[], 58 | const MPI_Datatype recvtypes[], MPI_Comm comm); 59 | 60 | int TAMPI_Ibarrier(MPI_Comm comm); 61 | 62 | int TAMPI_Ibcast(void *buf, int count, MPI_Datatype datatype, int root, 63 | MPI_Comm comm); 64 | 65 | int TAMPI_Igather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 66 | void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm); 67 | 68 | int TAMPI_Igatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 69 | void *recvbuf, const int recvcounts[], const int displs[], 70 | MPI_Datatype recvtype, int root, MPI_Comm comm); 71 | 72 | int TAMPI_Ireduce(const void *sendbuf, void *recvbuf, int count, 73 | MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm); 74 | 75 | int TAMPI_Ireduce_scatter(const void *sendbuf, void *recvbuf, 76 | const int recvcounts[], MPI_Datatype datatype, MPI_Op op, 77 | MPI_Comm comm); 78 | 79 | int TAMPI_Ireduce_scatter_block(const void *sendbuf, void *recvbuf, 80 | int recvcount, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); 81 | 82 | int TAMPI_Iscatter(const void *sendbuf, int sendcount, MPI_Datatype sendtype, 83 | void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm); 84 | 85 | int TAMPI_Iscatterv(const void *sendbuf, const int sendcounts[], 86 | const int displs[], MPI_Datatype sendtype, void *recvbuf, int recvcount, 87 | MPI_Datatype recvtype, int root, MPI_Comm comm); 88 | 89 | int TAMPI_Iscan(const void *sendbuf, void *recvbuf, int count, 90 | MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); 91 | 92 | int TAMPI_Iexscan(const void *sendbuf, void *recvbuf, int count, 93 | MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); 94 | 95 | #ifdef __cplusplus 96 | } 97 | #endif 98 | 99 | #pragma GCC visibility pop 100 | 101 | #endif /* TAMPI_WRAPPERS_H */ 102 | -------------------------------------------------------------------------------- /src/include/TAMPIf.h: -------------------------------------------------------------------------------- 1 | ! 2 | ! This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | ! 4 | ! Copyright (C) 2015-2024 Barcelona Supercomputing Center (BSC) 5 | ! 6 | 7 | #ifndef TAMPIF_H 8 | #define TAMPIF_H 9 | 10 | ! TAMPI does not support Fortran yet 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | # Compilers 2 | CXX=clang++ 3 | F90=mfc 4 | MPICXX?=mpicxx 5 | MPIF90?=mpif90 6 | 7 | # MPI Wrappers 8 | CXX_WRAPPERS=I_MPI_CXX=$(CXX) MPICH_CXX=$(CXX) OMPI_CXX=$(CXX) 9 | F90_WRAPPERS=I_MPI_F90=$(F90) MPICH_FC=$(F90) OMPI_FC=$(F90) 10 | 11 | CPPFLAGS=-I. 12 | CFLAGS=-O3 -std=c++11 --gcc-toolchain=$(shell which gcc | sed 's,/bin/gcc$$,,') 13 | FFLAGS=-O3 --pp 14 | 15 | ifdef LARGE_INPUT 16 | CPPFLAGS+=-DLARGE_INPUT 17 | endif 18 | 19 | # TAMPI Flags 20 | ifndef TAMPI_INCLUDE_PATH 21 | ifndef TAMPI_HOME 22 | $(error TAMPI_HOME must be defined if TAMPI_INCLUDE_PATH is not) 23 | endif 24 | TAMPI_INCLUDE_PATH=$(TAMPI_HOME)/include 25 | endif 26 | 27 | ifndef TAMPI_LIBRARY_PATH 28 | ifndef TAMPI_HOME 29 | $(error TAMPI_HOME must be defined if TAMPI_LIBRARY_PATH is not) 30 | endif 31 | TAMPI_LIBRARY_PATH=$(TAMPI_HOME)/lib 32 | endif 33 | 34 | TAMPI_CPPFLAGS=-I$(TAMPI_INCLUDE_PATH) 35 | TAMPI_LDCFLAGS=-L$(TAMPI_LIBRARY_PATH) -ltampi-c -Wl,-rpath=$(TAMPI_LIBRARY_PATH) 36 | TAMPI_LDFFLAGS=-L$(TAMPI_LIBRARY_PATH) -ltampi-fortran -Wl,-rpath=$(TAMPI_LIBRARY_PATH) 37 | 38 | all: $(PROGS) 39 | 40 | %.oss.test: oss/%.cpp 41 | @echo " MPICXX $@" 42 | $(CXX_WRAPPERS) $(MPICXX) $(CPPFLAGS) $(TAMPI_CPPFLAGS) $(CFLAGS) -fompss-2 $^ -o $@ $(TAMPI_LDCFLAGS) 43 | 44 | %.oss.test: oss/%.F90 45 | @echo " MPIF90 $@" 46 | $(F90_WRAPPERS) $(MPIF90) $(CPPFLAGS) $(FFLAGS) $(TAMPI_CPPFLAGS) --ompss-2 $^ -o $@ $(TAMPI_LDFFLAGS) 47 | 48 | %.omp.test: omp/%.cpp 49 | @echo " MPICXX $@" 50 | $(CXX_WRAPPERS) $(MPICXX) $(CPPFLAGS) $(CFLAGS) $(TAMPI_CPPFLAGS) -fopenmp=libompv $^ -o $@ $(TAMPI_LDCFLAGS) 51 | 52 | clean: 53 | rm -f *.o *.test *.mod 54 | -------------------------------------------------------------------------------- /tests/Utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_HPP 2 | #define UTILS_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #define CHECK(f...) \ 11 | do { \ 12 | const int __error = f; \ 13 | if (__error != MPI_SUCCESS) { \ 14 | fprintf(stderr, "Error: '%s' [%s:%i]: %i\n",#f,__FILE__,__LINE__, __error); \ 15 | std::abort(); \ 16 | } \ 17 | } while(0); 18 | 19 | #define ASSERT(e...) \ 20 | do { \ 21 | bool __condition = e; \ 22 | if (!__condition) { \ 23 | fprintf(stderr, "Error: '%s' [%s:%i]\n",#e,__FILE__,__LINE__); \ 24 | std::abort(); \ 25 | } \ 26 | } while(0); 27 | 28 | 29 | double getTime() 30 | { 31 | struct timeval tv; 32 | gettimeofday(&tv, 0); 33 | return tv.tv_sec + 1e-6 * tv.tv_usec; 34 | } 35 | 36 | #endif // UTILS_HPP 37 | 38 | -------------------------------------------------------------------------------- /tests/omp/CollectiveNonBlk.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2019-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | #include 13 | 14 | #ifdef LARGE_INPUT 15 | const int TIMESTEPS = 500; 16 | const int MSG_NUM = 1000; 17 | const int MSG_SIZE = 100; 18 | #else 19 | const int TIMESTEPS = 100; 20 | const int MSG_NUM = 100; 21 | const int MSG_SIZE = 100; 22 | #endif 23 | 24 | MPI_Comm comms[MSG_NUM]; 25 | 26 | int main(int argc, char **argv) 27 | { 28 | int provided; 29 | const int required = MPI_THREAD_MULTIPLE; 30 | CHECK(MPI_Init_thread(&argc, &argv, required, &provided)); 31 | ASSERT(provided == required); 32 | 33 | int rank, size; 34 | CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &rank)); 35 | CHECK(MPI_Comm_size(MPI_COMM_WORLD, &size)); 36 | ASSERT(size > 1); 37 | 38 | for (int c = 0; c < MSG_NUM; ++c) { 39 | CHECK(MPI_Comm_dup(MPI_COMM_WORLD, &comms[c])); 40 | } 41 | 42 | int * const buffer = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 43 | ASSERT(buffer != nullptr); 44 | 45 | #pragma omp parallel 46 | #pragma omp single 47 | { 48 | for (int t = 0; t < TIMESTEPS; ++t) { 49 | if (rank == 0) { 50 | int *message = buffer; 51 | 52 | for (int m = 0; m < MSG_NUM; ++m) { 53 | #pragma omp task depend(out: message[0:MSG_SIZE-1]) 54 | for (int d = 0; d < MSG_SIZE; ++d) { 55 | message[d] = d; 56 | } 57 | 58 | #pragma omp task depend(in: message[0:MSG_SIZE-1]) 59 | { 60 | CHECK(TAMPI_Ibcast(message, MSG_SIZE, MPI_INT, 0, comms[m])); 61 | } 62 | message += MSG_SIZE; 63 | } 64 | } else { 65 | int *message = buffer + (MSG_NUM - 1) * MSG_SIZE; 66 | 67 | for (int m = MSG_NUM - 1; m >= 0; --m) { 68 | #pragma omp task depend(out: message[0:MSG_SIZE-1]) 69 | { 70 | CHECK(TAMPI_Ibcast(message, MSG_SIZE, MPI_INT, 0, comms[m])); 71 | } 72 | 73 | #pragma omp task depend(in: message[0:MSG_SIZE-1]) 74 | for (int d = 0; d < MSG_SIZE; ++d) { 75 | ASSERT(message[d] == d); 76 | } 77 | message -= MSG_SIZE; 78 | } 79 | } 80 | } 81 | #pragma omp taskwait 82 | } 83 | 84 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 85 | 86 | for (int c = 0; c < MSG_NUM; ++c) { 87 | CHECK(MPI_Comm_free(&comms[c])); 88 | } 89 | CHECK(MPI_Finalize()); 90 | 91 | std::free(buffer); 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /tests/omp/MultiPrimitiveNonBlk.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2019-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | #include 13 | 14 | #ifdef LARGE_INPUT 15 | const int TIMESTEPS = 1000; 16 | const int MSG_NUM = 1000; 17 | const int MSG_SIZE = 100; 18 | #else 19 | const int TIMESTEPS = 100; 20 | const int MSG_NUM = 500; 21 | const int MSG_SIZE = 100; 22 | #endif 23 | 24 | struct statuses_t { 25 | MPI_Status status[4]; 26 | }; 27 | 28 | statuses_t statuses[MSG_NUM]; 29 | 30 | int main(int argc, char **argv) 31 | { 32 | int provided; 33 | const int required = MPI_THREAD_MULTIPLE; 34 | CHECK(MPI_Init_thread(&argc, &argv, required, &provided)); 35 | ASSERT(provided == required); 36 | 37 | int rank, size; 38 | CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &rank)); 39 | CHECK(MPI_Comm_size(MPI_COMM_WORLD, &size)); 40 | ASSERT(size >= 4); 41 | 42 | int * const buffer1 = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 43 | ASSERT(buffer1 != nullptr); 44 | 45 | int * buffer2 = nullptr; 46 | int * buffer3 = nullptr; 47 | if (rank == 0) { 48 | buffer2 = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 49 | buffer3 = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 50 | ASSERT(buffer2 != nullptr); 51 | ASSERT(buffer3 != nullptr); 52 | } 53 | 54 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 55 | double startTime = getTime(); 56 | 57 | #pragma omp parallel 58 | #pragma omp single 59 | { 60 | for (int t = 0; t < TIMESTEPS; ++t) { 61 | if (rank > 0) { 62 | int *message = buffer1; 63 | 64 | for (int m = 0; m < MSG_NUM; ++m) { 65 | #pragma omp task depend(out: message[0:MSG_SIZE-1]) 66 | for (int d = 0; d < MSG_SIZE; ++d) { 67 | message[d] = d; 68 | } 69 | 70 | #pragma omp task depend(in: message[0:MSG_SIZE-1]) 71 | { 72 | CHECK(TAMPI_Isend(message, MSG_SIZE, MPI_INT, 0, m, MPI_COMM_WORLD)); 73 | } 74 | message += MSG_SIZE; 75 | } 76 | } else if (rank == 0) { 77 | int *message1 = buffer1 + (MSG_NUM - 1) * MSG_SIZE; 78 | int *message2 = buffer2 + (MSG_NUM - 1) * MSG_SIZE; 79 | int *message3 = buffer3 + (MSG_NUM - 1) * MSG_SIZE; 80 | 81 | for (int m = MSG_NUM - 1; m >= 0; --m) { 82 | #pragma omp task depend(out: message1[0:MSG_SIZE-1], message2[0:MSG_SIZE-1], message3[0:MSG_SIZE-1]) depend(out: statuses[m]) 83 | { 84 | CHECK(TAMPI_Irecv(message1, MSG_SIZE, MPI_INT, 1, m, MPI_COMM_WORLD, &statuses[m].status[0])); 85 | CHECK(TAMPI_Irecv(message2, MSG_SIZE, MPI_INT, 2, m, MPI_COMM_WORLD, &statuses[m].status[1])); 86 | CHECK(TAMPI_Irecv(message3, MSG_SIZE, MPI_INT, 3, m, MPI_COMM_WORLD, &statuses[m].status[2])); 87 | } 88 | 89 | #pragma omp task depend(in: message1[0:MSG_SIZE-1], message2[0:MSG_SIZE-1], message3[0:MSG_SIZE-1]) depend(in: statuses[m]) 90 | { 91 | const MPI_Status &status1 = statuses[m].status[0]; 92 | const MPI_Status &status2 = statuses[m].status[1]; 93 | const MPI_Status &status3 = statuses[m].status[2]; 94 | 95 | int count1, count2, count3; 96 | CHECK(MPI_Get_count(&status1, MPI_INT, &count1)); 97 | CHECK(MPI_Get_count(&status2, MPI_INT, &count2)); 98 | CHECK(MPI_Get_count(&status3, MPI_INT, &count3)); 99 | ASSERT(count1 == MSG_SIZE); 100 | ASSERT(count2 == MSG_SIZE); 101 | ASSERT(count3 == MSG_SIZE); 102 | 103 | ASSERT(status1.MPI_TAG == m); 104 | ASSERT(status1.MPI_SOURCE == 1); 105 | ASSERT(status2.MPI_TAG == m); 106 | ASSERT(status2.MPI_SOURCE == 2); 107 | ASSERT(status3.MPI_TAG == m); 108 | ASSERT(status3.MPI_SOURCE == 3); 109 | 110 | for (int d = 0; d < MSG_SIZE; ++d) { 111 | ASSERT(message1[d] == d); 112 | } 113 | for (int d = 0; d < MSG_SIZE; ++d) { 114 | ASSERT(message2[d] == d); 115 | } 116 | for (int d = 0; d < MSG_SIZE; ++d) { 117 | ASSERT(message3[d] == d); 118 | } 119 | } 120 | 121 | message1 -= MSG_SIZE; 122 | message2 -= MSG_SIZE; 123 | message3 -= MSG_SIZE; 124 | } 125 | } 126 | } 127 | #pragma omp taskwait 128 | } 129 | 130 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 131 | 132 | if (rank == 0) { 133 | double endTime = getTime(); 134 | fprintf(stdout, "Success, time: %f\n", endTime - startTime); 135 | } 136 | 137 | CHECK(MPI_Finalize()); 138 | 139 | std::free(buffer1); 140 | if (rank == 0) { 141 | std::free(buffer2); 142 | std::free(buffer3); 143 | } 144 | 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /tests/omp/PrimitiveNonBlk.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2019-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | #include 13 | 14 | #ifdef LARGE_INPUT 15 | const int TIMESTEPS = 1000; 16 | const int MSG_NUM = 1000; 17 | const int MSG_SIZE = 100; 18 | #else 19 | const int TIMESTEPS = 500; 20 | const int MSG_NUM = 500; 21 | const int MSG_SIZE = 100; 22 | #endif 23 | 24 | MPI_Status statuses[MSG_NUM]; 25 | 26 | int main(int argc, char **argv) 27 | { 28 | int provided; 29 | const int required = MPI_THREAD_MULTIPLE; 30 | CHECK(MPI_Init_thread(&argc, &argv, required, &provided)); 31 | ASSERT(provided == required); 32 | 33 | int rank, size; 34 | CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &rank)); 35 | CHECK(MPI_Comm_size(MPI_COMM_WORLD, &size)); 36 | ASSERT(size > 1); 37 | 38 | int * const buffer = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 39 | ASSERT(buffer != nullptr); 40 | 41 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 42 | double startTime = getTime(); 43 | 44 | #pragma omp parallel 45 | #pragma omp single 46 | { 47 | for (int t = 0; t < TIMESTEPS; ++t) { 48 | if (rank == 0) { 49 | int *message = buffer; 50 | 51 | for (int m = 0; m < MSG_NUM; ++m) { 52 | #pragma omp task depend(out: message[0:MSG_SIZE-1]) 53 | for (int d = 0; d < MSG_SIZE; ++d) { 54 | message[d] = d; 55 | } 56 | 57 | #pragma omp task depend(in: message[0:MSG_SIZE-1]) 58 | { 59 | CHECK(TAMPI_Isend(message, MSG_SIZE, MPI_INT, 1, m, MPI_COMM_WORLD)); 60 | } 61 | message += MSG_SIZE; 62 | } 63 | } else if (rank == 1) { 64 | int *message = buffer + (MSG_NUM - 1) * MSG_SIZE; 65 | 66 | for (int m = MSG_NUM - 1; m >= 0; --m) { 67 | #pragma omp task depend(out: message[0:MSG_SIZE-1], statuses[m]) 68 | { 69 | CHECK(TAMPI_Irecv(message, MSG_SIZE, MPI_INT, 0, m, MPI_COMM_WORLD, &statuses[m])); 70 | } 71 | 72 | #pragma omp task depend(in: message[0:MSG_SIZE-1], statuses[m]) 73 | for (int d = 0; d < MSG_SIZE; ++d) { 74 | ASSERT(message[d] == d); 75 | ASSERT(statuses[m].MPI_TAG == m); 76 | ASSERT(statuses[m].MPI_SOURCE == 0); 77 | 78 | int count; 79 | CHECK(MPI_Get_count(&statuses[m], MPI_INT, &count)); 80 | ASSERT(count == MSG_SIZE); 81 | } 82 | message -= MSG_SIZE; 83 | } 84 | } 85 | } 86 | #pragma omp taskwait 87 | } 88 | 89 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 90 | 91 | if (rank == 0) { 92 | double endTime = getTime(); 93 | fprintf(stdout, "Success, time: %f\n", endTime - startTime); 94 | } 95 | 96 | CHECK(MPI_Finalize()); 97 | 98 | std::free(buffer); 99 | 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /tests/oss/CollectiveBlk.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2019-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | #include 13 | 14 | #ifdef LARGE_INPUT 15 | const int TIMESTEPS = 500; 16 | const int MSG_NUM = 1000; 17 | const int MSG_SIZE = 100; 18 | #else 19 | const int TIMESTEPS = 100; 20 | const int MSG_NUM = 100; 21 | const int MSG_SIZE = 100; 22 | #endif 23 | 24 | MPI_Comm comms[MSG_NUM]; 25 | 26 | int main(int argc, char **argv) 27 | { 28 | int provided; 29 | const int required = MPI_TASK_MULTIPLE; 30 | CHECK(MPI_Init_thread(&argc, &argv, required, &provided)); 31 | ASSERT(provided == required); 32 | 33 | int rank, size; 34 | CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &rank)); 35 | CHECK(MPI_Comm_size(MPI_COMM_WORLD, &size)); 36 | ASSERT(size > 1); 37 | 38 | for (int c = 0; c < MSG_NUM; ++c) { 39 | CHECK(MPI_Comm_dup(MPI_COMM_WORLD, &comms[c])); 40 | } 41 | 42 | int * const buffer = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 43 | ASSERT(buffer != nullptr); 44 | 45 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 46 | double startTime = getTime(); 47 | 48 | for (int t = 0; t < TIMESTEPS; ++t) { 49 | if (rank == 0) { 50 | int *message = buffer; 51 | 52 | for (int m = 0; m < MSG_NUM; ++m) { 53 | #pragma oss task out(message[0;MSG_SIZE]) label("init") 54 | for (int d = 0; d < MSG_SIZE; ++d) { 55 | message[d] = d; 56 | } 57 | 58 | #pragma oss task in(message[0;MSG_SIZE]) label("bcast") 59 | { 60 | CHECK(MPI_Bcast(message, MSG_SIZE, MPI_INT, 0, comms[m])); 61 | } 62 | message += MSG_SIZE; 63 | } 64 | } else { 65 | int *message = buffer + (MSG_NUM - 1) * MSG_SIZE; 66 | 67 | for (int m = MSG_NUM - 1; m >= 0; --m) { 68 | #pragma oss task out(message[0;MSG_SIZE]) label("bcast") 69 | { 70 | CHECK(MPI_Bcast(message, MSG_SIZE, MPI_INT, 0, comms[m])); 71 | } 72 | 73 | #pragma oss task in(message[0;MSG_SIZE]) label("check") 74 | for (int d = 0; d < MSG_SIZE; ++d) { 75 | ASSERT(message[d] == d); 76 | } 77 | message -= MSG_SIZE; 78 | } 79 | } 80 | } 81 | #pragma oss taskwait 82 | 83 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 84 | if (rank == 0) { 85 | double endTime = getTime(); 86 | fprintf(stdout, "Success, time: %f\n", endTime - startTime); 87 | } 88 | 89 | for (int c = 0; c < MSG_NUM; ++c) { 90 | CHECK(MPI_Comm_free(&comms[c])); 91 | } 92 | CHECK(MPI_Finalize()); 93 | 94 | std::free(buffer); 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /tests/oss/CollectiveNonBlk.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2019-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | #include 13 | 14 | #ifdef LARGE_INPUT 15 | const int TIMESTEPS = 500; 16 | const int MSG_NUM = 1000; 17 | const int MSG_SIZE = 100; 18 | #else 19 | const int TIMESTEPS = 100; 20 | const int MSG_NUM = 100; 21 | const int MSG_SIZE = 100; 22 | #endif 23 | 24 | MPI_Comm comms[MSG_NUM]; 25 | 26 | int main(int argc, char **argv) 27 | { 28 | int provided; 29 | const int required = MPI_THREAD_MULTIPLE; 30 | CHECK(MPI_Init_thread(&argc, &argv, required, &provided)); 31 | ASSERT(provided == required); 32 | 33 | int rank, size; 34 | CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &rank)); 35 | CHECK(MPI_Comm_size(MPI_COMM_WORLD, &size)); 36 | ASSERT(size > 1); 37 | 38 | for (int c = 0; c < MSG_NUM; ++c) { 39 | CHECK(MPI_Comm_dup(MPI_COMM_WORLD, &comms[c])); 40 | } 41 | 42 | int * const buffer = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 43 | ASSERT(buffer != nullptr); 44 | 45 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 46 | double startTime = getTime(); 47 | 48 | for (int t = 0; t < TIMESTEPS; ++t) { 49 | if (rank == 0) { 50 | int *message = buffer; 51 | 52 | for (int m = 0; m < MSG_NUM; ++m) { 53 | #pragma oss task out(message[0;MSG_SIZE]) label("init") 54 | for (int d = 0; d < MSG_SIZE; ++d) { 55 | message[d] = d; 56 | } 57 | 58 | #pragma oss task in(message[0;MSG_SIZE]) label("bcast") 59 | { 60 | CHECK(TAMPI_Ibcast(message, MSG_SIZE, MPI_INT, 0, comms[m])); 61 | } 62 | message += MSG_SIZE; 63 | } 64 | } else { 65 | int *message = buffer + (MSG_NUM - 1) * MSG_SIZE; 66 | 67 | for (int m = MSG_NUM - 1; m >= 0; --m) { 68 | #pragma oss task out(message[0;MSG_SIZE]) label("bcast") 69 | { 70 | CHECK(TAMPI_Ibcast(message, MSG_SIZE, MPI_INT, 0, comms[m])); 71 | } 72 | 73 | #pragma oss task in(message[0;MSG_SIZE]) label("check") 74 | for (int d = 0; d < MSG_SIZE; ++d) { 75 | ASSERT(message[d] == d); 76 | } 77 | message -= MSG_SIZE; 78 | } 79 | } 80 | } 81 | #pragma oss taskwait 82 | 83 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 84 | if (rank == 0) { 85 | double endTime = getTime(); 86 | fprintf(stdout, "Success, time: %f\n", endTime - startTime); 87 | } 88 | 89 | for (int c = 0; c < MSG_NUM; ++c) { 90 | CHECK(MPI_Comm_free(&comms[c])); 91 | } 92 | CHECK(MPI_Finalize()); 93 | 94 | std::free(buffer); 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /tests/oss/DoNotExecute.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2019-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | //! NOTE: Do not take this test as an example, since 13 | //! it is not correct. It is only useful to check that 14 | //! compiles properly. Please do not execute it. 15 | 16 | int main(int argc, char **argv) 17 | { 18 | fprintf(stderr, "This code should not be executed!\n"); 19 | if (argc > 0) { 20 | return 1; 21 | } 22 | 23 | int provided; 24 | const int required = MPI_TASK_MULTIPLE; 25 | MPI_Init_thread(&argc, &argv, required, &provided); 26 | 27 | int rank, size; 28 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); 29 | MPI_Comm_size(MPI_COMM_WORLD, &size); 30 | 31 | void *sendbuf, *recvbuf; 32 | MPI_Request request; 33 | MPI_Status status; 34 | MPI_Datatype type; 35 | int count, *aux; 36 | MPI_Comm comm; 37 | MPI_Op op; 38 | 39 | TAMPI_Ibsend(sendbuf, count, type, count, count, comm); 40 | TAMPI_Irecv(recvbuf, count, type, count, count, comm, &status); 41 | TAMPI_Irsend(sendbuf, count, type, count, count, comm); 42 | TAMPI_Isend(sendbuf, count, type, count, count, comm); 43 | TAMPI_Issend(sendbuf, count, type, count, count, comm); 44 | TAMPI_Iwait(&request, &status); 45 | TAMPI_Iwaitall(count, &request, &status); 46 | 47 | TAMPI_Iallgather(sendbuf, count, type, recvbuf, count, type, comm); 48 | TAMPI_Iallgatherv(sendbuf, count, type, recvbuf, aux, aux, type, comm); 49 | TAMPI_Iallreduce(sendbuf, recvbuf, count, type, op, comm); 50 | TAMPI_Ialltoall(sendbuf, count, type, recvbuf, count, type, comm); 51 | TAMPI_Ialltoallv(sendbuf, aux, aux, type, recvbuf, aux, aux, type, comm); 52 | TAMPI_Ialltoallw(sendbuf, aux, aux, &type, recvbuf, aux, aux, &type, comm); 53 | TAMPI_Ibarrier(comm); 54 | TAMPI_Ibcast(recvbuf, count, type, count, comm); 55 | TAMPI_Igather(sendbuf, count, type, recvbuf, count, type, count, comm); 56 | TAMPI_Igatherv(sendbuf, count, type, recvbuf, aux, aux, type, count, comm); 57 | TAMPI_Ireduce(sendbuf, recvbuf, count, type, op, count, comm); 58 | TAMPI_Ireduce_scatter(sendbuf, recvbuf, aux, type, op, comm); 59 | TAMPI_Ireduce_scatter_block(sendbuf, recvbuf, count, type, op, comm); 60 | TAMPI_Iscatter(sendbuf, count, type, recvbuf, count, type, count, comm); 61 | TAMPI_Iscatterv(sendbuf, aux, aux, type, recvbuf, count, type, count, comm); 62 | TAMPI_Iscan(sendbuf, recvbuf, count, type, op, comm); 63 | TAMPI_Iexscan(sendbuf, recvbuf, count, type, op, comm); 64 | 65 | MPI_Finalize(); 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /tests/oss/DoNotExecutef.F90: -------------------------------------------------------------------------------- 1 | ! 2 | ! This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | ! 4 | ! Copyright (C) 2019-2022 Barcelona Supercomputing Center (BSC) 5 | ! 6 | 7 | #include "TAMPIf.h" 8 | 9 | ! NOTE: Do not take this test as an example, since 10 | ! it is not correct. It is only useful to check that 11 | ! compiles properly. Please do not execute it. 12 | 13 | module test 14 | implicit none 15 | include "mpif.h" 16 | 17 | contains 18 | 19 | subroutine test_kernel 20 | implicit none 21 | 22 | integer :: rank, nranks, provided, err 23 | integer :: num, datatype, op, comm 24 | integer, allocatable :: sendbuf(:), recvbuf(:), requests(:), statuses(:,:), aux(:), datatypes(:) 25 | 26 | call MPI_Init_thread(MPI_TASK_MULTIPLE, provided, err) 27 | if (provided < 100) then 28 | write(*,'("This code should not be executed!")') 29 | return 30 | endif 31 | 32 | call MPI_Comm_rank(MPI_COMM_WORLD, rank, err) 33 | call MPI_Comm_size(MPI_COMM_WORLD, nranks, err) 34 | 35 | call TAMPI_Ibsend(sendbuf, num, datatype, num, num, comm, requests(1), err) 36 | call TAMPI_Irecv(recvbuf, num, datatype, num, num, comm, requests(1), statuses(:,1), err) 37 | call TAMPI_Irsend(sendbuf, num, datatype, num, num, comm, requests(1), err) 38 | call TAMPI_Isend(sendbuf, num, datatype, num, num, comm, requests(1), err) 39 | call TAMPI_Issend(sendbuf, num, datatype, num, num, comm, requests(1), err) 40 | call TAMPI_Iwait(requests(1), statuses(:,1), err) 41 | call TAMPI_Iwaitall(num, requests(:), statuses(:,:), err) 42 | 43 | call TAMPI_Iallgather(sendbuf, num, datatype, recvbuf, num, datatype, comm, requests(1), err) 44 | call TAMPI_Iallgatherv(sendbuf, num, datatype, recvbuf, aux, aux, datatype, comm, requests(1), err) 45 | call TAMPI_Iallreduce(sendbuf, recvbuf, num, datatype, op, comm, requests(1), err) 46 | call TAMPI_ialltoall(sendbuf, num, datatype, recvbuf, num, datatype, comm, requests(1), err) 47 | call TAMPI_ialltoallv(sendbuf, aux, aux, datatype, recvbuf, aux, aux, datatype, comm, requests(1), err) 48 | call TAMPI_ialltoallw(sendbuf, aux, aux, datatypes(:), recvbuf, aux, aux, datatypes(:), comm, requests(1), err) 49 | call TAMPI_Ibarrier(comm, requests(1), err) 50 | call TAMPI_Ibcast(recvbuf, num, datatype, num, comm, requests(1), err) 51 | call TAMPI_Igather(sendbuf, num, datatype, recvbuf, num, datatype, num, comm, requests(1), err) 52 | call TAMPI_IGATHERV(sendbuf, num, datatype, recvbuf, aux, aux, datatype, num, comm, requests(1), err) 53 | call TAMPI_Ireduce(sendbuf, recvbuf, num, datatype, op, num, comm, requests(1), err) 54 | call TAMPI_Ireduce_scatter(sendbuf, recvbuf, aux, datatype, op, comm, requests(1), err) 55 | call TAMPI_IREDUCE_SCATTER_BLOCK(sendbuf, recvbuf, num, datatype, op, comm, requests(1), err) 56 | call TAMPI_Iscatter(sendbuf, num, datatype, recvbuf, num, datatype, num, comm, requests(1), err) 57 | call TAMPI_Iscatterv(sendbuf, aux, aux, datatype, recvbuf, num, datatype, num, comm, requests(1), err) 58 | call TAMPI_Iscan(sendbuf, recvbuf, num, datatype, op, comm, requests(1), err) 59 | call TAMPI_Iexscan(sendbuf, recvbuf, num, datatype, op, comm, requests(1), err) 60 | call TAMPI_Wait(requests(1), statuses(:,1), err) 61 | call TAMPI_Waitall(num, requests(:), statuses(:,1), err) 62 | 63 | call MPI_Finalize(err) 64 | 65 | return 66 | end subroutine test_kernel 67 | end module test 68 | 69 | program test_program 70 | use test 71 | call test_kernel 72 | end program test_program 73 | -------------------------------------------------------------------------------- /tests/oss/HugeBlkTasks.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2019-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | #include 13 | 14 | #ifdef LARGE_INPUT 15 | const int TIMESTEPS = 1000; 16 | const int MSG_NUM = 1000; 17 | const int MSG_SIZE = 100; 18 | #else 19 | const int TIMESTEPS = 500; 20 | const int MSG_NUM = 500; 21 | const int MSG_SIZE = 100; 22 | #endif 23 | 24 | const int TOTAL_SIZE = MSG_NUM * MSG_SIZE; 25 | 26 | MPI_Status statuses[MSG_NUM]; 27 | 28 | int main(int argc, char **argv) 29 | { 30 | int provided; 31 | const int required = MPI_TASK_MULTIPLE; 32 | CHECK(MPI_Init_thread(&argc, &argv, required, &provided)); 33 | ASSERT(provided == required); 34 | 35 | int rank, size; 36 | CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &rank)); 37 | CHECK(MPI_Comm_size(MPI_COMM_WORLD, &size)); 38 | ASSERT(size > 1); 39 | 40 | int * const buffer = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 41 | ASSERT(buffer != nullptr); 42 | 43 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 44 | double startTime = getTime(); 45 | 46 | for (int t = 0; t < TIMESTEPS; ++t) { 47 | if (rank == 0) { 48 | #pragma oss task out(buffer[0;TOTAL_SIZE]) label("init") 49 | for (int d = 0; d < TOTAL_SIZE; ++d) { 50 | buffer[d] = d; 51 | } 52 | 53 | #pragma oss task in(buffer[0;TOTAL_SIZE]) label("send") 54 | { 55 | for (int m = 0; m < MSG_NUM; ++m) { 56 | CHECK(TAMPI_Isend(&buffer[m*MSG_SIZE], MSG_SIZE, MPI_INT, 1, m, MPI_COMM_WORLD)); 57 | } 58 | } 59 | } else if (rank == 1) { 60 | int *message = buffer + (MSG_NUM - 1) * MSG_SIZE; 61 | 62 | #pragma oss task out(buffer[0;TOTAL_SIZE]) shared(statuses) label("recv") 63 | { 64 | for (int m = MSG_NUM - 1; m >= 0; --m) { 65 | CHECK(MPI_Recv(&buffer[m*MSG_SIZE], MSG_SIZE, MPI_INT, 0, m, MPI_COMM_WORLD, &statuses[MSG_NUM-1-m])); 66 | } 67 | 68 | for (int m = 0; m < MSG_NUM; ++m) { 69 | ASSERT(statuses[m].MPI_TAG == MSG_NUM - 1 - m); 70 | ASSERT(statuses[m].MPI_SOURCE == 0); 71 | 72 | int count; 73 | CHECK(MPI_Get_count(&statuses[m], MPI_INT, &count)); 74 | ASSERT(count == MSG_SIZE); 75 | } 76 | } 77 | 78 | #pragma oss task in(buffer[0;TOTAL_SIZE]) label("check") 79 | for (int d = 0; d < TOTAL_SIZE; ++d) { 80 | ASSERT(buffer[d] == d); 81 | } 82 | } 83 | } 84 | #pragma oss taskwait 85 | 86 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 87 | 88 | if (rank == 0) { 89 | double endTime = getTime(); 90 | fprintf(stdout, "Success, time: %f\n", endTime - startTime); 91 | } 92 | 93 | CHECK(MPI_Finalize()); 94 | 95 | std::free(buffer); 96 | 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /tests/oss/HugeTasksf.F90: -------------------------------------------------------------------------------- 1 | ! 2 | ! This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | ! 4 | ! Copyright (C) 2019-2022 Barcelona Supercomputing Center (BSC) 5 | ! 6 | 7 | #include "TAMPIf.h" 8 | 9 | module test 10 | implicit none 11 | include "mpif.h" 12 | 13 | contains 14 | 15 | subroutine test_kernel 16 | implicit none 17 | 18 | integer :: err, provided, msg_size, msg_num, total_size 19 | integer :: rank, nranks, timesteps, t, m, d, tmp 20 | integer, allocatable :: buffer(:,:), requests(:), statuses(:,:) 21 | real(kind=8) :: start_time, end_time 22 | 23 | call MPI_Init_thread(MPI_TASK_MULTIPLE, provided, err) 24 | if (provided /= MPI_TASK_MULTIPLE) then 25 | write(*,'("Error: TAMPI not supported")') 26 | return 27 | endif 28 | 29 | call MPI_Comm_rank(MPI_COMM_WORLD, rank, err) 30 | call MPI_Comm_size(MPI_COMM_WORLD, nranks, err) 31 | 32 | #ifdef LARGE_INPUT 33 | timesteps = 1000; 34 | msg_num = 1000; 35 | msg_size = 100; 36 | #else 37 | timesteps = 500; 38 | msg_num = 500; 39 | msg_size = 100; 40 | #endif 41 | 42 | total_size = msg_num * msg_size; 43 | 44 | allocate(buffer(msg_size, msg_num)) 45 | allocate(requests(msg_num)) 46 | allocate(statuses(MPI_STATUS_SIZE, msg_num)) 47 | 48 | call MPI_Barrier(MPI_COMM_WORLD, err) 49 | 50 | start_time = MPI_Wtime() 51 | 52 | do t = 1, timesteps 53 | if (rank == 0) then 54 | !$OSS TASK LABEL("init") DEFAULT(shared) PRIVATE(m,d) FIRSTPRIVATE(t) OUT(buffer(:,:)) 55 | do m = 1, msg_num 56 | do d = 1, msg_size 57 | buffer(d, m) = d + t 58 | enddo 59 | enddo 60 | !$OSS END TASK 61 | 62 | !$OSS TASK LABEL("init") DEFAULT(shared) PRIVATE(m,d,err) IN(buffer(:,:)) 63 | do m = 1, msg_num 64 | call MPI_Isend(buffer(:, m), msg_size, MPI_INTEGER, 1, m, MPI_COMM_WORLD, requests(m), err) 65 | enddo 66 | call MPI_Waitall(msg_num, requests, MPI_STATUSES_IGNORE, err) 67 | !$OSS END TASK 68 | 69 | else if (rank == 1) then 70 | !$OSS TASK LABEL("recv") DEFAULT(shared) PRIVATE(m,d,err) OUT(buffer(:,:), statuses(:,:)) 71 | do m = 1, msg_num 72 | call MPI_Irecv(buffer(:, m), msg_size, MPI_INTEGER, 0, m, MPI_COMM_WORLD, requests(m), err) 73 | enddo 74 | call TAMPI_Iwaitall(msg_num, requests, statuses, err) 75 | !$OSS END TASK 76 | 77 | !$OSS TASK LABEL("init") DEFAULT(shared) PRIVATE(m,d,tmp,err) FIRSTPRIVATE(t) IN(buffer(:,:), statuses(:,:)) 78 | do m = 1, msg_num 79 | if (statuses(MPI_SOURCE, m) /= 0) then 80 | write(*,'("Error: Wrong source")') 81 | stop 82 | endif 83 | if (statuses(MPI_TAG, m) /= m) then 84 | write(*,'("Error: Wrong tag")') 85 | stop 86 | endif 87 | call MPI_Get_count(statuses(:, m), MPI_INTEGER, tmp, err) 88 | if (tmp /= msg_size) then 89 | write(*,'("Error: Wrong message size")') 90 | stop 91 | endif 92 | 93 | do d = 1, msg_size 94 | if (buffer(d, m) /= d + t) then 95 | write(*,'("Error: Wrong result")') 96 | stop 97 | endif 98 | enddo 99 | enddo 100 | !$OSS END TASK 101 | endif 102 | enddo 103 | 104 | !$OSS TASKWAIT 105 | 106 | call MPI_Barrier(MPI_COMM_WORLD, err) 107 | 108 | end_time = MPI_Wtime() 109 | 110 | if (rank == 0) then 111 | write(*, 1001) end_time - start_time 112 | 1001 format('Success, time: ',F9.3) 113 | end if 114 | 115 | deallocate(buffer) 116 | deallocate(requests) 117 | deallocate(statuses) 118 | 119 | call MPI_Finalize(err) 120 | 121 | return 122 | end subroutine test_kernel 123 | end module test 124 | 125 | program test_program 126 | use test 127 | call test_kernel 128 | end program test_program 129 | -------------------------------------------------------------------------------- /tests/oss/InitAuto.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | int main(int argc, char **argv) 13 | { 14 | int value; 15 | 16 | // Check the auto init is enabled by default 17 | CHECK(TAMPI_Property_get(TAMPI_PROPERTY_AUTO_INIT, &value)); 18 | ASSERT(value == 1); 19 | 20 | // Initialize MPI and TAMPI 21 | CHECK(MPI_Init(&argc, &argv)); 22 | 23 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 24 | 25 | // Finalize TAMPI and MPI 26 | CHECK(MPI_Finalize()); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /tests/oss/InitAutoTaskAware.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | int main(int argc, char **argv) 13 | { 14 | int required = MPI_TASK_MULTIPLE; 15 | int provided, value; 16 | 17 | // Check the auto init is enabled by default 18 | CHECK(TAMPI_Property_get(TAMPI_PROPERTY_AUTO_INIT, &value)); 19 | ASSERT(value == 1); 20 | 21 | // Initialize both MPI and TAMPI 22 | CHECK(MPI_Init_thread(&argc, &argv, required, &provided)); 23 | ASSERT(provided == required); 24 | 25 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 26 | 27 | // Finalize both TAMPI and MPI 28 | CHECK(MPI_Finalize()); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /tests/oss/InitExplicit.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | int main(int argc, char **argv) 13 | { 14 | int original, provided, value; 15 | 16 | // Disable automatic TAMPI initialization 17 | CHECK(TAMPI_Property_set(TAMPI_PROPERTY_AUTO_INIT, 0)); 18 | 19 | // Check the auto init is disabled now 20 | CHECK(TAMPI_Property_get(TAMPI_PROPERTY_AUTO_INIT, &value)); 21 | ASSERT(value == 0); 22 | 23 | // Initialize MPI; which will set the default thread level 24 | CHECK(MPI_Init(&argc, &argv)); 25 | 26 | // Get the default thread level of MPI 27 | CHECK(MPI_Query_thread(&original)); 28 | ASSERT(original >= MPI_THREAD_SINGLE); 29 | ASSERT(original <= MPI_THREAD_MULTIPLE); 30 | 31 | // Initialize TAMPI with the lowest thread level. The default 32 | // thread level should be provided instead 33 | CHECK(TAMPI_Init(MPI_THREAD_SINGLE, &provided)); 34 | ASSERT(provided == original); 35 | 36 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 37 | 38 | // Finalize TAMPI 39 | CHECK(TAMPI_Finalize()); 40 | 41 | // Finalize MPI 42 | CHECK(MPI_Finalize()); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /tests/oss/InitExplicitTaskAware.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | int main(int argc, char **argv) 13 | { 14 | int provided, required, value; 15 | 16 | // Disable automatic TAMPI initialization 17 | CHECK(TAMPI_Property_set(TAMPI_PROPERTY_AUTO_INIT, 0)); 18 | 19 | // Check the auto init is disabled now 20 | CHECK(TAMPI_Property_get(TAMPI_PROPERTY_AUTO_INIT, &value)); 21 | ASSERT(value == 0); 22 | 23 | required = MPI_THREAD_MULTIPLE; 24 | 25 | // Initialize MPI 26 | CHECK(MPI_Init_thread(&argc, &argv, required, &provided)); 27 | ASSERT(provided == required); 28 | 29 | required = MPI_TASK_MULTIPLE; 30 | 31 | // Initialize TAMPI 32 | CHECK(TAMPI_Init(required, &provided)); 33 | ASSERT(provided == required); 34 | 35 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 36 | 37 | // Finalize TAMPI 38 | CHECK(TAMPI_Finalize()); 39 | 40 | // Finalize MPI 41 | CHECK(MPI_Finalize()); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /tests/oss/MultiPrimitiveBlk.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2019-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | #include 13 | 14 | #ifdef LARGE_INPUT 15 | const int TIMESTEPS = 100; 16 | const int MSG_NUM = 1000; 17 | const int MSG_SIZE = 100; 18 | #else 19 | const int TIMESTEPS = 50; 20 | const int MSG_NUM = 500; 21 | const int MSG_SIZE = 100; 22 | #endif 23 | 24 | int main(int argc, char **argv) 25 | { 26 | int provided; 27 | const int required = MPI_TASK_MULTIPLE; 28 | CHECK(MPI_Init_thread(&argc, &argv, required, &provided)); 29 | ASSERT(provided == required); 30 | 31 | int rank, size; 32 | CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &rank)); 33 | CHECK(MPI_Comm_size(MPI_COMM_WORLD, &size)); 34 | ASSERT(size >= 4); 35 | 36 | int * const buffer1 = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 37 | ASSERT(buffer1 != nullptr); 38 | 39 | int * buffer2 = nullptr; 40 | int * buffer3 = nullptr; 41 | if (rank == 0) { 42 | buffer2 = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 43 | buffer3 = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 44 | ASSERT(buffer2 != nullptr); 45 | ASSERT(buffer3 != nullptr); 46 | } 47 | 48 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 49 | double startTime = getTime(); 50 | 51 | for (int t = 0; t < TIMESTEPS; ++t) { 52 | if (rank > 0 && rank < 4) { 53 | int *message = buffer1; 54 | 55 | for (int m = 0; m < MSG_NUM; ++m) { 56 | #pragma oss task out(message[0;MSG_SIZE]) label("init") 57 | for (int d = 0; d < MSG_SIZE; ++d) { 58 | message[d] = d; 59 | } 60 | 61 | #pragma oss task in(message[0;MSG_SIZE]) label("send") 62 | { 63 | CHECK(MPI_Send(message, MSG_SIZE, MPI_INT, 0, m, MPI_COMM_WORLD)); 64 | } 65 | message += MSG_SIZE; 66 | } 67 | } else if (rank == 0) { 68 | int *message1 = buffer1 + (MSG_NUM - 1) * MSG_SIZE; 69 | int *message2 = buffer2 + (MSG_NUM - 1) * MSG_SIZE; 70 | int *message3 = buffer3 + (MSG_NUM - 1) * MSG_SIZE; 71 | 72 | for (int m = MSG_NUM - 1; m >= 0; --m) { 73 | #pragma oss task out(message1[0;MSG_SIZE], message2[0;MSG_SIZE], message3[0;MSG_SIZE]) label("recv") 74 | { 75 | MPI_Status statuses[3]; 76 | CHECK(MPI_Recv(message1, MSG_SIZE, MPI_INT, 1, m, MPI_COMM_WORLD, &statuses[0])); 77 | CHECK(MPI_Recv(message2, MSG_SIZE, MPI_INT, 2, m, MPI_COMM_WORLD, &statuses[1])); 78 | CHECK(MPI_Recv(message3, MSG_SIZE, MPI_INT, 3, m, MPI_COMM_WORLD, &statuses[2])); 79 | 80 | int count1, count2, count3; 81 | CHECK(MPI_Get_count(&statuses[0], MPI_INT, &count1)); 82 | CHECK(MPI_Get_count(&statuses[1], MPI_INT, &count2)); 83 | CHECK(MPI_Get_count(&statuses[2], MPI_INT, &count3)); 84 | ASSERT(count1 == MSG_SIZE); 85 | ASSERT(count2 == MSG_SIZE); 86 | ASSERT(count3 == MSG_SIZE); 87 | 88 | ASSERT(statuses[0].MPI_TAG == m); 89 | ASSERT(statuses[0].MPI_SOURCE == 1); 90 | ASSERT(statuses[1].MPI_TAG == m); 91 | ASSERT(statuses[1].MPI_SOURCE == 2); 92 | ASSERT(statuses[2].MPI_TAG == m); 93 | ASSERT(statuses[2].MPI_SOURCE == 3); 94 | } 95 | 96 | #pragma oss task in(message1[0;MSG_SIZE], message2[0;MSG_SIZE], message3[0;MSG_SIZE]) label("check") 97 | { 98 | for (int d = 0; d < MSG_SIZE; ++d) { 99 | ASSERT(message1[d] == d); 100 | } 101 | for (int d = 0; d < MSG_SIZE; ++d) { 102 | ASSERT(message2[d] == d); 103 | } 104 | for (int d = 0; d < MSG_SIZE; ++d) { 105 | ASSERT(message3[d] == d); 106 | } 107 | } 108 | 109 | message1 -= MSG_SIZE; 110 | message2 -= MSG_SIZE; 111 | message3 -= MSG_SIZE; 112 | } 113 | } 114 | } 115 | #pragma oss taskwait 116 | 117 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 118 | 119 | if (rank == 0) { 120 | double endTime = getTime(); 121 | fprintf(stdout, "Success, time: %f\n", endTime - startTime); 122 | } 123 | 124 | CHECK(MPI_Finalize()); 125 | 126 | std::free(buffer1); 127 | if (rank == 0) { 128 | std::free(buffer2); 129 | std::free(buffer3); 130 | } 131 | 132 | return 0; 133 | } 134 | -------------------------------------------------------------------------------- /tests/oss/MultiPrimitiveNonBlk.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2019-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | #include 13 | 14 | #ifdef LARGE_INPUT 15 | const int TIMESTEPS = 1000; 16 | const int MSG_NUM = 1000; 17 | const int MSG_SIZE = 100; 18 | #else 19 | const int TIMESTEPS = 100; 20 | const int MSG_NUM = 500; 21 | const int MSG_SIZE = 100; 22 | #endif 23 | 24 | struct statuses_t { 25 | MPI_Status status[4]; 26 | }; 27 | 28 | statuses_t statuses[MSG_NUM]; 29 | 30 | int main(int argc, char **argv) 31 | { 32 | int provided; 33 | const int required = MPI_THREAD_MULTIPLE; 34 | CHECK(MPI_Init_thread(&argc, &argv, required, &provided)); 35 | ASSERT(provided == required); 36 | 37 | int rank, size; 38 | CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &rank)); 39 | CHECK(MPI_Comm_size(MPI_COMM_WORLD, &size)); 40 | ASSERT(size >= 4); 41 | 42 | int * const buffer1 = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 43 | ASSERT(buffer1 != nullptr); 44 | 45 | int * buffer2 = nullptr; 46 | int * buffer3 = nullptr; 47 | if (rank == 0) { 48 | buffer2 = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 49 | buffer3 = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 50 | ASSERT(buffer2 != nullptr); 51 | ASSERT(buffer3 != nullptr); 52 | } 53 | 54 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 55 | double startTime = getTime(); 56 | 57 | for (int t = 0; t < TIMESTEPS; ++t) { 58 | if (rank > 0 && rank < 4) { 59 | int *message = buffer1; 60 | 61 | for (int m = 0; m < MSG_NUM; ++m) { 62 | #pragma oss task out(message[0;MSG_SIZE]) label("init") 63 | for (int d = 0; d < MSG_SIZE; ++d) { 64 | message[d] = d; 65 | } 66 | 67 | #pragma oss task in(message[0;MSG_SIZE]) label("send") 68 | { 69 | CHECK(TAMPI_Isend(message, MSG_SIZE, MPI_INT, 0, m, MPI_COMM_WORLD)); 70 | } 71 | message += MSG_SIZE; 72 | } 73 | } else if (rank == 0) { 74 | int *message1 = buffer1 + (MSG_NUM - 1) * MSG_SIZE; 75 | int *message2 = buffer2 + (MSG_NUM - 1) * MSG_SIZE; 76 | int *message3 = buffer3 + (MSG_NUM - 1) * MSG_SIZE; 77 | 78 | for (int m = MSG_NUM - 1; m >= 0; --m) { 79 | #pragma oss task label("recv") out(message1[0;MSG_SIZE], message2[0;MSG_SIZE], message3[0;MSG_SIZE]) out(statuses[m]) 80 | { 81 | CHECK(TAMPI_Irecv(message1, MSG_SIZE, MPI_INT, 1, m, MPI_COMM_WORLD, &statuses[m].status[0])); 82 | CHECK(TAMPI_Irecv(message2, MSG_SIZE, MPI_INT, 2, m, MPI_COMM_WORLD, &statuses[m].status[1])); 83 | CHECK(TAMPI_Irecv(message3, MSG_SIZE, MPI_INT, 3, m, MPI_COMM_WORLD, &statuses[m].status[2])); 84 | } 85 | 86 | #pragma oss task label("check") in(message1[0;MSG_SIZE], message2[0;MSG_SIZE], message3[0;MSG_SIZE]) in(statuses[m]) 87 | { 88 | const MPI_Status &status1 = statuses[m].status[0]; 89 | const MPI_Status &status2 = statuses[m].status[1]; 90 | const MPI_Status &status3 = statuses[m].status[2]; 91 | 92 | int count1, count2, count3; 93 | CHECK(MPI_Get_count(&status1, MPI_INT, &count1)); 94 | CHECK(MPI_Get_count(&status2, MPI_INT, &count2)); 95 | CHECK(MPI_Get_count(&status3, MPI_INT, &count3)); 96 | ASSERT(count1 == MSG_SIZE); 97 | ASSERT(count2 == MSG_SIZE); 98 | ASSERT(count3 == MSG_SIZE); 99 | 100 | ASSERT(status1.MPI_TAG == m); 101 | ASSERT(status1.MPI_SOURCE == 1); 102 | ASSERT(status2.MPI_TAG == m); 103 | ASSERT(status2.MPI_SOURCE == 2); 104 | ASSERT(status3.MPI_TAG == m); 105 | ASSERT(status3.MPI_SOURCE == 3); 106 | 107 | for (int d = 0; d < MSG_SIZE; ++d) { 108 | ASSERT(message1[d] == d); 109 | } 110 | for (int d = 0; d < MSG_SIZE; ++d) { 111 | ASSERT(message2[d] == d); 112 | } 113 | for (int d = 0; d < MSG_SIZE; ++d) { 114 | ASSERT(message3[d] == d); 115 | } 116 | } 117 | 118 | message1 -= MSG_SIZE; 119 | message2 -= MSG_SIZE; 120 | message3 -= MSG_SIZE; 121 | } 122 | } 123 | } 124 | #pragma oss taskwait 125 | 126 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 127 | 128 | if (rank == 0) { 129 | double endTime = getTime(); 130 | fprintf(stdout, "Success, time: %f\n", endTime - startTime); 131 | } 132 | 133 | CHECK(MPI_Finalize()); 134 | 135 | std::free(buffer1); 136 | if (rank == 0) { 137 | std::free(buffer2); 138 | std::free(buffer3); 139 | } 140 | 141 | return 0; 142 | } 143 | -------------------------------------------------------------------------------- /tests/oss/PrimitiveBlk.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2019-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | #include 13 | 14 | #ifdef LARGE_INPUT 15 | const int TIMESTEPS = 1000; 16 | const int MSG_NUM = 1000; 17 | const int MSG_SIZE = 100; 18 | #else 19 | const int TIMESTEPS = 100; 20 | const int MSG_NUM = 500; 21 | const int MSG_SIZE = 100; 22 | #endif 23 | 24 | int main(int argc, char **argv) 25 | { 26 | int provided; 27 | const int required = MPI_TASK_MULTIPLE; 28 | CHECK(MPI_Init_thread(&argc, &argv, required, &provided)); 29 | ASSERT(provided == required); 30 | 31 | int rank, size; 32 | CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &rank)); 33 | CHECK(MPI_Comm_size(MPI_COMM_WORLD, &size)); 34 | ASSERT(size > 1); 35 | 36 | int * const buffer = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 37 | ASSERT(buffer != nullptr); 38 | 39 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 40 | double startTime = getTime(); 41 | 42 | for (int t = 0; t < TIMESTEPS; ++t) { 43 | if (rank == 0) { 44 | int *message = buffer; 45 | 46 | for (int m = 0; m < MSG_NUM; ++m) { 47 | #pragma oss task out(message[0;MSG_SIZE]) label("init") 48 | for (int d = 0; d < MSG_SIZE; ++d) { 49 | message[d] = d; 50 | } 51 | 52 | #pragma oss task in(message[0;MSG_SIZE]) label("send") 53 | { 54 | CHECK(MPI_Send(message, MSG_SIZE, MPI_INT, 1, m, MPI_COMM_WORLD)); 55 | } 56 | message += MSG_SIZE; 57 | } 58 | } else if (rank == 1) { 59 | int *message = buffer + (MSG_NUM - 1) * MSG_SIZE; 60 | 61 | for (int m = MSG_NUM - 1; m >= 0; --m) { 62 | #pragma oss task out(message[0;MSG_SIZE]) label("recv") 63 | { 64 | MPI_Status status; 65 | CHECK(MPI_Recv(message, MSG_SIZE, MPI_INT, 0, m, MPI_COMM_WORLD, &status)); 66 | ASSERT(status.MPI_TAG == m); 67 | ASSERT(status.MPI_SOURCE == 0); 68 | 69 | int count; 70 | CHECK(MPI_Get_count(&status, MPI_INT, &count)); 71 | ASSERT(count == MSG_SIZE); 72 | } 73 | 74 | #pragma oss task in(message[0;MSG_SIZE]) label("check") 75 | for (int d = 0; d < MSG_SIZE; ++d) { 76 | ASSERT(message[d] == d); 77 | } 78 | message -= MSG_SIZE; 79 | } 80 | } 81 | } 82 | #pragma oss taskwait 83 | 84 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 85 | 86 | if (rank == 0) { 87 | double endTime = getTime(); 88 | fprintf(stdout, "Success, time: %f\n", endTime - startTime); 89 | } 90 | 91 | CHECK(MPI_Finalize()); 92 | 93 | std::free(buffer); 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /tests/oss/PrimitiveNonBlk.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2019-2024 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | #include 13 | 14 | #ifdef LARGE_INPUT 15 | const int TIMESTEPS = 1000; 16 | const int MSG_NUM = 1000; 17 | const int MSG_SIZE = 100; 18 | #else 19 | const int TIMESTEPS = 500; 20 | const int MSG_NUM = 500; 21 | const int MSG_SIZE = 100; 22 | #endif 23 | 24 | MPI_Status statuses[MSG_NUM]; 25 | 26 | int main(int argc, char **argv) 27 | { 28 | int provided; 29 | const int required = MPI_THREAD_MULTIPLE; 30 | CHECK(MPI_Init_thread(&argc, &argv, required, &provided)); 31 | ASSERT(provided == required); 32 | 33 | int rank, size; 34 | CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &rank)); 35 | CHECK(MPI_Comm_size(MPI_COMM_WORLD, &size)); 36 | ASSERT(size > 1); 37 | 38 | int * const buffer = (int *) std::malloc(MSG_NUM * MSG_SIZE * sizeof(int)); 39 | ASSERT(buffer != nullptr); 40 | 41 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 42 | double startTime = getTime(); 43 | 44 | for (int t = 0; t < TIMESTEPS; ++t) { 45 | if (rank == 0) { 46 | int *message = buffer; 47 | 48 | for (int m = 0; m < MSG_NUM; ++m) { 49 | #pragma oss task out(message[0;MSG_SIZE]) label("init") 50 | for (int d = 0; d < MSG_SIZE; ++d) { 51 | message[d] = d; 52 | } 53 | 54 | #pragma oss task in(message[0;MSG_SIZE]) label("isend") 55 | { 56 | CHECK(TAMPI_Isend(message, MSG_SIZE, MPI_INT, 1, m, MPI_COMM_WORLD)); 57 | } 58 | message += MSG_SIZE; 59 | } 60 | } else if (rank == 1) { 61 | int *message = buffer + (MSG_NUM - 1) * MSG_SIZE; 62 | 63 | for (int m = MSG_NUM - 1; m >= 0; --m) { 64 | #pragma oss task out(message[0;MSG_SIZE], statuses[m]) label("irecv") 65 | { 66 | CHECK(TAMPI_Irecv(message, MSG_SIZE, MPI_INT, 0, m, MPI_COMM_WORLD, &statuses[m])); 67 | } 68 | 69 | #pragma oss task in(message[0;MSG_SIZE], statuses[m]) label("check") 70 | for (int d = 0; d < MSG_SIZE; ++d) { 71 | ASSERT(message[d] == d); 72 | ASSERT(statuses[m].MPI_TAG == m); 73 | ASSERT(statuses[m].MPI_SOURCE == 0); 74 | 75 | int count; 76 | CHECK(MPI_Get_count(&statuses[m], MPI_INT, &count)); 77 | ASSERT(count == MSG_SIZE); 78 | } 79 | message -= MSG_SIZE; 80 | } 81 | } 82 | } 83 | #pragma oss taskwait 84 | 85 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 86 | 87 | if (rank == 0) { 88 | double endTime = getTime(); 89 | fprintf(stdout, "Success, time: %f\n", endTime - startTime); 90 | } 91 | 92 | CHECK(MPI_Finalize()); 93 | 94 | std::free(buffer); 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /tests/oss/ThreadDisableTaskAwareness.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "Utils.hpp" 13 | 14 | #define NBARRIERS 100 15 | 16 | int rank, nranks; 17 | 18 | void performBarriers(int num) 19 | { 20 | // The OmpSs-2 tasks should run in an exclusive CPU. The task cannot change 21 | // to a different CPU if there is no scheduling point. This tests checks that 22 | // the task does not run any scheduling point. Take into account that this 23 | // test can produce false positives, e.g., when having a single core per rank 24 | const int cpu = sched_getcpu(); 25 | 26 | for (size_t b = 0; b < num; ++b) { 27 | // Produce some artificial desynchronization among ranks 28 | if (rank == 0) 29 | usleep(1000); 30 | 31 | // These communications should not be task-awareness 32 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 33 | 34 | // Check that the task did not change to another CPU 35 | ASSERT(cpu == sched_getcpu()); 36 | } 37 | } 38 | 39 | int main(int argc, char **argv) 40 | { 41 | int provided, value; 42 | 43 | // Check the thread task-awareness is enabled by default 44 | CHECK(TAMPI_Property_get(TAMPI_PROPERTY_THREAD_TASKAWARE, &value)); 45 | ASSERT(value == 1); 46 | 47 | // Initialize MPI and TAMPI 48 | CHECK(MPI_Init_thread(&argc, &argv, MPI_TASK_MULTIPLE, &provided)); 49 | ASSERT(provided == MPI_TASK_MULTIPLE); 50 | 51 | CHECK(MPI_Comm_rank(MPI_COMM_WORLD, &rank)); 52 | CHECK(MPI_Comm_size(MPI_COMM_WORLD, &nranks)); 53 | 54 | if (nranks < 2) { 55 | MPI_Abort(MPI_COMM_WORLD, 1); 56 | } 57 | 58 | // Disable the task-awareness for this thread 59 | CHECK(TAMPI_Property_set(TAMPI_PROPERTY_THREAD_TASKAWARE, 0)); 60 | 61 | // Perform several barriers without task-awareness 62 | performBarriers(NBARRIERS); 63 | 64 | // Restore the task-awareness for this thread 65 | CHECK(TAMPI_Property_set(TAMPI_PROPERTY_THREAD_TASKAWARE, 1)); 66 | 67 | // Check the thread task-awareness is still enabled 68 | CHECK(TAMPI_Property_get(TAMPI_PROPERTY_THREAD_TASKAWARE, &value)); 69 | ASSERT(value == 1); 70 | 71 | // Finalize MPI and TAMPI 72 | CHECK(MPI_Finalize()); 73 | 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /tests/oss/ThreadTaskAwareness.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Task-Aware MPI and is licensed under the terms contained in the COPYING and COPYING.LESSER files. 3 | 4 | Copyright (C) 2023 Barcelona Supercomputing Center (BSC) 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "Utils.hpp" 11 | 12 | void taskbody() 13 | { 14 | int value; 15 | 16 | // Check the thread task-awareness is enabled by default 17 | CHECK(TAMPI_Property_get(TAMPI_PROPERTY_THREAD_TASKAWARE, &value)); 18 | ASSERT(value == 1); 19 | 20 | // Disable the current thread task-awareness 21 | CHECK(TAMPI_Property_set(TAMPI_PROPERTY_THREAD_TASKAWARE, 0)); 22 | 23 | // Check the thread task-awareness is disabled now 24 | CHECK(TAMPI_Property_get(TAMPI_PROPERTY_THREAD_TASKAWARE, &value)); 25 | ASSERT(value == 0); 26 | 27 | // Disable the current thread task-awareness 28 | CHECK(TAMPI_Property_set(TAMPI_PROPERTY_THREAD_TASKAWARE, 1)); 29 | 30 | // Check the thread task-awareness is enabled again 31 | CHECK(TAMPI_Property_get(TAMPI_PROPERTY_THREAD_TASKAWARE, &value)); 32 | ASSERT(value == 1); 33 | } 34 | 35 | int main(int argc, char **argv) 36 | { 37 | int provided, value; 38 | 39 | // Check the thread task-awareness is enabled by default 40 | CHECK(TAMPI_Property_get(TAMPI_PROPERTY_THREAD_TASKAWARE, &value)); 41 | ASSERT(value == 1); 42 | 43 | // Initialize MPI and TAMPI 44 | CHECK(MPI_Init_thread(&argc, &argv, MPI_TASK_MULTIPLE, &provided)); 45 | ASSERT(provided == MPI_TASK_MULTIPLE); 46 | 47 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 48 | 49 | #pragma oss task 50 | taskbody(); 51 | 52 | #pragma oss taskwait 53 | 54 | CHECK(MPI_Barrier(MPI_COMM_WORLD)); 55 | 56 | // Check the thread task-awareness is still enabled 57 | CHECK(TAMPI_Property_get(TAMPI_PROPERTY_THREAD_TASKAWARE, &value)); 58 | ASSERT(value == 1); 59 | 60 | // Finalize MPI and TAMPI 61 | CHECK(MPI_Finalize()); 62 | 63 | return 0; 64 | } 65 | --------------------------------------------------------------------------------