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:
Greg Tatum 2019-06-19 21:30:48 +00:00
Родитель c46b8c0571
Коммит 8bc06cf8cd
8 изменённых файлов: 152 добавлений и 52 удалений

Просмотреть файл

@ -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