Skip to content

Commit 7399b64

Browse files
hoxyqfacebook-github-bot
authored andcommitted
refactor: well-defined behaviour (facebook#52187)
Summary: # Changelog: [Internal] - `tracing_` is now `std::atomic<bool>`. - `performanceMeasureCount_` is now`std::atomic<uint32_t>`. - `mutex_` -> `bufferMutex_`. The biggest change is that we no longer read from `tracing_` directly for an early-return when not tracing. This should not significantly regress performance of the subsystem, see the test plan for numbers. Differential Revision: D77053030
1 parent 7b7b538 commit 7399b64

File tree

2 files changed

+50
-76
lines changed

2 files changed

+50
-76
lines changed

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

Lines changed: 42 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,14 @@ PerformanceTracer::PerformanceTracer()
2727
: processId_(oscompat::getCurrentProcessId()) {}
2828

2929
bool PerformanceTracer::startTracing() {
30-
{
31-
std::lock_guard lock(mutex_);
32-
if (tracing_) {
33-
return false;
34-
}
35-
36-
tracing_ = true;
30+
if (tracing_.exchange(true, std::memory_order_acq_rel)) {
31+
return false;
3732
}
3833

3934
reportProcess(processId_, "React Native");
4035

4136
{
42-
std::lock_guard lock(mutex_);
37+
std::lock_guard lock(bufferMutex_);
4338
buffer_.push_back(TraceEvent{
4439
.name = "TracingStartedInPage",
4540
.cat = "disabled-by-default-devtools.timeline",
@@ -49,42 +44,44 @@ bool PerformanceTracer::startTracing() {
4944
.tid = oscompat::getCurrentThreadId(),
5045
.args = folly::dynamic::object("data", folly::dynamic::object()),
5146
});
52-
53-
return true;
5447
}
48+
49+
return true;
5550
}
5651

5752
bool PerformanceTracer::stopTracing() {
58-
std::lock_guard lock(mutex_);
59-
if (!tracing_) {
53+
if (!tracing_.exchange(false, std::memory_order_acq_rel)) {
6054
return false;
6155
}
6256

63-
// This is synthetic Trace Event, which should not be represented on a
64-
// timeline. CDT is not using Profile or ProfileChunk events for determining
65-
// trace timeline window, this is why trace that only contains JavaScript
66-
// samples will be displayed as empty. We use this event to avoid that.
67-
// This could happen for non-bridgeless apps, where Performance interface is
68-
// not supported and no spec-compliant Event Loop implementation.
69-
buffer_.push_back(TraceEvent{
70-
.name = "ReactNative-TracingStopped",
71-
.cat = "disabled-by-default-devtools.timeline",
72-
.ph = 'I',
73-
.ts = HighResTimeStamp::now(),
74-
.pid = processId_,
75-
.tid = oscompat::getCurrentThreadId(),
76-
});
57+
{
58+
std::lock_guard lock(bufferMutex_);
59+
// This is synthetic Trace Event, which should not be represented on a
60+
// timeline. CDT is not using Profile or ProfileChunk events for determining
61+
// trace timeline window, this is why trace that only contains JavaScript
62+
// samples will be displayed as empty. We use this event to avoid that.
63+
// This could happen for non-bridgeless apps, where Performance interface is
64+
// not supported and no spec-compliant Event Loop implementation.
65+
buffer_.push_back(TraceEvent{
66+
.name = "ReactNative-TracingStopped",
67+
.cat = "disabled-by-default-devtools.timeline",
68+
.ph = 'I',
69+
.ts = HighResTimeStamp::now(),
70+
.pid = processId_,
71+
.tid = oscompat::getCurrentThreadId(),
72+
});
73+
}
7774

78-
performanceMeasureCount_ = 0;
79-
tracing_ = false;
75+
// Potential increments of this counter are covered by tracing_ atomic flag.
76+
performanceMeasureCount_.store(0, std::memory_order_relaxed);
8077
return true;
8178
}
8279

8380
void PerformanceTracer::collectEvents(
8481
const std::function<void(const folly::dynamic& eventsChunk)>&
8582
resultCallback,
8683
uint16_t chunkSize) {
87-
std::lock_guard lock(mutex_);
84+
std::lock_guard lock(bufferMutex_);
8885

8986
if (buffer_.empty()) {
9087
return;
@@ -110,15 +107,11 @@ void PerformanceTracer::collectEvents(
110107
void PerformanceTracer::reportMark(
111108
const std::string_view& name,
112109
HighResTimeStamp start) {
113-
if (!tracing_) {
114-
return;
115-
}
116-
117-
std::lock_guard<std::mutex> lock(mutex_);
118-
if (!tracing_) {
110+
if (!isTracing()) {
119111
return;
120112
}
121113

114+
std::lock_guard<std::mutex> lock(bufferMutex_);
122115
buffer_.push_back(TraceEvent{
123116
.name = std::string(name),
124117
.cat = "blink.user_timing",
@@ -134,12 +127,7 @@ void PerformanceTracer::reportMeasure(
134127
HighResTimeStamp start,
135128
HighResDuration duration,
136129
const std::optional<DevToolsTrackEntryPayload>& trackMetadata) {
137-
if (!tracing_) {
138-
return;
139-
}
140-
141-
std::lock_guard<std::mutex> lock(mutex_);
142-
if (!tracing_) {
130+
if (!isTracing()) {
143131
return;
144132
}
145133

@@ -152,10 +140,12 @@ void PerformanceTracer::reportMeasure(
152140
folly::dynamic::object("detail", folly::toJson(devtoolsObject));
153141
}
154142

155-
++performanceMeasureCount_;
143+
auto eventId = ++performanceMeasureCount_;
156144
auto currentThreadId = oscompat::getCurrentThreadId();
145+
146+
std::lock_guard<std::mutex> lock(bufferMutex_);
157147
buffer_.push_back(TraceEvent{
158-
.id = performanceMeasureCount_,
148+
.id = eventId,
159149
.name = std::string(name),
160150
.cat = "blink.user_timing",
161151
.ph = 'b',
@@ -165,7 +155,7 @@ void PerformanceTracer::reportMeasure(
165155
.args = beginEventArgs,
166156
});
167157
buffer_.push_back(TraceEvent{
168-
.id = performanceMeasureCount_,
158+
.id = eventId,
169159
.name = std::string(name),
170160
.cat = "blink.user_timing",
171161
.ph = 'e',
@@ -176,15 +166,11 @@ void PerformanceTracer::reportMeasure(
176166
}
177167

178168
void PerformanceTracer::reportProcess(uint64_t id, const std::string& name) {
179-
if (!tracing_) {
180-
return;
181-
}
182-
183-
std::lock_guard<std::mutex> lock(mutex_);
184-
if (!tracing_) {
169+
if (!isTracing()) {
185170
return;
186171
}
187172

173+
std::lock_guard<std::mutex> lock(bufferMutex_);
188174
buffer_.push_back(TraceEvent{
189175
.name = "process_name",
190176
.cat = "__metadata",
@@ -201,15 +187,11 @@ void PerformanceTracer::reportJavaScriptThread() {
201187
}
202188

203189
void PerformanceTracer::reportThread(uint64_t id, const std::string& name) {
204-
if (!tracing_) {
205-
return;
206-
}
207-
208-
std::lock_guard<std::mutex> lock(mutex_);
209-
if (!tracing_) {
190+
if (!isTracing()) {
210191
return;
211192
}
212193

194+
std::lock_guard<std::mutex> lock(bufferMutex_);
213195
buffer_.push_back(TraceEvent{
214196
.name = "thread_name",
215197
.cat = "__metadata",
@@ -238,15 +220,11 @@ void PerformanceTracer::reportThread(uint64_t id, const std::string& name) {
238220
void PerformanceTracer::reportEventLoopTask(
239221
HighResTimeStamp start,
240222
HighResTimeStamp end) {
241-
if (!tracing_) {
242-
return;
243-
}
244-
245-
std::lock_guard lock(mutex_);
246-
if (!tracing_) {
223+
if (!isTracing()) {
247224
return;
248225
}
249226

227+
std::lock_guard lock(bufferMutex_);
250228
buffer_.push_back(TraceEvent{
251229
.name = "RunTask",
252230
.cat = "disabled-by-default-devtools.timeline",
@@ -261,15 +239,11 @@ void PerformanceTracer::reportEventLoopTask(
261239
void PerformanceTracer::reportEventLoopMicrotasks(
262240
HighResTimeStamp start,
263241
HighResTimeStamp end) {
264-
if (!tracing_) {
265-
return;
266-
}
267-
268-
std::lock_guard lock(mutex_);
269-
if (!tracing_) {
242+
if (!isTracing()) {
270243
return;
271244
}
272245

246+
std::lock_guard lock(bufferMutex_);
273247
buffer_.push_back(TraceEvent{
274248
.name = "RunMicrotasks",
275249
.cat = "v8.execute",

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <react/timing/primitives.h>
1515

1616
#include <folly/dynamic.h>
17+
#include <atomic>
1718
#include <functional>
1819
#include <mutex>
1920
#include <optional>
@@ -47,10 +48,8 @@ class PerformanceTracer {
4748
* avoid doing expensive work (like formatting strings) if tracing is not
4849
* enabled.
4950
*/
50-
bool isTracing() const {
51-
// This is not thread safe but it's only a performance optimization. The
52-
// call to report marks and measures is already thread safe.
53-
return tracing_;
51+
inline bool isTracing() const {
52+
return tracing_.load(std::memory_order_relaxed);
5453
}
5554

5655
/**
@@ -135,12 +134,13 @@ class PerformanceTracer {
135134

136135
folly::dynamic serializeTraceEvent(const TraceEvent& event) const;
137136

138-
bool tracing_{false};
139-
140137
uint64_t processId_;
141-
uint32_t performanceMeasureCount_{0};
138+
139+
std::atomic<bool> tracing_{false};
140+
std::atomic<uint32_t> performanceMeasureCount_{0};
141+
142142
std::vector<TraceEvent> buffer_;
143-
std::mutex mutex_;
143+
std::mutex bufferMutex_;
144144
};
145145

146146
} // namespace facebook::react::jsinspector_modern::tracing

0 commit comments

Comments
 (0)