implement AVX-512 second FMA detection
authorJeff Hammond <jeff.science@gmail.com>
Wed, 12 Aug 2020 12:47:28 +0000 (12:47 +0000)
committerPaul Bauer <paul.bauer.q@gmail.com>
Wed, 12 Aug 2020 12:47:28 +0000 (12:47 +0000)
This uses the CPUID processor name.

We use the condensed method developed for Google cpu_features:
https://github.com/jeffhammond/cpu_features/blob/avx512_fma_count/src/cpuinfo_x86.c#L119
(this link will expire when it is merged into the upstream project)

A more pedantic approach is shown here:
https://github.com/jeffhammond/vpu-count/blob/master/vpu-count.c

This code must be updated when new Intel processors are released.
The author of this commit will bear that maintenance burden as long as possible.

Signed-off-by: Hammond, Jeff R <jeff.r.hammond@intel.com>
src/gromacs/hardware/cpuinfo.cpp
src/gromacs/hardware/cpuinfo.h

index 2004d8fcb173cb98509d494a6c279623fef8e848..d65af627d76110a9d7f686fc5cd9435f1a37dc14 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the GROMACS molecular simulation package.
  *
  * Copyright (c) 2012-2018, The GROMACS development team.
- * Copyright (c) 2019, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -85,6 +85,7 @@
 #endif
 
 #include <cctype>
+#include <cstdint> // uint32_t in X86 processor name code
 #include <cstdlib>
 
 #include <algorithm>
@@ -251,6 +252,49 @@ CpuInfo::Vendor detectX86Vendor()
     return v;
 }
 
+/*! \brief Detect second AVX-512 FMA from the processor name
+ *
+ *  \param [in] brand     x86 processor name
+ *  \param [in] model     x86 model
+ *  \return               True if second FMA present
+ */
+bool detectProcCpuInfoSecondAvx512FMA(const std::string& brand, int model)
+{
+    // Skylake server
+    if (model == 0x55)
+    {
+        // detect Xeon
+        if (brand.find("Xeon") == 9)
+        {
+            // detect Silver or Bronze or specific models
+            if (brand.find("Silver") == 17 || brand.find("Bronze") == 17
+                || (brand.find('W') == 17 && brand.find('0') == 21)   // detect Xeon W 210x
+                || (brand.find('D') == 17 && brand.find("21") == 19)) // detect Xeon D 2xxx
+            {
+                return false;
+            }
+            // detect Gold 5120 and below
+            else if (brand.find("Gold") == 17 && brand.find('5') == 22)
+            {
+                return (brand.find("22") == 24);
+            }
+        }
+        return true;
+    }
+    // Cannon Lake client
+    if (model == 0x66)
+    {
+        return false;
+    }
+    // Ice Lake client
+    if (model == 0x7d || model == 0x7e)
+    {
+        return false;
+    }
+    // This is the right default...
+    return true;
+}
+
 /*! \brief Simple utility function to set/clear feature in a set
  *
  *  \param featureSet    Pointer to the feature set to update
@@ -328,22 +372,6 @@ void detectX86Features(std::string* brand, int* family, int* model, int* steppin
         setFeatureFromBit(features, CpuInfo::Feature::X86_Htt, edx, 28);
     }
 
-    if (maxStdLevel >= 0x7)
-    {
-        executeX86CpuID(0x7, 0, &eax, &ebx, &ecx, &edx);
-
-        setFeatureFromBit(features, CpuInfo::Feature::X86_Hle, ebx, 4);
-        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx2, ebx, 5);
-        setFeatureFromBit(features, CpuInfo::Feature::X86_Rtm, ebx, 11);
-        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx512F, ebx, 16);
-        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx512PF, ebx, 26);
-        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx512ER, ebx, 27);
-        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx512CD, ebx, 28);
-        setFeatureFromBit(features, CpuInfo::Feature::X86_Sha, ebx, 29);
-        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx512BW, ebx, 30);
-        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx512VL, ebx, 31);
-    }
-
     // Check whether Hyper-threading is really possible to enable in the hardware,
     // not just technically supported by this generation of processors
     if ((features->count(CpuInfo::Feature::X86_Htt) != 0U) && maxStdLevel >= 0x4)
@@ -394,6 +422,29 @@ void detectX86Features(std::string* brand, int* family, int* model, int* steppin
         trimString(brand);
     }
 
+    if (maxStdLevel >= 0x7)
+    {
+        executeX86CpuID(0x7, 0, &eax, &ebx, &ecx, &edx);
+
+        setFeatureFromBit(features, CpuInfo::Feature::X86_Hle, ebx, 4);
+        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx2, ebx, 5);
+        setFeatureFromBit(features, CpuInfo::Feature::X86_Rtm, ebx, 11);
+        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx512F, ebx, 16);
+        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx512PF, ebx, 26);
+        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx512ER, ebx, 27);
+        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx512CD, ebx, 28);
+        setFeatureFromBit(features, CpuInfo::Feature::X86_Sha, ebx, 29);
+        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx512BW, ebx, 30);
+        setFeatureFromBit(features, CpuInfo::Feature::X86_Avx512VL, ebx, 31);
+
+        // There is no CPUID bit for this...
+        if (detectProcCpuInfoSecondAvx512FMA(*brand, *model))
+        {
+            features->insert(CpuInfo::Feature::X86_Avx512secondFMA);
+        }
+    }
+
+
     if (maxExtLevel >= 0x80000007)
     {
         executeX86CpuID(0x80000007, 0, &eax, &ebx, &ecx, &edx);
@@ -1050,6 +1101,7 @@ const std::string& CpuInfo::featureString(Feature f)
         { Feature::X86_Avx512CD, "avx512cd" },
         { Feature::X86_Avx512BW, "avx512bw" },
         { Feature::X86_Avx512VL, "avx512vl" },
+        { Feature::X86_Avx512secondFMA, "avx512secondFMA" },
         { Feature::X86_Clfsh, "clfsh" },
         { Feature::X86_Cmov, "cmov" },
         { Feature::X86_Cx8, "cx8" },
index b2e305838caea4834418984609b5f775435efc44..d72b205de99c9ac3b1ab3acbb66972e15e64ae7a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019,2020, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -97,25 +97,26 @@ public:
      */
     enum class Feature
     {
-        X86_Aes,      //!< x86 advanced encryption standard accel.
-        X86_Amd,      //!< This is an AMD x86 processor
-        X86_Apic,     //!< APIC support
-        X86_Avx,      //!< Advanced vector extensions
-        X86_Avx2,     //!< AVX2 including gather support (not used yet)
-        X86_Avx512F,  //!< Foundation AVX-512 instructions
-        X86_Avx512PF, //!< Extended gather/scatter for AVX-512
-        X86_Avx512ER, //!< AVX-512 exponential and recpirocal extensions
-        X86_Avx512CD, //!< Memory conflict-detection for AVX-512
-        X86_Avx512BW, //!< AVX-512 byte and word instructions
-        X86_Avx512VL, //!< AVX-512 vector length extensions
-        X86_Clfsh,    //!< Supports CLFLUSH instruction
-        X86_Cmov,     //!< Conditional move insn support
-        X86_Cx8,      //!< Supports CMPXCHG8B (8-byte compare-exchange)
-        X86_Cx16,     //!< Supports CMPXCHG16B (16-byte compare-exchg)
-        X86_F16C,     //!< Supports 16-bit FP conversion instructions
-        X86_Fma,      //!< Fused-multiply add support (mainly for AVX)
-        X86_Fma4,     //!< 4-operand FMA, only on AMD for now
-        X86_Hle,      //!< Hardware lock elision
+        X86_Aes,             //!< x86 advanced encryption standard accel.
+        X86_Amd,             //!< This is an AMD x86 processor
+        X86_Apic,            //!< APIC support
+        X86_Avx,             //!< Advanced vector extensions
+        X86_Avx2,            //!< AVX2 including gather support (not used yet)
+        X86_Avx512F,         //!< Foundation AVX-512 instructions
+        X86_Avx512PF,        //!< Extended gather/scatter for AVX-512
+        X86_Avx512ER,        //!< AVX-512 exponential and recpirocal extensions
+        X86_Avx512CD,        //!< Memory conflict-detection for AVX-512
+        X86_Avx512BW,        //!< AVX-512 byte and word instructions
+        X86_Avx512VL,        //!< AVX-512 vector length extensions
+        X86_Avx512secondFMA, //!< AVX-512 second FMA unit
+        X86_Clfsh,           //!< Supports CLFLUSH instruction
+        X86_Cmov,            //!< Conditional move insn support
+        X86_Cx8,             //!< Supports CMPXCHG8B (8-byte compare-exchange)
+        X86_Cx16,            //!< Supports CMPXCHG16B (16-byte compare-exchg)
+        X86_F16C,            //!< Supports 16-bit FP conversion instructions
+        X86_Fma,             //!< Fused-multiply add support (mainly for AVX)
+        X86_Fma4,            //!< 4-operand FMA, only on AMD for now
+        X86_Hle,             //!< Hardware lock elision
         X86_Htt,   //!< Hyper-Threading enabled (NOTE: might not match the CPUID HTT support flag)
         X86_Intel, //!< This is an Intel x86 processor
         X86_Lahf,  //!< LAHF/SAHF support in 64 bits