gmx_string_hash_init;
/* Return a hash of the string according to Dan J. Bernsteins algorithm.
- * This routine only uses characters for which isalnum(c) is true,
- * and all characters are converted to upper case.
* On the first invocation for a new string, use the constant
* gmx_string_hash_init for the second argument. If you want to create a hash
* corresponding to several concatenated strings, provide the returned hash
* value as hash_init for the second string, etc.
*/
unsigned int
+gmx_string_fullhash_func(const char *s, unsigned int hash_init);
+
+/* Identical to gmx_string_fullhash_func, except that
+ * this routine only uses characters for which isalnum(c) is true,
+ * and all characters are converted to upper case.
+ */
+unsigned int
gmx_string_hash_func(const char *s, unsigned int hash_init);
/** Pattern matcing with wildcards. */
return ret;
}
+static void gmx_detect_gpus(FILE *fplog, const t_commrec *cr,
+ gmx_gpu_info_t *gpu_info)
+{
+#ifdef GMX_LIB_MPI
+ int rank_world;
+ MPI_Comm physicalnode_comm;
+#endif
+ int rank_local;
+
+ /* Under certain circumstances MPI ranks on the same physical node
+ * can not simultaneously access the same GPU(s). Therefore we run
+ * the detection only on one MPI rank per node and broadcast the info.
+ * Note that with thread-MPI only a single thread runs this code.
+ *
+ * TODO: We should also do CPU hardware detection only once on each
+ * physical node and broadcast it, instead of do it on every MPI rank.
+ */
+#ifdef GMX_LIB_MPI
+ /* A split of MPI_COMM_WORLD over physical nodes is only required here,
+ * so we create and destroy it locally.
+ */
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank_world);
+ MPI_Comm_split(MPI_COMM_WORLD, gmx_physicalnode_id_hash(),
+ rank_world, &physicalnode_comm);
+ MPI_Comm_rank(physicalnode_comm, &rank_local);
+#else
+ /* Here there should be only one process, check this */
+ assert(cr->nnodes == 1 && cr->sim_nodeid == 0);
+
+ rank_local = 0;
+#endif
+
+ if (rank_local == 0)
+ {
+ char detection_error[STRLEN], sbuf[STRLEN];
+
+ if (detect_cuda_gpus(&hwinfo_g->gpu_info, detection_error) != 0)
+ {
+ if (detection_error != NULL && detection_error[0] != '\0')
+ {
+ sprintf(sbuf, ":\n %s\n", detection_error);
+ }
+ else
+ {
+ sprintf(sbuf, ".");
+ }
+ md_print_warn(cr, fplog,
+ "NOTE: Error occurred during GPU detection%s"
+ " Can not use GPU acceleration, will fall back to CPU kernels.\n",
+ sbuf);
+ }
+ }
+
+#ifdef GMX_LIB_MPI
+ /* Broadcast the GPU info to the other ranks within this node */
+ MPI_Bcast(&hwinfo_g->gpu_info.ncuda_dev, 1, MPI_INT, 0, physicalnode_comm);
+
+ if (hwinfo_g->gpu_info.ncuda_dev > 0)
+ {
+ int cuda_dev_size;
+
+ cuda_dev_size = hwinfo_g->gpu_info.ncuda_dev*sizeof_cuda_dev_info();
+
+ if (rank_local > 0)
+ {
+ hwinfo_g->gpu_info.cuda_dev =
+ (cuda_dev_info_ptr_t)malloc(cuda_dev_size);
+ }
+ MPI_Bcast(hwinfo_g->gpu_info.cuda_dev, cuda_dev_size, MPI_BYTE,
+ 0, physicalnode_comm);
+ MPI_Bcast(&hwinfo_g->gpu_info.ncuda_dev_compatible, 1, MPI_INT,
+ 0, physicalnode_comm);
+ }
+
+ MPI_Comm_free(&physicalnode_comm);
+#endif
+}
+
gmx_hw_info_t *gmx_detect_hardware(FILE *fplog, const t_commrec *cr,
gmx_bool bDetectGPUs)
{
- char sbuf[STRLEN];
gmx_hw_info_t *hw;
- gmx_gpu_info_t gpuinfo_auto, gpuinfo_user;
int ret;
/* make sure no one else is doing the same thing */
getenv("GMX_DISABLE_GPU_DETECTION") == NULL);
if (hwinfo_g->gpu_info.bDetectGPUs)
{
- char detection_error[STRLEN];
-
- if (detect_cuda_gpus(&hwinfo_g->gpu_info, detection_error) != 0)
- {
- if (detection_error != NULL && detection_error[0] != '\0')
- {
- sprintf(sbuf, ":\n %s\n", detection_error);
- }
- else
- {
- sprintf(sbuf, ".");
- }
- md_print_warn(cr, fplog,
- "NOTE: Error occurred during GPU detection%s"
- " Can not use GPU acceleration, will fall back to CPU kernels.\n",
- sbuf);
- }
+ gmx_detect_gpus(fplog, cr, &hwinfo_g->gpu_info);
}
}
/* increase the reference counter */
#include "statutil.h"
#include <ctype.h>
#include "macros.h"
+#include "string2.h"
#ifdef GMX_LIB_MPI
#include <mpi.h>
#include <spi/include/kernel/location.h>
#endif
+int gmx_physicalnode_id_hash(void)
+{
+ int hash_int;
+
+#ifndef GMX_LIB_MPI
+ /* We have a single physical node */
+ hash_int = 0;
+#else
+ int resultlen;
+ char mpi_hostname[MPI_MAX_PROCESSOR_NAME];
+
+ /* This procedure can only differentiate nodes with different names.
+ * Architectures where different physical nodes have identical names,
+ * such as IBM Blue Gene, should use an architecture specific solution.
+ */
+ MPI_Get_processor_name(mpi_hostname, &resultlen);
+
+ /* The string hash function returns an unsigned int. We cast to an int.
+ * Negative numbers are converted to positive by setting the sign bit to 0.
+ * This makes the hash one bit smaller.
+ * A 63-bit hash (with 64-bit int) should be enough for unique node hashes,
+ * even on a million node machine. 31 bits might not be enough though!
+ */
+ hash_int =
+ (int)gmx_string_fullhash_func(mpi_hostname, gmx_string_hash_init);
+ if (hash_int < 0)
+ {
+ hash_int -= INT_MIN;
+ }
+#endif
+
+ return hash_int;
+}
+
+/* TODO: this function should be fully replaced by gmx_physicalnode_id_hash */
int gmx_hostname_num()
{
#ifndef GMX_MPI