Skip to the content
Documentation
Help Start
Reading in:
  • German: 9,059 of 9,059 pages
About the help in other languages
All help pages

Velocity and the opcode cache: why a page costs what it does, and how to measure it

This page is for administrators who run Exponential Velocity and want to know where the CPU time of a page goes. Two changes belong together (added 2026-10-02):

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/features/6.0/velocity-opcode-cache-and-profile.md

On this page

Velocity and the opcode cache: why a page costs what it does, and how to measure it

This page is for administrators who run Exponential Velocity and want to know where the CPU time of a page goes. Two changes belong together (added 2026-10-02):

  • Velocity's workers now keep the files the kernel rewrites (INI caches, override caches, compiled templates) in the opcode cache.
  • A diagnostic you switch on writes one line per request that says how the request used the opcode cache, so two engines can be compared with numbers.

What was wrong

PHP's opcode cache does not keep a script that was changed less than opcache.file_update_protection seconds before the request's start. Under PHP-FPM every request starts afresh, so only files written in the last two seconds are skipped. A Velocity worker lives for hours, and its "request start" is the time the worker started. Every file written afterwards (the caches regenerated after a deploy or a cache clear) counted as too new for the whole life of the worker, and was compiled again on every include.

Measured on the demonstration server: the cache served 2.7% of the includes under Velocity against 97% under PHP-FPM, and a rendered page cost 644 ms of CPU against 166 ms.

What changed

settings/velocity.ini passes opcache.file_update_protection=0 (next to opcache.revalidate_freq=0) to the server process. A file that is still being written is not kept by the cache: the server itself reads an include whole and drops the cache's copy of a file changed in the last two seconds, so nothing half written is served.

No setting of yours needs to change. A restart of Velocity applies it (workers keep what they loaded at warm-up).

FileBlockKeyShipped valueScope
settings/velocity.iniserver optionsIniOptions[]=opcache.file_update_protection=00the Velocity server process
settings/velocity.iniserver optionsIniOptions[]=opcache.revalidate_freq=00 (check every include)the Velocity server process
settings/velocity.iniserver optionsIniOptions[]=opcache.memory_consumption=512512 (MB)the Velocity server process

Check:

grep -n "opcache\." settings/velocity.ini

Measure it with the opcode cache profile

The profile is off unless the file var/tmp/opcache_profile.on exists (the kernel does one file_exists() per request to find out). With the file present, every request appends one JSON line to var/tmp/opcache_profile.log.

  1. Switch it on and send a few requests to each engine:
touch var/tmp/opcache_profile.on
curl -s -o /dev/null https://<site>/
tail -n 3 var/tmp/opcache_profile.log
  1. Read the line of the second and later requests of a process. A worker that keeps its files in the cache shows included_not_cached close to 0; one that compiles them again shows many. Compare it with a PHP-FPM line of the same address.
  2. Switch it off again by moving the .on file out of var/tmp/. The log grows with every request while it is on.
FieldMeaning
sapi, pid, uri, timeWhich engine process answered which address
hits_this_request, misses_this_requestThe change of OPcache's hit and miss counters during this request
cached_scripts, included_files, included_not_cachedHow many scripts OPcache holds, how many files the request included, how many of those OPcache did not hold (each is compiled again on every include)
served_most_this_requestThe ten scripts OPcache served most during this request
not_cached_sample, not_cached_probeThe first files not held, with real path, age and what OPcache says about them
opcache_iniThe OPcache settings the process runs with (file_update_protection, revalidate_freq, validate_timestamps, use_cwd)

Limits

  • Figures belong to the process that answered; compare several lines, not one.
  • The profile needs the opcache extension (function_exists('opcache_get_status')).

Become an Exponential Partner

Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.

Something wrong on this page? Report an error

Documentation license

This documentation is free documentation, licensed under the GNU Free Documentation License 1.3 or later.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x