summaryrefslogtreecommitdiffstats
path: root/libhb/fifo.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhb/fifo.c')
-rw-r--r--libhb/fifo.c285
1 files changed, 88 insertions, 197 deletions
diff --git a/libhb/fifo.c b/libhb/fifo.c
index 69b8b908b..1bf2a9de6 100644
--- a/libhb/fifo.c
+++ b/libhb/fifo.c
@@ -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,70 +79,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_log("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_log("Allocated %lld bytes of buffers on this pass and Freed %lld bytes, "
+ "%lld 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 +123,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 +143,66 @@ 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 );
+ 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( buffer_pool, b );
+ 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 )