From 1f67343d75d5116773f0582adf944097a9dfd6e9 Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Sat, 18 Feb 2023 00:51:22 +0000 Subject: [PATCH] Make traces work with multiple threads, I think. git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4184 ed5197a5-7fde-0310-b194-c3ffbd925b24 --- core/client.js | 2 +- src/ssb.c | 1 + src/trace.c | 169 +++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 138 insertions(+), 34 deletions(-) diff --git a/core/client.js b/core/client.js index a62b6f35..fa3d2845 100644 --- a/core/client.js +++ b/core/client.js @@ -137,7 +137,7 @@ function showFiles() { } function trace() { - window.open(`/speedscope/#profileURL=${encodeURIComponent('/trace')}&title=Tilde%20Friends`); + window.open(`/speedscope/#profileURL=${encodeURIComponent('/trace')}`); } function stats() { diff --git a/src/ssb.c b/src/ssb.c index 859818a6..eea00c48 100644 --- a/src/ssb.c +++ b/src/ssb.c @@ -2149,6 +2149,7 @@ sqlite3* tf_ssb_acquire_db_reader(tf_ssb_t* ssb) { sqlite3_open_v2(ssb->db_path, &db, SQLITE_OPEN_READONLY, NULL); tf_ssb_db_init_reader(db); + tf_trace_sqlite(ssb->trace, db); } uv_mutex_unlock(&ssb->db_readers_lock); return db; diff --git a/src/trace.c b/src/trace.c index 34bd83f0..3ccb835f 100644 --- a/src/trace.c +++ b/src/trace.c @@ -1,3 +1,7 @@ +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE + #include "trace.h" #include "mem.h" @@ -9,7 +13,9 @@ #include #include +#include #include +#include #if !defined(_countof) #define _countof(a) ((int)(sizeof((a)) / sizeof(*(a)))) @@ -29,20 +35,31 @@ typedef struct _tf_trace_stack_t tf_trace_stack_t* next; } tf_trace_stack_t; +typedef struct _tf_trace_thread_t +{ + pthread_t id; + tf_trace_stack_t* stack; + char name[64]; +} tf_trace_thread_t; + typedef struct _tf_trace_t { char buffer[k_buffer_size]; char process_name[256]; int write_offset; + uv_mutex_t mutex; tf_trace_write_callback_t* callback; void* user_data; - tf_trace_stack_t* stack; + uv_rwlock_t threads_lock; + tf_trace_thread_t** threads; + int threads_count; } tf_trace_t; static void _trace_append(tf_trace_t* trace, const char* buffer, size_t size, void* user_data) { + uv_mutex_lock(&trace->mutex); if (trace->write_offset + size + 2 >= k_buffer_size) { trace->buffer[trace->write_offset] = '\0'; @@ -55,6 +72,7 @@ static void _trace_append(tf_trace_t* trace, const char* buffer, size_t size, vo trace->write_offset += size; trace->buffer[trace->write_offset++] = '\n'; } + uv_mutex_unlock(&trace->mutex); } tf_trace_t* tf_trace_create() @@ -62,17 +80,27 @@ tf_trace_t* tf_trace_create() tf_trace_t* trace = tf_malloc(sizeof(tf_trace_t)); memset(trace, 0, sizeof(*trace)); trace->callback = _trace_append; + uv_mutex_init(&trace->mutex); + uv_rwlock_init(&trace->threads_lock); return trace; } void tf_trace_destroy(tf_trace_t* trace) { - while (trace->stack) + for (int i = 0; i < trace->threads_count; i++) { - tf_trace_stack_t* stack = trace->stack; - trace->stack = stack->next; - tf_free(stack); + tf_trace_thread_t* thread = trace->threads[i]; + while (thread->stack) + { + tf_trace_stack_t* stack = thread->stack; + thread->stack = stack->next; + tf_free(stack); + } + tf_free(thread); } + tf_free(trace->threads); + uv_rwlock_destroy(&trace->threads_lock); + uv_mutex_destroy(&trace->mutex); tf_free(trace); } @@ -152,6 +180,88 @@ static int _tf_trace_escape_name(char* out, size_t out_size, const char* name) return p; } +static tf_trace_thread_t* _tf_trace_get_thread(tf_trace_t* trace, pthread_t self) +{ + tf_trace_thread_t* found = NULL; + uv_rwlock_rdlock(&trace->threads_lock); + for (int i = 0; i < trace->threads_count; i++) + { + if (trace->threads[i]->id == self) + { + found = trace->threads[i]; + break; + } + } + uv_rwlock_rdunlock(&trace->threads_lock); + + if (!found) + { + uv_rwlock_wrlock(&trace->threads_lock); + /* Maybe it was added while we changed from rd to rw. */ + for (int i = 0; i < trace->threads_count; i++) + { + if (trace->threads[i]->id == self) + { + found = trace->threads[i]; + break; + } + } + + if (!found) + { + found = tf_malloc(sizeof(tf_trace_thread_t)); + *found = (tf_trace_thread_t) + { + .id = self, + }; +#if defined(__linux__) + pthread_getname_np(self, found->name, sizeof(found->name)); +#endif + trace->threads = tf_resize_vec(trace->threads, sizeof(tf_trace_thread_t*) * (trace->threads_count + 1)); + trace->threads[trace->threads_count++] = found; + } + uv_rwlock_wrunlock(&trace->threads_lock); + } + + return found; +} + +static void _tf_push_stack(tf_trace_t* trace, pthread_t self, const char* name) +{ + tf_trace_thread_t* thread = _tf_trace_get_thread(trace, self); + if (!thread->stack || thread->stack->count + 1 > (int)_countof(thread->stack->names)) + { + tf_trace_stack_t* stack = tf_malloc(sizeof(tf_trace_stack_t)); + memset(stack, 0, sizeof(*stack)); + stack->next = thread->stack; + thread->stack = stack; + } + tf_trace_stack_t* stack = thread->stack; + while (stack->count == 0 && stack->next && stack->next->count + 1 <= (int)_countof(thread->stack->names)) + { + stack = stack->next; + } + stack->names[stack->count++] = name; + +} + +static const char* _tf_pop_stack(tf_trace_t* trace, pthread_t self) +{ + tf_trace_thread_t* thread = _tf_trace_get_thread(trace, self); + tf_trace_stack_t* stack = thread->stack; + while (stack && stack->count == 0) + { + stack = stack->next; + } + const char* name = NULL; + if (stack && stack->count > 0) + { + name = stack->names[stack->count - 1]; + stack->count--; + } + return name; +} + void tf_trace_begin(tf_trace_t* trace, const char* name) { if (!trace) @@ -159,22 +269,11 @@ void tf_trace_begin(tf_trace_t* trace, const char* name) return; } - if (!trace->stack || trace->stack->count + 1 > _countof(trace->stack->names)) - { - tf_trace_stack_t* stack = tf_malloc(sizeof(tf_trace_stack_t)); - memset(stack, 0, sizeof(*stack)); - stack->next = trace->stack; - trace->stack = stack; - } - tf_trace_stack_t* stack = trace->stack; - while (stack->count == 0 && stack->next && stack->next->count + 1 <= _countof(trace->stack->names)) - { - stack = stack->next; - } - stack->names[stack->count++] = name; + pthread_t self = pthread_self(); + _tf_push_stack(trace, self, name); char line[1024]; - int p = snprintf(line, sizeof(line), "{\"ph\": \"B\", \"pid\": %d, \"tid\": %" PRId64 ", \"ts\": %" PRId64 ", \"name\": \"", getpid(), (int64_t)pthread_self(), _trace_ts()); + int p = snprintf(line, sizeof(line), "{\"ph\": \"B\", \"pid\": %d, \"tid\": \"0x%" PRIx64 "\", \"ts\": %" PRId64 ", \"name\": \"", getpid(), (int64_t)self, _trace_ts()); p += _tf_trace_escape_name(line + p, sizeof(line) - p, name); p += snprintf(line + p, sizeof(line) - p, "\"},"); trace->callback(trace, line, p, trace->user_data); @@ -187,24 +286,15 @@ void tf_trace_end(tf_trace_t* trace) return; } - tf_trace_stack_t* stack = trace->stack; - while (stack && stack->count == 0) - { - stack = stack->next; - } - const char* name = NULL; - if (stack && stack->count > 0) - { - name = stack->names[stack->count - 1]; - stack->count--; - } + pthread_t self = pthread_self(); + const char* name = _tf_pop_stack(trace, self); if (!name) { return; } char line[1024]; - int p = snprintf(line, sizeof(line), "{\"ph\": \"E\", \"pid\": %d, \"tid\": %" PRId64 ", \"ts\": %" PRId64 ", \"name\": \"", getpid(), (int64_t)pthread_self(), _trace_ts()); + int p = snprintf(line, sizeof(line), "{\"ph\": \"E\", \"pid\": %d, \"tid\": \"0x%" PRIx64 "\", \"ts\": %" PRId64 ", \"name\": \"", getpid(), (int64_t)pthread_self(), _trace_ts()); p += _tf_trace_escape_name(line + p, sizeof(line) - p, name); p += snprintf(line + p, sizeof(line) - p, "\"},"); trace->callback(trace, line, p, trace->user_data); @@ -219,6 +309,7 @@ char* tf_trace_export(tf_trace_t* trace) static const int k_extra_size = 1024; char* buffer = tf_malloc(k_buffer_size + k_extra_size); + uv_mutex_lock(&trace->mutex); const char* newline = strchr(trace->buffer + trace->write_offset, '\n'); int begin = newline ? newline - trace->buffer : 0; size_t size = 0; @@ -226,10 +317,21 @@ char* tf_trace_export(tf_trace_t* trace) if (*trace->process_name) { size += snprintf(buffer + size, k_buffer_size - size, - "{\"name\":\"process_name\",\"ph\":\"M\",\"pid\":%d,\"args\":{\"name\":\"%s\"}},", + "{\"ph\":\"M\",\"pid\":%d,\"name\":\"process_name\",\"args\":{\"name\":\"%s\"}},\n", getpid(), trace->process_name); } + uv_rwlock_rdlock(&trace->threads_lock); + for (int i = 0; i < trace->threads_count; i++) + { + tf_trace_thread_t* thread = trace->threads[i]; + size += snprintf(buffer + size, k_buffer_size - size, + "{\"ph\":\"M\",\"pid\":%d,\"tid\":\"0x%" PRIx64 "\",\"name\":\"thread_name\",\"args\":{\"name\":\"%s\"}},\n", + getpid(), + thread->id, + thread->name); + } + uv_rwlock_rdunlock(&trace->threads_lock); if (begin) { size_t this_size = strlen(trace->buffer + begin); @@ -238,14 +340,15 @@ char* tf_trace_export(tf_trace_t* trace) } memcpy(buffer + size, trace->buffer, trace->write_offset); size += trace->write_offset; + uv_mutex_unlock(&trace->mutex); if (size > 2 && buffer[size - 1] == '\n' && buffer[size - 2] == ',') { buffer[size - 2] = '\n'; size--; } size += snprintf(buffer + size, k_buffer_size - size, "]}\n"); - buffer[size] = '\0'; assert(size < (size_t)k_buffer_size + k_extra_size); + buffer[size] = '\0'; return buffer; }