Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace facebook::react::jsinspector_modern {
#ifdef HERMES_ENABLE_DEBUGGER
namespace {

const uint16_t HERMES_SAMPLING_FREQUENCY_HZ = 1000;
const uint16_t HERMES_SAMPLING_FREQUENCY_HZ = 10000;

} // namespace

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,8 @@ bool TracingAgent::handleRequest(const cdp::PreparsedRequest& req) {

return true;
}
instanceAgent_->stopTracing();
tracing::RuntimeSamplingProfileTraceEventSerializer::serializeAndBuffer(
PerformanceTracer::getInstance(),
instanceAgent_->collectTracingProfile().getRuntimeSamplingProfile(),
instanceTracingStartTimestamp_);

instanceAgent_->stopTracing();
bool correctlyStopped = PerformanceTracer::getInstance().stopTracing();
if (!correctlyStopped) {
frontendChannel_(cdp::jsonError(
Expand All @@ -80,12 +76,19 @@ bool TracingAgent::handleRequest(const cdp::PreparsedRequest& req) {
// Send response to Tracing.end request.
frontendChannel_(cdp::jsonResult(req.id));

auto dataCollectedCallback = [this](const folly::dynamic& eventsChunk) {
frontendChannel_(cdp::jsonNotification(
"Tracing.dataCollected",
folly::dynamic::object("value", eventsChunk)));
};
PerformanceTracer::getInstance().collectEvents(
[this](const folly::dynamic& eventsChunk) {
frontendChannel_(cdp::jsonNotification(
"Tracing.dataCollected",
folly::dynamic::object("value", eventsChunk)));
},
dataCollectedCallback, TRACE_EVENT_CHUNK_SIZE);

tracing::RuntimeSamplingProfileTraceEventSerializer::serializeAndNotify(
PerformanceTracer::getInstance(),
instanceAgent_->collectTracingProfile().getRuntimeSamplingProfile(),
instanceTracingStartTimestamp_,
dataCollectedCallback,
TRACE_EVENT_CHUNK_SIZE);

frontendChannel_(cdp::jsonNotification(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ bool PerformanceTracer::stopTracing() {
});

performanceMeasureCount_ = 0;
profileCount_ = 0;
tracing_ = false;
return true;
}
Expand Down Expand Up @@ -243,20 +242,35 @@ void PerformanceTracer::reportThread(uint64_t id, const std::string& name) {
});
}

uint16_t PerformanceTracer::reportRuntimeProfile(
uint64_t threadId,
uint64_t eventUnixTimestamp) {
void PerformanceTracer::reportEventLoopTask(uint64_t start, uint64_t end) {
if (!tracing_) {
return;
}

std::lock_guard lock(mutex_);
if (!tracing_) {
throw std::runtime_error(
"Runtime Profile should only be reported when Tracing is enabled");
return;
}

++profileCount_;
buffer_.push_back(TraceEvent{
.name = "RunTask",
.cat = "disabled-by-default-devtools.timeline",
.ph = 'X',
.ts = start,
.pid = oscompat::getCurrentProcessId(),
.tid = oscompat::getCurrentThreadId(),
.dur = end - start,
});
}

folly::dynamic PerformanceTracer::getSerializedRuntimeProfileTraceEvent(
uint64_t threadId,
uint16_t profileId,
uint64_t eventUnixTimestamp) {
// CDT prioritizes event timestamp over startTime metadata field.
// https://fburl.com/lo764pf4
buffer_.push_back(TraceEvent{
.id = profileCount_,
return serializeTraceEvent(TraceEvent{
.id = profileId,
.name = "Profile",
.cat = "disabled-by-default-v8.cpu_profiler",
.ph = 'P',
Expand All @@ -266,21 +280,14 @@ uint16_t PerformanceTracer::reportRuntimeProfile(
.args = folly::dynamic::object(
"data", folly ::dynamic::object("startTime", eventUnixTimestamp)),
});

return profileCount_;
}

void PerformanceTracer::reportRuntimeProfileChunk(
folly::dynamic PerformanceTracer::getSerializedRuntimeProfileChunkTraceEvent(
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{
return serializeTraceEvent(TraceEvent{
.id = profileId,
.name = "ProfileChunk",
.cat = "disabled-by-default-v8.cpu_profiler",
Expand All @@ -293,27 +300,6 @@ void PerformanceTracer::reportRuntimeProfileChunk(
});
}

void PerformanceTracer::reportEventLoopTask(uint64_t start, uint64_t end) {
if (!tracing_) {
return;
}

std::lock_guard lock(mutex_);
if (!tracing_) {
return;
}

buffer_.push_back(TraceEvent{
.name = "RunTask",
.cat = "disabled-by-default-devtools.timeline",
.ph = 'X',
.ts = start,
.pid = oscompat::getCurrentProcessId(),
.tid = oscompat::getCurrentThreadId(),
.dur = end - start,
});
}

folly::dynamic PerformanceTracer::serializeTraceEvent(TraceEvent event) const {
folly::dynamic result = folly::dynamic::object;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,25 +96,29 @@ class PerformanceTracer {
void reportJavaScriptThread();

/**
* Record a corresponding Profile Trace Event.
* \return the id of the profile, should be used to linking profile chunks.
* Record an Event Loop tick, which will be represented as an Event Loop task
* on a timeline view and grouped with JavaScript samples.
*/
uint16_t reportRuntimeProfile(uint64_t threadId, uint64_t eventUnixTimestamp);
void reportEventLoopTask(uint64_t start, uint64_t end);

/**
* Record a corresponding ProfileChunk Trace Event.
* Create and serialize Profile Trace Event.
* \return serialized Trace Event that represents a Profile for CDT.
*/
void reportRuntimeProfileChunk(
uint16_t profileId,
folly::dynamic getSerializedRuntimeProfileTraceEvent(
uint64_t threadId,
uint64_t eventUnixTimestamp,
const tracing::TraceEventProfileChunk& traceEventProfileChunk);
uint16_t profileId,
uint64_t eventUnixTimestamp);

/**
* Record an Event Loop tick, which will be represented as an Event Loop task
* on a timeline view and grouped with JavaScript samples.
* Create and serialize ProfileChunk Trace Event.
* \return serialized Trace Event that represents a Profile Chunk for CDT.
*/
void reportEventLoopTask(uint64_t start, uint64_t end);
folly::dynamic getSerializedRuntimeProfileChunkTraceEvent(
uint16_t profileId,
uint64_t threadId,
uint64_t eventUnixTimestamp,
const tracing::TraceEventProfileChunk& traceEventProfileChunk);

private:
PerformanceTracer();
Expand All @@ -127,7 +131,6 @@ class PerformanceTracer {
bool tracing_{false};
uint64_t processId_;
uint32_t performanceMeasureCount_{0};
uint16_t profileCount_{0};
std::vector<TraceEvent> buffer_;
std::mutex mutex_;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ namespace facebook::react::jsinspector_modern::tracing {

namespace {

// Right now we only emit single Profile. We might revisit this decision in the
// future, once we support multiple VMs being sampled at the same time.
const uint16_t PROFILE_ID = 1;

uint64_t formatTimePointToUnixTimestamp(
std::chrono::steady_clock::time_point timestamp) {
return std::chrono::duration_cast<std::chrono::microseconds>(
Expand Down Expand Up @@ -49,6 +53,7 @@ TraceEventProfileChunk::CPUProfile::Node convertToTraceEventProfileNode(

void emitSingleProfileChunk(
PerformanceTracer& performanceTracer,
std::vector<folly::dynamic>& buffer,
uint16_t profileId,
uint64_t threadId,
uint64_t chunkTimestamp,
Expand All @@ -61,35 +66,40 @@ void emitSingleProfileChunk(
traceEventNodes.push_back(convertToTraceEventProfileNode(node));
}

performanceTracer.reportRuntimeProfileChunk(
buffer.push_back(performanceTracer.getSerializedRuntimeProfileChunkTraceEvent(
profileId,
threadId,
chunkTimestamp,
TraceEventProfileChunk{
TraceEventProfileChunk::CPUProfile{traceEventNodes, samples},
TraceEventProfileChunk::TimeDeltas{timeDeltas},
});
}));
}

} // namespace

/* static */ void
RuntimeSamplingProfileTraceEventSerializer::serializeAndBuffer(
RuntimeSamplingProfileTraceEventSerializer::serializeAndNotify(
PerformanceTracer& performanceTracer,
const RuntimeSamplingProfile& profile,
std::chrono::steady_clock::time_point tracingStartTime,
const std::function<void(const folly::dynamic& traceEventsChunk)>&
notificationCallback,
uint16_t traceEventChunkSize,
uint16_t profileChunkSize) {
std::vector<RuntimeSamplingProfile::Sample> runtimeSamples =
profile.getSamples();
if (runtimeSamples.empty()) {
return;
}

std::vector<folly::dynamic> buffer;

uint64_t chunkThreadId = runtimeSamples.front().getThreadId();
uint64_t tracingStartUnixTimestamp =
formatTimePointToUnixTimestamp(tracingStartTime);
uint16_t profileId = performanceTracer.reportRuntimeProfile(
chunkThreadId, tracingStartUnixTimestamp);
buffer.push_back(performanceTracer.getSerializedRuntimeProfileTraceEvent(
chunkThreadId, PROFILE_ID, tracingStartUnixTimestamp));

uint32_t nodeCount = 0;
auto* rootNode = new ProfileTreeNode(
Expand Down Expand Up @@ -148,7 +158,8 @@ RuntimeSamplingProfileTraceEventSerializer::serializeAndBuffer(
if (chunkThreadId != sampleThreadId) {
emitSingleProfileChunk(
performanceTracer,
profileId,
buffer,
PROFILE_ID,
chunkThreadId,
chunkTimestamp,
nodesInThisChunk,
Expand Down Expand Up @@ -203,7 +214,8 @@ RuntimeSamplingProfileTraceEventSerializer::serializeAndBuffer(
if (samplesInThisChunk.size() == profileChunkSize) {
emitSingleProfileChunk(
performanceTracer,
profileId,
buffer,
PROFILE_ID,
chunkThreadId,
chunkTimestamp,
nodesInThisChunk,
Expand All @@ -214,18 +226,29 @@ RuntimeSamplingProfileTraceEventSerializer::serializeAndBuffer(
samplesInThisChunk.clear();
timeDeltasInThisChunk.clear();
}

if (buffer.size() == traceEventChunkSize) {
notificationCallback(folly::dynamic::array(buffer.begin(), buffer.end()));
buffer.clear();
}
}

if (!samplesInThisChunk.empty()) {
emitSingleProfileChunk(
performanceTracer,
profileId,
buffer,
PROFILE_ID,
chunkThreadId,
chunkTimestamp,
nodesInThisChunk,
samplesInThisChunk,
timeDeltasInThisChunk);
}

if (!buffer.empty()) {
notificationCallback(folly::dynamic::array(buffer.begin(), buffer.end()));
buffer.clear();
}
}

} // namespace facebook::react::jsinspector_modern::tracing
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ class RuntimeSamplingProfileTraceEventSerializer {
public:
RuntimeSamplingProfileTraceEventSerializer() = delete;

static void serializeAndBuffer(
static void serializeAndNotify(
PerformanceTracer& performanceTracer,
const RuntimeSamplingProfile& profile,
std::chrono::steady_clock::time_point tracingStartTime,
const std::function<void(const folly::dynamic& traceEventsChunk)>&
notificationCallback,
uint16_t traceEventChunkSize,
uint16_t profileChunkSize = 100);
};

Expand Down