com php-src: Added an experemental ability to move PHP code pages (PHP TEXT segment) into HUGE pages. PHP should be configured and built with
--enable-huge-code-pages, OS should be configured to provide huge pages. It's possible to enable/disable this future in php.ini through
opcache.enable_huge_code_pages=0/1. The fea ture was tested on Linux and provided 2% im provement on real-life apps, because of 2-3 times reduction
in number of iTLB misses.:

From: Date: Mon, 14 Sep 2015 10:34:17 +0000
Subject: com php-src: Added an experemental ability to move PHP code pages (PHP TEXT segment) into HUGE pages. PHP should be configured and built with
--enable-huge-code-pages, OS should be configured to provide huge pages. It's possible to enable/disable this future in php.ini through
opcache.enable_huge_code_pages=0/1. The fea ture was tested on Linux and provided 2% im provement on real-life apps, because of 2-3 times reduction
in number of iTLB misses.:
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-89014@lists.php.net to get a copy of this message
Commit: 669f0b39b184593e01e677360fd79b2b63058ca0 Author: Dmitry Stogov <dmitry@zend.com> Mon, 14 Sep 2015 13:34:17 +0300 Parents: 145708b658d0a60b738dde1a942dea9032f2f54e Branches: master Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=669f0b39b184593e01e677360fd79b2b63058ca0 Log: Added an experemental ability to move PHP code pages (PHP TEXT segment) into HUGE pages. PHP should be configured and built with --enable-huge-code-pages, OS should be configured to provide huge pages. It's possible to enable/disable this future in php.ini through opcache.enable_huge_code_pages=0/1. The feature was tested on Linux and provided 2% improvement on real-life apps, because of 2-3 times reduction in number of iTLB misses. Changed paths: M ext/opcache/ZendAccelerator.c M ext/opcache/ZendAccelerator.h M ext/opcache/config..m4 M ext/opcache/zend_accelerator_module.c Diff: diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 905700e..2c3d9a4 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -2480,6 +2480,92 @@ static void accel_gen_system_id(void) } #endif +#ifdef HAVE_HUGE_CODE_PAGES +# ifndef _WIN32 +# include <sys/mman.h> +# include <sys/prctl.h> +# ifndef MAP_ANON +# ifdef MAP_ANONYMOUS +# define MAP_ANON MAP_ANONYMOUS +# endif +# endif +# ifndef MAP_FAILED +# define MAP_FAILED ((void*)-1) +# endif +# endif + +# if defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE) +static int accel_remap_huge_pages(void *start, size_t size, const char *name, size_t offset) +{ + void *ret = MAP_FAILED; + void *mem; + int fd; + + fd = open(name, O_RDONLY); + if (fd < 0) { + return -1; + } + mem = mmap(NULL, size, + PROT_READ, + MAP_PRIVATE | MAP_FILE | MAP_POPULATE, + fd, offset); + if (mem == MAP_FAILED) { + close(fd); + return -1; + } + +#ifdef MAP_HUGETLB + ret = mmap(start, size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_HUGETLB, + -1, 0); +#endif +#ifdef MADV_HUGEPAGE + if (ret == MAP_FAILED) { + ret = mmap(start, size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, + -1, 0); + madvise(start, size, MADV_HUGEPAGE); + } +#endif + if (ret == start) { + memcpy(start, mem, size); + mprotect(start, size, PROT_READ | PROT_EXEC); + } + munmap(mem, size); + close(fd); + + return (ret == start) ? 0 : -1; +} + +static void accel_move_code_to_huge_pages(void) +{ + FILE *f; + long unsigned int huge_page_size = 2 * 1024 * 1024; + + f = fopen("/proc/self/maps", "r"); + if (f) { + long unsigned int start, end, offset, inode; + char perm[5], dev[6], name[MAXPATHLEN]; + int ret; + + ret = fscanf(f, "%lx-%lx %4s %lx %5s %ld %s\n", &start, &end, perm, &offset, dev, &inode, name); + if (ret == 7 && perm[0] == 'r' && perm[1] == '-' && perm[2] == 'x' && name[0] == '/') { + long unsigned int seg_start = ZEND_MM_ALIGNED_SIZE_EX(start, huge_page_size); + long unsigned int seg_end = (end & ~(huge_page_size-1L)); + + if (seg_end > seg_start) { + zend_accel_error(ACCEL_LOG_DEBUG, "remap to huge page %lx-%lx %s \n", seg_start, seg_end, name); + accel_remap_huge_pages((void*)seg_start, seg_end - seg_start, name, offset + seg_start - start); + } + } + fclose(f); + } +} +# endif +#endif /* HAVE_HUGE_CODE_PAGES */ + static int accel_startup(zend_extension *extension) { zend_function *func; @@ -2505,6 +2591,16 @@ static int accel_startup(zend_extension *extension) accel_gen_system_id(); #endif +#ifdef HAVE_HUGE_CODE_PAGES + if (ZCG(accel_directives).enable_huge_code_pages && + (strcmp(sapi_module.name, "cli") == 0 || + strcmp(sapi_module.name, "cli-server") == 0 || + strcmp(sapi_module.name, "cgi-fcgi") == 0 || + strcmp(sapi_module.name, "fpm-fcgi") == 0)) { + accel_move_code_to_huge_pages(); + } +#endif + /* no supported SAPI found - disable acceleration and stop initialization */ if (accel_find_sapi() == FAILURE) { accel_startup_ok = 0; diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index 6ce4613..da3fc66 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -219,6 +219,9 @@ typedef struct _zend_accel_directives { zend_bool file_cache_only; zend_bool file_cache_consistency_checks; #endif +#ifdef HAVE_HUGE_CODE_PAGES + zend_bool enable_huge_code_pages; +#endif } zend_accel_directives; typedef struct _zend_accel_globals { diff --git a/ext/opcache/config.m4 b/ext/opcache/config.m4 index 856f24a..d8f84e2 100644 --- a/ext/opcache/config.m4 +++ b/ext/opcache/config..m4 @@ -8,12 +8,19 @@ PHP_ARG_ENABLE(opcache, whether to enable Zend OPcache support, PHP_ARG_ENABLE(opcache-file, whether to enable file based caching (experimental), [ --enable-opcache-file Enable file based caching], no) +PHP_ARG_ENABLE(huge-code-pages, whether to enable copying PHP CODE pages into HUGE PAGES (experimental), +[ --enable-huge-code-pages Enable copying PHP CODE pages into HUGE PAGES], no) + if test "$PHP_OPCACHE" != "no"; then if test "$PHP_OPCACHE_FILE" == "yes"; then AC_DEFINE(HAVE_OPCACHE_FILE_CACHE, 1, [Define to enable file based caching (experimental)]) fi + if test "$PHP_HUGE_CODE_PAGES" == "yes"; then + AC_DEFINE(HAVE_HUGE_CODE_PAGES, 1, [Define to enable copying PHP CODE pages into HUGE PAGES (experimental)]) + fi + AC_CHECK_FUNC(mprotect,[ AC_DEFINE(HAVE_MPROTECT, 1, [Define if you have mprotect() function]) ]) diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index eb93f59...5dfa8c1 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -309,6 +309,9 @@ ZEND_INI_BEGIN() STD_PHP_INI_ENTRY("opcache.file_cache_only" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_only, zend_accel_globals, accel_globals) STD_PHP_INI_ENTRY("opcache.file_cache_consistency_checks" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.file_cache_consistency_checks, zend_accel_globals, accel_globals) #endif +#ifdef HAVE_HUGE_CODE_PAGES + STD_PHP_INI_BOOLEAN("opcache.enable_huge_code_pages" , "1" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_huge_code_pages, zend_accel_globals, accel_globals) +#endif ZEND_INI_END() static int filename_is_in_cache(zend_string *filename)

« previous php.cvs (#89014) next »