diff --git a/core/core.js b/core/core.js index 0c70bf00..88ad4d36 100644 --- a/core/core.js +++ b/core/core.js @@ -988,16 +988,12 @@ loadSettings().then(function() { return staticFileHandler(request, response, null, request.uri); } else if (match = /^(.*)(\/(?:save|delete)?)$/.exec(request.uri)) { return blobHandler(request, response, match[1], match[2]); - } else if (match = /^\/trace$/.exec(request.uri)) { - return stringResponse(response, trace()); } else if (match = /^\/disconnections$/.exec(request.uri)) { return stringResponse(response, JSON.stringify(disconnectionsDebug(), null, 2)); } else if (match = /^\/debug$/.exec(request.uri)) { return stringResponse(response, JSON.stringify(getDebug(), null, 2)); } else if (match = /^\/hitches$/.exec(request.uri)) { return stringResponse(response, JSON.stringify(getHitches(), null, 2)); - } else if (match = /^\/mem$/.exec(request.uri)) { - return stringResponse(response, JSON.stringify(getAllocations(), null, 2)); } else if ((match = /^\/.well-known\/(.*)/.exec(request.uri)) && request.uri.indexOf("..") == -1) { return wellKnownHandler(request, response, match[1]); } else { diff --git a/src/httpd.js.c b/src/httpd.js.c index a765c111..9bf7dc6a 100644 --- a/src/httpd.js.c +++ b/src/httpd.js.c @@ -5,6 +5,7 @@ #include "mem.h" #include "task.h" #include "tlscontext.js.h" +#include "trace.h" #include "util.js.h" #include "picohttpparser.h" @@ -18,6 +19,8 @@ #include #endif +#define tf_countof(a) ((int)(sizeof((a)) / sizeof(*(a)))) + static JSClassID _httpd_class_id; static JSClassID _httpd_request_class_id; @@ -365,6 +368,65 @@ void _httpd_request_finalizer(JSRuntime* runtime, JSValue value) tf_http_request_release(request); } +static void _httpd_endpoint_trace(tf_http_request_t* request) +{ + if (_httpd_redirect(request)) + { + return; + } + + tf_task_t* task = request->user_data; + tf_trace_t* trace = tf_task_get_trace(task); + tf_trace_begin(trace, __func__); + char* json = tf_trace_export(trace); + const char* headers[] = + { + "Content-Type", "application/json; charset=utf-8", + "Access-Control-Allow-Origin", "*", + }; + tf_http_respond(request, 200, headers, tf_countof(headers) / 2, json, json ? strlen(json) : 0); + tf_free(json); + tf_trace_end(trace); +} + +static void _httpd_endpoint_mem(tf_http_request_t* request) +{ + if (_httpd_redirect(request)) + { + return; + } + + tf_task_t* task = request->user_data; + tf_trace_t* trace = tf_task_get_trace(task); + tf_trace_begin(trace, __func__); + + char* response = NULL; + size_t length = 0; + + int count = 0; + tf_mem_allocation_t* alloc = tf_mem_summarize_allocations(&count); + for (int i = 0; i < count; i++) + { + const char* stack = tf_util_backtrace_to_string(alloc[i].frames, alloc[i].frames_count); + int line = snprintf(NULL, 0, "%zd bytes in %d allocations\n%s\n\n", alloc[i].size, alloc[i].count, stack); + response = tf_realloc(response, length + line); + snprintf(response + length, line, "%zd bytes in %d allocations\n%s\n\n", alloc[i].size, alloc[i].count, stack); + length += line - 1; + tf_free((void*)stack); + } + tf_free(alloc); + + const char* headers[] = + { + "Content-Type", "text/plain; charset=utf-8", + "Access-Control-Allow-Origin", "*", + }; + tf_http_respond(request, 200, headers, tf_countof(headers) / 2, response, length); + tf_free(response); + + tf_trace_end(trace); +} + void tf_httpd_register(JSContext* context) { JS_NewClassID(&_httpd_class_id); @@ -395,6 +457,9 @@ void tf_httpd_register(JSContext* context) tf_http_t* http = tf_http_create(loop); JS_SetOpaque(httpd, http); + tf_http_add_handler(http, "/trace", _httpd_endpoint_trace, task); + tf_http_add_handler(http, "/mem", _httpd_endpoint_mem, task); + JS_SetPropertyStr(context, httpd, "handlers", JS_NewObject(context)); JS_SetPropertyStr(context, httpd, "all", JS_NewCFunction(context, _httpd_all, "all", 2)); JS_SetPropertyStr(context, httpd, "registerSocketHandler", JS_NewCFunction(context, _httpd_register_socket_handler, "register_socket_handler", 2)); diff --git a/src/mem.c b/src/mem.c index 10439826..5ca3ad6c 100644 --- a/src/mem.c +++ b/src/mem.c @@ -199,7 +199,10 @@ tf_mem_allocation_t* tf_mem_summarize_allocations(int* out_count) { summary_t summary = { 0 }; tf_mem_walk_allocations(_tf_mem_summarize, &summary); - qsort(summary.allocations, summary.count, sizeof(tf_mem_allocation_t), _tf_mem_size_compare); + if (summary.count) + { + qsort(summary.allocations, summary.count, sizeof(tf_mem_allocation_t), _tf_mem_size_compare); + } *out_count = summary.count; tf_mem_allocation_t* result = tf_malloc(sizeof(tf_mem_allocation_t) * summary.count); if (result) diff --git a/src/task.c b/src/task.c index 4081793e..0c1e531c 100644 --- a/src/task.c +++ b/src/task.c @@ -181,7 +181,6 @@ static JSValue _tf_task_version(JSContext* context, JSValueConst this_val, int a static JSValue _tf_task_platform(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _tf_task_get_parent(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _tf_task_exit(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); -static JSValue _tf_task_trace(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _tf_task_getStats(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); static JSValue _tf_task_getFile(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv); @@ -781,22 +780,6 @@ static void _tf_task_release_export(tf_taskstub_t* stub, exportid_t exportId) } } -static JSValue _tf_task_trace(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) -{ - tf_task_t* task = JS_GetContextOpaque(context); - if (!task->_trace) - { - return JS_UNDEFINED; - } - - tf_trace_begin(task->_trace, __func__); - char* trace = tf_trace_export(task->_trace); - JSValue result = JS_NewString(context, trace); - tf_free(trace); - tf_trace_end(task->_trace); - return result; -} - static JSValue _tf_task_getStats(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { tf_task_t* task = JS_GetContextOpaque(context); @@ -938,32 +921,6 @@ static JSValue _tf_task_getHitches(JSContext* context, JSValueConst this_val, in return result; } -static JSValue _tf_task_getAllocations(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) -{ - tf_task_t* task = JS_GetContextOpaque(context); - tf_trace_begin(task->_trace, __func__); - JSValue result = JS_NewObject(context); - - int count = 0; - tf_mem_allocation_t* allocation_info = tf_mem_summarize_allocations(&count); - - JSValue allocations = JS_NewArray(context); - JS_SetPropertyStr(context, result, "allocations", allocations); - for (int i = 0; i < count; i++) - { - JSValue allocation = JS_NewObject(context); - 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 ? stack : "")); - tf_free((void*)stack); - JS_SetPropertyUint32(context, allocations, i, allocation); - } - tf_free(allocation_info); - tf_trace_end(task->_trace); - return result; -} - static JSValue _tf_task_disconnectionsDebug(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { tf_task_t* task = JS_GetContextOpaque(context); @@ -1746,11 +1703,10 @@ void tf_task_activate(tf_task_t* task) tf_ssb_server_open(task->_ssb, task->_ssb_port); } - JS_SetPropertyStr(context, global, "trace", JS_NewCFunction(context, _tf_task_trace, "trace", 1)); JS_SetPropertyStr(context, global, "getStats", JS_NewCFunction(context, _tf_task_getStats, "getStats", 0)); + JS_SetPropertyStr(context, global, "getDebug", JS_NewCFunction(context, _tf_task_getDebug, "getDebug", 0)); JS_SetPropertyStr(context, global, "getHitches", JS_NewCFunction(context, _tf_task_getHitches, "getHitches", 0)); - JS_SetPropertyStr(context, global, "getAllocations", JS_NewCFunction(context, _tf_task_getAllocations, "getAllocations", 0)); JS_SetPropertyStr(context, global, "disconnectionsDebug", JS_NewCFunction(context, _tf_task_disconnectionsDebug, "disconnectionsDebug", 0)); } else