1 /* $NetBSD: kernhist.h,v 1.26 2021/04/17 01:53:58 mrg 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 (/*CONSTCOND*/ 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 (/*CONSTCOND*/ 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 (/*CONSTCOND*/ 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 (/*CONSTCOND*/ 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 (/*CONSTCOND*/ 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 (/*CONSTCOND*/ 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