Skip to content

Commit 290f237

Browse files
hoxyqfacebook-github-bot
authored andcommitted
Expose API for registering profiles and profile chunks (facebook#49084)
Summary: Pull Request resolved: facebook#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. Reviewed By: huntie Differential Revision: D68558805 fbshipit-source-id: f5eca0435c56828909f99ec0b47841d24ee907b6
1 parent 1aced32 commit 290f237

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
}
@@ -213,6 +214,56 @@ void PerformanceTracer::reportThread(uint64_t id, const std::string& name) {
213214
});
214215
}
215216

217+
uint16_t PerformanceTracer::reportRuntimeProfile(
218+
uint64_t threadId,
219+
uint64_t eventUnixTimestamp) {
220+
std::lock_guard lock(mutex_);
221+
if (!tracing_) {
222+
throw std::runtime_error(
223+
"Runtime Profile should only be reported when Tracing is enabled");
224+
}
225+
226+
++profileCount_;
227+
// CDT prioritizes event timestamp over startTime metadata field.
228+
// https://fburl.com/lo764pf4
229+
buffer_.push_back(TraceEvent{
230+
.id = profileCount_,
231+
.name = "Profile",
232+
.cat = "disabled-by-default-v8.cpu_profiler",
233+
.ph = 'P',
234+
.ts = eventUnixTimestamp,
235+
.pid = processId_,
236+
.tid = threadId,
237+
.args = folly::dynamic::object(
238+
"data", folly ::dynamic::object("startTime", eventUnixTimestamp)),
239+
});
240+
241+
return profileCount_;
242+
}
243+
244+
void PerformanceTracer::reportRuntimeProfileChunk(
245+
uint16_t profileId,
246+
uint64_t threadId,
247+
uint64_t eventUnixTimestamp,
248+
const tracing::TraceEventProfileChunk& traceEventProfileChunk) {
249+
std::lock_guard lock(mutex_);
250+
if (!tracing_) {
251+
return;
252+
}
253+
254+
buffer_.push_back(TraceEvent{
255+
.id = profileId,
256+
.name = "ProfileChunk",
257+
.cat = "disabled-by-default-v8.cpu_profiler",
258+
.ph = 'P',
259+
.ts = eventUnixTimestamp,
260+
.pid = processId_,
261+
.tid = threadId,
262+
.args =
263+
folly::dynamic::object("data", traceEventProfileChunk.asDynamic()),
264+
});
265+
}
266+
216267
void PerformanceTracer::reportEventLoopTask(uint64_t start, uint64_t end) {
217268
if (!tracing_) {
218269
return;

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

@@ -94,6 +95,21 @@ class PerformanceTracer {
9495
*/
9596
void reportJavaScriptThread();
9697

98+
/**
99+
* Record a corresponding Profile Trace Event.
100+
* \return the id of the profile, should be used to linking profile chunks.
101+
*/
102+
uint16_t reportRuntimeProfile(uint64_t threadId, uint64_t eventUnixTimestamp);
103+
104+
/**
105+
* Record a corresponding ProfileChunk Trace Event.
106+
*/
107+
void reportRuntimeProfileChunk(
108+
uint16_t profileId,
109+
uint64_t threadId,
110+
uint64_t eventUnixTimestamp,
111+
const tracing::TraceEventProfileChunk& traceEventProfileChunk);
112+
97113
/**
98114
* Record an Event Loop tick, which will be represented as an Event Loop task
99115
* on a timeline view and grouped with JavaScript samples.
@@ -111,6 +127,7 @@ class PerformanceTracer {
111127
bool tracing_{false};
112128
uint64_t processId_;
113129
uint32_t performanceMeasureCount_{0};
130+
uint16_t profileCount_{0};
114131
std::vector<TraceEvent> buffer_;
115132
std::mutex mutex_;
116133
};
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)