The effect of this patch is really exiting to keep it disabled by
default... :)

$ perf stat -e instructions,iTLB-loads,iTLB-load-misses,cycles
sapi/cgi/php-cgi -d opcache.enable_huge_code_pages=0 -T 10000
/var/www/html/bench/wordpress-3.6/index.php > /dev/null

   191,778,620,621      instructions              #    0.81  insns per
cycle
       178,497,016
iTLB-loads
        87,351,276      iTLB-load-misses          #   48.94% of all iTLB
cache hits
   238,136,402,797
cycles

     110.221114219 seconds time elapsed

$ perf stat -e instructions,iTLB-loads,iTLB-load-misses,cycles
sapi/cgi/php-cgi -d opcache.enable_huge_code_pages=1 -T 10000
/var/www/html/bench/wordpress-3.6/index.php > /dev/null

   191,780,181,536      instructions              #    0.83  insns per
cycle
        39,017,004
iTLB-loads
        41,631,359      iTLB-load-misses          #  106.70% of all iTLB
cache hits
   231,287,491,307
cycles

     107.742837269 seconds time elapsed

May be we should enable this by default in RC (may be also file cache) and
make decision based on feedback?

Thanks. Dmtiry.



On Mon, Sep 14, 2015 at 1:34 PM, Dmitry Stogov <dmi...@php.net> wrote:

> Commit:    669f0b39b184593e01e677360fd79b2b63058ca0
> Author:    Dmitry Stogov <dmi...@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)
>
>
> --
> PHP CVS Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>

Reply via email to