From 4587a56466f0c55d91ece168f0dc872f81a8196c Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sat, 23 May 2020 05:30:16 +0200 Subject: block processor: recycle blocks to reduce allocation pressure Instead of freeing/allocating blocks all the time in the locked, serial path, use a free list to "recycle" blocks. Once a block is no longer used, throw it onto the free list. If a new block is, needed try to get one from the free list before calling malloc. After a few iterations, the block processor should stop allocating new blocks and only re-use the ones it already has. Signed-off-by: David Oberhollenzer --- lib/sqfs/block_processor/common.c | 57 ++++++++++++++++++++++++++--------- lib/sqfs/block_processor/internal.h | 2 ++ lib/sqfs/block_processor/serial.c | 33 +++++++++++--------- lib/sqfs/block_processor/winpthread.c | 20 ++++++------ 4 files changed, 73 insertions(+), 39 deletions(-) diff --git a/lib/sqfs/block_processor/common.c b/lib/sqfs/block_processor/common.c index 50c0573..b8f2760 100644 --- a/lib/sqfs/block_processor/common.c +++ b/lib/sqfs/block_processor/common.c @@ -44,6 +44,29 @@ static int set_block_size(sqfs_inode_generic_t **inode, return 0; } +static sqfs_block_t *get_new_block(sqfs_block_processor_t *proc) +{ + sqfs_block_t *blk; + + if (proc->free_list != NULL) { + blk = proc->free_list; + proc->free_list = blk->next; + } else { + blk = malloc(sizeof(*blk) + proc->max_block_size); + } + + if (blk != NULL) + memset(blk, 0, sizeof(*blk)); + + return blk; +} + +static void release_old_block(sqfs_block_processor_t *proc, sqfs_block_t *blk) +{ + blk->next = proc->free_list; + proc->free_list = blk; +} + int process_completed_block(sqfs_block_processor_t *proc, sqfs_block_t *blk) { sqfs_u64 location; @@ -53,7 +76,7 @@ int process_completed_block(sqfs_block_processor_t *proc, sqfs_block_t *blk) err = sqfs_block_writer_write(proc->wr, blk->size, blk->checksum, blk->flags, blk->data, &location); if (err) - return err; + goto out; if (blk->flags & SQFS_BLK_IS_SPARSE) { sqfs_inode_make_extended(*(blk->inode)); @@ -61,7 +84,7 @@ int process_completed_block(sqfs_block_processor_t *proc, sqfs_block_t *blk) err = set_block_size(blk->inode, blk->index, 0); if (err) - return err; + goto out; proc->stats.sparse_block_count += 1; } else if (blk->size != 0) { @@ -73,19 +96,20 @@ int process_completed_block(sqfs_block_processor_t *proc, sqfs_block_t *blk) err = sqfs_frag_table_set(proc->frag_tbl, blk->index, location, size); if (err) - return err; + goto out; } else { err = set_block_size(blk->inode, blk->index, size); if (err) - return err; + goto out; proc->stats.data_block_count += 1; } } if (blk->flags & SQFS_BLK_LAST_BLOCK) sqfs_inode_set_file_block_start(*(blk->inode), location); - - return 0; +out: + release_old_block(proc, blk); + return err; } static bool is_zero_block(unsigned char *ptr, size_t size) @@ -137,6 +161,7 @@ int process_completed_fragment(sqfs_block_processor_t *proc, sqfs_block_t *frag, (*(frag->inode))->data.file_ext.sparse += frag->size; proc->stats.sparse_block_count += 1; + release_old_block(proc, frag); return 0; } @@ -149,6 +174,7 @@ int process_completed_fragment(sqfs_block_processor_t *proc, sqfs_block_t *frag, if (err == 0) { sqfs_inode_set_frag_location(*(frag->inode), index, offset); + release_old_block(proc, frag); return 0; } } @@ -167,15 +193,12 @@ int process_completed_fragment(sqfs_block_processor_t *proc, sqfs_block_t *frag, if (err) goto fail; - size = sizeof(sqfs_block_t) + proc->max_block_size; - proc->frag_block = malloc(size); - + proc->frag_block = get_new_block(proc); if (proc->frag_block == NULL) { err = SQFS_ERROR_ALLOC; goto fail; } - memset(proc->frag_block, 0, sizeof(sqfs_block_t)); proc->frag_block->index = index; proc->frag_block->flags = SQFS_BLK_FRAGMENT_BLOCK; proc->stats.frag_block_count += 1; @@ -197,16 +220,21 @@ int process_completed_fragment(sqfs_block_processor_t *proc, sqfs_block_t *frag, proc->frag_block->flags |= (frag->flags & SQFS_BLK_DONT_COMPRESS); proc->frag_block->size += frag->size; proc->stats.actual_frag_count += 1; + + release_old_block(proc, frag); return 0; fail: - free(*blk_out); - *blk_out = NULL; + release_old_block(proc, frag); + if (*blk_out != NULL) { + release_old_block(proc, *blk_out); + *blk_out = NULL; + } return err; } static int add_sentinel_block(sqfs_block_processor_t *proc) { - sqfs_block_t *blk = calloc(1, sizeof(*blk)); + sqfs_block_t *blk = get_new_block(proc); if (blk == NULL) return SQFS_ERROR_ALLOC; @@ -269,11 +297,10 @@ int sqfs_block_processor_append(sqfs_block_processor_t *proc, const void *data, while (size > 0) { if (proc->blk_current == NULL) { - new = malloc(sizeof(*new) + proc->max_block_size); + new = get_new_block(proc); if (new == NULL) return SQFS_ERROR_ALLOC; - memset(new, 0, sizeof(*new)); proc->blk_current = new; proc->blk_current->flags = proc->blk_flags; proc->blk_current->inode = proc->inode; diff --git a/lib/sqfs/block_processor/internal.h b/lib/sqfs/block_processor/internal.h index fed0842..eff5374 100644 --- a/lib/sqfs/block_processor/internal.h +++ b/lib/sqfs/block_processor/internal.h @@ -54,6 +54,8 @@ struct sqfs_block_processor_t { sqfs_u32 blk_flags; sqfs_u32 blk_index; + sqfs_block_t *free_list; + size_t max_block_size; }; diff --git a/lib/sqfs/block_processor/serial.c b/lib/sqfs/block_processor/serial.c index b797ca0..a9190b1 100644 --- a/lib/sqfs/block_processor/serial.c +++ b/lib/sqfs/block_processor/serial.c @@ -16,6 +16,13 @@ typedef struct { static void block_processor_destroy(sqfs_object_t *obj) { sqfs_block_processor_t *proc = (sqfs_block_processor_t *)obj; + sqfs_block_t *blk; + + while (proc->free_list != NULL) { + blk = proc->free_list; + proc->free_list = blk->next; + free(blk); + } free(proc->blk_current); free(proc->frag_block); @@ -50,34 +57,31 @@ int append_to_work_queue(sqfs_block_processor_t *proc, sqfs_block_t *block) serial_block_processor_t *sproc = (serial_block_processor_t *)proc; sqfs_block_t *fragblk = NULL; - if (sproc->status != 0) - goto done; + if (sproc->status != 0) { + free(block); + return sproc->status; + } sproc->status = block_processor_do_block(block, proc->cmp, sproc->scratch, proc->max_block_size); if (sproc->status != 0) - goto done; + return sproc->status; if (block->flags & SQFS_BLK_IS_FRAGMENT) { sproc->status = process_completed_fragment(proc, block, &fragblk); if (fragblk == NULL) - goto done; - - free(block); - block = fragblk; + return sproc->status; - sproc->status = block_processor_do_block(block, proc->cmp, + sproc->status = block_processor_do_block(fragblk, proc->cmp, sproc->scratch, proc->max_block_size); if (sproc->status != 0) - goto done; + return sproc->status; } sproc->status = process_completed_block(proc, block); -done: - free(block); return sproc->status; } @@ -91,16 +95,17 @@ int sqfs_block_processor_finish(sqfs_block_processor_t *proc) serial_block_processor_t *sproc = (serial_block_processor_t *)proc; if (proc->frag_block == NULL || sproc->status != 0) - goto out; + goto fail; sproc->status = block_processor_do_block(proc->frag_block, proc->cmp, sproc->scratch, proc->max_block_size); if (sproc->status != 0) - goto out; + goto fail; sproc->status = process_completed_block(proc, proc->frag_block); -out: + return sproc->status; +fail: free(proc->frag_block); proc->frag_block = NULL; return sproc->status; diff --git a/lib/sqfs/block_processor/winpthread.c b/lib/sqfs/block_processor/winpthread.c index 80cbde9..281eb6b 100644 --- a/lib/sqfs/block_processor/winpthread.c +++ b/lib/sqfs/block_processor/winpthread.c @@ -192,6 +192,7 @@ static void block_processor_destroy(sqfs_object_t *obj) free_blk_list(proc->proc_queue); free_blk_list(proc->io_queue); free_blk_list(proc->done); + free_blk_list(proc->base.free_list); free(proc->base.blk_current); free(proc->base.frag_block); free(proc); @@ -390,12 +391,13 @@ static void append_block(thread_pool_processor_t *proc, sqfs_block_t *block) static int handle_io_queue(thread_pool_processor_t *proc, sqfs_block_t *list) { - sqfs_block_t *it = list; + sqfs_block_t *it; int status = 0; - while (status == 0 && it != NULL) { + while (status == 0 && list != NULL) { + it = list; + list = list->next; status = process_completed_block(&proc->base, it); - it = it->next; if (status != 0) { LOCK(&proc->mtx); @@ -413,7 +415,7 @@ int append_to_work_queue(sqfs_block_processor_t *proc, sqfs_block_t *block) { thread_pool_processor_t *thproc = (thread_pool_processor_t *)proc; sqfs_block_t *io_list = NULL, *io_list_last = NULL; - sqfs_block_t *blk, *fragblk, *free_list = NULL; + sqfs_block_t *blk, *fragblk; int status; LOCK(&thproc->mtx); @@ -454,8 +456,6 @@ int append_to_work_queue(sqfs_block_processor_t *proc, sqfs_block_t *block) fragblk = NULL; thproc->status = process_completed_fragment(proc, blk, &fragblk); - blk->next = free_list; - free_list = blk; if (fragblk != NULL) { fragblk->io_seq_num = thproc->io_enq_id++; @@ -472,11 +472,12 @@ int append_to_work_queue(sqfs_block_processor_t *proc, sqfs_block_t *block) UNLOCK(&thproc->mtx); free(block); - if (status == 0) + if (status == 0) { status = handle_io_queue(thproc, io_list); + } else { + free_blk_list(io_list); + } - free_blk_list(io_list); - free_blk_list(free_list); return status; } @@ -504,7 +505,6 @@ int sqfs_block_processor_finish(sqfs_block_processor_t *proc) if (status == 0) status = handle_io_queue(thproc, blk); - free(blk); if (status != 0) { LOCK(&thproc->mtx); -- cgit v1.2.3