Remove some utility -> legacyheaders dependencies
authorTeemu Murtola <teemu.murtola@gmail.com>
Sat, 5 Apr 2014 17:59:21 +0000 (20:59 +0300)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Tue, 8 Apr 2014 16:52:24 +0000 (18:52 +0200)
- Use methods in programcontext.h and baseversion.h instead of
  copyrite.h within utility/.
- Replace one use of asize() with an alternative implementation that
  doesn't require an explicit array size.
- Don't pass the whole hw_opt structure to the OpenMP thread affinity
  check, when only a single field is ever accessed.
- Don't call md_print_warn() from gmx_omp_check_thread_affinity(), but
  provide the message to the caller so that they can print it.

For the last two, the rationale is that if this function needs to be in
a generic OpenMP wrapper (which makes sense, since it requires in-depth
information about the actual OpenMP library), then it shouldn't depend
on any mdrun-specific code.

Change-Id: Icc8f4026e4a2ce8e5d533a5bb88e5f3dddcc9a4a

src/gromacs/gmxlib/gmx_omp_nthreads.c
src/gromacs/gmxlib/gmx_thread_affinity.c
src/gromacs/legacyheaders/gmx_thread_affinity.h
src/gromacs/mdlib/clincs.c
src/gromacs/mdlib/vsite.c
src/gromacs/utility/fatalerror.cpp [moved from src/gromacs/utility/fatalerror.c with 93% similarity]
src/gromacs/utility/gmxomp.cpp
src/gromacs/utility/gmxomp.h
src/programs/mdrun/runner.c

index 9407bd7f8c838ae1ab1c21d3614e51afdc8cabfe..1bc4944b63f3598a62a2078e2c7f57ba72d3c85f 100644 (file)
@@ -44,6 +44,7 @@
 
 #include "gromacs/utility/fatalerror.h"
 #include "typedefs.h"
+#include "types/commrec.h"
 #include "macros.h"
 #include "network.h"
 #include "copyrite.h"
index 64a68d1fa483de20a9bd7b7ffbad1f19a37c308a..8c35b8e7f022c85c5f9e26a4f9e7860d3acec6d1 100644 (file)
 #include "gmx_omp_nthreads.h"
 #include "md_logging.h"
 #include "gmx_thread_affinity.h"
+#include "network.h"
 
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxomp.h"
+#include "gromacs/utility/smalloc.h"
 
 static int
 get_thread_affinity_layout(FILE *fplog,
@@ -368,18 +370,53 @@ gmx_set_thread_affinity(FILE                *fplog,
  * Note that this will only work on Linux as we use a GNU feature.
  */
 void
-gmx_check_thread_affinity_set(FILE            gmx_unused *fplog,
-                              const t_commrec gmx_unused *cr,
-                              gmx_hw_opt_t    gmx_unused *hw_opt,
-                              int             gmx_unused  ncpus,
-                              gmx_bool        gmx_unused  bAfterOpenmpInit)
+gmx_check_thread_affinity_set(FILE            *fplog,
+                              const t_commrec *cr,
+                              gmx_hw_opt_t    *hw_opt,
+                              int  gmx_unused  ncpus,
+                              gmx_bool         bAfterOpenmpInit)
 {
 #ifdef HAVE_SCHED_GETAFFINITY
     cpu_set_t mask_current;
     int       i, ret, cpu_count, cpu_set;
     gmx_bool  bAllSet;
+#endif
 
     assert(hw_opt);
+    if (!bAfterOpenmpInit)
+    {
+        /* Check for externally set OpenMP affinity and turn off internal
+         * pinning if any is found. We need to do this check early to tell
+         * thread-MPI whether it should do pinning when spawning threads.
+         * TODO: the above no longer holds, we should move these checks later
+         */
+        if (hw_opt->thread_affinity != threadaffOFF)
+        {
+            char *message;
+            if (!gmx_omp_check_thread_affinity(&message))
+            {
+                /* TODO: with -pin auto we should only warn when using all cores */
+                md_print_warn(cr, fplog, "%s", message);
+                sfree(message);
+                hw_opt->thread_affinity = threadaffOFF;
+            }
+        }
+
+        /* With thread-MPI this is needed as pinning might get turned off,
+         * which needs to be known before starting thread-MPI.
+         * With thread-MPI hw_opt is processed here on the master rank
+         * and passed to the other ranks later, so we only do this on master.
+         */
+        if (!SIMMASTER(cr))
+        {
+            return;
+        }
+#ifndef GMX_THREAD_MPI
+        return;
+#endif
+    }
+
+#ifdef HAVE_SCHED_GETAFFINITY
     if (hw_opt->thread_affinity == threadaffOFF)
     {
         /* internal affinity setting is off, don't bother checking process affinity */
index 2ee5cfd4e328b03611cfcfa95339586b03d145b0..5ac0bb54c5186b415e4afb31cf796e4e0e75fef5 100644 (file)
@@ -34,6 +34,7 @@
  */
 #ifndef GMX_THREAD_AFFINITY_H_
 #define GMX_THREAD_AFFINITY_H_
+
 #include "typedefs.h"
 
 #ifdef __cplusplus
@@ -61,6 +62,8 @@ gmx_set_thread_affinity(FILE                *fplog,
  * made by the OpenMP library.
  *
  * Note that this will only work on Linux as we use a GNU feature.
+ * With bAfterOpenmpInit false, it will also detect whether OpenMP environment
+ * variables for setting the affinity are set.
  */
 void
 gmx_check_thread_affinity_set(FILE *fplog, const t_commrec *cr,
index 298eea4a59ed63e2238d9483c50342f4f61f123c..f72ba47528c7729e645efc932c5527068c09c14e 100644 (file)
@@ -40,6 +40,8 @@
 #endif
 
 #include <math.h>
+
+#include "types/commrec.h"
 #include "main.h"
 #include "constr.h"
 #include "copyrite.h"
index 7ad217f4a5cae44f14ecd28358ec664185f51b3e..c41dacff63842baef82a04599a9bdabfbe54efe7 100644 (file)
@@ -39,7 +39,9 @@
 #endif
 
 #include <stdio.h>
+
 #include "typedefs.h"
+#include "types/commrec.h"
 #include "vsite.h"
 #include "macros.h"
 #include "gromacs/utility/smalloc.h"
similarity index 93%
rename from src/gromacs/utility/fatalerror.c
rename to src/gromacs/utility/fatalerror.cpp
index 2c1171ef67ced6bbfa35ba530e87948f1b96cefc..0901d89d3227f6507aa6bd6ba07fc798aeb01d3d 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#include <exception>
+
 #include "thread_mpi/threads.h"
 
 #include "gromacs/legacyheaders/types/commrec.h"
-#include "gromacs/legacyheaders/copyrite.h"
-#include "gromacs/legacyheaders/macros.h"
 #include "gromacs/legacyheaders/network.h"
 
 #include "gromacs/fileio/futil.h"
 #include "gromacs/fileio/gmxfio.h"
+#include "gromacs/utility/baseversion.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/gmxmpi.h"
+#include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/smalloc.h"
 
 static gmx_bool            bDebug         = FALSE;
@@ -68,14 +70,6 @@ static tMPI_Thread_mutex_t where_mutex     = TMPI_THREAD_MUTEX_INITIALIZER;
 
 gmx_bool bDebugMode(void)
 {
-    gmx_bool ret;
-#if 0
-    tMPI_Thread_mutex_lock(&debug_mutex);
-#endif
-    ret = bDebug;
-#if 0
-    tMPI_Thread_mutex_unlock(&debug_mutex);
-#endif
     return bDebug;
 }
 
@@ -252,15 +246,12 @@ void gmx_fatal_collective(int f_errno, const char *file, int line,
                           const t_commrec *cr, gmx_domdec_t *dd,
                           const char *fmt, ...)
 {
-    gmx_bool    bFinalize;
     va_list     ap;
     char        msg[STRLEN];
 #ifdef GMX_MPI
     int         result;
 #endif
 
-    bFinalize = TRUE;
-
 #ifdef GMX_MPI
     /* Check if we are calling on all processes in MPI_COMM_WORLD */
     if (cr != NULL)
@@ -272,7 +263,9 @@ void gmx_fatal_collective(int f_errno, const char *file, int line,
         MPI_Comm_compare(dd->mpi_comm_all, MPI_COMM_WORLD, &result);
     }
     /* Any result except MPI_UNEQUAL allows us to call MPI_Finalize */
-    bFinalize = (result != MPI_UNEQUAL);
+    const bool bFinalize = (result != MPI_UNEQUAL);
+#else
+    const bool bFinalize = true;
 #endif
 
     if ((cr != NULL && MASTER(cr)  ) ||
@@ -375,11 +368,9 @@ char *gmx_strerror(const char *key)
         { "input",  "Input error or input inconsistency" },
         { "mem",    "Memory allocation/freeing error" },
         { "open",   "Can not open file" },
-        { "range",  "Range checking error" }
+        { "range",  "Range checking error" },
+        { NULL,     NULL}
     };
-#define NMSG asize(msg)
-    char        buf[1024];
-    size_t      i;
 
     if (key == NULL)
     {
@@ -387,22 +378,16 @@ char *gmx_strerror(const char *key)
     }
     else
     {
-        for (i = 0; (i < NMSG); i++)
+        for (size_t i = 0; msg[i].key != NULL; ++i)
         {
             if (strcmp(key, msg[i].key) == 0)
             {
-                break;
+                return strdup(msg[i].msg);
             }
         }
-        if (i == NMSG)
-        {
-            sprintf(buf, "No error message associated with key %s\n%s", key, gmxuser);
-            return strdup(buf);
-        }
-        else
-        {
-            return strdup(msg[i].msg);
-        }
+        char buf[1024];
+        sprintf(buf, "No error message associated with key %s\n%s", key, gmxuser);
+        return strdup(buf);
     }
 }
 
@@ -419,13 +404,23 @@ void _gmx_error(const char *key, const char *msg, const char *file, int line)
     {
         sprintf(errerrbuf, "Empty fatal_error message. %s", gmxuser);
     }
+    // In case ProgramInfo is not initialized and there is an issue with the
+    // initialization, fall back to "GROMACS".
+    const char *programName = "GROMACS";
+    try
+    {
+        programName = gmx::getProgramContext().displayName();
+    }
+    catch (const std::exception &)
+    {
+    }
 
     strerr = gmx_strerror(key);
     sprintf(buf, "\n%s\nProgram %s, %s\n"
             "Source code file: %s, line: %d\n\n"
             "%s:\n%s\nFor more information and tips for troubleshooting, please check the GROMACS\n"
             "website at http://www.gromacs.org/Documentation/Errors\n%s\n",
-            llines, ShortProgram(), GromacsVersion(), file, line,
+            llines, programName, gmx_version(), file, line,
             strerr, msg ? msg : errerrbuf, llines);
     free(strerr);
 
index a258481f237af32ebe944ae79c5aa14395adb8f1..7da093b53461450e7a8bf3ff9d177b57085ae704 100644 (file)
 #include "config.h"
 
 #include <stdio.h>
+#include <stdlib.h>
 
 #ifdef GMX_OPENMP
 #include <omp.h>
 #endif
 
-#include "gromacs/legacyheaders/copyrite.h"
-#include "gromacs/legacyheaders/md_logging.h"
-
 #include "gromacs/utility/common.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/programcontext.h"
+#include "gromacs/utility/stringutil.h"
 
 int gmx_omp_get_max_threads(void)
 {
@@ -91,58 +92,41 @@ void gmx_omp_set_num_threads(int num_threads)
 #endif
 }
 
-/*!
- * Thread affinity set by the OpenMP library can conflict with the GROMACS
- * internal affinity setting.
- *
- * While GNU OpenMP does not set affinity by default, the Intel OpenMP library
- * does. This conflicts with the internal affinity (especially thread-MPI)
- * setting, results in incorrectly locked threads, and causes dreadful performance.
- *
- * The KMP_AFFINITY environment variable is used by Intel, GOMP_CPU_AFFINITY
- * by the GNU compilers (Intel also honors it well). If any of the variables
- * is set, we honor it, disable the internal pinning, and warn the user.
- * When using Intel OpenMP, we will disable affinity if the user did not set it
- * anually through one of the aforementioned environment variables.
- *
- * Note that the Intel OpenMP affinity disabling iwll only take effect if this
- * function is called before the OpenMP library gets initialized which happens
- * when the first call is made into a compilation unit that contains OpenMP
- * pragmas.
- */
-void gmx_omp_check_thread_affinity(FILE            *fplog,
-                                   const t_commrec *cr,
-                                   gmx_hw_opt_t    *hw_opt)
+gmx_bool gmx_omp_check_thread_affinity(char **message)
 {
-    /* no need to worry if internal thread pinning is turned off */
-    if (hw_opt->thread_affinity == threadaffOFF)
-    {
-        return;
-    }
+    bool shouldSetAffinity = true;
 
-#ifndef GMX_OPENMP
-    GMX_UNUSED_VALUE(fplog);
-    GMX_UNUSED_VALUE(cr);
-#else
+    *message = NULL;
+#ifdef GMX_OPENMP
     /* We assume that the affinity setting is available on all platforms
      * gcc supports. Even if this is not the case (e.g. Mac OS) the user
      * will only get a warning. */
 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
+    const char *programName;
+    try
+    {
+        programName = gmx::getProgramContext().displayName();
+    }
+    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+
     const char *const gomp_env            = getenv("GOMP_CPU_AFFINITY");
     const bool        bGompCpuAffinitySet = (gomp_env != NULL);
 
     /* turn off internal pinning if GOMP_CPU_AFFINITY is set & non-empty */
     if (bGompCpuAffinitySet && *gomp_env != '\0')
     {
-        /* TODO: with -pin auto we should only warn when using all cores */
-        md_print_warn(cr, fplog,
-                      "NOTE: GOMP_CPU_AFFINITY set, will turn off %s internal affinity\n"
-                      "      setting as the two can conflict and cause performance degradation.\n"
-                      "      To keep using the %s internal affinity setting, unset the\n"
-                      "      GOMP_CPU_AFFINITY environment variable.",
-                      ShortProgram(), ShortProgram());
-
-        hw_opt->thread_affinity = threadaffOFF;
+        try
+        {
+            std::string buf = gmx::formatString(
+                        "NOTE: GOMP_CPU_AFFINITY set, will turn off %s internal affinity\n"
+                        "      setting as the two can conflict and cause performance degradation.\n"
+                        "      To keep using the %s internal affinity setting, unset the\n"
+                        "      GOMP_CPU_AFFINITY environment variable.",
+                        programName, programName);
+            *message = gmx_strdup(buf.c_str());
+        }
+        GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+        shouldSetAffinity = false;
     }
 #endif /* __GNUC__ || __INTEL_COMPILER */
 
@@ -178,17 +162,21 @@ void gmx_omp_check_thread_affinity(FILE            *fplog,
     /* turn off internal pinning KMP_AFFINITY != "disabled" */
     if (bKmpAffinitySet && (gmx_strncasecmp(kmp_env, "disabled", 8) != 0))
     {
-        /* TODO: with -pin auto we should only warn when using all cores */
-        md_print_warn(cr, fplog,
-                      "NOTE: KMP_AFFINITY set, will turn off %s internal affinity\n"
-                      "      setting as the two can conflict and cause performance degradation.\n"
-                      "      To keep using the %s internal affinity setting, set the\n"
-                      "      KMP_AFFINITY=disabled environment variable.",
-                      ShortProgram(), ShortProgram());
-
-        hw_opt->thread_affinity = threadaffOFF;
+        try
+        {
+            std::string buf = gmx::formatString(
+                        "NOTE: KMP_AFFINITY set, will turn off %s internal affinity\n"
+                        "      setting as the two can conflict and cause performance degradation.\n"
+                        "      To keep using the %s internal affinity setting, set the\n"
+                        "      KMP_AFFINITY=disabled environment variable.",
+                        programName, programName);
+            *message = gmx_strdup(buf.c_str());
+        }
+        GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+        shouldSetAffinity = false;
     }
 #endif /* __INTEL_COMPILER */
 
 #endif /* GMX_OPENMP */
+    return shouldSetAffinity;
 }
index af11cac918acdcc739daba306f3a41e8865c0f1a..9b5303b05b22f82a7d9d7edd250e9b9bfc404aad 100644 (file)
@@ -53,6 +53,8 @@
 #include "config.h"
 #endif
 
+#include <stdio.h>
+
 #ifndef GMX_NATIVE_WINDOWS
 /* Ugly hack because the openmp implementation below hacks into the SIMD
  * settings to decide when to use _mm_pause(). This should eventually be
@@ -67,8 +69,7 @@
 #include <windows.h>
 #endif
 
-#include "types/commrec.h"
-#include "mdrun.h"
+#include "gromacs/legacyheaders/types/simple.h"
 
 #ifdef __cplusplus
 extern "C"
@@ -113,9 +114,31 @@ void gmx_omp_set_num_threads(int num_threads);
 /*! \brief
  * Check for externally set thread affinity to avoid conflicts with \Gromacs
  * internal setting.
+ *
+ * \param[out] message  Receives the message to be shown to the user.
+ * \returns `true` if we can set thread affinity ourselves.
+ *
+ * While GNU OpenMP does not set affinity by default, the Intel OpenMP library
+ * does.  This conflicts with the internal affinity (especially thread-MPI)
+ * setting, results in incorrectly locked threads, and causes dreadful performance.
+ *
+ * The KMP_AFFINITY environment variable is used by Intel, GOMP_CPU_AFFINITY
+ * by the GNU compilers (Intel also honors it well).  If any of the variables
+ * is set, we should honor it and disable the internal pinning.
+ * When using Intel OpenMP, we will disable affinity if the user did not set it
+ * manually through one of the aforementioned environment variables.
+ *
+ * Note that the Intel OpenMP affinity disabling will only take effect if this
+ * function is called before the OpenMP library gets initialized, which happens
+ * when the first call is made into a compilation unit that contains OpenMP
+ * pragmas.
+ *
+ * If this function returns `false`, the caller is responsible to disable the
+ * pinning, show the message from \p *message to the user, and free the memory
+ * allocated for \p *message.
+ * If the return value is `true`, \p *message is NULL.
  */
-void gmx_omp_check_thread_affinity(FILE *fplog, const t_commrec *cr,
-                                   gmx_hw_opt_t *hw_opt);
+gmx_bool gmx_omp_check_thread_affinity(char **message);
 
 /*! \brief
  * Pause for use in a spin-wait loop.
index a0d7b7f8a4eb3f811424b7b5416f01511a03fa71..d4c7d5fb4a7e372cc76bac029d6ad62ffd2e202d 100644 (file)
@@ -84,7 +84,6 @@
 #include "gromacs/mdlib/nbnxn_consts.h"
 #include "gromacs/timing/wallcycle.h"
 #include "gromacs/utility/gmxmpi.h"
-#include "gromacs/utility/gmxomp.h"
 #include "gromacs/swap/swapcoords.h"
 #include "gromacs/essentialdynamics/edsam.h"
 #include "gromacs/pulling/pull.h"
@@ -1204,29 +1203,14 @@ int mdrunner(gmx_hw_opt_t *hw_opt,
         }
     }
 
-    /* Check for externally set OpenMP affinity and turn off internal
-     * pinning if any is found. We need to do this check early to tell
-     * thread-MPI whether it should do pinning when spawning threads.
-     * TODO: the above no longer holds, we should move these checks down
-     */
-    gmx_omp_check_thread_affinity(fplog, cr, hw_opt);
-
     /* Check and update the hardware options for internal consistency */
     check_and_update_hw_opt_1(hw_opt, SIMMASTER(cr));
 
+    /* Early check for externally set process affinity. */
+    gmx_check_thread_affinity_set(fplog, cr,
+                                  hw_opt, hwinfo->nthreads_hw_avail, FALSE);
     if (SIMMASTER(cr))
     {
-#ifdef GMX_THREAD_MPI
-        /* Early check for externally set process affinity.
-         * With thread-MPI this is needed as pinning might get turned off,
-         * which needs to be known before starting thread-MPI.
-         * With thread-MPI hw_opt is processed here on the master rank
-         * and passed to the other ranks later, so we only do this on master.
-         */
-        gmx_check_thread_affinity_set(fplog,
-                                      NULL,
-                                      hw_opt, hwinfo->nthreads_hw_avail, FALSE);
-#endif
 
 #ifdef GMX_THREAD_MPI
         if (cr->npmenodes > 0 && hw_opt->nthreads_tmpi <= 0)