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