从cpu_features源码看如何获得CPU信息

上一篇博文,提到可以用/proc/cpuinfo文件信息获得CPU的相关参数。如果觉得解析这个文件麻烦,也可以使用谷歌的cpu_features开源库来实现:cpu_features: cpu_features 是一个小型的开源函数库,可以在执行期间(Runtime)回报 CPU 的功能,为了维持最大的可移植性以 C89 编写,不占用内存且能在沙盒环境执行

376ebe5e942247e3ae3f5a98161b28b3.png在Linux下,cpu_features也是用 /proc/cpuinfo文件获得信息的,只是它对文件进行了解析处理。下面是部分核心代码:

static bool HandleAarch64Line(const LineResult result,
                              Aarch64Info* const info) {
  StringView line = result.line;
  StringView key, value;
  if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
    if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
      for (size_t i = 0; i < AARCH64_LAST_; ++i) {
        kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
                                         value, kCpuInfoFlags[i], ' '));
      }
    } else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
      info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
    } else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
      info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
    } else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
      info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
    } else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
      info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
    }
  }
  return !result.eof;
}

static void FillProcCpuInfoData(Aarch64Info* const info) {
  const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
  if (fd >= 0) {
    StackLineReader reader;
    StackLineReader_Initialize(&reader, fd);
    for (;;) {
      if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) {
        break;
      }
    }
    CpuFeatures_CloseFile(fd);
  }
}

static const Aarch64Info kEmptyAarch64Info;

Aarch64Info GetAarch64Info(void) {
  // capabilities are fetched from both getauxval and /proc/cpuinfo so we can
  // have some information if the executable is sandboxed (aka no access to
  // /proc/cpuinfo).
  Aarch64Info info = kEmptyAarch64Info;

  FillProcCpuInfoData(&info);
  const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
  for (size_t i = 0; i < AARCH64_LAST_; ++i) {
    if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
      kSetters[i](&info.features, true);
    }
  }

  return info;
}

在Windows下,它是通过调用Windows API GetNativeSystemInfo来获得相关信息的。下面是部分核心代码:

#ifdef CPU_FEATURES_MOCK_CPUID_AARCH64
extern bool GetWindowsIsProcessorFeaturePresent(DWORD);
extern WORD GetWindowsNativeSystemInfoProcessorRevision();
#else  // CPU_FEATURES_MOCK_CPUID_AARCH64
static bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
  return IsProcessorFeaturePresent(dwProcessorFeature);
}

static WORD GetWindowsNativeSystemInfoProcessorRevision() {
  SYSTEM_INFO system_info;
  GetNativeSystemInfo(&system_info);
  return system_info.wProcessorRevision;
}
#endif

static const Aarch64Info kEmptyAarch64Info;

Aarch64Info GetAarch64Info(void) {
  Aarch64Info info = kEmptyAarch64Info;
  info.revision = GetWindowsNativeSystemInfoProcessorRevision();
  info.features.fp =
      GetWindowsIsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE);
  info.features.asimd =
      GetWindowsIsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE);
  info.features.crc32 = GetWindowsIsProcessorFeaturePresent(
      PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
  info.features.asimddp =
      GetWindowsIsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE);
  info.features.jscvt = GetWindowsIsProcessorFeaturePresent(
      PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE);
  info.features.lrcpc = GetWindowsIsProcessorFeaturePresent(
      PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE);
  info.features.atomics = GetWindowsIsProcessorFeaturePresent(
      PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE);

  bool is_crypto_available = GetWindowsIsProcessorFeaturePresent(
      PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
  info.features.aes = is_crypto_available;
  info.features.sha1 = is_crypto_available;
  info.features.sha2 = is_crypto_available;
  info.features.pmull = is_crypto_available;
  return info;
}

#endif  // CPU_FEATURES_OS_WINDOWS
#endif  // CPU_FEATURES_ARCH_AARCH64

为什么cpu_features不直接用汇编获得相关信息呢?因为相关寄存器在用户态是无法访问的,需要在内核里面才能访问。

不过cpu_features在FreeBSD中确实调用了汇编获得CPUID。

uint64_t GetMidrEl1(void) {
  uint64_t midr_el1;
  __asm("mrs %0, MIDR_EL1" : "=r"(midr_el1));
  return midr_el1;
}

 

 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值