#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; isize; 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; inum_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)