the mega audio-memory-profiler-patch TM
[vg.git] / src / vg / vg_mem.h
1 #ifndef VG_MEM_H
2 #define VG_MEM_H
3
4 #include "vg_stdint.h"
5 #include "vg_platform.h"
6
7 #include <stdlib.h>
8 #include <malloc.h>
9
10 #define VG_MAX_ALLOCATIONS 64
11 #define VG_FUZZ_ALLOCATIONS
12
13 typedef struct vg_linear_allocator vg_linear_allocator;
14 typedef struct vg_allocation_meta vg_allocation_meta;
15
16 struct
17 {
18 void *rtmemory,
19 *scratch;
20
21 int use_libc_malloc;
22 u32 quota;
23 }
24 static vg_mem;
25
26 struct vg_allocation_meta
27 {
28 void *data;
29 enum allocation_type
30 {
31 k_allocation_type_block = 0,
32 k_allocation_type_linear = 1
33 }
34 type;
35 };
36
37 #define VG_MEMORY_SYSTEM 0x1 /* systems memory, slow and low counts */
38 #define VG_MEMORY_REALTIME 0x2 /* per-frame. no max allocs, only size. fast */
39
40 /* systems memory cannot be declared inside realtime memory regions */
41
42 /*
43 * Stored just behind the array. 32 bytes.
44 */
45 #pragma pack(push,1)
46 struct vg_linear_allocator
47 {
48 u32 size;
49 /* */
50 /* */
51 /* */
52 u32 cur;
53 /* */
54 /* */
55 /* */
56 u16 allocation_count;
57 /* */
58 u16 flags;
59 /* */
60 u32 last_alloc_size;
61 /* */
62 /* */
63 /* */
64 void *last_alloc;
65 /* */
66 /* */
67 /* */
68 /* */
69 /* */
70 /* */
71 /* */
72 vg_allocation_meta *alloc_table;
73 /* */
74 /* */
75 /* */
76 /* */
77 /* */
78 /* */
79 /* */
80 };
81 #pragma pack(pop)
82
83 VG_STATIC void vg_error(const char *fmt, ...);
84 VG_STATIC void vg_info(const char *fmt, ...);
85
86 /* Returns allocator structure from data pointer */
87 static vg_linear_allocator *vg_linear_header( void *data )
88 {
89 vg_linear_allocator *ptr = data;
90 ptr --;
91
92 return ptr;
93 }
94
95 /* allocate something from a linear allocator */
96 __attribute__((warn_unused_result))
97 VG_STATIC void *vg_linear_alloc( void *buffer, u32 size )
98 {
99 vg_linear_allocator *alloc = vg_linear_header( buffer );
100
101 if( (alloc->cur + size) > alloc->size )
102 {
103 vg_error( "%u + %u > %u\n", alloc->cur, size, alloc->size );
104 vg_fatal_exit_loop( "linear allocator overflow" );
105 }
106
107 if( alloc->flags & VG_MEMORY_SYSTEM )
108 if( (alloc->allocation_count + 1) > VG_MAX_ALLOCATIONS )
109 vg_fatal_exit_loop( "Max linear allocations reached" );
110
111 void *data;
112
113 if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) )
114 {
115 data = malloc( size );
116
117 vg_allocation_meta *meta = &alloc->alloc_table[ alloc->allocation_count ];
118 meta->type = k_allocation_type_block;
119 meta->data = data;
120 }
121 else
122 {
123 data = buffer + alloc->cur;
124 }
125
126 alloc->allocation_count ++;
127 alloc->last_alloc = data;
128 alloc->last_alloc_size = size;
129 alloc->cur += size;
130
131 return data;
132 }
133
134
135 /* resize latest block of memory from linear */
136 __attribute__((warn_unused_result))
137 VG_STATIC void *vg_linear_resize( void *buffer, void *data, u32 newsize )
138 {
139 vg_linear_allocator *alloc = vg_linear_header( buffer );
140
141 if( alloc->last_alloc != data )
142 vg_fatal_exit_loop( "This block has been fixed!" );
143
144 if( (alloc->cur - alloc->last_alloc_size + newsize) > alloc->size )
145 vg_fatal_exit_loop( "Cannot resize, overflow" );
146
147 alloc->cur -= alloc->last_alloc_size;
148 alloc->cur += newsize;
149 alloc->last_alloc_size = newsize;
150
151 if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) )
152 {
153 data = realloc( data, newsize );
154 if( !data )
155 vg_fatal_exit_loop( "realloc failed" );
156
157 alloc->alloc_table[ alloc->allocation_count-1 ].data = data;
158 alloc->last_alloc = data;
159 return data;
160 }
161 else
162 {
163 return data;
164 }
165 }
166
167 /* its possible to delete just the last item */
168 VG_STATIC void vg_linear_del( void *buffer, void *data )
169 {
170 vg_linear_allocator *alloc = vg_linear_header( buffer );
171
172 if( alloc->last_alloc != data )
173 vg_fatal_exit_loop( "This block has been fixed!" );
174
175 if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) )
176 {
177 vg_allocation_meta *meta = &alloc->alloc_table[alloc->allocation_count-1];
178 if( meta->type == k_allocation_type_linear )
179 vg_fatal_exit_loop( "Cannot free a linear allocator in this conext" );
180
181 free( data );
182 }
183
184 alloc->allocation_count --;
185 alloc->cur -= alloc->last_alloc_size;
186 alloc->last_alloc = NULL;
187 alloc->last_alloc_size = 0;
188 }
189
190 /* extend latest block of memory from linear */
191 __attribute__((warn_unused_result))
192 VG_STATIC void *vg_linear_extend( void *buffer, void *data, u32 extra )
193 {
194 vg_linear_allocator *alloc = vg_linear_header( buffer );
195
196 if( alloc->last_alloc != data )
197 vg_fatal_exit_loop( "This block has been fixed!" );
198
199 u32 new_size = alloc->last_alloc_size + extra;
200 return vg_linear_resize( buffer, data, new_size );
201 }
202
203 /* get the current usage of allocator */
204 VG_STATIC u32 vg_linear_get_cur( void *buffer )
205 {
206 vg_linear_allocator *alloc = vg_linear_header( buffer );
207 return alloc->cur;
208 }
209
210 /* get the capacity of allocator. */
211 VG_STATIC u32 vg_linear_get_capacity( void *buffer )
212 {
213 vg_linear_allocator *alloc = vg_linear_header( buffer );
214 return alloc->size;
215 }
216
217 /* get the remaining size of the allocator */
218 VG_STATIC u32 vg_linear_remaining( void *buffer )
219 {
220 vg_linear_allocator *alloc = vg_linear_header( buffer );
221 return alloc->size - alloc->cur;
222 }
223
224 /* yeet all memory from linear allocator */
225 VG_STATIC void vg_linear_clear( void *buffer )
226 {
227 vg_linear_allocator *alloc = vg_linear_header( buffer );
228
229 /* libc mode we recursively free any allocations made */
230 if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) )
231 {
232 for( u32 i=0; i<alloc->allocation_count; i++ )
233 {
234 vg_allocation_meta *meta = &alloc->alloc_table[i];
235
236 if( meta->type == k_allocation_type_block )
237 {
238 free( meta->data );
239 }
240 else
241 {
242 vg_linear_clear( meta->data );
243 vg_linear_allocator *sub = vg_linear_header( meta->data );
244
245 free( sub->alloc_table );
246 free( sub );
247 }
248 }
249 }
250
251 alloc->last_alloc = NULL;
252 alloc->last_alloc_size = 0;
253 alloc->allocation_count = 0;
254 alloc->cur = 0;
255 }
256
257 /* allocate a FIXED SIZE linear allocator */
258 VG_STATIC void *vg_create_linear_allocator( void *lin_alloc, u32 size,
259 u16 flags )
260 {
261 assert( sizeof( vg_linear_allocator ) == 32 );
262
263 vg_linear_allocator *header;
264 u32 block_size = size + sizeof(vg_linear_allocator);
265
266 /* Creating it inside an existing one */
267 if( lin_alloc )
268 {
269 vg_linear_allocator *alloc = vg_linear_header( lin_alloc );
270
271 if( alloc->cur + block_size > alloc->size )
272 vg_fatal_exit_loop( "Out of memory" );
273
274 if( alloc->allocation_count + 1 > VG_MAX_ALLOCATIONS )
275 vg_fatal_exit_loop( "Max allocations in linear allocator" );
276
277 if( (flags && VG_MEMORY_SYSTEM) && (alloc->flags & VG_MEMORY_REALTIME) )
278 vg_fatal_exit_loop( "Cannot declare realtime allocator inside systems"
279 " allocator" );
280
281 if( vg_mem.use_libc_malloc )
282 {
283 vg_allocation_meta *meta =
284 &alloc->alloc_table[ alloc->allocation_count ];
285
286 if( flags & VG_MEMORY_REALTIME )
287 header = malloc( block_size );
288 else
289 header = malloc( sizeof(vg_linear_allocator) );
290
291 meta->data = header+1;
292 meta->type = k_allocation_type_linear;
293 }
294 else
295 {
296 header = lin_alloc + alloc->cur;
297 }
298
299 alloc->cur += block_size;
300 alloc->last_alloc = NULL; /* cant resize this block! */
301 alloc->last_alloc_size = block_size;
302
303 alloc->allocation_count ++;
304 }
305 else
306 {
307 if( vg_mem.use_libc_malloc && (flags & VG_MEMORY_SYSTEM) )
308 header = malloc( sizeof(vg_linear_allocator) );
309 else
310 header = malloc( block_size );
311 }
312
313 header->allocation_count = 0;
314 header->cur = 0;
315 header->last_alloc = NULL;
316 header->last_alloc_size = 0;
317 header->size = size;
318 header->flags = flags;
319
320 if( vg_mem.use_libc_malloc && (flags & VG_MEMORY_SYSTEM) )
321 {
322 u32 table_size = sizeof(vg_allocation_meta)*VG_MAX_ALLOCATIONS;
323 header->alloc_table = malloc( table_size );
324 }
325 else
326 header->alloc_table = NULL;
327
328 return header+1;
329 }
330
331 /* request all the memory we need in advance */
332 VG_STATIC void vg_set_mem_quota( u32 size )
333 {
334 vg_mem.quota = size;
335 }
336
337 VG_STATIC void vg_alloc_quota(void)
338 {
339 u32 size_scratch = 10*1024*1024;
340 u32 size = VG_MAX( vg_mem.quota, size_scratch );
341
342 vg_mem.rtmemory = vg_create_linear_allocator( NULL, size, VG_MEMORY_SYSTEM );
343 vg_mem.scratch = vg_create_linear_allocator( vg_mem.rtmemory,
344 size_scratch,
345 VG_MEMORY_SYSTEM );
346 }
347
348 #endif /* VG_MEM_H */