1 /*
2 * Copyright © 2009 CNRS
3 * Copyright © 2009-2018 Inria. All rights reserved.
4 * Copyright © 2009-2012 Université Bordeaux
5 * Copyright © 2011 Cisco Systems, Inc. All rights reserved.
6 * See COPYING in top-level directory.
7 */
8
9 /* Misc macros and inlines. */
10
11 #ifndef HWLOC_PRIVATE_MISC_H
12 #define HWLOC_PRIVATE_MISC_H
13
14 #include <hwloc/autogen/config.h>
15 #include <private/autogen/config.h>
16
17 #ifdef HWLOC_HAVE_DECL_STRNCASECMP
18 #ifdef HAVE_STRINGS_H
19 #include <strings.h>
20 #endif
21 #else
22 #ifdef HAVE_CTYPE_H
23 #include <ctype.h>
24 #endif
25 #endif
26
27 /* Compile-time assertion */
28 #define HWLOC_BUILD_ASSERT(condition) ((void)sizeof(char[1 - 2*!(condition)]))
29
30 #define HWLOC_BITS_PER_LONG (HWLOC_SIZEOF_UNSIGNED_LONG * 8)
31 #define HWLOC_BITS_PER_INT (HWLOC_SIZEOF_UNSIGNED_INT * 8)
32
33 #if (HWLOC_BITS_PER_LONG != 32) && (HWLOC_BITS_PER_LONG != 64)
34 #error "unknown size for unsigned long."
35 #endif
36
37 #if (HWLOC_BITS_PER_INT != 16) && (HWLOC_BITS_PER_INT != 32) && (HWLOC_BITS_PER_INT != 64)
38 #error "unknown size for unsigned int."
39 #endif
40
41
42 /**
43 * ffsl helpers.
44 */
45
46 #if defined(HWLOC_HAVE_BROKEN_FFS)
47
48 /* System has a broken ffs().
49 * We must check the before __GNUC__ or HWLOC_HAVE_FFSL
50 */
51 # define HWLOC_NO_FFS
52
53 #elif defined(__GNUC__)
54
55 # if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))
56 /* Starting from 3.4, gcc has a long variant. */
57 # define hwloc_ffsl(x) __builtin_ffsl(x)
58 # else
59 # define hwloc_ffs(x) __builtin_ffs(x)
60 # define HWLOC_NEED_FFSL
61 # endif
62
63 #elif defined(HWLOC_HAVE_FFSL)
64
65 # ifndef HWLOC_HAVE_DECL_FFSL
66 extern int ffsl(long) __hwloc_attribute_const;
67 # endif
68
69 # define hwloc_ffsl(x) ffsl(x)
70
71 #elif defined(HWLOC_HAVE_FFS)
72
73 # ifndef HWLOC_HAVE_DECL_FFS
74 extern int ffs(int) __hwloc_attribute_const;
75 # endif
76
77 # define hwloc_ffs(x) ffs(x)
78 # define HWLOC_NEED_FFSL
79
80 #else /* no ffs implementation */
81
82 # define HWLOC_NO_FFS
83
84 #endif
85
86 #ifdef HWLOC_NO_FFS
87
88 /* no ffs or it is known to be broken */
89 static __hwloc_inline int
90 hwloc_ffsl_manual(unsigned long x) __hwloc_attribute_const;
91 static __hwloc_inline int
hwloc_ffsl_manual(unsigned long x)92 hwloc_ffsl_manual(unsigned long x)
93 {
94 int i;
95
96 if (!x)
97 return 0;
98
99 i = 1;
100 #if HWLOC_BITS_PER_LONG >= 64
101 if (!(x & 0xfffffffful)) {
102 x >>= 32;
103 i += 32;
104 }
105 #endif
106 if (!(x & 0xffffu)) {
107 x >>= 16;
108 i += 16;
109 }
110 if (!(x & 0xff)) {
111 x >>= 8;
112 i += 8;
113 }
114 if (!(x & 0xf)) {
115 x >>= 4;
116 i += 4;
117 }
118 if (!(x & 0x3)) {
119 x >>= 2;
120 i += 2;
121 }
122 if (!(x & 0x1)) {
123 x >>= 1;
124 i += 1;
125 }
126
127 return i;
128 }
129 /* always define hwloc_ffsl as a macro, to avoid renaming breakage */
130 #define hwloc_ffsl hwloc_ffsl_manual
131
132 #elif defined(HWLOC_NEED_FFSL)
133
134 /* We only have an int ffs(int) implementation, build a long one. */
135
136 /* First make it 32 bits if it was only 16. */
137 static __hwloc_inline int
138 hwloc_ffs32(unsigned long x) __hwloc_attribute_const;
139 static __hwloc_inline int
hwloc_ffs32(unsigned long x)140 hwloc_ffs32(unsigned long x)
141 {
142 #if HWLOC_BITS_PER_INT == 16
143 int low_ffs, hi_ffs;
144
145 low_ffs = hwloc_ffs(x & 0xfffful);
146 if (low_ffs)
147 return low_ffs;
148
149 hi_ffs = hwloc_ffs(x >> 16);
150 if (hi_ffs)
151 return hi_ffs + 16;
152
153 return 0;
154 #else
155 return hwloc_ffs(x);
156 #endif
157 }
158
159 /* Then make it 64 bit if longs are. */
160 static __hwloc_inline int
161 hwloc_ffsl_from_ffs32(unsigned long x) __hwloc_attribute_const;
162 static __hwloc_inline int
hwloc_ffsl_from_ffs32(unsigned long x)163 hwloc_ffsl_from_ffs32(unsigned long x)
164 {
165 #if HWLOC_BITS_PER_LONG == 64
166 int low_ffs, hi_ffs;
167
168 low_ffs = hwloc_ffs32(x & 0xfffffffful);
169 if (low_ffs)
170 return low_ffs;
171
172 hi_ffs = hwloc_ffs32(x >> 32);
173 if (hi_ffs)
174 return hi_ffs + 32;
175
176 return 0;
177 #else
178 return hwloc_ffs32(x);
179 #endif
180 }
181 /* always define hwloc_ffsl as a macro, to avoid renaming breakage */
182 #define hwloc_ffsl hwloc_ffsl_from_ffs32
183
184 #endif
185
186 /**
187 * flsl helpers.
188 */
189 #ifdef __GNUC_____
190
191 # if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))
192 # define hwloc_flsl(x) ((x) ? (8*sizeof(long) - __builtin_clzl(x)) : 0)
193 # else
194 # define hwloc_fls(x) ((x) ? (8*sizeof(int) - __builtin_clz(x)) : 0)
195 # define HWLOC_NEED_FLSL
196 # endif
197
198 #elif defined(HWLOC_HAVE_FLSL)
199
200 # ifndef HWLOC_HAVE_DECL_FLSL
201 extern int flsl(long) __hwloc_attribute_const;
202 # endif
203
204 # define hwloc_flsl(x) flsl(x)
205
206 #elif defined(HWLOC_HAVE_CLZL)
207
208 # ifndef HWLOC_HAVE_DECL_CLZL
209 extern int clzl(long) __hwloc_attribute_const;
210 # endif
211
212 # define hwloc_flsl(x) ((x) ? (8*sizeof(long) - clzl(x)) : 0)
213
214 #elif defined(HWLOC_HAVE_FLS)
215
216 # ifndef HWLOC_HAVE_DECL_FLS
217 extern int fls(int) __hwloc_attribute_const;
218 # endif
219
220 # define hwloc_fls(x) fls(x)
221 # define HWLOC_NEED_FLSL
222
223 #elif defined(HWLOC_HAVE_CLZ)
224
225 # ifndef HWLOC_HAVE_DECL_CLZ
226 extern int clz(int) __hwloc_attribute_const;
227 # endif
228
229 # define hwloc_fls(x) ((x) ? (8*sizeof(int) - clz(x)) : 0)
230 # define HWLOC_NEED_FLSL
231
232 #else /* no fls implementation */
233
234 static __hwloc_inline int
235 hwloc_flsl_manual(unsigned long x) __hwloc_attribute_const;
236 static __hwloc_inline int
hwloc_flsl_manual(unsigned long x)237 hwloc_flsl_manual(unsigned long x)
238 {
239 int i = 0;
240
241 if (!x)
242 return 0;
243
244 i = 1;
245 #if HWLOC_BITS_PER_LONG >= 64
246 if ((x & 0xffffffff00000000ul)) {
247 x >>= 32;
248 i += 32;
249 }
250 #endif
251 if ((x & 0xffff0000u)) {
252 x >>= 16;
253 i += 16;
254 }
255 if ((x & 0xff00)) {
256 x >>= 8;
257 i += 8;
258 }
259 if ((x & 0xf0)) {
260 x >>= 4;
261 i += 4;
262 }
263 if ((x & 0xc)) {
264 x >>= 2;
265 i += 2;
266 }
267 if ((x & 0x2)) {
268 x >>= 1;
269 i += 1;
270 }
271
272 return i;
273 }
274 /* always define hwloc_flsl as a macro, to avoid renaming breakage */
275 #define hwloc_flsl hwloc_flsl_manual
276
277 #endif
278
279 #ifdef HWLOC_NEED_FLSL
280
281 /* We only have an int fls(int) implementation, build a long one. */
282
283 /* First make it 32 bits if it was only 16. */
284 static __hwloc_inline int
285 hwloc_fls32(unsigned long x) __hwloc_attribute_const;
286 static __hwloc_inline int
hwloc_fls32(unsigned long x)287 hwloc_fls32(unsigned long x)
288 {
289 #if HWLOC_BITS_PER_INT == 16
290 int low_fls, hi_fls;
291
292 hi_fls = hwloc_fls(x >> 16);
293 if (hi_fls)
294 return hi_fls + 16;
295
296 low_fls = hwloc_fls(x & 0xfffful);
297 if (low_fls)
298 return low_fls;
299
300 return 0;
301 #else
302 return hwloc_fls(x);
303 #endif
304 }
305
306 /* Then make it 64 bit if longs are. */
307 static __hwloc_inline int
308 hwloc_flsl_from_fls32(unsigned long x) __hwloc_attribute_const;
309 static __hwloc_inline int
hwloc_flsl_from_fls32(unsigned long x)310 hwloc_flsl_from_fls32(unsigned long x)
311 {
312 #if HWLOC_BITS_PER_LONG == 64
313 int low_fls, hi_fls;
314
315 hi_fls = hwloc_fls32(x >> 32);
316 if (hi_fls)
317 return hi_fls + 32;
318
319 low_fls = hwloc_fls32(x & 0xfffffffful);
320 if (low_fls)
321 return low_fls;
322
323 return 0;
324 #else
325 return hwloc_fls32(x);
326 #endif
327 }
328 /* always define hwloc_flsl as a macro, to avoid renaming breakage */
329 #define hwloc_flsl hwloc_flsl_from_fls32
330
331 #endif
332
333 static __hwloc_inline int
334 hwloc_weight_long(unsigned long w) __hwloc_attribute_const;
335 static __hwloc_inline int
hwloc_weight_long(unsigned long w)336 hwloc_weight_long(unsigned long w)
337 {
338 #if HWLOC_BITS_PER_LONG == 32
339 #if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__) >= 4)
340 return __builtin_popcount(w);
341 #else
342 unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
343 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
344 res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
345 res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
346 return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
347 #endif
348 #else /* HWLOC_BITS_PER_LONG == 32 */
349 #if (__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__) >= 4)
350 return __builtin_popcountll(w);
351 #else
352 unsigned long res;
353 res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul);
354 res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
355 res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful);
356 res = (res & 0x00FF00FF00FF00FFul) + ((res >> 8) & 0x00FF00FF00FF00FFul);
357 res = (res & 0x0000FFFF0000FFFFul) + ((res >> 16) & 0x0000FFFF0000FFFFul);
358 return (res & 0x00000000FFFFFFFFul) + ((res >> 32) & 0x00000000FFFFFFFFul);
359 #endif
360 #endif /* HWLOC_BITS_PER_LONG == 64 */
361 }
362
363 #if !HAVE_DECL_STRTOULL && defined(HAVE_STRTOULL)
364 unsigned long long int strtoull(const char *nptr, char **endptr, int base);
365 #endif
366
hwloc_strncasecmp(const char * s1,const char * s2,size_t n)367 static __hwloc_inline int hwloc_strncasecmp(const char *s1, const char *s2, size_t n)
368 {
369 #ifdef HWLOC_HAVE_DECL_STRNCASECMP
370 return strncasecmp(s1, s2, n);
371 #else
372 while (n) {
373 char c1 = tolower(*s1), c2 = tolower(*s2);
374 if (!c1 || !c2 || c1 != c2)
375 return c1-c2;
376 n--; s1++; s2++;
377 }
378 return 0;
379 #endif
380 }
381
382 /* Parse a PCI link speed (GT/s) string from Linux sysfs */
383 #ifdef HWLOC_LINUX_SYS
384 #include <stdlib.h> /* for atof() */
385 static __hwloc_inline float
hwloc_linux_pci_link_speed_from_string(const char * string)386 hwloc_linux_pci_link_speed_from_string(const char *string)
387 {
388 /* don't parse Gen1 with atof() since it expects a localized string
389 * while the kernel sysfs files aren't.
390 */
391 if (!strncmp(string, "2.5 ", 4))
392 /* "2.5 GT/s" is Gen1 with 8/10 encoding */
393 return 2.5 * .8;
394
395 /* also hardwire Gen2 since it also has a specific encoding */
396 if (!strncmp(string, "5 ", 2))
397 /* "5 GT/s" is Gen2 with 8/10 encoding */
398 return 5 * .8;
399
400 /* handle Gen3+ in a generic way */
401 return atof(string) * 128./130; /* Gen3+ encoding is 128/130 */
402 }
403 #endif
404
405 #if !HAVE_DECL_MODFF
406 #define modff(x,iptr) (float)modf((double)x,(double *)iptr)
407 #endif
408
409 #ifdef HWLOC_WIN_SYS
410 # ifndef HAVE_SSIZE_T
411 typedef SSIZE_T ssize_t;
412 # endif
413 # if !HAVE_DECL_STRTOULL && !defined(HAVE_STRTOULL)
414 # define strtoull _strtoui64
415 # endif
416 # ifndef S_ISREG
417 # define S_ISREG(m) ((m) & S_IFREG)
418 # endif
419 # ifndef S_ISDIR
420 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
421 # endif
422 # ifndef S_IRWXU
423 # define S_IRWXU 00700
424 # endif
425 # ifndef HWLOC_HAVE_DECL_STRCASECMP
426 # define strcasecmp _stricmp
427 # endif
428 # if !HAVE_DECL_SNPRINTF
429 # define snprintf _snprintf
430 # endif
431 # if HAVE_DECL__STRDUP
432 # define strdup _strdup
433 # endif
434 # if HAVE_DECL__PUTENV
435 # define putenv _putenv
436 # endif
437 #endif
438
439 #endif /* HWLOC_PRIVATE_MISC_H */
440