Skip to content

Commit bcda99d

Browse files
hoxyqfacebook-github-bot
authored andcommitted
Define HighResTimeStamp, HighResDuration (#51254)
Summary: Pull Request resolved: #51254 # Changelog: [Internal] Defines single timestamp abstraction that will be used in C++ layer of React Native core: Key primitives include: - `HighResTimeStamp`: A class representing a specific point in time with high precision. - `HighResDuration`: A class representing a duration of time with high precision. Right now, all these just encapsulate `std::chrono::steady_clock` with no extra custom logic. We might revisit this in a future, once we decide to add support for [`Performance.timeOrigin`](https://developer.mozilla.org/en-US/docs/Web/API/Performance/timeOrigin). This diff also adds a `README.md` documentation file with a brief summary of the `react/timing` module. Reviewed By: rubennorte Differential Revision: D72796412
1 parent bf26cf9 commit bcda99d

File tree

3 files changed

+444
-0
lines changed

3 files changed

+444
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# React Native Timing
2+
3+
[🏠 Home](../../../../../../__docs__/README.md)
4+
5+
This directory contains the shared C++ implementation of high-resolution timing
6+
primitives for React Native. These primitives provide precise time measurement
7+
capabilities that align with Web standards while being optimized for the React
8+
Native environment.
9+
10+
## 🚀 Usage
11+
12+
The timing primitives in this module are primarily used by internal React Native
13+
systems that require precise time measurements. The monotonic clock is used for
14+
these primitives: they should be used for measuring time intervals. These
15+
primitives should not be used for wall times. They are not expected to be used
16+
directly by application developers but serve as foundational components for
17+
various React Native features.
18+
19+
Key primitives include:
20+
21+
- `HighResTimeStamp`: A class representing a specific point in time with high
22+
precision.
23+
- `HighResDuration`: A class representing a duration of time with high
24+
precision.
25+
26+
These primitives support various operations:
27+
28+
```cpp
29+
// Getting the current high-resolution timestamp
30+
auto start = HighResTimeStamp::now();
31+
32+
// Creating durations
33+
auto duration = HighResDuration::fromNanoseconds(100);
34+
auto durationMs = HighResDuration::fromMilliseconds(100);
35+
36+
// Arithmetic operations
37+
auto later = start + duration;
38+
auto elapsed = later - start;
39+
40+
// Converting to absolute time units of highest precision
41+
auto end = HighResTimeStamp::now();
42+
int64_t nanoseconds = (end - start).toNanoseconds();
43+
44+
// Converting to DOMHighResTimeStamp (for JavaScript interoperability)
45+
double jsTimeValue = now.toDOMHighResTimeStamp();
46+
```
47+
48+
## 📐 Design
49+
50+
The timing primitives are designed to align with Web standards while leveraging
51+
C++'s type system and the performance characteristics of native code. The
52+
implementation uses `std::chrono` internally but provides a more specialized
53+
interface tailored to React Native's needs.
54+
55+
### HighResTimeStamp
56+
57+
This class represents a specific point in time with high precision. It
58+
encapsulates a `std::chrono::steady_clock::time_point` and provides methods to:
59+
60+
- Convert to `DOMHighResTimeStamp` for JavaScript interoperability.
61+
- Perform arithmetic operations with durations.
62+
- Compare with other timestamps.
63+
64+
### HighResDuration
65+
66+
This class represents a duration of time with high precision. It encapsulates a
67+
`std::chrono::duration` and provides methods to:
68+
69+
- Convert to `DOMHighResTimeStamp` for JavaScript interoperability.
70+
- Convert to an absolute number of nanoseconds.
71+
- Perform arithmetic operations.
72+
- Compare with other durations.
73+
74+
## 🔗 Relationship with other systems
75+
76+
### Used by
77+
78+
- [Event Loop](../../renderer/runtimescheduler/__docs__/README.md): Uses timing
79+
primitives for measuring task execution times and scheduling.
80+
- Web Performance API: Timing primitives are used to implement performance
81+
measurement APIs like `PerformanceObserver` entries (e.g., `longtask` and
82+
`event`).
83+
- React Native DevTools: The timing primitives integrate with the React Native
84+
DevTools tracing infrastructure to report the timing of tasks and events.
85+
86+
### Related to
87+
88+
- Web timing APIs: The timing primitives are designed to be compatible with Web
89+
timing concepts, making it easier to implement Web-compatible APIs in React
90+
Native.

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

+270
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,274 @@ inline DOMHighResTimeStamp chronoToDOMHighResTimeStamp(
3030
return chronoToDOMHighResTimeStamp(timePoint.time_since_epoch());
3131
}
3232

33+
class HighResDuration;
34+
class HighResTimeStamp;
35+
36+
/*
37+
* A class representing a duration of time with high precision.
38+
*
39+
* @see __docs__/README.md for more information.
40+
*/
41+
class HighResDuration {
42+
friend class HighResTimeStamp;
43+
friend constexpr HighResDuration operator-(
44+
const HighResTimeStamp& lhs,
45+
const HighResTimeStamp& rhs);
46+
friend constexpr HighResTimeStamp operator+(
47+
const HighResTimeStamp& lhs,
48+
const HighResDuration& rhs);
49+
friend constexpr HighResTimeStamp operator-(
50+
const HighResTimeStamp& lhs,
51+
const HighResDuration& rhs);
52+
53+
public:
54+
constexpr HighResDuration()
55+
: chronoDuration_(std::chrono::steady_clock::duration()) {}
56+
57+
static constexpr HighResDuration zero() {
58+
return HighResDuration(std::chrono::steady_clock::duration::zero());
59+
}
60+
61+
static constexpr HighResDuration fromChrono(
62+
std::chrono::steady_clock::duration chronoDuration) {
63+
return HighResDuration(chronoDuration);
64+
}
65+
66+
static constexpr HighResDuration fromNanoseconds(int64_t units) {
67+
return HighResDuration(std::chrono::nanoseconds(units));
68+
}
69+
70+
static constexpr HighResDuration fromMilliseconds(int64_t units) {
71+
return HighResDuration(std::chrono::milliseconds(units));
72+
}
73+
74+
constexpr int64_t toNanoseconds() const {
75+
return std::chrono::duration_cast<std::chrono::nanoseconds>(chronoDuration_)
76+
.count();
77+
}
78+
79+
// @see https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp
80+
static constexpr HighResDuration fromDOMHighResTimeStamp(double units) {
81+
auto nanoseconds = static_cast<int64_t>(units * 1e6);
82+
return fromNanoseconds(nanoseconds);
83+
}
84+
85+
// @see https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp
86+
constexpr double toDOMHighResTimeStamp() const {
87+
return static_cast<std::chrono::duration<double, std::milli>>(
88+
chronoDuration_)
89+
.count();
90+
}
91+
92+
constexpr HighResDuration operator+(const HighResDuration& rhs) const {
93+
return HighResDuration(chronoDuration_ + rhs.chronoDuration_);
94+
}
95+
96+
constexpr HighResDuration operator+(
97+
const std::chrono::steady_clock::duration& rhs) const {
98+
return HighResDuration(chronoDuration_ + rhs);
99+
}
100+
101+
constexpr HighResDuration operator-(const HighResDuration& rhs) const {
102+
return HighResDuration(chronoDuration_ - rhs.chronoDuration_);
103+
}
104+
105+
constexpr HighResDuration operator-(
106+
const std::chrono::steady_clock::duration& rhs) const {
107+
return HighResDuration(chronoDuration_ - rhs);
108+
}
109+
110+
constexpr HighResDuration& operator+=(const HighResDuration& rhs) {
111+
chronoDuration_ += rhs.chronoDuration_;
112+
return *this;
113+
}
114+
115+
constexpr HighResDuration& operator+=(
116+
const std::chrono::steady_clock::duration& rhs) {
117+
chronoDuration_ += rhs;
118+
return *this;
119+
}
120+
121+
constexpr HighResDuration& operator-=(const HighResDuration& rhs) {
122+
chronoDuration_ -= rhs.chronoDuration_;
123+
return *this;
124+
}
125+
126+
constexpr HighResDuration& operator-=(
127+
const std::chrono::steady_clock::duration& rhs) {
128+
chronoDuration_ -= rhs;
129+
return *this;
130+
}
131+
132+
constexpr bool operator==(const HighResDuration& rhs) const {
133+
return chronoDuration_ == rhs.chronoDuration_;
134+
}
135+
136+
constexpr bool operator==(
137+
const std::chrono::steady_clock::duration& rhs) const {
138+
return chronoDuration_ == rhs;
139+
}
140+
141+
constexpr bool operator!=(const HighResDuration& rhs) const {
142+
return chronoDuration_ != rhs.chronoDuration_;
143+
}
144+
145+
constexpr bool operator!=(
146+
const std::chrono::steady_clock::duration& rhs) const {
147+
return chronoDuration_ != rhs;
148+
}
149+
150+
constexpr bool operator<(const HighResDuration& rhs) const {
151+
return chronoDuration_ < rhs.chronoDuration_;
152+
}
153+
154+
constexpr bool operator<(
155+
const std::chrono::steady_clock::duration& rhs) const {
156+
return chronoDuration_ < rhs;
157+
}
158+
159+
constexpr bool operator<=(const HighResDuration& rhs) const {
160+
return chronoDuration_ <= rhs.chronoDuration_;
161+
}
162+
163+
constexpr bool operator<=(
164+
const std::chrono::steady_clock::duration& rhs) const {
165+
return chronoDuration_ <= rhs;
166+
}
167+
168+
constexpr bool operator>(const HighResDuration& rhs) const {
169+
return chronoDuration_ > rhs.chronoDuration_;
170+
}
171+
172+
constexpr bool operator>(
173+
const std::chrono::steady_clock::duration& rhs) const {
174+
return chronoDuration_ > rhs;
175+
}
176+
177+
constexpr bool operator>=(const HighResDuration& rhs) const {
178+
return chronoDuration_ >= rhs.chronoDuration_;
179+
}
180+
181+
constexpr bool operator>=(
182+
const std::chrono::steady_clock::duration& rhs) const {
183+
return chronoDuration_ >= rhs;
184+
}
185+
186+
constexpr operator std::chrono::steady_clock::duration() const {
187+
return chronoDuration_;
188+
}
189+
190+
private:
191+
explicit constexpr HighResDuration(
192+
std::chrono::steady_clock::duration chronoDuration)
193+
: chronoDuration_(chronoDuration) {}
194+
195+
std::chrono::steady_clock::duration chronoDuration_;
196+
};
197+
198+
/*
199+
* A class representing a specific point in time with high precision.
200+
*
201+
* @see __docs__/README.md for more information.
202+
*/
203+
class HighResTimeStamp {
204+
friend constexpr HighResDuration operator-(
205+
const HighResTimeStamp& lhs,
206+
const HighResTimeStamp& rhs);
207+
friend constexpr HighResTimeStamp operator+(
208+
const HighResTimeStamp& lhs,
209+
const HighResDuration& rhs);
210+
friend constexpr HighResTimeStamp operator-(
211+
const HighResTimeStamp& lhs,
212+
const HighResDuration& rhs);
213+
214+
public:
215+
HighResTimeStamp() noexcept
216+
: chronoTimePoint_(std::chrono::steady_clock::now()) {}
217+
218+
static constexpr HighResTimeStamp now() noexcept {
219+
return HighResTimeStamp(std::chrono::steady_clock::now());
220+
}
221+
222+
static constexpr HighResTimeStamp min() noexcept {
223+
return HighResTimeStamp(std::chrono::steady_clock::time_point::min());
224+
}
225+
226+
static constexpr HighResTimeStamp max() noexcept {
227+
return HighResTimeStamp(std::chrono::steady_clock::time_point::max());
228+
}
229+
230+
// @see https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp
231+
static constexpr HighResTimeStamp fromDOMHighResTimeStamp(double units) {
232+
auto nanoseconds = static_cast<int64_t>(units * 1e6);
233+
return HighResTimeStamp(std::chrono::steady_clock::time_point(
234+
std::chrono::nanoseconds(nanoseconds)));
235+
}
236+
237+
// @see https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp
238+
constexpr double toDOMHighResTimeStamp() const {
239+
return HighResDuration(chronoTimePoint_.time_since_epoch())
240+
.toDOMHighResTimeStamp();
241+
}
242+
243+
constexpr bool operator==(const HighResTimeStamp& rhs) const {
244+
return chronoTimePoint_ == rhs.chronoTimePoint_;
245+
}
246+
247+
constexpr bool operator!=(const HighResTimeStamp& rhs) const {
248+
return chronoTimePoint_ != rhs.chronoTimePoint_;
249+
}
250+
251+
constexpr bool operator<(const HighResTimeStamp& rhs) const {
252+
return chronoTimePoint_ < rhs.chronoTimePoint_;
253+
}
254+
255+
constexpr bool operator<=(const HighResTimeStamp& rhs) const {
256+
return chronoTimePoint_ <= rhs.chronoTimePoint_;
257+
}
258+
259+
constexpr bool operator>(const HighResTimeStamp& rhs) const {
260+
return chronoTimePoint_ > rhs.chronoTimePoint_;
261+
}
262+
263+
constexpr bool operator>=(const HighResTimeStamp& rhs) const {
264+
return chronoTimePoint_ >= rhs.chronoTimePoint_;
265+
}
266+
267+
constexpr HighResTimeStamp& operator+=(const HighResDuration& rhs) {
268+
chronoTimePoint_ += rhs.chronoDuration_;
269+
return *this;
270+
}
271+
272+
constexpr HighResTimeStamp& operator-=(const HighResDuration& rhs) {
273+
chronoTimePoint_ -= rhs.chronoDuration_;
274+
return *this;
275+
}
276+
277+
private:
278+
explicit constexpr HighResTimeStamp(
279+
std::chrono::steady_clock::time_point chronoTimePoint)
280+
: chronoTimePoint_(chronoTimePoint) {}
281+
282+
std::chrono::steady_clock::time_point chronoTimePoint_;
283+
};
284+
285+
inline constexpr HighResDuration operator-(
286+
const HighResTimeStamp& lhs,
287+
const HighResTimeStamp& rhs) {
288+
return HighResDuration(lhs.chronoTimePoint_ - rhs.chronoTimePoint_);
289+
}
290+
291+
inline constexpr HighResTimeStamp operator+(
292+
const HighResTimeStamp& lhs,
293+
const HighResDuration& rhs) {
294+
return HighResTimeStamp(lhs.chronoTimePoint_ + rhs.chronoDuration_);
295+
}
296+
297+
inline constexpr HighResTimeStamp operator-(
298+
const HighResTimeStamp& lhs,
299+
const HighResDuration& rhs) {
300+
return HighResTimeStamp(lhs.chronoTimePoint_ - rhs.chronoDuration_);
301+
}
302+
33303
} // namespace facebook::react

0 commit comments

Comments
 (0)