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
This commit is contained in:
parent
4bea8bb6ba
commit
1f67343d75
@ -137,7 +137,7 @@ function showFiles() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function trace() {
|
function trace() {
|
||||||
window.open(`/speedscope/#profileURL=${encodeURIComponent('/trace')}&title=Tilde%20Friends`);
|
window.open(`/speedscope/#profileURL=${encodeURIComponent('/trace')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stats() {
|
function stats() {
|
||||||
|
@ -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);
|
sqlite3_open_v2(ssb->db_path, &db, SQLITE_OPEN_READONLY, NULL);
|
||||||
tf_ssb_db_init_reader(db);
|
tf_ssb_db_init_reader(db);
|
||||||
|
tf_trace_sqlite(ssb->trace, db);
|
||||||
}
|
}
|
||||||
uv_mutex_unlock(&ssb->db_readers_lock);
|
uv_mutex_unlock(&ssb->db_readers_lock);
|
||||||
return db;
|
return db;
|
||||||
|
167
src/trace.c
167
src/trace.c
@ -1,3 +1,7 @@
|
|||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <pthread.h>
|
||||||
|
#undef _GNU_SOURCE
|
||||||
|
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
@ -9,7 +13,9 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
|
#include <uv.h>
|
||||||
|
|
||||||
#if !defined(_countof)
|
#if !defined(_countof)
|
||||||
#define _countof(a) ((int)(sizeof((a)) / sizeof(*(a))))
|
#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* next;
|
||||||
} tf_trace_stack_t;
|
} 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
|
typedef struct _tf_trace_t
|
||||||
{
|
{
|
||||||
char buffer[k_buffer_size];
|
char buffer[k_buffer_size];
|
||||||
char process_name[256];
|
char process_name[256];
|
||||||
int write_offset;
|
int write_offset;
|
||||||
|
|
||||||
|
uv_mutex_t mutex;
|
||||||
tf_trace_write_callback_t* callback;
|
tf_trace_write_callback_t* callback;
|
||||||
void* user_data;
|
void* user_data;
|
||||||
|
|
||||||
tf_trace_stack_t* stack;
|
uv_rwlock_t threads_lock;
|
||||||
|
tf_trace_thread_t** threads;
|
||||||
|
int threads_count;
|
||||||
} tf_trace_t;
|
} tf_trace_t;
|
||||||
|
|
||||||
static void _trace_append(tf_trace_t* trace, const char* buffer, size_t size, void* user_data)
|
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)
|
if (trace->write_offset + size + 2 >= k_buffer_size)
|
||||||
{
|
{
|
||||||
trace->buffer[trace->write_offset] = '\0';
|
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->write_offset += size;
|
||||||
trace->buffer[trace->write_offset++] = '\n';
|
trace->buffer[trace->write_offset++] = '\n';
|
||||||
}
|
}
|
||||||
|
uv_mutex_unlock(&trace->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
tf_trace_t* tf_trace_create()
|
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));
|
tf_trace_t* trace = tf_malloc(sizeof(tf_trace_t));
|
||||||
memset(trace, 0, sizeof(*trace));
|
memset(trace, 0, sizeof(*trace));
|
||||||
trace->callback = _trace_append;
|
trace->callback = _trace_append;
|
||||||
|
uv_mutex_init(&trace->mutex);
|
||||||
|
uv_rwlock_init(&trace->threads_lock);
|
||||||
return trace;
|
return trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_trace_destroy(tf_trace_t* 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;
|
tf_trace_thread_t* thread = trace->threads[i];
|
||||||
trace->stack = stack->next;
|
while (thread->stack)
|
||||||
|
{
|
||||||
|
tf_trace_stack_t* stack = thread->stack;
|
||||||
|
thread->stack = stack->next;
|
||||||
tf_free(stack);
|
tf_free(stack);
|
||||||
}
|
}
|
||||||
|
tf_free(thread);
|
||||||
|
}
|
||||||
|
tf_free(trace->threads);
|
||||||
|
uv_rwlock_destroy(&trace->threads_lock);
|
||||||
|
uv_mutex_destroy(&trace->mutex);
|
||||||
tf_free(trace);
|
tf_free(trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,6 +180,88 @@ static int _tf_trace_escape_name(char* out, size_t out_size, const char* name)
|
|||||||
return p;
|
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)
|
void tf_trace_begin(tf_trace_t* trace, const char* name)
|
||||||
{
|
{
|
||||||
if (!trace)
|
if (!trace)
|
||||||
@ -159,22 +269,11 @@ void tf_trace_begin(tf_trace_t* trace, const char* name)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!trace->stack || trace->stack->count + 1 > _countof(trace->stack->names))
|
pthread_t self = pthread_self();
|
||||||
{
|
_tf_push_stack(trace, self, name);
|
||||||
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;
|
|
||||||
|
|
||||||
char line[1024];
|
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 += _tf_trace_escape_name(line + p, sizeof(line) - p, name);
|
||||||
p += snprintf(line + p, sizeof(line) - p, "\"},");
|
p += snprintf(line + p, sizeof(line) - p, "\"},");
|
||||||
trace->callback(trace, line, p, trace->user_data);
|
trace->callback(trace, line, p, trace->user_data);
|
||||||
@ -187,24 +286,15 @@ void tf_trace_end(tf_trace_t* trace)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tf_trace_stack_t* stack = trace->stack;
|
pthread_t self = pthread_self();
|
||||||
while (stack && stack->count == 0)
|
const char* name = _tf_pop_stack(trace, self);
|
||||||
{
|
|
||||||
stack = stack->next;
|
|
||||||
}
|
|
||||||
const char* name = NULL;
|
|
||||||
if (stack && stack->count > 0)
|
|
||||||
{
|
|
||||||
name = stack->names[stack->count - 1];
|
|
||||||
stack->count--;
|
|
||||||
}
|
|
||||||
if (!name)
|
if (!name)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char line[1024];
|
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 += _tf_trace_escape_name(line + p, sizeof(line) - p, name);
|
||||||
p += snprintf(line + p, sizeof(line) - p, "\"},");
|
p += snprintf(line + p, sizeof(line) - p, "\"},");
|
||||||
trace->callback(trace, line, p, trace->user_data);
|
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;
|
static const int k_extra_size = 1024;
|
||||||
char* buffer = tf_malloc(k_buffer_size + k_extra_size);
|
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');
|
const char* newline = strchr(trace->buffer + trace->write_offset, '\n');
|
||||||
int begin = newline ? newline - trace->buffer : 0;
|
int begin = newline ? newline - trace->buffer : 0;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
@ -226,10 +317,21 @@ char* tf_trace_export(tf_trace_t* trace)
|
|||||||
if (*trace->process_name)
|
if (*trace->process_name)
|
||||||
{
|
{
|
||||||
size += snprintf(buffer + size, k_buffer_size - size,
|
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(),
|
getpid(),
|
||||||
trace->process_name);
|
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)
|
if (begin)
|
||||||
{
|
{
|
||||||
size_t this_size = strlen(trace->buffer + 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);
|
memcpy(buffer + size, trace->buffer, trace->write_offset);
|
||||||
size += trace->write_offset;
|
size += trace->write_offset;
|
||||||
|
uv_mutex_unlock(&trace->mutex);
|
||||||
if (size > 2 && buffer[size - 1] == '\n' && buffer[size - 2] == ',')
|
if (size > 2 && buffer[size - 1] == '\n' && buffer[size - 2] == ',')
|
||||||
{
|
{
|
||||||
buffer[size - 2] = '\n';
|
buffer[size - 2] = '\n';
|
||||||
size--;
|
size--;
|
||||||
}
|
}
|
||||||
size += snprintf(buffer + size, k_buffer_size - size, "]}\n");
|
size += snprintf(buffer + size, k_buffer_size - size, "]}\n");
|
||||||
buffer[size] = '\0';
|
|
||||||
assert(size < (size_t)k_buffer_size + k_extra_size);
|
assert(size < (size_t)k_buffer_size + k_extra_size);
|
||||||
|
buffer[size] = '\0';
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user