Skip to content

Commit d15d831

Browse files
committed
Use a separate cache for fibers
Avoid poluting the main cache with different-sized pages, and do not clear the main cache when a fiber terminates
1 parent c675c1d commit d15d831

5 files changed

Lines changed: 67 additions & 16 deletions

File tree

Zend/zend_execute.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ ZEND_API void zend_vm_stack_init(void)
193193
EG(vm_stack_page_size) = ZEND_VM_STACK_PAGE_SIZE;
194194
EG(vm_stack_page_cache) = NULL;
195195
EG(vm_stack_page_cache_count) = 0;
196+
EG(fiber_vm_stack_page_cache) = NULL;
197+
EG(fiber_vm_stack_page_cache_count) = 0;
196198
EG(vm_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE, NULL);
197199
EG(vm_stack_top) = EG(vm_stack)->top;
198200
EG(vm_stack_end) = EG(vm_stack)->end;
@@ -205,6 +207,8 @@ ZEND_API void zend_vm_stack_init_ex(size_t page_size)
205207
EG(vm_stack_page_size) = page_size;
206208
EG(vm_stack_page_cache) = NULL;
207209
EG(vm_stack_page_cache_count) = 0;
210+
EG(fiber_vm_stack_page_cache) = NULL;
211+
EG(fiber_vm_stack_page_cache_count) = 0;
208212
EG(vm_stack) = zend_vm_stack_new_page(page_size, NULL);
209213
EG(vm_stack_top) = EG(vm_stack)->top;
210214
EG(vm_stack_end) = EG(vm_stack)->end;
@@ -214,18 +218,28 @@ ZEND_API void zend_vm_stack_destroy(void)
214218
{
215219
zend_vm_stack stack = EG(vm_stack);
216220

221+
while (stack != NULL) {
222+
zend_vm_stack p = stack->prev;
223+
efree(stack);
224+
stack = p;
225+
}
226+
}
227+
228+
ZEND_API void zend_vm_stack_destroy_caches(void)
229+
{
217230
while (EG(vm_stack_page_cache) != NULL) {
218231
zend_vm_stack cached = EG(vm_stack_page_cache);
219232
EG(vm_stack_page_cache) = cached->prev;
220233
efree(cached);
221234
}
222235
EG(vm_stack_page_cache_count) = 0;
223236

224-
while (stack != NULL) {
225-
zend_vm_stack p = stack->prev;
226-
efree(stack);
227-
stack = p;
237+
while (EG(fiber_vm_stack_page_cache) != NULL) {
238+
zend_vm_stack cached = EG(fiber_vm_stack_page_cache);
239+
EG(fiber_vm_stack_page_cache) = cached->prev;
240+
efree(cached);
228241
}
242+
EG(fiber_vm_stack_page_cache_count) = 0;
229243
}
230244

231245
ZEND_API void* zend_vm_stack_extend(size_t size)

Zend/zend_execute.h

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -322,15 +322,39 @@ ZEND_STATIC_ASSERT(ZEND_MM_ALIGNED_SIZE(sizeof(zval)) == sizeof(zval),
322322
ZEND_API void zend_vm_stack_init(void);
323323
ZEND_API void zend_vm_stack_init_ex(size_t page_size);
324324
ZEND_API void zend_vm_stack_destroy(void);
325+
ZEND_API void zend_vm_stack_destroy_caches(void);
325326
ZEND_API void* zend_vm_stack_extend(size_t size);
326327

327-
static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend_vm_stack prev) {
328-
zend_vm_stack page = EG(vm_stack_page_cache);
328+
#define ZEND_FIBER_VM_STACK_SIZE (1024 * sizeof(zval))
329+
330+
static zend_always_inline zend_vm_stack zend_vm_stack_cached_page(size_t size) {
331+
zend_vm_stack page;
329332

330-
if (page != NULL && EXPECTED((size_t)((char*)page->end - (char*)page) == size)) {
331-
EG(vm_stack_page_cache) = page->prev;
332-
EG(vm_stack_page_cache_count)--;
333+
if (size == ZEND_FIBER_VM_STACK_SIZE) {
334+
page = EG(fiber_vm_stack_page_cache);
335+
if (page) {
336+
ZEND_ASSERT((size_t)((char*)page->end - (char*)page) == size);
337+
EG(fiber_vm_stack_page_cache) = page->prev;
338+
EG(fiber_vm_stack_page_cache_count)--;
339+
return page;
340+
}
333341
} else {
342+
page = EG(vm_stack_page_cache);
343+
ZEND_ASSERT(!page || ((size_t)((char*)page->end - (char*)page) == size) || size != EG(vm_stack_page_size));
344+
if (page && EXPECTED((size_t)((char*)page->end - (char*)page) == size)) {
345+
EG(vm_stack_page_cache) = page->prev;
346+
EG(vm_stack_page_cache_count)--;
347+
return page;
348+
}
349+
}
350+
351+
return NULL;
352+
}
353+
354+
static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend_vm_stack prev) {
355+
zend_vm_stack page = zend_vm_stack_cached_page(size);
356+
357+
if (!page) {
334358
page = (zend_vm_stack)emalloc(size);
335359
}
336360

@@ -428,13 +452,23 @@ static zend_always_inline void zend_vm_stack_free_call_frame_ex(uint32_t call_in
428452
EG(vm_stack_top) = prev->top;
429453
EG(vm_stack_end) = prev->end;
430454
EG(vm_stack) = prev;
431-
if (EG(vm_stack_page_cache_count) < 32
432-
&& (size_t)((char*)p->end - (char*)p) == EG(vm_stack_page_size)) {
433-
p->prev = EG(vm_stack_page_cache);
434-
EG(vm_stack_page_cache) = p;
435-
EG(vm_stack_page_cache_count)++;
455+
if ((size_t)((char*)p->end - (char*)p) == ZEND_FIBER_VM_STACK_SIZE) {
456+
if (EG(fiber_vm_stack_page_cache_count) < 32) {
457+
p->prev = EG(fiber_vm_stack_page_cache);
458+
EG(fiber_vm_stack_page_cache) = p;
459+
EG(fiber_vm_stack_page_cache_count)++;
460+
} else {
461+
efree(p);
462+
}
436463
} else {
437-
efree(p);
464+
if (EG(vm_stack_page_cache_count) < 32
465+
&& (size_t)((char*)p->end - (char*)p) == EG(vm_stack_page_size)) {
466+
p->prev = EG(vm_stack_page_cache);
467+
EG(vm_stack_page_cache) = p;
468+
EG(vm_stack_page_cache_count)++;
469+
} else {
470+
efree(p);
471+
}
438472
}
439473
} else {
440474
EG(vm_stack_top) = (zval*)call;

Zend/zend_execute_API.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ void shutdown_executor(void) /* {{{ */
482482
zend_hash_discard(EG(class_table), EG(persistent_classes_count));
483483
} else {
484484
zend_vm_stack_destroy();
485+
zend_vm_stack_destroy_caches();
485486

486487
if (EG(full_tables_cleanup)) {
487488
zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);

Zend/zend_fibers.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#define ZEND_FIBER_GUARD_PAGES 1
2626

2727
#define ZEND_FIBER_DEFAULT_C_STACK_SIZE (4096 * (((sizeof(void *)) < 8) ? 256 : 512))
28-
#define ZEND_FIBER_VM_STACK_SIZE (1024 * sizeof(zval))
2928

3029
BEGIN_EXTERN_C()
3130

Zend/zend_globals.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,9 @@ struct _zend_executor_globals {
204204
size_t vm_stack_page_size;
205205
zend_vm_stack vm_stack_page_cache;
206206
uint32_t vm_stack_page_cache_count;
207+
/* Fibers use a different page size, so they need a separate cache */
208+
zend_vm_stack fiber_vm_stack_page_cache;
209+
uint32_t fiber_vm_stack_page_cache_count;
207210

208211
struct _zend_execute_data *current_execute_data;
209212
const zend_class_entry *fake_scope; /* used to avoid checks accessing properties */

0 commit comments

Comments
 (0)