tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Instruments.cpp (6232B)


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