Skip to content

Commit ffd8b16

Browse files
rubennortefacebook-github-bot
authored andcommitted
Add support for details field and custom tracks in performance.mark and performance.measure for DevTools (facebook#52613)
Summary: Pull Request resolved: facebook#52613 Changelog: [internal] This adds first-class support for the `detail` field in `performance.mark` and `performance.measure`. Now that we have access the JS entry in native, we can access the `detail` field to propagate it to DevTools (and use it to extract track names for Perfetto). In order to avoid the performance overhead of always having to extract the `detail` field from the entry, this is done lazily only if we're actively profiling with DevTools or Perfetto. Reviewed By: sbuggay Differential Revision: D78340911
1 parent 46bf900 commit ffd8b16

File tree

6 files changed

+94
-58
lines changed

6 files changed

+94
-58
lines changed

packages/react-native/ReactCommon/jsinspector-modern/tracing/CdpTracing.h

Lines changed: 0 additions & 21 deletions
This file was deleted.

packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ void PerformanceTracer::collectEvents(
113113

114114
void PerformanceTracer::reportMark(
115115
const std::string_view& name,
116-
HighResTimeStamp start) {
116+
HighResTimeStamp start,
117+
folly::dynamic&& detail) {
117118
if (!tracingAtomic_) {
118119
return;
119120
}
@@ -123,32 +124,37 @@ void PerformanceTracer::reportMark(
123124
return;
124125
}
125126

127+
folly::dynamic eventArgs = folly::dynamic::object();
128+
if (detail != nullptr) {
129+
eventArgs = folly::dynamic::object(
130+
"data",
131+
folly::dynamic::object("detail", folly::toJson(std::move(detail))));
132+
}
133+
126134
buffer_.emplace_back(TraceEvent{
127135
.name = std::string(name),
128136
.cat = "blink.user_timing",
129137
.ph = 'I',
130138
.ts = start,
131139
.pid = processId_,
132140
.tid = oscompat::getCurrentThreadId(),
141+
.args = eventArgs,
133142
});
134143
}
135144

136145
void PerformanceTracer::reportMeasure(
137146
const std::string_view& name,
138147
HighResTimeStamp start,
139148
HighResDuration duration,
140-
const std::optional<DevToolsTrackEntryPayload>& trackMetadata) {
149+
folly::dynamic&& detail) {
141150
if (!tracingAtomic_) {
142151
return;
143152
}
144153

145154
folly::dynamic beginEventArgs = folly::dynamic::object();
146-
if (trackMetadata.has_value()) {
147-
folly::dynamic devtoolsObject = folly::dynamic::object(
148-
"devtools",
149-
folly::dynamic::object("track", trackMetadata.value().track));
155+
if (detail != nullptr) {
150156
beginEventArgs =
151-
folly::dynamic::object("detail", folly::toJson(devtoolsObject));
157+
folly::dynamic::object("detail", folly::toJson(std::move(detail)));
152158
}
153159

154160
auto currentThreadId = oscompat::getCurrentThreadId();

packages/react-native/ReactCommon/jsinspector-modern/tracing/PerformanceTracer.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
#pragma once
99

10-
#include "CdpTracing.h"
1110
#include "ConsoleTimeStamp.h"
1211
#include "TraceEvent.h"
1312
#include "TraceEventProfile.h"
@@ -60,13 +59,17 @@ class PerformanceTracer {
6059
const std::function<void(const folly::dynamic& eventsChunk)>&
6160
resultCallback,
6261
uint16_t chunkSize);
62+
6363
/**
6464
* Record a `Performance.mark()` event - a labelled timestamp. If not
6565
* currently tracing, this is a no-op.
6666
*
6767
* See https://w3c.github.io/user-timing/#mark-method.
6868
*/
69-
void reportMark(const std::string_view& name, HighResTimeStamp start);
69+
void reportMark(
70+
const std::string_view& name,
71+
HighResTimeStamp start,
72+
folly::dynamic&& detail = nullptr);
7073

7174
/**
7275
* Record a `Performance.measure()` event - a labelled duration. If not
@@ -78,8 +81,7 @@ class PerformanceTracer {
7881
const std::string_view& name,
7982
HighResTimeStamp start,
8083
HighResDuration duration,
81-
const std::optional<DevToolsTrackEntryPayload>& trackMetadata =
82-
std::nullopt);
84+
folly::dynamic&& detail = nullptr);
8385

8486
/**
8587
* Record a "TimeStamp" Trace Event - a labelled entry on Performance

packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <cxxreact/JSExecutor.h>
1515
#include <cxxreact/ReactMarker.h>
16+
#include <jsi/JSIDynamic.h>
1617
#include <jsi/instrumentation.h>
1718
#include <react/performance/timeline/PerformanceEntryReporter.h>
1819
#include <react/performance/timeline/PerformanceObserver.h>
@@ -111,6 +112,19 @@ std::shared_ptr<PerformanceObserver> tryGetObserver(
111112
return observerWrapper ? observerWrapper->observer : nullptr;
112113
}
113114

115+
PerformanceEntryReporter::UserTimingDetailProvider getDetailProviderFromEntry(
116+
jsi::Runtime& rt,
117+
jsi::Value& entry) {
118+
return [&rt, &entry]() -> folly::dynamic {
119+
try {
120+
auto detail = entry.asObject(rt).getProperty(rt, "detail");
121+
return jsi::dynamicFromValue(rt, detail);
122+
} catch (jsi::JSIException& ex) {
123+
return nullptr;
124+
}
125+
};
126+
}
127+
114128
} // namespace
115129

116130
NativePerformance::NativePerformance(std::shared_ptr<CallInvoker> jsInvoker)
@@ -124,18 +138,19 @@ void NativePerformance::reportMark(
124138
jsi::Runtime& rt,
125139
std::string name,
126140
HighResTimeStamp startTime,
127-
jsi::Value /*entry*/) {
128-
PerformanceEntryReporter::getInstance()->reportMark(name, startTime);
141+
jsi::Value entry) {
142+
PerformanceEntryReporter::getInstance()->reportMark(
143+
name, startTime, getDetailProviderFromEntry(rt, entry));
129144
}
130145

131146
void NativePerformance::reportMeasure(
132147
jsi::Runtime& rt,
133148
std::string name,
134149
HighResTimeStamp startTime,
135150
HighResDuration duration,
136-
jsi::Value /*entry*/) {
151+
jsi::Value entry) {
137152
PerformanceEntryReporter::getInstance()->reportMeasure(
138-
name, startTime, duration);
153+
name, startTime, duration, getDetailProviderFromEntry(rt, entry));
139154
}
140155

141156
std::optional<double> NativePerformance::getMarkTime(

packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.cpp

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,22 @@ std::vector<PerformanceEntryType> getSupportedEntryTypesInternal() {
3737
return supportedEntryTypes;
3838
}
3939

40+
std::optional<std::string> getTrackFromDetail(folly::dynamic& detail) {
41+
auto maybeTrack = detail["devtools"]["track"];
42+
if (maybeTrack.isString()) {
43+
return maybeTrack.asString();
44+
}
45+
return std::nullopt;
46+
}
47+
48+
std::optional<std::string> getTrackGroupFromDetail(folly::dynamic& detail) {
49+
auto maybeTrackGroup = detail["devtools"]["trackGroup"];
50+
if (maybeTrackGroup.isString()) {
51+
return maybeTrackGroup.asString();
52+
}
53+
return std::nullopt;
54+
}
55+
4056
} // namespace
4157

4258
std::shared_ptr<PerformanceEntryReporter>&
@@ -142,10 +158,11 @@ void PerformanceEntryReporter::clearEntries(
142158

143159
void PerformanceEntryReporter::reportMark(
144160
const std::string& name,
145-
const HighResTimeStamp startTime) {
161+
const HighResTimeStamp startTime,
162+
UserTimingDetailProvider&& detailProvider) {
146163
const auto entry = PerformanceMark{{.name = name, .startTime = startTime}};
147164

148-
traceMark(entry);
165+
traceMark(entry, std::move(detailProvider));
149166

150167
// Add to buffers & notify observers
151168
{
@@ -160,14 +177,13 @@ void PerformanceEntryReporter::reportMeasure(
160177
const std::string& name,
161178
HighResTimeStamp startTime,
162179
HighResDuration duration,
163-
const std::optional<jsinspector_modern::DevToolsTrackEntryPayload>&
164-
trackMetadata) {
180+
UserTimingDetailProvider&& detailProvider) {
165181
const auto entry = PerformanceMeasure{
166182
{.name = std::string(name),
167183
.startTime = startTime,
168184
.duration = duration}};
169185

170-
traceMeasure(entry);
186+
traceMeasure(entry, std::move(detailProvider));
171187

172188
// Add to buffers & notify observers
173189
{
@@ -269,33 +285,43 @@ void PerformanceEntryReporter::reportResourceTiming(
269285
observerRegistry_->queuePerformanceEntry(entry);
270286
}
271287

272-
void PerformanceEntryReporter::traceMark(const PerformanceMark& entry) const {
288+
void PerformanceEntryReporter::traceMark(
289+
const PerformanceMark& entry,
290+
UserTimingDetailProvider&& detailProvider) const {
273291
auto& performanceTracer =
274292
jsinspector_modern::tracing::PerformanceTracer::getInstance();
275293
if (ReactPerfettoLogger::isTracing() || performanceTracer.isTracing()) {
276-
if (performanceTracer.isTracing()) {
277-
performanceTracer.reportMark(entry.name, entry.startTime);
278-
}
279-
280294
if (ReactPerfettoLogger::isTracing()) {
281295
ReactPerfettoLogger::mark(entry.name, entry.startTime);
282296
}
297+
298+
if (performanceTracer.isTracing()) {
299+
performanceTracer.reportMark(
300+
entry.name, entry.startTime, detailProvider());
301+
}
283302
}
284303
}
285304

286305
void PerformanceEntryReporter::traceMeasure(
287-
const PerformanceMeasure& entry) const {
306+
const PerformanceMeasure& entry,
307+
UserTimingDetailProvider&& detailProvider) const {
288308
auto& performanceTracer =
289309
jsinspector_modern::tracing::PerformanceTracer::getInstance();
290310
if (performanceTracer.isTracing() || ReactPerfettoLogger::isTracing()) {
291-
if (performanceTracer.isTracing()) {
292-
performanceTracer.reportMeasure(
293-
entry.name, entry.startTime, entry.duration);
294-
}
311+
auto detail = detailProvider();
295312

296313
if (ReactPerfettoLogger::isTracing()) {
297314
ReactPerfettoLogger::measure(
298-
entry.name, entry.startTime, entry.startTime + entry.duration);
315+
entry.name,
316+
entry.startTime,
317+
entry.startTime + entry.duration,
318+
getTrackFromDetail(detail),
319+
getTrackGroupFromDetail(detail));
320+
}
321+
322+
if (performanceTracer.isTracing()) {
323+
performanceTracer.reportMeasure(
324+
entry.name, entry.startTime, entry.duration, std::move(detail));
299325
}
300326
}
301327
}

packages/react-native/ReactCommon/react/performance/timeline/PerformanceEntryReporter.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include "PerformanceEntryKeyedBuffer.h"
1212
#include "PerformanceObserverRegistry.h"
1313

14-
#include <jsinspector-modern/tracing/CdpTracing.h>
14+
#include <folly/json.h>
1515
#include <react/timing/primitives.h>
1616

1717
#include <memory>
@@ -86,14 +86,18 @@ class PerformanceEntryReporter {
8686
std::optional<HighResTimeStamp> getMarkTime(
8787
const std::string& markName) const;
8888

89-
void reportMark(const std::string& name, HighResTimeStamp startTime);
89+
using UserTimingDetailProvider = std::function<folly::dynamic()>;
90+
91+
void reportMark(
92+
const std::string& name,
93+
HighResTimeStamp startTime,
94+
UserTimingDetailProvider&& detailProvider);
9095

9196
void reportMeasure(
9297
const std::string& name,
9398
HighResTimeStamp startTime,
9499
HighResDuration duration,
95-
const std::optional<jsinspector_modern::DevToolsTrackEntryPayload>&
96-
trackMetadata = std::nullopt);
100+
UserTimingDetailProvider&& detailProvider);
97101

98102
void reportEvent(
99103
std::string name,
@@ -167,8 +171,12 @@ class PerformanceEntryReporter {
167171
throw std::logic_error("Unhandled PerformanceEntryType");
168172
}
169173

170-
void traceMark(const PerformanceMark& entry) const;
171-
void traceMeasure(const PerformanceMeasure& entry) const;
174+
void traceMark(
175+
const PerformanceMark& entry,
176+
UserTimingDetailProvider&& detailProvider) const;
177+
void traceMeasure(
178+
const PerformanceMeasure& entry,
179+
UserTimingDetailProvider&& detailProvider) const;
172180
};
173181

174182
} // namespace facebook::react

0 commit comments

Comments
 (0)