]> git.ipfire.org Git - thirdparty/vectorscan.git/commitdiff
avx512: CPU detection and platform hints
authorMatthew Barr <matthew.barr@intel.com>
Tue, 4 Oct 2016 00:18:10 +0000 (11:18 +1100)
committerMatthew Barr <matthew.barr@intel.com>
Tue, 30 May 2017 03:59:23 +0000 (13:59 +1000)
12 files changed:
src/compiler/compiler.cpp
src/database.c
src/database.h
src/hs.cpp
src/hs_compile.h
src/util/arch.h
src/util/cpuid_flags.c
src/util/cpuid_flags.h
src/util/target_info.cpp
src/util/target_info.h
unit/hyperscan/single.cpp
unit/internal/database.cpp

index 9b726f777ef07cf1bb6d2c64b212a202eb067cb4..cce89e408119122be7ae973a378ba0561b91ea6a 100644 (file)
@@ -313,6 +313,9 @@ platform_t target_to_platform(const target_t &target_info) {
     if (!target_info.has_avx2()) {
         p |= HS_PLATFORM_NOAVX2;
     }
+    if (!target_info.has_avx512()) {
+        p |= HS_PLATFORM_NOAVX512;
+    }
     return p;
 }
 
index 61eb021fa106281de5db747ee98d02e763b990de..c6878d898de518bcbd58c5281e1bb49b6c080d40 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -114,7 +114,8 @@ hs_error_t hs_serialize_database(const hs_database_t *db, char **bytes,
 static
 hs_error_t db_check_platform(const u64a p) {
     if (p != hs_current_platform
-        && p != hs_current_platform_no_avx2) {
+        && p != hs_current_platform_no_avx2
+        && p != hs_current_platform_no_avx512) {
         return HS_DB_PLATFORM_ERROR;
     }
     // passed all checks
@@ -366,7 +367,9 @@ hs_error_t print_database_string(char **s, u32 version, const platform_t plat,
     u8 minor = (version >> 16) & 0xff;
     u8 major = (version >> 24) & 0xff;
 
-    const char *avx2 = (plat & HS_PLATFORM_NOAVX2)  ? "NOAVX2" : " AVX2";
+    const char *features = (plat & HS_PLATFORM_NOAVX512)
+                               ? (plat & HS_PLATFORM_NOAVX2) ? "" : "AVX2"
+                               : "AVX512";
 
     const char *mode = NULL;
 
@@ -395,7 +398,7 @@ hs_error_t print_database_string(char **s, u32 version, const platform_t plat,
         // that don't have snprintf but have a workalike.
         int p_len = SNPRINTF_COMPAT(
             buf, len, "Version: %u.%u.%u Features: %s Mode: %s",
-            major, minor, release, avx2, mode);
+            major, minor, release, features, mode);
         if (p_len < 0) {
             DEBUG_PRINTF("snprintf output error, returned %d\n", p_len);
             hs_misc_free(buf);
index 9b24abd437fd745f26552111e2acc3c0b7b342a8..5715ed677d6ed2a656ada11f91603529795ed657 100644 (file)
@@ -54,6 +54,7 @@ extern "C"
 #define HS_PLATFORM_CPU_MASK        0x3F
 
 #define HS_PLATFORM_NOAVX2          (4<<13)
+#define HS_PLATFORM_NOAVX512        (8<<13)
 
 /** \brief Platform features bitmask. */
 typedef u64a platform_t;
@@ -62,6 +63,9 @@ static UNUSED
 const platform_t hs_current_platform = {
 #if !defined(HAVE_AVX2)
     HS_PLATFORM_NOAVX2 |
+#endif
+#if !defined(HAVE_AVX512)
+    HS_PLATFORM_NOAVX512 |
 #endif
     0,
 };
@@ -69,6 +73,13 @@ const platform_t hs_current_platform = {
 static UNUSED
 const platform_t hs_current_platform_no_avx2 = {
     HS_PLATFORM_NOAVX2 |
+    HS_PLATFORM_NOAVX512 |
+    0,
+};
+
+static UNUSED
+const platform_t hs_current_platform_no_avx512 = {
+    HS_PLATFORM_NOAVX512 |
     0,
 };
 
index b9d3b356a2f3303e5404e9738445673e4df0b7ee..af1c3c6a713f0104c5802b609be8cd8c6e2fdd60 100644 (file)
@@ -120,8 +120,9 @@ bool checkMode(unsigned int mode, hs_compile_error **comp_error) {
 
 static
 bool checkPlatform(const hs_platform_info *p, hs_compile_error **comp_error) {
-#define HS_TUNE_LAST HS_TUNE_FAMILY_BDW
-#define HS_CPU_FEATURES_ALL (HS_CPU_FEATURES_AVX2)
+    static constexpr u32 HS_TUNE_LAST = HS_TUNE_FAMILY_GLM;
+    static constexpr u32 HS_CPU_FEATURES_ALL =
+        HS_CPU_FEATURES_AVX2 | HS_CPU_FEATURES_AVX512;
 
     if (!p) {
         return true;
index 1e2e0219834f16d781327617f584cb1679b3bd11..0b64e4b3b961479351591ef0ace535c8c87fe72e 100644 (file)
@@ -780,6 +780,14 @@ hs_error_t hs_populate_platform(hs_platform_info_t *platform);
  */
 #define HS_CPU_FEATURES_AVX2             (1ULL << 2)
 
+/**
+ * CPU features flag - Intel(R) Advanced Vector Extensions 512 (Intel(R) AVX512)
+ *
+ * Setting this flag indicates that the target platform supports AVX512
+ * instructions, specifically AVX-512BW. Using AVX512 implies the use of AVX2.
+ */
+#define HS_CPU_FEATURES_AVX512           (1ULL << 3)
+
 /** @} */
 
 /**
@@ -836,6 +844,30 @@ hs_error_t hs_populate_platform(hs_platform_info_t *platform);
  */
 #define HS_TUNE_FAMILY_BDW 5
 
+/**
+ * Tuning Parameter - Intel(R) microarchitecture code name Skylake
+ *
+ * This indicates that the compiled database should be tuned for the
+ * Skylake microarchitecture.
+ */
+#define HS_TUNE_FAMILY_SKL 6
+
+/**
+ * Tuning Parameter - Intel(R) microarchitecture code name Skylake Server
+ *
+ * This indicates that the compiled database should be tuned for the
+ * Skylake Server microarchitecture.
+ */
+#define HS_TUNE_FAMILY_SKX 7
+
+/**
+ * Tuning Parameter - Intel(R) microarchitecture code name Goldmont
+ *
+ * This indicates that the compiled database should be tuned for the
+ * Goldmont microarchitecture.
+ */
+#define HS_TUNE_FAMILY_GLM 8
+
 /** @} */
 
 /**
index 2ed1793a127c75d702152cea92c515101eac486f..c78ee9cedf3d99fcd08ce136e8a60c9c08290d43 100644 (file)
 #define HAVE_AVX2
 #endif
 
+#if defined(__AVX512BW__)
+#define HAVE_AVX512
+#endif
+
 /*
  * ICC and MSVC don't break out POPCNT or BMI/2 as separate pre-def macros
  */
index e9bdf69017fa9dd3d2ce67b515ade87a9c9b6610..d4eaa3196fb2d05655576bf3a31e3680fb74521f 100644 (file)
 #define AVX2 (1 << 5)
 #define BMI2 (1 << 8)
 
+// Structured Extended Feature Flags Enumeration Leaf EBX values
+#define AVX512F (1 << 16)
+#define AVX512BW (1 << 30)
+
 // Extended Control Register 0 (XCR0) values
 #define XCR0_SSE (1 << 1)
 #define XCR0_AVX (1 << 2)
+#define XCR0_OPMASK (1 << 5) // k-regs
+#define XCR0_ZMM_Hi256 (1 << 6) // upper 256 bits of ZMM0-ZMM15
+#define XCR0_Hi16_ZMM (1 << 7) // ZMM16-ZMM31
+
+#define XCR0_AVX512 (XCR0_OPMASK | XCR0_ZMM_Hi256 | XCR0_Hi16_ZMM)
 
 static __inline
 void cpuid(unsigned int op, unsigned int leaf, unsigned int *eax,
@@ -124,6 +133,49 @@ int check_avx2(void) {
 #endif
 }
 
+static
+int check_avx512(void) {
+    /*
+     * For our purposes, having avx512 really means "can we use AVX512BW?"
+     */
+#if defined(__INTEL_COMPILER)
+    return _may_i_use_cpu_feature(_FEATURE_AVX512BW);
+#else
+    unsigned int eax, ebx, ecx, edx;
+
+    cpuid(1, 0, &eax, &ebx, &ecx, &edx);
+
+    /* check XSAVE is enabled by OS */
+    if (!(ecx & XSAVE)) {
+        DEBUG_PRINTF("AVX and XSAVE not supported\n");
+        return 0;
+    }
+
+    /* check that AVX 512 registers are enabled by OS */
+    u64a xcr0 = xgetbv(0);
+    if ((xcr0 & XCR0_AVX512) != XCR0_AVX512) {
+        DEBUG_PRINTF("AVX512 registers not enabled\n");
+        return 0;
+    }
+
+    /* ECX and EDX contain capability flags */
+    ecx = 0;
+    cpuid(7, 0, &eax, &ebx, &ecx, &edx);
+
+    if (!(ebx & AVX512F)) {
+        DEBUG_PRINTF("AVX512F (AVX512 Foundation) instructions not enabled\n");
+        return 0;
+    }
+
+    if (ebx & AVX512BW) {
+        DEBUG_PRINTF("AVX512BW instructions enabled\n");
+        return 1;
+    }
+
+    return 0;
+#endif
+}
+
 u64a cpuid_flags(void) {
     u64a cap = 0;
 
@@ -132,10 +184,19 @@ u64a cpuid_flags(void) {
         cap |= HS_CPU_FEATURES_AVX2;
     }
 
+    if (check_avx512()) {
+        DEBUG_PRINTF("AVX512 enabled\n");
+        cap |= HS_CPU_FEATURES_AVX512;
+    }
+
 #if !defined(FAT_RUNTIME) && !defined(HAVE_AVX2)
     cap &= ~HS_CPU_FEATURES_AVX2;
 #endif
 
+#if !defined(FAT_RUNTIME) && !defined(HAVE_AVX512)
+    cap &= ~HS_CPU_FEATURES_AVX512;
+#endif
+
     return cap;
 }
 
@@ -168,33 +229,37 @@ struct family_id {
  * Family Numbers" */
 static const struct family_id known_microarch[] = {
     { 0x6, 0x37, HS_TUNE_FAMILY_SLM }, /* baytrail */
+    { 0x6, 0x4A, HS_TUNE_FAMILY_SLM }, /* silvermont */
+    { 0x6, 0x4C, HS_TUNE_FAMILY_SLM }, /* silvermont */
     { 0x6, 0x4D, HS_TUNE_FAMILY_SLM }, /* avoton, rangley */
+    { 0x6, 0x5A, HS_TUNE_FAMILY_SLM }, /* silvermont */
+    { 0x6, 0x5D, HS_TUNE_FAMILY_SLM }, /* silvermont */
+
+    { 0x6, 0x5C, HS_TUNE_FAMILY_GLM }, /* goldmont */
+    { 0x6, 0x5F, HS_TUNE_FAMILY_GLM }, /* denverton */
 
     { 0x6, 0x3C, HS_TUNE_FAMILY_HSW }, /* haswell */
     { 0x6, 0x45, HS_TUNE_FAMILY_HSW }, /* haswell */
     { 0x6, 0x46, HS_TUNE_FAMILY_HSW }, /* haswell */
-    { 0x6, 0x3F, HS_TUNE_FAMILY_HSW }, /* haswell */
+    { 0x6, 0x3F, HS_TUNE_FAMILY_HSW }, /* haswell Xeon */
 
-    { 0x6, 0x3E, HS_TUNE_FAMILY_IVB }, /* ivybridge */
+    { 0x6, 0x3E, HS_TUNE_FAMILY_IVB }, /* ivybridge Xeon */
     { 0x6, 0x3A, HS_TUNE_FAMILY_IVB }, /* ivybridge */
 
     { 0x6, 0x2A, HS_TUNE_FAMILY_SNB }, /* sandybridge */
-    { 0x6, 0x2D, HS_TUNE_FAMILY_SNB }, /* sandybridge */
+    { 0x6, 0x2D, HS_TUNE_FAMILY_SNB }, /* sandybridge Xeon */
 
     { 0x6, 0x3D, HS_TUNE_FAMILY_BDW }, /* broadwell Core-M */
+    { 0x6, 0x47, HS_TUNE_FAMILY_BDW }, /* broadwell */
     { 0x6, 0x4F, HS_TUNE_FAMILY_BDW }, /* broadwell xeon */
     { 0x6, 0x56, HS_TUNE_FAMILY_BDW }, /* broadwell xeon-d */
 
-//    { 0x6, 0x25, HS_TUNE_FAMILY_GENERIC }, /* westmere */
-//    { 0x6, 0x2C, HS_TUNE_FAMILY_GENERIC }, /* westmere */
-//    { 0x6, 0x2F, HS_TUNE_FAMILY_GENERIC }, /* westmere */
-
-//    { 0x6, 0x1E, HS_TUNE_FAMILY_GENERIC }, /* nehalem */
-//    { 0x6, 0x1A, HS_TUNE_FAMILY_GENERIC }, /* nehalem */
-//    { 0x6, 0x2E, HS_TUNE_FAMILY_GENERIC }, /* nehalem */
+    { 0x6, 0x4E, HS_TUNE_FAMILY_SKL }, /* Skylake Mobile */
+    { 0x6, 0x5E, HS_TUNE_FAMILY_SKL }, /* Skylake Core/E3 Xeon */
+    { 0x6, 0x55, HS_TUNE_FAMILY_SKX }, /* Skylake Xeon */
 
-//    { 0x6, 0x17, HS_TUNE_FAMILY_GENERIC }, /* penryn */
-//    { 0x6, 0x1D, HS_TUNE_FAMILY_GENERIC }, /* penryn */
+    { 0x6, 0x8E, HS_TUNE_FAMILY_SKL }, /* Kabylake Mobile */
+    { 0x6, 0x9E, HS_TUNE_FAMILY_SKL }, /* Kabylake desktop */
 
 };
 
@@ -204,10 +269,13 @@ const char *dumpTune(u32 tune) {
 #define T_CASE(x) case x: return #x;
     switch (tune) {
         T_CASE(HS_TUNE_FAMILY_SLM);
+        T_CASE(HS_TUNE_FAMILY_GLM);
         T_CASE(HS_TUNE_FAMILY_HSW);
         T_CASE(HS_TUNE_FAMILY_SNB);
         T_CASE(HS_TUNE_FAMILY_IVB);
         T_CASE(HS_TUNE_FAMILY_BDW);
+        T_CASE(HS_TUNE_FAMILY_SKL);
+        T_CASE(HS_TUNE_FAMILY_SKX);
     }
 #undef T_CASE
     return "unknown";
index 8b23d4958646756bda980e96a3c5ef2167b3e673..c39038a1151745f4ae00cd530a87d244fe247f0a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -26,8 +26,8 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef CPUID_H_53FFCB14B257C2
-#define CPUID_H_53FFCB14B257C2
+#ifndef UTIL_CPUID_H_
+#define UTIL_CPUID_H_
 
 #include "ue2common.h"
 
@@ -50,5 +50,5 @@ int check_popcnt(void);
 } /* extern "C" */
 #endif
 
-#endif /* CPUID_H_53FFCB14B257C2 */
+#endif /* UTIL_CPUID_H_ */
 
index 4eadec2d2cfcdcaae3771227ec7ffae33a2674ff..3a41e02078d367ad0c45e4df0e3ff90466e0bb6b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2017, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -46,6 +46,10 @@ bool target_t::can_run_on_code_built_for(const target_t &code_target) const {
         return false;
     }
 
+    if (!has_avx512() && code_target.has_avx512()) {
+        return false;
+    }
+
     return true;
 }
 
@@ -53,11 +57,15 @@ target_t::target_t(const hs_platform_info &p)
     : tune(p.tune), cpu_features(p.cpu_features) {}
 
 bool target_t::has_avx2(void) const {
-    return (cpu_features & HS_CPU_FEATURES_AVX2);
+    return cpu_features & HS_CPU_FEATURES_AVX2;
+}
+
+bool target_t::has_avx512(void) const {
+    return cpu_features & HS_CPU_FEATURES_AVX512;
 }
 
 bool target_t::is_atom_class(void) const {
-    return tune == HS_TUNE_FAMILY_SLM;
+    return tune == HS_TUNE_FAMILY_SLM || tune == HS_TUNE_FAMILY_GLM;
 }
 
 } // namespace ue2
index 67b5b7d9e1a87936e51851b3b41d91bda8190a58..794b2985579a409097531f2a252fb4d54b5ee360 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2016, Intel Corporation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -40,6 +40,8 @@ struct target_t {
 
     bool has_avx2(void) const;
 
+    bool has_avx512(void) const;
+
     bool is_atom_class(void) const;
 
     // This asks: can this target (the object) run on code that was built for
index 029d223ae9ab393d1027387eff9e2d551ac50872..01fbfeab56c4c429dbd85f0deb22ba16acd654ff 100644 (file)
@@ -363,7 +363,8 @@ static const unsigned validModes[] = {
 // Mode bits for switching off various architecture features
 static const unsigned long long featureMask[] = {
     ~0ULL, /* native */
-    ~HS_CPU_FEATURES_AVX2, /* no avx2 */
+    ~(HS_CPU_FEATURES_AVX2 | HS_CPU_FEATURES_AVX512), /* no avx2 */
+    ~HS_CPU_FEATURES_AVX512, /* no avx512 */
 };
 
 INSTANTIATE_TEST_CASE_P(Single,
index fa34ead2026bc14cdc01a552f72bb97f6fe4bfbd..8f0c1a695de9a8ba49ca8c4c11499f7f62694410 100644 (file)
@@ -52,6 +52,10 @@ TEST(DB, flagsToPlatform) {
     p.cpu_features |= HS_CPU_FEATURES_AVX2;
 #endif
 
+#if defined(HAVE_AVX512)
+    p.cpu_features |= HS_CPU_FEATURES_AVX512;
+#endif
+
     platform_t pp = target_to_platform(target_t(p));
     ASSERT_EQ(pp, hs_current_platform);
 }