Skip to content

fix(core): re-anchor hrTime() to the wall clock after the host sleeps - #7218

Open
overbalance wants to merge 1 commit into
open-telemetry:mainfrom
embrace-io:overbalance/hrtime-drift-correction
Open

overbalance wants to merge 1 commit into
open-telemetry:mainfrom
embrace-io:overbalance/hrtime-drift-correction

Conversation

@overbalance

@overbalance overbalance commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Which problem is this PR solving?

After the host sleeps, hrTime() returns timestamps that are behind the wall clock by the length of the sleep.

Fixes #7217

Short description of the changes

  • hrTime() stores the drift between Date.now() and performance.timeOrigin + performance.now() as a list of segments. It starts a new segment only when the drift differs from the latest one by more than 1 second. hrTime() uses the latest drift. hrTime(performanceNow) uses the drift of the segment that contains performanceNow, so a timestamp from before a sleep is not moved by that sleep.
  • Span._getTime converts performance timestamps with its own per-span offset directly. Before, it called hrTime(inp + offset), which would now apply the correction twice.
  • instrumentation-xml-http-request tests: the timeout helpers moved the fake Date forward 2 seconds and kept the fake performance.now() at 0. The new code sees this as a sleep and re-anchors. The tests passed before only because the resource-matching window was [0, 0], which matched no fixture resource. The helpers now advance both fake clocks together and start after the fixture resources, so the window still matches no resource.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

  • New hrTime tests: re-anchor after a sleep, no change for a performance timestamp from before a sleep, correction for one from after it, the drift of each segment, no re-anchor below the threshold, re-anchor when the wall clock steps backward, and a stable anchor after a re-anchor
  • New Span test: a performance timestamp after a sleep is corrected once. Without the Span change, the sleep is counted twice.
  • npm test, npm run test:browser, npm run test:webworker, and npm run lint all pass

Checklist:

  • Followed the style guidelines of this project
  • Unit tests have been added

@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Pull request dashboard status

Waiting on the author · refreshed 2026-10-24 00:31 UTC

Resolve merge conflicts.

Respond to 1 review item (e.g. link a commit, explain why not, ask a follow-up):

  • Inline threads: 1
Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Should this be with reviewers? Comment /dashboard route:reviewers to route it to them.
  • Anything wrong — including the routing? Report it with what you expected; it helps us improve the dashboard.

@codecov

codecov Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.15385% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 95.13%. Comparing base (83b6922) to head (aecc45e).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
packages/opentelemetry-core/src/common/time.ts 96.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7218   +/-   ##
=======================================
  Coverage   95.13%   95.13%           
=======================================
  Files         384      384           
  Lines       13548    13569   +21     
  Branches     3128     3133    +5     
=======================================
+ Hits        12889    12909   +20     
- Misses        659      660    +1     
Files with missing lines Coverage Δ
packages/sdk-trace/src/Span.ts 98.90% <100.00%> (ø)
packages/opentelemetry-core/src/common/time.ts 96.55% <96.00%> (-0.42%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@overbalance
overbalance force-pushed the overbalance/hrtime-drift-correction branch from 9da020d to 70cc9c6 Compare October 19, 2026 21:34
@overbalance
overbalance force-pushed the overbalance/hrtime-drift-correction branch from 70cc9c6 to aecc45e Compare October 19, 2026 21:52
const now = millisToHrTime(
typeof performanceNow === 'number' ? performanceNow : performance.now()
const currentPerformanceNow = performance.now();
updateClockDrift(currentPerformanceNow);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we keep using a monotonic clock for durations? It's an edge case, but if the wall clock moves backward during a request, we can now get a negative duration that the histogram drops. The HTTP and SDK duration calculations still use hrTime(), so I think we need to update those too.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

hrTime() falls behind the wall clock after the host sleeps

2 participants