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