1 /*	$NetBSD: kernhist.h,v 1.12 2016/04/09 17:04:53 riastradh 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 timeval tv; 		/* time stamp */
50 	int 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 	u_long call;			/* function call number */
56 	u_long 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 	unsigned int n;			/* number of entries */
64 	unsigned int f;			/* next free one */
65 	struct kern_history_ent *e;	/* the allocated entries */
66 };
67 
68 LIST_HEAD(kern_history_head, kern_history);
69 
70 /*
71  * grovelling lists all at once.  we currently do not allow more than
72  * 32 histories to exist, as the way to dump a number of them at once
73  * is by calling kern_hist() with a bitmask.
74  *
75  * XXX extend this to have a registration function?  however, there
76  * needs to be static ones as UVM requires this before almost anything
77  * else is setup.
78  */
79 
80 /* this is used to set the size of some arrays */
81 #define	MAXHISTS		32
82 
83 /* and these are the bit values of each history */
84 #define	KERNHIST_UVMMAPHIST	0x00000001	/* maphist */
85 #define	KERNHIST_UVMPDHIST	0x00000002	/* pdhist */
86 #define	KERNHIST_UVMUBCHIST	0x00000004	/* ubchist */
87 #define	KERNHIST_UVMLOANHIST	0x00000008	/* loanhist */
88 #define	KERNHIST_USBHIST	0x00000010	/* usbhist */
89 #define	KERNHIST_SCDEBUGHIST	0x00000020	/* scdebughist */
90 
91 #ifdef _KERNEL
92 
93 /*
94  * macros to use the history/tracing code.  note that KERNHIST_LOG
95  * must take 4 arguments (even if they are ignored by the format).
96  */
97 #ifndef KERNHIST
98 #define KERNHIST_DECL(NAME)
99 #define KERNHIST_DEFINE(NAME)
100 #define KERNHIST_INIT(NAME,N)
101 #define KERNHIST_INIT_STATIC(NAME,BUF)
102 #define KERNHIST_LOG(NAME,FMT,A,B,C,D)
103 #define KERNHIST_CALLARGS(NAME,FMT,A,B,C,D)
104 #define KERNHIST_CALLED(NAME)
105 #define KERNHIST_FUNC(FNAME)
106 #define KERNHIST_DUMP(NAME)
107 #else
108 #include <sys/kernel.h>		/* for "cold" variable */
109 #include <sys/atomic.h>
110 #include <sys/kmem.h>
111 
112 extern	struct kern_history_head kern_histories;
113 
114 #define KERNHIST_DECL(NAME) extern struct kern_history NAME
115 #define KERNHIST_DEFINE(NAME) struct kern_history NAME
116 
117 #define KERNHIST_INIT(NAME,N) \
118 do { \
119 	(NAME).name = __STRING(NAME); \
120 	(NAME).namelen = strlen(__STRING(NAME)); \
121 	(NAME).n = (N); \
122 	(NAME).f = 0; \
123 	(NAME).e = (struct kern_history_ent *) \
124 		kmem_zalloc(sizeof(struct kern_history_ent) * (N), KM_SLEEP); \
125 	LIST_INSERT_HEAD(&kern_histories, &(NAME), list); \
126 } while (/*CONSTCOND*/ 0)
127 
128 #define KERNHIST_INITIALIZER(NAME,BUF) \
129 { \
130 	.name = __STRING(NAME), \
131 	.namelen = sizeof(__STRING(NAME)) - 1, \
132 	.n = sizeof(BUF) / sizeof(struct kern_history_ent), \
133 	.f = 0, \
134 	.e = (struct kern_history_ent *) (BUF), \
135 	/* BUF will inititalized to zeroes by being in .bss */ \
136 }
137 
138 #define KERNHIST_LINK_STATIC(NAME) \
139 	LIST_INSERT_HEAD(&kern_histories, &(NAME), list)
140 
141 #define KERNHIST_INIT_STATIC(NAME,BUF) \
142 do { \
143 	(NAME).name = __STRING(NAME); \
144 	(NAME).namelen = strlen(__STRING(NAME)); \
145 	(NAME).n = sizeof(BUF) / sizeof(struct kern_history_ent); \
146 	(NAME).f = 0; \
147 	(NAME).e = (struct kern_history_ent *) (BUF); \
148 	memset((NAME).e, 0, sizeof(struct kern_history_ent) * (NAME).n); \
149 	KERNHIST_LINK_STATIC(NAME); \
150 } while (/*CONSTCOND*/ 0)
151 
152 #ifndef KERNHIST_DELAY
153 #define KERNHIST_DELAY	100000
154 #endif
155 
156 #if defined(KERNHIST_PRINT)
157 extern int kernhist_print_enabled;
158 #define KERNHIST_PRINTNOW(E) \
159 do { \
160 		if (kernhist_print_enabled) { \
161 			kernhist_entry_print(E, printf); \
162 			if (KERNHIST_DELAY != 0) \
163 				DELAY(KERNHIST_DELAY); \
164 		} \
165 } while (/*CONSTCOND*/ 0)
166 #else
167 #define KERNHIST_PRINTNOW(E) /* nothing */
168 #endif
169 
170 #define KERNHIST_LOG(NAME,FMT,A,B,C,D) \
171 do { \
172 	unsigned int _i_, _j_; \
173 	do { \
174 		_i_ = (NAME).f; \
175 		_j_ = (_i_ + 1 < (NAME).n) ? _i_ + 1 : 0; \
176 	} while (atomic_cas_uint(&(NAME).f, _i_, _j_) != _i_); \
177 	struct kern_history_ent * const _e_ = &(NAME).e[_i_]; \
178 	if (__predict_true(!cold)) \
179 		microtime(&_e_->tv); \
180 	_e_->cpunum = cpu_number(); \
181 	_e_->fmt = (FMT); \
182 	_e_->fmtlen = strlen(FMT); \
183 	_e_->fn = _kernhist_name; \
184 	_e_->fnlen = strlen(_kernhist_name); \
185 	_e_->call = _kernhist_call; \
186 	_e_->v[0] = (u_long)(A); \
187 	_e_->v[1] = (u_long)(B); \
188 	_e_->v[2] = (u_long)(C); \
189 	_e_->v[3] = (u_long)(D); \
190 	KERNHIST_PRINTNOW(_e_); \
191 } while (/*CONSTCOND*/ 0)
192 
193 #define KERNHIST_CALLED(NAME) \
194 do { \
195 	_kernhist_call = atomic_inc_uint_nv(&_kernhist_cnt); \
196 	KERNHIST_LOG(NAME, "called!", 0, 0, 0, 0); \
197 } while (/*CONSTCOND*/ 0)
198 
199 /*
200  * This extends kernhist to avoid wasting a separate "called!" entry on every
201  * function.
202  */
203 #define KERNHIST_CALLARGS(NAME, FMT, A, B, C, D) \
204 do { \
205 	_kernhist_call = atomic_inc_uint_nv(&_kernhist_cnt); \
206 	KERNHIST_LOG(NAME, "called: "FMT, (A), (B), (C), (D)); \
207 } while (/*CONSTCOND*/ 0)
208 
209 #define KERNHIST_FUNC(FNAME) \
210 	static unsigned int _kernhist_cnt = 0; \
211 	static const char *const _kernhist_name = FNAME; \
212 	unsigned int _kernhist_call = 0;
213 
214 #ifdef DDB
215 #define KERNHIST_DUMP(NAME)	kernhist_dump(&NAME, printf)
216 #else
217 #define KERNHIST_DUMP(NAME)
218 #endif
219 
220 static inline void
221 kernhist_entry_print(const struct kern_history_ent *e, void (*pr)(const char *, ...) __printflike(1, 2))
222 {
223 	pr("%06" PRIu64 ".%06d ", e->tv.tv_sec, e->tv.tv_usec);
224 	pr("%s#%ld@%d: ", e->fn, e->call, e->cpunum);
225 	pr(e->fmt, e->v[0], e->v[1], e->v[2], e->v[3]);
226 	pr("\n");
227 }
228 
229 #if defined(DDB)
230 void	kernhist_dump(struct kern_history *, void (*)(const char *, ...) __printflike(1, 2));
231 void	kernhist_print(void *, void (*)(const char *, ...) __printflike(1, 2));
232 #endif /* DDB */
233 
234 #endif /* KERNHIST */
235 
236 #endif /* _KERNEL */
237 
238 #endif /* _SYS_KERNHIST_H_ */
239