xref: /minix/sys/sys/kernhist.h (revision 6c8f7fc3)
1 /*	$NetBSD: kernhist.h,v 1.5 2012/07/30 23:56:48 matt 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_kernhist.h"
36 #endif
37 
38 #include <sys/queue.h>
39 #ifdef KERNHIST
40 #include <sys/cpu.h>
41 #endif
42 
43 /*
44  * kernel history/tracing, was uvm_stat
45  */
46 
47 struct kern_history_ent {
48 	struct timeval tv; 		/* time stamp */
49 	int cpunum;
50 	const char *fmt;		/* printf format */
51 	size_t fmtlen;			/* length of printf format */
52 	const char *fn;			/* function name */
53 	size_t fnlen;			/* length of function name */
54 	u_long call;			/* function call number */
55 	u_long v[4];			/* values */
56 };
57 
58 struct kern_history {
59 	const char *name;		/* name of this history */
60 	size_t namelen;			/* length of name, not including null */
61 	LIST_ENTRY(kern_history) list;	/* link on list of all histories */
62 	unsigned int n;			/* number of entries */
63 	unsigned int f;			/* next free one */
64 	struct kern_history_ent *e;	/* the allocated entries */
65 };
66 
67 LIST_HEAD(kern_history_head, kern_history);
68 
69 /*
70  * grovelling lists all at once.  we currently do not allow more than
71  * 32 histories to exist, as the way to dump a number of them at once
72  * is by calling kern_hist() with a bitmask.
73  *
74  * XXX extend this to have a registration function?  however, there
75  * needs to be static ones as UVM requires this before almost anything
76  * else is setup.
77  */
78 
79 /* this is used to set the size of some arrays */
80 #define	MAXHISTS		32
81 
82 /* and these are the bit values of each history */
83 #define	KERNHIST_UVMMAPHIST	0x00000001	/* maphist */
84 #define	KERNHIST_UVMPDHIST	0x00000002	/* pdhist */
85 #define	KERNHIST_UVMUBCHIST	0x00000004	/* ubchist */
86 #define	KERNHIST_UVMLOANHIST	0x00000008	/* loanhist */
87 
88 #ifdef _KERNEL
89 
90 /*
91  * macros to use the history/tracing code.  note that KERNHIST_LOG
92  * must take 4 arguments (even if they are ignored by the format).
93  */
94 #ifndef KERNHIST
95 #define KERNHIST_DECL(NAME)
96 #define KERNHIST_DEFINE(NAME)
97 #define KERNHIST_INIT(NAME,N)
98 #define KERNHIST_INIT_STATIC(NAME,BUF)
99 #define KERNHIST_LOG(NAME,FMT,A,B,C,D)
100 #define KERNHIST_CALLED(NAME)
101 #define KERNHIST_FUNC(FNAME)
102 #define kernhist_dump(NAME)
103 #else
104 #include <sys/kernel.h>		/* for "cold" variable */
105 #include <sys/atomic.h>
106 #include <sys/kmem.h>
107 
108 extern	struct kern_history_head kern_histories;
109 
110 #define KERNHIST_DECL(NAME) extern struct kern_history NAME
111 #define KERNHIST_DEFINE(NAME) struct kern_history NAME
112 
113 #define KERNHIST_INIT(NAME,N) \
114 do { \
115 	(NAME).name = __STRING(NAME); \
116 	(NAME).namelen = strlen(__STRING(NAME)); \
117 	(NAME).n = (N); \
118 	(NAME).f = 0; \
119 	(NAME).e = (struct kern_history_ent *) \
120 		kmem_zalloc(sizeof(struct kern_history_ent) * (N), KM_SLEEP); \
121 	LIST_INSERT_HEAD(&kern_histories, &(NAME), list); \
122 } while (/*CONSTCOND*/ 0)
123 
124 #define KERNHIST_INIT_STATIC(NAME,BUF) \
125 do { \
126 	(NAME).name = __STRING(NAME); \
127 	(NAME).namelen = strlen(__STRING(NAME)); \
128 	(NAME).n = sizeof(BUF) / sizeof(struct kern_history_ent); \
129 	(NAME).f = 0; \
130 	(NAME).e = (struct kern_history_ent *) (BUF); \
131 	memset((NAME).e, 0, sizeof(struct kern_history_ent) * (NAME).n); \
132 	LIST_INSERT_HEAD(&kern_histories, &(NAME), list); \
133 } while (/*CONSTCOND*/ 0)
134 
135 #if defined(KERNHIST_PRINT)
136 extern int kernhist_print_enabled;
137 #define KERNHIST_PRINTNOW(E) \
138 do { \
139 		if (kernhist_print_enabled) { \
140 			kernhist_entry_print(E); \
141 			DELAY(100000); \
142 		} \
143 } while (/*CONSTCOND*/ 0)
144 #else
145 #define KERNHIST_PRINTNOW(E) /* nothing */
146 #endif
147 
148 #define KERNHIST_LOG(NAME,FMT,A,B,C,D) \
149 do { \
150 	unsigned int _i_, _j_; \
151 	do { \
152 		_i_ = (NAME).f; \
153 		_j_ = (_i_ + 1 < (NAME).n) ? _i_ + 1 : 0; \
154 	} while (atomic_cas_uint(&(NAME).f, _i_, _j_) != _i_); \
155 	struct kern_history_ent * const _e_ = &(NAME).e[_i_]; \
156 	if (__predict_true(!cold)) \
157 		microtime(&_e_->tv); \
158 	_e_->cpunum = cpu_number(); \
159 	_e_->fmt = (FMT); \
160 	_e_->fmtlen = strlen(FMT); \
161 	_e_->fn = _kernhist_name; \
162 	_e_->fnlen = strlen(_kernhist_name); \
163 	_e_->call = _kernhist_call; \
164 	_e_->v[0] = (u_long)(A); \
165 	_e_->v[1] = (u_long)(B); \
166 	_e_->v[2] = (u_long)(C); \
167 	_e_->v[3] = (u_long)(D); \
168 	KERNHIST_PRINTNOW(_e_); \
169 } while (/*CONSTCOND*/ 0)
170 
171 #define KERNHIST_CALLED(NAME) \
172 do { \
173 	_kernhist_call = atomic_inc_uint_nv(&_kernhist_cnt); \
174 	KERNHIST_LOG(NAME, "called!", 0, 0, 0, 0); \
175 } while (/*CONSTCOND*/ 0)
176 
177 #define KERNHIST_FUNC(FNAME) \
178 	static unsigned int _kernhist_cnt = 0; \
179 	static const char *const _kernhist_name = FNAME; \
180 	int _kernhist_call = 0;
181 
182 static inline void kernhist_entry_print(const struct kern_history_ent *);
183 
184 static inline void
185 kernhist_entry_print(const struct kern_history_ent *e)
186 {
187 	printf("%06" PRIu64 ".%06d ", e->tv.tv_sec, e->tv.tv_usec);
188 	printf("%s#%ld@%d: ", e->fn, e->call, e->cpunum);
189 	printf(e->fmt, e->v[0], e->v[1], e->v[2], e->v[3]);
190 	printf("\n");
191 }
192 
193 #if defined(DDB)
194 void	kernhist_print(void (*)(const char *, ...) __printflike(1, 2));
195 #endif /* DDB */
196 
197 #endif /* KERNHIST */
198 
199 #endif /* _KERNEL */
200 
201 #endif /* _SYS_KERNHIST_H_ */
202