如何检测 Knights Landing AVX-512 支持(英特尔至强融核处理器)

英特尔至强融核处理器(代号“Knights Landing”)是第二代英特尔至强融核产品的一部分。Knights Landing 支持 AVX-512 指令,特别是 AVX-512F (foundation)、AVX-512CD(冲突检测)、AVX-512ER(指数函数和倒数函数)和 AVX-512PF(预取)。

如果希望应用能够随处运行,为了在程序中使用这些指令,需要确保操作系统和处理器在应用运行时支持这些指令。

英特尔编译器提供的单个函数 _may_i_use_cpu_feature 可轻松处理一切。 该程序显示了我们如何用它来测试是否能够 使用 AVX-512F、AVX-512ER、AVX-512PF 和 AVX-512CD 指令。

#include <immintrin.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
  const unsigned long knl_features =
      (_FEATURE_AVX512F | _FEATURE_AVX512ER |
       _FEATURE_AVX512PF | _FEATURE_AVX512CD );
  if ( _may_i_use_cpu_feature( knl_features ) )
    printf("This CPU supports AVX-512F+CD+ER+PF as introduced in Knights Landing\n");
  else
    printf("This CPU does not support all Knights Landing AVX-512 features\n");
  return 1;
}

如果采用 -xMIC_AVX512 标记进行编译,英特尔编译器将自动保护二进制,无需进行检查。例如,如果按照以下方式编译和运行,我们可以看到机器(并非 Knights Landing)的运行结果。

icc -xMIC-AVX512 -o sample sample.c
./sample

请验证操作系统和处理器是否支持英特尔 MOVBE、F16C、AVX、FMA、BMI、LZCNT、AVX2、AVX512F、ADX、RDSEED、AVX512ER、AVX512PF 和 AVX512CD 指令。


为了在所有处理器上运行,我们按照以下方式编译和运行:

icc -axMIC-AVX512 -o sample sample.c
./sample

在 Knights Landing 上运行时,将显示:
This CPU supports AVX-512F+CD+ER+PF as introduced in Knights Landing

在不支持 AVX-512 指令,但至少相当于 Knights Landing 的处理器上运行时,将显示:
该 CPU 不支持所有 Knights Landing AVX-512 特性

如果我们希望支持除英特尔之外的编译器,代码将稍微复杂一些,因为函数 _may_i_use_cpu_feature 不是标准函数(而且两个都不是 gcc 和 clang/LLVM 的 __buildin 函数)。以下代码至少适用于英特尔编译器、gcc、clang/LLVM 和 Microsoft 编译器。

#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1300)
 
#include <immintrin.h>
 
int has_intel_knl_features()
{
  const unsigned long knl_features =
      (_FEATURE_AVX512F | _FEATURE_AVX512ER | 
       _FEATURE_AVX512PF | _FEATURE_AVX512CD );
  return _may_i_use_cpu_feature( knl_features );
}
 
#else /* non-Intel compiler */
 
#include <stdint.h>
#if defined(_MSC_VER)
#include <intrin.h>
#endif
 
void run_cpuid(uint32_t eax, uint32_t ecx, uint32_t* abcd)
{
#if defined(_MSC_VER)
  __cpuidex(abcd, eax, ecx);
#else
  uint32_t ebx, edx;
 #if defined( __i386__ ) && defined ( __PIC__ )
  /* in case of PIC under 32-bit EBX cannot be clobbered */
  __asm__ ( "movl %%ebx, %%edi \n\t cpuid \n\t xchgl %%ebx, %%edi" : "=D" (ebx),
 # else
  __asm__ ( "cpuid" : "+b" (ebx),
 # endif
		      "+a" (eax), "+c" (ecx), "=d" (edx) );
	    abcd[0] = eax; abcd[1] = ebx; abcd[2] = ecx; abcd[3] = edx;
#endif
}     
   
int check_xcr0_zmm() {
  uint32_t xcr0;
  uint32_t zmm_ymm_xmm = (7 << 5) | (1 << 2) | (1 << 1);
#if defined(_MSC_VER)
  xcr0 = (uint32_t)_xgetbv(0);  /* min VS2010 SP1 compiler is required */
#else
  __asm__ ("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx" );
#endif
  return ((xcr0 & zmm_ymm_xmm) == zmm_ymm_xmm); /* check if xmm, zmm and zmm state are enabled in XCR0 */
}

int has_intel_knl_features() {
  uint32_t abcd[4];
  uint32_t osxsave_mask = (1 << 27); // OSX.
  uint32_t avx2_bmi12_mask = (1 << 16) | // AVX-512F
                             (1 << 26) | // AVX-512PF
                             (1 << 27) | // AVX-512ER
                             (1 << 28);  // AVX-512CD
  run_cpuid( 1, 0, abcd );
  // step 1 - must ensure OS supports extended processor state management
  if ( (abcd[2] & osxsave_mask) != osxsave_mask ) 
    return 0;
  // step 2 - must ensure OS supports ZMM registers (and YMM, and XMM)
  if ( ! check_xcr0_zmm() )
    return 0;
   
  return 1;
}
#endif /* non-Intel compiler */
   
static int can_use_intel_knl_features() {
  static int knl_features_available = -1;
  /* test is performed once */
  if (knl_features_available < 0 )
    knl_features_available = has_intel_knl_features();
  return knl_features_available;
}
   
#include <stdio.h>
   
int main(int argc, char *argv[]) {
  if ( can_use_intel_knl_features() )
    printf("This CPU supports AVX-512F+CD+ER+PF as introduced in Knights Landing\n");
  else
    printf("This CPU does not support all Knights Landing AVX-512 features\n");
  return 1;
}

致谢:感谢 Max Locktyukhin(英特尔)的文章 - “如何检测第四代智能英特尔酷睿处理器家族的新指令支持”,我将其用作 Knights Landing 检测代码的模型。

有关编译器优化的更完整信息,请参阅优化通知