php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #79027
Patch accel_get_hugepage_size revision 2019-12-31 13:32 UTC by chris at neadwerx dot com
Patch PHP7_huge_2mb_flag.patch revision 2019-12-31 12:37 UTC by chris at neadwerx dot com

Patch accel_get_hugepage_size for opcache Bug #79027

Patch version 2019-12-31 13:32 UTC

Return to Bug #79027 | Download this patch
Patch Revisions:

Developer: chris@neadwerx.com

diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 52276010af..305a0d94ac 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -2618,6 +2618,32 @@ static void accel_gen_system_id(void)
 # endif
 
 # if defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE)
+/* Validate the system's default hugepage size by checking
+ * /proc/meminfo. If it's larger than our allocation, we risk
+ * grabbing more memory than we would actually want. We'll be verifying this
+ * against our segment addresses in accel_move_code_to_huge_pages.
+ */
+static void accel_get_hugepage_size(unsigned long int * hugepage_size)
+{
+    FILE * fp = fopen( "/proc/meminfo", "r" );
+    char buf[128];
+    unsigned int size;
+    char c;
+
+    if ( fp ) {
+        while ( fgets( buf, sizeof( buf ), fp ) ) {
+            if ( sscanf( buf, "Hugepagesize: %u %c", &size, &c ) == 2 ) {
+                if ( c == 'k' ) {\
+                    *hugepage_size = size * 1024L;
+                    break;
+                }
+            }
+        }
+
+        fclose( fp );
+    }
+}
+
 static int accel_remap_huge_pages(void *start, size_t size, const char *name, size_t offset)
 {
        void *ret = MAP_FAILED;
@@ -2636,7 +2662,7 @@ static int accel_remap_huge_pages(void *start, size_t size, const char *name, si
        memcpy(mem, start, size);
 
 #  ifdef MAP_HUGETLB
-       ret = mmap(start, size,
+    ret = mmap(start, size,
                PROT_READ | PROT_WRITE | PROT_EXEC,
                MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_HUGETLB,
                -1, 0);
@@ -2682,22 +2708,27 @@ 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;
-
+        accel_get_hugepage_size(&huge_page_size);
                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) {
+                       if (seg_end > seg_start && ( seg_end - seg_start ) < huge_page_size) {
                                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);
-                       }
+                       } else {
+                if (seg_end > seg_start ) {
+                    zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": huge_code_pages: cannot align segment bounds");
+                } else {
+                    zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": system default huge page size too large to be utilized by opcache");
+                }
+            }
                }
                fclose(f);
        }
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Tue Oct 19 16:03:35 2021 UTC