Skip to content

Commit

Permalink
Improve profiling information for timers (facebook#45091)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: facebook#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.

Differential Revision: D58832112
  • Loading branch information
rubennorte authored and facebook-github-bot committed Jun 20, 2024
1 parent 3797fa3 commit a0df93c
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 14 deletions.
77 changes: 67 additions & 10 deletions packages/react-native/ReactCommon/react/runtime/TimerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {}
Expand Down Expand Up @@ -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);

Expand All @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down
21 changes: 17 additions & 4 deletions packages/react-native/ReactCommon/react/runtime/TimerManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <ReactCommon/RuntimeExecutor.h>
#include <cstdint>
#include <optional>
#include <unordered_map>
#include <vector>

Expand All @@ -18,17 +19,26 @@ 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.
*/
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());
Expand All @@ -37,6 +47,7 @@ struct TimerCallback {
jsi::Function callback_;
const std::vector<jsi::Value> args_;
bool repeat;
TimerSource source;
};

class TimerManager {
Expand All @@ -62,14 +73,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);

Expand Down

0 comments on commit a0df93c

Please sign in to comment.