1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ProfiledThreadData.h"
9 #include "BaseProfiler.h"
10 #include "ProfileBuffer.h"
12 #include "mozilla/BaseProfileJSONWriter.h"
14 #if defined(GP_OS_darwin)
19 namespace baseprofiler
{
21 ProfiledThreadData::ProfiledThreadData(ThreadInfo
* aThreadInfo
)
22 : mThreadInfo(aThreadInfo
) {}
24 ProfiledThreadData::~ProfiledThreadData() {}
26 void ProfiledThreadData::StreamJSON(const ProfileBuffer
& aBuffer
,
27 SpliceableJSONWriter
& aWriter
,
28 const std::string
& aProcessName
,
29 const std::string
& aETLDplus1
,
30 const TimeStamp
& aProcessStartTime
,
32 UniqueStacks uniqueStacks
;
34 aWriter
.SetUniqueStrings(uniqueStacks
.UniqueStrings());
38 StreamSamplesAndMarkers(mThreadInfo
->Name(), mThreadInfo
->ThreadId(),
39 aBuffer
, aWriter
, aProcessName
, aETLDplus1
,
40 aProcessStartTime
, mThreadInfo
->RegisterTime(),
41 mUnregisterTime
, aSinceTime
, uniqueStacks
);
43 aWriter
.StartObjectProperty("stackTable");
46 JSONSchemaWriter
schema(aWriter
);
47 schema
.WriteField("prefix");
48 schema
.WriteField("frame");
51 aWriter
.StartArrayProperty("data");
52 { uniqueStacks
.SpliceStackTableElements(aWriter
); }
57 aWriter
.StartObjectProperty("frameTable");
60 JSONSchemaWriter
schema(aWriter
);
61 schema
.WriteField("location");
62 schema
.WriteField("relevantForJS");
63 schema
.WriteField("innerWindowID");
64 schema
.WriteField("implementation");
65 schema
.WriteField("line");
66 schema
.WriteField("column");
67 schema
.WriteField("category");
68 schema
.WriteField("subcategory");
71 aWriter
.StartArrayProperty("data");
72 { uniqueStacks
.SpliceFrameTableElements(aWriter
); }
77 aWriter
.StartArrayProperty("stringTable");
79 std::move(uniqueStacks
.UniqueStrings())
80 .SpliceStringTableElements(aWriter
);
86 aWriter
.ResetUniqueStrings();
89 BaseProfilerThreadId
StreamSamplesAndMarkers(
90 const char* aName
, BaseProfilerThreadId aThreadId
,
91 const ProfileBuffer
& aBuffer
, SpliceableJSONWriter
& aWriter
,
92 const std::string
& aProcessName
, const std::string
& aETLDplus1
,
93 const TimeStamp
& aProcessStartTime
, const TimeStamp
& aRegisterTime
,
94 const TimeStamp
& aUnregisterTime
, double aSinceTime
,
95 UniqueStacks
& aUniqueStacks
) {
96 BaseProfilerThreadId processedThreadId
;
98 aWriter
.StringProperty(
100 "(unknown)" /* XRE_GeckoProcessTypeToString(XRE_GetProcessType()) */);
103 std::string name
= aName
;
104 // We currently need to distinguish threads output by Base Profiler from
105 // those in Gecko Profiler, as the frontend could get confused and lose
106 // tracks with the same name.
107 // TODO: As part of the profilers de-duplication, thread data from both
108 // profilers should end up in the same track, at which point this won't be
109 // necessary anymore. See meta bug 1557566.
110 name
+= " (pre-xul)";
111 aWriter
.StringProperty("name", name
);
114 // Use given process name (if any).
115 if (!aProcessName
.empty()) {
116 aWriter
.StringProperty("processName", aProcessName
);
118 if (!aETLDplus1
.empty()) {
119 aWriter
.StringProperty("eTLD+1", aETLDplus1
);
123 aWriter
.DoubleProperty(
124 "registerTime", (aRegisterTime
- aProcessStartTime
).ToMilliseconds());
126 aWriter
.NullProperty("registerTime");
129 if (aUnregisterTime
) {
130 aWriter
.DoubleProperty(
132 (aUnregisterTime
- aProcessStartTime
).ToMilliseconds());
134 aWriter
.NullProperty("unregisterTime");
137 aWriter
.StartObjectProperty("samples");
140 JSONSchemaWriter
schema(aWriter
);
141 schema
.WriteField("stack");
142 schema
.WriteField("time");
143 schema
.WriteField("eventDelay");
146 aWriter
.StartArrayProperty("data");
148 processedThreadId
= aBuffer
.StreamSamplesToJSON(
149 aWriter
, aThreadId
, aSinceTime
, aUniqueStacks
);
155 aWriter
.StartObjectProperty("markers");
158 JSONSchemaWriter
schema(aWriter
);
159 schema
.WriteField("name");
160 schema
.WriteField("startTime");
161 schema
.WriteField("endTime");
162 schema
.WriteField("phase");
163 schema
.WriteField("category");
164 schema
.WriteField("data");
167 aWriter
.StartArrayProperty("data");
169 aBuffer
.StreamMarkersToJSON(aWriter
, aThreadId
, aProcessStartTime
,
170 aSinceTime
, aUniqueStacks
);
176 // Tech note: If `ToNumber()` returns a uint64_t, the conversion to int64_t is
177 // "implementation-defined" before C++20. This is acceptable here, because
178 // this is a one-way conversion to a unique identifier that's used to visually
179 // separate data by thread on the front-end.
181 "pid", static_cast<int64_t>(profiler_current_process_id().ToNumber()));
182 aWriter
.IntProperty("tid",
183 static_cast<int64_t>(aThreadId
.IsSpecified()
184 ? aThreadId
.ToNumber()
185 : processedThreadId
.ToNumber()));
187 return processedThreadId
;
190 } // namespace baseprofiler
191 } // namespace mozilla