summaryrefslogtreecommitdiffstats
path: root/js/src/devtools/Instruments.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /js/src/devtools/Instruments.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/devtools/Instruments.cpp')
-rw-r--r--js/src/devtools/Instruments.cpp235
1 files changed, 235 insertions, 0 deletions
diff --git a/js/src/devtools/Instruments.cpp b/js/src/devtools/Instruments.cpp
new file mode 100644
index 000000000..7a69cac07
--- /dev/null
+++ b/js/src/devtools/Instruments.cpp
@@ -0,0 +1,235 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Instruments.h"
+#include "mozilla/Attributes.h"
+
+#ifdef __APPLE__
+
+#include <dlfcn.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <unistd.h>
+
+// There are now 2 paths to the DTPerformanceSession framework. We try to load
+// the one contained in /Applications/Xcode.app first, falling back to the one
+// contained in /Library/Developer/4.0/Instruments.
+#define DTPerformanceLibraryPath "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/DTPerformanceSession.framework/Versions/Current/DTPerformanceSession"
+#define OldDTPerformanceLibraryPath "/Library/Developer/4.0/Instruments/Frameworks/DTPerformanceSession.framework/Versions/Current/DTPerformanceSession"
+
+extern "C" {
+
+typedef CFTypeRef DTPerformanceSessionRef;
+
+#define DTPerformanceSession_TimeProfiler "com.apple.instruments.dtps.timeprofiler"
+// DTPerformanceSession_Option_SamplingInterval is measured in microseconds
+#define DTPerformanceSession_Option_SamplingInterval "com.apple.instruments.dtps.option.samplinginterval"
+
+typedef void (*dtps_errorcallback_t)(CFStringRef, CFErrorRef);
+typedef DTPerformanceSessionRef (*DTPerformanceSessionCreateFunction)(CFStringRef, CFStringRef, CFDictionaryRef, CFErrorRef*);
+typedef bool (*DTPerformanceSessionAddInstrumentFunction)(DTPerformanceSessionRef, CFStringRef, CFDictionaryRef, dtps_errorcallback_t, CFErrorRef*);
+typedef bool (*DTPerformanceSessionIsRecordingFunction)(DTPerformanceSessionRef);
+typedef bool (*DTPerformanceSessionStartFunction)(DTPerformanceSessionRef, CFArrayRef, CFErrorRef*);
+typedef bool (*DTPerformanceSessionStopFunction)(DTPerformanceSessionRef, CFArrayRef, CFErrorRef*);
+typedef bool (*DTPerformanceSessionSaveFunction)(DTPerformanceSessionRef, CFStringRef, CFErrorRef*);
+
+} // extern "C"
+
+namespace Instruments {
+
+static const int kSamplingInterval = 20; // microseconds
+
+template<typename T>
+class AutoReleased
+{
+public:
+ MOZ_IMPLICIT AutoReleased(T aTypeRef) : mTypeRef(aTypeRef)
+ {
+ }
+ ~AutoReleased()
+ {
+ if (mTypeRef) {
+ CFRelease(mTypeRef);
+ }
+ }
+
+ operator T()
+ {
+ return mTypeRef;
+ }
+
+private:
+ T mTypeRef;
+};
+
+#define DTPERFORMANCE_SYMBOLS \
+ SYMBOL(DTPerformanceSessionCreate) \
+ SYMBOL(DTPerformanceSessionAddInstrument) \
+ SYMBOL(DTPerformanceSessionIsRecording) \
+ SYMBOL(DTPerformanceSessionStart) \
+ SYMBOL(DTPerformanceSessionStop) \
+ SYMBOL(DTPerformanceSessionSave)
+
+#define SYMBOL(_sym) \
+ _sym##Function _sym = nullptr;
+
+DTPERFORMANCE_SYMBOLS
+
+#undef SYMBOL
+
+void*
+LoadDTPerformanceLibraries(bool dontLoad)
+{
+ int flags = RTLD_LAZY | RTLD_LOCAL | RTLD_NODELETE;
+ if (dontLoad) {
+ flags |= RTLD_NOLOAD;
+ }
+
+ void* DTPerformanceLibrary = dlopen(DTPerformanceLibraryPath, flags);
+ if (!DTPerformanceLibrary) {
+ DTPerformanceLibrary = dlopen(OldDTPerformanceLibraryPath, flags);
+ }
+ return DTPerformanceLibrary;
+}
+
+bool
+LoadDTPerformanceLibrary()
+{
+ void* DTPerformanceLibrary = LoadDTPerformanceLibraries(true);
+ if (!DTPerformanceLibrary) {
+ DTPerformanceLibrary = LoadDTPerformanceLibraries(false);
+ if (!DTPerformanceLibrary) {
+ return false;
+ }
+ }
+
+#define SYMBOL(_sym) \
+ _sym = reinterpret_cast<_sym##Function>(dlsym(DTPerformanceLibrary, #_sym)); \
+ if (!_sym) { \
+ dlclose(DTPerformanceLibrary); \
+ DTPerformanceLibrary = nullptr; \
+ return false; \
+ }
+
+ DTPERFORMANCE_SYMBOLS
+
+#undef SYMBOL
+
+ dlclose(DTPerformanceLibrary);
+
+ return true;
+}
+
+static DTPerformanceSessionRef gSession;
+
+bool
+Error(CFErrorRef error)
+{
+ if (gSession) {
+ CFErrorRef unused = nullptr;
+ DTPerformanceSessionStop(gSession, nullptr, &unused);
+ CFRelease(gSession);
+ gSession = nullptr;
+ }
+#ifdef DEBUG
+ AutoReleased<CFDataRef> data =
+ CFStringCreateExternalRepresentation(nullptr,
+ CFErrorCopyDescription(error),
+ kCFStringEncodingUTF8, '?');
+ if (data != nullptr) {
+ printf("%.*s\n\n", (int)CFDataGetLength(data), CFDataGetBytePtr(data));
+ }
+#endif
+ return false;
+}
+
+bool
+Start(pid_t pid)
+{
+ if (gSession) {
+ return false;
+ }
+
+ if (!LoadDTPerformanceLibrary()) {
+ return false;
+ }
+
+ AutoReleased<CFStringRef> process =
+ CFStringCreateWithFormat(kCFAllocatorDefault, nullptr, CFSTR("%d"), pid);
+ if (!process) {
+ return false;
+ }
+ CFErrorRef error = nullptr;
+ gSession = DTPerformanceSessionCreate(nullptr, process, nullptr, &error);
+ if (!gSession) {
+ return Error(error);
+ }
+
+ AutoReleased<CFNumberRef> interval =
+ CFNumberCreate(0, kCFNumberIntType, &kSamplingInterval);
+ if (!interval) {
+ return false;
+ }
+ CFStringRef keys[1] = { CFSTR(DTPerformanceSession_Option_SamplingInterval) };
+ CFNumberRef values[1] = { interval };
+ AutoReleased<CFDictionaryRef> options =
+ CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys,
+ (const void**)values, 1, &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ if (!options) {
+ return false;
+ }
+
+ if (!DTPerformanceSessionAddInstrument(gSession,
+ CFSTR(DTPerformanceSession_TimeProfiler),
+ options, nullptr, &error)) {
+ return Error(error);
+ }
+
+ return Resume();
+}
+
+void
+Pause()
+{
+ if (gSession && DTPerformanceSessionIsRecording(gSession)) {
+ CFErrorRef error = nullptr;
+ if (!DTPerformanceSessionStop(gSession, nullptr, &error)) {
+ Error(error);
+ }
+ }
+}
+
+bool
+Resume()
+{
+ if (!gSession) {
+ return false;
+ }
+
+ CFErrorRef error = nullptr;
+ return DTPerformanceSessionStart(gSession, nullptr, &error) ||
+ Error(error);
+}
+
+void
+Stop(const char* profileName)
+{
+ Pause();
+
+ CFErrorRef error = nullptr;
+ AutoReleased<CFStringRef> name =
+ CFStringCreateWithFormat(kCFAllocatorDefault, nullptr, CFSTR("%s%s"),
+ "/tmp/", profileName ? profileName : "mozilla");
+ if (!DTPerformanceSessionSave(gSession, name, &error)) {
+ Error(error);
+ return;
+ }
+
+ CFRelease(gSession);
+ gSession = nullptr;
+}
+
+} // namespace Instruments
+
+#endif /* __APPLE__ */