diff --git a/src/mem.c b/src/mem.c index 32585105..787c0f04 100644 --- a/src/mem.c +++ b/src/mem.c @@ -13,11 +13,11 @@ #include #include +typedef struct _tf_mem_node_t tf_mem_node_t; + static uv_mutex_t s_tracking_mutex; static bool s_mem_tracking; -static void** s_mem_tracked; -static int s_mem_tracked_count; -static int s_mem_tracked_capacity; +static tf_mem_node_t* s_mem_tracked; static int64_t s_tf_malloc_size; static int64_t s_uv_malloc_size; static int64_t s_tls_malloc_size; @@ -26,6 +26,11 @@ static int64_t s_sqlite_malloc_size; extern uint32_t fnv32a(const void* buffer, int length, uint32_t start); +static size_t _tf_mem_round_up(size_t size) +{ + return (size + 7) & ~7; +} + void tf_mem_startup(bool tracking) { s_mem_tracking = tracking; @@ -35,39 +40,54 @@ void tf_mem_startup(bool tracking) void tf_mem_shutdown() { s_mem_tracking = false; - free(s_mem_tracked); s_mem_tracked = NULL; - s_mem_tracked_capacity = 0; uv_mutex_destroy(&s_tracking_mutex); } -static void _tf_mem_add_tracked_allocation(void* ptr) +typedef struct _tf_mem_node_t +{ + void* ptr; + tf_mem_node_t* next; + tf_mem_node_t* previous; + int frames_count; + void* frames[]; +} tf_mem_node_t; + +static void _tf_mem_add_tracked_allocation(tf_mem_node_t* node) { if (s_mem_tracking) { uv_mutex_lock(&s_tracking_mutex); - if (s_mem_tracked_count + 1 >= s_mem_tracked_capacity) + if (s_mem_tracked) { - s_mem_tracked_capacity = s_mem_tracked_capacity ? (s_mem_tracked_capacity * 2) : 256; - s_mem_tracked = realloc(s_mem_tracked, sizeof(void*) * s_mem_tracked_capacity); + node->next = s_mem_tracked; + node->previous = s_mem_tracked->previous; + s_mem_tracked->previous->next = node; + s_mem_tracked->previous = node; + } + else + { + s_mem_tracked = node; + node->next = node->previous = node; } - s_mem_tracked[s_mem_tracked_count++] = ptr; uv_mutex_unlock(&s_tracking_mutex); } } -static void _tf_mem_remove_tracked_allocation(void* ptr) +static void _tf_mem_remove_tracked_allocation(tf_mem_node_t* node) { if (s_mem_tracking) { uv_mutex_lock(&s_tracking_mutex); - for (int i = 0; i < s_mem_tracked_count; i++) + tf_mem_node_t* previous = node->previous; + tf_mem_node_t* next = node->next; + next->previous = previous; + previous->next = next; + node->next = NULL; + node->previous = NULL; + if (node == s_mem_tracked) { - if (s_mem_tracked[i] == ptr) - { - s_mem_tracked[i] = s_mem_tracked[--s_mem_tracked_count]; - break; - } + s_mem_tracked = next != node ? next : NULL; } uv_mutex_unlock(&s_tracking_mutex); } @@ -76,26 +96,28 @@ static void _tf_mem_remove_tracked_allocation(void* ptr) void tf_mem_walk_allocations(void (*callback)(void* ptr, size_t size, int frames_count, void* const* frames, void* user_data), void* user_data) { uv_mutex_lock(&s_tracking_mutex); - for (int i = 0; i < s_mem_tracked_count; i++) + for (tf_mem_node_t* node = s_mem_tracked ? s_mem_tracked->next : NULL; node; node = node->next) { size_t size = 0; - int frames_count = 0; void* frames[32]; - memcpy(&size, s_mem_tracked[i], sizeof(size)); + memcpy(&size, node->ptr, sizeof(size)); if (s_mem_tracking) { - memcpy(&frames_count, (void*)((intptr_t)s_mem_tracked[i] + sizeof(size_t) + size), sizeof(frames_count)); - if (frames_count) + if (node->frames_count) { - memcpy(frames, (void*)((intptr_t)s_mem_tracked[i] + sizeof(size_t) + size + sizeof(frames_count)), sizeof(void*) * frames_count); + memcpy(frames, node->frames, sizeof(void*) * node->frames_count); } } callback( - (void*)((intptr_t)s_mem_tracked[i] + sizeof(size_t)), + (void*)((intptr_t)node->ptr + sizeof(size_t)), size, - frames_count, - frames_count ? frames : NULL, + node->frames_count, + node->frames_count ? frames : NULL, user_data); + if (node == s_mem_tracked) + { + break; + } } uv_mutex_unlock(&s_tracking_mutex); } @@ -194,20 +216,25 @@ static void* _tf_alloc(int64_t* total, size_t size) if (s_mem_tracking) { count = tf_util_backtrace(buffer, sizeof(buffer) / sizeof(*buffer)); - overhead += sizeof(count) + sizeof(void*) * count; + overhead += sizeof(tf_mem_node_t) + sizeof(void*) * count; } - void* ptr = malloc(size + overhead); + size_t rounded_up_size = _tf_mem_round_up(size); + void* ptr = malloc(rounded_up_size + overhead); if (ptr) { __atomic_add_fetch(total, size, __ATOMIC_RELAXED); memcpy(ptr, &size, sizeof(size_t)); - if (count) + if (s_mem_tracking) { - memcpy((void*)((intptr_t)ptr + sizeof(size_t) + size), &count, sizeof(count)); - memcpy((void*)((intptr_t)ptr + sizeof(size_t) + size + sizeof(count)), buffer, sizeof(void*) * count); + tf_mem_node_t* node = (tf_mem_node_t*)((intptr_t)ptr + sizeof(size_t) + rounded_up_size); + memcpy(node, &(tf_mem_node_t) { .ptr = ptr, .frames_count = count }, sizeof(tf_mem_node_t)); + if (count) + { + memcpy(node->frames, buffer, sizeof(void*) * count); + } + _tf_mem_add_tracked_allocation(node); } - _tf_mem_add_tracked_allocation(ptr); return (void*)((intptr_t)ptr + sizeof(size_t)); } else @@ -229,7 +256,7 @@ static void* _tf_realloc(int64_t* total, void* ptr, size_t size) if (s_mem_tracking) { count = tf_util_backtrace(buffer, sizeof(buffer) / sizeof(*buffer)); - overhead += sizeof(count) + sizeof(void*) * count; + overhead += sizeof(tf_mem_node_t) + sizeof(void*) * count; } void* old_ptr = ptr ? (void*)((intptr_t)ptr - sizeof(size_t)) : NULL; @@ -239,29 +266,35 @@ static void* _tf_realloc(int64_t* total, void* ptr, size_t size) memcpy(&old_size, old_ptr, sizeof(size_t)); } void* new_ptr = NULL; + tf_mem_node_t* node = (void*)((intptr_t)ptr + _tf_mem_round_up(old_size)); + size_t rounded_up_size = _tf_mem_round_up(size); if (old_ptr && !size) { - _tf_mem_remove_tracked_allocation(old_ptr); + _tf_mem_remove_tracked_allocation(node); free(old_ptr); } else { if (old_ptr) { - _tf_mem_remove_tracked_allocation(old_ptr); + _tf_mem_remove_tracked_allocation(node); } - new_ptr = realloc(old_ptr, size + overhead); + new_ptr = realloc(old_ptr, rounded_up_size + overhead); } if (new_ptr) { __atomic_add_fetch(total, (int64_t)size - (int64_t)old_size, __ATOMIC_RELAXED); memcpy(new_ptr, &size, sizeof(size_t)); - if (count) + if (s_mem_tracking) { - memcpy((void*)((intptr_t)new_ptr + sizeof(size_t) + size), &count, sizeof(count)); - memcpy((void*)((intptr_t)new_ptr + sizeof(size_t) + size + sizeof(count)), buffer, sizeof(void*) * count); + tf_mem_node_t* node = (tf_mem_node_t*)((intptr_t)new_ptr + sizeof(size_t) + rounded_up_size); + memcpy(node, &(tf_mem_node_t) { .ptr = new_ptr, .frames_count = count }, sizeof(tf_mem_node_t)); + if (count) + { + memcpy(node->frames, buffer, sizeof(void*) * count); + } + _tf_mem_add_tracked_allocation(node); } - _tf_mem_add_tracked_allocation(new_ptr); return (void*)((intptr_t)new_ptr + sizeof(size_t)); } else @@ -278,8 +311,9 @@ static void _tf_free(int64_t* total, void* ptr) void* old_ptr = (void*)((intptr_t)ptr - sizeof(size_t)); size_t size = 0; memcpy(&size, old_ptr, sizeof(size_t)); + tf_mem_node_t* node = (void*)((intptr_t)ptr + _tf_mem_round_up(size)); __atomic_sub_fetch(total, size, __ATOMIC_RELAXED); - _tf_mem_remove_tracked_allocation(old_ptr); + _tf_mem_remove_tracked_allocation(node); free(old_ptr); } } @@ -296,12 +330,31 @@ static void* _tf_uv_realloc(void* ptr, size_t size) static void* _tf_uv_calloc(size_t nmemb, size_t size) { - void* ptr = calloc(1, nmemb * size + sizeof(size_t)); + size_t total_size = nmemb * size; + size_t rounded_up_size = _tf_mem_round_up(total_size); + size_t overhead = sizeof(size_t); + void* buffer[32]; + int count = 0; + if (s_mem_tracking) + { + count = tf_util_backtrace(buffer, sizeof(buffer) / sizeof(*buffer)); + overhead += sizeof(tf_mem_node_t) + sizeof(void*) * count; + } + void* ptr = calloc(1, nmemb * rounded_up_size + overhead); if (ptr) { - size_t total_size = nmemb * size; __atomic_add_fetch(&s_uv_malloc_size, total_size, __ATOMIC_RELAXED); memcpy(ptr, &total_size, sizeof(size_t)); + if (s_mem_tracking) + { + tf_mem_node_t* node = (tf_mem_node_t*)((intptr_t)ptr + sizeof(size_t) + rounded_up_size); + memcpy(node, &(tf_mem_node_t) { .ptr = ptr, .frames_count = count }, sizeof(tf_mem_node_t)); + if (count) + { + memcpy(node->frames, buffer, sizeof(void*) * count); + } + _tf_mem_add_tracked_allocation(node); + } return (void*)((intptr_t)ptr + sizeof(size_t)); } else diff --git a/src/task.c b/src/task.c index b7fac2b5..01b7d0ed 100644 --- a/src/task.c +++ b/src/task.c @@ -851,7 +851,7 @@ static JSValue _tf_task_getAllocations(JSContext* context, JSValueConst this_val JS_SetPropertyStr(context, allocation, "size", JS_NewInt64(context, allocation_info[i].size)); JS_SetPropertyStr(context, allocation, "count", JS_NewInt32(context, allocation_info[i].count)); const char* stack = tf_util_backtrace_to_string(allocation_info[i].frames, allocation_info[i].frames_count); - JS_SetPropertyStr(context, allocation, "stack", JS_NewString(context, stack)); + JS_SetPropertyStr(context, allocation, "stack", JS_NewString(context, stack ? stack : "")); tf_free((void*)stack); JS_SetPropertyUint32(context, allocations, i, allocation); }