Skip to content

zend_hrtime: use CLOCK_MONOTONIC instead of CLOCK_MONOTONIC_RAW - #23790

Merged
TimWolla merged 4 commits into
php:PHP-8.6from
nicolas-grekas:hrtime-clock-monotonic
Sep 30, 2026
Merged

TimWolla merged 4 commits into
php:PHP-8.6from
nicolas-grekas:hrtime-clock-monotonic

Conversation

@nicolas-grekas

@nicolas-grekas nicolas-grekas commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

This should fix the hrtime.phpt failure reported in GH-22508.

CLOCK_MONOTONIC_RAW is not disciplined by NTP, so it ticks with the raw frequency error of the underlying oscillator. Under WSL2 here, that is 4% fast, measured over a 1s sleep:

             microtime delta   hrtime delta
8.5          1.000083 s        1.000086 s
8.6          1.000072 s        1.038898 s
8.6 + this   1.000158 s        1.000163 s

The relative uncertainty that ext/standard/tests/hrtime/hrtime.phpt computes goes from 0.038 back to 0.0002 with this, against the 0.05 the test allows. @mbeccati measured 0.0501 on Ubuntu 26.04 while packaging 8.6.0alpha1 and suggested raising that limit - I think the limit is fine and it is the clock that moved, but a confirmation on that box would be welcome.

The adjtime/NTP slew that GH-19221 wanted to avoid is bounded to 500ppm by the kernel, and it is precisely what makes CLOCK_MONOTONIC track elapsed real time, which is the contract that test asserts. CLOCK_MONOTONIC_RAW is also served by the vDSO only since Linux 5.3, so on eg. RHEL 8 it costs a syscall per call.

I kept the startup check from GH-19221, so that zend_hrtime() doesn't need to check what clock_gettime() returns. zend_hrtime_posix_clock_id stays for ABI compatibility even if it's now always CLOCK_MONOTONIC; removing it is for master.

@TimWolla

Copy link
Copy Markdown
Member

@marc-mabe as the original author of #19221.

@TimWolla

Copy link
Copy Markdown
Member

I kept the check-the-clock-once part

zend_hrtime_posix_clock_id is never reassigned though.

@nicolas-grekas
nicolas-grekas changed the base branch from master to PHP-8.6 September 29, 2026 08:12
@nicolas-grekas

Copy link
Copy Markdown
Contributor Author

Right, PR updated: the variable is gone. What I meant to keep is the startup check, which lets zend_hrtime() ignore the return value of clock_gettime().

I also retargeted to PHP-8.6: that's where the _RAW switch and the hrtime.phpt failure are, and dropping zend_hrtime_posix_clock_id is free only as long as no release exports it.

@mbeccati
mbeccati requested a review from ndossche September 29, 2026 08:45

@mbeccati mbeccati left a comment •

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.

Even if useless, please keep ZEND_API clockid_t zend_hrtime_posix_clock_id = CLOCK_MONOTONIC; as removing it is considerent an ABI break, which isn't allowed at this stage of 8.6.

It can then be removed in master instead.

@nicolas-grekas

Copy link
Copy Markdown
Contributor Author

PR updated, the variable is back. I'll send its removal to master once this is merged up.

@marc-mabe

Copy link
Copy Markdown
Contributor

Thanks for tracking this down, and you're right. I read the man page's note that "´CLOCK_MONOTONIC_RAWisn't affected by NTP or adjtime" as a reason to prefer it. I thought NTP could makeCLOCK_MONOTONICjump during a measurement but it only nudges its rate slightly to correct the hardware clock's error while_RAW` keeps that error, and in VMs it's much larger.

Keeping the startup check is enough. LGTM, and +1 to dropping zend_hrtime_posix_clock_id in master.

Comment thread Zend/zend_hrtime.c Outdated
CLOCK_MONOTONIC_RAW is not disciplined by NTP, so it ticks with the raw
frequency error of the underlying oscillator, which is 4% under WSL2 and
makes hrtime() disagree with microtime() by that much.

The slew that phpGH-19221 wanted to avoid is bounded to 500ppm by the kernel
and is what makes CLOCK_MONOTONIC track elapsed real time.

zend_hrtime_posix_clock_id stays for ABI compatibility, but nothing reads
it anymore.
@TimWolla

Copy link
Copy Markdown
Member

I just made a final adjustment to the error message, merged the latest PHP 8.6 and added NEWS. Will merge when CI is green.

@TimWolla
TimWolla merged commit 06f4640 into php:PHP-8.6 Sep 30, 2026
17 of 18 checks passed
TimWolla added a commit that referenced this pull request Sep 30, 2026
* PHP-8.6:
  zend_hrtime: use CLOCK_MONOTONIC instead of CLOCK_MONOTONIC_RAW (#23790)
arnaud-lb added a commit to arnaud-lb/php-src that referenced this pull request Sep 30, 2026
* PHP-8.6: (61 commits)
  zend_hrtime: use CLOCK_MONOTONIC instead of CLOCK_MONOTONIC_RAW (php#23790)
  sapi/cli: Fix built-in server truncating responses after a partial write
  Fix phpGH-24006: Skip gh18431.phpt when libzip lacks progress callbacks (php#24009)
  Updated to version 2026.5 (2026e)
  Fix phpGH-23896: Assertion failure in zend_call_function() after a throwing deprecation
  NEWS
  ext/gd: fix undefined behavior with GIFs with problematic LZW compression data
  Document missing deprecation entries for PHP 8.6 (php#23972)
  ext/tidy: Reject tidyNode use after the document is reparsed
  ext/bcmath: Clear the sign of BcMath\Number results that truncate to zero
  Fix phpGH-23980: ZEND_ASSERT violation @ ZEND_INCLUDE_OR_EVAL (include/eval run with a pending exception)
  Fix phpGH-23842: skipLazyInitialization() copies unresolved constant defaults
  Fall back to epoll_wait when epoll_pwait2 is unavailable at runtime (php#23825)
  openssl: Fix memory leak by doing early salt validation
  ext/libxml: Keep SimpleXML children alive across reconstruction
  Fix phpGH-23741: pdo_dblib use-after-free of statement error state
  NEWS
  Fix property hook escape analysis causing misoptimization
  Fix __isset escape analysis causing misoptimization
  Fix memory leak when closing a statement on a killed connection
  ...
@nicolas-grekas
nicolas-grekas deleted the hrtime-clock-monotonic branch September 30, 2026 12:43
TimWolla pushed a commit that referenced this pull request Sep 30, 2026
Nothing reads it since GH-23790, which kept it on PHP-8.6 for ABI
compatibility only.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants