Skip to content
Open
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 @@ -186,6 +186,11 @@ InstanceTarget& HostTarget::registerInstance(InstanceTargetDelegate& delegate) {
assert(!currentInstance_ && "Only one instance allowed");
currentInstance_ = InstanceTarget::create(
executionContextManager_, delegate, makeVoidExecutor(executorFromThis()));

if (isTracing_) {
startTracingInstanceTarget(currentInstance_.get());
}

sessions_.forEach(
[currentInstance = &*currentInstance_](HostTargetSession& session) {
session.setCurrentInstance(currentInstance);
Expand All @@ -197,6 +202,11 @@ void HostTarget::unregisterInstance(InstanceTarget& instance) {
assert(
currentInstance_ && currentInstance_.get() == &instance &&
"Invalid unregistration");

if (isTracing_) {
stopTracingInstanceTarget(&instance);
}

sessions_.forEach(
[](HostTargetSession& session) { session.setCurrentInstance(nullptr); });
currentInstance_.reset();
Expand Down
61 changes: 61 additions & 0 deletions packages/react-native/ReactCommon/jsinspector-modern/HostTarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "ScopedExecutor.h"
#include "WeakList.h"

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

#include <optional>
#include <string>

Expand Down Expand Up @@ -166,6 +168,21 @@ class HostTargetController final {
*/
bool decrementPauseOverlayCounter();

/**
* Start tracing the corresponding HostTarget. Can throw, if already tracing.
*/
void startTracing();

/**
* Stop tracing the corresponding HostTarget. Can throw, if wasn't tracing.
*/
void stopTracing();

/**
* Returns the full tracing profile for the last tracing session.
*/
tracing::HostTargetTracingProfile collectTracingProfile();

private:
HostTarget& target_;
size_t pauseOverlayCounter_{0};
Expand Down Expand Up @@ -237,6 +254,21 @@ class JSINSPECTOR_EXPORT HostTarget
*/
void sendCommand(HostCommand command);

/**
* Start tracing this HostTarget. Can throw, if already tracing.
*/
void startTracing();

/**
* Stop tracing this HostTarget. Can throw, if wasn't tracing.
*/
void stopTracing();

/**
* Returns the full tracing profile for the last tracing session.
*/
tracing::HostTargetTracingProfile collectTracingProfile();

private:
/**
* Constructs a new HostTarget.
Expand Down Expand Up @@ -265,6 +297,35 @@ class JSINSPECTOR_EXPORT HostTarget
return currentInstance_ != nullptr;
}

/**
* Whether this HostTarget is currently being traced.
* Keeping a local state is necessary to start tracing InstanceTarget right
* after its reinitialization.
*/
bool isTracing_{false};

/**
* A container for tracing profiles of all InstanceTargets that were
* registered during this tracing session.
*/
std::vector<tracing::InstanceTargetTracingProfile>
storedInstanceTargetTracingProfiles_;

/**
* Start tracing already registered InstanceTarget, or the one that is about
* to be registered, in case of reinitialization.
*/
void startTracingInstanceTarget(InstanceTarget* instanceTarget);

/**
* Stop tracing already registered InstanceTarget, of the one that is about to
* be unregistered, in case of reinitialization.
*
* Collects the tracing profile and stores it in
* \c storedInstanceTargetTracingProfiles_.
*/
void stopTracingInstanceTarget(InstanceTarget* instanceTarget);

// Necessary to allow HostAgent to access HostTarget's internals in a
// controlled way (i.e. only HostTargetController gets friend access, while
// HostAgent itself doesn't).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* 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.
*/

#include "HostTarget.h"

namespace facebook::react::jsinspector_modern {

void HostTargetController::startTracing() {
return target_.startTracing();
}

void HostTargetController::stopTracing() {
return target_.stopTracing();
}

tracing::HostTargetTracingProfile
HostTargetController::collectTracingProfile() {
return target_.collectTracingProfile();
}

void HostTarget::startTracing() {
if (isTracing_) {
throw std::runtime_error(
"HostTarget already has a pending tracing session.");
}

isTracing_ = true;
/**
* In case if \c HostTarget::collectTracingProfile was never called.
*/
storedInstanceTargetTracingProfiles_.clear();

if (currentInstance_) {
return startTracingInstanceTarget(currentInstance_.get());
}
}

void HostTarget::stopTracing() {
if (!isTracing_) {
throw std::runtime_error("HostTarget has no pending tracing session.");
}

isTracing_ = false;
if (currentInstance_) {
return stopTracingInstanceTarget(currentInstance_.get());
}
}

tracing::HostTargetTracingProfile HostTarget::collectTracingProfile() {
if (isTracing_) {
throw std::runtime_error(
"Attempted to collect HostTargetTracingProfile before stopping the tracing session.");
}

auto profiles = std::move(storedInstanceTargetTracingProfiles_);
storedInstanceTargetTracingProfiles_.clear();

return tracing::HostTargetTracingProfile{std::move(profiles)};
}

void HostTarget::startTracingInstanceTarget(InstanceTarget* instanceTarget) {
assert(
instanceTarget != nullptr &&
"Attempted to start tracing a null InstanceTarget");
return instanceTarget->startTracing();
}

void HostTarget::stopTracingInstanceTarget(InstanceTarget* instanceTarget) {
assert(
instanceTarget != nullptr &&
"Attempted to stop tracing a null InstanceTarget");

instanceTarget->stopTracing();
storedInstanceTargetTracingProfiles_.emplace_back(
instanceTarget->collectTracingProfile());
}

} // namespace facebook::react::jsinspector_modern
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,25 @@ RuntimeTarget& InstanceTarget::registerRuntime(
jsExecutor,
makeVoidExecutor(executorFromThis()));

if (isTracing_) {
startTracingRuntimeTarget(currentRuntime_.get());
}

agents_.forEach([currentRuntime = &*currentRuntime_](InstanceAgent& agent) {
agent.setCurrentRuntime(currentRuntime);
});
return *currentRuntime_;
}

void InstanceTarget::unregisterRuntime(RuntimeTarget& Runtime) {
void InstanceTarget::unregisterRuntime(RuntimeTarget& runtimeTarget) {
assert(
currentRuntime_ && currentRuntime_.get() == &Runtime &&
currentRuntime_ && currentRuntime_.get() == &runtimeTarget &&
"Invalid unregistration");

if (isTracing_) {
stopTracingRuntimeTarget(&runtimeTarget);
}

agents_.forEach(
[](InstanceAgent& agent) { agent.setCurrentRuntime(nullptr); });
currentRuntime_.reset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

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

#include <memory>

Expand Down Expand Up @@ -86,6 +87,21 @@ class InstanceTarget : public EnableExecutorFromThis<InstanceTarget> {
*/
void unregisterRuntime(RuntimeTarget& runtime);

/**
* Start tracing this InstanceTarget. Can throw, if already tracing.
*/
void startTracing();

/**
* Stop tracing this InstanceTarget. Can throw, if wasn't tracing.
*/
void stopTracing();

/**
* Returns the full tracing profile for the last tracing session.
*/
tracing::InstanceTargetTracingProfile collectTracingProfile();

private:
/**
* Constructs a new InstanceTarget. The caller must call setExecutor
Expand All @@ -103,6 +119,35 @@ class InstanceTarget : public EnableExecutorFromThis<InstanceTarget> {
std::shared_ptr<RuntimeTarget> currentRuntime_{nullptr};
WeakList<InstanceAgent> agents_;
std::shared_ptr<ExecutionContextManager> executionContextManager_;

/**
* Whether this InstanceTarget is currently being traced.
* Keeping a local state is necessary to start tracing RuntimeTarget right
* after its reinitialization.
*/
bool isTracing_{false};

/**
* A container for tracing profiles of all RuntimeTargets that were
* registered during this tracing session.
*/
std::vector<tracing::RuntimeSamplingProfile>
storedRuntimeTargetSamplingProfiles_;

/**
* Start tracing already registered RuntimeTarget, or the one that is about
* to be registered, in case of reinitialization.
*/
void startTracingRuntimeTarget(RuntimeTarget* runtimeTarget);

/**
* Stop tracing already registered RuntimeTarget, of the one that is about to
* be unregistered, in case of reinitialization.
*
* Collects the tracing profile and stores it in
* \c storedRuntimeTargetSamplingProfiles_.
*/
void stopTracingRuntimeTarget(RuntimeTarget* runtimeTarget);
};

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

#include "InstanceTarget.h"

namespace facebook::react::jsinspector_modern {

void InstanceTarget::startTracing() {
if (isTracing_) {
throw std::runtime_error(
"HostTarget already has a pending tracing session.");
}

isTracing_ = true;
/**
* In case if \c InstanceTarget::collectTracingProfile was never called.
*/
storedRuntimeTargetSamplingProfiles_.clear();

if (currentRuntime_) {
return startTracingRuntimeTarget(currentRuntime_.get());
}
}

void InstanceTarget::stopTracing() {
if (!isTracing_) {
throw std::runtime_error("HostTarget has no pending tracing session.");
}

isTracing_ = false;
if (currentRuntime_) {
return stopTracingRuntimeTarget(currentRuntime_.get());
}
}

tracing::InstanceTargetTracingProfile InstanceTarget::collectTracingProfile() {
if (isTracing_) {
throw std::runtime_error(
"Attempted to collect InstanceTargetTracingProfile before stopping the tracing session.");
}

auto profiles = std::move(storedRuntimeTargetSamplingProfiles_);
storedRuntimeTargetSamplingProfiles_.clear();

return tracing::InstanceTargetTracingProfile{std::move(profiles)};
}

void InstanceTarget::startTracingRuntimeTarget(RuntimeTarget* runtimeTarget) {
assert(
runtimeTarget != nullptr &&
"Attempted to start tracing a null RuntimeTarget");

runtimeTarget->registerForTracing();
return runtimeTarget->enableSamplingProfiler();
}

void InstanceTarget::stopTracingRuntimeTarget(RuntimeTarget* runtimeTarget) {
assert(
runtimeTarget != nullptr &&
"Attempted to stop tracing a null RuntimeTarget");

runtimeTarget->disableSamplingProfiler();
storedRuntimeTargetSamplingProfiles_.emplace_back(
runtimeTarget->collectSamplingProfile());
}

} // namespace facebook::react::jsinspector_modern
Loading
Loading