Skip to content

Commit 6aa99ad

Browse files
rubennortemeta-codesync[bot]
authored andcommitted
Use mach_absolute_time for HighResTimeStamp on Apple platforms (facebook#55977)
Summary: Pull Request resolved: facebook#55977 Changelog: [internal] On iOS/macOS, `std::chrono::steady_clock` uses `mach_continuous_time()` which includes device sleep time. This causes compatibility issues with iOS system APIs like `UITouch.timestamp` and `NSProcessInfo.processInfo.systemUptime` which use `mach_absolute_time()` (excludes sleep time). This diff modifies `HighResTimeStamp` to use `mach_absolute_time()` directly on Apple platforms, ensuring timestamps are compatible with iOS system APIs and native performance logging systems. Changes: - Added `mach_absolute_time()` based clock for Apple platforms in `primitives.h` - Simplified `RCTHighResTimeStampFromSeconds()` since iOS timestamps now share the same clock domain - Updated documentation to explain platform-specific clock behavior Reviewed By: hoxyq Differential Revision: D95554947 fbshipit-source-id: 322331867b9ed36260bb8f35b8bbca2f4937a0ed
1 parent 41a1941 commit 6aa99ad

File tree

3 files changed

+54
-10
lines changed

3 files changed

+54
-10
lines changed

packages/react-native/React/Fabric/RCTConversions.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,13 @@ NS_ASSUME_NONNULL_BEGIN
2121
* Converts an iOS timestamp (seconds since boot, NOT including sleep time, from
2222
* NSProcessInfo.processInfo.systemUptime or UITouch.timestamp) to a HighResTimeStamp.
2323
*
24-
* iOS timestamps use mach_absolute_time() which doesn't account for sleep time,
25-
* while std::chrono::steady_clock uses mach_continuous_time() which does.
26-
* To handle this correctly, we compute the relative offset from the current time
27-
* and apply it to HighResTimeStamp::now().
24+
* iOS timestamps and HighResTimeStamp both use mach_absolute_time() which doesn't
25+
* account for sleep time. We convert the timestamp directly since they share the
26+
* same time domain.
2827
*/
2928
inline facebook::react::HighResTimeStamp RCTHighResTimeStampFromSeconds(NSTimeInterval seconds)
3029
{
31-
NSTimeInterval nowSystemUptime = NSProcessInfo.processInfo.systemUptime;
32-
NSTimeInterval delta = nowSystemUptime - seconds;
33-
auto deltaDuration =
34-
std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double>(delta));
35-
return facebook::react::HighResTimeStamp::now() - facebook::react::HighResDuration::fromChrono(deltaDuration);
30+
return facebook::react::HighResTimeStamp::fromDOMHighResTimeStamp(seconds * 1e3);
3631
}
3732

3833
inline NSString *RCTNSStringFromString(

packages/react-native/ReactCommon/react/timing/__docs__/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,23 @@ C++'s type system and the performance characteristics of native code. The
5252
implementation uses `std::chrono` internally but provides a more specialized
5353
interface tailored to React Native's needs.
5454

55+
### Platform-Specific Clock Sources
56+
57+
On different platforms, `HighResTimeStamp` uses different underlying clock
58+
sources to ensure compatibility with platform-specific timing APIs:
59+
60+
- **iOS/macOS**: Uses `mach_absolute_time()`, which measures time since device
61+
boot and **excludes sleep time**. This ensures compatibility with iOS system
62+
APIs (like `UITouch.timestamp` and `NSProcessInfo.processInfo.systemUptime`)
63+
and native performance logging systems that use the same clock source.
64+
65+
- **Other platforms**: Uses `std::chrono::steady_clock`, which provides a
66+
monotonic clock that may include or exclude sleep time depending on the
67+
platform.
68+
69+
This design ensures that timestamps recorded in JavaScript and passed to native
70+
systems will have correct timing on all platforms.
71+
5572
### HighResTimeStamp
5673

5774
This class represents a specific point in time with high precision. It

packages/react-native/ReactCommon/react/timing/primitives.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
#include <chrono>
1212
#include <functional>
1313

14+
#ifdef __APPLE__
15+
#include <mach/mach_time.h>
16+
#endif
17+
1418
namespace facebook::react {
1519

1620
class HighResDuration;
@@ -312,6 +316,23 @@ class HighResTimeStamp {
312316
return HighResDuration(systemNow.time_since_epoch() - steadyNow.time_since_epoch());
313317
}
314318

319+
#ifdef __APPLE__
320+
static double getMachTimebaseConversionFactor()
321+
{
322+
mach_timebase_info_data_t info;
323+
mach_timebase_info(&info);
324+
return static_cast<double>(info.numer) / info.denom;
325+
}
326+
327+
static std::chrono::steady_clock::time_point machAbsoluteTimeToSteadyClockTimePoint()
328+
{
329+
static double conversionFactor = getMachTimebaseConversionFactor();
330+
uint64_t machTime = mach_absolute_time();
331+
auto nanoseconds = static_cast<int64_t>(static_cast<double>(machTime) * conversionFactor);
332+
return std::chrono::steady_clock::time_point(std::chrono::nanoseconds(nanoseconds));
333+
}
334+
#endif
335+
315336
#ifdef REACT_NATIVE_DEBUG
316337
static std::function<std::chrono::steady_clock::time_point()> &getTimeStampProvider()
317338
{
@@ -322,12 +343,23 @@ class HighResTimeStamp {
322343
static std::chrono::steady_clock::time_point chronoNow()
323344
{
324345
auto &timeStampProvider = getTimeStampProvider();
325-
return timeStampProvider != nullptr ? timeStampProvider() : std::chrono::steady_clock::now();
346+
if (timeStampProvider != nullptr) {
347+
return timeStampProvider();
348+
}
349+
#ifdef __APPLE__
350+
return machAbsoluteTimeToSteadyClockTimePoint();
351+
#else
352+
return std::chrono::steady_clock::now();
353+
#endif
326354
}
327355
#else
328356
inline static std::chrono::steady_clock::time_point chronoNow()
329357
{
358+
#ifdef __APPLE__
359+
return machAbsoluteTimeToSteadyClockTimePoint();
360+
#else
330361
return std::chrono::steady_clock::now();
362+
#endif
331363
}
332364
#endif
333365
};

0 commit comments

Comments
 (0)