├── CMakeLists.txt ├── README ├── include ├── detail │ ├── comm.h │ ├── decls.h │ ├── endpoint.h │ ├── message.h │ ├── request.h │ ├── status.h │ └── type_traits.h └── mpp.h └── test ├── simple_sendrecv.cc └── types.cc /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(mmpi CXX) 2 | 3 | # States that CMake required version must be >= 2.6 4 | cmake_minimum_required(VERSION 2.6) 5 | 6 | # enable ctest support for testing 7 | enable_testing() 8 | 9 | # get code root directory (based on current file name path) 10 | get_filename_component( mmpi_dir ${CMAKE_CURRENT_LIST_FILE} PATH ) 11 | 12 | set ( mmpi_include_dir ${mmpi_dir}/include ) 13 | 14 | # enable tests for this project 15 | find_package(GTest REQUIRED) 16 | include_directories(${GTEST_INCLUDE_DIRS}) 17 | 18 | # enable MPI 19 | find_package(MPI REQUIRED) 20 | set(CMAKE_REQUIRED_DEFINITIONS ${MPI_COMPILE_FLAGS}) 21 | set(CMAKE_REQUIRED_INCLUDES ${MPI_INCLUDE_PATH}) 22 | set(CMAKE_REQUIRED_LIBRARIES ${MPI_LIBRARIES}) 23 | 24 | # enable C++0x support within gcc (if supported) 25 | if (CMAKE_COMPILER_IS_GNUCXX) 26 | 27 | # add general flags 28 | add_definitions( -fshow-column ) 29 | add_definitions( -Wall ) 30 | 31 | # add flags for debug mode 32 | set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0") 33 | # set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O3") 34 | 35 | # ENABLE PROFILING 36 | # add_definitions( -pg ) 37 | # SET(CMAKE_EXE_LINKER_FLAGS -pg) 38 | 39 | # check for -std=c++0x 40 | include(CheckCXXCompilerFlag) 41 | check_cxx_compiler_flag( -std=c++11 CXX11_Support ) 42 | if(CXX11_Support) 43 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 44 | else() 45 | message( "WARNING: --std=c++11 not supported by your compiler!" ) 46 | endif() 47 | endif() 48 | 49 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MPI_COMPILE_FLAGS}") 50 | 51 | # avoid multiple import 52 | if (NOT MEMORY_CHECK_SETUP) 53 | option(CONDUCT_MEMORY_CHECKS "Checks all test cases for memory leaks using valgrind if enabled." OFF) 54 | 55 | # add -all-valgrind target 56 | add_custom_target(valgrind) 57 | 58 | # define macro for adding tests 59 | macro ( add_unit_test case_name ) 60 | 61 | # take value from environment variable 62 | set(USE_VALGRIND ${CONDUCT_MEMORY_CHECKS}) 63 | 64 | # check whether there was a 2nd argument 65 | if(${ARGC} GREATER 1) 66 | # use last argument as a valgrind flag 67 | set(USE_VALGRIND ${ARG2}) 68 | endif(${ARGC} GREATER 1) 69 | 70 | # add test case 71 | if(USE_VALGRIND) 72 | # no valgrind support in MSVC 73 | if(NOT MSVC) 74 | # add valgrind as a test 75 | add_test(NAME valgrind_${case_name} 76 | COMMAND valgrind 77 | --leak-check=full 78 | --show-reachable=no 79 | --track-fds=yes 80 | --error-exitcode=1 81 | #--log-file=${CMAKE_CURRENT_BINARY_DIR}/valgrind.log.${case_name} 82 | ${CMAKE_CURRENT_BINARY_DIR}/ut_${case_name} 83 | WORKING_DIRECTORY 84 | ${CMAKE_CURRENT_BINARY_DIR} 85 | ) 86 | endif(NOT MSVC) 87 | else(USE_VALGRIND) 88 | # add normal test 89 | add_test(ut_${case_name} ut_${case_name}) 90 | 91 | # + valgrind as a custom target (only of not explicitly prohibited) 92 | if ((NOT MSVC) AND ((NOT (${ARGC} GREATER 1)) OR (${ARG2}))) 93 | add_custom_target(valgrind_${case_name} 94 | COMMAND valgrind 95 | --leak-check=full 96 | --show-reachable=no 97 | --track-fds=yes 98 | --error-exitcode=1 99 | #--log-file=${CMAKE_CURRENT_BINARY_DIR}/valgrind.log.${case_name} 100 | ${CMAKE_CURRENT_BINARY_DIR}/ut_${case_name} 101 | WORKING_DIRECTORY 102 | ${CMAKE_CURRENT_BINARY_DIR} 103 | ) 104 | add_dependencies(valgrind valgrind_${case_name}) 105 | endif ((NOT MSVC) AND ((NOT (${ARGC} GREATER 1)) OR (${ARG2}))) 106 | endif(USE_VALGRIND) 107 | endmacro(add_unit_test) 108 | endif (NOT MEMORY_CHECK_SETUP) 109 | 110 | # mark as defined 111 | set(MEMORY_CHECK_SETUP OFF CACHE INTERNAL "Flag to avoid multiple setup" PARENT_SCOPE) 112 | 113 | file(GLOB test_cases test/*.cc) 114 | foreach ( case_file ${test_cases}) 115 | get_filename_component( case_name ${case_file} NAME_WE ) 116 | 117 | add_executable(ut_${case_name} ${case_file}) 118 | include_directories(ut_${case_name} ${mmpi_include_dir}) 119 | include_directories(ut_${case_name} ${MPI_INCLUDE_PATH}) 120 | target_link_libraries(ut_${case_name} ${GTEST_BOTH_LIBRARIES}) 121 | target_link_libraries(ut_${case_name} ${MPI_LIBRARIES}) 122 | 123 | add_unit_test(${case_name}) 124 | 125 | endforeach(case_file) 126 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | MPP: An MPI CPP Interface 3 | 4 | 5 | What's MPP 6 | ========== 7 | 8 | MPP is an advanced C++ interface for MPI. It is a lightweight interface 9 | (header-only) which focuses on reducing the interface overhead. It supports 10 | integration of user datatypes. 11 | 12 | MPP was developed as a proof-of-concept to show that an high level MPI interface 13 | can be designed without renouncing to performance (which is key in High 14 | Performance Computing). Experiments have shown that MPP has much lower overhead 15 | than Boost.MPI (see paper below). 16 | 17 | MPP supports few MPI routines for now (point-to-point), but I am slowly 18 | extending its functionalities. If you want to help, either with some coding or 19 | ideas, you are welcome. 20 | 21 | 22 | Publications 23 | ============ 24 | 25 | @article{10.1109/PDP.2012.42, 26 | author = {Simone Pellegrini and Radu Prodan and Thomas Fahringer}, 27 | title = {A Lightweight C++ Interface to MPI}, 28 | journal = {Parallel, Distributed, and Network-Based Processing, 29 | Euromicro Conference on}, 30 | volume = {0}, 31 | issn = {1066-6192}, 32 | year = {2012}, 33 | pages = {3-10}, 34 | doi = {http://doi.ieeecomputersociety.org/10.1109/PDP.2012.42}, 35 | publisher = {IEEE Computer Society}, 36 | address = {Los Alamitos, CA, USA}, 37 | } 38 | 39 | 40 | License 41 | ======= 42 | MPP: Advanced C++ MPI Bindings 43 | 44 | Copyright (C) 2011-2012 Simone Pellegrini 45 | 46 | This library is free software; you can redistribute it and/or modify it under 47 | the terms of the GNU Lesser General Public License as published by the Free 48 | Software Foundation; either version 2.1 of the License, or (at your option) any 49 | later version. 50 | 51 | This library is distributed in the hope that it will be useful, but WITHOUT ANY 52 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 53 | PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 54 | 55 | You should have received a copy of the GNU Lesser General Public License along 56 | with this library; if not, write to the Free Software Foundation, Inc., 51 57 | Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 58 | 59 | 60 | Acknoledgments 61 | ============== 62 | 63 | Special thanks to Roland Schulz (https://github.com/rolandschulz) for his 64 | contributions. 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /include/detail/comm.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * MPP: An MPI CPP Interface 4 | * 5 | * Copyright (C) 2011-2012 Simone Pellegrini 6 | * 7 | * This library is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation; either version 2.1 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 15 | * for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this library; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | ******************************************************************************/ 22 | 23 | #pragma once 24 | 25 | #include "detail/decls.h" 26 | 27 | namespace mpi { 28 | 29 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 30 | // comm: is the abstraction of the MPI_Comm class 31 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 | class comm { 33 | 34 | MPI_Comm m_comm; 35 | bool m_initialized; 36 | int m_comm_size; 37 | int m_rank; 38 | 39 | comm(MPI_Comm comm): 40 | m_comm(comm), 41 | m_initialized(false), 42 | m_comm_size(-1), 43 | m_rank(-1) { } 44 | 45 | // Check whether MPI_Init has been called 46 | inline void check_init() { 47 | 48 | if (m_initialized) { return; } 49 | 50 | int flag; 51 | MPI_Initialized(&flag); 52 | assert(flag != 0 && 53 | "FATAL: MPI environment not initialized (MPI_Init not called)"); 54 | 55 | m_initialized = true; 56 | MPI_Comm_size(m_comm, &m_comm_size); 57 | MPI_Comm_rank(m_comm, &m_rank); 58 | } 59 | 60 | public: 61 | // MPI_COMM_WORLD 62 | static comm world; 63 | 64 | inline int rank() { 65 | check_init(); 66 | return m_rank; 67 | } 68 | 69 | inline int rank() const { 70 | assert(m_initialized && "MPI communicator not initialized"); 71 | return m_rank; 72 | } 73 | 74 | inline int size() { 75 | check_init(); 76 | return m_comm_size; 77 | } 78 | 79 | inline int size() const { 80 | assert(m_initialized && "MPI communicator not initialized"); 81 | return m_comm_size; 82 | } 83 | 84 | const MPI_Comm& mpi_comm() const { 85 | return m_comm; 86 | } 87 | 88 | inline endpoint operator()( const int& rank_id ) const; 89 | 90 | }; 91 | 92 | comm comm::world = comm(MPI_COMM_WORLD); 93 | 94 | } // end mpi namespace 95 | 96 | #include "detail/endpoint.h" 97 | 98 | namespace mpi { 99 | 100 | inline endpoint comm::operator()(const int& rank_id) const { 101 | return endpoint(rank_id, *this); 102 | } 103 | 104 | } // end mpi namespace 105 | -------------------------------------------------------------------------------- /include/detail/decls.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * MPP: An MPI CPP Interface 4 | * 5 | * Copyright (C) 2011-2012 Simone Pellegrini 6 | * 7 | * This library is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation; either version 2.1 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 15 | * for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this library; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | ******************************************************************************/ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include 28 | 29 | /** 30 | * Contains the forward declaration of the base classes utilized by MPP 31 | */ 32 | 33 | namespace mpi { 34 | 35 | template 36 | class msg_impl; 37 | 38 | class status; 39 | 40 | template 41 | class request; 42 | 43 | class endpoint; 44 | 45 | // Expection which is thrown every time a communication fails 46 | struct comm_error : public std::logic_error { 47 | 48 | comm_error(const std::string& msg) : std::logic_error(msg) { } 49 | 50 | }; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /include/detail/endpoint.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * MPP: An MPI CPP Interface 4 | * 5 | * Copyright (C) 2011-2012 Simone Pellegrini 6 | * 7 | * This library is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation; either version 2.1 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 15 | * for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this library; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | ******************************************************************************/ 22 | 23 | #pragma once 24 | 25 | #include "detail/decls.h" 26 | 27 | #define OVERLOAD_SEND(name, impl) \ 28 | template \ 29 | inline endpoint& name(msg_impl&& m) { \ 30 | return name##_impl(impl, std::move(m)); \ 31 | } \ 32 | template \ 33 | inline endpoint& name(const msg_impl& m) { \ 34 | return name(std::move(m)); \ 35 | } \ 36 | template \ 37 | inline endpoint& name(const RawType& m) { \ 38 | return name( std::move( msg_impl(m) ) ); \ 39 | } 40 | 41 | namespace mpi { 42 | 43 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 44 | // endpoint: represent the src or dest of an MPI channel. Provides streaming 45 | // operations to send/recv messages (msg) both in a synchronous or asynch 46 | // ronous way. 47 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 48 | class endpoint { 49 | 50 | const int m_rank; // The rank of this endpoint 51 | const comm& m_comm; // The MPI communicator this endpoing 52 | // belongs to 53 | 54 | typedef int (*send_ptr)(void*,int,MPI_Datatype,int,int,MPI_Comm); 55 | 56 | // Make this class non-copyable 57 | endpoint(const endpoint& other) = delete; 58 | endpoint& operator=(const endpoint& other) = delete; 59 | 60 | public: 61 | endpoint(const int& rank, const comm& com): 62 | m_rank(rank), m_comm(com) { } 63 | 64 | endpoint(endpoint&& other) : 65 | m_rank(other.m_rank), 66 | m_comm(std::move(other.m_comm)) { } 67 | 68 | // Send a generic message to this endpoint (synchronously) 69 | template 70 | inline endpoint& send_impl(const send_ptr& func, msg_impl&& m); 71 | 72 | // MPI_Send wrappers 73 | OVERLOAD_SEND(send, MPI_Send) 74 | 75 | // MPI_Ssend wrappers 76 | OVERLOAD_SEND(ssend, MPI_Ssend) 77 | 78 | // MPI_Rsend wrappers 79 | OVERLOAD_SEND(rsend, MPI_Rsend) 80 | 81 | // Send a generic message to this endpoint (asynchronously) 82 | template 83 | inline request isend(msg_impl&& m); 84 | 85 | // Send a generic message to this endpoint (asynchronously) 86 | template 87 | inline request isend(const msg_impl& m) { 88 | return isend(std::move(m)); 89 | } 90 | 91 | // Send a generic message to this endpoint (asynchronously) 92 | template 93 | inline request isend(const RawMsg& m) { 94 | return isend( std::move( msg_impl(m) ) ); 95 | } 96 | 97 | 98 | template 99 | inline endpoint& operator<<(msg_impl&& m) { 100 | return send(std::move(m)); 101 | } 102 | 103 | template 104 | inline endpoint& operator<<(const msg_impl& m) { 105 | return send(std::move(m)); 106 | } 107 | 108 | template 109 | inline endpoint& operator<<(const RawType& m) { 110 | return send( std::move( msg_impl(m) ) ); 111 | } 112 | 113 | 114 | 115 | 116 | // Receive from this endpoint (synchronously) 117 | template 118 | inline status operator>>(RawType& m); 119 | 120 | template 121 | inline status operator>>(msg_impl&& m); 122 | 123 | // Receive from this endpoing (asynchronously) 124 | template 125 | inline request operator>(msg_impl&& m); 126 | 127 | // Receive from this endpoing (asynchronously 128 | template 129 | inline request operator>(RawType& m) { 130 | return operator>( std::move(msg_impl(m)) ); 131 | } 132 | 133 | // Returns the rank of this endpoit 134 | inline const int& rank() const { return m_rank; } 135 | }; 136 | 137 | } // end mpi namespace 138 | 139 | #include "detail/comm.h" 140 | 141 | namespace mpi { 142 | 143 | // Send a generic message to this endpoint (synchronously) 144 | template 145 | inline endpoint& endpoint::send_impl(const send_ptr& func, msg_impl&& m) { 146 | MPI_Datatype&& dt = m.type(); 147 | if ( func(const_cast(static_cast(m.addr())), 148 | static_cast(m.size()), dt, 149 | m_rank, 150 | m.tag(), 151 | m_comm.mpi_comm() 152 | ) == MPI_SUCCESS ) { 153 | return *this; 154 | } 155 | std::ostringstream ss; 156 | ss << "ERROR in MPI rank '" << comm::world.rank() 157 | << "': Failed to send message to destination rank '" 158 | << m_rank << "'"; 159 | throw comm_error( ss.str() ); 160 | } 161 | 162 | // Send a generic message to this endpoint (asynchronously) 163 | template 164 | inline request endpoint::isend(msg_impl&& m) { 165 | MPI_Datatype&& dt = m.type(); 166 | MPI_Request req; 167 | if ( MPI_Isend( const_cast(static_cast(m.addr())), 168 | static_cast(m.size()), dt, 169 | m_rank, 170 | m.tag(), 171 | m_comm.mpi_comm(), 172 | &req 173 | ) != MPI_SUCCESS ) 174 | { 175 | std::ostringstream ss; 176 | ss << "ERROR in MPI rank '" << comm::world.rank() 177 | << "': Failed to send message to destination rank '" 178 | << m_rank << "'"; 179 | 180 | throw comm_error( ss.str() ); 181 | } 182 | return request(m_comm, req, std::move(m)); 183 | } 184 | 185 | // Receive from this endpoing (asynchronously) 186 | template 187 | inline request endpoint::operator>(msg_impl&& m) { 188 | MPI_Request req; 189 | if( MPI_Irecv( static_cast(m.addr()), 190 | static_cast(m.size()), 191 | m.type(), 192 | m_rank, 193 | m.tag(), 194 | m_comm.mpi_comm(), 195 | &req 196 | ) != MPI_SUCCESS ) { 197 | std::ostringstream ss; 198 | ss << "ERROR in MPI rank '" << comm::world.rank() 199 | << "': Failed to receive message from destination rank '" 200 | << m_rank << "'"; 201 | throw comm_error( ss.str() ); 202 | } 203 | return request(m_comm, req, std::move(m)); 204 | } 205 | 206 | } // end mpi namespace 207 | 208 | 209 | #include "detail/status.h" 210 | 211 | namespace mpi { 212 | 213 | template 214 | inline status endpoint::operator>>(RawType& m) { 215 | return operator>>( msg_impl( m ) ); 216 | } 217 | 218 | template 219 | inline status endpoint::operator>>(msg_impl&& m) { 220 | status::mpi_status_ptr stat( new MPI_Status ); 221 | MPI_Datatype dt = m.type(); 222 | if(MPI_Recv( const_cast(static_cast(m.addr())), 223 | static_cast(m.size()), dt, 224 | m_rank, 225 | m.tag(), 226 | m_comm.mpi_comm(), 227 | stat.get() 228 | ) == MPI_SUCCESS ) { 229 | return status(m_comm, std::move(stat), dt); 230 | } 231 | std::ostringstream ss; 232 | ss << "ERROR in MPI rank '" << comm::world.rank() 233 | << "': Failed to receive message from destination rank '" 234 | << m_rank << "'"; 235 | throw comm_error( ss.str() ); 236 | } 237 | 238 | } // end mpi namespace 239 | -------------------------------------------------------------------------------- /include/detail/message.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * MPP: An MPI CPP Interface 4 | * 5 | * Copyright (C) 2011-2012 Simone Pellegrini 6 | * 7 | * This library is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation; either version 2.1 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 15 | * for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this library; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | ******************************************************************************/ 22 | 23 | #pragma once 24 | 25 | #include "detail/decls.h" 26 | 27 | #include "type_traits.h" 28 | 29 | namespace mpi { 30 | 31 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 | // msg: represent a single message which can be provided to the <<, <, >>, > 33 | // operations 34 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 35 | template 36 | struct msg_impl { 37 | 38 | typedef MsgTy value_type; 39 | 40 | // Builds a msg wrapping v 41 | msg_impl(value_type& v, int tag = 0) : m_data(v), m_tag(tag) { } 42 | 43 | // Move copy constructor 44 | msg_impl(msg_impl&& other) : 45 | m_data(other.m_data), 46 | m_tag(other.m_tag) { } 47 | 48 | inline typename mpi_type_traits::element_addr_type addr() const { 49 | return mpi_type_traits::get_addr(m_data); 50 | } 51 | 52 | inline const value_type& get() const { return m_data; } 53 | 54 | // Returns the dimension of this message 55 | inline size_t size() const { 56 | return mpi_type_traits::get_size(m_data); 57 | } 58 | 59 | inline MPI_Datatype type() const { 60 | return mpi_type_traits::get_type(std::move(m_data)); 61 | } 62 | 63 | // getter/setter for m_tag 64 | inline const int& tag() const { return m_tag; } 65 | inline int& tag() { return m_tag; } 66 | 67 | private: 68 | 69 | // Make this class non-copyable 70 | msg_impl(const msg_impl& other) = delete; 71 | msg_impl operator=(const msg_impl& other) = delete; 72 | 73 | value_type& m_data; 74 | int m_tag; 75 | }; 76 | 77 | 78 | template 79 | inline msg_impl msg(T& raw, int tag=0) { return msg_impl(raw, tag); } 80 | 81 | } // end mpi namespace 82 | -------------------------------------------------------------------------------- /include/detail/request.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * MPP: An MPI CPP Interface 4 | * 5 | * Copyright (C) 2011-2012 Simone Pellegrini 6 | * 7 | * This library is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation; either version 2.1 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 15 | * for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this library; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | ******************************************************************************/ 22 | 23 | #pragma once 24 | 25 | #include "detail/decls.h" 26 | 27 | #include "detail/status.h" 28 | 29 | namespace mpi { 30 | 31 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 | // request is an implementation of the future concept used for asynchronous 33 | // receives/sends (TODO) 34 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 35 | template 36 | class request{ 37 | const comm& m_comm; 38 | MPI_Request m_req; 39 | msg_impl m_msg; 40 | std::unique_ptr m_status; 41 | int done; 42 | 43 | public: 44 | request(const comm& com, MPI_Request req, msg_impl&& msg): 45 | m_comm(com), m_req(req), m_msg(std::move(msg)), done(0) { } 46 | 47 | request(request&& other) : 48 | m_comm( std::move(other.m_comm) ), 49 | m_req( std::move(other.m_req) ), 50 | m_msg( std::move(other.m_msg) ), 51 | m_status( std::move(other.m_status) ), 52 | done(other.done) { } 53 | 54 | void cancel(); 55 | 56 | inline const T& get() { 57 | if ( !done ) { 58 | status::mpi_status_ptr stat(new MPI_Status); 59 | // wait to receive the message 60 | MPI_Wait(&m_req, stat.get()); 61 | done = 1; 62 | m_status.reset( new status(m_comm, std::move(stat), m_msg.type()) ); 63 | } 64 | return m_msg.get(); 65 | } 66 | 67 | inline status getStatus() { 68 | if( isDone() ) { return *m_status; } 69 | throw "not done"; 70 | } 71 | 72 | inline bool isDone() { 73 | if ( !done ) { 74 | status::mpi_status_ptr stat(new MPI_Status); 75 | MPI_Test(&m_req, &done, stat.get()); 76 | if ( done ) { 77 | m_status.reset( new status(m_comm, std::move(stat), m_msg.type()) ); 78 | } 79 | } 80 | return done; 81 | } 82 | }; 83 | 84 | } // end mpi namespace 85 | -------------------------------------------------------------------------------- /include/detail/status.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * MPP: An MPI CPP Interface 4 | * 5 | * Copyright (C) 2011-2012 Simone Pellegrini 6 | * 7 | * This library is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation; either version 2.1 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 15 | * for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this library; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | ******************************************************************************/ 22 | 23 | #pragma once 24 | 25 | /** 26 | * Contains the defition of the status wrapper which exists fof the sake of 27 | * encapsulating the MPI_Status object. 28 | */ 29 | 30 | #include "detail/decls.h" 31 | 32 | #include 33 | 34 | namespace mpi { 35 | 36 | struct status{ 37 | 38 | typedef std::unique_ptr mpi_status_ptr; 39 | 40 | status(status&& other) : 41 | m_comm(std::move(other.m_comm)), 42 | m_status(std::move(other.m_status)), 43 | m_datatype(other.m_datatype) { } 44 | 45 | inline endpoint source(); 46 | 47 | inline int count() const { 48 | int count; 49 | MPI_Get_count(m_status.get(), m_datatype, &count); 50 | return count; 51 | } 52 | 53 | inline int tag() const { 54 | return m_status->MPI_TAG; 55 | } 56 | 57 | inline int error() const { 58 | return m_status->MPI_ERROR; 59 | } 60 | 61 | /** 62 | * Friend classes declarations 63 | */ 64 | friend class endpoint; 65 | 66 | template 67 | friend class request; 68 | 69 | private: 70 | 71 | /** 72 | * Avoid the generation of status objects, these objects are generated by 73 | * the MPP library and it would make no sense if the user could 74 | * automatically generate one of those 75 | */ 76 | status(const comm& com, mpi_status_ptr&& s, const MPI_Datatype& dt): 77 | m_comm(com), 78 | m_status(std::move(s)), 79 | m_datatype(dt) { } 80 | 81 | status(const status& other) = delete; 82 | status& operator=(const status& other) = delete; 83 | 84 | const comm& m_comm; 85 | mpi_status_ptr m_status; 86 | const MPI_Datatype m_datatype; 87 | }; 88 | 89 | } // end mpi namespace 90 | 91 | #include "detail/endpoint.h" 92 | 93 | namespace mpi { 94 | 95 | inline endpoint status::source() { 96 | return endpoint(m_status->MPI_SOURCE, m_comm); 97 | } 98 | 99 | 100 | } // end mpi namespace 101 | 102 | -------------------------------------------------------------------------------- /include/detail/type_traits.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * MPP: An MPI CPP Interface 4 | * 5 | * Copyright (C) 2011-2012 Simone Pellegrini 6 | * 7 | * This library is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation; either version 2.1 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 15 | * for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this library; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | ******************************************************************************/ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace mpi { 33 | 34 | //***************************************************************************** 35 | // MPI Type Traits 36 | //***************************************************************************** 37 | template 38 | struct mpi_type_traits { 39 | 40 | typedef T element_type; 41 | typedef T* element_addr_type; 42 | 43 | static inline MPI_Datatype get_type(T&& raw); 44 | 45 | static inline size_t get_size(T& raw) { return 1; } 46 | 47 | static inline element_addr_type get_addr(T& raw) { return &raw; } 48 | 49 | }; 50 | 51 | /** 52 | * Specialization of the mpi_type_traits for primitive types 53 | */ 54 | #define PRIMITIVE(Type, MpiType) \ 55 | template<> \ 56 | inline MPI_Datatype mpi_type_traits::get_type(Type&&) { \ 57 | return MpiType; \ 58 | } 59 | 60 | PRIMITIVE(char, MPI::CHAR); 61 | PRIMITIVE(wchar_t, MPI::WCHAR); 62 | PRIMITIVE(short, MPI::SHORT); 63 | PRIMITIVE(int, MPI::INT); 64 | PRIMITIVE(long, MPI::LONG); 65 | PRIMITIVE(signed char, MPI::SIGNED_CHAR); 66 | PRIMITIVE(unsigned char, MPI::UNSIGNED_CHAR); 67 | PRIMITIVE(unsigned short, MPI::UNSIGNED_SHORT); 68 | PRIMITIVE(unsigned int, MPI::UNSIGNED); 69 | PRIMITIVE(unsigned long, MPI::UNSIGNED_LONG); 70 | PRIMITIVE(unsigned long long, MPI::UNSIGNED_LONG_LONG); 71 | 72 | PRIMITIVE(float, MPI::FLOAT); 73 | PRIMITIVE(double, MPI::DOUBLE); 74 | PRIMITIVE(long double, MPI::LONG_DOUBLE); 75 | 76 | PRIMITIVE(bool, MPI::BOOL); 77 | PRIMITIVE(std::complex, MPI::COMPLEX); 78 | PRIMITIVE(std::complex, MPI::DOUBLE_COMPLEX); 79 | PRIMITIVE(std::complex, MPI::LONG_DOUBLE_COMPLEX); 80 | 81 | #undef PRIMITIVE 82 | 83 | // ... add missing types here ... 84 | 85 | template 86 | struct mpi_type_traits { 87 | 88 | typedef const typename mpi_type_traits::element_type element_type; 89 | typedef const typename mpi_type_traits::element_addr_type element_addr_type; 90 | 91 | static inline size_t get_size(const T& elem) { 92 | return mpi_type_traits::get_size( const_cast(elem) ); 93 | } 94 | 95 | static inline MPI_Datatype get_type(const T& elem) { 96 | return mpi_type_traits::get_type( T() ); 97 | } 98 | 99 | static inline element_addr_type get_addr(const T& elem) { 100 | return mpi_type_traits::get_addr( const_cast(elem) ); 101 | } 102 | }; 103 | 104 | 105 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 106 | // std::vector traits 107 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 108 | template 109 | struct mpi_type_traits> { 110 | 111 | typedef T element_type; 112 | typedef T* element_addr_type; 113 | 114 | static inline size_t get_size(std::vector& vec) { return vec.size(); } 115 | 116 | static inline MPI_Datatype get_type(std::vector&& vec) { 117 | return mpi_type_traits::get_type( T() ); 118 | } 119 | 120 | static inline element_addr_type get_addr(std::vector& vec) { 121 | return mpi_type_traits::get_addr( vec.front() ); 122 | } 123 | 124 | }; 125 | 126 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 127 | // std::array traits 128 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 129 | template 130 | struct mpi_type_traits> { 131 | 132 | inline static size_t get_size(const std::array& vec) { return N; } 133 | 134 | inline static MPI_Datatype get_type(const std::array& vec) { 135 | return mpi_type_traits::get_type( T() ); 136 | } 137 | 138 | static inline const T* get_addr(const std::array& vec) { 139 | return mpi_type_traits::get_addr( vec.front() ); 140 | } 141 | }; 142 | 143 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 144 | // std::list traits 145 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 146 | template 147 | struct mpi_type_traits> { 148 | 149 | static inline size_t get_size(const std::list& vec) { return 1; } 150 | 151 | static MPI_Datatype get_type(const std::list& l) { 152 | // we have to get the create an MPI_Datatype containing the offsets 153 | // of the current object 154 | 155 | // we consider the offsets starting from the first element 156 | std::vector address( l.size() ); 157 | std::vector dimension( l.size() ); 158 | std::vector types( l.size() ); 159 | 160 | std::vector::iterator dim_it = dimension.begin(); 161 | std::vector::iterator address_it = address.begin(); 162 | std::vector::iterator type_it = types.begin(); 163 | 164 | MPI_Aint base_address; 165 | MPI_Address(const_cast(&l.front()), &base_address); 166 | 167 | *(type_it++) = mpi_type_traits::get_type( l.front() ); 168 | *(dim_it++) = static_cast(mpi_type_traits::get_size( l.front() )); 169 | *(address_it++) = 0; 170 | 171 | typename std::list::const_iterator begin = l.begin(); 172 | ++begin; 173 | std::for_each(begin, l.cend(), [&](const T& curr) { 174 | assert( address_it != address.end() && 175 | type_it != types.end() && 176 | dim_it != dimension.end() ); 177 | 178 | MPI_Address(const_cast(&curr), &*address_it); 179 | *(address_it++) -= base_address; 180 | *(type_it++) = mpi_type_traits::get_type( curr ); 181 | *(dim_it++) = static_cast(mpi_type_traits::get_size( curr )); 182 | 183 | } 184 | ); 185 | 186 | MPI_Datatype list_dt; 187 | MPI_Type_create_struct(static_cast(l.size()), &dimension.front(), &address.front(), &types.front(), &list_dt); 188 | MPI_Type_commit( &list_dt ); 189 | 190 | return list_dt; 191 | } 192 | 193 | static inline const T* get_addr(const std::list& list) { 194 | return mpi_type_traits::get_addr( list.front() ); 195 | } 196 | 197 | }; 198 | 199 | } // end mpi namespace 200 | 201 | -------------------------------------------------------------------------------- /include/mpp.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * MPP: An MPI CPP Interface 4 | * 5 | * Copyright (C) 2011-2012 Simone Pellegrini 6 | * 7 | * This library is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation; either version 2.1 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * This library is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 15 | * for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with this library; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | * 21 | ******************************************************************************/ 22 | 23 | #pragma once 24 | 25 | #include "detail/comm.h" 26 | #include "detail/endpoint.h" 27 | #include "detail/message.h" 28 | #include "detail/status.h" 29 | #include "detail/request.h" 30 | 31 | #include 32 | 33 | namespace mpi { 34 | 35 | const int any = MPI_ANY_SOURCE; 36 | 37 | /** 38 | * Exception type used whenever the required thread level does not match 39 | * the one provided by the underlying MPI library. 40 | */ 41 | struct ThreadLevelException : public std::exception { 42 | const int required, provided; 43 | 44 | ThreadLevelException(int required, int provided): 45 | required(required), provided(provided) { } 46 | 47 | const char* what() const noexcept { 48 | return "Requested thread level does not match the one provided by the library."; 49 | } 50 | }; 51 | 52 | enum thread_level { NO_THREAD, 53 | THREAD_SINGLE, 54 | THREAD_FUNNELED, 55 | THREAD_SERIALIZED, 56 | THREAD_MULTIPLE 57 | }; 58 | 59 | inline void init(int argc = 0, char* argv[] = NULL, const thread_level required = NO_THREAD) { 60 | if(required == NO_THREAD) { 61 | MPI_Init(&argc, &argv); 62 | return; 63 | } 64 | 65 | int provided; 66 | // try initialize with the provided thread level 67 | MPI_Init_thread(&argc, &argv, required, &provided); 68 | 69 | if (provided < required) 70 | throw ThreadLevelException(required, provided); 71 | } 72 | 73 | inline void finalize(){ MPI_Finalize(); } 74 | 75 | } // end mpi namespace 76 | 77 | -------------------------------------------------------------------------------- /test/simple_sendrecv.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace mpi; 9 | 10 | TEST(SendRecv, Scalar) { 11 | if(comm::world.rank() == 0) { 12 | comm::world(1) << 4.2; 13 | int val; 14 | auto s = comm::world(1) >> val; 15 | EXPECT_EQ( 4, val); 16 | EXPECT_EQ( 1, s.source().rank() ); 17 | EXPECT_EQ( 0, s.tag() ); 18 | } else if (comm::world.rank() == 1) { 19 | double val; 20 | auto s = comm::world(0) >> val; 21 | EXPECT_EQ(4.2, val); 22 | EXPECT_EQ( 0, s.source().rank() ); 23 | EXPECT_EQ(0, s.tag()); 24 | comm::world(0) << static_cast(floor(val)); 25 | } 26 | } 27 | 28 | TEST(SendRecv, ScalarAsynch) { 29 | if(comm::world.rank() == 0) { 30 | auto req = comm::world(1).isend(4.2); 31 | req.get(); 32 | int val; 33 | auto s = comm::world(1) >> val; 34 | EXPECT_EQ( 4, val); 35 | EXPECT_EQ( 1, s.source().rank() ); 36 | EXPECT_EQ( 0, s.tag() ); 37 | } else if (comm::world.rank() == 1) { 38 | double val; 39 | auto s = comm::world(0) >> val; 40 | EXPECT_EQ(4.2, val); 41 | EXPECT_EQ( 0, s.source().rank() ); 42 | EXPECT_EQ(0, s.tag()); 43 | comm::world(0) << static_cast(floor(val)); 44 | } 45 | } 46 | 47 | TEST(SendRecv, Array) { 48 | int datav[] = {2, 4, 6, 8}; 49 | std::vector data(datav, datav+sizeof(datav)/sizeof(int)); 50 | if(comm::world.rank() == 0) { 51 | comm::world(1) << data; 52 | } else if (comm::world.rank() == 1) { 53 | std::vector vec(4); 54 | comm::world(0) >> vec; 55 | EXPECT_EQ( static_cast(4), vec.size() ); 56 | // check whether received data is equal to original data 57 | EXPECT_TRUE( std::equal(vec.begin(), vec.end(), data.begin(), std::equal_to()) ); 58 | } 59 | } 60 | 61 | TEST(SendRecv, Future) { 62 | if ( comm::world.rank() == 0 ) { 63 | comm::world(1) << 100; 64 | } else if(comm::world.rank() == 1) { 65 | int k; 66 | request r = comm::world(0) > k; 67 | r.get(); 68 | EXPECT_EQ(100, k); 69 | } 70 | } 71 | 72 | TEST(SendRecv, Tags) { 73 | 74 | if ( comm::world.rank() == 0 ) { 75 | comm::world(1) << msg(100, 11); 76 | comm::world(1) << msg(101, 0); 77 | } else if(comm::world.rank() == 1) { 78 | int k; 79 | comm::world(0) >> msg(k,0); 80 | EXPECT_EQ(101, k); 81 | comm::world(0) >> msg(k,11); 82 | EXPECT_EQ(100, k); 83 | } 84 | } 85 | 86 | TEST(SendRecv, PingPong) { 87 | int p=0; 88 | if(comm::world.rank() == 0) { 89 | // start the ping 90 | comm::world(1) << p; 91 | } 92 | 93 | while ( p <= 10 ) { 94 | auto ep = (comm::world(mpi::any) >> p ).source(); 95 | ep << p+1; 96 | EXPECT_TRUE(comm::world.rank()==0?p%2!=0:p%2==0); 97 | } 98 | } 99 | // 100 | // TEST(SendRecv, Lists) { 101 | // 102 | // if ( comm::world.rank() == 0 ) { 103 | // int data[] = {1,2,3,4,5}; 104 | // std::list l(data,data+sizeof(data)/sizeof(int)); 105 | // comm::world(1) << l; 106 | // } else if(comm::world.rank() == 1) { 107 | // std::vector l(5); 108 | // comm::world(0) >> l; 109 | // EXPECT_EQ(static_cast(5), l.size()); 110 | // EXPECT_EQ(1, l[0]); 111 | // EXPECT_EQ(2, l[1]); 112 | // EXPECT_EQ(3, l[2]); 113 | // EXPECT_EQ(4, l[3]); 114 | // EXPECT_EQ(5, l[4]); 115 | // } 116 | // } 117 | 118 | 119 | TEST(Performance, MpiScalar) { 120 | 121 | int rank; 122 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); 123 | 124 | auto bench = [&rank] () { 125 | // warmup 126 | if (rank == 0) { 127 | for(size_t i=0; i<100000; ++i) 128 | MPI_Send(&i,1,MPI_UNSIGNED_LONG,1,0,MPI_COMM_WORLD); 129 | } else { 130 | size_t val; 131 | for(size_t i=0; i<100000; ++i) { 132 | MPI_Status s; 133 | MPI_Recv(&val,1,MPI_UNSIGNED_LONG,0,0,MPI_COMM_WORLD,&s); 134 | EXPECT_EQ(i, val); 135 | } 136 | } 137 | }; 138 | 139 | MPI_Barrier(MPI_COMM_WORLD); 140 | bench(); 141 | MPI_Barrier(MPI_COMM_WORLD); 142 | 143 | auto start = std::chrono::system_clock::now(); 144 | bench(); 145 | auto end = std::chrono::system_clock::now(); 146 | 147 | size_t elapsed_time = 148 | std::chrono::duration_cast(end-start).count(); 149 | 150 | if (rank==0) 151 | std::cout << "MpiScalar: " << elapsed_time << " microsec" << std::endl; 152 | 153 | } 154 | 155 | TEST(Performance, MppScalar) { 156 | 157 | using mpi::comm; 158 | auto& world = comm::world; 159 | 160 | auto bench = [&]() { 161 | // warmup 162 | if (world.rank() == 0) { 163 | for(size_t i=0; i<100000; ++i) 164 | world(1) << i; 165 | } else { 166 | size_t val; 167 | for(size_t i=0; i<100000; ++i) { 168 | world(0) >> val; 169 | EXPECT_EQ(i, val); 170 | } 171 | } 172 | }; 173 | 174 | MPI_Barrier(MPI_COMM_WORLD); 175 | // Warmup 176 | bench(); 177 | MPI_Barrier(MPI_COMM_WORLD); 178 | 179 | auto start = std::chrono::system_clock::now(); 180 | bench(); 181 | auto end = std::chrono::system_clock::now(); 182 | 183 | size_t elapsed_time = 184 | std::chrono::duration_cast(end-start).count(); 185 | if (world.rank() == 0) 186 | std::cout << "MppScalar: " << elapsed_time << " microsec" << std::endl; 187 | } 188 | 189 | int main(int argc, char** argv) { 190 | MPI_Init(&argc, &argv); 191 | // Disables elapsed time by default. 192 | ::testing::GTEST_FLAG(print_time) = true; 193 | 194 | // This allows the user to override the flag on the command line. 195 | ::testing::InitGoogleTest(&argc, argv); 196 | 197 | size_t errcode = RUN_ALL_TESTS(); 198 | MPI_Finalize(); 199 | return static_cast(errcode); 200 | } 201 | -------------------------------------------------------------------------------- /test/types.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | using namespace mpi; 7 | 8 | TEST(Type, Char) { 9 | if(comm::world.rank() == 0) { 10 | comm::world(1) << 'a'; 11 | } else if (comm::world.rank() == 1) { 12 | char val; 13 | comm::world(0) >> val; 14 | EXPECT_EQ('a', val); 15 | } 16 | } 17 | 18 | TEST(Type, Unsigned) { 19 | if(comm::world.rank() == 0) { 20 | comm::world(1) << 10u; 21 | } else if (comm::world.rank() == 1) { 22 | unsigned val; 23 | comm::world(0) >> val; 24 | EXPECT_EQ(10u, val); 25 | } 26 | } 27 | 28 | TEST(Type, UnsignedLong) { 29 | if(comm::world.rank() == 0) { 30 | comm::world(1) << 1000000ul; 31 | } else if (comm::world.rank() == 1) { 32 | unsigned long val; 33 | comm::world(0) >> val; 34 | EXPECT_EQ(1000000ul, val); 35 | } 36 | } 37 | 38 | TEST(Type, LongDouble) { 39 | if(comm::world.rank() == 0) { 40 | long double ld = 0.000000010; 41 | comm::world(1) << ld; 42 | } else if (comm::world.rank() == 1) { 43 | long double val; 44 | comm::world(0) >> val; 45 | EXPECT_EQ(0.000000010, val); 46 | } 47 | } 48 | 49 | TEST(Type, Complex) { 50 | if(comm::world.rank() == 0) { 51 | comm::world(1) << std::complex(10.3, 2.4); 52 | } else if (comm::world.rank() == 1) { 53 | std::complex val; 54 | comm::world(0) >> val; 55 | EXPECT_EQ(10.3f, real(val)); 56 | EXPECT_EQ(2.4f, imag(val)); 57 | } 58 | } 59 | 60 | int main(int argc, char** argv) { 61 | MPI_Init(&argc, &argv); 62 | // Disables elapsed time by default. 63 | ::testing::GTEST_FLAG(print_time) = true; 64 | 65 | // This allows the user to override the flag on the command line. 66 | ::testing::InitGoogleTest(&argc, argv); 67 | 68 | size_t errcode = RUN_ALL_TESTS(); 69 | MPI_Finalize(); 70 | return static_cast(errcode); 71 | } 72 | 73 | --------------------------------------------------------------------------------