Skip to content

Commit ec1ee3d

Browse files
committed
ext/opcache: remove option huge_code_pages
This feature is useless at best, but is fragile and increases memory usage because it creates a copy of the PHP executable in RAM, when another copy is already in the kernel's page cache. Additionally, each PHP process has its own copy, multiplying the memory usage with the number of PHP processes. Even worse: under memory pressure, the kernel would usually just discard those code pages, and reload them from disk on demand; but with `huge_code_pages`, the kernel cannot simply discard those pages, instead it has to allocate room in the swap partition and then has to write the pages to the swap partition before being able to discard them. This adds disk I/O to an already extremely constrained situation. The feature was added 7 years ago in commit 669f0b3, and the commit message stated that this "provided 2% improvement on real-life apps, because of 2-3 times reduction in number of iTLB misses", but did not tell how these results were produced. I tried, but failed to measure a difference. None of my tests went any faster with `huge_code_pages` enabled. In a second attempt, I tried `perf stat` with events `itlb_misses.miss_causes_a_walk`, `itlb_misses.stlb_hit`, `itlb_misses.walk_completed`, `itlb_misses.walk_duration` and could not see any improvements here either. The results were unstable, but nothing suggested it was better with `huge_code_pages`. Quite contrary, this operation delays PHP startup by 5 ms (measured on an Intel Xeon E5-2630). phpinfo() with opcache.huge_code_pages=0: 17.92 msec task-clock:u # 0.985 CPUs utilized 29,804,809 cycles:u # 1.663 GHz 44,512,668 instructions:u # 1.49 insn per cycle phpinfo() with opcache.huge_code_pages=1: 23.20 msec task-clock:u # 0.988 CPUs utilized 35,709,593 cycles:u # 1.539 GHz 45,940,779 instructions:u # 1.29 insn per cycle In order to reduce PHP's memory size, reduce the load during PHP startup, simplify debugging and profiling, I propose removing this feature.
1 parent 061fcdb commit ec1ee3d

File tree

8 files changed

+2
-208
lines changed

8 files changed

+2
-208
lines changed

ext/opcache/ZendAccelerator.c

Lines changed: 0 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
#include "zend_vm.h"
3535
#include "zend_inheritance.h"
3636
#include "zend_exceptions.h"
37-
#include "zend_mmap.h"
3837
#include "zend_observer.h"
3938
#include "main/php_main.h"
4039
#include "main/SAPI.h"
@@ -2946,174 +2945,6 @@ static void accel_globals_ctor(zend_accel_globals *accel_globals)
29462945
memset(accel_globals, 0, sizeof(zend_accel_globals));
29472946
}
29482947

2949-
#ifdef HAVE_HUGE_CODE_PAGES
2950-
# ifndef _WIN32
2951-
# include <sys/mman.h>
2952-
# ifndef MAP_ANON
2953-
# ifdef MAP_ANONYMOUS
2954-
# define MAP_ANON MAP_ANONYMOUS
2955-
# endif
2956-
# endif
2957-
# ifndef MAP_FAILED
2958-
# define MAP_FAILED ((void*)-1)
2959-
# endif
2960-
# ifdef MAP_ALIGNED_SUPER
2961-
# include <sys/types.h>
2962-
# include <sys/sysctl.h>
2963-
# include <sys/user.h>
2964-
# define MAP_HUGETLB MAP_ALIGNED_SUPER
2965-
# endif
2966-
# endif
2967-
2968-
# if defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE)
2969-
static zend_result accel_remap_huge_pages(void *start, size_t size, size_t real_size, const char *name, size_t offset)
2970-
{
2971-
void *ret = MAP_FAILED;
2972-
void *mem;
2973-
2974-
mem = mmap(NULL, size,
2975-
PROT_READ | PROT_WRITE,
2976-
MAP_PRIVATE | MAP_ANONYMOUS,
2977-
-1, 0);
2978-
if (mem == MAP_FAILED) {
2979-
zend_error(E_WARNING,
2980-
ACCELERATOR_PRODUCT_NAME " huge_code_pages: mmap failed: %s (%d)",
2981-
strerror(errno), errno);
2982-
return FAILURE;
2983-
}
2984-
memcpy(mem, start, real_size);
2985-
2986-
# ifdef MAP_HUGETLB
2987-
ret = mmap(start, size,
2988-
PROT_READ | PROT_WRITE | PROT_EXEC,
2989-
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_HUGETLB,
2990-
-1, 0);
2991-
# endif
2992-
if (ret == MAP_FAILED) {
2993-
ret = mmap(start, size,
2994-
PROT_READ | PROT_WRITE | PROT_EXEC,
2995-
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
2996-
-1, 0);
2997-
/* this should never happen? */
2998-
ZEND_ASSERT(ret != MAP_FAILED);
2999-
# ifdef MADV_HUGEPAGE
3000-
if (-1 == madvise(start, size, MADV_HUGEPAGE)) {
3001-
memcpy(start, mem, real_size);
3002-
mprotect(start, size, PROT_READ | PROT_EXEC);
3003-
munmap(mem, size);
3004-
zend_error(E_WARNING,
3005-
ACCELERATOR_PRODUCT_NAME " huge_code_pages: madvise(HUGEPAGE) failed: %s (%d)",
3006-
strerror(errno), errno);
3007-
return FAILURE;
3008-
}
3009-
# else
3010-
memcpy(start, mem, real_size);
3011-
mprotect(start, size, PROT_READ | PROT_EXEC);
3012-
munmap(mem, size);
3013-
zend_error(E_WARNING,
3014-
ACCELERATOR_PRODUCT_NAME " huge_code_pages: mmap(HUGETLB) failed: %s (%d)",
3015-
strerror(errno), errno);
3016-
return FAILURE;
3017-
# endif
3018-
}
3019-
3020-
// Given the MAP_FIXED flag the address can never diverge
3021-
ZEND_ASSERT(ret == start);
3022-
zend_mmap_set_name(start, size, "zend_huge_code_pages");
3023-
memcpy(start, mem, real_size);
3024-
mprotect(start, size, PROT_READ | PROT_EXEC);
3025-
3026-
munmap(mem, size);
3027-
3028-
return SUCCESS;
3029-
}
3030-
3031-
static void accel_move_code_to_huge_pages(void)
3032-
{
3033-
#if defined(__linux__)
3034-
FILE *f;
3035-
long unsigned int huge_page_size = 2 * 1024 * 1024;
3036-
3037-
f = fopen("/proc/self/maps", "r");
3038-
if (f) {
3039-
long unsigned int start, end, offset, inode;
3040-
char perm[5], dev[10], name[MAXPATHLEN];
3041-
int ret;
3042-
3043-
while (1) {
3044-
ret = fscanf(f, "%lx-%lx %4s %lx %9s %ld %s\n", &start, &end, perm, &offset, dev, &inode, name);
3045-
if (ret == 7) {
3046-
if (perm[0] == 'r' && perm[1] == '-' && perm[2] == 'x' && name[0] == '/') {
3047-
long unsigned int seg_start = ZEND_MM_ALIGNED_SIZE_EX(start, huge_page_size);
3048-
long unsigned int seg_end = (end & ~(huge_page_size-1L));
3049-
long unsigned int real_end;
3050-
3051-
ret = fscanf(f, "%lx-", &start);
3052-
if (ret == 1 && start == seg_end + huge_page_size) {
3053-
real_end = end;
3054-
seg_end = start;
3055-
} else {
3056-
real_end = seg_end;
3057-
}
3058-
3059-
if (seg_end > seg_start) {
3060-
zend_accel_error(ACCEL_LOG_DEBUG, "remap to huge page %lx-%lx %s \n", seg_start, seg_end, name);
3061-
accel_remap_huge_pages((void*)seg_start, seg_end - seg_start, real_end - seg_start, name, offset + seg_start - start);
3062-
}
3063-
break;
3064-
}
3065-
} else {
3066-
break;
3067-
}
3068-
}
3069-
fclose(f);
3070-
}
3071-
#elif defined(__FreeBSD__)
3072-
size_t s = 0;
3073-
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
3074-
long unsigned int huge_page_size = 2 * 1024 * 1024;
3075-
if (sysctl(mib, 4, NULL, &s, NULL, 0) == 0) {
3076-
s = s * 4 / 3;
3077-
void *addr = mmap(NULL, s, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
3078-
if (addr != MAP_FAILED) {
3079-
if (sysctl(mib, 4, addr, &s, NULL, 0) == 0) {
3080-
uintptr_t start = (uintptr_t)addr;
3081-
uintptr_t end = start + s;
3082-
while (start < end) {
3083-
struct kinfo_vmentry *entry = (struct kinfo_vmentry *)start;
3084-
size_t sz = entry->kve_structsize;
3085-
if (sz == 0) {
3086-
break;
3087-
}
3088-
int permflags = entry->kve_protection;
3089-
if ((permflags & KVME_PROT_READ) && !(permflags & KVME_PROT_WRITE) &&
3090-
(permflags & KVME_PROT_EXEC) && entry->kve_path[0] != '\0') {
3091-
long unsigned int seg_start = ZEND_MM_ALIGNED_SIZE_EX(start, huge_page_size);
3092-
long unsigned int seg_end = (end & ~(huge_page_size-1L));
3093-
if (seg_end > seg_start) {
3094-
zend_accel_error(ACCEL_LOG_DEBUG, "remap to huge page %lx-%lx %s \n", seg_start, seg_end, entry->kve_path);
3095-
accel_remap_huge_pages((void*)seg_start, seg_end - seg_start, seg_end - seg_start, entry->kve_path, entry->kve_offset + seg_start - start);
3096-
// First relevant segment found is our binary
3097-
break;
3098-
}
3099-
}
3100-
start += sz;
3101-
}
3102-
}
3103-
munmap(addr, s);
3104-
}
3105-
}
3106-
#endif
3107-
}
3108-
# else
3109-
static void accel_move_code_to_huge_pages(void)
3110-
{
3111-
zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages has no affect as huge page is not supported");
3112-
return;
3113-
}
3114-
# endif /* defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE) */
3115-
#endif /* HAVE_HUGE_CODE_PAGES */
3116-
31172948
static int accel_startup(zend_extension *extension)
31182949
{
31192950
#ifdef ZTS
@@ -3145,16 +2976,6 @@ static int accel_startup(zend_extension *extension)
31452976
}
31462977
#endif
31472978

3148-
#ifdef HAVE_HUGE_CODE_PAGES
3149-
if (ZCG(accel_directives).huge_code_pages &&
3150-
(strcmp(sapi_module.name, "cli") == 0 ||
3151-
strcmp(sapi_module.name, "cli-server") == 0 ||
3152-
strcmp(sapi_module.name, "cgi-fcgi") == 0 ||
3153-
strcmp(sapi_module.name, "fpm-fcgi") == 0)) {
3154-
accel_move_code_to_huge_pages();
3155-
}
3156-
#endif
3157-
31582979
/* no supported SAPI found - disable acceleration and stop initialization */
31592980
if (accel_find_sapi() == FAILURE) {
31602981
accel_startup_ok = false;

ext/opcache/ZendAccelerator.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,6 @@ typedef struct _zend_accel_directives {
194194
bool file_cache_consistency_checks;
195195
#if ENABLE_FILE_CACHE_FALLBACK
196196
bool file_cache_fallback;
197-
#endif
198-
#ifdef HAVE_HUGE_CODE_PAGES
199-
bool huge_code_pages;
200197
#endif
201198
char *preload;
202199
#ifndef ZEND_WIN32

ext/opcache/config.m4

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,6 @@ PHP_ARG_ENABLE([opcache],
44
[Disable Zend OPcache support])],
55
[yes])
66

7-
PHP_ARG_ENABLE([huge-code-pages],
8-
[whether to enable copying PHP CODE pages into HUGE PAGES],
9-
[AS_HELP_STRING([--disable-huge-code-pages],
10-
[Disable copying PHP CODE pages into HUGE PAGES])],
11-
[yes],
12-
[no])
13-
147
PHP_ARG_ENABLE([opcache-jit],
158
[whether to enable JIT],
169
[AS_HELP_STRING([--disable-opcache-jit],
@@ -23,8 +16,6 @@ if test "$PHP_OPCACHE" != "no"; then
2316
dnl Always build as shared extension
2417
ext_shared=yes
2518

26-
AC_CHECK_HEADERS([stdatomic.h])
27-
2819
if test "$PHP_HUGE_CODE_PAGES" = "yes"; then
2920
AC_DEFINE(HAVE_HUGE_CODE_PAGES, 1, [Define to enable copying PHP CODE pages into HUGE PAGES (experimental)])
3021
fi

ext/opcache/jit/zend_jit_perf_dump.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ extern unsigned int thr_self(void);
5252
/*
5353
* 1) Profile using perf-<pid>.map
5454
*
55-
* perf record php -d opcache.huge_code_pages=0 -d opcache.jit_debug=0x10 bench.php
55+
* perf record php -d opcache.jit_debug=0x10 bench.php
5656
* perf report
5757
*
5858
* 2) Profile using jit-<pid>.dump
5959
*
60-
* perf record -k 1 php -d opcache.huge_code_pages=0 -d opcache.jit_debug=0x20 bench.php
60+
* perf record -k 1 php -d opcache.jit_debug=0x20 bench.php
6161
* perf inject -j -i perf.data -o perf.data.jitted
6262
* perf report -i perf.data.jitted
6363
*

ext/opcache/tests/zzz_basic_logging.phpt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ opcache.enable_cli=1
99
opcache.file_cache_only=0
1010
opcache.error_log=
1111
opcache.log_verbosity_level=4
12-
opcache.huge_code_pages=0
1312
opcache.preload=
1413
opcache.interned_strings_buffer=8
1514
--EXTENSIONS--

ext/opcache/zend_accelerator_module.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,6 @@ ZEND_INI_BEGIN()
293293
STD_PHP_INI_BOOLEAN("opcache.file_cache_consistency_checks" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals)
294294
#if ENABLE_FILE_CACHE_FALLBACK
295295
STD_PHP_INI_BOOLEAN("opcache.file_cache_fallback" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_fallback, zend_accel_globals, accel_globals)
296-
#endif
297-
#ifdef HAVE_HUGE_CODE_PAGES
298-
STD_PHP_INI_BOOLEAN("opcache.huge_code_pages" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.huge_code_pages, zend_accel_globals, accel_globals)
299296
#endif
300297
STD_PHP_INI_ENTRY("opcache.preload" , "" , PHP_INI_SYSTEM, OnUpdateStringUnempty, accel_directives.preload, zend_accel_globals, accel_globals)
301298
#ifndef ZEND_WIN32
@@ -807,9 +804,6 @@ ZEND_FUNCTION(opcache_get_configuration)
807804
add_assoc_long(&directives, "opcache.file_update_protection", ZCG(accel_directives).file_update_protection);
808805
add_assoc_long(&directives, "opcache.opt_debug_level", ZCG(accel_directives).opt_debug_level);
809806
add_assoc_string(&directives, "opcache.restrict_api", STRING_NOT_NULL(ZCG(accel_directives).restrict_api));
810-
#ifdef HAVE_HUGE_CODE_PAGES
811-
add_assoc_bool(&directives, "opcache.huge_code_pages", ZCG(accel_directives).huge_code_pages);
812-
#endif
813807
add_assoc_string(&directives, "opcache.preload", STRING_NOT_NULL(ZCG(accel_directives).preload));
814808
#ifndef ZEND_WIN32
815809
add_assoc_string(&directives, "opcache.preload_user", STRING_NOT_NULL(ZCG(accel_directives).preload_user));

php.ini-development

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,10 +1905,6 @@ ldap.max_links = -1
19051905
; cache is required.
19061906
;opcache.file_cache_fallback=1
19071907

1908-
; Enables or disables copying of PHP code (text segment) into HUGE PAGES.
1909-
; This should improve performance, but requires appropriate OS configuration.
1910-
;opcache.huge_code_pages=0
1911-
19121908
; Validate cached file permissions.
19131909
;opcache.validate_permission=0
19141910

php.ini-production

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1907,10 +1907,6 @@ ldap.max_links = -1
19071907
; cache is required.
19081908
;opcache.file_cache_fallback=1
19091909

1910-
; Enables or disables copying of PHP code (text segment) into HUGE PAGES.
1911-
; This should improve performance, but requires appropriate OS configuration.
1912-
;opcache.huge_code_pages=1
1913-
19141910
; Validate cached file permissions.
19151911
;opcache.validate_permission=0
19161912

0 commit comments

Comments
 (0)