commit 15b0f55ab57e9c333fe20af8e4a53984d81360e9
parent 9681c29277f9bd20aded112340cd1615d65dbb31
Author: Nazım Can Altınova <canaltinova@gmail.com>
Date: Tue, 21 Oct 2025 23:59:07 +0000
Bug 1979114 - Stream SourceTable for each process r=mstange,profiler-reviewers
This table keeps [uuid, filename] mapping for each source, and each
location string will include the index into source table for the
individual source for the JS frames.
Differential Revision: https://phabricator.services.mozilla.com/D266234
Diffstat:
4 files changed, 70 insertions(+), 0 deletions(-)
diff --git a/tools/profiler/core/ProfileBuffer.h b/tools/profiler/core/ProfileBuffer.h
@@ -13,10 +13,13 @@
#include "mozilla/PowerOfTwo.h"
#include "mozilla/ProfileBufferChunkManagerSingle.h"
#include "mozilla/ProfileChunkedBuffer.h"
+#include "nsTHashMap.h"
class ProcessStreamingContext;
class RunningTimes;
+struct ProfilerJSSourceData;
+
// Class storing most profiling data in a ProfileChunkedBuffer.
//
// This class is used as a queue of entries which, after construction, never
@@ -96,6 +99,12 @@ class ProfileBuffer final {
double aSinceTime,
mozilla::ProgressLogger aProgressLogger) const;
+ // Stream JavaScript source table to JSON and return mapping from sourceId
+ // to index into source table.
+ nsTHashMap<SourceId, IndexIntoSourceTable> StreamSourceTableToJSON(
+ SpliceableJSONWriter& aWriter,
+ const nsTArray<mozilla::JSSourceEntry>& aJSSourceEntries) const;
+
// Find (via |aLastSample|) the most recent sample for the thread denoted by
// |aThreadId| and clone it, patching in the current time as appropriate.
// Mutate |aLastSample| to point to the newly inserted sample.
diff --git a/tools/profiler/core/ProfileBufferEntry.cpp b/tools/profiler/core/ProfileBufferEntry.cpp
@@ -2512,5 +2512,53 @@ void ProfileBuffer::DiscardSamplesBeforeTime(double aTime) {
(void)aTime;
}
+nsTHashMap<SourceId, IndexIntoSourceTable>
+ProfileBuffer::StreamSourceTableToJSON(
+ SpliceableJSONWriter& aWriter,
+ const nsTArray<mozilla::JSSourceEntry>& aJSSourceEntries) const {
+ enum Schema : uint32_t { UUID = 0, FILENAME = 1 };
+ nsTHashMap<SourceId, IndexIntoSourceTable> sourceIdToIndexMap;
+
+ aWriter.StartObjectProperty("sources");
+ {
+ // Write the schema
+ {
+ JSONSchemaWriter schema(aWriter);
+ schema.WriteField("uuid");
+ schema.WriteField("filename");
+ }
+
+ // Write data array and build sourceId-to-index mapping
+ aWriter.StartArrayProperty("data");
+ uint32_t index = 0;
+ for (const auto& entry : aJSSourceEntries) {
+ // Build sourceId-to-index mapping
+ if (entry.sourceData.sourceId() != 0) {
+ MOZ_ASSERT(!sourceIdToIndexMap.Contains(entry.sourceData.sourceId()),
+ "Duplicate sourceId detected! This indicates sourceId "
+ "collision between different sources.");
+ sourceIdToIndexMap.InsertOrUpdate(entry.sourceData.sourceId(), index);
+ }
+
+ // Write [uuid, filename] entry
+ aWriter.StartArrayElement();
+ {
+ // TODO: Use AutoArraySchemaWithStringsWriter to write string indexes
+ // into string table once we have "process global" string table.
+ // Currently string tables are per-thread.
+ aWriter.StringElement(MakeStringSpan(entry.uuid.get()));
+ aWriter.StringElement(MakeStringSpan(entry.sourceData.filePath()));
+ }
+ aWriter.EndArray();
+
+ index++;
+ }
+ aWriter.EndArray();
+ }
+ aWriter.EndObject();
+
+ return sourceIdToIndexMap;
+}
+
// END ProfileBuffer
////////////////////////////////////////////////////////////////////////
diff --git a/tools/profiler/core/ProfileBufferEntry.h b/tools/profiler/core/ProfileBufferEntry.h
@@ -29,6 +29,11 @@
class ProfilerCodeAddressService;
struct JSContext;
+// Typedef for process-global identifiers for JS script sources.
+using SourceId = uint32_t;
+// Typedef for indexes into the source table array.
+using IndexIntoSourceTable = uint32_t;
+
class ProfileBufferEntry {
public:
using KindUnderlyingType =
diff --git a/tools/profiler/core/platform.cpp b/tools/profiler/core/platform.cpp
@@ -3874,6 +3874,14 @@ locked_profiler_stream_json_for_this_process(
nsTArray<mozilla::JSSourceEntry> jsSourceEntries =
ActivePS::GatherJSSources(aLock);
+ // If there are sources, stream the sources table that is shared between the
+ // threads, and get the UUID to index mappings needed for frame serialization.
+ Maybe<nsTHashMap<SourceId, IndexIntoSourceTable>> sourceIdToIndexMap;
+ if (!jsSourceEntries.IsEmpty()) {
+ sourceIdToIndexMap.emplace(
+ buffer.StreamSourceTableToJSON(aWriter, jsSourceEntries));
+ }
+
// Lists the samples for each thread profile
aWriter.StartArrayProperty("threads");
{