mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 16:25:38 +00:00
Bug 1545582 - Integrate JavaScript memory allocation tracking to the profiler; r=canaltinova
Differential Revision: https://phabricator.services.mozilla.com/D34543 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
c46b8c0571
commit
8bc06cf8cd
@ -116,11 +116,12 @@ void profiler_get_profile_json_into_lazily_allocated_buffer(
|
||||
const std::function<char*(size_t)>& aAllocator, double aSinceTime,
|
||||
bool aIsShuttingDown);
|
||||
|
||||
// Flags to conveniently track various JS features.
|
||||
enum class JSSamplingFlags {
|
||||
// Flags to conveniently track various JS instrumentations.
|
||||
enum class JSInstrumentationFlags {
|
||||
StackSampling = 0x1,
|
||||
TrackOptimizations = 0x2,
|
||||
TraceLogging = 0x4
|
||||
TraceLogging = 0x4,
|
||||
Allocations = 0x8
|
||||
};
|
||||
|
||||
// Record an exit profile from a child process.
|
||||
|
@ -36,7 +36,8 @@
|
||||
"tasktracer",
|
||||
"threads",
|
||||
"trackopts",
|
||||
"jstracer"
|
||||
"jstracer",
|
||||
"jsallocations"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -296,3 +296,28 @@ void LongTaskMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
|
||||
aUniqueStacks);
|
||||
aWriter.StringProperty("category", "LongTask");
|
||||
}
|
||||
|
||||
void JsAllocationMarkerPayload::StreamPayload(
|
||||
SpliceableJSONWriter& aWriter, const TimeStamp& aProcessStartTime,
|
||||
UniqueStacks& aUniqueStacks) {
|
||||
StreamCommonProps("JS allocation", aWriter, aProcessStartTime, aUniqueStacks);
|
||||
|
||||
if (mClassName) {
|
||||
aWriter.StringProperty("className", mClassName.get());
|
||||
}
|
||||
if (mScriptFilename) {
|
||||
aWriter.StringProperty("scriptFilename", mScriptFilename.get());
|
||||
}
|
||||
if (mTypeName) {
|
||||
aWriter.StringProperty("typeName",
|
||||
NS_ConvertUTF16toUTF8(mTypeName.get()).get());
|
||||
}
|
||||
if (mDescriptiveTypeName) {
|
||||
aWriter.StringProperty(
|
||||
"descriptiveTypeName",
|
||||
NS_ConvertUTF16toUTF8(mDescriptiveTypeName.get()).get());
|
||||
}
|
||||
aWriter.StringProperty("coarseType", mCoarseType);
|
||||
aWriter.IntProperty("size", mSize);
|
||||
aWriter.BoolProperty("inNursery", mInNursery);
|
||||
}
|
||||
|
@ -250,6 +250,11 @@ class RegisteredThread final {
|
||||
if (JSTracerEnabled()) {
|
||||
JS::StartTraceLogger(mContext);
|
||||
}
|
||||
if (JSAllocationsEnabled()) {
|
||||
// TODO - This probability should not be hardcoded. See Bug 1547284.
|
||||
JS::EnableRecordingAllocations(
|
||||
mContext, profiler_add_js_allocation_marker, 0.01);
|
||||
}
|
||||
js::RegisterContextProfilingEventMarker(mContext,
|
||||
profiler_add_js_marker);
|
||||
|
||||
@ -259,6 +264,9 @@ class RegisteredThread final {
|
||||
if (JSTracerEnabled()) {
|
||||
JS::StopTraceLogger(mContext);
|
||||
}
|
||||
if (JSAllocationsEnabled()) {
|
||||
JS::DisableRecordingAllocations(mContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -326,11 +334,15 @@ class RegisteredThread final {
|
||||
uint32_t mJSFlags;
|
||||
|
||||
bool TrackOptimizationsEnabled() {
|
||||
return mJSFlags & uint32_t(JSSamplingFlags::TrackOptimizations);
|
||||
return mJSFlags & uint32_t(JSInstrumentationFlags::TrackOptimizations);
|
||||
}
|
||||
|
||||
bool JSTracerEnabled() {
|
||||
return mJSFlags & uint32_t(JSSamplingFlags::TraceLogging);
|
||||
return mJSFlags & uint32_t(JSInstrumentationFlags::TraceLogging);
|
||||
}
|
||||
|
||||
bool JSAllocationsEnabled() {
|
||||
return mJSFlags & uint32_t(JSInstrumentationFlags::Allocations);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "VTuneProfiler.h"
|
||||
|
||||
#include "js/TraceLoggerAPI.h"
|
||||
#include "js/ProfilingFrameIterator.h"
|
||||
#include "memory_hooks.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
@ -654,12 +655,17 @@ class ActivePS {
|
||||
|
||||
static uint32_t JSFlags(PSLockRef aLock) {
|
||||
uint32_t Flags = 0;
|
||||
Flags |= FeatureJS(aLock) ? uint32_t(JSSamplingFlags::StackSampling) : 0;
|
||||
Flags |= FeatureTrackOptimizations(aLock)
|
||||
? uint32_t(JSSamplingFlags::TrackOptimizations)
|
||||
: 0;
|
||||
Flags |=
|
||||
FeatureJSTracer(aLock) ? uint32_t(JSSamplingFlags::TraceLogging) : 0;
|
||||
FeatureJS(aLock) ? uint32_t(JSInstrumentationFlags::StackSampling) : 0;
|
||||
Flags |= FeatureTrackOptimizations(aLock)
|
||||
? uint32_t(JSInstrumentationFlags::TrackOptimizations)
|
||||
: 0;
|
||||
Flags |= FeatureJSTracer(aLock)
|
||||
? uint32_t(JSInstrumentationFlags::TraceLogging)
|
||||
: 0;
|
||||
Flags |= FeatureJSAllocations(aLock)
|
||||
? uint32_t(JSInstrumentationFlags::Allocations)
|
||||
: 0;
|
||||
return Flags;
|
||||
}
|
||||
|
||||
@ -4006,6 +4012,13 @@ void profiler_add_js_marker(const char* aMarkerName) {
|
||||
profiler_add_marker(aMarkerName, JS::ProfilingCategoryPair::JS, nullptr);
|
||||
}
|
||||
|
||||
void profiler_add_js_allocation_marker(JS::RecordAllocationInfo&& info) {
|
||||
profiler_add_marker(
|
||||
"JS allocation", JS::ProfilingCategoryPair::JS,
|
||||
MakeUnique<JsAllocationMarkerPayload>(TimeStamp::Now(), std::move(info),
|
||||
profiler_get_backtrace()));
|
||||
}
|
||||
|
||||
void profiler_add_network_marker(
|
||||
nsIURI* aURI, int32_t aPriority, uint64_t aChannelId, NetworkLoadType aType,
|
||||
mozilla::TimeStamp aStart, mozilla::TimeStamp aEnd, int64_t aCount,
|
||||
|
@ -88,11 +88,12 @@ void profiler_get_profile_json_into_lazily_allocated_buffer(
|
||||
const std::function<char*(size_t)>& aAllocator, double aSinceTime,
|
||||
bool aIsShuttingDown);
|
||||
|
||||
// Flags to conveniently track various JS features.
|
||||
enum class JSSamplingFlags {
|
||||
// Flags to conveniently track various JS instrumentations.
|
||||
enum class JSInstrumentationFlags {
|
||||
StackSampling = 0x1,
|
||||
TrackOptimizations = 0x2,
|
||||
TraceLogging = 0x4
|
||||
TraceLogging = 0x4,
|
||||
Allocations = 0x8
|
||||
};
|
||||
|
||||
// Record an exit profile from a child process.
|
||||
|
@ -69,6 +69,8 @@
|
||||
|
||||
#else // !MOZ_GECKO_PROFILER
|
||||
|
||||
# include "js/AllocationRecording.h"
|
||||
# include "js/ProfilingFrameIterator.h"
|
||||
# include "js/ProfilingStack.h"
|
||||
# include "js/RootingAPI.h"
|
||||
# include "js/TypeDecls.h"
|
||||
@ -118,44 +120,47 @@ class Vector;
|
||||
// values are used internally only and so can be changed without consequence.
|
||||
// Any changes to this list should also be applied to the feature list in
|
||||
// toolkit/components/extensions/schemas/geckoProfiler.json.
|
||||
# define PROFILER_FOR_EACH_FEATURE(MACRO) \
|
||||
MACRO(0, "java", Java, "Profile Java code, Android only") \
|
||||
\
|
||||
MACRO(1, "js", JS, \
|
||||
"Get the JS engine to expose the JS stack to the profiler") \
|
||||
\
|
||||
/* The DevTools profiler doesn't want the native addresses. */ \
|
||||
MACRO(2, "leaf", Leaf, "Include the C++ leaf node if not stackwalking") \
|
||||
\
|
||||
MACRO(3, "mainthreadio", MainThreadIO, \
|
||||
"Add main thread I/O to the profile") \
|
||||
\
|
||||
MACRO(4, "memory", Memory, "Add memory measurements") \
|
||||
\
|
||||
MACRO(5, "privacy", Privacy, \
|
||||
"Do not include user-identifiable information") \
|
||||
\
|
||||
MACRO(6, "responsiveness", Responsiveness, \
|
||||
"Collect thread responsiveness information") \
|
||||
\
|
||||
MACRO(7, "screenshots", Screenshots, \
|
||||
"Take a snapshot of the window on every composition") \
|
||||
\
|
||||
MACRO(8, "seqstyle", SequentialStyle, \
|
||||
"Disable parallel traversal in styling") \
|
||||
\
|
||||
MACRO(9, "stackwalk", StackWalk, \
|
||||
"Walk the C++ stack, not available on all platforms") \
|
||||
\
|
||||
MACRO(10, "tasktracer", TaskTracer, \
|
||||
"Start profiling with feature TaskTracer") \
|
||||
\
|
||||
MACRO(11, "threads", Threads, "Profile the registered secondary threads") \
|
||||
\
|
||||
MACRO(12, "trackopts", TrackOptimizations, \
|
||||
"Have the JavaScript engine track JIT optimizations") \
|
||||
\
|
||||
MACRO(13, "jstracer", JSTracer, "Enable tracing of the JavaScript engine")
|
||||
# define PROFILER_FOR_EACH_FEATURE(MACRO) \
|
||||
MACRO(0, "java", Java, "Profile Java code, Android only") \
|
||||
\
|
||||
MACRO(1, "js", JS, \
|
||||
"Get the JS engine to expose the JS stack to the profiler") \
|
||||
\
|
||||
/* The DevTools profiler doesn't want the native addresses. */ \
|
||||
MACRO(2, "leaf", Leaf, "Include the C++ leaf node if not stackwalking") \
|
||||
\
|
||||
MACRO(3, "mainthreadio", MainThreadIO, \
|
||||
"Add main thread I/O to the profile") \
|
||||
\
|
||||
MACRO(4, "memory", Memory, "Add memory measurements") \
|
||||
\
|
||||
MACRO(5, "privacy", Privacy, \
|
||||
"Do not include user-identifiable information") \
|
||||
\
|
||||
MACRO(6, "responsiveness", Responsiveness, \
|
||||
"Collect thread responsiveness information") \
|
||||
\
|
||||
MACRO(7, "screenshots", Screenshots, \
|
||||
"Take a snapshot of the window on every composition") \
|
||||
\
|
||||
MACRO(8, "seqstyle", SequentialStyle, \
|
||||
"Disable parallel traversal in styling") \
|
||||
\
|
||||
MACRO(9, "stackwalk", StackWalk, \
|
||||
"Walk the C++ stack, not available on all platforms") \
|
||||
\
|
||||
MACRO(10, "tasktracer", TaskTracer, \
|
||||
"Start profiling with feature TaskTracer") \
|
||||
\
|
||||
MACRO(11, "threads", Threads, "Profile the registered secondary threads") \
|
||||
\
|
||||
MACRO(12, "trackopts", TrackOptimizations, \
|
||||
"Have the JavaScript engine track JIT optimizations") \
|
||||
\
|
||||
MACRO(13, "jstracer", JSTracer, "Enable tracing of the JavaScript engine") \
|
||||
\
|
||||
MACRO(14, "jsallocations", JSAllocations, \
|
||||
"Have the JavaScript engine track allocations")
|
||||
|
||||
struct ProfilerFeature {
|
||||
# define DECLARE(n_, str_, Name_, desc_) \
|
||||
@ -643,6 +648,7 @@ void profiler_add_marker(const char* aMarkerName,
|
||||
JS::ProfilingCategoryPair aCategoryPair,
|
||||
mozilla::UniquePtr<ProfilerMarkerPayload> aPayload);
|
||||
void profiler_add_js_marker(const char* aMarkerName);
|
||||
void profiler_add_js_allocation_marker(JS::RecordAllocationInfo&& info);
|
||||
|
||||
// Insert a marker in the profile timeline for a specified thread.
|
||||
void profiler_add_marker_for_thread(
|
||||
|
@ -16,9 +16,12 @@
|
||||
#include "mozilla/net/TimingStruct.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsCRTGlue.h"
|
||||
#include "GeckoProfiler.h"
|
||||
|
||||
#include "js/Utility.h"
|
||||
#include "js/AllocationRecording.h"
|
||||
#include "js/ProfilingFrameIterator.h"
|
||||
#include "gfxASurface.h"
|
||||
#include "mozilla/ServoTraversalStatistics.h"
|
||||
|
||||
@ -413,4 +416,42 @@ class LogMarkerPayload : public ProfilerMarkerPayload {
|
||||
nsCString mText;
|
||||
};
|
||||
|
||||
class JsAllocationMarkerPayload : public ProfilerMarkerPayload {
|
||||
public:
|
||||
JsAllocationMarkerPayload(const mozilla::TimeStamp& aStartTime,
|
||||
const JS::RecordAllocationInfo& aInfo,
|
||||
UniqueProfilerBacktrace aStack)
|
||||
: ProfilerMarkerPayload(aStartTime, aStartTime, mozilla::Nothing(),
|
||||
mozilla::Nothing(), std::move(aStack)),
|
||||
// Copy the strings, and take ownership of them.
|
||||
mTypeName(aInfo.typeName ? NS_xstrdup(aInfo.typeName) : nullptr),
|
||||
mClassName(aInfo.className ? strdup(aInfo.className) : nullptr),
|
||||
mDescriptiveTypeName(aInfo.descriptiveTypeName
|
||||
? NS_xstrdup(aInfo.descriptiveTypeName)
|
||||
: nullptr),
|
||||
mScriptFilename(aInfo.scriptFilename ? strdup(aInfo.scriptFilename)
|
||||
: nullptr),
|
||||
// The coarseType points to a string literal, so does not need to be
|
||||
// duplicated.
|
||||
mCoarseType(aInfo.coarseType),
|
||||
mSize(aInfo.size),
|
||||
mInNursery(aInfo.inNursery) {}
|
||||
|
||||
DECL_STREAM_PAYLOAD
|
||||
|
||||
private:
|
||||
mozilla::UniqueFreePtr<const char16_t> mTypeName;
|
||||
mozilla::UniqueFreePtr<const char> mClassName;
|
||||
mozilla::UniqueFreePtr<const char16_t> mDescriptiveTypeName;
|
||||
mozilla::UniqueFreePtr<const char> mScriptFilename;
|
||||
// Points to a string literal, so does not need to be freed.
|
||||
const char* mCoarseType;
|
||||
|
||||
// The size in bytes of the allocation.
|
||||
uint64_t mSize;
|
||||
|
||||
// Whether or not the allocation is in the nursery or not.
|
||||
bool mInNursery;
|
||||
};
|
||||
|
||||
#endif // ProfilerMarkerPayload_h
|
||||
|
Loading…
Reference in New Issue
Block a user