29#include <sys/boottrace.h>
30#include <sys/kernel.h>
31#include <sys/malloc.h>
34#include <sys/resourcevar.h>
36#include <sys/syscallsubr.h>
37#include <sys/sysctl.h>
40#include <machine/stdarg.h>
42#define dprintf(fmt, ...) \
44 if (dotrace_debugging) \
45 printf(fmt, ##__VA_ARGS__); \
48static MALLOC_DEFINE(M_BOOTTRACE,
"boottrace",
"memory for boot tracing");
50#define BT_TABLE_DEFSIZE 3000
51#define BT_TABLE_RUNSIZE 2000
52#define BT_TABLE_SHTSIZE 1000
53#define BT_TABLE_MINSIZE 500
66 char name[BT_EVENT_NAMELEN];
113 "boottrace statistics");
116 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE | CTLFLAG_SKIP,
118 "Print a log of the boottrace trace data");
120 CTLTYPE_STRING | CTLFLAG_WR | CTLFLAG_MPSAFE,
122 "Capture a boot-time trace event");
124 CTLTYPE_STRING | CTLFLAG_WR | CTLFLAG_MPSAFE,
126 "Capture a run-time trace event");
128 CTLTYPE_STRING | CTLFLAG_WR | CTLFLAG_MPSAFE,
130 "Capture a shutdown-time trace event");
132 CTLTYPE_INT | CTLFLAG_WR | CTLFLAG_MPSAFE,
134 "Reset run-time tracing table");
142 "Boot-time and shutdown-time tracing enabled");
150 "Enable kernel shutdown tracing to the console");
159 "Tracing threshold (ms) below which tracing is ignored");
189#define BTC_DELTA_PRINT(bte, msecs, delta) do { \
191 sbuf_printf(sbp, fmt, (bte)->cpuid, msecs, delta, \
192 (bte)->tdname, (bte)->name, (bte)->pid, \
193 (bte)->cputime / 1000000, \
194 ((bte)->cputime % 1000000) / 10000, \
195 (bte)->inblock, (bte)->oublock); \
197 printf(fmt, (bte)->cpuid, msecs, delta, \
198 (bte)->tdname, (bte)->name, (bte)->pid, \
199 (bte)->cputime / 1000000, \
200 ((bte)->cputime % 1000000) / 10000, \
201 (bte)->inblock, (bte)->oublock); \
216 uint64_t first_msecs;
219 uint64_t last_dmsecs;
220 uint64_t total_dmsecs;
223 const char *fmt =
"%3u %10llu %10llu %-24s %-40s %5d %4d.%02d %5u %5u\n";
224 const char *hdr_fmt =
"\n\n%3s %10s %10s %-24s %-40s %5s %6s %5s %5s\n";
231 "CPU",
"msecs",
"delta",
"process",
232 "event",
"PID",
"CPUtime",
"IBlks",
"OBlks");
235 "CPU",
"msecs",
"delta",
"process",
236 "event",
"PID",
"CPUtime",
"IBlks",
"OBlks");
242 last_printed =
false;
243 i = curr = btp->
curr;
246 evtp = &btp->
table[i];
251 dmsecs = (last_msecs != 0 && msecs > last_msecs) ?
252 msecs - last_msecs : 0;
259 if (dthres != 0 && (dmsecs > dthres)) {
264 if (last_evtp != NULL && !last_printed)
269 }
else if (dthres == 0) {
273 if (first_msecs == 0 || msecs < first_msecs)
277 last_dmsecs = dmsecs;
278 last_printed = printed;
281 i = (i + 1) % btp->
size;
284 total_dmsecs = last_msecs > first_msecs ?
285 (last_msecs - first_msecs) : 0;
287 sbuf_printf(sbp,
"Total measured time: %ju msecs\n",
288 (uintmax_t)total_dmsecs);
290 printf(
"Total measured time: %ju msecs\n",
291 (uintmax_t)total_dmsecs);
325 tdname = (curproc->p_flag & P_SYSTEM) ?
326 curthread->td_name : curproc->p_comm;
329 dprintf(
"cpu=%u, pid=%d, tsc=%ju, tick=%d, td='%s', event='%s'",
330 PCPU_GET(cpuid), curthread->td_proc->p_pid,
331 (uintmax_t)get_cyclecount(),
ticks, tdname, eventname);
332 if (btp->
table == NULL) {
334 dprintf(
", return=ENOSPC_1]\n");
341 nxt = (idx + 1) % btp->
size;
342 if (nxt == 0 && btp->
wrap == 0) {
344 dprintf(
", return=ENOSPC_2]\n");
347 }
while (!atomic_cmpset_int(&btp->
curr, idx, nxt));
350 btp->
table[idx].
tsc = get_cyclecount(),
352 btp->
table[idx].
pid = curthread->td_proc->p_pid;
358 if ((curthread->td_proc == &
proc0) || (curthread->td_critnest != 0)) {
365 (uint64_t)(usage.ru_utime.tv_sec * 1000000 +
366 usage.ru_utime.tv_usec + usage.ru_stime.tv_sec * 1000000 +
367 usage.ru_stime.tv_usec);
371 strlcpy(btp->
table[idx].
name, eventname, BT_EVENT_NAMELEN);
372 strlcpy(btp->
table[idx].
tdname, tdname, BT_EVENT_TDNAMELEN);
385 char eventname[BT_EVENT_NAMELEN];
393 vsnprintf(eventname,
sizeof(eventname), fmt, ap);
402 return (
dotrace(btp, eventname, tdname));
413 return (
dotrace(&
rt, eventname, tdname));
429 delim = strchr(message,
':');
433 *eventname = ++delim;
435 *tdname = curproc->p_comm;
436 *eventname = message;
442 struct sysctl_req *req)
444 char message[BT_MSGLEN];
445 char *eventname, *tdname;
457 error =
dotrace(btp, eventname, tdname);
458 if (error == ENOSPC) {
474 sbuf =
sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
492 if (req->newptr == NULL)
510 if (req->newptr == NULL)
528 if (req->newptr == NULL)
543 snprintf(tmpbuf,
sizeof(tmpbuf),
"reset: %s", actor);
559 M_BOOTTRACE, M_WAITOK | M_ZERO);
575 if (req->newptr != NULL)
590 TUNABLE_INT_FETCH(
"kern.boottrace.table_size", &
bt.
size);
598 strlcpy(
bt.
table[0].
name,
"initial event", BT_EVENT_NAMELEN);
void boottrace_dump_console(void)
#define BTC_DELTA_PRINT(bte, msecs, delta)
static void boottrace_init(void)
static int shutdown_trace_threshold
bool __read_mostly boottrace_enabled
static int _boottrace_sysctl(struct bt_table *btp, struct sysctl_oid *oidp, struct sysctl_req *req)
static bool dotrace_kernel
static void boottrace_parse_message(char *message, char **eventname, char **tdname)
static int sysctl_boottrace_reset(SYSCTL_HANDLER_ARGS)
void boottrace_reset(const char *actor)
static int sysctl_runtrace(SYSCTL_HANDLER_ARGS)
static struct bt_table bt
SYSCTL_BOOL(_kern_boottrace, OID_AUTO, enabled, CTLFLAG_RDTUN, &boottrace_enabled, 0, "Boot-time and shutdown-time tracing enabled")
static int dotrace(struct bt_table *btp, const char *eventname, const char *tdname)
static void boottrace_display(struct sbuf *sbp, struct bt_table *btp, uint64_t dthres)
static int sysctl_boottrace(SYSCTL_HANDLER_ARGS)
int boottrace_resize(u_int newsize)
SYSCTL_NODE(_kern, OID_AUTO, boottrace, CTLFLAG_RD|CTLFLAG_MPSAFE, 0, "boottrace statistics")
static int sysctl_log(SYSCTL_HANDLER_ARGS)
SYSCTL_INT(_kern_boottrace, OID_AUTO, shutdown_trace_threshold, CTLFLAG_RWTUN, &shutdown_trace_threshold, 0, "Tracing threshold (ms) below which tracing is ignored")
static int sysctl_shuttrace(SYSCTL_HANDLER_ARGS)
static struct bt_table st
static MALLOC_DEFINE(M_BOOTTRACE, "boottrace", "memory for boot tracing")
int boottrace(const char *tdname, const char *fmt,...)
TUNABLE_BOOL("debug.boottrace.dotrace_debugging", &dotrace_debugging)
static struct bt_table rt
SYSINIT(boottrace, SI_SUB_CPU, SI_ORDER_ANY, boottrace_init, 0)
static int runtrace(const char *eventname, const char *tdname)
SYSCTL_PROC(_kern_boottrace, OID_AUTO, log, CTLTYPE_STRING|CTLFLAG_RD|CTLFLAG_MPSAFE|CTLFLAG_SKIP, 0, 0, sysctl_log, "A", "Print a log of the boottrace trace data")
static bool dotrace_debugging
void *() malloc(size_t size, struct malloc_type *mtp, int flags)
void * realloc(void *addr, size_t size, struct malloc_type *mtp, int flags)
int kern_getrusage(struct thread *td, int who, struct rusage *rup)
int sysctl_handle_string(SYSCTL_HANDLER_ARGS)
uint64_t cputick2usec(uint64_t tick)
char name[BT_EVENT_NAMELEN]
char tdname[BT_EVENT_TDNAMELEN]
static bool kasan_enabled __read_mostly
int vsnprintf(char *str, size_t size, const char *format, va_list ap)
int printf(const char *fmt,...)
int snprintf(char *str, size_t size, const char *format,...)
void log(int level, const char *fmt,...)
int sbuf_finish(struct sbuf *s)
void sbuf_delete(struct sbuf *s)
int sbuf_printf(struct sbuf *s, const char *fmt,...)
ssize_t sbuf_len(struct sbuf *s)
char * sbuf_data(struct sbuf *s)
struct sbuf * sbuf_new(struct sbuf *s, char *buf, int length, int flags)