Table of Contents

PHP RFC: Opcache optimization without any caching

Introduction

Currently, it isn't possible to enable optimizations without enabling caching. They should be orthogonal features - it's already possible to cache without optimization passes by setting opcache.optimization_level=0.

Without the feature being proposed, users would either have to enable shared memory caching, or opcache.file_cache_only. Doing that has the following drawbacks:

Proposal

Make the opcode optimizer and JIT available without opcode caching, through a new setting opcache.allow_cache.

Use Cases

opcache.allow_cache=0 is useful when there isn't much available memory and/or there are multiple long-lived php scripts managed by something that is not a php script. Some example use cases are:

Even when barely any files are run, the virtual memory to track the shared memory segment seems to add 2MB extra per independent php process in “shared memory” segments, reducing the free RAM available for other processes.
(starting a large number of php CLI scripts that sleep() in a loop, free (Linux program to report free memory) reports that shared (shared memory) increases by 2MB per process with the default (opcache.allow_cache=1), but barely increases with opcache.allow_cache=0. This will vary on different systems, and will use up more memory if many php files are loaded.

opcache.allow_cache=0 is not intended for running web servers (e.g. apache), where PHP would share a common memory address space (it would almost always be better to cache when optimizations are enabled).

opcache.allow_cache=0 is also not intended for extremely short-lived CLI processes (Opcode optimization may be more time-consuming than the program being run, making opcache.file_cache or opcache.enable_cli=0 a better choice).

Interactions with other opcache features

opcache.allow_cache=0 takes precedence over opcache.file_cache and opcache.file_cache_only. Neither the shared memory cache nor the file cache will be used when opcache.allow_cache=0 is used to disable opcode caching.

It is an error to both set opcache.allow_cache=0 and provide a script to preload (opcache.preload). auto_prepend_file can be used instead of opcache.preload if you want to run a script before your file without caching it.

Opcache's opcode optimizations and JIT are unaffected.

Backward Incompatible Changes

None. Code that does not enable opcache.file_cache should not be affected.

Proposed PHP Version(s)

8.0

RFC Impact

To SAPIs

The APIs those SAPIs use will be unaffected.

Applications using the CLI, Development web server, embedded PHP, and so on will be able to take advantage of opcache.allow_cache=0 if it was useful to optimize without caching.

To Existing Extensions

Extensions that check if opcache is enabled may have to update their checks if they did so by checking if opcache caching settings are enabled.

To Opcache

The code changes to opcache's optimization and caching are minimal - the implementation of this RFC is effectively the same opcache.file_cache_only without reading or writing files.

opcache_get_status() now includes the following new booleans

opcache_get_status() already had the undocumented field opcache_enabled. Looking at the implementation, it appears to be true when shared memory caching is successfully enabled, whether or not optimizations are enabled. Similarly to the existing behavior for file_cache_only, when opcache.allow_cache=0, the field opcache_enabled will be false.

php.ini Defaults

opcache.allow_cache=1 (caching is allowed) will be the hardcoded default and the default value in php.ini-development and php.ini-production.

Discussion

Move optimizer and JIT into core instead?

On an unrelated PR, Dmitry Stogov mentioned that

Also, it would be great to move optimizer and JIT into core, to make them available even without opcode caching.

On the PR implementing opcache.allow_cache=0, Nikita Popov wrote:

I like the idea of having optimization without caching, but the way to go about this is definitely moving the optimizer into Zend and making it available completely independently of the opcache extension. This has been “planned” for a long time, but never actually happened.

Future Scope

Vote

Voting started on May 30th and ends on June 13th

Add opcache.allow_cache ini setting to support opcode optimization without caching
Real name Yes No
alec (alec)  
ashnazg (ashnazg)  
bmajdak (bmajdak)  
bwoebi (bwoebi)  
derick (derick)  
duncan3dc (duncan3dc)  
galvao (galvao)  
jasny (jasny)  
jbnahan (jbnahan)  
kalle (kalle)  
kguest (kguest)  
mike (mike)  
nikic (nikic)  
ocramius (ocramius)  
patrickallaert (patrickallaert)  
pollita (pollita)  
reywob (reywob)  
ruudboon (ruudboon)  
sebastian (sebastian)  
sergey (sergey)  
stas (stas)  
tandre (tandre)  
zimt (zimt)  
Final result: 10 13
This poll has been closed.

If you voted no, why?

The Discussion section mentioned alternative approaches to this RFC. This feedback is being gathered if it may be useful for other work on Opcache such as moving optimizations into PHP's core.

  1. I would only vote for optimizations without caching if Opcache's opcode optimizations were moved into core first.
  2. I don't want any form of optimization without caching / I think opcache.file_cache should be used instead
  3. I think different ini options/values should be used to do this
  4. Other
If you voted no on opcache.allow_cache, why?
Real name 1 2 3 4
ashnazg (ashnazg)    
bwoebi (bwoebi)    
kguest (kguest)    
nikic (nikic)    
patrickallaert (patrickallaert)    
ruudboon (ruudboon)    
sergey (sergey)    
zimt (zimt)    
Final result: 8 0 0 0
This poll has been closed.

Also, would you be interested in moving opcode optimizations and the JIT out of the zend_extension opcache into PHP's core?

I would be interested in moving opcode optimizations into core
Real name Yes No
ashnazg (ashnazg)  
bwoebi (bwoebi)  
dmitry (dmitry)  
galvao (galvao)  
jasny (jasny)  
kguest (kguest)  
nikic (nikic)  
ocramius (ocramius)  
patrickallaert (patrickallaert)  
pollita (pollita)  
ruudboon (ruudboon)  
sebastian (sebastian)  
sergey (sergey)  
zimt (zimt)  
Final result: 14 0
This poll has been closed.

Changelog

0.2: Previously, the ini setting override to disable caching was opcache.no_cache=1. This was changed to opcache.allow_cache=0 to avoid double negatives and to be consistent with naming of other ini settings such as allow_url_fopen and allow_url_include.

0.3: Fix documentation of changes to opcache_get_status()

0.4: Improve documentation of ini settings, add another example use case.

Ideas on moving the optimizer into core instead

There are various ways the suggestion in Discussion could be implemented. My ideas on a way that could be implemented are below (I'm not familiar enough with opcache to implement that or to be aware of any problems it would cause):

Nikita Popov mentions that

To be clear, “move into core” means moving optimizations into Zend/ and making them part of the compilation process (optionally). They shouldn't be in a separate ext/optimizer extension -- that would be not much better than having them in ext/opcache :)

References

https://externals.io/message/109959 “opcache.no_cache prototype: Opcode optimization without caching”

https://externals.io/message/110187 “[RFC] opcache.no_cache: Opcache optimization without any caching”