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