tor-browser

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

VTuneWrapper.cpp (5441B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "vtune/VTuneWrapper.h"
      8 
      9 #include "mozilla/Sprintf.h"
     10 
     11 #include "jit/JitCode.h"
     12 #include "js/Utility.h"
     13 #include "threading/LockGuard.h"
     14 #include "threading/Mutex.h"
     15 #include "vm/JSScript.h"
     16 #include "vm/MutexIDs.h"
     17 #include "vtune/jitprofiling.h"
     18 
     19 namespace js::vtune {
     20 
     21 // VTune internals are not known to be threadsafe.
     22 static Mutex* VTuneMutex = nullptr;
     23 
     24 // Firefox must be launched from within VTune. Then the profiler
     25 // status never changes, and we can avoid shared library checks.
     26 static bool VTuneLoaded(false);
     27 
     28 // Initialization is called from a single-threaded context.
     29 bool Initialize() {
     30  VTuneMutex = js_new<Mutex>(mutexid::VTuneLock);
     31  if (!VTuneMutex) return false;
     32 
     33  if (getenv("JS_LOAD_VTUNE_LIB")) {
     34    // Load the VTune shared library, if present.
     35    int loaded = loadiJIT_Funcs();
     36    if (loaded == 1) VTuneLoaded = true;
     37  }
     38 
     39  return true;
     40 }
     41 
     42 // Shutdown is called froma single-threaded context.
     43 void Shutdown() {
     44  js_delete(VTuneMutex);
     45  VTuneMutex = nullptr;
     46 }
     47 
     48 bool IsProfilingActive() {
     49  // Checking VTuneLoaded guards against VTune internals attempting
     50  // to load the VTune library upon their invocation.
     51  return VTuneLoaded && iJIT_IsProfilingActive() == iJIT_SAMPLING_ON;
     52 }
     53 
     54 uint32_t GenerateUniqueMethodID() {
     55  // iJIT_GetNewMethodID() is explicitly not threadsafe.
     56  MOZ_ASSERT(VTuneMutex);
     57  LockGuard<Mutex> guard(*VTuneMutex);
     58  return (uint32_t)iJIT_GetNewMethodID();
     59 }
     60 
     61 static int SafeNotifyEvent(iJIT_JVM_EVENT event_type, void* data) {
     62  MOZ_ASSERT(VTuneMutex);
     63  LockGuard<Mutex> guard(*VTuneMutex);
     64  return iJIT_NotifyEvent(event_type, data);
     65 }
     66 
     67 // Stubs and trampolines are created on engine initialization and are never
     68 // unloaded.
     69 void MarkStub(const js::jit::JitCode* code, const char* name) {
     70  if (!IsProfilingActive()) return;
     71 
     72  iJIT_Method_Load_V2 method = {0};
     73  method.method_id = GenerateUniqueMethodID();
     74  method.method_name = const_cast<char*>(name);
     75  method.method_load_address = code->raw();
     76  method.method_size = code->instructionsSize();
     77  method.module_name = const_cast<char*>("jitstubs");
     78 
     79  int ok =
     80      SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
     81  if (ok != 1) printf("[!] VTune Integration: Failed to load method.\n");
     82 }
     83 
     84 void MarkRegExp(const js::jit::JitCode* code, bool match_only) {
     85  if (!IsProfilingActive()) return;
     86 
     87  iJIT_Method_Load_V2 method = {0};
     88  method.method_id = GenerateUniqueMethodID();
     89  method.method_load_address = code->raw();
     90  method.method_size = code->instructionsSize();
     91 
     92  if (match_only)
     93    method.method_name = const_cast<char*>("regexp (match-only)");
     94  else
     95    method.method_name = const_cast<char*>("regexp (normal)");
     96 
     97  method.module_name = const_cast<char*>("irregexp");
     98 
     99  int ok =
    100      SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
    101  if (ok != 1) printf("[!] VTune Integration: Failed to load method.\n");
    102 }
    103 
    104 void MarkScript(const js::jit::JitCode* code, JSScript* script,
    105                const char* module) {
    106  if (!IsProfilingActive()) return;
    107 
    108  iJIT_Method_Load_V2 method = {0};
    109  method.method_id = script->vtuneMethodID();
    110  method.method_load_address = code->raw();
    111  method.method_size = code->instructionsSize();
    112  method.module_name = const_cast<char*>(module);
    113 
    114  char namebuf[512];
    115  SprintfLiteral(namebuf, "%s:%u:%u", script->filename(), script->lineno(),
    116                 script->column().oneOriginValue());
    117 
    118  method.method_name = &namebuf[0];
    119 
    120  int ok =
    121      SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
    122  if (ok != 1) printf("[!] VTune Integration: Failed to load method.\n");
    123 }
    124 
    125 void MarkWasm(unsigned methodId, const char* name, void* start,
    126              uintptr_t size) {
    127  if (!IsProfilingActive()) return;
    128 
    129  iJIT_Method_Load_V2 method = {0};
    130  method.method_id = methodId;
    131  method.method_name = const_cast<char*>(name);
    132  method.method_load_address = start;
    133  method.method_size = (unsigned)size;
    134  method.module_name = const_cast<char*>("wasm");
    135 
    136  int ok =
    137      SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
    138  if (ok != 1) printf("[!] VTune Integration: Failed to load method.\n");
    139 }
    140 
    141 void UnmarkCode(const js::jit::JitCode* code) {
    142  UnmarkBytes(code->raw(), (unsigned)code->instructionsSize());
    143 }
    144 
    145 void UnmarkBytes(void* bytes, unsigned size) {
    146  if (!IsProfilingActive()) return;
    147 
    148  // It appears that the method_id is not required for unloading.
    149  iJIT_Method_Load method = {0};
    150  method.method_load_address = bytes;
    151  method.method_size = size;
    152 
    153  // The iJVM_EVENT_TYPE_METHOD_UNLOAD_START event is undocumented.
    154  // VTune appears to happily accept unload events even for untracked JitCode.
    155  int ok = SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, (void*)&method);
    156 
    157  // Assertions aren't reported in VTune: instead, they immediately end
    158  // profiling with no warning that a crash occurred. This can generate
    159  // misleading profiles. So instead, print out a message to stdout (which VTune
    160  // does not redirect).
    161  if (ok != 1) printf("[!] VTune Integration: Failed to unload method.\n");
    162 }
    163 
    164 }  // namespace js::vtune