X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Ffifo.c;h=48f6459709b269d3f60eff34ad1155f7588fe023;hb=033e32de9c380f54c7d1362a3979da205ebc3a29;hp=4f844795c1a9453386aa8b5762f37fbf1b706748;hpb=967016fabf0eec61a50e29b80c88304761702b39;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/libhb/fifo.c b/libhb/fifo.c index 4f844795..48f64597 100644 --- a/libhb/fifo.c +++ b/libhb/fifo.c @@ -1,7 +1,7 @@ /* $Id: fifo.c,v 1.17 2005/10/15 18:05:03 titer Exp $ This file is part of the HandBrake source code. - Homepage: . + Homepage: . It may be used under the terms of the GNU General Public License. */ #include "hb.h" @@ -14,40 +14,50 @@ struct hb_fifo_s { hb_lock_t * lock; - int capacity; - int size; - int buffer_size; + uint32_t capacity; + uint32_t size; + uint32_t buffer_size; hb_buffer_t * first; hb_buffer_t * last; }; -#define MAX_BUFFER_POOLS 15 -#define BUFFER_POOL_MAX_ELEMENTS 2048 +/* we round the requested buffer size up to the next power of 2 so there can + * be at most 32 possible pools when the size is a 32 bit int. To avoid a lot + * of slow & error-prone run-time checking we allow for all 32. */ +#define MAX_BUFFER_POOLS 32 +/* the buffer pool only exists to avoid the two malloc and two free calls that + * it would otherwise take to allocate & free a buffer. but we don't want to + * tie up a lot of memory in the pool because this allocator isn't as general + * as malloc so memory tied up here puts more pressure on the malloc pool. + * A pool of 16 elements will avoid 94% of the malloc/free calls without wasting + * too much memory. */ +#define BUFFER_POOL_MAX_ELEMENTS 32 struct hb_buffer_pools_s { - int entries; - int allocated; - hb_fifo_t *pool[MAX_BUFFER_POOLS]; + int64_t allocated; hb_lock_t *lock; -}; + hb_fifo_t *pool[MAX_BUFFER_POOLS]; +} buffers; -struct hb_buffer_pools_s buffers; void hb_buffer_pool_init( void ) { - hb_fifo_t *buffer_pool; - int size = 512; - int max_size = 32768;; - - buffers.entries = 0; buffers.lock = hb_lock_init(); buffers.allocated = 0; - - while(size <= max_size) { - buffer_pool = buffers.pool[buffers.entries++] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS); - buffer_pool->buffer_size = size; - size *= 2; + + /* we allocate pools for sizes 2^10 through 2^25. requests larger than + * 2^25 will get passed through to malloc. */ + int i; + for ( i = 10; i < 26; ++i ) + { + buffers.pool[i] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS); + buffers.pool[i]->buffer_size = 1 << i; + } + /* requests smaller than 2^10 are satisfied from the 2^10 pool. */ + for ( i = 1; i < 10; ++i ) + { + buffers.pool[i] = buffers.pool[10]; } } @@ -55,12 +65,12 @@ void hb_buffer_pool_free( void ) { int i; int count; - int freed = 0; + int64_t freed = 0; hb_buffer_t *b; hb_lock(buffers.lock); - for( i = 0; i < buffers.entries; i++) + for( i = 10; i < 26; ++i) { count = 0; while( ( b = hb_fifo_get(buffers.pool[i]) ) ) @@ -69,91 +79,58 @@ void hb_buffer_pool_free( void ) if( b->data ) { free( b->data ); - b->data = NULL; } free( b ); count++; } - hb_log("Freed %d buffers of size %d", count, buffers.pool[i]->buffer_size); + if ( count ) + { + hb_deep_log( 2, "Freed %d buffers of size %d", count, + buffers.pool[i]->buffer_size); + } } - hb_log("Allocated %d bytes of buffers on this pass and Freed %d bytes, %d bytes leaked", - buffers.allocated, freed, buffers.allocated - freed); + hb_deep_log( 2, "Allocated %"PRId64" bytes of buffers on this pass and Freed %"PRId64" bytes, " + "%"PRId64" bytes leaked", buffers.allocated, freed, buffers.allocated - freed); buffers.allocated = 0; hb_unlock(buffers.lock); } - -hb_buffer_t * hb_buffer_init( int size ) -{ - hb_buffer_t * b; +static hb_fifo_t *size_to_pool( int size ) +{ int i; - hb_fifo_t *buffer_pool = NULL; - uint8_t *data; - int b_alloc; - int resize = 0; - - if( size > 0 ) + for ( i = 0; i < 30; ++i ) { - /* - * The buffer pools are allocated in increasing size - */ - for( i = 0; i < buffers.entries; i++ ) + if ( size <= (1 << i) ) { - if( buffers.pool[i]->buffer_size >= size ) - { - /* - * This pool is big enough, but are there any buffers in it? - */ - if( hb_fifo_size( buffers.pool[i] ) ) - { - /* - * We've found a matching buffer pool, with buffers. - */ - buffer_pool = buffers.pool[i]; - resize = buffers.pool[i]->buffer_size; - } else { - /* - * Buffer pool is empty, - */ - if( resize ) { - /* - * This is the second time through, so break - * out of here to avoid using too large a - * buffer for a small job. - */ - break; - } - resize = buffers.pool[i]->buffer_size; - } - } + return buffers.pool[i]; } } - /* - * Don't reuse the 0 size buffers, not much gain. - */ - if( size != 0 && buffer_pool ) + return NULL; +} + +hb_buffer_t * hb_buffer_init( int size ) +{ + hb_buffer_t * b; + hb_fifo_t *buffer_pool = size_to_pool( size ); + + if( buffer_pool ) { - b = hb_fifo_get( buffer_pool ); + b = hb_fifo_get( buffer_pool ); if( b ) { /* * Zero the contents of the buffer, would be nice if we * didn't have to do this. - * - hb_log("Reused buffer size %d for size %d from pool %d depth %d", - b->alloc, size, smallest_pool->buffer_size, - hb_fifo_size(smallest_pool)); - */ - data = b->data; - b_alloc = b->alloc; + */ + uint8_t *data = b->data; memset( b, 0, sizeof(hb_buffer_t) ); - b->alloc = b_alloc; + b->alloc = buffer_pool->buffer_size; b->size = size; b->data = data; return( b ); - } + } } /* @@ -166,152 +143,67 @@ hb_buffer_t * hb_buffer_init( int size ) } b->size = size; + b->alloc = buffer_pool? buffer_pool->buffer_size : size; - if( resize ) + if (size) { - size = resize; - } - b->alloc = size; - - /* - hb_log("Allocating new buffer of size %d for size %d", - b->alloc, - b->size); - */ - - if (!size) - return b; -#if defined( SYS_DARWIN ) || defined( SYS_FREEBSD ) - b->data = malloc( b->alloc ); +#if defined( SYS_DARWIN ) || defined( SYS_FREEBSD ) || defined( SYS_MINGW ) + b->data = malloc( b->alloc ); #elif defined( SYS_CYGWIN ) - /* FIXME */ - b->data = malloc( b->alloc + 17 ); + /* FIXME */ + b->data = malloc( b->alloc + 17 ); #else - b->data = memalign( 16, b->alloc ); + b->data = memalign( 16, b->alloc ); #endif - - if( !b->data ) - { - hb_log( "out of memory" ); - free( b ); - return NULL; + if( !b->data ) + { + hb_log( "out of memory" ); + free( b ); + return NULL; + } + hb_lock(buffers.lock); + buffers.allocated += b->alloc; + hb_unlock(buffers.lock); } - - buffers.allocated += b->alloc; - return b; } void hb_buffer_realloc( hb_buffer_t * b, int size ) { - /* No more alignment, but we don't care */ - if( size < 2048 ) { - size = 2048; + if ( size > b->alloc ) + { + uint32_t orig = b->alloc; + size = size_to_pool( size )->buffer_size; + b->data = realloc( b->data, size ); + b->alloc = size; + + hb_lock(buffers.lock); + buffers.allocated += size - orig; + hb_unlock(buffers.lock); } - b->data = realloc( b->data, size ); - buffers.allocated -= b->alloc; - b->alloc = size; - buffers.allocated += b->alloc; } void hb_buffer_close( hb_buffer_t ** _b ) { hb_buffer_t * b = *_b; - hb_fifo_t *buffer_pool = NULL; - int i; + hb_fifo_t *buffer_pool = size_to_pool( b->alloc ); - /* - * Put the buffer into our free list in the matching buffer pool, if there is one. - */ - if( b->alloc != 0 ) + if( buffer_pool && b->data && !hb_fifo_is_full( buffer_pool ) ) { - for( i = 0; i < buffers.entries; i++ ) - { - if( b->alloc == buffers.pool[i]->buffer_size ) - { - buffer_pool = buffers.pool[i]; - break; - } - } + hb_fifo_push_head( buffer_pool, b ); + *_b = NULL; + return; } - - if( buffer_pool ) + /* either the pool is full or this size doesn't use a pool - free the buf */ + if( b->data ) { - if( !hb_fifo_is_full( buffer_pool ) ) - { - if(b->data) - { - /* - hb_log("Putting a buffer of size %d on pool %d, depth %d", - b->alloc, - buffer_pool->buffer_size, - hb_fifo_size(buffer_pool)); - */ - hb_fifo_push( buffer_pool, b ); - } else { - free(b); - } - } else { - /* - * Got a load of these size ones already, free this buffer. - * - hb_log("Buffer pool for size %d full, freeing buffer", b->alloc); - */ - if( b->data ) - { - free( b->data ); - } - buffers.allocated -= b->alloc; - free( b ); - } - } else { - /* - * Need a new buffer pool for this size. - */ + free( b->data ); hb_lock(buffers.lock); - if ( b->alloc != 0 && buffers.entries < MAX_BUFFER_POOLS) - { - buffer_pool = buffers.pool[buffers.entries++] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS); - buffer_pool->buffer_size = b->alloc; - hb_fifo_push( buffer_pool, b ); - /* - hb_log("*** Allocated a new buffer pool for size %d [%d]", b->alloc, - buffers.entries ); - */ - } else { - if( b->alloc != 0 ) - { - for( i = buffers.entries-1; i >= 0; i-- ) - { - if( hb_fifo_size(buffers.pool[i]) == 0 ) - { - /* - * Reuse this pool as it is empty. - */ - buffers.pool[i]->buffer_size = b->alloc; - hb_fifo_push( buffers.pool[i], b ); - b = NULL; - break; - } - } - } - - if( b ) - { - if( b->data ) - { - free( b->data ); - b->data = NULL; - buffers.allocated -= b->alloc; - } - free( b ); - } - } + buffers.allocated -= b->alloc; hb_unlock(buffers.lock); } - + free( b ); *_b = NULL; - } void hb_buffer_copy_settings( hb_buffer_t * dst, const hb_buffer_t * src ) @@ -381,7 +273,7 @@ hb_buffer_t * hb_fifo_get( hb_fifo_t * f ) b->next = NULL; f->size -= 1; hb_unlock( f->lock ); - + return b; } @@ -443,12 +335,49 @@ void hb_fifo_push( hb_fifo_t * f, hb_buffer_t * b ) hb_unlock( f->lock ); } +void hb_fifo_push_head( hb_fifo_t * f, hb_buffer_t * b ) +{ + hb_buffer_t * tmp; + uint32_t size = 0; + + if( !b ) + { + return; + } + + hb_lock( f->lock ); + + /* + * If there are a chain of buffers prepend the lot + */ + tmp = b; + while( tmp->next ) + { + tmp = tmp->next; + size += 1; + } + + if( f->size > 0 ) + { + tmp->next = f->first; + } + else + { + f->last = tmp; + } + + f->first = b; + f->size += ( size + 1 ); + + hb_unlock( f->lock ); +} + void hb_fifo_close( hb_fifo_t ** _f ) { hb_fifo_t * f = *_f; hb_buffer_t * b; - - hb_log( "fifo_close: trashing %d buffer(s)", hb_fifo_size( f ) ); + + hb_deep_log( 2, "fifo_close: trashing %d buffer(s)", hb_fifo_size( f ) ); while( ( b = hb_fifo_get( f ) ) ) { hb_buffer_close( &b );