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