Skip to content

Commit a7ce02e

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 a7ce02e

5 files changed

Lines changed: 57 additions & 14 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: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -322,15 +322,31 @@ 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

328+
#define ZEND_FIBER_VM_STACK_SIZE (1024 * sizeof(zval))
329+
327330
static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend_vm_stack prev) {
328331
zend_vm_stack page = EG(vm_stack_page_cache);
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+
}
333340
} else {
341+
page = EG(vm_stack_page_cache);
342+
ZEND_ASSERT(!page || ((size_t)((char*)page->end - (char*)page) == size) || size != EG(vm_stack_page_size));
343+
if (page && EXPECTED((size_t)((char*)page->end - (char*)page) == size)) {
344+
EG(vm_stack_page_cache) = page->prev;
345+
EG(vm_stack_page_cache_count)--;
346+
}
347+
}
348+
349+
if (!page) {
334350
page = (zend_vm_stack)emalloc(size);
335351
}
336352

@@ -428,13 +444,23 @@ static zend_always_inline void zend_vm_stack_free_call_frame_ex(uint32_t call_in
428444
EG(vm_stack_top) = prev->top;
429445
EG(vm_stack_end) = prev->end;
430446
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)++;
447+
if ((size_t)((char*)p->end - (char*)p) == ZEND_FIBER_VM_STACK_SIZE) {
448+
if (EG(fiber_vm_stack_page_cache_count) < 32) {
449+
p->prev = EG(fiber_vm_stack_page_cache);
450+
EG(fiber_vm_stack_page_cache) = p;
451+
EG(fiber_vm_stack_page_cache_count)++;
452+
} else {
453+
efree(p);
454+
}
436455
} else {
437-
efree(p);
456+
if (EG(vm_stack_page_cache_count) < 32
457+
&& (size_t)((char*)p->end - (char*)p) == EG(vm_stack_page_size)) {
458+
p->prev = EG(vm_stack_page_cache);
459+
EG(vm_stack_page_cache) = p;
460+
EG(vm_stack_page_cache_count)++;
461+
} else {
462+
efree(p);
463+
}
438464
}
439465
} else {
440466
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)