21 #ifdef ENABLE_MEMORY_HOOK
33 const int MAXIMUM_HASH_SLOTS = 256 *
KILOBYTE;
37 const int SINGLE_LINE_SIZE_ESTIMATE = 200;
42 const int RESERVED_AREA = 1000;
46 #define CLEAR_ALLOCATED_MEMORY
51 #define MEMORY_CHECKER_STATISTICS
62 #include <basis/trap_new.addin>
63 void *
operator new(
size_t size,
char *file,
int line)
throw (std::bad_alloc)
65 #include <basis/untrap_new.addin>
67 void operator delete(
void *ptr)
throw ()
86 #ifdef ENABLE_CALLSTACK_TRACKING
90 void construct(
void *ptr,
int size,
char *where,
int line) {
94 _where = strdup(where);
95 if (strlen(_where) > SINGLE_LINE_SIZE_ESTIMATE - 40) {
97 _where[SINGLE_LINE_SIZE_ESTIMATE - 40] =
'\0';
100 #ifdef ENABLE_CALLSTACK_TRACKING
101 _stack = program_wide_stack_trace().full_trace();
112 #ifdef ENABLE_CALLSTACK_TRACKING
121 #ifdef MEMORY_CHECKER_STATISTICS
128 double _stat_new_allocations = 0;
129 double _stat_freed_allocations = 0;
131 double _stat_new_allocations_size = 0;
132 double _stat_freed_allocations_size = 0;
145 _lock = (mutex_base *)malloc(
sizeof(mutex_base));
153 int count()
const {
return _count; }
155 int record_memory(
void *ptr,
int size,
char *where,
int line) {
156 memlink *new_guy = (memlink *)malloc(
sizeof(memlink));
157 new_guy->construct(ptr, size, where, line);
161 new_guy->_next = _head;
168 int release_memory(
void *to_release) {
171 memlink *current = _head;
174 if (current->_chunk == to_release) {
175 #ifdef MEMORY_CHECKER_STATISTICS
177 _stat_freed_allocations += 1.0;
178 _stat_freed_allocations_size += current->_size;
180 #ifdef DEBUG_MEMORY_CHECKER
181 printf(
"found %p listed, removing for %s[%d]\n", to_release,
182 current->_where, current->_line);
187 _head = current->_next;
190 previous->_next = current->_next;
201 current = current->_next;
203 #ifdef DEBUG_MEMORY_CHECKER
204 printf(
"failed to find %p listed.\n", to_release);
207 return common::NOT_FOUND;
210 void dump_list(
char *add_to,
int &curr_size,
int max_size) {
211 int size_alloc = 2 * SINGLE_LINE_SIZE_ESTIMATE;
212 char *temp_str = (
char *)malloc(size_alloc);
213 memlink *current = _head;
216 sprintf(temp_str,
"\n\"%s[%d]\", \"size %d\", \"addr %p\"\n",
217 current->_where, current->_line, current->_size, current->_chunk);
218 int len_add = strlen(temp_str);
219 if (curr_size + len_add < max_size) {
220 strcat(add_to, temp_str);
221 curr_size += len_add;
223 #ifdef ENABLE_CALLSTACK_TRACKING
224 len_add = strlen(current->_stack);
225 if (curr_size + len_add < max_size) {
226 strcat(add_to, current->_stack);
227 curr_size += len_add;
230 current = current->_next;
243 class allocation_memories
246 void construct(
int num_slots) {
247 _num_slots = num_slots;
248 _bins = (memory_bin *)malloc(num_slots *
sizeof(memory_bin));
249 for (
int i = 0; i < num_slots; i++)
250 _bins[i].construct();
255 for (
int i = 0; i < _num_slots; i++) {
262 int compute_slot(
void *ptr) {
263 return utility::hash_bytes(&ptr,
sizeof(
void *)) % _num_slots;
266 void *provide_memory(
int size_needed,
char *file,
int line) {
267 void *new_allocation = malloc(size_needed);
269 int slot = compute_slot(new_allocation);
270 #ifdef DEBUG_MEMORY_CHECKER
271 printf(
"using slot %d for %p\n", slot, new_allocation);
273 _bins[slot].record_memory(new_allocation, size_needed, file, line);
274 #ifdef MEMORY_CHECKER_STATISTICS
275 _stat_new_allocations += 1.0;
276 _stat_new_allocations_size += size_needed;
278 return new_allocation;
281 int release_memory(
void *to_drop) {
282 int slot = compute_slot(to_drop);
283 #ifdef DEBUG_MEMORY_CHECKER
284 printf(
"removing mem %p from slot %d.\n", to_drop, slot);
286 return _bins[slot].release_memory(to_drop);
294 char *report_allocations() {
297 for (
int i = 0; i < _num_slots; i++) {
299 full_count += _bins[i].count();
303 int alloc_size = full_count * SINGLE_LINE_SIZE_ESTIMATE + RESERVED_AREA;
304 char *to_return = (
char *)malloc(alloc_size);
307 strcat(to_return,
"===================\n");
308 strcat(to_return,
"Unfreed Allocations\n");
309 strcat(to_return,
"===================\n");
311 int curr_size = strlen(to_return);
312 for (
int i = 0; i < _num_slots; i++) {
313 _bins[i].dump_list(to_return, curr_size, alloc_size - RESERVED_AREA);
319 char *text_form(
bool show_outstanding) {
321 if (show_outstanding) {
322 to_return = report_allocations();
324 to_return = (
char *)malloc(RESERVED_AREA);
327 #ifdef MEMORY_CHECKER_STATISTICS
328 char *temp_str = (
char *)malloc(4 * SINGLE_LINE_SIZE_ESTIMATE);
330 sprintf(temp_str,
"=================\n");
331 strcat(to_return, temp_str);
332 sprintf(temp_str,
"Memory Statistics\n");
333 strcat(to_return, temp_str);
334 sprintf(temp_str,
"=================\n");
335 strcat(to_return, temp_str);
336 sprintf(temp_str,
"Measurements taken across entire program runtime:\n");
337 strcat(to_return, temp_str);
338 sprintf(temp_str,
" %.0f new allocations.\n", _stat_new_allocations);
339 strcat(to_return, temp_str);
340 sprintf(temp_str,
" %.4f new Mbytes.\n",
341 _stat_new_allocations_size /
MEGABYTE);
342 strcat(to_return, temp_str);
343 sprintf(temp_str,
" %.0f freed deallocations.\n",
344 _stat_freed_allocations);
345 strcat(to_return, temp_str);
346 sprintf(temp_str,
" %.4f freed Mbytes.\n",
347 _stat_freed_allocations_size /
MEGABYTE);
348 strcat(to_return, temp_str);
362 void memory_checker::construct()
364 _mems = (allocation_memories *)malloc(
sizeof(allocation_memories));
365 _mems->construct(MAXIMUM_HASH_SLOTS);
370 void memory_checker::destruct()
372 if (_unusable)
return;
373 if (!_mems) printf(
"memory_checker::destruct being invoked twice!\n");
376 char *mem_state = text_form(
true);
377 printf(
"%s", mem_state);
388 void *memory_checker::provide_memory(
size_t size,
char *file,
int line)
390 if (_unusable || !_enabled)
return malloc(size);
391 return _mems->provide_memory(size, file, line);
394 int memory_checker::release_memory(
void *ptr)
396 if (_unusable || !_enabled) {
400 return _mems->release_memory(ptr);
403 char *memory_checker::text_form(
bool show_outstanding)
405 if (_unusable)
return strdup(
"already destroyed memory_checker!\n");
406 return _mems->text_form(show_outstanding);
Constants and objects used throughout HOOPLE.
#define NULL_POINTER
The value representing a pointer to nothing.
#define program_wide_memories()
basis::astring dump_list(type v[], int size)
dumps the contents of the list out, assuming that the type can be turned into an int.
const int MEGABYTE
Number of bytes in a megabyte.
const int KILOBYTE
Number of bytes in a kilobyte.