Track memory allocations with a linked list. This is only about 3x slower than without tracking instead of 5x and growing.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4192 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
parent
a6a6fe75ec
commit
86bc46a11e
139
src/mem.c
139
src/mem.c
@ -13,11 +13,11 @@
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user