xref: /netbsd-src/sys/uvm/uvm_stat.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /*	$NetBSD: uvm_stat.c,v 1.35 2011/01/05 21:20:44 enami Exp $	 */
2 
3 /*
4  *
5  * Copyright (c) 1997 Charles D. Cranor and Washington University.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by Charles D. Cranor and
19  *      Washington University.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * from: Id: uvm_stat.c,v 1.1.2.3 1997/12/19 15:01:00 mrg Exp
35  */
36 
37 /*
38  * uvm_stat.c
39  */
40 
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: uvm_stat.c,v 1.35 2011/01/05 21:20:44 enami Exp $");
43 
44 #include "opt_uvmhist.h"
45 #include "opt_readahead.h"
46 #include "opt_ddb.h"
47 
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/cpu.h>
51 
52 #include <uvm/uvm.h>
53 #include <uvm/uvm_ddb.h>
54 
55 /*
56  * globals
57  */
58 
59 #ifdef UVMHIST
60 struct uvm_history_head uvm_histories;
61 #endif
62 
63 #ifdef UVMHIST_PRINT
64 int uvmhist_print_enabled = 1;
65 #endif
66 
67 #ifdef DDB
68 
69 /*
70  * prototypes
71  */
72 
73 #ifdef UVMHIST
74 void uvmhist_dump(struct uvm_history *);
75 void uvm_hist(u_int32_t);
76 static void uvmhist_dump_histories(struct uvm_history *[]);
77 #endif
78 void uvmcnt_dump(void);
79 
80 
81 #ifdef UVMHIST
82 /* call this from ddb */
83 void
84 uvmhist_dump(struct uvm_history *l)
85 {
86 	int lcv, s;
87 
88 	s = splhigh();
89 	lcv = l->f;
90 	do {
91 		if (l->e[lcv].fmt)
92 			uvmhist_entry_print(&l->e[lcv]);
93 		lcv = (lcv + 1) % l->n;
94 	} while (lcv != l->f);
95 	splx(s);
96 }
97 
98 /*
99  * print a merged list of uvm_history structures
100  */
101 static void
102 uvmhist_dump_histories(struct uvm_history *hists[])
103 {
104 	struct timeval  tv;
105 	int	cur[MAXHISTS];
106 	int	s, lcv, hi;
107 
108 	/* so we don't get corrupted lists! */
109 	s = splhigh();
110 
111 	/* find the first of each list */
112 	for (lcv = 0; hists[lcv]; lcv++)
113 		 cur[lcv] = hists[lcv]->f;
114 
115 	/*
116 	 * here we loop "forever", finding the next earliest
117 	 * history entry and printing it.  cur[X] is the current
118 	 * entry to test for the history in hists[X].  if it is
119 	 * -1, then this history is finished.
120 	 */
121 	for (;;) {
122 		hi = -1;
123 		tv.tv_sec = tv.tv_usec = 0;
124 
125 		/* loop over each history */
126 		for (lcv = 0; hists[lcv]; lcv++) {
127 restart:
128 			if (cur[lcv] == -1)
129 				continue;
130 
131 			/*
132 			 * if the format is empty, go to the next entry
133 			 * and retry.
134 			 */
135 			if (hists[lcv]->e[cur[lcv]].fmt == NULL) {
136 				cur[lcv] = (cur[lcv] + 1) % (hists[lcv]->n);
137 				if (cur[lcv] == hists[lcv]->f)
138 					cur[lcv] = -1;
139 				goto restart;
140 			}
141 
142 			/*
143 			 * if the time hasn't been set yet, or this entry is
144 			 * earlier than the current tv, set the time and history
145 			 * index.
146 			 */
147 			if (tv.tv_sec == 0 ||
148 			    timercmp(&hists[lcv]->e[cur[lcv]].tv, &tv, <)) {
149 				tv = hists[lcv]->e[cur[lcv]].tv;
150 				hi = lcv;
151 			}
152 		}
153 
154 		/* if we didn't find any entries, we must be done */
155 		if (hi == -1)
156 			break;
157 
158 		/* print and move to the next entry */
159 		uvmhist_entry_print(&hists[hi]->e[cur[hi]]);
160 		cur[hi] = (cur[hi] + 1) % (hists[hi]->n);
161 		if (cur[hi] == hists[hi]->f)
162 			cur[hi] = -1;
163 	}
164 	splx(s);
165 }
166 
167 /*
168  * call this from ddb.  `bitmask' is from <uvm/uvm_stat.h>.  it
169  * merges the named histories.
170  */
171 void
172 uvm_hist(u_int32_t bitmask)	/* XXX only support 32 hists */
173 {
174 	struct uvm_history *hists[MAXHISTS + 1];
175 	int i = 0;
176 
177 	if ((bitmask & UVMHIST_MAPHIST) || bitmask == 0)
178 		hists[i++] = &maphist;
179 
180 	if ((bitmask & UVMHIST_PDHIST) || bitmask == 0)
181 		hists[i++] = &pdhist;
182 
183 	if ((bitmask & UVMHIST_UBCHIST) || bitmask == 0)
184 		hists[i++] = &ubchist;
185 
186 	if ((bitmask & UVMHIST_LOANHIST) || bitmask == 0)
187 		hists[i++] = &loanhist;
188 
189 	hists[i] = NULL;
190 
191 	uvmhist_dump_histories(hists);
192 }
193 
194 /*
195  * uvmhist_print: ddb hook to print uvm history
196  */
197 void
198 uvmhist_print(void (*pr)(const char *, ...))
199 {
200 	uvmhist_dump(LIST_FIRST(&uvm_histories));
201 }
202 
203 #endif /* UVMHIST */
204 
205 /*
206  * uvmexp_print: ddb hook to print interesting uvm counters
207  */
208 void
209 uvmexp_print(void (*pr)(const char *, ...)
210     __attribute__((__format__(__printf__,1,2))))
211 {
212 	int active, inactive;
213 	CPU_INFO_ITERATOR cii;
214 	struct cpu_info *ci;
215 
216 	uvm_estimatepageable(&active, &inactive);
217 
218 	(*pr)("Current UVM status:\n");
219 	(*pr)("  pagesize=%d (0x%x), pagemask=0x%x, pageshift=%d\n, ncolors=%d",
220 	    uvmexp.pagesize, uvmexp.pagesize, uvmexp.pagemask,
221 	    uvmexp.pageshift, uvmexp.ncolors);
222 	(*pr)("  %d VM pages: %d active, %d inactive, %d wired, %d free\n",
223 	    uvmexp.npages, active, inactive, uvmexp.wired,
224 	    uvmexp.free);
225 	(*pr)("  pages  %d anon, %d file, %d exec\n",
226 	    uvmexp.anonpages, uvmexp.filepages, uvmexp.execpages);
227 	(*pr)("  freemin=%d, free-target=%d, wired-max=%d\n",
228 	    uvmexp.freemin, uvmexp.freetarg, uvmexp.wiredmax);
229 
230 	for (CPU_INFO_FOREACH(cii, ci)) {
231 		(*pr)("  cpu%u:\n", cpu_index(ci));
232 		(*pr)("    faults=%" PRIu64 ", traps=%" PRIu64 ", "
233 		    "intrs=%" PRIu64 ", ctxswitch=%" PRIu64 "\n",
234 		    ci->ci_data.cpu_nfault, ci->ci_data.cpu_ntrap,
235 		    ci->ci_data.cpu_nintr, ci->ci_data.cpu_nswtch);
236 		(*pr)("    softint=%" PRIu64 ", syscalls=%" PRIu64 "\n",
237 		    ci->ci_data.cpu_nsoft, ci->ci_data.cpu_nsyscall);
238 	}
239 
240 	(*pr)("  fault counts:\n");
241 	(*pr)("    noram=%d, noanon=%d, pgwait=%d, pgrele=%d\n",
242 	    uvmexp.fltnoram, uvmexp.fltnoanon, uvmexp.fltpgwait,
243 	    uvmexp.fltpgrele);
244 	(*pr)("    ok relocks(total)=%d(%d), anget(retrys)=%d(%d), "
245 	    "amapcopy=%d\n", uvmexp.fltrelckok, uvmexp.fltrelck,
246 	    uvmexp.fltanget, uvmexp.fltanretry, uvmexp.fltamcopy);
247 	(*pr)("    neighbor anon/obj pg=%d/%d, gets(lock/unlock)=%d/%d\n",
248 	    uvmexp.fltnamap, uvmexp.fltnomap, uvmexp.fltlget, uvmexp.fltget);
249 	(*pr)("    cases: anon=%d, anoncow=%d, obj=%d, prcopy=%d, przero=%d\n",
250 	    uvmexp.flt_anon, uvmexp.flt_acow, uvmexp.flt_obj, uvmexp.flt_prcopy,
251 	    uvmexp.flt_przero);
252 
253 	(*pr)("  daemon and swap counts:\n");
254 	(*pr)("    woke=%d, revs=%d, scans=%d, obscans=%d, anscans=%d\n",
255 	    uvmexp.pdwoke, uvmexp.pdrevs, uvmexp.pdscans, uvmexp.pdobscan,
256 	    uvmexp.pdanscan);
257 	(*pr)("    busy=%d, freed=%d, reactivate=%d, deactivate=%d\n",
258 	    uvmexp.pdbusy, uvmexp.pdfreed, uvmexp.pdreact, uvmexp.pddeact);
259 	(*pr)("    pageouts=%d, pending=%d, nswget=%d\n", uvmexp.pdpageouts,
260 	    uvmexp.pdpending, uvmexp.nswget);
261 	(*pr)("    nswapdev=%d, swpgavail=%d\n",
262 	    uvmexp.nswapdev, uvmexp.swpgavail);
263 	(*pr)("    swpages=%d, swpginuse=%d, swpgonly=%d, paging=%d\n",
264 	    uvmexp.swpages, uvmexp.swpginuse, uvmexp.swpgonly, uvmexp.paging);
265 }
266 #endif
267 
268 #if defined(READAHEAD_STATS)
269 
270 #define	UVM_RA_EVCNT_DEFINE(name) \
271 struct evcnt uvm_ra_##name = \
272 EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "readahead", #name); \
273 EVCNT_ATTACH_STATIC(uvm_ra_##name);
274 
275 UVM_RA_EVCNT_DEFINE(total);
276 UVM_RA_EVCNT_DEFINE(hit);
277 UVM_RA_EVCNT_DEFINE(miss);
278 
279 #endif /* defined(READAHEAD_STATS) */
280