2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2017, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
36 * \brief Defines routines for handling user-specified GPU IDs.
38 * \author Mark Abraham <mark.j.abraham@gmail.com>
39 * \ingroup module_taskassignment
43 #include "usergpuids.h"
52 #include "gromacs/gpu_utils/gpu_utils.h"
53 #include "gromacs/hardware/hw_info.h"
54 #include "gromacs/utility/exceptions.h"
55 #include "gromacs/utility/stringutil.h"
61 parseUserGpuIds(const std::string
&gpuIdString
)
63 // An optional comma is used to separate GPU IDs assigned to the
64 // same type of task, which will be useful for any nodes that have
65 // more than ten GPUs.
67 std::vector
<int> digits
;
68 auto foundCommaDelimiters
= gpuIdString
.find(',') != std::string::npos
;
69 if (!foundCommaDelimiters
)
71 for (const auto &c
: gpuIdString
)
73 if (std::isdigit(c
) == 0)
75 GMX_THROW(InvalidInputError(formatString("Invalid character in GPU ID string: \"%c\"\n", c
)));
77 // Convert each character in the token to an integer
78 digits
.push_back(c
- '0');
83 if (gpuIdString
[0] == ',')
85 GMX_THROW(InvalidInputError("Invalid use of leading comma in GPU ID string"));
87 std::istringstream
ss(gpuIdString
);
89 digits
.reserve(gpuIdString
.length());
90 token
.reserve(gpuIdString
.length());
91 while (std::getline(ss
, token
, ','))
93 // Convert the whole token to an integer
96 GMX_THROW(InvalidInputError("Invalid use of comma in GPU ID string"));
98 digits
.push_back(std::stoi(token
));
105 makeGpuIds(const std::vector
<int> &compatibleGpus
,
108 std::vector
<int> gpuIdsToUse
;
110 gpuIdsToUse
.reserve(numGpuTasks
);
112 auto currentGpuId
= compatibleGpus
.begin();
113 for (size_t i
= 0; i
!= numGpuTasks
; ++i
)
115 GMX_ASSERT(!compatibleGpus
.empty(), "Must have compatible GPUs from which to build a list of GPU IDs to use");
116 gpuIdsToUse
.push_back(*currentGpuId
);
118 if (currentGpuId
== compatibleGpus
.end())
120 // Wrap around and assign tasks again.
121 currentGpuId
= compatibleGpus
.begin();
124 std::sort(gpuIdsToUse
.begin(), gpuIdsToUse
.end());
129 makeGpuIdString(const std::vector
<int> &gpuIds
,
130 int totalNumberOfTasks
)
132 auto resultGpuIds
= makeGpuIds(gpuIds
, totalNumberOfTasks
);
133 return formatAndJoin(resultGpuIds
, ",", StringFormatter("%d"));
136 void checkUserGpuIds(const gmx_gpu_info_t
&gpu_info
,
137 const std::vector
<int> &compatibleGpus
,
138 const std::vector
<int> &gpuIds
)
140 bool foundIncompatibleGpuIds
= false;
142 = "Some of the requested GPUs do not exist, behave strangely, or are not compatible:\n";
144 for (const auto &gpuId
: gpuIds
)
146 if (std::find(compatibleGpus
.begin(), compatibleGpus
.end(), gpuId
) == compatibleGpus
.end())
148 foundIncompatibleGpuIds
= true;
149 message
+= gmx::formatString(" GPU #%d: %s\n",
151 getGpuCompatibilityDescription(gpu_info
, gpuId
));
154 if (foundIncompatibleGpuIds
)
156 GMX_THROW(InconsistentInputError(message
));