mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 00:35:44 +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,
|
const std::function<char*(size_t)>& aAllocator, double aSinceTime,
|
||||||
bool aIsShuttingDown);
|
bool aIsShuttingDown);
|
||||||
|
|
||||||
// Flags to conveniently track various JS features.
|
// Flags to conveniently track various JS instrumentations.
|
||||||
enum class JSSamplingFlags {
|
enum class JSInstrumentationFlags {
|
||||||
StackSampling = 0x1,
|
StackSampling = 0x1,
|
||||||
TrackOptimizations = 0x2,
|
TrackOptimizations = 0x2,
|
||||||
TraceLogging = 0x4
|
TraceLogging = 0x4,
|
||||||
|
Allocations = 0x8
|
||||||
};
|
};
|
||||||
|
|
||||||
// Record an exit profile from a child process.
|
// Record an exit profile from a child process.
|
||||||
|
@ -36,7 +36,8 @@
|
|||||||
"tasktracer",
|
"tasktracer",
|
||||||
"threads",
|
"threads",
|
||||||
"trackopts",
|
"trackopts",
|
||||||
"jstracer"
|
"jstracer",
|
||||||
|
"jsallocations"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -296,3 +296,28 @@ void LongTaskMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
|
|||||||
aUniqueStacks);
|
aUniqueStacks);
|
||||||
aWriter.StringProperty("category", "LongTask");
|
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()) {
|
if (JSTracerEnabled()) {
|
||||||
JS::StartTraceLogger(mContext);
|
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,
|
js::RegisterContextProfilingEventMarker(mContext,
|
||||||
profiler_add_js_marker);
|
profiler_add_js_marker);
|
||||||
|
|
||||||
@ -259,6 +264,9 @@ class RegisteredThread final {
|
|||||||
if (JSTracerEnabled()) {
|
if (JSTracerEnabled()) {
|
||||||
JS::StopTraceLogger(mContext);
|
JS::StopTraceLogger(mContext);
|
||||||
}
|
}
|
||||||
|
if (JSAllocationsEnabled()) {
|
||||||
|
JS::DisableRecordingAllocations(mContext);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,11 +334,15 @@ class RegisteredThread final {
|
|||||||
uint32_t mJSFlags;
|
uint32_t mJSFlags;
|
||||||
|
|
||||||
bool TrackOptimizationsEnabled() {
|
bool TrackOptimizationsEnabled() {
|
||||||
return mJSFlags & uint32_t(JSSamplingFlags::TrackOptimizations);
|
return mJSFlags & uint32_t(JSInstrumentationFlags::TrackOptimizations);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JSTracerEnabled() {
|
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 "VTuneProfiler.h"
|
||||||
|
|
||||||
#include "js/TraceLoggerAPI.h"
|
#include "js/TraceLoggerAPI.h"
|
||||||
|
#include "js/ProfilingFrameIterator.h"
|
||||||
#include "memory_hooks.h"
|
#include "memory_hooks.h"
|
||||||
#include "mozilla/ArrayUtils.h"
|
#include "mozilla/ArrayUtils.h"
|
||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
@ -654,12 +655,17 @@ class ActivePS {
|
|||||||
|
|
||||||
static uint32_t JSFlags(PSLockRef aLock) {
|
static uint32_t JSFlags(PSLockRef aLock) {
|
||||||
uint32_t Flags = 0;
|
uint32_t Flags = 0;
|
||||||
Flags |= FeatureJS(aLock) ? uint32_t(JSSamplingFlags::StackSampling) : 0;
|
|
||||||
Flags |= FeatureTrackOptimizations(aLock)
|
|
||||||
? uint32_t(JSSamplingFlags::TrackOptimizations)
|
|
||||||
: 0;
|
|
||||||
Flags |=
|
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;
|
return Flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4006,6 +4012,13 @@ void profiler_add_js_marker(const char* aMarkerName) {
|
|||||||
profiler_add_marker(aMarkerName, JS::ProfilingCategoryPair::JS, nullptr);
|
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(
|
void profiler_add_network_marker(
|
||||||
nsIURI* aURI, int32_t aPriority, uint64_t aChannelId, NetworkLoadType aType,
|
nsIURI* aURI, int32_t aPriority, uint64_t aChannelId, NetworkLoadType aType,
|
||||||
mozilla::TimeStamp aStart, mozilla::TimeStamp aEnd, int64_t aCount,
|
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,
|
const std::function<char*(size_t)>& aAllocator, double aSinceTime,
|
||||||
bool aIsShuttingDown);
|
bool aIsShuttingDown);
|
||||||
|
|
||||||
// Flags to conveniently track various JS features.
|
// Flags to conveniently track various JS instrumentations.
|
||||||
enum class JSSamplingFlags {
|
enum class JSInstrumentationFlags {
|
||||||
StackSampling = 0x1,
|
StackSampling = 0x1,
|
||||||
TrackOptimizations = 0x2,
|
TrackOptimizations = 0x2,
|
||||||
TraceLogging = 0x4
|
TraceLogging = 0x4,
|
||||||
|
Allocations = 0x8
|
||||||
};
|
};
|
||||||
|
|
||||||
// Record an exit profile from a child process.
|
// Record an exit profile from a child process.
|
||||||
|
@ -69,6 +69,8 @@
|
|||||||
|
|
||||||
#else // !MOZ_GECKO_PROFILER
|
#else // !MOZ_GECKO_PROFILER
|
||||||
|
|
||||||
|
# include "js/AllocationRecording.h"
|
||||||
|
# include "js/ProfilingFrameIterator.h"
|
||||||
# include "js/ProfilingStack.h"
|
# include "js/ProfilingStack.h"
|
||||||
# include "js/RootingAPI.h"
|
# include "js/RootingAPI.h"
|
||||||
# include "js/TypeDecls.h"
|
# include "js/TypeDecls.h"
|
||||||
@ -118,44 +120,47 @@ class Vector;
|
|||||||
// values are used internally only and so can be changed without consequence.
|
// 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
|
// Any changes to this list should also be applied to the feature list in
|
||||||
// toolkit/components/extensions/schemas/geckoProfiler.json.
|
// toolkit/components/extensions/schemas/geckoProfiler.json.
|
||||||
# define PROFILER_FOR_EACH_FEATURE(MACRO) \
|
# define PROFILER_FOR_EACH_FEATURE(MACRO) \
|
||||||
MACRO(0, "java", Java, "Profile Java code, Android only") \
|
MACRO(0, "java", Java, "Profile Java code, Android only") \
|
||||||
\
|
\
|
||||||
MACRO(1, "js", JS, \
|
MACRO(1, "js", JS, \
|
||||||
"Get the JS engine to expose the JS stack to the profiler") \
|
"Get the JS engine to expose the JS stack to the profiler") \
|
||||||
\
|
\
|
||||||
/* The DevTools profiler doesn't want the native addresses. */ \
|
/* The DevTools profiler doesn't want the native addresses. */ \
|
||||||
MACRO(2, "leaf", Leaf, "Include the C++ leaf node if not stackwalking") \
|
MACRO(2, "leaf", Leaf, "Include the C++ leaf node if not stackwalking") \
|
||||||
\
|
\
|
||||||
MACRO(3, "mainthreadio", MainThreadIO, \
|
MACRO(3, "mainthreadio", MainThreadIO, \
|
||||||
"Add main thread I/O to the profile") \
|
"Add main thread I/O to the profile") \
|
||||||
\
|
\
|
||||||
MACRO(4, "memory", Memory, "Add memory measurements") \
|
MACRO(4, "memory", Memory, "Add memory measurements") \
|
||||||
\
|
\
|
||||||
MACRO(5, "privacy", Privacy, \
|
MACRO(5, "privacy", Privacy, \
|
||||||
"Do not include user-identifiable information") \
|
"Do not include user-identifiable information") \
|
||||||
\
|
\
|
||||||
MACRO(6, "responsiveness", Responsiveness, \
|
MACRO(6, "responsiveness", Responsiveness, \
|
||||||
"Collect thread responsiveness information") \
|
"Collect thread responsiveness information") \
|
||||||
\
|
\
|
||||||
MACRO(7, "screenshots", Screenshots, \
|
MACRO(7, "screenshots", Screenshots, \
|
||||||
"Take a snapshot of the window on every composition") \
|
"Take a snapshot of the window on every composition") \
|
||||||
\
|
\
|
||||||
MACRO(8, "seqstyle", SequentialStyle, \
|
MACRO(8, "seqstyle", SequentialStyle, \
|
||||||
"Disable parallel traversal in styling") \
|
"Disable parallel traversal in styling") \
|
||||||
\
|
\
|
||||||
MACRO(9, "stackwalk", StackWalk, \
|
MACRO(9, "stackwalk", StackWalk, \
|
||||||
"Walk the C++ stack, not available on all platforms") \
|
"Walk the C++ stack, not available on all platforms") \
|
||||||
\
|
\
|
||||||
MACRO(10, "tasktracer", TaskTracer, \
|
MACRO(10, "tasktracer", TaskTracer, \
|
||||||
"Start profiling with feature TaskTracer") \
|
"Start profiling with feature TaskTracer") \
|
||||||
\
|
\
|
||||||
MACRO(11, "threads", Threads, "Profile the registered secondary threads") \
|
MACRO(11, "threads", Threads, "Profile the registered secondary threads") \
|
||||||
\
|
\
|
||||||
MACRO(12, "trackopts", TrackOptimizations, \
|
MACRO(12, "trackopts", TrackOptimizations, \
|
||||||
"Have the JavaScript engine track JIT optimizations") \
|
"Have the JavaScript engine track JIT optimizations") \
|
||||||
\
|
\
|
||||||
MACRO(13, "jstracer", JSTracer, "Enable tracing of the JavaScript engine")
|
MACRO(13, "jstracer", JSTracer, "Enable tracing of the JavaScript engine") \
|
||||||
|
\
|
||||||
|
MACRO(14, "jsallocations", JSAllocations, \
|
||||||
|
"Have the JavaScript engine track allocations")
|
||||||
|
|
||||||
struct ProfilerFeature {
|
struct ProfilerFeature {
|
||||||
# define DECLARE(n_, str_, Name_, desc_) \
|
# define DECLARE(n_, str_, Name_, desc_) \
|
||||||
@ -643,6 +648,7 @@ void profiler_add_marker(const char* aMarkerName,
|
|||||||
JS::ProfilingCategoryPair aCategoryPair,
|
JS::ProfilingCategoryPair aCategoryPair,
|
||||||
mozilla::UniquePtr<ProfilerMarkerPayload> aPayload);
|
mozilla::UniquePtr<ProfilerMarkerPayload> aPayload);
|
||||||
void profiler_add_js_marker(const char* aMarkerName);
|
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.
|
// Insert a marker in the profile timeline for a specified thread.
|
||||||
void profiler_add_marker_for_thread(
|
void profiler_add_marker_for_thread(
|
||||||
|
@ -16,9 +16,12 @@
|
|||||||
#include "mozilla/net/TimingStruct.h"
|
#include "mozilla/net/TimingStruct.h"
|
||||||
|
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
#include "nsCRTGlue.h"
|
||||||
#include "GeckoProfiler.h"
|
#include "GeckoProfiler.h"
|
||||||
|
|
||||||
#include "js/Utility.h"
|
#include "js/Utility.h"
|
||||||
|
#include "js/AllocationRecording.h"
|
||||||
|
#include "js/ProfilingFrameIterator.h"
|
||||||
#include "gfxASurface.h"
|
#include "gfxASurface.h"
|
||||||
#include "mozilla/ServoTraversalStatistics.h"
|
#include "mozilla/ServoTraversalStatistics.h"
|
||||||
|
|
||||||
@ -413,4 +416,42 @@ class LogMarkerPayload : public ProfilerMarkerPayload {
|
|||||||
nsCString mText;
|
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
|
#endif // ProfilerMarkerPayload_h
|
||||||
|
Loading…
Reference in New Issue
Block a user