mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Expose API for registering profiles and profile chunks (#49084)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/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
This commit is contained in:
committed by
Facebook GitHub Bot
parent
1aced32a1c
commit
290f237cfa
@@ -68,6 +68,7 @@ bool PerformanceTracer::stopTracing() {
|
||||
}
|
||||
|
||||
performanceMeasureCount_ = 0;
|
||||
profileCount_ = 0;
|
||||
tracing_ = false;
|
||||
return true;
|
||||
}
|
||||
@@ -213,6 +214,56 @@ void PerformanceTracer::reportThread(uint64_t id, const std::string& name) {
|
||||
});
|
||||
}
|
||||
|
||||
uint16_t PerformanceTracer::reportRuntimeProfile(
|
||||
uint64_t threadId,
|
||||
uint64_t eventUnixTimestamp) {
|
||||
std::lock_guard lock(mutex_);
|
||||
if (!tracing_) {
|
||||
throw std::runtime_error(
|
||||
"Runtime Profile should only be reported when Tracing is enabled");
|
||||
}
|
||||
|
||||
++profileCount_;
|
||||
// CDT prioritizes event timestamp over startTime metadata field.
|
||||
// https://fburl.com/lo764pf4
|
||||
buffer_.push_back(TraceEvent{
|
||||
.id = profileCount_,
|
||||
.name = "Profile",
|
||||
.cat = "disabled-by-default-v8.cpu_profiler",
|
||||
.ph = 'P',
|
||||
.ts = eventUnixTimestamp,
|
||||
.pid = processId_,
|
||||
.tid = threadId,
|
||||
.args = folly::dynamic::object(
|
||||
"data", folly ::dynamic::object("startTime", eventUnixTimestamp)),
|
||||
});
|
||||
|
||||
return profileCount_;
|
||||
}
|
||||
|
||||
void PerformanceTracer::reportRuntimeProfileChunk(
|
||||
uint16_t profileId,
|
||||
uint64_t threadId,
|
||||
uint64_t eventUnixTimestamp,
|
||||
const tracing::TraceEventProfileChunk& traceEventProfileChunk) {
|
||||
std::lock_guard lock(mutex_);
|
||||
if (!tracing_) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer_.push_back(TraceEvent{
|
||||
.id = profileId,
|
||||
.name = "ProfileChunk",
|
||||
.cat = "disabled-by-default-v8.cpu_profiler",
|
||||
.ph = 'P',
|
||||
.ts = eventUnixTimestamp,
|
||||
.pid = processId_,
|
||||
.tid = threadId,
|
||||
.args =
|
||||
folly::dynamic::object("data", traceEventProfileChunk.asDynamic()),
|
||||
});
|
||||
}
|
||||
|
||||
void PerformanceTracer::reportEventLoopTask(uint64_t start, uint64_t end) {
|
||||
if (!tracing_) {
|
||||
return;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "CdpTracing.h"
|
||||
#include "TraceEvent.h"
|
||||
#include "TraceEventProfile.h"
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
|
||||
@@ -94,6 +95,21 @@ class PerformanceTracer {
|
||||
*/
|
||||
void reportJavaScriptThread();
|
||||
|
||||
/**
|
||||
* Record a corresponding Profile Trace Event.
|
||||
* \return the id of the profile, should be used to linking profile chunks.
|
||||
*/
|
||||
uint16_t reportRuntimeProfile(uint64_t threadId, uint64_t eventUnixTimestamp);
|
||||
|
||||
/**
|
||||
* Record a corresponding ProfileChunk Trace Event.
|
||||
*/
|
||||
void reportRuntimeProfileChunk(
|
||||
uint16_t profileId,
|
||||
uint64_t threadId,
|
||||
uint64_t eventUnixTimestamp,
|
||||
const tracing::TraceEventProfileChunk& traceEventProfileChunk);
|
||||
|
||||
/**
|
||||
* Record an Event Loop tick, which will be represented as an Event Loop task
|
||||
* on a timeline view and grouped with JavaScript samples.
|
||||
@@ -111,6 +127,7 @@ class PerformanceTracer {
|
||||
bool tracing_{false};
|
||||
uint64_t processId_;
|
||||
uint32_t performanceMeasureCount_{0};
|
||||
uint16_t profileCount_{0};
|
||||
std::vector<TraceEvent> buffer_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace facebook::react::jsinspector_modern::tracing {
|
||||
|
||||
/// Arbitrary data structure, which represents payload of the "ProfileChunk"
|
||||
/// Trace Event.
|
||||
struct TraceEventProfileChunk {
|
||||
/// Deltas between timestamps of chronolocigally sorted samples.
|
||||
/// Will be sent as part of the "ProfileChunk" trace event.
|
||||
struct TimeDeltas {
|
||||
public:
|
||||
explicit TimeDeltas(std::vector<long long> deltas)
|
||||
: deltas_(std::move(deltas)) {}
|
||||
|
||||
folly::dynamic asDynamic() const {
|
||||
folly::dynamic value = folly::dynamic::array();
|
||||
for (auto delta : deltas_) {
|
||||
value.push_back(delta);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<long long> deltas_;
|
||||
};
|
||||
|
||||
/// Contains Profile information that will be emitted in this chunk: nodes and
|
||||
/// sample root node ids.
|
||||
struct CPUProfile {
|
||||
/// Unique node in the profile tree, has unique id, call frame and
|
||||
/// optionally
|
||||
/// id of its parent node. Only root node has no parent.
|
||||
struct Node {
|
||||
/// Unique call frame in the call stack.
|
||||
struct CallFrame {
|
||||
public:
|
||||
CallFrame(
|
||||
std::string codeType,
|
||||
uint32_t scriptId,
|
||||
std::string functionName,
|
||||
std::optional<std::string> url = std::nullopt,
|
||||
std::optional<uint32_t> lineNumber = std::nullopt,
|
||||
std::optional<uint32_t> columnNumber = std::nullopt)
|
||||
: codeType_(std::move(codeType)),
|
||||
scriptId_(scriptId),
|
||||
functionName_(std::move(functionName)),
|
||||
url_(std::move(url)),
|
||||
lineNumber_(lineNumber),
|
||||
columnNumber_(columnNumber) {}
|
||||
|
||||
folly::dynamic asDynamic() const {
|
||||
folly::dynamic dynamicCallFrame = folly::dynamic::object();
|
||||
dynamicCallFrame["codeType"] = codeType_;
|
||||
dynamicCallFrame["scriptId"] = scriptId_;
|
||||
dynamicCallFrame["functionName"] = functionName_;
|
||||
if (url_.has_value()) {
|
||||
dynamicCallFrame["url"] = url_.value();
|
||||
}
|
||||
if (lineNumber_.has_value()) {
|
||||
dynamicCallFrame["lineNumber"] = lineNumber_.value();
|
||||
}
|
||||
if (columnNumber_.has_value()) {
|
||||
dynamicCallFrame["columnNumber"] = columnNumber_.value();
|
||||
}
|
||||
|
||||
return dynamicCallFrame;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string codeType_;
|
||||
uint32_t scriptId_;
|
||||
std::string functionName_;
|
||||
std::optional<std::string> url_;
|
||||
std::optional<uint32_t> lineNumber_;
|
||||
std::optional<uint32_t> columnNumber_;
|
||||
};
|
||||
|
||||
public:
|
||||
Node(
|
||||
uint32_t id,
|
||||
CallFrame callFrame,
|
||||
std::optional<uint32_t> parentId = std::nullopt)
|
||||
: id_(id), callFrame_(std::move(callFrame)), parentId_(parentId) {}
|
||||
|
||||
folly::dynamic asDynamic() const {
|
||||
folly::dynamic dynamicNode = folly::dynamic::object();
|
||||
|
||||
dynamicNode["callFrame"] = callFrame_.asDynamic();
|
||||
dynamicNode["id"] = id_;
|
||||
if (parentId_.has_value()) {
|
||||
dynamicNode["parent"] = parentId_.value();
|
||||
}
|
||||
|
||||
return dynamicNode;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t id_;
|
||||
CallFrame callFrame_;
|
||||
std::optional<uint32_t> parentId_;
|
||||
};
|
||||
|
||||
public:
|
||||
CPUProfile(std::vector<Node> nodes, std::vector<uint32_t> samples)
|
||||
: nodes_(std::move(nodes)), samples_(std::move(samples)) {}
|
||||
|
||||
folly::dynamic asDynamic() const {
|
||||
folly::dynamic dynamicNodes = folly::dynamic::array();
|
||||
for (const auto& node : nodes_) {
|
||||
dynamicNodes.push_back(node.asDynamic());
|
||||
}
|
||||
|
||||
folly::dynamic dynamicSamples = folly::dynamic::array();
|
||||
for (auto sample : samples_) {
|
||||
dynamicSamples.push_back(sample);
|
||||
}
|
||||
|
||||
return folly::dynamic::object("nodes", dynamicNodes)(
|
||||
"samples", dynamicSamples);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Node> nodes_;
|
||||
std::vector<uint32_t> samples_;
|
||||
};
|
||||
|
||||
public:
|
||||
TraceEventProfileChunk(CPUProfile cpuProfile, TimeDeltas timeDeltas)
|
||||
: cpuProfile_(std::move(cpuProfile)),
|
||||
timeDeltas_(std::move(timeDeltas)) {}
|
||||
|
||||
folly::dynamic asDynamic() const {
|
||||
folly::dynamic value = folly::dynamic::object;
|
||||
value["cpuProfile"] = cpuProfile_.asDynamic();
|
||||
value["timeDeltas"] = timeDeltas_.asDynamic();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
CPUProfile cpuProfile_;
|
||||
TimeDeltas timeDeltas_;
|
||||
};
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern::tracing
|
||||
Reference in New Issue
Block a user