File: cpu_info.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (233 lines) | stat: -rw-r--r-- 6,671 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/*
 *  Copyright (c) 2025 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtc_base/cpu_info.h"

#include <cstdint>

#if defined(WEBRTC_WIN)
#include <windows.h>
#elif defined(WEBRTC_MAC)
#include <sys/sysctl.h>
#elif defined(WEBRTC_ANDROID)
#include <cpu-features.h>
#include <unistd.h>
#elif defined(WEBRTC_FUCHSIA)
#include <zircon/syscalls.h>
#elif defined(WEBRTC_LINUX)
#include <features.h>
#include <stdlib.h>
#include <string.h>  // IWYU pragma: keep
#include <unistd.h>

#ifdef __GLIBC_PREREQ
#define WEBRTC_GLIBC_PREREQ(a, b) __GLIBC_PREREQ(a, b)
#else
#define WEBRTC_GLIBC_PREREQ(a, b) 0
#endif

#if WEBRTC_GLIBC_PREREQ(2, 16)
#include <sys/auxv.h>  // IWYU pragma: keep
#else
#include <errno.h>
#include <fcntl.h>
#include <link.h>
#endif
#endif  // WEBRTC_LINUX

#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/system/arch.h"
#include "rtc_base/system/unused.h"  // IWYU pragma: keep

#if defined(WEBRTC_ARCH_X86_FAMILY) && defined(_MSC_VER)
#include <intrin.h>
#endif
#if defined(WEBRTC_ARCH_ARM_FAMILY) && defined(WEBRTC_LINUX)
#include <asm/hwcap.h>
#endif

// Parts of this file derived from Chromium's base/cpu.cc.

namespace {

uint32_t DetectNumberOfCores() {
  int number_of_cores = 0;

#if defined(WEBRTC_WIN)
  SYSTEM_INFO si;
  GetNativeSystemInfo(&si);
  number_of_cores = static_cast<int>(si.dwNumberOfProcessors);
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
  number_of_cores = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
  if (number_of_cores <= 0) {
    RTC_LOG(LS_ERROR) << "Failed to get number of cores";
    number_of_cores = 1;
  }
#elif defined(WEBRTC_MAC) || defined(WEBRTC_IOS)
  int name[] = {CTL_HW, HW_AVAILCPU};
  size_t size = sizeof(number_of_cores);
  if (0 != sysctl(name, 2, &number_of_cores, &size, NULL, 0)) {
    RTC_LOG(LS_ERROR) << "Failed to get number of cores";
    number_of_cores = 1;
  }
#elif defined(WEBRTC_FUCHSIA)
  number_of_cores = zx_system_get_num_cpus();
#else
  RTC_LOG(LS_ERROR) << "No function to get number of cores";
  number_of_cores = 1;
#endif

  RTC_LOG(LS_INFO) << "Available number of cores: " << number_of_cores;

  RTC_CHECK_GT(number_of_cores, 0);
  return static_cast<uint32_t>(number_of_cores);
}

#if defined(WEBRTC_ARCH_X86_FAMILY)

#if defined(WEBRTC_ENABLE_AVX2)
// xgetbv returns the value of an Intel Extended Control Register (XCR).
// Currently only XCR0 is defined by Intel so `xcr` should always be zero.
uint64_t xgetbv(uint32_t xcr) {
#if defined(_MSC_VER)
  return _xgetbv(xcr);
#else
  uint32_t eax, edx;

  __asm__ volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
  return (static_cast<uint64_t>(edx) << 32) | eax;
#endif  // _MSC_VER
}
#endif  // WEBRTC_ENABLE_AVX2

#ifndef _MSC_VER
// Intrinsic for "cpuid".
#if defined(__pic__) && defined(__i386__)
static inline void __cpuid(int cpu_info[4], int info_type) {
  __asm__ volatile(
      "mov %%ebx, %%edi\n"
      "cpuid\n"
      "xchg %%edi, %%ebx\n"
      : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]),
        "=d"(cpu_info[3])
      : "a"(info_type));
}
#else
inline void __cpuid(int cpu_info[4], int info_type) {
  __asm__ volatile("cpuid\n"
                   : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]),
                     "=d"(cpu_info[3])
                   : "a"(info_type), "c"(0));
}
#endif
#endif  // _MSC_VER

#endif  // WEBRTC_ARCH_X86_FAMILY

}  // namespace

namespace webrtc {

namespace cpu_info {

uint32_t DetectNumberOfCores() {
  // Statically cache the number of system cores available since if the process
  // is running in a sandbox, we may only be able to read the value once (before
  // the sandbox is initialized) and not thereafter.
  // For more information see crbug.com/176522.
  static const uint32_t logical_cpus = ::DetectNumberOfCores();
  return logical_cpus;
}

bool Supports(ISA instruction_set_architecture) {
#if defined(WEBRTC_ARCH_X86_FAMILY)
  int cpu_info[4];
  __cpuid(cpu_info, 1);
  if (instruction_set_architecture == ISA::kSSE2) {
    return 0 != (cpu_info[3] & 0x04000000);
  }
  if (instruction_set_architecture == ISA::kSSE3) {
    return 0 != (cpu_info[2] & 0x00000001);
  }
#if defined(WEBRTC_ENABLE_AVX2)
  if (instruction_set_architecture == ISA::kAVX2) {
    int cpu_info7[4];
    __cpuid(cpu_info7, 0);
    int num_ids = cpu_info7[0];
    if (num_ids < 7) {
      return false;
    }
    // Interpret CPU feature information.
    __cpuid(cpu_info7, 7);

    // AVX instructions can be used when
    //     a) AVX are supported by the CPU,
    //     b) XSAVE is supported by the CPU,
    //     c) XSAVE is enabled by the kernel.
    // Compiling with MSVC and /arch:AVX2 surprisingly generates BMI2
    // instructions (see crbug.com/1315519).
    return (cpu_info[2] & 0x10000000) != 0 /* AVX */ &&
           (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
           (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
           (xgetbv(0) & 0x00000006) == 6 /* XSAVE enabled by kernel */ &&
           (cpu_info7[1] & 0x00000020) != 0 /* AVX2 */ &&
           (cpu_info7[1] & 0x00000100) != 0 /* BMI2 */;
  }
#endif  // WEBRTC_ENABLE_AVX2
  if (instruction_set_architecture == ISA::kFMA3) {
    return 0 != (cpu_info[2] & 0x00001000);
  }
#elif defined(WEBRTC_ARCH_ARM_FAMILY)
  if (instruction_set_architecture == ISA::kNeon) {
#if defined(WEBRTC_ANDROID)
    return 0 != (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON);
#elif defined(WEBRTC_LINUX)
    uint64_t hwcap = 0;
#if WEBRTC_GLIBC_PREREQ(2, 16)
    hwcap = getauxval(AT_HWCAP);
#else
    ElfW(auxv_t) auxv;
    int fd = open("/proc/self/auxv", O_RDONLY);
    if (fd >= 0) {
      while (hwcap == 0) {
        if (read(fd, &auxv, sizeof(auxv)) < (ssize_t)sizeof(auxv)) {
          if (errno == EINTR) {
            continue;
          }
          break;
        }
        if (AT_HWCAP == auxv.a_type) {
          hwcap = auxv.a_un.a_val;
        }
      }
      close(fd);
    }
#endif  // WEBRTC_GLIBC_PREREQ(2, 16)
#if defined(__aarch64__)
    if ((hwcap & HWCAP_ASIMD) != 0) {
      return true;
    }
#else
    if ((hwcap & HWCAP_NEON) != 0) {
      return true;
    }
#endif
#endif  // WEBRTC_LINUX
  }
#else
  RTC_UNUSED(instruction_set_architecture);
#endif  // WEBRTC_ARCH_ARM_FAMILY
  return false;
}

}  // namespace cpu_info

}  // namespace webrtc