Skip to content
Closed
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
13 changes: 4 additions & 9 deletions packages/react-native/React/Fabric/RCTConversions.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,13 @@ NS_ASSUME_NONNULL_BEGIN
* Converts an iOS timestamp (seconds since boot, NOT including sleep time, from
* NSProcessInfo.processInfo.systemUptime or UITouch.timestamp) to a HighResTimeStamp.
*
* iOS timestamps use mach_absolute_time() which doesn't account for sleep time,
* while std::chrono::steady_clock uses mach_continuous_time() which does.
* To handle this correctly, we compute the relative offset from the current time
* and apply it to HighResTimeStamp::now().
* iOS timestamps and HighResTimeStamp both use mach_absolute_time() which doesn't
* account for sleep time. We convert the timestamp directly since they share the
* same time domain.
*/
inline facebook::react::HighResTimeStamp RCTHighResTimeStampFromSeconds(NSTimeInterval seconds)
{
NSTimeInterval nowSystemUptime = NSProcessInfo.processInfo.systemUptime;
NSTimeInterval delta = nowSystemUptime - seconds;
auto deltaDuration =
std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double>(delta));
return facebook::react::HighResTimeStamp::now() - facebook::react::HighResDuration::fromChrono(deltaDuration);
return facebook::react::HighResTimeStamp::fromDOMHighResTimeStamp(seconds * 1e3);
}

inline NSString *RCTNSStringFromString(
Expand Down
17 changes: 17 additions & 0 deletions packages/react-native/ReactCommon/react/timing/__docs__/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,23 @@ C++'s type system and the performance characteristics of native code. The
implementation uses `std::chrono` internally but provides a more specialized
interface tailored to React Native's needs.

### Platform-Specific Clock Sources

On different platforms, `HighResTimeStamp` uses different underlying clock
sources to ensure compatibility with platform-specific timing APIs:

- **iOS/macOS**: Uses `mach_absolute_time()`, which measures time since device
boot and **excludes sleep time**. This ensures compatibility with iOS system
APIs (like `UITouch.timestamp` and `NSProcessInfo.processInfo.systemUptime`)
and native performance logging systems that use the same clock source.

- **Other platforms**: Uses `std::chrono::steady_clock`, which provides a
monotonic clock that may include or exclude sleep time depending on the
platform.

This design ensures that timestamps recorded in JavaScript and passed to native
systems will have correct timing on all platforms.

### HighResTimeStamp

This class represents a specific point in time with high precision. It
Expand Down
34 changes: 33 additions & 1 deletion packages/react-native/ReactCommon/react/timing/primitives.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
#include <chrono>
#include <functional>

#ifdef __APPLE__
#include <mach/mach_time.h>
#endif

namespace facebook::react {

class HighResDuration;
Expand Down Expand Up @@ -312,6 +316,23 @@ class HighResTimeStamp {
return HighResDuration(systemNow.time_since_epoch() - steadyNow.time_since_epoch());
}

#ifdef __APPLE__
static double getMachTimebaseConversionFactor()
{
mach_timebase_info_data_t info;
mach_timebase_info(&info);
return static_cast<double>(info.numer) / info.denom;
}

static std::chrono::steady_clock::time_point machAbsoluteTimeToSteadyClockTimePoint()
{
static double conversionFactor = getMachTimebaseConversionFactor();
uint64_t machTime = mach_absolute_time();
auto nanoseconds = static_cast<int64_t>(static_cast<double>(machTime) * conversionFactor);
return std::chrono::steady_clock::time_point(std::chrono::nanoseconds(nanoseconds));
}
#endif

#ifdef REACT_NATIVE_DEBUG
static std::function<std::chrono::steady_clock::time_point()> &getTimeStampProvider()
{
Expand All @@ -322,12 +343,23 @@ class HighResTimeStamp {
static std::chrono::steady_clock::time_point chronoNow()
{
auto &timeStampProvider = getTimeStampProvider();
return timeStampProvider != nullptr ? timeStampProvider() : std::chrono::steady_clock::now();
if (timeStampProvider != nullptr) {
return timeStampProvider();
}
#ifdef __APPLE__
return machAbsoluteTimeToSteadyClockTimePoint();
#else
return std::chrono::steady_clock::now();
#endif
}
#else
inline static std::chrono::steady_clock::time_point chronoNow()
{
#ifdef __APPLE__
return machAbsoluteTimeToSteadyClockTimePoint();
#else
return std::chrono::steady_clock::now();
#endif
}
#endif
};
Expand Down
Loading