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