ImagingMemoryBlock structure

This commit is contained in:
Alexander 2017-09-18 22:41:28 +03:00
parent 67e1e03c79
commit 44c2698f69
3 changed files with 42 additions and 27 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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) {