Skip to content

Commit ee72e11

Browse files
rubennortefacebook-github-bot
authored andcommitted
Refactor tracing in performance.mark and performance.measure
Summary: Changelog: [internal] This refactors some code in the performance API and Perfetto to avoid doing unnecessary work when not tracing (e.g.: string manipulation for tracks). It also reduces the cost of logging marks/measures to tracing backends if not actively tracing (e.g.: moving the check to outside the lock). Differential Revision: D69246772
1 parent ab0fc8e commit ee72e11

File tree

7 files changed

+132
-73
lines changed

7 files changed

+132
-73
lines changed

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ bool PerformanceTracer::stopTracing() {
7272
return true;
7373
}
7474

75+
bool PerformanceTracer::isTracing() const {
76+
// This is not thread safe but it's only a performance optimization. The call
77+
// to report marks and measures is already thread safe.
78+
return tracing_;
79+
}
80+
7581
void PerformanceTracer::collectEvents(
7682
const std::function<void(const folly::dynamic& eventsChunk)>&
7783
resultCallback,
@@ -102,6 +108,10 @@ void PerformanceTracer::collectEvents(
102108
void PerformanceTracer::reportMark(
103109
const std::string_view& name,
104110
uint64_t start) {
111+
if (!tracing_) {
112+
return;
113+
}
114+
105115
std::lock_guard<std::mutex> lock(mutex_);
106116
if (!tracing_) {
107117
return;
@@ -122,6 +132,10 @@ void PerformanceTracer::reportMeasure(
122132
uint64_t start,
123133
uint64_t duration,
124134
const std::optional<DevToolsTrackEntryPayload>& trackMetadata) {
135+
if (!tracing_) {
136+
return;
137+
}
138+
125139
std::lock_guard<std::mutex> lock(mutex_);
126140
if (!tracing_) {
127141
return;

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ class PerformanceTracer {
4040
*/
4141
bool stopTracing();
4242

43+
/**
44+
* Returns whether the tracer is currently tracing. This can be useful to
45+
* avoid doing expensive work (like formatting strings) if tracing is not
46+
* enabled.
47+
*/
48+
bool isTracing() const;
49+
4350
/**
4451
* Flush out buffered CDP Trace Events using the given callback.
4552
*/

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

Lines changed: 2 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,15 @@
1414
#include <cxxreact/JSExecutor.h>
1515
#include <cxxreact/ReactMarker.h>
1616
#include <jsi/instrumentation.h>
17-
#include <jsinspector-modern/tracing/CdpTracing.h>
1817
#include <react/performance/timeline/PerformanceEntryReporter.h>
1918
#include <react/performance/timeline/PerformanceObserver.h>
20-
#include <reactperflogger/ReactPerfettoLogger.h>
2119

2220
#include "NativePerformance.h"
2321

2422
#ifdef RN_DISABLE_OSS_PLUGIN_HEADER
2523
#include "Plugins.h"
2624
#endif
2725

28-
#ifdef WITH_PERFETTO
29-
#include <reactperflogger/ReactPerfetto.h>
30-
#endif
31-
3226
std::shared_ptr<facebook::react::TurboModule> NativePerformanceModuleProvider(
3327
std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
3428
return std::make_shared<facebook::react::NativePerformance>(
@@ -39,33 +33,6 @@ namespace facebook::react {
3933

4034
namespace {
4135

42-
#if defined(__clang__)
43-
#define NO_DESTROY [[clang::no_destroy]]
44-
#else
45-
#define NO_DESTROY
46-
#endif
47-
48-
NO_DESTROY const std::string TRACK_PREFIX = "Track:";
49-
50-
std::tuple<std::optional<std::string>, std::string_view> parseTrackName(
51-
const std::string& name) {
52-
// Until there's a standard way to pass through track information, parse it
53-
// manually, e.g., "Track:Foo:Event name"
54-
// https://github.com/w3c/user-timing/issues/109
55-
std::optional<std::string> trackName;
56-
std::string_view eventName(name);
57-
if (name.starts_with(TRACK_PREFIX)) {
58-
const auto trackNameDelimiter = name.find(':', TRACK_PREFIX.length());
59-
if (trackNameDelimiter != std::string::npos) {
60-
trackName = name.substr(
61-
TRACK_PREFIX.length(), trackNameDelimiter - TRACK_PREFIX.length());
62-
eventName = std::string_view(name).substr(trackNameDelimiter + 1);
63-
}
64-
}
65-
66-
return std::make_tuple(trackName, eventName);
67-
}
68-
6936
class PerformanceObserverWrapper : public jsi::NativeState {
7037
public:
7138
explicit PerformanceObserverWrapper(
@@ -103,11 +70,7 @@ std::shared_ptr<PerformanceObserver> tryGetObserver(
10370
} // namespace
10471

10572
NativePerformance::NativePerformance(std::shared_ptr<CallInvoker> jsInvoker)
106-
: NativePerformanceCxxSpec(std::move(jsInvoker)) {
107-
#ifdef WITH_PERFETTO
108-
initializePerfetto();
109-
#endif
110-
}
73+
: NativePerformanceCxxSpec(std::move(jsInvoker)) {}
11174

11275
double NativePerformance::now(jsi::Runtime& /*rt*/) {
11376
return JSExecutor::performanceNow();
@@ -117,12 +80,8 @@ double NativePerformance::markWithResult(
11780
jsi::Runtime& rt,
11881
std::string name,
11982
std::optional<double> startTime) {
120-
auto [trackName, eventName] = parseTrackName(name);
12183
auto entry =
12284
PerformanceEntryReporter::getInstance()->reportMark(name, startTime);
123-
124-
ReactPerfettoLogger::mark(eventName, entry.startTime, trackName);
125-
12685
return entry.startTime;
12786
}
12887

@@ -134,26 +93,8 @@ std::tuple<double, double> NativePerformance::measureWithResult(
13493
std::optional<double> duration,
13594
std::optional<std::string> startMark,
13695
std::optional<std::string> endMark) {
137-
auto [trackName, eventName] = parseTrackName(name);
138-
139-
std::optional<jsinspector_modern::DevToolsTrackEntryPayload> trackMetadata;
140-
141-
if (trackName.has_value()) {
142-
trackMetadata = {.track = trackName.value()};
143-
}
144-
14596
auto entry = PerformanceEntryReporter::getInstance()->reportMeasure(
146-
eventName,
147-
startTime,
148-
endTime,
149-
duration,
150-
startMark,
151-
endMark,
152-
trackMetadata);
153-
154-
ReactPerfettoLogger::measure(
155-
eventName, entry.startTime, entry.startTime + entry.duration, trackName);
156-
97+
name, startTime, endTime, duration, startMark, endMark);
15798
return std::tuple{entry.startTime, entry.duration};
15899
}
159100

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

Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
#include <cxxreact/JSExecutor.h>
1111
#include <jsinspector-modern/tracing/PerformanceTracer.h>
1212
#include <react/featureflags/ReactNativeFeatureFlags.h>
13+
#include <reactperflogger/ReactPerfettoLogger.h>
14+
15+
#ifdef WITH_PERFETTO
16+
#include <reactperflogger/ReactPerfetto.h>
17+
#endif
1318

1419
namespace facebook::react {
1520

@@ -33,6 +38,33 @@ uint64_t timestampToMicroseconds(DOMHighResTimeStamp timestamp) {
3338
return static_cast<uint64_t>(timestamp * 1000);
3439
}
3540

41+
#if defined(__clang__)
42+
#define NO_DESTROY [[clang::no_destroy]]
43+
#else
44+
#define NO_DESTROY
45+
#endif
46+
47+
NO_DESTROY const std::string TRACK_PREFIX = "Track:";
48+
49+
std::tuple<std::optional<std::string>, std::string_view> parseTrackName(
50+
const std::string& name) {
51+
// Until there's a standard way to pass through track information, parse it
52+
// manually, e.g., "Track:Foo:Event name"
53+
// https://github.com/w3c/user-timing/issues/109
54+
std::optional<std::string> trackName;
55+
std::string_view eventName(name);
56+
if (name.starts_with(TRACK_PREFIX)) {
57+
const auto trackNameDelimiter = name.find(':', TRACK_PREFIX.length());
58+
if (trackNameDelimiter != std::string::npos) {
59+
trackName = name.substr(
60+
TRACK_PREFIX.length(), trackNameDelimiter - TRACK_PREFIX.length());
61+
eventName = std::string_view(name).substr(trackNameDelimiter + 1);
62+
}
63+
}
64+
65+
return std::make_tuple(trackName, eventName);
66+
}
67+
3668
} // namespace
3769

3870
std::shared_ptr<PerformanceEntryReporter>&
@@ -42,7 +74,11 @@ PerformanceEntryReporter::getInstance() {
4274
}
4375

4476
PerformanceEntryReporter::PerformanceEntryReporter()
45-
: observerRegistry_(std::make_unique<PerformanceObserverRegistry>()) {}
77+
: observerRegistry_(std::make_unique<PerformanceObserverRegistry>()) {
78+
#ifdef WITH_PERFETTO
79+
initializePerfetto();
80+
#endif
81+
}
4682

4783
DOMHighResTimeStamp PerformanceEntryReporter::getCurrentTimeStamp() const {
4884
return timeStampProvider_ != nullptr ? timeStampProvider_()
@@ -135,26 +171,28 @@ void PerformanceEntryReporter::clearEntries(
135171
PerformanceEntry PerformanceEntryReporter::reportMark(
136172
const std::string& name,
137173
const std::optional<DOMHighResTimeStamp>& startTime) {
174+
// Resolve timings
138175
auto startTimeVal = startTime ? *startTime : getCurrentTimeStamp();
139176
const auto entry = PerformanceEntry{
140177
.name = name,
141178
.entryType = PerformanceEntryType::MARK,
142179
.startTime = startTimeVal};
143180

181+
traceMark(entry);
182+
183+
// Add to buffers & notify observers
144184
{
145185
std::unique_lock lock(buffersMutex_);
146186
markBuffer_.add(entry);
147187
}
148188

149-
jsinspector_modern::PerformanceTracer::getInstance().reportMark(
150-
name, timestampToMicroseconds(startTimeVal));
151-
152189
observerRegistry_->queuePerformanceEntry(entry);
190+
153191
return entry;
154192
}
155193

156194
PerformanceEntry PerformanceEntryReporter::reportMeasure(
157-
const std::string_view& name,
195+
const std::string& name,
158196
DOMHighResTimeStamp startTime,
159197
DOMHighResTimeStamp endTime,
160198
const std::optional<DOMHighResTimeStamp>& duration,
@@ -181,18 +219,16 @@ PerformanceEntry PerformanceEntryReporter::reportMeasure(
181219
.startTime = startTimeVal,
182220
.duration = durationVal};
183221

222+
traceMeasure(entry);
223+
224+
// Add to buffers & notify observers
184225
{
185226
std::unique_lock lock(buffersMutex_);
186227
measureBuffer_.add(entry);
187228
}
188229

189-
jsinspector_modern::PerformanceTracer::getInstance().reportMeasure(
190-
name,
191-
timestampToMicroseconds(startTimeVal),
192-
timestampToMicroseconds(durationVal),
193-
trackMetadata);
194-
195230
observerRegistry_->queuePerformanceEntry(entry);
231+
196232
return entry;
197233
}
198234

@@ -257,4 +293,52 @@ void PerformanceEntryReporter::reportLongTask(
257293
observerRegistry_->queuePerformanceEntry(entry);
258294
}
259295

296+
void PerformanceEntryReporter::traceMark(const PerformanceEntry& entry) const {
297+
auto& performanceTracer =
298+
jsinspector_modern::PerformanceTracer::getInstance();
299+
if (ReactPerfettoLogger::isTracing() || performanceTracer.isTracing()) {
300+
auto [trackName, eventName] = parseTrackName(entry.name);
301+
302+
if (performanceTracer.isTracing()) {
303+
performanceTracer.reportMark(
304+
entry.name, timestampToMicroseconds(entry.startTime));
305+
}
306+
307+
if (ReactPerfettoLogger::isTracing()) {
308+
ReactPerfettoLogger::mark(eventName, entry.startTime, trackName);
309+
}
310+
}
311+
}
312+
313+
void PerformanceEntryReporter::traceMeasure(
314+
const PerformanceEntry& entry) const {
315+
auto& performanceTracer =
316+
jsinspector_modern::PerformanceTracer::getInstance();
317+
if (performanceTracer.isTracing() || ReactPerfettoLogger::isTracing()) {
318+
auto [trackName, eventName] = parseTrackName(entry.name);
319+
320+
if (performanceTracer.isTracing()) {
321+
std::optional<jsinspector_modern::DevToolsTrackEntryPayload>
322+
trackMetadata;
323+
324+
if (trackName.has_value()) {
325+
trackMetadata = {.track = trackName.value()};
326+
}
327+
performanceTracer.reportMeasure(
328+
eventName,
329+
timestampToMicroseconds(entry.startTime),
330+
timestampToMicroseconds(entry.duration),
331+
trackMetadata);
332+
}
333+
334+
if (ReactPerfettoLogger::isTracing()) {
335+
ReactPerfettoLogger::measure(
336+
eventName,
337+
entry.startTime,
338+
entry.startTime + entry.duration,
339+
trackName);
340+
}
341+
}
342+
}
343+
260344
} // namespace facebook::react

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class PerformanceEntryReporter {
8282
const std::optional<DOMHighResTimeStamp>& startTime = std::nullopt);
8383

8484
PerformanceEntry reportMeasure(
85-
const std::string_view& name,
85+
const std::string& name,
8686
double startTime,
8787
double endTime,
8888
const std::optional<double>& duration = std::nullopt,
@@ -148,6 +148,9 @@ class PerformanceEntryReporter {
148148
}
149149
throw std::logic_error("Unhandled PerformanceEntryType");
150150
}
151+
152+
void traceMark(const PerformanceEntry& entry) const;
153+
void traceMeasure(const PerformanceEntry& entry) const;
151154
};
152155

153156
} // namespace facebook::react

packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfettoLogger.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ std::string toPerfettoTrackName(
2929
} // namespace
3030
#endif
3131

32+
/* static */ bool ReactPerfettoLogger::isTracing() {
33+
#ifdef WITH_PERFETTO
34+
return TRACE_EVENT_CATEGORY_ENABLED("react-native");
35+
#else
36+
return false;
37+
#endif
38+
}
39+
3240
/* static */ void ReactPerfettoLogger::measure(
3341
const std::string_view& eventName,
3442
double startTime,

packages/react-native/ReactCommon/reactperflogger/reactperflogger/ReactPerfettoLogger.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ namespace facebook::react {
2020
*/
2121
class ReactPerfettoLogger {
2222
public:
23+
static bool isTracing();
24+
2325
static void mark(
2426
const std::string_view& eventName,
2527
double startTime,

0 commit comments

Comments
 (0)