js/src/devtools/Instruments.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:c9963b5d4f21
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/. */
4
5 #include "Instruments.h"
6
7 #ifdef __APPLE__
8
9 #include <dlfcn.h>
10 #include <CoreFoundation/CoreFoundation.h>
11 #include <unistd.h>
12
13 // There are now 2 paths to the DTPerformanceSession framework. We try to load
14 // the one contained in /Applications/Xcode.app first, falling back to the one
15 // contained in /Library/Developer/4.0/Instruments.
16 #define DTPerformanceLibraryPath "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/DTPerformanceSession.framework/Versions/Current/DTPerformanceSession"
17 #define OldDTPerformanceLibraryPath "/Library/Developer/4.0/Instruments/Frameworks/DTPerformanceSession.framework/Versions/Current/DTPerformanceSession"
18
19 extern "C" {
20
21 typedef CFTypeRef DTPerformanceSessionRef;
22
23 #define DTPerformanceSession_TimeProfiler "com.apple.instruments.dtps.timeprofiler"
24 // DTPerformanceSession_Option_SamplingInterval is measured in microseconds
25 #define DTPerformanceSession_Option_SamplingInterval "com.apple.instruments.dtps.option.samplinginterval"
26
27 typedef void (*dtps_errorcallback_t)(CFStringRef, CFErrorRef);
28 typedef DTPerformanceSessionRef (*DTPerformanceSessionCreateFunction)(CFStringRef, CFStringRef, CFDictionaryRef, CFErrorRef*);
29 typedef bool (*DTPerformanceSessionAddInstrumentFunction)(DTPerformanceSessionRef, CFStringRef, CFDictionaryRef, dtps_errorcallback_t, CFErrorRef*);
30 typedef bool (*DTPerformanceSessionIsRecordingFunction)(DTPerformanceSessionRef);
31 typedef bool (*DTPerformanceSessionStartFunction)(DTPerformanceSessionRef, CFArrayRef, CFErrorRef*);
32 typedef bool (*DTPerformanceSessionStopFunction)(DTPerformanceSessionRef, CFArrayRef, CFErrorRef*);
33 typedef bool (*DTPerformanceSessionSaveFunction)(DTPerformanceSessionRef, CFStringRef, CFErrorRef*);
34
35 } // extern "C"
36
37 namespace Instruments {
38
39 static const int kSamplingInterval = 20; // microseconds
40
41 template<typename T>
42 class AutoReleased
43 {
44 public:
45 AutoReleased(T aTypeRef) : mTypeRef(aTypeRef)
46 {
47 }
48 ~AutoReleased()
49 {
50 if (mTypeRef) {
51 CFRelease(mTypeRef);
52 }
53 }
54
55 operator T()
56 {
57 return mTypeRef;
58 }
59
60 private:
61 T mTypeRef;
62 };
63
64 #define DTPERFORMANCE_SYMBOLS \
65 SYMBOL(DTPerformanceSessionCreate) \
66 SYMBOL(DTPerformanceSessionAddInstrument) \
67 SYMBOL(DTPerformanceSessionIsRecording) \
68 SYMBOL(DTPerformanceSessionStart) \
69 SYMBOL(DTPerformanceSessionStop) \
70 SYMBOL(DTPerformanceSessionSave)
71
72 #define SYMBOL(_sym) \
73 _sym##Function _sym = nullptr;
74
75 DTPERFORMANCE_SYMBOLS
76
77 #undef SYMBOL
78
79 void*
80 LoadDTPerformanceLibraries(bool dontLoad)
81 {
82 int flags = RTLD_LAZY | RTLD_LOCAL | RTLD_NODELETE;
83 if (dontLoad) {
84 flags |= RTLD_NOLOAD;
85 }
86
87 void *DTPerformanceLibrary = dlopen(DTPerformanceLibraryPath, flags);
88 if (!DTPerformanceLibrary) {
89 DTPerformanceLibrary = dlopen(OldDTPerformanceLibraryPath, flags);
90 }
91 return DTPerformanceLibrary;
92 }
93
94 bool
95 LoadDTPerformanceLibrary()
96 {
97 void *DTPerformanceLibrary = LoadDTPerformanceLibraries(true);
98 if (!DTPerformanceLibrary) {
99 DTPerformanceLibrary = LoadDTPerformanceLibraries(false);
100 if (!DTPerformanceLibrary) {
101 return false;
102 }
103 }
104
105 #define SYMBOL(_sym) \
106 _sym = reinterpret_cast<_sym##Function>(dlsym(DTPerformanceLibrary, #_sym)); \
107 if (!_sym) { \
108 dlclose(DTPerformanceLibrary); \
109 DTPerformanceLibrary = nullptr; \
110 return false; \
111 }
112
113 DTPERFORMANCE_SYMBOLS
114
115 #undef SYMBOL
116
117 dlclose(DTPerformanceLibrary);
118
119 return true;
120 }
121
122 static DTPerformanceSessionRef gSession;
123
124 bool
125 Error(CFErrorRef error)
126 {
127 if (gSession) {
128 CFErrorRef unused = nullptr;
129 DTPerformanceSessionStop(gSession, nullptr, &unused);
130 CFRelease(gSession);
131 gSession = nullptr;
132 }
133 #ifdef DEBUG
134 AutoReleased<CFDataRef> data =
135 CFStringCreateExternalRepresentation(nullptr,
136 CFErrorCopyDescription(error),
137 kCFStringEncodingUTF8, '?');
138 if (data != nullptr) {
139 printf("%.*s\n\n", (int)CFDataGetLength(data), CFDataGetBytePtr(data));
140 }
141 #endif
142 return false;
143 }
144
145 bool
146 Start(pid_t pid)
147 {
148 if (gSession) {
149 return false;
150 }
151
152 if (!LoadDTPerformanceLibrary()) {
153 return false;
154 }
155
156 AutoReleased<CFStringRef> process =
157 CFStringCreateWithFormat(kCFAllocatorDefault, nullptr, CFSTR("%d"), pid);
158 if (!process) {
159 return false;
160 }
161 CFErrorRef error = nullptr;
162 gSession = DTPerformanceSessionCreate(nullptr, process, nullptr, &error);
163 if (!gSession) {
164 return Error(error);
165 }
166
167 AutoReleased<CFNumberRef> interval =
168 CFNumberCreate(0, kCFNumberIntType, &kSamplingInterval);
169 if (!interval) {
170 return false;
171 }
172 CFStringRef keys[1] = { CFSTR(DTPerformanceSession_Option_SamplingInterval) };
173 CFNumberRef values[1] = { interval };
174 AutoReleased<CFDictionaryRef> options =
175 CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys,
176 (const void**)values, 1, &kCFTypeDictionaryKeyCallBacks,
177 &kCFTypeDictionaryValueCallBacks);
178 if (!options) {
179 return false;
180 }
181
182 if (!DTPerformanceSessionAddInstrument(gSession,
183 CFSTR(DTPerformanceSession_TimeProfiler),
184 options, nullptr, &error)) {
185 return Error(error);
186 }
187
188 return Resume();
189 }
190
191 void
192 Pause()
193 {
194 if (gSession && DTPerformanceSessionIsRecording(gSession)) {
195 CFErrorRef error = nullptr;
196 if (!DTPerformanceSessionStop(gSession, nullptr, &error)) {
197 Error(error);
198 }
199 }
200 }
201
202 bool
203 Resume()
204 {
205 if (!gSession) {
206 return false;
207 }
208
209 CFErrorRef error = nullptr;
210 return DTPerformanceSessionStart(gSession, nullptr, &error) ||
211 Error(error);
212 }
213
214 void
215 Stop(const char* profileName)
216 {
217 Pause();
218
219 CFErrorRef error = nullptr;
220 AutoReleased<CFStringRef> name =
221 CFStringCreateWithFormat(kCFAllocatorDefault, nullptr, CFSTR("%s%s"),
222 "/tmp/", profileName ? profileName : "mozilla");
223 if (!DTPerformanceSessionSave(gSession, name, &error)) {
224 Error(error);
225 return;
226 }
227
228 CFRelease(gSession);
229 gSession = nullptr;
230 }
231
232 } // namespace Instruments
233
234 #endif /* __APPLE__ */

mercurial