set(PTHREADS_LIBRARIES)
if (CMAKE_USE_PTHREADS_INIT)
set(PTHREADS_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+ list(APPEND GMOCK_COMPILE_DEFINITIONS "GTEST_HAS_PTHREAD=1")
+ set(GTEST_IS_THREADSAFE 1)
+else()
+ list(APPEND GMOCK_COMPILE_DEFINITIONS "GTEST_HAS_PTHREAD=0")
+ set(GTEST_IS_THREADSAFE 0)
endif()
# Skip variadic implementation of matchers if using GCC < 4.7 due to
set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIRS} PARENT_SCOPE)
set(GMOCK_COMPILE_DEFINITIONS ${GMOCK_COMPILE_DEFINITIONS} PARENT_SCOPE)
set(GMOCK_COMPILE_FLAGS "${GMOCK_COMPILE_FLAGS}" PARENT_SCOPE)
+set(GTEST_IS_THREADSAFE "${GTEST_IS_THREADSAFE}" PARENT_SCOPE)
#include "testutils/cmdlinetest.h"
#include "testutils/integrationtests.h"
+#include "testutils/mpitest.h"
#include "testutils/testoptions.h"
namespace gmx
namespace
{
-#if GMX_THREAD_MPI || defined(DOXYGEN)
-//! Number of tMPI threads for child mdrun call.
-int g_numThreads = 1;
-#endif
#if GMX_OPENMP || defined(DOXYGEN)
//! Number of OpenMP threads for child mdrun call.
int g_numOpenMPThreads = 1;
GMX_TEST_OPTIONS(MdrunTestOptions, options)
{
GMX_UNUSED_VALUE(options);
-#if GMX_THREAD_MPI
- options->addOption(IntegerOption("nt").store(&g_numThreads)
- .description("Number of thread-MPI threads/ranks for child mdrun calls"));
-#endif
#if GMX_OPENMP
options->addOption(IntegerOption("nt_omp").store(&g_numOpenMPThreads)
.description("Number of OpenMP threads for child mdrun calls"));
#if GMX_MPI
# if GMX_GPU != GMX_GPU_NONE
-# if GMX_THREAD_MPI
- int numGpusNeeded = g_numThreads;
-# else /* Must be real MPI */
- int numGpusNeeded = gmx_node_num();
-# endif
+ const int numGpusNeeded = getNumberOfTestMpiRanks();
std::string gpuIdString(numGpusNeeded, '0');
caller.addOption("-gpu_id", gpuIdString.c_str());
# endif
#endif
#if GMX_THREAD_MPI
- caller.addOption("-ntmpi", g_numThreads);
+ caller.addOption("-ntmpi", getNumberOfTestMpiRanks());
#endif
#if GMX_OPENMP
* node regardless of the number of ranks, because that's true in
* Jenkins and for most developers running the tests. */
int numberOfNodes = 1;
-#if GMX_THREAD_MPI
- /* Can't use gmx_node_num() because it is only valid after spawn of thread-MPI threads */
- int numberOfRanks = g_numThreads;
-#elif GMX_LIB_MPI
- int numberOfRanks = gmx_node_num();
-#else
- int numberOfRanks = 1;
-#endif
+ int numberOfRanks = getNumberOfTestMpiRanks();
if (numberOfRanks > numberOfNodes && !gmx_multiple_gpu_per_node_supported())
{
if (gmx_node_rank() == 0)
integrationtests.cpp
interactivetest.cpp
mpi-printer.cpp
+ mpitest.cpp
refdata.cpp
refdata-xml.cpp
stringtest.cpp
elseif(GMX_THREAD_MPI)
add_test(NAME ${NAME}
COMMAND
- $<TARGET_FILE:${EXENAME}> -nt ${NUMPROC}
+ $<TARGET_FILE:${EXENAME}> -ntmpi ${NUMPROC}
--gtest_output=xml:${CMAKE_BINARY_DIR}/Testing/Temporary/${NAME}.xml
)
set_tests_properties(${testname} PROPERTIES LABELS "MpiIntegrationTest")
gmx_add_gtest_executable(${EXENAME} ${ARGN})
gmx_register_unit_test(${NAME} ${EXENAME})
endfunction()
+
+function (gmx_add_mpi_unit_test NAME EXENAME RANKS)
+ if (GMX_MPI OR (GMX_THREAD_MPI AND GTEST_IS_THREADSAFE))
+ gmx_add_gtest_executable(${EXENAME} MPI ${ARGN})
+ # TODO: This function needs a new name.
+ gmx_register_mpi_integration_test(${NAME} ${EXENAME} ${RANKS})
+ endif()
+endfunction()
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * If you want to redistribute modifications to GROMACS, 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 must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements functions in mpitest.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_testutils
+ */
+#include "gmxpre.h"
+
+#include "mpitest.h"
+
+#include "config.h"
+
+#include <gtest/gtest.h>
+
+#include "thread_mpi/tmpi.h"
+
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/ioptionscontainer.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/exceptions.h"
+
+#include "testutils/testoptions.h"
+
+namespace gmx
+{
+namespace test
+{
+
+#if GMX_THREAD_MPI
+
+namespace
+{
+
+//! Number of tMPI threads.
+int g_numThreads = 1;
+//! \cond
+GMX_TEST_OPTIONS(ThreadMpiTestOptions, options)
+{
+ options->addOption(IntegerOption("ntmpi").store(&g_numThreads)
+ .description("Number of thread-MPI threads/ranks for the test"));
+}
+//! \endcond
+
+//! Thread entry function for other thread-MPI threads.
+void threadStartFunc(void *data)
+{
+ std::function<void()> &testBody = *reinterpret_cast<std::function<void()> *>(data);
+ try
+ {
+ testBody();
+ }
+ GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+}
+
+//! Helper function for starting thread-MPI threads for a test.
+bool startThreads(std::function<void()> *testBody)
+{
+ int ret = tMPI_Init_fn(TRUE, g_numThreads, TMPI_AFFINITY_NONE,
+ threadStartFunc, testBody);
+ return ret == TMPI_SUCCESS;
+}
+
+class InTestGuard
+{
+ public:
+ explicit InTestGuard(bool *inTest) : inTest_(inTest) { *inTest = true; }
+ ~InTestGuard() { *inTest_ = false; }
+
+ private:
+ bool *inTest_;
+};
+
+} // namespace
+
+//! \cond internal
+bool threadMpiTestRunner(std::function<void()> testBody)
+{
+ static bool inTest = false;
+
+ if (inTest || g_numThreads <= 1)
+ {
+ return true;
+ }
+#if GMX_THREAD_MPI && !GTEST_IS_THREADSAFE
+ ADD_FAILURE()
+ << "Google Test is not thread safe on this platform. "
+ << "Cannot run multi-rank tests with thread-MPI.";
+#else
+ InTestGuard guard(&inTest);
+ if (!startThreads(&testBody))
+ {
+ return false;
+ }
+ try
+ {
+ testBody();
+ }
+ GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+ tMPI_Finalize();
+#endif
+ return false;
+}
+//! \endcond
+
+#endif
+
+int getNumberOfTestMpiRanks()
+{
+#if GMX_THREAD_MPI
+ return g_numThreads;
+#else
+ return gmx_node_num();
+#endif
+}
+
+} // namespace test
+} // namespace gmx
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * If you want to redistribute modifications to GROMACS, 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 must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief
+ * Helper functions for MPI tests to make thread-MPI look like real MPI.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_testutils
+ */
+#ifndef GMX_TESTUTILS_MPITEST_H
+#define GMX_TESTUTILS_MPITEST_H
+
+#include "config.h"
+
+#include <functional>
+#include <type_traits>
+
+#include "gromacs/utility/basenetwork.h"
+
+namespace gmx
+{
+namespace test
+{
+
+/*! \brief
+ * Returns the number of MPI ranks to use for an MPI test.
+ *
+ * For thread-MPI builds, this will return the requested number of ranks
+ * even before the thread-MPI threads have been started.
+ *
+ * \ingroup module_testutils
+ */
+int getNumberOfTestMpiRanks();
+//! \cond internal
+/*! \brief
+ * Helper function for GMX_MPI_TEST().
+ *
+ * \ingroup module_testutils
+ */
+bool threadMpiTestRunner(std::function<void()> testBody);
+//! \endcond
+
+/*! \brief
+ * Declares that this test is an MPI-enabled unit test.
+ *
+ * \param[in] expectedRankCount Expected number of ranks for this test.
+ * The test will fail if run with unsupported number of ranks.
+ *
+ * To write unit tests that run under MPI, you need to do a few things:
+ * - Put GMX_MPI_TEST() as the first statement in your test body and
+ * specify the number of ranks this test expects.
+ * - Declare your unit test in CMake with gmx_add_mpi_unit_test().
+ * Note that all tests in the binary should fulfill the conditions above,
+ * and work with the same number of ranks.
+ * TODO: Figure out a mechanism for mixing tests with different rank counts in
+ * the same binary (possibly, also MPI and non-MPI tests).
+ *
+ * When you do the above, the following will happen:
+ * - The test will get compiled only if thread-MPI or real MPI is enabled.
+ * - The test will get executed on the number of ranks specified.
+ * If you are using real MPI, the whole test binary is run under MPI and
+ * test execution across the processes is synchronized (GMX_MPI_TEST()
+ * actually has no effect in this case, the synchronization is handled at a
+ * higher level).
+ * If you are using thread-MPI, GMX_MPI_TEST() is required and it
+ * initializes thread-MPI with the specified number of threads and runs the
+ * rest of the test on each of the threads.
+ *
+ * You need to be extra careful for variables in the test fixture, if you use
+ * one: when run under thread-MPI, these will be shared across all the ranks,
+ * while under real MPI, these are naturally different for each process.
+ * Local variables in the test body are private to each rank in both cases.
+ *
+ * Currently, it is not possible to specify the number of ranks as one, because
+ * that will lead to problems with (at least) thread-MPI, but such tests can be
+ * written as serial tests anyways.
+ *
+ * \ingroup module_testutils
+ */
+#if GMX_THREAD_MPI
+#define GMX_MPI_TEST(expectedRankCount) \
+ do { \
+ ASSERT_EQ(expectedRankCount, ::gmx::test::getNumberOfTestMpiRanks()); \
+ typedef std::remove_reference<decltype(*this)>::type MyTestClass; \
+ if (!::gmx::test::threadMpiTestRunner(std::bind(&MyTestClass::TestBody, this))) \
+ { \
+ return; \
+ } \
+ } while (0)
+#else
+#define GMX_MPI_TEST(expectedRankCount) \
+ ASSERT_EQ(expectedRankCount, ::gmx::test::getNumberOfTestMpiRanks())
+#endif
+
+} // namespace test
+} // namespace gmx
+
+#endif
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2011,2012,2014,2015, by the GROMACS development team, led by
+# Copyright (c) 2011,2012,2014,2015,2016, by the GROMACS development team, led by
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
# and including many others, as listed in the AUTHORS file in the
# top-level source directory and at http://www.gromacs.org.
refdata_tests.cpp
testasserts_tests.cpp
xvgtest_tests.cpp)
+
+gmx_add_mpi_unit_test(TestUtilsMpiUnitTests testutils-mpi-test 2
+ mpitest.cpp)
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2016, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * If you want to redistribute modifications to GROMACS, 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 must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Tests for infrastructure for running tests under MPI.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_testutils
+ */
+#include "gmxpre.h"
+
+#include "testutils/mpitest.h"
+
+#include "config.h"
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/gmxmpi.h"
+
+namespace
+{
+
+class MpiSelfTest : public ::testing::Test
+{
+ public:
+ MpiSelfTest() : reached {0, 0}
+ {}
+
+ int reached[2];
+};
+
+TEST_F(MpiSelfTest, Runs)
+{
+ GMX_MPI_TEST(2);
+#if GMX_THREAD_MPI
+ reached[gmx_node_rank()] = 1;
+ MPI_Barrier(MPI_COMM_WORLD);
+#else
+ int value = 1;
+ MPI_Gather(&value, 1, MPI_INT, reached, 1, MPI_INT, 0, MPI_COMM_WORLD);
+#endif
+ if (gmx_node_rank() == 0)
+ {
+ EXPECT_EQ(1, reached[0]);
+ EXPECT_EQ(1, reached[1]);
+ }
+}
+
+} // namespace