cyb70289 commented on code in PR #13112:
URL: https://github.com/apache/arrow/pull/13112#discussion_r873588128


##########
cpp/src/arrow/util/cpu_info.cc:
##########
@@ -308,262 +218,431 @@ bool RetrieveCPUInfo(int64_t* hardware_flags, 
std::string* model_name,
       if (features_EBX[31]) *hardware_flags |= CpuInfo::AVX512VL;
     }
   }
-
-  return true;
+}
+#elif defined(CPUINFO_ARCH_ARM)
+// Windows on Arm
+void OsRetrieveCpuInfo(int64_t* hardware_flags, CpuInfo::Vendor* vendor,
+                       std::string* model_name) {
+  *hardware_flags |= CpuInfo::ASIMD;
+  // TODO: vendor, model_name
 }
 #endif
-#endif
-
-}  // namespace
 
-CpuInfo::CpuInfo()
-    : hardware_flags_(0),
-      num_cores_(1),
-      model_name_("unknown"),
-      vendor_(Vendor::Unknown) {}
-
-std::unique_ptr<CpuInfo> g_cpu_info;
-static std::once_flag cpuinfo_initialized;
-
-CpuInfo* CpuInfo::GetInstance() {
-  std::call_once(cpuinfo_initialized, []() {
-    g_cpu_info.reset(new CpuInfo);
-    g_cpu_info->Init();
-  });
-  return g_cpu_info.get();
+#elif defined(__APPLE__)
+//------------------------------ MACOS ------------------------------//
+util::optional<int64_t> IntegerSysCtlByName(const char* name) {
+  size_t len = sizeof(int64_t);
+  int64_t data = 0;
+  if (sysctlbyname(name, &data, &len, nullptr, 0) == 0) {
+    return data;
+  }
+  // ENOENT is the official errno value for non-existing sysctl's,
+  // but EINVAL and ENOTSUP have been seen in the wild.
+  if (errno != ENOENT && errno != EINVAL && errno != ENOTSUP) {
+    auto st = IOErrorFromErrno(errno, "sysctlbyname failed for '", name, "'");
+    ARROW_LOG(WARNING) << st.ToString();
+  }
+  return util::nullopt;
 }
 
-void CpuInfo::Init() {
-  std::string line;
-  std::string name;
-  std::string value;
-
-  float max_mhz = 0;
-  int num_cores = 0;
-
-  memset(&cache_sizes_, 0, sizeof(cache_sizes_));
-
-#ifdef _WIN32
-  SYSTEM_INFO system_info;
-  GetSystemInfo(&system_info);
-  num_cores = system_info.dwNumberOfProcessors;
-
-  LARGE_INTEGER performance_frequency;
-  if (QueryPerformanceFrequency(&performance_frequency)) {
-    max_mhz = static_cast<float>(performance_frequency.QuadPart);
+void OsRetrieveCacheSize(std::array<int64_t, kCacheLevels>* cache_sizes) {
+  static_assert(kCacheLevels >= 3, "");
+  auto c = IntegerSysCtlByName("hw.l1dcachesize");
+  if (c.has_value()) {
+    (*cache_sizes)[0] = *c;
   }
-#elif defined(__APPLE__)
-  // On macOS, get CPU information from system information base
+  c = IntegerSysCtlByName("hw.l2cachesize");
+  if (c.has_value()) {
+    (*cache_sizes)[1] = *c;
+  }
+  c = IntegerSysCtlByName("hw.l3cachesize");
+  if (c.has_value()) {
+    (*cache_sizes)[2] = *c;
+  }
+}
+
+void OsRetrieveCpuInfo(int64_t* hardware_flags, CpuInfo::Vendor* vendor,
+                       std::string* model_name) {
+  // hardware_flags
   struct SysCtlCpuFeature {
     const char* name;
     int64_t flag;
   };
   std::vector<SysCtlCpuFeature> features = {
-#if defined(__aarch64__)
+#if defined(CPUINFO_ARCH_X86)
+    {"hw.optional.sse4_2",
+     CpuInfo::SSSE3 | CpuInfo::SSE4_1 | CpuInfo::SSE4_2 | CpuInfo::POPCNT},
+    {"hw.optional.avx1_0", CpuInfo::AVX},
+    {"hw.optional.avx2_0", CpuInfo::AVX2},
+    {"hw.optional.bmi1", CpuInfo::BMI1},
+    {"hw.optional.bmi2", CpuInfo::BMI2},
+    {"hw.optional.avx512f", CpuInfo::AVX512F},
+    {"hw.optional.avx512cd", CpuInfo::AVX512CD},
+    {"hw.optional.avx512dq", CpuInfo::AVX512DQ},
+    {"hw.optional.avx512bw", CpuInfo::AVX512BW},
+    {"hw.optional.avx512vl", CpuInfo::AVX512VL},
+#elif defined(CPUINFO_ARCH_ARM)
     // ARM64 (note that this is exposed under Rosetta as well)
-    {"hw.optional.neon", ASIMD},
-#else
-    // x86
-    {"hw.optional.sse4_2", SSSE3 | SSE4_1 | SSE4_2 | POPCNT},
-    {"hw.optional.avx1_0", AVX},
-    {"hw.optional.avx2_0", AVX2},
-    {"hw.optional.bmi1", BMI1},
-    {"hw.optional.bmi2", BMI2},
-    {"hw.optional.avx512f", AVX512F},
-    {"hw.optional.avx512cd", AVX512CD},
-    {"hw.optional.avx512dq", AVX512DQ},
-    {"hw.optional.avx512bw", AVX512BW},
-    {"hw.optional.avx512vl", AVX512VL},
+    {"hw.optional.neon", CpuInfo::ASIMD},
 #endif
   };
   for (const auto& feature : features) {
     auto v = IntegerSysCtlByName(feature.name);
     if (v.value_or(0)) {
-      hardware_flags_ |= feature.flag;
+      *hardware_flags |= feature.flag;
     }
   }
+
+  // TODO: vendor, model_name
+}
+
 #else
-  // Read from /proc/cpuinfo
+//------------------------------ LINUX ------------------------------//
+// Get cache size, return 0 on error
+int64_t LinuxGetCacheSize(int level) {
+  const struct {
+    int sysconf_name;
+    const char* sysfs_path;
+  } kCacheSizeEntries[] = {
+      {
+          _SC_LEVEL1_DCACHE_SIZE,
+          "/sys/devices/system/cpu/cpu0/cache/index0/size",  // l1d (index1 is 
l1i)
+      },
+      {
+          _SC_LEVEL2_CACHE_SIZE,
+          "/sys/devices/system/cpu/cpu0/cache/index2/size",  // l2
+      },
+      {
+          _SC_LEVEL3_CACHE_SIZE,
+          "/sys/devices/system/cpu/cpu0/cache/index3/size",  // l3
+      },
+  };
+  static_assert(sizeof(kCacheSizeEntries) / sizeof(kCacheSizeEntries[0]) == 
kCacheLevels,
+                "");
+
+  // get cache size by sysconf()
+  errno = 0;
+  const int64_t cache_size = sysconf(kCacheSizeEntries[level].sysconf_name);
+  if (errno == 0 && cache_size > 0) {
+    return cache_size;
+  }
+
+  // get cache size from sysfs if sysconf() fails (it does happen on Arm)
+  std::ifstream cacheinfo(kCacheSizeEntries[level].sysfs_path, std::ios::in);
+  if (!cacheinfo) {
+    return 0;
+  }
+  std::string line;

Review Comment:
   Good catch, code updated.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to