1c06b1ef8dba891a87d827102e6d98066547adca Add tslog(4) boot-time event tracing facility diff --git a/share/man/man4/tslog.4 b/share/man/man4/tslog.4 new file mode 100644 index 00000000000..d329c005820 --- /dev/null +++ b/share/man/man4/tslog.4 @@ -0,0 +1,155 @@ +.\" $NetBSD$ +.\" +.\" Copyright (c) 2024 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.\" Ported from FreeBSD +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2022 Mateusz Piotrowski <0mp@FreeBSD.org> +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January, 2024 +.Dt TSLOG 4 +.Os +.Sh NAME +.Nm tslog +.Nd Boot-time event tracing facility +.Sh SYNOPSIS +To compile this boot-time event tracing facility into the kernel, +place the following line in the kernel configuration file: +.Bd -ragged -offset indent +.Cd "option TSLOG" +.Ed +.Sh DESCRIPTION +.Nm +is a boot-time event tracing facility. +It is suitable for tracing recursive events +based on function entries and exits. +Its purpose is to ease pinpointing and reducing the overall +.Nx +boot time by generating detailed timing information. +.Pp +.Nm +is able to trace the boot loader, kernel initialization, and userland processes. +.Pp +In userland, it records the following details for each process ID: +.Bl -dash +.It +The timestamp of the +.Xr fork 2 +which creates the given process ID and the parent process ID. +.It +The path passed to +.Xr execve 2 , +if any. +.It +The first path resolved by +.Xr namei 9 , +if any. +.It +The timestamp of the +.Xr exit 3 +which terminates the process. +.El +.Sh SYSCTL VARIABLES +The following +.Xr sysctl 8 +variables are available: +.Bl -tag -width indent +.It Va debug.tslog +Dump the +.Nm +buffer of recorded loader and kernel event timestamps. +.It Va debug.tslog_user +Dump the +.Nm +buffer +of recorded userland event timestamps. +.El +.Sh FLAMEGRAPHS +The +.Nm +buffer dumps +can be used to generate flamegraphs of the +.Nx +boot process for visual analysis. +See +.Lk https://github.com/cperciva/freebsd-boot-profiling +for more information. +.Sh SEE ALSO +.Xr dtrace 1 +.Sh HISTORY +.Nm +first appeared in +.Fx 12.0 . +Support for tracing boot loaders and userland process +was added in +.Fx 13.2 . +.Pp +.Nm +first appeared in +.Nx 11.0 . +.Ss TSLOG vs. DTrace +.Xr dtrace 1 +is not always the right tool for profiling early kernel initialization. +The reason is it requires some kernel subroutines +which are not yet available early in the boot process, e.g.: +traps, memory allocation, or thread scheduling. +.Nm +depends on fewer kernel subroutines than +.Xr dtrace 1 +and because of that can trace early kernel initialization. +.Sh AUTHORS +.An -nosplit +.Nm +was originally written by +.An Colin Percival Aq Mt cperciva@FreeBSD.org for +.Fx, +.Nx port was made by +.An Emile 'iMil' Heitor Aq Mt imil@NetBSD.org +.Pp +This manual page was originally written by +.An Mateusz Piotrowski Aq Mt 0mp@FreeBSD.org . diff --git a/sys/arch/x86/conf/MICROVM.common b/sys/arch/x86/conf/MICROVM.common index c64c41df2ab..5bdc65f3630 100644 --- a/sys/arch/x86/conf/MICROVM.common +++ b/sys/arch/x86/conf/MICROVM.common @@ -120,3 +120,6 @@ pseudo-device drvctl file-system PUFFS pseudo-device putter + +# tslog(4) boot-time event tracing facility +#options TSLOG diff --git a/sys/arch/x86/conf/files.x86 b/sys/arch/x86/conf/files.x86 index e6c48c1e48b..08aa47b1da0 100644 --- a/sys/arch/x86/conf/files.x86 +++ b/sys/arch/x86/conf/files.x86 @@ -168,6 +168,9 @@ file arch/x86/pci/pciide_machdep.c pciide_common file arch/x86/pci/pci_bus_fixup.c pci_bus_fixup file arch/x86/pci/pci_addr_fixup.c pci_addr_fixup +# tslog(4) framework +file arch/x86/x86/tslog.c tslog + # AES-NI include "crypto/aes/arch/x86/files.aesni" diff --git a/sys/arch/x86/include/tslog.h b/sys/arch/x86/include/tslog.h new file mode 100644 index 00000000000..b03a04c7271 --- /dev/null +++ b/sys/arch/x86/include/tslog.h @@ -0,0 +1,100 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Emile 'iMil' Heitor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 2017 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TSLOG_H_ +#define _TSLOG_H_ + +#ifdef _KERNEL +#ifdef TSLOG +#include +#include +#endif + +#define TS_ENTER 0 +#define TS_EXIT 1 +#define TS_THREAD 2 +#define TS_EVENT 3 + +#define TSENTER() TSRAW(curlwp, TS_ENTER, __func__, NULL) +#define TSENTER2(x) TSRAW(curlwp, TS_ENTER, __func__, x) +#define TSEXIT() TSRAW(curlwp, TS_EXIT, __func__, NULL) +#define TSEXIT2(x) TSRAW(curlwp, TS_EXIT, __func__, x) +#define TSTHREAD(td, x) TSRAW(td, TS_THREAD, x, NULL) +#define TSEVENT(x) TSRAW(curlwp, TS_EVENT, x, NULL) +#define TSEVENT2(x, y) TSRAW(curlwp, TS_EVENT, x, y) +#define TSLINE() TSEVENT2(__FILE__, __XSTRING(__LINE__)) +#define TSWAIT(x) TSEVENT2("WAIT", x); +#define TSUNWAIT(x) TSEVENT2("UNWAIT", x); +#define TSHOLD(x) TSEVENT2("HOLD", x); +#define TSRELEASE(x) TSEVENT2("RELEASE", x); +#define TSFORK(p, pp) TSRAW_USER(p, pp, NULL, NULL) +#define TSEXEC(p, name) TSRAW_USER(p, (pid_t)(-1), name, NULL) +#define TSNAMEI(p, name) TSRAW_USER(p, (pid_t)(-1), NULL, name) +#define TSPROCEXIT(p) TSRAW_USER(p, (pid_t)(-1), NULL, NULL) + +#ifdef TSLOG +#define TSRAW(a, b, c, d) tslog(a, b, c, d) +void tslog(const lwp_t *, int, const char *, const char *); +#define TSRAW_USER(a, b, c, d) tslog_user(a, b, c, d) +void tslog_user(pid_t, pid_t, const char *, const char *); +#else +#define TSRAW(a, b, c, d) /* Timestamp logging disabled */ +#define TSRAW_USER(a, b, c, d) /* Timestamp logging disabled */ +#endif + +#endif /* _KERNEL */ +#endif /* _TSLOG_H_ */ diff --git a/sys/arch/x86/x86/tslog.c b/sys/arch/x86/x86/tslog.c new file mode 100644 index 00000000000..9d63c1f0305 --- /dev/null +++ b/sys/arch/x86/x86/tslog.c @@ -0,0 +1,326 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Emile 'iMil' Heitor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 2017 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#ifndef TSLOGSIZE +#define TSLOGSIZE 262144 +#endif + +#define nitems(x) __arraycount(x) + +static __inline uint64_t +atomic_fetchadd_64(volatile uint64_t *p, uint64_t v) +{ + uint64_t oldval, newval; + + do { + oldval = *p; + newval = oldval + v; + } while (atomic_cas_64(p, oldval, newval) != oldval); + + return oldval; +} + +/* from nm(1), GENERIC biggest symbol is 85 chars long */ +#define MAX_FUNC_NAME 128 + +static volatile uint64_t nrecs = 0; +static struct timestamp { + const lwp_t *l; + int type; + char f[MAX_FUNC_NAME]; + const char *s; + uint64_t tsc; +} timestamps[TSLOGSIZE]; + +void tslog(const lwp_t *, int, const char *, const char *); +void tslog_user(pid_t, pid_t, const char *, const char *); +static int sysctl_debug_tslog(SYSCTLFN_PROTO); + +void +tslog(const lwp_t *l, int type, const char *f, const char *s) +{ + uint64_t tsc = rdtsc(); + long pos; + + /* A NULL thread is lwp0 before curthread is set. */ + if (l == NULL) + l = &lwp0; + + /* Grab a slot. */ + pos = atomic_fetchadd_64(&nrecs, 1); + if (pos < nitems(timestamps)) { + timestamps[pos].l = l; + timestamps[pos].type = type; + /* + * Must record it for TSTHREAD + * - the compiled string is a format string + * - kernel thread might be destroyed + * + * As this variable might also be used for + * function names, MAXCOMLEN is not enough. + */ + if (f != NULL) + strlcpy(timestamps[pos].f, f, MAX_FUNC_NAME); + else + strcpy(timestamps[pos].f, "(null)"); + timestamps[pos].s = s; + timestamps[pos].tsc = tsc; + } +} + +#undef MAX_FUNC_NAME + +static int +sysctl_debug_tslog(SYSCTLFN_ARGS) +{ + char buf[LINE_MAX] = ""; + char *where = oldp; + size_t slen, i, limit; + int error = 0; + static size_t needed = 0; + + /* sysctl first tries with a size of 1024 */ + if (*oldlenp < needed) { + *oldlenp = needed; + return ENOMEM; + } + /* Add data logged within the kernel. */ + limit = MIN(nrecs, nitems(timestamps)); + for (i = 0; i < limit; i++) { + snprintf(buf, LINE_MAX, "0x%x %"PRIu64, + timestamps[i].l->l_lid, timestamps[i].tsc); + switch (timestamps[i].type) { + case TS_ENTER: + strcat(buf, " ENTER"); + break; + case TS_EXIT: + strcat(buf, " EXIT"); + break; + case TS_THREAD: + strcat(buf, " THREAD"); + break; + case TS_EVENT: + strcat(buf, " EVENT"); + break; + } + snprintf(buf, LINE_MAX, "%s %s", buf, timestamps[i].f); + if (timestamps[i].s) + snprintf(buf, LINE_MAX, "%s %s\n", buf, + timestamps[i].s); + else + strcat(buf, "\n"); + + slen = strlen(buf) + 1; + + if (where == NULL) /* 1st pass, calculate needed */ + needed += slen; + else { + if (i > 0) + where--; /* overwrite last \0 */ + if ((error = copyout(buf, where, slen))) + break; + where += slen; + } + } + /* Come back with an address */ + if (oldp == NULL) + *oldlenp = needed; + + return error; +} + +MALLOC_DEFINE(M_TSLOGUSER, "tsloguser", "Strings used by userland tslog"); +static struct procdata { + pid_t ppid; + uint64_t tsc_forked; + uint64_t tsc_exited; + char *execname; + char *namei; + int reused; +} procs[PID_MAX + 1]; + +void +tslog_user(pid_t pid, pid_t ppid, const char *execname, const char *namei) +{ + uint64_t tsc = rdtsc(); + size_t len; + + /* If we wrapped, do nothing. */ + if (procs[pid].reused) + return; + + /* If we have a ppid, we're recording a fork. */ + if (ppid != (pid_t)(-1)) { + /* If we have a ppid already, we wrapped. */ + if (procs[pid].ppid) { + procs[pid].reused = 1; + return; + } + + /* Fill in some fields. */ + procs[pid].ppid = ppid; + procs[pid].tsc_forked = tsc; + return; + } + + /* If we have an execname, record it. */ + if (execname != NULL) { + if (procs[pid].execname != NULL) + free(procs[pid].execname, M_TSLOGUSER); + len = strlen(execname) + 1; + procs[pid].execname = malloc(len, + M_TSLOGUSER, M_WAITOK | M_ZERO); + strlcpy(procs[pid].execname, execname, len); + return; + } + + /* Record the first namei for the process. */ + if (namei != NULL) { + len = strlen(namei) + 1; + if (procs[pid].namei == NULL) { + procs[pid].namei = malloc(len, + M_TSLOGUSER, M_WAITOK | M_ZERO); + strlcpy(procs[pid].namei, namei, len); + } + return; + } + + /* Otherwise we're recording an exit. */ + procs[pid].tsc_exited = tsc; +} + +static int +sysctl_debug_tslog_user(SYSCTLFN_ARGS) +{ + pid_t pid; + char buf[LINE_MAX] = ""; + char *where = oldp; + size_t slen; + int error = 0; + static size_t needed = 0; + + /* sysctl first tries with a size of 1024 */ + if (*oldlenp < needed) { + *oldlenp = needed; + return ENOMEM; + } + /* Export the data we logged. */ + for (pid = 0; pid <= PID_MAX; pid++) { + if (procs[pid].tsc_forked == 0 && + procs[pid].execname == NULL && + procs[pid].namei == NULL && + procs[pid].tsc_exited == 0) + continue; + snprintf(buf, LINE_MAX, "%zu", (size_t)pid); + snprintf(buf, LINE_MAX, "%s %zu", buf, (size_t)procs[pid].ppid); + snprintf(buf, LINE_MAX, "%s %llu", buf, + (unsigned long long)procs[pid].tsc_forked); + snprintf(buf, LINE_MAX, "%s %llu", buf, + (unsigned long long)procs[pid].tsc_exited); + snprintf(buf, LINE_MAX, "%s \"%s\"", buf, procs[pid].execname ? + procs[pid].execname : ""); + snprintf(buf, LINE_MAX, "%s \"%s\"", buf, procs[pid].namei ? + procs[pid].namei : ""); + strcat(buf, "\n"); + + slen = strlen(buf) + 1; + + if (where == NULL) /* 1st pass, calculate needed */ + needed += slen; + else { + if (pid > 1) + where--; /* overwrite last \0 */ + if ((error = copyout(buf, where, slen))) + break; + where += slen; + } + } + /* Come back with an address */ + if (oldp == NULL) + *oldlenp = needed; + + return (error); +} + +SYSCTL_SETUP(sysctl_tslog_setup, "tslog sysctl") +{ + sysctl_createv(NULL, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READONLY, + CTLTYPE_STRING, "tslog", + SYSCTL_DESCR("Dump recorded event timestamps"), + sysctl_debug_tslog, 0, NULL, 0, + CTL_DEBUG, CTL_CREATE, CTL_EOL); + sysctl_createv(NULL, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READONLY, + CTLTYPE_STRING, "tslog_user", + SYSCTL_DESCR("Dump recorded userland event timestamps"), + sysctl_debug_tslog_user, 0, NULL, 0, + CTL_DEBUG, CTL_CREATE, CTL_EOL); +} +