Merge release-5-0 into master
[alexxy/gromacs.git] / src / gromacs / gmxlib / gmx_cpuid.c
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_H
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_MAXLEN 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_MAXLEN];
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__)
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_MAXLEN];
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)))
360         {
361             p++;
362         }
363         strncpy(cpuid->brand, p, GMX_CPUID_BRAND_MAXLEN);
364     }
365     else
366     {
367         strncpy(cpuid->brand, "Unknown CPU brand", GMX_CPUID_BRAND_MAXLEN);
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     free(unique);
469     return nunique;
470 }
471
472 /* APIC IDs, or everything you wanted to know about your x86 cores but were afraid to ask...
473  *
474  * Raw APIC IDs are unfortunately somewhat dirty. For technical reasons they are assigned
475  * in power-of-2 chunks, and even then there are no guarantees about specific numbers - all
476  * we know is that the part for each thread/core/package is unique, and how many bits are
477  * reserved for that part.
478  * This routine does internal renumbering so we get continuous indices, and also
479  * decodes the actual number of packages,cores-per-package and hwthreads-per-core.
480  * Returns: 0 on success, non-zero on failure.
481  */
482 static int
483 cpuid_x86_decode_apic_id(gmx_cpuid_t cpuid, int *apic_id, int core_bits, int hwthread_bits)
484 {
485     int i, idx;
486     int hwthread_mask, core_mask_after_shift;
487
488     cpuid->hwthread_id     = malloc(sizeof(int)*cpuid->nproc);
489     cpuid->core_id         = malloc(sizeof(int)*cpuid->nproc);
490     cpuid->package_id      = malloc(sizeof(int)*cpuid->nproc);
491     cpuid->locality_order  = malloc(sizeof(int)*cpuid->nproc);
492
493     hwthread_mask         = (1 << hwthread_bits) - 1;
494     core_mask_after_shift = (1 << core_bits) - 1;
495
496     for (i = 0; i < cpuid->nproc; i++)
497     {
498         cpuid->hwthread_id[i] = apic_id[i] & hwthread_mask;
499         cpuid->core_id[i]     = (apic_id[i] >> hwthread_bits) & core_mask_after_shift;
500         cpuid->package_id[i]  = apic_id[i] >> (core_bits + hwthread_bits);
501     }
502
503     cpuid->npackages            = cpuid_renumber_elements(cpuid->package_id, cpuid->nproc);
504     cpuid->ncores_per_package   = cpuid_renumber_elements(cpuid->core_id, cpuid->nproc);
505     cpuid->nhwthreads_per_core  = cpuid_renumber_elements(cpuid->hwthread_id, cpuid->nproc);
506
507     /* now check for consistency */
508     if ( (cpuid->npackages * cpuid->ncores_per_package *
509           cpuid->nhwthreads_per_core) != cpuid->nproc)
510     {
511         /* the packages/cores-per-package/hwthreads-per-core counts are
512            inconsistent. */
513         return -1;
514     }
515
516     /* Create a locality order array, i.e. first all resources in package0, which in turn
517      * are sorted so we first have all resources in core0, where threads are sorted in order, etc.
518      */
519
520     for (i = 0; i < cpuid->nproc; i++)
521     {
522         idx = (cpuid->package_id[i]*cpuid->ncores_per_package + cpuid->core_id[i])*cpuid->nhwthreads_per_core + cpuid->hwthread_id[i];
523         cpuid->locality_order[idx] = i;
524     }
525     return 0;
526 }
527
528
529 /* Detection of AMD-specific CPU features */
530 static int
531 cpuid_check_amd_x86(gmx_cpuid_t                cpuid)
532 {
533     int                       max_stdfn, max_extfn, ret;
534     unsigned int              eax, ebx, ecx, edx;
535     int                       hwthread_bits, core_bits;
536     int *                     apic_id;
537
538     cpuid_check_common_x86(cpuid);
539
540     execute_x86cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
541     max_stdfn = eax;
542
543     execute_x86cpuid(0x80000000, 0, &eax, &ebx, &ecx, &edx);
544     max_extfn = eax;
545
546     if (max_extfn >= 0x80000001)
547     {
548         execute_x86cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx);
549
550         cpuid->feature[GMX_CPUID_FEATURE_X86_SSE4A]       = (ecx & (1 << 6))  != 0;
551         cpuid->feature[GMX_CPUID_FEATURE_X86_MISALIGNSSE] = (ecx & (1 << 7))  != 0;
552         cpuid->feature[GMX_CPUID_FEATURE_X86_XOP]         = (ecx & (1 << 11)) != 0;
553         cpuid->feature[GMX_CPUID_FEATURE_X86_FMA4]        = (ecx & (1 << 16)) != 0;
554     }
555
556     /* Query APIC information on AMD */
557     if (max_extfn >= 0x80000008)
558     {
559 #if (defined HAVE_SCHED_H && defined HAVE_SCHED_SETAFFINITY && defined HAVE_SYSCONF && defined __linux__)
560         /* Linux */
561         unsigned int   i;
562         cpu_set_t      cpuset, save_cpuset;
563         cpuid->nproc = sysconf(_SC_NPROCESSORS_ONLN);
564         apic_id      = malloc(sizeof(int)*cpuid->nproc);
565         sched_getaffinity(0, sizeof(cpu_set_t), &save_cpuset);
566         /* Get APIC id from each core */
567         CPU_ZERO(&cpuset);
568         for (i = 0; i < cpuid->nproc; i++)
569         {
570             CPU_SET(i, &cpuset);
571             sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
572             execute_x86cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
573             apic_id[i] = ebx >> 24;
574             CPU_CLR(i, &cpuset);
575         }
576         /* Reset affinity to the value it had when calling this routine */
577         sched_setaffinity(0, sizeof(cpu_set_t), &save_cpuset);
578 #define CPUID_HAVE_APIC
579 #elif defined GMX_NATIVE_WINDOWS
580         /* Windows */
581         DWORD_PTR     i;
582         SYSTEM_INFO   sysinfo;
583         unsigned int  save_affinity, affinity;
584         GetSystemInfo( &sysinfo );
585         cpuid->nproc  = sysinfo.dwNumberOfProcessors;
586         apic_id       = malloc(sizeof(int)*cpuid->nproc);
587         /* Get previous affinity mask */
588         save_affinity = SetThreadAffinityMask(GetCurrentThread(), 1);
589         for (i = 0; i < cpuid->nproc; i++)
590         {
591             SetThreadAffinityMask(GetCurrentThread(), (((DWORD_PTR)1)<<i));
592             Sleep(0);
593             execute_x86cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
594             apic_id[i] = ebx >> 24;
595         }
596         SetThreadAffinityMask(GetCurrentThread(), save_affinity);
597 #define CPUID_HAVE_APIC
598 #endif
599 #ifdef CPUID_HAVE_APIC
600         /* AMD does not support SMT yet - there are no hwthread bits in apic ID */
601         hwthread_bits = 0;
602         /* Get number of core bits in apic ID - try modern extended method first */
603         execute_x86cpuid(0x80000008, 0, &eax, &ebx, &ecx, &edx);
604         core_bits = (ecx >> 12) & 0xf;
605         if (core_bits == 0)
606         {
607             /* Legacy method for old single/dual core AMD CPUs */
608             int i = ecx & 0xF;
609             for (core_bits = 0; (i>>core_bits) > 0; core_bits++)
610             {
611                 ;
612             }
613         }
614         ret = cpuid_x86_decode_apic_id(cpuid, apic_id, core_bits,
615                                        hwthread_bits);
616         cpuid->have_cpu_topology = (ret == 0);
617 #endif
618     }
619     return 0;
620 }
621
622 /* Detection of Intel-specific CPU features */
623 static int
624 cpuid_check_intel_x86(gmx_cpuid_t                cpuid)
625 {
626     unsigned int              max_stdfn, max_extfn, ret;
627     unsigned int              eax, ebx, ecx, edx;
628     unsigned int              max_logical_cores, max_physical_cores;
629     int                       hwthread_bits, core_bits;
630     int *                     apic_id;
631
632     cpuid_check_common_x86(cpuid);
633
634     execute_x86cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
635     max_stdfn = eax;
636
637     execute_x86cpuid(0x80000000, 0, &eax, &ebx, &ecx, &edx);
638     max_extfn = eax;
639
640     if (max_stdfn >= 1)
641     {
642         execute_x86cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
643         cpuid->feature[GMX_CPUID_FEATURE_X86_PDCM]    = (ecx & (1 << 15)) != 0;
644         cpuid->feature[GMX_CPUID_FEATURE_X86_PCID]    = (ecx & (1 << 17)) != 0;
645         cpuid->feature[GMX_CPUID_FEATURE_X86_X2APIC]  = (ecx & (1 << 21)) != 0;
646         cpuid->feature[GMX_CPUID_FEATURE_X86_TDT]     = (ecx & (1 << 24)) != 0;
647     }
648
649     if (max_stdfn >= 7)
650     {
651         execute_x86cpuid(0x7, 0, &eax, &ebx, &ecx, &edx);
652         cpuid->feature[GMX_CPUID_FEATURE_X86_AVX2]    = (ebx & (1 << 5))  != 0;
653     }
654
655     /* Check whether Hyper-Threading is enabled, not only supported */
656     if (cpuid->feature[GMX_CPUID_FEATURE_X86_HTT] && max_stdfn >= 4)
657     {
658         execute_x86cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
659         max_logical_cores  = (ebx >> 16) & 0x0FF;
660         execute_x86cpuid(0x4, 0, &eax, &ebx, &ecx, &edx);
661         max_physical_cores = ((eax >> 26) & 0x3F) + 1;
662
663         /* Clear HTT flag if we only have 1 logical core per physical */
664         if (max_logical_cores/max_physical_cores < 2)
665         {
666             cpuid->feature[GMX_CPUID_FEATURE_X86_HTT] = 0;
667         }
668     }
669
670     if (max_stdfn >= 0xB)
671     {
672         /* Query x2 APIC information from cores */
673 #if (defined HAVE_SCHED_H && defined HAVE_SCHED_SETAFFINITY && defined HAVE_SYSCONF && defined __linux__)
674         /* Linux */
675         unsigned int   i;
676         cpu_set_t      cpuset, save_cpuset;
677         cpuid->nproc = sysconf(_SC_NPROCESSORS_ONLN);
678         apic_id      = malloc(sizeof(int)*cpuid->nproc);
679         sched_getaffinity(0, sizeof(cpu_set_t), &save_cpuset);
680         /* Get x2APIC ID from each hardware thread */
681         CPU_ZERO(&cpuset);
682         for (i = 0; i < cpuid->nproc; i++)
683         {
684             CPU_SET(i, &cpuset);
685             sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
686             execute_x86cpuid(0xB, 0, &eax, &ebx, &ecx, &edx);
687             apic_id[i] = edx;
688             CPU_CLR(i, &cpuset);
689         }
690         /* Reset affinity to the value it had when calling this routine */
691         sched_setaffinity(0, sizeof(cpu_set_t), &save_cpuset);
692 #define CPUID_HAVE_APIC
693 #elif defined GMX_NATIVE_WINDOWS
694         /* Windows */
695         DWORD_PTR     i;
696         SYSTEM_INFO   sysinfo;
697         unsigned int  save_affinity, affinity;
698         GetSystemInfo( &sysinfo );
699         cpuid->nproc  = sysinfo.dwNumberOfProcessors;
700         apic_id       = malloc(sizeof(int)*cpuid->nproc);
701         /* Get previous affinity mask */
702         save_affinity = SetThreadAffinityMask(GetCurrentThread(), 1);
703         for (i = 0; i < cpuid->nproc; i++)
704         {
705             SetThreadAffinityMask(GetCurrentThread(), (((DWORD_PTR)1)<<i));
706             Sleep(0);
707             execute_x86cpuid(0xB, 0, &eax, &ebx, &ecx, &edx);
708             apic_id[i] = edx;
709         }
710         SetThreadAffinityMask(GetCurrentThread(), save_affinity);
711 #define CPUID_HAVE_APIC
712 #endif
713 #ifdef CPUID_HAVE_APIC
714         execute_x86cpuid(0xB, 0, &eax, &ebx, &ecx, &edx);
715         hwthread_bits    = eax & 0x1F;
716         execute_x86cpuid(0xB, 1, &eax, &ebx, &ecx, &edx);
717         core_bits        = (eax & 0x1F) - hwthread_bits;
718         ret              = cpuid_x86_decode_apic_id(cpuid, apic_id, core_bits,
719                                                     hwthread_bits);
720         cpuid->have_cpu_topology = (ret == 0);
721 #endif
722     }
723     return 0;
724 }
725 #endif /* GMX_CPUID_X86 */
726
727
728
729
730 static void
731 chomp_substring_before_colon(const char *in, char *s, int maxlength)
732 {
733     char *p;
734     strncpy(s, in, maxlength);
735     p = strchr(s, ':');
736     if (p != NULL)
737     {
738         *p = '\0';
739         while (isspace(*(--p)) && (p >= s))
740         {
741             *p = '\0';
742         }
743     }
744     else
745     {
746         *s = '\0';
747     }
748 }
749
750 static void
751 chomp_substring_after_colon(const char *in, char *s, int maxlength)
752 {
753     char *p;
754     if ( (p = strchr(in, ':')) != NULL)
755     {
756         p++;
757         while (isspace(*p))
758         {
759             p++;
760         }
761         strncpy(s, p, maxlength);
762         p = s+strlen(s);
763         while (isspace(*(--p)) && (p >= s))
764         {
765             *p = '\0';
766         }
767     }
768     else
769     {
770         *s = '\0';
771     }
772 }
773
774 /* Try to find the vendor of the current CPU, so we know what specific
775  * detection routine to call.
776  */
777 static enum gmx_cpuid_vendor
778 cpuid_check_vendor(void)
779 {
780     enum gmx_cpuid_vendor      i, vendor;
781     /* Register data used on x86 */
782     unsigned int               eax, ebx, ecx, edx;
783     char                       vendorstring[13];
784     FILE *                     fp;
785     char                       buffer[255], before_colon[255], after_colon[255];
786
787     /* Set default first */
788     vendor = GMX_CPUID_VENDOR_UNKNOWN;
789
790 #ifdef GMX_CPUID_X86
791     execute_x86cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
792
793     memcpy(vendorstring, &ebx, 4);
794     memcpy(vendorstring+4, &edx, 4);
795     memcpy(vendorstring+8, &ecx, 4);
796
797     vendorstring[12] = '\0';
798
799     for (i = GMX_CPUID_VENDOR_UNKNOWN; i < GMX_CPUID_NVENDORS; i++)
800     {
801         if (!strncmp(vendorstring, gmx_cpuid_vendor_string[i], 12))
802         {
803             vendor = i;
804         }
805     }
806 #elif defined(__linux__) || defined(__linux)
807     /* General Linux. Try to get CPU vendor from /proc/cpuinfo */
808     if ( (fp = fopen("/proc/cpuinfo", "r")) != NULL)
809     {
810         while ( (vendor == GMX_CPUID_VENDOR_UNKNOWN) && (fgets(buffer, sizeof(buffer), fp) != NULL))
811         {
812             chomp_substring_before_colon(buffer, before_colon, sizeof(before_colon));
813             /* Intel/AMD use "vendor_id", IBM "vendor"(?) or "model". Fujitsu "manufacture". Add others if you have them! */
814             if (!strcmp(before_colon, "vendor_id")
815                 || !strcmp(before_colon, "vendor")
816                 || !strcmp(before_colon, "manufacture")
817                 || !strcmp(before_colon, "model"))
818             {
819                 chomp_substring_after_colon(buffer, after_colon, sizeof(after_colon));
820                 for (i = GMX_CPUID_VENDOR_UNKNOWN; i < GMX_CPUID_NVENDORS; i++)
821                 {
822                     /* Be liberal and accept if we find the vendor
823                      * string (or alternative string) anywhere. Using
824                      * strcasestr() would be non-portable. */
825                     if (strstr(after_colon, gmx_cpuid_vendor_string[i])
826                         || strstr(after_colon, gmx_cpuid_vendor_string_alternative[i]))
827                     {
828                         vendor = i;
829                     }
830                 }
831             }
832         }
833     }
834     fclose(fp);
835 #endif
836
837     return vendor;
838 }
839
840
841
842 int
843 gmx_cpuid_topology(gmx_cpuid_t        cpuid,
844                    int *              nprocessors,
845                    int *              npackages,
846                    int *              ncores_per_package,
847                    int *              nhwthreads_per_core,
848                    const int **       package_id,
849                    const int **       core_id,
850                    const int **       hwthread_id,
851                    const int **       locality_order)
852 {
853     int rc;
854
855     if (cpuid->have_cpu_topology)
856     {
857         *nprocessors          = cpuid->nproc;
858         *npackages            = cpuid->npackages;
859         *ncores_per_package   = cpuid->ncores_per_package;
860         *nhwthreads_per_core  = cpuid->nhwthreads_per_core;
861         *package_id           = cpuid->package_id;
862         *core_id              = cpuid->core_id;
863         *hwthread_id          = cpuid->hwthread_id;
864         *locality_order       = cpuid->locality_order;
865         rc                    = 0;
866     }
867     else
868     {
869         rc = -1;
870     }
871     return rc;
872 }
873
874
875 enum gmx_cpuid_x86_smt
876 gmx_cpuid_x86_smt(gmx_cpuid_t cpuid)
877 {
878     enum gmx_cpuid_x86_smt rc;
879
880     if (cpuid->have_cpu_topology)
881     {
882         rc = (cpuid->nhwthreads_per_core > 1) ? GMX_CPUID_X86_SMT_ENABLED : GMX_CPUID_X86_SMT_DISABLED;
883     }
884     else if (cpuid->vendor == GMX_CPUID_VENDOR_AMD || gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_HTT) == 0)
885     {
886         rc = GMX_CPUID_X86_SMT_DISABLED;
887     }
888     else
889     {
890         rc = GMX_CPUID_X86_SMT_CANNOTDETECT;
891     }
892     return rc;
893 }
894
895
896 int
897 gmx_cpuid_init               (gmx_cpuid_t *              pcpuid)
898 {
899     gmx_cpuid_t cpuid;
900     int         i;
901     FILE *      fp;
902     char        buffer[255], buffer2[255];
903     int         found_brand;
904
905     cpuid = malloc(sizeof(*cpuid));
906
907     *pcpuid = cpuid;
908
909     for (i = 0; i < GMX_CPUID_NFEATURES; i++)
910     {
911         cpuid->feature[i] = 0;
912     }
913
914     cpuid->have_cpu_topology   = 0;
915     cpuid->nproc               = 0;
916     cpuid->npackages           = 0;
917     cpuid->ncores_per_package  = 0;
918     cpuid->nhwthreads_per_core = 0;
919     cpuid->package_id          = NULL;
920     cpuid->core_id             = NULL;
921     cpuid->hwthread_id         = NULL;
922     cpuid->locality_order      = NULL;
923
924     cpuid->vendor = cpuid_check_vendor();
925
926     switch (cpuid->vendor)
927     {
928 #ifdef GMX_CPUID_X86
929         case GMX_CPUID_VENDOR_INTEL:
930             cpuid_check_intel_x86(cpuid);
931             break;
932         case GMX_CPUID_VENDOR_AMD:
933             cpuid_check_amd_x86(cpuid);
934             break;
935 #endif
936         default:
937             /* Default value */
938             strncpy(cpuid->brand, "Unknown CPU brand", GMX_CPUID_BRAND_MAXLEN);
939 #if defined(__linux__) || defined(__linux)
940             /* General Linux. Try to get CPU type from /proc/cpuinfo */
941             if ( (fp = fopen("/proc/cpuinfo", "r")) != NULL)
942             {
943                 found_brand = 0;
944                 while ( (found_brand == 0) && (fgets(buffer, sizeof(buffer), fp) != NULL))
945                 {
946                     chomp_substring_before_colon(buffer, buffer2, sizeof(buffer2));
947                     /* Intel uses "model name", Fujitsu and IBM "cpu". */
948                     if (!strcmp(buffer2, "model name") || !strcmp(buffer2, "cpu"))
949                     {
950                         chomp_substring_after_colon(buffer, cpuid->brand, GMX_CPUID_BRAND_MAXLEN);
951                         found_brand = 1;
952                     }
953                 }
954             }
955             fclose(fp);
956 #endif
957             cpuid->family         = 0;
958             cpuid->model          = 0;
959             cpuid->stepping       = 0;
960
961             for (i = 0; i < GMX_CPUID_NFEATURES; i++)
962             {
963                 cpuid->feature[i] = 0;
964             }
965             cpuid->feature[GMX_CPUID_FEATURE_CANNOTDETECT] = 1;
966             break;
967     }
968     return 0;
969 }
970
971
972
973 void
974 gmx_cpuid_done               (gmx_cpuid_t              cpuid)
975 {
976     free(cpuid);
977 }
978
979
980 int
981 gmx_cpuid_formatstring       (gmx_cpuid_t              cpuid,
982                               char *                   str,
983                               int                      n)
984 {
985     int                     c;
986     int                     i;
987     enum gmx_cpuid_feature  feature;
988
989 #ifdef _MSC_VER
990     _snprintf(str, n,
991               "Vendor: %s\n"
992               "Brand:  %s\n"
993               "Family: %2d  Model: %2d  Stepping: %2d\n"
994               "Features:",
995               gmx_cpuid_vendor_string[gmx_cpuid_vendor(cpuid)],
996               gmx_cpuid_brand(cpuid),
997               gmx_cpuid_family(cpuid), gmx_cpuid_model(cpuid), gmx_cpuid_stepping(cpuid));
998 #else
999     snprintf(str, n,
1000              "Vendor: %s\n"
1001              "Brand:  %s\n"
1002              "Family: %2d  Model: %2d  Stepping: %2d\n"
1003              "Features:",
1004              gmx_cpuid_vendor_string[gmx_cpuid_vendor(cpuid)],
1005              gmx_cpuid_brand(cpuid),
1006              gmx_cpuid_family(cpuid), gmx_cpuid_model(cpuid), gmx_cpuid_stepping(cpuid));
1007 #endif
1008
1009     str[n-1] = '\0';
1010     c        = strlen(str);
1011     n       -= c;
1012     str     += c;
1013
1014     for (feature = GMX_CPUID_FEATURE_CANNOTDETECT; feature < GMX_CPUID_NFEATURES; feature++)
1015     {
1016         if (gmx_cpuid_feature(cpuid, feature) == 1)
1017         {
1018 #ifdef _MSC_VER
1019             _snprintf(str, n, " %s", gmx_cpuid_feature_string[feature]);
1020 #else
1021             snprintf(str, n, " %s", gmx_cpuid_feature_string[feature]);
1022 #endif
1023             str[n-1] = '\0';
1024             c        = strlen(str);
1025             n       -= c;
1026             str     += c;
1027         }
1028     }
1029 #ifdef _MSC_VER
1030     _snprintf(str, n, "\n");
1031 #else
1032     snprintf(str, n, "\n");
1033 #endif
1034     str[n-1] = '\0';
1035
1036     return 0;
1037 }
1038
1039
1040
1041 enum gmx_cpuid_simd
1042 gmx_cpuid_simd_suggest  (gmx_cpuid_t                 cpuid)
1043 {
1044     enum gmx_cpuid_simd  tmpsimd;
1045
1046     tmpsimd = GMX_CPUID_SIMD_NONE;
1047
1048     if (gmx_cpuid_vendor(cpuid) == GMX_CPUID_VENDOR_INTEL)
1049     {
1050         if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_AVX2))
1051         {
1052             tmpsimd = GMX_CPUID_SIMD_X86_AVX2_256;
1053         }
1054         else if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_AVX))
1055         {
1056             tmpsimd = GMX_CPUID_SIMD_X86_AVX_256;
1057         }
1058         else if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_SSE4_1))
1059         {
1060             tmpsimd = GMX_CPUID_SIMD_X86_SSE4_1;
1061         }
1062         else if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_SSE2))
1063         {
1064             tmpsimd = GMX_CPUID_SIMD_X86_SSE2;
1065         }
1066     }
1067     else if (gmx_cpuid_vendor(cpuid) == GMX_CPUID_VENDOR_AMD)
1068     {
1069         if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_AVX))
1070         {
1071             tmpsimd = GMX_CPUID_SIMD_X86_AVX_128_FMA;
1072         }
1073         else if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_SSE4_1))
1074         {
1075             tmpsimd = GMX_CPUID_SIMD_X86_SSE4_1;
1076         }
1077         else if (gmx_cpuid_feature(cpuid, GMX_CPUID_FEATURE_X86_SSE2))
1078         {
1079             tmpsimd = GMX_CPUID_SIMD_X86_SSE2;
1080         }
1081     }
1082     else if (gmx_cpuid_vendor(cpuid) == GMX_CPUID_VENDOR_FUJITSU)
1083     {
1084         if (strstr(gmx_cpuid_brand(cpuid), "SPARC64"))
1085         {
1086             tmpsimd = GMX_CPUID_SIMD_SPARC64_HPC_ACE;
1087         }
1088     }
1089     else if (gmx_cpuid_vendor(cpuid) == GMX_CPUID_VENDOR_IBM)
1090     {
1091         if (strstr(gmx_cpuid_brand(cpuid), "A2"))
1092         {
1093             tmpsimd = GMX_CPUID_SIMD_IBM_QPX;
1094         }
1095     }
1096     return tmpsimd;
1097 }
1098
1099
1100
1101 int
1102 gmx_cpuid_simd_check(gmx_cpuid_t   cpuid,
1103                      FILE *        log,
1104                      int           print_to_stderr)
1105 {
1106     int                           rc;
1107     char                          str[1024];
1108     enum gmx_cpuid_simd           simd;
1109
1110     simd = gmx_cpuid_simd_suggest(cpuid);
1111
1112     rc = (simd != compiled_simd);
1113
1114     gmx_cpuid_formatstring(cpuid, str, 1023);
1115     str[1023] = '\0';
1116
1117     if (log != NULL)
1118     {
1119         fprintf(log,
1120                 "\nDetecting CPU SIMD instructions.\nPresent hardware specification:\n"
1121                 "%s"
1122                 "SIMD instructions most likely to fit this hardware: %s\n"
1123                 "SIMD instructions selected at GROMACS compile time: %s\n\n",
1124                 str,
1125                 gmx_cpuid_simd_string[simd],
1126                 gmx_cpuid_simd_string[compiled_simd]);
1127     }
1128
1129     if (rc != 0)
1130     {
1131         if (log != NULL)
1132         {
1133             fprintf(log, "\nBinary not matching hardware - you might be losing performance.\n"
1134                     "SIMD instructions most likely to fit this hardware: %s\n"
1135                     "SIMD instructions selected at GROMACS compile time: %s\n\n",
1136                     gmx_cpuid_simd_string[simd],
1137                     gmx_cpuid_simd_string[compiled_simd]);
1138         }
1139         if (print_to_stderr)
1140         {
1141             fprintf(stderr, "Compiled SIMD instructions: %s (Gromacs could use %s on this machine, which is better)\n",
1142                     gmx_cpuid_simd_string[compiled_simd],
1143                     gmx_cpuid_simd_string[simd]);
1144         }
1145     }
1146     return rc;
1147 }
1148
1149
1150 #ifdef GMX_CPUID_STANDALONE
1151 /* Stand-alone program to enable queries of CPU features from Cmake.
1152  * Note that you need to check inline ASM capabilities before compiling and set
1153  * -DGMX_X86_GCC_INLINE_ASM for the cpuid instruction to work...
1154  */
1155 int
1156 main(int argc, char **argv)
1157 {
1158     gmx_cpuid_t                   cpuid;
1159     enum gmx_cpuid_simd           simd;
1160     int                           i, cnt;
1161
1162     if (argc < 2)
1163     {
1164         fprintf(stdout,
1165                 "Usage:\n\n%s [flags]\n\n"
1166                 "Available flags:\n"
1167                 "-vendor        Print CPU vendor.\n"
1168                 "-brand         Print CPU brand string.\n"
1169                 "-family        Print CPU family version.\n"
1170                 "-model         Print CPU model version.\n"
1171                 "-stepping      Print CPU stepping version.\n"
1172                 "-features      Print CPU feature flags.\n"
1173                 "-simd          Print suggested GROMACS SIMD instructions.\n",
1174                 argv[0]);
1175         exit(0);
1176     }
1177
1178     gmx_cpuid_init(&cpuid);
1179
1180     if (!strncmp(argv[1], "-vendor", 3))
1181     {
1182         printf("%s\n", gmx_cpuid_vendor_string[cpuid->vendor]);
1183     }
1184     else if (!strncmp(argv[1], "-brand", 3))
1185     {
1186         printf("%s\n", cpuid->brand);
1187     }
1188     else if (!strncmp(argv[1], "-family", 3))
1189     {
1190         printf("%d\n", cpuid->family);
1191     }
1192     else if (!strncmp(argv[1], "-model", 3))
1193     {
1194         printf("%d\n", cpuid->model);
1195     }
1196     else if (!strncmp(argv[1], "-stepping", 3))
1197     {
1198         printf("%d\n", cpuid->stepping);
1199     }
1200     else if (!strncmp(argv[1], "-features", 3))
1201     {
1202         cnt = 0;
1203         for (i = 0; i < GMX_CPUID_NFEATURES; i++)
1204         {
1205             if (cpuid->feature[i] == 1)
1206             {
1207                 if (cnt++ > 0)
1208                 {
1209                     printf(" ");
1210                 }
1211                 printf("%s", gmx_cpuid_feature_string[i]);
1212             }
1213         }
1214         printf("\n");
1215     }
1216     else if (!strncmp(argv[1], "-simd", 3))
1217     {
1218         simd = gmx_cpuid_simd_suggest(cpuid);
1219         fprintf(stdout, "%s\n", gmx_cpuid_simd_string[simd]);
1220     }
1221
1222     gmx_cpuid_done(cpuid);
1223
1224
1225     return 0;
1226 }
1227
1228 #endif