1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
#include "../include/al/lib.h"
AL_ASSERT_TYPE_SIZE(int, 4);
AL_ASSERT_TYPE_SIZE(unsigned, 4);
#if defined AL_WE_64BIT
AL_ASSERT_TYPE_SIZE(intptr_t, 8);
#elif defined AL_WE_32BIT
AL_ASSERT_TYPE_SIZE(long, 4);
AL_ASSERT_TYPE_SIZE(intptr_t, 4);
#endif
#ifdef AL_MEMORY_TRACKING
static void *(*_al_malloc)(size_t) = NULL;
static void *(*_al_calloc)(size_t, size_t) = NULL;
static void *(*_al_realloc)(void *, size_t) = NULL;
static void (*_al_free)(void *) = NULL;
#ifdef AL_HAVE_POSIX_MEMALIGN
s32 (*_al_posix_memalign)(void **, size_t, size_t) = NULL;
#endif
static void (*_al_malloc_lock)(void) = NULL;
static void (*_al_malloc_unlock)(void) = NULL;
// Testing allocation tracking stuff (Very scuffed).
struct al_alloc_t {
void *ptr;
size_t size;
};
// Use stdlib malloc for the allocation tracking array.
// This avoids a circular dependency and also keeps allocations
// from the memory tracking code out of the stats.
#include "../include/al/types.h"
#define AL_ARRAY_MALLOC malloc
#define AL_ARRAY_REALLOC realloc
#define AL_ARRAY_FREE free
#include "array.c"
static array(struct al_alloc_t) allocations;
static size_t current_alloc = 0;
static size_t peak_alloc = 0;
static size_t total_alloc = 0;
static size_t alloc_operations = 0;
#define total_changed_by(n) \
total_alloc += (n); \
#define current_changed_by(n) \
current_alloc += (n); \
if (current_alloc > peak_alloc) { \
peak_alloc = current_alloc; \
} \
alloc_operations++;
void al_malloc_init(void)
{
al_array_init(allocations);
}
void al_malloc_close(void)
{
al_array_free(allocations);
}
void *al_malloc(size_t n)
{
al_printf("**al_malloc(%zu)\n", n);
void *ptr = _al_malloc(n);
_al_malloc_lock();
total_changed_by(n);
current_changed_by(n);
al_array_push(allocations, ((struct al_alloc_t){ ptr, n }));
_al_malloc_unlock();
return ptr;
}
void *al_calloc(size_t n, size_t size)
{
al_printf("**al_calloc(%zu, %zu)\n", n, size);
void *ptr = _al_calloc(n, size);
size_t total_size = n * size;
_al_malloc_lock();
total_changed_by(total_size);
current_changed_by(total_size);
al_array_push(allocations, ((struct al_alloc_t){ ptr, total_size }));
_al_malloc_unlock();
return ptr;
}
void *al_realloc(void *ptr, size_t n)
{
al_printf("**al_realloc(%p, %zu)\n", ptr, n);
#ifdef AL_PARANOID_REALLOC
void *new_ptr = ptr ? _al_realloc(ptr, n) : _al_malloc(n);
#else
void *new_ptr = _al_realloc(ptr, n);
#endif
_al_malloc_lock();
total_changed_by(n);
if (!ptr) {
current_changed_by(n);
al_array_push(allocations, ((struct al_alloc_t){ new_ptr, n }));
} else {
struct al_alloc_t *alloc;
al_array_foreach_ptr(allocations, i, alloc) {
al_assert(alloc->ptr);
if (alloc->ptr == ptr) {
ptrdiff_t diff = (ptrdiff_t)n - (ptrdiff_t)alloc->size;
current_changed_by(diff);
alloc->ptr = new_ptr;
alloc->size = n;
break;
}
}
}
_al_malloc_unlock();
return new_ptr;
}
void al_free(void *ptr)
{
al_printf("**al_free(%p)\n", ptr);
_al_malloc_lock();
bool found = false;
struct al_alloc_t *alloc;
al_array_foreach_ptr(allocations, i, alloc) {
if (alloc->ptr == ptr) {
al_assert(!found);
current_changed_by(-alloc->size);
al_array_remove_at(allocations, i);
found = true;
}
}
al_assert(found);
_al_malloc_unlock();
_al_free(ptr);
}
#ifdef AL_HAVE_POSIX_MEMALIGN
s32 al_posix_memalign(void **ptr, size_t alignment, size_t n)
{
size_t real_size = (n + alignment) - ((n + alignment) % alignment);
al_printf("**al_posix_memalign(%zu, %zu(%zu))\n", alignment, n, real_size);
s32 result = _al_posix_memalign(ptr, alignment, n);
_al_malloc_lock();
total_changed_by(real_size);
current_changed_by(real_size);
al_array_push(allocations, ((struct al_alloc_t){ *ptr, real_size }));
_al_malloc_unlock();
return result;
}
#endif
void al_malloc_stats(size_t *current, size_t *peak, size_t *total, size_t *ops)
{
_al_malloc_lock();
*current = current_alloc;
*peak = peak_alloc;
*total = total_alloc;
*ops = alloc_operations;
_al_malloc_unlock();
}
void al_set_alloc(void *(*malloc_func)(size_t), void *(*calloc_func)(size_t, size_t),
void *(*realloc_func)(void *, size_t),
#ifdef AL_HAVE_POSIX_MEMALIGN
s32 (*posix_memalign_func)(void **, size_t, size_t),
#endif
void (*free_func)(void *), void (*lock_func)(void), void (*unlock_func)(void))
{
_al_malloc = malloc_func;
_al_calloc = calloc_func;
_al_realloc = realloc_func;
#ifdef AL_HAVE_POSIX_MEMALIGN
_al_posix_memalign = posix_memalign_func;
#endif
_al_free = free_func;
_al_malloc_lock = lock_func;
_al_malloc_unlock = unlock_func;
}
#endif
u32 al_grow_step = 0xfff; // 0b111111111111, 4095
//u32 al_grow_step = 0x3fff; // 0b11111111111111, 16383
u32 al_growing_allocation(void **ptr, u32 prev_size, u32 size, void *(*realloc_func)(void *, size_t))
{
if (size <= prev_size) return prev_size;
al_assert(size > 0);
if (size <= al_grow_step) {
// next_power_of_two(4096) = 4096.
size = al_next_power_of_two(size);
} else {
size = al_u32_add_wrap(size, al_grow_step, MAX_ALLOC_32) & ~al_grow_step;
}
// size can only be 0 after wrapping around MAX_ALLOC_32 (zero all possible bits).
if (size == 0) size = MAX_ALLOC_32;
*ptr = realloc_func(*ptr, size);
al_assert(*ptr);
return size;
}
size_t al_page_size = 0x1000; // 4096
void al_set_page_size(size_t size)
{
al_assert(size > 0);
al_page_size = size;
}
|