1
0
mirror of https://github.com/php/php-src.git synced 2026-04-18 05:21:02 +02:00

erealloc() optimization

This commit is contained in:
Dmitry Stogov
2017-11-03 18:35:03 +03:00
parent 9359ad73bf
commit 522cc6926b

View File

@@ -1423,7 +1423,115 @@ static size_t zend_mm_size(zend_mm_heap *heap, void *ptr ZEND_FILE_LINE_DC ZEND_
}
}
static void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
static zend_never_inline void *zend_mm_realloc_slow(zend_mm_heap *heap, void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
void *ret;
#if ZEND_MM_STAT
do {
size_t orig_peak = heap->peak;
size_t orig_real_peak = heap->real_peak;
#endif
ret = zend_mm_alloc_heap(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
memcpy(ret, ptr, copy_size);
zend_mm_free_heap(heap, ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#if ZEND_MM_STAT
heap->peak = MAX(orig_peak, heap->size);
heap->real_peak = MAX(orig_real_peak, heap->real_size);
} while (0);
#endif
return ret;
}
static zend_never_inline void *zend_mm_realloc_huge(zend_mm_heap *heap, void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
size_t old_size;
size_t new_size;
#if ZEND_DEBUG
size_t real_size;
zend_mm_debug_info *dbg;
#endif
old_size = zend_mm_get_huge_block_size(heap, ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#if ZEND_DEBUG
real_size = size;
size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info));
#endif
if (size > ZEND_MM_MAX_LARGE_SIZE) {
#if ZEND_DEBUG
size = real_size;
#endif
#ifdef ZEND_WIN32
/* On Windows we don't have ability to extend huge blocks in-place.
* We allocate them with 2MB size granularity, to avoid many
* reallocations when they are extended by small pieces
*/
new_size = ZEND_MM_ALIGNED_SIZE_EX(size, MAX(REAL_PAGE_SIZE, ZEND_MM_CHUNK_SIZE));
#else
new_size = ZEND_MM_ALIGNED_SIZE_EX(size, REAL_PAGE_SIZE);
#endif
if (new_size == old_size) {
#if ZEND_DEBUG
zend_mm_change_huge_block_size(heap, ptr, new_size, real_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#else
zend_mm_change_huge_block_size(heap, ptr, new_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#endif
return ptr;
} else if (new_size < old_size) {
/* unmup tail */
if (zend_mm_chunk_truncate(heap, ptr, old_size, new_size)) {
#if ZEND_MM_STAT || ZEND_MM_LIMIT
heap->real_size -= old_size - new_size;
#endif
#if ZEND_MM_STAT
heap->size -= old_size - new_size;
#endif
#if ZEND_DEBUG
zend_mm_change_huge_block_size(heap, ptr, new_size, real_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#else
zend_mm_change_huge_block_size(heap, ptr, new_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#endif
return ptr;
}
} else /* if (new_size > old_size) */ {
#if ZEND_MM_LIMIT
if (UNEXPECTED(heap->real_size + (new_size - old_size) > heap->limit)) {
if (zend_mm_gc(heap) && heap->real_size + (new_size - old_size) <= heap->limit) {
/* pass */
} else if (heap->overflow == 0) {
#if ZEND_DEBUG
zend_mm_safe_error(heap, "Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)", heap->limit, __zend_filename, __zend_lineno, size);
#else
zend_mm_safe_error(heap, "Allowed memory size of %zu bytes exhausted (tried to allocate %zu bytes)", heap->limit, size);
#endif
return NULL;
}
}
#endif
/* try to map tail right after this block */
if (zend_mm_chunk_extend(heap, ptr, old_size, new_size)) {
#if ZEND_MM_STAT || ZEND_MM_LIMIT
heap->real_size += new_size - old_size;
#endif
#if ZEND_MM_STAT
heap->real_peak = MAX(heap->real_peak, heap->real_size);
heap->size += new_size - old_size;
heap->peak = MAX(heap->peak, heap->size);
#endif
#if ZEND_DEBUG
zend_mm_change_huge_block_size(heap, ptr, new_size, real_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#else
zend_mm_change_huge_block_size(heap, ptr, new_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#endif
return ptr;
}
}
}
return zend_mm_realloc_slow(heap, ptr, size, MIN(old_size, copy_size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size, zend_bool use_copy_size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
size_t page_offset;
size_t old_size;
@@ -1436,83 +1544,10 @@ static void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size, si
page_offset = ZEND_MM_ALIGNED_OFFSET(ptr, ZEND_MM_CHUNK_SIZE);
if (UNEXPECTED(page_offset == 0)) {
if (UNEXPECTED(ptr == NULL)) {
return zend_mm_alloc_heap(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
old_size = zend_mm_get_huge_block_size(heap, ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#if ZEND_DEBUG
real_size = size;
size = ZEND_MM_ALIGNED_SIZE(size) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_debug_info));
#endif
if (size > ZEND_MM_MAX_LARGE_SIZE) {
#if ZEND_DEBUG
size = real_size;
#endif
#ifdef ZEND_WIN32
/* On Windows we don't have ability to extend huge blocks in-place.
* We allocate them with 2MB size granularity, to avoid many
* reallocations when they are extended by small pieces
*/
new_size = ZEND_MM_ALIGNED_SIZE_EX(size, MAX(REAL_PAGE_SIZE, ZEND_MM_CHUNK_SIZE));
#else
new_size = ZEND_MM_ALIGNED_SIZE_EX(size, REAL_PAGE_SIZE);
#endif
if (new_size == old_size) {
#if ZEND_DEBUG
zend_mm_change_huge_block_size(heap, ptr, new_size, real_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#else
zend_mm_change_huge_block_size(heap, ptr, new_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#endif
return ptr;
} else if (new_size < old_size) {
/* unmup tail */
if (zend_mm_chunk_truncate(heap, ptr, old_size, new_size)) {
#if ZEND_MM_STAT || ZEND_MM_LIMIT
heap->real_size -= old_size - new_size;
#endif
#if ZEND_MM_STAT
heap->size -= old_size - new_size;
#endif
#if ZEND_DEBUG
zend_mm_change_huge_block_size(heap, ptr, new_size, real_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#else
zend_mm_change_huge_block_size(heap, ptr, new_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#endif
return ptr;
}
} else /* if (new_size > old_size) */ {
#if ZEND_MM_LIMIT
if (UNEXPECTED(heap->real_size + (new_size - old_size) > heap->limit)) {
if (zend_mm_gc(heap) && heap->real_size + (new_size - old_size) <= heap->limit) {
/* pass */
} else if (heap->overflow == 0) {
#if ZEND_DEBUG
zend_mm_safe_error(heap, "Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)", heap->limit, __zend_filename, __zend_lineno, size);
#else
zend_mm_safe_error(heap, "Allowed memory size of %zu bytes exhausted (tried to allocate %zu bytes)", heap->limit, size);
#endif
return NULL;
}
}
#endif
/* try to map tail right after this block */
if (zend_mm_chunk_extend(heap, ptr, old_size, new_size)) {
#if ZEND_MM_STAT || ZEND_MM_LIMIT
heap->real_size += new_size - old_size;
#endif
#if ZEND_MM_STAT
heap->real_peak = MAX(heap->real_peak, heap->real_size);
heap->size += new_size - old_size;
heap->peak = MAX(heap->peak, heap->size);
#endif
#if ZEND_DEBUG
zend_mm_change_huge_block_size(heap, ptr, new_size, real_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#else
zend_mm_change_huge_block_size(heap, ptr, new_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#endif
return ptr;
}
}
if (EXPECTED(ptr == NULL)) {
return _zend_mm_alloc(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
} else {
return zend_mm_realloc_huge(heap, ptr, size, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
} else {
zend_mm_chunk *chunk = (zend_mm_chunk*)ZEND_MM_ALIGNED_BASE(ptr, ZEND_MM_CHUNK_SIZE);
@@ -1527,21 +1562,56 @@ static void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size, si
ZEND_MM_CHECK(chunk->heap == heap, "zend_mm_heap corrupted");
if (info & ZEND_MM_IS_SRUN) {
int old_bin_num = ZEND_MM_SRUN_BIN_NUM(info);
old_size = bin_data_size[old_bin_num];
if (size <= ZEND_MM_MAX_SMALL_SIZE) {
int bin_num = ZEND_MM_SMALL_SIZE_TO_BIN(size);
if (old_bin_num == bin_num) {
#if ZEND_DEBUG
dbg = zend_mm_get_debug_info(heap, ptr);
dbg->size = real_size;
dbg->filename = __zend_filename;
dbg->orig_filename = __zend_orig_filename;
dbg->lineno = __zend_lineno;
dbg->orig_lineno = __zend_orig_lineno;
do {
old_size = bin_data_size[old_bin_num];
/* Check if requested size fits into current bin */
if (size <= old_size) {
/* Check if truncation is necessary */
if (old_bin_num > 0 && size <= bin_data_size[old_bin_num - 1]) {
/* truncation */
ret = zend_mm_alloc_small(heap, size, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
copy_size = use_copy_size ? MIN(size, copy_size) : size;
memcpy(ret, ptr, copy_size);
zend_mm_free_small(heap, ptr, old_bin_num);
} else {
/* reallocation in-place */
ret = ptr;
}
} else if (size <= ZEND_MM_MAX_SMALL_SIZE) {
/* small extension */
#if ZEND_MM_STAT
do {
size_t orig_peak = heap->peak;
size_t orig_real_peak = heap->real_peak;
#endif
return ptr;
ret = zend_mm_alloc_small(heap, size, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
copy_size = use_copy_size ? MIN(old_size, copy_size) : old_size;
memcpy(ret, ptr, copy_size);
zend_mm_free_small(heap, ptr, old_bin_num);
#if ZEND_MM_STAT
heap->peak = MAX(orig_peak, heap->size);
heap->real_peak = MAX(orig_real_peak, heap->real_size);
} while (0);
#endif
} else {
/* slow reallocation */
break;
}
}
#if ZEND_DEBUG
dbg = zend_mm_get_debug_info(heap, ret);
dbg->size = real_size;
dbg->filename = __zend_filename;
dbg->orig_filename = __zend_orig_filename;
dbg->lineno = __zend_lineno;
dbg->orig_lineno = __zend_orig_lineno;
#endif
return ret;
} while (0);
} else /* if (info & ZEND_MM_IS_LARGE_RUN) */ {
ZEND_MM_CHECK(ZEND_MM_ALIGNED_OFFSET(page_offset, ZEND_MM_PAGE_SIZE) == 0, "zend_mm_heap corrupted");
old_size = ZEND_MM_LRUN_PAGES(info) * ZEND_MM_PAGE_SIZE;
@@ -1613,21 +1683,8 @@ static void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size, si
#endif
}
/* Naive reallocation */
#if ZEND_MM_STAT
do {
size_t orig_peak = heap->peak;
size_t orig_real_peak = heap->real_peak;
#endif
ret = zend_mm_alloc_heap(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
memcpy(ret, ptr, MIN(old_size, copy_size));
zend_mm_free_heap(heap, ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
#if ZEND_MM_STAT
heap->peak = MAX(orig_peak, heap->size);
heap->real_peak = MAX(orig_real_peak, heap->real_size);
} while (0);
#endif
return ret;
copy_size = MIN(old_size, copy_size);
return zend_mm_realloc_slow(heap, ptr, size, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
/*********************/
@@ -2277,12 +2334,12 @@ ZEND_API void ZEND_FASTCALL _zend_mm_free(zend_mm_heap *heap, void *ptr ZEND_FIL
void* ZEND_FASTCALL _zend_mm_realloc(zend_mm_heap *heap, void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
return zend_mm_realloc_heap(heap, ptr, size, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
return zend_mm_realloc_heap(heap, ptr, size, 0, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
void* ZEND_FASTCALL _zend_mm_realloc2(zend_mm_heap *heap, void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
return zend_mm_realloc_heap(heap, ptr, size, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
return zend_mm_realloc_heap(heap, ptr, size, 1, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
ZEND_API size_t ZEND_FASTCALL _zend_mm_block_size(zend_mm_heap *heap, void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
@@ -2459,7 +2516,7 @@ ZEND_API void* ZEND_FASTCALL _erealloc(void *ptr, size_t size ZEND_FILE_LINE_DC
return AG(mm_heap)->custom_heap.std._realloc(ptr, size);
}
}
return zend_mm_realloc_heap(AG(mm_heap), ptr, size, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
return zend_mm_realloc_heap(AG(mm_heap), ptr, size, 0, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
ZEND_API void* ZEND_FASTCALL _erealloc2(void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
@@ -2472,7 +2529,7 @@ ZEND_API void* ZEND_FASTCALL _erealloc2(void *ptr, size_t size, size_t copy_size
return AG(mm_heap)->custom_heap.std._realloc(ptr, size);
}
}
return zend_mm_realloc_heap(AG(mm_heap), ptr, size, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
return zend_mm_realloc_heap(AG(mm_heap), ptr, size, 1, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
ZEND_API size_t ZEND_FASTCALL _zend_mem_block_size(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)