Implement parse_digits_from_csv_string
authorRobert McGibbon <rmcgibbo@gmail.com>
Wed, 14 Oct 2015 08:36:46 +0000 (01:36 -0700)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Wed, 9 Dec 2015 03:03:40 +0000 (04:03 +0100)
Allow -gpu_id and GMX_GPU_ID to use a comma separated list of digits,
to support specification of >10 GPUs per node.

Change-Id: I62e6b54476efadd24aef00ed63d29c98e4d15c38

src/gromacs/gmxana/gmx_tune_pme.cpp
src/gromacs/gmxlib/gmx_detect_hardware.cpp
src/gromacs/utility/cstringutil.cpp
src/gromacs/utility/cstringutil.h

index 35b6ed00db9e44d285397e8d0c6c26dc7b87feb1..663fcb93c9abe37c5252238cf69dec8cbabd9446 100644 (file)
@@ -2455,7 +2455,7 @@ int gmx_tune_pme(int argc, char *argv[])
                 asize(pa), pa);
     /* Check any GPU IDs passed make sense, and fill the data structure for them */
     snew(gpu_ids, 1);
-    parse_digits_from_plain_string(eligible_gpu_ids, &gpu_ids->n, &gpu_ids->ids);
+    parse_digits_from_string(eligible_gpu_ids, &gpu_ids->n, &gpu_ids->ids);
 
     /* Determine the maximum and minimum number of PME nodes to test,
      * the actual list of settings is build in do_the_tests(). */
index 0ca346bb1df97a63f5f160cbfeed27d710528a90..89cb1f5db5294c7e301c8d387336164e9b7e3443 100644 (file)
@@ -1176,12 +1176,11 @@ void gmx_parse_gpu_ids(gmx_gpu_opt_t *gpu_opt)
     /* parse GPU IDs if the user passed any */
     if (env != NULL)
     {
-        /* Parse a "plain" GPU ID string which contains a sequence of
-         * digits corresponding to GPU IDs; the order will indicate
-         * the process/tMPI thread - GPU assignment. */
-        parse_digits_from_plain_string(env,
-                                       &gpu_opt->n_dev_use,
-                                       &gpu_opt->dev_use);
+        /* Parse a "plain" or comma-separated GPU ID string which contains a
+         * sequence of digits corresponding to GPU IDs; the order will
+         * indicate the process/tMPI thread - GPU assignment. */
+        parse_digits_from_string(env, &gpu_opt->n_dev_use, &gpu_opt->dev_use);
+
         if (!gmx_multiple_gpu_per_node_supported() && 1 < gpu_opt->n_dev_use)
         {
             gmx_fatal(FARGS, "The %s implementation only supports using exactly one PP rank per node", getGpuImplementationString());
index b73c15a89314b793bb2ca442fa68f41f5f8d2b53..d5bfbf388961e53f29fe44a9f640d6c9a4ea151c 100644 (file)
 #include <cctype>
 #include <cstring>
 
+#include <sstream>
+#include <string>
+#include <vector>
+
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
@@ -537,6 +541,18 @@ char *gmx_step_str(gmx_int64_t i, char *buf)
     return buf;
 }
 
+void parse_digits_from_string(const char *digitstring, int *ndigits, int **digitlist)
+{
+    if (strstr(digitstring, ",") != NULL)
+    {
+        parse_digits_from_csv_string(digitstring, ndigits, digitlist);
+    }
+    else
+    {
+        parse_digits_from_plain_string(digitstring, ndigits, digitlist);
+    }
+}
+
 void parse_digits_from_plain_string(const char *digitstring, int *ndigits, int **digitlist)
 {
     int i;
@@ -562,3 +578,34 @@ void parse_digits_from_plain_string(const char *digitstring, int *ndigits, int *
         (*digitlist)[i] = digitstring[i] - '0';
     }
 }
+
+void parse_digits_from_csv_string(const char *digitstring, int *ndigits, int **digitlist)
+{
+    if (NULL == digitstring)
+    {
+        *ndigits   = 0;
+        *digitlist = NULL;
+        return;
+    }
+
+    std::vector<int>   digits;
+    std::istringstream ss(digitstring);
+    std::string        token;
+    while (std::getline(ss, token, ','))
+    {
+        if (token.find_first_not_of("0123456789") != std::string::npos)
+        {
+            gmx_fatal(FARGS, "Invalid token in digit-only string: \"%s\"\n",
+                      token.c_str());
+        }
+        int number = static_cast<int>(str_to_int64_t(token.c_str(), NULL));
+        digits.push_back(number);
+    }
+
+    *ndigits = digits.size();
+    snew(*digitlist, *ndigits);
+    for (size_t i = 0; i < digits.size(); i++)
+    {
+        (*digitlist)[i] = digits[i];
+    }
+}
index fabe7788246016d7b5def483380800882c3ca9cf..44f6012500776de136e848c46924bce35a2471a6 100644 (file)
@@ -206,6 +206,37 @@ char *gmx_step_str(gmx_int64_t i, char *buf);
  */
 void parse_digits_from_plain_string(const char *digitstring, int *ndigits, int **digitlist);
 
+/*! \brief Construct an array of digits from a comma separated input string
+ *
+ * \param[in]  digitstring  String that must contain only digits and commas
+ * \param[out] ndigits      Size of return array with the values of the digits
+ * \param[out] digitlist    Array of digits found in
+ *                          digitstring. Allocated by this function
+ *                          with size *ndigits. Calling code is
+ *                          responsible for deallocation.
+ *
+ * If digitstring is NULL, then ndigits is set to zero and digitlist
+ * to NULL. If digitstring contains a non digit-or-comma character, a fatal
+ * error results.
+ */
+void parse_digits_from_csv_string(const char *digitstring, int *ndigits, int **digitlist);
+
+/*! \brief Construct an array of digits an input string
+ *
+ *
+ * \param[in]  digitstring  String that must contain only digits, or only
+ *                          digits and commas
+ * \param[out] ndigits      Size of return array with the values of the digits
+ * \param[out] digitlist    Array of digits found in
+ *                          digitstring. Allocated by this function
+ *                          with size *ndigits. Calling code is
+ *                          responsible for deallocation.
+ * If digitstring is NULL, then ndigits is set to zero and digitlist
+ * to NULL. If digitstring contains a non digit-or-comma character, a fatal
+ * error results.
+ */
+void parse_digits_from_string(const char *digitstring, int *ndigits, int **digitlist);
+
 #ifdef __cplusplus
 }
 #endif