+static std::string detected_hardware_string(const gmx_hw_info_t *hwinfo,
+ bool bFullCpuInfo)
+{
+ std::string s;
+
+ s = gmx::formatString("\n");
+ s += gmx::formatString("Running on %d node%s with total",
+ hwinfo->nphysicalnode,
+ hwinfo->nphysicalnode == 1 ? "" : "s");
+ if (hwinfo->ncore_tot > 0)
+ {
+ s += gmx::formatString(" %d cores,", hwinfo->ncore_tot);
+ }
+ s += gmx::formatString(" %d hardware threads", hwinfo->nhwthread_tot);
+ if (hwinfo->gpu_info.bDetectGPUs)
+ {
+ s += gmx::formatString(", %d compatible GPU%s",
+ hwinfo->ngpu_compatible_tot,
+ hwinfo->ngpu_compatible_tot == 1 ? "" : "s");
+ }
+ else if (bGPUBinary)
+ {
+ s += gmx::formatString(" (GPU detection deactivated)");
+ }
+ s += gmx::formatString("\n");
+
+ if (hwinfo->nphysicalnode > 1)
+ {
+ /* Print per node hardware feature counts */
+ if (hwinfo->ncore_max > 0)
+ {
+ s += gmx::formatString("Cores per node: %2d", hwinfo->ncore_min);
+ if (hwinfo->ncore_max > hwinfo->ncore_min)
+ {
+ s += gmx::formatString(" - %2d", hwinfo->ncore_max);
+ }
+ s += gmx::formatString("\n");
+ }
+ s += gmx::formatString("Hardware threads per node: %2d", hwinfo->nhwthread_min);
+ if (hwinfo->nhwthread_max > hwinfo->nhwthread_min)
+ {
+ s += gmx::formatString(" - %2d", hwinfo->nhwthread_max);
+ }
+ s += gmx::formatString("\n");
+ if (bGPUBinary)
+ {
+ s += gmx::formatString("Compatible GPUs per node: %2d",
+ hwinfo->ngpu_compatible_min);
+ if (hwinfo->ngpu_compatible_max > hwinfo->ngpu_compatible_min)
+ {
+ s += gmx::formatString(" - %2d", hwinfo->ngpu_compatible_max);
+ }
+ s += gmx::formatString("\n");
+ if (hwinfo->ngpu_compatible_tot > 0)
+ {
+ if (hwinfo->bIdenticalGPUs)
+ {
+ s += gmx::formatString("All nodes have identical type(s) of GPUs\n");
+ }
+ else
+ {
+ /* This message will also appear with identical GPU types
+ * when at least one node has no GPU.
+ */
+ s += gmx::formatString("Different nodes have different type(s) and/or order of GPUs\n");
+ }
+ }
+ }
+ }
+
+#ifdef GMX_LIB_MPI
+ char host[255];
+ int rank;
+
+ gmx_gethostname(host, 255);
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+ s += gmx::formatString("Hardware detected on host %s (the node of MPI rank %d):\n",
+ host, rank);
+#else
+ s += gmx::formatString("Hardware detected:\n");
+#endif
+ s += gmx::formatString(" CPU info:\n");
+ if (bFullCpuInfo)
+ {
+ char buf[1024];
+
+ gmx_cpuid_formatstring(hwinfo->cpuid_info, buf, 1023);
+ buf[1023] = '\0';
+
+ s += gmx::formatString("%s", buf);
+ }
+ else
+ {
+ s += gmx::formatString(" Vendor: %s\n",
+ gmx_cpuid_vendor_string[gmx_cpuid_vendor(hwinfo->cpuid_info)]);
+ s += gmx::formatString(" Brand: %s\n",
+ gmx_cpuid_brand(hwinfo->cpuid_info));
+ }
+ s += gmx::formatString(" SIMD instructions most likely to fit this hardware: %s",
+ gmx_cpuid_simd_string[hwinfo->simd_suggest_min]);
+ if (hwinfo->simd_suggest_max > hwinfo->simd_suggest_min)
+ {
+ s += gmx::formatString(" - %s",
+ gmx_cpuid_simd_string[hwinfo->simd_suggest_max]);
+ }
+ s += gmx::formatString("\n");
+ s += gmx::formatString(" SIMD instructions selected at GROMACS compile time: %s\n",
+ gmx_cpuid_simd_string[gmx_compiled_simd()]);
+ if (bGPUBinary && (hwinfo->ngpu_compatible_tot > 0 ||
+ hwinfo->gpu_info.n_dev > 0))
+ {
+ s += gmx::formatString(" GPU info:\n");
+ s += gmx::formatString(" Number of GPUs detected: %d\n",
+ hwinfo->gpu_info.n_dev);
+ if (hwinfo->gpu_info.n_dev > 0)
+ {
+ char buf[STRLEN];
+
+ sprint_gpus(buf, &hwinfo->gpu_info);
+ s += gmx::formatString("%s\n", buf);
+ }
+ }
+
+ return s;
+}
+
+void gmx_print_detected_hardware(FILE *fplog, const t_commrec *cr,
+ const gmx_hw_info_t *hwinfo)
+{
+ if (fplog != NULL)
+ {
+ std::string detected;
+
+ detected = detected_hardware_string(hwinfo, TRUE);
+
+ fprintf(fplog, "%s\n", detected.c_str());
+ }
+
+ if (MULTIMASTER(cr))
+ {
+ std::string detected;
+
+ detected = detected_hardware_string(hwinfo, FALSE);
+
+ fprintf(stderr, "%s\n", detected.c_str());
+ }
+
+ /* Check the compiled SIMD instruction set against that of the node
+ * with the lowest SIMD level support.
+ */
+ gmx_cpuid_simd_check(hwinfo->simd_suggest_min, fplog, MULTIMASTER(cr));
+
+ /* For RDTSCP we only check on our local node and skip the MPI reduction */
+ check_use_of_rdtscp_on_this_cpu(fplog, cr, hwinfo);
+}
+