1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/devtools/Instruments.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,234 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "Instruments.h" 1.9 + 1.10 +#ifdef __APPLE__ 1.11 + 1.12 +#include <dlfcn.h> 1.13 +#include <CoreFoundation/CoreFoundation.h> 1.14 +#include <unistd.h> 1.15 + 1.16 +// There are now 2 paths to the DTPerformanceSession framework. We try to load 1.17 +// the one contained in /Applications/Xcode.app first, falling back to the one 1.18 +// contained in /Library/Developer/4.0/Instruments. 1.19 +#define DTPerformanceLibraryPath "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/DTPerformanceSession.framework/Versions/Current/DTPerformanceSession" 1.20 +#define OldDTPerformanceLibraryPath "/Library/Developer/4.0/Instruments/Frameworks/DTPerformanceSession.framework/Versions/Current/DTPerformanceSession" 1.21 + 1.22 +extern "C" { 1.23 + 1.24 +typedef CFTypeRef DTPerformanceSessionRef; 1.25 + 1.26 +#define DTPerformanceSession_TimeProfiler "com.apple.instruments.dtps.timeprofiler" 1.27 +// DTPerformanceSession_Option_SamplingInterval is measured in microseconds 1.28 +#define DTPerformanceSession_Option_SamplingInterval "com.apple.instruments.dtps.option.samplinginterval" 1.29 + 1.30 +typedef void (*dtps_errorcallback_t)(CFStringRef, CFErrorRef); 1.31 +typedef DTPerformanceSessionRef (*DTPerformanceSessionCreateFunction)(CFStringRef, CFStringRef, CFDictionaryRef, CFErrorRef*); 1.32 +typedef bool (*DTPerformanceSessionAddInstrumentFunction)(DTPerformanceSessionRef, CFStringRef, CFDictionaryRef, dtps_errorcallback_t, CFErrorRef*); 1.33 +typedef bool (*DTPerformanceSessionIsRecordingFunction)(DTPerformanceSessionRef); 1.34 +typedef bool (*DTPerformanceSessionStartFunction)(DTPerformanceSessionRef, CFArrayRef, CFErrorRef*); 1.35 +typedef bool (*DTPerformanceSessionStopFunction)(DTPerformanceSessionRef, CFArrayRef, CFErrorRef*); 1.36 +typedef bool (*DTPerformanceSessionSaveFunction)(DTPerformanceSessionRef, CFStringRef, CFErrorRef*); 1.37 + 1.38 +} // extern "C" 1.39 + 1.40 +namespace Instruments { 1.41 + 1.42 +static const int kSamplingInterval = 20; // microseconds 1.43 + 1.44 +template<typename T> 1.45 +class AutoReleased 1.46 +{ 1.47 +public: 1.48 + AutoReleased(T aTypeRef) : mTypeRef(aTypeRef) 1.49 + { 1.50 + } 1.51 + ~AutoReleased() 1.52 + { 1.53 + if (mTypeRef) { 1.54 + CFRelease(mTypeRef); 1.55 + } 1.56 + } 1.57 + 1.58 + operator T() 1.59 + { 1.60 + return mTypeRef; 1.61 + } 1.62 + 1.63 +private: 1.64 + T mTypeRef; 1.65 +}; 1.66 + 1.67 +#define DTPERFORMANCE_SYMBOLS \ 1.68 + SYMBOL(DTPerformanceSessionCreate) \ 1.69 + SYMBOL(DTPerformanceSessionAddInstrument) \ 1.70 + SYMBOL(DTPerformanceSessionIsRecording) \ 1.71 + SYMBOL(DTPerformanceSessionStart) \ 1.72 + SYMBOL(DTPerformanceSessionStop) \ 1.73 + SYMBOL(DTPerformanceSessionSave) 1.74 + 1.75 +#define SYMBOL(_sym) \ 1.76 + _sym##Function _sym = nullptr; 1.77 + 1.78 +DTPERFORMANCE_SYMBOLS 1.79 + 1.80 +#undef SYMBOL 1.81 + 1.82 +void* 1.83 +LoadDTPerformanceLibraries(bool dontLoad) 1.84 +{ 1.85 + int flags = RTLD_LAZY | RTLD_LOCAL | RTLD_NODELETE; 1.86 + if (dontLoad) { 1.87 + flags |= RTLD_NOLOAD; 1.88 + } 1.89 + 1.90 + void *DTPerformanceLibrary = dlopen(DTPerformanceLibraryPath, flags); 1.91 + if (!DTPerformanceLibrary) { 1.92 + DTPerformanceLibrary = dlopen(OldDTPerformanceLibraryPath, flags); 1.93 + } 1.94 + return DTPerformanceLibrary; 1.95 +} 1.96 + 1.97 +bool 1.98 +LoadDTPerformanceLibrary() 1.99 +{ 1.100 + void *DTPerformanceLibrary = LoadDTPerformanceLibraries(true); 1.101 + if (!DTPerformanceLibrary) { 1.102 + DTPerformanceLibrary = LoadDTPerformanceLibraries(false); 1.103 + if (!DTPerformanceLibrary) { 1.104 + return false; 1.105 + } 1.106 + } 1.107 + 1.108 +#define SYMBOL(_sym) \ 1.109 + _sym = reinterpret_cast<_sym##Function>(dlsym(DTPerformanceLibrary, #_sym)); \ 1.110 + if (!_sym) { \ 1.111 + dlclose(DTPerformanceLibrary); \ 1.112 + DTPerformanceLibrary = nullptr; \ 1.113 + return false; \ 1.114 + } 1.115 + 1.116 + DTPERFORMANCE_SYMBOLS 1.117 + 1.118 +#undef SYMBOL 1.119 + 1.120 + dlclose(DTPerformanceLibrary); 1.121 + 1.122 + return true; 1.123 +} 1.124 + 1.125 +static DTPerformanceSessionRef gSession; 1.126 + 1.127 +bool 1.128 +Error(CFErrorRef error) 1.129 +{ 1.130 + if (gSession) { 1.131 + CFErrorRef unused = nullptr; 1.132 + DTPerformanceSessionStop(gSession, nullptr, &unused); 1.133 + CFRelease(gSession); 1.134 + gSession = nullptr; 1.135 + } 1.136 +#ifdef DEBUG 1.137 + AutoReleased<CFDataRef> data = 1.138 + CFStringCreateExternalRepresentation(nullptr, 1.139 + CFErrorCopyDescription(error), 1.140 + kCFStringEncodingUTF8, '?'); 1.141 + if (data != nullptr) { 1.142 + printf("%.*s\n\n", (int)CFDataGetLength(data), CFDataGetBytePtr(data)); 1.143 + } 1.144 +#endif 1.145 + return false; 1.146 +} 1.147 + 1.148 +bool 1.149 +Start(pid_t pid) 1.150 +{ 1.151 + if (gSession) { 1.152 + return false; 1.153 + } 1.154 + 1.155 + if (!LoadDTPerformanceLibrary()) { 1.156 + return false; 1.157 + } 1.158 + 1.159 + AutoReleased<CFStringRef> process = 1.160 + CFStringCreateWithFormat(kCFAllocatorDefault, nullptr, CFSTR("%d"), pid); 1.161 + if (!process) { 1.162 + return false; 1.163 + } 1.164 + CFErrorRef error = nullptr; 1.165 + gSession = DTPerformanceSessionCreate(nullptr, process, nullptr, &error); 1.166 + if (!gSession) { 1.167 + return Error(error); 1.168 + } 1.169 + 1.170 + AutoReleased<CFNumberRef> interval = 1.171 + CFNumberCreate(0, kCFNumberIntType, &kSamplingInterval); 1.172 + if (!interval) { 1.173 + return false; 1.174 + } 1.175 + CFStringRef keys[1] = { CFSTR(DTPerformanceSession_Option_SamplingInterval) }; 1.176 + CFNumberRef values[1] = { interval }; 1.177 + AutoReleased<CFDictionaryRef> options = 1.178 + CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, 1.179 + (const void**)values, 1, &kCFTypeDictionaryKeyCallBacks, 1.180 + &kCFTypeDictionaryValueCallBacks); 1.181 + if (!options) { 1.182 + return false; 1.183 + } 1.184 + 1.185 + if (!DTPerformanceSessionAddInstrument(gSession, 1.186 + CFSTR(DTPerformanceSession_TimeProfiler), 1.187 + options, nullptr, &error)) { 1.188 + return Error(error); 1.189 + } 1.190 + 1.191 + return Resume(); 1.192 +} 1.193 + 1.194 +void 1.195 +Pause() 1.196 +{ 1.197 + if (gSession && DTPerformanceSessionIsRecording(gSession)) { 1.198 + CFErrorRef error = nullptr; 1.199 + if (!DTPerformanceSessionStop(gSession, nullptr, &error)) { 1.200 + Error(error); 1.201 + } 1.202 + } 1.203 +} 1.204 + 1.205 +bool 1.206 +Resume() 1.207 +{ 1.208 + if (!gSession) { 1.209 + return false; 1.210 + } 1.211 + 1.212 + CFErrorRef error = nullptr; 1.213 + return DTPerformanceSessionStart(gSession, nullptr, &error) || 1.214 + Error(error); 1.215 +} 1.216 + 1.217 +void 1.218 +Stop(const char* profileName) 1.219 +{ 1.220 + Pause(); 1.221 + 1.222 + CFErrorRef error = nullptr; 1.223 + AutoReleased<CFStringRef> name = 1.224 + CFStringCreateWithFormat(kCFAllocatorDefault, nullptr, CFSTR("%s%s"), 1.225 + "/tmp/", profileName ? profileName : "mozilla"); 1.226 + if (!DTPerformanceSessionSave(gSession, name, &error)) { 1.227 + Error(error); 1.228 + return; 1.229 + } 1.230 + 1.231 + CFRelease(gSession); 1.232 + gSession = nullptr; 1.233 +} 1.234 + 1.235 +} // namespace Instruments 1.236 + 1.237 +#endif /* __APPLE__ */