Merge branch 'master' into pygromacs
[alexxy/gromacs.git] / src / gromacs / gmxlib / gmx_detect_hardware.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 #include "gmxpre.h"
36
37 #include "gromacs/legacyheaders/gmx_detect_hardware.h"
38
39 #include "config.h"
40
41 #include <assert.h>
42 #include <errno.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include <string>
47 #include <vector>
48
49 #ifdef HAVE_UNISTD_H
50 /* For sysconf */
51 #include <unistd.h>
52 #endif
53 #ifdef GMX_NATIVE_WINDOWS
54 #include <windows.h>
55 #endif
56
57 #include "thread_mpi/threads.h"
58
59 #include "gromacs/gmxlib/gpu_utils/gpu_utils.h"
60 #include "gromacs/legacyheaders/copyrite.h"
61 #include "gromacs/legacyheaders/gmx_cpuid.h"
62 #include "gromacs/legacyheaders/md_logging.h"
63 #include "gromacs/legacyheaders/network.h"
64 #include "gromacs/legacyheaders/types/commrec.h"
65 #include "gromacs/legacyheaders/types/enums.h"
66 #include "gromacs/legacyheaders/types/hw_info.h"
67 #include "gromacs/utility/arrayref.h"
68 #include "gromacs/utility/basenetwork.h"
69 #include "gromacs/utility/cstringutil.h"
70 #include "gromacs/utility/exceptions.h"
71 #include "gromacs/utility/fatalerror.h"
72 #include "gromacs/utility/gmxassert.h"
73 #include "gromacs/utility/gmxomp.h"
74 #include "gromacs/utility/smalloc.h"
75 #include "gromacs/utility/stringutil.h"
76 #include "gromacs/utility/sysinfo.h"
77
78
79 #ifdef GMX_GPU
80
81 static const bool  bGPUBinary = TRUE;
82
83 #  ifdef GMX_USE_OPENCL
84
85 static const char *gpu_implementation       = "OpenCL";
86 /* Our current OpenCL implementation only supports using exactly one
87  * GPU per PP rank, so sharing is impossible */
88 static const bool bGpuSharingSupported      = false;
89 /* Our current OpenCL implementation is not known to handle
90  * concurrency correctly (at context creation, JIT compilation, or JIT
91  * cache-management stages). OpenCL runtimes need not support it
92  * either; library MPI segfaults when creating OpenCL contexts;
93  * thread-MPI seems to work but is not yet known to be safe. */
94 static const bool bMultiGpuPerNodeSupported = false;
95
96 #  else /* GMX_USE_OPENCL */
97
98 // Our CUDA implementation supports everything
99 static const char *gpu_implementation        = "CUDA";
100 static const bool  bGpuSharingSupported      = true;
101 static const bool  bMultiGpuPerNodeSupported = true;
102
103 #  endif /* GMX_USE_OPENCL */
104
105 #else    /* GMX_GPU */
106
107 // Not compiled with GPU support
108 static const bool  bGPUBinary                = false;
109 static const char *gpu_implementation        = "non-GPU";
110 static const bool  bGpuSharingSupported      = false;
111 static const bool  bMultiGpuPerNodeSupported = false;
112
113 #endif /* GMX_GPU */
114
115 /* Names of the GPU detection/check results (see e_gpu_detect_res_t in hw_info.h). */
116 const char * const gpu_detect_res_str[egpuNR] =
117 {
118     "compatible", "inexistent", "incompatible", "insane"
119 };
120
121 static const char * invalid_gpuid_hint =
122     "A delimiter-free sequence of valid numeric IDs of available GPUs is expected.";
123
124 /* The globally shared hwinfo structure. */
125 static gmx_hw_info_t      *hwinfo_g;
126 /* A reference counter for the hwinfo structure */
127 static int                 n_hwinfo = 0;
128 /* A lock to protect the hwinfo structure */
129 static tMPI_Thread_mutex_t hw_info_lock = TMPI_THREAD_MUTEX_INITIALIZER;
130
131 #define HOSTNAMELEN 80
132
133 /* FW decl. */
134 static void set_gpu_ids(gmx_gpu_opt_t *gpu_opt, int nrank, int rank);
135 static int gmx_count_gpu_dev_unique(const gmx_gpu_info_t *gpu_info,
136                                     const gmx_gpu_opt_t  *gpu_opt);
137
138 gmx_bool gmx_multiple_gpu_per_node_supported()
139 {
140     return bMultiGpuPerNodeSupported;
141 }
142
143 gmx_bool gmx_gpu_sharing_supported()
144 {
145     return bGpuSharingSupported;
146 }
147
148 static void sprint_gpus(char *sbuf, const gmx_gpu_info_t *gpu_info)
149 {
150     int      i, ndev;
151     char     stmp[STRLEN];
152
153     ndev = gpu_info->n_dev;
154
155     sbuf[0] = '\0';
156     for (i = 0; i < ndev; i++)
157     {
158         get_gpu_device_info_string(stmp, gpu_info, i);
159         strcat(sbuf, "    ");
160         strcat(sbuf, stmp);
161         if (i < ndev - 1)
162         {
163             strcat(sbuf, "\n");
164         }
165     }
166 }
167
168 static void print_gpu_detection_stats(FILE                 *fplog,
169                                       const gmx_gpu_info_t *gpu_info,
170                                       const t_commrec      *cr)
171 {
172     char onhost[HOSTNAMELEN+10], stmp[STRLEN];
173     int  ngpu;
174
175     if (!gpu_info->bDetectGPUs)
176     {
177         /* We skipped the detection, so don't print detection stats */
178         return;
179     }
180
181     ngpu = gpu_info->n_dev;
182
183 #if defined GMX_MPI && !defined GMX_THREAD_MPI
184     /* We only print the detection on one, of possibly multiple, nodes */
185     strncpy(onhost, " on host ", 10);
186     gmx_gethostname(onhost + 9, HOSTNAMELEN);
187 #else
188     /* We detect all relevant GPUs */
189     strncpy(onhost, "", 1);
190 #endif
191
192     if (ngpu > 0)
193     {
194         sprint_gpus(stmp, gpu_info);
195         md_print_warn(cr, fplog, "%d GPU%s detected%s:\n%s\n",
196                       ngpu, (ngpu > 1) ? "s" : "", onhost, stmp);
197     }
198     else
199     {
200         md_print_warn(cr, fplog, "No GPUs detected%s\n", onhost);
201     }
202 }
203
204 /*! \brief Helper function for reporting GPU usage information
205  * in the mdrun log file
206  *
207  * \param[in] gpu_info       Pointer to per-node GPU info struct
208  * \param[in] gpu_opt        Pointer to per-node GPU options struct
209  * \param[in] numPpRanks     Number of PP ranks per node
210  * \param[in] bPrintHostName Print the hostname in the usage information
211  * \return                   String to write to the log file
212  * \throws                   std::bad_alloc if out of memory */
213 static std::string
214 makeGpuUsageReport(const gmx_gpu_info_t *gpu_info,
215                    const gmx_gpu_opt_t  *gpu_opt,
216                    size_t                numPpRanks,
217                    bool                  bPrintHostName)
218 {
219     int  ngpu_use  = gpu_opt->n_dev_use;
220     int  ngpu_comp = gpu_info->n_dev_compatible;
221     char host[HOSTNAMELEN];
222
223     if (bPrintHostName)
224     {
225         gmx_gethostname(host, HOSTNAMELEN);
226     }
227
228     /* Issue a note if GPUs are available but not used */
229     if (ngpu_comp > 0 && ngpu_use < 1)
230     {
231         return gmx::formatString("%d compatible GPU%s detected in the system, but none will be used.\n"
232                                  "Consider trying GPU acceleration with the Verlet scheme!\n",
233                                  ngpu_comp, (ngpu_comp > 1) ? "s" : "");
234     }
235
236     std::string output;
237     if (!gpu_opt->bUserSet)
238     {
239         // gpu_opt->dev_compatible is only populated during auto-selection
240         std::string gpuIdsString =
241             formatAndJoin(gmx::constArrayRefFromArray(gpu_opt->dev_compatible,
242                                                       gpu_opt->n_dev_compatible),
243                           ",", gmx::StringFormatter("%d"));
244         bool bPluralGpus = gpu_opt->n_dev_compatible > 1;
245
246         if (bPrintHostName)
247         {
248             output += gmx::formatString("On host %s ", host);
249         }
250         output += gmx::formatString("%d compatible GPU%s %s present, with ID%s %s\n",
251                                     gpu_opt->n_dev_compatible,
252                                     bPluralGpus ? "s" : "",
253                                     bPluralGpus ? "are" : "is",
254                                     bPluralGpus ? "s" : "",
255                                     gpuIdsString.c_str());
256     }
257
258     {
259         std::vector<int> gpuIdsInUse;
260         for (int i = 0; i < ngpu_use; i++)
261         {
262             gpuIdsInUse.push_back(get_gpu_device_id(gpu_info, gpu_opt, i));
263         }
264         std::string gpuIdsString =
265             formatAndJoin(gpuIdsInUse, ",", gmx::StringFormatter("%d"));
266         int         numGpusInUse = gmx_count_gpu_dev_unique(gpu_info, gpu_opt);
267         bool        bPluralGpus  = numGpusInUse > 1;
268
269         if (bPrintHostName)
270         {
271             output += gmx::formatString("On host %s ", host);
272         }
273         output += gmx::formatString("%d GPU%s %sselected for this run.\n"
274                                     "Mapping of GPU ID%s to the %d PP rank%s in this node: %s\n",
275                                     numGpusInUse, bPluralGpus ? "s" : "",
276                                     gpu_opt->bUserSet ? "user-" : "auto-",
277                                     bPluralGpus ? "s" : "",
278                                     numPpRanks,
279                                     (numPpRanks > 1) ? "s" : "",
280                                     gpuIdsString.c_str());
281     }
282
283     return output;
284 }
285
286 /* Give a suitable fatal error or warning if the build configuration
287    and runtime CPU do not match. */
288 static void
289 check_use_of_rdtscp_on_this_cpu(FILE                *fplog,
290                                 const t_commrec     *cr,
291                                 const gmx_hw_info_t *hwinfo)
292 {
293     gmx_bool bCpuHasRdtscp, bBinaryUsesRdtscp;
294 #ifdef HAVE_RDTSCP
295     bBinaryUsesRdtscp = TRUE;
296 #else
297     bBinaryUsesRdtscp = FALSE;
298 #endif
299
300     bCpuHasRdtscp = gmx_cpuid_feature(hwinfo->cpuid_info, GMX_CPUID_FEATURE_X86_RDTSCP);
301
302     if (!bCpuHasRdtscp && bBinaryUsesRdtscp)
303     {
304         gmx_fatal(FARGS, "The %s executable was compiled to use the rdtscp CPU instruction. "
305                   "However, this is not supported by the current hardware and continuing would lead to a crash. "
306                   "Please rebuild GROMACS with the GMX_USE_RDTSCP=OFF CMake option.",
307                   ShortProgram());
308     }
309
310     if (bCpuHasRdtscp && !bBinaryUsesRdtscp)
311     {
312         md_print_warn(cr, fplog, "The current CPU can measure timings more accurately than the code in\n"
313                       "%s was configured to use. This might affect your simulation\n"
314                       "speed as accurate timings are needed for load-balancing.\n"
315                       "Please consider rebuilding %s with the GMX_USE_RDTSCP=ON CMake option.\n",
316                       ShortProgram(), ShortProgram());
317     }
318 }
319
320 void gmx_check_hw_runconf_consistency(FILE                *fplog,
321                                       const gmx_hw_info_t *hwinfo,
322                                       const t_commrec     *cr,
323                                       const gmx_hw_opt_t  *hw_opt,
324                                       gmx_bool             bUseGPU)
325 {
326     int      npppn;
327     char     th_or_proc[STRLEN], th_or_proc_plural[STRLEN], pernode[STRLEN];
328     gmx_bool btMPI, bMPI, bNthreadsAuto, bEmulateGPU;
329
330     assert(hwinfo);
331     assert(cr);
332
333     /* Below we only do consistency checks for PP and GPUs,
334      * this is irrelevant for PME only nodes, so in that case we return
335      * here.
336      */
337     if (!(cr->duty & DUTY_PP))
338     {
339         return;
340     }
341
342 #if defined(GMX_THREAD_MPI)
343     bMPI          = FALSE;
344     btMPI         = TRUE;
345     bNthreadsAuto = (hw_opt->nthreads_tmpi < 1);
346 #elif defined(GMX_LIB_MPI)
347     bMPI          = TRUE;
348     btMPI         = FALSE;
349     bNthreadsAuto = FALSE;
350 #else
351     bMPI          = FALSE;
352     btMPI         = FALSE;
353     bNthreadsAuto = FALSE;
354 #endif
355
356     /* GPU emulation detection is done later, but we need here as well
357      * -- uncool, but there's no elegant workaround */
358     bEmulateGPU       = (getenv("GMX_EMULATE_GPU") != NULL);
359
360     if (hwinfo->gpu_info.n_dev_compatible > 0)
361     {
362         std::string gpuUseageReport;
363         try
364         {
365             gpuUseageReport = makeGpuUsageReport(&hwinfo->gpu_info,
366                                                  &hw_opt->gpu_opt,
367                                                  cr->nrank_pp_intranode,
368                                                  bMPI && cr->nnodes > 1);
369         }
370         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
371
372         /* NOTE: this print is only for and on one physical node */
373         md_print_info(cr, fplog, "%s\n", gpuUseageReport.c_str());
374     }
375
376     /* Need to ensure that we have enough GPUs:
377      * - need one GPU per PP node
378      * - no GPU oversubscription with tMPI
379      * */
380     /* number of PP processes per node */
381     npppn = cr->nrank_pp_intranode;
382
383     pernode[0]           = '\0';
384     th_or_proc_plural[0] = '\0';
385     if (btMPI)
386     {
387         sprintf(th_or_proc, "thread-MPI thread");
388         if (npppn > 1)
389         {
390             sprintf(th_or_proc_plural, "s");
391         }
392     }
393     else if (bMPI)
394     {
395         sprintf(th_or_proc, "MPI process");
396         if (npppn > 1)
397         {
398             sprintf(th_or_proc_plural, "es");
399         }
400         sprintf(pernode, " per node");
401     }
402     else
403     {
404         /* neither MPI nor tMPI */
405         sprintf(th_or_proc, "process");
406     }
407
408     if (bUseGPU && hwinfo->gpu_info.n_dev_compatible > 0 &&
409         !bEmulateGPU)
410     {
411         int  ngpu_comp, ngpu_use;
412         char gpu_comp_plural[2], gpu_use_plural[2];
413
414         ngpu_comp = hwinfo->gpu_info.n_dev_compatible;
415         ngpu_use  = hw_opt->gpu_opt.n_dev_use;
416
417         sprintf(gpu_comp_plural, "%s", (ngpu_comp > 1) ? "s" : "");
418         sprintf(gpu_use_plural,  "%s", (ngpu_use > 1) ? "s" : "");
419
420         /* number of tMPI threads auto-adjusted */
421         if (btMPI && bNthreadsAuto)
422         {
423             if (hw_opt->gpu_opt.bUserSet && npppn < ngpu_use)
424             {
425                 /* The user manually provided more GPUs than threads we
426                    could automatically start. */
427                 gmx_fatal(FARGS,
428                           "%d GPU%s provided, but only %d PP thread-MPI thread%s coud be started.\n"
429                           "%s requires one PP tread-MPI thread per GPU; use fewer GPUs.",
430                           ngpu_use, gpu_use_plural,
431                           npppn, th_or_proc_plural,
432                           ShortProgram());
433             }
434
435             if (!hw_opt->gpu_opt.bUserSet && npppn < ngpu_comp)
436             {
437                 /* There are more GPUs than tMPI threads; we have
438                    limited the number GPUs used. */
439                 md_print_warn(cr, fplog,
440                               "NOTE: %d GPU%s were detected, but only %d PP thread-MPI thread%s can be started.\n"
441                               "      %s can use one GPU per PP tread-MPI thread, so only %d GPU%s will be used.\n",
442                               ngpu_comp, gpu_comp_plural,
443                               npppn, th_or_proc_plural,
444                               ShortProgram(), npppn,
445                               npppn > 1 ? "s" : "");
446             }
447         }
448
449         if (hw_opt->gpu_opt.bUserSet)
450         {
451             if (ngpu_use != npppn)
452             {
453                 gmx_fatal(FARGS,
454                           "Incorrect launch configuration: mismatching number of PP %s%s and GPUs%s.\n"
455                           "%s was started with %d PP %s%s%s, but you provided %d GPU%s.",
456                           th_or_proc, btMPI ? "s" : "es", pernode,
457                           ShortProgram(), npppn, th_or_proc,
458                           th_or_proc_plural, pernode,
459                           ngpu_use, gpu_use_plural);
460             }
461         }
462         else
463         {
464             /* TODO Should we have a gpu_opt->n_dev_supported field? */
465             if (ngpu_comp > npppn && gmx_multiple_gpu_per_node_supported())
466             {
467                 md_print_warn(cr, fplog,
468                               "NOTE: potentially sub-optimal launch configuration, %s started with less\n"
469                               "      PP %s%s%s than GPU%s available.\n"
470                               "      Each PP %s can use only one GPU, %d GPU%s%s will be used.\n",
471                               ShortProgram(), th_or_proc,
472                               th_or_proc_plural, pernode, gpu_comp_plural,
473                               th_or_proc, npppn, gpu_use_plural, pernode);
474             }
475
476             if (ngpu_use != npppn)
477             {
478                 /* Avoid duplicate error messages.
479                  * Unfortunately we can only do this at the physical node
480                  * level, since the hardware setup and MPI process count
481                  * might differ between physical nodes.
482                  */
483                 if (cr->rank_pp_intranode == 0)
484                 {
485                     std::string reasonForLimit;
486                     if (ngpu_comp > 1 &&
487                         ngpu_use == 1 &&
488                         !gmx_multiple_gpu_per_node_supported())
489                     {
490                         reasonForLimit  = "can be used by ";
491                         reasonForLimit += gpu_implementation;
492                         reasonForLimit += " in GROMACS";
493                     }
494                     else
495                     {
496                         reasonForLimit = "was detected";
497                     }
498                     gmx_fatal(FARGS,
499                               "Incorrect launch configuration: mismatching number of PP %s%s and GPUs%s.\n"
500                               "%s was started with %d PP %s%s%s, but only %d GPU%s %s.",
501                               th_or_proc, btMPI ? "s" : "es", pernode,
502                               ShortProgram(), npppn, th_or_proc,
503                               th_or_proc_plural, pernode,
504                               ngpu_use, gpu_use_plural, reasonForLimit.c_str());
505                 }
506             }
507         }
508
509         {
510             int      same_count;
511
512             same_count = gmx_count_gpu_dev_shared(&hw_opt->gpu_opt);
513
514             if (same_count > 0)
515             {
516                 md_print_info(cr, fplog,
517                               "NOTE: You assigned %s to multiple %s%s.\n",
518                               same_count > 1 ? "GPUs" : "a GPU", th_or_proc, btMPI ? "s" : "es");
519             }
520         }
521     }
522
523 #ifdef GMX_MPI
524     if (PAR(cr))
525     {
526         /* Avoid other ranks to continue after
527            inconsistency */
528         MPI_Barrier(cr->mpi_comm_mygroup);
529     }
530 #endif
531
532 }
533
534 /* Return 0 if none of the GPU (per node) are shared among PP ranks.
535  *
536  * Sharing GPUs among multiple PP ranks is possible when the user passes
537  * GPU IDs. Here we check for sharing and return a non-zero value when
538  * this is detected. Note that the return value represents the number of
539  * PP rank pairs that share a device.
540  */
541 int gmx_count_gpu_dev_shared(const gmx_gpu_opt_t *gpu_opt)
542 {
543     int      same_count    = 0;
544     int      ngpu          = gpu_opt->n_dev_use;
545
546     if (gpu_opt->bUserSet)
547     {
548         int      i, j;
549
550         for (i = 0; i < ngpu - 1; i++)
551         {
552             for (j = i + 1; j < ngpu; j++)
553             {
554                 same_count      += (gpu_opt->dev_use[i] ==
555                                     gpu_opt->dev_use[j]);
556             }
557         }
558     }
559
560     return same_count;
561 }
562
563 /* Count and return the number of unique GPUs (per node) selected.
564  *
565  * As sharing GPUs among multiple PP ranks is possible when the user passes
566  * GPU IDs, the number of GPUs user (per node) can be different from the
567  * number of GPU IDs selected.
568  */
569 static int gmx_count_gpu_dev_unique(const gmx_gpu_info_t *gpu_info,
570                                     const gmx_gpu_opt_t  *gpu_opt)
571 {
572     int  i, uniq_count, ngpu;
573     int *uniq_ids;
574
575     assert(gpu_info);
576     assert(gpu_opt);
577
578     ngpu = gpu_info->n_dev;
579
580     uniq_count  = 0;
581
582     snew(uniq_ids, ngpu);
583
584     /* Each element in uniq_ids will be set to 0 or 1. The n-th element set
585      * to 1 indicates that the respective GPU was selected to be used. */
586     for (i = 0; i < gpu_opt->n_dev_use; i++)
587     {
588         int device_id;
589
590         device_id           = gmx_gpu_sharing_supported() ? get_gpu_device_id(gpu_info, gpu_opt, i) : i;
591         uniq_ids[device_id] = 1;
592     }
593     /* Count the devices used. */
594     for (i = 0; i < ngpu; i++)
595     {
596         uniq_count += uniq_ids[i];
597     }
598
599     sfree(uniq_ids);
600
601     return uniq_count;
602 }
603
604 static int get_ncores(gmx_cpuid_t cpuid)
605 {
606     int        nprocessors, npackages, ncores_per_package, nhwthreads_per_core;
607     const int *package_id, *core_id, *hwthread_id, *locality_order;
608     int        rc;
609
610     rc = gmx_cpuid_topology(cpuid,
611                             &nprocessors, &npackages,
612                             &ncores_per_package, &nhwthreads_per_core,
613                             &package_id, &core_id,
614                             &hwthread_id, &locality_order);
615
616     if (rc == 0)
617     {
618         return npackages*ncores_per_package;
619     }
620     else
621     {
622         /* We don't have cpuid topology info, return 0 core count */
623         return 0;
624     }
625 }
626
627 /* Return the number of hardware threads supported by the current CPU.
628  * We assume that this is equal with the number of "processors"
629  * reported to be online by the OS at the time of the call. The
630  * definition of "processor" is according to an old POSIX standard.
631  *
632  * Note that the number of hardware threads is generally greater than
633  * the number of cores (e.g. x86 hyper-threading, Power). Managing the
634  * mapping of software threads to hardware threads is managed
635  * elsewhere. */
636 static int get_nthreads_hw_avail(FILE gmx_unused *fplog, const t_commrec gmx_unused *cr)
637 {
638     int ret = 0;
639
640 #if ((defined(WIN32) || defined( _WIN32 ) || defined(WIN64) || defined( _WIN64 )) && !(defined (__CYGWIN__) || defined (__CYGWIN32__)))
641     /* Windows */
642     SYSTEM_INFO sysinfo;
643     GetSystemInfo( &sysinfo );
644     ret = sysinfo.dwNumberOfProcessors;
645 #elif defined HAVE_SYSCONF
646     /* We are probably on Unix.
647      * Now check if we have the argument to use before executing the call
648      */
649 #if defined(_SC_NPROCESSORS_ONLN)
650     ret = sysconf(_SC_NPROCESSORS_ONLN);
651 #elif defined(_SC_NPROC_ONLN)
652     ret = sysconf(_SC_NPROC_ONLN);
653 #elif defined(_SC_NPROCESSORS_CONF)
654     ret = sysconf(_SC_NPROCESSORS_CONF);
655 #elif defined(_SC_NPROC_CONF)
656     ret = sysconf(_SC_NPROC_CONF);
657 #else
658 #warning "No valid sysconf argument value found. Executables will not be able to determine the number of logical cores: mdrun will use 1 thread by default!"
659 #endif /* End of check for sysconf argument values */
660
661 #else
662     /* Neither windows nor Unix. No fscking idea how many hardware threads we have! */
663     ret = -1;
664 #endif
665
666     if (debug)
667     {
668         fprintf(debug, "Detected %d hardware threads to use.\n", ret);
669     }
670
671 #ifdef GMX_OPENMP
672     if (ret != gmx_omp_get_num_procs())
673     {
674         md_print_warn(cr, fplog,
675                       "Number of logical cores detected (%d) does not match the number reported by OpenMP (%d).\n"
676                       "Consider setting the launch configuration manually!",
677                       ret, gmx_omp_get_num_procs());
678     }
679 #endif
680
681     return ret;
682 }
683
684 static void gmx_detect_gpus(FILE *fplog, const t_commrec *cr)
685 {
686 #ifdef GMX_LIB_MPI
687     int              rank_world;
688     MPI_Comm         physicalnode_comm;
689 #endif
690     int              rank_local;
691
692     /* Under certain circumstances MPI ranks on the same physical node
693      * can not simultaneously access the same GPU(s). Therefore we run
694      * the detection only on one MPI rank per node and broadcast the info.
695      * Note that with thread-MPI only a single thread runs this code.
696      *
697      * TODO: We should also do CPU hardware detection only once on each
698      * physical node and broadcast it, instead of do it on every MPI rank.
699      */
700 #ifdef GMX_LIB_MPI
701     /* A split of MPI_COMM_WORLD over physical nodes is only required here,
702      * so we create and destroy it locally.
703      */
704     MPI_Comm_rank(MPI_COMM_WORLD, &rank_world);
705     MPI_Comm_split(MPI_COMM_WORLD, gmx_physicalnode_id_hash(),
706                    rank_world, &physicalnode_comm);
707     MPI_Comm_rank(physicalnode_comm, &rank_local);
708 #else
709     /* Here there should be only one process, check this */
710     assert(cr->nnodes == 1 && cr->sim_nodeid == 0);
711
712     rank_local = 0;
713 #endif
714
715     if (rank_local == 0)
716     {
717         char detection_error[STRLEN] = "", sbuf[STRLEN];
718
719         if (detect_gpus(&hwinfo_g->gpu_info, detection_error) != 0)
720         {
721             if (detection_error[0] != '\0')
722             {
723                 sprintf(sbuf, ":\n      %s\n", detection_error);
724             }
725             else
726             {
727                 sprintf(sbuf, ".");
728             }
729             md_print_warn(cr, fplog,
730                           "NOTE: Error occurred during GPU detection%s"
731                           "      Can not use GPU acceleration, will fall back to CPU kernels.\n",
732                           sbuf);
733         }
734     }
735
736 #ifdef GMX_LIB_MPI
737     /* Broadcast the GPU info to the other ranks within this node */
738     MPI_Bcast(&hwinfo_g->gpu_info.n_dev, 1, MPI_INT, 0, physicalnode_comm);
739
740     if (hwinfo_g->gpu_info.n_dev > 0)
741     {
742         int dev_size;
743
744         dev_size = hwinfo_g->gpu_info.n_dev*sizeof_gpu_dev_info();
745
746         if (rank_local > 0)
747         {
748             hwinfo_g->gpu_info.gpu_dev =
749                 (struct gmx_device_info_t *)malloc(dev_size);
750         }
751         MPI_Bcast(hwinfo_g->gpu_info.gpu_dev, dev_size, MPI_BYTE,
752                   0, physicalnode_comm);
753         MPI_Bcast(&hwinfo_g->gpu_info.n_dev_compatible, 1, MPI_INT,
754                   0, physicalnode_comm);
755     }
756
757     MPI_Comm_free(&physicalnode_comm);
758 #endif
759 }
760
761 static void gmx_collect_hardware_mpi()
762 {
763 #ifdef GMX_LIB_MPI
764     int  rank_id;
765     int  nrank, rank, ncore, nhwthread, ngpu, i;
766     int  gpu_hash;
767     int *buf, *all;
768
769     rank_id   = gmx_physicalnode_id_hash();
770     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
771     MPI_Comm_size(MPI_COMM_WORLD, &nrank);
772     ncore     = hwinfo_g->ncore;
773     nhwthread = hwinfo_g->nthreads_hw_avail;
774     ngpu      = hwinfo_g->gpu_info.n_dev_compatible;
775     /* Create a unique hash of the GPU type(s) in this node */
776     gpu_hash  = 0;
777     /* Here it might be better to only loop over the compatible GPU, but we
778      * don't have that information available and it would also require
779      * removing the device ID from the device info string.
780      */
781     for (i = 0; i < hwinfo_g->gpu_info.n_dev; i++)
782     {
783         char stmp[STRLEN];
784
785         /* Since the device ID is incorporated in the hash, the order of
786          * the GPUs affects the hash. Also two identical GPUs won't give
787          * a gpu_hash of zero after XORing.
788          */
789         get_gpu_device_info_string(stmp, &hwinfo_g->gpu_info, i);
790         gpu_hash ^= gmx_string_fullhash_func(stmp, gmx_string_hash_init);
791     }
792
793     snew(buf, nrank);
794     snew(all, nrank);
795     buf[rank] = rank_id;
796
797     MPI_Allreduce(buf, all, nrank, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
798
799     gmx_bool bFound;
800     int      nnode0, ncore0, nhwthread0, ngpu0, r;
801
802     bFound     = FALSE;
803     ncore0     = 0;
804     nnode0     = 0;
805     nhwthread0 = 0;
806     ngpu0      = 0;
807     for (r = 0; r < nrank; r++)
808     {
809         if (all[r] == rank_id)
810         {
811             if (!bFound && r == rank)
812             {
813                 /* We are the first rank in this physical node */
814                 nnode0     = 1;
815                 ncore0     = ncore;
816                 nhwthread0 = nhwthread;
817                 ngpu0      = ngpu;
818             }
819             bFound = TRUE;
820         }
821     }
822
823     sfree(buf);
824     sfree(all);
825
826     int sum[4], maxmin[10];
827
828     {
829         int buf[4];
830
831         /* Sum values from only intra-rank 0 so we get the sum over all nodes */
832         buf[0] = nnode0;
833         buf[1] = ncore0;
834         buf[2] = nhwthread0;
835         buf[3] = ngpu0;
836
837         MPI_Allreduce(buf, sum, 4, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
838     }
839
840     {
841         int buf[10];
842
843         /* Store + and - values for all ranks,
844          * so we can get max+min with one MPI call.
845          */
846         buf[0] = ncore;
847         buf[1] = nhwthread;
848         buf[2] = ngpu;
849         buf[3] = gmx_cpuid_simd_suggest(hwinfo_g->cpuid_info);
850         buf[4] = gpu_hash;
851         buf[5] = -buf[0];
852         buf[6] = -buf[1];
853         buf[7] = -buf[2];
854         buf[8] = -buf[3];
855         buf[9] = -buf[4];
856
857         MPI_Allreduce(buf, maxmin, 10, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
858     }
859
860     hwinfo_g->nphysicalnode       = sum[0];
861     hwinfo_g->ncore_tot           = sum[1];
862     hwinfo_g->ncore_min           = -maxmin[5];
863     hwinfo_g->ncore_max           = maxmin[0];
864     hwinfo_g->nhwthread_tot       = sum[2];
865     hwinfo_g->nhwthread_min       = -maxmin[6];
866     hwinfo_g->nhwthread_max       = maxmin[1];
867     hwinfo_g->ngpu_compatible_tot = sum[3];
868     hwinfo_g->ngpu_compatible_min = -maxmin[7];
869     hwinfo_g->ngpu_compatible_max = maxmin[2];
870     hwinfo_g->simd_suggest_min    = static_cast<enum gmx_cpuid_simd>(-maxmin[8]);
871     hwinfo_g->simd_suggest_max    = static_cast<enum gmx_cpuid_simd>(maxmin[3]);
872     hwinfo_g->bIdenticalGPUs      = (maxmin[4] == -maxmin[9]);
873 #else
874     /* All ranks use the same pointer, protect it with a mutex */
875     tMPI_Thread_mutex_lock(&hw_info_lock);
876     hwinfo_g->nphysicalnode       = 1;
877     hwinfo_g->ncore_tot           = hwinfo_g->ncore;
878     hwinfo_g->ncore_min           = hwinfo_g->ncore;
879     hwinfo_g->ncore_max           = hwinfo_g->ncore;
880     hwinfo_g->nhwthread_tot       = hwinfo_g->nthreads_hw_avail;
881     hwinfo_g->nhwthread_min       = hwinfo_g->nthreads_hw_avail;
882     hwinfo_g->nhwthread_max       = hwinfo_g->nthreads_hw_avail;
883     hwinfo_g->ngpu_compatible_tot = hwinfo_g->gpu_info.n_dev_compatible;
884     hwinfo_g->ngpu_compatible_min = hwinfo_g->gpu_info.n_dev_compatible;
885     hwinfo_g->ngpu_compatible_max = hwinfo_g->gpu_info.n_dev_compatible;
886     hwinfo_g->simd_suggest_min    = gmx_cpuid_simd_suggest(hwinfo_g->cpuid_info);
887     hwinfo_g->simd_suggest_max    = gmx_cpuid_simd_suggest(hwinfo_g->cpuid_info);
888     hwinfo_g->bIdenticalGPUs      = TRUE;
889     tMPI_Thread_mutex_unlock(&hw_info_lock);
890 #endif
891 }
892
893 gmx_hw_info_t *gmx_detect_hardware(FILE *fplog, const t_commrec *cr,
894                                    gmx_bool bDetectGPUs)
895 {
896     int ret;
897
898     /* make sure no one else is doing the same thing */
899     ret = tMPI_Thread_mutex_lock(&hw_info_lock);
900     if (ret != 0)
901     {
902         gmx_fatal(FARGS, "Error locking hwinfo mutex: %s", strerror(errno));
903     }
904
905     /* only initialize the hwinfo structure if it is not already initalized */
906     if (n_hwinfo == 0)
907     {
908         snew(hwinfo_g, 1);
909
910         /* detect CPUID info; no fuss, we don't detect system-wide
911          * -- sloppy, but that's it for now */
912         if (gmx_cpuid_init(&hwinfo_g->cpuid_info) != 0)
913         {
914             gmx_fatal_collective(FARGS, cr, NULL, "CPUID detection failed!");
915         }
916
917         /* get the number of cores, will be 0 when not detected */
918         hwinfo_g->ncore             = get_ncores(hwinfo_g->cpuid_info);
919
920         /* detect number of hardware threads */
921         hwinfo_g->nthreads_hw_avail = get_nthreads_hw_avail(fplog, cr);
922
923         /* detect GPUs */
924         hwinfo_g->gpu_info.n_dev            = 0;
925         hwinfo_g->gpu_info.n_dev_compatible = 0;
926         hwinfo_g->gpu_info.gpu_dev          = NULL;
927
928         /* Run the detection if the binary was compiled with GPU support
929          * and we requested detection.
930          */
931         hwinfo_g->gpu_info.bDetectGPUs =
932             (bGPUBinary && bDetectGPUs &&
933              getenv("GMX_DISABLE_GPU_DETECTION") == NULL);
934         if (hwinfo_g->gpu_info.bDetectGPUs)
935         {
936             gmx_detect_gpus(fplog, cr);
937         }
938     }
939     /* increase the reference counter */
940     n_hwinfo++;
941
942     ret = tMPI_Thread_mutex_unlock(&hw_info_lock);
943     if (ret != 0)
944     {
945         gmx_fatal(FARGS, "Error unlocking hwinfo mutex: %s", strerror(errno));
946     }
947
948     gmx_collect_hardware_mpi();
949
950     return hwinfo_g;
951 }
952
953 static std::string detected_hardware_string(const gmx_hw_info_t *hwinfo,
954                                             bool                 bFullCpuInfo)
955 {
956     std::string s;
957
958     s  = gmx::formatString("\n");
959     s += gmx::formatString("Running on %d node%s with total",
960                            hwinfo->nphysicalnode,
961                            hwinfo->nphysicalnode == 1 ? "" : "s");
962     if (hwinfo->ncore_tot > 0)
963     {
964         s += gmx::formatString(" %d cores,", hwinfo->ncore_tot);
965     }
966     s += gmx::formatString(" %d logical cores", hwinfo->nhwthread_tot);
967     if (hwinfo->gpu_info.bDetectGPUs)
968     {
969         s += gmx::formatString(", %d compatible GPU%s",
970                                hwinfo->ngpu_compatible_tot,
971                                hwinfo->ngpu_compatible_tot == 1 ? "" : "s");
972     }
973     else if (bGPUBinary)
974     {
975         s += gmx::formatString(" (GPU detection deactivated)");
976     }
977     s += gmx::formatString("\n");
978
979     if (hwinfo->nphysicalnode > 1)
980     {
981         /* Print per node hardware feature counts */
982         if (hwinfo->ncore_max > 0)
983         {
984             s += gmx::formatString("  Cores per node:           %2d", hwinfo->ncore_min);
985             if (hwinfo->ncore_max > hwinfo->ncore_min)
986             {
987                 s += gmx::formatString(" - %2d", hwinfo->ncore_max);
988             }
989             s += gmx::formatString("\n");
990         }
991         s += gmx::formatString("  Logical cores per node:   %2d", hwinfo->nhwthread_min);
992         if (hwinfo->nhwthread_max > hwinfo->nhwthread_min)
993         {
994             s += gmx::formatString(" - %2d", hwinfo->nhwthread_max);
995         }
996         s += gmx::formatString("\n");
997         if (bGPUBinary)
998         {
999             s += gmx::formatString("  Compatible GPUs per node: %2d",
1000                                    hwinfo->ngpu_compatible_min);
1001             if (hwinfo->ngpu_compatible_max > hwinfo->ngpu_compatible_min)
1002             {
1003                 s += gmx::formatString(" - %2d", hwinfo->ngpu_compatible_max);
1004             }
1005             s += gmx::formatString("\n");
1006             if (hwinfo->ngpu_compatible_tot > 0)
1007             {
1008                 if (hwinfo->bIdenticalGPUs)
1009                 {
1010                     s += gmx::formatString("  All nodes have identical type(s) of GPUs\n");
1011                 }
1012                 else
1013                 {
1014                     /* This message will also appear with identical GPU types
1015                      * when at least one node has no GPU.
1016                      */
1017                     s += gmx::formatString("  Different nodes have different type(s) and/or order of GPUs\n");
1018                 }
1019             }
1020         }
1021     }
1022
1023 #ifdef GMX_LIB_MPI
1024     char host[HOSTNAMELEN];
1025     int  rank;
1026
1027     gmx_gethostname(host, HOSTNAMELEN);
1028     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
1029
1030     s += gmx::formatString("Hardware detected on host %s (the node of MPI rank %d):\n",
1031                            host, rank);
1032 #else
1033     s += gmx::formatString("Hardware detected:\n");
1034 #endif
1035     s += gmx::formatString("  CPU info:\n");
1036     if (bFullCpuInfo)
1037     {
1038         char buf[1024];
1039
1040         gmx_cpuid_formatstring(hwinfo->cpuid_info, buf, 1023);
1041         buf[1023] = '\0';
1042
1043         s += gmx::formatString("%s", buf);
1044     }
1045     else
1046     {
1047         s += gmx::formatString("    Vendor: %s\n",
1048                                gmx_cpuid_vendor_string[gmx_cpuid_vendor(hwinfo->cpuid_info)]);
1049         s += gmx::formatString("    Brand:  %s\n",
1050                                gmx_cpuid_brand(hwinfo->cpuid_info));
1051     }
1052     s += gmx::formatString("    SIMD instructions most likely to fit this hardware: %s",
1053                            gmx_cpuid_simd_string[hwinfo->simd_suggest_min]);
1054     if (hwinfo->simd_suggest_max > hwinfo->simd_suggest_min)
1055     {
1056         s += gmx::formatString(" - %s",
1057                                gmx_cpuid_simd_string[hwinfo->simd_suggest_max]);
1058     }
1059     s += gmx::formatString("\n");
1060     s += gmx::formatString("    SIMD instructions selected at GROMACS compile time: %s\n",
1061                            gmx_cpuid_simd_string[gmx_compiled_simd()]);
1062     if (bGPUBinary && (hwinfo->ngpu_compatible_tot > 0 ||
1063                        hwinfo->gpu_info.n_dev > 0))
1064     {
1065         s += gmx::formatString("  GPU info:\n");
1066         s += gmx::formatString("    Number of GPUs detected: %d\n",
1067                                hwinfo->gpu_info.n_dev);
1068         if (hwinfo->gpu_info.n_dev > 0)
1069         {
1070             char buf[STRLEN];
1071
1072             sprint_gpus(buf, &hwinfo->gpu_info);
1073             s += gmx::formatString("%s\n", buf);
1074         }
1075     }
1076
1077     return s;
1078 }
1079
1080 void gmx_print_detected_hardware(FILE *fplog, const t_commrec *cr,
1081                                  const gmx_hw_info_t *hwinfo)
1082 {
1083     if (fplog != NULL)
1084     {
1085         std::string detected;
1086
1087         detected = detected_hardware_string(hwinfo, TRUE);
1088
1089         fprintf(fplog, "%s\n", detected.c_str());
1090     }
1091
1092     if (MULTIMASTER(cr))
1093     {
1094         std::string detected;
1095
1096         detected = detected_hardware_string(hwinfo, FALSE);
1097
1098         fprintf(stderr, "%s\n", detected.c_str());
1099     }
1100
1101     /* Check the compiled SIMD instruction set against that of the node
1102      * with the lowest SIMD level support.
1103      */
1104     gmx_cpuid_simd_check(hwinfo->simd_suggest_min, fplog, MULTIMASTER(cr));
1105
1106     /* For RDTSCP we only check on our local node and skip the MPI reduction */
1107     check_use_of_rdtscp_on_this_cpu(fplog, cr, hwinfo);
1108 }
1109
1110 //! \brief Return if any GPU ID (e.g in a user-supplied string) is repeated
1111 static gmx_bool anyGpuIdIsRepeated(const gmx_gpu_opt_t *gpu_opt)
1112 {
1113     /* Loop over IDs in the string */
1114     for (int i = 0; i < gpu_opt->n_dev_use - 1; ++i)
1115     {
1116         /* Look for the ID in location i in the following part of the
1117            string */
1118         for (int j = i + 1; j < gpu_opt->n_dev_use; ++j)
1119         {
1120             if (gpu_opt->dev_use[i] == gpu_opt->dev_use[j])
1121             {
1122                 /* Same ID found in locations i and j */
1123                 return TRUE;
1124             }
1125         }
1126     }
1127
1128     return FALSE;
1129 }
1130
1131 void gmx_parse_gpu_ids(gmx_gpu_opt_t *gpu_opt)
1132 {
1133     char *env;
1134
1135     if (gpu_opt->gpu_id != NULL && !bGPUBinary)
1136     {
1137         gmx_fatal(FARGS, "GPU ID string set, but %s was compiled without GPU support!", ShortProgram());
1138     }
1139
1140     env = getenv("GMX_GPU_ID");
1141     if (env != NULL && gpu_opt->gpu_id != NULL)
1142     {
1143         gmx_fatal(FARGS, "GMX_GPU_ID and -gpu_id can not be used at the same time");
1144     }
1145     if (env == NULL)
1146     {
1147         env = gpu_opt->gpu_id;
1148     }
1149
1150     /* parse GPU IDs if the user passed any */
1151     if (env != NULL)
1152     {
1153         /* Parse a "plain" GPU ID string which contains a sequence of
1154          * digits corresponding to GPU IDs; the order will indicate
1155          * the process/tMPI thread - GPU assignment. */
1156         parse_digits_from_plain_string(env,
1157                                        &gpu_opt->n_dev_use,
1158                                        &gpu_opt->dev_use);
1159         if (!gmx_multiple_gpu_per_node_supported() && 1 < gpu_opt->n_dev_use)
1160         {
1161             gmx_fatal(FARGS, "The %s implementation only supports using exactly one PP rank per node", gpu_implementation);
1162         }
1163         if (!gmx_gpu_sharing_supported() && anyGpuIdIsRepeated(gpu_opt))
1164         {
1165             gmx_fatal(FARGS, "The %s implementation only supports using exactly one PP rank per GPU", gpu_implementation);
1166         }
1167         if (gpu_opt->n_dev_use == 0)
1168         {
1169             gmx_fatal(FARGS, "Empty GPU ID string encountered.\n%s\n",
1170                       invalid_gpuid_hint);
1171         }
1172
1173         gpu_opt->bUserSet = TRUE;
1174     }
1175 }
1176
1177 void gmx_select_gpu_ids(FILE *fplog, const t_commrec *cr,
1178                         const gmx_gpu_info_t *gpu_info,
1179                         gmx_bool bForceUseGPU,
1180                         gmx_gpu_opt_t *gpu_opt)
1181 {
1182     int              i;
1183     char             sbuf[STRLEN], stmp[STRLEN];
1184
1185     /* Bail if binary is not compiled with GPU acceleration, but this is either
1186      * explicitly (-nb gpu) or implicitly (gpu ID passed) requested. */
1187     if (bForceUseGPU && !bGPUBinary)
1188     {
1189         gmx_fatal(FARGS, "GPU acceleration requested, but %s was compiled without GPU support!", ShortProgram());
1190     }
1191
1192     if (!(cr->duty & DUTY_PP))
1193     {
1194         /* Our rank is not doing PP, we don't use a GPU */
1195         return;
1196     }
1197
1198     if (gpu_opt->bUserSet)
1199     {
1200         /* Check the GPU IDs passed by the user.
1201          * (GPU IDs have been parsed by gmx_parse_gpu_ids before)
1202          */
1203         int *checkres;
1204         int  res;
1205
1206         snew(checkres, gpu_opt->n_dev_use);
1207
1208         res = check_selected_gpus(checkres, gpu_info, gpu_opt);
1209
1210         if (!res)
1211         {
1212             print_gpu_detection_stats(fplog, gpu_info, cr);
1213
1214             sprintf(sbuf, "Some of the requested GPUs do not exist, behave strangely, or are not compatible:\n");
1215             for (i = 0; i < gpu_opt->n_dev_use; i++)
1216             {
1217                 if (checkres[i] != egpuCompatible)
1218                 {
1219                     sprintf(stmp, "    GPU #%d: %s\n",
1220                             gpu_opt->dev_use[i],
1221                             gpu_detect_res_str[checkres[i]]);
1222                     strcat(sbuf, stmp);
1223                 }
1224             }
1225             gmx_fatal(FARGS, "%s", sbuf);
1226         }
1227
1228         sfree(checkres);
1229     }
1230     else if (getenv("GMX_EMULATE_GPU") == NULL)
1231     {
1232         pick_compatible_gpus(&hwinfo_g->gpu_info, gpu_opt);
1233         set_gpu_ids(gpu_opt, cr->nrank_pp_intranode, cr->rank_pp_intranode);
1234     }
1235
1236     /* If the user asked for a GPU, check whether we have a GPU */
1237     if (bForceUseGPU && gpu_info->n_dev_compatible == 0)
1238     {
1239         gmx_fatal(FARGS, "GPU acceleration requested, but no compatible GPUs were detected.");
1240     }
1241 }
1242
1243 /* Select the GPUs we will use. This is an operation local to each physical
1244  * node. If we have less MPI ranks than GPUs, we will waste some GPUs.
1245  * nrank and rank are the rank count and id for PP processes in our node.
1246  */
1247 static void set_gpu_ids(gmx_gpu_opt_t *gpu_opt, int nrank, int rank)
1248 {
1249     GMX_RELEASE_ASSERT(gpu_opt, "Invalid gpu_opt pointer passed");
1250     GMX_RELEASE_ASSERT(nrank >= 1,
1251                        gmx::formatString("Invalid limit (%d) for the number of GPUs (detected %d compatible GPUs)",
1252                                          rank, gpu_opt->n_dev_compatible).c_str());
1253
1254     if (gpu_opt->n_dev_compatible == 0)
1255     {
1256         char host[HOSTNAMELEN];
1257
1258         gmx_gethostname(host, HOSTNAMELEN);
1259         gmx_fatal(FARGS, "A GPU was requested on host %s, but no compatible GPUs were detected. All nodes with PP ranks need to have GPUs. If you intended to use GPU acceleration in a parallel run, you can either avoid using the nodes that don't have GPUs or place PME ranks on these nodes.", host);
1260     }
1261
1262     int nshare;
1263
1264     nshare = 1;
1265     if (nrank > gpu_opt->n_dev_compatible)
1266     {
1267         if (nrank % gpu_opt->n_dev_compatible == 0)
1268         {
1269             nshare = gmx_gpu_sharing_supported() ? nrank/gpu_opt->n_dev_compatible : 1;
1270         }
1271         else
1272         {
1273             if (rank == 0)
1274             {
1275                 gmx_fatal(FARGS, "The number of MPI ranks (%d) in a physical node is not a multiple of the number of GPUs (%d). Select a different number of MPI ranks or use the -gpu_id option to manually specify the GPU to be used.",
1276                           nrank, gpu_opt->n_dev_compatible);
1277             }
1278
1279 #ifdef GMX_MPI
1280             /* We use a global barrier to prevent ranks from continuing with
1281              * an invalid setup.
1282              */
1283             MPI_Barrier(MPI_COMM_WORLD);
1284 #endif
1285         }
1286     }
1287
1288     /* Here we will waste GPUs when nrank < gpu_opt->n_dev_compatible */
1289     gpu_opt->n_dev_use = std::min(gpu_opt->n_dev_compatible*nshare, nrank);
1290     if (!gmx_multiple_gpu_per_node_supported())
1291     {
1292         gpu_opt->n_dev_use = std::min(gpu_opt->n_dev_use, 1);
1293     }
1294     snew(gpu_opt->dev_use, gpu_opt->n_dev_use);
1295     for (int i = 0; i != gpu_opt->n_dev_use; ++i)
1296     {
1297         /* TODO: improve this implementation: either sort GPUs or remove the weakest here */
1298         gpu_opt->dev_use[i] = gpu_opt->dev_compatible[i/nshare];
1299     }
1300 }
1301
1302 void gmx_hardware_info_free(gmx_hw_info_t *hwinfo)
1303 {
1304     int ret;
1305
1306     ret = tMPI_Thread_mutex_lock(&hw_info_lock);
1307     if (ret != 0)
1308     {
1309         gmx_fatal(FARGS, "Error locking hwinfo mutex: %s", strerror(errno));
1310     }
1311
1312     /* decrease the reference counter */
1313     n_hwinfo--;
1314
1315
1316     if (hwinfo != hwinfo_g)
1317     {
1318         gmx_incons("hwinfo < hwinfo_g");
1319     }
1320
1321     if (n_hwinfo < 0)
1322     {
1323         gmx_incons("n_hwinfo < 0");
1324     }
1325
1326     if (n_hwinfo == 0)
1327     {
1328         gmx_cpuid_done(hwinfo_g->cpuid_info);
1329         free_gpu_info(&hwinfo_g->gpu_info);
1330         sfree(hwinfo_g);
1331     }
1332
1333     ret = tMPI_Thread_mutex_unlock(&hw_info_lock);
1334     if (ret != 0)
1335     {
1336         gmx_fatal(FARGS, "Error unlocking hwinfo mutex: %s", strerror(errno));
1337     }
1338 }