Make function call tracing lockless

This commit is contained in:
Justine Tunney 2022-07-11 08:04:58 -07:00
parent 9877c04fac
commit 694a0da990
2 changed files with 37 additions and 50 deletions

View file

@ -20,14 +20,14 @@
#include "libc/fmt/itoa.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/lockcmpxchg.h"
#include "libc/intrin/nopl.h"
#include "libc/intrin/pthread.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/gettls.h"
#include "libc/nexgen32e/stackframe.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/thread/thread.h"
#define MAX_NESTING 512
@ -41,25 +41,7 @@
void ftrace_hook(void);
static struct Ftrace {
int skew;
int stackdigs;
int64_t lastaddr;
pthread_mutex_t lock;
volatile bool noreentry;
} g_ftrace;
static void __ftrace_lock(void) {
if (__threaded) {
pthread_mutex_lock(&g_ftrace.lock);
}
}
static void __ftrace_unlock(void) {
if (__threaded) {
pthread_mutex_unlock(&g_ftrace.lock);
}
}
static int g_stackdigs;
static privileged inline int GetNestingLevelImpl(struct StackFrame *frame) {
int nesting = -2;
@ -70,11 +52,12 @@ static privileged inline int GetNestingLevelImpl(struct StackFrame *frame) {
return MAX(0, nesting);
}
static privileged inline int GetNestingLevel(struct StackFrame *frame) {
static privileged inline int GetNestingLevel(struct FtraceTls *ft,
struct StackFrame *sf) {
int nesting;
nesting = GetNestingLevelImpl(frame);
if (nesting < g_ftrace.skew) g_ftrace.skew = nesting;
nesting -= g_ftrace.skew;
nesting = GetNestingLevelImpl(sf);
if (nesting < ft->skew) ft->skew = nesting;
nesting -= ft->skew;
return MIN(MAX_NESTING, nesting);
}
@ -87,31 +70,30 @@ static privileged inline int GetNestingLevel(struct StackFrame *frame) {
*/
privileged void ftracer(void) {
long stackuse;
struct StackFrame *frame;
__ftrace_lock();
if (_cmpxchg(&g_ftrace.noreentry, false, true)) {
frame = __builtin_frame_address(0);
frame = frame->next;
if (frame->addr != g_ftrace.lastaddr) {
stackuse = GetStackAddr() + GetStackSize() - (intptr_t)frame;
kprintf("%rFUN %6P %'13T %'*ld %*s%t\n", g_ftrace.stackdigs, stackuse,
GetNestingLevel(frame) * 2, "", frame->addr);
g_ftrace.lastaddr = frame->addr;
struct FtraceTls *ft;
struct StackFrame *sf;
ft = (struct FtraceTls *)(__get_tls_inline() + 0x08);
if (_cmpxchg(&ft->once, false, true)) {
ft->lastaddr = -1;
ft->skew = GetNestingLevelImpl(__builtin_frame_address(0));
}
g_ftrace.noreentry = false;
if (_cmpxchg(&ft->noreentry, false, true)) {
sf = __builtin_frame_address(0);
sf = sf->next;
if (sf->addr != ft->lastaddr) {
stackuse = GetStackAddr() + GetStackSize() - (intptr_t)sf;
kprintf("%rFUN %6P %'13T %'*ld %*s%t\n", g_stackdigs, stackuse,
GetNestingLevel(ft, sf) * 2, "", sf->addr);
ft->lastaddr = sf->addr;
}
ft->noreentry = false;
}
__ftrace_unlock();
}
textstartup int ftrace_install(void) {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&g_ftrace.lock, &attr);
if (GetSymbolTable()) {
g_ftrace.lastaddr = -1;
g_ftrace.stackdigs = LengthInt64Thousands(GetStackSize());
g_ftrace.skew = GetNestingLevelImpl(__builtin_frame_address(0));
__enable_tls();
g_stackdigs = LengthInt64Thousands(GetStackSize());
return __hook(ftrace_hook, GetSymbolTable());
} else {
kprintf("error: --ftrace failed to open symbol table\n");

View file

@ -17,12 +17,17 @@ enum cthread_state {
cthread_detached = 4,
};
struct FtraceTls { /* 16 */
bool once; /* 0 */
bool noreentry; /* 1 */
int skew; /* 4 */
int64_t lastaddr; /* 8 */
};
struct cthread_descriptor_t {
struct cthread_descriptor_t *self; /* 0x00 */
void *(*func)(void *); /* 0x08 */
int32_t __pad0; /* 0x10 */
int32_t state; /* 0x14 */
void *arg; /* 0x18 */
struct FtraceTls ftrace; /* 0x08 */
int64_t __pad0; /* 0x10 */
int64_t __pad1; /* 0x20 */
int64_t __pad2; /* 0x28 */
struct cthread_descriptor_t *self2; /* 0x30 */