]> granicus.if.org Git - php/commitdiff
Reduced initial VM_STACK page size of Generators to 4 KB (256 slots)
authorBob Weinand <bobwei9@hotmail.com>
Sat, 7 Mar 2015 12:07:18 +0000 (13:07 +0100)
committerBob Weinand <bobwei9@hotmail.com>
Sat, 7 Mar 2015 12:25:21 +0000 (13:25 +0100)
Generators all have their own vm_stack, but usually don't go really deep.
In most cases even most of the 4 KB will remain unused (in my tests average is rather 1 KB), but this was tested a straightforward implementation without a lot of abstraction layers.
That way I'm using a more conservative 4 KB stack size which really should be enough for, I think, at least 90% of the cases.
This was necessary to not immediately run out of memory with 95%+ usused vm_stack space: If you have a few thousands of Generators active, your application quickly hits memory_limit with a stack page size of 256 KB...
In addition, it's also a bit faster (70% less instructions for zend_vm_stack_new_page) due to emalloc() not having to allocate a whole new segment (segment size 256 KB). Also no mmap()/malloc() necessary.

Zend/zend_execute.c

index 4dd8e2c6b24514834812441a06d715271ba3b106..1609e7367ce4a14fd4befba4291e5b0e8de472c6 100644 (file)
@@ -123,15 +123,18 @@ static const zend_internal_function zend_pass_function = {
 #define DECODE_CTOR(ce) \
        ((zend_class_entry*)(((zend_uintptr_t)(ce)) & ~(CTOR_CALL_BIT|CTOR_USED_BIT)))
 
-#define ZEND_VM_STACK_PAGE_SLOTS (16 * 1024) /* should be a power of 2 */
+#define ZEND_VM_MAIN_STACK_PAGE_SLOTS (16 * 1024) /* should be a power of 2 */
+#define ZEND_VM_GENERATOR_STACK_PAGE_SLOTS (256)
 
-#define ZEND_VM_STACK_PAGE_SIZE  (ZEND_VM_STACK_PAGE_SLOTS * sizeof(zval))
+#define ZEND_VM_STACK_PAGE_SLOTS(gen) ((gen) ? ZEND_VM_GENERATOR_STACK_PAGE_SLOTS : ZEND_VM_MAIN_STACK_PAGE_SLOTS)
 
-#define ZEND_VM_STACK_FREE_PAGE_SIZE \
-       ((ZEND_VM_STACK_PAGE_SLOTS - ZEND_VM_STACK_HEADER_SLOTS) * sizeof(zval))
+#define ZEND_VM_STACK_PAGE_SIZE(gen)  (ZEND_VM_STACK_PAGE_SLOTS(gen) * sizeof(zval))
 
-#define ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size) \
-       (((size) + (ZEND_VM_STACK_FREE_PAGE_SIZE - 1)) & ~ZEND_VM_STACK_PAGE_SIZE)
+#define ZEND_VM_STACK_FREE_PAGE_SIZE(gen) \
+       ((ZEND_VM_STACK_PAGE_SLOTS(gen) - ZEND_VM_STACK_HEADER_SLOTS) * sizeof(zval))
+
+#define ZEND_VM_STACK_PAGE_ALIGNED_SIZE(gen, size) \
+       (((size) + (ZEND_VM_STACK_FREE_PAGE_SIZE(gen) - 1)) & ~ZEND_VM_STACK_PAGE_SIZE(gen))
 
 static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend_vm_stack prev) {
        zend_vm_stack page = (zend_vm_stack)emalloc(size);
@@ -144,7 +147,7 @@ static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend
 
 ZEND_API void zend_vm_stack_init(void)
 {
-       EG(vm_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE, NULL);
+       EG(vm_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE(0 /* main stack */), NULL);
        EG(vm_stack)->top++;
        EG(vm_stack_top) = EG(vm_stack)->top;
        EG(vm_stack_end) = EG(vm_stack)->end;
@@ -163,14 +166,14 @@ ZEND_API void zend_vm_stack_destroy(void)
 
 ZEND_API void* zend_vm_stack_extend(size_t size)
 {
-    zend_vm_stack stack;
-    void *ptr;
+       zend_vm_stack stack;
+       void *ptr;
 
-    stack = EG(vm_stack);
-    stack->top = EG(vm_stack_top);
+       stack = EG(vm_stack);
+       stack->top = EG(vm_stack_top);
        EG(vm_stack) = stack = zend_vm_stack_new_page(
-               EXPECTED(size < ZEND_VM_STACK_FREE_PAGE_SIZE) ?
-                       ZEND_VM_STACK_PAGE_SIZE : ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size),
+               EXPECTED(size < ZEND_VM_STACK_FREE_PAGE_SIZE(0)) ?
+                       ZEND_VM_STACK_PAGE_SIZE(0) : ZEND_VM_STACK_PAGE_ALIGNED_SIZE(0, size),
                stack);
        ptr = stack->top;
        EG(vm_stack_top) = (void*)(((char*)ptr) + size);
@@ -1934,9 +1937,9 @@ ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data
        size_t stack_size = (ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args)) * sizeof(zval);
 
        EG(vm_stack) = zend_vm_stack_new_page(
-               EXPECTED(stack_size < ZEND_VM_STACK_FREE_PAGE_SIZE) ?
-                       ZEND_VM_STACK_PAGE_SIZE :
-                       ZEND_VM_STACK_PAGE_ALIGNED_SIZE(stack_size),
+               EXPECTED(stack_size < ZEND_VM_STACK_FREE_PAGE_SIZE(1)) ?
+                       ZEND_VM_STACK_PAGE_SIZE(1) :
+                       ZEND_VM_STACK_PAGE_ALIGNED_SIZE(1, stack_size),
                NULL);
        EG(vm_stack_top) = EG(vm_stack)->top;
        EG(vm_stack_end) = EG(vm_stack)->end;