xref: /netbsd-src/sys/uvm/uvm_stat.c (revision 46f5119e40af2e51998f686b2fdcc76b5488f7f3)
1 /*	$NetBSD: uvm_stat.c,v 1.36 2011/02/02 15:13:34 chuck 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: Id: uvm_stat.c,v 1.1.2.3 1997/12/19 15:01:00 mrg Exp
28  */
29 
30 /*
31  * uvm_stat.c
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: uvm_stat.c,v 1.36 2011/02/02 15:13:34 chuck Exp $");
36 
37 #include "opt_uvmhist.h"
38 #include "opt_readahead.h"
39 #include "opt_ddb.h"
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/cpu.h>
44 
45 #include <uvm/uvm.h>
46 #include <uvm/uvm_ddb.h>
47 
48 /*
49  * globals
50  */
51 
52 #ifdef UVMHIST
53 struct uvm_history_head uvm_histories;
54 #endif
55 
56 #ifdef UVMHIST_PRINT
57 int uvmhist_print_enabled = 1;
58 #endif
59 
60 #ifdef DDB
61 
62 /*
63  * prototypes
64  */
65 
66 #ifdef UVMHIST
67 void uvmhist_dump(struct uvm_history *);
68 void uvm_hist(u_int32_t);
69 static void uvmhist_dump_histories(struct uvm_history *[]);
70 #endif
71 void uvmcnt_dump(void);
72 
73 
74 #ifdef UVMHIST
75 /* call this from ddb */
76 void
77 uvmhist_dump(struct uvm_history *l)
78 {
79 	int lcv, s;
80 
81 	s = splhigh();
82 	lcv = l->f;
83 	do {
84 		if (l->e[lcv].fmt)
85 			uvmhist_entry_print(&l->e[lcv]);
86 		lcv = (lcv + 1) % l->n;
87 	} while (lcv != l->f);
88 	splx(s);
89 }
90 
91 /*
92  * print a merged list of uvm_history structures
93  */
94 static void
95 uvmhist_dump_histories(struct uvm_history *hists[])
96 {
97 	struct timeval  tv;
98 	int	cur[MAXHISTS];
99 	int	s, lcv, hi;
100 
101 	/* so we don't get corrupted lists! */
102 	s = splhigh();
103 
104 	/* find the first of each list */
105 	for (lcv = 0; hists[lcv]; lcv++)
106 		 cur[lcv] = hists[lcv]->f;
107 
108 	/*
109 	 * here we loop "forever", finding the next earliest
110 	 * history entry and printing it.  cur[X] is the current
111 	 * entry to test for the history in hists[X].  if it is
112 	 * -1, then this history is finished.
113 	 */
114 	for (;;) {
115 		hi = -1;
116 		tv.tv_sec = tv.tv_usec = 0;
117 
118 		/* loop over each history */
119 		for (lcv = 0; hists[lcv]; lcv++) {
120 restart:
121 			if (cur[lcv] == -1)
122 				continue;
123 
124 			/*
125 			 * if the format is empty, go to the next entry
126 			 * and retry.
127 			 */
128 			if (hists[lcv]->e[cur[lcv]].fmt == NULL) {
129 				cur[lcv] = (cur[lcv] + 1) % (hists[lcv]->n);
130 				if (cur[lcv] == hists[lcv]->f)
131 					cur[lcv] = -1;
132 				goto restart;
133 			}
134 
135 			/*
136 			 * if the time hasn't been set yet, or this entry is
137 			 * earlier than the current tv, set the time and history
138 			 * index.
139 			 */
140 			if (tv.tv_sec == 0 ||
141 			    timercmp(&hists[lcv]->e[cur[lcv]].tv, &tv, <)) {
142 				tv = hists[lcv]->e[cur[lcv]].tv;
143 				hi = lcv;
144 			}
145 		}
146 
147 		/* if we didn't find any entries, we must be done */
148 		if (hi == -1)
149 			break;
150 
151 		/* print and move to the next entry */
152 		uvmhist_entry_print(&hists[hi]->e[cur[hi]]);
153 		cur[hi] = (cur[hi] + 1) % (hists[hi]->n);
154 		if (cur[hi] == hists[hi]->f)
155 			cur[hi] = -1;
156 	}
157 	splx(s);
158 }
159 
160 /*
161  * call this from ddb.  `bitmask' is from <uvm/uvm_stat.h>.  it
162  * merges the named histories.
163  */
164 void
165 uvm_hist(u_int32_t bitmask)	/* XXX only support 32 hists */
166 {
167 	struct uvm_history *hists[MAXHISTS + 1];
168 	int i = 0;
169 
170 	if ((bitmask & UVMHIST_MAPHIST) || bitmask == 0)
171 		hists[i++] = &maphist;
172 
173 	if ((bitmask & UVMHIST_PDHIST) || bitmask == 0)
174 		hists[i++] = &pdhist;
175 
176 	if ((bitmask & UVMHIST_UBCHIST) || bitmask == 0)
177 		hists[i++] = &ubchist;
178 
179 	if ((bitmask & UVMHIST_LOANHIST) || bitmask == 0)
180 		hists[i++] = &loanhist;
181 
182 	hists[i] = NULL;
183 
184 	uvmhist_dump_histories(hists);
185 }
186 
187 /*
188  * uvmhist_print: ddb hook to print uvm history
189  */
190 void
191 uvmhist_print(void (*pr)(const char *, ...))
192 {
193 	uvmhist_dump(LIST_FIRST(&uvm_histories));
194 }
195 
196 #endif /* UVMHIST */
197 
198 /*
199  * uvmexp_print: ddb hook to print interesting uvm counters
200  */
201 void
202 uvmexp_print(void (*pr)(const char *, ...)
203     __attribute__((__format__(__printf__,1,2))))
204 {
205 	int active, inactive;
206 	CPU_INFO_ITERATOR cii;
207 	struct cpu_info *ci;
208 
209 	uvm_estimatepageable(&active, &inactive);
210 
211 	(*pr)("Current UVM status:\n");
212 	(*pr)("  pagesize=%d (0x%x), pagemask=0x%x, pageshift=%d\n, ncolors=%d",
213 	    uvmexp.pagesize, uvmexp.pagesize, uvmexp.pagemask,
214 	    uvmexp.pageshift, uvmexp.ncolors);
215 	(*pr)("  %d VM pages: %d active, %d inactive, %d wired, %d free\n",
216 	    uvmexp.npages, active, inactive, uvmexp.wired,
217 	    uvmexp.free);
218 	(*pr)("  pages  %d anon, %d file, %d exec\n",
219 	    uvmexp.anonpages, uvmexp.filepages, uvmexp.execpages);
220 	(*pr)("  freemin=%d, free-target=%d, wired-max=%d\n",
221 	    uvmexp.freemin, uvmexp.freetarg, uvmexp.wiredmax);
222 
223 	for (CPU_INFO_FOREACH(cii, ci)) {
224 		(*pr)("  cpu%u:\n", cpu_index(ci));
225 		(*pr)("    faults=%" PRIu64 ", traps=%" PRIu64 ", "
226 		    "intrs=%" PRIu64 ", ctxswitch=%" PRIu64 "\n",
227 		    ci->ci_data.cpu_nfault, ci->ci_data.cpu_ntrap,
228 		    ci->ci_data.cpu_nintr, ci->ci_data.cpu_nswtch);
229 		(*pr)("    softint=%" PRIu64 ", syscalls=%" PRIu64 "\n",
230 		    ci->ci_data.cpu_nsoft, ci->ci_data.cpu_nsyscall);
231 	}
232 
233 	(*pr)("  fault counts:\n");
234 	(*pr)("    noram=%d, noanon=%d, pgwait=%d, pgrele=%d\n",
235 	    uvmexp.fltnoram, uvmexp.fltnoanon, uvmexp.fltpgwait,
236 	    uvmexp.fltpgrele);
237 	(*pr)("    ok relocks(total)=%d(%d), anget(retrys)=%d(%d), "
238 	    "amapcopy=%d\n", uvmexp.fltrelckok, uvmexp.fltrelck,
239 	    uvmexp.fltanget, uvmexp.fltanretry, uvmexp.fltamcopy);
240 	(*pr)("    neighbor anon/obj pg=%d/%d, gets(lock/unlock)=%d/%d\n",
241 	    uvmexp.fltnamap, uvmexp.fltnomap, uvmexp.fltlget, uvmexp.fltget);
242 	(*pr)("    cases: anon=%d, anoncow=%d, obj=%d, prcopy=%d, przero=%d\n",
243 	    uvmexp.flt_anon, uvmexp.flt_acow, uvmexp.flt_obj, uvmexp.flt_prcopy,
244 	    uvmexp.flt_przero);
245 
246 	(*pr)("  daemon and swap counts:\n");
247 	(*pr)("    woke=%d, revs=%d, scans=%d, obscans=%d, anscans=%d\n",
248 	    uvmexp.pdwoke, uvmexp.pdrevs, uvmexp.pdscans, uvmexp.pdobscan,
249 	    uvmexp.pdanscan);
250 	(*pr)("    busy=%d, freed=%d, reactivate=%d, deactivate=%d\n",
251 	    uvmexp.pdbusy, uvmexp.pdfreed, uvmexp.pdreact, uvmexp.pddeact);
252 	(*pr)("    pageouts=%d, pending=%d, nswget=%d\n", uvmexp.pdpageouts,
253 	    uvmexp.pdpending, uvmexp.nswget);
254 	(*pr)("    nswapdev=%d, swpgavail=%d\n",
255 	    uvmexp.nswapdev, uvmexp.swpgavail);
256 	(*pr)("    swpages=%d, swpginuse=%d, swpgonly=%d, paging=%d\n",
257 	    uvmexp.swpages, uvmexp.swpginuse, uvmexp.swpgonly, uvmexp.paging);
258 }
259 #endif
260 
261 #if defined(READAHEAD_STATS)
262 
263 #define	UVM_RA_EVCNT_DEFINE(name) \
264 struct evcnt uvm_ra_##name = \
265 EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "readahead", #name); \
266 EVCNT_ATTACH_STATIC(uvm_ra_##name);
267 
268 UVM_RA_EVCNT_DEFINE(total);
269 UVM_RA_EVCNT_DEFINE(hit);
270 UVM_RA_EVCNT_DEFINE(miss);
271 
272 #endif /* defined(READAHEAD_STATS) */
273