Skip to content

[RFC] opcache.allow_cache=0: Opcode optimization without caching #5504

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 52 additions & 10 deletions ext/opcache/ZendAccelerator.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ zend_bool accel_startup_ok = 0;
static char *zps_failure_reason = NULL;
char *zps_api_failure_reason = NULL;
zend_bool file_cache_only = 0; /* process uses file cache only */
zend_bool allow_cache = 1; /* process does not use any cache (takes precedence over file_cache_only) */
#if ENABLE_FILE_CACHE_FALLBACK
zend_bool fallback_process = 0; /* process uses file cache fallback */
#endif
Expand Down Expand Up @@ -469,7 +470,7 @@ zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str)
uint32_t pos, *hash_slot;
zend_string *s;

if (UNEXPECTED(file_cache_only)) {
if (UNEXPECTED(file_cache_only || !allow_cache)) {
return str;
}

Expand Down Expand Up @@ -1947,6 +1948,28 @@ zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type)
return op_array;
}

// Optimize opcodes without caching the file in shared memory or in disk
zend_op_array *no_cache_compile_file(zend_file_handle *file_handle, int type)
{
zend_op_array *op_array = NULL;
zend_persistent_script *persistent_script; // not actually persistent with opcache.allow_cache=0.

if (is_stream_path(file_handle->filename) &&
!is_cacheable_stream_path(file_handle->filename)) {
return accelerator_orig_compile_file(file_handle, type);
}

// Take the same code path as if attempting to save a blacklisted script to file cache.
persistent_script = opcache_compile_file(file_handle, type, NULL, &op_array);
if (persistent_script) {
// Attempt to optimize the script before returning it.
zend_optimize_script(&persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level);

return zend_accel_load_script(persistent_script, /* from_memory */ 0);
}
return op_array;
}

int check_persistent_script_access(zend_persistent_script *persistent_script)
{
char *phar_path, *ptr;
Expand Down Expand Up @@ -1983,11 +2006,19 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
ZCG(cache_opline) = NULL;
ZCG(cache_persistent_script) = NULL;
if (file_handle->filename
&& ZCG(accel_directives).file_cache
&& ZCG(enabled) && accel_startup_ok) {
return file_cache_compile_file(file_handle, type);
if (!allow_cache) {
return no_cache_compile_file(file_handle, type);
} else if (ZCG(accel_directives).file_cache) {
return file_cache_compile_file(file_handle, type);
}
}
return accelerator_orig_compile_file(file_handle, type);
} else if (!allow_cache) {
// TODO: Why is opcache_get_status using accelerator_enabled instead of enabled?
ZCG(cache_opline) = NULL;
ZCG(cache_persistent_script) = NULL;
return no_cache_compile_file(file_handle, type);
} else if (file_cache_only) {
ZCG(cache_opline) = NULL;
ZCG(cache_persistent_script) = NULL;
Expand Down Expand Up @@ -2313,7 +2344,7 @@ static int persistent_stream_open_function(const char *filename, zend_file_handl
/* zend_resolve_path() replacement for PHP 5.3 and above */
static zend_string* persistent_zend_resolve_path(const char *filename, size_t filename_len)
{
if (!file_cache_only &&
if (!file_cache_only && allow_cache &&
ZCG(accelerator_enabled)) {

/* check if callback is called from include_once or it's a main request */
Expand Down Expand Up @@ -2437,7 +2468,7 @@ int accel_activate(INIT_FUNC_ARGS)
ZCG(cwd_key_len) = 0;
ZCG(cwd_check) = 1;

if (file_cache_only) {
if (file_cache_only || !allow_cache) {
ZCG(accelerator_enabled) = 0;
return SUCCESS;
}
Expand Down Expand Up @@ -2997,7 +3028,8 @@ static int accel_post_startup(void)
/* End of non-SHM dependent initializations */
/********************************************/
file_cache_only = ZCG(accel_directives).file_cache_only;
if (!file_cache_only) {
allow_cache = ZCG(accel_directives).allow_cache;
if (!file_cache_only && allow_cache) {
size_t shm_size = ZCG(accel_directives).memory_consumption;
#ifdef HAVE_JIT
size_t jit_size = 0;
Expand Down Expand Up @@ -3085,7 +3117,7 @@ static int accel_post_startup(void)
zend_shared_alloc_unlock();

SHM_PROTECT();
} else if (!ZCG(accel_directives).file_cache) {
} else if (file_cache_only && !ZCG(accel_directives).file_cache) {
accel_startup_ok = 0;
zend_accel_error(ACCEL_LOG_FATAL, "opcache.file_cache_only is set without a proper setting of opcache.file_cache");
return SUCCESS;
Expand Down Expand Up @@ -3149,7 +3181,7 @@ static int accel_post_startup(void)

zend_optimizer_startup();

if (!file_cache_only && ZCG(accel_directives).interned_strings_buffer) {
if (!file_cache_only && allow_cache && ZCG(accel_directives).interned_strings_buffer) {
accel_use_shm_interned_strings();
}

Expand All @@ -3167,6 +3199,7 @@ void accel_shutdown(void)
{
zend_ini_entry *ini_entry;
zend_bool _file_cache_only = 0;
zend_bool _allow_cache = 1;

#ifdef HAVE_JIT
zend_jit_shutdown();
Expand All @@ -3188,15 +3221,16 @@ void accel_shutdown(void)
}

_file_cache_only = file_cache_only;
_allow_cache = allow_cache;

accel_reset_pcre_cache();

#ifdef ZTS
ts_free_id(accel_globals_id);
#endif

if (!_file_cache_only) {
/* Delay SHM detach */
if (!_file_cache_only && _allow_cache) {
/* Delay SHM detach - this only needs to be done if SHM is used */
orig_post_shutdown_cb = zend_post_shutdown_cb;
zend_post_shutdown_cb = accel_post_shutdown;
}
Expand Down Expand Up @@ -4786,6 +4820,10 @@ static int accel_finish_startup(void)
}

if (ZCG(accel_directives).preload && *ZCG(accel_directives).preload) {
if (!allow_cache) {
zend_accel_error(ACCEL_LOG_ERROR, "Preloading cannot be combined with allow_cache=0");
return FAILURE;
}
#ifdef ZEND_WIN32
zend_accel_error(ACCEL_LOG_ERROR, "Preloading is not supported on Windows");
return FAILURE;
Expand All @@ -4809,6 +4847,10 @@ static int accel_finish_startup(void)
zend_bool old_reset_signals = SIGG(reset);
#endif

if (UNEXPECTED(!allow_cache)) {
zend_accel_error(ACCEL_LOG_WARNING, "Preloading doesn't work in \"allow_cache=0\" mode");
return SUCCESS;
}
if (UNEXPECTED(file_cache_only)) {
zend_accel_error(ACCEL_LOG_WARNING, "Preloading doesn't work in \"file_cache_only\" mode");
return SUCCESS;
Expand Down
2 changes: 2 additions & 0 deletions ext/opcache/ZendAccelerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ typedef struct _zend_accel_directives {
#endif
char *file_cache;
zend_bool file_cache_only;
zend_bool allow_cache;
zend_bool file_cache_consistency_checks;
#if ENABLE_FILE_CACHE_FALLBACK
zend_bool file_cache_fallback;
Expand Down Expand Up @@ -295,6 +296,7 @@ extern char accel_uname_id[32];
#endif
extern zend_bool accel_startup_ok;
extern zend_bool file_cache_only;
extern zend_bool allow_cache;
#if ENABLE_FILE_CACHE_FALLBACK
extern zend_bool fallback_process;
#endif
Expand Down
5 changes: 5 additions & 0 deletions ext/opcache/tests/001_cli.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
opcache.enable=1
opcache.enable_cli=1
opcache.file_cache_only=0
opcache.optimization_level=-1
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
Expand All @@ -13,8 +14,12 @@ $status = opcache_get_status();
var_dump($config["directives"]["opcache.enable"]);
var_dump($config["directives"]["opcache.enable_cli"]);
var_dump($status["opcache_enabled"]);
var_dump($status["optimizations_enabled"]);
var_dump($status["allow_cache"]);
?>
--EXPECT--
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
23 changes: 23 additions & 0 deletions ext/opcache/tests/allow_cache_1.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
allow_cache_1: Opcache indicates if optimizations and caching are enabled
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.allow_cache=0
opcache.preload=
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
<?php
$status = opcache_get_status();
var_dump($status);
?>
--EXPECT--
array(3) {
["optimizations_enabled"]=>
bool(true)
["opcache_enabled"]=>
bool(false)
["allow_cache"]=>
bool(false)
}
42 changes: 42 additions & 0 deletions ext/opcache/tests/allow_cache_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
--TEST--
allow_cache_2: allow_cache=0 takes precedence over file_cache
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_cache_only=1
opcache.file_cache="{TMP}"
opcache.allow_cache=0
opcache.opt_debug_level=0x20000
opcache.optimization_level=-1
opcache.preload=
--SKIPIF--
<?php require_once('skipif.inc'); ?>
<?php if (PHP_OS_FAMILY == 'Windows') die('skip.. not for Windows'); ?>
--FILE--
<?php
// Opcache should actually run.
// Because allow_cache is used, this will consistently emit debug output as a side effect.
// It should also indicate that file_cache is not used.
$status = opcache_get_status();
var_dump($status);
?>
--EXPECTF--
$_main:
; (lines=7, args=0, vars=1, tmps=1)
; (after optimizer)
; %sallow_cache_2.php:1-8
0000 INIT_FCALL 0 %d string("opcache_get_status")
0001 V1 = DO_ICALL
0002 ASSIGN CV0($status) V1
0003 INIT_FCALL 1 %d string("var_dump")
0004 SEND_VAR CV0($status) 1
0005 DO_ICALL
0006 RETURN int(1)
array(3) {
["optimizations_enabled"]=>
bool(true)
["opcache_enabled"]=>
bool(false)
["allow_cache"]=>
bool(false)
}
21 changes: 17 additions & 4 deletions ext/opcache/zend_accelerator_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ ZEND_INI_BEGIN()
#if ENABLE_FILE_CACHE_FALLBACK
STD_PHP_INI_BOOLEAN("opcache.file_cache_fallback" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_fallback, zend_accel_globals, accel_globals)
#endif
STD_PHP_INI_ENTRY("opcache.allow_cache" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.allow_cache, zend_accel_globals, accel_globals)
#ifdef HAVE_HUGE_CODE_PAGES
STD_PHP_INI_BOOLEAN("opcache.huge_code_pages" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.huge_code_pages, zend_accel_globals, accel_globals)
#endif
Expand Down Expand Up @@ -405,6 +406,10 @@ void zend_accel_override_file_functions(void)
{
zend_function *old_function;
if (ZCG(enabled) && accel_startup_ok && ZCG(accel_directives).file_override_enabled) {
if (!allow_cache) {
zend_accel_error(ACCEL_LOG_WARNING, "file_override_enabled has no effect when allow_cache=0");
return;
}
if (file_cache_only) {
zend_accel_error(ACCEL_LOG_WARNING, "file_override_enabled has no effect when file_cache_only is set");
return;
Expand Down Expand Up @@ -438,7 +443,7 @@ void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS)
{
php_info_print_table_start();

if (ZCG(accelerator_enabled) || file_cache_only) {
if ((ZCG(accelerator_enabled) || file_cache_only) && allow_cache) {
php_info_print_table_row(2, "Opcode Caching", "Up and Running");
} else {
php_info_print_table_row(2, "Opcode Caching", "Disabled");
Expand All @@ -448,12 +453,12 @@ void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS)
} else {
php_info_print_table_row(2, "Optimization", "Disabled");
}
if (!file_cache_only) {
if (!file_cache_only && allow_cache) {
php_info_print_table_row(2, "SHM Cache", "Enabled");
} else {
php_info_print_table_row(2, "SHM Cache", "Disabled");
}
if (ZCG(accel_directives).file_cache) {
if (ZCG(accel_directives).file_cache && allow_cache) {
php_info_print_table_row(2, "File Cache", "Enabled");
} else {
php_info_print_table_row(2, "File Cache", "Disabled");
Expand All @@ -471,7 +476,7 @@ void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS)
#else
php_info_print_table_row(2, "JIT", "Not Available");
#endif
if (file_cache_only) {
if (file_cache_only || !allow_cache) { // TODO test failure mode
if (!accel_startup_ok || zps_api_failure_reason) {
php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason);
} else {
Expand Down Expand Up @@ -613,8 +618,15 @@ ZEND_FUNCTION(opcache_get_status)
array_init(return_value);

/* Trivia */
/* Whether opcodes get optimized */
add_assoc_bool(return_value, "optimizations_enabled", ZCG(enabled) && accel_startup_ok && ZCG(accel_directives).optimization_level);
/* Whether the caching is enabled */
add_assoc_bool(return_value, "opcache_enabled", ZCG(accelerator_enabled));

add_assoc_bool(return_value, "allow_cache", allow_cache);
if (!allow_cache) {
return;
}
if (ZCG(accel_directives).file_cache) {
add_assoc_string(return_value, "file_cache", ZCG(accel_directives).file_cache);
}
Expand Down Expand Up @@ -784,6 +796,7 @@ ZEND_FUNCTION(opcache_get_configuration)
#if ENABLE_FILE_CACHE_FALLBACK
add_assoc_bool(&directives, "opcache.file_cache_fallback", ZCG(accel_directives).file_cache_fallback);
#endif
add_assoc_bool(&directives, "opcache.allow_cache", ZCG(accel_directives).allow_cache);

add_assoc_long(&directives, "opcache.file_update_protection", ZCG(accel_directives).file_update_protection);
add_assoc_long(&directives, "opcache.opt_debug_level", ZCG(accel_directives).opt_debug_level);
Expand Down
4 changes: 4 additions & 0 deletions php.ini-development
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,10 @@ ldap.max_links = -1
; cache is required.
;opcache.file_cache_fallback=1

; If set to 0, it disables both the shared memory cache and the file cache,
; while opcache continues to optimize code.
;opcache.allow_cache=1

; Enables or disables copying of PHP code (text segment) into HUGE PAGES.
; This should improve performance, but requires appropriate OS configuration.
;opcache.huge_code_pages=0
Expand Down
4 changes: 4 additions & 0 deletions php.ini-production
Original file line number Diff line number Diff line change
Expand Up @@ -1858,6 +1858,10 @@ ldap.max_links = -1
; cache is required.
;opcache.file_cache_fallback=1

; If set to 0, it disables both the shared memory cache and the file cache,
; while opcache continues to optimize code.
;opcache.allow_cache=1

; Enables or disables copying of PHP code (text segment) into HUGE PAGES.
; This should improve performance, but requires appropriate OS configuration.
;opcache.huge_code_pages=1
Expand Down