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