Merge branch 'release-4-6' into release-5-0
[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     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;
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__)
559         /* Linux */
560         unsigned int   i;
561         cpu_set_t      cpuset, save_cpuset;
562         cpuid->nproc = sysconf(_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);
567         for (i = 0; i < cpuid->nproc; i++)
568         {
569             CPU_SET(i, &cpuset);
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);
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__)
673         /* Linux */
674         unsigned int   i;
675         cpu_set_t      cpuset, save_cpuset;
676         cpuid->nproc = sysconf(_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);
681         for (i = 0; i < cpuid->nproc; i++)
682         {
683             CPU_SET(i, &cpuset);
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);
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);
734     p = strchr(s, ':');
735     if (p != NULL)
736     {
737         *p = '\0';
738         while (isspace(*(--p)) && (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, ':')) != NULL)
754     {
755         p++;
756         while (isspace(*p))
757         {
758             p++;
759         }
760         strncpy(s, p, maxlength);
761         p = s+strlen(s);
762         while (isspace(*(--p)) && (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))
801         {
802             vendor = i;
803         }
804     }
805 #elif defined(__linux__) || defined(__linux)
806     /* General Linux. Try to get CPU vendor from /proc/cpuinfo */
807     if ( (fp = fopen("/proc/cpuinfo", "r")) != NULL)
808     {
809         while ( (vendor == GMX_CPUID_VENDOR_UNKNOWN) && (fgets(buffer, sizeof(buffer), fp) != NULL))
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")
814                 || !strcmp(before_colon, "vendor")
815                 || !strcmp(before_colon, "manufacture")
816                 || !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;
919     cpuid->core_id             = NULL;
920     cpuid->hwthread_id         = NULL;
921     cpuid->locality_order      = NULL;
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);
938 #if defined(__linux__) || defined(__linux)
939             /* General Linux. Try to get CPU type from /proc/cpuinfo */
940             if ( (fp = fopen("/proc/cpuinfo", "r")) != NULL)
941             {
942                 found_brand = 0;
943                 while ( (found_brand == 0) && (fgets(buffer, sizeof(buffer), fp) != NULL))
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") || !strcmp(buffer2, "cpu"))
948                     {
949                         chomp_substring_after_colon(buffer, cpuid->brand, GMX_CPUID_BRAND_MAXLEN);
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)
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)
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(stderr, "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(stdout,
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))
1180     {
1181         printf("%s\n", gmx_cpuid_vendor_string[cpuid->vendor]);
1182     }
1183     else if (!strncmp(argv[1], "-brand", 3))
1184     {
1185         printf("%s\n", cpuid->brand);
1186     }
1187     else if (!strncmp(argv[1], "-family", 3))
1188     {
1189         printf("%d\n", cpuid->family);
1190     }
1191     else if (!strncmp(argv[1], "-model", 3))
1192     {
1193         printf("%d\n", cpuid->model);
1194     }
1195     else if (!strncmp(argv[1], "-stepping", 3))
1196     {
1197         printf("%d\n", cpuid->stepping);
1198     }
1199     else if (!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))
1216     {
1217         simd = gmx_cpuid_simd_suggest(cpuid);
1218         fprintf(stdout, "%s\n", gmx_cpuid_simd_string[simd]);
1219     }
1220
1221     gmx_cpuid_done(cpuid);
1222
1223
1224     return 0;
1225 }
1226
1227 #endif