From 380c082e32321b306a42897913b8c13520d0461f Mon Sep 17 00:00:00 2001 From: Andi Gutmans Date: Sun, 16 Jun 2002 17:17:47 +0000 Subject: [PATCH] - Commit an initial version of a home made memory manager. - It's just for seeing if this would be an advantage to PHP in MT - environments. If this is to become production material there is still - a long way to go. --- Zend/ZendTS.dsp | 8 ++ Zend/zend_alloc.c | 17 ++- Zend/zend_globals.h | 4 + Zend/zend_mm.c | 320 ++++++++++++++++++++++++++++++++++++++++++++ Zend/zend_mm.h | 31 +++++ 5 files changed, 376 insertions(+), 4 deletions(-) create mode 100644 Zend/zend_mm.c create mode 100644 Zend/zend_mm.h diff --git a/Zend/ZendTS.dsp b/Zend/ZendTS.dsp index 50e3ad956b..fecc69baea 100644 --- a/Zend/ZendTS.dsp +++ b/Zend/ZendTS.dsp @@ -212,6 +212,10 @@ SOURCE=.\zend_llist.c # End Source File # Begin Source File +SOURCE=.\zend_mm.c +# End Source File +# Begin Source File + SOURCE=.\zend_object_handlers.c # End Source File # Begin Source File @@ -368,6 +372,10 @@ SOURCE=.\zend_llist.h # End Source File # Begin Source File +SOURCE=.\zend_mm.h +# End Source File +# Begin Source File + SOURCE=.\zend_modules.h # End Source File # Begin Source File diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index b24e31c2a1..8c4e3e187e 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -31,6 +31,8 @@ # include #endif +#include "zend_mm.h" + #ifndef ZTS ZEND_API zend_alloc_globals alloc_globals; #endif @@ -38,8 +40,11 @@ ZEND_API zend_alloc_globals alloc_globals; #define ZEND_DISABLE_MEMORY_CACHE 0 - -#ifdef ZEND_WIN32 +#if ZEND_MM +#define ZEND_DO_MALLOC(size) zend_mm_alloc(&AG(mm_heap), size) +#define ZEND_DO_FREE(ptr) zend_mm_free(&AG(mm_heap), ptr) +#define ZEND_DO_REALLOC(ptr, size) zend_mm_realloc(&AG(mm_heap), ptr, size) +#elif defined(ZEND_WIN32) #define ZEND_DO_MALLOC(size) (AG(memory_heap) ? HeapAlloc(AG(memory_heap), HEAP_NO_SERIALIZE, size) : malloc(size)) #define ZEND_DO_FREE(ptr) (AG(memory_heap) ? HeapFree(AG(memory_heap), HEAP_NO_SERIALIZE, ptr) : free(ptr)) #define ZEND_DO_REALLOC(ptr, size) (AG(memory_heap) ? HeapReAlloc(AG(memory_heap), HEAP_NO_SERIALIZE, ptr, size) : realloc(ptr, size)) @@ -415,7 +420,9 @@ ZEND_API void start_memory_manager(TSRMLS_D) memset(AG(fast_cache_list_head), 0, sizeof(AG(fast_cache_list_head))); memset(AG(cache_count), 0, sizeof(AG(cache_count))); -#ifdef ZEND_WIN32 +#if ZEND_MM + zend_mm_startup(&AG(mm_heap), 256*1024); +#elif defined(ZEND_WIN32) AG(memory_heap) = HeapCreate(HEAP_NO_SERIALIZE, 256*1024, 0); #endif @@ -454,7 +461,9 @@ ZEND_API void shutdown_memory_manager(int silent, int clean_cache TSRMLS_DC) #endif zend_fast_cache_list_entry *fast_cache_list_entry, *next_fast_cache_list_entry; -#if defined(ZEND_WIN32) && !ZEND_DEBUG +#if ZEND_MM + return; +#elif defined(ZEND_WIN32) && !ZEND_DEBUG if (clean_cache && AG(memory_heap)) { HeapDestroy(AG(memory_heap)); return; diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index b133dfe5c0..8c3e53f016 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -209,6 +209,7 @@ struct _zend_executor_globals { void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; +#include "zend_mm.h" struct _zend_alloc_globals { zend_mem_header *head; /* standard list */ @@ -232,6 +233,9 @@ struct _zend_alloc_globals { unsigned int allocated_memory_peak; unsigned char memory_exhausted; #endif +#if ZEND_MM + zend_mm_heap mm_heap; +#endif }; struct _zend_scanner_globals { diff --git a/Zend/zend_mm.c b/Zend/zend_mm.c new file mode 100644 index 0000000000..17d8c5f167 --- /dev/null +++ b/Zend/zend_mm.c @@ -0,0 +1,320 @@ +#include +#include "zend_mm.h" + +#if WIN32|WINNT +# ifndef inline +# define inline __inline +# endif +#endif + +#define ZEND_MM_FREE_BLOCK 0 +#define ZEND_MM_USED_BLOCK 1 + + +/* Platform alignment test */ +typedef union _mm_align_test { + void *ptr; + double dbl; + long lng; +} mm_align_test; + +#if (defined (__GNUC__) && __GNUC__ >= 2) +#define ZEND_MM_ALIGNMENT (__alignof__ (mm_align_test)) +#else +#define ZEND_MM_ALIGNMENT (sizeof(mm_align_test)) +#endif + + +/* Aligned header size */ +#define ZEND_MM_ALIGNED_SIZE(size) (size+(((ZEND_MM_ALIGNMENT-size)%ZEND_MM_ALIGNMENT+ZEND_MM_ALIGNMENT)%ZEND_MM_ALIGNMENT)) +#define ZEND_MM_ALIGNED_HEADER_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_block)) + + +/* Memory calculations */ +#define ZEND_MM_BLOCK_AT(blk, offset) ((zend_mm_block *) (((char *) (blk))+(offset))) +#define ZEND_MM_DATA_OF(p) ((void *) (((char *) (p))+ZEND_MM_ALIGNED_HEADER_SIZE)) +#define ZEND_MM_HEADER_OF(blk) ZEND_MM_BLOCK_AT(blk, -(int)ZEND_MM_ALIGNED_HEADER_SIZE) + +/* Debug output */ +#define ZEND_MM_DEBUG(stmt) + + +static inline void zend_mm_add_to_free_list(zend_mm_heap *heap, zend_mm_block *mm_block) +{ + mm_block->next_free_block = heap->free_list; + mm_block->prev_free_block = NULL; + heap->free_list = mm_block; + + if (mm_block->next_free_block) { + mm_block->next_free_block->prev_free_block = mm_block; + } +} + + +static inline void zend_mm_remove_from_free_list(zend_mm_heap *heap, zend_mm_block *mm_block) +{ + if (mm_block->prev_free_block) { + mm_block->prev_free_block->next_free_block = mm_block->next_free_block; + } else { + heap->free_list = mm_block->next_free_block; + } + + if (mm_block->next_free_block) { + mm_block->next_free_block->prev_free_block = mm_block->prev_free_block; + } +} + + +zend_bool zend_mm_add_memory_block(zend_mm_heap *heap, size_t block_size) +{ + zend_mm_block *mm_block; + zend_mm_block *guard_block; + + /* align block size downwards */ + block_size -= block_size % ZEND_MM_ALIGNMENT; + + mm_block = (zend_mm_block *) malloc(block_size); + if (!mm_block) { + return 1; + } + mm_block->size = block_size - ZEND_MM_ALIGNED_HEADER_SIZE; /* keep one guard block in the end */ + mm_block->type = ZEND_MM_FREE_BLOCK; + mm_block->prev_size = 0; /* Size is always at least ZEND_MM_ALIGNED_HEADER_SIZE big (>0) so 0 is OK */ + + /* setup guard block */ + guard_block = ZEND_MM_BLOCK_AT(mm_block, mm_block->size); + guard_block->type = ZEND_MM_USED_BLOCK; + guard_block->size = ZEND_MM_ALIGNED_HEADER_SIZE; + guard_block->prev_size = mm_block->size; + ZEND_MM_DEBUG(("Setup guard block at 0x%0.8X\n", guard_block)); + + zend_mm_add_to_free_list(heap, mm_block); + + return 0; +} + +/* Notes: + * - This function may alter the block_sizes values to match platform alignment + * - This function does *not* perform sanity checks on the arguments + */ +zend_bool zend_mm_startup(zend_mm_heap *heap, size_t block_size) +{ + block_size -= block_size % ZEND_MM_ALIGNMENT; + heap->block_size = block_size; + heap->free_list = NULL; + + if (zend_mm_add_memory_block(heap, block_size)) { + return 1; + } + + return 0; +} + + +void zend_mm_shutdown(zend_mm_heap *heap) +{ +} + +void *zend_mm_alloc(zend_mm_heap *heap, size_t size) +{ + size_t true_size; + zend_mm_block *p, *best_fit=NULL, *new_free_block; + size_t remaining_size; + + true_size = ZEND_MM_ALIGNED_SIZE(size)+ZEND_MM_ALIGNED_HEADER_SIZE; + for (p = heap->free_list; p; p = p->next_free_block) { + if (p->size == true_size) { + best_fit = p; + break; + } + if ((p->size > true_size) && (!best_fit || (best_fit->size > p->size))) { /* better fit */ + best_fit = p; + } + } + if (!best_fit) { + if (true_size > (heap->block_size - ZEND_MM_ALIGNED_HEADER_SIZE)) { + /* Make sure we add a memory block which is big enough */ + zend_mm_add_memory_block(heap, true_size + ZEND_MM_ALIGNED_HEADER_SIZE); + } else { + zend_mm_add_memory_block(heap, heap->block_size); + } + return zend_mm_alloc(heap, size); + } + + /* mark as used */ + best_fit->type = ZEND_MM_USED_BLOCK; + + /* remove from free list */ + zend_mm_remove_from_free_list(heap, best_fit); + + /* calculate sizes */ + remaining_size = best_fit->size - true_size; + + if (remaining_size < ZEND_MM_ALIGNED_HEADER_SIZE) { + /* keep best_fit->size as is, it'll include this extra space */ + return ZEND_MM_DATA_OF(best_fit); + } + + /* prepare new free block */ + best_fit->size = true_size; + new_free_block = ZEND_MM_BLOCK_AT(best_fit, best_fit->size); + + new_free_block->type = ZEND_MM_FREE_BLOCK; + new_free_block->size = remaining_size; + new_free_block->prev_size = true_size; + + /* update the next block's prev_size */ + ZEND_MM_BLOCK_AT(new_free_block, new_free_block->size)->prev_size = new_free_block->size; + + /* add the new free block to the free list */ + zend_mm_add_to_free_list(heap, new_free_block); + + return ZEND_MM_DATA_OF(best_fit); +} + + +void zend_mm_free(zend_mm_heap *heap, void *p) +{ + zend_mm_block *mm_block = ZEND_MM_HEADER_OF(p); + zend_mm_block *prev_block, *next_block; + int in_free_list=0; + + if (mm_block->type!=ZEND_MM_USED_BLOCK) { + /* error */ + return; + } + + next_block = ZEND_MM_BLOCK_AT(mm_block, mm_block->size); + + /* merge with previous block if empty */ + if (mm_block->prev_size != 0 + && (prev_block=ZEND_MM_BLOCK_AT(mm_block, -(int)mm_block->prev_size))->type == ZEND_MM_FREE_BLOCK) { + prev_block->size += mm_block->size; + mm_block = prev_block; + next_block->prev_size = mm_block->size; + in_free_list = 1; /* linked two ways */ + } + + /* merge with the next block if empty */ + if (next_block->type == ZEND_MM_FREE_BLOCK) { + mm_block->size += next_block->size; + zend_mm_remove_from_free_list(heap, next_block); + next_block = ZEND_MM_BLOCK_AT(mm_block, mm_block->size); /* recalculate */ + next_block->prev_size = mm_block->size; + } + + mm_block->type = ZEND_MM_FREE_BLOCK; + if (!in_free_list) { + zend_mm_add_to_free_list(heap, mm_block); + } +} + +void *zend_mm_realloc(zend_mm_heap *heap, void *p, size_t size) +{ + void *ptr; + zend_mm_block *mm_block = ZEND_MM_HEADER_OF(p); + size_t true_size = ZEND_MM_ALIGNED_SIZE(size)+ZEND_MM_ALIGNED_HEADER_SIZE; + + if (true_size <= mm_block->size) { + return p; + } + ptr = zend_mm_alloc(heap, size); + memcpy(ptr, p, mm_block->size - ZEND_MM_ALIGNED_HEADER_SIZE); + zend_mm_free(heap, p); + return ptr; +} + +/* Debug functions & Test */ +#if 0 + +int zend_mm_num_blocks() +{ + zend_mm_block *mm_block=free_list; + int i=0; + + while (mm_block) { + i++; + mm_block = mm_block->next_free_block; + } + return i; +} + + +static void zend_mm_display_blocks(char *str) +{ +#if 0 + int i=0; + zend_mm_block *mm_block; + zend_mm_block *end_block=NULL; + + printf("%s: free_list -> ", str); + for (mm_block=free_list; mm_block; mm_block=mm_block->next_free_block) { + // printf("0x%0.8X -> ", mm_block); + printf("%d -> ", mm_block->size); + end_block = mm_block; + } + printf("NULL\n"); + + printf("%s: ", str); + for (mm_block=end_block; mm_block; mm_block=mm_block->prev_free_block) { + printf("0x%0.8X -> ", mm_block); + } + printf("NULL\n"); +#endif +} + + +#define NUM_CHUNKS 5 +#define CHUNK_SIZE 1048576 +#define ALLOCS 100 + +int main() +{ + void *chunks[NUM_CHUNKS]; + size_t chunk_sizes[NUM_CHUNKS]; + int i, j; + void *p[ALLOCS]; + size_t allocated_sizes[ALLOCS]; + int num_blocks=0; + int size_allocated; + + srand(time(NULL)); + for (i=0; i0) { + i = rand()%ALLOCS; + if (p[i]) { +// printf("Freeing block %d: %d bytes - 0x%0.8X\n", i, allocated_sizes[i], p[i]); + zend_mm_free(p[i]); + p[i] = NULL; + num_blocks--; + } + } + zend_mm_num_blocks("After freeing"); + } + + return 0; +} + +#endif diff --git a/Zend/zend_mm.h b/Zend/zend_mm.h new file mode 100644 index 0000000000..591402d998 --- /dev/null +++ b/Zend/zend_mm.h @@ -0,0 +1,31 @@ +#ifndef _ZEND_MM_H +#define _ZEND_MM_H + +#include + +#include "zend.h" + +#define ZEND_MM 0 + +/* mm block type */ +typedef struct _zend_mm_block { + size_t size; + unsigned int type; + size_t prev_size; + struct _zend_mm_block *prev_free_block; + struct _zend_mm_block *next_free_block; +} zend_mm_block; + +typedef struct _zend_mm_heap { + /* Head of free list */ + zend_mm_block *free_list; + size_t block_size; +} zend_mm_heap; + +zend_bool zend_mm_startup(zend_mm_heap *heap, size_t block_size); +void zend_mm_shutdown(zend_mm_heap *heap); +void *zend_mm_alloc(zend_mm_heap *heap, size_t size); +void zend_mm_free(zend_mm_heap *heap, void *p); +void *zend_mm_realloc(zend_mm_heap *heap, void *p, size_t size); + +#endif /* _ZEND_MM_H */ -- 2.40.0