mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Refactor PerformanceTracer buffer type to use output event format (#48310)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/48310 Refactors the internal storage format of trace events buffered by `PerformanceTracer`. Aligning with the emitted [Trace Event Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview?pli=1&tab=t.0#heading=h.yr4qxyxotyw) enables us to simplify away the issue of defining and converting from any intermediate formats. This becomes desirable as we generalise to more event types and forthcoming browser-emulating `__metadata` events. Changelog: [Internal] Reviewed By: hoxyq Differential Revision: D67337442 fbshipit-source-id: 580928dfb4fcf4ac5efc82f93ab85a0d1d6dfb5c
This commit is contained in:
committed by
Facebook GitHub Bot
parent
8696b79f73
commit
dfdacb84ce
+62
-84
@@ -53,28 +53,45 @@ bool PerformanceTracer::stopTracingAndCollectEvents(
|
||||
return true;
|
||||
}
|
||||
|
||||
auto traceEvents = folly::dynamic::array();
|
||||
|
||||
// Register "Main" process
|
||||
traceEvents.push_back(folly::dynamic::object(
|
||||
"args", folly::dynamic::object("name", "Main"))("cat", "__metadata")(
|
||||
"name", "process_name")("ph", "M")("pid", PID)("tid", 0)("ts", 0));
|
||||
buffer_.push_back(TraceEvent{
|
||||
.name = "process_name",
|
||||
.cat = "__metadata",
|
||||
.ph = 'M',
|
||||
.ts = 0,
|
||||
.pid = PID,
|
||||
.tid = 0,
|
||||
.args = folly::dynamic::object("name", "Main"),
|
||||
});
|
||||
// Register "Timings" track
|
||||
// NOTE: This is a hack to make the trace viewer show a "Timings" track
|
||||
// NOTE: This is a hack to make the Trace Viewer show a "Timings" track
|
||||
// adjacent to custom tracks in our current build of Chrome DevTools.
|
||||
// In future, we should align events exactly.
|
||||
traceEvents.push_back(
|
||||
folly::dynamic::object("args", folly::dynamic::object("name", "Timings"))(
|
||||
"cat", "__metadata")("name", "thread_name")("ph", "M")("pid", PID)(
|
||||
"tid", USER_TIMINGS_DEFAULT_TRACK)("ts", 0));
|
||||
buffer_.push_back(TraceEvent{
|
||||
.name = "thread_name",
|
||||
.cat = "__metadata",
|
||||
.ph = 'M',
|
||||
.ts = 0,
|
||||
.pid = PID,
|
||||
.tid = USER_TIMINGS_DEFAULT_TRACK,
|
||||
.args = folly::dynamic::object("name", "Timings"),
|
||||
});
|
||||
|
||||
for (const auto& [trackName, trackId] : customTrackIdMap_) {
|
||||
// Register custom tracks
|
||||
traceEvents.push_back(folly::dynamic::object(
|
||||
"args", folly::dynamic::object("name", trackName))("cat", "__metadata")(
|
||||
"name", "thread_name")("ph", "M")("pid", PID)("tid", trackId)("ts", 0));
|
||||
buffer_.push_back(TraceEvent{
|
||||
.name = "thread_name",
|
||||
.cat = "__metadata",
|
||||
.ph = 'M',
|
||||
.ts = 0,
|
||||
.pid = PID,
|
||||
.tid = trackId,
|
||||
.args = folly::dynamic::object("name", trackName),
|
||||
});
|
||||
}
|
||||
|
||||
auto traceEvents = folly::dynamic::array();
|
||||
|
||||
for (auto event : buffer_) {
|
||||
// Emit trace events
|
||||
traceEvents.push_back(serializeTraceEvent(event));
|
||||
@@ -102,14 +119,15 @@ void PerformanceTracer::reportMark(
|
||||
return;
|
||||
}
|
||||
|
||||
TraceEventBase* event = new InstantTraceEvent{
|
||||
std::string(name),
|
||||
std::vector{TraceEventCategory::UserTiming},
|
||||
start,
|
||||
PID, // FIXME: This should be real process ID.
|
||||
USER_TIMINGS_DEFAULT_TRACK, // FIXME: This should be real thread ID.
|
||||
};
|
||||
buffer_.push_back(event);
|
||||
buffer_.push_back(TraceEvent{
|
||||
.name = std::string(name),
|
||||
.cat = "blink.user_timing",
|
||||
.ph = 'I',
|
||||
.ts = start,
|
||||
.pid = PID, // FIXME: This should be the real process ID.
|
||||
.tid = USER_TIMINGS_DEFAULT_TRACK, // FIXME: This should be the real
|
||||
// thread ID.
|
||||
});
|
||||
}
|
||||
|
||||
void PerformanceTracer::reportMeasure(
|
||||
@@ -122,8 +140,10 @@ void PerformanceTracer::reportMeasure(
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t threadId =
|
||||
USER_TIMINGS_DEFAULT_TRACK; // FIXME: This should be real thread ID.
|
||||
// NOTE: We synthetically create custom tracks as a hack to render them in
|
||||
// our current build of Chrome DevTools frontend.
|
||||
// TODO: Remove and align with web.
|
||||
uint64_t threadId = USER_TIMINGS_DEFAULT_TRACK;
|
||||
if (trackMetadata.has_value()) {
|
||||
std::string trackName = trackMetadata.value().track;
|
||||
|
||||
@@ -136,71 +156,29 @@ void PerformanceTracer::reportMeasure(
|
||||
}
|
||||
}
|
||||
|
||||
TraceEventBase* event = new CompleteTraceEvent{
|
||||
std::string(name),
|
||||
std::vector{TraceEventCategory::UserTiming},
|
||||
start,
|
||||
PID, // FIXME: This should be real process ID.
|
||||
threadId, // FIXME: This should be real thread ID.
|
||||
duration};
|
||||
buffer_.push_back(event);
|
||||
buffer_.push_back(TraceEvent{
|
||||
.name = std::string(name),
|
||||
.cat = "blink.user_timing",
|
||||
.ph = 'X',
|
||||
.ts = start,
|
||||
.pid = PID, // FIXME: This should be the real process ID.
|
||||
.tid = threadId, // FIXME: This should be the real thread ID.
|
||||
.dur = duration,
|
||||
});
|
||||
}
|
||||
|
||||
std::string PerformanceTracer::serializeTraceEventCategories(
|
||||
TraceEventBase* event) const {
|
||||
std::string result;
|
||||
|
||||
for (const auto& category : event->categories) {
|
||||
switch (category) {
|
||||
case TraceEventCategory::UserTiming:
|
||||
result += "blink.user_timing";
|
||||
break;
|
||||
case TraceEventCategory::TimelineEvent:
|
||||
result += "disabled-by-default-devtools.timeline";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error("Unknown trace event category");
|
||||
}
|
||||
|
||||
result += ",";
|
||||
}
|
||||
|
||||
if (result.length() > 0) {
|
||||
result.pop_back();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
folly::dynamic PerformanceTracer::serializeTraceEvent(
|
||||
TraceEventBase* event) const {
|
||||
folly::dynamic PerformanceTracer::serializeTraceEvent(TraceEvent event) const {
|
||||
folly::dynamic result = folly::dynamic::object;
|
||||
|
||||
result["name"] = event->name;
|
||||
result["cat"] = serializeTraceEventCategories(event);
|
||||
result["args"] = event->args;
|
||||
result["ts"] = event->timestamp;
|
||||
result["pid"] = event->processId;
|
||||
result["tid"] = event->threadId;
|
||||
|
||||
switch (event->type) {
|
||||
case TraceEventType::Instant:
|
||||
result["ph"] = "I";
|
||||
|
||||
break;
|
||||
|
||||
case TraceEventType::Complete: {
|
||||
result["ph"] = "X";
|
||||
|
||||
auto completeEvent = static_cast<CompleteTraceEvent*>(event);
|
||||
result["dur"] = completeEvent->duration;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw std::runtime_error("Unknown trace event type");
|
||||
result["name"] = event.name;
|
||||
result["cat"] = event.cat;
|
||||
result["ph"] = std::string(1, event.ph);
|
||||
result["ts"] = event.ts;
|
||||
result["pid"] = event.pid;
|
||||
result["tid"] = event.tid;
|
||||
result["args"] = event.args;
|
||||
if (event.dur.has_value()) {
|
||||
result["dur"] = event.dur.value();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -21,80 +21,50 @@ namespace facebook::react::jsinspector_modern {
|
||||
// TODO: Review how this API is integrated into jsinspector_modern (singleton
|
||||
// design is copied from earlier FuseboxTracer prototype).
|
||||
|
||||
enum class TraceEventType {
|
||||
Instant,
|
||||
Complete,
|
||||
};
|
||||
|
||||
enum class TraceEventCategory {
|
||||
UserTiming,
|
||||
TimelineEvent,
|
||||
};
|
||||
|
||||
/*
|
||||
* Based on the out-of-date "Trace Event Format" document from Google and our
|
||||
* findings while reverse engineering the contract between Chrome and Chrome
|
||||
* DevTools.
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* A trace event to send to the debugger frontend, as defined by the Trace Event
|
||||
* Format.
|
||||
* https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview?pli=1&tab=t.0#heading=h.yr4qxyxotyw
|
||||
*/
|
||||
struct TraceEventBase {
|
||||
*/
|
||||
struct TraceEvent {
|
||||
/** The name of the event, as displayed in the Trace Viewer. */
|
||||
std::string name;
|
||||
std::vector<TraceEventCategory> categories;
|
||||
TraceEventType type;
|
||||
uint64_t timestamp;
|
||||
uint64_t processId;
|
||||
uint64_t threadId;
|
||||
|
||||
/**
|
||||
* A comma separated list of categories for the event, configuring how
|
||||
* events are shown in the Trace Viewer UI.
|
||||
*/
|
||||
std::string cat;
|
||||
|
||||
/**
|
||||
* The event type. This is a single character which changes depending on the
|
||||
* type of event being output. See
|
||||
* https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview?pli=1&tab=t.0#heading=h.puwqg050lyuy
|
||||
*/
|
||||
char ph;
|
||||
|
||||
/** The tracing clock timestamp of the event, in microseconds (µs). */
|
||||
uint64_t ts;
|
||||
|
||||
/** The process ID for the process that output this event. */
|
||||
uint64_t pid;
|
||||
|
||||
/** The thread ID for the process that output this event. */
|
||||
uint64_t tid;
|
||||
|
||||
/** Any arguments provided for the event. */
|
||||
folly::dynamic args = folly::dynamic::object();
|
||||
|
||||
/**
|
||||
* The duration of the event, in microseconds (µs). Only applicable to
|
||||
* complete events ("ph": "X").
|
||||
*/
|
||||
std::optional<uint64_t> dur;
|
||||
};
|
||||
|
||||
template <TraceEventType T>
|
||||
struct TraceEvent : public TraceEventBase {
|
||||
TraceEvent(
|
||||
std::string name,
|
||||
std::vector<TraceEventCategory> categories,
|
||||
uint64_t timestamp,
|
||||
uint64_t processId,
|
||||
uint64_t threadId)
|
||||
: TraceEventBase{
|
||||
std::move(name),
|
||||
std::move(categories),
|
||||
T,
|
||||
timestamp,
|
||||
processId,
|
||||
threadId} {}
|
||||
};
|
||||
|
||||
struct CompleteTraceEvent : public TraceEvent<TraceEventType::Complete> {
|
||||
uint64_t duration;
|
||||
|
||||
CompleteTraceEvent(
|
||||
std::string name,
|
||||
std::vector<TraceEventCategory> categories,
|
||||
uint64_t timestamp,
|
||||
uint64_t processId,
|
||||
uint64_t threadId,
|
||||
uint64_t duration)
|
||||
: TraceEvent<
|
||||
TraceEventType::
|
||||
Complete>{std::move(name), std::move(categories), timestamp, processId, threadId},
|
||||
duration(duration) {}
|
||||
};
|
||||
|
||||
struct InstantTraceEvent : public TraceEvent<TraceEventType::Instant> {
|
||||
InstantTraceEvent(
|
||||
std::string name,
|
||||
std::vector<TraceEventCategory> categories,
|
||||
uint64_t timestamp,
|
||||
uint64_t processId,
|
||||
uint64_t threadId)
|
||||
: TraceEvent<TraceEventType::Instant>{
|
||||
std::move(name),
|
||||
std::move(categories),
|
||||
timestamp,
|
||||
processId,
|
||||
threadId} {}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* [Experimental] An interface for logging performance trace events to the
|
||||
@@ -145,12 +115,11 @@ class PerformanceTracer {
|
||||
PerformanceTracer& operator=(const PerformanceTracer&) = delete;
|
||||
~PerformanceTracer() = default;
|
||||
|
||||
std::string serializeTraceEventCategories(TraceEventBase* event) const;
|
||||
folly::dynamic serializeTraceEvent(TraceEventBase* event) const;
|
||||
folly::dynamic serializeTraceEvent(TraceEvent event) const;
|
||||
|
||||
bool tracing_{false};
|
||||
std::unordered_map<std::string, uint64_t> customTrackIdMap_;
|
||||
std::vector<TraceEventBase*> buffer_;
|
||||
std::vector<TraceEvent> buffer_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user