mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Static generators for Profile Trace Events (#52915)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52915 # Changelog: [Internal] This removes the use of `PerformanceTracer` instance in a serialization logic. Reviewed By: rubennorte Differential Revision: D78919220 fbshipit-source-id: 5c663ea77eb36eb7664623c1595308a9450f7825
This commit is contained in:
committed by
Facebook GitHub Bot
parent
3ed6def874
commit
a8f6c96bc2
+8
-2
@@ -5,10 +5,12 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include "HermesRuntimeSamplingProfileSerializer.h"
|
||||
|
||||
#include <oscompat/OSCompat.h>
|
||||
|
||||
#include <variant>
|
||||
|
||||
namespace facebook::react::jsinspector_modern::tracing {
|
||||
|
||||
namespace {
|
||||
@@ -163,6 +165,10 @@ HermesRuntimeSamplingProfileSerializer::serializeToTracingSamplingProfile(
|
||||
|
||||
return RuntimeSamplingProfile{
|
||||
"Hermes",
|
||||
// Hermes' Profile should be the source of truth for this,
|
||||
// but it is safe to reuse the process ID here, since everything runs in
|
||||
// the same process.
|
||||
oscompat::getCurrentProcessId(),
|
||||
std::move(reconciledSamples),
|
||||
std::make_unique<RawHermesRuntimeProfile>(std::move(hermesProfile))};
|
||||
}
|
||||
|
||||
@@ -111,9 +111,7 @@ bool TracingAgent::handleRequest(const cdp::PreparsedRequest& req) {
|
||||
dataCollectedCallback, TRACE_EVENT_CHUNK_SIZE);
|
||||
|
||||
tracing::RuntimeSamplingProfileTraceEventSerializer serializer(
|
||||
performanceTracer,
|
||||
dataCollectedCallback,
|
||||
PROFILE_TRACE_EVENT_CHUNK_SIZE);
|
||||
dataCollectedCallback, PROFILE_TRACE_EVENT_CHUNK_SIZE);
|
||||
auto tracingProfile = instanceAgent_->collectTracingProfile();
|
||||
serializer.serializeAndNotify(
|
||||
std::move(tracingProfile.runtimeSamplingProfile),
|
||||
|
||||
+14
-11
@@ -305,46 +305,49 @@ void PerformanceTracer::reportEventLoopMicrotasks(
|
||||
});
|
||||
}
|
||||
|
||||
folly::dynamic PerformanceTracer::getSerializedRuntimeProfileTraceEvent(
|
||||
ThreadId threadId,
|
||||
/* static */ TraceEvent PerformanceTracer::constructRuntimeProfileTraceEvent(
|
||||
RuntimeProfileId profileId,
|
||||
ProcessId processId,
|
||||
ThreadId threadId,
|
||||
HighResTimeStamp profileTimestamp) {
|
||||
// CDT prioritizes event timestamp over startTime metadata field.
|
||||
// https://fburl.com/lo764pf4
|
||||
return TraceEventSerializer::serialize(TraceEvent{
|
||||
return TraceEvent{
|
||||
.id = profileId,
|
||||
.name = "Profile",
|
||||
.cat = "disabled-by-default-v8.cpu_profiler",
|
||||
.ph = 'P',
|
||||
.ts = profileTimestamp,
|
||||
.pid = processId_,
|
||||
.pid = processId,
|
||||
.tid = threadId,
|
||||
.args = folly::dynamic::object(
|
||||
"data",
|
||||
folly::dynamic::object(
|
||||
"startTime",
|
||||
highResTimeStampToTracingClockTimeStamp(profileTimestamp))),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
folly::dynamic PerformanceTracer::getSerializedRuntimeProfileChunkTraceEvent(
|
||||
ThreadId threadId,
|
||||
/* static */ TraceEvent
|
||||
PerformanceTracer::constructRuntimeProfileChunkTraceEvent(
|
||||
RuntimeProfileId profileId,
|
||||
ProcessId processId,
|
||||
ProcessId threadId,
|
||||
HighResTimeStamp chunkTimestamp,
|
||||
tracing::TraceEventProfileChunk&& traceEventProfileChunk) {
|
||||
return TraceEventSerializer::serialize(TraceEvent{
|
||||
TraceEventProfileChunk&& traceEventProfileChunk) {
|
||||
return TraceEvent{
|
||||
.id = profileId,
|
||||
.name = "ProfileChunk",
|
||||
.cat = "disabled-by-default-v8.cpu_profiler",
|
||||
.ph = 'P',
|
||||
.ts = chunkTimestamp,
|
||||
.pid = processId_,
|
||||
.pid = processId,
|
||||
.tid = threadId,
|
||||
.args = folly::dynamic::object(
|
||||
"data",
|
||||
TraceEventSerializer::serializeProfileChunk(
|
||||
std::move(traceEventProfileChunk))),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern::tracing
|
||||
|
||||
@@ -116,21 +116,25 @@ class PerformanceTracer {
|
||||
void reportEventLoopMicrotasks(HighResTimeStamp start, HighResTimeStamp end);
|
||||
|
||||
/**
|
||||
* Create and serialize Profile Trace Event.
|
||||
* \return serialized Trace Event that represents a Profile for CDT.
|
||||
* Creates "Profile" Trace Event.
|
||||
*
|
||||
* Can be serialized to JSON with TraceEventSerializer::serialize.
|
||||
*/
|
||||
folly::dynamic getSerializedRuntimeProfileTraceEvent(
|
||||
ThreadId threadId,
|
||||
static TraceEvent constructRuntimeProfileTraceEvent(
|
||||
RuntimeProfileId profileId,
|
||||
ProcessId processId,
|
||||
ThreadId threadId,
|
||||
HighResTimeStamp profileTimestamp);
|
||||
|
||||
/**
|
||||
* Create and serialize ProfileChunk Trace Event.
|
||||
* \return serialized Trace Event that represents a Profile Chunk for CDT.
|
||||
* Creates "ProfileChunk" Trace Event.
|
||||
*
|
||||
* Can be serialized to JSON with TraceEventSerializer::serialize.
|
||||
*/
|
||||
folly::dynamic getSerializedRuntimeProfileChunkTraceEvent(
|
||||
ProcessId threadId,
|
||||
static TraceEvent constructRuntimeProfileChunkTraceEvent(
|
||||
RuntimeProfileId profileId,
|
||||
ProcessId processId,
|
||||
ProcessId threadId,
|
||||
HighResTimeStamp chunkTimestamp,
|
||||
TraceEventProfileChunk&& traceEventProfileChunk);
|
||||
|
||||
|
||||
@@ -91,9 +91,11 @@ struct RuntimeSamplingProfile {
|
||||
|
||||
RuntimeSamplingProfile(
|
||||
std::string runtimeName,
|
||||
ProcessId processId,
|
||||
std::vector<Sample> samples,
|
||||
std::unique_ptr<RawRuntimeProfile> rawRuntimeProfile)
|
||||
: runtimeName(std::move(runtimeName)),
|
||||
processId(processId),
|
||||
samples(std::move(samples)),
|
||||
rawRuntimeProfile(std::move(rawRuntimeProfile)) {}
|
||||
|
||||
@@ -109,6 +111,8 @@ struct RuntimeSamplingProfile {
|
||||
|
||||
/// Name of the runtime, where sampling occurred: Hermes, V8, etc.
|
||||
std::string runtimeName;
|
||||
/// The ID of the OS-level process where the sampling occurred.
|
||||
ProcessId processId;
|
||||
/// List of recorded samples, should be chronologically sorted.
|
||||
std::vector<Sample> samples;
|
||||
/// A unique pointer to the original raw runtime profile, collected from the
|
||||
|
||||
+36
-21
@@ -5,10 +5,12 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "ProfileTreeNode.h"
|
||||
#include "RuntimeSamplingProfileTraceEventSerializer.h"
|
||||
#include "PerformanceTracer.h"
|
||||
#include "ProfileTreeNode.h"
|
||||
#include "TraceEventSerializer.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace facebook::react::jsinspector_modern::tracing {
|
||||
|
||||
@@ -96,14 +98,16 @@ class ProfileTreeRootNode : public ProfileTreeNode {
|
||||
} // namespace
|
||||
|
||||
void RuntimeSamplingProfileTraceEventSerializer::sendProfileTraceEvent(
|
||||
ProcessId processId,
|
||||
ThreadId threadId,
|
||||
RuntimeProfileId profileId,
|
||||
HighResTimeStamp profileStartTimestamp) const {
|
||||
auto traceEvent = PerformanceTracer::constructRuntimeProfileTraceEvent(
|
||||
profileId, processId, threadId, profileStartTimestamp);
|
||||
folly::dynamic serializedTraceEvent =
|
||||
performanceTracer_.getSerializedRuntimeProfileTraceEvent(
|
||||
threadId, profileId, profileStartTimestamp);
|
||||
TraceEventSerializer::serialize(std::move(traceEvent));
|
||||
|
||||
notificationCallback_(folly::dynamic::array(serializedTraceEvent));
|
||||
notificationCallback_(folly::dynamic::array(std::move(serializedTraceEvent)));
|
||||
}
|
||||
|
||||
void RuntimeSamplingProfileTraceEventSerializer::chunkEmptySample(
|
||||
@@ -127,18 +131,22 @@ void RuntimeSamplingProfileTraceEventSerializer::bufferProfileChunkTraceEvent(
|
||||
traceEventNodes.push_back(convertToTraceEventProfileNode(node));
|
||||
}
|
||||
|
||||
traceEventBuffer_.push_back(
|
||||
performanceTracer_.getSerializedRuntimeProfileChunkTraceEvent(
|
||||
profileId,
|
||||
chunk.threadId,
|
||||
chunk.timestamp,
|
||||
TraceEventProfileChunk{
|
||||
.cpuProfile =
|
||||
TraceEventProfileChunk::CPUProfile{
|
||||
.nodes = std::move(traceEventNodes),
|
||||
.samples = std::move(chunk.samples)},
|
||||
.timeDeltas = std::move(chunk.timeDeltas),
|
||||
}));
|
||||
auto traceEvent = PerformanceTracer::constructRuntimeProfileChunkTraceEvent(
|
||||
profileId,
|
||||
chunk.processId,
|
||||
chunk.threadId,
|
||||
chunk.timestamp,
|
||||
TraceEventProfileChunk{
|
||||
.cpuProfile =
|
||||
TraceEventProfileChunk::CPUProfile{
|
||||
.nodes = std::move(traceEventNodes),
|
||||
.samples = std::move(chunk.samples)},
|
||||
.timeDeltas = std::move(chunk.timeDeltas),
|
||||
});
|
||||
auto serializedTraceEvent =
|
||||
TraceEventSerializer::serialize(std::move(traceEvent));
|
||||
|
||||
traceEventBuffer_.push_back(std::move(serializedTraceEvent));
|
||||
}
|
||||
|
||||
void RuntimeSamplingProfileTraceEventSerializer::processCallStack(
|
||||
@@ -202,12 +210,16 @@ void RuntimeSamplingProfileTraceEventSerializer::serializeAndNotify(
|
||||
HighResTimeStamp previousSampleTimestamp = tracingStartTime;
|
||||
HighResTimeStamp currentChunkTimestamp = tracingStartTime;
|
||||
|
||||
sendProfileTraceEvent(firstChunkThreadId, PROFILE_ID, tracingStartTime);
|
||||
sendProfileTraceEvent(
|
||||
profile.processId, firstChunkThreadId, PROFILE_ID, tracingStartTime);
|
||||
|
||||
// There could be any number of new nodes in this chunk. Empty if all nodes
|
||||
// are already emitted in previous chunks.
|
||||
ProfileChunk chunk{
|
||||
profileChunkSize_, firstChunkThreadId, currentChunkTimestamp};
|
||||
profileChunkSize_,
|
||||
profile.processId,
|
||||
firstChunkThreadId,
|
||||
currentChunkTimestamp};
|
||||
|
||||
NodeIdGenerator nodeIdGenerator{};
|
||||
|
||||
@@ -238,7 +250,10 @@ void RuntimeSamplingProfileTraceEventSerializer::serializeAndNotify(
|
||||
if (currentSampleThreadId != chunk.threadId || chunk.isFull()) {
|
||||
bufferProfileChunkTraceEvent(std::move(chunk), PROFILE_ID);
|
||||
chunk = ProfileChunk{
|
||||
profileChunkSize_, currentSampleThreadId, currentChunkTimestamp};
|
||||
profileChunkSize_,
|
||||
profile.processId,
|
||||
currentSampleThreadId,
|
||||
currentChunkTimestamp};
|
||||
}
|
||||
|
||||
if (traceEventBuffer_.size() == traceEventChunkSize_) {
|
||||
|
||||
+10
-7
@@ -7,7 +7,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PerformanceTracer.h"
|
||||
#include "ProfileTreeNode.h"
|
||||
#include "RuntimeSamplingProfile.h"
|
||||
|
||||
@@ -37,9 +36,13 @@ class RuntimeSamplingProfileTraceEventSerializer {
|
||||
struct ProfileChunk {
|
||||
ProfileChunk(
|
||||
uint16_t chunkSize,
|
||||
ProcessId chunkProcessId,
|
||||
ThreadId chunkThreadId,
|
||||
HighResTimeStamp chunkTimestamp)
|
||||
: size(chunkSize), threadId(chunkThreadId), timestamp(chunkTimestamp) {
|
||||
: size(chunkSize),
|
||||
processId(chunkProcessId),
|
||||
threadId(chunkThreadId),
|
||||
timestamp(chunkTimestamp) {
|
||||
samples.reserve(size);
|
||||
timeDeltas.reserve(size);
|
||||
}
|
||||
@@ -56,13 +59,13 @@ class RuntimeSamplingProfileTraceEventSerializer {
|
||||
std::vector<uint32_t> samples;
|
||||
std::vector<HighResDuration> timeDeltas;
|
||||
uint16_t size;
|
||||
ProcessId processId;
|
||||
ThreadId threadId;
|
||||
HighResTimeStamp timestamp;
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* \param performanceTracer A reference to PerformanceTracer instance.
|
||||
* \param notificationCallback A reference to a callback, which is called
|
||||
* when a chunk of trace events is ready to be sent.
|
||||
* \param traceEventChunkSize The maximum number of ProfileChunk trace
|
||||
@@ -71,13 +74,11 @@ class RuntimeSamplingProfileTraceEventSerializer {
|
||||
* that can be sent in a single ProfileChunk trace event.
|
||||
*/
|
||||
RuntimeSamplingProfileTraceEventSerializer(
|
||||
PerformanceTracer& performanceTracer,
|
||||
std::function<void(folly::dynamic&& traceEventsChunk)>
|
||||
notificationCallback,
|
||||
uint16_t traceEventChunkSize,
|
||||
uint16_t profileChunkSize = 10)
|
||||
: performanceTracer_(performanceTracer),
|
||||
notificationCallback_(std::move(notificationCallback)),
|
||||
: notificationCallback_(std::move(notificationCallback)),
|
||||
traceEventChunkSize_(traceEventChunkSize),
|
||||
profileChunkSize_(profileChunkSize) {
|
||||
traceEventBuffer_ = folly::dynamic::array();
|
||||
@@ -96,12 +97,15 @@ class RuntimeSamplingProfileTraceEventSerializer {
|
||||
private:
|
||||
/**
|
||||
* Sends a single "Profile" Trace Event via notificationCallback_.
|
||||
|
||||
* \param processId The id of the process, where the Profile was collected.
|
||||
* \param threadId The id of the thread, where the Profile was collected.
|
||||
* \param profileId The id of the Profile.
|
||||
* \param profileStartUnixTimestamp The Unix timestamp of the start of the
|
||||
* profile.
|
||||
*/
|
||||
void sendProfileTraceEvent(
|
||||
ProcessId processId,
|
||||
ThreadId threadId,
|
||||
RuntimeProfileId profileId,
|
||||
HighResTimeStamp profileStartTimestamp) const;
|
||||
@@ -154,7 +158,6 @@ class RuntimeSamplingProfileTraceEventSerializer {
|
||||
*/
|
||||
void sendBufferedTraceEventsAndClear();
|
||||
|
||||
PerformanceTracer& performanceTracer_;
|
||||
const std::function<void(folly::dynamic&& traceEventsChunk)>
|
||||
notificationCallback_;
|
||||
const uint16_t traceEventChunkSize_;
|
||||
|
||||
+8
-14
@@ -55,12 +55,12 @@ class RuntimeSamplingProfileTraceEventSerializerTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
RuntimeSamplingProfile createEmptyProfile() {
|
||||
return {"TestRuntime", {}, {}};
|
||||
return {"TestRuntime", 1, {}, {}};
|
||||
}
|
||||
|
||||
RuntimeSamplingProfile createProfileWithSamples(
|
||||
std::vector<RuntimeSamplingProfile::Sample> samples) {
|
||||
return {"TestRuntime", std::move(samples), {}};
|
||||
return {"TestRuntime", 1, std::move(samples), {}};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -68,7 +68,7 @@ TEST_F(RuntimeSamplingProfileTraceEventSerializerTest, EmptyProfile) {
|
||||
// Setup
|
||||
auto notificationCallback = createNotificationCallback();
|
||||
RuntimeSamplingProfileTraceEventSerializer serializer(
|
||||
PerformanceTracer::getInstance(), notificationCallback, 10);
|
||||
notificationCallback, 10);
|
||||
|
||||
auto profile = createEmptyProfile();
|
||||
auto tracingStartTime = HighResTimeStamp::now();
|
||||
@@ -86,7 +86,7 @@ TEST_F(
|
||||
// Setup
|
||||
auto notificationCallback = createNotificationCallback();
|
||||
RuntimeSamplingProfileTraceEventSerializer serializer(
|
||||
PerformanceTracer::getInstance(), notificationCallback, 10);
|
||||
notificationCallback, 10);
|
||||
|
||||
// [ foo ]
|
||||
// [ bar ]
|
||||
@@ -136,7 +136,7 @@ TEST_F(RuntimeSamplingProfileTraceEventSerializerTest, EmptySample) {
|
||||
// Setup
|
||||
auto notificationCallback = createNotificationCallback();
|
||||
RuntimeSamplingProfileTraceEventSerializer serializer(
|
||||
PerformanceTracer::getInstance(), notificationCallback, 10);
|
||||
notificationCallback, 10);
|
||||
|
||||
// Create an empty sample (no call stack)
|
||||
std::vector<RuntimeSamplingProfile::SampleCallStackFrame> emptyCallStack;
|
||||
@@ -172,7 +172,7 @@ TEST_F(
|
||||
// Setup
|
||||
auto notificationCallback = createNotificationCallback();
|
||||
RuntimeSamplingProfileTraceEventSerializer serializer(
|
||||
PerformanceTracer::getInstance(), notificationCallback, 10);
|
||||
notificationCallback, 10);
|
||||
|
||||
// Create samples with different thread IDs
|
||||
std::vector<RuntimeSamplingProfile::SampleCallStackFrame> callStack = {
|
||||
@@ -209,10 +209,7 @@ TEST_F(
|
||||
uint16_t traceEventChunkSize = 2;
|
||||
uint16_t profileChunkSize = 2;
|
||||
RuntimeSamplingProfileTraceEventSerializer serializer(
|
||||
PerformanceTracer::getInstance(),
|
||||
notificationCallback,
|
||||
traceEventChunkSize,
|
||||
profileChunkSize);
|
||||
notificationCallback, traceEventChunkSize, profileChunkSize);
|
||||
|
||||
// Create multiple samples
|
||||
std::vector<RuntimeSamplingProfile::SampleCallStackFrame> callStack = {
|
||||
@@ -250,10 +247,7 @@ TEST_F(RuntimeSamplingProfileTraceEventSerializerTest, ProfileChunkSizeLimit) {
|
||||
uint16_t profileChunkSize = 2;
|
||||
double samplesCount = 5;
|
||||
RuntimeSamplingProfileTraceEventSerializer serializer(
|
||||
PerformanceTracer::getInstance(),
|
||||
notificationCallback,
|
||||
traceEventChunkSize,
|
||||
profileChunkSize);
|
||||
notificationCallback, traceEventChunkSize, profileChunkSize);
|
||||
|
||||
// Create multiple samples
|
||||
std::vector<RuntimeSamplingProfile::SampleCallStackFrame> callStack = {
|
||||
|
||||
Reference in New Issue
Block a user