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