if(GMX_THREAD_MPI)
set(PKG_CFLAGS "${PKG_CFLAGS} -DGMX_THREAD_MPI")
include(ThreadMPI)
+ tmpi_make_cxx_lib()
set(THREAD_MPI_LIB thread_mpi)
set(GMX_MPI 1)
string(TOUPPER ${GMX_FFT_LIBRARY} ${GMX_FFT_LIBRARY})
endif(NOT DEFINED TMPI_ATOMICS)
ENDMACRO(TEST_TMPI_ATOMICS VARIABLE)
+MACRO(TMPI_MAKE_CXX_LIB)
+ set(TMPI_CXX_LIB 1)
+ # the C++ library
+ set(THREAD_MPI_CXX_SRC
+ thread_mpi/system_error.cpp )
+ENDMACRO(TMPI_MAKE_CXX_LIB)
include(FindThreads)
if (CMAKE_USE_PTHREADS_INIT)
thread_mpi/group.c thread_mpi/tmpi_init.c
thread_mpi/topology.c thread_mpi/list.c
thread_mpi/type.c thread_mpi/lock.c
- thread_mpi/numa_malloc.c thread_mpi/once.c)
+ thread_mpi/numa_malloc.c thread_mpi/once.c )
set(THREAD_LIB ${CMAKE_THREAD_LIBS_INIT})
else (CMAKE_USE_PTHREADS_INIT)
if (CMAKE_USE_WIN32_THREADS_INIT)
endif (CMAKE_USE_WIN32_THREADS_INIT)
endif (CMAKE_USE_PTHREADS_INIT)
+
# the spin-waiting option
option(THREAD_MPI_WAIT_FOR_NO_ONE "Use busy waits without yielding to the OS scheduler. Turning this on might improve performance (very) slightly at the cost of very poor performance if the threads are competing for CPU time." OFF)
mark_as_advanced(THREAD_MPI_WAIT_FOR_NO_ONE)
include(CheckCSourceCompiles)
+## Windows NUMA allocator
+#if (THREAD_WINDOWS)
+# check_c_source_compiles(
+# "#include <windows.h>
+# int main(void) { PROCESSOR_NUMBER a; return 0; }"
+# HAVE_PROCESSOR_NUMBER)
+# if(HAVE_PROCESSOR_NUMBER)
+# #add_definitions(-DTMPI_WINDOWS_NUMA_API)
+# set(TMPI_WINDOWS_NUMA_API 1)
+# endif(HAVE_PROCESSOR_NUMBER)
+#endif(THREAD_WINDOWS)
+
# option to set affinity
option(THREAD_MPI_SET_AFFINITY "Set thread affinity to a core if number of threads equal to number of hardware threads." ON)
mark_as_advanced(THREAD_MPI_SET_AFFINITY)
# An ugly hack to get absolute paths...
file(GLOB THREAD_MPI_SOURCES ${THREAD_MPI_SRC})
+file(GLOB THREAD_MPI_CXX_SOURCES ${THREAD_MPI_CXX_SRC})
set(GMX_SSEKERNEL_ASM_SRC ${GMX_SSEKERNEL_ASM_SRC} PARENT_SCOPE)
set(GMXLIB_SOURCES ${GMXLIB_SOURCES}
${GMX_SSEKERNEL_C_SRC} ${FORTRAN_SOURCES}
${GMX_BLUEGENE_C_SRC} ${GMX_PPC_ALTIVEC_SRC} ${THREAD_MPI_SOURCES}
+ ${THREAD_MPI_CXX_SOURCES}
PARENT_SCOPE)
errhandler.c p2p_send_recv.c type.c
event.c p2p_wait.c
gather.c profile.c
- group.c numa_malloc.c)
+ group.c numa_malloc.c )
if (THREAD_PTHREADS)
# make it link to the threads library (-lpthreads, for example)
target_link_libraries(thread_mpi ${THREAD_LIB})
+if (TMPI_CXX_LIB)
+ set(THREAD_MPI_CXX_LIB_SOURCE
+ system_error.cpp )
+ add_library(thread_mpi_cxx STATIC ${THREAD_MPI_CXX_LIB_SOURCE})
+ target_link_libraries(thread_mpi_cxx thread_mpi)
+endif (TMPI_CXX_LIB)
#configure_file(tmpi_config.h.cmakein tmpi_config.h)
#add_definitions(-DHAVE_TMPI_CONFIG_H)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_definitions(-DHAVE_TMPI_CONFIG_H)
+install(TARGETS thread_mpi DESTINATION lib)
/* the p2p communication events (incoming envelopes + finished send
envelopes generate events) */
tMPI_Event p2p_event;
- TMPI_YIELD_WAIT_DATA; /* data associated with waiting */
+ TMPI_YIELD_WAIT_DATA /* data associated with waiting */
struct req_list rql; /* list of pre-allocated requests */
/* collective communication structures: */
{
return tMPI_Error(TMPI_COMM_WORLD, TMPI_ERR_COMM);
}
- send_dst = tMPI_Get_thread(comm, dest);
+ send_dst=tMPI_Get_thread(comm, dest);
if (!send_dst)
{
return tMPI_Error(comm, TMPI_ERR_SEND_DEST);
--- /dev/null
+/*
+This source code file is part of thread_mpi.
+Written by Sander Pronk, Erik Lindahl, and possibly others.
+
+Copyright (c) 2009, Sander Pronk, Erik Lindahl.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1) Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2) Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3) Neither the name of the copyright holders nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+If you want to redistribute modifications, please consider that
+scientific software is very special. Version control is crucial -
+bugs must be traceable. We will be happy to consider code for
+inclusion in the official distribution, but derived work should not
+be called official thread_mpi. Details are found in the README & COPYING
+files.
+*/
+
+#ifdef __cplusplus
+
+#include <cerrno>
+#include <cstring>
+#include <cstdlib>
+#include <stdexcept>
+#include "thread_mpi/system_error.h"
+
+tMPI::system_error::system_error(error_code ec)
+ : runtime_error(std::strerror(ec)), ec_(ec)
+{
+}
+
+#endif /* __cplusplus */
+
files.
*/
-#ifndef _TMPI_ATOMIC_H_
-#define _TMPI_ATOMIC_H_
+#ifndef TMPI_ATOMIC_H_
+#define TMPI_ATOMIC_H_
/*! \file atomic.h
*
too */
#if ( (defined(__GNUC__) || defined(__PATHSCALE__) || defined(__PGI)) && (!defined(__xlc__)) )
+
+
+
/* now check specifically for several architectures: */
-#if (defined(i386) || defined(__x86_64__))
+#if ((defined(i386) || defined(__x86_64__)) && ! defined(__OPEN64__))
/* first x86: */
#include "atomic/gcc_x86.h"
/*#include "atomic/gcc.h"*/
#endif
-#endif /* _TMPI_ATOMIC_H_ */
+#endif /* TMPI_ATOMIC_H_ */
/* we put all of these on their own cache line by padding the data structure
to the size of a cache line on x86 (64 bytes): */
+#define TMPI_SIZEOF_X86_CACHE_LINE 64
typedef struct tMPI_Atomic
{
int value;
- char padding[64-sizeof(int)];
+ char padding[TMPI_SIZEOF_X86_CACHE_LINE-sizeof(int)];
} tMPI_Atomic_t;
typedef struct tMPI_Atomic_ptr
{
void* value;
- char padding[64-sizeof(void*)];
+ char padding[TMPI_SIZEOF_X86_CACHE_LINE-sizeof(void*)];
} tMPI_Atomic_ptr_t;
typedef struct tMPI_Spinlock
{
unsigned int lock;
- char padding[64-sizeof(unsigned int)];
+ char padding[TMPI_SIZEOF_X86_CACHE_LINE-sizeof(unsigned int)];
} tMPI_Spinlock_t;
files.
*/
-#ifndef _TMPI_BARRIER_H_
-#define _TMPI_BARRIER_H_
+#ifndef TMPI_BARRIER_H_
+#define TMPI_BARRIER_H_
#include "wait.h"
tMPI_Atomic_t count; /*!< Number of threads remaining */
int threshold; /*!< Total number of threads */
volatile int cycle; /*!< Current cycle (alternating 0/1) */
- TMPI_YIELD_WAIT_DATA;
+ TMPI_YIELD_WAIT_DATA
};
#define tMPI_Barrier_N(barrier) ((barrier)->threshold)
#endif
-#endif
+#endif /* TMPI_BARRIER_H_ */
files.
*/
-#ifndef _THREAD_MPI_COLLECTIVE_H_
-#define _THREAD_MPI_COLLECTIVE_H_
+#ifndef TMPI_COLLECTIVE_H_
+#define TMPI_COLLECTIVE_H_
/** \file
*
} /* closing extern "C" */
#endif
-#endif /* _THREAD_MPI_COLLECTIVE_H_ */
+#endif /* TMPI_COLLECTIVE_H_ */
files.
*/
-#ifndef _TMPI_EVENT_H_
-#define _TMPI_EVENT_H_
+#ifndef TMPI_EVENT_H_
+#define TMPI_EVENT_H_
#include "wait.h"
{
tMPI_Atomic_t sync; /* the event sync counter */
int last_sync; /* the last sync event looked at */
- TMPI_YIELD_WAIT_DATA; /* data associated with yielding */
+ TMPI_YIELD_WAIT_DATA /* data associated with yielding */
};
}
#endif
-#endif
+#endif /* TMPI_EVENT_H_ */
files.
*/
-#ifndef _TMPI_LIST_H_
-#define _TMPI_LIST_H_
+#ifndef TMPI_LIST_H_
+#define TMPI_LIST_H_
#include "atomic.h"
} /* closing extern "C" */
#endif
-#endif /* _TMPI_H_ */
+#endif /* TMPI_LIST_H_ */
files.
*/
-#ifndef _TMPI_FASTLOCK_H_
-#define _TMPI_FASTLOCK_H_
+#ifndef TMPI_FASTLOCK_H_
+#define TMPI_FASTLOCK_H_
#include "wait.h"
#include "atomic.h"
struct tMPI_Lock
{
tMPI_Spinlock_t lock; /*!< The underlying spin lock */
- TMPI_YIELD_WAIT_DATA;
+ TMPI_YIELD_WAIT_DATA
};
-#endif
+#endif /* TMPI_FASTLOCK_H_ */
files.
*/
-#ifndef _MPI_BINDINGS_H_
-#define _MPI_BINDINGS_H_
+#ifndef TMPI_MPI_BINDINGS_H_
+#define TMPI_MPI_BINDINGS_H_
/** \file
\brief MPI bindings for thread_mpi/tmpi.h
#endif
-#endif /* _MPI_BINDINGS_H_ */
+#endif /* TMPI_MPI_BINDINGS_H_ */
--- /dev/null
+/*
+This source code file is part of thread_mpi.
+Written by Sander Pronk, Erik Lindahl, and possibly others.
+
+Copyright (c) 2009, Sander Pronk, Erik Lindahl.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1) Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2) Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3) Neither the name of the copyright holders nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+If you want to redistribute modifications, please consider that
+scientific software is very special. Version control is crucial -
+bugs must be traceable. We will be happy to consider code for
+inclusion in the official distribution, but derived work should not
+be called official thread_mpi. Details are found in the README & COPYING
+files.
+*/
+
+/** \file
+ *
+ * \brief mutex objects with C++11 API compatibility.
+ *
+ * This header contains classes mutex and lock_guard, used in C++ mutex
+ * implementations safe for exceptions.
+*/
+
+#ifndef TMPI_MUTEX_H_
+#define TMPI_MUTEX_H_
+
+#include "system_error.h"
+#include "threads.h"
+
+#ifdef __cplusplus
+
+
+namespace tMPI
+{
+ /*! \brief A lock guard class that allows for the simple management of
+ mutexes. C++11 compatible.
+
+ In C++, mutexes would normally have to be unlocked with explicit
+ exception handlers and unlock statements. This class automates that
+ by handling the mutex unlock in a destructor. The constructor locks
+ the mutex.
+
+ Usage example:
+ tMPI::mutex mtx;
+ void do_count()
+ {
+ tMPI::lock_guard<tMPI::mutex> lock(mtx);
+ count += 1;
+ }
+ */
+ template <class Mutex> class lock_guard
+ {
+ public:
+ typedef Mutex mutex_type;
+ /*! \brief The constructor, which locks the mutex.
+
+ \param m The exisiting (globally accessible) mutex to lock. */
+ explicit lock_guard(mutex_type &m) : m_(m)
+ {
+ m_.lock();
+ }
+ //lock_guard(mutex_type &m, adopt_lock_t t);
+
+ /*! \brief The destructor, which unlocks the mutex */
+ ~lock_guard()
+ {
+ m_.unlock();
+ }
+ private:
+ // forbid copy constructor & assignment
+ lock_guard(const lock_guard &l);
+ lock_guard& operator=(const lock_guard &l);
+
+ mutex_type &m_;
+ };
+
+ /*! \brief A basic mutex class with C++11 compatibility. */
+ class mutex
+ {
+ public:
+ typedef tMPI_Thread_mutex_t* native_handle_type;
+
+ /*! \brief The constructor.
+
+ Throws a tMPI::system_error exception upon failure. */
+ mutex()
+ {
+ int ret=tMPI_Thread_mutex_init(&handle_);
+ if (ret)
+ throw system_error(ret);
+ }
+
+ /*! \brief The destructor.*/
+ ~mutex()
+ {
+ tMPI_Thread_mutex_destroy(&handle_);
+ }
+
+ /*! \brief The lock function.
+
+ Throws a tMPI::system_error exception upon failure. */
+ void lock()
+ {
+ int ret=tMPI_Thread_mutex_lock(&handle_);
+ if (ret)
+ throw system_error(ret);
+ }
+
+ /*! \brief The try_lock function.
+
+ Throws a tMPI::system_error exception upon failure.
+ \return true if the lock was locked successfully, false if not*/
+ bool try_lock()
+ {
+ if (tMPI_Thread_mutex_trylock(&handle_))
+ return false;
+ return true;
+ }
+
+ /*! \brief The unlock function.
+
+ Throws a tMPI::system_error exception upon failure. */
+ void unlock()
+ {
+ int ret=tMPI_Thread_mutex_unlock(&handle_);
+ if (ret)
+ throw system_error(ret);
+ }
+
+ native_handle_type native_handle() { return &handle_; }
+ private:
+ // forbid copy constructor & assignment
+ mutex(const mutex &m);
+ mutex& operator=(const mutex &m);
+
+ tMPI_Thread_mutex_t handle_;
+ };
+}
+
+#endif /* __cplusplus */
+
+#endif /* TMPI_MUTEX_H_ */
+
*/
-#ifndef _TMPI_NUMA_MALLOC_H_
-#define _TMPI_NUMA_MALLOC_H_
+#ifndef TMPI_NUMA_MALLOC_H_
+#define TMPI_NUMA_MALLOC_H_
/*! \file numa_alloc.h
}
#endif
-#endif /* _TMPI_NUMA_MALLOC_H_ */
+#endif /* TMPI_NUMA_MALLOC_H_ */
--- /dev/null
+/*
+This source code file is part of thread_mpi.
+Written by Sander Pronk, Erik Lindahl, and possibly others.
+
+Copyright (c) 2009, Sander Pronk, Erik Lindahl.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1) Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2) Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3) Neither the name of the copyright holders nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+If you want to redistribute modifications, please consider that
+scientific software is very special. Version control is crucial -
+bugs must be traceable. We will be happy to consider code for
+inclusion in the official distribution, but derived work should not
+be called official thread_mpi. Details are found in the README & COPYING
+files.
+*/
+
+/** \file
+ * \brief A C++11 compatible system_error class for reporting exceptions
+ *
+ * This header contains class definitions for system_error.
+ */
+
+#ifndef TMPI_SYSTEM_ERROR_H_
+#define TMPI_SYSTEM_ERROR_H_
+
+#include <stdexcept>
+
+#ifdef __cplusplus
+
+
+namespace tMPI
+{
+ /*! \brief Subset of the C++11 system_error class
+
+ Only contains the errno-based constructor. */
+ class system_error : public std::runtime_error
+ {
+ public:
+ typedef int error_code;
+
+ //system_error(error_code ec, const std::string& what_arg);
+ //system_error(error_code ec, const char* what_arg);
+ /*! \brief Constuctor that takes an system error number */
+ system_error(error_code ec) ;
+
+ /*! \brief Returns the error code */
+ const error_code& code() const
+ {
+ return ec_;
+ }
+ private:
+ error_code ec_;
+ };
+}
+
+#endif /* __cplusplus */
+
+#endif /* TMPI_SYSTEM_ERROR_H_ */
*/
-#ifndef _TMPI_THREAD_H_
-#define _TMPI_THREAD_H_
+#ifndef TMPI_THREADS_H_
+#define TMPI_THREADS_H_
/*! \file threads.h
*
*
* This routine always return directly. If the mutex was available and
* we successfully locked it we return 0, otherwise a non-zero
- * error code (usually meaning the mutex was already locked).
+ * return code (usually meaning the mutex was already locked).
*
* \param mtx Pointer to the mutex to try and lock
- * \return 0 or a non-zero error code.
+ * \return 0 or a non-zero return error code.
*/
int tMPI_Thread_mutex_trylock(tMPI_Thread_mutex_t *mtx);
}
#endif
-#endif /* _TMPI_THREAD_H_ */
+#endif /* TMPI_THREADS_H_ */
files.
*/
-#ifndef _TMPI_H_
-#define _TMPI_H_
+#ifndef TMPI_TMPI_H_
+#define TMPI_TMPI_H_
/** \file
*
} /* closing extern "C" */
#endif
-#endif /* _TMPI_H_ */
+#endif /* TMPI_TMPI_H_ */
*/
-#ifndef _TMPI_WAIT_H_
-#define _TMPI_WAIT_H_
+#ifndef TMPI_WAIT_H_
+#define TMPI_WAIT_H_
#ifndef TMPI_WAIT_FOR_NO_ONE
lead to starvation. This mixed approach actually gives better real-world
performance in the test program.*/
/* the data associated with waiting. */
-#define TMPI_YIELD_WAIT_DATA int yield_wait_counter
+#define TMPI_YIELD_WAIT_DATA int yield_wait_counter;
/* the initialization associated with waiting. */
#define TMPI_YIELD_WAIT_DATA_INIT(data) { (data)->yield_wait_counter=0; }
#endif /* !TMPI_WAIT_FOR_NO_ONE */
-#endif
+#endif /* TMPI_WAIT_H_ */