Improve profiling information for timers (#45091)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/45091

Changelog: [internal]

We're currently logging when we execute timers in Systrace/Perfetto, but we have no information about them whatsoever.

This adds some additional information:
  * What kind of timer it is
  * It's ID
  * And most importantly, when it was created (including the ID as well).

This allows us to know where was a specific timer scheduled and with what API.

Reviewed By: bgirard

Differential Revision: D58832112

fbshipit-source-id: 1bc11759b6c8296acf63ff3533ca1dc3428360a7
This commit is contained in:
Rubén Norte
2024-06-21 05:13:20 -07:00
committed by Facebook GitHub Bot
parent fdf0183831
commit a8a76f9bfa
2 changed files with 83 additions and 14 deletions
@@ -13,6 +13,21 @@
namespace facebook::react {
namespace {
inline const char* getTimerSourceName(TimerSource source) {
switch (source) {
case TimerSource::Unknown:
return "unknown";
case TimerSource::SetTimeout:
return "setTimeout";
case TimerSource::SetInterval:
return "setInterval";
case TimerSource::RequestAnimationFrame:
return "requestAnimationFrame";
}
}
} // namespace
TimerManager::TimerManager(
std::unique_ptr<PlatformTimerRegistry> platformTimerRegistry) noexcept
: platformTimerRegistry_(std::move(platformTimerRegistry)) {}
@@ -60,14 +75,28 @@ void TimerManager::callReactNativeMicrotasks(jsi::Runtime& runtime) {
TimerHandle TimerManager::createTimer(
jsi::Function&& callback,
std::vector<jsi::Value>&& args,
double delay) {
double delay,
TimerSource source) {
// Get the id for the callback.
TimerHandle timerID = timerIndex_++;
SystraceSection s(
"TimerManager::createTimer",
"id",
timerID,
"type",
getTimerSourceName(source),
"delay",
delay);
timers_.emplace(
std::piecewise_construct,
std::forward_as_tuple(timerID),
std::forward_as_tuple(
std::move(callback), std::move(args), /* repeat */ false));
std::move(callback),
std::move(args),
/* repeat */ false,
source));
platformTimerRegistry_->createTimer(timerID, delay);
@@ -77,14 +106,25 @@ TimerHandle TimerManager::createTimer(
TimerHandle TimerManager::createRecurringTimer(
jsi::Function&& callback,
std::vector<jsi::Value>&& args,
double delay) {
double delay,
TimerSource source) {
// Get the id for the callback.
TimerHandle timerID = timerIndex_++;
SystraceSection s(
"TimerManager::createRecurringTimer",
"id",
timerID,
"type",
getTimerSourceName(source),
"delay",
delay);
timers_.emplace(
std::piecewise_construct,
std::forward_as_tuple(timerID),
std::forward_as_tuple(
std::move(callback), std::move(args), /* repeat */ true));
std::move(callback), std::move(args), /* repeat */ true, source));
platformTimerRegistry_->createRecurringTimer(timerID, delay);
@@ -131,11 +171,20 @@ void TimerManager::deleteRecurringTimer(
void TimerManager::callTimer(TimerHandle timerHandle) {
runtimeExecutor_([this, timerHandle](jsi::Runtime& runtime) {
SystraceSection s("TimerManager::callTimer");
auto it = timers_.find(timerHandle);
if (it != timers_.end()) {
bool repeats = it->second.repeat;
it->second.invoke(runtime);
auto& timerCallback = it->second;
bool repeats = timerCallback.repeat;
{
SystraceSection s(
"TimerManager::callTimer",
"id",
timerHandle,
"type",
getTimerSourceName(timerCallback.source));
timerCallback.invoke(runtime);
}
if (!repeats) {
// Invoking a timer has the potential to delete it. Do not re-use the
@@ -246,7 +295,11 @@ void TimerManager::attachGlobals(jsi::Runtime& runtime) {
moreArgs.emplace_back(rt, args[extraArgNum]);
}
return createTimer(std::move(callback), std::move(moreArgs), delay);
return createTimer(
std::move(callback),
std::move(moreArgs),
delay,
TimerSource::SetTimeout);
}));
runtime.global().setProperty(
@@ -301,7 +354,10 @@ void TimerManager::attachGlobals(jsi::Runtime& runtime) {
}
return createRecurringTimer(
std::move(callback), std::move(moreArgs), delay);
std::move(callback),
std::move(moreArgs),
delay,
TimerSource::SetInterval);
}));
runtime.global().setProperty(
@@ -370,7 +426,8 @@ void TimerManager::attachGlobals(jsi::Runtime& runtime) {
return createTimer(
std::move(callback),
std::vector<jsi::Value>(),
/* delay */ 0);
/* delay */ 0,
TimerSource::RequestAnimationFrame);
}));
runtime.global().setProperty(
@@ -18,6 +18,13 @@ namespace facebook::react {
using TimerHandle = int;
enum class TimerSource {
Unknown,
SetTimeout,
SetInterval,
RequestAnimationFrame
};
/*
* Wraps a jsi::Function to make it copyable so we can pass it into a lambda.
*/
@@ -25,10 +32,12 @@ struct TimerCallback {
TimerCallback(
jsi::Function callback,
std::vector<jsi::Value> args,
bool repeat)
bool repeat,
TimerSource source = TimerSource::Unknown)
: callback_(std::move(callback)),
args_(std::move(args)),
repeat(repeat) {}
repeat(repeat),
source(source) {}
void invoke(jsi::Runtime& runtime) {
callback_.call(runtime, args_.data(), args_.size());
@@ -37,6 +46,7 @@ struct TimerCallback {
jsi::Function callback_;
const std::vector<jsi::Value> args_;
bool repeat;
TimerSource source;
};
class TimerManager {
@@ -62,14 +72,16 @@ class TimerManager {
TimerHandle createTimer(
jsi::Function&& callback,
std::vector<jsi::Value>&& args,
double delay);
double delay,
TimerSource source = TimerSource::Unknown);
void deleteTimer(jsi::Runtime& runtime, TimerHandle handle);
TimerHandle createRecurringTimer(
jsi::Function&& callback,
std::vector<jsi::Value>&& args,
double delay);
double delay,
TimerSource source = TimerSource::Unknown);
void deleteRecurringTimer(jsi::Runtime& runtime, TimerHandle handle);