Blender  V2.93
util_system.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "util/util_system.h"
18 
19 #include "util/util_logging.h"
20 #include "util/util_string.h"
21 #include "util/util_types.h"
22 
23 #include <numaapi.h>
24 
25 #include <OpenImageIO/sysutil.h>
26 OIIO_NAMESPACE_USING
27 
28 #ifdef _WIN32
29 # if (!defined(FREE_WINDOWS))
30 # include <intrin.h>
31 # endif
32 # include "util_windows.h"
33 #elif defined(__APPLE__)
34 # include <sys/ioctl.h>
35 # include <sys/sysctl.h>
36 # include <sys/types.h>
37 #else
38 # include <sys/ioctl.h>
39 # include <unistd.h>
40 #endif
41 
43 
45 {
46  static bool is_initialized = false;
47  static bool result = false;
48  if (is_initialized) {
49  return result;
50  }
51  is_initialized = true;
52  const NUMAAPI_Result numa_result = numaAPI_Initialize();
53  result = (numa_result == NUMAAPI_SUCCESS);
54  return result;
55 }
56 
57 /* Fallback solution, which doesn't use NUMA/CPU groups. */
59 {
60 #ifdef _WIN32
61  SYSTEM_INFO info;
62  GetSystemInfo(&info);
63  return info.dwNumberOfProcessors;
64 #elif defined(__APPLE__)
65  int count;
66  size_t len = sizeof(count);
67  int mib[2] = {CTL_HW, HW_NCPU};
68  sysctl(mib, 2, &count, &len, NULL, 0);
69  return count;
70 #else
71  return sysconf(_SC_NPROCESSORS_ONLN);
72 #endif
73 }
74 
76 {
77  const int num_nodes = system_cpu_num_numa_nodes();
78  int num_threads = 0;
79  for (int node = 0; node < num_nodes; ++node) {
81  continue;
82  }
84  }
85  return num_threads;
86 }
87 
89 {
91  /* Fallback to a single node with all the threads. */
92  return 1;
93  }
94  return numaAPI_GetNumNodes();
95 }
96 
98 {
100  return true;
101  }
103 }
104 
106 {
109  }
111 }
112 
114 {
116  return true;
117  }
119 }
120 
122 {
123  int columns = 0;
124 
125 #ifdef _WIN32
126  CONSOLE_SCREEN_BUFFER_INFO csbi;
127  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
128  columns = csbi.dwSize.X;
129  }
130 #else
131  struct winsize w;
132  if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
133  columns = w.ws_col;
134  }
135 #endif
136 
137  return (columns > 0) ? columns : 80;
138 }
139 
141 {
144  }
146 }
147 
148 /* Equivalent of Windows __cpuid for x86 processors on other platforms. */
149 #if (!defined(_WIN32) || defined(FREE_WINDOWS)) && (defined(__x86_64__) || defined(__i386__))
150 static void __cpuid(int data[4], int selector)
151 {
152 # if defined(__x86_64__)
153  asm("cpuid" : "=a"(data[0]), "=b"(data[1]), "=c"(data[2]), "=d"(data[3]) : "a"(selector));
154 # elif defined(__i386__)
155  asm("pushl %%ebx \n\t"
156  "cpuid \n\t"
157  "movl %%ebx, %1 \n\t"
158  "popl %%ebx \n\t"
159  : "=a"(data[0]), "=r"(data[1]), "=c"(data[2]), "=d"(data[3])
160  : "a"(selector)
161  : "ebx");
162 # else
163  data[0] = data[1] = data[2] = data[3] = 0;
164 # endif
165 }
166 #endif
167 
169 {
170 #if defined(__APPLE__)
171  /* Get from system on macOS. */
172  char modelname[512] = "";
173  size_t bufferlen = 512;
174  if (sysctlbyname("machdep.cpu.brand_string", &modelname, &bufferlen, NULL, 0) == 0) {
175  return modelname;
176  }
177 #elif defined(WIN32) || defined(__x86_64__) || defined(__i386__)
178  /* Get from intrinsics on Windows and x86. */
179  char buf[49] = {0};
180  int result[4] = {0};
181 
182  __cpuid(result, 0x80000000);
183 
184  if (result[0] != 0 && result[0] >= (int)0x80000004) {
185  __cpuid((int *)(buf + 0), 0x80000002);
186  __cpuid((int *)(buf + 16), 0x80000003);
187  __cpuid((int *)(buf + 32), 0x80000004);
188 
189  string brand = buf;
190 
191  /* Make it a bit more presentable. */
192  brand = string_remove_trademark(brand);
193 
194  return brand;
195  }
196 #else
197  /* Get from /proc/cpuinfo on Unix systems. */
198  FILE *cpuinfo = fopen("/proc/cpuinfo", "r");
199  if (cpuinfo != nullptr) {
200  char cpuinfo_buf[513] = "";
201  fread(cpuinfo_buf, sizeof(cpuinfo_buf) - 1, 1, cpuinfo);
202  fclose(cpuinfo);
203 
204  char *modelname = strstr(cpuinfo_buf, "model name");
205  if (modelname != nullptr) {
206  modelname = strchr(modelname, ':');
207  if (modelname != nullptr) {
208  modelname += 2;
209  char *modelname_end = strchr(modelname, '\n');
210  if (modelname_end != nullptr) {
211  *modelname_end = '\0';
212  return modelname;
213  }
214  }
215  }
216  }
217 #endif
218  return "Unknown CPU";
219 }
220 
222 {
223  return (sizeof(void *) * 8);
224 }
225 
226 #if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
227 
228 struct CPUCapabilities {
229  bool x64;
230  bool mmx;
231  bool sse;
232  bool sse2;
233  bool sse3;
234  bool ssse3;
235  bool sse41;
236  bool sse42;
237  bool sse4a;
238  bool avx;
239  bool f16c;
240  bool avx2;
241  bool xop;
242  bool fma3;
243  bool fma4;
244  bool bmi1;
245  bool bmi2;
246 };
247 
248 static CPUCapabilities &system_cpu_capabilities()
249 {
250  static CPUCapabilities caps;
251  static bool caps_init = false;
252 
253  if (!caps_init) {
254  int result[4], num;
255 
256  memset(&caps, 0, sizeof(caps));
257 
258  __cpuid(result, 0);
259  num = result[0];
260 
261  if (num >= 1) {
262  __cpuid(result, 0x00000001);
263  caps.mmx = (result[3] & ((int)1 << 23)) != 0;
264  caps.sse = (result[3] & ((int)1 << 25)) != 0;
265  caps.sse2 = (result[3] & ((int)1 << 26)) != 0;
266  caps.sse3 = (result[2] & ((int)1 << 0)) != 0;
267 
268  caps.ssse3 = (result[2] & ((int)1 << 9)) != 0;
269  caps.sse41 = (result[2] & ((int)1 << 19)) != 0;
270  caps.sse42 = (result[2] & ((int)1 << 20)) != 0;
271 
272  caps.fma3 = (result[2] & ((int)1 << 12)) != 0;
273  caps.avx = false;
274  bool os_uses_xsave_xrestore = (result[2] & ((int)1 << 27)) != 0;
275  bool cpu_avx_support = (result[2] & ((int)1 << 28)) != 0;
276 
277  if (os_uses_xsave_xrestore && cpu_avx_support) {
278  // Check if the OS will save the YMM registers
279  uint32_t xcr_feature_mask;
280 # if defined(__GNUC__)
281  int edx; /* not used */
282  /* actual opcode for xgetbv */
283  __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(xcr_feature_mask), "=d"(edx) : "c"(0));
284 # elif defined(_MSC_VER) && defined(_XCR_XFEATURE_ENABLED_MASK)
285  xcr_feature_mask = (uint32_t)_xgetbv(
286  _XCR_XFEATURE_ENABLED_MASK); /* min VS2010 SP1 compiler is required */
287 # else
288  xcr_feature_mask = 0;
289 # endif
290  caps.avx = (xcr_feature_mask & 0x6) == 0x6;
291  }
292 
293  caps.f16c = (result[2] & ((int)1 << 29)) != 0;
294 
295  __cpuid(result, 0x00000007);
296  caps.bmi1 = (result[1] & ((int)1 << 3)) != 0;
297  caps.bmi2 = (result[1] & ((int)1 << 8)) != 0;
298  caps.avx2 = (result[1] & ((int)1 << 5)) != 0;
299  }
300 
301  caps_init = true;
302  }
303 
304  return caps;
305 }
306 
308 {
309  CPUCapabilities &caps = system_cpu_capabilities();
310  return caps.sse && caps.sse2;
311 }
312 
314 {
315  CPUCapabilities &caps = system_cpu_capabilities();
316  return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3;
317 }
318 
320 {
321  CPUCapabilities &caps = system_cpu_capabilities();
322  return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41;
323 }
324 
326 {
327  CPUCapabilities &caps = system_cpu_capabilities();
328  return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41 && caps.avx;
329 }
330 
332 {
333  CPUCapabilities &caps = system_cpu_capabilities();
334  return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41 && caps.avx && caps.f16c &&
335  caps.avx2 && caps.fma3 && caps.bmi1 && caps.bmi2;
336 }
337 #else
338 
340 {
341  return false;
342 }
343 
345 {
346  return false;
347 }
348 
350 {
351  return false;
352 }
353 
355 {
356  return false;
357 }
359 {
360  return false;
361 }
362 
363 #endif
364 
366 {
367  /* Escape program and arguments in case they contain spaces. */
368  string cmd = "\"" + Sysutil::this_program_path() + "\"";
369 
370  for (int i = 0; i < args.size(); i++) {
371  cmd += " \"" + args[i] + "\"";
372  }
373 
374 #ifdef _WIN32
375  /* Use cmd /S to avoid issues with spaces in arguments. */
376  cmd = "cmd /S /C \"" + cmd + " > nul \"";
377 #else
378  /* Quiet output. */
379  cmd += " > /dev/null";
380 #endif
381 
382  return (system(cmd.c_str()) == 0);
383 }
384 
386 {
387 #ifdef _WIN32
388  MEMORYSTATUSEX ram;
389  ram.dwLength = sizeof(ram);
390  GlobalMemoryStatusEx(&ram);
391  return ram.ullTotalPhys;
392 #elif defined(__APPLE__)
393  uint64_t ram = 0;
394  size_t len = sizeof(ram);
395  if (sysctlbyname("hw.memsize", &ram, &len, NULL, 0) == 0) {
396  return ram;
397  }
398  return 0;
399 #else
400  size_t ps = sysconf(_SC_PAGESIZE);
401  size_t pn = sysconf(_SC_PHYS_PAGES);
402  return ps * pn;
403 #endif
404 }
405 
bool is_initialized
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
OperationNode * node
int count
#define CCL_NAMESPACE_END
bool numaAPI_IsNodeAvailable(int node)
Definition: numaapi_stub.c:45
NUMAAPI_Result numaAPI_Initialize(void)
Definition: numaapi_stub.c:34
NUMAAPI_Result
Definition: numaapi.h:36
@ NUMAAPI_SUCCESS
Definition: numaapi.h:37
int numaAPI_GetNumCurrentNodesProcessors(void)
Definition: numaapi_stub.c:58
int numaAPI_GetNumNodeProcessors(int node)
Definition: numaapi_stub.c:50
int numaAPI_GetNumNodes(void)
Definition: numaapi_stub.c:41
bool numaAPI_RunThreadOnNode(int node)
Definition: numaapi_stub.c:70
unsigned int uint32_t
Definition: stdint.h:83
unsigned __int64 uint64_t
Definition: stdint.h:93
static void __cpuid(int data[4], int selector)
Definition: system.c:114
string string_remove_trademark(const string &s)
size_t system_physical_ram()
bool system_cpu_support_avx2()
int system_cpu_num_active_group_processors()
int system_cpu_bits()
bool system_cpu_run_thread_on_node(int node)
int system_cpu_thread_count()
Definition: util_system.cpp:75
string system_cpu_brand_string()
int system_console_width()
bool system_cpu_support_avx()
bool system_cpu_is_numa_node_available(int node)
Definition: util_system.cpp:97
int system_cpu_num_numa_nodes()
Definition: util_system.cpp:88
static int system_cpu_thread_count_fallback()
Definition: util_system.cpp:58
int system_cpu_num_numa_node_processors(int node)
OIIO_NAMESPACE_USING CCL_NAMESPACE_BEGIN bool system_cpu_ensure_initialized()
Definition: util_system.cpp:44
bool system_call_self(const vector< string > &args)
bool system_cpu_support_sse3()
bool system_cpu_support_sse41()
bool system_cpu_support_sse2()
uint len