From 8b479382384f94b90831402049c624159f2ef189 Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Thu, 27 Feb 2025 19:41:21 -0500 Subject: [PATCH] perf: Make promise stack trace collection opt-in. --- src/mem.c | 4 +--- src/task.c | 57 ++++++++++++++++++++++++++------------------------- src/util.js.c | 11 ++++++++++ src/util.js.h | 9 ++++++++ 4 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/mem.c b/src/mem.c index 456e8299..d77c0490 100644 --- a/src/mem.c +++ b/src/mem.c @@ -22,8 +22,6 @@ static int64_t s_tls_malloc_size; static int64_t s_js_malloc_size; 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; @@ -156,7 +154,7 @@ static void _tf_mem_summarize(void* ptr, size_t size, int frames_count, void* co { summary_t* summary = user_data; tf_mem_allocation_t allocation = { - .stack_hash = fnv32a(frames, sizeof(void*) * frames_count, 0), + .stack_hash = tf_util_fnv32a(frames, sizeof(void*) * frames_count, 0), .count = 1, .size = size, .frames_count = frames_count, diff --git a/src/task.c b/src/task.c index 04805032..1de0f192 100644 --- a/src/task.c +++ b/src/task.c @@ -164,6 +164,7 @@ typedef struct _tf_task_t promise_stack_t* _promise_stacks; int _promise_stack_count; + bool _promise_stack_debug; timeout_t* timeouts; @@ -1252,10 +1253,13 @@ static void _add_promise_stack(tf_task_t* task, uint32_t hash, const char* stack static void _remove_promise_stack(tf_task_t* task, uint32_t hash) { - promise_stack_t* found = bsearch(&hash, task->_promise_stacks, task->_promise_stack_count, sizeof(promise_stack_t), _promise_stack_compare); - if (found) + if (task->_promise_stack_debug) { - found->count--; + promise_stack_t* found = bsearch(&hash, task->_promise_stacks, task->_promise_stack_count, sizeof(promise_stack_t), _promise_stack_compare); + if (found) + { + found->count--; + } } } @@ -1271,33 +1275,26 @@ static void _tf_task_free_promise(tf_task_t* task, promiseid_t id) } } -uint32_t fnv32a(const void* buffer, int length, uint32_t start) -{ - uint32_t result = 0x811c9dc5; - for (int i = 0; i < length; i++) - { - result ^= ((const uint8_t*)buffer)[i]; - result += (result << 1) + (result << 4) + (result << 7) + (result << 8) + (result << 24); - } - return result; -} - JSValue tf_task_allocate_promise(tf_task_t* task, promiseid_t* out_promise) { - JSValue error = JS_ThrowInternalError(task->_context, "promise callstack"); - JSValue exception = JS_GetException(task->_context); - JSValue stack_value = JS_GetPropertyStr(task->_context, exception, "stack"); - size_t length = 0; - const char* stack = JS_ToCStringLen(task->_context, &length, stack_value); - uint32_t stack_hash = fnv32a((const void*)stack, (int)length, 0); - void* buffer[32]; - int count = tf_util_backtrace(buffer, sizeof(buffer) / sizeof(*buffer)); - stack_hash = fnv32a((const void*)buffer, sizeof(void*) * count, stack_hash); - _add_promise_stack(task, stack_hash, stack, buffer, count); - JS_FreeCString(task->_context, stack); - JS_FreeValue(task->_context, stack_value); - JS_FreeValue(task->_context, exception); - JS_FreeValue(task->_context, error); + uint32_t stack_hash = 0; + if (task->_promise_stack_debug) + { + JSValue error = JS_ThrowInternalError(task->_context, "promise callstack"); + JSValue exception = JS_GetException(task->_context); + JSValue stack_value = JS_GetPropertyStr(task->_context, exception, "stack"); + size_t length = 0; + const char* stack = JS_ToCStringLen(task->_context, &length, stack_value); + stack_hash = tf_util_fnv32a((const void*)stack, (int)length, 0); + void* buffer[32]; + int count = tf_util_backtrace(buffer, sizeof(buffer) / sizeof(*buffer)); + stack_hash = tf_util_fnv32a((const void*)buffer, sizeof(void*) * count, stack_hash); + _add_promise_stack(task, stack_hash, stack, buffer, count); + JS_FreeCString(task->_context, stack); + JS_FreeValue(task->_context, stack_value); + JS_FreeValue(task->_context, exception); + JS_FreeValue(task->_context, error); + } promiseid_t promiseId; do @@ -1592,6 +1589,10 @@ tf_task_t* tf_task_create() *task = (tf_task_t) { 0 }; ++_count; + char buffer[8] = { 0 }; + size_t buffer_size = sizeof(buffer); + task->_promise_stack_debug = uv_os_getenv("TF_PROMISE_DEBUG", buffer, &buffer_size) == 0 && strcmp(buffer, "1") == 0; + JSMallocFunctions funcs = { 0 }; tf_get_js_malloc_functions(&funcs); task->_runtime = JS_NewRuntime2(&funcs, NULL); diff --git a/src/util.js.c b/src/util.js.c index d14a1d54..bbc07e7d 100644 --- a/src/util.js.c +++ b/src/util.js.c @@ -683,3 +683,14 @@ bool tf_util_is_mobile() { return TF_IS_MOBILE != 0; } + +uint32_t tf_util_fnv32a(const void* buffer, int length, uint32_t start) +{ + uint32_t result = 0x811c9dc5; + for (int i = 0; i < length; i++) + { + result ^= ((const uint8_t*)buffer)[i]; + result += (result << 1) + (result << 4) + (result << 7) + (result << 8) + (result << 24); + } + return result; +} diff --git a/src/util.js.h b/src/util.js.h index 70b60d0b..16e77acd 100644 --- a/src/util.js.h +++ b/src/util.js.h @@ -224,4 +224,13 @@ void tf_util_document_settings(const char* line_prefix); */ bool tf_util_is_mobile(); +/** +** Compute a 32-bit hash of a buffer. +** @param buffer The data. +** @param length The size of the buffer in bytes. +** @param start The hash seed. +** @return The computed hash. +*/ +uint32_t tf_util_fnv32a(const void* buffer, int length, uint32_t start); + /** @} */