1 /* $Id: fifo.c,v 1.17 2005/10/15 18:05:03 titer Exp $
3 This file is part of the HandBrake source code.
4 Homepage: <http://handbrake.fr/>.
5 It may be used under the terms of the GNU General Public License. */
24 /* we round the requested buffer size up to the next power of 2 so there can
25 * be at most 32 possible pools when the size is a 32 bit int. To avoid a lot
26 * of slow & error-prone run-time checking we allow for all 32. */
27 #define MAX_BUFFER_POOLS 32
28 /* the buffer pool only exists to avoid the two malloc and two free calls that
29 * it would otherwise take to allocate & free a buffer. but we don't want to
30 * tie up a lot of memory in the pool because this allocator isn't as general
31 * as malloc so memory tied up here puts more pressure on the malloc pool.
32 * A pool of 16 elements will avoid 94% of the malloc/free calls without wasting
34 #define BUFFER_POOL_MAX_ELEMENTS 32
36 struct hb_buffer_pools_s
40 hb_fifo_t *pool[MAX_BUFFER_POOLS];
44 void hb_buffer_pool_init( void )
46 buffers.lock = hb_lock_init();
47 buffers.allocated = 0;
49 /* we allocate pools for sizes 2^10 through 2^25. requests larger than
50 * 2^25 will get passed through to malloc. */
52 for ( i = 10; i < 26; ++i )
54 buffers.pool[i] = hb_fifo_init(BUFFER_POOL_MAX_ELEMENTS);
55 buffers.pool[i]->buffer_size = 1 << i;
57 /* requests smaller than 2^10 are satisfied from the 2^10 pool. */
58 for ( i = 1; i < 10; ++i )
60 buffers.pool[i] = buffers.pool[10];
64 void hb_buffer_pool_free( void )
71 hb_lock(buffers.lock);
73 for( i = 10; i < 26; ++i)
76 while( ( b = hb_fifo_get(buffers.pool[i]) ) )
88 hb_deep_log( 2, "Freed %d buffers of size %d", count,
89 buffers.pool[i]->buffer_size);
93 hb_deep_log( 2, "Allocated %lld bytes of buffers on this pass and Freed %lld bytes, "
94 "%lld bytes leaked", buffers.allocated, freed, buffers.allocated - freed);
95 buffers.allocated = 0;
96 hb_unlock(buffers.lock);
99 static hb_fifo_t *size_to_pool( int size )
102 for ( i = 0; i < 30; ++i )
104 if ( size <= (1 << i) )
106 return buffers.pool[i];
112 hb_buffer_t * hb_buffer_init( int size )
115 hb_fifo_t *buffer_pool = size_to_pool( size );
119 b = hb_fifo_get( buffer_pool );
124 * Zero the contents of the buffer, would be nice if we
125 * didn't have to do this.
127 uint8_t *data = b->data;
128 memset( b, 0, sizeof(hb_buffer_t) );
129 b->alloc = buffer_pool->buffer_size;
137 * No existing buffers, create a new one
139 if( !( b = calloc( sizeof( hb_buffer_t ), 1 ) ) )
141 hb_log( "out of memory" );
146 b->alloc = buffer_pool? buffer_pool->buffer_size : size;
150 #if defined( SYS_DARWIN ) || defined( SYS_FREEBSD )
151 b->data = malloc( b->alloc );
152 #elif defined( SYS_CYGWIN )
154 b->data = malloc( b->alloc + 17 );
156 b->data = memalign( 16, b->alloc );
160 hb_log( "out of memory" );
164 hb_lock(buffers.lock);
165 buffers.allocated += b->alloc;
166 hb_unlock(buffers.lock);
171 void hb_buffer_realloc( hb_buffer_t * b, int size )
173 if ( size > b->alloc )
175 uint32_t orig = b->alloc;
176 size = size_to_pool( size )->buffer_size;
177 b->data = realloc( b->data, size );
180 hb_lock(buffers.lock);
181 buffers.allocated += size - orig;
182 hb_unlock(buffers.lock);
186 void hb_buffer_close( hb_buffer_t ** _b )
188 hb_buffer_t * b = *_b;
189 hb_fifo_t *buffer_pool = size_to_pool( b->alloc );
191 if( buffer_pool && b->data && !hb_fifo_is_full( buffer_pool ) )
193 hb_fifo_push_head( buffer_pool, b );
196 /* either the pool is full or this size doesn't use a pool - free the buf */
200 hb_lock(buffers.lock);
201 buffers.allocated -= b->alloc;
202 hb_unlock(buffers.lock);
208 void hb_buffer_copy_settings( hb_buffer_t * dst, const hb_buffer_t * src )
210 dst->start = src->start;
211 dst->stop = src->stop;
212 dst->new_chap = src->new_chap;
213 dst->frametype = src->frametype;
214 dst->flags = src->flags;
217 hb_fifo_t * hb_fifo_init( int capacity )
220 f = calloc( sizeof( hb_fifo_t ), 1 );
221 f->lock = hb_lock_init();
222 f->capacity = capacity;
227 int hb_fifo_size( hb_fifo_t * f )
233 hb_unlock( f->lock );
238 int hb_fifo_is_full( hb_fifo_t * f )
243 ret = ( f->size >= f->capacity );
244 hb_unlock( f->lock );
249 float hb_fifo_percent_full( hb_fifo_t * f )
254 ret = f->size / f->capacity;
255 hb_unlock( f->lock );
260 hb_buffer_t * hb_fifo_get( hb_fifo_t * f )
267 hb_unlock( f->lock );
274 hb_unlock( f->lock );
279 hb_buffer_t * hb_fifo_see( hb_fifo_t * f )
286 hb_unlock( f->lock );
290 hb_unlock( f->lock );
295 hb_buffer_t * hb_fifo_see2( hb_fifo_t * f )
302 hb_unlock( f->lock );
306 hb_unlock( f->lock );
311 void hb_fifo_push( hb_fifo_t * f, hb_buffer_t * b )
329 while( f->last->next )
332 f->last = f->last->next;
334 hb_unlock( f->lock );
337 void hb_fifo_push_head( hb_fifo_t * f, hb_buffer_t * b )
350 * If there are a chain of buffers prepend the lot
361 tmp->next = f->first;
369 f->size += ( size + 1 );
371 hb_unlock( f->lock );
374 void hb_fifo_close( hb_fifo_t ** _f )
379 hb_deep_log( 2, "fifo_close: trashing %d buffer(s)", hb_fifo_size( f ) );
380 while( ( b = hb_fifo_get( f ) ) )
382 hb_buffer_close( &b );
385 hb_lock_close( &f->lock );