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,
ProgressLogger aProgressLogger,
JSONWriter::CollectionStyle aStyle) {
using namespace mozilla::literals::ProportionValue_literals; // For `10_pc`.
mStringTableWriter.StartBareList(aStyle);
uint32_t count = aOther.mStringHashToIndexMap.count();
if (count != 0) {
MOZ_RELEASE_ASSERT(mStringHashToIndexMap.reserve(count));
for (auto iter = aOther.mStringHashToIndexMap.iter(); !iter.done();
iter.next()) {
MOZ_ALWAYS_TRUE(mStringHashToIndexMap.reserve(count));
auto iter = aOther.mStringHashToIndexMap.iter();
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(),
iter.get().value());
iter.next();
}
aProgressLogger.SetLocalProgress(90_pc, "Copied unique strings");
mStringTableWriter.CopyAndSplice(
aOther.mStringTableWriter.ChunkedWriteFunc());
aProgressLogger.SetLocalProgress(100_pc, "Spliced unique strings");
}
}

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

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

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

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

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

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

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

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

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

@ -144,7 +144,8 @@ struct JITFrameInfoForBufferRange final {
struct JITFrameInfo final {
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
// information about the provided JIT return addresses using aCx.

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

@ -18,6 +18,8 @@
# include <pthread.h>
#endif
using namespace mozilla::literals::ProportionValue_literals;
ProfiledThreadData::ProfiledThreadData(
const mozilla::profiler::ThreadRegistrationInfo& aThreadInfo)
: mThreadInfo(aThreadInfo.Name(), aThreadInfo.ThreadId(),
@ -126,7 +128,8 @@ static void StreamTraceLoggerJSON(JSContext* aCx, SpliceableJSONWriter& aWriter,
static void StreamTablesAndTraceLogger(
UniqueStacks&& aUniqueStacks, JSContext* aCx, SpliceableJSONWriter& aWriter,
const mozilla::TimeStamp& aProcessStartTime, bool JSTracerEnabled) {
const mozilla::TimeStamp& aProcessStartTime, bool JSTracerEnabled,
mozilla::ProgressLogger aProgressLogger) {
aWriter.StartObjectProperty("stackTable");
{
{
@ -136,7 +139,11 @@ static void StreamTablesAndTraceLogger(
}
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.EndObject();
@ -157,42 +164,62 @@ static void StreamTablesAndTraceLogger(
}
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.EndObject();
aWriter.StartArrayProperty("stringTable");
{
aProgressLogger.SetLocalProgress(60_pc, "Splicing string table...");
std::move(*aUniqueStacks.mUniqueStrings).SpliceStringTableElements(aWriter);
aProgressLogger.SetLocalProgress(90_pc, "Spliced string table");
}
aWriter.EndArray();
if (aCx && JSTracerEnabled) {
aProgressLogger.SetLocalProgress(90_pc, "Streaming trace logger...");
StreamTraceLoggerJSON(aCx, aWriter, aProcessStartTime);
aProgressLogger.SetLocalProgress(100_pc, "Streamed trace logger");
} else {
aProgressLogger.SetLocalProgress(100_pc, "No trace logger");
}
}
mozilla::NotNull<mozilla::UniquePtr<UniqueStacks>>
ProfiledThreadData::PrepareUniqueStacks(const ProfileBuffer& aBuffer,
JSContext* aCx,
ProfilerCodeAddressService* aService) {
ProfiledThreadData::PrepareUniqueStacks(
const ProfileBuffer& aBuffer, JSContext* aCx,
ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger) {
if (mJITFrameInfoForPreviousJSContexts &&
mJITFrameInfoForPreviousJSContexts->HasExpired(
aBuffer.BufferRangeStart())) {
mJITFrameInfoForPreviousJSContexts = nullptr;
}
aProgressLogger.SetLocalProgress(1_pc, "Checked JIT frame info presence");
// If we have an existing JITFrameInfo in mJITFrameInfoForPreviousJSContexts,
// copy the data from it.
JITFrameInfo jitFrameInfo =
mJITFrameInfoForPreviousJSContexts
? JITFrameInfo(*mJITFrameInfoForPreviousJSContexts)
? JITFrameInfo(*mJITFrameInfoForPreviousJSContexts,
aProgressLogger.CreateSubLoggerTo(
"Retrieving JIT frame info...", 10_pc,
"Retrieved JIT frame info"))
: JITFrameInfo();
if (aCx && mBufferPositionWhenReceivedJSContext) {
aBuffer.AddJITInfoForRange(*mBufferPositionWhenReceivedJSContext,
mThreadInfo.ThreadId(), aCx, jitFrameInfo);
aBuffer.AddJITInfoForRange(
*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>>(
@ -203,22 +230,31 @@ void ProfiledThreadData::StreamJSON(
const ProfileBuffer& aBuffer, JSContext* aCx, SpliceableJSONWriter& aWriter,
const nsACString& aProcessName, const nsACString& aETLDplus1,
const mozilla::TimeStamp& aProcessStartTime, double aSinceTime,
bool JSTracerEnabled, ProfilerCodeAddressService* aService) {
bool JSTracerEnabled, ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger) {
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);
aWriter.SetUniqueStrings(*uniqueStacks->mUniqueStrings);
aWriter.Start();
{
StreamSamplesAndMarkers(mThreadInfo.Name(), mThreadInfo.ThreadId(), aBuffer,
aWriter, aProcessName, aETLDplus1,
aProcessStartTime, mThreadInfo.RegisterTime(),
mUnregisterTime, aSinceTime, *uniqueStacks);
StreamSamplesAndMarkers(
mThreadInfo.Name(), mThreadInfo.ThreadId(), aBuffer, aWriter,
aProcessName, aETLDplus1, aProcessStartTime, mThreadInfo.RegisterTime(),
mUnregisterTime, aSinceTime, *uniqueStacks,
aProgressLogger.CreateSubLoggerTo(
90_pc,
"ProfiledThreadData::StreamJSON: Streamed samples and markers"));
StreamTablesAndTraceLogger(std::move(*uniqueStacks), aCx, aWriter,
aProcessStartTime, JSTracerEnabled);
aProcessStartTime, JSTracerEnabled,
aProgressLogger.CreateSubLoggerTo(
99_pc, "Streamed tables and trace logger"));
}
aWriter.End();
@ -229,24 +265,33 @@ void ProfiledThreadData::StreamJSON(
ThreadStreamingContext&& aThreadStreamingContext,
SpliceableJSONWriter& aWriter, const nsACString& aProcessName,
const nsACString& aETLDplus1, const mozilla::TimeStamp& aProcessStartTime,
bool JSTracerEnabled, ProfilerCodeAddressService* aService) {
bool JSTracerEnabled, ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger) {
aWriter.Start();
{
StreamSamplesAndMarkers(mThreadInfo.Name(), aThreadStreamingContext,
aWriter, aProcessName, aETLDplus1,
aProcessStartTime, mThreadInfo.RegisterTime(),
mUnregisterTime);
StreamSamplesAndMarkers(
mThreadInfo.Name(), aThreadStreamingContext, aWriter, aProcessName,
aETLDplus1, aProcessStartTime, mThreadInfo.RegisterTime(),
mUnregisterTime,
aProgressLogger.CreateSubLoggerFromTo(
1_pc, "ProfiledThreadData::StreamJSON(context): Streaming...",
90_pc,
"ProfiledThreadData::StreamJSON(context): Streamed samples and "
"markers"));
StreamTablesAndTraceLogger(
std::move(*aThreadStreamingContext.mUniqueStacks),
aThreadStreamingContext.mJSContext, aWriter, aProcessStartTime,
JSTracerEnabled);
JSTracerEnabled,
aProgressLogger.CreateSubLoggerTo(
"ProfiledThreadData::StreamJSON(context): Streaming tables...",
99_pc, "ProfiledThreadData::StreamJSON(context): Streamed tables"));
}
aWriter.End();
}
// StreamSamplesDataCallback: () -> ProfilerThreadId
// StreamMarkersDataCallback: () -> void
// StreamSamplesDataCallback: (ProgressLogger) -> ProfilerThreadId
// StreamMarkersDataCallback: (ProgressLogger) -> void
// Returns the ProfilerThreadId returned by StreamSamplesDataCallback, which
// 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
@ -260,6 +305,7 @@ ProfilerThreadId DoStreamSamplesAndMarkers(
const mozilla::TimeStamp& aProcessStartTime,
const mozilla::TimeStamp& aRegisterTime,
const mozilla::TimeStamp& aUnregisterTime,
mozilla::ProgressLogger aProgressLogger,
StreamSamplesDataCallback&& aStreamSamplesDataCallback,
StreamMarkersDataCallback&& aStreamMarkersDataCallback) {
ProfilerThreadId processedThreadId;
@ -317,8 +363,9 @@ ProfilerThreadId DoStreamSamplesAndMarkers(
aWriter.StartArrayProperty("data");
{
processedThreadId =
std::forward<StreamSamplesDataCallback>(aStreamSamplesDataCallback)();
processedThreadId = std::forward<StreamSamplesDataCallback>(
aStreamSamplesDataCallback)(aProgressLogger.CreateSubLoggerFromTo(
1_pc, "Streaming samples...", 49_pc, "Streamed samples"));
}
aWriter.EndArray();
}
@ -337,7 +384,11 @@ ProfilerThreadId DoStreamSamplesAndMarkers(
}
aWriter.StartArrayProperty("data");
{ std::forward<StreamMarkersDataCallback>(aStreamMarkersDataCallback)(); }
{
std::forward<StreamMarkersDataCallback>(aStreamMarkersDataCallback)(
aProgressLogger.CreateSubLoggerFromTo(50_pc, "Streaming markers...",
99_pc, "Streamed markers"));
}
aWriter.EndArray();
}
aWriter.EndObject();
@ -360,18 +411,20 @@ ProfilerThreadId StreamSamplesAndMarkers(
const nsACString& aETLDplus1, const mozilla::TimeStamp& aProcessStartTime,
const mozilla::TimeStamp& aRegisterTime,
const mozilla::TimeStamp& aUnregisterTime, double aSinceTime,
UniqueStacks& aUniqueStacks) {
UniqueStacks& aUniqueStacks, mozilla::ProgressLogger aProgressLogger) {
return DoStreamSamplesAndMarkers(
aName, aWriter, aProcessName, aETLDplus1, aProcessStartTime,
aRegisterTime, aUnregisterTime,
[&]() {
aRegisterTime, aUnregisterTime, std::move(aProgressLogger),
[&](mozilla::ProgressLogger aSubProgressLogger) {
ProfilerThreadId processedThreadId = aBuffer.StreamSamplesToJSON(
aWriter, aThreadId, aSinceTime, aUniqueStacks);
aWriter, aThreadId, aSinceTime, aUniqueStacks,
std::move(aSubProgressLogger));
return aThreadId.IsSpecified() ? aThreadId : processedThreadId;
},
[&]() {
[&](mozilla::ProgressLogger aSubProgressLogger) {
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 mozilla::TimeStamp& aProcessStartTime,
const mozilla::TimeStamp& aRegisterTime,
const mozilla::TimeStamp& aUnregisterTime) {
const mozilla::TimeStamp& aUnregisterTime,
mozilla::ProgressLogger aProgressLogger) {
(void)DoStreamSamplesAndMarkers(
aName, aWriter, aProcessName, aETLDplus1, aProcessStartTime,
aRegisterTime, aUnregisterTime,
[&]() {
aRegisterTime, aUnregisterTime, std::move(aProgressLogger),
[&](mozilla::ProgressLogger aSubProgressLogger) {
aWriter.TakeAndSplice(
aThreadData.mSamplesDataWriter.TakeChunkedWriteFunc());
return aThreadData.mProfiledThreadData.Info().ThreadId();
},
[&]() {
[&](mozilla::ProgressLogger aSubProgressLogger) {
aWriter.TakeAndSplice(
aThreadData.mMarkersDataWriter.TakeChunkedWriteFunc());
});
@ -418,7 +472,8 @@ void ProfiledThreadData::NotifyAboutToLoseJSContext(
: mozilla::MakeUnique<JITFrameInfo>();
aBuffer.AddJITInfoForRange(*mBufferPositionWhenReceivedJSContext,
mThreadInfo.ThreadId(), aContext, *jitFrameInfo);
mThreadInfo.ThreadId(), aContext, *jitFrameInfo,
mozilla::ProgressLogger{});
mJITFrameInfoForPreviousJSContexts = std::move(jitFrameInfo);
mBufferPositionWhenReceivedJSContext = mozilla::Nothing();
@ -426,11 +481,15 @@ void ProfiledThreadData::NotifyAboutToLoseJSContext(
ThreadStreamingContext::ThreadStreamingContext(
ProfiledThreadData& aProfiledThreadData, const ProfileBuffer& aBuffer,
JSContext* aCx, ProfilerCodeAddressService* aService)
JSContext* aCx, ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger)
: mProfiledThreadData(aProfiledThreadData),
mJSContext(aCx),
mUniqueStacks(
mProfiledThreadData.PrepareUniqueStacks(aBuffer, aCx, aService)) {
mUniqueStacks(mProfiledThreadData.PrepareUniqueStacks(
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.StartBareList();
mMarkersDataWriter.SetUniqueStrings(*mUniqueStacks->mUniqueStrings);
@ -458,11 +517,15 @@ ProcessStreamingContext::~ProcessStreamingContext() {
void ProcessStreamingContext::AddThreadStreamingContext(
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() < mTIDList.capacity(),
"Didn't pre-allocate enough");
mTIDList.infallibleAppend(aProfiledThreadData.Info().ThreadId());
mThreadStreamingContextList.infallibleEmplaceBack(aProfiledThreadData,
aBuffer, aCx, aService);
mThreadStreamingContextList.infallibleEmplaceBack(
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(
const ProfileBuffer& aBuffer, JSContext* aCx,
ProfilerCodeAddressService* aService);
ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger);
void StreamJSON(const ProfileBuffer& aBuffer, JSContext* aCx,
SpliceableJSONWriter& aWriter, const nsACString& aProcessName,
const nsACString& aETLDplus1,
const mozilla::TimeStamp& aProcessStartTime,
double aSinceTime, bool aJSTracerEnabled,
ProfilerCodeAddressService* aService);
ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger);
void StreamJSON(ThreadStreamingContext&& aThreadStreamingContext,
SpliceableJSONWriter& aWriter, const nsACString& aProcessName,
const nsACString& aETLDplus1,
const mozilla::TimeStamp& aProcessStartTime,
bool aJSTracerEnabled, ProfilerCodeAddressService* aService);
bool aJSTracerEnabled, ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger);
const mozilla::profiler::ThreadRegistrationInfo& Info() const {
return mThreadInfo;
@ -159,7 +162,8 @@ struct ThreadStreamingContext {
ThreadStreamingContext(ProfiledThreadData& aProfiledThreadData,
const ProfileBuffer& aBuffer, JSContext* aCx,
ProfilerCodeAddressService* aService);
ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger);
void FinalizeWriter();
};
@ -178,7 +182,8 @@ class ProcessStreamingContext {
// should be called exactly the number of times specified in the constructor.
void AddThreadStreamingContext(ProfiledThreadData& aProfiledThreadData,
const ProfileBuffer& aBuffer, JSContext* aCx,
ProfilerCodeAddressService* aService);
ProfilerCodeAddressService* aService,
mozilla::ProgressLogger aProgressLogger);
// Retrieve the ThreadStreamingContext for a given thread id.
// 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 mozilla::TimeStamp& aRegisterTime,
const mozilla::TimeStamp& aUnregisterTime, double aSinceTime,
UniqueStacks& aUniqueStacks);
UniqueStacks& aUniqueStacks, mozilla::ProgressLogger aProgressLogger);
void StreamSamplesAndMarkers(const char* aName,
ThreadStreamingContext& aThreadData,
SpliceableJSONWriter& aWriter,
@ -232,6 +237,7 @@ void StreamSamplesAndMarkers(const char* aName,
const nsACString& aETLDplus1,
const mozilla::TimeStamp& aProcessStartTime,
const mozilla::TimeStamp& aRegisterTime,
const mozilla::TimeStamp& aUnregisterTime);
const mozilla::TimeStamp& aUnregisterTime,
mozilla::ProgressLogger aProgressLogger);
#endif // ProfiledThreadData_h

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

@ -85,7 +85,7 @@ ProfilerThreadId ProfilerBacktrace::StreamJSON(
""_ns, aProcessStartTime,
/* aRegisterTime */ mozilla::TimeStamp(),
/* aUnregisterTime */ mozilla::TimeStamp(),
/* aSinceTime */ 0, aUniqueStacks);
/* aSinceTime */ 0, aUniqueStacks, mozilla::ProgressLogger{});
} else if (mProfileChunkedBuffer) {
ProfileBuffer profileBuffer(*mProfileChunkedBuffer);
processedThreadId = StreamSamplesAndMarkers(
@ -93,7 +93,7 @@ ProfilerThreadId ProfilerBacktrace::StreamJSON(
aProcessStartTime,
/* aRegisterTime */ 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.

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

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

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

@ -36,6 +36,7 @@
#include "mozilla/MathAlgorithms.h"
#include "mozilla/ProfileBufferEntrySerialization.h"
#include "mozilla/ProfilerUtils.h"
#include "mozilla/ProgressLogger.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Vector.h"
@ -95,7 +96,7 @@ uint32_t ParseFeaturesFromStringArray(const char** aFeatures,
void profiler_get_profile_json_into_lazily_allocated_buffer(
const std::function<char*(size_t)>& aAllocator, double aSinceTime,
bool aIsShuttingDown);
bool aIsShuttingDown, mozilla::ProgressLogger aProgressLogger);
// Flags to conveniently track various JS instrumentations.
enum class JSInstrumentationFlags {

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

@ -261,7 +261,10 @@ mozilla::ipc::IPCResult ProfilerChild::RecvDestroyReleasedChunksAtOrBefore(
mozilla::ipc::IPCResult ProfilerChild::RecvGatherProfile(
GatherProfileResolver&& aResolve) {
// TODO: Use a real ProgressLogger with shared progress.
mozilla::ProgressLogger progressLogger{};
mozilla::ipc::Shmem shmem;
using namespace mozilla::literals::ProportionValue_literals; // For `1_pc`.
profiler_get_profile_json_into_lazily_allocated_buffer(
[&](size_t allocationSize) -> char* {
if (AllocShmem(allocationSize,
@ -271,7 +274,12 @@ mozilla::ipc::IPCResult ProfilerChild::RecvGatherProfile(
return nullptr;
},
/* 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));
return IPC_OK();
}

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

@ -27,6 +27,7 @@
#include "mozilla/ProfilerMarkers.h"
#include "mozilla/ProfilerState.h"
#include "mozilla/ProfilerThreadState.h"
#include "mozilla/ProgressLogger.h"
enum class IsFastShutdown {
No,
@ -511,7 +512,8 @@ mozilla::UniquePtr<char[]> profiler_get_profile(double aSinceTime = 0,
bool profiler_stream_json_for_this_process(
mozilla::baseprofiler::SpliceableJSONWriter& aWriter, double aSinceTime = 0,
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
// inactive.

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

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