mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Backed out 9 changesets (bug 1499507) for bustages on ProfileBuffer.cpp . CLOSED TREE
Backed out changeset 541186291b88 (bug 1499507) Backed out changeset 8a3f4acbad3b (bug 1499507) Backed out changeset f427afc392b0 (bug 1499507) Backed out changeset 58dc19fb2b76 (bug 1499507) Backed out changeset 9225e9aea377 (bug 1499507) Backed out changeset ca23a517da63 (bug 1499507) Backed out changeset 16d6c90333de (bug 1499507) Backed out changeset bc134fe1722a (bug 1499507) Backed out changeset 4a9c9a91182c (bug 1499507)
This commit is contained in:
parent
564e8965fd
commit
2c6edfdde8
@ -125,7 +125,7 @@ nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx,
|
||||
:
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
mAutoProfilerLabel("nsJSUtils::ExecutionContext", /* dynamicStr */ nullptr,
|
||||
js::ProfilingStackFrame::Category::JS),
|
||||
__LINE__, js::ProfilingStackFrame::Category::JS),
|
||||
#endif
|
||||
mCx(aCx)
|
||||
, mRealm(aCx, aGlobal)
|
||||
|
@ -1586,6 +1586,12 @@ class CGAbstractMethod(CGThing):
|
||||
maybeNewline = " " if self.inline else "\n"
|
||||
return ' '.join(decorators) + maybeNewline
|
||||
|
||||
def _auto_profiler_label(self):
|
||||
profiler_label_and_jscontext = self.profiler_label_and_jscontext()
|
||||
if profiler_label_and_jscontext:
|
||||
return 'AUTO_PROFILER_LABEL_FAST("%s", DOM, %s);' % profiler_label_and_jscontext
|
||||
return None
|
||||
|
||||
def declare(self):
|
||||
if self.inline:
|
||||
return self._define(True)
|
||||
@ -1610,9 +1616,9 @@ class CGAbstractMethod(CGThing):
|
||||
def definition_prologue(self, fromDeclare):
|
||||
prologue = "%s%s%s(%s)\n{\n" % (self._template(), self._decorators(),
|
||||
self.name, self._argstring(fromDeclare))
|
||||
profiler_label = self.auto_profiler_label()
|
||||
profiler_label = self._auto_profiler_label()
|
||||
if profiler_label:
|
||||
prologue += indent(profiler_label) + "\n"
|
||||
prologue += " %s\n\n" % profiler_label
|
||||
|
||||
return prologue
|
||||
|
||||
@ -1626,7 +1632,7 @@ class CGAbstractMethod(CGThing):
|
||||
Override this method to return a pair of (descriptive string, name of a
|
||||
JSContext* variable) in order to generate a profiler label for this method.
|
||||
"""
|
||||
def auto_profiler_label(self):
|
||||
def profiler_label_and_jscontext(self):
|
||||
return None # Override me!
|
||||
|
||||
class CGAbstractStaticMethod(CGAbstractMethod):
|
||||
@ -1869,17 +1875,13 @@ class CGClassConstructor(CGAbstractStaticMethod):
|
||||
constructorName=ctorName)
|
||||
return preamble + "\n" + callGenerator.define()
|
||||
|
||||
def auto_profiler_label(self):
|
||||
def profiler_label_and_jscontext(self):
|
||||
name = self._ctor.identifier.name
|
||||
if name != "constructor":
|
||||
ctorName = name
|
||||
else:
|
||||
ctorName = self.descriptor.interface.identifier.name
|
||||
return fill(
|
||||
"""
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_FAST("${ctorName}", "constructor", DOM, cx, 0);
|
||||
""",
|
||||
ctorName=ctorName)
|
||||
return ("%s constructor" % ctorName, "cx")
|
||||
|
||||
# Encapsulate the constructor in a helper method to share genConstructorBody with CGJSImplMethod.
|
||||
class CGConstructNavigatorObject(CGAbstractMethod):
|
||||
@ -8669,9 +8671,17 @@ class CGAbstractStaticBindingMethod(CGAbstractStaticMethod):
|
||||
""")
|
||||
return unwrap + self.generate_code().define()
|
||||
|
||||
def profiler_label_and_jscontext(self):
|
||||
# Our args are JSNativeArguments() which contain a "JSContext* cx"
|
||||
# argument. We let our subclasses choose the label.
|
||||
return (self.profiler_label(), "cx")
|
||||
|
||||
def generate_code(self):
|
||||
assert False # Override me
|
||||
|
||||
def profiler_label(self):
|
||||
assert False # Override me
|
||||
|
||||
|
||||
def MakeNativeName(name):
|
||||
return name[0].upper() + IDLToCIdentifier(name[1:])
|
||||
@ -8698,17 +8708,10 @@ class CGSpecializedMethod(CGAbstractStaticMethod):
|
||||
return CGMethodCall(nativeName, self.method.isStatic(), self.descriptor,
|
||||
self.method).define()
|
||||
|
||||
def auto_profiler_label(self):
|
||||
def profiler_label_and_jscontext(self):
|
||||
interface_name = self.descriptor.interface.identifier.name
|
||||
method_name = self.method.identifier.name
|
||||
return fill(
|
||||
"""
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_FAST(
|
||||
"${interface_name}", "${method_name}", DOM, cx,
|
||||
uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD));
|
||||
""",
|
||||
interface_name=interface_name,
|
||||
method_name=method_name)
|
||||
return ("%s.%s" % (interface_name, method_name), "cx")
|
||||
|
||||
@staticmethod
|
||||
def makeNativeName(descriptor, method):
|
||||
@ -8965,17 +8968,10 @@ class CGStaticMethod(CGAbstractStaticBindingMethod):
|
||||
self.method)
|
||||
return CGMethodCall(nativeName, True, self.descriptor, self.method)
|
||||
|
||||
def auto_profiler_label(self):
|
||||
def profiler_label(self):
|
||||
interface_name = self.descriptor.interface.identifier.name
|
||||
method_name = self.method.identifier.name
|
||||
return fill(
|
||||
"""
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_FAST(
|
||||
"${interface_name}", "${method_name}", DOM, cx,
|
||||
uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD));
|
||||
""",
|
||||
interface_name=interface_name,
|
||||
method_name=method_name)
|
||||
return "%s.%s" % (interface_name, method_name)
|
||||
|
||||
|
||||
class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||
@ -9079,17 +9075,10 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||
cgGetterCall(self.attr.type, nativeName,
|
||||
self.descriptor, self.attr).define())
|
||||
|
||||
def auto_profiler_label(self):
|
||||
def profiler_label_and_jscontext(self):
|
||||
interface_name = self.descriptor.interface.identifier.name
|
||||
attr_name = self.attr.identifier.name
|
||||
return fill(
|
||||
"""
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_FAST(
|
||||
"${interface_name}", "${attr_name}", DOM, cx,
|
||||
uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER));
|
||||
""",
|
||||
interface_name=interface_name,
|
||||
attr_name=attr_name)
|
||||
return ("get %s.%s" % (interface_name, attr_name), "cx")
|
||||
|
||||
@staticmethod
|
||||
def makeNativeName(descriptor, attr):
|
||||
@ -9149,17 +9138,10 @@ class CGStaticGetter(CGAbstractStaticBindingMethod):
|
||||
return CGGetterCall(self.attr.type, nativeName, self.descriptor,
|
||||
self.attr)
|
||||
|
||||
def auto_profiler_label(self):
|
||||
def profiler_label(self):
|
||||
interface_name = self.descriptor.interface.identifier.name
|
||||
attr_name = self.attr.identifier.name
|
||||
return fill(
|
||||
"""
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_FAST(
|
||||
"${interface_name}", "${attr_name}", DOM, cx,
|
||||
uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER));
|
||||
""",
|
||||
interface_name=interface_name,
|
||||
attr_name=attr_name)
|
||||
return "get %s.%s" % (interface_name, attr_name)
|
||||
|
||||
|
||||
class CGSpecializedSetter(CGAbstractStaticMethod):
|
||||
@ -9183,17 +9165,10 @@ class CGSpecializedSetter(CGAbstractStaticMethod):
|
||||
return CGSetterCall(self.attr.type, nativeName, self.descriptor,
|
||||
self.attr).define()
|
||||
|
||||
def auto_profiler_label(self):
|
||||
def profiler_label_and_jscontext(self):
|
||||
interface_name = self.descriptor.interface.identifier.name
|
||||
attr_name = self.attr.identifier.name
|
||||
return fill(
|
||||
"""
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_FAST(
|
||||
"${interface_name}", "${attr_name}", DOM, cx,
|
||||
uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER));
|
||||
""",
|
||||
interface_name=interface_name,
|
||||
attr_name=attr_name)
|
||||
return ("set %s.%s" % (interface_name, attr_name), "cx")
|
||||
|
||||
@staticmethod
|
||||
def makeNativeName(descriptor, attr):
|
||||
@ -9224,17 +9199,10 @@ class CGStaticSetter(CGAbstractStaticBindingMethod):
|
||||
self.attr)
|
||||
return CGList([checkForArg, call])
|
||||
|
||||
def auto_profiler_label(self):
|
||||
def profiler_label(self):
|
||||
interface_name = self.descriptor.interface.identifier.name
|
||||
attr_name = self.attr.identifier.name
|
||||
return fill(
|
||||
"""
|
||||
AUTO_PROFILER_LABEL_DYNAMIC_FAST(
|
||||
"${interface_name}", "${attr_name}", DOM, cx,
|
||||
uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER));
|
||||
""",
|
||||
interface_name=interface_name,
|
||||
attr_name=attr_name)
|
||||
return "set %s.%s" % (interface_name, attr_name)
|
||||
|
||||
|
||||
class CGSpecializedForwardingSetter(CGSpecializedSetter):
|
||||
|
@ -645,7 +645,7 @@ AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
// ran.
|
||||
, mCallerOverride(cx())
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
, mAutoProfilerLabel("AutoEntryScript", aReason,
|
||||
, mAutoProfilerLabel("AutoEntryScript", aReason, __LINE__,
|
||||
js::ProfilingStackFrame::Category::JS)
|
||||
#endif
|
||||
{
|
||||
|
@ -145,16 +145,13 @@ class ProfilingStackFrame
|
||||
mozilla::Atomic<void*, mozilla::ReleaseAcquire,
|
||||
mozilla::recordreplay::Behavior::DontPreserve> spOrScript;
|
||||
|
||||
// The bytecode offset for JS stack frames.
|
||||
// Must not be used on non-JS frames; it'll contain either the default 0,
|
||||
// or a leftover value from a previous JS stack frame that was using this
|
||||
// ProfilingStackFrame object.
|
||||
// Line number for non-JS stack frames, the bytecode offset otherwise.
|
||||
mozilla::Atomic<int32_t, mozilla::ReleaseAcquire,
|
||||
mozilla::recordreplay::Behavior::DontPreserve> pcOffsetIfJS_;
|
||||
mozilla::recordreplay::Behavior::DontPreserve> lineOrPcOffset;
|
||||
|
||||
// Bits 0...6 hold the Flags. Bits 7...31 hold the category.
|
||||
// Bits 0...1 hold the Kind. Bits 2...31 hold the category.
|
||||
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire,
|
||||
mozilla::recordreplay::Behavior::DontPreserve> flagsAndCategory_;
|
||||
mozilla::recordreplay::Behavior::DontPreserve> kindAndCategory_;
|
||||
|
||||
static int32_t pcToOffset(JSScript* aScript, jsbytecode* aPc);
|
||||
|
||||
@ -166,49 +163,34 @@ class ProfilingStackFrame
|
||||
dynamicString_ = other.dynamicString();
|
||||
void* spScript = other.spOrScript;
|
||||
spOrScript = spScript;
|
||||
int32_t offsetIfJS = other.pcOffsetIfJS_;
|
||||
pcOffsetIfJS_ = offsetIfJS;
|
||||
uint32_t flagsAndCategory = other.flagsAndCategory_;
|
||||
flagsAndCategory_ = flagsAndCategory;
|
||||
int32_t offset = other.lineOrPcOffset;
|
||||
lineOrPcOffset = offset;
|
||||
uint32_t kindAndCategory = other.kindAndCategory_;
|
||||
kindAndCategory_ = kindAndCategory;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 7 bits for the flags.
|
||||
// That leaves 32 - 7 = 25 bits for the category.
|
||||
enum class Flags : uint32_t {
|
||||
// The first three flags describe the kind of the frame and are
|
||||
// mutually exclusive. (We still give them individual bits for
|
||||
// simplicity.)
|
||||
|
||||
enum class Kind : uint32_t {
|
||||
// A regular label frame. These usually come from AutoProfilerLabel.
|
||||
IS_LABEL_FRAME = 1 << 0,
|
||||
LABEL = 0,
|
||||
|
||||
// A special frame indicating the start of a run of JS profiling stack
|
||||
// frames. IS_SP_MARKER_FRAME frames are ignored, except for the sp
|
||||
// field. These frames are needed to get correct ordering between JS
|
||||
// and LABEL frames because JS frames don't carry sp information.
|
||||
// frames. SP_MARKER frames are ignored, except for the sp field.
|
||||
// These frames are needed to get correct ordering between JS and LABEL
|
||||
// frames because JS frames don't carry sp information.
|
||||
// SP is short for "stack pointer".
|
||||
IS_SP_MARKER_FRAME = 1 << 1,
|
||||
SP_MARKER = 1,
|
||||
|
||||
// A JS frame.
|
||||
IS_JS_FRAME = 1 << 2,
|
||||
// A normal JS frame.
|
||||
JS_NORMAL = 2,
|
||||
|
||||
// An interpreter JS frame that has OSR-ed into baseline. IS_JS_FRAME
|
||||
// frames can have this flag set and unset during their lifetime.
|
||||
// JS_OSR frames are ignored.
|
||||
JS_OSR = 1 << 3,
|
||||
// An interpreter JS frame that has OSR-ed into baseline. JS_NORMAL
|
||||
// frames can be converted to JS_OSR and back. JS_OSR frames are
|
||||
// ignored.
|
||||
JS_OSR = 3,
|
||||
|
||||
// The next three are mutually exclusive.
|
||||
// By default, for profiling stack frames that have both a label and a
|
||||
// dynamic string, the two strings are combined into one string of the
|
||||
// form "<label> <dynamicString>" during JSON serialization. The
|
||||
// following flags can be used to change this preset.
|
||||
STRING_TEMPLATE_METHOD = 1 << 4, // "<label>.<dynamicString>"
|
||||
STRING_TEMPLATE_GETTER = 1 << 5, // "get <label>.<dynamicString>"
|
||||
STRING_TEMPLATE_SETTER = 1 << 6, // "set <label>.<dynamicString>"
|
||||
|
||||
FLAGS_BITCOUNT = 7,
|
||||
FLAGS_MASK = (1 << FLAGS_BITCOUNT) - 1
|
||||
KIND_BITCOUNT = 2,
|
||||
KIND_MASK = (1 << KIND_BITCOUNT) - 1
|
||||
};
|
||||
|
||||
// Keep these in sync with devtools/client/performance/modules/categories.js
|
||||
@ -226,36 +208,23 @@ class ProfilingStackFrame
|
||||
LAST = DOM,
|
||||
};
|
||||
|
||||
static_assert(uint32_t(Category::LAST) <= (UINT32_MAX >> uint32_t(Flags::FLAGS_BITCOUNT)),
|
||||
"Too many categories to fit into u32 with together with the reserved bits for the flags");
|
||||
static_assert(uint32_t(Category::LAST) <= (UINT32_MAX >> uint32_t(Kind::KIND_BITCOUNT)),
|
||||
"Too many categories to fit into u32 with two bits reserved for the kind");
|
||||
|
||||
bool isLabelFrame() const
|
||||
{
|
||||
return uint32_t(flagsAndCategory_) & uint32_t(Flags::IS_LABEL_FRAME);
|
||||
return kind() == Kind::LABEL;
|
||||
}
|
||||
|
||||
bool isSpMarkerFrame() const
|
||||
{
|
||||
return uint32_t(flagsAndCategory_) & uint32_t(Flags::IS_SP_MARKER_FRAME);
|
||||
return kind() == Kind::SP_MARKER;
|
||||
}
|
||||
|
||||
bool isJsFrame() const
|
||||
{
|
||||
return uint32_t(flagsAndCategory_) & uint32_t(Flags::IS_JS_FRAME);
|
||||
}
|
||||
|
||||
bool isOSRFrame() const {
|
||||
return uint32_t(flagsAndCategory_) & uint32_t(Flags::JS_OSR);
|
||||
}
|
||||
|
||||
void setIsOSRFrame(bool isOSR) {
|
||||
if (isOSR) {
|
||||
flagsAndCategory_ =
|
||||
uint32_t(flagsAndCategory_) | uint32_t(Flags::JS_OSR);
|
||||
} else {
|
||||
flagsAndCategory_ =
|
||||
uint32_t(flagsAndCategory_) & ~uint32_t(Flags::JS_OSR);
|
||||
}
|
||||
Kind k = kind();
|
||||
return k == Kind::JS_NORMAL || k == Kind::JS_OSR;
|
||||
}
|
||||
|
||||
void setLabel(const char* aLabel) { label_ = aLabel; }
|
||||
@ -264,16 +233,13 @@ class ProfilingStackFrame
|
||||
const char* dynamicString() const { return dynamicString_; }
|
||||
|
||||
void initLabelFrame(const char* aLabel, const char* aDynamicString, void* sp,
|
||||
Category aCategory, uint32_t aFlags)
|
||||
uint32_t aLine, Category aCategory)
|
||||
{
|
||||
label_ = aLabel;
|
||||
dynamicString_ = aDynamicString;
|
||||
spOrScript = sp;
|
||||
// pcOffsetIfJS_ is not set and must not be used on label frames.
|
||||
flagsAndCategory_ =
|
||||
uint32_t(Flags::IS_LABEL_FRAME) |
|
||||
(uint32_t(aCategory) << uint32_t(Flags::FLAGS_BITCOUNT)) |
|
||||
aFlags;
|
||||
lineOrPcOffset = static_cast<int32_t>(aLine);
|
||||
kindAndCategory_ = uint32_t(Kind::LABEL) | (uint32_t(aCategory) << uint32_t(Kind::KIND_BITCOUNT));
|
||||
MOZ_ASSERT(isLabelFrame());
|
||||
}
|
||||
|
||||
@ -282,10 +248,8 @@ class ProfilingStackFrame
|
||||
label_ = "";
|
||||
dynamicString_ = nullptr;
|
||||
spOrScript = sp;
|
||||
// pcOffsetIfJS_ is not set and must not be used on sp marker frames.
|
||||
flagsAndCategory_ =
|
||||
uint32_t(Flags::IS_SP_MARKER_FRAME) |
|
||||
(uint32_t(Category::OTHER) << uint32_t(Flags::FLAGS_BITCOUNT));
|
||||
lineOrPcOffset = 0;
|
||||
kindAndCategory_ = uint32_t(Kind::SP_MARKER) | (uint32_t(Category::OTHER) << uint32_t(Kind::KIND_BITCOUNT));
|
||||
MOZ_ASSERT(isSpMarkerFrame());
|
||||
}
|
||||
|
||||
@ -295,19 +259,21 @@ class ProfilingStackFrame
|
||||
label_ = aLabel;
|
||||
dynamicString_ = aDynamicString;
|
||||
spOrScript = aScript;
|
||||
pcOffsetIfJS_ = pcToOffset(aScript, aPc);
|
||||
flagsAndCategory_ =
|
||||
uint32_t(Flags::IS_JS_FRAME) |
|
||||
(uint32_t(Category::JS) << uint32_t(Flags::FLAGS_BITCOUNT));
|
||||
lineOrPcOffset = pcToOffset(aScript, aPc);
|
||||
kindAndCategory_ = uint32_t(Kind::JS_NORMAL) | (uint32_t(Category::JS) << uint32_t(Kind::KIND_BITCOUNT));
|
||||
MOZ_ASSERT(isJsFrame());
|
||||
}
|
||||
|
||||
uint32_t flags() const {
|
||||
return uint32_t(flagsAndCategory_) & uint32_t(Flags::FLAGS_MASK);
|
||||
void setKind(Kind aKind) {
|
||||
kindAndCategory_ = uint32_t(aKind) | (uint32_t(category()) << uint32_t(Kind::KIND_BITCOUNT));
|
||||
}
|
||||
|
||||
Kind kind() const {
|
||||
return Kind(kindAndCategory_ & uint32_t(Kind::KIND_MASK));
|
||||
}
|
||||
|
||||
Category category() const {
|
||||
return Category(flagsAndCategory_ >> uint32_t(Flags::FLAGS_BITCOUNT));
|
||||
return Category(kindAndCategory_ >> uint32_t(Kind::KIND_BITCOUNT));
|
||||
}
|
||||
|
||||
void* stackAddress() const {
|
||||
@ -317,6 +283,11 @@ class ProfilingStackFrame
|
||||
|
||||
JS_PUBLIC_API(JSScript*) script() const;
|
||||
|
||||
uint32_t line() const {
|
||||
MOZ_ASSERT(!isJsFrame());
|
||||
return static_cast<uint32_t>(lineOrPcOffset);
|
||||
}
|
||||
|
||||
// Note that the pointer returned might be invalid.
|
||||
JSScript* rawScript() const {
|
||||
MOZ_ASSERT(isJsFrame());
|
||||
@ -392,20 +363,12 @@ class ProfilingStack final
|
||||
~ProfilingStack();
|
||||
|
||||
void pushLabelFrame(const char* label, const char* dynamicString, void* sp,
|
||||
js::ProfilingStackFrame::Category category,
|
||||
uint32_t flags = 0) {
|
||||
// This thread is the only one that ever changes the value of
|
||||
// stackPointer.
|
||||
// Store the value of the atomic in a non-atomic local variable so that
|
||||
// the compiler won't generate two separate loads from the atomic for
|
||||
// the size check and the frames[] array indexing operation.
|
||||
uint32_t stackPointerVal = stackPointer;
|
||||
uint32_t line, js::ProfilingStackFrame::Category category) {
|
||||
uint32_t oldStackPointer = stackPointer;
|
||||
|
||||
if (MOZ_UNLIKELY(stackPointerVal >= capacity)) {
|
||||
ensureCapacitySlow();
|
||||
if (MOZ_LIKELY(capacity > oldStackPointer) || MOZ_LIKELY(ensureCapacitySlow())) {
|
||||
frames[oldStackPointer].initLabelFrame(label, dynamicString, sp, line, category);
|
||||
}
|
||||
frames[stackPointerVal].initLabelFrame(label, dynamicString, sp,
|
||||
category, flags);
|
||||
|
||||
// This must happen at the end! The compiler will not reorder this
|
||||
// update because stackPointer is Atomic<..., ReleaseAcquire>, so any
|
||||
@ -413,19 +376,17 @@ class ProfilingStack final
|
||||
// Do the read and the write as two separate statements, in order to
|
||||
// make it clear that we don't need an atomic increment, which would be
|
||||
// more expensive on x86 than the separate operations done here.
|
||||
// However, don't use stackPointerVal here; instead, allow the compiler
|
||||
// to turn this store into a non-atomic increment instruction which
|
||||
// takes up less code size.
|
||||
stackPointer = stackPointer + 1;
|
||||
// This thread is the only one that ever changes the value of
|
||||
// stackPointer.
|
||||
stackPointer = oldStackPointer + 1;
|
||||
}
|
||||
|
||||
void pushSpMarkerFrame(void* sp) {
|
||||
uint32_t oldStackPointer = stackPointer;
|
||||
|
||||
if (MOZ_UNLIKELY(oldStackPointer >= capacity)) {
|
||||
ensureCapacitySlow();
|
||||
if (MOZ_LIKELY(capacity > oldStackPointer) || MOZ_LIKELY(ensureCapacitySlow())) {
|
||||
frames[oldStackPointer].initSpMarkerFrame(sp);
|
||||
}
|
||||
frames[oldStackPointer].initSpMarkerFrame(sp);
|
||||
|
||||
// This must happen at the end, see the comment in pushLabelFrame.
|
||||
stackPointer = oldStackPointer + 1;
|
||||
@ -433,17 +394,14 @@ class ProfilingStack final
|
||||
|
||||
void pushJsFrame(const char* label, const char* dynamicString, JSScript* script,
|
||||
jsbytecode* pc) {
|
||||
// This thread is the only one that ever changes the value of
|
||||
// stackPointer. Only load the atomic once.
|
||||
uint32_t oldStackPointer = stackPointer;
|
||||
|
||||
if (MOZ_UNLIKELY(oldStackPointer >= capacity)) {
|
||||
ensureCapacitySlow();
|
||||
if (MOZ_LIKELY(capacity > oldStackPointer) || MOZ_LIKELY(ensureCapacitySlow())) {
|
||||
frames[oldStackPointer].initJsFrame(label, dynamicString, script, pc);
|
||||
}
|
||||
frames[oldStackPointer].initJsFrame(label, dynamicString, script, pc);
|
||||
|
||||
// This must happen at the end, see the comment in pushLabelFrame.
|
||||
stackPointer = stackPointer + 1;
|
||||
stackPointer = oldStackPointer + 1;
|
||||
}
|
||||
|
||||
void pop() {
|
||||
@ -457,13 +415,13 @@ class ProfilingStack final
|
||||
stackPointer = oldStackPointer - 1;
|
||||
}
|
||||
|
||||
uint32_t stackSize() const { return stackPointer; }
|
||||
uint32_t stackSize() const { return std::min(uint32_t(stackPointer), stackCapacity()); }
|
||||
uint32_t stackCapacity() const { return capacity; }
|
||||
|
||||
private:
|
||||
// Out of line path for expanding the buffer, since otherwise this would get inlined in every
|
||||
// DOM WebIDL call.
|
||||
MOZ_COLD void ensureCapacitySlow();
|
||||
MOZ_COLD MOZ_MUST_USE bool ensureCapacitySlow();
|
||||
|
||||
// No copying.
|
||||
ProfilingStack(const ProfilingStack&) = delete;
|
||||
@ -513,16 +471,12 @@ class GeckoProfilerThread
|
||||
|
||||
ProfilingStack* profilingStack_;
|
||||
|
||||
// Same as profilingStack_ if the profiler is currently active, otherwise null.
|
||||
ProfilingStack* profilingStackIfEnabled_;
|
||||
|
||||
public:
|
||||
GeckoProfilerThread();
|
||||
|
||||
uint32_t stackPointer() { MOZ_ASSERT(infraInstalled()); return profilingStack_->stackPointer; }
|
||||
ProfilingStackFrame* stack() { return profilingStack_->frames; }
|
||||
ProfilingStack* getProfilingStack() { return profilingStack_; }
|
||||
ProfilingStack* getProfilingStackIfEnabled() { return profilingStackIfEnabled_; }
|
||||
|
||||
/*
|
||||
* True if the profiler infrastructure is setup. Should be true in builds
|
||||
@ -531,8 +485,7 @@ class GeckoProfilerThread
|
||||
*/
|
||||
bool infraInstalled() { return profilingStack_ != nullptr; }
|
||||
|
||||
void setProfilingStack(ProfilingStack* profilingStack, bool enabled);
|
||||
void enable(bool enable) { profilingStackIfEnabled_ = enable ? profilingStack_ : nullptr; }
|
||||
void setProfilingStack(ProfilingStack* profilingStack);
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
/*
|
||||
|
@ -866,8 +866,8 @@ class RootingContext
|
||||
|
||||
// Gecko profiling metadata.
|
||||
// This isn't really rooting related. It's only here because we want
|
||||
// GetContextProfilingStackIfEnabled to be inlineable into non-JS code, and
|
||||
// we didn't want to add another superclass of JSContext just for this.
|
||||
// GetContextProfilingStack to be inlineable into non-JS code, and we
|
||||
// didn't want to add another superclass of JSContext just for this.
|
||||
js::GeckoProfilerThread geckoProfiler_;
|
||||
|
||||
public:
|
||||
@ -1093,9 +1093,9 @@ GetContextZone(const JSContext* cx)
|
||||
}
|
||||
|
||||
inline ProfilingStack*
|
||||
GetContextProfilingStackIfEnabled(JSContext* cx)
|
||||
GetContextProfilingStack(JSContext* cx)
|
||||
{
|
||||
return JS::RootingContext::get(cx)->geckoProfiler().getProfilingStackIfEnabled();
|
||||
return JS::RootingContext::get(cx)->geckoProfiler().getProfilingStack();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,6 +98,7 @@ AutoGeckoProfilerEntry::AutoGeckoProfilerEntry(JSContext* cx, const char* label,
|
||||
profiler_->profilingStack_->pushLabelFrame(label,
|
||||
/* dynamicString = */ nullptr,
|
||||
/* sp = */ this,
|
||||
/* line = */ 0,
|
||||
category);
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,6 @@ using mozilla::DebugOnly;
|
||||
|
||||
GeckoProfilerThread::GeckoProfilerThread()
|
||||
: profilingStack_(nullptr)
|
||||
, profilingStackIfEnabled_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@ -45,10 +44,9 @@ GeckoProfilerRuntime::GeckoProfilerRuntime(JSRuntime* rt)
|
||||
}
|
||||
|
||||
void
|
||||
GeckoProfilerThread::setProfilingStack(ProfilingStack* profilingStack, bool enabled)
|
||||
GeckoProfilerThread::setProfilingStack(ProfilingStack* profilingStack)
|
||||
{
|
||||
profilingStack_ = profilingStack;
|
||||
profilingStackIfEnabled_ = enabled ? profilingStack : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
@ -256,7 +254,7 @@ GeckoProfilerThread::exit(JSScript* script, JSFunction* maybeFun)
|
||||
if (frame.isJsFrame()) {
|
||||
fprintf(stderr, " [%d] JS %s\n", i, frame.dynamicString());
|
||||
} else {
|
||||
fprintf(stderr, " [%d] Label %s\n", i, frame.dynamicString());
|
||||
fprintf(stderr, " [%d] C line %d %s\n", i, frame.line(), frame.dynamicString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -403,8 +401,8 @@ GeckoProfilerBaselineOSRMarker::GeckoProfilerBaselineOSRMarker(JSContext* cx, bo
|
||||
}
|
||||
|
||||
ProfilingStackFrame& frame = profiler->profilingStack_->frames[sp - 1];
|
||||
MOZ_ASSERT(!frame.isOSRFrame());
|
||||
frame.setIsOSRFrame(true);
|
||||
MOZ_ASSERT(frame.kind() == ProfilingStackFrame::Kind::JS_NORMAL);
|
||||
frame.setKind(ProfilingStackFrame::Kind::JS_OSR);
|
||||
}
|
||||
|
||||
GeckoProfilerBaselineOSRMarker::~GeckoProfilerBaselineOSRMarker()
|
||||
@ -420,8 +418,8 @@ GeckoProfilerBaselineOSRMarker::~GeckoProfilerBaselineOSRMarker()
|
||||
}
|
||||
|
||||
ProfilingStackFrame& frame = profiler->stack()[sp - 1];
|
||||
MOZ_ASSERT(frame.isOSRFrame());
|
||||
frame.setIsOSRFrame(false);
|
||||
MOZ_ASSERT(frame.kind() == ProfilingStackFrame::Kind::JS_OSR);
|
||||
frame.setKind(ProfilingStackFrame::Kind::JS_NORMAL);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSScript*)
|
||||
@ -449,12 +447,12 @@ JS_FRIEND_API(jsbytecode*)
|
||||
ProfilingStackFrame::pc() const
|
||||
{
|
||||
MOZ_ASSERT(isJsFrame());
|
||||
if (pcOffsetIfJS_ == NullPCOffset) {
|
||||
if (lineOrPcOffset == NullPCOffset) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSScript* script = this->script();
|
||||
return script ? script->offsetToPC(pcOffsetIfJS_) : nullptr;
|
||||
return script ? script->offsetToPC(lineOrPcOffset) : nullptr;
|
||||
}
|
||||
|
||||
/* static */ int32_t
|
||||
@ -468,20 +466,18 @@ ProfilingStackFrame::setPC(jsbytecode* pc)
|
||||
MOZ_ASSERT(isJsFrame());
|
||||
JSScript* script = this->script();
|
||||
MOZ_ASSERT(script); // This should not be called while profiling is suppressed.
|
||||
pcOffsetIfJS_ = pcToOffset(script, pc);
|
||||
lineOrPcOffset = pcToOffset(script, pc);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js::SetContextProfilingStack(JSContext* cx, ProfilingStack* profilingStack)
|
||||
{
|
||||
cx->geckoProfiler().setProfilingStack(profilingStack,
|
||||
cx->runtime()->geckoProfiler().enabled());
|
||||
cx->geckoProfiler().setProfilingStack(profilingStack);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js::EnableContextProfilingStack(JSContext* cx, bool enabled)
|
||||
{
|
||||
cx->geckoProfiler().enable(enabled);
|
||||
cx->runtime()->geckoProfiler().enable(enabled);
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ GlobalHelperThreadState* gHelperThreadState = nullptr;
|
||||
#define PROFILER_RAII_EXPAND(id, line) PROFILER_RAII_PASTE(id, line)
|
||||
#define PROFILER_RAII PROFILER_RAII_EXPAND(raiiObject, __LINE__)
|
||||
#define AUTO_PROFILER_LABEL(label, category) \
|
||||
HelperThread::AutoProfilerLabel PROFILER_RAII(this, label, \
|
||||
HelperThread::AutoProfilerLabel PROFILER_RAII(this, label, __LINE__, \
|
||||
js::ProfilingStackFrame::Category::category)
|
||||
|
||||
bool
|
||||
@ -2583,11 +2583,12 @@ const HelperThread::TaskSpec HelperThread::taskSpecs[] = {
|
||||
|
||||
HelperThread::AutoProfilerLabel::AutoProfilerLabel(HelperThread* helperThread,
|
||||
const char* label,
|
||||
uint32_t line,
|
||||
ProfilingStackFrame::Category category)
|
||||
: profilingStack(helperThread->profilingStack)
|
||||
{
|
||||
if (profilingStack) {
|
||||
profilingStack->pushLabelFrame(label, nullptr, this, category);
|
||||
profilingStack->pushLabelFrame(label, nullptr, this, line, category);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -421,6 +421,7 @@ struct HelperThread
|
||||
struct AutoProfilerLabel
|
||||
{
|
||||
AutoProfilerLabel(HelperThread* helperThread, const char* label,
|
||||
uint32_t line,
|
||||
ProfilingStackFrame::Category category);
|
||||
~AutoProfilerLabel();
|
||||
|
||||
|
@ -24,7 +24,7 @@ ProfilingStack::~ProfilingStack()
|
||||
delete[] frames;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
ProfilingStack::ensureCapacitySlow()
|
||||
{
|
||||
MOZ_ASSERT(stackPointer >= capacity);
|
||||
@ -33,7 +33,11 @@ ProfilingStack::ensureCapacitySlow()
|
||||
uint32_t sp = stackPointer;
|
||||
auto newCapacity = std::max(sp + 1, capacity ? capacity * 2 : kInitialCapacity);
|
||||
|
||||
auto* newFrames = new js::ProfilingStackFrame[newCapacity];
|
||||
auto* newFrames =
|
||||
new (mozilla::fallible) js::ProfilingStackFrame[newCapacity];
|
||||
if (MOZ_UNLIKELY(!newFrames)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// It's important that `frames` / `capacity` / `stackPointer` remain consistent here at
|
||||
// all times.
|
||||
@ -45,4 +49,6 @@ ProfilingStack::ensureCapacitySlow()
|
||||
frames = newFrames;
|
||||
capacity = newCapacity;
|
||||
delete[] oldFrames;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -669,7 +669,8 @@ continue_loading:
|
||||
// A few DLLs such as xul.dll and nss3.dll get loaded before mozglue's
|
||||
// AutoProfilerLabel is initialized, and this is a no-op in those cases. But
|
||||
// the vast majority of DLLs do get labelled here.
|
||||
AutoProfilerLabel label("WindowsDllBlocklist::patched_LdrLoadDll", dllName);
|
||||
AutoProfilerLabel label("WindowsDllBlocklist::patched_LdrLoadDll", dllName,
|
||||
__LINE__);
|
||||
|
||||
#ifdef _M_AMD64
|
||||
// Prevent the stack walker from suspending this thread when LdrLoadDll
|
||||
|
@ -20,12 +20,13 @@ RegisterProfilerLabelEnterExit(ProfilerLabelEnter aEnter,
|
||||
}
|
||||
|
||||
AutoProfilerLabel::AutoProfilerLabel(const char* aLabel,
|
||||
const char* aDynamicString
|
||||
const char* aDynamicString,
|
||||
uint32_t aLine
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
mProfilingStack = sEnter ? sEnter(aLabel, aDynamicString, this) : nullptr;
|
||||
mProfilingStack = sEnter ? sEnter(aLabel, aDynamicString, this, aLine) : nullptr;
|
||||
}
|
||||
|
||||
AutoProfilerLabel::~AutoProfilerLabel()
|
||||
|
@ -29,7 +29,8 @@ class ProfilingStack;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
typedef ProfilingStack* (*ProfilerLabelEnter)(const char*, const char*, void*);
|
||||
typedef ProfilingStack* (*ProfilerLabelEnter)(const char*, const char*, void*,
|
||||
uint32_t);
|
||||
typedef void (*ProfilerLabelExit)(ProfilingStack*);
|
||||
|
||||
// Register callbacks that do the entry/exit work involving sProfilingStack.
|
||||
@ -43,7 +44,8 @@ MFBT_API void RegisterProfilerLabelEnterExit(ProfilerLabelEnter aEnter,
|
||||
class MOZ_RAII AutoProfilerLabel
|
||||
{
|
||||
public:
|
||||
AutoProfilerLabel(const char* aLabel, const char* aDynamicString
|
||||
AutoProfilerLabel(const char* aLabel, const char* aDynamicString,
|
||||
uint32_t aLine
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
|
||||
~AutoProfilerLabel();
|
||||
|
||||
|
@ -68,12 +68,11 @@ ProfileBuffer::AddStoredMarker(ProfilerMarker *aStoredMarker)
|
||||
|
||||
void
|
||||
ProfileBuffer::CollectCodeLocation(
|
||||
const char* aLabel, const char* aStr, uint32_t aFrameFlags,
|
||||
const char* aLabel, const char* aStr,
|
||||
const Maybe<uint32_t>& aLineNumber, const Maybe<uint32_t>& aColumnNumber,
|
||||
const Maybe<js::ProfilingStackFrame::Category>& aCategory)
|
||||
{
|
||||
AddEntry(ProfileBufferEntry::Label(aLabel));
|
||||
AddEntry(ProfileBufferEntry::FrameFlags(uint64_t(aFrameFlags)));
|
||||
|
||||
if (aStr) {
|
||||
// Store the string using one or more DynamicStringFragment entries.
|
||||
@ -155,8 +154,7 @@ ProfileBufferCollector::CollectJitReturnAddr(void* aAddr)
|
||||
void
|
||||
ProfileBufferCollector::CollectWasmFrame(const char* aLabel)
|
||||
{
|
||||
mBuf.CollectCodeLocation("", aLabel, 0,
|
||||
Nothing(), Nothing(), Nothing());
|
||||
mBuf.CollectCodeLocation("", aLabel, Nothing(), Nothing(), Nothing());
|
||||
}
|
||||
|
||||
void
|
||||
@ -164,8 +162,8 @@ ProfileBufferCollector::CollectProfilingStackFrame(const js::ProfilingStackFrame
|
||||
{
|
||||
// WARNING: this function runs within the profiler's "critical section".
|
||||
|
||||
MOZ_ASSERT(aFrame.isLabelFrame() ||
|
||||
(aFrame.isJSFrame() && !aFrame.isOSRFrame()));
|
||||
MOZ_ASSERT(aFrame.kind() == js::ProfilingStackFrame::Kind::LABEL ||
|
||||
aFrame.kind() == js::ProfilingStackFrame::Kind::JS_NORMAL);
|
||||
|
||||
const char* label = aFrame.label();
|
||||
const char* dynamicString = aFrame.dynamicString();
|
||||
@ -200,6 +198,7 @@ ProfileBufferCollector::CollectProfilingStackFrame(const js::ProfilingStackFrame
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(aFrame.isLabelFrame());
|
||||
line = Some(aFrame.line());
|
||||
}
|
||||
|
||||
if (dynamicString) {
|
||||
@ -211,6 +210,6 @@ ProfileBufferCollector::CollectProfilingStackFrame(const js::ProfilingStackFrame
|
||||
}
|
||||
}
|
||||
|
||||
mBuf.CollectCodeLocation(label, dynamicString, aFrame.flags(),
|
||||
line, column, Some(aFrame.category()));
|
||||
mBuf.CollectCodeLocation(label, dynamicString, line, column,
|
||||
Some(aFrame.category()));
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
uint64_t AddThreadIdEntry(int aThreadId);
|
||||
|
||||
void CollectCodeLocation(
|
||||
const char* aLabel, const char* aStr, uint32_t aFrameFlags,
|
||||
const char* aLabel, const char* aStr,
|
||||
const mozilla::Maybe<uint32_t>& aLineNumber,
|
||||
const mozilla::Maybe<uint32_t>& aColumnNumber,
|
||||
const mozilla::Maybe<js::ProfilingStackFrame::Category>& aCategory);
|
||||
|
@ -823,7 +823,7 @@ private:
|
||||
// ThreadId
|
||||
// Time
|
||||
// ( NativeLeafAddr
|
||||
// | Label FrameFlags? DynamicStringFragment* LineNumber? Category?
|
||||
// | Label DynamicStringFragment* LineNumber? Category?
|
||||
// | JitReturnAddr
|
||||
// )+
|
||||
// Marker*
|
||||
@ -866,14 +866,12 @@ private:
|
||||
// - ProfilingStack frames with a dynamic string:
|
||||
//
|
||||
// Label("nsObserverService::NotifyObservers")
|
||||
// FrameFlags(uint64_t(ProfilingStackFrame::Flags::IS_LABEL_FRAME))
|
||||
// DynamicStringFragment("domwindo")
|
||||
// DynamicStringFragment("wopened")
|
||||
// LineNumber(291)
|
||||
// Category(ProfilingStackFrame::Category::OTHER)
|
||||
//
|
||||
// Label("")
|
||||
// FrameFlags(uint64_t(ProfilingStackFrame::Flags::IS_JS_FRAME))
|
||||
// DynamicStringFragment("closeWin")
|
||||
// DynamicStringFragment("dow (chr")
|
||||
// DynamicStringFragment("ome://gl")
|
||||
@ -886,7 +884,6 @@ private:
|
||||
// Category(ProfilingStackFrame::Category::JS)
|
||||
//
|
||||
// Label("")
|
||||
// FrameFlags(uint64_t(ProfilingStackFrame::Flags::IS_JS_FRAME))
|
||||
// DynamicStringFragment("bound (s")
|
||||
// DynamicStringFragment("elf-host")
|
||||
// DynamicStringFragment("ed:914)")
|
||||
@ -896,7 +893,6 @@ private:
|
||||
// - A profiling stack frame with a dynamic string, but with privacy enabled:
|
||||
//
|
||||
// Label("nsObserverService::NotifyObservers")
|
||||
// FrameFlags(uint64_t(ProfilingStackFrame::Flags::IS_LABEL_FRAME))
|
||||
// DynamicStringFragment("(private")
|
||||
// DynamicStringFragment(")")
|
||||
// LineNumber(291)
|
||||
@ -905,7 +901,6 @@ private:
|
||||
// - A profiling stack frame with an overly long dynamic string:
|
||||
//
|
||||
// Label("")
|
||||
// FrameFlags(uint64_t(ProfilingStackFrame::Flags::IS_LABEL_FRAME))
|
||||
// DynamicStringFragment("(too lon")
|
||||
// DynamicStringFragment("g)")
|
||||
// LineNumber(100)
|
||||
@ -914,7 +909,6 @@ private:
|
||||
// - A wasm JIT frame:
|
||||
//
|
||||
// Label("")
|
||||
// FrameFlags(uint64_t(0))
|
||||
// DynamicStringFragment("wasm-fun")
|
||||
// DynamicStringFragment("ction[87")
|
||||
// DynamicStringFragment("36] (blo")
|
||||
@ -931,7 +925,6 @@ private:
|
||||
// - A JS frame in a synchronous sample:
|
||||
//
|
||||
// Label("")
|
||||
// FrameFlags(uint64_t(ProfilingStackFrame::Flags::IS_LABEL_FRAME))
|
||||
// DynamicStringFragment("u (https")
|
||||
// DynamicStringFragment("://perf-")
|
||||
// DynamicStringFragment("html.io/")
|
||||
@ -956,7 +949,7 @@ ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId,
|
||||
double aSinceTime,
|
||||
UniqueStacks& aUniqueStacks) const
|
||||
{
|
||||
UniquePtr<char[]> dynStrBuf = MakeUnique<char[]>(kMaxFrameKeyLength);
|
||||
UniquePtr<char[]> strbuf = MakeUnique<char[]>(kMaxFrameKeyLength);
|
||||
|
||||
EntryGetter e(*this);
|
||||
|
||||
@ -1031,26 +1024,30 @@ ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId,
|
||||
} else if (e.Get().IsLabel()) {
|
||||
numFrames++;
|
||||
|
||||
// Copy the label into strbuf.
|
||||
const char* label = e.Get().u.mString;
|
||||
strncpy(strbuf.get(), label, kMaxFrameKeyLength);
|
||||
size_t i = strlen(label);
|
||||
e.Next();
|
||||
|
||||
using FrameFlags = js::ProfilingStackFrame::Flags;
|
||||
uint32_t frameFlags = 0;
|
||||
if (e.Has() && e.Get().IsFrameFlags()) {
|
||||
frameFlags = uint32_t(e.Get().u.mUint64);
|
||||
e.Next();
|
||||
}
|
||||
|
||||
// Copy potential dynamic string fragments into dynStrBuf, so that
|
||||
// dynStrBuf will then contain the entire dynamic string.
|
||||
size_t i = 0;
|
||||
dynStrBuf[0] = '\0';
|
||||
bool seenFirstDynamicStringFragment = false;
|
||||
while (e.Has()) {
|
||||
if (e.Get().IsDynamicStringFragment()) {
|
||||
// If this is the first dynamic string fragment and we have a
|
||||
// non-empty label, insert a ' ' after the label and before the
|
||||
// dynamic string.
|
||||
if (!seenFirstDynamicStringFragment) {
|
||||
if (i > 0 && i < kMaxFrameKeyLength) {
|
||||
strbuf[i] = ' ';
|
||||
i++;
|
||||
}
|
||||
seenFirstDynamicStringFragment = true;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < ProfileBufferEntry::kNumChars; j++) {
|
||||
const char* chars = e.Get().u.mChars;
|
||||
if (i < kMaxFrameKeyLength) {
|
||||
dynStrBuf[i] = chars[j];
|
||||
strbuf[i] = chars[j];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@ -1059,25 +1056,7 @@ ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId,
|
||||
break;
|
||||
}
|
||||
}
|
||||
dynStrBuf[kMaxFrameKeyLength - 1] = '\0';
|
||||
bool hasDynamicString = (i != 0);
|
||||
|
||||
nsCString frameLabel;
|
||||
if (label[0] != '\0' && hasDynamicString) {
|
||||
if (frameFlags & uint32_t(FrameFlags::STRING_TEMPLATE_METHOD)) {
|
||||
frameLabel.AppendPrintf("%s.%s", label, dynStrBuf.get());
|
||||
} else if (frameFlags & uint32_t(FrameFlags::STRING_TEMPLATE_GETTER)) {
|
||||
frameLabel.AppendPrintf("get %s.%s", label, dynStrBuf.get());
|
||||
} else if (frameFlags & uint32_t(FrameFlags::STRING_TEMPLATE_SETTER)) {
|
||||
frameLabel.AppendPrintf("set %s.%s", label, dynStrBuf.get());
|
||||
} else {
|
||||
frameLabel.AppendPrintf("%s %s", label, dynStrBuf.get());
|
||||
}
|
||||
} else if (hasDynamicString) {
|
||||
frameLabel.Append(dynStrBuf.get());
|
||||
} else {
|
||||
frameLabel.Append(label);
|
||||
}
|
||||
strbuf[kMaxFrameKeyLength - 1] = '\0';
|
||||
|
||||
Maybe<unsigned> line;
|
||||
if (e.Has() && e.Get().IsLineNumber()) {
|
||||
@ -1098,8 +1077,7 @@ ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId,
|
||||
}
|
||||
|
||||
stack = aUniqueStacks.AppendFrame(
|
||||
stack, UniqueStacks::FrameKey(std::move(frameLabel), line, column,
|
||||
category));
|
||||
stack, UniqueStacks::FrameKey(strbuf.get(), line, column, category));
|
||||
|
||||
} else if (e.Get().IsJitReturnAddr()) {
|
||||
numFrames++;
|
||||
|
@ -37,7 +37,6 @@ class ProfilerMarker;
|
||||
macro(CollectionStart, double) \
|
||||
macro(CollectionEnd, double) \
|
||||
macro(Label, const char*) \
|
||||
macro(FrameFlags, uint64_t) \
|
||||
macro(DynamicStringFragment, char*) /* char[kNumChars], really */ \
|
||||
macro(JitReturnAddr, void*) \
|
||||
macro(LineNumber, int) \
|
||||
@ -236,10 +235,10 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
FrameKey(nsCString&& aLocation, const mozilla::Maybe<unsigned>& aLine,
|
||||
FrameKey(const char* aLocation, const mozilla::Maybe<unsigned>& aLine,
|
||||
const mozilla::Maybe<unsigned>& aColumn,
|
||||
const mozilla::Maybe<unsigned>& aCategory)
|
||||
: mData(NormalFrameData{ aLocation, aLine, aColumn, aCategory })
|
||||
: mData(NormalFrameData{ nsCString(aLocation), aLine, aColumn, aCategory })
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -985,7 +985,7 @@ MergeStacks(uint32_t aFeatures, bool aIsSynchronous,
|
||||
// To avoid both the profiling stack frame and jit frame being recorded
|
||||
// (and showing up twice), the interpreter marks the interpreter
|
||||
// profiling stack frame as JS_OSR to ensure that it doesn't get counted.
|
||||
if (profilingStackFrame.isOSRFrame()) {
|
||||
if (profilingStackFrame.kind() == js::ProfilingStackFrame::Kind::JS_OSR) {
|
||||
profilingStackIndex++;
|
||||
continue;
|
||||
}
|
||||
@ -1840,9 +1840,8 @@ CollectJavaThreadProfileData()
|
||||
parentFrameWasIdleFrame = false;
|
||||
}
|
||||
|
||||
buffer->CollectCodeLocation("", frameNameString.get(),
|
||||
js::ProfilingStackFrame::StringTemplate::DEFAULT,
|
||||
Nothing(), Nothing(), category);
|
||||
buffer->CollectCodeLocation("", frameNameString.get(), Nothing(),
|
||||
Nothing(), category);
|
||||
}
|
||||
sampleId++;
|
||||
}
|
||||
@ -2494,11 +2493,12 @@ locked_profiler_start(PSLockRef aLock, uint32_t aCapacity, double aInterval,
|
||||
|
||||
// This basically duplicates AutoProfilerLabel's constructor.
|
||||
ProfilingStack*
|
||||
MozGlueLabelEnter(const char* aLabel, const char* aDynamicString, void* aSp)
|
||||
MozGlueLabelEnter(const char* aLabel, const char* aDynamicString, void* aSp,
|
||||
uint32_t aLine)
|
||||
{
|
||||
ProfilingStack* profilingStack = AutoProfilerLabel::sProfilingStack.get();
|
||||
if (profilingStack) {
|
||||
profilingStack->pushLabelFrame(aLabel, aDynamicString, aSp,
|
||||
profilingStack->pushLabelFrame(aLabel, aDynamicString, aSp, aLine,
|
||||
js::ProfilingStackFrame::Category::OTHER);
|
||||
}
|
||||
return profilingStack;
|
||||
|
@ -46,7 +46,6 @@
|
||||
#define AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(label, category, nsCStr)
|
||||
#define AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(label, category, nsStr)
|
||||
#define AUTO_PROFILER_LABEL_FAST(label, category, ctx)
|
||||
#define AUTO_PROFILER_LABEL_DYNAMIC_FAST(label, dynamicString, category, ctx, flags)
|
||||
|
||||
#define PROFILER_ADD_MARKER(markerName)
|
||||
#define PROFILER_ADD_NETWORK_MARKER(uri, pri, channel, type, start, end, count, timings, redirect)
|
||||
@ -474,7 +473,7 @@ mozilla::Maybe<ProfilerBufferInfo> profiler_get_buffer_info();
|
||||
// Use AUTO_PROFILER_LABEL_DYNAMIC_* if you want to add additional / dynamic
|
||||
// information to the label stack frame.
|
||||
#define AUTO_PROFILER_LABEL(label, category) \
|
||||
mozilla::AutoProfilerLabel PROFILER_RAII(label, nullptr, \
|
||||
mozilla::AutoProfilerLabel PROFILER_RAII(label, nullptr, __LINE__, \
|
||||
js::ProfilingStackFrame::Category::category)
|
||||
|
||||
// Similar to AUTO_PROFILER_LABEL, but with an additional string. The inserted
|
||||
@ -498,7 +497,7 @@ mozilla::Maybe<ProfilerBufferInfo> profiler_get_buffer_info();
|
||||
// the profile buffer than AUTO_PROFILER_LABEL_DYNAMIC_* frames.
|
||||
#define AUTO_PROFILER_LABEL_DYNAMIC_CSTR(label, category, cStr) \
|
||||
mozilla::AutoProfilerLabel \
|
||||
PROFILER_RAII(label, cStr, js::ProfilingStackFrame::Category::category)
|
||||
PROFILER_RAII(label, cStr, __LINE__, js::ProfilingStackFrame::Category::category)
|
||||
|
||||
// Similar to AUTO_PROFILER_LABEL_DYNAMIC_CSTR, but takes an nsACString.
|
||||
//
|
||||
@ -512,7 +511,7 @@ mozilla::Maybe<ProfilerBufferInfo> profiler_get_buffer_info();
|
||||
mozilla::Maybe<AutoProfilerLabel> raiiObjectNsCString; \
|
||||
if (profiler_is_active()) { \
|
||||
autoCStr.emplace(nsCStr); \
|
||||
raiiObjectNsCString.emplace(label, autoCStr->get(), \
|
||||
raiiObjectNsCString.emplace(label, autoCStr->get(), __LINE__, \
|
||||
js::ProfilingStackFrame::Category::category); \
|
||||
}
|
||||
|
||||
@ -529,7 +528,7 @@ mozilla::Maybe<ProfilerBufferInfo> profiler_get_buffer_info();
|
||||
mozilla::Maybe<AutoProfilerLabel> raiiObjectLossyNsString; \
|
||||
if (profiler_is_active()) { \
|
||||
asciiStr.emplace(nsStr); \
|
||||
raiiObjectLossyNsString.emplace(label, asciiStr->get(), \
|
||||
raiiObjectLossyNsString.emplace(label, asciiStr->get(), __LINE__, \
|
||||
js::ProfilingStackFrame::Category::category); \
|
||||
}
|
||||
|
||||
@ -540,17 +539,9 @@ mozilla::Maybe<ProfilerBufferInfo> profiler_get_buffer_info();
|
||||
// ProfilingStack from the JS context, and avoids almost all overhead in the case
|
||||
// where the profiler is disabled.
|
||||
#define AUTO_PROFILER_LABEL_FAST(label, category, ctx) \
|
||||
mozilla::AutoProfilerLabel PROFILER_RAII(ctx, label, nullptr, \
|
||||
mozilla::AutoProfilerLabel PROFILER_RAII(ctx, label, nullptr, __LINE__, \
|
||||
js::ProfilingStackFrame::Category::category)
|
||||
|
||||
// Similar to AUTO_PROFILER_LABEL_FAST, but also takes an extra string and an
|
||||
// additional set of flags. The flags parameter should carry values from the
|
||||
// js::ProfilingStackFrame::Flags enum.
|
||||
#define AUTO_PROFILER_LABEL_DYNAMIC_FAST(label, dynamicString, category, ctx, flags) \
|
||||
mozilla::AutoProfilerLabel PROFILER_RAII(ctx, label, dynamicString, \
|
||||
js::ProfilingStackFrame::Category::category, \
|
||||
flags)
|
||||
|
||||
// Insert a marker in the profile timeline. This is useful to delimit something
|
||||
// important happening such as the first paint. Unlike labels, which are only
|
||||
// recorded in the profile buffer if a sample is collected while the label is
|
||||
@ -728,39 +719,41 @@ class MOZ_RAII AutoProfilerLabel
|
||||
public:
|
||||
// This is the AUTO_PROFILER_LABEL and AUTO_PROFILER_LABEL_DYNAMIC variant.
|
||||
AutoProfilerLabel(const char* aLabel, const char* aDynamicString,
|
||||
js::ProfilingStackFrame::Category aCategory
|
||||
uint32_t aLine, js::ProfilingStackFrame::Category aCategory
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
// Get the ProfilingStack from TLS.
|
||||
Push(sProfilingStack.get(), aLabel, aDynamicString, aCategory);
|
||||
Push(sProfilingStack.get(), aLabel, aDynamicString, aLine, aCategory);
|
||||
}
|
||||
|
||||
// This is the AUTO_PROFILER_LABEL_FAST variant. It retrieves the ProfilingStack
|
||||
// from the JSContext and does nothing if the profiler is inactive.
|
||||
// This is the AUTO_PROFILER_LABEL_FAST variant. It's guarded on
|
||||
// profiler_is_active() and retrieves the ProfilingStack from the JSContext.
|
||||
AutoProfilerLabel(JSContext* aJSContext,
|
||||
const char* aLabel, const char* aDynamicString,
|
||||
js::ProfilingStackFrame::Category aCategory,
|
||||
uint32_t aFlags
|
||||
uint32_t aLine, js::ProfilingStackFrame::Category aCategory
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
Push(js::GetContextProfilingStackIfEnabled(aJSContext),
|
||||
aLabel, aDynamicString, aCategory, aFlags);
|
||||
if (profiler_is_active()) {
|
||||
Push(js::GetContextProfilingStack(aJSContext),
|
||||
aLabel, aDynamicString, aLine, aCategory);
|
||||
} else {
|
||||
mProfilingStack = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Push(ProfilingStack* aProfilingStack,
|
||||
const char* aLabel, const char* aDynamicString,
|
||||
js::ProfilingStackFrame::Category aCategory,
|
||||
uint32_t aFlags = 0)
|
||||
uint32_t aLine, js::ProfilingStackFrame::Category aCategory)
|
||||
{
|
||||
// This function runs both on and off the main thread.
|
||||
|
||||
mProfilingStack = aProfilingStack;
|
||||
if (mProfilingStack) {
|
||||
mProfilingStack->pushLabelFrame(aLabel, aDynamicString, this, aCategory,
|
||||
aFlags);
|
||||
mProfilingStack->pushLabelFrame(aLabel, aDynamicString, this, aLine,
|
||||
aCategory);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -748,9 +748,9 @@ TEST(GeckoProfiler, ProfilingStack)
|
||||
ASSERT_TRUE(profiler_get_backtrace());
|
||||
}
|
||||
|
||||
AutoProfilerLabel label1("A", nullptr,
|
||||
AutoProfilerLabel label1("A", nullptr, 888,
|
||||
js::ProfilingStackFrame::Category::DOM);
|
||||
AutoProfilerLabel label2("A", dynamic.get(),
|
||||
AutoProfilerLabel label2("A", dynamic.get(), 888,
|
||||
js::ProfilingStackFrame::Category::NETWORK);
|
||||
ASSERT_TRUE(profiler_get_backtrace());
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user