PHP-5.2.6 Fat Memory Manager Brian Shire & Facebook Inc. Optimizes CPU performance over memory performance by making a single persistent memory request for all requests. To use: Apply the patch with the following commands: cd php-5.2.6 patch -p1 -i fatmm.5.2.6.patch Rebuild ./configure by running ./buildconf --force. Re-configure PHP with --with-fatmm=SIZE, where SIZE is megabytes to allocate per process. For example, to allocate 64MB use: --with-fatmm=64 Provide feedback to diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index d48c29c..82939c8 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -25,6 +25,13 @@ #include "zend_globals.h" #include "zend_operators.h" +/*** BEGIN Patch: Fat MM ***/ +#ifdef ZEND_FATMM +zend_mm_fat_t zend_mm_fat = {0}; +#endif +/*** END Patch: Fat MM ***/ + + #ifdef HAVE_SIGNAL_H # include #endif @@ -875,6 +882,20 @@ static inline void zend_mm_init(zend_mm_heap *heap) heap->large_free_buckets[i] = NULL; } heap->rest_buckets[0] = heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(heap); + +/* BEGIN Patch: Fat MM */ +#ifdef ZEND_FATMM + { + if(!zend_mm_fat.base) { + zend_mm_fat.size = ZEND_FATMM *1024*1024; + zend_mm_fat.base = malloc(zend_mm_fat.size); + zend_mm_fat.top = (void*)((size_t)zend_mm_fat.base + zend_mm_fat.size); + zend_mm_fat.cur = zend_mm_fat.base; + zend_mm_fat.avail = zend_mm_fat.size; + } + } +#endif +/* END Patch: Fat MM */ } static void zend_mm_del_segment(zend_mm_heap *heap, zend_mm_segment *segment) @@ -1507,6 +1528,13 @@ ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, int full_shutdown, int silent zend_mm_segment *prev; int internal; +/* BEGIN Patch: Fat MM */ +#ifdef ZEND_FATMM + zend_mm_fat.cur = zend_mm_fat.base; + zend_mm_fat.avail = zend_mm_fat.size; +#endif +/* END Patch: Fat MM */ + if (heap->reserve) { #if ZEND_DEBUG if (!silent) { @@ -2272,7 +2300,13 @@ ZEND_API int is_zend_mm(TSRMLS_D) return AG(mm_heap)->use_zend_alloc; } +/* BEGIN Patch: Fat MM */ +#ifdef ZEND_FATMM +ZEND_API void *_orig_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) +#else ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) +#endif +/* END Patch: Fat MM */ { TSRMLS_FETCH(); @@ -2282,7 +2316,13 @@ ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) return _zend_mm_alloc_int(AG(mm_heap), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); } +/* BEGIN Patch: Fat MM */ +#ifdef ZEND_FATMM +ZEND_API void _orig_efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) +#else ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) +#endif +/* END Patch: Fat MM */ { TSRMLS_FETCH(); @@ -2297,6 +2337,29 @@ ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LIN { TSRMLS_FETCH(); +/* BEGIN Patch: Fat MM */ +#ifdef ZEND_FATMM + { + void *fat_p=NULL; + if (!ptr || (zend_mm_fat.base <= ptr && ptr < zend_mm_fat.top)) { + if (zend_mm_fat.avail > (size + sizeof(size_t))) { + fat_p = (void*)((size_t)zend_mm_fat.cur + sizeof(size_t)); + *(size_t*)zend_mm_fat.cur = size; + zend_mm_fat.cur = (void*)((size_t)zend_mm_fat.cur + size + sizeof(size_t)); + zend_mm_fat.avail -= (size + sizeof(size_t)); + } else { + fat_p = _zend_mm_alloc_int(AG(mm_heap), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + } + if (ptr) { + size_t old_size = *(size_t*)((size_t)ptr - sizeof(size_t)); /* size of alloc'd block is size_t bytes behind ptr */ + memcpy(fat_p, ptr, size > old_size ? old_size : size); + } + return fat_p; + } + } +#endif +/* END Patch: Fat MM */ + if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) { return realloc(ptr, size); } diff --git a/Zend/zend_alloc.h b/Zend/zend_alloc.h index bd5f4cd..f09fd3e 100644 --- a/Zend/zend_alloc.h +++ b/Zend/zend_alloc.h @@ -40,10 +40,22 @@ BEGIN_EXTERN_C() ZEND_API char *zend_strndup(const char *s, unsigned int length) ZEND_ATTRIBUTE_MALLOC; +/* BEGIN Patch: Fat MM */ +#ifdef ZEND_FATMM +ZEND_API void *_orig_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC; +#else ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC; +#endif +/* END Patch: Fat MM */ ZEND_API void *_safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC; ZEND_API void *_safe_malloc(size_t nmemb, size_t size, size_t offset) ZEND_ATTRIBUTE_MALLOC; +/* BEGIN Patch: Fat MM */ +#ifdef ZEND_FATMM +ZEND_API void _orig_efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); +#else ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); +#endif +/* END Patch: Fat MM */ ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC; ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); ZEND_API void *_safe_erealloc(void *ptr, size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); @@ -52,6 +64,45 @@ ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_API char *_estrndup(const char *s, unsigned int length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC; ZEND_API size_t _zend_mem_block_size(void *ptr TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); +/*** BEGIN Patch: Fat MM ***/ +#ifdef ZEND_FATMM + +#if ZEND_FATMM < 1 +# error "ZEND_FATMM must be greater than 0." +#endif + +typedef struct _zend_mm_fat_t { + void *base; + void *top; + void *cur; + size_t size; + size_t avail; +} zend_mm_fat_t; + +extern zend_mm_fat_t zend_mm_fat; + +static inline void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { + if (zend_mm_fat.avail > (size + sizeof(size_t))) { + register void *ptr = (void*)((size_t)zend_mm_fat.cur + sizeof(size_t)); + *(size_t*)zend_mm_fat.cur = size; + zend_mm_fat.cur = (void*)((size_t)zend_mm_fat.cur + size + sizeof(size_t)); + zend_mm_fat.avail -= (size + sizeof(size_t)); + return ptr; + } + return _orig_emalloc(size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); +} + +static inline void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { + if (zend_mm_fat.base > ptr || ptr > zend_mm_fat.top) { + _orig_efree(ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + } +} + +#endif +/*** END Patch: Fat MM ***/ + + + /* Standard wrapper macros */ #define emalloc(size) _emalloc((size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC) #define safe_emalloc(nmemb, size, offset) _safe_emalloc((nmemb), (size), (offset) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC) diff --git a/configure.in b/configure.in index a74bf24..5f935d4 100644 --- a/configure.in +++ b/configure.in @@ -827,6 +827,17 @@ if test "$PHP_DMALLOC" = "yes"; then ]) fi +dnl BEGIN Patch: Fat MM +PHP_ARG_WITH(fatmm, Fat Memory Manager, +[ --with-fatmm=SIZE Use the Fat Memory Manager optimization with SIZE megabytes],,) +if test "$PHP_FATMM" != "no"; then + if test "$PHP_FATMM" == "yes" || test "$PHP_FATMM" -lt 1; then + AC_MSG_ERROR([--with-fatmm must be a size greater than or equal to 1!]) + fi + AC_DEFINE_UNQUOTED(ZEND_FATMM,$PHP_FATMM,[ ]) +fi +dnl END Patch: Fat MM + PHP_ARG_ENABLE(ipv6, whether to enable IPv6 support, [ --disable-ipv6 Disable IPv6 support], yes, no) diff --git a/ext/standard/info.c b/ext/standard/info.c index 0c3118a..063a350 100644 --- a/ext/standard/info.c +++ b/ext/standard/info.c @@ -531,6 +531,15 @@ PHPAPI void php_print_info(int flag TSRMLS_DC) #endif php_info_print_table_row(2, "Zend Memory Manager", is_zend_mm(TSRMLS_C) ? "enabled" : "disabled" ); +#ifdef ZEND_FATALLOC + { + char temp_fatalloc[64]; + snprintf(temp_fatalloc, sizeof(temp_fatalloc), "pre-allocating: %dMB", ZEND_FATALLOC); + php_info_print_table_row(2, "Zend FAT Allocator", temp_fatalloc ); + } +#else + php_info_print_table_row(2, "Zend FAT Allocator", "disabled" ); +#endif #if HAVE_IPV6 php_info_print_table_row(2, "IPv6 Support", "enabled" );