1 // --------------------------------------------------------------------------
4 // Markus Wittmann, 2016-2017
5 // RRZE, University of Erlangen-Nuremberg, Germany
6 // markus.wittmann -at- fau.de or hpc -at- rrze.fau.de
9 // LSS, University of Erlangen-Nuremberg, Germany
11 // This file is part of the Lattice Boltzmann Benchmark Kernels (LbmBenchKernels).
13 // LbmBenchKernels is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation, either version 3 of the License, or
16 // (at your option) any later version.
18 // LbmBenchKernels is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU General Public License for more details.
23 // You should have received a copy of the GNU General Public License
24 // along with LbmBenchKernels. If not, see <http://www.gnu.org/licenses/>.
26 // --------------------------------------------------------------------------
37 // -----------------------------------------------------------------------
39 // Binds the calling thread to specified core.
41 // Return value: 0 = success, else error.
43 // -----------------------------------------------------------------------
45 int PinCurrentThreadToCore(int coreNumber)
51 CPU_SET(coreNumber, &cpu_set);
53 error = sched_setaffinity((pid_t)0, sizeof(cpu_set_t), &cpu_set);
56 Error("pinning thread to core %d failed (%d): %s\n",
57 coreNumber, error, strerror(error));
64 // -----------------------------------------------------------------------
66 // Binds the calling thread to specified core by a cpu list specified
67 // in the given environment variable.
69 // Return value: 0 = success, else error.
71 // -----------------------------------------------------------------------
73 int PinCurrentThreadByEnvVar(const char * envVarName, int threadNumber)
75 const char * envVarValue;
78 envVarValue = getenv(envVarName);
80 if (envVarValue == NULL) {
81 printf("WARNING: skip pinning: env var %s not set\n", envVarName);
86 core = PinParseCpuList(envVarValue, threadNumber);
92 return PinCurrentThreadToCore(core);
96 // -----------------------------------------------------------------------
98 // Binds the calling thread to a core specified in the CPU list.
100 // Return value: 0 = success, else error.
102 // -----------------------------------------------------------------------
104 int PinCurrentThreadByCpuList(const char * cpuList, int threadNumber)
108 if (cpuList == NULL) {
109 printf("ERROR: cpu list is NULL.\n");
114 core = PinParseCpuList(cpuList, threadNumber);
120 return PinCurrentThreadToCore(core);
124 // -----------------------------------------------------------------------
126 // Parses the provided cpu list and returns the core number for the
129 // The cpu list has for example a format of: 0,1,2
131 // -----------------------------------------------------------------------
133 int PinParseCpuList(const char * cpuList, int threadNumber)
137 if (cpuList == NULL) {
141 const char * c = cpuList;
143 // Ensure only valid characters are in the cpu list.
144 // Cpu list is in the format of "0,1,2,3,4,5".
145 while (((*c >= '0' && *c <= '9') || *c == ',')) {
150 // Invalid character detected.
156 // Now find the core for the specified thread.
160 while (t < threadNumber && *c != 0x00) {
167 if (t != threadNumber || *c < '0' || *c > '9') {
168 // Cpu for this threadNumber not found.
179 // -----------------------------------------------------------------------
181 // Returns the first core from the calling thread's affinity set.
183 // On error a value < 0 is returned.
185 // -----------------------------------------------------------------------
195 err = sched_getaffinity((pid_t)0, sizeof(cpu_set_t), &cpu_set);
197 // constant CPU_SETSIZE is one larger than the maximum CPU
198 // number that can be stored in a CPU set
199 for (int i = 0; i < CPU_SETSIZE; ++i) {
200 if (CPU_ISSET(i, &cpu_set)) {
207 Error("getting thread affinty failed (%d): %s\n", err, strerror(err));
216 // -----------------------------------------------------------------------
218 // Returns the all cores from the calling thread's affinity set.
220 // On error a value < 0 is returned.
222 // -----------------------------------------------------------------------
224 typedef cpu_set_t CpuSet;
227 static CpuSet PinCurrentCores()
235 err = sched_getaffinity((pid_t)0, sizeof(cpu_set_t), &cpu_set);
240 Error("getting thread affinty failed (%d): %s\n", err, strerror(err));
247 static char * CpuSetToString(cpu_set_t * cpu_set)
249 int previousSetCore = -2;
250 int rangeBeginCore = -2;
252 char * buffer1 = (char *)malloc(1024);
253 Assert(buffer1 != NULL);
254 char * buffer2 = (char *)malloc(1024);
255 Assert(buffer2 != NULL);
260 char * buffer = buffer1;
261 char * bufferOld = buffer2;
263 const char * empty = "";
264 const char * realComma = ",";
265 const char * comma = empty;
267 // TODO: use snprintf
268 // TODO: increase allocated buffer if necessary
270 for (int i = 0; i < CPU_SETSIZE; ++i) {
271 if (!CPU_ISSET(i, cpu_set)) {
275 if (i == previousSetCore + 1) {
280 // Now we reached the end of a range.
281 // The range can also consist of only one core.
282 // Be aware, that this core is not part of the range.
284 // TODO: this code is repeated below -> use it only once
285 if (rangeBeginCore >= 0 && previousSetCore >= 0) {
292 if (rangeBeginCore < previousSetCore) {
293 sprintf(buffer, "%s%s%d-%d", bufferOld, comma, rangeBeginCore, previousSetCore);
296 sprintf(buffer, "%s%s%d", bufferOld, comma, previousSetCore);
302 // With this core a new range begins.
307 if (rangeBeginCore >= 0 && previousSetCore >= 0) {
314 if (rangeBeginCore < previousSetCore) {
315 sprintf(buffer, "%s%s%d-%d", bufferOld, comma, rangeBeginCore, previousSetCore);
318 sprintf(buffer, "%s%s%d", bufferOld, comma, previousSetCore);
322 free(bufferOld); bufferOld = NULL;
327 char * PinCpuListAsString()
329 CpuSet cpuSet = PinCurrentCores();
331 return CpuSetToString(&cpuSet);
336 int main(int argc, char * argv[])
338 char * cpuList = PinCpuListAsString();
340 printf("pinned to cores: %s\n", cpuList);
342 free(cpuList); cpuList = NULL;