Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / gmxlib / gmx_detect_hardware.cpp
index e5478b00202cea6d0f027e9d161350530bab7a92..bc7817d5f614b2d16b704f1efa321a4c76097f67 100644 (file)
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "gmxpre.h"
+
+#include "gromacs/legacyheaders/gmx_detect_hardware.h"
+
+#include "config.h"
 
 #include <assert.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include <string>
+#include <vector>
+
 #ifdef HAVE_UNISTD_H
 /* For sysconf */
 #include <unistd.h>
 #endif
+#ifdef GMX_NATIVE_WINDOWS
+#include <windows.h>
+#endif
 
-#include "types/enums.h"
-#include "types/hw_info.h"
-#include "types/commrec.h"
-#include "network.h"
-#include "md_logging.h"
-#include "gmx_cpuid.h"
-#include "gpu_utils.h"
-#include "copyrite.h"
-#include "gmx_detect_hardware.h"
-#include "md_logging.h"
+#include "thread_mpi/threads.h"
 
+#include "gromacs/legacyheaders/copyrite.h"
+#include "gromacs/legacyheaders/gmx_cpuid.h"
+#include "gromacs/legacyheaders/gpu_utils.h"
+#include "gromacs/legacyheaders/md_logging.h"
+#include "gromacs/legacyheaders/network.h"
+#include "gromacs/legacyheaders/types/commrec.h"
+#include "gromacs/legacyheaders/types/enums.h"
+#include "gromacs/legacyheaders/types/hw_info.h"
 #include "gromacs/utility/basenetwork.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxomp.h"
 #include "gromacs/utility/smalloc.h"
-
-#include "thread_mpi/threads.h"
-
-#ifdef GMX_NATIVE_WINDOWS
-#include <windows.h>
-#endif
+#include "gromacs/utility/stringutil.h"
 
 #ifdef GMX_GPU
 const gmx_bool bGPUBinary = TRUE;
@@ -147,50 +150,74 @@ static void print_gpu_detection_stats(FILE                 *fplog,
     }
 }
 
-static void print_gpu_use_stats(FILE                 *fplog,
-                                const gmx_gpu_info_t *gpu_info,
-                                const gmx_gpu_opt_t  *gpu_opt,
-                                const t_commrec      *cr)
+/*! \brief Helper function for writing comma-separated GPU IDs.
+ *
+ * \param[in] ids  A container of integer GPU IDs
+ * \return         A comma-separated string of GPU IDs */
+template <typename Container>
+static std::string makeGpuIdsString(const Container &ids)
 {
-    char sbuf[STRLEN], stmp[STRLEN];
-    int  i, ngpu_comp, ngpu_use;
+    std::string output;
+
+    if (0 != ids.size())
+    {
+        typename Container::const_iterator it = ids.begin();
+        output += gmx::formatString("%d", *it);
+        for (++it; it != ids.end(); ++it)
+        {
+            output += gmx::formatString(",%d", *it);
+        }
+    }
+    return output;
+}
 
-    ngpu_comp = gpu_info->ncuda_dev_compatible;
-    ngpu_use  = gpu_opt->ncuda_dev_use;
+/*! \brief Helper function for reporting GPU usage information
+ * in the mdrun log file
+ *
+ * \param[in] gpu_info    Pointer to per-node GPU info struct
+ * \param[in] gpu_opt     Pointer to per-node GPU options struct
+ * \param[in] numPpRanks  Number of PP ranks per node
+ * \return                String to write to the log file
+ * \throws                std::bad_alloc if out of memory */
+static std::string
+makeGpuUsageReport(const gmx_gpu_info_t *gpu_info,
+                   const gmx_gpu_opt_t  *gpu_opt,
+                   size_t                numPpRanks)
+{
+    int ngpu_use  = gpu_opt->ncuda_dev_use;
+    int ngpu_comp = gpu_info->ncuda_dev_compatible;
 
     /* Issue a note if GPUs are available but not used */
     if (ngpu_comp > 0 && ngpu_use < 1)
     {
-        sprintf(sbuf,
-                "%d compatible GPU%s detected in the system, but none will be used.\n"
-                "Consider trying GPU acceleration with the Verlet scheme!",
-                ngpu_comp, (ngpu_comp > 1) ? "s" : "");
+        return gmx::formatString("%d compatible GPU%s detected in the system, but none will be used.\n"
+                                 "Consider trying GPU acceleration with the Verlet scheme!\n",
+                                 ngpu_comp, (ngpu_comp > 1) ? "s" : "");
     }
-    else
-    {
-        int ngpu_use_uniq;
 
-        ngpu_use_uniq = gmx_count_gpu_dev_unique(gpu_info, gpu_opt);
+    std::string output;
 
-        sprintf(sbuf, "%d GPU%s %sselected for this run.\n"
-                "Mapping of GPU%s to the %d PP rank%s in this node: ",
-                ngpu_use_uniq, (ngpu_use_uniq > 1) ? "s" : "",
-                gpu_opt->bUserSet ? "user-" : "auto-",
-                (ngpu_use > 1) ? "s" : "",
-                cr->nrank_pp_intranode,
-                (cr->nrank_pp_intranode > 1) ? "s" : "");
-
-        for (i = 0; i < ngpu_use; i++)
+    {
+        std::vector<int> gpuIdsInUse;
+        for (int i = 0; i < ngpu_use; i++)
         {
-            sprintf(stmp, "#%d", get_gpu_device_id(gpu_info, gpu_opt, i));
-            if (i < ngpu_use - 1)
-            {
-                strcat(stmp, ", ");
-            }
-            strcat(sbuf, stmp);
+            gpuIdsInUse.push_back(get_gpu_device_id(gpu_info, gpu_opt, i));
         }
+        std::string gpuIdsString = makeGpuIdsString(gpuIdsInUse);
+        int         numGpusInUse = gmx_count_gpu_dev_unique(gpu_info, gpu_opt);
+        bool        bPluralGpus  = numGpusInUse > 1;
+
+        output += gmx::formatString("%d GPU%s %sselected for this run.\n"
+                                    "Mapping of GPU ID%s to the %d PP rank%s in this node: %s\n",
+                                    numGpusInUse, bPluralGpus ? "s" : "",
+                                    gpu_opt->bUserSet ? "user-" : "auto-",
+                                    bPluralGpus ? "s" : "",
+                                    numPpRanks,
+                                    (numPpRanks > 1) ? "s" : "",
+                                    gpuIdsString.c_str());
     }
-    md_print_info(cr, fplog, "%s\n\n", sbuf);
+
+    return output;
 }
 
 /* Give a suitable fatal error or warning if the build configuration
@@ -281,8 +308,17 @@ void gmx_check_hw_runconf_consistency(FILE                *fplog,
 
     if (hwinfo->gpu_info.ncuda_dev_compatible > 0)
     {
+        std::string gpuUseageReport;
+        try
+        {
+            gpuUseageReport = makeGpuUsageReport(&hwinfo->gpu_info,
+                                                 &hw_opt->gpu_opt,
+                                                 cr->nrank_pp_intranode);
+        }
+        GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+
         /* NOTE: this print is only for and on one physical node */
-        print_gpu_use_stats(fplog, &hwinfo->gpu_info, &hw_opt->gpu_opt, cr);
+        md_print_info(cr, fplog, gpuUseageReport.c_str());
     }
 
     /* Need to ensure that we have enough GPUs:
@@ -498,9 +534,14 @@ static int gmx_count_gpu_dev_unique(const gmx_gpu_info_t *gpu_info,
 
 
 /* Return the number of hardware threads supported by the current CPU.
- * We assume that this is equal with the number of CPUs reported to be
- * online by the OS at the time of the call.
- */
+ * We assume that this is equal with the number of "processors"
+ * reported to be online by the OS at the time of the call. The
+ * definition of "processor" is according to an old POSIX standard.
+ *
+ * Note that the number of hardware threads is generally greater than
+ * the number of cores (e.g. x86 hyper-threading, Power). Managing the
+ * mapping of software threads to hardware threads is managed
+ * elsewhere. */
 static int get_nthreads_hw_avail(FILE gmx_unused *fplog, const t_commrec gmx_unused *cr)
 {
     int ret = 0;
@@ -527,21 +568,20 @@ static int get_nthreads_hw_avail(FILE gmx_unused *fplog, const t_commrec gmx_unu
 #endif /* End of check for sysconf argument values */
 
 #else
-    /* Neither windows nor Unix. No fscking idea how many CPUs we have! */
+    /* Neither windows nor Unix. No fscking idea how many hardware threads we have! */
     ret = -1;
 #endif
 
     if (debug)
     {
-        fprintf(debug, "Detected %d processors, will use this as the number "
-                "of supported hardware threads.\n", ret);
+        fprintf(debug, "Detected %d hardware threads to use.\n", ret);
     }
 
 #ifdef GMX_OPENMP
     if (ret != gmx_omp_get_num_procs())
     {
         md_print_warn(cr, fplog,
-                      "Number of CPUs detected (%d) does not match the number reported by OpenMP (%d).\n"
+                      "Number of hardware threads detected (%d) does not match the number reported by OpenMP (%d).\n"
                       "Consider setting the launch configuration manually!",
                       ret, gmx_omp_get_num_procs());
     }