From 44c2698f6967f233c24a53cb187b3e2036527eb3 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 18 Sep 2017 22:41:28 +0300 Subject: [PATCH] ImagingMemoryBlock structure --- Tests/test_core_resources.py | 2 ++ libImaging/Imaging.h | 9 ++++-- libImaging/Storage.c | 58 ++++++++++++++++++++---------------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/Tests/test_core_resources.py b/Tests/test_core_resources.py index 46ca12e38..5fe632bed 100644 --- a/Tests/test_core_resources.py +++ b/Tests/test_core_resources.py @@ -124,6 +124,7 @@ class TestCoreMemory(PillowTestCase): @unittest.skipIf(is_pypy, "images are not collected") def test_clear_cache_stats(self): Image.core.reset_stats() + Image.core.clear_cache() Image.core.set_blocks_max(128) Image.core.set_block_size(4096) Image.new('RGB', (256, 256)) @@ -131,6 +132,7 @@ class TestCoreMemory(PillowTestCase): Image.core.clear_cache() stats = Image.core.get_stats() + print(stats) self.assertGreaterEqual(stats['new_count'], 2) self.assertGreaterEqual(stats['allocated_blocks'], 64) self.assertGreaterEqual(stats['reused_blocks'], 64) diff --git a/libImaging/Imaging.h b/libImaging/Imaging.h index 14fac0225..556f3965e 100644 --- a/libImaging/Imaging.h +++ b/libImaging/Imaging.h @@ -75,6 +75,11 @@ typedef struct ImagingPaletteInstance* ImagingPalette; #define IMAGING_MODE_LENGTH 6+1 /* Band names ("1", "L", "P", "RGB", "RGBA", "CMYK", "YCbCr", "BGR;xy") */ +typedef struct { + char *ptr; + int size; +} ImagingMemoryBlock; + struct ImagingMemoryInstance { /* Format */ @@ -95,7 +100,7 @@ struct ImagingMemoryInstance { /* Internals */ char **image; /* Actual raster data. */ char *block; /* Set if data is allocated in a single block. */ - char **blocks; /* Memory blocks for pixel storage */ + ImagingMemoryBlock *blocks; /* Memory blocks for pixel storage */ int pixelsize; /* Size of a pixel, in bytes (1, 2 or 4) */ int linesize; /* Size of a line, in bytes (xsize * pixelsize) */ @@ -158,7 +163,7 @@ typedef struct ImagingMemoryArena { int block_size; int blocks_max; int blocks_cached; - void **blocks; + ImagingMemoryBlock *blocks; int stats_new_count; int stats_allocated_blocks; int stats_reused_blocks; diff --git a/libImaging/Storage.c b/libImaging/Storage.c index 433e100cf..7f12088a1 100644 --- a/libImaging/Storage.c +++ b/libImaging/Storage.c @@ -284,14 +284,14 @@ ImagingMemorySetBlocksMax(ImagingMemoryArena arena, int blocks_max) free(arena->blocks); arena->blocks = NULL; } else if (arena->blocks != NULL) { - p = realloc(arena->blocks, sizeof(void*) * blocks_max); + p = realloc(arena->blocks, sizeof(*arena->blocks) * blocks_max); if ( ! p) { // Leave previous blocks_max value return 0; } arena->blocks = p; } else { - arena->blocks = calloc(sizeof(void*), blocks_max); + arena->blocks = calloc(sizeof(*arena->blocks), blocks_max); if ( ! arena->blocks) { return 0; } @@ -306,49 +306,57 @@ ImagingMemoryClearCache(ImagingMemoryArena arena, int new_size) { while (arena->blocks_cached > new_size) { arena->blocks_cached -= 1; - free(arena->blocks[arena->blocks_cached]); + free(arena->blocks[arena->blocks_cached].ptr); arena->stats_freed_blocks += 1; } } -void * +ImagingMemoryBlock memory_get_block(ImagingMemoryArena arena, int requested_size, int dirty) { - void *block; + ImagingMemoryBlock block = {NULL, 0}; + if (arena->blocks_cached > 0) { + // Get block from cache arena->blocks_cached -= 1; - block = realloc(arena->blocks[arena->blocks_cached], requested_size); - if ( ! block) { - free(arena->blocks[arena->blocks_cached]); - arena->stats_freed_blocks += 1; - return NULL; + block = arena->blocks[arena->blocks_cached]; + // Reallocate if needed + if (block.size != requested_size){ + block.ptr = realloc(block.ptr, requested_size); } - arena->stats_reused_blocks += 1; - if (block != arena->blocks[arena->blocks_cached]) { - arena->stats_reallocated_blocks += 1; + if ( ! block.ptr) { + // Can't allocate, free prevous pointer (it is still valid) + free(arena->blocks[arena->blocks_cached].ptr); + arena->stats_freed_blocks += 1; + return block; } if ( ! dirty) { - memset(block, 0, requested_size); + memset(block.ptr, 0, requested_size); + } + arena->stats_reused_blocks += 1; + if (block.ptr != arena->blocks[arena->blocks_cached].ptr) { + arena->stats_reallocated_blocks += 1; } } else { if (dirty) { - block = malloc(requested_size); + block.ptr = malloc(requested_size); } else { - block = calloc(1, requested_size); + block.ptr = calloc(1, requested_size); } arena->stats_allocated_blocks += 1; } + block.size = requested_size; return block; } void -memory_return_block(ImagingMemoryArena arena, void *block) +memory_return_block(ImagingMemoryArena arena, ImagingMemoryBlock block) { if (arena->blocks_cached < arena->blocks_max) { arena->blocks[arena->blocks_cached] = block; arena->blocks_cached += 1; } else { - free(block); + free(block.ptr); arena->stats_freed_blocks += 1; } } @@ -360,7 +368,7 @@ ImagingDestroyArray(Imaging im) int y = 0; if (im->blocks) { - while (im->blocks[y]) { + while (im->blocks[y].ptr) { memory_return_block(&ImagingDefaultArena, im->blocks[y]); y += 1; } @@ -373,7 +381,7 @@ ImagingAllocateArray(Imaging im, int dirty) { int y, line_in_block, current_block; ImagingMemoryArena arena = &ImagingDefaultArena; - char* p = NULL; + ImagingMemoryBlock block = {NULL, 0}; int linesize, lines_per_block, blocks_count; /* 0-width or 0-height image. No need to do anything */ @@ -391,7 +399,7 @@ ImagingAllocateArray(Imaging im, int dirty) im->destroy = ImagingDestroyArray; /* One extra ponter is always NULL */ - im->blocks = (char **)calloc(sizeof(char *), blocks_count + 1); + im->blocks = calloc(sizeof(*im->blocks), blocks_count + 1); if ( ! im->blocks) { return (Imaging) ImagingError_MemoryError(); } @@ -406,14 +414,14 @@ ImagingAllocateArray(Imaging im, int dirty) if (lines_remained > im->ysize - y) { lines_remained = im->ysize - y; } - p = memory_get_block(arena, lines_remained * linesize, dirty); - if ( ! p) { + block = memory_get_block(arena, lines_remained * linesize, dirty); + if ( ! block.ptr) { return (Imaging) ImagingError_MemoryError(); } - im->blocks[current_block] = p; + im->blocks[current_block] = block; } - im->image[y] = p + linesize * line_in_block; + im->image[y] = block.ptr + linesize * line_in_block; line_in_block += 1; if (line_in_block >= lines_per_block) {