mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1853720 - Add a "hot" variant of AUTO_PROFILER_LABEL, for lower overhead when the profiler is disabled. r=aabh,profiler-reviewers
The overhead is showing up in Speedometer 3, especially in the innerHTML setter when it calls into the frame constructor. Full breakdown of callers across sp3 is here: https://share.firefox.dev/3rfckTG Time spent in AutoProfilerLabel during TodoMVC-jQuery innerHTML: Before: https://share.firefox.dev/3Znlydp 378 sampes After: https://share.firefox.dev/45VdVgr 71 samples Differential Revision: https://phabricator.services.mozilla.com/D188487
This commit is contained in:
parent
abfc9f5199
commit
b474c8da56
@ -811,7 +811,7 @@ nsresult EventDispatcher::Dispatch(EventTarget* aTarget,
|
||||
nsEventStatus* aEventStatus,
|
||||
EventDispatchingCallback* aCallback,
|
||||
nsTArray<EventTarget*>* aTargets) {
|
||||
AUTO_PROFILER_LABEL("EventDispatcher::Dispatch", OTHER);
|
||||
AUTO_PROFILER_LABEL_HOT("EventDispatcher::Dispatch", OTHER);
|
||||
|
||||
NS_ASSERTION(aEvent, "Trying to dispatch without WidgetEvent!");
|
||||
NS_ENSURE_TRUE(!aEvent->mFlags.mIsBeingDispatched,
|
||||
|
@ -2607,8 +2607,8 @@ nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
|
||||
}
|
||||
|
||||
nsIFrame* nsCSSFrameConstructor::ConstructRootFrame() {
|
||||
AUTO_PROFILER_LABEL("nsCSSFrameConstructor::ConstructRootFrame",
|
||||
LAYOUT_FrameConstruction);
|
||||
AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ConstructRootFrame",
|
||||
LAYOUT_FrameConstruction);
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
|
||||
ServoStyleSet* styleSet = mPresShell->StyleSet();
|
||||
@ -6491,8 +6491,8 @@ void nsCSSFrameConstructor::ContentAppended(nsIContent* aFirstNewContent,
|
||||
MOZ_ASSERT(aInsertionKind == InsertionKind::Sync ||
|
||||
!RestyleManager()->IsInStyleRefresh());
|
||||
|
||||
AUTO_PROFILER_LABEL("nsCSSFrameConstructor::ContentAppended",
|
||||
LAYOUT_FrameConstruction);
|
||||
AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ContentAppended",
|
||||
LAYOUT_FrameConstruction);
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -6803,8 +6803,8 @@ void nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aStartChild,
|
||||
MOZ_ASSERT(aInsertionKind == InsertionKind::Sync ||
|
||||
!RestyleManager()->IsInStyleRefresh());
|
||||
|
||||
AUTO_PROFILER_LABEL("nsCSSFrameConstructor::ContentRangeInserted",
|
||||
LAYOUT_FrameConstruction);
|
||||
AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ContentRangeInserted",
|
||||
LAYOUT_FrameConstruction);
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
|
||||
MOZ_ASSERT(aStartChild, "must always pass a child");
|
||||
@ -7301,8 +7301,8 @@ bool nsCSSFrameConstructor::ContentRemoved(nsIContent* aChild,
|
||||
MOZ_ASSERT(aChild);
|
||||
MOZ_ASSERT(!aChild->IsRootOfNativeAnonymousSubtree() || !aOldNextSibling,
|
||||
"Anonymous roots don't have siblings");
|
||||
AUTO_PROFILER_LABEL("nsCSSFrameConstructor::ContentRemoved",
|
||||
LAYOUT_FrameConstruction);
|
||||
AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::ContentRemoved",
|
||||
LAYOUT_FrameConstruction);
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
nsPresContext* presContext = mPresShell->GetPresContext();
|
||||
MOZ_ASSERT(presContext, "Our presShell should have a valid presContext");
|
||||
@ -7679,8 +7679,8 @@ bool nsCSSFrameConstructor::EnsureFrameForTextNodeIsCreatedAfterFlush(
|
||||
|
||||
void nsCSSFrameConstructor::CharacterDataChanged(
|
||||
nsIContent* aContent, const CharacterDataChangeInfo& aInfo) {
|
||||
AUTO_PROFILER_LABEL("nsCSSFrameConstructor::CharacterDataChanged",
|
||||
LAYOUT_FrameConstruction);
|
||||
AUTO_PROFILER_LABEL_HOT("nsCSSFrameConstructor::CharacterDataChanged",
|
||||
LAYOUT_FrameConstruction);
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
|
||||
if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
|
||||
|
@ -94,7 +94,7 @@ static bool ContainingBlockMayHaveChanged(const ComputedStyle& aOldStyle,
|
||||
|
||||
nsChangeHint ComputedStyle::CalcStyleDifference(const ComputedStyle& aNewStyle,
|
||||
uint32_t* aEqualStructs) const {
|
||||
AUTO_PROFILER_LABEL("ComputedStyle::CalcStyleDifference", LAYOUT);
|
||||
AUTO_PROFILER_LABEL_HOT("ComputedStyle::CalcStyleDifference", LAYOUT);
|
||||
static_assert(StyleStructConstants::kStyleStructCount <= 32,
|
||||
"aEqualStructs is not big enough");
|
||||
|
||||
|
@ -6869,7 +6869,7 @@ bool profiler_capture_backtrace_into(ProfileChunkedBuffer& aChunkedBuffer,
|
||||
|
||||
UniquePtr<ProfileChunkedBuffer> profiler_capture_backtrace() {
|
||||
MOZ_RELEASE_ASSERT(CorePS::Exists());
|
||||
AUTO_PROFILER_LABEL("profiler_capture_backtrace", PROFILER);
|
||||
AUTO_PROFILER_LABEL_HOT("profiler_capture_backtrace", PROFILER);
|
||||
|
||||
// Quick is-active and feature check before allocating a buffer.
|
||||
// If NoMarkerStacks is set, we don't want to capture a backtrace.
|
||||
|
@ -11,6 +11,7 @@
|
||||
#ifndef ProfilerLabels_h
|
||||
#define ProfilerLabels_h
|
||||
|
||||
#include "mozilla/ProfilerState.h"
|
||||
#include "mozilla/ProfilerThreadState.h"
|
||||
|
||||
#include "js/ProfilingCategory.h"
|
||||
@ -38,11 +39,25 @@ struct JSContext;
|
||||
// like this: "ClassName::FunctionName:PartName".
|
||||
//
|
||||
// Use AUTO_PROFILER_LABEL_DYNAMIC_* if you want to add additional / dynamic
|
||||
// information to the label stack frame.
|
||||
// information to the label stack frame, and AUTO_PROFILER_LABEL_HOT if you're
|
||||
// instrumenting functions for which overhead on the order of nanoseconds is
|
||||
// noticeable.
|
||||
#define AUTO_PROFILER_LABEL(label, categoryPair) \
|
||||
mozilla::AutoProfilerLabel PROFILER_RAII( \
|
||||
label, nullptr, JS::ProfilingCategoryPair::categoryPair)
|
||||
|
||||
// Like AUTO_PROFILER_LABEL, but for super-hot code where overhead must be
|
||||
// kept to the absolute minimum. This variant doesn't push the label if the
|
||||
// profiler isn't running.
|
||||
// Don't use this for long-running functions: If the profiler is started in
|
||||
// the middle of the function, this label won't be on the stack until the
|
||||
// function is entered the next time. As a result, category information for
|
||||
// samples at the start of the profile can be misleading.
|
||||
// For short-running functions, that's often an acceptable trade-off.
|
||||
#define AUTO_PROFILER_LABEL_HOT(label, categoryPair) \
|
||||
mozilla::AutoProfilerLabelHot PROFILER_RAII( \
|
||||
label, nullptr, JS::ProfilingCategoryPair::categoryPair)
|
||||
|
||||
// Similar to AUTO_PROFILER_LABEL, but that adds the RELEVANT_FOR_JS flag.
|
||||
#define AUTO_PROFILER_LABEL_RELEVANT_FOR_JS(label, categoryPair) \
|
||||
mozilla::AutoProfilerLabel PROFILER_RAII( \
|
||||
@ -171,7 +186,7 @@ struct JSContext;
|
||||
// ProfilingStack from the JS context, and avoids almost all overhead in the
|
||||
// case where the profiler is disabled.
|
||||
#define AUTO_PROFILER_LABEL_FAST(label, categoryPair, ctx) \
|
||||
mozilla::AutoProfilerLabel PROFILER_RAII( \
|
||||
mozilla::AutoProfilerLabelHot PROFILER_RAII( \
|
||||
ctx, label, nullptr, JS::ProfilingCategoryPair::categoryPair)
|
||||
|
||||
// Similar to AUTO_PROFILER_LABEL_FAST, but also takes an extra string and an
|
||||
@ -179,7 +194,7 @@ struct JSContext;
|
||||
// js::ProfilingStackFrame::Flags enum.
|
||||
#define AUTO_PROFILER_LABEL_DYNAMIC_FAST(label, dynamicString, categoryPair, \
|
||||
ctx, flags) \
|
||||
mozilla::AutoProfilerLabel PROFILER_RAII( \
|
||||
mozilla::AutoProfilerLabelHot PROFILER_RAII( \
|
||||
ctx, label, dynamicString, JS::ProfilingCategoryPair::categoryPair, \
|
||||
flags)
|
||||
|
||||
@ -194,14 +209,25 @@ class MOZ_RAII AutoProfilerLabel {
|
||||
JS::ProfilingCategoryPair aCategoryPair,
|
||||
uint32_t aFlags = 0) {}
|
||||
|
||||
// This is the AUTO_PROFILER_LABEL_FAST variant.
|
||||
AutoProfilerLabel(JSContext* aJSContext, const char* aLabel,
|
||||
const char* aDynamicString,
|
||||
JS::ProfilingCategoryPair aCategoryPair, uint32_t aFlags) {}
|
||||
|
||||
~AutoProfilerLabel() {}
|
||||
};
|
||||
|
||||
class MOZ_RAII AutoProfilerLabelHot {
|
||||
public:
|
||||
// This is the AUTO_PROFILER_LABEL_HOT variant.
|
||||
AutoProfilerLabelHot(const char* aLabel, const char* aDynamicString,
|
||||
JS::ProfilingCategoryPair aCategoryPair,
|
||||
uint32_t aFlags = 0) {}
|
||||
|
||||
// This is the AUTO_PROFILER_LABEL_FAST variant.
|
||||
AutoProfilerLabelHot(JSContext* aJSContext, const char* aLabel,
|
||||
const char* aDynamicString,
|
||||
JS::ProfilingCategoryPair aCategoryPair,
|
||||
uint32_t aFlags) {}
|
||||
|
||||
~AutoProfilerLabelHot() {}
|
||||
};
|
||||
|
||||
#else // !MOZ_GECKO_PROFILER
|
||||
|
||||
// This class creates a non-owning ProfilingStack reference. Objects of this
|
||||
@ -227,23 +253,62 @@ class MOZ_RAII AutoProfilerLabel {
|
||||
}
|
||||
}
|
||||
|
||||
// This is the AUTO_PROFILER_LABEL_FAST variant. It retrieves the
|
||||
// ProfilingStack from the JSContext and does nothing if the profiler is
|
||||
// inactive.
|
||||
AutoProfilerLabel(JSContext* aJSContext, const char* aLabel,
|
||||
const char* aDynamicString,
|
||||
JS::ProfilingCategoryPair aCategoryPair, uint32_t aFlags) {
|
||||
mProfilingStack = js::GetContextProfilingStackIfEnabled(aJSContext);
|
||||
~AutoProfilerLabel() {
|
||||
// This function runs both on and off the main thread.
|
||||
|
||||
if (mProfilingStack) {
|
||||
mProfilingStack->pop();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// We save a ProfilingStack pointer in the ctor so we don't have to redo the
|
||||
// TLS lookup in the dtor.
|
||||
ProfilingStack* mProfilingStack;
|
||||
};
|
||||
|
||||
class MOZ_RAII AutoProfilerLabelHot {
|
||||
public:
|
||||
// This is the AUTO_PROFILER_LABEL_HOT variant. It does nothing if
|
||||
// the profiler is inactive.
|
||||
AutoProfilerLabelHot(const char* aLabel, const char* aDynamicString,
|
||||
JS::ProfilingCategoryPair aCategoryPair,
|
||||
uint32_t aFlags = 0) {
|
||||
if (MOZ_LIKELY(!profiler_is_active())) {
|
||||
mProfilingStack = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the ProfilingStack from TLS.
|
||||
mProfilingStack = profiler::ThreadRegistration::WithOnThreadRefOr(
|
||||
[](profiler::ThreadRegistration::OnThreadRef aThread) {
|
||||
return &aThread.UnlockedConstReaderAndAtomicRWRef()
|
||||
.ProfilingStackRef();
|
||||
},
|
||||
nullptr);
|
||||
if (mProfilingStack) {
|
||||
mProfilingStack->pushLabelFrame(aLabel, aDynamicString, this,
|
||||
aCategoryPair, aFlags);
|
||||
}
|
||||
}
|
||||
|
||||
~AutoProfilerLabel() {
|
||||
// This function runs both on and off the main thread.
|
||||
// This is the AUTO_PROFILER_LABEL_FAST variant. It retrieves the
|
||||
// ProfilingStack from the JSContext and does nothing if the profiler is
|
||||
// inactive.
|
||||
AutoProfilerLabelHot(JSContext* aJSContext, const char* aLabel,
|
||||
const char* aDynamicString,
|
||||
JS::ProfilingCategoryPair aCategoryPair,
|
||||
uint32_t aFlags) {
|
||||
mProfilingStack = js::GetContextProfilingStackIfEnabled(aJSContext);
|
||||
if (MOZ_UNLIKELY(mProfilingStack)) {
|
||||
mProfilingStack->pushLabelFrame(aLabel, aDynamicString, this,
|
||||
aCategoryPair, aFlags);
|
||||
}
|
||||
}
|
||||
|
||||
if (mProfilingStack) {
|
||||
~AutoProfilerLabelHot() {
|
||||
// This function runs both on and off the main thread.
|
||||
if (MOZ_UNLIKELY(mProfilingStack)) {
|
||||
mProfilingStack->pop();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user