From 7632a411e3b839e6a438aa1367ec3d6f310d3d90 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 28 Jun 2019 10:19:18 +0200 Subject: Add tracked arena allocator Available under -DZEND_TRACK_ARENA_ALLOC. This will use the system allocator combined with arena checkpointing & release semantics and allows analyzing arena usage under asan/valgrind. I've sacrificed the duplicate arena implementation in mysqlnd, as the integration with mysqlnd alloc is not worth the code duplication to me. --- ext/mysqlnd/mysqlnd_block_alloc.c | 96 ++++++--------------------------------- 1 file changed, 15 insertions(+), 81 deletions(-) (limited to 'ext/mysqlnd') diff --git a/ext/mysqlnd/mysqlnd_block_alloc.c b/ext/mysqlnd/mysqlnd_block_alloc.c index bce28a0330..63a48f4faa 100644 --- a/ext/mysqlnd/mysqlnd_block_alloc.c +++ b/ext/mysqlnd/mysqlnd_block_alloc.c @@ -24,83 +24,13 @@ #include "mysqlnd_debug.h" #include "mysqlnd_priv.h" - -/* {{{ mysqlnd_arena_create */ -static zend_always_inline zend_arena* mysqlnd_arena_create(size_t size) -{ - zend_arena *arena = (zend_arena*)mnd_emalloc(size); - - arena->ptr = (char*) arena + ZEND_MM_ALIGNED_SIZE(sizeof(zend_arena)); - arena->end = (char*) arena + size; - arena->prev = NULL; - return arena; -} -/* }}} */ - -/* {{{ mysqlnd_arena_destroy */ -static zend_always_inline void mysqlnd_arena_destroy(zend_arena *arena) -{ - do { - zend_arena *prev = arena->prev; - mnd_efree(arena); - arena = prev; - } while (arena); -} -/* }}} */ - -/* {{{ mysqlnd_arena_alloc */ -static zend_always_inline void* mysqlnd_arena_alloc(zend_arena **arena_ptr, size_t size) -{ - zend_arena *arena = *arena_ptr; - char *ptr = arena->ptr; - - size = ZEND_MM_ALIGNED_SIZE(size); - - if (EXPECTED(size <= (size_t)(arena->end - ptr))) { - arena->ptr = ptr + size; - } else { - size_t arena_size = - UNEXPECTED((size + ZEND_MM_ALIGNED_SIZE(sizeof(zend_arena))) > (size_t)(arena->end - (char*) arena)) ? - (size + ZEND_MM_ALIGNED_SIZE(sizeof(zend_arena))) : - (size_t)(arena->end - (char*) arena); - zend_arena *new_arena = (zend_arena*)mnd_emalloc(arena_size); - - ptr = (char*) new_arena + ZEND_MM_ALIGNED_SIZE(sizeof(zend_arena)); - new_arena->ptr = (char*) new_arena + ZEND_MM_ALIGNED_SIZE(sizeof(zend_arena)) + size; - new_arena->end = (char*) new_arena + arena_size; - new_arena->prev = arena; - *arena_ptr = new_arena; - } - - return (void*) ptr; -} -/* }}} */ - -static zend_always_inline void* mysqlnd_arena_checkpoint(zend_arena *arena) -{ - return arena->ptr; -} - -static zend_always_inline void mysqlnd_arena_release(zend_arena **arena_ptr, void *checkpoint) -{ - zend_arena *arena = *arena_ptr; - - while (UNEXPECTED((char*)checkpoint > arena->end) || - UNEXPECTED((char*)checkpoint <= (char*)arena)) { - zend_arena *prev = arena->prev; - mnd_efree(arena); - *arena_ptr = arena = prev; - } - ZEND_ASSERT((char*)checkpoint > (char*)arena && (char*)checkpoint <= arena->end); - arena->ptr = (char*)checkpoint; -} - /* {{{ mysqlnd_mempool_free_chunk */ static void mysqlnd_mempool_free_chunk(MYSQLND_MEMORY_POOL * pool, void * ptr) { DBG_ENTER("mysqlnd_mempool_free_chunk"); /* Try to back-off and guess if this is the last block allocated */ +#ifndef ZEND_TRACK_ARENA_ALLOC if (ptr == pool->last) { /* This was the last allocation. Lucky us, we can free @@ -109,6 +39,7 @@ mysqlnd_mempool_free_chunk(MYSQLND_MEMORY_POOL * pool, void * ptr) pool->arena->ptr = (char*)ptr; pool->last = NULL; } +#endif DBG_VOID_RETURN; } /* }}} */ @@ -120,6 +51,7 @@ mysqlnd_mempool_resize_chunk(MYSQLND_MEMORY_POOL * pool, void * ptr, size_t old_ { DBG_ENTER("mysqlnd_mempool_resize_chunk"); +#ifndef ZEND_TRACK_ARENA_ALLOC /* Try to back-off and guess if this is the last block allocated */ if (ptr == pool->last && (ZEND_MM_ALIGNED_SIZE(size) <= ((char*)pool->arena->end - (char*)ptr))) { @@ -128,11 +60,13 @@ mysqlnd_mempool_resize_chunk(MYSQLND_MEMORY_POOL * pool, void * ptr, size_t old_ a bit of memory from the pool. Next time we will return from the same ptr. */ pool->arena->ptr = (char*)ptr + ZEND_MM_ALIGNED_SIZE(size); - } else { - void *new_ptr = mysqlnd_arena_alloc(&pool->arena, size); - memcpy(new_ptr, ptr, MIN(old_size, size)); - pool->last = ptr = new_ptr; + DBG_RETURN(ptr); } +#endif + + void *new_ptr = zend_arena_alloc(&pool->arena, size); + memcpy(new_ptr, ptr, MIN(old_size, size)); + pool->last = ptr = new_ptr; DBG_RETURN(ptr); } /* }}} */ @@ -145,7 +79,7 @@ mysqlnd_mempool_get_chunk(MYSQLND_MEMORY_POOL * pool, size_t size) void *ptr = NULL; DBG_ENTER("mysqlnd_mempool_get_chunk"); - ptr = mysqlnd_arena_alloc(&pool->arena, size); + ptr = zend_arena_alloc(&pool->arena, size); pool->last = ptr; DBG_RETURN(ptr); @@ -161,8 +95,8 @@ mysqlnd_mempool_create(size_t arena_size) MYSQLND_MEMORY_POOL * ret; DBG_ENTER("mysqlnd_mempool_create"); - arena = mysqlnd_arena_create(MAX(arena_size, sizeof(zend_arena))); - ret = mysqlnd_arena_alloc(&arena, sizeof(MYSQLND_MEMORY_POOL)); + arena = zend_arena_create(MAX(arena_size, sizeof(zend_arena))); + ret = zend_arena_alloc(&arena, sizeof(MYSQLND_MEMORY_POOL)); ret->arena = arena; ret->last = NULL; ret->checkpoint = NULL; @@ -180,7 +114,7 @@ mysqlnd_mempool_destroy(MYSQLND_MEMORY_POOL * pool) { DBG_ENTER("mysqlnd_mempool_destroy"); /* mnd_free will reference LOCK_access and might crash, depending on the caller...*/ - mysqlnd_arena_destroy(pool->arena); + zend_arena_destroy(pool->arena); DBG_VOID_RETURN; } /* }}} */ @@ -190,7 +124,7 @@ PHPAPI void mysqlnd_mempool_save_state(MYSQLND_MEMORY_POOL * pool) { DBG_ENTER("mysqlnd_mempool_save_state"); - pool->checkpoint = mysqlnd_arena_checkpoint(pool->arena); + pool->checkpoint = zend_arena_checkpoint(pool->arena); DBG_VOID_RETURN; } /* }}} */ @@ -201,7 +135,7 @@ mysqlnd_mempool_restore_state(MYSQLND_MEMORY_POOL * pool) { DBG_ENTER("mysqlnd_mempool_restore_state"); if (pool->checkpoint) { - mysqlnd_arena_release(&pool->arena, pool->checkpoint); + zend_arena_release(&pool->arena, pool->checkpoint); pool->last = NULL; pool->checkpoint = NULL; } -- cgit v1.2.1