2021-01-02 13:10:00 -05:00
|
|
|
#include "trace.h"
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <malloc.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <sqlite3.h>
|
|
|
|
|
2021-10-24 11:46:30 -04:00
|
|
|
#if !defined(_countof)
|
|
|
|
#define _countof(a) ((int)(sizeof((a)) / sizeof(*(a))))
|
|
|
|
#endif
|
|
|
|
|
2021-01-02 13:10:00 -05:00
|
|
|
enum {
|
|
|
|
k_buffer_size = 4 * 1024 * 1024,
|
|
|
|
};
|
|
|
|
|
2021-10-24 11:46:30 -04:00
|
|
|
typedef struct _tf_trace_stack_t tf_trace_stack_t;
|
|
|
|
|
|
|
|
typedef struct _tf_trace_stack_t
|
|
|
|
{
|
|
|
|
const char* names[256];
|
|
|
|
int count;
|
|
|
|
tf_trace_stack_t* next;
|
|
|
|
} tf_trace_stack_t;
|
|
|
|
|
2021-01-02 13:10:00 -05:00
|
|
|
typedef struct _tf_trace_t
|
|
|
|
{
|
|
|
|
char buffer[k_buffer_size];
|
|
|
|
int write_offset;
|
2021-10-24 11:46:30 -04:00
|
|
|
|
|
|
|
tf_trace_stack_t* stack;
|
2021-01-02 13:10:00 -05:00
|
|
|
} tf_trace_t;
|
|
|
|
|
|
|
|
tf_trace_t* tf_trace_create()
|
|
|
|
{
|
|
|
|
tf_trace_t* trace = malloc(sizeof(tf_trace_t));
|
|
|
|
memset(trace, 0, sizeof(*trace));
|
|
|
|
return trace;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tf_trace_destroy(tf_trace_t* trace)
|
|
|
|
{
|
2021-10-24 11:46:30 -04:00
|
|
|
while (trace->stack)
|
|
|
|
{
|
|
|
|
tf_trace_stack_t* stack = trace->stack;
|
|
|
|
trace->stack = stack->next;
|
|
|
|
free(stack);
|
|
|
|
}
|
2021-01-02 13:10:00 -05:00
|
|
|
free(trace);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t _trace_ts()
|
|
|
|
{
|
|
|
|
int64_t result = 0;
|
|
|
|
struct timespec ts;
|
2021-10-10 17:51:38 -04:00
|
|
|
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
result = (ts.tv_sec * 1e9 + ts.tv_nsec) / 1e3;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _trace_append(tf_trace_t* trace, const char* buffer, size_t size)
|
|
|
|
{
|
2021-10-10 17:51:38 -04:00
|
|
|
if (trace->write_offset + size >= k_buffer_size)
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
trace->buffer[trace->write_offset] = '\0';
|
|
|
|
trace->write_offset = 0;
|
|
|
|
}
|
|
|
|
|
2021-10-10 17:51:38 -04:00
|
|
|
if (trace->write_offset + size < k_buffer_size)
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
memcpy(trace->buffer + trace->write_offset, buffer, size);
|
|
|
|
trace->write_offset += size;
|
|
|
|
trace->buffer[trace->write_offset++] = '\n';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void tf_trace_counter(tf_trace_t* trace, const char* name, int argc, const char** arg_names, const int64_t* arg_values)
|
|
|
|
{
|
2021-10-10 17:51:38 -04:00
|
|
|
if (!trace)
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
char line[1024];
|
|
|
|
int p = 0;
|
|
|
|
p += snprintf(line + p, sizeof(line) - p, "{\"ph\": \"C\", \"pid\": %d, \"ts\": %" PRId64 ", \"name\": \"%s\", \"args\": {", getpid(), _trace_ts(), name);
|
|
|
|
for (int i = 0; i < argc; i++)
|
|
|
|
{
|
|
|
|
p += snprintf(line + p, sizeof(line) - p, "\"%s\": %" PRId64 "%s", arg_names[i], arg_values[i], i == argc - 1 ? "}}," : ", ");
|
|
|
|
}
|
|
|
|
|
|
|
|
_trace_append(trace, line, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tf_trace_begin(tf_trace_t* trace, const char* name)
|
|
|
|
{
|
2021-10-10 17:51:38 -04:00
|
|
|
if (!trace)
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-10-24 11:46:30 -04:00
|
|
|
if (!trace->stack || trace->stack->count + 1 < _countof(trace->stack->names))
|
|
|
|
{
|
|
|
|
tf_trace_stack_t* stack = 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->count + 1 < _countof(trace->stack->names))
|
|
|
|
{
|
|
|
|
stack = stack->next;
|
|
|
|
}
|
|
|
|
stack->names[stack->count++] = name;
|
|
|
|
|
2021-01-02 13:10:00 -05:00
|
|
|
char line[1024];
|
2021-10-24 11:46:30 -04:00
|
|
|
int p = snprintf(line, sizeof(line), "{\"ph\": \"B\", \"pid\": %d, \"tid\": 0, \"ts\": %" PRId64 ", \"name\": \"", getpid(), _trace_ts());
|
2021-10-10 17:51:38 -04:00
|
|
|
for (const char* c = name; *c && p < (int)sizeof(line); c++)
|
|
|
|
{
|
|
|
|
switch (*c)
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
case '"':
|
|
|
|
case '\\':
|
|
|
|
line[p++] = '\\';
|
2021-10-10 17:51:38 -04:00
|
|
|
if (p < (int)sizeof(line))
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
line[p++] = *c;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
line[p++] = *c;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p += snprintf(line + p, sizeof(line) - p, "\"},");
|
|
|
|
_trace_append(trace, line, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tf_trace_end(tf_trace_t* trace)
|
|
|
|
{
|
2021-10-10 17:51:38 -04:00
|
|
|
if (!trace)
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-10-24 11:46:30 -04:00
|
|
|
tf_trace_stack_t* stack = trace->stack;
|
|
|
|
while (stack && stack->count == 0)
|
|
|
|
{
|
|
|
|
stack = stack->next;
|
|
|
|
}
|
|
|
|
const char* name = stack && stack->count > 0 ? stack->names[stack->count - 1] : NULL;
|
|
|
|
|
2021-01-02 13:10:00 -05:00
|
|
|
char line[1024];
|
2021-10-24 11:46:30 -04:00
|
|
|
int p = snprintf(line, sizeof(line), "{\"ph\": \"E\", \"pid\": %d, \"tid\": 0, \"ts\": %" PRId64 ", \"name\": \"", getpid(), _trace_ts());
|
|
|
|
for (const char* c = name; *c && p < (int)sizeof(line); c++)
|
|
|
|
{
|
|
|
|
switch (*c)
|
|
|
|
{
|
|
|
|
case '"':
|
|
|
|
case '\\':
|
|
|
|
line[p++] = '\\';
|
|
|
|
if (p < (int)sizeof(line))
|
|
|
|
{
|
|
|
|
line[p++] = *c;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
line[p++] = *c;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p += snprintf(line + p, sizeof(line) - p, "\"},");
|
2021-01-02 13:10:00 -05:00
|
|
|
_trace_append(trace, line, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* tf_trace_export(tf_trace_t* trace)
|
|
|
|
{
|
2021-10-10 17:51:38 -04:00
|
|
|
if (!trace)
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const int k_extra_size = 1024;
|
|
|
|
char* buffer = malloc(k_buffer_size + k_extra_size);
|
|
|
|
const char* newline = strchr(trace->buffer + trace->write_offset, '\n');
|
|
|
|
int begin = newline ? newline - trace->buffer : 0;
|
|
|
|
size_t size = 0;
|
|
|
|
size += snprintf(buffer, k_buffer_size, "{\"displayTimeUnit\": \"ns\",\n\"traceEvents\": [\n");
|
2021-10-10 17:51:38 -04:00
|
|
|
if (begin)
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
size_t this_size = strlen(trace->buffer + begin);
|
|
|
|
memcpy(buffer + size, trace->buffer + begin, this_size);
|
|
|
|
size += this_size;
|
|
|
|
}
|
|
|
|
memcpy(buffer + size, trace->buffer, trace->write_offset);
|
|
|
|
size += trace->write_offset;
|
2021-10-10 17:51:38 -04:00
|
|
|
if (size > 2 && buffer[size - 1] == '\n' && buffer[size - 2] == ',')
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
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);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int _tf_trace_sqlite_callback(unsigned int t, void* c, void* p, void* x)
|
|
|
|
{
|
|
|
|
tf_trace_t* trace = c;
|
2021-10-10 17:51:38 -04:00
|
|
|
switch (t)
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
case SQLITE_TRACE_STMT:
|
|
|
|
{
|
|
|
|
const char* statement = x;
|
2021-10-10 17:51:38 -04:00
|
|
|
if (statement[0] != '-' || statement[1] != '-')
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
tf_trace_begin(trace, statement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SQLITE_TRACE_PROFILE:
|
|
|
|
tf_trace_end(trace);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tf_trace_sqlite(tf_trace_t* trace, sqlite3* sqlite)
|
|
|
|
{
|
2021-10-10 17:51:38 -04:00
|
|
|
if (sqlite)
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
sqlite3_trace_v2(sqlite, SQLITE_TRACE_STMT | SQLITE_TRACE_PROFILE, _tf_trace_sqlite_callback, trace);
|
2021-10-10 17:51:38 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
sqlite3_trace_v2(sqlite, 0, NULL, NULL);
|
|
|
|
}
|
|
|
|
}
|