Skip to content

Commit 3572790

Browse files
hoxyqfacebook-github-bot
authored andcommitted
refactor: well-defined behaviour
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 f214a52 commit 3572790

File tree

2 files changed

+53
-76
lines changed

2 files changed

+53
-76
lines changed

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

Lines changed: 45 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,15 @@ 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_.load(std::memory_order_acquire)) {
31+
return false;
3732
}
33+
tracing_.store(true, std::memory_order_release);
3834

3935
reportProcess(processId_, "React Native");
4036

4137
{
42-
std::lock_guard lock(mutex_);
38+
std::lock_guard lock(bufferMutex_);
4339
buffer_.push_back(TraceEvent{
4440
.name = "TracingStartedInPage",
4541
.cat = "disabled-by-default-devtools.timeline",
@@ -49,42 +45,45 @@ bool PerformanceTracer::startTracing() {
4945
.tid = oscompat::getCurrentThreadId(),
5046
.args = folly::dynamic::object("data", folly::dynamic::object()),
5147
});
52-
53-
return true;
5448
}
49+
50+
return true;
5551
}
5652

5753
bool PerformanceTracer::stopTracing() {
58-
std::lock_guard lock(mutex_);
59-
if (!tracing_) {
54+
if (!tracing_.load(std::memory_order_acquire)) {
6055
return false;
6156
}
57+
tracing_.store(false, std::memory_order_release);
6258

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

78-
performanceMeasureCount_ = 0;
79-
tracing_ = false;
77+
// Potential increments of this counter are covered by tracing_ atomic flag.
78+
performanceMeasureCount_.store(0, std::memory_order_relaxed);
8079
return true;
8180
}
8281

8382
void PerformanceTracer::collectEvents(
8483
const std::function<void(const folly::dynamic& eventsChunk)>&
8584
resultCallback,
8685
uint16_t chunkSize) {
87-
std::lock_guard lock(mutex_);
86+
std::lock_guard lock(bufferMutex_);
8887

8988
if (buffer_.empty()) {
9089
return;
@@ -110,15 +109,11 @@ void PerformanceTracer::collectEvents(
110109
void PerformanceTracer::reportMark(
111110
const std::string_view& name,
112111
HighResTimeStamp start) {
113-
if (!tracing_) {
114-
return;
115-
}
116-
117-
std::lock_guard<std::mutex> lock(mutex_);
118-
if (!tracing_) {
112+
if (!isTracing()) {
119113
return;
120114
}
121115

116+
std::lock_guard<std::mutex> lock(bufferMutex_);
122117
buffer_.push_back(TraceEvent{
123118
.name = std::string(name),
124119
.cat = "blink.user_timing",
@@ -134,12 +129,7 @@ void PerformanceTracer::reportMeasure(
134129
HighResTimeStamp start,
135130
HighResDuration duration,
136131
const std::optional<DevToolsTrackEntryPayload>& trackMetadata) {
137-
if (!tracing_) {
138-
return;
139-
}
140-
141-
std::lock_guard<std::mutex> lock(mutex_);
142-
if (!tracing_) {
132+
if (!isTracing()) {
143133
return;
144134
}
145135

@@ -152,10 +142,13 @@ void PerformanceTracer::reportMeasure(
152142
folly::dynamic::object("detail", folly::toJson(devtoolsObject));
153143
}
154144

155-
++performanceMeasureCount_;
145+
auto eventId =
146+
performanceMeasureCount_.fetch_add(1, std::memory_order_relaxed);
156147
auto currentThreadId = oscompat::getCurrentThreadId();
148+
149+
std::lock_guard<std::mutex> lock(bufferMutex_);
157150
buffer_.push_back(TraceEvent{
158-
.id = performanceMeasureCount_,
151+
.id = eventId,
159152
.name = std::string(name),
160153
.cat = "blink.user_timing",
161154
.ph = 'b',
@@ -165,7 +158,7 @@ void PerformanceTracer::reportMeasure(
165158
.args = beginEventArgs,
166159
});
167160
buffer_.push_back(TraceEvent{
168-
.id = performanceMeasureCount_,
161+
.id = eventId,
169162
.name = std::string(name),
170163
.cat = "blink.user_timing",
171164
.ph = 'e',
@@ -176,15 +169,11 @@ void PerformanceTracer::reportMeasure(
176169
}
177170

178171
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_) {
172+
if (!isTracing()) {
185173
return;
186174
}
187175

176+
std::lock_guard<std::mutex> lock(bufferMutex_);
188177
buffer_.push_back(TraceEvent{
189178
.name = "process_name",
190179
.cat = "__metadata",
@@ -201,15 +190,11 @@ void PerformanceTracer::reportJavaScriptThread() {
201190
}
202191

203192
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_) {
193+
if (!isTracing()) {
210194
return;
211195
}
212196

197+
std::lock_guard<std::mutex> lock(bufferMutex_);
213198
buffer_.push_back(TraceEvent{
214199
.name = "thread_name",
215200
.cat = "__metadata",
@@ -238,15 +223,11 @@ void PerformanceTracer::reportThread(uint64_t id, const std::string& name) {
238223
void PerformanceTracer::reportEventLoopTask(
239224
HighResTimeStamp start,
240225
HighResTimeStamp end) {
241-
if (!tracing_) {
242-
return;
243-
}
244-
245-
std::lock_guard lock(mutex_);
246-
if (!tracing_) {
226+
if (!isTracing()) {
247227
return;
248228
}
249229

230+
std::lock_guard lock(bufferMutex_);
250231
buffer_.push_back(TraceEvent{
251232
.name = "RunTask",
252233
.cat = "disabled-by-default-devtools.timeline",
@@ -261,15 +242,11 @@ void PerformanceTracer::reportEventLoopTask(
261242
void PerformanceTracer::reportEventLoopMicrotasks(
262243
HighResTimeStamp start,
263244
HighResTimeStamp end) {
264-
if (!tracing_) {
265-
return;
266-
}
267-
268-
std::lock_guard lock(mutex_);
269-
if (!tracing_) {
245+
if (!isTracing()) {
270246
return;
271247
}
272248

249+
std::lock_guard lock(bufferMutex_);
273250
buffer_.push_back(TraceEvent{
274251
.name = "RunMicrotasks",
275252
.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)