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"
11 # include <CoreFoundation/CoreFoundation.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"
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
,
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
*);
51 namespace Instruments
{
53 static const int kSamplingInterval
= 20; // microseconds
58 MOZ_IMPLICIT
AutoReleased(T aTypeRef
) : mTypeRef(aTypeRef
) {}
65 operator T() { return 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;
85 void* LoadDTPerformanceLibraries(bool dontLoad
) {
86 int flags
= RTLD_LAZY
| RTLD_LOCAL
| RTLD_NODELETE
;
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
) {
107 # define SYMBOL(_sym) \
109 reinterpret_cast<_sym##Function>(dlsym(DTPerformanceLibrary, #_sym)); \
111 dlclose(DTPerformanceLibrary); \
112 DTPerformanceLibrary = nullptr; \
116 DTPERFORMANCE_SYMBOLS
120 dlclose(DTPerformanceLibrary
);
125 static DTPerformanceSessionRef gSession
;
127 bool Error(CFErrorRef error
) {
129 CFErrorRef unused
= nullptr;
130 DTPerformanceSessionStop(gSession
, nullptr, &unused
);
135 AutoReleased
<CFDataRef
> data
= CFStringCreateExternalRepresentation(
136 nullptr, CFErrorCopyDescription(error
), kCFStringEncodingUTF8
, '?');
137 if (data
!= nullptr) {
138 printf("%.*s\n\n", (int)CFDataGetLength(data
), CFDataGetBytePtr(data
));
144 bool Start(pid_t pid
) {
149 if (!LoadDTPerformanceLibrary()) {
153 AutoReleased
<CFStringRef
> process
=
154 CFStringCreateWithFormat(kCFAllocatorDefault
, nullptr, CFSTR("%d"), pid
);
158 CFErrorRef error
= nullptr;
159 gSession
= DTPerformanceSessionCreate(nullptr, process
, nullptr, &error
);
164 AutoReleased
<CFNumberRef
> interval
=
165 CFNumberCreate(0, kCFNumberIntType
, &kSamplingInterval
);
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
);
178 if (!DTPerformanceSessionAddInstrument(
179 gSession
, CFSTR(DTPerformanceSession_TimeProfiler
), options
, nullptr,
188 if (gSession
&& DTPerformanceSessionIsRecording(gSession
)) {
189 CFErrorRef error
= nullptr;
190 if (!DTPerformanceSessionStop(gSession
, nullptr, &error
)) {
201 CFErrorRef error
= nullptr;
202 return DTPerformanceSessionStart(gSession
, nullptr, &error
) || Error(error
);
205 void Stop(const char* profileName
) {
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
)) {
221 } // namespace Instruments
223 #endif /* __APPLE__ */