Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Scaffold support for Tracing by jsinspector (#48836)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #48836

# Changelog: [Internal]

Differential Revision: D68327630
hoxyq authored and facebook-github-bot committed Jan 22, 2025
1 parent f65ee5a commit ecdecf0
Showing 16 changed files with 297 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -28,6 +28,12 @@ using namespace facebook::hermes;
namespace facebook::react::jsinspector_modern {

#ifdef HERMES_ENABLE_DEBUGGER
namespace {

const uint16_t HERMES_SAMPLING_FREQUENCY_HZ = 1000;

}

class HermesRuntimeTargetDelegate::Impl final : public RuntimeTargetDelegate {
using HermesStackTrace = debugger::StackTrace;

@@ -167,6 +173,18 @@ class HermesRuntimeTargetDelegate::Impl final : public RuntimeTargetDelegate {
runtime_->getDebugger().captureStackTrace());
}

void enableSamplingProfiler() override {
runtime_->enableSamplingProfiler(HERMES_SAMPLING_FREQUENCY_HZ);
}

void disableSamplingProfiler() override {
runtime_->disableSamplingProfiler();
}

tracing::RuntimeSamplingProfile collectSamplingProfile() override {
return tracing::RuntimeSamplingProfile{};
}

private:
HermesRuntimeTargetDelegate& delegate_;
std::shared_ptr<HermesRuntime> runtime_;
@@ -228,6 +246,19 @@ std::unique_ptr<StackTrace> HermesRuntimeTargetDelegate::captureStackTrace(
return impl_->captureStackTrace(runtime, framesToSkip);
}

void HermesRuntimeTargetDelegate::enableSamplingProfiler() {
impl_->enableSamplingProfiler();
}

void HermesRuntimeTargetDelegate::disableSamplingProfiler() {
impl_->disableSamplingProfiler();
}

tracing::RuntimeSamplingProfile
HermesRuntimeTargetDelegate::collectSamplingProfile() {
return impl_->collectSamplingProfile();
}

#ifdef HERMES_ENABLE_DEBUGGER
CDPDebugAPI& HermesRuntimeTargetDelegate::getCDPDebugAPI() {
return impl_->getCDPDebugAPI();
Original file line number Diff line number Diff line change
@@ -54,6 +54,12 @@ class HermesRuntimeTargetDelegate : public RuntimeTargetDelegate {
jsi::Runtime& runtime,
size_t framesToSkip) override;

void enableSamplingProfiler() override;

void disableSamplingProfiler() override;

tracing::RuntimeSamplingProfile collectSamplingProfile() override;

private:
// We use the private implementation idiom to ensure this class has the same
// layout regardless of whether HERMES_ENABLE_DEBUGGER is defined. The net
Original file line number Diff line number Diff line change
@@ -44,4 +44,18 @@ std::unique_ptr<StackTrace> FallbackRuntimeTargetDelegate::captureStackTrace(
return std::make_unique<StackTrace>();
}

void FallbackRuntimeTargetDelegate::enableSamplingProfiler() {
// no-op
};

void FallbackRuntimeTargetDelegate::disableSamplingProfiler() {
// no-op
};

tracing::RuntimeSamplingProfile
FallbackRuntimeTargetDelegate::collectSamplingProfile() {
throw std::logic_error(
"Sampling Profiler capabilities are not supported for Runtime fallback");
}

} // namespace facebook::react::jsinspector_modern
Original file line number Diff line number Diff line change
@@ -40,6 +40,12 @@ class FallbackRuntimeTargetDelegate : public RuntimeTargetDelegate {
jsi::Runtime& runtime,
size_t framesToSkip) override;

void enableSamplingProfiler() override;

void disableSamplingProfiler() override;

tracing::RuntimeSamplingProfile collectSamplingProfile() override;

private:
std::string engineDescription_;
};
Original file line number Diff line number Diff line change
@@ -223,8 +223,11 @@ void HostAgent::sendInfoLogEntry(

void HostAgent::setCurrentInstanceAgent(
std::shared_ptr<InstanceAgent> instanceAgent) {
tracingAgent_.setCurrentInstanceAgent(instanceAgent);

auto previousInstanceAgent = std::move(instanceAgent_);
instanceAgent_ = std::move(instanceAgent);

if (!sessionState_.isRuntimeDomainEnabled) {
return;
}
Original file line number Diff line number Diff line change
@@ -152,4 +152,23 @@ void InstanceAgent::maybeSendPendingConsoleMessages() {
}
}

void InstanceAgent::startTracing() {
if (runtimeAgent_) {
runtimeAgent_->enableSamplingProfiler();
}
}

void InstanceAgent::stopTracing() {
if (runtimeAgent_) {
runtimeAgent_->disableSamplingProfiler();
}
}

tracing::InstanceTracingProfile InstanceAgent::collectTracingProfile() {
tracing::RuntimeSamplingProfile runtimeSamplingProfile =
runtimeAgent_->collectSamplingProfile();

return tracing::InstanceTracingProfile{runtimeSamplingProfile};
}

} // namespace facebook::react::jsinspector_modern
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@

#include <jsinspector-modern/InspectorInterfaces.h>
#include <jsinspector-modern/RuntimeAgent.h>
#include <jsinspector-modern/tracing/InstanceTracingProfile.h>

#include <functional>

@@ -59,6 +60,23 @@ class InstanceAgent final {
*/
void sendConsoleMessage(SimpleConsoleMessage message);

/**
* Notify Instance about started Tracing session. Should be initiated by
* TracingAgent on Tracing.start CDP method.
*/
void startTracing();

/**
* Notify Instance about stopped Tracing session. Should be initiated by
* TracingAgent on Tracing.end CDP method.
*/
void stopTracing();

/**
* Return recorded profile for the previous tracing session.
*/
tracing::InstanceTracingProfile collectTracingProfile();

private:
void maybeSendExecutionContextCreatedNotification();
void sendConsoleMessageImmediately(SimpleConsoleMessage message);
Original file line number Diff line number Diff line change
@@ -149,4 +149,16 @@ RuntimeAgent::~RuntimeAgent() {
sessionState_.lastRuntimeAgentExportedState = getExportedState();
}

void RuntimeAgent::enableSamplingProfiler() {
targetController_.enableSamplingProfiler();
}

void RuntimeAgent::disableSamplingProfiler() {
targetController_.disableSamplingProfiler();
}

tracing::RuntimeSamplingProfile RuntimeAgent::collectSamplingProfile() {
return targetController_.collectSamplingProfile();
}

} // namespace facebook::react::jsinspector_modern
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@
#include "RuntimeAgentDelegate.h"
#include "RuntimeTarget.h"

#include <jsinspector-modern/tracing/RuntimeSamplingProfile.h>

namespace facebook::react::jsinspector_modern {

class RuntimeTargetController;
@@ -81,6 +83,21 @@ class RuntimeAgent final {
*/
ExportedState getExportedState();

/**
* Start sampling profiler for the corresponding RuntimeTarget.
*/
void enableSamplingProfiler();

/**
* Stop sampling profiler for the corresponding RuntimeTarget.
*/
void disableSamplingProfiler();

/**
* Return recorded sampling profile for the previous sampling session.
*/
tracing::RuntimeSamplingProfile collectSamplingProfile();

private:
FrontendChannel frontendChannel_;
RuntimeTargetController& targetController_;
Original file line number Diff line number Diff line change
@@ -159,4 +159,29 @@ void RuntimeTargetController::notifyDebuggerSessionDestroyed() {
target_.emitDebuggerSessionDestroyed();
}

void RuntimeTargetController::enableSamplingProfiler() {
target_.enableSamplingProfiler();
}

void RuntimeTargetController::disableSamplingProfiler() {
target_.disableSamplingProfiler();
}

tracing::RuntimeSamplingProfile
RuntimeTargetController::collectSamplingProfile() {
return target_.collectSamplingProfile();
}

void RuntimeTarget::enableSamplingProfiler() {
delegate_.enableSamplingProfiler();
}

void RuntimeTarget::disableSamplingProfiler() {
delegate_.disableSamplingProfiler();
}

tracing::RuntimeSamplingProfile RuntimeTarget::collectSamplingProfile() {
return delegate_.collectSamplingProfile();
}

} // namespace facebook::react::jsinspector_modern
Original file line number Diff line number Diff line change
@@ -7,8 +7,6 @@

#pragma once

#include <ReactCommon/RuntimeExecutor.h>

#include "ConsoleMessage.h"
#include "ExecutionContext.h"
#include "InspectorInterfaces.h"
@@ -17,6 +15,9 @@
#include "StackTrace.h"
#include "WeakList.h"

#include <ReactCommon/RuntimeExecutor.h>
#include <jsinspector-modern/tracing/RuntimeSamplingProfile.h>

#include <memory>

#ifndef JSINSPECTOR_EXPORT
@@ -90,6 +91,21 @@ class RuntimeTargetDelegate {
virtual std::unique_ptr<StackTrace> captureStackTrace(
jsi::Runtime& runtime,
size_t framesToSkip = 0) = 0;

/**
* Start sampling profiler.
*/
virtual void enableSamplingProfiler() = 0;

/**
* Stop sampling profiler.
*/
virtual void disableSamplingProfiler() = 0;

/**
* Return recorded sampling profile for the previous sampling session.
*/
virtual tracing::RuntimeSamplingProfile collectSamplingProfile() = 0;
};

/**
@@ -118,6 +134,21 @@ class RuntimeTargetController {
*/
void notifyDebuggerSessionDestroyed();

/**
* Start sampling profiler for the corresponding RuntimeTarget.
*/
void enableSamplingProfiler();

/**
* Stop sampling profiler for the corresponding RuntimeTarget.
*/
void disableSamplingProfiler();

/**
* Return recorded sampling profile for the previous sampling session.
*/
tracing::RuntimeSamplingProfile collectSamplingProfile();

private:
RuntimeTarget& target_;
};
@@ -171,6 +202,21 @@ class JSINSPECTOR_EXPORT RuntimeTarget
FrontendChannel channel,
SessionState& sessionState);

/**
* Start sampling profiler for a particular JavaScript runtime.
*/
void enableSamplingProfiler();

/**
* Stop sampling profiler for a particular JavaScript runtime.
*/
void disableSamplingProfiler();

/**
* Return recorded sampling profile for the previous sampling session.
*/
tracing::RuntimeSamplingProfile collectSamplingProfile();

private:
/**
* Constructs a new RuntimeTarget. The caller must call setExecutor
Original file line number Diff line number Diff line change
@@ -24,20 +24,44 @@ const uint16_t TRACE_EVENT_CHUNK_SIZE = 1000;
bool TracingAgent::handleRequest(const cdp::PreparsedRequest& req) {
if (req.method == "Tracing.start") {
// @cdp Tracing.start support is experimental.
if (PerformanceTracer::getInstance().startTracing()) {
frontendChannel_(cdp::jsonResult(req.id));
} else {
if (!instanceAgent_) {
frontendChannel_(cdp::jsonError(
req.id,
cdp::ErrorCode::InternalError,
"Couldn't find instance available for Tracing"));

return true;
}

bool correctlyStartedPerformanceTracer =
PerformanceTracer::getInstance().startTracing();

if (!correctlyStartedPerformanceTracer) {
frontendChannel_(cdp::jsonError(
req.id,
cdp::ErrorCode::InternalError,
"Tracing session already started"));

return true;
}

instanceAgent_->startTracing();
frontendChannel_(cdp::jsonResult(req.id));

return true;
} else if (req.method == "Tracing.end") {
// @cdp Tracing.end support is experimental.
bool correctlyStopped = PerformanceTracer::getInstance().stopTracing();
if (!instanceAgent_) {
frontendChannel_(cdp::jsonError(
req.id,
cdp::ErrorCode::InternalError,
"Couldn't find instance available for Tracing"));

return true;
}
instanceAgent_->stopTracing();

bool correctlyStopped = PerformanceTracer::getInstance().stopTracing();
if (!correctlyStopped) {
frontendChannel_(cdp::jsonError(
req.id,
@@ -68,4 +92,9 @@ bool TracingAgent::handleRequest(const cdp::PreparsedRequest& req) {
return false;
}

void TracingAgent::setCurrentInstanceAgent(
std::shared_ptr<InstanceAgent> instanceAgent) {
instanceAgent_ = std::move(instanceAgent);
}

} // namespace facebook::react::jsinspector_modern
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@

#include "CdpJson.h"
#include "InspectorInterfaces.h"
#include "InstanceAgent.h"

namespace facebook::react::jsinspector_modern {

@@ -31,11 +32,24 @@ class TracingAgent {
*/
bool handleRequest(const cdp::PreparsedRequest& req);

/**
* Replace the current InstanceAgent with the given one.
* \param agent The new InstanceAgent. May be null to signify that there is
* currently no active instance.
*/
void setCurrentInstanceAgent(std::shared_ptr<InstanceAgent> agent);

private:
/**
* A channel used to send responses and events to the frontend.
*/
FrontendChannel frontendChannel_;

/**
* Current InstanceAgent. May be null to signify that there is
* currently no active instance.
*/
std::shared_ptr<InstanceAgent> instanceAgent_;
};

} // namespace facebook::react::jsinspector_modern
Original file line number Diff line number Diff line change
@@ -161,6 +161,13 @@ class MockRuntimeTargetDelegate : public RuntimeTargetDelegate {
captureStackTrace,
(jsi::Runtime & runtime, size_t framesToSkip),
(override));
MOCK_METHOD(void, enableSamplingProfiler, (), (override));
MOCK_METHOD(void, disableSamplingProfiler, (), (override));
MOCK_METHOD(
tracing::RuntimeSamplingProfile,
collectSamplingProfile,
(),
(override));
};

class MockRuntimeAgentDelegate : public RuntimeAgentDelegate {
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 "RuntimeSamplingProfile.h"

#include <memory>

namespace facebook::react::jsinspector_modern::tracing {

struct InstanceTracingProfile {
public:
explicit InstanceTracingProfile(
const RuntimeSamplingProfile runtimeSamplingProfile)
: runtimeSamplingProfile_(runtimeSamplingProfile) {}

const RuntimeSamplingProfile& getRuntimeSamplingProfile() const {
return runtimeSamplingProfile_;
}

private:
RuntimeSamplingProfile runtimeSamplingProfile_;
};

} // namespace facebook::react::jsinspector_modern::tracing
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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

namespace facebook::react::jsinspector_modern::tracing {

struct RuntimeSamplingProfile {};

} // namespace facebook::react::jsinspector_modern::tracing

0 comments on commit ecdecf0

Please sign in to comment.