1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#include "sysinfo.h"
5#include "intrinsics.h"
6#include "string.h"
7#include "ref.h"
8#if defined(__FREEBSD__)
9#include <sys/cpuset.h>
10#include <pthread_np.h>
11typedef cpuset_t cpu_set_t;
12#endif
13
14////////////////////////////////////////////////////////////////////////////////
15/// All Platforms
16////////////////////////////////////////////////////////////////////////////////
17
18namespace embree
19{
20 NullTy null;
21
22 std::string getPlatformName()
23 {
24#if defined(__ANDROID__) && !defined(__64BIT__)
25 return "Android (32bit)";
26#elif defined(__ANDROID__) && defined(__64BIT__)
27 return "Android (64bit)";
28#elif defined(__LINUX__) && !defined(__64BIT__)
29 return "Linux (32bit)";
30#elif defined(__LINUX__) && defined(__64BIT__)
31 return "Linux (64bit)";
32#elif defined(__FREEBSD__) && !defined(__64BIT__)
33 return "FreeBSD (32bit)";
34#elif defined(__FREEBSD__) && defined(__64BIT__)
35 return "FreeBSD (64bit)";
36#elif defined(__CYGWIN__) && !defined(__64BIT__)
37 return "Cygwin (32bit)";
38#elif defined(__CYGWIN__) && defined(__64BIT__)
39 return "Cygwin (64bit)";
40#elif defined(__WIN32__) && !defined(__64BIT__)
41 return "Windows (32bit)";
42#elif defined(__WIN32__) && defined(__64BIT__)
43 return "Windows (64bit)";
44#elif defined(__MACOSX__) && !defined(__64BIT__)
45 return "Mac OS X (32bit)";
46#elif defined(__MACOSX__) && defined(__64BIT__)
47 return "Mac OS X (64bit)";
48#elif defined(__UNIX__) && !defined(__64BIT__)
49 return "Unix (32bit)";
50#elif defined(__UNIX__) && defined(__64BIT__)
51 return "Unix (64bit)";
52#else
53 return "Unknown";
54#endif
55 }
56
57 std::string getCompilerName()
58 {
59#if defined(__INTEL_COMPILER)
60 int icc_mayor = __INTEL_COMPILER / 100 % 100;
61 int icc_minor = __INTEL_COMPILER % 100;
62 std::string version = "Intel Compiler ";
63 version += toString(icc_mayor);
64 version += "." + toString(icc_minor);
65#if defined(__INTEL_COMPILER_UPDATE)
66 version += "." + toString(__INTEL_COMPILER_UPDATE);
67#endif
68 return version;
69#elif defined(__clang__)
70 return "CLANG " __clang_version__;
71#elif defined (__GNUC__)
72 return "GCC " __VERSION__;
73#elif defined(_MSC_VER)
74 std::string version = toString(_MSC_FULL_VER);
75 version.insert(4,".");
76 version.insert(9,".");
77 version.insert(2,".");
78 return "Visual C++ Compiler " + version;
79#else
80 return "Unknown Compiler";
81#endif
82 }
83
84 std::string getCPUVendor()
85 {
86#if defined(__X86_ASM__)
87 int cpuinfo[4];
88 __cpuid (cpuinfo, 0);
89 int name[4];
90 name[0] = cpuinfo[1];
91 name[1] = cpuinfo[3];
92 name[2] = cpuinfo[2];
93 name[3] = 0;
94 return (char*)name;
95#elif defined(__ARM_NEON)
96 return "ARM";
97#else
98 return "Unknown";
99#endif
100 }
101
102 CPU getCPUModel()
103 {
104#if defined(__X86_ASM__)
105 if (getCPUVendor() != "GenuineIntel")
106 return CPU::UNKNOWN;
107
108 int out[4];
109 __cpuid(out, 0);
110 if (out[0] < 1) return CPU::UNKNOWN;
111 __cpuid(out, 1);
112
113 /* please see CPUID documentation for these formulas */
114 uint32_t family_ID = (out[0] >> 8) & 0x0F;
115 uint32_t extended_family_ID = (out[0] >> 20) & 0xFF;
116
117 uint32_t model_ID = (out[0] >> 4) & 0x0F;
118 uint32_t extended_model_ID = (out[0] >> 16) & 0x0F;
119
120 uint32_t DisplayFamily = family_ID;
121 if (family_ID == 0x0F)
122 DisplayFamily += extended_family_ID;
123
124 uint32_t DisplayModel = model_ID;
125 if (family_ID == 0x06 || family_ID == 0x0F)
126 DisplayModel += extended_model_ID << 4;
127
128 uint32_t DisplayFamily_DisplayModel = (DisplayFamily << 8) + (DisplayModel << 0);
129
130 // Data from IntelĀ® 64 and IA-32 Architectures, Volume 4, Chapter 2, Table 2-1 (CPUID Signature Values of DisplayFamily_DisplayModel)
131 if (DisplayFamily_DisplayModel == 0x067D) return CPU::CORE_ICE_LAKE;
132 if (DisplayFamily_DisplayModel == 0x067E) return CPU::CORE_ICE_LAKE;
133 if (DisplayFamily_DisplayModel == 0x068C) return CPU::CORE_TIGER_LAKE;
134 if (DisplayFamily_DisplayModel == 0x06A5) return CPU::CORE_COMET_LAKE;
135 if (DisplayFamily_DisplayModel == 0x06A6) return CPU::CORE_COMET_LAKE;
136 if (DisplayFamily_DisplayModel == 0x0666) return CPU::CORE_CANNON_LAKE;
137 if (DisplayFamily_DisplayModel == 0x068E) return CPU::CORE_KABY_LAKE;
138 if (DisplayFamily_DisplayModel == 0x069E) return CPU::CORE_KABY_LAKE;
139 if (DisplayFamily_DisplayModel == 0x066A) return CPU::XEON_ICE_LAKE;
140 if (DisplayFamily_DisplayModel == 0x066C) return CPU::XEON_ICE_LAKE;
141 if (DisplayFamily_DisplayModel == 0x0655) return CPU::XEON_SKY_LAKE;
142 if (DisplayFamily_DisplayModel == 0x064E) return CPU::CORE_SKY_LAKE;
143 if (DisplayFamily_DisplayModel == 0x065E) return CPU::CORE_SKY_LAKE;
144 if (DisplayFamily_DisplayModel == 0x0656) return CPU::XEON_BROADWELL;
145 if (DisplayFamily_DisplayModel == 0x064F) return CPU::XEON_BROADWELL;
146 if (DisplayFamily_DisplayModel == 0x0647) return CPU::CORE_BROADWELL;
147 if (DisplayFamily_DisplayModel == 0x063D) return CPU::CORE_BROADWELL;
148 if (DisplayFamily_DisplayModel == 0x063F) return CPU::XEON_HASWELL;
149 if (DisplayFamily_DisplayModel == 0x063C) return CPU::CORE_HASWELL;
150 if (DisplayFamily_DisplayModel == 0x0645) return CPU::CORE_HASWELL;
151 if (DisplayFamily_DisplayModel == 0x0646) return CPU::CORE_HASWELL;
152 if (DisplayFamily_DisplayModel == 0x063E) return CPU::XEON_IVY_BRIDGE;
153 if (DisplayFamily_DisplayModel == 0x063A) return CPU::CORE_IVY_BRIDGE;
154 if (DisplayFamily_DisplayModel == 0x062D) return CPU::SANDY_BRIDGE;
155 if (DisplayFamily_DisplayModel == 0x062F) return CPU::SANDY_BRIDGE;
156 if (DisplayFamily_DisplayModel == 0x062A) return CPU::SANDY_BRIDGE;
157 if (DisplayFamily_DisplayModel == 0x062E) return CPU::NEHALEM;
158 if (DisplayFamily_DisplayModel == 0x0625) return CPU::NEHALEM;
159 if (DisplayFamily_DisplayModel == 0x062C) return CPU::NEHALEM;
160 if (DisplayFamily_DisplayModel == 0x061E) return CPU::NEHALEM;
161 if (DisplayFamily_DisplayModel == 0x061F) return CPU::NEHALEM;
162 if (DisplayFamily_DisplayModel == 0x061A) return CPU::NEHALEM;
163 if (DisplayFamily_DisplayModel == 0x061D) return CPU::NEHALEM;
164 if (DisplayFamily_DisplayModel == 0x0617) return CPU::CORE2;
165 if (DisplayFamily_DisplayModel == 0x060F) return CPU::CORE2;
166 if (DisplayFamily_DisplayModel == 0x060E) return CPU::CORE1;
167
168 if (DisplayFamily_DisplayModel == 0x0685) return CPU::XEON_PHI_KNIGHTS_MILL;
169 if (DisplayFamily_DisplayModel == 0x0657) return CPU::XEON_PHI_KNIGHTS_LANDING;
170
171#elif defined(__ARM_NEON)
172 return CPU::ARM;
173#endif
174
175 return CPU::UNKNOWN;
176 }
177
178 std::string stringOfCPUModel(CPU model)
179 {
180 switch (model) {
181 case CPU::XEON_ICE_LAKE : return "Xeon Ice Lake";
182 case CPU::CORE_ICE_LAKE : return "Core Ice Lake";
183 case CPU::CORE_TIGER_LAKE : return "Core Tiger Lake";
184 case CPU::CORE_COMET_LAKE : return "Core Comet Lake";
185 case CPU::CORE_CANNON_LAKE : return "Core Cannon Lake";
186 case CPU::CORE_KABY_LAKE : return "Core Kaby Lake";
187 case CPU::XEON_SKY_LAKE : return "Xeon Sky Lake";
188 case CPU::CORE_SKY_LAKE : return "Core Sky Lake";
189 case CPU::XEON_PHI_KNIGHTS_MILL : return "Xeon Phi Knights Mill";
190 case CPU::XEON_PHI_KNIGHTS_LANDING: return "Xeon Phi Knights Landing";
191 case CPU::XEON_BROADWELL : return "Xeon Broadwell";
192 case CPU::CORE_BROADWELL : return "Core Broadwell";
193 case CPU::XEON_HASWELL : return "Xeon Haswell";
194 case CPU::CORE_HASWELL : return "Core Haswell";
195 case CPU::XEON_IVY_BRIDGE : return "Xeon Ivy Bridge";
196 case CPU::CORE_IVY_BRIDGE : return "Core Ivy Bridge";
197 case CPU::SANDY_BRIDGE : return "Sandy Bridge";
198 case CPU::NEHALEM : return "Nehalem";
199 case CPU::CORE2 : return "Core2";
200 case CPU::CORE1 : return "Core";
201 case CPU::ARM : return "ARM";
202 case CPU::UNKNOWN : return "Unknown CPU";
203 }
204 return "Unknown CPU (error)";
205 }
206
207#if defined(__X86_ASM__)
208 /* constants to access destination registers of CPUID instruction */
209 static const int EAX = 0;
210 static const int EBX = 1;
211 static const int ECX = 2;
212 static const int EDX = 3;
213
214 /* cpuid[eax=1].ecx */
215 static const int CPU_FEATURE_BIT_SSE3 = 1 << 0;
216 static const int CPU_FEATURE_BIT_SSSE3 = 1 << 9;
217 static const int CPU_FEATURE_BIT_FMA3 = 1 << 12;
218 static const int CPU_FEATURE_BIT_SSE4_1 = 1 << 19;
219 static const int CPU_FEATURE_BIT_SSE4_2 = 1 << 20;
220 //static const int CPU_FEATURE_BIT_MOVBE = 1 << 22;
221 static const int CPU_FEATURE_BIT_POPCNT = 1 << 23;
222 //static const int CPU_FEATURE_BIT_XSAVE = 1 << 26;
223 static const int CPU_FEATURE_BIT_OXSAVE = 1 << 27;
224 static const int CPU_FEATURE_BIT_AVX = 1 << 28;
225 static const int CPU_FEATURE_BIT_F16C = 1 << 29;
226 static const int CPU_FEATURE_BIT_RDRAND = 1 << 30;
227
228 /* cpuid[eax=1].edx */
229 static const int CPU_FEATURE_BIT_SSE = 1 << 25;
230 static const int CPU_FEATURE_BIT_SSE2 = 1 << 26;
231
232 /* cpuid[eax=0x80000001].ecx */
233 static const int CPU_FEATURE_BIT_LZCNT = 1 << 5;
234
235 /* cpuid[eax=7,ecx=0].ebx */
236 static const int CPU_FEATURE_BIT_BMI1 = 1 << 3;
237 static const int CPU_FEATURE_BIT_AVX2 = 1 << 5;
238 static const int CPU_FEATURE_BIT_BMI2 = 1 << 8;
239 static const int CPU_FEATURE_BIT_AVX512F = 1 << 16; // AVX512F (foundation)
240 static const int CPU_FEATURE_BIT_AVX512DQ = 1 << 17; // AVX512DQ (doubleword and quadword instructions)
241 static const int CPU_FEATURE_BIT_AVX512PF = 1 << 26; // AVX512PF (prefetch gather/scatter instructions)
242 static const int CPU_FEATURE_BIT_AVX512ER = 1 << 27; // AVX512ER (exponential and reciprocal instructions)
243 static const int CPU_FEATURE_BIT_AVX512CD = 1 << 28; // AVX512CD (conflict detection instructions)
244 static const int CPU_FEATURE_BIT_AVX512BW = 1 << 30; // AVX512BW (byte and word instructions)
245 static const int CPU_FEATURE_BIT_AVX512VL = 1 << 31; // AVX512VL (vector length extensions)
246 static const int CPU_FEATURE_BIT_AVX512IFMA = 1 << 21; // AVX512IFMA (integer fused multiple-add instructions)
247
248 /* cpuid[eax=7,ecx=0].ecx */
249 static const int CPU_FEATURE_BIT_AVX512VBMI = 1 << 1; // AVX512VBMI (vector bit manipulation instructions)
250#endif
251
252#if defined(__X86_ASM__)
253 __noinline int64_t get_xcr0()
254 {
255#if defined (__WIN32__) && !defined (__MINGW32__) && defined(_XCR_XFEATURE_ENABLED_MASK)
256 int64_t xcr0 = 0; // int64_t is workaround for compiler bug under VS2013, Win32
257 xcr0 = _xgetbv(0);
258 return xcr0;
259#else
260 int xcr0 = 0;
261 __asm__ ("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx" );
262 return xcr0;
263#endif
264 }
265#endif
266
267 int getCPUFeatures()
268 {
269#if defined(__X86_ASM__)
270 /* cache CPU features access */
271 static int cpu_features = 0;
272 if (cpu_features)
273 return cpu_features;
274
275 /* get number of CPUID leaves */
276 int cpuid_leaf0[4];
277 __cpuid(cpuid_leaf0, 0x00000000);
278 unsigned nIds = cpuid_leaf0[EAX];
279
280 /* get number of extended CPUID leaves */
281 int cpuid_leafe[4];
282 __cpuid(cpuid_leafe, 0x80000000);
283 unsigned nExIds = cpuid_leafe[EAX];
284
285 /* get CPUID leaves for EAX = 1,7, and 0x80000001 */
286 int cpuid_leaf_1[4] = { 0,0,0,0 };
287 int cpuid_leaf_7[4] = { 0,0,0,0 };
288 int cpuid_leaf_e1[4] = { 0,0,0,0 };
289 if (nIds >= 1) __cpuid (cpuid_leaf_1,0x00000001);
290#if _WIN32
291#if _MSC_VER && (_MSC_FULL_VER < 160040219)
292#else
293 if (nIds >= 7) __cpuidex(cpuid_leaf_7,0x00000007,0);
294#endif
295#else
296 if (nIds >= 7) __cpuid_count(cpuid_leaf_7,0x00000007,0);
297#endif
298 if (nExIds >= 0x80000001) __cpuid(cpuid_leaf_e1,0x80000001);
299
300 /* detect if OS saves XMM, YMM, and ZMM states */
301 bool xmm_enabled = true;
302 bool ymm_enabled = false;
303 bool zmm_enabled = false;
304 if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_OXSAVE) {
305 int64_t xcr0 = get_xcr0();
306 xmm_enabled = ((xcr0 & 0x02) == 0x02); /* checks if xmm are enabled in XCR0 */
307 ymm_enabled = xmm_enabled && ((xcr0 & 0x04) == 0x04); /* checks if ymm state are enabled in XCR0 */
308 zmm_enabled = ymm_enabled && ((xcr0 & 0xE0) == 0xE0); /* checks if OPMASK state, upper 256-bit of ZMM0-ZMM15 and ZMM16-ZMM31 state are enabled in XCR0 */
309 }
310 if (xmm_enabled) cpu_features |= CPU_FEATURE_XMM_ENABLED;
311 if (ymm_enabled) cpu_features |= CPU_FEATURE_YMM_ENABLED;
312 if (zmm_enabled) cpu_features |= CPU_FEATURE_ZMM_ENABLED;
313
314 if (cpuid_leaf_1[EDX] & CPU_FEATURE_BIT_SSE ) cpu_features |= CPU_FEATURE_SSE;
315 if (cpuid_leaf_1[EDX] & CPU_FEATURE_BIT_SSE2 ) cpu_features |= CPU_FEATURE_SSE2;
316 if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSE3 ) cpu_features |= CPU_FEATURE_SSE3;
317 if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSSE3 ) cpu_features |= CPU_FEATURE_SSSE3;
318 if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSE4_1) cpu_features |= CPU_FEATURE_SSE41;
319 if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_SSE4_2) cpu_features |= CPU_FEATURE_SSE42;
320 if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_POPCNT) cpu_features |= CPU_FEATURE_POPCNT;
321
322 if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_AVX ) cpu_features |= CPU_FEATURE_AVX;
323 if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_F16C ) cpu_features |= CPU_FEATURE_F16C;
324 if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_RDRAND) cpu_features |= CPU_FEATURE_RDRAND;
325 if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX2 ) cpu_features |= CPU_FEATURE_AVX2;
326 if (cpuid_leaf_1[ECX] & CPU_FEATURE_BIT_FMA3 ) cpu_features |= CPU_FEATURE_FMA3;
327 if (cpuid_leaf_e1[ECX] & CPU_FEATURE_BIT_LZCNT) cpu_features |= CPU_FEATURE_LZCNT;
328 if (cpuid_leaf_7 [EBX] & CPU_FEATURE_BIT_BMI1 ) cpu_features |= CPU_FEATURE_BMI1;
329 if (cpuid_leaf_7 [EBX] & CPU_FEATURE_BIT_BMI2 ) cpu_features |= CPU_FEATURE_BMI2;
330
331 if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512F ) cpu_features |= CPU_FEATURE_AVX512F;
332 if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512DQ ) cpu_features |= CPU_FEATURE_AVX512DQ;
333 if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512PF ) cpu_features |= CPU_FEATURE_AVX512PF;
334 if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512ER ) cpu_features |= CPU_FEATURE_AVX512ER;
335 if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512CD ) cpu_features |= CPU_FEATURE_AVX512CD;
336 if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512BW ) cpu_features |= CPU_FEATURE_AVX512BW;
337 if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512IFMA) cpu_features |= CPU_FEATURE_AVX512IFMA;
338 if (cpuid_leaf_7[EBX] & CPU_FEATURE_BIT_AVX512VL ) cpu_features |= CPU_FEATURE_AVX512VL;
339 if (cpuid_leaf_7[ECX] & CPU_FEATURE_BIT_AVX512VBMI) cpu_features |= CPU_FEATURE_AVX512VBMI;
340
341 return cpu_features;
342
343#elif defined(__ARM_NEON) || defined(__EMSCRIPTEN__)
344
345 int cpu_features = CPU_FEATURE_NEON|CPU_FEATURE_SSE|CPU_FEATURE_SSE2;
346 cpu_features |= CPU_FEATURE_SSE3|CPU_FEATURE_SSSE3|CPU_FEATURE_SSE42;
347 cpu_features |= CPU_FEATURE_XMM_ENABLED;
348 cpu_features |= CPU_FEATURE_YMM_ENABLED;
349 cpu_features |= CPU_FEATURE_SSE41 | CPU_FEATURE_RDRAND | CPU_FEATURE_F16C;
350 cpu_features |= CPU_FEATURE_POPCNT;
351 cpu_features |= CPU_FEATURE_AVX;
352 cpu_features |= CPU_FEATURE_AVX2;
353 cpu_features |= CPU_FEATURE_FMA3;
354 cpu_features |= CPU_FEATURE_LZCNT;
355 cpu_features |= CPU_FEATURE_BMI1;
356 cpu_features |= CPU_FEATURE_BMI2;
357 cpu_features |= CPU_FEATURE_NEON_2X;
358 return cpu_features;
359
360#else
361 /* Unknown CPU. */
362 return 0;
363#endif
364 }
365
366 std::string stringOfCPUFeatures(int features)
367 {
368 std::string str;
369 if (features & CPU_FEATURE_XMM_ENABLED) str += "XMM ";
370 if (features & CPU_FEATURE_YMM_ENABLED) str += "YMM ";
371 if (features & CPU_FEATURE_ZMM_ENABLED) str += "ZMM ";
372 if (features & CPU_FEATURE_SSE ) str += "SSE ";
373 if (features & CPU_FEATURE_SSE2 ) str += "SSE2 ";
374 if (features & CPU_FEATURE_SSE3 ) str += "SSE3 ";
375 if (features & CPU_FEATURE_SSSE3 ) str += "SSSE3 ";
376 if (features & CPU_FEATURE_SSE41 ) str += "SSE4.1 ";
377 if (features & CPU_FEATURE_SSE42 ) str += "SSE4.2 ";
378 if (features & CPU_FEATURE_POPCNT) str += "POPCNT ";
379 if (features & CPU_FEATURE_AVX ) str += "AVX ";
380 if (features & CPU_FEATURE_F16C ) str += "F16C ";
381 if (features & CPU_FEATURE_RDRAND) str += "RDRAND ";
382 if (features & CPU_FEATURE_AVX2 ) str += "AVX2 ";
383 if (features & CPU_FEATURE_FMA3 ) str += "FMA3 ";
384 if (features & CPU_FEATURE_LZCNT ) str += "LZCNT ";
385 if (features & CPU_FEATURE_BMI1 ) str += "BMI1 ";
386 if (features & CPU_FEATURE_BMI2 ) str += "BMI2 ";
387 if (features & CPU_FEATURE_AVX512F) str += "AVX512F ";
388 if (features & CPU_FEATURE_AVX512DQ) str += "AVX512DQ ";
389 if (features & CPU_FEATURE_AVX512PF) str += "AVX512PF ";
390 if (features & CPU_FEATURE_AVX512ER) str += "AVX512ER ";
391 if (features & CPU_FEATURE_AVX512CD) str += "AVX512CD ";
392 if (features & CPU_FEATURE_AVX512BW) str += "AVX512BW ";
393 if (features & CPU_FEATURE_AVX512VL) str += "AVX512VL ";
394 if (features & CPU_FEATURE_AVX512IFMA) str += "AVX512IFMA ";
395 if (features & CPU_FEATURE_AVX512VBMI) str += "AVX512VBMI ";
396 if (features & CPU_FEATURE_NEON) str += "NEON ";
397 if (features & CPU_FEATURE_NEON_2X) str += "2xNEON ";
398 return str;
399 }
400
401 std::string stringOfISA (int isa)
402 {
403 if (isa == SSE) return "SSE";
404 if (isa == SSE2) return "SSE2";
405 if (isa == SSE3) return "SSE3";
406 if (isa == SSSE3) return "SSSE3";
407 if (isa == SSE41) return "SSE4.1";
408 if (isa == SSE42) return "SSE4.2";
409 if (isa == AVX) return "AVX";
410 if (isa == AVX2) return "AVX2";
411 if (isa == AVX512) return "AVX512";
412
413 if (isa == NEON) return "NEON";
414 if (isa == NEON_2X) return "2xNEON";
415 return "UNKNOWN";
416 }
417
418 bool hasISA(int features, int isa) {
419 return (features & isa) == isa;
420 }
421
422 std::string supportedTargetList (int features)
423 {
424 std::string v;
425 if (hasISA(features,SSE)) v += "SSE ";
426 if (hasISA(features,SSE2)) v += "SSE2 ";
427 if (hasISA(features,SSE3)) v += "SSE3 ";
428 if (hasISA(features,SSSE3)) v += "SSSE3 ";
429 if (hasISA(features,SSE41)) v += "SSE4.1 ";
430 if (hasISA(features,SSE42)) v += "SSE4.2 ";
431 if (hasISA(features,AVX)) v += "AVX ";
432 if (hasISA(features,AVXI)) v += "AVXI ";
433 if (hasISA(features,AVX2)) v += "AVX2 ";
434 if (hasISA(features,AVX512)) v += "AVX512 ";
435
436 if (hasISA(features,NEON)) v += "NEON ";
437 if (hasISA(features,NEON_2X)) v += "2xNEON ";
438 return v;
439 }
440}
441
442////////////////////////////////////////////////////////////////////////////////
443/// Windows Platform
444////////////////////////////////////////////////////////////////////////////////
445
446#if defined(__WIN32__)
447
448#define WIN32_LEAN_AND_MEAN
449#include <windows.h>
450#include <psapi.h>
451
452namespace embree
453{
454 std::string getExecutableFileName() {
455 char filename[1024];
456 if (!GetModuleFileName(nullptr, filename, sizeof(filename)))
457 return std::string();
458 return std::string(filename);
459 }
460
461 unsigned int getNumberOfLogicalThreads()
462 {
463 static int nThreads = -1;
464 if (nThreads != -1) return nThreads;
465
466 typedef WORD (WINAPI *GetActiveProcessorGroupCountFunc)();
467 typedef DWORD (WINAPI *GetActiveProcessorCountFunc)(WORD);
468 HMODULE hlib = LoadLibrary("Kernel32");
469 GetActiveProcessorGroupCountFunc pGetActiveProcessorGroupCount = (GetActiveProcessorGroupCountFunc)GetProcAddress(hlib, "GetActiveProcessorGroupCount");
470 GetActiveProcessorCountFunc pGetActiveProcessorCount = (GetActiveProcessorCountFunc) GetProcAddress(hlib, "GetActiveProcessorCount");
471
472 if (pGetActiveProcessorGroupCount && pGetActiveProcessorCount)
473 {
474 int groups = pGetActiveProcessorGroupCount();
475 int totalProcessors = 0;
476 for (int i = 0; i < groups; i++)
477 totalProcessors += pGetActiveProcessorCount(i);
478 nThreads = totalProcessors;
479 }
480 else
481 {
482 SYSTEM_INFO sysinfo;
483 GetSystemInfo(&sysinfo);
484 nThreads = sysinfo.dwNumberOfProcessors;
485 }
486 assert(nThreads);
487 return nThreads;
488 }
489
490 int getTerminalWidth()
491 {
492 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
493 if (handle == INVALID_HANDLE_VALUE) return 80;
494 CONSOLE_SCREEN_BUFFER_INFO info;
495 memset(&info,0,sizeof(info));
496 GetConsoleScreenBufferInfo(handle, &info);
497 return info.dwSize.X;
498 }
499
500 double getSeconds()
501 {
502 LARGE_INTEGER freq, val;
503 QueryPerformanceFrequency(&freq);
504 QueryPerformanceCounter(&val);
505 return (double)val.QuadPart / (double)freq.QuadPart;
506 }
507
508 void sleepSeconds(double t) {
509 Sleep(DWORD(1000.0*t));
510 }
511
512 size_t getVirtualMemoryBytes()
513 {
514 PROCESS_MEMORY_COUNTERS info;
515 GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
516 return (size_t)info.QuotaPeakPagedPoolUsage;
517 }
518
519 size_t getResidentMemoryBytes()
520 {
521 PROCESS_MEMORY_COUNTERS info;
522 GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
523 return (size_t)info.WorkingSetSize;
524 }
525}
526#endif
527
528////////////////////////////////////////////////////////////////////////////////
529/// Linux Platform
530////////////////////////////////////////////////////////////////////////////////
531
532#if defined(__LINUX__)
533
534#include <stdio.h>
535#include <unistd.h>
536
537namespace embree
538{
539 std::string getExecutableFileName()
540 {
541 std::string pid = "/proc/" + toString(getpid()) + "/exe";
542 char buf[4096];
543 memset(buf,0,sizeof(buf));
544 if (readlink(pid.c_str(), buf, sizeof(buf)-1) == -1)
545 return std::string();
546 return std::string(buf);
547 }
548
549 size_t getVirtualMemoryBytes()
550 {
551 size_t virt, resident, shared;
552 std::ifstream buffer("/proc/self/statm");
553 buffer >> virt >> resident >> shared;
554 return virt*sysconf(_SC_PAGE_SIZE);
555 }
556
557 size_t getResidentMemoryBytes()
558 {
559 size_t virt, resident, shared;
560 std::ifstream buffer("/proc/self/statm");
561 buffer >> virt >> resident >> shared;
562 return resident*sysconf(_SC_PAGE_SIZE);
563 }
564}
565
566#endif
567
568////////////////////////////////////////////////////////////////////////////////
569/// FreeBSD Platform
570////////////////////////////////////////////////////////////////////////////////
571
572#if defined (__FreeBSD__)
573
574#include <sys/sysctl.h>
575
576namespace embree
577{
578 std::string getExecutableFileName()
579 {
580 const int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
581 char buf[4096];
582 memset(buf,0,sizeof(buf));
583 size_t len = sizeof(buf)-1;
584 if (sysctl(mib, 4, buf, &len, 0x0, 0) == -1)
585 return std::string();
586 return std::string(buf);
587 }
588
589 size_t getVirtualMemoryBytes() {
590 return 0;
591 }
592
593 size_t getResidentMemoryBytes() {
594 return 0;
595 }
596}
597
598#endif
599
600////////////////////////////////////////////////////////////////////////////////
601/// Mac OS X Platform
602////////////////////////////////////////////////////////////////////////////////
603
604#if defined(__MACOSX__)
605
606#include <mach-o/dyld.h>
607
608namespace embree
609{
610 std::string getExecutableFileName()
611 {
612 char buf[4096];
613 uint32_t size = sizeof(buf);
614 if (_NSGetExecutablePath(buf, &size) != 0)
615 return std::string();
616 return std::string(buf);
617 }
618
619 size_t getVirtualMemoryBytes() {
620 return 0;
621 }
622
623 size_t getResidentMemoryBytes() {
624 return 0;
625 }
626}
627
628#endif
629
630////////////////////////////////////////////////////////////////////////////////
631/// Unix Platform
632////////////////////////////////////////////////////////////////////////////////
633
634#if defined(__UNIX__)
635
636#include <unistd.h>
637#include <sys/ioctl.h>
638#include <sys/time.h>
639#include <pthread.h>
640
641#if defined(__EMSCRIPTEN__)
642#include <emscripten.h>
643
644// -- GODOT start --
645extern "C" {
646extern int godot_js_os_hw_concurrency_get();
647}
648// -- GODOT end --
649#endif
650
651namespace embree
652{
653 unsigned int getNumberOfLogicalThreads()
654 {
655 static int nThreads = -1;
656 if (nThreads != -1) return nThreads;
657
658#if defined(__MACOSX__) || defined(__ANDROID__)
659 nThreads = sysconf(_SC_NPROCESSORS_ONLN); // does not work in Linux LXC container
660 assert(nThreads);
661#elif defined(__EMSCRIPTEN__)
662 // -- GODOT start --
663 nThreads = godot_js_os_hw_concurrency_get();
664 // -- GODOT end --
665#else
666 cpu_set_t set;
667 if (pthread_getaffinity_np(pthread_self(), sizeof(set), &set) == 0)
668 nThreads = CPU_COUNT(&set);
669#endif
670
671 assert(nThreads);
672 return nThreads;
673 }
674
675 int getTerminalWidth()
676 {
677 struct winsize info;
678 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &info) < 0) return 80;
679 return info.ws_col;
680 }
681
682 double getSeconds() {
683 struct timeval tp; gettimeofday(&tp,nullptr);
684 return double(tp.tv_sec) + double(tp.tv_usec)/1E6;
685 }
686
687 void sleepSeconds(double t) {
688 usleep(1000000.0*t);
689 }
690}
691#endif
692
693