File: | gromacs/gmxlib/gmx_cpuid.c |
Location: | line 540, column 5 |
Description: | Value stored to 'max_stdfn' is never read |
1 | /* |
2 | * This file is part of the GROMACS molecular simulation package. |
3 | * |
4 | * Copyright (c) 2012,2013,2014, 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. |
8 | * |
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. |
13 | * |
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. |
18 | * |
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. |
23 | * |
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. |
31 | * |
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. |
34 | */ |
35 | #ifdef HAVE_CONFIG_H1 |
36 | #include <config.h> |
37 | #endif |
38 | |
39 | #ifdef HAVE_SCHED_H |
40 | #define _GNU_SOURCE |
41 | #include <sched.h> |
42 | #endif |
43 | |
44 | #include <stdio.h> |
45 | #include <stdlib.h> |
46 | #include <string.h> |
47 | #include <ctype.h> |
48 | #ifdef _MSC_VER |
49 | /* MSVC definition for __cpuid() */ |
50 | #include <intrin.h> |
51 | /* sysinfo functions */ |
52 | #include <windows.h> |
53 | #endif |
54 | #ifdef HAVE_UNISTD_H |
55 | /* sysconf() definition */ |
56 | #include <unistd.h> |
57 | #endif |
58 | |
59 | #include "gmx_cpuid.h" |
60 | |
61 | |
62 | |
63 | /* For convenience, and to enable configure-time invocation, we keep all architectures |
64 | * in a single file, but to avoid repeated ifdefs we set the overall architecture here. |
65 | */ |
66 | #ifdef GMX_TARGET_X86 |
67 | /* OK, it is x86, but can we execute cpuid? */ |
68 | #if defined(GMX_X86_GCC_INLINE_ASM) || ( defined(_MSC_VER) && ( (_MSC_VER > 1500) || (_MSC_VER == 1500 & _MSC_FULL_VER >= 150030729))) |
69 | # define GMX_CPUID_X86 |
70 | #endif |
71 | #endif |
72 | |
73 | /* Global constant character strings corresponding to our enumerated types */ |
74 | const char * |
75 | gmx_cpuid_vendor_string[GMX_CPUID_NVENDORS] = |
76 | { |
77 | "CannotDetect", |
78 | "Unknown", |
79 | "GenuineIntel", |
80 | "AuthenticAMD", |
81 | "Fujitsu", |
82 | "IBM" |
83 | }; |
84 | |
85 | const char * |
86 | gmx_cpuid_vendor_string_alternative[GMX_CPUID_NVENDORS] = |
87 | { |
88 | "CannotDetect", |
89 | "Unknown", |
90 | "GenuineIntel", |
91 | "AuthenticAMD", |
92 | "Fujitsu", |
93 | "ibm" /* Used on BlueGene/Q */ |
94 | }; |
95 | |
96 | const char * |
97 | gmx_cpuid_feature_string[GMX_CPUID_NFEATURES] = |
98 | { |
99 | "CannotDetect", |
100 | "aes", |
101 | "apic", |
102 | "avx", |
103 | "avx2", |
104 | "clfsh", |
105 | "cmov", |
106 | "cx8", |
107 | "cx16", |
108 | "f16c", |
109 | "fma", |
110 | "fma4", |
111 | "htt", |
112 | "lahf_lm", |
113 | "misalignsse", |
114 | "mmx", |
115 | "msr", |
116 | "nonstop_tsc", |
117 | "pcid", |
118 | "pclmuldq", |
119 | "pdcm", |
120 | "pdpe1gb", |
121 | "popcnt", |
122 | "pse", |
123 | "rdrnd", |
124 | "rdtscp", |
125 | "sse2", |
126 | "sse3", |
127 | "sse4a", |
128 | "sse4.1", |
129 | "sse4.2", |
130 | "ssse3", |
131 | "tdt", |
132 | "x2apic", |
133 | "xop" |
134 | }; |
135 | |
136 | const char * |
137 | gmx_cpuid_simd_string[GMX_CPUID_NSIMD] = |
138 | { |
139 | "CannotDetect", |
140 | "None", |
141 | "Reference", |
142 | "SSE2", |
143 | "SSE4.1", |
144 | "AVX_128_FMA", |
145 | "AVX_256", |
146 | "AVX2_256", |
147 | "Sparc64 HPC-ACE", |
148 | "IBM_QPX" |
149 | }; |
150 | |
151 | /* Max length of brand string */ |
152 | #define GMX_CPUID_BRAND_MAXLEN256 256 |
153 | |
154 | |
155 | /* Contents of the abstract datatype */ |
156 | struct gmx_cpuid |
157 | { |
158 | enum gmx_cpuid_vendor vendor; |
159 | char brand[GMX_CPUID_BRAND_MAXLEN256]; |
160 | int family; |
161 | int model; |
162 | int stepping; |
163 | /* Not using gmx_bool here, since this file must be possible to compile without simple.h */ |
164 | char feature[GMX_CPUID_NFEATURES]; |
165 | |
166 | /* Basic CPU topology information. For x86 this is a bit complicated since the topology differs between |
167 | * operating systems and sometimes even settings. For most other architectures you can likely just check |
168 | * the documentation and then write static information to these arrays rather than detecting on-the-fly. |
169 | */ |
170 | int have_cpu_topology; |
171 | int nproc; /* total number of logical processors from OS */ |
172 | int npackages; |
173 | int ncores_per_package; |
174 | int nhwthreads_per_core; |
175 | int * package_id; |
176 | int * core_id; /* Local core id in each package */ |
177 | int * hwthread_id; /* Local hwthread id in each core */ |
178 | int * locality_order; /* Processor indices sorted in locality order */ |
179 | }; |
180 | |
181 | |
182 | /* Simple routines to access the data structure. The initialization routine is |
183 | * further down since that needs to call other static routines in this file. |
184 | */ |
185 | enum gmx_cpuid_vendor |
186 | gmx_cpuid_vendor (gmx_cpuid_t cpuid) |
187 | { |
188 | return cpuid->vendor; |
189 | } |
190 | |
191 | |
192 | const char * |
193 | gmx_cpuid_brand (gmx_cpuid_t cpuid) |
194 | { |
195 | return cpuid->brand; |
196 | } |
197 | |
198 | int |
199 | gmx_cpuid_family (gmx_cpuid_t cpuid) |
200 | { |
201 | return cpuid->family; |
202 | } |
203 | |
204 | int |
205 | gmx_cpuid_model (gmx_cpuid_t cpuid) |
206 | { |
207 | return cpuid->model; |
208 | } |
209 | |
210 | int |
211 | gmx_cpuid_stepping (gmx_cpuid_t cpuid) |
212 | { |
213 | return cpuid->stepping; |
214 | } |
215 | |
216 | int |
217 | gmx_cpuid_feature (gmx_cpuid_t cpuid, |
218 | enum gmx_cpuid_feature feature) |
219 | { |
220 | return (cpuid->feature[feature] != 0); |
221 | } |
222 | |
223 | |
224 | |
225 | |
226 | /* What type of SIMD was compiled in, if any? */ |
227 | #ifdef GMX_SIMD_X86_AVX2_256 |
228 | static const enum gmx_cpuid_simd compiled_simd = GMX_CPUID_SIMD_X86_AVX2_256; |
229 | #elif defined GMX_SIMD_X86_AVX_256 |
230 | static const enum gmx_cpuid_simd compiled_simd = GMX_CPUID_SIMD_X86_AVX_256; |
231 | #elif defined GMX_SIMD_X86_AVX_128_FMA |
232 | static const enum gmx_cpuid_simd compiled_simd = GMX_CPUID_SIMD_X86_AVX_128_FMA; |
233 | #elif defined GMX_SIMD_X86_SSE4_1 |
234 | static const enum gmx_cpuid_simd compiled_simd = GMX_CPUID_SIMD_X86_SSE4_1; |
235 | #elif defined GMX_SIMD_X86_SSE2 |
236 | static const enum gmx_cpuid_simd compiled_simd = GMX_CPUID_SIMD_X86_SSE2; |
237 | #elif defined GMX_SIMD_SPARC64_HPC_ACE |
238 | static const enum gmx_cpuid_simd compiled_simd = GMX_CPUID_SIMD_SPARC64_HPC_ACE; |
239 | #elif defined GMX_SIMD_IBM_QPX |
240 | static const enum gmx_cpuid_simd compiled_simd = GMX_CPUID_SIMD_IBM_QPX; |
241 | #elif defined GMX_SIMD_REFERENCE |
242 | static const enum gmx_cpuid_simd compiled_simd = GMX_CPUID_SIMD_REFERENCE; |
243 | #else |
244 | static const enum gmx_cpuid_simd compiled_simd = GMX_CPUID_SIMD_NONE; |
245 | #endif |
246 | |
247 | |
248 | #ifdef GMX_CPUID_X86 |
249 | |
250 | /* Execute CPUID on x86 class CPUs. level sets function to exec, and the |
251 | * contents of register output is returned. See Intel/AMD docs for details. |
252 | * |
253 | * This version supports extended information where we can also have an input |
254 | * value in the ecx register. This is ignored for most levels, but some of them |
255 | * (e.g. level 0xB on Intel) use it. |
256 | */ |
257 | static int |
258 | execute_x86cpuid(unsigned int level, |
259 | unsigned int ecxval, |
260 | unsigned int * eax, |
261 | unsigned int * ebx, |
262 | unsigned int * ecx, |
263 | unsigned int * edx) |
264 | { |
265 | int rc = 0; |
266 | |
267 | /* Currently CPUID is only supported (1) if we can use an instruction on MSVC, or (2) |
268 | * if the compiler handles GNU-style inline assembly. |
269 | */ |
270 | |
271 | #if (defined _MSC_VER) |
272 | int CPUInfo[4]; |
273 | |
274 | #if (_MSC_VER > 1500) || (_MSC_VER == 1500 & _MSC_FULL_VER >= 150030729) |
275 | /* MSVC 9.0 SP1 or later */ |
276 | __cpuidex(CPUInfo, level, ecxval); |
277 | rc = 0; |
278 | #else |
279 | __cpuid(CPUInfo, level); |
280 | /* Set an error code if the user wanted a non-zero ecxval, since we did not have cpuidex */ |
281 | rc = (ecxval > 0) ? -1 : 0; |
282 | #endif |
283 | *eax = CPUInfo[0]; |
284 | *ebx = CPUInfo[1]; |
285 | *ecx = CPUInfo[2]; |
286 | *edx = CPUInfo[3]; |
287 | |
288 | #elif (defined GMX_X86_GCC_INLINE_ASM) |
289 | /* for now this means GMX_X86_GCC_INLINE_ASM should be defined, |
290 | * but there might be more options added in the future. |
291 | */ |
292 | *eax = level; |
293 | *ecx = ecxval; |
294 | *ebx = 0; |
295 | *edx = 0; |
296 | #if defined(__i386__) && defined(__PIC__2) |
297 | /* Avoid clobbering the global offset table in 32-bit pic code (ebx register) */ |
298 | __asm__ __volatile__ ("xchgl %%ebx, %1 \n\t" |
299 | "cpuid \n\t" |
300 | "xchgl %%ebx, %1 \n\t" |
301 | : "+a" (*eax), "+r" (*ebx), "+c" (*ecx), "+d" (*edx)); |
302 | #else |
303 | /* i386 without PIC, or x86-64. Things are easy and we can clobber any reg we want :-) */ |
304 | __asm__ __volatile__ ("cpuid \n\t" |
305 | : "+a" (*eax), "+b" (*ebx), "+c" (*ecx), "+d" (*edx)); |
306 | #endif |
307 | rc = 0; |
308 | #else |
309 | /* Death and horror! |
310 | * Apparently this is an x86 platform where we don't know how to call cpuid. |
311 | * |
312 | * This is REALLY bad, since we will lose all Gromacs SIMD support. |
313 | */ |
314 | *eax = 0; |
315 | *ebx = 0; |
316 | *ecx = 0; |
317 | *edx = 0; |
318 | |
319 | rc = -1; |
320 | #endif |
321 | return rc; |
322 | } |
323 | |
324 | |
325 | /* Identify CPU features common to Intel & AMD - mainly brand string, |
326 | * version and some features. Vendor has already been detected outside this. |
327 | */ |
328 | static int |
329 | cpuid_check_common_x86(gmx_cpuid_t cpuid) |
330 | { |
331 | int fn, max_stdfn, max_extfn; |
332 | unsigned int eax, ebx, ecx, edx; |
333 | char str[GMX_CPUID_BRAND_MAXLEN256]; |
334 | char * p; |
335 | |
336 | /* Find largest standard/extended function input value */ |
337 | execute_x86cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); |
338 | max_stdfn = eax; |
339 | execute_x86cpuid(0x80000000, 0, &eax, &ebx, &ecx, &edx); |
340 | max_extfn = eax; |
341 | |
342 | p = str; |
343 | if (max_extfn >= 0x80000005) |
344 | { |
345 | /* Get CPU brand string */ |
346 | for (fn = 0x80000002; fn < 0x80000005; fn++) |
347 | { |
348 | execute_x86cpuid(fn, 0, &eax, &ebx, &ecx, &edx); |
349 | memcpy(p, &eax, 4); |
350 | memcpy(p+4, &ebx, 4); |
351 | memcpy(p+8, &ecx, 4); |
352 | memcpy(p+12, &edx, 4); |
353 | p += 16; |
354 | } |
355 | *p = '\0'; |
356 | |
357 | /* Remove empty initial space */ |
358 | p = str; |
359 | while (isspace(*(p))((*__ctype_b_loc ())[(int) ((*(p)))] & (unsigned short int ) _ISspace)) |
360 | { |
361 | p++; |
362 | } |
363 | strncpy(cpuid->brand, p, GMX_CPUID_BRAND_MAXLEN)__builtin_strncpy (cpuid->brand, p, 256); |
364 | } |
365 | else |
366 | { |
367 | strncpy(cpuid->brand, "Unknown CPU brand", GMX_CPUID_BRAND_MAXLEN)__builtin_strncpy (cpuid->brand, "Unknown CPU brand", 256); |
368 | } |
369 | |
370 | /* Find basic CPU properties */ |
371 | if (max_stdfn >= 1) |
372 | { |
373 | execute_x86cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); |
374 | |
375 | cpuid->family = ((eax & 0x0FF00000) >> 20) + ((eax & 0x00000F00) >> 8); |
376 | /* Note that extended model should be shifted left 4, so only shift right 12 iso 16. */ |
377 | cpuid->model = ((eax & 0x000F0000) >> 12) + ((eax & 0x000000F0) >> 4); |
378 | cpuid->stepping = (eax & 0x0000000F); |
379 | |
380 | /* Feature flags common to AMD and intel */ |
381 | cpuid->feature[GMX_CPUID_FEATURE_X86_SSE3] = (ecx & (1 << 0)) != 0; |
382 | cpuid->feature[GMX_CPUID_FEATURE_X86_PCLMULDQ] = (ecx & (1 << 1)) != 0; |
383 | cpuid->feature[GMX_CPUID_FEATURE_X86_SSSE3] = (ecx & (1 << 9)) != 0; |
384 | cpuid->feature[GMX_CPUID_FEATURE_X86_FMA] = (ecx & (1 << 12)) != 0; |
385 | cpuid->feature[GMX_CPUID_FEATURE_X86_CX16] = (ecx & (1 << 13)) != 0; |
386 | cpuid->feature[GMX_CPUID_FEATURE_X86_SSE4_1] = (ecx & (1 << 19)) != 0; |
387 | cpuid->feature[GMX_CPUID_FEATURE_X86_SSE4_2] = (ecx & (1 << 20)) != 0; |
388 | cpuid->feature[GMX_CPUID_FEATURE_X86_POPCNT] = (ecx & (1 << 23)) != 0; |
389 | cpuid->feature[GMX_CPUID_FEATURE_X86_AES] = (ecx & (1 << 25)) != 0; |
390 | cpuid->feature[GMX_CPUID_FEATURE_X86_AVX] = (ecx & (1 << 28)) != 0; |
391 | cpuid->feature[GMX_CPUID_FEATURE_X86_F16C] = (ecx & (1 << 29)) != 0; |
392 | cpuid->feature[GMX_CPUID_FEATURE_X86_RDRND] = (ecx & (1 << 30)) != 0; |
393 | |
394 | cpuid->feature[GMX_CPUID_FEATURE_X86_PSE] = (edx & (1 << 3)) != 0; |
395 | cpuid->feature[GMX_CPUID_FEATURE_X86_MSR] = (edx & (1 << 5)) != 0; |
396 | cpuid->feature[GMX_CPUID_FEATURE_X86_CX8] = (edx & (1 << 8)) != 0; |
397 | cpuid->feature[GMX_CPUID_FEATURE_X86_APIC] = (edx & (1 << 9)) != 0; |
398 | cpuid->feature[GMX_CPUID_FEATURE_X86_CMOV] = (edx & (1 << 15)) != 0; |
399 | cpuid->feature[GMX_CPUID_FEATURE_X86_CLFSH] = (edx & (1 << 19)) != 0; |
400 | cpuid->feature[GMX_CPUID_FEATURE_X86_MMX] = (edx & (1 << 23)) != 0; |
401 | cpuid->feature[GMX_CPUID_FEATURE_X86_SSE2] = (edx & (1 << 26)) != 0; |
402 | cpuid->feature[GMX_CPUID_FEATURE_X86_HTT] = (edx & (1 << 28)) != 0; |
403 | } |
404 | else |
405 | { |
406 | cpuid->family = -1; |
407 | cpuid->model = -1; |
408 | cpuid->stepping = -1; |
409 | } |
410 | |
411 | if (max_extfn >= 0x80000001) |
412 | { |
413 | execute_x86cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx); |
414 | cpuid->feature[GMX_CPUID_FEATURE_X86_LAHF_LM] = (ecx & (1 << 0)) != 0; |
415 | cpuid->feature[GMX_CPUID_FEATURE_X86_PDPE1GB] = (edx & (1 << 26)) != 0; |
416 | cpuid->feature[GMX_CPUID_FEATURE_X86_RDTSCP] = (edx & (1 << 27)) != 0; |
417 | } |
418 | |
419 | if (max_extfn >= 0x80000007) |
420 | { |
421 | execute_x86cpuid(0x80000007, 0, &eax, &ebx, &ecx, &edx); |
422 | cpuid->feature[GMX_CPUID_FEATURE_X86_NONSTOP_TSC] = (edx & (1 << 8)) != 0; |
423 | } |
424 | return 0; |
425 | } |
426 | |
427 | /* This routine returns the number of unique different elements found in the array, |
428 | * and renumbers these starting from 0. For example, the array {0,1,2,8,9,10,8,9,10,0,1,2} |
429 | * will be rewritten to {0,1,2,3,4,5,3,4,5,0,1,2}, and it returns 6 for the |
430 | * number of unique elements. |
431 | */ |
432 | static int |
433 | cpuid_renumber_elements(int *data, int n) |
434 | { |
435 | int *unique; |
436 | int i, j, nunique, found; |
437 | |
438 | unique = malloc(sizeof(int)*n); |
439 | |
440 | nunique = 0; |
441 | for (i = 0; i < n; i++) |
442 | { |
443 | for (j = 0, found = 0; j < nunique && !found; j++) |
444 | { |
445 | found = (data[i] == unique[j]); |
446 | } |
447 | if (!found) |
448 | { |
449 | /* Insert in sorted order! */ |
450 | for (j = nunique++; j > 0 && unique[j-1] > data[i]; j--) |
451 | { |
452 | unique[j] = unique[j-1]; |
453 | } |
454 | unique[j] = data[i]; |
455 | } |
456 | } |
457 | /* renumber */ |
458 | for (i = 0; i < n; i++) |
459 | { |
460 | for (j = 0; j < nunique; j++) |
461 | { |
462 | if (data[i] == unique[j]) |
463 | { |
464 | data[i] = j; |
465 | } |
466 | } |
467 | } |
468 | return nunique; |
469 | } |
470 | |
471 | /* APIC IDs, or everything you wanted to know about your x86 cores but were afraid to ask... |
472 | * |
473 | * Raw APIC IDs are unfortunately somewhat dirty. For technical reasons they are assigned |
474 | * in power-of-2 chunks, and even then there are no guarantees about specific numbers - all |
475 | * we know is that the part for each thread/core/package is unique, and how many bits are |
476 | * reserved for that part. |
477 | * This routine does internal renumbering so we get continuous indices, and also |
478 | * decodes the actual number of packages,cores-per-package and hwthreads-per-core. |
479 | * Returns: 0 on success, non-zero on failure. |
480 | */ |
481 | static int |
482 | cpuid_x86_decode_apic_id(gmx_cpuid_t cpuid, int *apic_id, int core_bits, int hwthread_bits) |
483 | { |
484 | int i, idx; |
485 | int hwthread_mask, core_mask_after_shift; |
486 | |
487 | cpuid->hwthread_id = malloc(sizeof(int)*cpuid->nproc); |
488 | cpuid->core_id = malloc(sizeof(int)*cpuid->nproc); |
489 | cpuid->package_id = malloc(sizeof(int)*cpuid->nproc); |
490 | cpuid->locality_order = malloc(sizeof(int)*cpuid->nproc); |
491 | |
492 | hwthread_mask = (1 << hwthread_bits) - 1; |
493 | core_mask_after_shift = (1 << core_bits) - 1; |
494 | |
495 | for (i = 0; i < cpuid->nproc; i++) |
496 | { |
497 | cpuid->hwthread_id[i] = apic_id[i] & hwthread_mask; |
498 | cpuid->core_id[i] = (apic_id[i] >> hwthread_bits) & core_mask_after_shift; |
499 | cpuid->package_id[i] = apic_id[i] >> (core_bits + hwthread_bits); |
500 | } |
501 | |
502 | cpuid->npackages = cpuid_renumber_elements(cpuid->package_id, cpuid->nproc); |
503 | cpuid->ncores_per_package = cpuid_renumber_elements(cpuid->core_id, cpuid->nproc); |
504 | cpuid->nhwthreads_per_core = cpuid_renumber_elements(cpuid->hwthread_id, cpuid->nproc); |
505 | |
506 | /* now check for consistency */ |
507 | if ( (cpuid->npackages * cpuid->ncores_per_package * |
508 | cpuid->nhwthreads_per_core) != cpuid->nproc) |
509 | { |
510 | /* the packages/cores-per-package/hwthreads-per-core counts are |
511 | inconsistent. */ |
512 | return -1; |
513 | } |
514 | |
515 | /* Create a locality order array, i.e. first all resources in package0, which in turn |
516 | * are sorted so we first have all resources in core0, where threads are sorted in order, etc. |
517 | */ |
518 | |
519 | for (i = 0; i < cpuid->nproc; i++) |
520 | { |
521 | idx = (cpuid->package_id[i]*cpuid->ncores_per_package + cpuid->core_id[i])*cpuid->nhwthreads_per_core + cpuid->hwthread_id[i]; |
522 | cpuid->locality_order[idx] = i; |
523 | } |
524 | return 0; |
525 | } |
526 | |
527 | |
528 | /* Detection of AMD-specific CPU features */ |
529 | static int |
530 | cpuid_check_amd_x86(gmx_cpuid_t cpuid) |
531 | { |
532 | int max_stdfn, max_extfn, ret; |
533 | unsigned int eax, ebx, ecx, edx; |
534 | int hwthread_bits, core_bits; |
535 | int * apic_id; |
536 | |
537 | cpuid_check_common_x86(cpuid); |
538 | |
539 | execute_x86cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); |
540 | max_stdfn = eax; |
Value stored to 'max_stdfn' is never read | |
541 | |
542 | execute_x86cpuid(0x80000000, 0, &eax, &ebx, &ecx, &edx); |
543 | max_extfn = eax; |
544 | |
545 | if (max_extfn >= 0x80000001) |
546 | { |
547 | execute_x86cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx); |
548 | |
549 | cpuid->feature[GMX_CPUID_FEATURE_X86_SSE4A] = (ecx & (1 << 6)) != 0; |
550 | cpuid->feature[GMX_CPUID_FEATURE_X86_MISALIGNSSE] = (ecx & (1 << 7)) != 0; |
551 | cpuid->feature[GMX_CPUID_FEATURE_X86_XOP] = (ecx & (1 << 11)) != 0; |
552 | cpuid->feature[GMX_CPUID_FEATURE_X86_FMA4] = (ecx & (1 << 16)) != 0; |
553 | } |
554 | |
555 | /* Query APIC information on AMD */ |
556 | if (max_extfn >= 0x80000008) |
557 | { |
558 | #if (defined HAVE_SCHED_H && defined HAVE_SCHED_SETAFFINITY && defined HAVE_SYSCONF && defined __linux__1) |
559 | /* Linux */ |
560 | unsigned int i; |
561 | cpu_set_t cpuset, save_cpuset; |
562 | cpuid->nproc = sysconf(_SC_NPROCESSORS_ONLN_SC_NPROCESSORS_ONLN); |
563 | apic_id = malloc(sizeof(int)*cpuid->nproc); |
564 | sched_getaffinity(0, sizeof(cpu_set_t), &save_cpuset); |
565 | /* Get APIC id from each core */ |
566 | CPU_ZERO(&cpuset)do __builtin_memset (&cpuset, '\0', sizeof (cpu_set_t)); while (0); |
567 | for (i = 0; i < cpuid->nproc; i++) |
568 | { |
569 | CPU_SET(i, &cpuset)(__extension__ ({ size_t __cpu = (i); __cpu / 8 < (sizeof ( cpu_set_t)) ? (((__cpu_mask *) ((&cpuset)->__bits))[(( __cpu) / (8 * sizeof (__cpu_mask)))] |= ((__cpu_mask) 1 << ((__cpu) % (8 * sizeof (__cpu_mask))))) : 0; })); |
570 | sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); |
571 | execute_x86cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); |
572 | apic_id[i] = ebx >> 24; |
573 | CPU_CLR(i, &cpuset)(__extension__ ({ size_t __cpu = (i); __cpu / 8 < (sizeof ( cpu_set_t)) ? (((__cpu_mask *) ((&cpuset)->__bits))[(( __cpu) / (8 * sizeof (__cpu_mask)))] &= ~((__cpu_mask) 1 << ((__cpu) % (8 * sizeof (__cpu_mask))))) : 0; })); |
574 | } |
575 | /* Reset affinity to the value it had when calling this routine */ |
576 | sched_setaffinity(0, sizeof(cpu_set_t), &save_cpuset); |
577 | #define CPUID_HAVE_APIC |
578 | #elif defined GMX_NATIVE_WINDOWS |
579 | /* Windows */ |
580 | DWORD_PTR i; |
581 | SYSTEM_INFO sysinfo; |
582 | unsigned int save_affinity, affinity; |
583 | GetSystemInfo( &sysinfo ); |
584 | cpuid->nproc = sysinfo.dwNumberOfProcessors; |
585 | apic_id = malloc(sizeof(int)*cpuid->nproc); |
586 | /* Get previous affinity mask */ |
587 | save_affinity = SetThreadAffinityMask(GetCurrentThread(), 1); |
588 | for (i = 0; i < cpuid->nproc; i++) |
589 | { |
590 | SetThreadAffinityMask(GetCurrentThread(), (((DWORD_PTR)1)<<i)); |
591 | Sleep(0); |
592 | execute_x86cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); |
593 | apic_id[i] = ebx >> 24; |
594 | } |
595 | SetThreadAffinityMask(GetCurrentThread(), save_affinity); |
596 | #define CPUID_HAVE_APIC |
597 | #endif |
598 | #ifdef CPUID_HAVE_APIC |
599 | /* AMD does not support SMT yet - there are no hwthread bits in apic ID */ |
600 | hwthread_bits = 0; |
601 | /* Get number of core bits in apic ID - try modern extended method first */ |
602 | execute_x86cpuid(0x80000008, 0, &eax, &ebx, &ecx, &edx); |
603 | core_bits = (ecx >> 12) & 0xf; |
604 | if (core_bits == 0) |
605 | { |
606 | /* Legacy method for old single/dual core AMD CPUs */ |
607 | int i = ecx & 0xF; |
608 | for (core_bits = 0; (i>>core_bits) > 0; core_bits++) |
609 | { |
610 | ; |
611 | } |
612 | } |
613 | ret = cpuid_x86_decode_apic_id(cpuid, apic_id, core_bits, |
614 | hwthread_bits); |
615 | cpuid->have_cpu_topology = (ret == 0); |
616 | #endif |
617 | } |
618 | return 0; |
619 | } |
620 | |
621 | /* Detection of Intel-specific CPU features */ |
622 | static int |
623 | cpuid_check_intel_x86(gmx_cpuid_t cpuid) |
624 | { |
625 | unsigned int max_stdfn, max_extfn, ret; |
626 | unsigned int eax, ebx, ecx, edx; |
627 | unsigned int max_logical_cores, max_physical_cores; |
628 | int hwthread_bits, core_bits; |
629 | int * apic_id; |
630 | |
631 | cpuid_check_common_x86(cpuid); |
632 | |
633 | execute_x86cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); |
634 | max_stdfn = eax; |
635 | |
636 | execute_x86cpuid(0x80000000, 0, &eax, &ebx, &ecx, &edx); |
637 | max_extfn = eax; |
638 | |
639 | if (max_stdfn >= 1) |
640 | { |
641 | execute_x86cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); |
642 | cpuid->feature[GMX_CPUID_FEATURE_X86_PDCM] = (ecx & (1 << 15)) != 0; |
643 | cpuid->feature[GMX_CPUID_FEATURE_X86_PCID] = (ecx & (1 << 17)) != 0; |
644 | cpuid->feature[GMX_CPUID_FEATURE_X86_X2APIC] = (ecx & (1 << 21)) != 0; |
645 | cpuid->feature[GMX_CPUID_FEATURE_X86_TDT] = (ecx & (1 << 24)) != 0; |
646 | } |
647 | |
648 | if (max_stdfn >= 7) |
649 | { |
650 | execute_x86cpuid(0x7, 0, &eax, &ebx, &ecx, &edx); |
651 | cpuid->feature[GMX_CPUID_FEATURE_X86_AVX2] = (ebx & (1 << 5)) != 0; |
652 | } |
653 | |
654 | /* Check whether Hyper-Threading is enabled, not only supported */ |
655 | if (cpuid->feature[GMX_CPUID_FEATURE_X86_HTT] && max_stdfn >= 4) |
656 | { |
657 | execute_x86cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); |
658 | max_logical_cores = (ebx >> 16) & 0x0FF; |
659 | execute_x86cpuid(0x4, 0, &eax, &ebx, &ecx, &edx); |
660 | max_physical_cores = ((eax >> 26) & 0x3F) + 1; |
661 | |
662 | /* Clear HTT flag if we only have 1 logical core per physical */ |
663 | if (max_logical_cores/max_physical_cores < 2) |
664 | { |
665 | cpuid->feature[GMX_CPUID_FEATURE_X86_HTT] = 0; |
666 | } |
667 | } |
668 | |
669 | if (max_stdfn >= 0xB) |
670 | { |
671 | /* Query x2 APIC information from cores */ |
672 | #if (defined HAVE_SCHED_H && defined HAVE_SCHED_SETAFFINITY && defined HAVE_SYSCONF && defined __linux__1) |
673 | /* Linux */ |
674 | unsigned int i; |
675 | cpu_set_t cpuset, save_cpuset; |
676 | cpuid->nproc = sysconf(_SC_NPROCESSORS_ONLN_SC_NPROCESSORS_ONLN); |
677 | apic_id = malloc(sizeof(int)*cpuid->nproc); |
678 | sched_getaffinity(0, sizeof(cpu_set_t), &save_cpuset); |
679 | /* Get x2APIC ID from each hardware thread */ |
680 | CPU_ZERO(&cpuset)do __builtin_memset (&cpuset, '\0', sizeof (cpu_set_t)); while (0); |
681 | for (i = 0; i < cpuid->nproc; i++) |
682 | { |
683 | CPU_SET(i, &cpuset)(__extension__ ({ size_t __cpu = (i); __cpu / 8 < (sizeof ( cpu_set_t)) ? (((__cpu_mask *) ((&cpuset)->__bits))[(( __cpu) / (8 * sizeof (__cpu_mask)))] |= ((__cpu_mask) 1 << ((__cpu) % (8 * sizeof (__cpu_mask))))) : 0; })); |
684 | sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); |
685 | execute_x86cpuid(0xB, 0, &eax, &ebx, &ecx, &edx); |
686 | apic_id[i] = edx; |
687 | CPU_CLR(i, &cpuset)(__extension__ ({ size_t __cpu = (i); __cpu / 8 < (sizeof ( cpu_set_t)) ? (((__cpu_mask *) ((&cpuset)->__bits))[(( __cpu) / (8 * sizeof (__cpu_mask)))] &= ~((__cpu_mask) 1 << ((__cpu) % (8 * sizeof (__cpu_mask))))) : 0; })); |
688 | } |
689 | /* Reset affinity to the value it had when calling this routine */ |
690 | sched_setaffinity(0, sizeof(cpu_set_t), &save_cpuset); |
691 | #define CPUID_HAVE_APIC |
692 | #elif defined GMX_NATIVE_WINDOWS |
693 | /* Windows */ |
694 | DWORD_PTR i; |
695 | SYSTEM_INFO sysinfo; |
696 | unsigned int save_affinity, affinity; |
697 | GetSystemInfo( &sysinfo ); |
698 | cpuid->nproc = sysinfo.dwNumberOfProcessors; |
699 | apic_id = malloc(sizeof(int)*cpuid->nproc); |
700 | /* Get previous affinity mask */ |
701 | save_affinity = SetThreadAffinityMask(GetCurrentThread(), 1); |
702 | for (i = 0; i < cpuid->nproc; i++) |
703 | { |
704 | SetThreadAffinityMask(GetCurrentThread(), (((DWORD_PTR)1)<<i)); |
705 | Sleep(0); |
706 | execute_x86cpuid(0xB, 0, &eax, &ebx, &ecx, &edx); |
707 | apic_id[i] = edx; |
708 | } |
709 | SetThreadAffinityMask(GetCurrentThread(), save_affinity); |
710 | #define CPUID_HAVE_APIC |
711 | #endif |
712 | #ifdef CPUID_HAVE_APIC |
713 | execute_x86cpuid(0xB, 0, &eax, &ebx, &ecx, &edx); |
714 | hwthread_bits = eax & 0x1F; |
715 | execute_x86cpuid(0xB, 1, &eax, &ebx, &ecx, &edx); |
716 | core_bits = (eax & 0x1F) - hwthread_bits; |
717 | ret = cpuid_x86_decode_apic_id(cpuid, apic_id, core_bits, |
718 | hwthread_bits); |
719 | cpuid->have_cpu_topology = (ret == 0); |
720 | #endif |
721 | } |
722 | return 0; |
723 | } |
724 | #endif /* GMX_CPUID_X86 */ |
725 | |
726 | |
727 | |
728 | |
729 | static void |
730 | chomp_substring_before_colon(const char *in, char *s, int maxlength) |
731 | { |
732 | char *p; |
733 | strncpy(s, in, maxlength)__builtin_strncpy (s, in, maxlength); |
734 | p = strchr(s, ':')(__extension__ (__builtin_constant_p (':') && !__builtin_constant_p (s) && (':') == '\0' ? (char *) __rawmemchr (s, ':') : __builtin_strchr (s, ':'))); |
735 | if (p != NULL((void*)0)) |
736 | { |
737 | *p = '\0'; |
738 | while (isspace(*(--p))((*__ctype_b_loc ())[(int) ((*(--p)))] & (unsigned short int ) _ISspace) && (p >= s)) |
739 | { |
740 | *p = '\0'; |
741 | } |
742 | } |
743 | else |
744 | { |
745 | *s = '\0'; |
746 | } |
747 | } |
748 | |
749 | static void |
750 | chomp_substring_after_colon(const char *in, char *s, int maxlength) |
751 | { |
752 | char *p; |
753 | if ( (p = strchr(in, ':')(__extension__ (__builtin_constant_p (':') && !__builtin_constant_p (in) && (':') == '\0' ? (char *) __rawmemchr (in, ':' ) : __builtin_strchr (in, ':')))) != NULL((void*)0)) |
754 | { |
755 | p++; |
756 | while (isspace(*p)((*__ctype_b_loc ())[(int) ((*p))] & (unsigned short int) _ISspace)) |
757 | { |
758 | p++; |
759 | } |
760 | strncpy(s, p, maxlength)__builtin_strncpy (s, p, maxlength); |
761 | p = s+strlen(s); |
762 | while (isspace(*(--p))((*__ctype_b_loc ())[(int) ((*(--p)))] & (unsigned short int ) _ISspace) && (p >= s)) |
763 | { |
764 | *p = '\0'; |
765 | } |
766 | } |
767 | else |
768 | { |
769 | *s = '\0'; |
770 | } |
771 | } |
772 | |
773 | /* Try to find the vendor of the current CPU, so we know what specific |
774 | * detection routine to call. |
775 | */ |
776 | static enum gmx_cpuid_vendor |
777 | cpuid_check_vendor(void) |
778 | { |
779 | enum gmx_cpuid_vendor i, vendor; |
780 | /* Register data used on x86 */ |
781 | unsigned int eax, ebx, ecx, edx; |
782 | char vendorstring[13]; |
783 | FILE * fp; |
784 | char buffer[255], before_colon[255], after_colon[255]; |
785 | |
786 | /* Set default first */ |
787 | vendor = GMX_CPUID_VENDOR_UNKNOWN; |
788 | |
789 | #ifdef GMX_CPUID_X86 |
790 | execute_x86cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); |
791 | |
792 | memcpy(vendorstring, &ebx, 4); |
793 | memcpy(vendorstring+4, &edx, 4); |
794 | memcpy(vendorstring+8, &ecx, 4); |
795 | |
796 | vendorstring[12] = '\0'; |
797 | |
798 | for (i = GMX_CPUID_VENDOR_UNKNOWN; i < GMX_CPUID_NVENDORS; i++) |
799 | { |
800 | if (!strncmp(vendorstring, gmx_cpuid_vendor_string[i], 12)(__extension__ (__builtin_constant_p (12) && ((__builtin_constant_p (vendorstring) && strlen (vendorstring) < ((size_t ) (12))) || (__builtin_constant_p (gmx_cpuid_vendor_string[i] ) && strlen (gmx_cpuid_vendor_string[i]) < ((size_t ) (12)))) ? __extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (vendorstring) && __builtin_constant_p (gmx_cpuid_vendor_string [i]) && (__s1_len = strlen (vendorstring), __s2_len = strlen (gmx_cpuid_vendor_string[i]), (!((size_t)(const void * )((vendorstring) + 1) - (size_t)(const void *)(vendorstring) == 1) || __s1_len >= 4) && (!((size_t)(const void *) ((gmx_cpuid_vendor_string[i]) + 1) - (size_t)(const void *)(gmx_cpuid_vendor_string [i]) == 1) || __s2_len >= 4)) ? __builtin_strcmp (vendorstring , gmx_cpuid_vendor_string[i]) : (__builtin_constant_p (vendorstring ) && ((size_t)(const void *)((vendorstring) + 1) - (size_t )(const void *)(vendorstring) == 1) && (__s1_len = strlen (vendorstring), __s1_len < 4) ? (__builtin_constant_p (gmx_cpuid_vendor_string [i]) && ((size_t)(const void *)((gmx_cpuid_vendor_string [i]) + 1) - (size_t)(const void *)(gmx_cpuid_vendor_string[i] ) == 1) ? __builtin_strcmp (vendorstring, gmx_cpuid_vendor_string [i]) : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (gmx_cpuid_vendor_string[i]); int __result = (((const unsigned char *) (const char *) (vendorstring))[0 ] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (vendorstring ))[1] - __s2[1]); if (__s1_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (vendorstring ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (vendorstring ))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ( gmx_cpuid_vendor_string[i]) && ((size_t)(const void * )((gmx_cpuid_vendor_string[i]) + 1) - (size_t)(const void *)( gmx_cpuid_vendor_string[i]) == 1) && (__s2_len = strlen (gmx_cpuid_vendor_string[i]), __s2_len < 4) ? (__builtin_constant_p (vendorstring) && ((size_t)(const void *)((vendorstring ) + 1) - (size_t)(const void *)(vendorstring) == 1) ? __builtin_strcmp (vendorstring, gmx_cpuid_vendor_string[i]) : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (vendorstring); int __result = (((const unsigned char *) (const char *) (gmx_cpuid_vendor_string[i]))[0] - __s2[0] ); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (gmx_cpuid_vendor_string [i]))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (gmx_cpuid_vendor_string [i]))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (gmx_cpuid_vendor_string [i]))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp ( vendorstring, gmx_cpuid_vendor_string[i])))); }) : strncmp (vendorstring , gmx_cpuid_vendor_string[i], 12)))) |
801 | { |
802 | vendor = i; |
803 | } |
804 | } |
805 | #elif defined(__linux__1) || defined(__linux1) |
806 | /* General Linux. Try to get CPU vendor from /proc/cpuinfo */ |
807 | if ( (fp = fopen("/proc/cpuinfo", "r")) != NULL((void*)0)) |
808 | { |
809 | while ( (vendor == GMX_CPUID_VENDOR_UNKNOWN) && (fgets(buffer, sizeof(buffer), fp) != NULL((void*)0))) |
810 | { |
811 | chomp_substring_before_colon(buffer, before_colon, sizeof(before_colon)); |
812 | /* Intel/AMD use "vendor_id", IBM "vendor"(?) or "model". Fujitsu "manufacture". Add others if you have them! */ |
813 | if (!strcmp(before_colon, "vendor_id")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (before_colon) && __builtin_constant_p ("vendor_id") && (__s1_len = strlen (before_colon), __s2_len = strlen ("vendor_id"), (!((size_t)(const void *)((before_colon) + 1) - (size_t)(const void *)(before_colon) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("vendor_id") + 1) - (size_t)(const void *)("vendor_id") == 1) || __s2_len >= 4 )) ? __builtin_strcmp (before_colon, "vendor_id") : (__builtin_constant_p (before_colon) && ((size_t)(const void *)((before_colon ) + 1) - (size_t)(const void *)(before_colon) == 1) && (__s1_len = strlen (before_colon), __s1_len < 4) ? (__builtin_constant_p ("vendor_id") && ((size_t)(const void *)(("vendor_id" ) + 1) - (size_t)(const void *)("vendor_id") == 1) ? __builtin_strcmp (before_colon, "vendor_id") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("vendor_id" ); int __result = (((const unsigned char *) (const char *) (before_colon ))[0] - __s2[0]); if (__s1_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (before_colon ))[1] - __s2[1]); if (__s1_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (before_colon ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (before_colon ))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ( "vendor_id") && ((size_t)(const void *)(("vendor_id") + 1) - (size_t)(const void *)("vendor_id") == 1) && ( __s2_len = strlen ("vendor_id"), __s2_len < 4) ? (__builtin_constant_p (before_colon) && ((size_t)(const void *)((before_colon ) + 1) - (size_t)(const void *)(before_colon) == 1) ? __builtin_strcmp (before_colon, "vendor_id") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (before_colon ); int __result = (((const unsigned char *) (const char *) ("vendor_id" ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("vendor_id" ))[1] - __s2[1]); if (__s2_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("vendor_id" ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) ("vendor_id" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (before_colon , "vendor_id")))); }) |
814 | || !strcmp(before_colon, "vendor")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (before_colon) && __builtin_constant_p ("vendor") && (__s1_len = strlen (before_colon), __s2_len = strlen ("vendor" ), (!((size_t)(const void *)((before_colon) + 1) - (size_t)(const void *)(before_colon) == 1) || __s1_len >= 4) && ( !((size_t)(const void *)(("vendor") + 1) - (size_t)(const void *)("vendor") == 1) || __s2_len >= 4)) ? __builtin_strcmp ( before_colon, "vendor") : (__builtin_constant_p (before_colon ) && ((size_t)(const void *)((before_colon) + 1) - (size_t )(const void *)(before_colon) == 1) && (__s1_len = strlen (before_colon), __s1_len < 4) ? (__builtin_constant_p ("vendor" ) && ((size_t)(const void *)(("vendor") + 1) - (size_t )(const void *)("vendor") == 1) ? __builtin_strcmp (before_colon , "vendor") : (__extension__ ({ const unsigned char *__s2 = ( const unsigned char *) (const char *) ("vendor"); int __result = (((const unsigned char *) (const char *) (before_colon))[0 ] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (before_colon ))[1] - __s2[1]); if (__s1_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (before_colon ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (before_colon ))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ( "vendor") && ((size_t)(const void *)(("vendor") + 1) - (size_t)(const void *)("vendor") == 1) && (__s2_len = strlen ("vendor"), __s2_len < 4) ? (__builtin_constant_p ( before_colon) && ((size_t)(const void *)((before_colon ) + 1) - (size_t)(const void *)(before_colon) == 1) ? __builtin_strcmp (before_colon, "vendor") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (before_colon ); int __result = (((const unsigned char *) (const char *) ("vendor" ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("vendor" ))[1] - __s2[1]); if (__s2_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("vendor" ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) ("vendor" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (before_colon , "vendor")))); }) |
815 | || !strcmp(before_colon, "manufacture")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (before_colon) && __builtin_constant_p ("manufacture" ) && (__s1_len = strlen (before_colon), __s2_len = strlen ("manufacture"), (!((size_t)(const void *)((before_colon) + 1 ) - (size_t)(const void *)(before_colon) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("manufacture") + 1) - (size_t)(const void *)("manufacture") == 1) || __s2_len >= 4)) ? __builtin_strcmp (before_colon, "manufacture") : (__builtin_constant_p (before_colon) && ((size_t)(const void *)((before_colon ) + 1) - (size_t)(const void *)(before_colon) == 1) && (__s1_len = strlen (before_colon), __s1_len < 4) ? (__builtin_constant_p ("manufacture") && ((size_t)(const void *)(("manufacture" ) + 1) - (size_t)(const void *)("manufacture") == 1) ? __builtin_strcmp (before_colon, "manufacture") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("manufacture" ); int __result = (((const unsigned char *) (const char *) (before_colon ))[0] - __s2[0]); if (__s1_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (before_colon ))[1] - __s2[1]); if (__s1_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) (before_colon ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (before_colon ))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ( "manufacture") && ((size_t)(const void *)(("manufacture" ) + 1) - (size_t)(const void *)("manufacture") == 1) && (__s2_len = strlen ("manufacture"), __s2_len < 4) ? (__builtin_constant_p (before_colon) && ((size_t)(const void *)((before_colon ) + 1) - (size_t)(const void *)(before_colon) == 1) ? __builtin_strcmp (before_colon, "manufacture") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (before_colon ); int __result = (((const unsigned char *) (const char *) ("manufacture" ))[0] - __s2[0]); if (__s2_len > 0 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("manufacture" ))[1] - __s2[1]); if (__s2_len > 1 && __result == 0 ) { __result = (((const unsigned char *) (const char *) ("manufacture" ))[2] - __s2[2]); if (__s2_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) ("manufacture" ))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (before_colon , "manufacture")))); }) |
816 | || !strcmp(before_colon, "model")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (before_colon) && __builtin_constant_p ("model") && (__s1_len = strlen (before_colon), __s2_len = strlen ("model" ), (!((size_t)(const void *)((before_colon) + 1) - (size_t)(const void *)(before_colon) == 1) || __s1_len >= 4) && ( !((size_t)(const void *)(("model") + 1) - (size_t)(const void *)("model") == 1) || __s2_len >= 4)) ? __builtin_strcmp ( before_colon, "model") : (__builtin_constant_p (before_colon) && ((size_t)(const void *)((before_colon) + 1) - (size_t )(const void *)(before_colon) == 1) && (__s1_len = strlen (before_colon), __s1_len < 4) ? (__builtin_constant_p ("model" ) && ((size_t)(const void *)(("model") + 1) - (size_t )(const void *)("model") == 1) ? __builtin_strcmp (before_colon , "model") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("model"); int __result = (( (const unsigned char *) (const char *) (before_colon))[0] - __s2 [0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (before_colon))[1 ] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (before_colon ))[2] - __s2[2]); if (__s1_len > 2 && __result == 0 ) __result = (((const unsigned char *) (const char *) (before_colon ))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ( "model") && ((size_t)(const void *)(("model") + 1) - ( size_t)(const void *)("model") == 1) && (__s2_len = strlen ("model"), __s2_len < 4) ? (__builtin_constant_p (before_colon ) && ((size_t)(const void *)((before_colon) + 1) - (size_t )(const void *)(before_colon) == 1) ? __builtin_strcmp (before_colon , "model") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (before_colon); int __result = (((const unsigned char *) (const char *) ("model"))[0] - __s2 [0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ("model"))[1] - __s2 [1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ("model"))[2] - __s2 [2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("model"))[3] - __s2 [3]); } } __result; })))) : __builtin_strcmp (before_colon, "model" )))); })) |
817 | { |
818 | chomp_substring_after_colon(buffer, after_colon, sizeof(after_colon)); |
819 | for (i = GMX_CPUID_VENDOR_UNKNOWN; i < GMX_CPUID_NVENDORS; i++) |
820 | { |
821 | /* Be liberal and accept if we find the vendor |
822 | * string (or alternative string) anywhere. Using |
823 | * strcasestr() would be non-portable. */ |
824 | if (strstr(after_colon, gmx_cpuid_vendor_string[i]) |
825 | || strstr(after_colon, gmx_cpuid_vendor_string_alternative[i])) |
826 | { |
827 | vendor = i; |
828 | } |
829 | } |
830 | } |
831 | } |
832 | } |
833 | fclose(fp); |
834 | #endif |
835 | |
836 | return vendor; |
837 | } |
838 | |
839 | |
840 | |
841 | int |
842 | gmx_cpuid_topology(gmx_cpuid_t cpuid, |
843 | int * nprocessors, |
844 | int * npackages, |
845 | int * ncores_per_package, |
846 | int * nhwthreads_per_core, |
847 | const int ** package_id, |
848 | const int ** core_id, |
849 | const int ** hwthread_id, |
850 | const int ** locality_order) |
851 | { |
852 | int rc; |
853 | |
854 | if (cpuid->have_cpu_topology) |
855 | { |
856 | *nprocessors = cpuid->nproc; |
857 | *npackages = cpuid->npackages; |
858 | *ncores_per_package = cpuid->ncores_per_package; |
859 | *nhwthreads_per_core = cpuid->nhwthreads_per_core; |
860 | *package_id = cpuid->package_id; |
861 | *core_id = cpuid->core_id; |
862 | *hwthread_id = cpuid->hwthread_id; |
863 | *locality_order = cpuid->locality_order; |
864 | rc = 0; |
865 | } |
866 | else |
867 | { |
868 | rc = -1; |
869 | } |
870 | return rc; |
871 | } |
872 | |
873 | |
874 | enum gmx_cpuid_x86_smt |
875 | gmx_cpuid_x86_smt(gmx_cpuid_t cpuid) |
876 | { |
877 | enum gmx_cpuid_x86_smt rc; |
878 | |
879 | if (cpuid->have_cpu_topology) |
880 | { |
881 | rc = (cpuid->nhwthreads_per_core > 1) ? GMX_CPUID_X86_SMT_ENABLED : GMX_CPUID_X86_SMT_DISABLED; |
882 | } |
883 | else if (cpuid->vendor == GMX_CPUID_VENDOR_AMD || gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_HTT) == 0) |
884 | { |
885 | rc = GMX_CPUID_X86_SMT_DISABLED; |
886 | } |
887 | else |
888 | { |
889 | rc = GMX_CPUID_X86_SMT_CANNOTDETECT; |
890 | } |
891 | return rc; |
892 | } |
893 | |
894 | |
895 | int |
896 | gmx_cpuid_init (gmx_cpuid_t * pcpuid) |
897 | { |
898 | gmx_cpuid_t cpuid; |
899 | int i; |
900 | FILE * fp; |
901 | char buffer[255], buffer2[255]; |
902 | int found_brand; |
903 | |
904 | cpuid = malloc(sizeof(*cpuid)); |
905 | |
906 | *pcpuid = cpuid; |
907 | |
908 | for (i = 0; i < GMX_CPUID_NFEATURES; i++) |
909 | { |
910 | cpuid->feature[i] = 0; |
911 | } |
912 | |
913 | cpuid->have_cpu_topology = 0; |
914 | cpuid->nproc = 0; |
915 | cpuid->npackages = 0; |
916 | cpuid->ncores_per_package = 0; |
917 | cpuid->nhwthreads_per_core = 0; |
918 | cpuid->package_id = NULL((void*)0); |
919 | cpuid->core_id = NULL((void*)0); |
920 | cpuid->hwthread_id = NULL((void*)0); |
921 | cpuid->locality_order = NULL((void*)0); |
922 | |
923 | cpuid->vendor = cpuid_check_vendor(); |
924 | |
925 | switch (cpuid->vendor) |
926 | { |
927 | #ifdef GMX_CPUID_X86 |
928 | case GMX_CPUID_VENDOR_INTEL: |
929 | cpuid_check_intel_x86(cpuid); |
930 | break; |
931 | case GMX_CPUID_VENDOR_AMD: |
932 | cpuid_check_amd_x86(cpuid); |
933 | break; |
934 | #endif |
935 | default: |
936 | /* Default value */ |
937 | strncpy(cpuid->brand, "Unknown CPU brand", GMX_CPUID_BRAND_MAXLEN)__builtin_strncpy (cpuid->brand, "Unknown CPU brand", 256); |
938 | #if defined(__linux__1) || defined(__linux1) |
939 | /* General Linux. Try to get CPU type from /proc/cpuinfo */ |
940 | if ( (fp = fopen("/proc/cpuinfo", "r")) != NULL((void*)0)) |
941 | { |
942 | found_brand = 0; |
943 | while ( (found_brand == 0) && (fgets(buffer, sizeof(buffer), fp) != NULL((void*)0))) |
944 | { |
945 | chomp_substring_before_colon(buffer, buffer2, sizeof(buffer2)); |
946 | /* Intel uses "model name", Fujitsu and IBM "cpu". */ |
947 | if (!strcmp(buffer2, "model name")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (buffer2) && __builtin_constant_p ("model name") && (__s1_len = strlen (buffer2), __s2_len = strlen ("model name" ), (!((size_t)(const void *)((buffer2) + 1) - (size_t)(const void *)(buffer2) == 1) || __s1_len >= 4) && (!((size_t )(const void *)(("model name") + 1) - (size_t)(const void *)( "model name") == 1) || __s2_len >= 4)) ? __builtin_strcmp ( buffer2, "model name") : (__builtin_constant_p (buffer2) && ((size_t)(const void *)((buffer2) + 1) - (size_t)(const void *)(buffer2) == 1) && (__s1_len = strlen (buffer2), __s1_len < 4) ? (__builtin_constant_p ("model name") && (( size_t)(const void *)(("model name") + 1) - (size_t)(const void *)("model name") == 1) ? __builtin_strcmp (buffer2, "model name" ) : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("model name"); int __result = (((const unsigned char *) (const char *) (buffer2))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (buffer2))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (buffer2))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (buffer2))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ("model name") && ((size_t)(const void *)(("model name") + 1) - (size_t)(const void *)("model name") == 1) && (__s2_len = strlen ("model name" ), __s2_len < 4) ? (__builtin_constant_p (buffer2) && ((size_t)(const void *)((buffer2) + 1) - (size_t)(const void *)(buffer2) == 1) ? __builtin_strcmp (buffer2, "model name") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (buffer2); int __result = (((const unsigned char *) (const char *) ("model name"))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ("model name"))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ("model name"))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("model name"))[3] - __s2[3]); } } __result ; })))) : __builtin_strcmp (buffer2, "model name")))); }) || !strcmp(buffer2, "cpu")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p (buffer2) && __builtin_constant_p ("cpu") && (__s1_len = strlen (buffer2), __s2_len = strlen ("cpu"), (!( (size_t)(const void *)((buffer2) + 1) - (size_t)(const void * )(buffer2) == 1) || __s1_len >= 4) && (!((size_t)( const void *)(("cpu") + 1) - (size_t)(const void *)("cpu") == 1) || __s2_len >= 4)) ? __builtin_strcmp (buffer2, "cpu") : (__builtin_constant_p (buffer2) && ((size_t)(const void *)((buffer2) + 1) - (size_t)(const void *)(buffer2) == 1 ) && (__s1_len = strlen (buffer2), __s1_len < 4) ? (__builtin_constant_p ("cpu") && ((size_t)(const void *)(("cpu") + 1) - (size_t)(const void *)("cpu") == 1) ? __builtin_strcmp (buffer2, "cpu") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("cpu"); int __result = (((const unsigned char *) (const char *) (buffer2))[0] - __s2 [0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (buffer2))[1] - __s2 [1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (buffer2))[2] - __s2 [2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (buffer2))[3] - __s2 [3]); } } __result; }))) : (__builtin_constant_p ("cpu") && ((size_t)(const void *)(("cpu") + 1) - (size_t)(const void * )("cpu") == 1) && (__s2_len = strlen ("cpu"), __s2_len < 4) ? (__builtin_constant_p (buffer2) && ((size_t )(const void *)((buffer2) + 1) - (size_t)(const void *)(buffer2 ) == 1) ? __builtin_strcmp (buffer2, "cpu") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (buffer2); int __result = (((const unsigned char *) ( const char *) ("cpu"))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ("cpu"))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ("cpu"))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("cpu"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (buffer2, "cpu")))); })) |
948 | { |
949 | chomp_substring_after_colon(buffer, cpuid->brand, GMX_CPUID_BRAND_MAXLEN256); |
950 | found_brand = 1; |
951 | } |
952 | } |
953 | } |
954 | fclose(fp); |
955 | #endif |
956 | cpuid->family = 0; |
957 | cpuid->model = 0; |
958 | cpuid->stepping = 0; |
959 | |
960 | for (i = 0; i < GMX_CPUID_NFEATURES; i++) |
961 | { |
962 | cpuid->feature[i] = 0; |
963 | } |
964 | cpuid->feature[GMX_CPUID_FEATURE_CANNOTDETECT] = 1; |
965 | break; |
966 | } |
967 | return 0; |
968 | } |
969 | |
970 | |
971 | |
972 | void |
973 | gmx_cpuid_done (gmx_cpuid_t cpuid) |
974 | { |
975 | free(cpuid); |
976 | } |
977 | |
978 | |
979 | int |
980 | gmx_cpuid_formatstring (gmx_cpuid_t cpuid, |
981 | char * str, |
982 | int n) |
983 | { |
984 | int c; |
985 | int i; |
986 | enum gmx_cpuid_feature feature; |
987 | |
988 | #ifdef _MSC_VER |
989 | _snprintf(str, n, |
990 | "Vendor: %s\n" |
991 | "Brand: %s\n" |
992 | "Family: %2d Model: %2d Stepping: %2d\n" |
993 | "Features:", |
994 | gmx_cpuid_vendor_string[gmx_cpuid_vendor(cpuid)], |
995 | gmx_cpuid_brand(cpuid), |
996 | gmx_cpuid_family(cpuid), gmx_cpuid_model(cpuid), gmx_cpuid_stepping(cpuid)); |
997 | #else |
998 | snprintf(str, n, |
999 | "Vendor: %s\n" |
1000 | "Brand: %s\n" |
1001 | "Family: %2d Model: %2d Stepping: %2d\n" |
1002 | "Features:", |
1003 | gmx_cpuid_vendor_string[gmx_cpuid_vendor(cpuid)], |
1004 | gmx_cpuid_brand(cpuid), |
1005 | gmx_cpuid_family(cpuid), gmx_cpuid_model(cpuid), gmx_cpuid_stepping(cpuid)); |
1006 | #endif |
1007 | |
1008 | str[n-1] = '\0'; |
1009 | c = strlen(str); |
1010 | n -= c; |
1011 | str += c; |
1012 | |
1013 | for (feature = GMX_CPUID_FEATURE_CANNOTDETECT; feature < GMX_CPUID_NFEATURES; feature++) |
1014 | { |
1015 | if (gmx_cpuid_feature(cpuid, feature) == 1) |
1016 | { |
1017 | #ifdef _MSC_VER |
1018 | _snprintf(str, n, " %s", gmx_cpuid_feature_string[feature]); |
1019 | #else |
1020 | snprintf(str, n, " %s", gmx_cpuid_feature_string[feature]); |
1021 | #endif |
1022 | str[n-1] = '\0'; |
1023 | c = strlen(str); |
1024 | n -= c; |
1025 | str += c; |
1026 | } |
1027 | } |
1028 | #ifdef _MSC_VER |
1029 | _snprintf(str, n, "\n"); |
1030 | #else |
1031 | snprintf(str, n, "\n"); |
1032 | #endif |
1033 | str[n-1] = '\0'; |
1034 | |
1035 | return 0; |
1036 | } |
1037 | |
1038 | |
1039 | |
1040 | enum gmx_cpuid_simd |
1041 | gmx_cpuid_simd_suggest (gmx_cpuid_t cpuid) |
1042 | { |
1043 | enum gmx_cpuid_simd tmpsimd; |
1044 | |
1045 | tmpsimd = GMX_CPUID_SIMD_NONE; |
1046 | |
1047 | if (gmx_cpuid_vendor(cpuid) == GMX_CPUID_VENDOR_INTEL) |
1048 | { |
1049 | if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_AVX2)) |
1050 | { |
1051 | tmpsimd = GMX_CPUID_SIMD_X86_AVX2_256; |
1052 | } |
1053 | else if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_AVX)) |
1054 | { |
1055 | tmpsimd = GMX_CPUID_SIMD_X86_AVX_256; |
1056 | } |
1057 | else if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_SSE4_1)) |
1058 | { |
1059 | tmpsimd = GMX_CPUID_SIMD_X86_SSE4_1; |
1060 | } |
1061 | else if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_SSE2)) |
1062 | { |
1063 | tmpsimd = GMX_CPUID_SIMD_X86_SSE2; |
1064 | } |
1065 | } |
1066 | else if (gmx_cpuid_vendor(cpuid) == GMX_CPUID_VENDOR_AMD) |
1067 | { |
1068 | if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_AVX)) |
1069 | { |
1070 | tmpsimd = GMX_CPUID_SIMD_X86_AVX_128_FMA; |
1071 | } |
1072 | else if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_SSE4_1)) |
1073 | { |
1074 | tmpsimd = GMX_CPUID_SIMD_X86_SSE4_1; |
1075 | } |
1076 | else if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_SSE2)) |
1077 | { |
1078 | tmpsimd = GMX_CPUID_SIMD_X86_SSE2; |
1079 | } |
1080 | } |
1081 | else if (gmx_cpuid_vendor(cpuid) == GMX_CPUID_VENDOR_FUJITSU) |
1082 | { |
1083 | if (strstr(gmx_cpuid_brand(cpuid), "SPARC64")) |
1084 | { |
1085 | tmpsimd = GMX_CPUID_SIMD_SPARC64_HPC_ACE; |
1086 | } |
1087 | } |
1088 | else if (gmx_cpuid_vendor(cpuid) == GMX_CPUID_VENDOR_IBM) |
1089 | { |
1090 | if (strstr(gmx_cpuid_brand(cpuid), "A2")) |
1091 | { |
1092 | tmpsimd = GMX_CPUID_SIMD_IBM_QPX; |
1093 | } |
1094 | } |
1095 | return tmpsimd; |
1096 | } |
1097 | |
1098 | |
1099 | |
1100 | int |
1101 | gmx_cpuid_simd_check(gmx_cpuid_t cpuid, |
1102 | FILE * log, |
1103 | int print_to_stderr) |
1104 | { |
1105 | int rc; |
1106 | char str[1024]; |
1107 | enum gmx_cpuid_simd simd; |
1108 | |
1109 | simd = gmx_cpuid_simd_suggest(cpuid); |
1110 | |
1111 | rc = (simd != compiled_simd); |
1112 | |
1113 | gmx_cpuid_formatstring(cpuid, str, 1023); |
1114 | str[1023] = '\0'; |
1115 | |
1116 | if (log != NULL((void*)0)) |
1117 | { |
1118 | fprintf(log, |
1119 | "\nDetecting CPU SIMD instructions.\nPresent hardware specification:\n" |
1120 | "%s" |
1121 | "SIMD instructions most likely to fit this hardware: %s\n" |
1122 | "SIMD instructions selected at GROMACS compile time: %s\n\n", |
1123 | str, |
1124 | gmx_cpuid_simd_string[simd], |
1125 | gmx_cpuid_simd_string[compiled_simd]); |
1126 | } |
1127 | |
1128 | if (rc != 0) |
1129 | { |
1130 | if (log != NULL((void*)0)) |
1131 | { |
1132 | fprintf(log, "\nBinary not matching hardware - you might be losing performance.\n" |
1133 | "SIMD instructions most likely to fit this hardware: %s\n" |
1134 | "SIMD instructions selected at GROMACS compile time: %s\n\n", |
1135 | gmx_cpuid_simd_string[simd], |
1136 | gmx_cpuid_simd_string[compiled_simd]); |
1137 | } |
1138 | if (print_to_stderr) |
1139 | { |
1140 | fprintf(stderrstderr, "Compiled SIMD instructions: %s (Gromacs could use %s on this machine, which is better)\n", |
1141 | gmx_cpuid_simd_string[compiled_simd], |
1142 | gmx_cpuid_simd_string[simd]); |
1143 | } |
1144 | } |
1145 | return rc; |
1146 | } |
1147 | |
1148 | |
1149 | #ifdef GMX_CPUID_STANDALONE |
1150 | /* Stand-alone program to enable queries of CPU features from Cmake. |
1151 | * Note that you need to check inline ASM capabilities before compiling and set |
1152 | * -DGMX_X86_GCC_INLINE_ASM for the cpuid instruction to work... |
1153 | */ |
1154 | int |
1155 | main(int argc, char **argv) |
1156 | { |
1157 | gmx_cpuid_t cpuid; |
1158 | enum gmx_cpuid_simd simd; |
1159 | int i, cnt; |
1160 | |
1161 | if (argc < 2) |
1162 | { |
1163 | fprintf(stdoutstdout, |
1164 | "Usage:\n\n%s [flags]\n\n" |
1165 | "Available flags:\n" |
1166 | "-vendor Print CPU vendor.\n" |
1167 | "-brand Print CPU brand string.\n" |
1168 | "-family Print CPU family version.\n" |
1169 | "-model Print CPU model version.\n" |
1170 | "-stepping Print CPU stepping version.\n" |
1171 | "-features Print CPU feature flags.\n" |
1172 | "-simd Print suggested GROMACS SIMD instructions.\n", |
1173 | argv[0]); |
1174 | exit(0); |
1175 | } |
1176 | |
1177 | gmx_cpuid_init(&cpuid); |
1178 | |
1179 | if (!strncmp(argv[1], "-vendor", 3)(__extension__ (__builtin_constant_p (3) && ((__builtin_constant_p (argv[1]) && strlen (argv[1]) < ((size_t) (3))) || (__builtin_constant_p ("-vendor") && strlen ("-vendor" ) < ((size_t) (3)))) ? __extension__ ({ size_t __s1_len, __s2_len ; (__builtin_constant_p (argv[1]) && __builtin_constant_p ("-vendor") && (__s1_len = strlen (argv[1]), __s2_len = strlen ("-vendor"), (!((size_t)(const void *)((argv[1]) + 1 ) - (size_t)(const void *)(argv[1]) == 1) || __s1_len >= 4 ) && (!((size_t)(const void *)(("-vendor") + 1) - (size_t )(const void *)("-vendor") == 1) || __s2_len >= 4)) ? __builtin_strcmp (argv[1], "-vendor") : (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1) && (__s1_len = strlen (argv[1]), __s1_len < 4) ? (__builtin_constant_p ("-vendor") && ((size_t )(const void *)(("-vendor") + 1) - (size_t)(const void *)("-vendor" ) == 1) ? __builtin_strcmp (argv[1], "-vendor") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("-vendor"); int __result = (((const unsigned char * ) (const char *) (argv[1]))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv[1]))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv[1]))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (argv[1]))[3] - __s2[3]); } } __result; }) )) : (__builtin_constant_p ("-vendor") && ((size_t)(const void *)(("-vendor") + 1) - (size_t)(const void *)("-vendor") == 1) && (__s2_len = strlen ("-vendor"), __s2_len < 4) ? (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1 ) ? __builtin_strcmp (argv[1], "-vendor") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (argv[1]); int __result = (((const unsigned char *) ( const char *) ("-vendor"))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-vendor"))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-vendor"))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("-vendor"))[3] - __s2[3]); } } __result; } )))) : __builtin_strcmp (argv[1], "-vendor")))); }) : strncmp (argv[1], "-vendor", 3)))) |
1180 | { |
1181 | printf("%s\n", gmx_cpuid_vendor_string[cpuid->vendor]); |
1182 | } |
1183 | else if (!strncmp(argv[1], "-brand", 3)(__extension__ (__builtin_constant_p (3) && ((__builtin_constant_p (argv[1]) && strlen (argv[1]) < ((size_t) (3))) || (__builtin_constant_p ("-brand") && strlen ("-brand" ) < ((size_t) (3)))) ? __extension__ ({ size_t __s1_len, __s2_len ; (__builtin_constant_p (argv[1]) && __builtin_constant_p ("-brand") && (__s1_len = strlen (argv[1]), __s2_len = strlen ("-brand"), (!((size_t)(const void *)((argv[1]) + 1 ) - (size_t)(const void *)(argv[1]) == 1) || __s1_len >= 4 ) && (!((size_t)(const void *)(("-brand") + 1) - (size_t )(const void *)("-brand") == 1) || __s2_len >= 4)) ? __builtin_strcmp (argv[1], "-brand") : (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1) && (__s1_len = strlen (argv[1]), __s1_len < 4) ? (__builtin_constant_p ("-brand") && ((size_t )(const void *)(("-brand") + 1) - (size_t)(const void *)("-brand" ) == 1) ? __builtin_strcmp (argv[1], "-brand") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("-brand"); int __result = (((const unsigned char *) (const char *) (argv[1]))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv[1]))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv[1]))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (argv[1]))[3] - __s2[3]); } } __result; }) )) : (__builtin_constant_p ("-brand") && ((size_t)(const void *)(("-brand") + 1) - (size_t)(const void *)("-brand") == 1) && (__s2_len = strlen ("-brand"), __s2_len < 4 ) ? (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1 ) ? __builtin_strcmp (argv[1], "-brand") : (- (__extension__ ( { const unsigned char *__s2 = (const unsigned char *) (const char *) (argv[1]); int __result = (((const unsigned char *) (const char *) ("-brand"))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-brand"))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-brand"))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("-brand"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (argv[1], "-brand")))); }) : strncmp (argv[1], "-brand", 3)) )) |
1184 | { |
1185 | printf("%s\n", cpuid->brand); |
1186 | } |
1187 | else if (!strncmp(argv[1], "-family", 3)(__extension__ (__builtin_constant_p (3) && ((__builtin_constant_p (argv[1]) && strlen (argv[1]) < ((size_t) (3))) || (__builtin_constant_p ("-family") && strlen ("-family" ) < ((size_t) (3)))) ? __extension__ ({ size_t __s1_len, __s2_len ; (__builtin_constant_p (argv[1]) && __builtin_constant_p ("-family") && (__s1_len = strlen (argv[1]), __s2_len = strlen ("-family"), (!((size_t)(const void *)((argv[1]) + 1 ) - (size_t)(const void *)(argv[1]) == 1) || __s1_len >= 4 ) && (!((size_t)(const void *)(("-family") + 1) - (size_t )(const void *)("-family") == 1) || __s2_len >= 4)) ? __builtin_strcmp (argv[1], "-family") : (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1) && (__s1_len = strlen (argv[1]), __s1_len < 4) ? (__builtin_constant_p ("-family") && ((size_t )(const void *)(("-family") + 1) - (size_t)(const void *)("-family" ) == 1) ? __builtin_strcmp (argv[1], "-family") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("-family"); int __result = (((const unsigned char * ) (const char *) (argv[1]))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv[1]))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv[1]))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (argv[1]))[3] - __s2[3]); } } __result; }) )) : (__builtin_constant_p ("-family") && ((size_t)(const void *)(("-family") + 1) - (size_t)(const void *)("-family") == 1) && (__s2_len = strlen ("-family"), __s2_len < 4) ? (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1 ) ? __builtin_strcmp (argv[1], "-family") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (argv[1]); int __result = (((const unsigned char *) ( const char *) ("-family"))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-family"))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-family"))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("-family"))[3] - __s2[3]); } } __result; } )))) : __builtin_strcmp (argv[1], "-family")))); }) : strncmp (argv[1], "-family", 3)))) |
1188 | { |
1189 | printf("%d\n", cpuid->family); |
1190 | } |
1191 | else if (!strncmp(argv[1], "-model", 3)(__extension__ (__builtin_constant_p (3) && ((__builtin_constant_p (argv[1]) && strlen (argv[1]) < ((size_t) (3))) || (__builtin_constant_p ("-model") && strlen ("-model" ) < ((size_t) (3)))) ? __extension__ ({ size_t __s1_len, __s2_len ; (__builtin_constant_p (argv[1]) && __builtin_constant_p ("-model") && (__s1_len = strlen (argv[1]), __s2_len = strlen ("-model"), (!((size_t)(const void *)((argv[1]) + 1 ) - (size_t)(const void *)(argv[1]) == 1) || __s1_len >= 4 ) && (!((size_t)(const void *)(("-model") + 1) - (size_t )(const void *)("-model") == 1) || __s2_len >= 4)) ? __builtin_strcmp (argv[1], "-model") : (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1) && (__s1_len = strlen (argv[1]), __s1_len < 4) ? (__builtin_constant_p ("-model") && ((size_t )(const void *)(("-model") + 1) - (size_t)(const void *)("-model" ) == 1) ? __builtin_strcmp (argv[1], "-model") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("-model"); int __result = (((const unsigned char *) (const char *) (argv[1]))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv[1]))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv[1]))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (argv[1]))[3] - __s2[3]); } } __result; }) )) : (__builtin_constant_p ("-model") && ((size_t)(const void *)(("-model") + 1) - (size_t)(const void *)("-model") == 1) && (__s2_len = strlen ("-model"), __s2_len < 4 ) ? (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1 ) ? __builtin_strcmp (argv[1], "-model") : (- (__extension__ ( { const unsigned char *__s2 = (const unsigned char *) (const char *) (argv[1]); int __result = (((const unsigned char *) (const char *) ("-model"))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-model"))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-model"))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("-model"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (argv[1], "-model")))); }) : strncmp (argv[1], "-model", 3)) )) |
1192 | { |
1193 | printf("%d\n", cpuid->model); |
1194 | } |
1195 | else if (!strncmp(argv[1], "-stepping", 3)(__extension__ (__builtin_constant_p (3) && ((__builtin_constant_p (argv[1]) && strlen (argv[1]) < ((size_t) (3))) || (__builtin_constant_p ("-stepping") && strlen ("-stepping" ) < ((size_t) (3)))) ? __extension__ ({ size_t __s1_len, __s2_len ; (__builtin_constant_p (argv[1]) && __builtin_constant_p ("-stepping") && (__s1_len = strlen (argv[1]), __s2_len = strlen ("-stepping"), (!((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("-stepping") + 1) - (size_t)(const void *)("-stepping") == 1) || __s2_len >= 4 )) ? __builtin_strcmp (argv[1], "-stepping") : (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1) && (__s1_len = strlen (argv[1]), __s1_len < 4) ? (__builtin_constant_p ( "-stepping") && ((size_t)(const void *)(("-stepping") + 1) - (size_t)(const void *)("-stepping") == 1) ? __builtin_strcmp (argv[1], "-stepping") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("-stepping") ; int __result = (((const unsigned char *) (const char *) (argv [1]))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv [1]))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv [1]))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (argv [1]))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ("-stepping") && ((size_t)(const void *)(("-stepping" ) + 1) - (size_t)(const void *)("-stepping") == 1) && (__s2_len = strlen ("-stepping"), __s2_len < 4) ? (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1) ? __builtin_strcmp (argv [1], "-stepping") : (- (__extension__ ({ const unsigned char * __s2 = (const unsigned char *) (const char *) (argv[1]); int __result = (((const unsigned char *) (const char *) ("-stepping"))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-stepping"))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-stepping"))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("-stepping"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (argv[1], "-stepping")))); }) : strncmp (argv[1], "-stepping", 3)))) |
1196 | { |
1197 | printf("%d\n", cpuid->stepping); |
1198 | } |
1199 | else if (!strncmp(argv[1], "-features", 3)(__extension__ (__builtin_constant_p (3) && ((__builtin_constant_p (argv[1]) && strlen (argv[1]) < ((size_t) (3))) || (__builtin_constant_p ("-features") && strlen ("-features" ) < ((size_t) (3)))) ? __extension__ ({ size_t __s1_len, __s2_len ; (__builtin_constant_p (argv[1]) && __builtin_constant_p ("-features") && (__s1_len = strlen (argv[1]), __s2_len = strlen ("-features"), (!((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("-features") + 1) - (size_t)(const void *)("-features") == 1) || __s2_len >= 4 )) ? __builtin_strcmp (argv[1], "-features") : (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1) && (__s1_len = strlen (argv[1]), __s1_len < 4) ? (__builtin_constant_p ( "-features") && ((size_t)(const void *)(("-features") + 1) - (size_t)(const void *)("-features") == 1) ? __builtin_strcmp (argv[1], "-features") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("-features") ; int __result = (((const unsigned char *) (const char *) (argv [1]))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv [1]))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv [1]))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (argv [1]))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ("-features") && ((size_t)(const void *)(("-features" ) + 1) - (size_t)(const void *)("-features") == 1) && (__s2_len = strlen ("-features"), __s2_len < 4) ? (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1) ? __builtin_strcmp (argv [1], "-features") : (- (__extension__ ({ const unsigned char * __s2 = (const unsigned char *) (const char *) (argv[1]); int __result = (((const unsigned char *) (const char *) ("-features"))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-features"))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-features"))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("-features"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (argv[1], "-features")))); }) : strncmp (argv[1], "-features", 3)))) |
1200 | { |
1201 | cnt = 0; |
1202 | for (i = 0; i < GMX_CPUID_NFEATURES; i++) |
1203 | { |
1204 | if (cpuid->feature[i] == 1) |
1205 | { |
1206 | if (cnt++ > 0) |
1207 | { |
1208 | printf(" "); |
1209 | } |
1210 | printf("%s", gmx_cpuid_feature_string[i]); |
1211 | } |
1212 | } |
1213 | printf("\n"); |
1214 | } |
1215 | else if (!strncmp(argv[1], "-simd", 3)(__extension__ (__builtin_constant_p (3) && ((__builtin_constant_p (argv[1]) && strlen (argv[1]) < ((size_t) (3))) || (__builtin_constant_p ("-simd") && strlen ("-simd") < ((size_t) (3)))) ? __extension__ ({ size_t __s1_len, __s2_len ; (__builtin_constant_p (argv[1]) && __builtin_constant_p ("-simd") && (__s1_len = strlen (argv[1]), __s2_len = strlen ("-simd"), (!((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1) || __s1_len >= 4) && (!((size_t)(const void *)(("-simd") + 1) - (size_t)(const void *)("-simd") == 1) || __s2_len >= 4)) ? __builtin_strcmp ( argv[1], "-simd") : (__builtin_constant_p (argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - (size_t)(const void *)(argv[1]) == 1) && (__s1_len = strlen (argv[1]), __s1_len < 4) ? (__builtin_constant_p ("-simd") && ((size_t )(const void *)(("-simd") + 1) - (size_t)(const void *)("-simd" ) == 1) ? __builtin_strcmp (argv[1], "-simd") : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) ("-simd"); int __result = (((const unsigned char *) ( const char *) (argv[1]))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv[1]))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (argv[1]))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (argv[1]))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p ("-simd") && ((size_t)(const void *)(("-simd") + 1) - (size_t)(const void *)("-simd") == 1) && (__s2_len = strlen ("-simd"), __s2_len < 4) ? (__builtin_constant_p ( argv[1]) && ((size_t)(const void *)((argv[1]) + 1) - ( size_t)(const void *)(argv[1]) == 1) ? __builtin_strcmp (argv [1], "-simd") : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (argv[1]); int __result = (((const unsigned char *) (const char *) ("-simd"))[0] - __s2 [0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-simd"))[1] - __s2 [1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) ("-simd"))[2] - __s2 [2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) ("-simd"))[3] - __s2 [3]); } } __result; })))) : __builtin_strcmp (argv[1], "-simd" )))); }) : strncmp (argv[1], "-simd", 3)))) |
1216 | { |
1217 | simd = gmx_cpuid_simd_suggest(cpuid); |
1218 | fprintf(stdoutstdout, "%s\n", gmx_cpuid_simd_string[simd]); |
1219 | } |
1220 | |
1221 | gmx_cpuid_done(cpuid); |
1222 | |
1223 | |
1224 | return 0; |
1225 | } |
1226 | |
1227 | #endif |