117 lines
3.7 KiB
C
117 lines
3.7 KiB
C
#include "rvprof_internal.h"
|
|
|
|
// custom malloc, realloc and free help us tracking the memory footprint of rvprof
|
|
|
|
void* rvprof_malloc(size_t size){
|
|
void* ptr = malloc(size);
|
|
if (ptr) g_rvprof.total_memory_allocated += size;
|
|
return ptr;
|
|
}
|
|
|
|
void* rvprof_realloc(void* ptr, size_t old_size, size_t new_size){
|
|
void* new_ptr = realloc(ptr, new_size);
|
|
if (new_ptr) g_rvprof.total_memory_allocated += (new_size - old_size);
|
|
return new_ptr;
|
|
}
|
|
|
|
void rvprof_free(void* ptr, size_t size){
|
|
if(ptr){
|
|
free(ptr);
|
|
g_rvprof.total_memory_allocated -= size;
|
|
}
|
|
}
|
|
|
|
// DYNAMIC ARRAY MANAGEMENT
|
|
|
|
|
|
// generic ensure_capacity implementation, independent of actual array type
|
|
// maybe if switching to C++ in the future, we may move from pre-processor magic to templates
|
|
#define IMPLEMENT_ARRAY_ENSURE_CAPACITY(type, name, initial_size) \
|
|
int name##_array_ensure_capacity(name##_array_t* arr, int needed){ \
|
|
if (needed >= arr-> capacity){ \
|
|
int new_capacity; \
|
|
if (arr->capacity == 0){ \
|
|
new_capacity = initial_size; \
|
|
} else { \
|
|
new_capacity = arr->capacity; \
|
|
} \
|
|
\
|
|
while (new_capacity <= needed){ \
|
|
new_capacity *= GROWTH_FACTOR; \
|
|
} \
|
|
\
|
|
size_t old_size = arr->capacity * sizeof(type); \
|
|
size_t new_size = new_capacity * sizeof(type); \
|
|
type* new_data = rvprof_realloc(arr->data, old_size, new_size); \
|
|
if(!new_data){ \
|
|
return RVPROF_ERROR_MEMORY; \
|
|
} \
|
|
\
|
|
arr->data = new_data; \
|
|
arr->capacity = new_capacity; \
|
|
} \
|
|
return RVPROF_SUCCESS;\
|
|
}
|
|
|
|
// do the same for cleanup, taking a fuction alias for the slightly different cleanup logic for each type
|
|
#define IMPLEMENT_ARRAY_CLEANUP(type, name, cleanup_fn) \
|
|
void name##_array_cleanup(name##_array_t* arr){ \
|
|
if (arr->data){ \
|
|
for(int i=0; i<arr->size; i++){ \
|
|
cleanup_fn(&arr->data[i]); \
|
|
} \
|
|
rvprof_free(arr->data, arr->capacity * sizeof(type)); \
|
|
arr->data = NULL; \
|
|
arr->size = 0; \
|
|
arr->capacity = 0; \
|
|
} \
|
|
}
|
|
|
|
// full array implementation macro
|
|
#define IMPLEMENT_DYNAMIC_ARRAY(type, name, initial_size, cleanup_fn) \
|
|
IMPLEMENT_ARRAY_ENSURE_CAPACITY(type, name, initial_size) \
|
|
IMPLEMENT_ARRAY_CLEANUP(type, name, cleanup_fn)
|
|
|
|
// type-specific cleanups
|
|
static void cleanup_region_entry(void* item){
|
|
// region array doesn't need nested cleanup
|
|
return;
|
|
}
|
|
|
|
static void cleanup_symbol_entry(void* item){
|
|
symbol_entry_t* symbol = (symbol_entry_t*)item;
|
|
rvprof_free(symbol->name, strlen(symbol->name)+1);
|
|
symbol->name = NULL;
|
|
}
|
|
|
|
static void cleanup_function_stats(void* item){
|
|
function_stats_t* stats = (function_stats_t*)item;
|
|
if (stats->stack_ids) {
|
|
rvprof_free(stats->stack_ids, stats->max_stack_ids*sizeof(int));
|
|
stats->stack_ids = NULL;
|
|
}
|
|
if (stats->callers) {
|
|
for (int i=0; i<stats->num_callers; i++){
|
|
rvprof_free(stats->callers[i], strlen(stats->callers[i]+1));
|
|
}
|
|
rvprof_free(stats->callers, stats->max_callers*sizeof(char*));
|
|
stats->callers = NULL;
|
|
}
|
|
}
|
|
|
|
static void cleanup_stack_info(void* item){
|
|
stack_info_t* stack = (stack_info_t*)item;
|
|
if (stack->stack_path){
|
|
rvprof_free(stack->stack_path, strlen(stack->stack_path)+1);
|
|
stack->stack_path = NULL;
|
|
}
|
|
}
|
|
|
|
// acutal dynamic array implementations:
|
|
IMPLEMENT_DYNAMIC_ARRAY(region_t, region, INITIAL_REGIONS, cleanup_region_entry)
|
|
IMPLEMENT_DYNAMIC_ARRAY(symbol_entry_t, symbol, INITIAL_SYMBOLS, cleanup_symbol_entry)
|
|
IMPLEMENT_DYNAMIC_ARRAY(function_stats_t, function_stats, INITIAL_FUNCTIONS, cleanup_function_stats)
|
|
IMPLEMENT_DYNAMIC_ARRAY(stack_info_t, stack_info, INITIAL_STACKS, cleanup_stack_info)
|
|
|
|
|