Skip to content

Commit b6a1e1c

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 371ae12 commit b6a1e1c

File tree

8 files changed

+2
-216
lines changed

8 files changed

+2
-216
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"
@@ -2947,174 +2946,6 @@ static void accel_globals_ctor(zend_accel_globals *accel_globals)
29472946
memset(accel_globals, 0, sizeof(zend_accel_globals));
29482947
}
29492948

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

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

ext/opcache/ZendAccelerator.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,6 @@ typedef struct _zend_accel_directives {
186186
bool file_cache_consistency_checks;
187187
#if ENABLE_FILE_CACHE_FALLBACK
188188
bool file_cache_fallback;
189-
#endif
190-
#ifdef HAVE_HUGE_CODE_PAGES
191-
bool huge_code_pages;
192189
#endif
193190
char *preload;
194191
#ifndef ZEND_WIN32

ext/opcache/config.m4

Lines changed: 0 additions & 7 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],

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 & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,15 +1914,6 @@ ldap.max_links = -1
19141914
; cache is required.
19151915
;opcache.file_cache_fallback=1
19161916

1917-
; Enables or disables copying of PHP code (text segment) into HUGE PAGES.
1918-
; Under certain circumstances (if only a single global PHP process is
1919-
; started from which all others fork), this can increase performance
1920-
; by a tiny amount because TLB misses are reduced. On the other hand, this
1921-
; delays PHP startup, increases memory usage and degrades performance
1922-
; under memory pressure - use with care.
1923-
; Requires appropriate OS configuration.
1924-
;opcache.huge_code_pages=0
1925-
19261917
; Validate cached file permissions.
19271918
;opcache.validate_permission=0
19281919

php.ini-production

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,15 +1916,6 @@ ldap.max_links = -1
19161916
; cache is required.
19171917
;opcache.file_cache_fallback=1
19181918

1919-
; Enables or disables copying of PHP code (text segment) into HUGE PAGES.
1920-
; Under certain circumstances (if only a single global PHP process is
1921-
; started from which all others fork), this can increase performance
1922-
; by a tiny amount because TLB misses are reduced. On the other hand, this
1923-
; delays PHP startup, increases memory usage and degrades performance
1924-
; under memory pressure - use with care.
1925-
; Requires appropriate OS configuration.
1926-
;opcache.huge_code_pages=0
1927-
19281919
; Validate cached file permissions.
19291920
;opcache.validate_permission=0
19301921

0 commit comments

Comments
 (0)