X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Ffifo.c;h=7337874bfe9673d22fea41f6e1d1b09cf9ebca97;hb=69bcedab6772552b36bc8f1591db6ea0c8de08c3;hp=44c64d9b072733612a064aca8563d5c25039ad8e;hpb=53e2779d92fae78e365b89358ee55b08eeb3c340;p=handbrake-jp%2Fhandbrake-jp-git.git
diff --git a/libhb/fifo.c b/libhb/fifo.c
index 44c64d9b..7337874b 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,55 +10,199 @@
#include
#endif
+/* Fifo */
+struct hb_fifo_s
+{
+ hb_lock_t * lock;
+ uint32_t capacity;
+ uint32_t size;
+ uint32_t buffer_size;
+ hb_buffer_t * first;
+ hb_buffer_t * last;
+};
+
+/* 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
+{
+ int64_t allocated;
+ hb_lock_t *lock;
+ hb_fifo_t *pool[MAX_BUFFER_POOLS];
+} buffers;
+
+
+void hb_buffer_pool_init( void )
+{
+ buffers.lock = hb_lock_init();
+ buffers.allocated = 0;
+
+ /* 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];
+ }
+}
+
+void hb_buffer_pool_free( void )
+{
+ int i;
+ int count;
+ int64_t freed = 0;
+ hb_buffer_t *b;
+
+ hb_lock(buffers.lock);
+
+ for( i = 10; i < 26; ++i)
+ {
+ count = 0;
+ while( ( b = hb_fifo_get(buffers.pool[i]) ) )
+ {
+ freed += b->alloc;
+ if( b->data )
+ {
+ free( b->data );
+ }
+ free( b );
+ count++;
+ }
+ if ( count )
+ {
+ hb_deep_log( 2, "Freed %d buffers of size %d", count,
+ buffers.pool[i]->buffer_size);
+ }
+ }
+
+ hb_deep_log( 2, "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);
+}
+
+static hb_fifo_t *size_to_pool( int size )
+{
+ int i;
+ for ( i = 0; i < 30; ++i )
+ {
+ if ( size <= (1 << i) )
+ {
+ return buffers.pool[i];
+ }
+ }
+ 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 );
+
+ if( b )
+ {
+ /*
+ * Zero the contents of the buffer, would be nice if we
+ * didn't have to do this.
+ */
+ uint8_t *data = b->data;
+ memset( b, 0, sizeof(hb_buffer_t) );
+ b->alloc = buffer_pool->buffer_size;
+ b->size = size;
+ b->data = data;
+ return( b );
+ }
+ }
+
+ /*
+ * No existing buffers, create a new one
+ */
if( !( b = calloc( sizeof( hb_buffer_t ), 1 ) ) )
{
hb_log( "out of memory" );
return NULL;
}
- b->alloc = size;
b->size = size;
- if (!size)
- return b;
-#if defined( SYS_DARWIN ) || defined( SYS_FREEBSD )
- b->data = malloc( size );
+ b->alloc = buffer_pool? buffer_pool->buffer_size : size;
+
+ if (size)
+ {
+#if defined( SYS_DARWIN ) || defined( SYS_FREEBSD ) || defined( SYS_MINGW )
+ b->data = malloc( b->alloc );
#elif defined( SYS_CYGWIN )
- /* FIXME */
- b->data = malloc( size + 17 );
+ /* FIXME */
+ b->data = malloc( b->alloc + 17 );
#else
- b->data = memalign( 16, size );
+ 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);
}
return b;
}
void hb_buffer_realloc( hb_buffer_t * b, int size )
{
- /* No more alignment, but we don't care */
- b->data = realloc( b->data, size );
- b->alloc = size;
+ 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 = size_to_pool( b->alloc );
+ if( buffer_pool && b->data && !hb_fifo_is_full( buffer_pool ) )
+ {
+ hb_fifo_push_head( buffer_pool, b );
+ *_b = NULL;
+ return;
+ }
+ /* either the pool is full or this size doesn't use a pool - free the buf */
if( b->data )
{
free( b->data );
+ hb_lock(buffers.lock);
+ buffers.allocated -= b->alloc;
+ hb_unlock(buffers.lock);
}
free( b );
-
*_b = NULL;
}
@@ -71,22 +215,13 @@ void hb_buffer_copy_settings( hb_buffer_t * dst, const hb_buffer_t * src )
dst->flags = src->flags;
}
-/* Fifo */
-struct hb_fifo_s
-{
- hb_lock_t * lock;
- int capacity;
- int size;
- hb_buffer_t * first;
- hb_buffer_t * last;
-};
-
hb_fifo_t * hb_fifo_init( int capacity )
{
hb_fifo_t * f;
f = calloc( sizeof( hb_fifo_t ), 1 );
f->lock = hb_lock_init();
f->capacity = capacity;
+ f->buffer_size = 0;
return f;
}
@@ -138,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;
}
@@ -200,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 );