Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / js / src / devtools / Instruments.cpp
blob39fbe882b843c8c3c32b48454e2d965e13d1415a
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "Instruments.h"
6 #include "mozilla/Attributes.h"
8 #ifdef __APPLE__
10 # include <dlfcn.h>
11 # include <CoreFoundation/CoreFoundation.h>
12 # include <unistd.h>
14 // There are now 2 paths to the DTPerformanceSession framework. We try to load
15 // the one contained in /Applications/Xcode.app first, falling back to the one
16 // contained in /Library/Developer/4.0/Instruments.
17 # define DTPerformanceLibraryPath \
18 "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/" \
19 "DTPerformanceSession.framework/Versions/Current/DTPerformanceSession"
20 # define OldDTPerformanceLibraryPath \
21 "/Library/Developer/4.0/Instruments/Frameworks/" \
22 "DTPerformanceSession.framework/Versions/Current/DTPerformanceSession"
24 extern "C" {
26 typedef CFTypeRef DTPerformanceSessionRef;
28 # define DTPerformanceSession_TimeProfiler \
29 "com.apple.instruments.dtps.timeprofiler"
30 // DTPerformanceSession_Option_SamplingInterval is measured in microseconds
31 # define DTPerformanceSession_Option_SamplingInterval \
32 "com.apple.instruments.dtps.option.samplinginterval"
34 typedef void (*dtps_errorcallback_t)(CFStringRef, CFErrorRef);
35 typedef DTPerformanceSessionRef (*DTPerformanceSessionCreateFunction)(
36 CFStringRef, CFStringRef, CFDictionaryRef, CFErrorRef*);
37 typedef bool (*DTPerformanceSessionAddInstrumentFunction)(
38 DTPerformanceSessionRef, CFStringRef, CFDictionaryRef, dtps_errorcallback_t,
39 CFErrorRef*);
40 typedef bool (*DTPerformanceSessionIsRecordingFunction)(
41 DTPerformanceSessionRef);
42 typedef bool (*DTPerformanceSessionStartFunction)(DTPerformanceSessionRef,
43 CFArrayRef, CFErrorRef*);
44 typedef bool (*DTPerformanceSessionStopFunction)(DTPerformanceSessionRef,
45 CFArrayRef, CFErrorRef*);
46 typedef bool (*DTPerformanceSessionSaveFunction)(DTPerformanceSessionRef,
47 CFStringRef, CFErrorRef*);
49 } // extern "C"
51 namespace Instruments {
53 static const int kSamplingInterval = 20; // microseconds
55 template <typename T>
56 class AutoReleased {
57 public:
58 MOZ_IMPLICIT AutoReleased(T aTypeRef) : mTypeRef(aTypeRef) {}
59 ~AutoReleased() {
60 if (mTypeRef) {
61 CFRelease(mTypeRef);
65 operator T() { return mTypeRef; }
67 private:
68 T mTypeRef;
71 # define DTPERFORMANCE_SYMBOLS \
72 SYMBOL(DTPerformanceSessionCreate) \
73 SYMBOL(DTPerformanceSessionAddInstrument) \
74 SYMBOL(DTPerformanceSessionIsRecording) \
75 SYMBOL(DTPerformanceSessionStart) \
76 SYMBOL(DTPerformanceSessionStop) \
77 SYMBOL(DTPerformanceSessionSave)
79 # define SYMBOL(_sym) _sym##Function _sym = nullptr;
81 DTPERFORMANCE_SYMBOLS
83 # undef SYMBOL
85 void* LoadDTPerformanceLibraries(bool dontLoad) {
86 int flags = RTLD_LAZY | RTLD_LOCAL | RTLD_NODELETE;
87 if (dontLoad) {
88 flags |= RTLD_NOLOAD;
91 void* DTPerformanceLibrary = dlopen(DTPerformanceLibraryPath, flags);
92 if (!DTPerformanceLibrary) {
93 DTPerformanceLibrary = dlopen(OldDTPerformanceLibraryPath, flags);
95 return DTPerformanceLibrary;
98 bool LoadDTPerformanceLibrary() {
99 void* DTPerformanceLibrary = LoadDTPerformanceLibraries(true);
100 if (!DTPerformanceLibrary) {
101 DTPerformanceLibrary = LoadDTPerformanceLibraries(false);
102 if (!DTPerformanceLibrary) {
103 return false;
107 # define SYMBOL(_sym) \
108 _sym = \
109 reinterpret_cast<_sym##Function>(dlsym(DTPerformanceLibrary, #_sym)); \
110 if (!_sym) { \
111 dlclose(DTPerformanceLibrary); \
112 DTPerformanceLibrary = nullptr; \
113 return false; \
116 DTPERFORMANCE_SYMBOLS
118 # undef SYMBOL
120 dlclose(DTPerformanceLibrary);
122 return true;
125 static DTPerformanceSessionRef gSession;
127 bool Error(CFErrorRef error) {
128 if (gSession) {
129 CFErrorRef unused = nullptr;
130 DTPerformanceSessionStop(gSession, nullptr, &unused);
131 CFRelease(gSession);
132 gSession = nullptr;
134 # ifdef DEBUG
135 AutoReleased<CFDataRef> data = CFStringCreateExternalRepresentation(
136 nullptr, CFErrorCopyDescription(error), kCFStringEncodingUTF8, '?');
137 if (data != nullptr) {
138 printf("%.*s\n\n", (int)CFDataGetLength(data), CFDataGetBytePtr(data));
140 # endif
141 return false;
144 bool Start(pid_t pid) {
145 if (gSession) {
146 return false;
149 if (!LoadDTPerformanceLibrary()) {
150 return false;
153 AutoReleased<CFStringRef> process =
154 CFStringCreateWithFormat(kCFAllocatorDefault, nullptr, CFSTR("%d"), pid);
155 if (!process) {
156 return false;
158 CFErrorRef error = nullptr;
159 gSession = DTPerformanceSessionCreate(nullptr, process, nullptr, &error);
160 if (!gSession) {
161 return Error(error);
164 AutoReleased<CFNumberRef> interval =
165 CFNumberCreate(0, kCFNumberIntType, &kSamplingInterval);
166 if (!interval) {
167 return false;
169 CFStringRef keys[1] = {CFSTR(DTPerformanceSession_Option_SamplingInterval)};
170 CFNumberRef values[1] = {interval};
171 AutoReleased<CFDictionaryRef> options = CFDictionaryCreate(
172 kCFAllocatorDefault, (const void**)keys, (const void**)values, 1,
173 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
174 if (!options) {
175 return false;
178 if (!DTPerformanceSessionAddInstrument(
179 gSession, CFSTR(DTPerformanceSession_TimeProfiler), options, nullptr,
180 &error)) {
181 return Error(error);
184 return Resume();
187 void Pause() {
188 if (gSession && DTPerformanceSessionIsRecording(gSession)) {
189 CFErrorRef error = nullptr;
190 if (!DTPerformanceSessionStop(gSession, nullptr, &error)) {
191 Error(error);
196 bool Resume() {
197 if (!gSession) {
198 return false;
201 CFErrorRef error = nullptr;
202 return DTPerformanceSessionStart(gSession, nullptr, &error) || Error(error);
205 void Stop(const char* profileName) {
206 Pause();
208 CFErrorRef error = nullptr;
209 AutoReleased<CFStringRef> name =
210 CFStringCreateWithFormat(kCFAllocatorDefault, nullptr, CFSTR("%s%s"),
211 "/tmp/", profileName ? profileName : "mozilla");
212 if (!DTPerformanceSessionSave(gSession, name, &error)) {
213 Error(error);
214 return;
217 CFRelease(gSession);
218 gSession = nullptr;
221 } // namespace Instruments
223 #endif /* __APPLE__ */