X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Ffifo.c;h=a29e84696f453bb49a7160c21b89377468ba6185;hb=1d6fbf402512f7cbba3c9dac7e10a72aeebd1d81;hp=484f3195c219d9422eeb869df4b089ba54e536d5;hpb=90fba27222b3467b91c29803f217c4d5335c7ad0;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/libhb/fifo.c b/libhb/fifo.c index 484f3195..a29e8469 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" @@ -10,44 +10,61 @@ #include #endif +#define FIFO_TIMEOUT 200 + /* Fifo */ struct hb_fifo_s { hb_lock_t * lock; - int capacity; - int size; - int buffer_size; + hb_cond_t * cond_full; + int wait_full; + hb_cond_t * cond_empty; + int wait_empty; + uint32_t capacity; + uint32_t thresh; + 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, 1); + 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 +72,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,70 +86,42 @@ 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 ) +static hb_fifo_t *size_to_pool( int size ) { - hb_buffer_t * b; 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 ); @@ -141,15 +130,10 @@ hb_buffer_t * hb_buffer_init( int size ) /* * 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 +150,72 @@ 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; - } - b->data = realloc( b->data, size ); - buffers.allocated -= b->alloc; - b->alloc = size; - buffers.allocated += b->alloc; + 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); + } } 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 */ + while( b ) { - if( !hb_fifo_is_full( buffer_pool ) ) + hb_buffer_t * next = b->next; + if( b->data ) { - 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 ); - } + free( b->data ); + hb_lock(buffers.lock); buffers.allocated -= b->alloc; - free( b ); - } - } else { - /* - * Need a new buffer pool for this size. - */ - 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 ); - } + hb_unlock(buffers.lock); } - hb_unlock(buffers.lock); + free( b ); + b = next; } - *_b = NULL; - } void hb_buffer_copy_settings( hb_buffer_t * dst, const hb_buffer_t * src ) @@ -323,16 +227,36 @@ void hb_buffer_copy_settings( hb_buffer_t * dst, const hb_buffer_t * src ) dst->flags = src->flags; } -hb_fifo_t * hb_fifo_init( int capacity ) +hb_fifo_t * hb_fifo_init( int capacity, int thresh ) { hb_fifo_t * f; - f = calloc( sizeof( hb_fifo_t ), 1 ); - f->lock = hb_lock_init(); - f->capacity = capacity; + f = calloc( sizeof( hb_fifo_t ), 1 ); + f->lock = hb_lock_init(); + f->cond_full = hb_cond_init(); + f->cond_empty = hb_cond_init(); + f->capacity = capacity; + f->thresh = thresh; f->buffer_size = 0; return f; } +int hb_fifo_size_bytes( hb_fifo_t * f ) +{ + int ret = 0; + hb_buffer_t * link; + + hb_lock( f->lock ); + link = f->first; + while ( link ) + { + ret += link->size; + link = link->next; + } + hb_unlock( f->lock ); + + return ret; +} + int hb_fifo_size( hb_fifo_t * f ) { int ret; @@ -366,6 +290,35 @@ float hb_fifo_percent_full( hb_fifo_t * f ) return ret; } +hb_buffer_t * hb_fifo_get_wait( hb_fifo_t * f ) +{ + hb_buffer_t * b; + + hb_lock( f->lock ); + if( f->size < 1 ) + { + f->wait_empty = 1; + hb_cond_timedwait( f->cond_empty, f->lock, FIFO_TIMEOUT ); + if( f->size < 1 ) + { + hb_unlock( f->lock ); + return NULL; + } + } + b = f->first; + f->first = b->next; + b->next = NULL; + f->size -= 1; + if( f->wait_full && f->size == f->capacity - f->thresh ) + { + f->wait_full = 0; + hb_cond_signal( f->cond_full ); + } + hb_unlock( f->lock ); + + return b; +} + hb_buffer_t * hb_fifo_get( hb_fifo_t * f ) { hb_buffer_t * b; @@ -380,6 +333,32 @@ hb_buffer_t * hb_fifo_get( hb_fifo_t * f ) f->first = b->next; b->next = NULL; f->size -= 1; + if( f->wait_full && f->size == f->capacity - f->thresh ) + { + f->wait_full = 0; + hb_cond_signal( f->cond_full ); + } + hb_unlock( f->lock ); + + return b; +} + +hb_buffer_t * hb_fifo_see_wait( hb_fifo_t * f ) +{ + hb_buffer_t * b; + + hb_lock( f->lock ); + if( f->size < 1 ) + { + f->wait_empty = 1; + hb_cond_timedwait( f->cond_empty, f->lock, FIFO_TIMEOUT ); + if( f->size < 1 ) + { + hb_unlock( f->lock ); + return NULL; + } + } + b = f->first; hb_unlock( f->lock ); return b; @@ -417,6 +396,57 @@ hb_buffer_t * hb_fifo_see2( hb_fifo_t * f ) return b; } +int hb_fifo_full_wait( hb_fifo_t * f ) +{ + int result; + + hb_lock( f->lock ); + if( f->size >= f->capacity ) + { + f->wait_full = 1; + hb_cond_timedwait( f->cond_full, f->lock, FIFO_TIMEOUT ); + } + result = ( f->size < f->capacity ); + hb_unlock( f->lock ); + return result; +} + +void hb_fifo_push_wait( hb_fifo_t * f, hb_buffer_t * b ) +{ + if( !b ) + { + return; + } + + hb_lock( f->lock ); + if( f->size >= f->capacity ) + { + f->wait_full = 1; + hb_cond_timedwait( f->cond_full, f->lock, FIFO_TIMEOUT ); + } + if( f->size > 0 ) + { + f->last->next = b; + } + else + { + f->first = b; + } + f->last = b; + f->size += 1; + while( f->last->next ) + { + f->size += 1; + f->last = f->last->next; + } + if( f->wait_empty && f->size >= f->thresh ) + { + f->wait_empty = 0; + hb_cond_signal( f->cond_empty ); + } + hb_unlock( f->lock ); +} + void hb_fifo_push( hb_fifo_t * f, hb_buffer_t * b ) { if( !b ) @@ -440,6 +470,48 @@ void hb_fifo_push( hb_fifo_t * f, hb_buffer_t * b ) f->size += 1; f->last = f->last->next; } + if( f->wait_empty && f->size >= f->thresh ) + { + f->wait_empty = 0; + hb_cond_signal( f->cond_empty ); + } + 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 ); } @@ -448,14 +520,32 @@ 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 ); } hb_lock_close( &f->lock ); + hb_cond_close( &f->cond_empty ); + hb_cond_close( &f->cond_full ); free( f ); *_f = NULL; } + +void hb_fifo_flush( hb_fifo_t * f ) +{ + hb_buffer_t * b; + + while( ( b = hb_fifo_get( f ) ) ) + { + hb_buffer_close( &b ); + } + hb_lock( f->lock ); + hb_cond_signal( f->cond_empty ); + hb_cond_signal( f->cond_full ); + hb_unlock( f->lock ); + +} +