Improved diagnostics when PME cannot run on GPUs
[alexxy/gromacs.git] / src / gromacs / taskassignment / decidegpuusage.cpp
index 8e74f9b0872cebae8854770b08175478032226d3..b1f2a547df87634928d19257ffd7656bd39cc5a3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019, 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.
@@ -51,6 +51,7 @@
 #include <algorithm>
 #include <string>
 
+#include "gromacs/ewald/pme.h"
 #include "gromacs/hardware/cpuinfo.h"
 #include "gromacs/hardware/detecthardware.h"
 #include "gromacs/hardware/hardwaretopology.h"
@@ -153,14 +154,18 @@ decideWhetherToUseGpusForPmeWithThreadMpi(const bool              useGpuForNonbo
                                           const TaskTarget        pmeTarget,
                                           const std::vector<int> &gpuIdsToUse,
                                           const std::vector<int> &userGpuTaskAssignment,
-                                          const bool              canUseGpuForPme,
+                                          const gmx_hw_info_t    &hardwareInfo,
+                                          const t_inputrec       &inputrec,
+                                          const gmx_mtop_t       &mtop,
                                           const int               numRanksPerSimulation,
                                           const int               numPmeRanksPerSimulation)
 {
     // First, exclude all cases where we can't run PME on GPUs.
     if ((pmeTarget == TaskTarget::Cpu) ||
         !useGpuForNonbonded ||
-        !canUseGpuForPme)
+        !pme_gpu_supports_build(nullptr) ||
+        !pme_gpu_supports_hardware(hardwareInfo, nullptr) ||
+        !pme_gpu_supports_input(inputrec, mtop, nullptr))
     {
         // PME can't run on a GPU. If the user required that, we issue
         // an error later.
@@ -335,7 +340,9 @@ bool decideWhetherToUseGpusForNonbonded(const TaskTarget           nonbondedTarg
 bool decideWhetherToUseGpusForPme(const bool              useGpuForNonbonded,
                                   const TaskTarget        pmeTarget,
                                   const std::vector<int> &userGpuTaskAssignment,
-                                  const bool              canUseGpuForPme,
+                                  const gmx_hw_info_t    &hardwareInfo,
+                                  const t_inputrec       &inputrec,
+                                  const gmx_mtop_t       &mtop,
                                   const int               numRanksPerSimulation,
                                   const int               numPmeRanksPerSimulation,
                                   const bool              gpusWereDetected)
@@ -350,18 +357,36 @@ bool decideWhetherToUseGpusForPme(const bool              useGpuForNonbonded,
         if (pmeTarget == TaskTarget::Gpu)
         {
             GMX_THROW(NotImplementedError
-                          ("The PME on the GPU is only supported when nonbonded interactions run on GPUs also."));
+                          ("PME on GPUs is only supported when nonbonded interactions run on GPUs also."));
         }
         return false;
     }
 
-    if (!canUseGpuForPme)
+    std::string message;
+    if (!pme_gpu_supports_build(&message))
     {
         if (pmeTarget == TaskTarget::Gpu)
         {
-            // TODO Pass in the inputrec so we can give more help here?
             GMX_THROW(NotImplementedError
-                          ("The input simulation did not use PME in a way that is supported on the GPU."));
+                          ("Cannot compute PME interactions on a GPU, because " + message));
+        }
+        return false;
+    }
+    if (!pme_gpu_supports_hardware(hardwareInfo, &message))
+    {
+        if (pmeTarget == TaskTarget::Gpu)
+        {
+            GMX_THROW(NotImplementedError
+                          ("Cannot compute PME interactions on a GPU, because " + message));
+        }
+        return false;
+    }
+    if (!pme_gpu_supports_input(inputrec, mtop, &message))
+    {
+        if (pmeTarget == TaskTarget::Gpu)
+        {
+            GMX_THROW(NotImplementedError
+                          ("Cannot compute PME interactions on a GPU, because " + message));
         }
         return false;
     }
@@ -383,7 +408,7 @@ bool decideWhetherToUseGpusForPme(const bool              useGpuForNonbonded,
         // Specifying -gputasks requires specifying everything.
         if (pmeTarget == TaskTarget::Auto)
         {
-            GMX_THROW(InconsistentInputError(formatString(g_specifyEverythingFormatString, "all of -nb, -pme, and -ntmpi")));
+            GMX_THROW(InconsistentInputError(formatString(g_specifyEverythingFormatString, "all of -nb, -pme, and -ntmpi"))); // TODO ntmpi?
         }
 
         return true;