Skip to content

improve cpu metrics - #107

Merged
fcoelho merged 2 commits into
mainfrom
feature/ops-1311-improve-cpu-metrics
Aug 12, 2026
Merged

fcoelho merged 2 commits into
mainfrom
feature/ops-1311-improve-cpu-metrics

Conversation

@fcoelho

@fcoelho fcoelho commented Aug 11, 2026

Copy link
Copy Markdown
Contributor
  • fix(metrics): derive cpu_seconds instead of summing cpu_total
  • fix(metrics): derive memory_byte_seconds instead of summing peak memory_bytes

php-fpm's %C is the percentage of a request's wall time spent on CPU, not a
duration -- see sapi/fpm/fpm/fpm_log.c, which computes it as

    tms_total / fpm_scoreboard_get_tick() / cpu_duration * 100

Summing a percentage across requests therefore produces a meaningless number,
so phpfpm_request_cpu_total_sum could not be used for anything and the image
had no CPU metric suitable for capacity work.

Multiply by the request duration instead to get CPU seconds, which is additive
across requests, pools and sites:

    cpu_seconds = (cpu_total / 100) * (duration_ms / 1000)

rate(phpfpm_request_cpu_seconds_sum) is then CPU cores consumed. fpm_request_end()
derives %C's denominator and %d from the same interval (both start at
proc->accepted), so the conversion is exact rather than approximate.

The duration-weighted mean percentage remains recoverable as
cpu_seconds_sum / (duration_ms_sum / 1000) * 100, which is a more correct mean
than the previous unweighted one.

Note this makes %d a prerequisite: a custom METRICS_PHP_FPM_ACCESS_LOG_FORMAT
without a duration cannot produce cpu_seconds, and will emit no CPU metric.

BREAKING CHANGE: phpfpm_request_cpu_total_{sum,count} are no longer emitted and
are replaced by phpfpm_request_cpu_seconds_{sum,count}. Series count per request
is unchanged.
…ry_bytes

php-fpm's %M reads proc.memory, which fpm_request_end() sets from
zend_memory_peak_usage(1) -- a per-request high-water mark, not an amount of
memory consumed. Summing high-water marks across requests yields a number that
never corresponded to any memory that existed, the same class of error as
summing cpu_total. Only sum/count was interpretable, and that discards the tail.

Multiply by the request duration to get the time integral, matching the
cpu_seconds treatment:

    memory_byte_seconds = memory_bytes * (duration_ms / 1000)

rate(phpfpm_request_memory_byte_seconds_sum) is then the mean bytes held
concurrently by php workers, which is additive across requests, pools and sites.
The duration-weighted mean peak remains recoverable as
memory_byte_seconds_sum / (duration_ms_sum / 1000).

Two caveats worth knowing when using it:

- peak * duration overestimates the true integral, since memory ramps up
  rather than sitting at peak for the whole request. The error is in the
  safe direction for capacity work.

- this is request-attributable memory, not container memory. PHP's
  allocator does not return memory to the OS, so a worker retains its
  own high-water mark across every subsequent request until
  pm.max_requests recycles it. No per-request metric can observe that;
  cgroup memory accounting is the right source for container-level sizing.

BREAKING CHANGE: phpfpm_request_memory_bytes_{sum,count} are no longer emitted
and are replaced by phpfpm_request_memory_byte_seconds_{sum,count}, which has a
different unit (byte-seconds rather than bytes). Series count per request is
unchanged.
@fcoelho
fcoelho force-pushed the feature/ops-1311-improve-cpu-metrics branch from d24a7c8 to 477fee3 Compare August 11, 2026 11:30
@fcoelho
fcoelho marked this pull request as ready for review August 11, 2026 12:07
@fcoelho
fcoelho merged commit b05bb7b into main Aug 12, 2026
1 check passed
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.

3 participants