1 /*        $NetBSD: kernhist.h,v 1.27 2024/05/12 10:34:56 rillig Exp $ */
2 
3 /*
4  * Copyright (c) 1997 Charles D. Cranor and Washington University.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * from: NetBSD: uvm_stat.h,v 1.49 2011/04/23 18:14:13 rmind Exp
28  * from: Id: uvm_stat.h,v 1.1.2.4 1998/02/07 01:16:56 chs Exp
29  */
30 
31 #ifndef _SYS_KERNHIST_H_
32 #define _SYS_KERNHIST_H_
33 
34 #if defined(_KERNEL_OPT)
35 #include "opt_ddb.h"
36 #include "opt_kernhist.h"
37 #endif
38 
39 #include <sys/queue.h>
40 #ifdef KERNHIST
41 #include <sys/cpu.h>
42 #endif
43 
44 /*
45  * kernel history/tracing, was uvm_stat
46  */
47 
48 struct kern_history_ent {
49           struct bintime bt;            /* time stamp */
50           uint32_t cpunum;
51           const char *fmt;              /* printf format */
52           size_t fmtlen;                          /* length of printf format */
53           const char *fn;                         /* function name */
54           size_t fnlen;                           /* length of function name */
55           uint32_t call;                          /* function call number */
56           uintmax_t v[4];                         /* values */
57 };
58 
59 struct kern_history {
60           const char *name;             /* name of this history */
61           size_t namelen;                         /* length of name, not including null */
62           LIST_ENTRY(kern_history) list;          /* link on list of all histories */
63           uint32_t n;                             /* number of entries */
64           uint32_t f;                             /* next free one */
65           struct kern_history_ent *e;   /* the allocated entries */
66           int s;                                  /* our sysctl number */
67 };
68 
69 /*
70  * structs for exporting history info via sysctl(3)
71  */
72 
73 /*
74  * Bump this version definition whenever the contents of the
75  * sysctl structures change.
76  */
77 
78 #define KERNHIST_SYSCTL_VERSION 1
79 
80 /* info for a single history event */
81 struct sysctl_history_event {
82           struct bintime      she_bintime;
83           uintmax_t she_values[4];
84           uint32_t  she_callnumber;
85           uint32_t  she_cpunum;
86           uint32_t  she_fmtoffset;
87           uint32_t  she_funcoffset;
88 };
89 
90 /* list of all events for a single history */
91 struct sysctl_history {
92           uint32_t  filler;
93           uint32_t  sh_nameoffset;
94           uint32_t  sh_numentries;
95           uint32_t  sh_nextfree;
96           struct sysctl_history_event
97                               sh_events[];
98           /* char             sh_strings[]; */    /* follows last sh_events */
99 };
100 
101 LIST_HEAD(kern_history_head, kern_history);
102 
103 /*
104  * grovelling lists all at once.  we currently do not allow more than
105  * 32 histories to exist, as the way to dump a number of them at once
106  * is by calling kern_hist() with a bitmask.
107  *
108  * XXX extend this to have a registration function?  however, there
109  * needs to be static ones as UVM requires this before almost anything
110  * else is setup.
111  */
112 
113 /* this is used to set the size of some arrays */
114 #define   MAXHISTS            32
115 
116 /* and these are the bit values of each history */
117 #define   KERNHIST_UVMMAPHIST 0x00000001          /* maphist */
118 #define   KERNHIST_UVMPDHIST  0x00000002          /* pdhist */
119 #define   KERNHIST_UVMUBCHIST 0x00000004          /* ubchist */
120 #define   KERNHIST_UVMLOANHIST          0x00000008          /* loanhist */
121 #define   KERNHIST_USBHIST    0x00000010          /* usbhist */
122 #define   KERNHIST_SCDEBUGHIST          0x00000020          /* scdebughist */
123 #define   KERNHIST_BIOHIST    0x00000040          /* biohist */
124 
125 #ifdef _KERNEL
126 
127 /*
128  * macros to use the history/tracing code.  note that KERNHIST_LOG
129  * must take 4 arguments (even if they are ignored by the format).
130  */
131 #ifndef KERNHIST
132 #define KERNHIST_DECL(NAME)
133 #define KERNHIST_DEFINE(NAME)
134 #define KERNHIST_INIT(NAME,N)
135 #define KERNHIST_LOG(NAME,FMT,A,B,C,D)
136 #define KERNHIST_CALLARGS(NAME,FMT,A,B,C,D)
137 #define KERNHIST_CALLED(NAME)
138 #define KERNHIST_FUNC(FNAME)
139 #define KERNHIST_DUMP(NAME)
140 #else
141 #include <sys/kernel.h>                 /* for "cold" variable */
142 #include <sys/atomic.h>
143 #include <sys/kmem.h>
144 
145 extern    struct kern_history_head kern_histories;
146 
147 #define KERNHIST_DECL(NAME) extern struct kern_history NAME
148 #define KERNHIST_DEFINE(NAME) struct kern_history NAME
149 
150 #define KERNHIST_LINK_STATIC(NAME) \
151 do { \
152           LIST_INSERT_HEAD(&kern_histories, &(NAME), list); \
153           sysctl_kernhist_new(&(NAME)); \
154 } while (0)
155 
156 #define KERNHIST_INIT(NAME,N) \
157 do { \
158           (NAME).name = __STRING(NAME); \
159           (NAME).namelen = strlen(__STRING(NAME)); \
160           (NAME).n = (N); \
161           (NAME).f = 0; \
162           (NAME).e = (struct kern_history_ent *) \
163                     kmem_zalloc(sizeof(struct kern_history_ent) * (N), KM_SLEEP); \
164           (NAME).s = 0; \
165           KERNHIST_LINK_STATIC(NAME); \
166 } while (0)
167 
168 #define KERNHIST_INITIALIZER(NAME,BUF) \
169 { \
170           .name = __STRING(NAME), \
171           .namelen = sizeof(__STRING(NAME)) - 1, \
172           .n = sizeof(BUF) / sizeof(struct kern_history_ent), \
173           .f = 0, \
174           .e = (struct kern_history_ent *) (BUF), \
175           .s = 0, \
176           /* BUF will inititalized to zeroes by being in .bss */ \
177 }
178 
179 #ifndef KERNHIST_DELAY
180 #define KERNHIST_DELAY        100000
181 #endif
182 
183 #if defined(KERNHIST_PRINT)
184 extern int kernhist_print_enabled;
185 #define KERNHIST_PRINTNOW(E) \
186 do { \
187                     if (kernhist_print_enabled) { \
188                               kernhist_entry_print(E, printf); \
189                               if (KERNHIST_DELAY != 0) \
190                                         DELAY(KERNHIST_DELAY); \
191                     } \
192 } while (0)
193 #else
194 #define KERNHIST_PRINTNOW(E) /* nothing */
195 #endif
196 
197 #define KERNHIST_LOG(NAME,FMT,A,B,C,D) \
198 do { \
199           unsigned int _i_, _j_; \
200           do { \
201                     _i_ = (NAME).f; \
202                     _j_ = (_i_ + 1 < (NAME).n) ? _i_ + 1 : 0; \
203           } while (atomic_cas_uint(&(NAME).f, _i_, _j_) != _i_); \
204           struct kern_history_ent * const _e_ = &(NAME).e[_i_]; \
205           if (__predict_true(!cold)) \
206                     bintime(&_e_->bt); \
207           _e_->cpunum = (uint32_t)cpu_number(); \
208           _e_->fmt = (FMT); \
209           _e_->fmtlen = strlen(FMT); \
210           _e_->fn = _kernhist_name; \
211           _e_->fnlen = strlen(_kernhist_name); \
212           _e_->call = _kernhist_call; \
213           _e_->v[0] = (uintmax_t)(A); \
214           _e_->v[1] = (uintmax_t)(B); \
215           _e_->v[2] = (uintmax_t)(C); \
216           _e_->v[3] = (uintmax_t)(D); \
217           KERNHIST_PRINTNOW(_e_); \
218 } while (0)
219 
220 #define KERNHIST_CALLED(NAME) \
221 do { \
222           _kernhist_call = atomic_inc_32_nv(&_kernhist_cnt); \
223           KERNHIST_LOG(NAME, "called!", 0, 0, 0, 0); \
224 } while (0)
225 
226 /*
227  * This extends kernhist to avoid wasting a separate "called!" entry on every
228  * function.
229  */
230 #define KERNHIST_CALLARGS(NAME, FMT, A, B, C, D) \
231 do { \
232           _kernhist_call = atomic_inc_32_nv(&_kernhist_cnt); \
233           KERNHIST_LOG(NAME, "called: "FMT, (A), (B), (C), (D)); \
234 } while (0)
235 
236 #define KERNHIST_FUNC(FNAME) \
237           static uint32_t _kernhist_cnt = 0; \
238           static const char *const _kernhist_name = FNAME; \
239           uint32_t _kernhist_call = 0;
240 
241 #ifdef DDB
242 #define KERNHIST_DUMP(NAME)   kernhist_dump(&NAME, 0, printf)
243 #else
244 #define KERNHIST_DUMP(NAME)
245 #endif
246 
247 static __inline void
248 kernhist_entry_print(const struct kern_history_ent *e, void (*pr)(const char *, ...) __printflike(1, 2))
249 {
250           struct timeval tv;
251 
252           bintime2timeval(&e->bt, &tv);
253           pr("%06ld.%06ld ", (long int)tv.tv_sec, (long int)tv.tv_usec);
254           pr("%s#%" PRIu32 "@%" PRIu32 ": ", e->fn, e->call, e->cpunum);
255           pr(e->fmt, e->v[0], e->v[1], e->v[2], e->v[3]);
256           pr("\n");
257 }
258 
259 #if defined(DDB)
260 void      kernhist_dump(struct kern_history *, size_t, void (*)(const char *, ...) __printflike(1, 2));
261 void      kernhist_print(void *, size_t, const char *, void (*)(const char *, ...) __printflike(1, 2));
262 #endif /* DDB */
263 
264 void sysctl_kernhist_init(void);
265 void sysctl_kernhist_new(struct kern_history *);
266 
267 #endif /* KERNHIST */
268 
269 #endif /* _KERNEL */
270 
271 #endif /* _SYS_KERNHIST_H_ */
272