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