1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2020 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21 */
22
23 namespace juce
24 {
25
getJUCEVersion()26 String SystemStats::getJUCEVersion()
27 {
28 // Some basic tests, to keep an eye on things and make sure these types work ok
29 // on all platforms. Let me know if any of these assertions fail on your system!
30 static_assert (sizeof (pointer_sized_int) == sizeof (void*), "Basic sanity test failed: please report!");
31 static_assert (sizeof (int8) == 1, "Basic sanity test failed: please report!");
32 static_assert (sizeof (uint8) == 1, "Basic sanity test failed: please report!");
33 static_assert (sizeof (int16) == 2, "Basic sanity test failed: please report!");
34 static_assert (sizeof (uint16) == 2, "Basic sanity test failed: please report!");
35 static_assert (sizeof (int32) == 4, "Basic sanity test failed: please report!");
36 static_assert (sizeof (uint32) == 4, "Basic sanity test failed: please report!");
37 static_assert (sizeof (int64) == 8, "Basic sanity test failed: please report!");
38 static_assert (sizeof (uint64) == 8, "Basic sanity test failed: please report!");
39
40 return "JUCE v" JUCE_STRINGIFY(JUCE_MAJOR_VERSION)
41 "." JUCE_STRINGIFY(JUCE_MINOR_VERSION)
42 "." JUCE_STRINGIFY(JUCE_BUILDNUMBER);
43 }
44
45 #if JUCE_ANDROID && ! defined (JUCE_DISABLE_JUCE_VERSION_PRINTING)
46 #define JUCE_DISABLE_JUCE_VERSION_PRINTING 1
47 #endif
48
49 #if JUCE_DEBUG && ! JUCE_DISABLE_JUCE_VERSION_PRINTING
50 struct JuceVersionPrinter
51 {
JuceVersionPrinterjuce::JuceVersionPrinter52 JuceVersionPrinter()
53 {
54 DBG (SystemStats::getJUCEVersion());
55 }
56 };
57
58 static JuceVersionPrinter juceVersionPrinter;
59 #endif
60
getDeviceIdentifiers()61 StringArray SystemStats::getDeviceIdentifiers()
62 {
63 StringArray ids;
64
65 #if JUCE_WINDOWS
66 File f (File::getSpecialLocation (File::windowsSystemDirectory));
67 #else
68 File f ("~");
69 #endif
70 if (auto num = f.getFileIdentifier())
71 {
72 ids.add (String::toHexString ((int64) num));
73 }
74 else
75 {
76 for (auto& address : MACAddress::getAllAddresses())
77 ids.add (address.toString());
78 }
79
80 jassert (! ids.isEmpty()); // Failed to create any IDs!
81 return ids;
82 }
83
84 //==============================================================================
85 struct CPUInformation
86 {
CPUInformationjuce::CPUInformation87 CPUInformation() noexcept { initialise(); }
88
89 void initialise() noexcept;
90
91 int numLogicalCPUs = 0, numPhysicalCPUs = 0;
92
93 bool hasMMX = false, hasSSE = false, hasSSE2 = false, hasSSE3 = false,
94 has3DNow = false, hasFMA3 = false, hasFMA4 = false, hasSSSE3 = false,
95 hasSSE41 = false, hasSSE42 = false, hasAVX = false, hasAVX2 = false,
96 hasAVX512F = false, hasAVX512BW = false, hasAVX512CD = false,
97 hasAVX512DQ = false, hasAVX512ER = false, hasAVX512IFMA = false,
98 hasAVX512PF = false, hasAVX512VBMI = false, hasAVX512VL = false,
99 hasAVX512VPOPCNTDQ = false,
100 hasNeon = false;
101 };
102
getCPUInformation()103 static const CPUInformation& getCPUInformation() noexcept
104 {
105 static CPUInformation info;
106 return info;
107 }
108
getNumCpus()109 int SystemStats::getNumCpus() noexcept { return getCPUInformation().numLogicalCPUs; }
getNumPhysicalCpus()110 int SystemStats::getNumPhysicalCpus() noexcept { return getCPUInformation().numPhysicalCPUs; }
hasMMX()111 bool SystemStats::hasMMX() noexcept { return getCPUInformation().hasMMX; }
has3DNow()112 bool SystemStats::has3DNow() noexcept { return getCPUInformation().has3DNow; }
hasFMA3()113 bool SystemStats::hasFMA3() noexcept { return getCPUInformation().hasFMA3; }
hasFMA4()114 bool SystemStats::hasFMA4() noexcept { return getCPUInformation().hasFMA4; }
hasSSE()115 bool SystemStats::hasSSE() noexcept { return getCPUInformation().hasSSE; }
hasSSE2()116 bool SystemStats::hasSSE2() noexcept { return getCPUInformation().hasSSE2; }
hasSSE3()117 bool SystemStats::hasSSE3() noexcept { return getCPUInformation().hasSSE3; }
hasSSSE3()118 bool SystemStats::hasSSSE3() noexcept { return getCPUInformation().hasSSSE3; }
hasSSE41()119 bool SystemStats::hasSSE41() noexcept { return getCPUInformation().hasSSE41; }
hasSSE42()120 bool SystemStats::hasSSE42() noexcept { return getCPUInformation().hasSSE42; }
hasAVX()121 bool SystemStats::hasAVX() noexcept { return getCPUInformation().hasAVX; }
hasAVX2()122 bool SystemStats::hasAVX2() noexcept { return getCPUInformation().hasAVX2; }
hasAVX512F()123 bool SystemStats::hasAVX512F() noexcept { return getCPUInformation().hasAVX512F; }
hasAVX512BW()124 bool SystemStats::hasAVX512BW() noexcept { return getCPUInformation().hasAVX512BW; }
hasAVX512CD()125 bool SystemStats::hasAVX512CD() noexcept { return getCPUInformation().hasAVX512CD; }
hasAVX512DQ()126 bool SystemStats::hasAVX512DQ() noexcept { return getCPUInformation().hasAVX512DQ; }
hasAVX512ER()127 bool SystemStats::hasAVX512ER() noexcept { return getCPUInformation().hasAVX512ER; }
hasAVX512IFMA()128 bool SystemStats::hasAVX512IFMA() noexcept { return getCPUInformation().hasAVX512IFMA; }
hasAVX512PF()129 bool SystemStats::hasAVX512PF() noexcept { return getCPUInformation().hasAVX512PF; }
hasAVX512VBMI()130 bool SystemStats::hasAVX512VBMI() noexcept { return getCPUInformation().hasAVX512VBMI; }
hasAVX512VL()131 bool SystemStats::hasAVX512VL() noexcept { return getCPUInformation().hasAVX512VL; }
hasAVX512VPOPCNTDQ()132 bool SystemStats::hasAVX512VPOPCNTDQ() noexcept { return getCPUInformation().hasAVX512VPOPCNTDQ; }
hasNeon()133 bool SystemStats::hasNeon() noexcept { return getCPUInformation().hasNeon; }
134
135
136 //==============================================================================
getStackBacktrace()137 String SystemStats::getStackBacktrace()
138 {
139 String result;
140
141 #if JUCE_ANDROID || JUCE_MINGW || JUCE_WASM
142 jassertfalse; // sorry, not implemented yet!
143
144 #elif JUCE_WINDOWS
145 HANDLE process = GetCurrentProcess();
146 SymInitialize (process, nullptr, TRUE);
147
148 void* stack[128];
149 int frames = (int) CaptureStackBackTrace (0, numElementsInArray (stack), stack, nullptr);
150
151 HeapBlock<SYMBOL_INFO> symbol;
152 symbol.calloc (sizeof (SYMBOL_INFO) + 256, 1);
153 symbol->MaxNameLen = 255;
154 symbol->SizeOfStruct = sizeof (SYMBOL_INFO);
155
156 for (int i = 0; i < frames; ++i)
157 {
158 DWORD64 displacement = 0;
159
160 if (SymFromAddr (process, (DWORD64) stack[i], &displacement, symbol))
161 {
162 result << i << ": ";
163
164 IMAGEHLP_MODULE64 moduleInfo;
165 zerostruct (moduleInfo);
166 moduleInfo.SizeOfStruct = sizeof (moduleInfo);
167
168 if (::SymGetModuleInfo64 (process, symbol->ModBase, &moduleInfo))
169 result << moduleInfo.ModuleName << ": ";
170
171 result << symbol->Name << " + 0x" << String::toHexString ((int64) displacement) << newLine;
172 }
173 }
174
175 #else
176 void* stack[128];
177 int frames = backtrace (stack, numElementsInArray (stack));
178 char** frameStrings = backtrace_symbols (stack, frames);
179
180 for (int i = 0; i < frames; ++i)
181 result << frameStrings[i] << newLine;
182
183 ::free (frameStrings);
184 #endif
185
186 return result;
187 }
188
189 //==============================================================================
190 #if ! JUCE_WASM
191
192 static SystemStats::CrashHandlerFunction globalCrashHandler = nullptr;
193
194 #if JUCE_WINDOWS
handleCrash(LPEXCEPTION_POINTERS ep)195 static LONG WINAPI handleCrash (LPEXCEPTION_POINTERS ep)
196 {
197 globalCrashHandler (ep);
198 return EXCEPTION_EXECUTE_HANDLER;
199 }
200 #else
handleCrash(int signum)201 static void handleCrash (int signum)
202 {
203 globalCrashHandler ((void*) (pointer_sized_int) signum);
204 ::kill (getpid(), SIGKILL);
205 }
206
207 int juce_siginterrupt (int sig, int flag);
208 #endif
209
setApplicationCrashHandler(CrashHandlerFunction handler)210 void SystemStats::setApplicationCrashHandler (CrashHandlerFunction handler)
211 {
212 jassert (handler != nullptr); // This must be a valid function.
213 globalCrashHandler = handler;
214
215 #if JUCE_WINDOWS
216 SetUnhandledExceptionFilter (handleCrash);
217 #else
218 const int signals[] = { SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGABRT, SIGSYS };
219
220 for (int i = 0; i < numElementsInArray (signals); ++i)
221 {
222 ::signal (signals[i], handleCrash);
223 juce_siginterrupt (signals[i], 1);
224 }
225 #endif
226 }
227
228 #endif
229
isRunningInAppExtensionSandbox()230 bool SystemStats::isRunningInAppExtensionSandbox() noexcept
231 {
232 #if JUCE_MAC || JUCE_IOS
233 static bool firstQuery = true;
234 static bool isRunningInAppSandbox = false;
235
236 if (firstQuery)
237 {
238 firstQuery = false;
239
240 File bundle = File::getSpecialLocation (File::invokedExecutableFile).getParentDirectory();
241
242 #if JUCE_MAC
243 bundle = bundle.getParentDirectory().getParentDirectory();
244 #endif
245
246 if (bundle.isDirectory())
247 isRunningInAppSandbox = (bundle.getFileExtension() == ".appex");
248 }
249
250 return isRunningInAppSandbox;
251 #else
252 return false;
253 #endif
254 }
255
256 } // namespace juce
257