Blender  V3.3
system.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #include "util/system.h"
5 
6 #include "util/log.h"
7 #include "util/string.h"
8 #include "util/types.h"
9 
10 #include <OpenImageIO/sysutil.h>
11 
12 OIIO_NAMESPACE_USING
13 
14 #ifdef _WIN32
15 # if (!defined(FREE_WINDOWS))
16 # include <intrin.h>
17 # endif
18 # include "util/windows.h"
19 #elif defined(__APPLE__)
20 # include <sys/ioctl.h>
21 # include <sys/sysctl.h>
22 # include <sys/types.h>
23 # include <unistd.h>
24 #else
25 # include <sys/ioctl.h>
26 # include <unistd.h>
27 #endif
28 
30 
32 {
33  int columns = 0;
34 
35 #ifdef _WIN32
36  CONSOLE_SCREEN_BUFFER_INFO csbi;
37  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
38  columns = csbi.dwSize.X;
39  }
40 #else
41  struct winsize w;
42  if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
43  columns = w.ws_col;
44  }
45 #endif
46 
47  return (columns > 0) ? columns : 80;
48 }
49 
50 /* Equivalent of Windows __cpuid for x86 processors on other platforms. */
51 #if (!defined(_WIN32) || defined(FREE_WINDOWS)) && (defined(__x86_64__) || defined(__i386__))
52 static void __cpuid(int data[4], int selector)
53 {
54 # if defined(__x86_64__)
55  asm("cpuid" : "=a"(data[0]), "=b"(data[1]), "=c"(data[2]), "=d"(data[3]) : "a"(selector));
56 # elif defined(__i386__)
57  asm("pushl %%ebx \n\t"
58  "cpuid \n\t"
59  "movl %%ebx, %1 \n\t"
60  "popl %%ebx \n\t"
61  : "=a"(data[0]), "=r"(data[1]), "=c"(data[2]), "=d"(data[3])
62  : "a"(selector)
63  : "ebx");
64 # else
65  data[0] = data[1] = data[2] = data[3] = 0;
66 # endif
67 }
68 #endif
69 
71 {
72 #if defined(__APPLE__)
73  /* Get from system on macOS. */
74  char modelname[512] = "";
75  size_t bufferlen = 512;
76  if (sysctlbyname("machdep.cpu.brand_string", &modelname, &bufferlen, NULL, 0) == 0) {
77  return modelname;
78  }
79 #elif defined(WIN32) || defined(__x86_64__) || defined(__i386__)
80  /* Get from intrinsics on Windows and x86. */
81  char buf[49] = {0};
82  int result[4] = {0};
83 
84  __cpuid(result, 0x80000000);
85 
86  if (result[0] != 0 && result[0] >= (int)0x80000004) {
87  __cpuid((int *)(buf + 0), 0x80000002);
88  __cpuid((int *)(buf + 16), 0x80000003);
89  __cpuid((int *)(buf + 32), 0x80000004);
90 
91  string brand = buf;
92 
93  /* Make it a bit more presentable. */
94  brand = string_remove_trademark(brand);
95 
96  return brand;
97  }
98 #else
99  /* Get from /proc/cpuinfo on Unix systems. */
100  FILE *cpuinfo = fopen("/proc/cpuinfo", "r");
101  if (cpuinfo != nullptr) {
102  char cpuinfo_buf[513] = "";
103  fread(cpuinfo_buf, sizeof(cpuinfo_buf) - 1, 1, cpuinfo);
104  fclose(cpuinfo);
105 
106  char *modelname = strstr(cpuinfo_buf, "model name");
107  if (modelname != nullptr) {
108  modelname = strchr(modelname, ':');
109  if (modelname != nullptr) {
110  modelname += 2;
111  char *modelname_end = strchr(modelname, '\n');
112  if (modelname_end != nullptr) {
113  *modelname_end = '\0';
114  return modelname;
115  }
116  }
117  }
118  }
119 #endif
120  return "Unknown CPU";
121 }
122 
124 {
125  return (sizeof(void *) * 8);
126 }
127 
128 #if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
129 
130 struct CPUCapabilities {
131  bool sse2;
132  bool sse3;
133  bool sse41;
134  bool avx;
135  bool avx2;
136 };
137 
138 static CPUCapabilities &system_cpu_capabilities()
139 {
140  static CPUCapabilities caps = {};
141  static bool caps_init = false;
142 
143  if (!caps_init) {
144  int result[4], num;
145 
146  __cpuid(result, 0);
147  num = result[0];
148 
149  if (num >= 1) {
150  __cpuid(result, 0x00000001);
151  const bool sse = (result[3] & ((int)1 << 25)) != 0;
152  const bool sse2 = (result[3] & ((int)1 << 26)) != 0;
153  const bool sse3 = (result[2] & ((int)1 << 0)) != 0;
154 
155  const bool ssse3 = (result[2] & ((int)1 << 9)) != 0;
156  const bool sse41 = (result[2] & ((int)1 << 19)) != 0;
157  /* const bool sse42 = (result[2] & ((int)1 << 20)) != 0; */
158 
159  const bool fma3 = (result[2] & ((int)1 << 12)) != 0;
160  const bool os_uses_xsave_xrestore = (result[2] & ((int)1 << 27)) != 0;
161  const bool cpu_avx_support = (result[2] & ((int)1 << 28)) != 0;
162 
163  /* Simplify to combined capabilities for which we specialize kernels. */
164  caps.sse2 = sse && sse2;
165  caps.sse3 = sse && sse2 && sse3 && ssse3;
166  caps.sse41 = sse && sse2 && sse3 && ssse3 && sse41;
167 
168  if (os_uses_xsave_xrestore && cpu_avx_support) {
169  // Check if the OS will save the YMM registers
170  uint32_t xcr_feature_mask;
171 # if defined(__GNUC__)
172  int edx; /* not used */
173  /* actual opcode for xgetbv */
174  __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(xcr_feature_mask), "=d"(edx) : "c"(0));
175 # elif defined(_MSC_VER) && defined(_XCR_XFEATURE_ENABLED_MASK)
176  /* Minimum VS2010 SP1 compiler is required. */
177  xcr_feature_mask = (uint32_t)_xgetbv(_XCR_XFEATURE_ENABLED_MASK);
178 # else
179  xcr_feature_mask = 0;
180 # endif
181  const bool avx = (xcr_feature_mask & 0x6) == 0x6;
182  const bool f16c = (result[2] & ((int)1 << 29)) != 0;
183 
184  __cpuid(result, 0x00000007);
185  bool bmi1 = (result[1] & ((int)1 << 3)) != 0;
186  bool bmi2 = (result[1] & ((int)1 << 8)) != 0;
187  bool avx2 = (result[1] & ((int)1 << 5)) != 0;
188 
189  caps.avx = sse && sse2 && sse3 && ssse3 && sse41 && avx;
190  caps.avx2 = sse && sse2 && sse3 && ssse3 && sse41 && avx && f16c && avx2 && fma3 && bmi1 &&
191  bmi2;
192  }
193  }
194 
195  caps_init = true;
196  }
197 
198  return caps;
199 }
200 
202 {
203  CPUCapabilities &caps = system_cpu_capabilities();
204  return caps.sse2;
205 }
206 
208 {
209  CPUCapabilities &caps = system_cpu_capabilities();
210  return caps.sse3;
211 }
212 
214 {
215  CPUCapabilities &caps = system_cpu_capabilities();
216  return caps.sse41;
217 }
218 
220 {
221  CPUCapabilities &caps = system_cpu_capabilities();
222  return caps.avx;
223 }
224 
226 {
227  CPUCapabilities &caps = system_cpu_capabilities();
228  return caps.avx2;
229 }
230 #else
231 
233 {
234  return false;
235 }
236 
238 {
239  return false;
240 }
241 
243 {
244  return false;
245 }
246 
248 {
249  return false;
250 }
252 {
253  return false;
254 }
255 
256 #endif
257 
259 {
260 #ifdef _WIN32
261  MEMORYSTATUSEX ram;
262  ram.dwLength = sizeof(ram);
263  GlobalMemoryStatusEx(&ram);
264  return ram.ullTotalPhys;
265 #elif defined(__APPLE__)
266  uint64_t ram = 0;
267  size_t len = sizeof(ram);
268  if (sysctlbyname("hw.memsize", &ram, &len, NULL, 0) == 0) {
269  return ram;
270  }
271  return 0;
272 #else
273  size_t ps = sysconf(_SC_PAGESIZE);
274  size_t pn = sysconf(_SC_PHYS_PAGES);
275  return ps * pn;
276 #endif
277 }
278 
280 {
281 #ifdef _WIN32
282  return GetCurrentProcessId();
283 #else
284  return getpid();
285 #endif
286 }
287 
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
int len
Definition: draw_manager.c:108
unsigned int uint32_t
Definition: stdint.h:80
unsigned __int64 uint64_t
Definition: stdint.h:90
string string_remove_trademark(const string &s)
Definition: string.cpp:152
static void __cpuid(int data[4], int selector)
Definition: system.c:97
size_t system_physical_ram()
Definition: system.cpp:258
bool system_cpu_support_avx2()
Definition: system.cpp:251
int system_cpu_bits()
Definition: system.cpp:123
OIIO_NAMESPACE_USING CCL_NAMESPACE_BEGIN int system_console_width()
Definition: system.cpp:31
string system_cpu_brand_string()
Definition: system.cpp:70
bool system_cpu_support_avx()
Definition: system.cpp:247
uint64_t system_self_process_id()
Definition: system.cpp:279
bool system_cpu_support_sse3()
Definition: system.cpp:237
bool system_cpu_support_sse41()
Definition: system.cpp:242
bool system_cpu_support_sse2()
Definition: system.cpp:232