Use CLOCK_MONOTONIC_RAW on macOS for nanosecond precision#5994
Conversation
CLOCK_MONOTONIC on macOS only has microsecond precision, while CLOCK_MONOTONIC_RAW has nanosecond precision. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Thank you for updating Change log entry section 👏 Visited at: 2026-07-06 08:15:32 UTC |
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: f80041c | Docs | Datadog PR Page | Give us feedback! |
BenchmarksBenchmark execution time: 2026-07-03 15:52:59 Comparing candidate commit f80041c in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 48 metrics, 1 unstable metrics.
|
ivoanjo
left a comment
There was a problem hiding this comment.
Looks reasonable; no concerns here.
This is a very "rabbit hole" suggestion, and I'd do it as a separate PR, but I wonder if we should instead use CLOCK_MONOTONIC_RAW everywhere.
|
The reason to not use RAW on Linux is mostly this (from Claude but I agree, I think it's important that 1 second is 1 second, not +/- something): ⏺ CLOCK_MONOTONIC is the better default for a profiler. The main tradeoffs:
For a profiler that samples frequently, the cost of reading the clock matters more than sub-ppm accuracy from NTP correction. CLOCK_MONOTONIC is the pragmatic choice unless you're on a modern kernel and need to correlate with a clock source that's completely independent of NTP (e.g., cross-machine hardware timestamp comparison). So CLOCK_MONOTONIC is the best for speed on Linux and (more arguable) the portable correct clock to use in the first place. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f80041cec6
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
|
||
| // CLOCK_MONOTONIC on macOS only has microsecond precision, CLOCK_MONOTONIC_RAW has nanosecond precision | ||
| #ifdef __APPLE__ | ||
| static inline long monotonic_wall_time_now_ns(raise_on_failure_setting raise_on_failure) { return retrieve_clock_as_ns(CLOCK_MONOTONIC_RAW, raise_on_failure); } |
There was a problem hiding this comment.
Keep coarse and regular monotonic clocks consistent
On macOS with allocation profiling and dynamic sampling enabled, this changes monotonic_wall_time_now_ns to CLOCK_MONOTONIC_RAW, but the skip fast path still calls monotonic_coarse_wall_time_now_ns(), which falls back to CLOCK_MONOTONIC on macOS before should_readjust subtracts it from last_readjust_time_ns (collectors_discrete_dynamic_sampler.c:122-124). Mixing these clock domains means the sampler can readjust too early or never as the adjusted and raw clocks diverge; the macOS fallback should use the same Darwin clock as the regular helper, or the skip path should avoid the coarse helper there.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
I believe this might be a problem -- on Linux we use monotonic_coarse_wall_time_now_ns() and monotonic_wall_time_now_ns() but there's an underlying clear assumption -- those are directly comparable, just one is cheaper than the other.
But CLOCK_MONOTONIC I don't think will be comparable to CLOCK_MONOTONIC_RAW, so monotonic_coarse_wall_time_now_ns should probably use CLOCK_MONOTONIC_RAW as well for macOS (and we probably need a comment there saying "whatever gets used here needs to be comparable to monotonic_wall_time_now_ns")
| # | ||
| # @param unit [Symbol] unit for the resulting value, same as ::Process#clock_gettime, defaults to :float_second | ||
| # @return [Float|Integer] timestamp in the requested unit, since some unspecified starting point | ||
| MONOTONIC_CLOCK_ID = RUBY_PLATFORM.include?("darwin") ? Process::CLOCK_MONOTONIC_RAW : Process::CLOCK_MONOTONIC |
There was a problem hiding this comment.
Keep configuration clock provider in sync
On macOS this makes Core::Utils::Time.get_time use CLOCK_MONOTONIC_RAW, but the get_time_provider option's default/resetter still return a proc using ::Process::CLOCK_MONOTONIC (settings.rb:834-844). After a custom provider is reset, or when code uses Datadog.configuration.get_time_provider directly, Datadog goes back to the old microsecond-precision clock and can compare Ruby timestamps from CLOCK_MONOTONIC with native timestamps from CLOCK_MONOTONIC_RAW; update the configuration default/resetter to use the same clock id.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
This is a good point... And this is another very awkward legacy mechanism that's very awkwardly implemented -- we monkey patch ourselves and whatnot.
Also, this gets used in production so it might impact performance if CLOCK_MONOTONIC_RAW is slower than CLOCK_MONOTONIC.
So... in hindsight this part I think it probably needs some validation, as this is not only a "change it for the tests should be fine" change.
CLOCK_MONOTONIC on macOS only has microsecond precision, while CLOCK_MONOTONIC_RAW has nanosecond precision.
What does this PR do?
Motivation:
Finer-grained times on macOS, same granularity as on Linux, which may help avoid flaky tests.
Change log entry
None
Additional Notes:
How to test the change?