OSDN Git Service

LinGui: SRT support
[handbrake-jp/handbrake-jp-git.git] / libhb / fifo.c
index 44c64d9..48f6459 100644 (file)
@@ -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: <http://handbrake.m0k.org/>.
+   Homepage: <http://handbrake.fr/>.
    It may be used under the terms of the GNU General Public License. */
 
 #include "hb.h"
 #include <malloc.h>
 #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 %"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);
+}
+
+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 );