Skip to content

Commit 28bf14c

Browse files
hoxyqfacebook-github-bot
authored andcommitted
Expose API for registering profiles and profile chunks (#49084)
Summary: Pull Request resolved: #49084 # Changelog: [Internal] > NOTE: Some CI jobs are expected to fail, because changes in Hermes D67353585 should be landed first, and then grafted to Static Hermes. Added public methods to `PerformanceTracer` instance for registering `Profile` and `ProfileChunk` Trace Events. Also created data structs in `TraceEvent.h` to simplify serialization process for objects like call frames / samples / etc. Differential Revision: D68558805 Reviewed By: huntie
1 parent 018d943 commit 28bf14c

File tree

3 files changed

+225
-0
lines changed

3 files changed

+225
-0
lines changed

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ bool PerformanceTracer::stopTracing() {
6868
}
6969

7070
performanceMeasureCount_ = 0;
71+
profileCount_ = 0;
7172
tracing_ = false;
7273
return true;
7374
}
@@ -197,6 +198,56 @@ void PerformanceTracer::reportThread(uint64_t id, const std::string& name) {
197198
});
198199
}
199200

201+
uint16_t PerformanceTracer::reportRuntimeProfile(
202+
uint64_t threadId,
203+
uint64_t eventUnixTimestamp) {
204+
std::lock_guard lock(mutex_);
205+
if (!tracing_) {
206+
throw std::runtime_error(
207+
"Runtime Profile should only be reported when Tracing is enabled");
208+
}
209+
210+
++profileCount_;
211+
// CDT prioritizes event timestamp over startTime metadata field.
212+
// https://fburl.com/lo764pf4
213+
buffer_.push_back(TraceEvent{
214+
.id = profileCount_,
215+
.name = "Profile",
216+
.cat = "disabled-by-default-v8.cpu_profiler",
217+
.ph = 'P',
218+
.ts = eventUnixTimestamp,
219+
.pid = processId_,
220+
.tid = threadId,
221+
.args = folly::dynamic::object(
222+
"data", folly ::dynamic::object("startTime", eventUnixTimestamp)),
223+
});
224+
225+
return profileCount_;
226+
}
227+
228+
void PerformanceTracer::reportRuntimeProfileChunk(
229+
uint16_t profileId,
230+
uint64_t threadId,
231+
uint64_t eventUnixTimestamp,
232+
const tracing::TraceEventProfileChunk& traceEventProfileChunk) {
233+
std::lock_guard lock(mutex_);
234+
if (!tracing_) {
235+
return;
236+
}
237+
238+
buffer_.push_back(TraceEvent{
239+
.id = profileId,
240+
.name = "ProfileChunk",
241+
.cat = "disabled-by-default-v8.cpu_profiler",
242+
.ph = 'P',
243+
.ts = eventUnixTimestamp,
244+
.pid = processId_,
245+
.tid = threadId,
246+
.args =
247+
folly::dynamic::object("data", traceEventProfileChunk.asDynamic()),
248+
});
249+
}
250+
200251
void PerformanceTracer::reportEventLoopTask(uint64_t start, uint64_t end) {
201252
std::lock_guard lock(mutex_);
202253
if (!tracing_) {

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "CdpTracing.h"
1111
#include "TraceEvent.h"
12+
#include "TraceEventProfile.h"
1213

1314
#include <folly/dynamic.h>
1415

@@ -83,6 +84,21 @@ class PerformanceTracer {
8384
*/
8485
void reportJavaScriptThread();
8586

87+
/**
88+
* Record a corresponding Profile Trace Event.
89+
* \return the id of the profile, should be used to linking profile chunks.
90+
*/
91+
uint16_t reportRuntimeProfile(uint64_t threadId, uint64_t eventUnixTimestamp);
92+
93+
/**
94+
* Record a corresponding ProfileChunk Trace Event.
95+
*/
96+
void reportRuntimeProfileChunk(
97+
uint16_t profileId,
98+
uint64_t threadId,
99+
uint64_t eventUnixTimestamp,
100+
const tracing::TraceEventProfileChunk& traceEventProfileChunk);
101+
86102
void reportEventLoopTask(uint64_t start, uint64_t end);
87103

88104
private:
@@ -96,6 +112,7 @@ class PerformanceTracer {
96112
bool tracing_{false};
97113
uint64_t processId_;
98114
uint32_t performanceMeasureCount_{0};
115+
uint16_t profileCount_{0};
99116
std::vector<TraceEvent> buffer_;
100117
std::mutex mutex_;
101118
};
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#include <folly/dynamic.h>
11+
12+
#include <utility>
13+
14+
namespace facebook::react::jsinspector_modern::tracing {
15+
16+
/// Arbitrary data structure, which represents payload of the "ProfileChunk"
17+
/// Trace Event.
18+
struct TraceEventProfileChunk {
19+
/// Deltas between timestamps of chronolocigally sorted samples.
20+
/// Will be sent as part of the "ProfileChunk" trace event.
21+
struct TimeDeltas {
22+
public:
23+
explicit TimeDeltas(std::vector<long long> deltas)
24+
: deltas_(std::move(deltas)) {}
25+
26+
folly::dynamic asDynamic() const {
27+
folly::dynamic value = folly::dynamic::array();
28+
for (auto delta : deltas_) {
29+
value.push_back(delta);
30+
}
31+
32+
return value;
33+
}
34+
35+
private:
36+
std::vector<long long> deltas_;
37+
};
38+
39+
/// Contains Profile information that will be emitted in this chunk: nodes and
40+
/// sample root node ids.
41+
struct CPUProfile {
42+
/// Unique node in the profile tree, has unique id, call frame and
43+
/// optionally
44+
/// id of its parent node. Only root node has no parent.
45+
struct Node {
46+
/// Unique call frame in the call stack.
47+
struct CallFrame {
48+
public:
49+
CallFrame(
50+
std::string codeType,
51+
uint32_t scriptId,
52+
std::string functionName,
53+
std::optional<std::string> url = std::nullopt,
54+
std::optional<uint32_t> lineNumber = std::nullopt,
55+
std::optional<uint32_t> columnNumber = std::nullopt)
56+
: codeType_(std::move(codeType)),
57+
scriptId_(scriptId),
58+
functionName_(std::move(functionName)),
59+
url_(std::move(url)),
60+
lineNumber_(lineNumber),
61+
columnNumber_(columnNumber) {}
62+
63+
folly::dynamic asDynamic() const {
64+
folly::dynamic dynamicCallFrame = folly::dynamic::object();
65+
dynamicCallFrame["codeType"] = codeType_;
66+
dynamicCallFrame["scriptId"] = scriptId_;
67+
dynamicCallFrame["functionName"] = functionName_;
68+
if (url_.has_value()) {
69+
dynamicCallFrame["url"] = url_.value();
70+
}
71+
if (lineNumber_.has_value()) {
72+
dynamicCallFrame["lineNumber"] = lineNumber_.value();
73+
}
74+
if (columnNumber_.has_value()) {
75+
dynamicCallFrame["columnNumber"] = columnNumber_.value();
76+
}
77+
78+
return dynamicCallFrame;
79+
}
80+
81+
private:
82+
std::string codeType_;
83+
uint32_t scriptId_;
84+
std::string functionName_;
85+
std::optional<std::string> url_;
86+
std::optional<uint32_t> lineNumber_;
87+
std::optional<uint32_t> columnNumber_;
88+
};
89+
90+
public:
91+
Node(
92+
uint32_t id,
93+
CallFrame callFrame,
94+
std::optional<uint32_t> parentId = std::nullopt)
95+
: id_(id), callFrame_(std::move(callFrame)), parentId_(parentId) {}
96+
97+
folly::dynamic asDynamic() const {
98+
folly::dynamic dynamicNode = folly::dynamic::object();
99+
100+
dynamicNode["callFrame"] = callFrame_.asDynamic();
101+
dynamicNode["id"] = id_;
102+
if (parentId_.has_value()) {
103+
dynamicNode["parent"] = parentId_.value();
104+
}
105+
106+
return dynamicNode;
107+
}
108+
109+
private:
110+
uint32_t id_;
111+
CallFrame callFrame_;
112+
std::optional<uint32_t> parentId_;
113+
};
114+
115+
public:
116+
CPUProfile(std::vector<Node> nodes, std::vector<uint32_t> samples)
117+
: nodes_(std::move(nodes)), samples_(std::move(samples)) {}
118+
119+
folly::dynamic asDynamic() const {
120+
folly::dynamic dynamicNodes = folly::dynamic::array();
121+
for (const auto& node : nodes_) {
122+
dynamicNodes.push_back(node.asDynamic());
123+
}
124+
125+
folly::dynamic dynamicSamples = folly::dynamic::array();
126+
for (auto sample : samples_) {
127+
dynamicSamples.push_back(sample);
128+
}
129+
130+
return folly::dynamic::object("nodes", dynamicNodes)(
131+
"samples", dynamicSamples);
132+
}
133+
134+
private:
135+
std::vector<Node> nodes_;
136+
std::vector<uint32_t> samples_;
137+
};
138+
139+
public:
140+
TraceEventProfileChunk(CPUProfile cpuProfile, TimeDeltas timeDeltas)
141+
: cpuProfile_(std::move(cpuProfile)),
142+
timeDeltas_(std::move(timeDeltas)) {}
143+
144+
folly::dynamic asDynamic() const {
145+
folly::dynamic value = folly::dynamic::object;
146+
value["cpuProfile"] = cpuProfile_.asDynamic();
147+
value["timeDeltas"] = timeDeltas_.asDynamic();
148+
149+
return value;
150+
}
151+
152+
private:
153+
CPUProfile cpuProfile_;
154+
TimeDeltas timeDeltas_;
155+
};
156+
157+
} // namespace facebook::react::jsinspector_modern::tracing

0 commit comments

Comments
 (0)