DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * 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 "vtune/VTuneWrapper.h"

#include "mozilla/Sprintf.h"

#include "threading/LockGuard.h"
#include "threading/Mutex.h"
#include "vm/JSContext.h"
#include "vm/MutexIDs.h"
#include "vm/Realm.h"
#include "vm/Shape.h"

#ifdef MOZ_VTUNE

namespace js {
namespace vtune {

// VTune internals are not known to be threadsafe.
static Mutex* VTuneMutex = nullptr;

// Firefox must be launched from within VTune. Then the profiler
// status never changes, and we can avoid shared library checks.
static bool VTuneLoaded(false);

// Initialization is called from a single-threaded context.
bool Initialize() {
  VTuneMutex = js_new<Mutex>(mutexid::VTuneLock);
  if (!VTuneMutex) return false;

  // Load the VTune shared library, if present.
  int loaded = loadiJIT_Funcs();
  if (loaded == 1) VTuneLoaded = true;

  return true;
}

// Shutdown is called froma single-threaded context.
void Shutdown() {
  js_delete(VTuneMutex);
  VTuneMutex = nullptr;
}

bool IsProfilingActive() {
  // Checking VTuneLoaded guards against VTune internals attempting
  // to load the VTune library upon their invocation.
  return VTuneLoaded && iJIT_IsProfilingActive() == iJIT_SAMPLING_ON;
}

uint32_t GenerateUniqueMethodID() {
  // iJIT_GetNewMethodID() is explicitly not threadsafe.
  MOZ_ASSERT(VTuneMutex);
  LockGuard<Mutex> guard(*VTuneMutex);
  return (uint32_t)iJIT_GetNewMethodID();
}

static int SafeNotifyEvent(iJIT_JVM_EVENT event_type, void* data) {
  MOZ_ASSERT(VTuneMutex);
  LockGuard<Mutex> guard(*VTuneMutex);
  return iJIT_NotifyEvent(event_type, data);
}

// Stubs and trampolines are created on engine initialization and are never
// unloaded.
void MarkStub(const js::jit::JitCode* code, const char* name) {
  if (!IsProfilingActive()) return;

  iJIT_Method_Load_V2 method = {0};
  method.method_id = GenerateUniqueMethodID();
  method.method_name = const_cast<char*>(name);
  method.method_load_address = code->raw();
  method.method_size = code->instructionsSize();
  method.module_name = const_cast<char*>("jitstubs");

  int ok =
      SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
  if (ok != 1) printf("[!] VTune Integration: Failed to load method.\n");
}

void MarkRegExp(const js::jit::JitCode* code, bool match_only) {
  if (!IsProfilingActive()) return;

  iJIT_Method_Load_V2 method = {0};
  method.method_id = GenerateUniqueMethodID();
  method.method_load_address = code->raw();
  method.method_size = code->instructionsSize();

  if (match_only)
    method.method_name = const_cast<char*>("regexp (match-only)");
  else
    method.method_name = const_cast<char*>("regexp (normal)");

  method.module_name = const_cast<char*>("irregexp");

  int ok =
      SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
  if (ok != 1) printf("[!] VTune Integration: Failed to load method.\n");
}

void MarkScript(const js::jit::JitCode* code, JSScript* script,
                const char* module) {
  if (!IsProfilingActive()) return;

  iJIT_Method_Load_V2 method = {0};
  method.method_id = script->vtuneMethodID();
  method.method_load_address = code->raw();
  method.method_size = code->instructionsSize();
  method.module_name = const_cast<char*>(module);

  // Line numbers begin at 1, but columns begin at 0.
  // Text editors start at 1,1 so fixup is performed to match.
  char namebuf[512];
  SprintfLiteral(namebuf, "%s:%u:%u", script->filename(), script->lineno(),
                 script->column() + 1);

  method.method_name = &namebuf[0];

  int ok =
      SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
  if (ok != 1) printf("[!] VTune Integration: Failed to load method.\n");
}

void MarkWasm(unsigned methodId, const char* name, void* start,
              uintptr_t size) {
  if (!IsProfilingActive()) return;

  iJIT_Method_Load_V2 method = {0};
  method.method_id = methodId;
  method.method_name = const_cast<char*>(name);
  method.method_load_address = start;
  method.method_size = (unsigned)size;
  method.module_name = const_cast<char*>("wasm");

  int ok =
      SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, (void*)&method);
  if (ok != 1) printf("[!] VTune Integration: Failed to load method.\n");
}

void UnmarkCode(const js::jit::JitCode* code) {
  UnmarkBytes(code->raw(), (unsigned)code->instructionsSize());
}

void UnmarkBytes(void* bytes, unsigned size) {
  if (!IsProfilingActive()) return;

  // It appears that the method_id is not required for unloading.
  iJIT_Method_Load method = {0};
  method.method_load_address = bytes;
  method.method_size = size;

  // The iJVM_EVENT_TYPE_METHOD_UNLOAD_START event is undocumented.
  // VTune appears to happily accept unload events even for untracked JitCode.
  int ok = SafeNotifyEvent(iJVM_EVENT_TYPE_METHOD_UNLOAD_START, (void*)&method);

  // Assertions aren't reported in VTune: instead, they immediately end
  // profiling with no warning that a crash occurred. This can generate
  // misleading profiles. So instead, print out a message to stdout (which VTune
  // does not redirect).
  if (ok != 1) printf("[!] VTune Integration: Failed to unload method.\n");
}

}  // namespace vtune
}  // namespace js

#endif  // MOZ_VTUNE