Skip to content

Replace RuntimeSchedulerClock with HighResTimeClock #51251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
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 @@ -15,6 +15,7 @@
#include <react/bridging/Error.h>
#include <react/bridging/EventEmitter.h>
#include <react/bridging/Function.h>
#include <react/bridging/HighResTimeStamp.h>
#include <react/bridging/Number.h>
#include <react/bridging/Object.h>
#include <react/bridging/Promise.h>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ add_library(react_bridging OBJECT ${react_bridging_SRC})

target_include_directories(react_bridging PUBLIC ${REACT_COMMON_DIR})

target_link_libraries(react_bridging jsi callinvoker)
target_link_libraries(react_bridging jsi callinvoker react_timing)
target_compile_reactnative_options(react_bridging PRIVATE "ReactNative")
target_compile_options(react_bridging PRIVATE -Wpedantic)
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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 <react/bridging/Base.h>
#include <react/timing/primitives.h>

namespace facebook::react {

template <>
struct Bridging<HighResTimeStamp> {
static HighResTimeStamp fromJs(
jsi::Runtime& /*rt*/,
const jsi::Value& jsiValue) {
return HighResTimeStamp::fromDOMHighResTimeStamp(jsiValue.asNumber());
}

static double toJs(jsi::Runtime& /*rt*/, const HighResTimeStamp& value) {
return value.toDOMHighResTimeStamp();
}
};

template <>
struct Bridging<HighResDuration> {
static HighResDuration fromJs(
jsi::Runtime& /*rt*/,
const jsi::Value& jsiValue) {
return HighResDuration::fromDOMHighResTimeStamp(jsiValue.asNumber());
}

static double toJs(jsi::Runtime& /*rt*/, const HighResDuration& value) {
return value.toDOMHighResTimeStamp();
}
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,13 @@ TEST_F(BridgingTest, supportTest) {
EXPECT_FALSE((bridging::supportsFromJs<jsi::Function, jsi::Array>));
EXPECT_FALSE((bridging::supportsFromJs<jsi::Function, jsi::Array&>));

// Ensure we can create HighResTimeStamp and HighResDuration from JSI
// values.
EXPECT_TRUE((bridging::supportsFromJs<HighResTimeStamp, jsi::Value>));
EXPECT_TRUE((bridging::supportsFromJs<HighResTimeStamp, jsi::Value&>));
EXPECT_TRUE((bridging::supportsFromJs<HighResDuration, jsi::Value>));
EXPECT_TRUE((bridging::supportsFromJs<HighResDuration, jsi::Value&>));

// Ensure we can convert some basic types to JSI values.
EXPECT_TRUE((bridging::supportsToJs<bool>));
EXPECT_TRUE((bridging::supportsToJs<int>));
Expand All @@ -677,6 +684,11 @@ TEST_F(BridgingTest, supportTest) {
EXPECT_FALSE((bridging::supportsToJs<double, jsi::Object>));
EXPECT_FALSE((bridging::supportsToJs<std::string, jsi::Object>));
EXPECT_FALSE((bridging::supportsToJs<std::vector<int>, jsi::Function>));

// Ensure we can convert HighResTimeStamp and HighResDuration to
// DOMHighResTimeStamp (double).
EXPECT_TRUE((bridging::supportsToJs<HighResTimeStamp, double>));
EXPECT_TRUE((bridging::supportsToJs<HighResDuration, double>));
}

TEST_F(BridgingTest, dynamicTest) {
Expand Down Expand Up @@ -765,4 +777,22 @@ TEST_F(BridgingTest, dynamicTest) {
EXPECT_TRUE(undefinedFromJsResult.isNull());
}

TEST_F(BridgingTest, highResTimeStampTest) {
HighResTimeStamp timestamp = HighResTimeStamp::now();
EXPECT_EQ(
timestamp,
bridging::fromJs<HighResTimeStamp>(
rt, bridging::toJs(rt, timestamp), invoker));

HighResDuration duration = HighResDuration::fromNanoseconds(1);
EXPECT_EQ(
duration,
bridging::fromJs<HighResDuration>(
rt, bridging::toJs(rt, duration), invoker));

EXPECT_EQ(1.0, bridging::toJs(rt, HighResDuration::fromNanoseconds(1e6)));
EXPECT_EQ(
1.000001, bridging::toJs(rt, HighResDuration::fromNanoseconds(1e6 + 1)));
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <react/renderer/runtimescheduler/RuntimeScheduler.h>
#include <react/renderer/runtimescheduler/RuntimeSchedulerBinding.h>
#include <react/renderer/runtimescheduler/Task.h>
#include <chrono>
#include <react/timing/primitives.h>
#include <utility>

#ifdef RN_DISABLE_OSS_PLUGIN_HEADER
Expand All @@ -36,7 +36,7 @@ class IdleTaskRef : public jsi::NativeState {
jsi::Function makeTimeRemainingFunction(
jsi::Runtime& runtime,
std::shared_ptr<RuntimeScheduler> runtimeScheduler,
RuntimeSchedulerTimePoint deadline) {
HighResTimeStamp deadline) {
return jsi::Function::createFromHostFunction(
runtime,
jsi::PropNameID::forAscii(runtime, "timeRemaining"),
Expand All @@ -55,13 +55,8 @@ jsi::Function makeTimeRemainingFunction(
expired = true;
} else {
auto now = runtimeScheduler->now();

remainingTime = std::max(
static_cast<double>(
std::chrono::duration_cast<std::chrono::milliseconds>(
deadline - now)
.count()),
0.0);
auto diff = deadline - now;
remainingTime = std::max(diff.toDOMHighResTimeStamp(), 0.0);

if (remainingTime == 0) {
expired = true;
Expand All @@ -86,15 +81,13 @@ CallbackHandle NativeIdleCallbacks::requestIdleCallback(
auto runtimeScheduler = binding->getRuntimeScheduler();

// handle timeout parameter
std::optional<RuntimeSchedulerTimeout> timeout;
std::optional<RuntimeSchedulerTimePoint> expirationTime;
std::optional<HighResDuration> timeout;
std::optional<HighResTimeStamp> expirationTime;

if (options.has_value() && options.value().timeout.has_value()) {
auto userTimeout = (options.value().timeout.value());
if (userTimeout > 0) {
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::duration<double, std::milli>(userTimeout));
expirationTime = runtimeScheduler->now() + timeout.value();
HighResDuration userTimeout = options.value().timeout.value();
if (userTimeout > HighResDuration::zero()) {
expirationTime = runtimeScheduler->now() + userTimeout;
}
}

Expand All @@ -110,7 +103,7 @@ CallbackHandle NativeIdleCallbacks::requestIdleCallback(
// we interrupt the current one. The general outcome should be the same.

auto executionStartTime = runtimeScheduler->now();
auto deadline = executionStartTime + std::chrono::milliseconds(50);
auto deadline = executionStartTime + HighResDuration::fromMilliseconds(50);
auto didTimeout = expirationTime.has_value()
? executionStartTime > expirationTime
: false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ namespace facebook::react {
using CallbackHandle = jsi::Object;

using NativeRequestIdleCallbackOptions =
NativeIdleCallbacksRequestIdleCallbackOptions<std::optional<double>>;
NativeIdleCallbacksRequestIdleCallbackOptions<
std::optional<HighResDuration>>;

template <>
struct Bridging<NativeRequestIdleCallbackOptions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include "RuntimeScheduler.h"
#include "RuntimeScheduler_Legacy.h"
#include "RuntimeScheduler_Modern.h"
#include "SchedulerPriorityUtils.h"

#include <cxxreact/ErrorUtils.h>
#include <cxxreact/TraceSection.h>
Expand All @@ -22,7 +21,7 @@ extern const char RuntimeSchedulerKey[] = "RuntimeScheduler";
namespace {
std::unique_ptr<RuntimeSchedulerBase> getRuntimeSchedulerImplementation(
RuntimeExecutor runtimeExecutor,
std::function<RuntimeSchedulerTimePoint()> now,
std::function<HighResTimeStamp()> now,
RuntimeSchedulerTaskErrorHandler onTaskError) {
if (ReactNativeFeatureFlags::enableBridgelessArchitecture()) {
return std::make_unique<RuntimeScheduler_Modern>(
Expand All @@ -37,7 +36,7 @@ std::unique_ptr<RuntimeSchedulerBase> getRuntimeSchedulerImplementation(

RuntimeScheduler::RuntimeScheduler(
RuntimeExecutor runtimeExecutor,
std::function<RuntimeSchedulerTimePoint()> now,
std::function<HighResTimeStamp()> now,
RuntimeSchedulerTaskErrorHandler onTaskError)
: runtimeSchedulerImpl_(getRuntimeSchedulerImplementation(
std::move(runtimeExecutor),
Expand Down Expand Up @@ -68,13 +67,13 @@ std::shared_ptr<Task> RuntimeScheduler::scheduleTask(

std::shared_ptr<Task> RuntimeScheduler::scheduleIdleTask(
jsi::Function&& callback,
RuntimeSchedulerTimeout timeout) noexcept {
HighResDuration timeout) noexcept {
return runtimeSchedulerImpl_->scheduleIdleTask(std::move(callback), timeout);
}

std::shared_ptr<Task> RuntimeScheduler::scheduleIdleTask(
RawCallback&& callback,
RuntimeSchedulerTimeout timeout) noexcept {
HighResDuration timeout) noexcept {
return runtimeSchedulerImpl_->scheduleIdleTask(std::move(callback), timeout);
}

Expand All @@ -90,7 +89,7 @@ SchedulerPriority RuntimeScheduler::getCurrentPriorityLevel() const noexcept {
return runtimeSchedulerImpl_->getCurrentPriorityLevel();
}

RuntimeSchedulerTimePoint RuntimeScheduler::now() const noexcept {
HighResTimeStamp RuntimeScheduler::now() const noexcept {
return runtimeSchedulerImpl_->now();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@
#include <ReactCommon/RuntimeExecutor.h>
#include <react/performance/timeline/PerformanceEntryReporter.h>
#include <react/renderer/consistency/ShadowTreeRevisionConsistencyManager.h>
#include <react/renderer/runtimescheduler/RuntimeSchedulerClock.h>
#include <react/renderer/runtimescheduler/SchedulerPriorityUtils.h>
#include <react/renderer/runtimescheduler/Task.h>
#include <react/timing/primitives.h>
#include "RuntimeSchedulerEventTimingDelegate.h"

namespace facebook::react {

using RuntimeSchedulerRenderingUpdate = std::function<void()>;
using RuntimeSchedulerTimeout = std::chrono::milliseconds;
using SurfaceId = int32_t;

using RuntimeSchedulerTaskErrorHandler =
Expand All @@ -41,16 +40,16 @@ class RuntimeSchedulerBase {
RawCallback&& callback) noexcept = 0;
virtual std::shared_ptr<Task> scheduleIdleTask(
jsi::Function&& callback,
RuntimeSchedulerTimeout timeout = timeoutForSchedulerPriority(
HighResDuration timeout = timeoutForSchedulerPriority(
SchedulerPriority::IdlePriority)) noexcept = 0;
virtual std::shared_ptr<Task> scheduleIdleTask(
RawCallback&& callback,
RuntimeSchedulerTimeout timeout = timeoutForSchedulerPriority(
HighResDuration timeout = timeoutForSchedulerPriority(
SchedulerPriority::IdlePriority)) noexcept = 0;
virtual void cancelTask(Task& task) noexcept = 0;
virtual bool getShouldYield() noexcept = 0;
virtual SchedulerPriority getCurrentPriorityLevel() const noexcept = 0;
virtual RuntimeSchedulerTimePoint now() const noexcept = 0;
virtual HighResTimeStamp now() const noexcept = 0;
virtual void callExpiredTasks(jsi::Runtime& runtime) = 0;
virtual void scheduleRenderingUpdate(
SurfaceId surfaceId,
Expand All @@ -69,8 +68,7 @@ class RuntimeScheduler final : RuntimeSchedulerBase {
public:
explicit RuntimeScheduler(
RuntimeExecutor runtimeExecutor,
std::function<RuntimeSchedulerTimePoint()> now =
RuntimeSchedulerClock::now,
std::function<HighResTimeStamp()> now = HighResTimeStamp::now,
RuntimeSchedulerTaskErrorHandler onTaskError = handleTaskErrorDefault);

/*
Expand Down Expand Up @@ -112,12 +110,12 @@ class RuntimeScheduler final : RuntimeSchedulerBase {

std::shared_ptr<Task> scheduleIdleTask(
jsi::Function&& callback,
RuntimeSchedulerTimeout timeout = timeoutForSchedulerPriority(
HighResDuration timeout = timeoutForSchedulerPriority(
SchedulerPriority::IdlePriority)) noexcept override;

std::shared_ptr<Task> scheduleIdleTask(
RawCallback&& callback,
RuntimeSchedulerTimeout timeout = timeoutForSchedulerPriority(
HighResDuration timeout = timeoutForSchedulerPriority(
SchedulerPriority::IdlePriority)) noexcept override;

/*
Expand Down Expand Up @@ -149,7 +147,7 @@ class RuntimeScheduler final : RuntimeSchedulerBase {
*
* Thread synchronization must be enforced externally.
*/
RuntimeSchedulerTimePoint now() const noexcept override;
HighResTimeStamp now() const noexcept override;

/*
* Expired task is a task that should have been already executed. Designed to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

#include "RuntimeSchedulerBinding.h"
#include <ReactCommon/SchedulerPriority.h>
#include <react/timing/primitives.h>
#include "RuntimeScheduler.h"
#include "SchedulerPriorityUtils.h"
#include "primitives.h"

#include <chrono>
#include <memory>
#include <utility>

Expand Down Expand Up @@ -144,10 +144,8 @@ jsi::Value RuntimeSchedulerBinding::get(
const jsi::Value*,
size_t) noexcept -> jsi::Value {
auto now = runtimeScheduler_->now();
auto asDouble =
std::chrono::duration<double, std::milli>(now.time_since_epoch())
.count();
return {asDouble};
auto domHighResTimeStamp = now.toDOMHighResTimeStamp();
return {domHighResTimeStamp};
});
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace facebook::react {

RuntimeScheduler_Legacy::RuntimeScheduler_Legacy(
RuntimeExecutor runtimeExecutor,
std::function<RuntimeSchedulerTimePoint()> now,
std::function<HighResTimeStamp()> now,
RuntimeSchedulerTaskErrorHandler onTaskError)
: runtimeExecutor_(std::move(runtimeExecutor)),
now_(std::move(now)),
Expand Down Expand Up @@ -84,7 +84,7 @@ std::shared_ptr<Task> RuntimeScheduler_Legacy::scheduleTask(

std::shared_ptr<Task> RuntimeScheduler_Legacy::scheduleIdleTask(
jsi::Function&& /*callback*/,
RuntimeSchedulerTimeout /*timeout*/) noexcept {
HighResDuration /*timeout*/) noexcept {
// Idle tasks are not supported on Legacy RuntimeScheduler.
// Because the method is `noexcept`, we return `nullptr` here and handle it
// on the caller side.
Expand All @@ -93,7 +93,7 @@ std::shared_ptr<Task> RuntimeScheduler_Legacy::scheduleIdleTask(

std::shared_ptr<Task> RuntimeScheduler_Legacy::scheduleIdleTask(
RawCallback&& /*callback*/,
RuntimeSchedulerTimeout /*timeout*/) noexcept {
HighResDuration /*timeout*/) noexcept {
// Idle tasks are not supported on Legacy RuntimeScheduler.
// Because the method is `noexcept`, we return `nullptr` here and handle it
// on the caller side.
Expand All @@ -113,7 +113,7 @@ SchedulerPriority RuntimeScheduler_Legacy::getCurrentPriorityLevel()
return currentPriority_;
}

RuntimeSchedulerTimePoint RuntimeScheduler_Legacy::now() const noexcept {
HighResTimeStamp RuntimeScheduler_Legacy::now() const noexcept {
return now_();
}

Expand Down
Loading
Loading