From 2c59f6decc622f845b8ca658521a675654ee55e9 Mon Sep 17 00:00:00 2001 From: Mark Abraham Date: Sat, 17 May 2014 15:27:25 +0200 Subject: [PATCH] Refactor string handling for GPU usage report This prepares for future addition of reporting the list of available compatible GPUs in the auto-selection case, which is needed for gmx tune-pme to function well. Current outputs are only of IDs of available GPUs, or IDs of those that will be used. The latter depends on the number of PP ranks, so it doesn't help gmx tune-pme find out how to run the optimization. At some point, delegating this kind of task to hwinfo called from gmx tune-pme might be preferable. The only functionality changes here are of reporting GPU ids by referring to them as IDs, and the string of the ones used is of style "0,1,4" rather than "#0, #1, #4". The use of the template function and constructing the temporary vector prepares for the next commit. Change-Id: Ic37989ce2f8e6396f450e1b5457ea7ea70b3849b --- src/gromacs/gmxlib/gmx_detect_hardware.cpp | 104 ++++++++++++++------- 1 file changed, 71 insertions(+), 33 deletions(-) diff --git a/src/gromacs/gmxlib/gmx_detect_hardware.cpp b/src/gromacs/gmxlib/gmx_detect_hardware.cpp index e5478b0020..385bdee82e 100644 --- a/src/gromacs/gmxlib/gmx_detect_hardware.cpp +++ b/src/gromacs/gmxlib/gmx_detect_hardware.cpp @@ -36,6 +36,9 @@ #include #endif +#include +#include + #include #include #include @@ -59,9 +62,11 @@ #include "gromacs/utility/basenetwork.h" #include "gromacs/utility/cstringutil.h" +#include "gromacs/utility/exceptions.h" #include "gromacs/utility/fatalerror.h" #include "gromacs/utility/gmxomp.h" #include "gromacs/utility/smalloc.h" +#include "gromacs/utility/stringutil.h" #include "thread_mpi/threads.h" @@ -147,50 +152,74 @@ static void print_gpu_detection_stats(FILE *fplog, } } -static void print_gpu_use_stats(FILE *fplog, - const gmx_gpu_info_t *gpu_info, - const gmx_gpu_opt_t *gpu_opt, - const t_commrec *cr) +/*! \brief Helper function for writing comma-separated GPU IDs. + * + * \param[in] ids A container of integer GPU IDs + * \return A comma-separated string of GPU IDs */ +template +static std::string makeGpuIdsString(const Container &ids) { - char sbuf[STRLEN], stmp[STRLEN]; - int i, ngpu_comp, ngpu_use; + std::string output; - ngpu_comp = gpu_info->ncuda_dev_compatible; - ngpu_use = gpu_opt->ncuda_dev_use; + if (0 != ids.size()) + { + typename Container::const_iterator it = ids.begin(); + output += gmx::formatString("%d", *it); + for (++it; it != ids.end(); ++it) + { + output += gmx::formatString(",%d", *it); + } + } + return output; +} + +/*! \brief Helper function for reporting GPU usage information + * in the mdrun log file + * + * \param[in] gpu_info Pointer to per-node GPU info struct + * \param[in] gpu_opt Pointer to per-node GPU options struct + * \param[in] numPpRanks Number of PP ranks per node + * \return String to write to the log file + * \throws std::bad_alloc if out of memory */ +static std::string +makeGpuUsageReport(const gmx_gpu_info_t *gpu_info, + const gmx_gpu_opt_t *gpu_opt, + size_t numPpRanks) +{ + int ngpu_use = gpu_opt->ncuda_dev_use; + int ngpu_comp = gpu_info->ncuda_dev_compatible; /* Issue a note if GPUs are available but not used */ if (ngpu_comp > 0 && ngpu_use < 1) { - sprintf(sbuf, - "%d compatible GPU%s detected in the system, but none will be used.\n" - "Consider trying GPU acceleration with the Verlet scheme!", - ngpu_comp, (ngpu_comp > 1) ? "s" : ""); + return gmx::formatString("%d compatible GPU%s detected in the system, but none will be used.\n" + "Consider trying GPU acceleration with the Verlet scheme!\n", + ngpu_comp, (ngpu_comp > 1) ? "s" : ""); } - else - { - int ngpu_use_uniq; - - ngpu_use_uniq = gmx_count_gpu_dev_unique(gpu_info, gpu_opt); - sprintf(sbuf, "%d GPU%s %sselected for this run.\n" - "Mapping of GPU%s to the %d PP rank%s in this node: ", - ngpu_use_uniq, (ngpu_use_uniq > 1) ? "s" : "", - gpu_opt->bUserSet ? "user-" : "auto-", - (ngpu_use > 1) ? "s" : "", - cr->nrank_pp_intranode, - (cr->nrank_pp_intranode > 1) ? "s" : ""); + std::string output; - for (i = 0; i < ngpu_use; i++) + { + std::vector gpuIdsInUse; + for (int i = 0; i < ngpu_use; i++) { - sprintf(stmp, "#%d", get_gpu_device_id(gpu_info, gpu_opt, i)); - if (i < ngpu_use - 1) - { - strcat(stmp, ", "); - } - strcat(sbuf, stmp); + gpuIdsInUse.push_back(get_gpu_device_id(gpu_info, gpu_opt, i)); } + std::string gpuIdsString = makeGpuIdsString(gpuIdsInUse); + int numGpusInUse = gmx_count_gpu_dev_unique(gpu_info, gpu_opt); + bool bPluralGpus = numGpusInUse > 1; + + output += gmx::formatString("%d GPU%s %sselected for this run.\n" + "Mapping of GPU ID%s to the %d PP rank%s in this node: %s\n", + numGpusInUse, bPluralGpus ? "s" : "", + gpu_opt->bUserSet ? "user-" : "auto-", + bPluralGpus ? "s" : "", + numPpRanks, + (numPpRanks > 1) ? "s" : "", + gpuIdsString.c_str()); } - md_print_info(cr, fplog, "%s\n\n", sbuf); + + return output; } /* Give a suitable fatal error or warning if the build configuration @@ -281,8 +310,17 @@ void gmx_check_hw_runconf_consistency(FILE *fplog, if (hwinfo->gpu_info.ncuda_dev_compatible > 0) { + std::string gpuUseageReport; + try + { + gpuUseageReport = makeGpuUsageReport(&hwinfo->gpu_info, + &hw_opt->gpu_opt, + cr->nrank_pp_intranode); + } + GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR; + /* NOTE: this print is only for and on one physical node */ - print_gpu_use_stats(fplog, &hwinfo->gpu_info, &hw_opt->gpu_opt, cr); + md_print_info(cr, fplog, gpuUseageReport.c_str()); } /* Need to ensure that we have enough GPUs: -- 2.22.0