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: | Dmitry Stogov | 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)