Bug 1439014 - Add a profiler feature to enable JIT optimization tracking. r?sfink, r?njn
MozReview-Commit-ID: LDxiLVp7e9v
--- a/browser/components/extensions/schemas/geckoProfiler.json
+++ b/browser/components/extensions/schemas/geckoProfiler.json
@@ -27,17 +27,18 @@
"js",
"leaf",
"mainthreadio",
"memory",
"privacy",
"restyle",
"stackwalk",
"tasktracer",
- "threads"
+ "threads",
+ "trackopts"
]
}
],
"functions": [
{
"name": "start",
"type": "function",
"description": "Starts the profiler with the specified settings.",
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -7255,16 +7255,19 @@ JS_SetGlobalJitCompilerOption(JSContext*
break;
case JSJITCOMPILER_JUMP_THRESHOLD:
if (value == uint32_t(-1)) {
jit::DefaultJitOptions defaultValues;
value = defaultValues.jumpThreshold;
}
jit::JitOptions.jumpThreshold = value;
break;
+ case JSJITCOMPILER_TRACK_OPTIMIZATIONS:
+ jit::JitOptions.disableOptimizationTracking = !value;
+ break;
case JSJITCOMPILER_SPECTRE_INDEX_MASKING:
jit::JitOptions.spectreIndexMasking = !!value;
break;
case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS_BARRIERS:
jit::JitOptions.spectreObjectMitigationsBarriers = !!value;
break;
case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS_MISC:
jit::JitOptions.spectreObjectMitigationsMisc = !!value;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5862,16 +5862,17 @@ JS_SetOffthreadIonCompilationEnabled(JSC
Register(ION_FORCE_IC, "ion.forceinlineCaches") \
Register(ION_ENABLE, "ion.enable") \
Register(ION_INTERRUPT_WITHOUT_SIGNAL, "ion.interrupt-without-signals") \
Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \
Register(BASELINE_ENABLE, "baseline.enable") \
Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
Register(FULL_DEBUG_CHECKS, "jit.full-debug-checks") \
Register(JUMP_THRESHOLD, "jump-threshold") \
+ Register(TRACK_OPTIMIZATIONS, "jit.track-optimizations") \
Register(SIMULATOR_ALWAYS_INTERRUPT, "simulator.always-interrupt") \
Register(SPECTRE_INDEX_MASKING, "spectre.index-masking") \
Register(SPECTRE_OBJECT_MITIGATIONS_BARRIERS, "spectre.object-mitigations.barriers") \
Register(SPECTRE_OBJECT_MITIGATIONS_MISC, "spectre.object-mitigations.misc") \
Register(SPECTRE_STRING_MITIGATIONS, "spectre.string-mitigations") \
Register(SPECTRE_VALUE_MASKING, "spectre.value-masking") \
Register(SPECTRE_JIT_TO_CXX_CALLS, "spectre.jit-to-C++-calls") \
Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \
--- a/tools/profiler/core/RegisteredThread.cpp
+++ b/tools/profiler/core/RegisteredThread.cpp
@@ -10,16 +10,17 @@ RegisteredThread::RegisteredThread(Threa
void* aStackTop)
: mRacyRegisteredThread(aInfo->ThreadId())
, mPlatformData(AllocPlatformData(aInfo->ThreadId()))
, mStackTop(aStackTop)
, mThreadInfo(aInfo)
, mThread(aThread)
, mContext(nullptr)
, mJSSampling(INACTIVE)
+ , mJSTrackOptimizations(false)
{
MOZ_COUNT_CTOR(RegisteredThread);
// We don't have to guess on mac
#if defined(GP_OS_darwin)
pthread_t self = pthread_self();
mStackTop = pthread_get_stackaddr_np(self);
#endif
--- a/tools/profiler/core/RegisteredThread.h
+++ b/tools/profiler/core/RegisteredThread.h
@@ -192,23 +192,24 @@ public:
JSContext* GetJSContext() const { return mContext; }
const RefPtr<ThreadInfo> Info() const { return mThreadInfo; }
const nsCOMPtr<nsIEventTarget> GetEventTarget() const { return mThread; }
// Request that this thread start JS sampling. JS sampling won't actually
// start until a subsequent PollJSSampling() call occurs *and* mContext has
// been set.
- void StartJSSampling()
+ void StartJSSampling(bool aTrackOptimizations)
{
// This function runs on-thread or off-thread.
MOZ_RELEASE_ASSERT(mJSSampling == INACTIVE ||
mJSSampling == INACTIVE_REQUESTED);
mJSSampling = ACTIVE_REQUESTED;
+ mJSTrackOptimizations = aTrackOptimizations;
}
// Request that this thread stop JS sampling. JS sampling won't actually stop
// until a subsequent PollJSSampling() call occurs.
void StopJSSampling()
{
// This function runs on-thread or off-thread.
@@ -231,16 +232,18 @@ public:
// - ACTIVE, INACTIVE_REQUESTED, ACTIVE_REQUESTED, ACTIVE
//
// Therefore, the if and else branches here aren't always interleaved.
// This is ok because the JS engine can handle that.
//
if (mJSSampling == ACTIVE_REQUESTED) {
mJSSampling = ACTIVE;
js::EnableContextProfilingStack(mContext, true);
+ JS_SetGlobalJitCompilerOption(mContext, JSJITCOMPILER_TRACK_OPTIMIZATIONS,
+ mJSTrackOptimizations);
js::RegisterContextProfilingEventMarker(mContext, profiler_add_marker);
} else if (mJSSampling == INACTIVE_REQUESTED) {
mJSSampling = INACTIVE;
js::EnableContextProfilingStack(mContext, false);
}
}
}
@@ -299,11 +302,13 @@ private:
// to actually happen.
//
enum {
INACTIVE = 0,
ACTIVE_REQUESTED = 1,
ACTIVE = 2,
INACTIVE_REQUESTED = 3,
} mJSSampling;
+
+ bool mJSTrackOptimizations;
};
#endif // RegisteredThread_h
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -2248,17 +2248,18 @@ locked_register_thread(PSLockRef aLock,
nsCOMPtr<nsIEventTarget> eventTarget = registeredThread->GetEventTarget();
ProfiledThreadData* profiledThreadData =
ActivePS::AddLiveProfiledThread(aLock, registeredThread.get(),
MakeUnique<ProfiledThreadData>(info, eventTarget));
if (ActivePS::FeatureJS(aLock)) {
// This StartJSSampling() call is on-thread, so we can poll manually to
// start JS sampling immediately.
- registeredThread->StartJSSampling();
+ registeredThread->StartJSSampling(
+ ActivePS::FeatureTrackOptimizations(aLock));
registeredThread->PollJSSampling();
if (registeredThread->GetJSContext()) {
profiledThreadData->NotifyReceivedJSContext(ActivePS::Buffer(aLock).mRangeEnd);
}
}
}
CorePS::AppendRegisteredThread(aLock, Move(registeredThread));
@@ -2847,17 +2848,18 @@ locked_profiler_start(PSLockRef aLock, u
RefPtr<ThreadInfo> info = registeredThread->Info();
if (ActivePS::ShouldProfileThread(aLock, info)) {
nsCOMPtr<nsIEventTarget> eventTarget = registeredThread->GetEventTarget();
ProfiledThreadData* profiledThreadData =
ActivePS::AddLiveProfiledThread(aLock, registeredThread.get(),
MakeUnique<ProfiledThreadData>(info, eventTarget));
if (ActivePS::FeatureJS(aLock)) {
- registeredThread->StartJSSampling();
+ registeredThread->StartJSSampling(
+ ActivePS::FeatureTrackOptimizations(aLock));
if (info->ThreadId() == tid) {
// We can manually poll the current thread so it starts sampling
// immediately.
registeredThread->PollJSSampling();
} else if (info->IsMainThread()) {
// Dispatch a runnable to the main thread to call PollJSSampling(),
// so that we don't have wait for the next JS interrupt callback in
// order to start profiling JS.
@@ -3475,17 +3477,18 @@ profiler_clear_js_context()
// nulling out the JSContext.
registeredThread->StopJSSampling();
registeredThread->PollJSSampling();
registeredThread->ClearJSContext();
// Tell the thread that we'd like to have JS sampling on this
// thread again, once it gets a new JSContext (if ever).
- registeredThread->StartJSSampling();
+ registeredThread->StartJSSampling(
+ ActivePS::FeatureTrackOptimizations(lock));
return;
}
}
registeredThread->ClearJSContext();
}
int
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -123,17 +123,20 @@ class TimeStamp;
\
/* Walk the C++ stack. Not available on all platforms. */ \
macro(7, "stackwalk", StackWalk) \
\
/* Start profiling with feature TaskTracer. */ \
macro(8, "tasktracer", TaskTracer) \
\
/* Profile the registered secondary threads. */ \
- macro(9, "threads", Threads)
+ macro(9, "threads", Threads) \
+ \
+ /* Have the JavaScript engine track JIT optimizations. */ \
+ macro(10, "trackopts", TrackOptimizations)
struct ProfilerFeature
{
#define DECLARE(n_, str_, Name_) \
static const uint32_t Name_ = (1u << n_); \
static bool Has##Name_(uint32_t aFeatures) { return aFeatures & Name_; } \
static void Set##Name_(uint32_t& aFeatures) { aFeatures |= Name_; } \
static void Clear##Name_(uint32_t& aFeatures) { aFeatures &= ~Name_; }