1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements.  See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership.  The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License.  You may obtain a copy of the License at
8 //
9 //   http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied.  See the License for the
15 // specific language governing permissions and limitations
16 // under the License.
17 
18 // From Apache Impala (incubating) as of 2016-01-29. Pared down to a minimal
19 // set of functions needed for Apache Arrow / Apache parquet-cpp
20 
21 #pragma once
22 
23 #include <cstdint>
24 #include <string>
25 
26 #include "arrow/util/visibility.h"
27 
28 namespace arrow {
29 namespace internal {
30 
31 /// CpuInfo is an interface to query for cpu information at runtime.  The caller can
32 /// ask for the sizes of the caches and what hardware features are supported.
33 /// On Linux, this information is pulled from a couple of sys files (/proc/cpuinfo and
34 /// /sys/devices)
35 class ARROW_EXPORT CpuInfo {
36  public:
37   static constexpr int64_t SSSE3 = (1 << 1);
38   static constexpr int64_t SSE4_1 = (1 << 2);
39   static constexpr int64_t SSE4_2 = (1 << 3);
40   static constexpr int64_t POPCNT = (1 << 4);
41   static constexpr int64_t ASIMD = (1 << 5);
42   static constexpr int64_t AVX = (1 << 6);
43   static constexpr int64_t AVX2 = (1 << 7);
44   static constexpr int64_t AVX512F = (1 << 8);
45   static constexpr int64_t AVX512CD = (1 << 9);
46   static constexpr int64_t AVX512VL = (1 << 10);
47   static constexpr int64_t AVX512DQ = (1 << 11);
48   static constexpr int64_t AVX512BW = (1 << 12);
49   static constexpr int64_t BMI1 = (1 << 13);
50   static constexpr int64_t BMI2 = (1 << 14);
51 
52   /// Typical AVX512 subsets consists of AVX512F,AVX512BW,AVX512VL,AVX512CD,AVX512DQ
53   static constexpr int64_t AVX512 = AVX512F | AVX512CD | AVX512VL | AVX512DQ | AVX512BW;
54 
55   /// Cache enums for L1 (data), L2 and L3
56   enum CacheLevel {
57     L1_CACHE = 0,
58     L2_CACHE = 1,
59     L3_CACHE = 2,
60   };
61 
62   enum class Vendor : int { Unknown = 0, Intel, AMD };
63 
64   static CpuInfo* GetInstance();
65 
66   /// Determine if the CPU meets the minimum CPU requirements and if not, issue an error
67   /// and terminate.
68   void VerifyCpuRequirements();
69 
70   /// Returns all the flags for this cpu
71   int64_t hardware_flags();
72 
73   /// \brief Returns whether or not the given feature is enabled.
74   ///
75   /// IsSupported() is true iff IsDetected() is also true and the feature
76   /// wasn't disabled by the user (for example by setting the ARROW_USER_SIMD_LEVEL
77   /// environment variable).
IsSupported(int64_t flags)78   bool IsSupported(int64_t flags) const { return (hardware_flags_ & flags) == flags; }
79 
80   /// Returns whether or not the given feature is available on the CPU.
IsDetected(int64_t flags)81   bool IsDetected(int64_t flags) const {
82     return (original_hardware_flags_ & flags) == flags;
83   }
84 
85   /// \brief The processor supports SSE4.2 and the Arrow libraries are built
86   /// with support for it
87   bool CanUseSSE4_2() const;
88 
89   /// Toggle a hardware feature on and off.  It is not valid to turn on a feature
90   /// that the underlying hardware cannot support. This is useful for testing.
91   void EnableFeature(int64_t flag, bool enable);
92 
93   /// Returns the size of the cache in KB at this cache level
94   int64_t CacheSize(CacheLevel level);
95 
96   /// Returns the number of cpu cycles per millisecond
97   int64_t cycles_per_ms();
98 
99   /// Returns the number of cores (including hyper-threaded) on this machine.
100   int num_cores();
101 
102   /// Returns the model name of the cpu (e.g. Intel i7-2600)
103   std::string model_name();
104 
105   /// Returns the vendor of the cpu.
vendor()106   Vendor vendor() const { return vendor_; }
107 
HasEfficientBmi2()108   bool HasEfficientBmi2() const {
109     // BMI2 (pext, pdep) is only efficient on Intel X86 processors.
110     return vendor() == Vendor::Intel && IsSupported(BMI2);
111   }
112 
113  private:
114   CpuInfo();
115 
116   enum UserSimdLevel {
117     USER_SIMD_NONE = 0,
118     USER_SIMD_SSE4_2,
119     USER_SIMD_AVX,
120     USER_SIMD_AVX2,
121     USER_SIMD_AVX512,
122     USER_SIMD_MAX,
123   };
124 
125   void Init();
126 
127   /// Inits CPU cache size variables with default values
128   void SetDefaultCacheSize();
129 
130   /// Parse the SIMD level by ARROW_USER_SIMD_LEVEL env
131   void ParseUserSimdLevel();
132 
133   int64_t hardware_flags_;
134   int64_t original_hardware_flags_;
135   int64_t cache_sizes_[L3_CACHE + 1];
136   int64_t cycles_per_ms_;
137   int num_cores_;
138   std::string model_name_;
139   Vendor vendor_;
140 };
141 
142 }  // namespace internal
143 }  // namespace arrow
144