Hey:

On Mon, Sep 14, 2015 at 6:57 PM, Dmitry Stogov <dmi...@zend.com> wrote:
> 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?
>
For me, it is a safe improvement,  and it shouldn't break any
functions (except the perf report/anno symbols lost, which actually is
a limitation by current perf tool self , maybe it could be fixed
later).

and it give us a significant improvement,  I'd like to see it to be
enabled by default.

thanks
> 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
>>
>



-- 
Xinchen Hui
@Laruence
http://www.laruence.com/

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to