From 989546f97ea2be3a5e2fda2a09804b8293241b19 Mon Sep 17 00:00:00 2001 From: Olivier Payen Date: Fri, 10 Jun 2022 12:52:34 -0700 Subject: [PATCH] Use monotonic clock for performance.now() (#33983) Summary: In https://github.com/facebook/react-native/pull/32695, the `Performance.now()` implementation changed to use unix epoch timestamps instead of a monotonic clock. This is problematic, because it means that performance measurements get skewed if the device clock changes between two measurements. With this change, the clock is now monotonic (and the implementation stays consistent between platforms). More details and repro steps can be found in [this issue](https://github.com/facebook/react-native/issues/33977) Closes https://github.com/facebook/react-native/issues/33977 ## Changelog [General] [Fixed] - Use monotonic clock for performance.now() Pull Request resolved: https://github.com/facebook/react-native/pull/33983 Test Plan: Run on iOS and Android: ``` const now = global.performance.now() console.log(`${Platform.OS}: ${now}`) ``` Reviewed By: JoshuaGross, cipolleschi Differential Revision: D37066999 Pulled By: dmitryrykun fbshipit-source-id: 298547bf39faea1b025c17ff2d2e1a03f929865b --- React/CxxBridge/RCTJSIExecutorRuntimeInstaller.mm | 10 ++++++++-- ReactAndroid/src/main/jni/react/jni/NativeTime.cpp | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/React/CxxBridge/RCTJSIExecutorRuntimeInstaller.mm b/React/CxxBridge/RCTJSIExecutorRuntimeInstaller.mm index f5c82368f31..da0f919a3f8 100644 --- a/React/CxxBridge/RCTJSIExecutorRuntimeInstaller.mm +++ b/React/CxxBridge/RCTJSIExecutorRuntimeInstaller.mm @@ -22,8 +22,14 @@ JSIExecutor::RuntimeInstaller RCTJSIExecutorRuntimeInstaller(JSIExecutor::Runtim bindNativeLogger(runtime, iosLoggingBinder); PerformanceNow iosPerformanceNowBinder = []() { - auto time = std::chrono::system_clock::now().time_since_epoch(); - return std::chrono::duration_cast(time).count(); + auto time = std::chrono::steady_clock::now(); + auto duration = std::chrono::duration_cast( + time.time_since_epoch()) + .count(); + + constexpr double NANOSECONDS_IN_MILLISECOND = 1000000.0; + + return duration / NANOSECONDS_IN_MILLISECOND; }; bindNativePerformanceNow(runtime, iosPerformanceNowBinder); diff --git a/ReactAndroid/src/main/jni/react/jni/NativeTime.cpp b/ReactAndroid/src/main/jni/react/jni/NativeTime.cpp index a338db11ee3..042805ff66d 100644 --- a/ReactAndroid/src/main/jni/react/jni/NativeTime.cpp +++ b/ReactAndroid/src/main/jni/react/jni/NativeTime.cpp @@ -12,8 +12,14 @@ namespace facebook { namespace react { double reactAndroidNativePerformanceNowHook() { - auto time = std::chrono::system_clock::now().time_since_epoch(); - return std::chrono::duration_cast(time).count(); + auto time = std::chrono::steady_clock::now(); + auto duration = std::chrono::duration_cast( + time.time_since_epoch()) + .count(); + + constexpr double NANOSECONDS_IN_MILLISECOND = 1000000.0; + + return duration / NANOSECONDS_IN_MILLISECOND; } } // namespace react