Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386/* ac-trace — Unified BPF trace loader for AC Native OS. * * Usage: * ac-trace syscall — syscall frequency/latency profiling * ac-trace frame — DRM page flip jitter detection * ac-trace alsa — ALSA xrun tracing * ac-trace input — evdev input latency histogram * ac-trace alloc — kernel memory allocation profiling * ac-trace stop — stop all active traces * ac-trace status — show active tracers * ac-trace dump — write current buffers to /mnt/trace/ * * Each subcommand loads its pre-compiled BPF bytecode (embedded at build time * via xxd -i), attaches the probes, and streams output to /mnt/trace/<name>.csv. * * Build: musl-gcc -static -O2 -o ac-trace ac-trace.c -lbpf -lelf -lz * (or link against vendored minimal libbpf) */
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <signal.h>#include <unistd.h>#include <sys/stat.h>#include <errno.h>#include <time.h>
/* BPF bytecode skeletons are included at build time. * Each is generated by: xxd -i progs/<name>.bpf.o > <name>.skel.h * For now, this file provides the CLI framework; the actual BPF loading * uses libbpf's bpf_object__open_mem() + bpf_object__load(). */
#ifdef HAS_LIBBPF#include <bpf/libbpf.h>#include <bpf/bpf.h>
/* Embedded BPF ELF bytecodes (generated by xxd -i during build) */#include "syscall_profile_bpf.skel.h"#include "frame_jitter_bpf.skel.h"#include "alsa_xrun_bpf.skel.h"#include "input_latency_bpf.skel.h"#include "alloc_profile_bpf.skel.h"#endif
#define TRACE_DIR "/mnt/trace"#define PID_FILE "/tmp/.ac-trace.pid"
static volatile int running = 1;
static void sig_handler(int sig) { (void)sig; running = 0;}
static void ensure_trace_dir(void) { mkdir(TRACE_DIR, 0755);}
static void write_pid(void) { FILE *f = fopen(PID_FILE, "w"); if (f) { fprintf(f, "%d\n", getpid()); fclose(f); }}
static void remove_pid(void) { unlink(PID_FILE);}
static int is_running(void) { FILE *f = fopen(PID_FILE, "r"); if (!f) return 0; int pid = 0; if (fscanf(f, "%d", &pid) == 1) { fclose(f); return kill(pid, 0) == 0; } fclose(f); return 0;}
static void cmd_status(void) { if (is_running()) { FILE *f = fopen(PID_FILE, "r"); int pid = 0; if (f) { fscanf(f, "%d", &pid); fclose(f); } printf("ac-trace active (pid %d)\n", pid); } else { printf("ac-trace inactive\n"); }
/* List any existing trace files */ struct stat st; const char *names[] = {"syscall", "frame", "alsa", "input", "alloc"}; for (int i = 0; i < 5; i++) { char path[128]; snprintf(path, sizeof(path), TRACE_DIR "/%s.csv", names[i]); if (stat(path, &st) == 0) { printf(" %s.csv %ldB %s", names[i], (long)st.st_size, ctime(&st.st_mtime)); } }}
static void cmd_stop(void) { FILE *f = fopen(PID_FILE, "r"); if (!f) { printf("no active trace\n"); return; } int pid = 0; if (fscanf(f, "%d", &pid) == 1 && kill(pid, 0) == 0) { kill(pid, SIGTERM); printf("stopped ac-trace (pid %d)\n", pid); } fclose(f); remove_pid();}
/* Stub implementations for when libbpf is not available. * These use ftrace/tracefs directly as a fallback. */static int cmd_syscall_ftrace(void) { printf("syscall profiling via ftrace (BPF not available)\n"); ensure_trace_dir(); write_pid();
/* Enable syscall tracing via tracefs */ FILE *f; f = fopen("/sys/kernel/tracing/current_tracer", "w"); if (!f) { perror("tracefs not mounted"); remove_pid(); return 1; } fprintf(f, "nop\n"); fclose(f);
f = fopen("/sys/kernel/tracing/events/raw_syscalls/sys_enter/enable", "w"); if (f) { fprintf(f, "1\n"); fclose(f); } f = fopen("/sys/kernel/tracing/events/raw_syscalls/sys_exit/enable", "w"); if (f) { fprintf(f, "1\n"); fclose(f); } f = fopen("/sys/kernel/tracing/tracing_on", "w"); if (f) { fprintf(f, "1\n"); fclose(f); }
printf("tracing syscalls → " TRACE_DIR "/syscall.csv (ctrl-c to stop)\n");
/* Poll trace_pipe and write CSV */ FILE *pipe = fopen("/sys/kernel/tracing/trace_pipe", "r"); FILE *out = fopen(TRACE_DIR "/syscall.csv", "w"); if (!pipe || !out) { perror("open trace_pipe/output"); remove_pid(); return 1; } fprintf(out, "timestamp,pid,syscall_nr,latency_us\n");
char line[512]; while (running && fgets(line, sizeof(line), pipe)) { /* Parse ftrace output and write simplified CSV */ fputs(line, out); fflush(out); }
/* Cleanup */ f = fopen("/sys/kernel/tracing/events/raw_syscalls/sys_enter/enable", "w"); if (f) { fprintf(f, "0\n"); fclose(f); } f = fopen("/sys/kernel/tracing/events/raw_syscalls/sys_exit/enable", "w"); if (f) { fprintf(f, "0\n"); fclose(f); }
fclose(pipe); fclose(out); remove_pid(); printf("stopped. output: " TRACE_DIR "/syscall.csv\n"); return 0;}
static int cmd_frame_ftrace(void) { printf("frame jitter tracing via ftrace\n"); ensure_trace_dir(); write_pid();
/* Enable function_graph tracer on DRM functions */ FILE *f; f = fopen("/sys/kernel/tracing/current_tracer", "w"); if (!f) { perror("tracefs"); remove_pid(); return 1; } fprintf(f, "function_graph\n"); fclose(f);
f = fopen("/sys/kernel/tracing/set_graph_function", "w"); if (f) { fprintf(f, "drm_atomic_helper_commit\n"); fclose(f); } f = fopen("/sys/kernel/tracing/tracing_on", "w"); if (f) { fprintf(f, "1\n"); fclose(f); }
printf("tracing DRM commits → " TRACE_DIR "/frame.csv (ctrl-c to stop)\n");
FILE *pipe = fopen("/sys/kernel/tracing/trace_pipe", "r"); FILE *out = fopen(TRACE_DIR "/frame.csv", "w"); if (!pipe || !out) { perror("open"); remove_pid(); return 1; } fprintf(out, "timestamp,function,duration_us\n");
char line[512]; while (running && fgets(line, sizeof(line), pipe)) { fputs(line, out); fflush(out); }
f = fopen("/sys/kernel/tracing/tracing_on", "w"); if (f) { fprintf(f, "0\n"); fclose(f); } f = fopen("/sys/kernel/tracing/current_tracer", "w"); if (f) { fprintf(f, "nop\n"); fclose(f); }
fclose(pipe); fclose(out); remove_pid(); printf("stopped. output: " TRACE_DIR "/frame.csv\n"); return 0;}
static int cmd_alsa_ftrace(void) { printf("ALSA xrun tracing via ftrace\n"); ensure_trace_dir(); write_pid();
/* Try to enable ALSA tracepoints if available */ FILE *f; f = fopen("/sys/kernel/tracing/current_tracer", "w"); if (!f) { perror("tracefs"); remove_pid(); return 1; } fprintf(f, "nop\n"); fclose(f);
f = fopen("/sys/kernel/tracing/set_ftrace_filter", "w"); if (f) { fprintf(f, "snd_pcm_xrun\n"); fclose(f); } f = fopen("/sys/kernel/tracing/current_tracer", "w"); if (f) { fprintf(f, "function\n"); fclose(f); } f = fopen("/sys/kernel/tracing/tracing_on", "w"); if (f) { fprintf(f, "1\n"); fclose(f); }
printf("tracing ALSA xruns → " TRACE_DIR "/alsa.csv (ctrl-c to stop)\n");
FILE *pipe = fopen("/sys/kernel/tracing/trace_pipe", "r"); FILE *out = fopen(TRACE_DIR "/alsa.csv", "w"); if (!pipe || !out) { perror("open"); remove_pid(); return 1; } fprintf(out, "timestamp,event\n");
char line[512]; while (running && fgets(line, sizeof(line), pipe)) { fputs(line, out); fflush(out); }
f = fopen("/sys/kernel/tracing/tracing_on", "w"); if (f) { fprintf(f, "0\n"); fclose(f); } f = fopen("/sys/kernel/tracing/current_tracer", "w"); if (f) { fprintf(f, "nop\n"); fclose(f); }
fclose(pipe); fclose(out); remove_pid(); printf("stopped. output: " TRACE_DIR "/alsa.csv\n"); return 0;}
static int cmd_input_ftrace(void) { printf("input latency tracing via ftrace\n"); ensure_trace_dir(); write_pid();
FILE *f; f = fopen("/sys/kernel/tracing/current_tracer", "w"); if (!f) { perror("tracefs"); remove_pid(); return 1; } fprintf(f, "nop\n"); fclose(f);
f = fopen("/sys/kernel/tracing/set_ftrace_filter", "w"); if (f) { fprintf(f, "input_event\n"); fclose(f); } f = fopen("/sys/kernel/tracing/current_tracer", "w"); if (f) { fprintf(f, "function\n"); fclose(f); } f = fopen("/sys/kernel/tracing/tracing_on", "w"); if (f) { fprintf(f, "1\n"); fclose(f); }
printf("tracing input events → " TRACE_DIR "/input.csv (ctrl-c to stop)\n");
FILE *pipe = fopen("/sys/kernel/tracing/trace_pipe", "r"); FILE *out = fopen(TRACE_DIR "/input.csv", "w"); if (!pipe || !out) { perror("open"); remove_pid(); return 1; } fprintf(out, "timestamp,function,latency_us\n");
char line[512]; while (running && fgets(line, sizeof(line), pipe)) { fputs(line, out); fflush(out); }
f = fopen("/sys/kernel/tracing/tracing_on", "w"); if (f) { fprintf(f, "0\n"); fclose(f); } f = fopen("/sys/kernel/tracing/current_tracer", "w"); if (f) { fprintf(f, "nop\n"); fclose(f); }
fclose(pipe); fclose(out); remove_pid(); printf("stopped. output: " TRACE_DIR "/input.csv\n"); return 0;}
static int cmd_alloc_ftrace(void) { printf("allocation profiling via ftrace\n"); ensure_trace_dir(); write_pid();
FILE *f; f = fopen("/sys/kernel/tracing/current_tracer", "w"); if (!f) { perror("tracefs"); remove_pid(); return 1; } fprintf(f, "nop\n"); fclose(f);
f = fopen("/sys/kernel/tracing/set_ftrace_filter", "w"); if (f) { fprintf(f, "__kmalloc\nkfree\n"); fclose(f); } f = fopen("/sys/kernel/tracing/current_tracer", "w"); if (f) { fprintf(f, "function\n"); fclose(f); } f = fopen("/sys/kernel/tracing/tracing_on", "w"); if (f) { fprintf(f, "1\n"); fclose(f); }
printf("tracing allocations → " TRACE_DIR "/alloc.csv (ctrl-c to stop)\n");
FILE *pipe = fopen("/sys/kernel/tracing/trace_pipe", "r"); FILE *out = fopen(TRACE_DIR "/alloc.csv", "w"); if (!pipe || !out) { perror("open"); remove_pid(); return 1; } fprintf(out, "timestamp,function\n");
char line[512]; while (running && fgets(line, sizeof(line), pipe)) { fputs(line, out); fflush(out); }
f = fopen("/sys/kernel/tracing/tracing_on", "w"); if (f) { fprintf(f, "0\n"); fclose(f); } f = fopen("/sys/kernel/tracing/current_tracer", "w"); if (f) { fprintf(f, "nop\n"); fclose(f); }
fclose(pipe); fclose(out); remove_pid(); printf("stopped. output: " TRACE_DIR "/alloc.csv\n"); return 0;}
static void usage(void) { printf("ac-trace — BPF/ftrace tracer for AC Native OS\n\n" "Usage: ac-trace <command>\n\n" "Commands:\n" " syscall Syscall frequency/latency profiling\n" " frame DRM page flip jitter detection\n" " alsa ALSA xrun (underrun) tracing\n" " input evdev input latency histogram\n" " alloc Kernel memory allocation profiling\n" " stop Stop active trace session\n" " status Show active tracers and output files\n" " dump Copy trace buffers to /mnt/trace/\n");}
int main(int argc, char **argv) { if (argc < 2) { usage(); return 1; }
signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler);
const char *cmd = argv[1];
if (strcmp(cmd, "status") == 0) { cmd_status(); return 0; } if (strcmp(cmd, "stop") == 0) { cmd_stop(); return 0; } if (strcmp(cmd, "dump") == 0) { printf("trace files in " TRACE_DIR "/:\n"); cmd_status(); return 0; }
/* Check if already running */ if (is_running()) { fprintf(stderr, "ac-trace already running. Use 'ac-trace stop' first.\n"); return 1; }
/* Dispatch to tracer (ftrace fallback when libbpf not linked) */ if (strcmp(cmd, "syscall") == 0) return cmd_syscall_ftrace(); if (strcmp(cmd, "frame") == 0) return cmd_frame_ftrace(); if (strcmp(cmd, "alsa") == 0) return cmd_alsa_ftrace(); if (strcmp(cmd, "input") == 0) return cmd_input_ftrace(); if (strcmp(cmd, "alloc") == 0) return cmd_alloc_ftrace();
fprintf(stderr, "unknown command: %s\n", cmd); usage(); return 1;}