add citation information
[LbmBenchmarkKernelsPublic.git] / src / Pinning.c
CommitLineData
10988083
MW
1// --------------------------------------------------------------------------
2//
3// Copyright
4// Markus Wittmann, 2016-2017
5// RRZE, University of Erlangen-Nuremberg, Germany
6// markus.wittmann -at- fau.de or hpc -at- rrze.fau.de
7//
8// Viktor Haag, 2016
9// LSS, University of Erlangen-Nuremberg, Germany
10//
11// This file is part of the Lattice Boltzmann Benchmark Kernels (LbmBenchKernels).
12//
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.
17//
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.
22//
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/>.
25//
26// --------------------------------------------------------------------------
27#ifndef _GNU_SOURCE
28 #define _GNU_SOURCE
29#endif
30#include <sched.h>
31#include <errno.h>
32
33
34#include "Base.h"
35#include "Pinning.h"
36
10988083
MW
37// -----------------------------------------------------------------------
38//
39// Binds the calling thread to specified core.
40//
41// Return value: 0 = success, else error.
42//
43// -----------------------------------------------------------------------
44
45int PinCurrentThreadToCore(int coreNumber)
46{
47 int error = 0;
48
49 cpu_set_t cpu_set;
50 CPU_ZERO(&cpu_set);
51 CPU_SET(coreNumber, &cpu_set);
52
53 error = sched_setaffinity((pid_t)0, sizeof(cpu_set_t), &cpu_set);
54
55 if (error != 0) {
56 Error("pinning thread to core %d failed (%d): %s\n",
57 coreNumber, error, strerror(error));
58 }
59
60 return error;
61}
62
63
64// -----------------------------------------------------------------------
65//
66// Binds the calling thread to specified core by a cpu list specified
67// in the given environment variable.
68//
69// Return value: 0 = success, else error.
70//
71// -----------------------------------------------------------------------
72
e3f82424 73int PinCurrentThreadByEnvVar(const char * envVarName, int threadNumber)
10988083
MW
74{
75 const char * envVarValue;
76 int core;
77
78 envVarValue = getenv(envVarName);
79
80 if (envVarValue == NULL) {
e3f82424 81 printf("WARNING: skip pinning: env var %s not set\n", envVarName);
10988083
MW
82
83 return 0;
84 }
85
e3f82424 86 core = PinParseCpuList(envVarValue, threadNumber);
10988083
MW
87
88 if (core < 0) {
89 return core;
90 }
91
92 return PinCurrentThreadToCore(core);
93}
94
95
96// -----------------------------------------------------------------------
97//
98// Binds the calling thread to a core specified in the CPU list.
99//
100// Return value: 0 = success, else error.
101//
102// -----------------------------------------------------------------------
103
e3f82424 104int PinCurrentThreadByCpuList(const char * cpuList, int threadNumber)
10988083
MW
105{
106 int core;
107
108 if (cpuList == NULL) {
e3f82424 109 printf("ERROR: cpu list is NULL.\n");
10988083
MW
110
111 exit(1);
112 }
113
e3f82424 114 core = PinParseCpuList(cpuList, threadNumber);
10988083
MW
115
116 if (core < 0) {
117 return core;
118 }
119
120 return PinCurrentThreadToCore(core);
121}
122
123
124// -----------------------------------------------------------------------
125//
126// Parses the provided cpu list and returns the core number for the
e3f82424 127// specified thread.
10988083 128//
e3f82424 129// The cpu list has for example a format of: 0,1,2
10988083
MW
130//
131// -----------------------------------------------------------------------
132
e3f82424 133int PinParseCpuList(const char * cpuList, int threadNumber)
10988083
MW
134{
135 int cpu = -1;
136
137 if (cpuList == NULL) {
138 return -1;
139 }
140
141 const char * c = cpuList;
142
143 // Ensure only valid characters are in the cpu list.
e3f82424
MW
144 // Cpu list is in the format of "0,1,2,3,4,5".
145 while (((*c >= '0' && *c <= '9') || *c == ',')) {
10988083
MW
146 ++c;
147 }
148
149 if (*c != 0x00) {
150 // Invalid character detected.
151 return -2;
152 }
153
154 c = cpuList;
155
10988083
MW
156 // Now find the core for the specified thread.
157
158 int t = 0;
159
160 while (t < threadNumber && *c != 0x00) {
161 if (*c == ',') {
162 ++t;
163 }
10988083
MW
164 ++c;
165 }
166
167 if (t != threadNumber || *c < '0' || *c > '9') {
168 // Cpu for this threadNumber not found.
169 return -4;
170 }
171
172 cpu = atoi(c);
173
174 return cpu;
175}
176
177
178
179// -----------------------------------------------------------------------
180//
181// Returns the first core from the calling thread's affinity set.
182//
183// On error a value < 0 is returned.
184//
185// -----------------------------------------------------------------------
186
187int PinCurrentCore()
188{
189 int core = -1;
190 int err;
191
192 cpu_set_t cpu_set;
193 CPU_ZERO(&cpu_set);
194
195 err = sched_getaffinity((pid_t)0, sizeof(cpu_set_t), &cpu_set);
196
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)) {
201 core = i;
202 break;
203 }
204 }
205
206 if (err != 0) {
207 Error("getting thread affinty failed (%d): %s\n", err, strerror(err));
208 return -1;
209 }
210
211 return core;
212}
213
214
215
216// -----------------------------------------------------------------------
217//
218// Returns the all cores from the calling thread's affinity set.
219//
220// On error a value < 0 is returned.
221//
222// -----------------------------------------------------------------------
223
224typedef cpu_set_t CpuSet;
225
226
227static CpuSet PinCurrentCores()
228{
229 CpuSet cpuSet;
230 int err;
231
232 cpu_set_t cpu_set;
233 CPU_ZERO(&cpu_set);
234
235 err = sched_getaffinity((pid_t)0, sizeof(cpu_set_t), &cpu_set);
236
237 cpuSet = cpu_set;
238
239 if (err != 0) {
240 Error("getting thread affinty failed (%d): %s\n", err, strerror(err));
241 return cpuSet;
242 }
243
244 return cpuSet;
245}
246
247static char * CpuSetToString(cpu_set_t * cpu_set)
248{
249 int previousSetCore = -2;
250 int rangeBeginCore = -2;
251
252 char * buffer1 = (char *)malloc(1024);
253 Assert(buffer1 != NULL);
254 char * buffer2 = (char *)malloc(1024);
255 Assert(buffer2 != NULL);
256
257 buffer1[0] = 0x00;
258 buffer2[0] = 0x00;
259
260 char * buffer = buffer1;
261 char * bufferOld = buffer2;
262
263 const char * empty = "";
264 const char * realComma = ",";
265 const char * comma = empty;
266
267 // TODO: use snprintf
268 // TODO: increase allocated buffer if necessary
269
270 for (int i = 0; i < CPU_SETSIZE; ++i) {
271 if (!CPU_ISSET(i, cpu_set)) {
272 continue;
273 }
274
275 if (i == previousSetCore + 1) {
276 previousSetCore = i;
277 continue;
278 }
279
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.
283
284 // TODO: this code is repeated below -> use it only once
285 if (rangeBeginCore >= 0 && previousSetCore >= 0) {
286 char * tmp;
287
288 tmp = buffer;
289 buffer = bufferOld;
290 bufferOld = tmp;
291
292 if (rangeBeginCore < previousSetCore) {
293 sprintf(buffer, "%s%s%d-%d", bufferOld, comma, rangeBeginCore, previousSetCore);
294 }
295 else {
296 sprintf(buffer, "%s%s%d", bufferOld, comma, previousSetCore);
297 }
298
299 comma = realComma;
300 }
301
302 // With this core a new range begins.
303 rangeBeginCore = i;
304 previousSetCore = i;
305 }
306
307 if (rangeBeginCore >= 0 && previousSetCore >= 0) {
308 char * tmp;
309
310 tmp = buffer;
311 buffer = bufferOld;
312 bufferOld = tmp;
313
314 if (rangeBeginCore < previousSetCore) {
315 sprintf(buffer, "%s%s%d-%d", bufferOld, comma, rangeBeginCore, previousSetCore);
316 }
317 else {
318 sprintf(buffer, "%s%s%d", bufferOld, comma, previousSetCore);
319 }
320 }
321
322 free(bufferOld); bufferOld = NULL;
323
324 return buffer;
325}
326
327char * PinCpuListAsString()
328{
329 CpuSet cpuSet = PinCurrentCores();
330
331 return CpuSetToString(&cpuSet);
332}
333
334#ifdef TEST
335
336int main(int argc, char * argv[])
337{
338 char * cpuList = PinCpuListAsString();
339
340 printf("pinned to cores: %s\n", cpuList);
341
342 free(cpuList); cpuList = NULL;
343
344 return 0;
345}
346
347#endif // TEST
348
This page took 0.073453 seconds and 5 git commands to generate.