Bug 1673513 - Use ProgressLogger in Gecko Profiler - r=florian

Add `ProgressLogger` parameter to most JSON-generating functions.
Each function can update the given `ProgressLogger` between 0% and 100%, and create sub-loggers when calling functions.

The main goal of this instrumentation is to notice when any progress is made by child processes (when the parent process is gathering profiles), so it needs to go deep enough so that it is not stuck on a progress value for "too long" -- During development, that meant progress was always happening when observed every 10ms; In later patches, the overall timeout for no-progress-made will be at least 1 second.

Differential Revision: https://phabricator.services.mozilla.com/D135479
This commit is contained in:
Gerald Squelart 2022-01-31 02:22:27 +00:00
Родитель 57b6cfaee2
Коммит 50995cc271
14 изменённых файлов: 359 добавлений и 144 удалений

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

@ -13,18 +13,30 @@ UniqueJSONStrings::UniqueJSONStrings(JSONWriter::CollectionStyle aStyle) {
} }
UniqueJSONStrings::UniqueJSONStrings(const UniqueJSONStrings& aOther, UniqueJSONStrings::UniqueJSONStrings(const UniqueJSONStrings& aOther,
ProgressLogger aProgressLogger,
JSONWriter::CollectionStyle aStyle) { JSONWriter::CollectionStyle aStyle) {
using namespace mozilla::literals::ProportionValue_literals; // For `10_pc`.
mStringTableWriter.StartBareList(aStyle); mStringTableWriter.StartBareList(aStyle);
uint32_t count = aOther.mStringHashToIndexMap.count(); uint32_t count = aOther.mStringHashToIndexMap.count();
if (count != 0) { if (count != 0) {
MOZ_RELEASE_ASSERT(mStringHashToIndexMap.reserve(count)); MOZ_ALWAYS_TRUE(mStringHashToIndexMap.reserve(count));
for (auto iter = aOther.mStringHashToIndexMap.iter(); !iter.done(); auto iter = aOther.mStringHashToIndexMap.iter();
iter.next()) { for (auto&& [unusedIndex, progressLogger] :
aProgressLogger.CreateLoopSubLoggersFromTo(
10_pc, 90_pc, count, "Copying unique strings...")) {
(void)unusedIndex;
if (iter.done()) {
break;
}
mStringHashToIndexMap.putNewInfallible(iter.get().key(), mStringHashToIndexMap.putNewInfallible(iter.get().key(),
iter.get().value()); iter.get().value());
iter.next();
} }
aProgressLogger.SetLocalProgress(90_pc, "Copied unique strings");
mStringTableWriter.CopyAndSplice( mStringTableWriter.CopyAndSplice(
aOther.mStringTableWriter.ChunkedWriteFunc()); aOther.mStringTableWriter.ChunkedWriteFunc());
aProgressLogger.SetLocalProgress(100_pc, "Spliced unique strings");
} }
} }

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

@ -9,6 +9,7 @@
#include "mozilla/HashFunctions.h" #include "mozilla/HashFunctions.h"
#include "mozilla/HashTable.h" #include "mozilla/HashTable.h"
#include "mozilla/JSONWriter.h" #include "mozilla/JSONWriter.h"
#include "mozilla/ProgressLogger.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
@ -406,7 +407,7 @@ class UniqueJSONStrings {
// Start with a copy of the strings from another list. // Start with a copy of the strings from another list.
MFBT_API explicit UniqueJSONStrings( MFBT_API explicit UniqueJSONStrings(
const UniqueJSONStrings& aOther, const UniqueJSONStrings& aOther, ProgressLogger aProgressLogger,
JSONWriter::CollectionStyle aStyle = JSONWriter::MultiLineStyle); JSONWriter::CollectionStyle aStyle = JSONWriter::MultiLineStyle);
MFBT_API ~UniqueJSONStrings(); MFBT_API ~UniqueJSONStrings();

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

@ -4705,7 +4705,8 @@ void TestUniqueJSONStrings() {
ujs.WriteElement(writer, "external1"); ujs.WriteElement(writer, "external1");
ujs.WriteElement(writer, "external0"); ujs.WriteElement(writer, "external0");
} }
UJS ujsCopy(ujs, mozilla::JSONWriter::SingleLineStyle); UJS ujsCopy(ujs, mozilla::ProgressLogger{},
mozilla::JSONWriter::SingleLineStyle);
VerifyUniqueStringContents( VerifyUniqueStringContents(
[](SCJW& aWriter, UJS& aUniqueStrings) { [](SCJW& aWriter, UJS& aUniqueStrings) {
aUniqueStrings.WriteElement(aWriter, "string0"); aUniqueStrings.WriteElement(aWriter, "string0");

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

@ -54,8 +54,8 @@ class ProfileBuffer final {
// that are currently in the buffer at or after aRangeStart, in samples // that are currently in the buffer at or after aRangeStart, in samples
// for the given thread. // for the given thread.
void AddJITInfoForRange(uint64_t aRangeStart, ProfilerThreadId aThreadId, void AddJITInfoForRange(uint64_t aRangeStart, ProfilerThreadId aThreadId,
JSContext* aContext, JSContext* aContext, JITFrameInfo& aJITFrameInfo,
JITFrameInfo& aJITFrameInfo) const; mozilla::ProgressLogger aProgressLogger) const;
// Stream JSON for samples in the buffer to aWriter, using the supplied // Stream JSON for samples in the buffer to aWriter, using the supplied
// UniqueStacks object. // UniqueStacks object.
@ -67,30 +67,34 @@ class ProfileBuffer final {
// words, you need to have called AddJITInfoForRange for every range that // words, you need to have called AddJITInfoForRange for every range that
// might contain JIT frame information before calling this method. // might contain JIT frame information before calling this method.
// Return the thread ID of the streamed sample(s), or 0. // Return the thread ID of the streamed sample(s), or 0.
ProfilerThreadId StreamSamplesToJSON(SpliceableJSONWriter& aWriter, ProfilerThreadId StreamSamplesToJSON(
ProfilerThreadId aThreadId, SpliceableJSONWriter& aWriter, ProfilerThreadId aThreadId,
double aSinceTime, double aSinceTime, UniqueStacks& aUniqueStacks,
UniqueStacks& aUniqueStacks) const; mozilla::ProgressLogger aProgressLogger) const;
void StreamMarkersToJSON(SpliceableJSONWriter& aWriter, void StreamMarkersToJSON(SpliceableJSONWriter& aWriter,
ProfilerThreadId aThreadId, ProfilerThreadId aThreadId,
const mozilla::TimeStamp& aProcessStartTime, const mozilla::TimeStamp& aProcessStartTime,
double aSinceTime, double aSinceTime, UniqueStacks& aUniqueStacks,
UniqueStacks& aUniqueStacks) const; mozilla::ProgressLogger aProgressLogger) const;
// Stream samples and markers from all threads that `aProcessStreamingContext` // Stream samples and markers from all threads that `aProcessStreamingContext`
// accepts. // accepts.
void StreamSamplesAndMarkersToJSON( void StreamSamplesAndMarkersToJSON(
ProcessStreamingContext& aProcessStreamingContext) const; ProcessStreamingContext& aProcessStreamingContext,
mozilla::ProgressLogger aProgressLogger) const;
void StreamPausedRangesToJSON(SpliceableJSONWriter& aWriter, void StreamPausedRangesToJSON(SpliceableJSONWriter& aWriter,
double aSinceTime) const; double aSinceTime,
void StreamProfilerOverheadToJSON(SpliceableJSONWriter& aWriter, mozilla::ProgressLogger aProgressLogger) const;
const mozilla::TimeStamp& aProcessStartTime, void StreamProfilerOverheadToJSON(
double aSinceTime) const; SpliceableJSONWriter& aWriter,
const mozilla::TimeStamp& aProcessStartTime, double aSinceTime,
mozilla::ProgressLogger aProgressLogger) const;
void StreamCountersToJSON(SpliceableJSONWriter& aWriter, void StreamCountersToJSON(SpliceableJSONWriter& aWriter,
const mozilla::TimeStamp& aProcessStartTime, const mozilla::TimeStamp& aProcessStartTime,
double aSinceTime) const; double aSinceTime,
mozilla::ProgressLogger aProgressLogger) const;
// Find (via |aLastSample|) the most recent sample for the thread denoted by // Find (via |aLastSample|) the most recent sample for the thread denoted by
// |aThreadId| and clone it, patching in the current time as appropriate. // |aThreadId| and clone it, patching in the current time as appropriate.
@ -197,8 +201,8 @@ class ProfileBuffer final {
ProfilerThreadId DoStreamSamplesAndMarkersToJSON( ProfilerThreadId DoStreamSamplesAndMarkersToJSON(
GetStreamingParametersForThreadCallback&& GetStreamingParametersForThreadCallback&&
aGetStreamingParametersForThreadCallback, aGetStreamingParametersForThreadCallback,
double aSinceTime, double aSinceTime, ProcessStreamingContext* aStreamingContextForMarkers,
ProcessStreamingContext* aStreamingContextForMarkers) const; mozilla::ProgressLogger aProgressLogger) const;
double mFirstSamplingTimeUs = 0.0; double mFirstSamplingTimeUs = 0.0;
double mLastSamplingTimeUs = 0.0; double mLastSamplingTimeUs = 0.0;

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

@ -28,6 +28,7 @@
#include <type_traits> #include <type_traits>
using namespace mozilla; using namespace mozilla;
using namespace mozilla::literals::ProportionValue_literals;
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// BEGIN ProfileBufferEntry // BEGIN ProfileBufferEntry
@ -263,10 +264,17 @@ JITFrameInfoForBufferRange JITFrameInfoForBufferRange::Clone() const {
std::move(jitFrameToFrameJSONMap)}; std::move(jitFrameToFrameJSONMap)};
} }
JITFrameInfo::JITFrameInfo(const JITFrameInfo& aOther) JITFrameInfo::JITFrameInfo(const JITFrameInfo& aOther,
: mUniqueStrings(MakeUnique<UniqueJSONStrings>(*aOther.mUniqueStrings)) { mozilla::ProgressLogger aProgressLogger)
for (const JITFrameInfoForBufferRange& range : aOther.mRanges) { : mUniqueStrings(MakeUnique<UniqueJSONStrings>(
MOZ_RELEASE_ASSERT(mRanges.append(range.Clone())); *aOther.mUniqueStrings,
aProgressLogger.CreateSubLoggerFromTo(
0_pc, "Creating JIT frame info unique strings...", 49_pc,
"Created JIT frame info unique strings"))) {
MOZ_ALWAYS_TRUE(mRanges.reserve(aOther.mRanges.length()));
for (auto&& [i, progressLogger] : aProgressLogger.CreateLoopSubLoggersFromTo(
50_pc, 100_pc, aOther.mRanges.length(), "Copying JIT frame info")) {
mRanges.infallibleAppend(aOther.mRanges[i].Clone());
} }
} }
@ -636,13 +644,21 @@ static void StreamMarkerAfterKind(
class EntryGetter { class EntryGetter {
public: public:
explicit EntryGetter( explicit EntryGetter(
ProfileChunkedBuffer::Reader& aReader, uint64_t aInitialReadPos = 0, ProfileChunkedBuffer::Reader& aReader,
mozilla::ProgressLogger aProgressLogger = {},
uint64_t aInitialReadPos = 0,
ProcessStreamingContext* aStreamingContextForMarkers = nullptr) ProcessStreamingContext* aStreamingContextForMarkers = nullptr)
: mStreamingContextForMarkers(aStreamingContextForMarkers), : mStreamingContextForMarkers(aStreamingContextForMarkers),
mBlockIt( mBlockIt(
aReader.At(ProfileBufferBlockIndex::CreateFromProfileBufferIndex( aReader.At(ProfileBufferBlockIndex::CreateFromProfileBufferIndex(
aInitialReadPos))), aInitialReadPos))),
mBlockItEnd(aReader.end()) { mBlockItEnd(aReader.end()),
mRangeStart(mBlockIt.BufferRangeStart().ConvertToProfileBufferIndex()),
mRangeSize(
double(mBlockIt.BufferRangeEnd().ConvertToProfileBufferIndex() -
mRangeStart)),
mProgressLogger(std::move(aProgressLogger)) {
SetLocalProgress(ProgressLogger::NO_LOCATION_UPDATE);
if (!ReadLegacyOrEnd()) { if (!ReadLegacyOrEnd()) {
// Find and read the next non-legacy entry. // Find and read the next non-legacy entry.
Next(); Next();
@ -684,6 +700,14 @@ class EntryGetter {
return CurBlockIndex().ConvertToProfileBufferIndex(); return CurBlockIndex().ConvertToProfileBufferIndex();
} }
void SetLocalProgress(const char* aLocation) {
mProgressLogger.SetLocalProgress(
ProportionValue{double(CurBlockIndex().ConvertToProfileBufferIndex() -
mRangeStart) /
mRangeSize},
aLocation);
}
private: private:
// Try to read the entry at the current `mBlockIt` position. // Try to read the entry at the current `mBlockIt` position.
// * If we're at the end of the buffer, just return `true`. // * If we're at the end of the buffer, just return `true`.
@ -706,6 +730,7 @@ class EntryGetter {
if (type == ProfileBufferEntry::Kind::Marker && if (type == ProfileBufferEntry::Kind::Marker &&
mStreamingContextForMarkers) { mStreamingContextForMarkers) {
StreamMarkerAfterKind(er, *mStreamingContextForMarkers); StreamMarkerAfterKind(er, *mStreamingContextForMarkers);
SetLocalProgress("Processed marker");
} }
er.SetRemainingBytes(0); er.SetRemainingBytes(0);
return false; return false;
@ -727,6 +752,7 @@ class EntryGetter {
// Otherwise loop around until we hit a legacy entry or the end. // Otherwise loop around until we hit a legacy entry or the end.
++mBlockIt; ++mBlockIt;
} }
SetLocalProgress(ProgressLogger::NO_LOCATION_UPDATE);
} }
ProcessStreamingContext* const mStreamingContextForMarkers; ProcessStreamingContext* const mStreamingContextForMarkers;
@ -734,6 +760,12 @@ class EntryGetter {
ProfileBufferEntry mEntry; ProfileBufferEntry mEntry;
ProfileChunkedBuffer::BlockIterator mBlockIt; ProfileChunkedBuffer::BlockIterator mBlockIt;
const ProfileChunkedBuffer::BlockIterator mBlockItEnd; const ProfileChunkedBuffer::BlockIterator mBlockItEnd;
// Progress logger, and the data needed to compute the current relative
// position in the buffer.
const mozilla::ProfileBufferIndex mRangeStart;
const double mRangeSize;
mozilla::ProgressLogger mProgressLogger;
}; };
// The following grammar shows legal sequences of profile buffer entries. // The following grammar shows legal sequences of profile buffer entries.
@ -899,8 +931,8 @@ template <typename GetStreamingParametersForThreadCallback>
ProfilerThreadId ProfileBuffer::DoStreamSamplesAndMarkersToJSON( ProfilerThreadId ProfileBuffer::DoStreamSamplesAndMarkersToJSON(
GetStreamingParametersForThreadCallback&& GetStreamingParametersForThreadCallback&&
aGetStreamingParametersForThreadCallback, aGetStreamingParametersForThreadCallback,
double aSinceTime, double aSinceTime, ProcessStreamingContext* aStreamingContextForMarkers,
ProcessStreamingContext* aStreamingContextForMarkers) const { mozilla::ProgressLogger aProgressLogger) const {
UniquePtr<char[]> dynStrBuf = MakeUnique<char[]>(kMaxFrameKeyLength); UniquePtr<char[]> dynStrBuf = MakeUnique<char[]>(kMaxFrameKeyLength);
return mEntries.Read([&](ProfileChunkedBuffer::Reader* aReader) { return mEntries.Read([&](ProfileChunkedBuffer::Reader* aReader) {
@ -910,7 +942,7 @@ ProfilerThreadId ProfileBuffer::DoStreamSamplesAndMarkersToJSON(
ProfilerThreadId processedThreadId; ProfilerThreadId processedThreadId;
EntryGetter e(*aReader, /* aInitialReadPos */ 0, EntryGetter e(*aReader, std::move(aProgressLogger), /* aInitialReadPos */ 0,
aStreamingContextForMarkers); aStreamingContextForMarkers);
for (;;) { for (;;) {
@ -1149,6 +1181,8 @@ ProfilerThreadId ProfileBuffer::DoStreamSamplesAndMarkersToJSON(
// would need these frames to be present. // would need these frames to be present.
ReadStack(e, time, 0, Nothing{}, RunningTimes{}); ReadStack(e, time, 0, Nothing{}, RunningTimes{});
e.SetLocalProgress("Processed sample");
} else if (e.Has() && e.Get().IsTimeBeforeCompactStack()) { } else if (e.Has() && e.Get().IsTimeBeforeCompactStack()) {
double time = e.Get().GetDouble(); double time = e.Get().GetDouble();
// Note: Even if this sample is too old (before aSinceTime), we still // Note: Even if this sample is too old (before aSinceTime), we still
@ -1212,6 +1246,8 @@ ProfilerThreadId ProfileBuffer::DoStreamSamplesAndMarkersToJSON(
} }
e.RestartAfter(it); e.RestartAfter(it);
e.SetLocalProgress("Processed compact sample");
} else if (e.Has() && e.Get().IsTimeBeforeSameSample()) { } else if (e.Has() && e.Get().IsTimeBeforeSameSample()) {
if (previousStackState == ThreadStreamingContext::eNoStackYet) { if (previousStackState == ThreadStreamingContext::eNoStackYet) {
// We don't have any full sample yet, we cannot duplicate a "previous" // We don't have any full sample yet, we cannot duplicate a "previous"
@ -1278,6 +1314,8 @@ ProfilerThreadId ProfileBuffer::DoStreamSamplesAndMarkersToJSON(
} }
e.RestartAfter(it); e.RestartAfter(it);
e.SetLocalProgress("Processed repeated sample");
} else { } else {
ERROR_AND_CONTINUE("expected a Time entry"); ERROR_AND_CONTINUE("expected a Time entry");
} }
@ -1289,7 +1327,8 @@ ProfilerThreadId ProfileBuffer::DoStreamSamplesAndMarkersToJSON(
ProfilerThreadId ProfileBuffer::StreamSamplesToJSON( ProfilerThreadId ProfileBuffer::StreamSamplesToJSON(
SpliceableJSONWriter& aWriter, ProfilerThreadId aThreadId, SpliceableJSONWriter& aWriter, ProfilerThreadId aThreadId,
double aSinceTime, UniqueStacks& aUniqueStacks) const { double aSinceTime, UniqueStacks& aUniqueStacks,
mozilla::ProgressLogger aProgressLogger) const {
ThreadStreamingContext::PreviousStackState previousStackState = ThreadStreamingContext::PreviousStackState previousStackState =
ThreadStreamingContext::eNoStackYet; ThreadStreamingContext::eNoStackYet;
uint32_t stack = 0u; uint32_t stack = 0u;
@ -1312,11 +1351,13 @@ ProfilerThreadId ProfileBuffer::StreamSamplesToJSON(
} }
return streamingParameters; return streamingParameters;
}, },
aSinceTime, /* aStreamingContextForMarkers */ nullptr); aSinceTime, /* aStreamingContextForMarkers */ nullptr,
std::move(aProgressLogger));
} }
void ProfileBuffer::StreamSamplesAndMarkersToJSON( void ProfileBuffer::StreamSamplesAndMarkersToJSON(
ProcessStreamingContext& aProcessStreamingContext) const { ProcessStreamingContext& aProcessStreamingContext,
mozilla::ProgressLogger aProgressLogger) const {
(void)DoStreamSamplesAndMarkersToJSON( (void)DoStreamSamplesAndMarkersToJSON(
[&](ProfilerThreadId aReadThreadId) { [&](ProfilerThreadId aReadThreadId) {
Maybe<StreamingParametersForThread> streamingParameters; Maybe<StreamingParametersForThread> streamingParameters;
@ -1329,13 +1370,14 @@ void ProfileBuffer::StreamSamplesAndMarkersToJSON(
} }
return streamingParameters; return streamingParameters;
}, },
aProcessStreamingContext.GetSinceTime(), &aProcessStreamingContext); aProcessStreamingContext.GetSinceTime(), &aProcessStreamingContext,
std::move(aProgressLogger));
} }
void ProfileBuffer::AddJITInfoForRange(uint64_t aRangeStart, void ProfileBuffer::AddJITInfoForRange(
ProfilerThreadId aThreadId, uint64_t aRangeStart, ProfilerThreadId aThreadId, JSContext* aContext,
JSContext* aContext, JITFrameInfo& aJITFrameInfo,
JITFrameInfo& aJITFrameInfo) const { mozilla::ProgressLogger aProgressLogger) const {
// We can only process JitReturnAddr entries if we have a JSContext. // We can only process JitReturnAddr entries if we have a JSContext.
MOZ_RELEASE_ASSERT(aContext); MOZ_RELEASE_ASSERT(aContext);
@ -1351,7 +1393,7 @@ void ProfileBuffer::AddJITInfoForRange(uint64_t aRangeStart,
"ProfileChunkedBuffer cannot be out-of-session when " "ProfileChunkedBuffer cannot be out-of-session when "
"sampler is running"); "sampler is running");
EntryGetter e(*aReader, aRangeStart); EntryGetter e(*aReader, std::move(aProgressLogger), aRangeStart);
while (true) { while (true) {
// Advance to the next ThreadId entry. // Advance to the next ThreadId entry.
@ -1430,11 +1472,11 @@ void ProfileBuffer::AddJITInfoForRange(uint64_t aRangeStart,
}); });
} }
void ProfileBuffer::StreamMarkersToJSON(SpliceableJSONWriter& aWriter, void ProfileBuffer::StreamMarkersToJSON(
ProfilerThreadId aThreadId, SpliceableJSONWriter& aWriter, ProfilerThreadId aThreadId,
const TimeStamp& aProcessStartTime, const TimeStamp& aProcessStartTime, double aSinceTime,
double aSinceTime, UniqueStacks& aUniqueStacks,
UniqueStacks& aUniqueStacks) const { mozilla::ProgressLogger aProgressLogger) const {
mEntries.ReadEach([&](ProfileBufferEntryReader& aER) { mEntries.ReadEach([&](ProfileBufferEntryReader& aER) {
auto type = static_cast<ProfileBufferEntry::Kind>( auto type = static_cast<ProfileBufferEntry::Kind>(
aER.ReadObject<ProfileBufferEntry::KindUnderlyingType>()); aER.ReadObject<ProfileBufferEntry::KindUnderlyingType>());
@ -1482,13 +1524,13 @@ void ProfileBuffer::StreamMarkersToJSON(SpliceableJSONWriter& aWriter,
void ProfileBuffer::StreamProfilerOverheadToJSON( void ProfileBuffer::StreamProfilerOverheadToJSON(
SpliceableJSONWriter& aWriter, const TimeStamp& aProcessStartTime, SpliceableJSONWriter& aWriter, const TimeStamp& aProcessStartTime,
double aSinceTime) const { double aSinceTime, mozilla::ProgressLogger aProgressLogger) const {
mEntries.Read([&](ProfileChunkedBuffer::Reader* aReader) { mEntries.Read([&](ProfileChunkedBuffer::Reader* aReader) {
MOZ_ASSERT(aReader, MOZ_ASSERT(aReader,
"ProfileChunkedBuffer cannot be out-of-session when sampler is " "ProfileChunkedBuffer cannot be out-of-session when sampler is "
"running"); "running");
EntryGetter e(*aReader); EntryGetter e(*aReader, std::move(aProgressLogger));
enum Schema : uint32_t { enum Schema : uint32_t {
TIME = 0, TIME = 0,
@ -1629,9 +1671,9 @@ static auto& LookupOrAdd(HashM& aMap, Key&& aKey) {
return addPtr->value(); return addPtr->value();
} }
void ProfileBuffer::StreamCountersToJSON(SpliceableJSONWriter& aWriter, void ProfileBuffer::StreamCountersToJSON(
const TimeStamp& aProcessStartTime, SpliceableJSONWriter& aWriter, const TimeStamp& aProcessStartTime,
double aSinceTime) const { double aSinceTime, mozilla::ProgressLogger aProgressLogger) const {
// Because this is a format entirely internal to the Profiler, any parsing // Because this is a format entirely internal to the Profiler, any parsing
// error indicates a bug in the ProfileBuffer writing or the parser itself, // error indicates a bug in the ProfileBuffer writing or the parser itself,
// or possibly flaky hardware. // or possibly flaky hardware.
@ -1641,7 +1683,7 @@ void ProfileBuffer::StreamCountersToJSON(SpliceableJSONWriter& aWriter,
"ProfileChunkedBuffer cannot be out-of-session when sampler is " "ProfileChunkedBuffer cannot be out-of-session when sampler is "
"running"); "running");
EntryGetter e(*aReader); EntryGetter e(*aReader, std::move(aProgressLogger));
enum Schema : uint32_t { TIME = 0, NUMBER = 1, COUNT = 2 }; enum Schema : uint32_t { TIME = 0, NUMBER = 1, COUNT = 2 };
@ -1842,14 +1884,17 @@ static void AddPausedRange(SpliceableJSONWriter& aWriter, const char* aReason,
aWriter.End(); aWriter.End();
} }
void ProfileBuffer::StreamPausedRangesToJSON(SpliceableJSONWriter& aWriter, void ProfileBuffer::StreamPausedRangesToJSON(
double aSinceTime) const { SpliceableJSONWriter& aWriter, double aSinceTime,
mozilla::ProgressLogger aProgressLogger) const {
mEntries.Read([&](ProfileChunkedBuffer::Reader* aReader) { mEntries.Read([&](ProfileChunkedBuffer::Reader* aReader) {
MOZ_ASSERT(aReader, MOZ_ASSERT(aReader,
"ProfileChunkedBuffer cannot be out-of-session when sampler is " "ProfileChunkedBuffer cannot be out-of-session when sampler is "
"running"); "running");
EntryGetter e(*aReader); EntryGetter e(*aReader,
aProgressLogger.CreateSubLoggerFromTo(
1_pc, "Streaming pauses...", 99_pc, "Streamed pauses"));
Maybe<double> currentPauseStartTime; Maybe<double> currentPauseStartTime;
Maybe<double> currentCollectionStartTime; Maybe<double> currentCollectionStartTime;
@ -1949,7 +1994,9 @@ bool ProfileBuffer::DuplicateLastSample(ProfilerThreadId aThreadId,
"ProfileChunkedBuffer cannot be out-of-session when sampler is " "ProfileChunkedBuffer cannot be out-of-session when sampler is "
"running"); "running");
EntryGetter e(*aReader, *aLastSample); // DuplicateLsatSample is only called during profiling, so we don't need a
// progress logger (only useful when capturing the final profile).
EntryGetter e(*aReader, ProgressLogger{}, *aLastSample);
if (e.CurPos() != *aLastSample) { if (e.CurPos() != *aLastSample) {
// The last sample is no longer within the buffer range, so we cannot // The last sample is no longer within the buffer range, so we cannot

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

@ -144,7 +144,8 @@ struct JITFrameInfoForBufferRange final {
struct JITFrameInfo final { struct JITFrameInfo final {
JITFrameInfo() : mUniqueStrings(mozilla::MakeUnique<UniqueJSONStrings>()) {} JITFrameInfo() : mUniqueStrings(mozilla::MakeUnique<UniqueJSONStrings>()) {}
MOZ_IMPLICIT JITFrameInfo(const JITFrameInfo& aOther); MOZ_IMPLICIT JITFrameInfo(const JITFrameInfo& aOther,
mozilla::ProgressLogger aProgressLogger);
// Creates a new JITFrameInfoForBufferRange object in mRanges by looking up // Creates a new JITFrameInfoForBufferRange object in mRanges by looking up
// information about the provided JIT return addresses using aCx. // information about the provided JIT return addresses using aCx.

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

@ -18,6 +18,8 @@
# include <pthread.h> # include <pthread.h>
#endif #endif
using namespace mozilla::literals::ProportionValue_literals;
ProfiledThreadData::ProfiledThreadData( ProfiledThreadData::ProfiledThreadData(
const mozilla::profiler::ThreadRegistrationInfo& aThreadInfo) const mozilla::profiler::ThreadRegistrationInfo& aThreadInfo)
: mThreadInfo(aThreadInfo.Name(), aThreadInfo.ThreadId(), : mThreadInfo(aThreadInfo.Name(), aThreadInfo.ThreadId(),
@ -126,7 +128,8 @@ static void StreamTraceLoggerJSON(JSContext* aCx, SpliceableJSONWriter& aWriter,
static void StreamTablesAndTraceLogger( static void StreamTablesAndTraceLogger(
UniqueStacks&& aUniqueStacks, JSContext* aCx, SpliceableJSONWriter& aWriter, UniqueStacks&& aUniqueStacks, JSContext* aCx, SpliceableJSONWriter& aWriter,
const mozilla::TimeStamp& aProcessStartTime, bool JSTracerEnabled) { const mozilla::TimeStamp& aProcessStartTime, bool JSTracerEnabled,
mozilla::ProgressLogger aProgressLogger) {
aWriter.StartObjectProperty("stackTable"); aWriter.StartObjectProperty("stackTable");
{ {
{ {
@ -136,7 +139,11 @@ static void StreamTablesAndTraceLogger(
} }
aWriter.StartArrayProperty("data"); aWriter.StartArrayProperty("data");
{ aUniqueStacks.SpliceStackTableElements(aWriter); } {
aProgressLogger.SetLocalProgress(1_pc, "Splicing stack table...");
aUniqueStacks.SpliceStackTableElements(aWriter);
aProgressLogger.SetLocalProgress(30_pc, "Spliced stack table");
}
aWriter.EndArray(); aWriter.EndArray();
} }
aWriter.EndObject(); aWriter.EndObject();
@ -157,42 +164,62 @@ static void StreamTablesAndTraceLogger(
} }
aWriter.StartArrayProperty("data"); aWriter.StartArrayProperty("data");
{ aUniqueStacks.SpliceFrameTableElements(aWriter); } {
aProgressLogger.SetLocalProgress(30_pc, "Splicing frame table...");
aUniqueStacks.SpliceFrameTableElements(aWriter);
aProgressLogger.SetLocalProgress(60_pc, "Spliced frame table");
}
aWriter.EndArray(); aWriter.EndArray();
} }
aWriter.EndObject(); aWriter.EndObject();
aWriter.StartArrayProperty("stringTable"); aWriter.StartArrayProperty("stringTable");
{ {
aProgressLogger.SetLocalProgress(60_pc, "Splicing string table...");
std::move(*aUniqueStacks.mUniqueStrings).SpliceStringTableElements(aWriter); std::move(*aUniqueStacks.mUniqueStrings).SpliceStringTableElements(aWriter);
aProgressLogger.SetLocalProgress(90_pc, "Spliced string table");
} }
aWriter.EndArray(); aWriter.EndArray();
if (aCx && JSTracerEnabled) { if (aCx && JSTracerEnabled) {
aProgressLogger.SetLocalProgress(90_pc, "Streaming trace logger...");
StreamTraceLoggerJSON(aCx, aWriter, aProcessStartTime); StreamTraceLoggerJSON(aCx, aWriter, aProcessStartTime);
aProgressLogger.SetLocalProgress(100_pc, "Streamed trace logger");
} else {
aProgressLogger.SetLocalProgress(100_pc, "No trace logger");
} }
} }
mozilla::NotNull<mozilla::UniquePtr<UniqueStacks>> mozilla::NotNull<mozilla::UniquePtr<UniqueStacks>>
ProfiledThreadData::PrepareUniqueStacks(const ProfileBuffer& aBuffer, ProfiledThreadData::PrepareUniqueStacks(
JSContext* aCx, const ProfileBuffer& aBuffer, JSContext* aCx,
ProfilerCodeAddressService* aService) { ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger) {
if (mJITFrameInfoForPreviousJSContexts && if (mJITFrameInfoForPreviousJSContexts &&
mJITFrameInfoForPreviousJSContexts->HasExpired( mJITFrameInfoForPreviousJSContexts->HasExpired(
aBuffer.BufferRangeStart())) { aBuffer.BufferRangeStart())) {
mJITFrameInfoForPreviousJSContexts = nullptr; mJITFrameInfoForPreviousJSContexts = nullptr;
} }
aProgressLogger.SetLocalProgress(1_pc, "Checked JIT frame info presence");
// If we have an existing JITFrameInfo in mJITFrameInfoForPreviousJSContexts, // If we have an existing JITFrameInfo in mJITFrameInfoForPreviousJSContexts,
// copy the data from it. // copy the data from it.
JITFrameInfo jitFrameInfo = JITFrameInfo jitFrameInfo =
mJITFrameInfoForPreviousJSContexts mJITFrameInfoForPreviousJSContexts
? JITFrameInfo(*mJITFrameInfoForPreviousJSContexts) ? JITFrameInfo(*mJITFrameInfoForPreviousJSContexts,
aProgressLogger.CreateSubLoggerTo(
"Retrieving JIT frame info...", 10_pc,
"Retrieved JIT frame info"))
: JITFrameInfo(); : JITFrameInfo();
if (aCx && mBufferPositionWhenReceivedJSContext) { if (aCx && mBufferPositionWhenReceivedJSContext) {
aBuffer.AddJITInfoForRange(*mBufferPositionWhenReceivedJSContext, aBuffer.AddJITInfoForRange(
mThreadInfo.ThreadId(), aCx, jitFrameInfo); *mBufferPositionWhenReceivedJSContext, mThreadInfo.ThreadId(), aCx,
jitFrameInfo,
aProgressLogger.CreateSubLoggerTo("Adding JIT info...", 90_pc,
"Added JIT info"));
} else {
aProgressLogger.SetLocalProgress(90_pc, "No JIT info");
} }
return mozilla::MakeNotNull<mozilla::UniquePtr<UniqueStacks>>( return mozilla::MakeNotNull<mozilla::UniquePtr<UniqueStacks>>(
@ -203,22 +230,31 @@ void ProfiledThreadData::StreamJSON(
const ProfileBuffer& aBuffer, JSContext* aCx, SpliceableJSONWriter& aWriter, const ProfileBuffer& aBuffer, JSContext* aCx, SpliceableJSONWriter& aWriter,
const nsACString& aProcessName, const nsACString& aETLDplus1, const nsACString& aProcessName, const nsACString& aETLDplus1,
const mozilla::TimeStamp& aProcessStartTime, double aSinceTime, const mozilla::TimeStamp& aProcessStartTime, double aSinceTime,
bool JSTracerEnabled, ProfilerCodeAddressService* aService) { bool JSTracerEnabled, ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger) {
mozilla::NotNull<mozilla::UniquePtr<UniqueStacks>> uniqueStacks = mozilla::NotNull<mozilla::UniquePtr<UniqueStacks>> uniqueStacks =
PrepareUniqueStacks(aBuffer, aCx, aService); PrepareUniqueStacks(aBuffer, aCx, aService,
aProgressLogger.CreateSubLoggerFromTo(
0_pc, "Preparing unique stacks...", 10_pc,
"Prepared Unique stacks"));
MOZ_ASSERT(uniqueStacks->mUniqueStrings); MOZ_ASSERT(uniqueStacks->mUniqueStrings);
aWriter.SetUniqueStrings(*uniqueStacks->mUniqueStrings); aWriter.SetUniqueStrings(*uniqueStacks->mUniqueStrings);
aWriter.Start(); aWriter.Start();
{ {
StreamSamplesAndMarkers(mThreadInfo.Name(), mThreadInfo.ThreadId(), aBuffer, StreamSamplesAndMarkers(
aWriter, aProcessName, aETLDplus1, mThreadInfo.Name(), mThreadInfo.ThreadId(), aBuffer, aWriter,
aProcessStartTime, mThreadInfo.RegisterTime(), aProcessName, aETLDplus1, aProcessStartTime, mThreadInfo.RegisterTime(),
mUnregisterTime, aSinceTime, *uniqueStacks); mUnregisterTime, aSinceTime, *uniqueStacks,
aProgressLogger.CreateSubLoggerTo(
90_pc,
"ProfiledThreadData::StreamJSON: Streamed samples and markers"));
StreamTablesAndTraceLogger(std::move(*uniqueStacks), aCx, aWriter, StreamTablesAndTraceLogger(std::move(*uniqueStacks), aCx, aWriter,
aProcessStartTime, JSTracerEnabled); aProcessStartTime, JSTracerEnabled,
aProgressLogger.CreateSubLoggerTo(
99_pc, "Streamed tables and trace logger"));
} }
aWriter.End(); aWriter.End();
@ -229,24 +265,33 @@ void ProfiledThreadData::StreamJSON(
ThreadStreamingContext&& aThreadStreamingContext, ThreadStreamingContext&& aThreadStreamingContext,
SpliceableJSONWriter& aWriter, const nsACString& aProcessName, SpliceableJSONWriter& aWriter, const nsACString& aProcessName,
const nsACString& aETLDplus1, const mozilla::TimeStamp& aProcessStartTime, const nsACString& aETLDplus1, const mozilla::TimeStamp& aProcessStartTime,
bool JSTracerEnabled, ProfilerCodeAddressService* aService) { bool JSTracerEnabled, ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger) {
aWriter.Start(); aWriter.Start();
{ {
StreamSamplesAndMarkers(mThreadInfo.Name(), aThreadStreamingContext, StreamSamplesAndMarkers(
aWriter, aProcessName, aETLDplus1, mThreadInfo.Name(), aThreadStreamingContext, aWriter, aProcessName,
aProcessStartTime, mThreadInfo.RegisterTime(), aETLDplus1, aProcessStartTime, mThreadInfo.RegisterTime(),
mUnregisterTime); mUnregisterTime,
aProgressLogger.CreateSubLoggerFromTo(
1_pc, "ProfiledThreadData::StreamJSON(context): Streaming...",
90_pc,
"ProfiledThreadData::StreamJSON(context): Streamed samples and "
"markers"));
StreamTablesAndTraceLogger( StreamTablesAndTraceLogger(
std::move(*aThreadStreamingContext.mUniqueStacks), std::move(*aThreadStreamingContext.mUniqueStacks),
aThreadStreamingContext.mJSContext, aWriter, aProcessStartTime, aThreadStreamingContext.mJSContext, aWriter, aProcessStartTime,
JSTracerEnabled); JSTracerEnabled,
aProgressLogger.CreateSubLoggerTo(
"ProfiledThreadData::StreamJSON(context): Streaming tables...",
99_pc, "ProfiledThreadData::StreamJSON(context): Streamed tables"));
} }
aWriter.End(); aWriter.End();
} }
// StreamSamplesDataCallback: () -> ProfilerThreadId // StreamSamplesDataCallback: (ProgressLogger) -> ProfilerThreadId
// StreamMarkersDataCallback: () -> void // StreamMarkersDataCallback: (ProgressLogger) -> void
// Returns the ProfilerThreadId returned by StreamSamplesDataCallback, which // Returns the ProfilerThreadId returned by StreamSamplesDataCallback, which
// should be the thread id of the last sample that was processed (if any; // should be the thread id of the last sample that was processed (if any;
// otherwise it is left unspecified). This is mostly useful when the caller // otherwise it is left unspecified). This is mostly useful when the caller
@ -260,6 +305,7 @@ ProfilerThreadId DoStreamSamplesAndMarkers(
const mozilla::TimeStamp& aProcessStartTime, const mozilla::TimeStamp& aProcessStartTime,
const mozilla::TimeStamp& aRegisterTime, const mozilla::TimeStamp& aRegisterTime,
const mozilla::TimeStamp& aUnregisterTime, const mozilla::TimeStamp& aUnregisterTime,
mozilla::ProgressLogger aProgressLogger,
StreamSamplesDataCallback&& aStreamSamplesDataCallback, StreamSamplesDataCallback&& aStreamSamplesDataCallback,
StreamMarkersDataCallback&& aStreamMarkersDataCallback) { StreamMarkersDataCallback&& aStreamMarkersDataCallback) {
ProfilerThreadId processedThreadId; ProfilerThreadId processedThreadId;
@ -317,8 +363,9 @@ ProfilerThreadId DoStreamSamplesAndMarkers(
aWriter.StartArrayProperty("data"); aWriter.StartArrayProperty("data");
{ {
processedThreadId = processedThreadId = std::forward<StreamSamplesDataCallback>(
std::forward<StreamSamplesDataCallback>(aStreamSamplesDataCallback)(); aStreamSamplesDataCallback)(aProgressLogger.CreateSubLoggerFromTo(
1_pc, "Streaming samples...", 49_pc, "Streamed samples"));
} }
aWriter.EndArray(); aWriter.EndArray();
} }
@ -337,7 +384,11 @@ ProfilerThreadId DoStreamSamplesAndMarkers(
} }
aWriter.StartArrayProperty("data"); aWriter.StartArrayProperty("data");
{ std::forward<StreamMarkersDataCallback>(aStreamMarkersDataCallback)(); } {
std::forward<StreamMarkersDataCallback>(aStreamMarkersDataCallback)(
aProgressLogger.CreateSubLoggerFromTo(50_pc, "Streaming markers...",
99_pc, "Streamed markers"));
}
aWriter.EndArray(); aWriter.EndArray();
} }
aWriter.EndObject(); aWriter.EndObject();
@ -360,18 +411,20 @@ ProfilerThreadId StreamSamplesAndMarkers(
const nsACString& aETLDplus1, const mozilla::TimeStamp& aProcessStartTime, const nsACString& aETLDplus1, const mozilla::TimeStamp& aProcessStartTime,
const mozilla::TimeStamp& aRegisterTime, const mozilla::TimeStamp& aRegisterTime,
const mozilla::TimeStamp& aUnregisterTime, double aSinceTime, const mozilla::TimeStamp& aUnregisterTime, double aSinceTime,
UniqueStacks& aUniqueStacks) { UniqueStacks& aUniqueStacks, mozilla::ProgressLogger aProgressLogger) {
return DoStreamSamplesAndMarkers( return DoStreamSamplesAndMarkers(
aName, aWriter, aProcessName, aETLDplus1, aProcessStartTime, aName, aWriter, aProcessName, aETLDplus1, aProcessStartTime,
aRegisterTime, aUnregisterTime, aRegisterTime, aUnregisterTime, std::move(aProgressLogger),
[&]() { [&](mozilla::ProgressLogger aSubProgressLogger) {
ProfilerThreadId processedThreadId = aBuffer.StreamSamplesToJSON( ProfilerThreadId processedThreadId = aBuffer.StreamSamplesToJSON(
aWriter, aThreadId, aSinceTime, aUniqueStacks); aWriter, aThreadId, aSinceTime, aUniqueStacks,
std::move(aSubProgressLogger));
return aThreadId.IsSpecified() ? aThreadId : processedThreadId; return aThreadId.IsSpecified() ? aThreadId : processedThreadId;
}, },
[&]() { [&](mozilla::ProgressLogger aSubProgressLogger) {
aBuffer.StreamMarkersToJSON(aWriter, aThreadId, aProcessStartTime, aBuffer.StreamMarkersToJSON(aWriter, aThreadId, aProcessStartTime,
aSinceTime, aUniqueStacks); aSinceTime, aUniqueStacks,
std::move(aSubProgressLogger));
}); });
} }
@ -382,16 +435,17 @@ void StreamSamplesAndMarkers(const char* aName,
const nsACString& aETLDplus1, const nsACString& aETLDplus1,
const mozilla::TimeStamp& aProcessStartTime, const mozilla::TimeStamp& aProcessStartTime,
const mozilla::TimeStamp& aRegisterTime, const mozilla::TimeStamp& aRegisterTime,
const mozilla::TimeStamp& aUnregisterTime) { const mozilla::TimeStamp& aUnregisterTime,
mozilla::ProgressLogger aProgressLogger) {
(void)DoStreamSamplesAndMarkers( (void)DoStreamSamplesAndMarkers(
aName, aWriter, aProcessName, aETLDplus1, aProcessStartTime, aName, aWriter, aProcessName, aETLDplus1, aProcessStartTime,
aRegisterTime, aUnregisterTime, aRegisterTime, aUnregisterTime, std::move(aProgressLogger),
[&]() { [&](mozilla::ProgressLogger aSubProgressLogger) {
aWriter.TakeAndSplice( aWriter.TakeAndSplice(
aThreadData.mSamplesDataWriter.TakeChunkedWriteFunc()); aThreadData.mSamplesDataWriter.TakeChunkedWriteFunc());
return aThreadData.mProfiledThreadData.Info().ThreadId(); return aThreadData.mProfiledThreadData.Info().ThreadId();
}, },
[&]() { [&](mozilla::ProgressLogger aSubProgressLogger) {
aWriter.TakeAndSplice( aWriter.TakeAndSplice(
aThreadData.mMarkersDataWriter.TakeChunkedWriteFunc()); aThreadData.mMarkersDataWriter.TakeChunkedWriteFunc());
}); });
@ -418,7 +472,8 @@ void ProfiledThreadData::NotifyAboutToLoseJSContext(
: mozilla::MakeUnique<JITFrameInfo>(); : mozilla::MakeUnique<JITFrameInfo>();
aBuffer.AddJITInfoForRange(*mBufferPositionWhenReceivedJSContext, aBuffer.AddJITInfoForRange(*mBufferPositionWhenReceivedJSContext,
mThreadInfo.ThreadId(), aContext, *jitFrameInfo); mThreadInfo.ThreadId(), aContext, *jitFrameInfo,
mozilla::ProgressLogger{});
mJITFrameInfoForPreviousJSContexts = std::move(jitFrameInfo); mJITFrameInfoForPreviousJSContexts = std::move(jitFrameInfo);
mBufferPositionWhenReceivedJSContext = mozilla::Nothing(); mBufferPositionWhenReceivedJSContext = mozilla::Nothing();
@ -426,11 +481,15 @@ void ProfiledThreadData::NotifyAboutToLoseJSContext(
ThreadStreamingContext::ThreadStreamingContext( ThreadStreamingContext::ThreadStreamingContext(
ProfiledThreadData& aProfiledThreadData, const ProfileBuffer& aBuffer, ProfiledThreadData& aProfiledThreadData, const ProfileBuffer& aBuffer,
JSContext* aCx, ProfilerCodeAddressService* aService) JSContext* aCx, ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger)
: mProfiledThreadData(aProfiledThreadData), : mProfiledThreadData(aProfiledThreadData),
mJSContext(aCx), mJSContext(aCx),
mUniqueStacks( mUniqueStacks(mProfiledThreadData.PrepareUniqueStacks(
mProfiledThreadData.PrepareUniqueStacks(aBuffer, aCx, aService)) { aBuffer, aCx, aService,
aProgressLogger.CreateSubLoggerFromTo(
0_pc, "Preparing thread streaming context unique stacks...",
99_pc, "Prepared thread streaming context Unique stacks"))) {
mSamplesDataWriter.SetUniqueStrings(*mUniqueStacks->mUniqueStrings); mSamplesDataWriter.SetUniqueStrings(*mUniqueStacks->mUniqueStrings);
mSamplesDataWriter.StartBareList(); mSamplesDataWriter.StartBareList();
mMarkersDataWriter.SetUniqueStrings(*mUniqueStacks->mUniqueStrings); mMarkersDataWriter.SetUniqueStrings(*mUniqueStacks->mUniqueStrings);
@ -458,11 +517,15 @@ ProcessStreamingContext::~ProcessStreamingContext() {
void ProcessStreamingContext::AddThreadStreamingContext( void ProcessStreamingContext::AddThreadStreamingContext(
ProfiledThreadData& aProfiledThreadData, const ProfileBuffer& aBuffer, ProfiledThreadData& aProfiledThreadData, const ProfileBuffer& aBuffer,
JSContext* aCx, ProfilerCodeAddressService* aService) { JSContext* aCx, ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger) {
MOZ_ASSERT(mTIDList.length() == mThreadStreamingContextList.length()); MOZ_ASSERT(mTIDList.length() == mThreadStreamingContextList.length());
MOZ_ASSERT(mTIDList.length() < mTIDList.capacity(), MOZ_ASSERT(mTIDList.length() < mTIDList.capacity(),
"Didn't pre-allocate enough"); "Didn't pre-allocate enough");
mTIDList.infallibleAppend(aProfiledThreadData.Info().ThreadId()); mTIDList.infallibleAppend(aProfiledThreadData.Info().ThreadId());
mThreadStreamingContextList.infallibleEmplaceBack(aProfiledThreadData, mThreadStreamingContextList.infallibleEmplaceBack(
aBuffer, aCx, aService); aProfiledThreadData, aBuffer, aCx, aService,
aProgressLogger.CreateSubLoggerFromTo(
1_pc, "Prepared streaming thread id", 100_pc,
"Added thread streaming context"));
} }

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

@ -74,19 +74,22 @@ class ProfiledThreadData final {
mozilla::NotNull<mozilla::UniquePtr<UniqueStacks>> PrepareUniqueStacks( mozilla::NotNull<mozilla::UniquePtr<UniqueStacks>> PrepareUniqueStacks(
const ProfileBuffer& aBuffer, JSContext* aCx, const ProfileBuffer& aBuffer, JSContext* aCx,
ProfilerCodeAddressService* aService); ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger);
void StreamJSON(const ProfileBuffer& aBuffer, JSContext* aCx, void StreamJSON(const ProfileBuffer& aBuffer, JSContext* aCx,
SpliceableJSONWriter& aWriter, const nsACString& aProcessName, SpliceableJSONWriter& aWriter, const nsACString& aProcessName,
const nsACString& aETLDplus1, const nsACString& aETLDplus1,
const mozilla::TimeStamp& aProcessStartTime, const mozilla::TimeStamp& aProcessStartTime,
double aSinceTime, bool aJSTracerEnabled, double aSinceTime, bool aJSTracerEnabled,
ProfilerCodeAddressService* aService); ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger);
void StreamJSON(ThreadStreamingContext&& aThreadStreamingContext, void StreamJSON(ThreadStreamingContext&& aThreadStreamingContext,
SpliceableJSONWriter& aWriter, const nsACString& aProcessName, SpliceableJSONWriter& aWriter, const nsACString& aProcessName,
const nsACString& aETLDplus1, const nsACString& aETLDplus1,
const mozilla::TimeStamp& aProcessStartTime, const mozilla::TimeStamp& aProcessStartTime,
bool aJSTracerEnabled, ProfilerCodeAddressService* aService); bool aJSTracerEnabled, ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger);
const mozilla::profiler::ThreadRegistrationInfo& Info() const { const mozilla::profiler::ThreadRegistrationInfo& Info() const {
return mThreadInfo; return mThreadInfo;
@ -159,7 +162,8 @@ struct ThreadStreamingContext {
ThreadStreamingContext(ProfiledThreadData& aProfiledThreadData, ThreadStreamingContext(ProfiledThreadData& aProfiledThreadData,
const ProfileBuffer& aBuffer, JSContext* aCx, const ProfileBuffer& aBuffer, JSContext* aCx,
ProfilerCodeAddressService* aService); ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger);
void FinalizeWriter(); void FinalizeWriter();
}; };
@ -178,7 +182,8 @@ class ProcessStreamingContext {
// should be called exactly the number of times specified in the constructor. // should be called exactly the number of times specified in the constructor.
void AddThreadStreamingContext(ProfiledThreadData& aProfiledThreadData, void AddThreadStreamingContext(ProfiledThreadData& aProfiledThreadData,
const ProfileBuffer& aBuffer, JSContext* aCx, const ProfileBuffer& aBuffer, JSContext* aCx,
ProfilerCodeAddressService* aService); ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger);
// Retrieve the ThreadStreamingContext for a given thread id. // Retrieve the ThreadStreamingContext for a given thread id.
// Returns null if that thread id doesn't correspond to any profiled thread. // Returns null if that thread id doesn't correspond to any profiled thread.
@ -224,7 +229,7 @@ ProfilerThreadId StreamSamplesAndMarkers(
const nsACString& aETLDplus1, const mozilla::TimeStamp& aProcessStartTime, const nsACString& aETLDplus1, const mozilla::TimeStamp& aProcessStartTime,
const mozilla::TimeStamp& aRegisterTime, const mozilla::TimeStamp& aRegisterTime,
const mozilla::TimeStamp& aUnregisterTime, double aSinceTime, const mozilla::TimeStamp& aUnregisterTime, double aSinceTime,
UniqueStacks& aUniqueStacks); UniqueStacks& aUniqueStacks, mozilla::ProgressLogger aProgressLogger);
void StreamSamplesAndMarkers(const char* aName, void StreamSamplesAndMarkers(const char* aName,
ThreadStreamingContext& aThreadData, ThreadStreamingContext& aThreadData,
SpliceableJSONWriter& aWriter, SpliceableJSONWriter& aWriter,
@ -232,6 +237,7 @@ void StreamSamplesAndMarkers(const char* aName,
const nsACString& aETLDplus1, const nsACString& aETLDplus1,
const mozilla::TimeStamp& aProcessStartTime, const mozilla::TimeStamp& aProcessStartTime,
const mozilla::TimeStamp& aRegisterTime, const mozilla::TimeStamp& aRegisterTime,
const mozilla::TimeStamp& aUnregisterTime); const mozilla::TimeStamp& aUnregisterTime,
mozilla::ProgressLogger aProgressLogger);
#endif // ProfiledThreadData_h #endif // ProfiledThreadData_h

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

@ -85,7 +85,7 @@ ProfilerThreadId ProfilerBacktrace::StreamJSON(
""_ns, aProcessStartTime, ""_ns, aProcessStartTime,
/* aRegisterTime */ mozilla::TimeStamp(), /* aRegisterTime */ mozilla::TimeStamp(),
/* aUnregisterTime */ mozilla::TimeStamp(), /* aUnregisterTime */ mozilla::TimeStamp(),
/* aSinceTime */ 0, aUniqueStacks); /* aSinceTime */ 0, aUniqueStacks, mozilla::ProgressLogger{});
} else if (mProfileChunkedBuffer) { } else if (mProfileChunkedBuffer) {
ProfileBuffer profileBuffer(*mProfileChunkedBuffer); ProfileBuffer profileBuffer(*mProfileChunkedBuffer);
processedThreadId = StreamSamplesAndMarkers( processedThreadId = StreamSamplesAndMarkers(
@ -93,7 +93,7 @@ ProfilerThreadId ProfilerBacktrace::StreamJSON(
aProcessStartTime, aProcessStartTime,
/* aRegisterTime */ mozilla::TimeStamp(), /* aRegisterTime */ mozilla::TimeStamp(),
/* aUnregisterTime */ mozilla::TimeStamp(), /* aUnregisterTime */ mozilla::TimeStamp(),
/* aSinceTime */ 0, aUniqueStacks); /* aSinceTime */ 0, aUniqueStacks, mozilla::ProgressLogger{});
} }
// If there are no buffers, the backtrace is empty and nothing is streamed. // If there are no buffers, the backtrace is empty and nothing is streamed.

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

@ -185,6 +185,7 @@
#endif #endif
using namespace mozilla; using namespace mozilla;
using namespace mozilla::literals::ProportionValue_literals;
using mozilla::profiler::detail::RacyFeatures; using mozilla::profiler::detail::RacyFeatures;
using ThreadRegistration = mozilla::profiler::ThreadRegistration; using ThreadRegistration = mozilla::profiler::ThreadRegistration;
@ -2958,7 +2959,8 @@ profiler_code_address_service_for_presymbolication() {
static void locked_profiler_stream_json_for_this_process( static void locked_profiler_stream_json_for_this_process(
PSLockRef aLock, SpliceableJSONWriter& aWriter, double aSinceTime, PSLockRef aLock, SpliceableJSONWriter& aWriter, double aSinceTime,
const PreRecordedMetaInformation& aPreRecordedMetaInformation, const PreRecordedMetaInformation& aPreRecordedMetaInformation,
bool aIsShuttingDown, ProfilerCodeAddressService* aService) { bool aIsShuttingDown, ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger) {
LOG("locked_profiler_stream_json_for_this_process"); LOG("locked_profiler_stream_json_for_this_process");
MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock)); MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock));
@ -2969,12 +2971,15 @@ static void locked_profiler_stream_json_for_this_process(
ProfileBuffer& buffer = ActivePS::Buffer(aLock); ProfileBuffer& buffer = ActivePS::Buffer(aLock);
aProgressLogger.SetLocalProgress(1_pc, "Locked profile buffer");
// If there is a set "Window length", discard older data. // If there is a set "Window length", discard older data.
Maybe<double> durationS = ActivePS::Duration(aLock); Maybe<double> durationS = ActivePS::Duration(aLock);
if (durationS.isSome()) { if (durationS.isSome()) {
const double durationStartMs = collectionStartMs - *durationS * 1000; const double durationStartMs = collectionStartMs - *durationS * 1000;
buffer.DiscardSamplesBeforeTime(durationStartMs); buffer.DiscardSamplesBeforeTime(durationStartMs);
} }
aProgressLogger.SetLocalProgress(2_pc, "Discarded old data");
#if defined(GP_OS_android) #if defined(GP_OS_android)
// Java thread profile data should be collected before serializing the meta // Java thread profile data should be collected before serializing the meta
@ -2995,6 +3000,7 @@ static void locked_profiler_stream_json_for_this_process(
ProfileBuffer javaBuffer(javaBufferManager); ProfileBuffer javaBuffer(javaBufferManager);
if (ActivePS::FeatureJava(aLock)) { if (ActivePS::FeatureJava(aLock)) {
CollectJavaThreadProfileData(javaBuffer); CollectJavaThreadProfileData(javaBuffer);
aProgressLogger.SetLocalProgress(3_pc, "Collected Java thread");
} }
#endif #endif
@ -3002,6 +3008,7 @@ static void locked_profiler_stream_json_for_this_process(
aWriter.StartArrayProperty("libs"); aWriter.StartArrayProperty("libs");
AppendSharedLibraries(aWriter); AppendSharedLibraries(aWriter);
aWriter.EndArray(); aWriter.EndArray();
aProgressLogger.SetLocalProgress(4_pc, "Wrote library information");
// Put meta data // Put meta data
aWriter.StartObjectProperty("meta"); aWriter.StartObjectProperty("meta");
@ -3010,47 +3017,69 @@ static void locked_profiler_stream_json_for_this_process(
aPreRecordedMetaInformation); aPreRecordedMetaInformation);
} }
aWriter.EndObject(); aWriter.EndObject();
aProgressLogger.SetLocalProgress(5_pc, "Wrote profile metadata");
// Put page data // Put page data
aWriter.StartArrayProperty("pages"); aWriter.StartArrayProperty("pages");
{ StreamPages(aLock, aWriter); } { StreamPages(aLock, aWriter); }
aWriter.EndArray(); aWriter.EndArray();
aProgressLogger.SetLocalProgress(6_pc, "Wrote pages");
buffer.StreamProfilerOverheadToJSON(aWriter, CorePS::ProcessStartTime(), buffer.StreamProfilerOverheadToJSON(
aSinceTime); aWriter, CorePS::ProcessStartTime(), aSinceTime,
buffer.StreamCountersToJSON(aWriter, CorePS::ProcessStartTime(), aSinceTime); aProgressLogger.CreateSubLoggerTo(10_pc, "Wrote profiler overheads"));
buffer.StreamCountersToJSON(
aWriter, CorePS::ProcessStartTime(), aSinceTime,
aProgressLogger.CreateSubLoggerTo(14_pc, "Wrote counters"));
// Lists the samples for each thread profile // Lists the samples for each thread profile
aWriter.StartArrayProperty("threads"); aWriter.StartArrayProperty("threads");
{ {
ActivePS::DiscardExpiredDeadProfiledThreads(aLock); ActivePS::DiscardExpiredDeadProfiledThreads(aLock);
aProgressLogger.SetLocalProgress(15_pc, "Discarded expired profiles");
ThreadRegistry::LockedRegistry lockedRegistry; ThreadRegistry::LockedRegistry lockedRegistry;
ActivePS::ProfiledThreadList threads = ActivePS::ProfiledThreadList threads =
ActivePS::ProfiledThreads(lockedRegistry, aLock); ActivePS::ProfiledThreads(lockedRegistry, aLock);
const uint32_t threadCount = uint32_t(threads.length());
// Prepare the streaming context for each thread. // Prepare the streaming context for each thread.
ProcessStreamingContext processStreamingContext( ProcessStreamingContext processStreamingContext(
threads.length(), CorePS::ProcessStartTime(), aSinceTime); threadCount, CorePS::ProcessStartTime(), aSinceTime);
for (ActivePS::ProfiledThreadListElement& thread : threads) { for (auto&& [i, progressLogger] : aProgressLogger.CreateLoopSubLoggersTo(
20_pc, threadCount, "Preparing thread streaming contexts...")) {
ActivePS::ProfiledThreadListElement& thread = threads[i];
MOZ_RELEASE_ASSERT(thread.mProfiledThreadData); MOZ_RELEASE_ASSERT(thread.mProfiledThreadData);
processStreamingContext.AddThreadStreamingContext( processStreamingContext.AddThreadStreamingContext(
*thread.mProfiledThreadData, buffer, thread.mJSContext, aService); *thread.mProfiledThreadData, buffer, thread.mJSContext, aService,
std::move(progressLogger));
} }
// Read the buffer once, and extract all samples and markers that the // Read the buffer once, and extract all samples and markers that the
// context expects. // context expects.
buffer.StreamSamplesAndMarkersToJSON(processStreamingContext); buffer.StreamSamplesAndMarkersToJSON(
processStreamingContext, aProgressLogger.CreateSubLoggerTo(
"Processing samples and markers...", 80_pc,
"Processed samples and markers"));
// Stream each thread from the pre-filled context. // Stream each thread from the pre-filled context.
for (ThreadStreamingContext& threadStreamingContext : ThreadStreamingContext* const contextListBegin =
std::move(processStreamingContext)) { processStreamingContext.begin();
MOZ_ASSERT(uint32_t(processStreamingContext.end() - contextListBegin) ==
threadCount);
for (auto&& [i, progressLogger] : aProgressLogger.CreateLoopSubLoggersTo(
92_pc, threadCount, "Streaming threads...")) {
ThreadStreamingContext& threadStreamingContext = contextListBegin[i];
threadStreamingContext.FinalizeWriter(); threadStreamingContext.FinalizeWriter();
threadStreamingContext.mProfiledThreadData.StreamJSON( threadStreamingContext.mProfiledThreadData.StreamJSON(
std::move(threadStreamingContext), aWriter, std::move(threadStreamingContext), aWriter,
CorePS::ProcessName(aLock), CorePS::ETLDplus1(aLock), CorePS::ProcessName(aLock), CorePS::ETLDplus1(aLock),
CorePS::ProcessStartTime(), ActivePS::FeatureJSTracer(aLock), CorePS::ProcessStartTime(), ActivePS::FeatureJSTracer(aLock),
aService); aService, std::move(progressLogger));
} }
aProgressLogger.SetLocalProgress(92_pc, "Wrote samples and markers");
#if defined(GP_OS_android) #if defined(GP_OS_android)
if (ActivePS::FeatureJava(aLock)) { if (ActivePS::FeatureJava(aLock)) {
@ -3068,7 +3097,11 @@ static void locked_profiler_stream_json_for_this_process(
profiledThreadData.StreamJSON( profiledThreadData.StreamJSON(
javaBuffer, nullptr, aWriter, CorePS::ProcessName(aLock), javaBuffer, nullptr, aWriter, CorePS::ProcessName(aLock),
CorePS::ETLDplus1(aLock), CorePS::ProcessStartTime(), aSinceTime, CorePS::ETLDplus1(aLock), CorePS::ProcessStartTime(), aSinceTime,
ActivePS::FeatureJSTracer(aLock), nullptr); ActivePS::FeatureJSTracer(aLock), nullptr,
aProgressLogger.CreateSubLoggerTo("Streaming Java thread...", 96_pc,
"Streamed Java thread"));
} else {
aProgressLogger.SetLocalProgress(96_pc, "No Java thread");
} }
#endif #endif
@ -3076,6 +3109,9 @@ static void locked_profiler_stream_json_for_this_process(
ActivePS::MoveBaseProfileThreads(aLock); ActivePS::MoveBaseProfileThreads(aLock);
if (baseProfileThreads) { if (baseProfileThreads) {
aWriter.Splice(MakeStringSpan(baseProfileThreads.get())); aWriter.Splice(MakeStringSpan(baseProfileThreads.get()));
aProgressLogger.SetLocalProgress(97_pc, "Wrote baseprofiler data");
} else {
aProgressLogger.SetLocalProgress(97_pc, "No baseprofiler data");
} }
} }
aWriter.EndArray(); aWriter.EndArray();
@ -3093,9 +3129,15 @@ static void locked_profiler_stream_json_for_this_process(
} }
aWriter.EndArray(); aWriter.EndArray();
} }
aProgressLogger.SetLocalProgress(98_pc, "Handled JS Tracer dictionary");
aWriter.StartArrayProperty("pausedRanges"); aWriter.StartArrayProperty("pausedRanges");
{ buffer.StreamPausedRangesToJSON(aWriter, aSinceTime); } {
buffer.StreamPausedRangesToJSON(
aWriter, aSinceTime,
aProgressLogger.CreateSubLoggerTo("Streaming pauses...", 99_pc,
"Streamed pauses"));
}
aWriter.EndArray(); aWriter.EndArray();
const double collectionEndMs = profiler_time(); const double collectionEndMs = profiler_time();
@ -3112,13 +3154,16 @@ static void locked_profiler_stream_json_for_this_process(
// Keep this internal function non-static, so it may be used by tests. // Keep this internal function non-static, so it may be used by tests.
bool do_profiler_stream_json_for_this_process( bool do_profiler_stream_json_for_this_process(
SpliceableJSONWriter& aWriter, double aSinceTime, bool aIsShuttingDown, SpliceableJSONWriter& aWriter, double aSinceTime, bool aIsShuttingDown,
ProfilerCodeAddressService* aService) { ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger) {
LOG("profiler_stream_json_for_this_process"); LOG("profiler_stream_json_for_this_process");
MOZ_RELEASE_ASSERT(CorePS::Exists()); MOZ_RELEASE_ASSERT(CorePS::Exists());
const auto preRecordedMetaInformation = PreRecordMetaInformation(); const auto preRecordedMetaInformation = PreRecordMetaInformation();
aProgressLogger.SetLocalProgress(2_pc, "PreRecordMetaInformation done");
if (profiler_is_active()) { if (profiler_is_active()) {
invoke_profiler_state_change_callbacks(ProfilingState::GeneratingProfile); invoke_profiler_state_change_callbacks(ProfilingState::GeneratingProfile);
} }
@ -3129,21 +3174,26 @@ bool do_profiler_stream_json_for_this_process(
return false; return false;
} }
locked_profiler_stream_json_for_this_process(lock, aWriter, aSinceTime, locked_profiler_stream_json_for_this_process(
preRecordedMetaInformation, lock, aWriter, aSinceTime, preRecordedMetaInformation, aIsShuttingDown,
aIsShuttingDown, aService); aService,
aProgressLogger.CreateSubLoggerFromTo(
3_pc, "locked_profiler_stream_json_for_this_process started", 100_pc,
"locked_profiler_stream_json_for_this_process done"));
return true; return true;
} }
bool profiler_stream_json_for_this_process( bool profiler_stream_json_for_this_process(
SpliceableJSONWriter& aWriter, double aSinceTime, bool aIsShuttingDown, SpliceableJSONWriter& aWriter, double aSinceTime, bool aIsShuttingDown,
ProfilerCodeAddressService* aService) { ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger) {
MOZ_RELEASE_ASSERT( MOZ_RELEASE_ASSERT(
!XRE_IsParentProcess() || NS_IsMainThread(), !XRE_IsParentProcess() || NS_IsMainThread(),
"In the parent process, profiles should only be generated from the main " "In the parent process, profiles should only be generated from the main "
"thread, otherwise they will be incomplete."); "thread, otherwise they will be incomplete.");
return do_profiler_stream_json_for_this_process(aWriter, aSinceTime, return do_profiler_stream_json_for_this_process(aWriter, aSinceTime,
aIsShuttingDown, aService); aIsShuttingDown, aService,
std::move(aProgressLogger));
} }
// END saving/streaming code // END saving/streaming code
@ -5000,15 +5050,23 @@ void profiler_shutdown(IsFastShutdown aIsFastShutdown) {
static bool WriteProfileToJSONWriter(SpliceableChunkedJSONWriter& aWriter, static bool WriteProfileToJSONWriter(SpliceableChunkedJSONWriter& aWriter,
double aSinceTime, bool aIsShuttingDown, double aSinceTime, bool aIsShuttingDown,
ProfilerCodeAddressService* aService) { ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger) {
LOG("WriteProfileToJSONWriter"); LOG("WriteProfileToJSONWriter");
MOZ_RELEASE_ASSERT(CorePS::Exists()); MOZ_RELEASE_ASSERT(CorePS::Exists());
aWriter.Start(); aWriter.Start();
{ {
if (!profiler_stream_json_for_this_process(aWriter, aSinceTime, if (!profiler_stream_json_for_this_process(
aIsShuttingDown, aService)) { aWriter, aSinceTime, aIsShuttingDown, aService,
aProgressLogger.CreateSubLoggerFromTo(
0_pc,
"WriteProfileToJSONWriter: "
"profiler_stream_json_for_this_process started",
100_pc,
"WriteProfileToJSONWriter: "
"profiler_stream_json_for_this_process done"))) {
return false; return false;
} }
@ -5040,8 +5098,8 @@ UniquePtr<char[]> profiler_get_profile(double aSinceTime,
profiler_code_address_service_for_presymbolication(); profiler_code_address_service_for_presymbolication();
SpliceableChunkedJSONWriter b; SpliceableChunkedJSONWriter b;
if (!WriteProfileToJSONWriter(b, aSinceTime, aIsShuttingDown, if (!WriteProfileToJSONWriter(b, aSinceTime, aIsShuttingDown, service.get(),
service.get())) { ProgressLogger{})) {
return nullptr; return nullptr;
} }
return b.ChunkedWriteFunc().CopyData(); return b.ChunkedWriteFunc().CopyData();
@ -5049,15 +5107,22 @@ UniquePtr<char[]> profiler_get_profile(double aSinceTime,
void profiler_get_profile_json_into_lazily_allocated_buffer( 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, mozilla::ProgressLogger aProgressLogger) {
LOG("profiler_get_profile_json_into_lazily_allocated_buffer"); LOG("profiler_get_profile_json_into_lazily_allocated_buffer");
UniquePtr<ProfilerCodeAddressService> service = UniquePtr<ProfilerCodeAddressService> service =
profiler_code_address_service_for_presymbolication(); profiler_code_address_service_for_presymbolication();
SpliceableChunkedJSONWriter b; SpliceableChunkedJSONWriter b;
if (!WriteProfileToJSONWriter(b, aSinceTime, aIsShuttingDown, if (!WriteProfileToJSONWriter(
service.get())) { b, aSinceTime, aIsShuttingDown, service.get(),
aProgressLogger.CreateSubLoggerFromTo(
1_pc,
"profiler_get_profile_json_into_lazily_allocated_buffer: "
"WriteProfileToJSONWriter started",
98_pc,
"profiler_get_profile_json_into_lazily_allocated_buffer: "
"WriteProfileToJSONWriter done"))) {
return; return;
} }
@ -5203,9 +5268,9 @@ static void locked_profiler_save_profile_to_file(
SpliceableJSONWriter w(MakeUnique<OStreamJSONWriteFunc>(stream)); SpliceableJSONWriter w(MakeUnique<OStreamJSONWriteFunc>(stream));
w.Start(); w.Start();
{ {
locked_profiler_stream_json_for_this_process(aLock, w, /* sinceTime */ 0, locked_profiler_stream_json_for_this_process(
aPreRecordedMetaInformation, aLock, w, /* sinceTime */ 0, aPreRecordedMetaInformation,
aIsShuttingDown, nullptr); aIsShuttingDown, nullptr, ProgressLogger{});
w.StartArrayProperty("processes"); w.StartArrayProperty("processes");
Vector<nsCString> exitProfiles = ActivePS::MoveExitProfiles(aLock); Vector<nsCString> exitProfiles = ActivePS::MoveExitProfiles(aLock);

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

@ -36,6 +36,7 @@
#include "mozilla/MathAlgorithms.h" #include "mozilla/MathAlgorithms.h"
#include "mozilla/ProfileBufferEntrySerialization.h" #include "mozilla/ProfileBufferEntrySerialization.h"
#include "mozilla/ProfilerUtils.h" #include "mozilla/ProfilerUtils.h"
#include "mozilla/ProgressLogger.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "mozilla/Vector.h" #include "mozilla/Vector.h"
@ -95,7 +96,7 @@ uint32_t ParseFeaturesFromStringArray(const char** aFeatures,
void profiler_get_profile_json_into_lazily_allocated_buffer( 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, mozilla::ProgressLogger aProgressLogger);
// Flags to conveniently track various JS instrumentations. // Flags to conveniently track various JS instrumentations.
enum class JSInstrumentationFlags { enum class JSInstrumentationFlags {

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

@ -261,7 +261,10 @@ mozilla::ipc::IPCResult ProfilerChild::RecvDestroyReleasedChunksAtOrBefore(
mozilla::ipc::IPCResult ProfilerChild::RecvGatherProfile( mozilla::ipc::IPCResult ProfilerChild::RecvGatherProfile(
GatherProfileResolver&& aResolve) { GatherProfileResolver&& aResolve) {
// TODO: Use a real ProgressLogger with shared progress.
mozilla::ProgressLogger progressLogger{};
mozilla::ipc::Shmem shmem; mozilla::ipc::Shmem shmem;
using namespace mozilla::literals::ProportionValue_literals; // For `1_pc`.
profiler_get_profile_json_into_lazily_allocated_buffer( profiler_get_profile_json_into_lazily_allocated_buffer(
[&](size_t allocationSize) -> char* { [&](size_t allocationSize) -> char* {
if (AllocShmem(allocationSize, if (AllocShmem(allocationSize,
@ -271,7 +274,12 @@ mozilla::ipc::IPCResult ProfilerChild::RecvGatherProfile(
return nullptr; return nullptr;
}, },
/* aSinceTime */ 0, /* aSinceTime */ 0,
/* aIsShuttingDown */ false); /* aIsShuttingDown */ false,
progressLogger.CreateSubLoggerFromTo(
1_pc,
"profiler_get_profile_json_into_lazily_allocated_buffer started",
99_pc,
"profiler_get_profile_json_into_lazily_allocated_buffer done"));
aResolve(std::move(shmem)); aResolve(std::move(shmem));
return IPC_OK(); return IPC_OK();
} }

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

@ -27,6 +27,7 @@
#include "mozilla/ProfilerMarkers.h" #include "mozilla/ProfilerMarkers.h"
#include "mozilla/ProfilerState.h" #include "mozilla/ProfilerState.h"
#include "mozilla/ProfilerThreadState.h" #include "mozilla/ProfilerThreadState.h"
#include "mozilla/ProgressLogger.h"
enum class IsFastShutdown { enum class IsFastShutdown {
No, No,
@ -511,7 +512,8 @@ mozilla::UniquePtr<char[]> profiler_get_profile(double aSinceTime = 0,
bool profiler_stream_json_for_this_process( bool profiler_stream_json_for_this_process(
mozilla::baseprofiler::SpliceableJSONWriter& aWriter, double aSinceTime = 0, mozilla::baseprofiler::SpliceableJSONWriter& aWriter, double aSinceTime = 0,
bool aIsShuttingDown = false, bool aIsShuttingDown = false,
ProfilerCodeAddressService* aService = nullptr); ProfilerCodeAddressService* aService = nullptr,
mozilla::ProgressLogger aProgressLogger = {});
// Get the profile and write it into a file. A no-op if the profile is // Get the profile and write it into a file. A no-op if the profile is
// inactive. // inactive.

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

@ -14,6 +14,7 @@
#include "mozilla/ProfilerThreadRegistrationInfo.h" #include "mozilla/ProfilerThreadRegistrationInfo.h"
#include "mozilla/ProfilerThreadRegistry.h" #include "mozilla/ProfilerThreadRegistry.h"
#include "mozilla/ProfilerUtils.h" #include "mozilla/ProfilerUtils.h"
#include "mozilla/ProgressLogger.h"
#include "mozilla/UniquePtrExtensions.h" #include "mozilla/UniquePtrExtensions.h"
#include "nsIThread.h" #include "nsIThread.h"
@ -3670,7 +3671,8 @@ TEST(GeckoProfiler, StreamJSONForThisProcess)
// an incomplete profile. // an incomplete profile.
bool do_profiler_stream_json_for_this_process( bool do_profiler_stream_json_for_this_process(
SpliceableJSONWriter& aWriter, double aSinceTime, bool aIsShuttingDown, SpliceableJSONWriter& aWriter, double aSinceTime, bool aIsShuttingDown,
ProfilerCodeAddressService* aService); ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger);
TEST(GeckoProfiler, StreamJSONForThisProcessThreaded) TEST(GeckoProfiler, StreamJSONForThisProcessThreaded)
{ {
@ -3698,7 +3700,8 @@ TEST(GeckoProfiler, StreamJSONForThisProcessThreaded)
ASSERT_TRUE(::do_profiler_stream_json_for_this_process( ASSERT_TRUE(::do_profiler_stream_json_for_this_process(
w, /* double aSinceTime */ 0.0, w, /* double aSinceTime */ 0.0,
/* bool aIsShuttingDown */ false, /* bool aIsShuttingDown */ false,
/* ProfilerCodeAddressService* aService */ nullptr)); /* ProfilerCodeAddressService* aService */ nullptr,
mozilla::ProgressLogger{}));
w.End(); w.End();
}), }),
NS_DISPATCH_SYNC); NS_DISPATCH_SYNC);
@ -3717,7 +3720,8 @@ TEST(GeckoProfiler, StreamJSONForThisProcessThreaded)
ASSERT_TRUE(!::do_profiler_stream_json_for_this_process( ASSERT_TRUE(!::do_profiler_stream_json_for_this_process(
w, /* double aSinceTime */ 0.0, w, /* double aSinceTime */ 0.0,
/* bool aIsShuttingDown */ false, /* bool aIsShuttingDown */ false,
/* ProfilerCodeAddressService* aService */ nullptr)); /* ProfilerCodeAddressService* aService */ nullptr,
mozilla::ProgressLogger{}));
}), }),
NS_DISPATCH_SYNC); NS_DISPATCH_SYNC);
thread->Shutdown(); thread->Shutdown();