зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1334927 - Handle multiple contexts per runtime in the Gecko profiler, r=shu.
--HG-- extra : rebase_source : 8673bc042c7d04b5595583c229a13a1e18b7f73e
This commit is contained in:
Родитель
6cce3a3af9
Коммит
3601646de2
|
@ -46,7 +46,7 @@ struct ForEachTrackedOptimizationTypeInfoOp;
|
|||
// contents to become out of date.
|
||||
class JS_PUBLIC_API(ProfilingFrameIterator)
|
||||
{
|
||||
JSRuntime* rt_;
|
||||
JSContext* cx_;
|
||||
uint32_t sampleBufferGen_;
|
||||
js::Activation* activation_;
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ CompileRuntime::wellKnownSymbols()
|
|||
const void*
|
||||
CompileRuntime::addressOfActiveJSContext()
|
||||
{
|
||||
return &runtime()->activeContext;
|
||||
return runtime()->addressOfActiveContext();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -284,7 +284,7 @@ class JitProfilingFrameIterator
|
|||
void moveToNextFrame(CommonFrameLayout* frame);
|
||||
|
||||
public:
|
||||
JitProfilingFrameIterator(JSRuntime* rt,
|
||||
JitProfilingFrameIterator(JSContext* cx,
|
||||
const JS::ProfilingFrameIterator::RegisterState& state);
|
||||
explicit JitProfilingFrameIterator(void* exitFrame);
|
||||
|
||||
|
|
|
@ -2832,11 +2832,10 @@ JitFrameIterator::verifyReturnAddressUsingNativeToBytecodeMap()
|
|||
#endif // DEBUG
|
||||
|
||||
JitProfilingFrameIterator::JitProfilingFrameIterator(
|
||||
JSRuntime* rt, const JS::ProfilingFrameIterator::RegisterState& state)
|
||||
JSContext* cx, const JS::ProfilingFrameIterator::RegisterState& state)
|
||||
{
|
||||
// If no profilingActivation is live, initialize directly to
|
||||
// end-of-iteration state.
|
||||
JSContext* cx = rt->unsafeContextFromAnyThread();
|
||||
if (!cx->profilingActivation()) {
|
||||
type_ = JitFrame_Entry;
|
||||
fp_ = nullptr;
|
||||
|
@ -2862,7 +2861,7 @@ JitProfilingFrameIterator::JitProfilingFrameIterator(
|
|||
fp_ = (uint8_t*) act->lastProfilingFrame();
|
||||
void* lastCallSite = act->lastProfilingCallSite();
|
||||
|
||||
JitcodeGlobalTable* table = rt->jitRuntime()->getJitcodeGlobalTable();
|
||||
JitcodeGlobalTable* table = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
|
||||
|
||||
// Profiler sampling must NOT be suppressed if we are here.
|
||||
MOZ_ASSERT(cx->isProfilerSamplingEnabled());
|
||||
|
@ -2872,7 +2871,7 @@ JitProfilingFrameIterator::JitProfilingFrameIterator(
|
|||
return;
|
||||
|
||||
// Try initializing with sampler pc using native=>bytecode table.
|
||||
if (tryInitWithTable(table, state.pc, rt, /* forLastCallSite = */ false))
|
||||
if (tryInitWithTable(table, state.pc, cx->runtime(), /* forLastCallSite = */ false))
|
||||
return;
|
||||
|
||||
// Try initializing with lastProfilingCallSite pc
|
||||
|
@ -2881,7 +2880,7 @@ JitProfilingFrameIterator::JitProfilingFrameIterator(
|
|||
return;
|
||||
|
||||
// Try initializing with lastProfilingCallSite pc using native=>bytecode table.
|
||||
if (tryInitWithTable(table, lastCallSite, rt, /* forLastCallSite = */ true))
|
||||
if (tryInitWithTable(table, lastCallSite, cx->runtime(), /* forLastCallSite = */ true))
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "vm/GeckoProfiler-inl.h"
|
||||
#include "vm/TypeInference-inl.h"
|
||||
|
||||
using mozilla::Maybe;
|
||||
|
|
|
@ -243,6 +243,7 @@
|
|||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "gc/Heap-inl.h"
|
||||
#include "vm/GeckoProfiler-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
#include "vm/String-inl.h"
|
||||
|
||||
|
@ -5517,7 +5518,7 @@ GCRuntime::compactPhase(JS::gcreason::Reason reason, SliceBudget& sliceBudget,
|
|||
// middle of relocating an arena, invalid JSScript pointers may be
|
||||
// accessed. Suppress all sampling until a finer-grained solution can be
|
||||
// found. See bug 1295775.
|
||||
AutoSuppressProfilerSampling suppressSampling(rt);
|
||||
AutoSuppressProfilerSampling suppressSampling(TlsContext.get());
|
||||
|
||||
ZoneList relocatedZones;
|
||||
Arena* relocatedArenas = nullptr;
|
||||
|
|
|
@ -47,7 +47,7 @@ CheckActiveThread<Background>::check() const
|
|||
return;
|
||||
|
||||
JSContext* cx = TlsContext.get();
|
||||
MOZ_ASSERT(cx == cx->runtime()->activeContext);
|
||||
MOZ_ASSERT(cx == cx->runtime()->activeContext());
|
||||
#endif // XP_WIN
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "jsopcodeinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "vm/GeckoProfiler-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* 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/. */
|
||||
|
||||
#ifndef vm_GeckoProfiler_inl_h
|
||||
#define vm_GeckoProfiler_inl_h
|
||||
|
||||
#include "vm/GeckoProfiler.h"
|
||||
|
||||
#include "vm/Runtime.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* This class is used to suppress profiler sampling during
|
||||
* critical sections where stack state is not valid.
|
||||
*/
|
||||
class MOZ_RAII AutoSuppressProfilerSampling
|
||||
{
|
||||
public:
|
||||
explicit AutoSuppressProfilerSampling(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
|
||||
~AutoSuppressProfilerSampling();
|
||||
|
||||
private:
|
||||
JSContext* cx_;
|
||||
bool previouslyEnabled_;
|
||||
JSRuntime::AutoProhibitActiveContextChange prohibitContextChange_;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // vm_GeckoProfiler_inl_h
|
|
@ -4,7 +4,7 @@
|
|||
* 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 "vm/GeckoProfiler.h"
|
||||
#include "vm/GeckoProfiler-inl.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
|
@ -86,10 +86,13 @@ GeckoProfiler::enable(bool enabled)
|
|||
rt->resetProfilerSampleBufferGen();
|
||||
rt->resetProfilerSampleBufferLapCount();
|
||||
|
||||
// Ensure that lastProfilingFrame is null before 'enabled' becomes true.
|
||||
if (rt->contextFromMainThread()->jitActivation) {
|
||||
rt->contextFromMainThread()->jitActivation->setLastProfilingFrame(nullptr);
|
||||
rt->contextFromMainThread()->jitActivation->setLastProfilingCallSite(nullptr);
|
||||
// Ensure that lastProfilingFrame is null for all threads before 'enabled' becomes true.
|
||||
for (size_t i = 0; i < rt->cooperatingContexts().length(); i++) {
|
||||
JSContext* cx = rt->cooperatingContexts()[i];
|
||||
if (cx->jitActivation) {
|
||||
cx->jitActivation->setLastProfilingFrame(nullptr);
|
||||
cx->jitActivation->setLastProfilingCallSite(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
enabled_ = enabled;
|
||||
|
@ -104,24 +107,27 @@ GeckoProfiler::enable(bool enabled)
|
|||
/* Update lastProfilingFrame to point to the top-most JS jit-frame currently on
|
||||
* stack.
|
||||
*/
|
||||
if (rt->contextFromMainThread()->jitActivation) {
|
||||
// Walk through all activations, and set their lastProfilingFrame appropriately.
|
||||
if (enabled) {
|
||||
void* lastProfilingFrame = GetTopProfilingJitFrame(rt->contextFromMainThread()->jitTop);
|
||||
jit::JitActivation* jitActivation = rt->contextFromMainThread()->jitActivation;
|
||||
while (jitActivation) {
|
||||
jitActivation->setLastProfilingFrame(lastProfilingFrame);
|
||||
jitActivation->setLastProfilingCallSite(nullptr);
|
||||
for (size_t i = 0; i < rt->cooperatingContexts().length(); i++) {
|
||||
JSContext* cx = rt->cooperatingContexts()[i];
|
||||
if (cx->jitActivation) {
|
||||
// Walk through all activations, and set their lastProfilingFrame appropriately.
|
||||
if (enabled) {
|
||||
void* lastProfilingFrame = GetTopProfilingJitFrame(cx->jitTop);
|
||||
jit::JitActivation* jitActivation = cx->jitActivation;
|
||||
while (jitActivation) {
|
||||
jitActivation->setLastProfilingFrame(lastProfilingFrame);
|
||||
jitActivation->setLastProfilingCallSite(nullptr);
|
||||
|
||||
lastProfilingFrame = GetTopProfilingJitFrame(jitActivation->prevJitTop());
|
||||
jitActivation = jitActivation->prevJitActivation();
|
||||
}
|
||||
} else {
|
||||
jit::JitActivation* jitActivation = rt->contextFromMainThread()->jitActivation;
|
||||
while (jitActivation) {
|
||||
jitActivation->setLastProfilingFrame(nullptr);
|
||||
jitActivation->setLastProfilingCallSite(nullptr);
|
||||
jitActivation = jitActivation->prevJitActivation();
|
||||
lastProfilingFrame = GetTopProfilingJitFrame(jitActivation->prevJitTop());
|
||||
jitActivation = jitActivation->prevJitActivation();
|
||||
}
|
||||
} else {
|
||||
jit::JitActivation* jitActivation = cx->jitActivation;
|
||||
while (jitActivation) {
|
||||
jitActivation->setLastProfilingFrame(nullptr);
|
||||
jitActivation->setLastProfilingCallSite(nullptr);
|
||||
jitActivation = jitActivation->prevJitActivation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -495,8 +501,12 @@ ProfileEntry::script() const volatile
|
|||
// If profiling is supressed then we can't trust the script pointers to be
|
||||
// valid as they could be in the process of being moved by a compacting GC
|
||||
// (although it's still OK to get the runtime from them).
|
||||
JSRuntime* rt = script->zoneFromAnyThread()->runtimeFromAnyThread();
|
||||
if (!rt->unsafeContextFromAnyThread()->isProfilerSamplingEnabled())
|
||||
//
|
||||
// We only need to check the active context here, as
|
||||
// AutoSuppressProfilerSampling prohibits the runtime's active context from
|
||||
// being changed while it exists.
|
||||
JSContext* cx = script->runtimeFromAnyThread()->activeContext();
|
||||
if (!cx->isProfilerSamplingEnabled())
|
||||
return nullptr;
|
||||
|
||||
MOZ_ASSERT(!IsForwarded(script));
|
||||
|
@ -550,28 +560,19 @@ js::ProfilingGetPC(JSContext* cx, JSScript* script, void* ip)
|
|||
|
||||
AutoSuppressProfilerSampling::AutoSuppressProfilerSampling(JSContext* cx
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
: rt_(cx->runtime()),
|
||||
previouslyEnabled_(cx->isProfilerSamplingEnabled())
|
||||
: cx_(cx),
|
||||
previouslyEnabled_(cx->isProfilerSamplingEnabled()),
|
||||
prohibitContextChange_(cx->runtime())
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
if (previouslyEnabled_)
|
||||
rt_->contextFromMainThread()->disableProfilerSampling();
|
||||
}
|
||||
|
||||
AutoSuppressProfilerSampling::AutoSuppressProfilerSampling(JSRuntime* rt
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
: rt_(rt),
|
||||
previouslyEnabled_(rt_->contextFromMainThread()->isProfilerSamplingEnabled())
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
if (previouslyEnabled_)
|
||||
rt_->contextFromMainThread()->disableProfilerSampling();
|
||||
cx_->disableProfilerSampling();
|
||||
}
|
||||
|
||||
AutoSuppressProfilerSampling::~AutoSuppressProfilerSampling()
|
||||
{
|
||||
if (previouslyEnabled_)
|
||||
rt_->contextFromMainThread()->enableProfilerSampling();
|
||||
cx_->enableProfilerSampling();
|
||||
}
|
||||
|
||||
void*
|
||||
|
|
|
@ -217,24 +217,6 @@ class GeckoProfiler
|
|||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* This class is used to suppress profiler sampling during
|
||||
* critical sections where stack state is not valid.
|
||||
*/
|
||||
class MOZ_RAII AutoSuppressProfilerSampling
|
||||
{
|
||||
public:
|
||||
explicit AutoSuppressProfilerSampling(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
explicit AutoSuppressProfilerSampling(JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
|
||||
~AutoSuppressProfilerSampling();
|
||||
|
||||
private:
|
||||
JSRuntime* rt_;
|
||||
bool previouslyEnabled_;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
inline size_t
|
||||
GeckoProfiler::stringsCount()
|
||||
{
|
||||
|
|
|
@ -95,7 +95,8 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
|||
#ifdef DEBUG
|
||||
updateChildRuntimeCount(parentRuntime),
|
||||
#endif
|
||||
activeContext(nullptr),
|
||||
activeContext_(nullptr),
|
||||
activeContextChangeProhibited_(0),
|
||||
profilerSampleBufferGen_(0),
|
||||
profilerSampleBufferLapCount_(1),
|
||||
telemetryCallback(nullptr),
|
||||
|
@ -192,7 +193,9 @@ JSRuntime::init(JSContext* cx, uint32_t maxbytes, uint32_t maxNurseryBytes)
|
|||
if (CanUseExtraThreads() && !EnsureHelperThreadsInitialized())
|
||||
return false;
|
||||
|
||||
activeContext = cx;
|
||||
activeContext_ = cx;
|
||||
if (!cooperatingContexts().append(cx))
|
||||
return false;
|
||||
|
||||
singletonContext = cx;
|
||||
|
||||
|
@ -344,6 +347,15 @@ JSRuntime::destroyRuntime()
|
|||
js_delete(zoneGroupFromMainThread());
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::setActiveContext(JSContext* cx)
|
||||
{
|
||||
MOZ_ASSERT_IF(cx, isCooperatingContext(cx));
|
||||
MOZ_RELEASE_ASSERT(!activeContextChangeProhibited());
|
||||
|
||||
activeContext_ = cx;
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::addTelemetry(int id, uint32_t sample, const char* key)
|
||||
{
|
||||
|
|
|
@ -297,10 +297,57 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
AutoUpdateChildRuntimeCount updateChildRuntimeCount;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// The context for the thread which currently has exclusive access to most
|
||||
// contents of the runtime. When execution on the runtime is cooperatively
|
||||
// scheduled, this is the thread which is currently running.
|
||||
mozilla::Atomic<JSContext*, mozilla::ReleaseAcquire> activeContext;
|
||||
mozilla::Atomic<JSContext*, mozilla::ReleaseAcquire> activeContext_;
|
||||
|
||||
// All contexts participating in cooperative scheduling. All threads other
|
||||
// than |activeContext_| are suspended.
|
||||
js::ActiveThreadData<js::Vector<JSContext*, 4, js::SystemAllocPolicy>> cooperatingContexts_;
|
||||
|
||||
// Count of AutoProhibitActiveContextChange instances on the active context.
|
||||
js::ActiveThreadData<size_t> activeContextChangeProhibited_;
|
||||
|
||||
public:
|
||||
JSContext* activeContext() { return activeContext_; }
|
||||
const void* addressOfActiveContext() { return &activeContext_; }
|
||||
|
||||
void setActiveContext(JSContext* cx);
|
||||
|
||||
js::Vector<JSContext*, 4, js::SystemAllocPolicy>& cooperatingContexts() {
|
||||
return cooperatingContexts_.ref();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool isCooperatingContext(JSContext* cx) {
|
||||
for (size_t i = 0; i < cooperatingContexts().length(); i++) {
|
||||
if (cooperatingContexts()[i] == cx)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
class MOZ_RAII AutoProhibitActiveContextChange
|
||||
{
|
||||
JSRuntime* rt;
|
||||
|
||||
public:
|
||||
explicit AutoProhibitActiveContextChange(JSRuntime* rt)
|
||||
: rt(rt)
|
||||
{
|
||||
rt->activeContextChangeProhibited_++;
|
||||
}
|
||||
|
||||
~AutoProhibitActiveContextChange()
|
||||
{
|
||||
rt->activeContextChangeProhibited_--;
|
||||
}
|
||||
};
|
||||
|
||||
bool activeContextChangeProhibited() { return activeContextChangeProhibited_; }
|
||||
|
||||
/*
|
||||
* The profiler sampler generation after the latest sample.
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
using namespace js;
|
||||
|
||||
using mozilla::ArrayLength;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::PodCopy;
|
||||
|
||||
|
@ -1739,7 +1740,7 @@ ActivationIterator::settle()
|
|||
|
||||
JS::ProfilingFrameIterator::ProfilingFrameIterator(JSContext* cx, const RegisterState& state,
|
||||
uint32_t sampleBufferGen)
|
||||
: rt_(cx->runtime()),
|
||||
: cx_(cx),
|
||||
sampleBufferGen_(sampleBufferGen),
|
||||
activation_(nullptr),
|
||||
savedPrevJitTop_(nullptr)
|
||||
|
@ -1821,7 +1822,7 @@ JS::ProfilingFrameIterator::iteratorConstruct(const RegisterState& state)
|
|||
}
|
||||
|
||||
MOZ_ASSERT(activation_->asJit()->isActive());
|
||||
new (storage_.addr()) jit::JitProfilingFrameIterator(rt_, state);
|
||||
new (storage_.addr()) jit::JitProfilingFrameIterator(cx_, state);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1899,9 +1900,9 @@ JS::ProfilingFrameIterator::getPhysicalFrameAndEntry(jit::JitcodeGlobalEntry* en
|
|||
|
||||
// Look up an entry for the return address.
|
||||
void* returnAddr = jitIter().returnAddressToFp();
|
||||
jit::JitcodeGlobalTable* table = rt_->jitRuntime()->getJitcodeGlobalTable();
|
||||
jit::JitcodeGlobalTable* table = cx_->runtime()->jitRuntime()->getJitcodeGlobalTable();
|
||||
if (hasSampleBufferGen())
|
||||
*entry = table->lookupForSamplerInfallible(returnAddr, rt_, sampleBufferGen_);
|
||||
*entry = table->lookupForSamplerInfallible(returnAddr, cx_->runtime(), sampleBufferGen_);
|
||||
else
|
||||
*entry = table->lookupInfallible(returnAddr);
|
||||
|
||||
|
@ -1941,8 +1942,9 @@ JS::ProfilingFrameIterator::extractStack(Frame* frames, uint32_t offset, uint32_
|
|||
|
||||
// Extract the stack for the entry. Assume maximum inlining depth is <64
|
||||
const char* labels[64];
|
||||
uint32_t depth = entry.callStackAtAddr(rt_, jitIter().returnAddressToFp(), labels, 64);
|
||||
MOZ_ASSERT(depth < 64);
|
||||
uint32_t depth = entry.callStackAtAddr(cx_->runtime(), jitIter().returnAddressToFp(),
|
||||
labels, ArrayLength(labels));
|
||||
MOZ_ASSERT(depth < ArrayLength(labels));
|
||||
for (uint32_t i = 0; i < depth; i++) {
|
||||
if (offset + i >= end)
|
||||
return i;
|
||||
|
|
Загрузка…
Ссылка в новой задаче