Skip to content

Commit 7aa1d6e

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 7aa1d6e

File tree

6 files changed

+114
-58
lines changed

6 files changed

+114
-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: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,42 @@ std::vector<PerformanceEntryType> getSupportedEntryTypesInternal() {
3737
return supportedEntryTypes;
3838
}
3939

40+
std::optional<std::string> getTrackFromDetail(folly::dynamic& detail) {
41+
if (!detail.isObject()) {
42+
return std::nullopt;
43+
}
44+
45+
auto maybeDevtools = detail["devtools"];
46+
if (!maybeDevtools.isObject()) {
47+
return std::nullopt;
48+
}
49+
50+
auto maybeTrack = maybeDevtools["track"];
51+
if (!maybeTrack.isString()) {
52+
return std::nullopt;
53+
}
54+
55+
return maybeTrack.asString();
56+
}
57+
58+
std::optional<std::string> getTrackGroupFromDetail(folly::dynamic& detail) {
59+
if (!detail.isObject()) {
60+
return std::nullopt;
61+
}
62+
63+
auto maybeDevtools = detail["devtools"];
64+
if (!maybeDevtools.isObject()) {
65+
return std::nullopt;
66+
}
67+
68+
auto maybeTrackGroup = maybeDevtools["trackGroup"];
69+
if (!maybeTrackGroup.isString()) {
70+
return std::nullopt;
71+
}
72+
73+
return maybeTrackGroup.asString();
74+
}
75+
4076
} // namespace
4177

4278
std::shared_ptr<PerformanceEntryReporter>&
@@ -142,10 +178,11 @@ void PerformanceEntryReporter::clearEntries(
142178

143179
void PerformanceEntryReporter::reportMark(
144180
const std::string& name,
145-
const HighResTimeStamp startTime) {
181+
const HighResTimeStamp startTime,
182+
UserTimingDetailProvider&& detailProvider) {
146183
const auto entry = PerformanceMark{{.name = name, .startTime = startTime}};
147184

148-
traceMark(entry);
185+
traceMark(entry, std::move(detailProvider));
149186

150187
// Add to buffers & notify observers
151188
{
@@ -160,14 +197,13 @@ void PerformanceEntryReporter::reportMeasure(
160197
const std::string& name,
161198
HighResTimeStamp startTime,
162199
HighResDuration duration,
163-
const std::optional<jsinspector_modern::DevToolsTrackEntryPayload>&
164-
trackMetadata) {
200+
UserTimingDetailProvider&& detailProvider) {
165201
const auto entry = PerformanceMeasure{
166202
{.name = std::string(name),
167203
.startTime = startTime,
168204
.duration = duration}};
169205

170-
traceMeasure(entry);
206+
traceMeasure(entry, std::move(detailProvider));
171207

172208
// Add to buffers & notify observers
173209
{
@@ -269,33 +305,43 @@ void PerformanceEntryReporter::reportResourceTiming(
269305
observerRegistry_->queuePerformanceEntry(entry);
270306
}
271307

272-
void PerformanceEntryReporter::traceMark(const PerformanceMark& entry) const {
308+
void PerformanceEntryReporter::traceMark(
309+
const PerformanceMark& entry,
310+
UserTimingDetailProvider&& detailProvider) const {
273311
auto& performanceTracer =
274312
jsinspector_modern::tracing::PerformanceTracer::getInstance();
275313
if (ReactPerfettoLogger::isTracing() || performanceTracer.isTracing()) {
276-
if (performanceTracer.isTracing()) {
277-
performanceTracer.reportMark(entry.name, entry.startTime);
278-
}
279-
280314
if (ReactPerfettoLogger::isTracing()) {
281315
ReactPerfettoLogger::mark(entry.name, entry.startTime);
282316
}
317+
318+
if (performanceTracer.isTracing()) {
319+
performanceTracer.reportMark(
320+
entry.name, entry.startTime, detailProvider());
321+
}
283322
}
284323
}
285324

286325
void PerformanceEntryReporter::traceMeasure(
287-
const PerformanceMeasure& entry) const {
326+
const PerformanceMeasure& entry,
327+
UserTimingDetailProvider&& detailProvider) const {
288328
auto& performanceTracer =
289329
jsinspector_modern::tracing::PerformanceTracer::getInstance();
290330
if (performanceTracer.isTracing() || ReactPerfettoLogger::isTracing()) {
291-
if (performanceTracer.isTracing()) {
292-
performanceTracer.reportMeasure(
293-
entry.name, entry.startTime, entry.duration);
294-
}
331+
auto detail = detailProvider();
295332

296333
if (ReactPerfettoLogger::isTracing()) {
297334
ReactPerfettoLogger::measure(
298-
entry.name, entry.startTime, entry.startTime + entry.duration);
335+
entry.name,
336+
entry.startTime,
337+
entry.startTime + entry.duration,
338+
getTrackFromDetail(detail),
339+
getTrackGroupFromDetail(detail));
340+
}
341+
342+
if (performanceTracer.isTracing()) {
343+
performanceTracer.reportMeasure(
344+
entry.name, entry.startTime, entry.duration, std::move(detail));
299345
}
300346
}
301347
}

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)