This moves the OpenCL specific definition into under macro in the main header.
Makes device stream and context definitions more consistent.
pmesolvetest.cpp
pmesplinespreadtest.cpp
pmetestcommon.cpp
- testhardwarecontexts.cpp
-)
-
-gmx_add_libgromacs_sources(
- testhardwarecontext.cpp
)
#include "testutils/testasserts.h"
#include "pmetestcommon.h"
-#include "testhardwarecontexts.h"
namespace gmx
{
#include "gromacs/utility/stringutil.h"
#include "testutils/refdata.h"
+#include "testutils/test_hardware_environment.h"
#include "testutils/testasserts.h"
#include "pmetestcommon.h"
-#include "testhardwarecontexts.h"
namespace gmx
{
public:
PmeGatherTest() = default;
- //! Sets the input atom data references once
+ //! Sets the input atom data references and programs once
static void SetUpTestCase()
{
size_t start = 0;
}
s_inputAtomDataSets_[atomCount] = atomData;
}
+ s_pmeTestHardwareContexts = createPmeTestHardwareContextList();
}
+
//! The test
void runTest()
{
inputRec.epsilon_r = 1.0;
TestReferenceData refData;
- for (const auto& context : getPmeTestEnv()->getHardwareContexts())
+ for (const auto& pmeTestHardwareContext : s_pmeTestHardwareContexts)
{
- CodePath codePath = context->codePath();
- const bool supportedInput =
- pmeSupportsInputForMode(*getPmeTestEnv()->hwinfo(), &inputRec, codePath);
+ pmeTestHardwareContext->activate();
+ CodePath codePath = pmeTestHardwareContext->codePath();
+ const bool supportedInput = pmeSupportsInputForMode(
+ *getTestHardwareEnvironment()->hwinfo(), &inputRec, codePath);
if (!supportedInput)
{
/* Testing the failure for the unsupported input */
/* Describing the test uniquely */
SCOPED_TRACE(
- formatString("Testing force gathering with %s %sfor PME grid size %d %d %d"
+ formatString("Testing force gathering on %s for PME grid size %d %d %d"
", order %d, %zu atoms",
- codePathToString(codePath), context->description().c_str(),
- gridSize[XX], gridSize[YY], gridSize[ZZ], pmeOrder, atomCount));
+ pmeTestHardwareContext->description().c_str(), gridSize[XX],
+ gridSize[YY], gridSize[ZZ], pmeOrder, atomCount));
PmeSafePointer pmeSafe =
- pmeInitWrapper(&inputRec, codePath, context->deviceContext(),
- context->deviceStream(), context->pmeGpuProgram(), box);
+ pmeInitWrapper(&inputRec, codePath, pmeTestHardwareContext->deviceContext(),
+ pmeTestHardwareContext->deviceStream(),
+ pmeTestHardwareContext->pmeGpuProgram(), box);
std::unique_ptr<StatePropagatorDataGpu> stateGpu =
(codePath == CodePath::GPU)
- ? makeStatePropagatorDataGpu(*pmeSafe.get(), context->deviceContext(),
- context->deviceStream())
+ ? makeStatePropagatorDataGpu(*pmeSafe.get(),
+ pmeTestHardwareContext->deviceContext(),
+ pmeTestHardwareContext->deviceStream())
: nullptr;
pmeInitAtoms(pmeSafe.get(), stateGpu.get(), codePath, inputAtomData.coordinates,
forceChecker.checkSequence(forces.begin(), forces.end(), "Forces");
}
}
+
+ static std::vector<std::unique_ptr<PmeTestHardwareContext>> s_pmeTestHardwareContexts;
};
+std::vector<std::unique_ptr<PmeTestHardwareContext>> PmeGatherTest::s_pmeTestHardwareContexts;
+
// An instance of static atom data
InputDataByAtomCount PmeGatherTest::s_inputAtomDataSets_;
#include "gromacs/utility/stringutil.h"
#include "testutils/refdata.h"
+#include "testutils/test_hardware_environment.h"
#include "testutils/testasserts.h"
#include "pmetestcommon.h"
-#include "testhardwarecontexts.h"
namespace gmx
{
public:
PmeSolveTest() = default;
+ //! Sets the programs once
+ static void SetUpTestCase() { s_pmeTestHardwareContexts = createPmeTestHardwareContextList(); }
+
//! The test
void runTest()
{
}
TestReferenceData refData;
- for (const auto& context : getPmeTestEnv()->getHardwareContexts())
+ for (const auto& pmeTestHardwareContext : s_pmeTestHardwareContexts)
{
- CodePath codePath = context->codePath();
- const bool supportedInput =
- pmeSupportsInputForMode(*getPmeTestEnv()->hwinfo(), &inputRec, codePath);
+ pmeTestHardwareContext->activate();
+ CodePath codePath = pmeTestHardwareContext->codePath();
+ const bool supportedInput = pmeSupportsInputForMode(
+ *getTestHardwareEnvironment()->hwinfo(), &inputRec, codePath);
if (!supportedInput)
{
/* Testing the failure for the unsupported input */
- EXPECT_THROW_GMX(pmeInitEmpty(&inputRec, codePath, nullptr, nullptr, nullptr, box,
- ewaldCoeff_q, ewaldCoeff_lj),
+ EXPECT_THROW_GMX(pmeInitWrapper(&inputRec, codePath, nullptr, nullptr, nullptr, box,
+ ewaldCoeff_q, ewaldCoeff_lj),
NotImplementedError);
continue;
}
{
/* Describing the test*/
SCOPED_TRACE(formatString(
- "Testing solving (%s, %s, %s energy/virial) with %s %sfor PME grid "
+ "Testing solving (%s, %s, %s energy/virial) on %s for PME grid "
"size %d %d %d, Ewald coefficients %g %g",
(method == PmeSolveAlgorithm::LennardJones) ? "Lennard-Jones" : "Coulomb",
gridOrdering.second.c_str(), computeEnergyAndVirial ? "with" : "without",
- codePathToString(codePath), context->description().c_str(),
- gridSize[XX], gridSize[YY], gridSize[ZZ], ewaldCoeff_q, ewaldCoeff_lj));
+ pmeTestHardwareContext->description().c_str(), gridSize[XX],
+ gridSize[YY], gridSize[ZZ], ewaldCoeff_q, ewaldCoeff_lj));
/* Running the test */
- PmeSafePointer pmeSafe = pmeInitEmpty(
- &inputRec, codePath, context->deviceContext(), context->deviceStream(),
- context->pmeGpuProgram(), box, ewaldCoeff_q, ewaldCoeff_lj);
+ PmeSafePointer pmeSafe = pmeInitWrapper(
+ &inputRec, codePath, pmeTestHardwareContext->deviceContext(),
+ pmeTestHardwareContext->deviceStream(),
+ pmeTestHardwareContext->pmeGpuProgram(), box, ewaldCoeff_q, ewaldCoeff_lj);
pmeSetComplexGrid(pmeSafe.get(), codePath, gridOrdering.first, nonZeroGridValues);
const real cellVolume = box[0] * box[4] * box[8];
// FIXME - this is box[XX][XX] * box[YY][YY] * box[ZZ][ZZ], should be stored in the PME structure
}
}
}
+
+ static std::vector<std::unique_ptr<PmeTestHardwareContext>> s_pmeTestHardwareContexts;
};
+std::vector<std::unique_ptr<PmeTestHardwareContext>> PmeSolveTest::s_pmeTestHardwareContexts;
+
/*! \brief Test for PME solving */
TEST_P(PmeSolveTest, ReproducesOutputs)
{
#include "gromacs/utility/stringutil.h"
#include "testutils/refdata.h"
+#include "testutils/test_hardware_environment.h"
#include "testutils/testasserts.h"
#include "pmetestcommon.h"
-#include "testhardwarecontexts.h"
namespace gmx
{
{
public:
PmeSplineAndSpreadTest() = default;
+
+ //! Sets the programs once
+ static void SetUpTestCase() { s_pmeTestHardwareContexts = createPmeTestHardwareContextList(); }
+
//! The test
void runTest()
{
inputRec.coulombtype = eelPME;
inputRec.epsilon_r = 1.0;
- TestReferenceData refData;
-
const std::map<PmeSplineAndSpreadOptions, std::string> optionsToTest = {
{ PmeSplineAndSpreadOptions::SplineAndSpreadUnified,
"spline computation and charge spreading (fused)" },
bool gridValuesSizeAssigned = false;
size_t previousGridValuesSize;
- for (const auto& context : getPmeTestEnv()->getHardwareContexts())
+ TestReferenceData refData;
+ for (const auto& pmeTestHardwareContext : s_pmeTestHardwareContexts)
{
- CodePath codePath = context->codePath();
- const bool supportedInput =
- pmeSupportsInputForMode(*getPmeTestEnv()->hwinfo(), &inputRec, codePath);
+ pmeTestHardwareContext->activate();
+ CodePath codePath = pmeTestHardwareContext->codePath();
+ const bool supportedInput = pmeSupportsInputForMode(
+ *getTestHardwareEnvironment()->hwinfo(), &inputRec, codePath);
if (!supportedInput)
{
/* Testing the failure for the unsupported input */
/* Describing the test uniquely in case it fails */
SCOPED_TRACE(formatString(
- "Testing %s with %s %sfor PME grid size %d %d %d"
+ "Testing %s on %s for PME grid size %d %d %d"
", order %d, %zu atoms",
- option.second.c_str(), codePathToString(codePath), context->description().c_str(),
+ option.second.c_str(), pmeTestHardwareContext->description().c_str(),
gridSize[XX], gridSize[YY], gridSize[ZZ], pmeOrder, atomCount));
/* Running the test */
PmeSafePointer pmeSafe =
- pmeInitWrapper(&inputRec, codePath, context->deviceContext(),
- context->deviceStream(), context->pmeGpuProgram(), box);
+ pmeInitWrapper(&inputRec, codePath, pmeTestHardwareContext->deviceContext(),
+ pmeTestHardwareContext->deviceStream(),
+ pmeTestHardwareContext->pmeGpuProgram(), box);
std::unique_ptr<StatePropagatorDataGpu> stateGpu =
(codePath == CodePath::GPU)
- ? makeStatePropagatorDataGpu(*pmeSafe.get(), context->deviceContext(),
- context->deviceStream())
+ ? makeStatePropagatorDataGpu(*pmeSafe.get(),
+ pmeTestHardwareContext->deviceContext(),
+ pmeTestHardwareContext->deviceStream())
: nullptr;
pmeInitAtoms(pmeSafe.get(), stateGpu.get(), codePath, coordinates, charges);
}
}
}
+
+ static std::vector<std::unique_ptr<PmeTestHardwareContext>> s_pmeTestHardwareContexts;
};
+std::vector<std::unique_ptr<PmeTestHardwareContext>> PmeSplineAndSpreadTest::s_pmeTestHardwareContexts;
+
/*! \brief Test for spline parameter computation and charge spreading. */
TEST_P(PmeSplineAndSpreadTest, ReproducesOutputs)
#include "gromacs/ewald/pme_solve.h"
#include "gromacs/ewald/pme_spread.h"
#include "gromacs/fft/parallel_3dfft.h"
-#include "gromacs/gpu_utils/device_stream_manager.h"
+#include "gromacs/gpu_utils/device_context.h"
#include "gromacs/gpu_utils/gpu_utils.h"
#include "gromacs/math/invertmatrix.h"
#include "gromacs/mdtypes/commrec.h"
#include "gromacs/utility/logger.h"
#include "gromacs/utility/stringutil.h"
+#include "testutils/test_hardware_environment.h"
#include "testutils/testasserts.h"
-#include "testhardwarecontexts.h"
-
namespace gmx
{
namespace test
return pme;
}
-//! Simple PME initialization based on input, no atom data
-PmeSafePointer pmeInitEmpty(const t_inputrec* inputRec,
- const CodePath mode,
- const DeviceContext* deviceContext,
- const DeviceStream* deviceStream,
- const PmeGpuProgram* pmeGpuProgram,
- const Matrix3x3& box,
- const real ewaldCoeff_q,
- const real ewaldCoeff_lj)
-{
- return pmeInitWrapper(inputRec, mode, deviceContext, deviceStream, pmeGpuProgram, box,
- ewaldCoeff_q, ewaldCoeff_lj);
- // hiding the fact that PME actually needs to know the number of atoms in advance
-}
-
PmeSafePointer pmeInitEmpty(const t_inputrec* inputRec)
{
const Matrix3x3 defaultBox = { { 1.0F, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 0.0F, 1.0F } };
return output;
}
+const char* codePathToString(CodePath codePath)
+{
+ switch (codePath)
+ {
+ case CodePath::CPU: return "CPU";
+ case CodePath::GPU: return "GPU";
+ default: GMX_THROW(NotImplementedError("This CodePath should support codePathToString"));
+ }
+}
+
+PmeTestHardwareContext::PmeTestHardwareContext() : codePath_(CodePath::CPU) {}
+
+PmeTestHardwareContext::PmeTestHardwareContext(TestDevice* testDevice) :
+ codePath_(CodePath::CPU),
+ testDevice_(testDevice)
+{
+ setActiveDevice(testDevice_->deviceInfo());
+ pmeGpuProgram_ = buildPmeGpuProgram(testDevice_->deviceContext());
+}
+
+//! Returns a human-readable context description line
+std::string PmeTestHardwareContext::description() const
+{
+ switch (codePath_)
+ {
+ case CodePath::CPU: return "CPU";
+ case CodePath::GPU: return "GPU (" + testDevice_->description() + ")";
+ default: return "Unknown code path.";
+ }
+}
+
+void PmeTestHardwareContext::activate() const
+{
+ if (codePath_ == CodePath::GPU)
+ {
+ setActiveDevice(testDevice_->deviceInfo());
+ }
+}
+
+std::vector<std::unique_ptr<PmeTestHardwareContext>> createPmeTestHardwareContextList()
+{
+ std::vector<std::unique_ptr<PmeTestHardwareContext>> pmeTestHardwareContextList;
+ // Add CPU
+ pmeTestHardwareContextList.emplace_back(std::make_unique<PmeTestHardwareContext>());
+ // Add GPU devices
+ const auto& testDeviceList = getTestHardwareEnvironment()->getTestDeviceList();
+ for (const auto& testDevice : testDeviceList)
+ {
+ pmeTestHardwareContextList.emplace_back(std::make_unique<PmeTestHardwareContext>(testDevice.get()));
+ }
+ return pmeTestHardwareContextList;
+}
+
} // namespace test
} // namespace gmx
#include "gromacs/mdtypes/state_propagator_data_gpu.h"
#include "gromacs/utility/unique_cptr.h"
+#include "testutils/test_device.h"
+
namespace gmx
{
-class DeviceStreamManager;
template<typename>
class ArrayRef;
namespace test
{
-// Forward declaration
-enum class CodePath;
+//! Hardware code path being tested
+enum class CodePath : int
+{
+ //! CPU code path
+ CPU,
+ //! GPU code path
+ GPU,
+ //! Total number of code paths
+ Count
+};
+
+//! Return a string useful for human-readable messages describing a \c codePath.
+const char* codePathToString(CodePath codePath);
// Convenience typedefs
//! A safe pointer type for PME.
//! TODO: make proper C++ matrix for the whole Gromacs, get rid of this
typedef std::array<real, DIM * DIM> Matrix3x3;
//! PME solver type
-enum class PmeSolveAlgorithm
+enum class PmeSolveAlgorithm : int
{
+ //! Coulomb electrostatics
Coulomb,
+ //! Lennard-Jones
LennardJones,
+ //! Total number of solvers
+ Count
};
// Misc.
const Matrix3x3& box,
real ewaldCoeff_q = 1.0F,
real ewaldCoeff_lj = 1.0F);
-//! Simple PME initialization (no atom data)
-PmeSafePointer pmeInitEmpty(const t_inputrec* inputRec,
- CodePath mode,
- const DeviceContext* deviceContext,
- const DeviceStream* deviceStream,
- const PmeGpuProgram* pmeGpuProgram,
- const Matrix3x3& box,
- real ewaldCoeff_q,
- real ewaldCoeff_lj);
//! Simple PME initialization based on inputrec only
PmeSafePointer pmeInitEmpty(const t_inputrec* inputRec);
SparseComplexGridValuesOutput pmeGetComplexGrid(const gmx_pme_t* pme, CodePath mode, GridOrdering gridOrdering);
//! Getting the reciprocal energy and virial
PmeOutput pmeGetReciprocalEnergyAndVirial(const gmx_pme_t* pme, CodePath mode, PmeSolveAlgorithm method);
+
+struct PmeTestHardwareContext
+{
+ //! Hardware path for the code being tested.
+ CodePath codePath_;
+ //! Returns a human-readable context description line
+ std::string description() const;
+ //! Pointer to the global test hardware device (if on GPU)
+ TestDevice* testDevice_ = nullptr;
+ //! PME GPU program if needed
+ PmeGpuProgramStorage pmeGpuProgram_ = nullptr;
+ // Constructor for CPU context
+ PmeTestHardwareContext();
+ // Constructor for GPU context
+ explicit PmeTestHardwareContext(TestDevice* testDevice);
+
+ //! Get the code path
+ CodePath codePath() const { return codePath_; }
+ //! Get the PME GPU program
+ const PmeGpuProgram* pmeGpuProgram() const
+ {
+ return codePath() == CodePath::GPU ? pmeGpuProgram_.get() : nullptr;
+ }
+
+ const DeviceContext* deviceContext() const
+ {
+ return codePath() == CodePath::GPU ? &testDevice_->deviceContext() : nullptr;
+ }
+
+ const DeviceStream* deviceStream() const
+ {
+ return codePath() == CodePath::GPU ? &testDevice_->deviceStream() : nullptr;
+ }
+
+ //! Activate the context (set the device)
+ void activate() const;
+};
+
+std::vector<std::unique_ptr<PmeTestHardwareContext>> createPmeTestHardwareContextList();
+
} // namespace test
} // namespace gmx
-#endif
+#endif // GMX_EWALD_PME_TEST_COMMON_H
#include "gromacs/ewald/pme.h"
#include "gromacs/hardware/detecthardware.h"
#include "gromacs/hardware/device_management.h"
+#include "gromacs/hardware/hw_info.h"
#include "gromacs/trajectory/energyframe.h"
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/gmxmpi.h"
class PmeTest : public MdrunTestFixture
{
public:
- //! Before any test is run, work out whether any compatible GPUs exist.
- static void SetUpTestCase();
- //! Store whether any compatible GPUs exist.
- static bool s_hasCompatibleGpus;
//! Convenience typedef
using RunModesList = std::map<std::string, std::vector<const char*>>;
//! Runs the test with the given inputs
void runTest(const RunModesList& runModes);
};
-bool PmeTest::s_hasCompatibleGpus = false;
-
-void PmeTest::SetUpTestCase()
-{
- s_hasCompatibleGpus = canComputeOnDevice();
-}
-
void PmeTest::runTest(const RunModesList& runModes)
{
const std::string inputFile = "spc-and-methanol";
{
SCOPED_TRACE("mdrun " + joinStrings(mode.second, " "));
auto modeTargetsGpus = (mode.first.find("Gpu") != std::string::npos);
- if (modeTargetsGpus && !s_hasCompatibleGpus)
+ if (modeTargetsGpus && getCompatibleDevices(hardwareInfo_->deviceInfoList).empty())
{
// This run mode will cause a fatal error from mdrun when
// it can't find GPUs, which is not something we're trying
testasserts.cpp
testfilemanager.cpp
testfileredirector.cpp
+ test_device.cpp
+ test_hardware_environment.cpp
testinit.cpp
testmatchers.cpp
testoptions.cpp
list(APPEND TESTUTILS_SOURCES ../external/tinyxml2/tinyxml2.cpp)
endif()
-add_library(testutils STATIC ${UNITTEST_TARGET_OPTIONS} ${TESTUTILS_SOURCES})
+if (GMX_GPU_CUDA)
+ # Work around FindCUDA that prevents using target_link_libraries()
+ # with keywords otherwise...
+ set(CUDA_LIBRARIES PRIVATE ${CUDA_LIBRARIES})
+ if (NOT GMX_CLANG_CUDA)
+ gmx_cuda_add_library(testutils ${TESTUTILS_SOURCES})
+ else()
+ add_library(testutils STATIC ${TESTUTILS_SOURCES})
+ endif()
+ target_link_libraries(testutils PRIVATE ${CUDA_CUFFT_LIBRARIES})
+else()
+ add_library(testutils STATIC ${UNITTEST_TARGET_OPTIONS} ${TESTUTILS_SOURCES})
+endif()
+
gmx_target_compile_options(testutils)
target_compile_definitions(testutils PRIVATE HAVE_CONFIG_H)
target_include_directories(testutils SYSTEM BEFORE PRIVATE ${PROJECT_SOURCE_DIR}/src/external/thread_mpi/include)
* \author Aleksei Iupinov <a.yupinov@gmail.com>
* \author Artem Zhmurov <zhmurov@gmail.com>
*
- * \ingroup module_ewald
+ * \ingroup module_testutils
*/
-
#include "gmxpre.h"
-#include "testhardwarecontext.h"
+#include "test_device.h"
#include <memory>
-#include "gromacs/ewald/pme.h"
#include "gromacs/gpu_utils/device_context.h"
#include "gromacs/gpu_utils/device_stream.h"
#include "gromacs/gpu_utils/gpu_utils.h"
+#include "gromacs/gpu_utils/gputraits.h"
#include "gromacs/hardware/detecthardware.h"
#include "gromacs/hardware/hw_info.h"
#include "gromacs/utility/basenetwork.h"
namespace test
{
-TestHardwareContext::TestHardwareContext(CodePath codePath, const char* description) :
- codePath_(codePath),
- description_(description)
+class TestDevice::Impl
{
- GMX_RELEASE_ASSERT(codePath == CodePath::CPU,
- "A GPU code path should provide DeviceInformation to the "
- "TestHerdwareContext constructor.");
- deviceContext_ = nullptr;
- deviceStream_ = nullptr;
-}
+public:
+ Impl(const char* description);
+ Impl(const char* description, const DeviceInformation& deviceInfo);
+ ~Impl();
+ //! Returns a human-readable context description line
+ std::string description() const { return description_; }
+ //! Returns the device info pointer
+ const DeviceInformation& deviceInfo() const { return deviceContext_.deviceInfo(); }
+ //! Get the device context
+ const DeviceContext& deviceContext() const { return deviceContext_; }
+ //! Get the device stream
+ const DeviceStream& deviceStream() const { return deviceStream_; }
+
+private:
+ //! Readable description
+ std::string description_;
+ //! Device context
+ DeviceContext deviceContext_;
+ //! Device stream
+ DeviceStream deviceStream_;
+};
-TestHardwareContext::TestHardwareContext(CodePath codePath,
- const char* description,
- const DeviceInformation& deviceInfo) :
- codePath_(codePath),
- description_(description)
+TestDevice::Impl::Impl(const char* description, const DeviceInformation& deviceInfo) :
+ description_(description),
+ deviceContext_(deviceInfo),
+ deviceStream_(deviceContext_, DeviceStreamPriority::Normal, false)
{
- GMX_RELEASE_ASSERT(codePath == CodePath::GPU,
- "TestHardwareContext tries to construct DeviceContext and PmeGpuProgram "
- "in CPU build.");
- deviceContext_ = new DeviceContext(deviceInfo);
- deviceStream_ = new DeviceStream(*deviceContext_, DeviceStreamPriority::Normal, false);
- program_ = buildPmeGpuProgram(*deviceContext_);
}
-TestHardwareContext::~TestHardwareContext()
+TestDevice::Impl::~Impl() = default;
+
+TestDevice::TestDevice(const char* description, const DeviceInformation& deviceInfo) :
+ impl_(new Impl(description, deviceInfo))
{
- delete (deviceStream_);
- delete (deviceContext_);
}
-const DeviceInformation* TestHardwareContext::deviceInfo() const
+TestDevice::~TestDevice() = default;
+
+std::string TestDevice::description() const
{
- return &deviceContext_->deviceInfo();
+ return impl_->description();
}
-const DeviceContext* TestHardwareContext::deviceContext() const
+const DeviceInformation& TestDevice::deviceInfo() const
{
- return deviceContext_;
+ return impl_->deviceInfo();
}
-//! Get the device stream
-const DeviceStream* TestHardwareContext::deviceStream() const
+
+const DeviceContext& TestDevice::deviceContext() const
{
- return deviceStream_;
+ return impl_->deviceContext();
}
-const char* codePathToString(CodePath codePath)
+const DeviceStream& TestDevice::deviceStream() const
{
- switch (codePath)
- {
- case CodePath::CPU: return "CPU";
- case CodePath::GPU: return "GPU";
- default: GMX_THROW(NotImplementedError("This CodePath should support codePathToString"));
- }
+ return impl_->deviceStream();
}
} // namespace test
* To help us fund GROMACS development, we humbly ask that you cite
* the research papers on the package. Check out http://www.gromacs.org.
*/
-#ifndef GMX_EWALD_TEST_HARDWARE_CONTEXT_H
-#define GMX_EWALD_TEST_HARDWARE_CONTEXT_H
+#ifndef GMX_TESTUTILS_TEST_DEVICE_H
+#define GMX_TESTUTILS_TEST_DEVICE_H
/*! \internal \file
* \brief
- * Describes test environment class which performs hardware enumeration for unit tests.
+ * Describes test environment class which performs GPU device enumeration for unit tests.
*
* \author Aleksei Iupinov <a.yupinov@gmail.com>
* \author Artem Zhmurov <zhmurov@gmail.com>
- * \ingroup module_ewald
+ *
+ * \ingroup module_testutils
*/
#include <map>
#include <string>
#include <vector>
-#include "gromacs/ewald/pme_gpu_program.h"
+#include "gromacs/utility/classhelpers.h"
#include "gromacs/utility/gmxassert.h"
class DeviceContext;
{
namespace test
{
-//! Hardware code path being tested
-enum class CodePath
-{
- CPU,
- GPU
-};
-
-//! Return a string useful for human-readable messages describing a \c codePath.
-const char* codePathToString(CodePath codePath);
/*! \internal \brief
- * A structure to describe a hardware context that persists over the lifetime
- * of the test binary - an abstraction over PmeGpuProgram with a human-readable string.
+ * A structure to describe a hardware context that persists over the lifetime
+ * of the test binary.
*/
-struct TestHardwareContext
+class TestDevice
{
- //! Hardware path for the code being tested.
- CodePath codePath_;
- //! Readable description
- std::string description_;
- //! Device context
- DeviceContext* deviceContext_ = nullptr;
- //! Device stream
- DeviceStream* deviceStream_ = nullptr;
- //! Persistent compiled GPU kernels for PME.
- PmeGpuProgramStorage program_;
-
public:
- //! Retuns the code path for this context.
- CodePath codePath() const { return codePath_; }
//! Returns a human-readable context description line
- std::string description() const { return description_; }
+ std::string description() const;
//! Returns the device info pointer
- const DeviceInformation* deviceInfo() const;
+ const DeviceInformation& deviceInfo() const;
//! Get the device context
- const DeviceContext* deviceContext() const;
+ const DeviceContext& deviceContext() const;
//! Get the device stream
- const DeviceStream* deviceStream() const;
- //! Returns the persistent PME GPU kernels
- const PmeGpuProgram* pmeGpuProgram() const { return program_.get(); }
- //! Constructs the context for CPU builds
- TestHardwareContext(CodePath codePath, const char* description);
- //! Constructs the context for GPU builds
- TestHardwareContext(CodePath codePath, const char* description, const DeviceInformation& deviceInfo);
+ const DeviceStream& deviceStream() const;
+ //! Creates the device context and stream for tests on the GPU
+ TestDevice(const char* description, const DeviceInformation& deviceInfo);
//! Destructor
- ~TestHardwareContext();
+ ~TestDevice();
+
+private:
+ //! Implementation type.
+ class Impl;
+ //! Implementation object.
+ PrivateImplPointer<Impl> impl_;
};
} // namespace test
} // namespace gmx
-#endif
+
+#endif // GMX_TESTUTILS_TEST_DEVICE_H
* Implements test environment class which performs hardware enumeration for unit tests.
*
* \author Aleksei Iupinov <a.yupinov@gmail.com>
- * \ingroup module_ewald
+ * \author Artem Zhmurov <zhmurov@gmail.com>
+ *
+ * \ingroup module_testutils
*/
#include "gmxpre.h"
-#include "testhardwarecontexts.h"
+#include "test_hardware_environment.h"
#include <memory>
-#include "gromacs/ewald/pme.h"
+#include "gromacs/gpu_utils/gpu_utils.h"
#include "gromacs/hardware/detecthardware.h"
#include "gromacs/hardware/device_management.h"
#include "gromacs/hardware/hw_info.h"
* so there is no deinitialization issue. See
* https://isocpp.org/wiki/faq/ctors for discussion of alternatives
* and trade-offs. */
-const PmeTestEnvironment* getPmeTestEnv()
+const TestHardwareEnvironment* getTestHardwareEnvironment()
{
- static PmeTestEnvironment* pmeTestEnvironment = nullptr;
- if (pmeTestEnvironment == nullptr)
+ static TestHardwareEnvironment* testHardwareEnvironment = nullptr;
+ if (testHardwareEnvironment == nullptr)
{
// Ownership of the TestEnvironment is taken by GoogleTest, so nothing can leak
- pmeTestEnvironment = static_cast<PmeTestEnvironment*>(
- ::testing::AddGlobalTestEnvironment(new PmeTestEnvironment));
+ testHardwareEnvironment = static_cast<TestHardwareEnvironment*>(
+ ::testing::AddGlobalTestEnvironment(new TestHardwareEnvironment));
}
- return pmeTestEnvironment;
+ return testHardwareEnvironment;
}
void callAddGlobalTestEnvironment()
{
- getPmeTestEnv();
+ getTestHardwareEnvironment();
}
//! Simple hardware initialization
return gmx_detect_hardware(MDLogger{}, physicalNodeComm);
}
-void PmeTestEnvironment::SetUp()
+void TestHardwareEnvironment::SetUp()
{
- hardwareContexts_.emplace_back(std::make_unique<TestHardwareContext>(CodePath::CPU, "(CPU) "));
-
+ testDeviceList_.clear();
hardwareInfo_ = hardwareInit();
- if (!pme_gpu_supports_build(nullptr) || !pme_gpu_supports_hardware(*hardwareInfo_, nullptr))
- {
- // PME can only run on the CPU, so don't make any more test contexts.
- return;
- }
// Constructing contexts for all compatible GPUs - will be empty on non-GPU builds
for (const DeviceInformation& compatibleDeviceInfo : getCompatibleDevices(hardwareInfo_->deviceInfoList))
{
setActiveDevice(compatibleDeviceInfo);
- std::string deviceDescription = getDeviceInformationString(compatibleDeviceInfo);
- std::string description = "(GPU " + deviceDescription + ") ";
- hardwareContexts_.emplace_back(std::make_unique<TestHardwareContext>(
- CodePath::GPU, description.c_str(), compatibleDeviceInfo));
+ std::string description = getDeviceInformationString(compatibleDeviceInfo);
+ testDeviceList_.emplace_back(std::make_unique<TestDevice>(description.c_str(), compatibleDeviceInfo));
}
}
-void PmeTestEnvironment::TearDown()
+void TestHardwareEnvironment::TearDown()
{
- hardwareContexts_.clear();
+ testDeviceList_.clear();
}
} // namespace test
* To help us fund GROMACS development, we humbly ask that you cite
* the research papers on the package. Check out http://www.gromacs.org.
*/
-#ifndef GMX_EWALD_TEST_HARDWARE_CONTEXTS_H
-#define GMX_EWALD_TEST_HARDWARE_CONTEXTS_H
+#ifndef GMX_TESTUTILS_TEST_HARDWARE_ENVIRONMENT_H
+#define GMX_TESTUTILS_TEST_HARDWARE_ENVIRONMENT_H
/*! \internal \file
* \brief
* Describes test environment class which performs hardware enumeration for unit tests.
*
* \author Aleksei Iupinov <a.yupinov@gmail.com>
- * \ingroup module_ewald
+ * \author Artem Zhmurov <zhmurov@gmail.com>
+ *
+ * \ingroup module_testutils
*/
#include <map>
#include <gtest/gtest.h>
-#include "gromacs/ewald/pme_gpu_program.h"
-#include "gromacs/hardware/device_management.h"
#include "gromacs/utility/gmxassert.h"
-#include "testhardwarecontext.h"
+#include "testutils/test_device.h"
struct gmx_hw_info_t;
namespace test
{
-//! A container of handles to hardware contexts
-typedef std::vector<std::unique_ptr<TestHardwareContext>> TestHardwareContexts;
-
/*! \internal \brief
* This class performs one-time test initialization (enumerating the hardware)
*/
-class PmeTestEnvironment : public ::testing::Environment
+class TestHardwareEnvironment : public ::testing::Environment
{
private:
//! General hardware info
gmx_hw_info_t* hardwareInfo_;
//! Storage of hardware contexts
- TestHardwareContexts hardwareContexts_;
+ std::vector<std::unique_ptr<TestDevice>> testDeviceList_;
public:
//! This is called by GTest framework once to query the hardware
//! This is called by GTest framework once release the hardware
void TearDown() override;
//! Get available hardware contexts.
- const TestHardwareContexts& getHardwareContexts() const { return hardwareContexts_; }
+ const std::vector<std::unique_ptr<TestDevice>>& getTestDeviceList() const
+ {
+ return testDeviceList_;
+ }
//! Get available hardware information.
const gmx_hw_info_t* hwinfo() const { return hardwareInfo_; }
};
//! Get the test environment
-const PmeTestEnvironment* getPmeTestEnv();
+const TestHardwareEnvironment* getTestHardwareEnvironment();
/*! \brief This constructs the test environment during setup of the
* unit test so that they can use the hardware context. */
} // namespace test
} // namespace gmx
-#endif
+#endif // GMX_TESTUTILS_TEST_HARDWARE_ENVIRONMENT_H
#include "testutils/mpi_printer.h"
#include "testutils/refdata.h"
+#include "testutils/test_hardware_environment.h"
#include "testutils/testfilemanager.h"
#include "testutils/testoptions.h"
void finalizeTestUtils();
//! \endcond
-/*! \brief Declare a function that all unit test implementations can use
- * to set up any environment that they need.
- *
- * When registering the unit test in CMake, the HARDWARE_DETECTION
- * flag requires that the code for that unit test implements this
- * function. Otherwise, a default stub implementation is provided.
- *
- * This approach conforms to the recommendation by GoogleTest to
- * arrange for the code that sets up the global test environment to be
- * called from main, rather than potentially rely on brittle static
- * initialization order. */
-void callAddGlobalTestEnvironment();
-
} // namespace test
} // namespace gmx
* This file is part of the GROMACS molecular simulation package.
*
* Copyright (c) 2010-2017, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, 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.
#ifndef TEST_USES_HARDWARE_DETECTION
//! Whether the test expects/supports running with knowledge of the hardware.
# define TEST_USES_HARDWARE_DETECTION false
-namespace gmx
-{
-namespace test
-{
-//! Implement a stub definition for tests that don't ask for a real one.
-void callAddGlobalTestEnvironment(){};
-} // namespace test
-} // namespace gmx
#endif
/*! \brief