Exemple #1
0
/* check whether an 'nst'-style parameter p is a multiple of nst, and
   set it to be one if not, with a warning. */
static void check_nst_param(const gmx::MDLogger &mdlog,
                            const char *desc_nst, int nst,
                            const char *desc_p, int *p)
{
    if (*p > 0 && *p % nst != 0)
    {
        /* Round up to the next multiple of nst */
        *p = ((*p)/nst + 1)*nst;
        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
                "NOTE: %s changes %s to %d", desc_nst, desc_p, *p);
    }
}
void gmx_omp_nthreads_read_env(const gmx::MDLogger &mdlog,
                               int                 *nthreads_omp)
{
    char    *env;
    gmx_bool bCommandLineSetNthreadsOMP = *nthreads_omp > 0;
    char     buffer[STRLEN];

    GMX_RELEASE_ASSERT(nthreads_omp, "nthreads_omp must be a non-NULL pointer");

    if ((env = getenv("OMP_NUM_THREADS")) != nullptr)
    {
        int nt_omp;

        sscanf(env, "%d", &nt_omp);
        if (nt_omp <= 0)
        {
            gmx_fatal(FARGS, "OMP_NUM_THREADS is invalid: '%s'", env);
        }

        if (bCommandLineSetNthreadsOMP && nt_omp != *nthreads_omp)
        {
            gmx_fatal(FARGS, "Environment variable OMP_NUM_THREADS (%d) and the number of threads requested on the command line (%d) have different values. Either omit one, or set them both to the same value.", nt_omp, *nthreads_omp);
        }

        /* Setting the number of OpenMP threads. */
        *nthreads_omp = nt_omp;

        /* Output the results */
        sprintf(buffer,
                "\nThe number of OpenMP threads was set by environment variable OMP_NUM_THREADS to %d%s\n\n",
                nt_omp,
                bCommandLineSetNthreadsOMP ? " (and the command-line setting agreed with that)" : "");

        /* This prints once per simulation for multi-simulations,
         * which might help diagnose issues with inhomogenous
         * cluster setups. */
        GMX_LOG(mdlog.info).appendTextFormatted("%s", buffer);
        if (debug)
        {
            /* This prints once per process for real MPI (i.e. once
             * per debug file), and once per simulation for thread MPI
             * (because of logic in the calling function). */
            fputs(buffer, debug);
        }
    }
}
Exemple #3
0
int check_nstglobalcomm(const gmx::MDLogger &mdlog, int nstglobalcomm, t_inputrec *ir)
{
    if (!EI_DYNAMICS(ir->eI))
    {
        nstglobalcomm = 1;
    }

    if (nstglobalcomm == -1)
    {
        // Set up the default behaviour
        if (!(ir->nstcalcenergy > 0 ||
              ir->nstlist > 0 ||
              ir->etc != etcNO ||
              ir->epc != epcNO))
        {
            /* The user didn't choose the period for anything
               important, so we just make sure we can send signals and
               write output suitably. */
            nstglobalcomm = 10;
            if (ir->nstenergy > 0 && ir->nstenergy < nstglobalcomm)
            {
                nstglobalcomm = ir->nstenergy;
            }
        }
        else
        {
            /* The user has made a choice (perhaps implicitly), so we
             * ensure that we do timely intra-simulation communication
             * for (possibly) each of the four parts that care.
             *
             * TODO Does the Verlet scheme (+ DD) need any
             * communication at nstlist steps? Is the use of nstlist
             * here a leftover of the twin-range scheme? Can we remove
             * nstlist when we remove the group scheme?
             */
            nstglobalcomm = lcd4(ir->nstcalcenergy,
                                 ir->nstlist,
                                 ir->etc != etcNO ? ir->nsttcouple : 0,
                                 ir->epc != epcNO ? ir->nstpcouple : 0);
        }
    }
    else
    {
        // Check that the user's choice of mdrun -gcom will work
        if (ir->nstlist > 0 &&
            nstglobalcomm > ir->nstlist && nstglobalcomm % ir->nstlist != 0)
        {
            nstglobalcomm = (nstglobalcomm / ir->nstlist)*ir->nstlist;
            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
                    "WARNING: nstglobalcomm is larger than nstlist, but not a multiple, setting it to %d",
                    nstglobalcomm);
        }
        if (ir->nstcalcenergy > 0)
        {
            check_nst_param(mdlog, "-gcom", nstglobalcomm,
                            "nstcalcenergy", &ir->nstcalcenergy);
        }
        if (ir->etc != etcNO && ir->nsttcouple > 0)
        {
            check_nst_param(mdlog, "-gcom", nstglobalcomm,
                            "nsttcouple", &ir->nsttcouple);
        }
        if (ir->epc != epcNO && ir->nstpcouple > 0)
        {
            check_nst_param(mdlog, "-gcom", nstglobalcomm,
                            "nstpcouple", &ir->nstpcouple);
        }

        check_nst_param(mdlog, "-gcom", nstglobalcomm,
                        "nstenergy", &ir->nstenergy);

        check_nst_param(mdlog, "-gcom", nstglobalcomm,
                        "nstlog", &ir->nstlog);
    }

    if (ir->comm_mode != ecmNO && ir->nstcomm < nstglobalcomm)
    {
        GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
                "WARNING: Changing nstcomm from %d to %d",
                ir->nstcomm, nstglobalcomm);
        ir->nstcomm = nstglobalcomm;
    }

    GMX_LOG(mdlog.info).appendTextFormatted(
            "Intra-simulation communication will occur every %d steps.\n", nstglobalcomm);
    return nstglobalcomm;
}
/*! \brief Report on the OpenMP settings that will be used */
static void
reportOpenmpSettings(const gmx::MDLogger &mdlog,
                     const t_commrec     *cr,
                     gmx_bool             bOMP,
                     gmx_bool             bFullOmpSupport,
                     gmx_bool             bSepPME)
{
#if GMX_THREAD_MPI
    const char *mpi_str = "per tMPI thread";
#else
    const char *mpi_str = "per MPI process";
#endif
    int         nth_min, nth_max, nth_pme_min, nth_pme_max;

    /* inform the user about the settings */
    if (!bOMP)
    {
        return;
    }

#if GMX_MPI
    if (cr->nnodes + cr->npmenodes > 1)
    {
        /* Get the min and max thread counts over the MPI ranks */
        int buf_in[4], buf_out[4];

        buf_in[0] = -modth.gnth;
        buf_in[1] =  modth.gnth;
        buf_in[2] = -modth.gnth_pme;
        buf_in[3] =  modth.gnth_pme;

        MPI_Allreduce(buf_in, buf_out, 4, MPI_INT, MPI_MAX, cr->mpi_comm_mysim);

        nth_min     = -buf_out[0];
        nth_max     =  buf_out[1];
        nth_pme_min = -buf_out[2];
        nth_pme_max =  buf_out[3];
    }
    else
#endif
    {
        nth_min     = modth.gnth;
        nth_max     = modth.gnth;
        nth_pme_min = modth.gnth_pme;
        nth_pme_max = modth.gnth_pme;
    }

    /* for group scheme we print PME threads info only */
    if (bFullOmpSupport)
    {
        if (nth_max == nth_min)
        {
            GMX_LOG(mdlog.warning).appendTextFormatted(
                    "Using %d OpenMP thread%s %s",
                    nth_min, nth_min > 1 ? "s" : "",
                    cr->nnodes > 1 ? mpi_str : "");
        }
        else
        {
            GMX_LOG(mdlog.warning).appendTextFormatted(
                    "Using %d - %d OpenMP threads %s",
                    nth_min, nth_max, mpi_str);
        }
    }
    if (bSepPME && (nth_pme_min != nth_min || nth_pme_max != nth_max))
    {
        if (nth_pme_max == nth_pme_min)
        {
            GMX_LOG(mdlog.warning).appendTextFormatted(
                    "Using %d OpenMP thread%s %s for PME",
                    nth_pme_min, nth_pme_min > 1 ? "s" : "",
                    cr->nnodes > 1 ? mpi_str : "");
        }
        else
        {
            GMX_LOG(mdlog.warning).appendTextFormatted(
                    "Using %d - %d OpenMP threads %s for PME",
                    nth_pme_min, nth_pme_max, mpi_str);
        }
    }
    GMX_LOG(mdlog.warning);
}
/** Determine the number of threads for module \p mod.
 *
 *  \p m takes values form the module_nth_t enum and maps these to the
 *  corresponding value in modth_env_var.
 *
 *  Each number of threads per module takes the default value unless
 *  GMX_*_NUM_THERADS env var is set, case in which its value overrides
 *  the deafult.
 *
 *  The "group" scheme supports OpenMP only in PME and in thise case all but
 *  the PME nthread values default to 1.
 */
static void pick_module_nthreads(const gmx::MDLogger &mdlog, int m,
                                 gmx_bool bFullOmpSupport,
                                 gmx_bool bSepPME)
{
    char      *env;
    int        nth;

    const bool bOMP = GMX_OPENMP;

    /* The default should never be set through a GMX_*_NUM_THREADS env var
     * as it's always equal with gnth. */
    if (m == emntDefault)
    {
        return;
    }

    /* check the environment variable */
    if ((env = getenv(modth_env_var[m])) != nullptr)
    {
        sscanf(env, "%d", &nth);

        if (!bOMP)
        {
            gmx_warning("%s=%d is set, but %s is compiled without OpenMP!",
                        modth_env_var[m], nth,
                        gmx::getProgramContext().displayName());
        }

        /* with the verlet codepath, when any GMX_*_NUM_THREADS env var is set,
         * OMP_NUM_THREADS also has to be set */
        if (bFullOmpSupport && getenv("OMP_NUM_THREADS") == nullptr)
        {
            gmx_warning("%s=%d is set, the default number of threads also "
                        "needs to be set with OMP_NUM_THREADS!",
                        modth_env_var[m], nth);
        }

        /* with the group scheme warn if any env var except PME is set */
        if (!bFullOmpSupport)
        {
            if (m != emntPME)
            {
                gmx_warning("%s=%d is set, but OpenMP multithreading is not "
                            "supported in %s!",
                            modth_env_var[m], nth, mod_name[m]);
                nth = 1;
            }
        }

        /* only babble if we are really overriding with a different value */
        if ((bSepPME && m == emntPME && nth != modth.gnth_pme) || (nth != modth.gnth))
        {
            GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
                    "%s=%d set, overriding the default number of %s threads",
                    modth_env_var[m], nth, mod_name[m]);
        }
    }
    else
    {
        /* pick the global PME node nthreads if we are setting the number
         * of threads in separate PME nodes  */
        nth = (bSepPME && m == emntPME) ? modth.gnth_pme : modth.gnth;
    }

    gmx_omp_nthreads_set(m, nth);
}