Big luma optimisations, minor pooling optimisations
[melted] / src / framework / mlt_pool.c
1 /*
2 * mlt_pool.c -- memory pooling functionality
3 * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #include "mlt_properties.h"
22 #include "mlt_deque.h"
23
24 #include <stdlib.h>
25 #include <malloc.h>
26 #include <string.h>
27 #include <pthread.h>
28
29 /** Singleton repositories
30 */
31
32 static mlt_properties pools = NULL;
33
34 /** Private pooling structure.
35 */
36
37 typedef struct mlt_pool_s
38 {
39 pthread_mutex_t lock;
40 mlt_deque stack;
41 int size;
42 int count;
43 }
44 *mlt_pool;
45
46 typedef struct mlt_release_s
47 {
48 mlt_pool pool;
49 int references;
50 }
51 *mlt_release;
52
53 /** Create a pool.
54 */
55
56 static mlt_pool pool_init( int size )
57 {
58 // Create the pool
59 mlt_pool this = calloc( 1, sizeof( struct mlt_pool_s ) );
60
61 // Initialise it
62 if ( this != NULL )
63 {
64 // Initialise the mutex
65 pthread_mutex_init( &this->lock, NULL );
66
67 // Create the stack
68 this->stack = mlt_deque_init( );
69
70 // Assign the size
71 this->size = size;
72 }
73
74 // Return it
75 return this;
76 }
77
78 /** Get an item from the pool.
79 */
80
81 static void *pool_fetch( mlt_pool this )
82 {
83 // We will generate a release object
84 void *ptr = NULL;
85
86 // Sanity check
87 if ( this != NULL )
88 {
89 // Lock the pool
90 pthread_mutex_lock( &this->lock );
91
92 // Check if the stack is empty
93 if ( mlt_deque_count( this->stack ) != 0 )
94 {
95 // Pop the top of the stack
96 ptr = mlt_deque_pop_back( this->stack );
97
98 // Assign the reference
99 ( ( mlt_release )ptr )->references = 1;
100 }
101 else
102 {
103 // We need to generate a release item
104 mlt_release release = memalign( 16, this->size );
105
106 // Initialise it
107 if ( release != NULL )
108 {
109 // Assign the pool
110 release->pool = this;
111
112 // Assign the reference
113 release->references = 1;
114
115 // Determine the ptr
116 ptr = ( void * )release + sizeof( struct mlt_release_s );
117 }
118 }
119
120 // Unlock the pool
121 pthread_mutex_unlock( &this->lock );
122 }
123
124 // Return the generated release object
125 return ptr;
126 }
127
128 /** Return an item to the pool.
129 */
130
131 static void pool_return( void *ptr )
132 {
133 // Sanity checks
134 if ( ptr != NULL )
135 {
136 // Get the release pointer
137 mlt_release that = ptr - sizeof( struct mlt_release_s );
138
139 // Get the pool
140 mlt_pool this = that->pool;
141
142 if ( this != NULL )
143 {
144 // Lock the pool
145 pthread_mutex_lock( &this->lock );
146
147 // Push the that back back on to the stack
148 mlt_deque_push_back( this->stack, ptr );
149
150 // Unlock the pool
151 pthread_mutex_unlock( &this->lock );
152
153 // Ensure that we don't clean up
154 ptr = NULL;
155 }
156 }
157
158 // Tidy up - this will only occur if the returned item is incorrect
159 if ( ptr != NULL )
160 {
161 // Free the release itself
162 free( ptr - sizeof( struct mlt_release_s ) );
163 }
164 }
165
166 /** Destroy a pool.
167 */
168
169 static void pool_close( mlt_pool this )
170 {
171 if ( this != NULL )
172 {
173 // We need to free up all items in the pool
174 void *release = NULL;
175
176 // Iterate through the stack until depleted
177 while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL )
178 {
179 // We'll free this item now
180 free( release - sizeof( struct mlt_release_s ) );
181 }
182
183 // We can now close the stack
184 mlt_deque_close( this->stack );
185
186 // Destroy the mutex
187 pthread_mutex_destroy( &this->lock );
188
189 // Close the pool
190 free( this );
191 }
192 }
193
194 /** Initialise the pool.
195 */
196
197 void mlt_pool_init( )
198 {
199 // Loop variable used to create the pools
200 int i = 0;
201
202 // Create the pools
203 pools = mlt_properties_new( );
204
205 // Create the pools
206 for ( i = 8; i < 31; i ++ )
207 {
208 // Each properties item needs a name
209 char name[ 32 ];
210
211 // Construct a pool
212 mlt_pool pool = pool_init( 1 << i );
213
214 // Generate a name
215 sprintf( name, "%d", i );
216
217 // Register with properties
218 mlt_properties_set_data( pools, name, pool, 0, ( mlt_destructor )pool_close, NULL );
219 }
220 }
221
222 /** Allocate size bytes from the pool.
223 */
224
225 void *mlt_pool_alloc( int size )
226 {
227 // This will be used to obtain the pool to use
228 mlt_pool pool = NULL;
229
230 // Determines the index of the pool to use
231 int index = 8;
232
233 // Minimum size pooled is 256 bytes
234 size = size + sizeof( mlt_release );
235 while ( ( 1 << index ) < size )
236 index ++;
237
238 // Now get the pool at the index
239 pool = mlt_properties_get_data_at( pools, index - 8, NULL );
240
241 // Now get the real item
242 return pool_fetch( pool );
243 }
244
245 /** Release the allocated memory.
246 */
247
248 void mlt_pool_release( void *release )
249 {
250 // Return to the pool
251 pool_return( release );
252 }
253
254 /** Close the pool.
255 */
256
257 void mlt_pool_close( )
258 {
259 // Close the properties
260 mlt_properties_close( pools );
261 }
262