| @@ -1,2260 +1,2265 @@ | | | @@ -1,2260 +1,2265 @@ |
1 | /* $NetBSD: vmstat.c,v 1.243 2021/03/03 08:25:16 simonb Exp $ */ | | 1 | /* $NetBSD: vmstat.c,v 1.244 2021/04/01 05:33:50 simonb Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1998, 2000, 2001, 2007, 2019, 2020 | | 4 | * Copyright (c) 1998, 2000, 2001, 2007, 2019, 2020 |
5 | * The NetBSD Foundation, Inc. | | 5 | * The NetBSD Foundation, Inc. |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * This code is derived from software contributed to The NetBSD Foundation by: | | 8 | * This code is derived from software contributed to The NetBSD Foundation by: |
9 | * - Jason R. Thorpe of the Numerical Aerospace Simulation Facility, | | 9 | * - Jason R. Thorpe of the Numerical Aerospace Simulation Facility, |
10 | * NASA Ames Research Center. | | 10 | * NASA Ames Research Center. |
11 | * - Simon Burge and Luke Mewburn of Wasabi Systems, Inc. | | 11 | * - Simon Burge and Luke Mewburn of Wasabi Systems, Inc. |
12 | * | | 12 | * |
13 | * Redistribution and use in source and binary forms, with or without | | 13 | * Redistribution and use in source and binary forms, with or without |
14 | * modification, are permitted provided that the following conditions | | 14 | * modification, are permitted provided that the following conditions |
15 | * are met: | | 15 | * are met: |
16 | * 1. Redistributions of source code must retain the above copyright | | 16 | * 1. Redistributions of source code must retain the above copyright |
17 | * notice, this list of conditions and the following disclaimer. | | 17 | * notice, this list of conditions and the following disclaimer. |
18 | * 2. Redistributions in binary form must reproduce the above copyright | | 18 | * 2. Redistributions in binary form must reproduce the above copyright |
19 | * notice, this list of conditions and the following disclaimer in the | | 19 | * notice, this list of conditions and the following disclaimer in the |
20 | * documentation and/or other materials provided with the distribution. | | 20 | * documentation and/or other materials provided with the distribution. |
21 | * | | 21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 22 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
23 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 23 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
24 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 24 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
25 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 25 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
32 | * POSSIBILITY OF SUCH DAMAGE. | | 32 | * POSSIBILITY OF SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | /* | | 35 | /* |
36 | * Copyright (c) 1980, 1986, 1991, 1993 | | 36 | * Copyright (c) 1980, 1986, 1991, 1993 |
37 | * The Regents of the University of California. All rights reserved. | | 37 | * The Regents of the University of California. All rights reserved. |
38 | * | | 38 | * |
39 | * Redistribution and use in source and binary forms, with or without | | 39 | * Redistribution and use in source and binary forms, with or without |
40 | * modification, are permitted provided that the following conditions | | 40 | * modification, are permitted provided that the following conditions |
41 | * are met: | | 41 | * are met: |
42 | * 1. Redistributions of source code must retain the above copyright | | 42 | * 1. Redistributions of source code must retain the above copyright |
43 | * notice, this list of conditions and the following disclaimer. | | 43 | * notice, this list of conditions and the following disclaimer. |
44 | * 2. Redistributions in binary form must reproduce the above copyright | | 44 | * 2. Redistributions in binary form must reproduce the above copyright |
45 | * notice, this list of conditions and the following disclaimer in the | | 45 | * notice, this list of conditions and the following disclaimer in the |
46 | * documentation and/or other materials provided with the distribution. | | 46 | * documentation and/or other materials provided with the distribution. |
47 | * 3. Neither the name of the University nor the names of its contributors | | 47 | * 3. Neither the name of the University nor the names of its contributors |
48 | * may be used to endorse or promote products derived from this software | | 48 | * may be used to endorse or promote products derived from this software |
49 | * without specific prior written permission. | | 49 | * without specific prior written permission. |
50 | * | | 50 | * |
51 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 51 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
52 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 52 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
53 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 53 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
54 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 54 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
55 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 55 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
56 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 56 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
57 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 57 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
58 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 58 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
59 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 59 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
60 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 60 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
61 | * SUCH DAMAGE. | | 61 | * SUCH DAMAGE. |
62 | */ | | 62 | */ |
63 | | | 63 | |
64 | #include <sys/cdefs.h> | | 64 | #include <sys/cdefs.h> |
65 | #ifndef lint | | 65 | #ifndef lint |
66 | __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1991, 1993\ | | 66 | __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1991, 1993\ |
67 | The Regents of the University of California. All rights reserved."); | | 67 | The Regents of the University of California. All rights reserved."); |
68 | #endif /* not lint */ | | 68 | #endif /* not lint */ |
69 | | | 69 | |
70 | #ifndef lint | | 70 | #ifndef lint |
71 | #if 0 | | 71 | #if 0 |
72 | static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95"; | | 72 | static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95"; |
73 | #else | | 73 | #else |
74 | __RCSID("$NetBSD: vmstat.c,v 1.243 2021/03/03 08:25:16 simonb Exp $"); | | 74 | __RCSID("$NetBSD: vmstat.c,v 1.244 2021/04/01 05:33:50 simonb Exp $"); |
75 | #endif | | 75 | #endif |
76 | #endif /* not lint */ | | 76 | #endif /* not lint */ |
77 | | | 77 | |
78 | #define __POOL_EXPOSE | | 78 | #define __POOL_EXPOSE |
79 | #define __NAMECACHE_PRIVATE | | 79 | #define __NAMECACHE_PRIVATE |
80 | | | 80 | |
81 | #include <sys/param.h> | | 81 | #include <sys/param.h> |
82 | #include <sys/types.h> | | 82 | #include <sys/types.h> |
83 | #include <sys/mount.h> | | 83 | #include <sys/mount.h> |
84 | #include <sys/uio.h> | | 84 | #include <sys/uio.h> |
85 | | | 85 | |
86 | #include <sys/buf.h> | | 86 | #include <sys/buf.h> |
87 | #include <sys/evcnt.h> | | 87 | #include <sys/evcnt.h> |
88 | #include <sys/ioctl.h> | | 88 | #include <sys/ioctl.h> |
89 | #include <sys/malloc.h> | | 89 | #include <sys/malloc.h> |
90 | #include <sys/mallocvar.h> | | 90 | #include <sys/mallocvar.h> |
91 | #include <sys/namei.h> | | 91 | #include <sys/namei.h> |
92 | #include <sys/pool.h> | | 92 | #include <sys/pool.h> |
93 | #include <sys/proc.h> | | 93 | #include <sys/proc.h> |
94 | #include <sys/sched.h> | | 94 | #include <sys/sched.h> |
95 | #include <sys/socket.h> | | 95 | #include <sys/socket.h> |
96 | #include <sys/sysctl.h> | | 96 | #include <sys/sysctl.h> |
97 | #include <sys/time.h> | | 97 | #include <sys/time.h> |
98 | #include <sys/queue.h> | | 98 | #include <sys/queue.h> |
99 | #include <sys/kernhist.h> | | 99 | #include <sys/kernhist.h> |
100 | #include <sys/vnode.h> | | 100 | #include <sys/vnode.h> |
101 | #include <sys/vnode_impl.h> | | 101 | #include <sys/vnode_impl.h> |
102 | | | 102 | |
103 | #include <uvm/uvm_extern.h> | | 103 | #include <uvm/uvm_extern.h> |
104 | #include <uvm/uvm_stat.h> | | 104 | #include <uvm/uvm_stat.h> |
105 | | | 105 | |
106 | #include <net/if.h> | | 106 | #include <net/if.h> |
107 | #include <netinet/in.h> | | 107 | #include <netinet/in.h> |
108 | #include <netinet/in_var.h> | | 108 | #include <netinet/in_var.h> |
109 | | | 109 | |
110 | #include <ufs/ufs/inode.h> | | 110 | #include <ufs/ufs/inode.h> |
111 | | | 111 | |
112 | #include <nfs/rpcv2.h> | | 112 | #include <nfs/rpcv2.h> |
113 | #include <nfs/nfsproto.h> | | 113 | #include <nfs/nfsproto.h> |
114 | #include <nfs/nfsnode.h> | | 114 | #include <nfs/nfsnode.h> |
115 | | | 115 | |
116 | #include <ctype.h> | | 116 | #include <ctype.h> |
117 | #include <err.h> | | 117 | #include <err.h> |
118 | #include <errno.h> | | 118 | #include <errno.h> |
119 | #include <fcntl.h> | | 119 | #include <fcntl.h> |
120 | #include <kvm.h> | | 120 | #include <kvm.h> |
121 | #include <limits.h> | | 121 | #include <limits.h> |
122 | #include <nlist.h> | | 122 | #include <nlist.h> |
123 | #undef n_hash | | 123 | #undef n_hash |
124 | #include <paths.h> | | 124 | #include <paths.h> |
125 | #include <signal.h> | | 125 | #include <signal.h> |
126 | #include <stdio.h> | | 126 | #include <stdio.h> |
127 | #include <stddef.h> | | 127 | #include <stddef.h> |
128 | #include <stdlib.h> | | 128 | #include <stdlib.h> |
129 | #include <string.h> | | 129 | #include <string.h> |
130 | #include <time.h> | | 130 | #include <time.h> |
131 | #include <unistd.h> | | 131 | #include <unistd.h> |
132 | #include <util.h> | | 132 | #include <util.h> |
133 | | | 133 | |
134 | #include "drvstats.h" | | 134 | #include "drvstats.h" |
135 | | | 135 | |
136 | /* | | 136 | /* |
137 | * All this mess will go away once everything is converted. | | 137 | * All this mess will go away once everything is converted. |
138 | */ | | 138 | */ |
139 | #ifdef __HAVE_CPU_DATA_FIRST | | 139 | #ifdef __HAVE_CPU_DATA_FIRST |
140 | | | 140 | |
141 | # include <sys/cpu_data.h> | | 141 | # include <sys/cpu_data.h> |
142 | struct cpu_info { | | 142 | struct cpu_info { |
143 | struct cpu_data ci_data; | | 143 | struct cpu_data ci_data; |
144 | }; | | 144 | }; |
145 | #else | | 145 | #else |
146 | # include <sys/cpu.h> | | 146 | # include <sys/cpu.h> |
147 | #endif | | 147 | #endif |
148 | | | 148 | |
149 | /* | | 149 | /* |
150 | * General namelist | | 150 | * General namelist |
151 | */ | | 151 | */ |
152 | struct nlist namelist[] = | | 152 | struct nlist namelist[] = |
153 | { | | 153 | { |
154 | #define X_HZ 0 | | 154 | #define X_HZ 0 |
155 | { .n_name = "_hz" }, | | 155 | { .n_name = "_hz" }, |
156 | #define X_STATHZ 1 | | 156 | #define X_STATHZ 1 |
157 | { .n_name = "_stathz" }, | | 157 | { .n_name = "_stathz" }, |
158 | #define X_NCHSTATS 2 | | 158 | #define X_NCHSTATS 2 |
159 | { .n_name = "_nchstats" }, | | 159 | { .n_name = "_nchstats" }, |
160 | #define X_ALLEVENTS 3 | | 160 | #define X_ALLEVENTS 3 |
161 | { .n_name = "_allevents" }, | | 161 | { .n_name = "_allevents" }, |
162 | #define X_POOLHEAD 4 | | 162 | #define X_POOLHEAD 4 |
163 | { .n_name = "_pool_head" }, | | 163 | { .n_name = "_pool_head" }, |
164 | #define X_UVMEXP 5 | | 164 | #define X_UVMEXP 5 |
165 | { .n_name = "_uvmexp" }, | | 165 | { .n_name = "_uvmexp" }, |
166 | #define X_CPU_INFOS 6 | | 166 | #define X_CPU_INFOS 6 |
167 | { .n_name = "_cpu_infos" }, | | 167 | { .n_name = "_cpu_infos" }, |
168 | #define X_NL_SIZE 7 | | 168 | #define X_NL_SIZE 7 |
169 | { .n_name = NULL }, | | 169 | { .n_name = NULL }, |
170 | }; | | 170 | }; |
171 | | | 171 | |
172 | /* | | 172 | /* |
173 | * Namelist for time data. | | 173 | * Namelist for time data. |
174 | */ | | 174 | */ |
175 | struct nlist timenl[] = | | 175 | struct nlist timenl[] = |
176 | { | | 176 | { |
177 | #define X_TIMEBASEBIN 0 | | 177 | #define X_TIMEBASEBIN 0 |
178 | { .n_name = "_timebasebin" }, | | 178 | { .n_name = "_timebasebin" }, |
179 | #define X_TIME_SECOND 1 | | 179 | #define X_TIME_SECOND 1 |
180 | { .n_name = "_time_second" }, | | 180 | { .n_name = "_time_second" }, |
181 | #define X_TIME 2 | | 181 | #define X_TIME 2 |
182 | { .n_name = "_time" }, | | 182 | { .n_name = "_time" }, |
183 | #define X_TIMENL_SIZE 3 | | 183 | #define X_TIMENL_SIZE 3 |
184 | { .n_name = NULL }, | | 184 | { .n_name = NULL }, |
185 | }; | | 185 | }; |
186 | | | 186 | |
187 | /* | | 187 | /* |
188 | * Namelist for pre-evcnt interrupt counters. | | 188 | * Namelist for pre-evcnt interrupt counters. |
189 | */ | | 189 | */ |
190 | struct nlist intrnl[] = | | 190 | struct nlist intrnl[] = |
191 | { | | 191 | { |
192 | #define X_INTRNAMES 0 | | 192 | #define X_INTRNAMES 0 |
193 | { .n_name = "_intrnames" }, | | 193 | { .n_name = "_intrnames" }, |
194 | #define X_EINTRNAMES 1 | | 194 | #define X_EINTRNAMES 1 |
195 | { .n_name = "_eintrnames" }, | | 195 | { .n_name = "_eintrnames" }, |
196 | #define X_INTRCNT 2 | | 196 | #define X_INTRCNT 2 |
197 | { .n_name = "_intrcnt" }, | | 197 | { .n_name = "_intrcnt" }, |
198 | #define X_EINTRCNT 3 | | 198 | #define X_EINTRCNT 3 |
199 | { .n_name = "_eintrcnt" }, | | 199 | { .n_name = "_eintrcnt" }, |
200 | #define X_INTRNL_SIZE 4 | | 200 | #define X_INTRNL_SIZE 4 |
201 | { .n_name = NULL }, | | 201 | { .n_name = NULL }, |
202 | }; | | 202 | }; |
203 | | | 203 | |
204 | | | 204 | |
205 | /* | | 205 | /* |
206 | * Namelist for hash statistics | | 206 | * Namelist for hash statistics |
207 | */ | | 207 | */ |
208 | struct nlist hashnl[] = | | 208 | struct nlist hashnl[] = |
209 | { | | 209 | { |
210 | #define X_NFSNODE 0 | | 210 | #define X_NFSNODE 0 |
211 | { .n_name = "_nfsnodehash" }, | | 211 | { .n_name = "_nfsnodehash" }, |
212 | #define X_NFSNODETBL 1 | | 212 | #define X_NFSNODETBL 1 |
213 | { .n_name = "_nfsnodehashtbl" }, | | 213 | { .n_name = "_nfsnodehashtbl" }, |
214 | #define X_IHASH 2 | | 214 | #define X_IHASH 2 |
215 | { .n_name = "_ihash" }, | | 215 | { .n_name = "_ihash" }, |
216 | #define X_IHASHTBL 3 | | 216 | #define X_IHASHTBL 3 |
217 | { .n_name = "_ihashtbl" }, | | 217 | { .n_name = "_ihashtbl" }, |
218 | #define X_BUFHASH 4 | | 218 | #define X_BUFHASH 4 |
219 | { .n_name = "_bufhash" }, | | 219 | { .n_name = "_bufhash" }, |
220 | #define X_BUFHASHTBL 5 | | 220 | #define X_BUFHASHTBL 5 |
221 | { .n_name = "_bufhashtbl" }, | | 221 | { .n_name = "_bufhashtbl" }, |
222 | #define X_UIHASH 6 | | 222 | #define X_UIHASH 6 |
223 | { .n_name = "_uihash" }, | | 223 | { .n_name = "_uihash" }, |
224 | #define X_UIHASHTBL 7 | | 224 | #define X_UIHASHTBL 7 |
225 | { .n_name = "_uihashtbl" }, | | 225 | { .n_name = "_uihashtbl" }, |
226 | #define X_IFADDRHASH 8 | | 226 | #define X_IFADDRHASH 8 |
227 | { .n_name = "_in_ifaddrhash" }, | | 227 | { .n_name = "_in_ifaddrhash" }, |
228 | #define X_IFADDRHASHTBL 9 | | 228 | #define X_IFADDRHASHTBL 9 |
229 | { .n_name = "_in_ifaddrhashtbl" }, | | 229 | { .n_name = "_in_ifaddrhashtbl" }, |
230 | #define X_VCACHEHASH 10 | | 230 | #define X_VCACHEHASH 10 |
231 | { .n_name = "_vcache_hashmask" }, | | 231 | { .n_name = "_vcache_hashmask" }, |
232 | #define X_VCACHETBL 11 | | 232 | #define X_VCACHETBL 11 |
233 | { .n_name = "_vcache_hashtab" }, | | 233 | { .n_name = "_vcache_hashtab" }, |
234 | #define X_HASHNL_SIZE 12 /* must be last */ | | 234 | #define X_HASHNL_SIZE 12 /* must be last */ |
235 | { .n_name = NULL }, | | 235 | { .n_name = NULL }, |
236 | }; | | 236 | }; |
237 | | | 237 | |
238 | /* | | 238 | /* |
239 | * Namelist for kernel histories | | 239 | * Namelist for kernel histories |
240 | */ | | 240 | */ |
241 | struct nlist histnl[] = | | 241 | struct nlist histnl[] = |
242 | { | | 242 | { |
243 | { .n_name = "_kern_histories" }, | | 243 | { .n_name = "_kern_histories" }, |
244 | #define X_KERN_HISTORIES 0 | | 244 | #define X_KERN_HISTORIES 0 |
245 | { .n_name = NULL }, | | 245 | { .n_name = NULL }, |
246 | }; | | 246 | }; |
247 | | | 247 | |
248 | | | 248 | |
249 | #define KILO 1024 | | 249 | #define KILO 1024 |
250 | | | 250 | |
251 | struct cpu_counter { | | 251 | struct cpu_counter { |
252 | uint64_t nintr; | | 252 | uint64_t nintr; |
253 | uint64_t nsyscall; | | 253 | uint64_t nsyscall; |
254 | uint64_t nswtch; | | 254 | uint64_t nswtch; |
255 | uint64_t nfault; | | 255 | uint64_t nfault; |
256 | uint64_t ntrap; | | 256 | uint64_t ntrap; |
257 | uint64_t nsoft; | | 257 | uint64_t nsoft; |
258 | } cpucounter, ocpucounter; | | 258 | } cpucounter, ocpucounter; |
259 | | | 259 | |
260 | struct uvmexp_sysctl uvmexp, ouvmexp; | | 260 | struct uvmexp_sysctl uvmexp, ouvmexp; |
261 | int ndrives; | | 261 | int ndrives; |
262 | | | 262 | |
263 | int winlines = 20; | | 263 | int winlines = 20; |
264 | | | 264 | |
265 | kvm_t *kd; | | 265 | kvm_t *kd; |
266 | | | 266 | |
267 | | | 267 | |
268 | #define FORKSTAT 0x001 | | 268 | #define FORKSTAT 0x001 |
269 | #define INTRSTAT 0x002 | | 269 | #define INTRSTAT 0x002 |
270 | #define MEMSTAT 0x004 | | 270 | #define MEMSTAT 0x004 |
271 | #define SUMSTAT 0x008 | | 271 | #define SUMSTAT 0x008 |
272 | #define EVCNTSTAT 0x010 | | 272 | #define EVCNTSTAT 0x010 |
273 | #define VMSTAT 0x020 | | 273 | #define VMSTAT 0x020 |
274 | #define HISTLIST 0x040 | | 274 | #define HISTLIST 0x040 |
275 | #define HISTDUMP 0x080 | | 275 | #define HISTDUMP 0x080 |
276 | #define HASHSTAT 0x100 | | 276 | #define HASHSTAT 0x100 |
277 | #define HASHLIST 0x200 | | 277 | #define HASHLIST 0x200 |
278 | #define VMTOTAL 0x400 | | 278 | #define VMTOTAL 0x400 |
279 | #define POOLCACHESTAT 0x800 | | 279 | #define POOLCACHESTAT 0x800 |
280 | | | 280 | |
281 | /* | | 281 | /* |
282 | * Print single word. `ovflow' is number of characters didn't fit | | 282 | * Print single word. `ovflow' is number of characters didn't fit |
283 | * on the last word. `fmt' is a format string to print this word. | | 283 | * on the last word. `fmt' is a format string to print this word. |
284 | * It must contain asterisk for field width. `width' is a width | | 284 | * It must contain asterisk for field width. `width' is a width |
285 | * occupied by this word. `fixed' is a number of constant chars in | | 285 | * occupied by this word. `fixed' is a number of constant chars in |
286 | * `fmt'. `val' is a value to be printed using format string `fmt'. | | 286 | * `fmt'. `val' is a value to be printed using format string `fmt'. |
287 | */ | | 287 | */ |
288 | #define PRWORD(ovflw, fmt, width, fixed, val) do { \ | | 288 | #define PRWORD(ovflw, fmt, width, fixed, val) do { \ |
289 | (ovflw) += printf((fmt), \ | | 289 | (ovflw) += printf((fmt), \ |
290 | (width) - (fixed) - (ovflw) > 0 ? \ | | 290 | (width) - (fixed) - (ovflw) > 0 ? \ |
291 | (width) - (fixed) - (ovflw) : 0, \ | | 291 | (width) - (fixed) - (ovflw) : 0, \ |
292 | (val)) - (width); \ | | 292 | (val)) - (width); \ |
293 | if ((ovflw) < 0) \ | | 293 | if ((ovflw) < 0) \ |
294 | (ovflw) = 0; \ | | 294 | (ovflw) = 0; \ |
295 | } while (/* CONSTCOND */0) | | 295 | } while (/* CONSTCOND */0) |
296 | | | 296 | |
297 | void cpustats(int *); | | 297 | void cpustats(int *); |
298 | void cpucounters(struct cpu_counter *); | | 298 | void cpucounters(struct cpu_counter *); |
299 | void deref_kptr(const void *, void *, size_t, const char *); | | 299 | void deref_kptr(const void *, void *, size_t, const char *); |
300 | void drvstats(int *); | | 300 | void drvstats(int *); |
301 | void doevcnt(int verbose, int type); | | 301 | void doevcnt(int verbose, int type); |
302 | void dohashstat(int, int, const char *); | | 302 | void dohashstat(int, int, const char *); |
303 | void dointr(int verbose); | | 303 | void dointr(int verbose); |
304 | void dopool(int, int); | | 304 | void dopool(int, int); |
305 | void dopoolcache(int); | | 305 | void dopoolcache(int); |
306 | void dosum(void); | | 306 | void dosum(void); |
307 | void dovmstat(struct timespec *, int); | | 307 | void dovmstat(struct timespec *, int); |
308 | void print_total_hdr(void); | | 308 | void print_total_hdr(void); |
309 | void dovmtotal(struct timespec *, int); | | 309 | void dovmtotal(struct timespec *, int); |
310 | void kread(struct nlist *, int, void *, size_t); | | 310 | void kread(struct nlist *, int, void *, size_t); |
311 | int kreadc(struct nlist *, int, void *, size_t); | | 311 | int kreadc(struct nlist *, int, void *, size_t); |
312 | void needhdr(int); | | 312 | void needhdr(int); |
313 | void getnlist(int); | | 313 | void getnlist(int); |
314 | long getuptime(void); | | 314 | long getuptime(void); |
315 | void printhdr(void); | | 315 | void printhdr(void); |
316 | long pct(u_long, u_long); | | 316 | long pct(u_long, u_long); |
317 | __dead static void usage(void); | | 317 | __dead static void usage(void); |
318 | void doforkst(void); | | 318 | void doforkst(void); |
319 | | | 319 | |
320 | void hist_traverse(int, const char *); | | 320 | void hist_traverse(int, const char *); |
321 | void hist_dodump(struct kern_history *); | | 321 | void hist_dodump(struct kern_history *); |
322 | void hist_traverse_sysctl(int, const char *); | | 322 | void hist_traverse_sysctl(int, const char *); |
323 | void hist_dodump_sysctl(int[], unsigned int); | | 323 | void hist_dodump_sysctl(int[], unsigned int); |
324 | | | 324 | |
325 | char **choosedrives(char **); | | 325 | char **choosedrives(char **); |
326 | | | 326 | |
327 | /* Namelist and memory file names. */ | | 327 | /* Namelist and memory file names. */ |
328 | char *nlistf, *memf; | | 328 | char *nlistf, *memf; |
329 | | | 329 | |
330 | /* allow old usage [vmstat 1] */ | | 330 | /* allow old usage [vmstat 1] */ |
331 | #define BACKWARD_COMPATIBILITY | | 331 | #define BACKWARD_COMPATIBILITY |
332 | | | 332 | |
333 | static const int clockrate_mib[] = { CTL_KERN, KERN_CLOCKRATE }; | | 333 | static const int clockrate_mib[] = { CTL_KERN, KERN_CLOCKRATE }; |
334 | static const int vmmeter_mib[] = { CTL_VM, VM_METER }; | | 334 | static const int vmmeter_mib[] = { CTL_VM, VM_METER }; |
335 | static const int uvmexp2_mib[] = { CTL_VM, VM_UVMEXP2 }; | | 335 | static const int uvmexp2_mib[] = { CTL_VM, VM_UVMEXP2 }; |
336 | static const int boottime_mib[] = { CTL_KERN, KERN_BOOTTIME }; | | 336 | static const int boottime_mib[] = { CTL_KERN, KERN_BOOTTIME }; |
337 | static char kvm_errbuf[_POSIX2_LINE_MAX]; | | 337 | static char kvm_errbuf[_POSIX2_LINE_MAX]; |
338 | | | 338 | |
339 | int | | 339 | int |
340 | main(int argc, char *argv[]) | | 340 | main(int argc, char *argv[]) |
341 | { | | 341 | { |
342 | int c, todo, verbose, wide; | | 342 | int c, todo, verbose, wide; |
343 | struct timespec interval; | | 343 | struct timespec interval; |
344 | int reps; | | 344 | int reps; |
345 | gid_t egid = getegid(); | | 345 | gid_t egid = getegid(); |
346 | const char *histname, *hashname; | | 346 | const char *histname, *hashname; |
347 | | | 347 | |
348 | histname = hashname = NULL; | | 348 | histname = hashname = NULL; |
349 | (void)setegid(getgid()); | | 349 | (void)setegid(getgid()); |
350 | memf = nlistf = NULL; | | 350 | memf = nlistf = NULL; |
351 | reps = todo = verbose = wide = 0; | | 351 | reps = todo = verbose = wide = 0; |
352 | interval.tv_sec = 0; | | 352 | interval.tv_sec = 0; |
353 | interval.tv_nsec = 0; | | 353 | interval.tv_nsec = 0; |
354 | while ((c = getopt(argc, argv, "Cc:efh:HilLM:mN:stu:UvWw:")) != -1) { | | 354 | while ((c = getopt(argc, argv, "Cc:efh:HilLM:mN:stu:UvWw:")) != -1) { |
355 | switch (c) { | | 355 | switch (c) { |
356 | case 'c': | | 356 | case 'c': |
357 | reps = atoi(optarg); | | 357 | reps = atoi(optarg); |
358 | break; | | 358 | break; |
359 | case 'C': | | 359 | case 'C': |
360 | todo |= POOLCACHESTAT; | | 360 | todo |= POOLCACHESTAT; |
361 | break; | | 361 | break; |
362 | case 'e': | | 362 | case 'e': |
363 | todo |= EVCNTSTAT; | | 363 | todo |= EVCNTSTAT; |
364 | break; | | 364 | break; |
365 | case 'f': | | 365 | case 'f': |
366 | todo |= FORKSTAT; | | 366 | todo |= FORKSTAT; |
367 | break; | | 367 | break; |
368 | case 'h': | | 368 | case 'h': |
369 | hashname = optarg; | | 369 | hashname = optarg; |
370 | /* FALLTHROUGH */ | | 370 | /* FALLTHROUGH */ |
371 | case 'H': | | 371 | case 'H': |
372 | todo |= HASHSTAT; | | 372 | todo |= HASHSTAT; |
373 | break; | | 373 | break; |
374 | case 'i': | | 374 | case 'i': |
375 | todo |= INTRSTAT; | | 375 | todo |= INTRSTAT; |
376 | break; | | 376 | break; |
377 | case 'l': | | 377 | case 'l': |
378 | todo |= HISTLIST; | | 378 | todo |= HISTLIST; |
379 | break; | | 379 | break; |
380 | case 'L': | | 380 | case 'L': |
381 | todo |= HASHLIST; | | 381 | todo |= HASHLIST; |
382 | break; | | 382 | break; |
383 | case 'M': | | 383 | case 'M': |
384 | memf = optarg; | | 384 | memf = optarg; |
385 | break; | | 385 | break; |
386 | case 'm': | | 386 | case 'm': |
387 | todo |= MEMSTAT; | | 387 | todo |= MEMSTAT; |
388 | break; | | 388 | break; |
389 | case 'N': | | 389 | case 'N': |
390 | nlistf = optarg; | | 390 | nlistf = optarg; |
391 | break; | | 391 | break; |
392 | case 's': | | 392 | case 's': |
393 | todo |= SUMSTAT; | | 393 | todo |= SUMSTAT; |
394 | break; | | 394 | break; |
395 | case 't': | | 395 | case 't': |
396 | todo |= VMTOTAL; | | 396 | todo |= VMTOTAL; |
397 | break; | | 397 | break; |
398 | case 'u': | | 398 | case 'u': |
399 | histname = optarg; | | 399 | histname = optarg; |
400 | /* FALLTHROUGH */ | | 400 | /* FALLTHROUGH */ |
401 | case 'U': | | 401 | case 'U': |
402 | todo |= HISTDUMP; | | 402 | todo |= HISTDUMP; |
403 | break; | | 403 | break; |
404 | case 'v': | | 404 | case 'v': |
405 | verbose++; | | 405 | verbose++; |
406 | break; | | 406 | break; |
407 | case 'W': | | 407 | case 'W': |
408 | wide++; | | 408 | wide++; |
409 | break; | | 409 | break; |
410 | case 'w': | | 410 | case 'w': |
411 | interval.tv_sec = atol(optarg); | | 411 | interval.tv_sec = atol(optarg); |
412 | break; | | 412 | break; |
413 | case '?': | | 413 | case '?': |
414 | default: | | 414 | default: |
415 | usage(); | | 415 | usage(); |
416 | } | | 416 | } |
417 | } | | 417 | } |
418 | argc -= optind; | | 418 | argc -= optind; |
419 | argv += optind; | | 419 | argv += optind; |
420 | | | 420 | |
421 | if (todo == 0) | | 421 | if (todo == 0) |
422 | todo = VMSTAT; | | 422 | todo = VMSTAT; |
423 | | | 423 | |
424 | /* | | 424 | /* |
425 | * Discard setgid privileges. If not the running kernel, we toss | | 425 | * Discard setgid privileges. If not the running kernel, we toss |
426 | * them away totally so that bad guys can't print interesting stuff | | 426 | * them away totally so that bad guys can't print interesting stuff |
427 | * from kernel memory, otherwise switch back to kmem for the | | 427 | * from kernel memory, otherwise switch back to kmem for the |
428 | * duration of the kvm_openfiles() call. | | 428 | * duration of the kvm_openfiles() call. |
429 | */ | | 429 | */ |
430 | if (nlistf != NULL || memf != NULL) | | 430 | if (nlistf != NULL || memf != NULL) |
431 | (void)setgid(getgid()); | | 431 | (void)setgid(getgid()); |
432 | else | | 432 | else |
433 | (void)setegid(egid); | | 433 | (void)setegid(egid); |
434 | | | 434 | |
435 | kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, kvm_errbuf); | | 435 | kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, kvm_errbuf); |
436 | if (kd == NULL) { | | 436 | if (kd == NULL) { |
437 | if (nlistf != NULL || memf != NULL) { | | 437 | if (nlistf != NULL || memf != NULL) { |
438 | errx(1, "kvm_openfiles: %s", kvm_errbuf); | | 438 | errx(1, "kvm_openfiles: %s", kvm_errbuf); |
439 | } | | 439 | } |
440 | } | | 440 | } |
441 | | | 441 | |
442 | if (nlistf == NULL && memf == NULL) | | 442 | if (nlistf == NULL && memf == NULL) |
443 | (void)setgid(getgid()); | | 443 | (void)setgid(getgid()); |
444 | | | 444 | |
445 | | | 445 | |
446 | if (todo & VMSTAT) { | | 446 | if (todo & VMSTAT) { |
447 | struct winsize winsize; | | 447 | struct winsize winsize; |
448 | | | 448 | |
449 | (void)drvinit(0);/* Initialize disk stats, no disks selected. */ | | 449 | (void)drvinit(0);/* Initialize disk stats, no disks selected. */ |
450 | | | 450 | |
451 | (void)setgid(getgid()); /* don't need privs anymore */ | | 451 | (void)setgid(getgid()); /* don't need privs anymore */ |
452 | | | 452 | |
453 | argv = choosedrives(argv); /* Select disks. */ | | 453 | argv = choosedrives(argv); /* Select disks. */ |
454 | winsize.ws_row = 0; | | 454 | winsize.ws_row = 0; |
455 | (void)ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize); | | 455 | (void)ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize); |
456 | if (winsize.ws_row > 0) | | 456 | if (winsize.ws_row > 0) |
457 | winlines = winsize.ws_row; | | 457 | winlines = winsize.ws_row; |
458 | | | 458 | |
459 | } | | 459 | } |
460 | | | 460 | |
461 | #ifdef BACKWARD_COMPATIBILITY | | 461 | #ifdef BACKWARD_COMPATIBILITY |
462 | if (*argv) { | | 462 | if (*argv) { |
463 | interval.tv_sec = atol(*argv); | | 463 | interval.tv_sec = atol(*argv); |
464 | if (*++argv) | | 464 | if (*++argv) |
465 | reps = atoi(*argv); | | 465 | reps = atoi(*argv); |
466 | } | | 466 | } |
467 | #endif | | 467 | #endif |
468 | | | 468 | |
469 | if (interval.tv_sec) { | | 469 | if (interval.tv_sec) { |
470 | if (!reps) | | 470 | if (!reps) |
471 | reps = -1; | | 471 | reps = -1; |
472 | } else if (reps) | | 472 | } else if (reps) |
473 | interval.tv_sec = 1; | | 473 | interval.tv_sec = 1; |
474 | | | 474 | |
475 | | | 475 | |
476 | getnlist(todo); | | 476 | getnlist(todo); |
477 | /* | | 477 | /* |
478 | * Statistics dumping is incompatible with the default | | 478 | * Statistics dumping is incompatible with the default |
479 | * VMSTAT/dovmstat() output. So perform the interval/reps handling | | 479 | * VMSTAT/dovmstat() output. So perform the interval/reps handling |
480 | * for it here. | | 480 | * for it here. |
481 | */ | | 481 | */ |
482 | if ((todo & (VMSTAT|VMTOTAL)) == 0) { | | 482 | if ((todo & (VMSTAT|VMTOTAL)) == 0) { |
483 | for (;;) { | | 483 | for (;;) { |
484 | if (todo & (HISTLIST|HISTDUMP)) { | | 484 | if (todo & (HISTLIST|HISTDUMP)) { |
485 | if ((todo & (HISTLIST|HISTDUMP)) == | | 485 | if ((todo & (HISTLIST|HISTDUMP)) == |
486 | (HISTLIST|HISTDUMP)) | | 486 | (HISTLIST|HISTDUMP)) |
487 | errx(1, "you may list or dump," | | 487 | errx(1, "you may list or dump," |
488 | " but not both!"); | | 488 | " but not both!"); |
489 | if (memf != NULL) | | 489 | if (memf != NULL) |
490 | hist_traverse(todo, histname); | | 490 | hist_traverse(todo, histname); |
491 | else | | 491 | else |
492 | hist_traverse_sysctl(todo, histname); | | 492 | hist_traverse_sysctl(todo, histname); |
493 | (void)putchar('\n'); | | 493 | (void)putchar('\n'); |
494 | } | | 494 | } |
495 | if (todo & FORKSTAT) { | | 495 | if (todo & FORKSTAT) { |
496 | doforkst(); | | 496 | doforkst(); |
497 | (void)putchar('\n'); | | 497 | (void)putchar('\n'); |
498 | } | | 498 | } |
499 | if (todo & MEMSTAT) { | | 499 | if (todo & MEMSTAT) { |
500 | dopool(verbose, wide); | | 500 | dopool(verbose, wide); |
501 | (void)putchar('\n'); | | 501 | (void)putchar('\n'); |
502 | } | | 502 | } |
503 | if (todo & POOLCACHESTAT) { | | 503 | if (todo & POOLCACHESTAT) { |
504 | dopoolcache(verbose); | | 504 | dopoolcache(verbose); |
505 | (void)putchar('\n'); | | 505 | (void)putchar('\n'); |
506 | } | | 506 | } |
507 | if (todo & SUMSTAT) { | | 507 | if (todo & SUMSTAT) { |
508 | dosum(); | | 508 | dosum(); |
509 | (void)putchar('\n'); | | 509 | (void)putchar('\n'); |
510 | } | | 510 | } |
511 | if (todo & INTRSTAT) { | | 511 | if (todo & INTRSTAT) { |
512 | dointr(verbose); | | 512 | dointr(verbose); |
513 | (void)putchar('\n'); | | 513 | (void)putchar('\n'); |
514 | } | | 514 | } |
515 | if (todo & EVCNTSTAT) { | | 515 | if (todo & EVCNTSTAT) { |
516 | doevcnt(verbose, EVCNT_TYPE_ANY); | | 516 | doevcnt(verbose, EVCNT_TYPE_ANY); |
517 | (void)putchar('\n'); | | 517 | (void)putchar('\n'); |
518 | } | | 518 | } |
519 | if (todo & (HASHLIST|HASHSTAT)) { | | 519 | if (todo & (HASHLIST|HASHSTAT)) { |
520 | if ((todo & (HASHLIST|HASHSTAT)) == | | 520 | if ((todo & (HASHLIST|HASHSTAT)) == |
521 | (HASHLIST|HASHSTAT)) | | 521 | (HASHLIST|HASHSTAT)) |
522 | errx(1, "you may list or display," | | 522 | errx(1, "you may list or display," |
523 | " but not both!"); | | 523 | " but not both!"); |
524 | dohashstat(verbose, todo, hashname); | | 524 | dohashstat(verbose, todo, hashname); |
525 | (void)putchar('\n'); | | 525 | (void)putchar('\n'); |
526 | } | | 526 | } |
527 | | | 527 | |
528 | fflush(stdout); | | 528 | fflush(stdout); |
529 | if (reps >= 0 && --reps <=0) | | 529 | if (reps >= 0 && --reps <=0) |
530 | break; | | 530 | break; |
531 | (void)nanosleep(&interval, NULL); | | 531 | (void)nanosleep(&interval, NULL); |
532 | } | | 532 | } |
533 | } else { | | 533 | } else { |
534 | if ((todo & (VMSTAT|VMTOTAL)) == (VMSTAT|VMTOTAL)) { | | 534 | if ((todo & (VMSTAT|VMTOTAL)) == (VMSTAT|VMTOTAL)) { |
535 | errx(1, "you may not both do vmstat and vmtotal"); | | 535 | errx(1, "you may not both do vmstat and vmtotal"); |
536 | } | | 536 | } |
537 | if (todo & VMSTAT) | | 537 | if (todo & VMSTAT) |
538 | dovmstat(&interval, reps); | | 538 | dovmstat(&interval, reps); |
539 | if (todo & VMTOTAL) | | 539 | if (todo & VMTOTAL) |
540 | dovmtotal(&interval, reps); | | 540 | dovmtotal(&interval, reps); |
541 | } | | 541 | } |
542 | return 0; | | 542 | return 0; |
543 | } | | 543 | } |
544 | | | 544 | |
545 | void | | 545 | void |
546 | getnlist(int todo) | | 546 | getnlist(int todo) |
547 | { | | 547 | { |
548 | static int namelist_done = 0; | | 548 | static int namelist_done = 0; |
549 | static int done = 0; | | 549 | static int done = 0; |
550 | int c; | | 550 | int c; |
551 | size_t i; | | 551 | size_t i; |
552 | | | 552 | |
553 | if (kd == NULL) | | 553 | if (kd == NULL) |
554 | errx(1, "kvm_openfiles: %s", kvm_errbuf); | | 554 | errx(1, "kvm_openfiles: %s", kvm_errbuf); |
555 | | | 555 | |
556 | if (!namelist_done) { | | 556 | if (!namelist_done) { |
557 | namelist_done = 1; | | 557 | namelist_done = 1; |
558 | if ((c = kvm_nlist(kd, namelist)) != 0) { | | 558 | if ((c = kvm_nlist(kd, namelist)) != 0) { |
559 | int doexit = 0; | | 559 | int doexit = 0; |
560 | if (c == -1) | | 560 | if (c == -1) |
561 | errx(1, "kvm_nlist: %s %s", | | 561 | errx(1, "kvm_nlist: %s %s", |
562 | "namelist", kvm_geterr(kd)); | | 562 | "namelist", kvm_geterr(kd)); |
563 | for (i = 0; i < __arraycount(namelist)-1; i++) | | 563 | for (i = 0; i < __arraycount(namelist)-1; i++) |
564 | if (namelist[i].n_type == 0) { | | 564 | if (namelist[i].n_type == 0) { |
565 | if (doexit++ == 0) | | 565 | if (doexit++ == 0) |
566 | (void)fprintf(stderr, | | 566 | (void)fprintf(stderr, |
567 | "%s: undefined symbols:", | | 567 | "%s: undefined symbols:", |
568 | getprogname()); | | 568 | getprogname()); |
569 | (void)fprintf(stderr, " %s", | | 569 | (void)fprintf(stderr, " %s", |
570 | namelist[i].n_name); | | 570 | namelist[i].n_name); |
571 | } | | 571 | } |
572 | if (doexit) { | | 572 | if (doexit) { |
573 | (void)fputc('\n', stderr); | | 573 | (void)fputc('\n', stderr); |
574 | exit(1); | | 574 | exit(1); |
575 | } | | 575 | } |
576 | } | | 576 | } |
577 | } | | 577 | } |
578 | if ((todo & (VMSTAT|INTRSTAT)) && !(done & (VMSTAT))) { | | 578 | if ((todo & (VMSTAT|INTRSTAT)) && !(done & (VMSTAT))) { |
579 | done |= VMSTAT; | | 579 | done |= VMSTAT; |
580 | if ((c = kvm_nlist(kd, timenl)) == -1 || c == X_TIMENL_SIZE) | | 580 | if ((c = kvm_nlist(kd, timenl)) == -1 || c == X_TIMENL_SIZE) |
581 | errx(1, "kvm_nlist: %s %s", "timenl", kvm_geterr(kd)); | | 581 | errx(1, "kvm_nlist: %s %s", "timenl", kvm_geterr(kd)); |
582 | } | | 582 | } |
583 | if ((todo & (SUMSTAT|INTRSTAT)) && !(done & (SUMSTAT|INTRSTAT))) { | | 583 | if ((todo & (SUMSTAT|INTRSTAT)) && !(done & (SUMSTAT|INTRSTAT))) { |
584 | done |= SUMSTAT|INTRSTAT; | | 584 | done |= SUMSTAT|INTRSTAT; |
585 | (void) kvm_nlist(kd, intrnl); | | 585 | (void) kvm_nlist(kd, intrnl); |
586 | } | | 586 | } |
587 | if ((todo & (HASHLIST|HASHSTAT)) && !(done & (HASHLIST|HASHSTAT))) { | | 587 | if ((todo & (HASHLIST|HASHSTAT)) && !(done & (HASHLIST|HASHSTAT))) { |
588 | done |= HASHLIST|HASHSTAT; | | 588 | done |= HASHLIST|HASHSTAT; |
589 | if ((c = kvm_nlist(kd, hashnl)) == -1 || c == X_HASHNL_SIZE) | | 589 | if ((c = kvm_nlist(kd, hashnl)) == -1 || c == X_HASHNL_SIZE) |
590 | errx(1, "kvm_nlist: %s %s", "hashnl", kvm_geterr(kd)); | | 590 | errx(1, "kvm_nlist: %s %s", "hashnl", kvm_geterr(kd)); |
591 | } | | 591 | } |
592 | if ((todo & (HISTLIST|HISTDUMP)) && !(done & (HISTLIST|HISTDUMP))) { | | 592 | if ((todo & (HISTLIST|HISTDUMP)) && !(done & (HISTLIST|HISTDUMP))) { |
593 | done |= HISTLIST|HISTDUMP; | | 593 | done |= HISTLIST|HISTDUMP; |
594 | if (kvm_nlist(kd, histnl) == -1) | | 594 | if (kvm_nlist(kd, histnl) == -1) |
595 | errx(1, "kvm_nlist: %s %s", "histnl", kvm_geterr(kd)); | | 595 | errx(1, "kvm_nlist: %s %s", "histnl", kvm_geterr(kd)); |
596 | } | | 596 | } |
597 | } | | 597 | } |
598 | | | 598 | |
599 | char ** | | 599 | char ** |
600 | choosedrives(char **argv) | | 600 | choosedrives(char **argv) |
601 | { | | 601 | { |
602 | size_t i; | | 602 | size_t i; |
603 | | | 603 | |
604 | /* | | 604 | /* |
605 | * Choose drives to be displayed. Priority goes to (in order) drives | | 605 | * Choose drives to be displayed. Priority goes to (in order) drives |
606 | * supplied as arguments, default drives. If everything isn't filled | | 606 | * supplied as arguments, default drives. If everything isn't filled |
607 | * in and there are drives not taken care of, display the first few | | 607 | * in and there are drives not taken care of, display the first few |
608 | * that fit. | | 608 | * that fit. |
609 | */ | | 609 | */ |
610 | #define BACKWARD_COMPATIBILITY | | 610 | #define BACKWARD_COMPATIBILITY |
611 | for (ndrives = 0; *argv; ++argv) { | | 611 | for (ndrives = 0; *argv; ++argv) { |
612 | #ifdef BACKWARD_COMPATIBILITY | | 612 | #ifdef BACKWARD_COMPATIBILITY |
613 | if (isdigit((unsigned char)**argv)) | | 613 | if (isdigit((unsigned char)**argv)) |
614 | break; | | 614 | break; |
615 | #endif | | 615 | #endif |
616 | for (i = 0; i < ndrive; i++) { | | 616 | for (i = 0; i < ndrive; i++) { |
617 | if (strcmp(dr_name[i], *argv)) | | 617 | if (strcmp(dr_name[i], *argv)) |
618 | continue; | | 618 | continue; |
619 | drv_select[i] = 1; | | 619 | drv_select[i] = 1; |
620 | ++ndrives; | | 620 | ++ndrives; |
621 | break; | | 621 | break; |
622 | } | | 622 | } |
623 | } | | 623 | } |
624 | for (i = 0; i < ndrive && ndrives < 2; i++) { | | 624 | for (i = 0; i < ndrive && ndrives < 2; i++) { |
625 | if (drv_select[i]) | | 625 | if (drv_select[i]) |
626 | continue; | | 626 | continue; |
627 | drv_select[i] = 1; | | 627 | drv_select[i] = 1; |
628 | ++ndrives; | | 628 | ++ndrives; |
629 | } | | 629 | } |
630 | | | 630 | |
631 | return (argv); | | 631 | return (argv); |
632 | } | | 632 | } |
633 | | | 633 | |
634 | long | | 634 | long |
635 | getuptime(void) | | 635 | getuptime(void) |
636 | { | | 636 | { |
637 | static struct timespec boottime; | | 637 | static struct timespec boottime; |
638 | struct timespec now; | | 638 | struct timespec now; |
639 | time_t uptime, nowsec; | | 639 | time_t uptime, nowsec; |
640 | | | 640 | |
641 | if (memf == NULL) { | | 641 | if (memf == NULL) { |
642 | if (boottime.tv_sec == 0) { | | 642 | if (boottime.tv_sec == 0) { |
643 | size_t buflen = sizeof(boottime); | | 643 | size_t buflen = sizeof(boottime); |
644 | if (sysctl(boottime_mib, __arraycount(boottime_mib), | | 644 | if (sysctl(boottime_mib, __arraycount(boottime_mib), |
645 | &boottime, &buflen, NULL, 0) == -1) | | 645 | &boottime, &buflen, NULL, 0) == -1) |
646 | warn("Can't get boottime"); | | 646 | warn("Can't get boottime"); |
647 | } | | 647 | } |
648 | clock_gettime(CLOCK_REALTIME, &now); | | 648 | clock_gettime(CLOCK_REALTIME, &now); |
649 | } else { | | 649 | } else { |
650 | if (boottime.tv_sec == 0) { | | 650 | if (boottime.tv_sec == 0) { |
651 | struct bintime bt; | | 651 | struct bintime bt; |
652 | | | 652 | |
653 | kread(timenl, X_TIMEBASEBIN, &bt, sizeof(bt)); | | 653 | kread(timenl, X_TIMEBASEBIN, &bt, sizeof(bt)); |
654 | bintime2timespec(&bt, &boottime); | | 654 | bintime2timespec(&bt, &boottime); |
655 | } | | 655 | } |
656 | if (kreadc(timenl, X_TIME_SECOND, &nowsec, sizeof(nowsec))) { | | 656 | if (kreadc(timenl, X_TIME_SECOND, &nowsec, sizeof(nowsec))) { |
657 | /* | | 657 | /* |
658 | * XXX this assignment dance can be removed once | | 658 | * XXX this assignment dance can be removed once |
659 | * timeval tv_sec is SUS mandated time_t | | 659 | * timeval tv_sec is SUS mandated time_t |
660 | */ | | 660 | */ |
661 | now.tv_sec = nowsec; | | 661 | now.tv_sec = nowsec; |
662 | now.tv_nsec = 0; | | 662 | now.tv_nsec = 0; |
663 | } else { | | 663 | } else { |
664 | kread(timenl, X_TIME, &now, sizeof(now)); | | 664 | kread(timenl, X_TIME, &now, sizeof(now)); |
665 | } | | 665 | } |
666 | } | | 666 | } |
667 | uptime = now.tv_sec - boottime.tv_sec; | | 667 | uptime = now.tv_sec - boottime.tv_sec; |
668 | if (uptime <= 0 || uptime > 60*60*24*365*10) | | 668 | if (uptime <= 0 || uptime > 60*60*24*365*10) |
669 | errx(1, "time makes no sense; namelist must be wrong."); | | 669 | errx(1, "time makes no sense; namelist must be wrong."); |
670 | return (uptime); | | 670 | return (uptime); |
671 | } | | 671 | } |
672 | | | 672 | |
673 | int hz, hdrcnt; | | 673 | int hz, hdrcnt; |
674 | | | 674 | |
675 | void | | 675 | void |
676 | print_total_hdr(void) | | 676 | print_total_hdr(void) |
677 | { | | 677 | { |
678 | | | 678 | |
679 | (void)printf("procs memory\n"); | | 679 | (void)printf("procs memory\n"); |
680 | (void)printf("ru dw pw sl"); | | 680 | (void)printf("ru dw pw sl"); |
681 | (void)printf(" total-v active-v active-r"); | | 681 | (void)printf(" total-v active-v active-r"); |
682 | (void)printf(" vm-sh avm-sh rm-sh arm-sh free\n"); | | 682 | (void)printf(" vm-sh avm-sh rm-sh arm-sh free\n"); |
683 | hdrcnt = winlines - 2; | | 683 | hdrcnt = winlines - 2; |
684 | } | | 684 | } |
685 | | | 685 | |
686 | void | | 686 | void |
687 | dovmtotal(struct timespec *interval, int reps) | | 687 | dovmtotal(struct timespec *interval, int reps) |
688 | { | | 688 | { |
689 | struct vmtotal total; | | 689 | struct vmtotal total; |
690 | size_t size; | | 690 | size_t size; |
691 | | | 691 | |
692 | (void)signal(SIGCONT, needhdr); | | 692 | (void)signal(SIGCONT, needhdr); |
693 | | | 693 | |
694 | for (hdrcnt = 1;;) { | | 694 | for (hdrcnt = 1;;) { |
695 | if (!--hdrcnt) | | 695 | if (!--hdrcnt) |
696 | print_total_hdr(); | | 696 | print_total_hdr(); |
697 | if (memf != NULL) { | | 697 | if (memf != NULL) { |
698 | warnx("Unable to get vmtotals from crash dump."); | | 698 | warnx("Unable to get vmtotals from crash dump."); |
699 | (void)memset(&total, 0, sizeof(total)); | | 699 | (void)memset(&total, 0, sizeof(total)); |
700 | } else { | | 700 | } else { |
701 | size = sizeof(total); | | 701 | size = sizeof(total); |
702 | if (sysctl(vmmeter_mib, __arraycount(vmmeter_mib), | | 702 | if (sysctl(vmmeter_mib, __arraycount(vmmeter_mib), |
703 | &total, &size, NULL, 0) == -1) { | | 703 | &total, &size, NULL, 0) == -1) { |
704 | warn("Can't get vmtotals"); | | 704 | warn("Can't get vmtotals"); |
705 | (void)memset(&total, 0, sizeof(total)); | | 705 | (void)memset(&total, 0, sizeof(total)); |
706 | } | | 706 | } |
707 | } | | 707 | } |
708 | (void)printf("%2d ", total.t_rq); | | 708 | (void)printf("%2d ", total.t_rq); |
709 | (void)printf("%2d ", total.t_dw); | | 709 | (void)printf("%2d ", total.t_dw); |
710 | (void)printf("%2d ", total.t_pw); | | 710 | (void)printf("%2d ", total.t_pw); |
711 | (void)printf("%2d ", total.t_sl); | | 711 | (void)printf("%2d ", total.t_sl); |
712 | | | 712 | |
713 | (void)printf("%9d ", total.t_vm); | | 713 | (void)printf("%9d ", total.t_vm); |
714 | (void)printf("%9d ", total.t_avm); | | 714 | (void)printf("%9d ", total.t_avm); |
715 | (void)printf("%9d ", total.t_arm); | | 715 | (void)printf("%9d ", total.t_arm); |
716 | (void)printf("%5d ", total.t_vmshr); | | 716 | (void)printf("%5d ", total.t_vmshr); |
717 | (void)printf("%6d ", total.t_avmshr); | | 717 | (void)printf("%6d ", total.t_avmshr); |
718 | (void)printf("%5d ", total.t_rmshr); | | 718 | (void)printf("%5d ", total.t_rmshr); |
719 | (void)printf("%6d ", total.t_armshr); | | 719 | (void)printf("%6d ", total.t_armshr); |
720 | (void)printf("%5d", total.t_free); | | 720 | (void)printf("%5d", total.t_free); |
721 | | | 721 | |
722 | (void)putchar('\n'); | | 722 | (void)putchar('\n'); |
723 | | | 723 | |
724 | (void)fflush(stdout); | | 724 | (void)fflush(stdout); |
725 | if (reps >= 0 && --reps <= 0) | | 725 | if (reps >= 0 && --reps <= 0) |
726 | break; | | 726 | break; |
727 | | | 727 | |
728 | (void)nanosleep(interval, NULL); | | 728 | (void)nanosleep(interval, NULL); |
729 | } | | 729 | } |
730 | } | | 730 | } |
731 | | | 731 | |
732 | void | | 732 | void |
733 | dovmstat(struct timespec *interval, int reps) | | 733 | dovmstat(struct timespec *interval, int reps) |
734 | { | | 734 | { |
735 | struct vmtotal total; | | 735 | struct vmtotal total; |
736 | time_t uptime, halfuptime; | | 736 | time_t uptime, halfuptime; |
737 | size_t size; | | 737 | size_t size; |
738 | int pagesize = getpagesize(); | | 738 | int pagesize = getpagesize(); |
739 | int ovflw; | | 739 | int ovflw; |
740 | | | 740 | |
741 | uptime = getuptime(); | | 741 | uptime = getuptime(); |
742 | halfuptime = uptime / 2; | | 742 | halfuptime = uptime / 2; |
743 | (void)signal(SIGCONT, needhdr); | | 743 | (void)signal(SIGCONT, needhdr); |
744 | | | 744 | |
745 | if (memf != NULL) { | | 745 | if (memf != NULL) { |
746 | if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0) | | 746 | if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0) |
747 | kread(namelist, X_STATHZ, &hz, sizeof(hz)); | | 747 | kread(namelist, X_STATHZ, &hz, sizeof(hz)); |
748 | if (!hz) | | 748 | if (!hz) |
749 | kread(namelist, X_HZ, &hz, sizeof(hz)); | | 749 | kread(namelist, X_HZ, &hz, sizeof(hz)); |
750 | } else { | | 750 | } else { |
751 | struct clockinfo clockinfo; | | 751 | struct clockinfo clockinfo; |
752 | size = sizeof(clockinfo); | | 752 | size = sizeof(clockinfo); |
753 | if (sysctl(clockrate_mib, 2, &clockinfo, &size, NULL, 0) == -1) | | 753 | if (sysctl(clockrate_mib, 2, &clockinfo, &size, NULL, 0) == -1) |
754 | err(1, "sysctl kern.clockrate failed"); | | 754 | err(1, "sysctl kern.clockrate failed"); |
755 | hz = clockinfo.stathz; | | 755 | hz = clockinfo.stathz; |
756 | if (!hz) | | 756 | if (!hz) |
757 | hz = clockinfo.hz; | | 757 | hz = clockinfo.hz; |
758 | } | | 758 | } |
759 | | | 759 | |
760 | for (hdrcnt = 1;;) { | | 760 | for (hdrcnt = 1;;) { |
761 | if (!--hdrcnt) | | 761 | if (!--hdrcnt) |
762 | printhdr(); | | 762 | printhdr(); |
763 | /* Read new disk statistics */ | | 763 | /* Read new disk statistics */ |
764 | cpureadstats(); | | 764 | cpureadstats(); |
765 | drvreadstats(); | | 765 | drvreadstats(); |
766 | tkreadstats(); | | 766 | tkreadstats(); |
767 | if (memf != NULL) { | | 767 | if (memf != NULL) { |
768 | struct uvmexp uvmexp_kernel; | | 768 | struct uvmexp uvmexp_kernel; |
769 | /* | | 769 | /* |
770 | * XXX Can't do this if we're reading a crash | | 770 | * XXX Can't do this if we're reading a crash |
771 | * XXX dump because they're lazily-calculated. | | 771 | * XXX dump because they're lazily-calculated. |
772 | */ | | 772 | */ |
773 | warnx("Unable to get vmtotals from crash dump."); | | 773 | warnx("Unable to get vmtotals from crash dump."); |
774 | (void)memset(&total, 0, sizeof(total)); | | 774 | (void)memset(&total, 0, sizeof(total)); |
775 | kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel)); | | 775 | kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel)); |
776 | #define COPY(field) uvmexp.field = uvmexp_kernel.field | | 776 | #define COPY(field) uvmexp.field = uvmexp_kernel.field |
777 | COPY(pdreact); | | 777 | COPY(pdreact); |
778 | COPY(pageins); | | 778 | COPY(pageins); |
779 | COPY(pgswapout); | | 779 | COPY(pgswapout); |
780 | COPY(pdfreed); | | 780 | COPY(pdfreed); |
781 | COPY(pdscans); | | 781 | COPY(pdscans); |
782 | #undef COPY | | 782 | #undef COPY |
783 | } else { | | 783 | } else { |
784 | size = sizeof(total); | | 784 | size = sizeof(total); |
785 | if (sysctl(vmmeter_mib, __arraycount(vmmeter_mib), | | 785 | if (sysctl(vmmeter_mib, __arraycount(vmmeter_mib), |
786 | &total, &size, NULL, 0) == -1) { | | 786 | &total, &size, NULL, 0) == -1) { |
787 | warn("Can't get vmtotals"); | | 787 | warn("Can't get vmtotals"); |
788 | (void)memset(&total, 0, sizeof(total)); | | 788 | (void)memset(&total, 0, sizeof(total)); |
789 | } | | 789 | } |
790 | size = sizeof(uvmexp); | | 790 | size = sizeof(uvmexp); |
791 | if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp, | | 791 | if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp, |
792 | &size, NULL, 0) == -1) | | 792 | &size, NULL, 0) == -1) |
793 | warn("sysctl vm.uvmexp2 failed"); | | 793 | warn("sysctl vm.uvmexp2 failed"); |
794 | } | | 794 | } |
795 | cpucounters(&cpucounter); | | 795 | cpucounters(&cpucounter); |
796 | ovflw = 0; | | 796 | ovflw = 0; |
797 | PRWORD(ovflw, " %*d", 2, 1, total.t_rq - 1); | | 797 | PRWORD(ovflw, " %*d", 2, 1, total.t_rq - 1); |
798 | PRWORD(ovflw, " %*d", 2, 1, total.t_dw + total.t_pw); | | 798 | PRWORD(ovflw, " %*d", 2, 1, total.t_dw + total.t_pw); |
799 | #define pgtok(a) (long)((a) * ((uint32_t)pagesize >> 10)) | | 799 | #define pgtok(a) (long)((a) * ((uint32_t)pagesize >> 10)) |
800 | #define rate(x) (u_long)(((x) + halfuptime) / uptime) /* round */ | | 800 | #define rate(x) (u_long)(((x) + halfuptime) / uptime) /* round */ |
801 | PRWORD(ovflw, " %*ld", 9, 1, pgtok(total.t_avm)); | | 801 | PRWORD(ovflw, " %*ld", 9, 1, pgtok(total.t_avm)); |
802 | PRWORD(ovflw, " %*ld", 7, 1, pgtok(total.t_free)); | | 802 | PRWORD(ovflw, " %*ld", 7, 1, pgtok(total.t_free)); |
803 | PRWORD(ovflw, " %*ld", 5, 1, | | 803 | PRWORD(ovflw, " %*ld", 5, 1, |
804 | rate(cpucounter.nfault - ocpucounter.nfault)); | | 804 | rate(cpucounter.nfault - ocpucounter.nfault)); |
805 | PRWORD(ovflw, " %*ld", 4, 1, | | 805 | PRWORD(ovflw, " %*ld", 4, 1, |
806 | rate(uvmexp.pdreact - ouvmexp.pdreact)); | | 806 | rate(uvmexp.pdreact - ouvmexp.pdreact)); |
807 | PRWORD(ovflw, " %*ld", 4, 1, | | 807 | PRWORD(ovflw, " %*ld", 4, 1, |
808 | rate(uvmexp.pageins - ouvmexp.pageins)); | | 808 | rate(uvmexp.pageins - ouvmexp.pageins)); |
809 | PRWORD(ovflw, " %*ld", 5, 1, | | 809 | PRWORD(ovflw, " %*ld", 5, 1, |
810 | rate(uvmexp.pgswapout - ouvmexp.pgswapout)); | | 810 | rate(uvmexp.pgswapout - ouvmexp.pgswapout)); |
811 | PRWORD(ovflw, " %*ld", 5, 1, | | 811 | PRWORD(ovflw, " %*ld", 5, 1, |
812 | rate(uvmexp.pdfreed - ouvmexp.pdfreed)); | | 812 | rate(uvmexp.pdfreed - ouvmexp.pdfreed)); |
813 | PRWORD(ovflw, " %*ld", 6, 2, | | 813 | PRWORD(ovflw, " %*ld", 6, 2, |
814 | rate(uvmexp.pdscans - ouvmexp.pdscans)); | | 814 | rate(uvmexp.pdscans - ouvmexp.pdscans)); |
815 | drvstats(&ovflw); | | 815 | drvstats(&ovflw); |
816 | PRWORD(ovflw, " %*ld", 5, 1, | | 816 | PRWORD(ovflw, " %*ld", 5, 1, |
817 | rate(cpucounter.nintr - ocpucounter.nintr)); | | 817 | rate(cpucounter.nintr - ocpucounter.nintr)); |
818 | PRWORD(ovflw, " %*ld", 5, 1, | | 818 | PRWORD(ovflw, " %*ld", 5, 1, |
819 | rate(cpucounter.nsyscall - ocpucounter.nsyscall)); | | 819 | rate(cpucounter.nsyscall - ocpucounter.nsyscall)); |
820 | PRWORD(ovflw, " %*ld", 4, 1, | | 820 | PRWORD(ovflw, " %*ld", 4, 1, |
821 | rate(cpucounter.nswtch - ocpucounter.nswtch)); | | 821 | rate(cpucounter.nswtch - ocpucounter.nswtch)); |
822 | cpustats(&ovflw); | | 822 | cpustats(&ovflw); |
823 | (void)putchar('\n'); | | 823 | (void)putchar('\n'); |
824 | (void)fflush(stdout); | | 824 | (void)fflush(stdout); |
825 | if (reps >= 0 && --reps <= 0) | | 825 | if (reps >= 0 && --reps <= 0) |
826 | break; | | 826 | break; |
827 | ouvmexp = uvmexp; | | 827 | ouvmexp = uvmexp; |
828 | ocpucounter = cpucounter; | | 828 | ocpucounter = cpucounter; |
829 | uptime = interval->tv_sec; | | 829 | uptime = interval->tv_sec; |
830 | /* | | 830 | /* |
831 | * We round upward to avoid losing low-frequency events | | 831 | * We round upward to avoid losing low-frequency events |
832 | * (i.e., >= 1 per interval but < 1 per second). | | 832 | * (i.e., >= 1 per interval but < 1 per second). |
833 | */ | | 833 | */ |
834 | halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2; | | 834 | halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2; |
835 | (void)nanosleep(interval, NULL); | | 835 | (void)nanosleep(interval, NULL); |
836 | } | | 836 | } |
837 | } | | 837 | } |
838 | | | 838 | |
839 | void | | 839 | void |
840 | printhdr(void) | | 840 | printhdr(void) |
841 | { | | 841 | { |
842 | size_t i; | | 842 | size_t i; |
843 | | | 843 | |
844 | (void)printf(" procs memory page%*s", 23, ""); | | 844 | (void)printf(" procs memory page%*s", 23, ""); |
845 | if (ndrives > 0) | | 845 | if (ndrives > 0) |
846 | (void)printf("%s %*sfaults cpu\n", | | 846 | (void)printf("%s %*sfaults cpu\n", |
847 | ((ndrives > 1) ? "disks" : "disk"), | | 847 | ((ndrives > 1) ? "disks" : "disk"), |
848 | ((ndrives > 1) ? ndrives * 3 - 4 : 0), ""); | | 848 | ((ndrives > 1) ? ndrives * 3 - 4 : 0), ""); |
849 | else | | 849 | else |
850 | (void)printf("%*s faults cpu\n", | | 850 | (void)printf("%*s faults cpu\n", |
851 | ndrives * 3, ""); | | 851 | ndrives * 3, ""); |
852 | | | 852 | |
853 | (void)printf(" r b avm fre flt re pi po fr sr "); | | 853 | (void)printf(" r b avm fre flt re pi po fr sr "); |
854 | for (i = 0; i < ndrive; i++) | | 854 | for (i = 0; i < ndrive; i++) |
855 | if (drv_select[i]) | | 855 | if (drv_select[i]) |
856 | (void)printf("%c%c ", dr_name[i][0], | | 856 | (void)printf("%c%c ", dr_name[i][0], |
857 | dr_name[i][strlen(dr_name[i]) - 1]); | | 857 | dr_name[i][strlen(dr_name[i]) - 1]); |
858 | (void)printf(" in sy cs us sy id\n"); | | 858 | (void)printf(" in sy cs us sy id\n"); |
859 | hdrcnt = winlines - 2; | | 859 | hdrcnt = winlines - 2; |
860 | } | | 860 | } |
861 | | | 861 | |
862 | /* | | 862 | /* |
863 | * Force a header to be prepended to the next output. | | 863 | * Force a header to be prepended to the next output. |
864 | */ | | 864 | */ |
865 | void | | 865 | void |
866 | /*ARGSUSED*/ | | 866 | /*ARGSUSED*/ |
867 | needhdr(int dummy) | | 867 | needhdr(int dummy) |
868 | { | | 868 | { |
869 | | | 869 | |
870 | hdrcnt = 1; | | 870 | hdrcnt = 1; |
871 | } | | 871 | } |
872 | | | 872 | |
873 | long | | 873 | long |
874 | pct(u_long top, u_long bot) | | 874 | pct(u_long top, u_long bot) |
875 | { | | 875 | { |
876 | long ans; | | 876 | long ans; |
877 | | | 877 | |
878 | if (bot == 0) | | 878 | if (bot == 0) |
879 | return (0); | | 879 | return (0); |
880 | ans = (long)((quad_t)top * 100 / bot); | | 880 | ans = (long)((quad_t)top * 100 / bot); |
881 | return (ans); | | 881 | return (ans); |
882 | } | | 882 | } |
883 | | | 883 | |
884 | #define PCT(top, bot) (int)pct((u_long)(top), (u_long)(bot)) | | 884 | #define PCT(top, bot) (int)pct((u_long)(top), (u_long)(bot)) |
885 | | | 885 | |
886 | void | | 886 | void |
887 | dosum(void) | | 887 | dosum(void) |
888 | { | | 888 | { |
889 | struct nchstats nch_stats; | | 889 | struct nchstats nch_stats; |
890 | uint64_t nchtotal; | | 890 | uint64_t nchtotal; |
891 | size_t ssize; | | 891 | size_t ssize; |
892 | int active_kernel; | | 892 | int active_kernel; |
893 | struct cpu_counter cc; | | 893 | struct cpu_counter cc; |
894 | | | 894 | |
895 | /* | | 895 | /* |
896 | * The "active" and "inactive" variables | | 896 | * The "active" and "inactive" variables |
897 | * are now estimated by the kernel and sadly | | 897 | * are now estimated by the kernel and sadly |
898 | * can not easily be dug out of a crash dump. | | 898 | * can not easily be dug out of a crash dump. |
899 | */ | | 899 | */ |
900 | ssize = sizeof(uvmexp); | | 900 | ssize = sizeof(uvmexp); |
901 | memset(&uvmexp, 0, ssize); | | 901 | memset(&uvmexp, 0, ssize); |
902 | active_kernel = (memf == NULL); | | 902 | active_kernel = (memf == NULL); |
903 | if (active_kernel) { | | 903 | if (active_kernel) { |
904 | /* only on active kernel */ | | 904 | /* only on active kernel */ |
905 | if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp, | | 905 | if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp, |
906 | &ssize, NULL, 0) == -1) | | 906 | &ssize, NULL, 0) == -1) |
907 | warn("sysctl vm.uvmexp2 failed"); | | 907 | warn("sysctl vm.uvmexp2 failed"); |
908 | } else { | | 908 | } else { |
909 | struct uvmexp uvmexp_kernel; | | 909 | struct uvmexp uvmexp_kernel; |
910 | struct pool pool, *pp = &pool; | | 910 | struct pool pool, *pp = &pool; |
911 | struct pool_allocator pa; | | 911 | struct pool_allocator pa; |
912 | TAILQ_HEAD(,pool) pool_head; | | 912 | TAILQ_HEAD(,pool) pool_head; |
913 | void *addr; | | 913 | void *addr; |
914 | uint64_t bytes; | | 914 | uint64_t bytes; |
915 | | | 915 | |
916 | kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel)); | | 916 | kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel)); |
917 | #define COPY(field) uvmexp.field = uvmexp_kernel.field | | 917 | #define COPY(field) uvmexp.field = uvmexp_kernel.field |
918 | COPY(pagesize); | | 918 | COPY(pagesize); |
919 | COPY(ncolors); | | 919 | COPY(ncolors); |
920 | COPY(npages); | | 920 | COPY(npages); |
921 | COPY(free); | | 921 | COPY(free); |
922 | COPY(paging); | | 922 | COPY(paging); |
923 | COPY(wired); | | 923 | COPY(wired); |
924 | COPY(reserve_pagedaemon); | | 924 | COPY(reserve_pagedaemon); |
925 | COPY(reserve_kernel); | | 925 | COPY(reserve_kernel); |
926 | COPY(anonpages); | | 926 | COPY(anonpages); |
927 | COPY(filepages); | | 927 | COPY(filepages); |
928 | COPY(execpages); | | 928 | COPY(execpages); |
929 | COPY(freemin); | | 929 | COPY(freemin); |
930 | COPY(freetarg); | | 930 | COPY(freetarg); |
931 | COPY(wiredmax); | | 931 | COPY(wiredmax); |
932 | COPY(nswapdev); | | 932 | COPY(nswapdev); |
933 | COPY(swpages); | | 933 | COPY(swpages); |
934 | COPY(swpginuse); | | 934 | COPY(swpginuse); |
935 | COPY(nswget); | | 935 | COPY(nswget); |
936 | COPY(pageins); | | 936 | COPY(pageins); |
937 | COPY(pdpageouts); | | 937 | COPY(pdpageouts); |
938 | COPY(pgswapin); | | 938 | COPY(pgswapin); |
939 | COPY(pgswapout); | | 939 | COPY(pgswapout); |
940 | COPY(forks); | | 940 | COPY(forks); |
941 | COPY(forks_ppwait); | | 941 | COPY(forks_ppwait); |
942 | COPY(forks_sharevm); | | 942 | COPY(forks_sharevm); |
943 | COPY(colorhit); | | 943 | COPY(colorhit); |
944 | COPY(colormiss); | | 944 | COPY(colormiss); |
945 | COPY(cpuhit); | | 945 | COPY(cpuhit); |
946 | COPY(cpumiss); | | 946 | COPY(cpumiss); |
947 | COPY(fltnoram); | | 947 | COPY(fltnoram); |
948 | COPY(fltnoanon); | | 948 | COPY(fltnoanon); |
949 | COPY(fltpgwait); | | 949 | COPY(fltpgwait); |
950 | COPY(fltpgrele); | | 950 | COPY(fltpgrele); |
951 | COPY(fltrelck); | | 951 | COPY(fltrelck); |
952 | COPY(fltrelckok); | | 952 | COPY(fltrelckok); |
953 | COPY(fltanget); | | 953 | COPY(fltanget); |
954 | COPY(fltanretry); | | 954 | COPY(fltanretry); |
955 | COPY(fltamcopy); | | 955 | COPY(fltamcopy); |
956 | COPY(fltamcopy); | | 956 | COPY(fltamcopy); |
957 | COPY(fltnomap); | | 957 | COPY(fltnomap); |
958 | COPY(fltlget); | | 958 | COPY(fltlget); |
959 | COPY(fltget); | | 959 | COPY(fltget); |
960 | COPY(flt_anon); | | 960 | COPY(flt_anon); |
961 | COPY(flt_acow); | | 961 | COPY(flt_acow); |
962 | COPY(flt_obj); | | 962 | COPY(flt_obj); |
963 | COPY(flt_prcopy); | | 963 | COPY(flt_prcopy); |
964 | COPY(flt_przero); | | 964 | COPY(flt_przero); |
965 | COPY(pdwoke); | | 965 | COPY(pdwoke); |
966 | COPY(pdrevs); | | 966 | COPY(pdrevs); |
967 | COPY(pdfreed); | | 967 | COPY(pdfreed); |
968 | COPY(pdscans); | | 968 | COPY(pdscans); |
969 | COPY(pdanscan); | | 969 | COPY(pdanscan); |
970 | COPY(pdobscan); | | 970 | COPY(pdobscan); |
971 | COPY(pdreact); | | 971 | COPY(pdreact); |
972 | COPY(pdbusy); | | 972 | COPY(pdbusy); |
973 | COPY(pdpending); | | 973 | COPY(pdpending); |
974 | COPY(pddeact); | | 974 | COPY(pddeact); |
975 | COPY(bootpages); | | 975 | COPY(bootpages); |
976 | #undef COPY | | 976 | #undef COPY |
977 | kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head)); | | 977 | kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head)); |
978 | addr = TAILQ_FIRST(&pool_head); | | 978 | addr = TAILQ_FIRST(&pool_head); |
979 | uvmexp.poolpages = 0; | | 979 | uvmexp.poolpages = 0; |
980 | for (; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist)) { | | 980 | for (; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist)) { |
981 | deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed"); | | 981 | deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed"); |
982 | deref_kptr(pp->pr_alloc, &pa, sizeof(pa), | | 982 | deref_kptr(pp->pr_alloc, &pa, sizeof(pa), |
983 | "pool allocator trashed"); | | 983 | "pool allocator trashed"); |
984 | bytes = pp->pr_npages * pa.pa_pagesz; | | 984 | bytes = pp->pr_npages * pa.pa_pagesz; |
985 | if ((pp->pr_roflags & PR_RECURSIVE) != 0) | | 985 | if ((pp->pr_roflags & PR_RECURSIVE) != 0) |
986 | bytes -= (pp->pr_nout * pp->pr_size); | | 986 | bytes -= (pp->pr_nout * pp->pr_size); |
987 | uvmexp.poolpages += bytes / uvmexp.pagesize; | | 987 | uvmexp.poolpages += bytes / uvmexp.pagesize; |
988 | } | | 988 | } |
989 | } | | 989 | } |
990 | | | 990 | |
991 | | | 991 | |
992 | (void)printf("%9" PRIu64 " bytes per page\n", uvmexp.pagesize); | | 992 | (void)printf("%9" PRIu64 " bytes per page\n", uvmexp.pagesize); |
993 | | | 993 | |
994 | (void)printf("%9" PRIu64 " page color%s\n", | | 994 | (void)printf("%9" PRIu64 " page color%s\n", |
995 | uvmexp.ncolors, uvmexp.ncolors == 1 ? "" : "s"); | | 995 | uvmexp.ncolors, uvmexp.ncolors == 1 ? "" : "s"); |
996 | | | 996 | |
997 | (void)printf("%9" PRIu64 " pages managed\n", uvmexp.npages); | | 997 | (void)printf("%9" PRIu64 " pages managed\n", uvmexp.npages); |
998 | (void)printf("%9" PRIu64 " pages free\n", uvmexp.free); | | 998 | (void)printf("%9" PRIu64 " pages free\n", uvmexp.free); |
999 | if (active_kernel) { | | 999 | if (active_kernel) { |
1000 | (void)printf("%9" PRIu64 " pages active\n", uvmexp.active); | | 1000 | (void)printf("%9" PRIu64 " pages active\n", uvmexp.active); |
1001 | (void)printf("%9" PRIu64 " pages inactive\n", uvmexp.inactive); | | 1001 | (void)printf("%9" PRIu64 " pages inactive\n", uvmexp.inactive); |
1002 | } | | 1002 | } |
1003 | (void)printf("%9" PRIu64 " pages paging\n", uvmexp.paging); | | 1003 | (void)printf("%9" PRIu64 " pages paging\n", uvmexp.paging); |
1004 | (void)printf("%9" PRIu64 " pages wired\n", uvmexp.wired); | | 1004 | (void)printf("%9" PRIu64 " pages wired\n", uvmexp.wired); |
1005 | (void)printf("%9" PRIu64 " reserve pagedaemon pages\n", | | 1005 | (void)printf("%9" PRIu64 " reserve pagedaemon pages\n", |
1006 | uvmexp.reserve_pagedaemon); | | 1006 | uvmexp.reserve_pagedaemon); |
1007 | (void)printf("%9" PRIu64 " reserve kernel pages\n", uvmexp.reserve_kernel); | | 1007 | (void)printf("%9" PRIu64 " reserve kernel pages\n", uvmexp.reserve_kernel); |
1008 | (void)printf("%9" PRIu64 " boot kernel pages\n", uvmexp.bootpages); | | 1008 | (void)printf("%9" PRIu64 " boot kernel pages\n", uvmexp.bootpages); |
1009 | (void)printf("%9" PRIu64 " kernel pool pages\n", uvmexp.poolpages); | | 1009 | (void)printf("%9" PRIu64 " kernel pool pages\n", uvmexp.poolpages); |
1010 | (void)printf("%9" PRIu64 " anonymous pages\n", uvmexp.anonpages); | | 1010 | (void)printf("%9" PRIu64 " anonymous pages\n", uvmexp.anonpages); |
1011 | (void)printf("%9" PRIu64 " cached file pages\n", uvmexp.filepages); | | 1011 | (void)printf("%9" PRIu64 " cached file pages\n", uvmexp.filepages); |
1012 | (void)printf("%9" PRIu64 " cached executable pages\n", uvmexp.execpages); | | 1012 | (void)printf("%9" PRIu64 " cached executable pages\n", uvmexp.execpages); |
1013 | | | 1013 | |
1014 | (void)printf("%9" PRIu64 " minimum free pages\n", uvmexp.freemin); | | 1014 | (void)printf("%9" PRIu64 " minimum free pages\n", uvmexp.freemin); |
1015 | (void)printf("%9" PRIu64 " target free pages\n", uvmexp.freetarg); | | 1015 | (void)printf("%9" PRIu64 " target free pages\n", uvmexp.freetarg); |
1016 | (void)printf("%9" PRIu64 " maximum wired pages\n", uvmexp.wiredmax); | | 1016 | (void)printf("%9" PRIu64 " maximum wired pages\n", uvmexp.wiredmax); |
1017 | | | 1017 | |
1018 | (void)printf("%9" PRIu64 " swap devices\n", uvmexp.nswapdev); | | 1018 | (void)printf("%9" PRIu64 " swap devices\n", uvmexp.nswapdev); |
1019 | (void)printf("%9" PRIu64 " swap pages\n", uvmexp.swpages); | | 1019 | (void)printf("%9" PRIu64 " swap pages\n", uvmexp.swpages); |
1020 | (void)printf("%9" PRIu64 " swap pages in use\n", uvmexp.swpginuse); | | 1020 | (void)printf("%9" PRIu64 " swap pages in use\n", uvmexp.swpginuse); |
1021 | (void)printf("%9" PRIu64 " swap allocations\n", uvmexp.nswget); | | 1021 | (void)printf("%9" PRIu64 " swap allocations\n", uvmexp.nswget); |
1022 | | | 1022 | |
1023 | cpucounters(&cc); | | 1023 | cpucounters(&cc); |
1024 | | | 1024 | |
1025 | (void)printf("%9" PRIu64 " total faults taken\n", cc.nfault); | | 1025 | (void)printf("%9" PRIu64 " total faults taken\n", cc.nfault); |
1026 | (void)printf("%9" PRIu64 " traps\n", cc.ntrap); | | 1026 | (void)printf("%9" PRIu64 " traps\n", cc.ntrap); |
1027 | (void)printf("%9" PRIu64 " device interrupts\n", cc.nintr); | | 1027 | (void)printf("%9" PRIu64 " device interrupts\n", cc.nintr); |
1028 | (void)printf("%9" PRIu64 " CPU context switches\n", cc.nswtch); | | 1028 | (void)printf("%9" PRIu64 " CPU context switches\n", cc.nswtch); |
1029 | (void)printf("%9" PRIu64 " software interrupts\n", cc.nsoft); | | 1029 | (void)printf("%9" PRIu64 " software interrupts\n", cc.nsoft); |
1030 | (void)printf("%9" PRIu64 " system calls\n", cc.nsyscall); | | 1030 | (void)printf("%9" PRIu64 " system calls\n", cc.nsyscall); |
1031 | (void)printf("%9" PRIu64 " pagein requests\n", uvmexp.pageins); | | 1031 | (void)printf("%9" PRIu64 " pagein requests\n", uvmexp.pageins); |
1032 | (void)printf("%9" PRIu64 " pageout requests\n", uvmexp.pdpageouts); | | 1032 | (void)printf("%9" PRIu64 " pageout requests\n", uvmexp.pdpageouts); |
1033 | (void)printf("%9" PRIu64 " pages swapped in\n", uvmexp.pgswapin); | | 1033 | (void)printf("%9" PRIu64 " pages swapped in\n", uvmexp.pgswapin); |
1034 | (void)printf("%9" PRIu64 " pages swapped out\n", uvmexp.pgswapout); | | 1034 | (void)printf("%9" PRIu64 " pages swapped out\n", uvmexp.pgswapout); |
1035 | (void)printf("%9" PRIu64 " forks total\n", uvmexp.forks); | | 1035 | (void)printf("%9" PRIu64 " forks total\n", uvmexp.forks); |
1036 | (void)printf("%9" PRIu64 " forks blocked parent\n", uvmexp.forks_ppwait); | | 1036 | (void)printf("%9" PRIu64 " forks blocked parent\n", uvmexp.forks_ppwait); |
1037 | (void)printf("%9" PRIu64 " forks shared address space with parent\n", | | 1037 | (void)printf("%9" PRIu64 " forks shared address space with parent\n", |
1038 | uvmexp.forks_sharevm); | | 1038 | uvmexp.forks_sharevm); |
1039 | (void)printf("%9" PRIu64 " pagealloc desired color avail\n", | | 1039 | (void)printf("%9" PRIu64 " pagealloc desired color avail\n", |
1040 | uvmexp.colorhit); | | 1040 | uvmexp.colorhit); |
1041 | (void)printf("%9" PRIu64 " pagealloc desired color not avail\n", | | 1041 | (void)printf("%9" PRIu64 " pagealloc desired color not avail\n", |
1042 | uvmexp.colormiss); | | 1042 | uvmexp.colormiss); |
1043 | (void)printf("%9" PRIu64 " pagealloc local cpu avail\n", | | 1043 | (void)printf("%9" PRIu64 " pagealloc local cpu avail\n", |
1044 | uvmexp.cpuhit); | | 1044 | uvmexp.cpuhit); |
1045 | (void)printf("%9" PRIu64 " pagealloc local cpu not avail\n", | | 1045 | (void)printf("%9" PRIu64 " pagealloc local cpu not avail\n", |
1046 | uvmexp.cpumiss); | | 1046 | uvmexp.cpumiss); |
1047 | | | 1047 | |
1048 | (void)printf("%9" PRIu64 " faults with no memory\n", uvmexp.fltnoram); | | 1048 | (void)printf("%9" PRIu64 " faults with no memory\n", uvmexp.fltnoram); |
1049 | (void)printf("%9" PRIu64 " faults with no anons\n", uvmexp.fltnoanon); | | 1049 | (void)printf("%9" PRIu64 " faults with no anons\n", uvmexp.fltnoanon); |
1050 | (void)printf("%9" PRIu64 " faults had to wait on pages\n", uvmexp.fltpgwait); | | 1050 | (void)printf("%9" PRIu64 " faults had to wait on pages\n", uvmexp.fltpgwait); |
1051 | (void)printf("%9" PRIu64 " faults found released page\n", uvmexp.fltpgrele); | | 1051 | (void)printf("%9" PRIu64 " faults found released page\n", uvmexp.fltpgrele); |
1052 | (void)printf("%9" PRIu64 " faults relock (%" PRIu64 " ok)\n", uvmexp.fltrelck, | | 1052 | (void)printf("%9" PRIu64 " faults relock (%" PRIu64 " ok)\n", uvmexp.fltrelck, |
1053 | uvmexp.fltrelckok); | | 1053 | uvmexp.fltrelckok); |
1054 | (void)printf("%9" PRIu64 " anon page faults\n", uvmexp.fltanget); | | 1054 | (void)printf("%9" PRIu64 " anon page faults\n", uvmexp.fltanget); |
1055 | (void)printf("%9" PRIu64 " anon retry faults\n", uvmexp.fltanretry); | | 1055 | (void)printf("%9" PRIu64 " anon retry faults\n", uvmexp.fltanretry); |
1056 | (void)printf("%9" PRIu64 " amap copy faults\n", uvmexp.fltamcopy); | | 1056 | (void)printf("%9" PRIu64 " amap copy faults\n", uvmexp.fltamcopy); |
1057 | (void)printf("%9" PRIu64 " neighbour anon page faults\n", uvmexp.fltnamap); | | 1057 | (void)printf("%9" PRIu64 " neighbour anon page faults\n", uvmexp.fltnamap); |
1058 | (void)printf("%9" PRIu64 " neighbour object page faults\n", uvmexp.fltnomap); | | 1058 | (void)printf("%9" PRIu64 " neighbour object page faults\n", uvmexp.fltnomap); |
1059 | (void)printf("%9" PRIu64 " locked pager get faults\n", uvmexp.fltlget); | | 1059 | (void)printf("%9" PRIu64 " locked pager get faults\n", uvmexp.fltlget); |
1060 | (void)printf("%9" PRIu64 " unlocked pager get faults\n", uvmexp.fltget); | | 1060 | (void)printf("%9" PRIu64 " unlocked pager get faults\n", uvmexp.fltget); |
1061 | (void)printf("%9" PRIu64 " anon faults\n", uvmexp.flt_anon); | | 1061 | (void)printf("%9" PRIu64 " anon faults\n", uvmexp.flt_anon); |
1062 | (void)printf("%9" PRIu64 " anon copy on write faults\n", uvmexp.flt_acow); | | 1062 | (void)printf("%9" PRIu64 " anon copy on write faults\n", uvmexp.flt_acow); |
1063 | (void)printf("%9" PRIu64 " object faults\n", uvmexp.flt_obj); | | 1063 | (void)printf("%9" PRIu64 " object faults\n", uvmexp.flt_obj); |
1064 | (void)printf("%9" PRIu64 " promote copy faults\n", uvmexp.flt_prcopy); | | 1064 | (void)printf("%9" PRIu64 " promote copy faults\n", uvmexp.flt_prcopy); |
1065 | (void)printf("%9" PRIu64 " promote zero fill faults\n", uvmexp.flt_przero); | | 1065 | (void)printf("%9" PRIu64 " promote zero fill faults\n", uvmexp.flt_przero); |
1066 | (void)printf("%9" PRIu64 " faults upgraded lock\n", | | 1066 | (void)printf("%9" PRIu64 " faults upgraded lock\n", |
1067 | uvmexp.fltup); | | 1067 | uvmexp.fltup); |
1068 | (void)printf("%9" PRIu64 " faults couldn't upgrade lock\n", | | 1068 | (void)printf("%9" PRIu64 " faults couldn't upgrade lock\n", |
1069 | uvmexp.fltnoup); | | 1069 | uvmexp.fltnoup); |
1070 | | | 1070 | |
1071 | (void)printf("%9" PRIu64 " times daemon wokeup\n",uvmexp.pdwoke); | | 1071 | (void)printf("%9" PRIu64 " times daemon wokeup\n",uvmexp.pdwoke); |
1072 | (void)printf("%9" PRIu64 " revolutions of the clock hand\n", uvmexp.pdrevs); | | 1072 | (void)printf("%9" PRIu64 " revolutions of the clock hand\n", uvmexp.pdrevs); |
1073 | (void)printf("%9" PRIu64 " pages freed by daemon\n", uvmexp.pdfreed); | | 1073 | (void)printf("%9" PRIu64 " pages freed by daemon\n", uvmexp.pdfreed); |
1074 | (void)printf("%9" PRIu64 " pages scanned by daemon\n", uvmexp.pdscans); | | 1074 | (void)printf("%9" PRIu64 " pages scanned by daemon\n", uvmexp.pdscans); |
1075 | (void)printf("%9" PRIu64 " anonymous pages scanned by daemon\n", | | 1075 | (void)printf("%9" PRIu64 " anonymous pages scanned by daemon\n", |
1076 | uvmexp.pdanscan); | | 1076 | uvmexp.pdanscan); |
1077 | (void)printf("%9" PRIu64 " object pages scanned by daemon\n", uvmexp.pdobscan); | | 1077 | (void)printf("%9" PRIu64 " object pages scanned by daemon\n", uvmexp.pdobscan); |
1078 | (void)printf("%9" PRIu64 " pages reactivated\n", uvmexp.pdreact); | | 1078 | (void)printf("%9" PRIu64 " pages reactivated\n", uvmexp.pdreact); |
1079 | (void)printf("%9" PRIu64 " pages found busy by daemon\n", uvmexp.pdbusy); | | 1079 | (void)printf("%9" PRIu64 " pages found busy by daemon\n", uvmexp.pdbusy); |
1080 | (void)printf("%9" PRIu64 " total pending pageouts\n", uvmexp.pdpending); | | 1080 | (void)printf("%9" PRIu64 " total pending pageouts\n", uvmexp.pdpending); |
1081 | (void)printf("%9" PRIu64 " pages deactivated\n", uvmexp.pddeact); | | 1081 | (void)printf("%9" PRIu64 " pages deactivated\n", uvmexp.pddeact); |
1082 | (void)printf("%9" PRIu64 " per-cpu stats synced\n", uvmexp.countsyncall); | | 1082 | (void)printf("%9" PRIu64 " per-cpu stats synced\n", uvmexp.countsyncall); |
1083 | (void)printf("%9" PRIu64 " anon pages possibly dirty\n", uvmexp.anonunknown); | | 1083 | (void)printf("%9" PRIu64 " anon pages possibly dirty\n", uvmexp.anonunknown); |
1084 | (void)printf("%9" PRIu64 " anon pages dirty\n", uvmexp.anondirty); | | 1084 | (void)printf("%9" PRIu64 " anon pages dirty\n", uvmexp.anondirty); |
1085 | (void)printf("%9" PRIu64 " anon pages clean\n", uvmexp.anonclean); | | 1085 | (void)printf("%9" PRIu64 " anon pages clean\n", uvmexp.anonclean); |
1086 | (void)printf("%9" PRIu64 " file pages possibly dirty\n", uvmexp.fileunknown); | | 1086 | (void)printf("%9" PRIu64 " file pages possibly dirty\n", uvmexp.fileunknown); |
1087 | (void)printf("%9" PRIu64 " file pages dirty\n", uvmexp.filedirty); | | 1087 | (void)printf("%9" PRIu64 " file pages dirty\n", uvmexp.filedirty); |
1088 | (void)printf("%9" PRIu64 " file pages clean\n", uvmexp.fileclean); | | 1088 | (void)printf("%9" PRIu64 " file pages clean\n", uvmexp.fileclean); |
1089 | | | 1089 | |
1090 | if (active_kernel) { | | 1090 | if (active_kernel) { |
1091 | ssize = sizeof(nch_stats); | | 1091 | ssize = sizeof(nch_stats); |
1092 | if (sysctlbyname("vfs.namecache_stats", &nch_stats, &ssize, | | 1092 | if (sysctlbyname("vfs.namecache_stats", &nch_stats, &ssize, |
1093 | NULL, 0)) { | | 1093 | NULL, 0)) { |
1094 | warn("vfs.namecache_stats failed"); | | 1094 | warn("vfs.namecache_stats failed"); |
1095 | memset(&nch_stats, 0, sizeof(nch_stats)); | | 1095 | memset(&nch_stats, 0, sizeof(nch_stats)); |
1096 | } | | 1096 | } |
1097 | } else { | | 1097 | } else { |
1098 | kread(namelist, X_NCHSTATS, &nch_stats, sizeof(nch_stats)); | | 1098 | kread(namelist, X_NCHSTATS, &nch_stats, sizeof(nch_stats)); |
1099 | } | | 1099 | } |
1100 | | | 1100 | |
1101 | nchtotal = nch_stats.ncs_goodhits + nch_stats.ncs_neghits + | | 1101 | nchtotal = nch_stats.ncs_goodhits + nch_stats.ncs_neghits + |
1102 | nch_stats.ncs_badhits + nch_stats.ncs_falsehits + | | 1102 | nch_stats.ncs_badhits + nch_stats.ncs_falsehits + |
1103 | nch_stats.ncs_miss + nch_stats.ncs_long; | | 1103 | nch_stats.ncs_miss + nch_stats.ncs_long; |
1104 | (void)printf("%9" PRIu64 " total name lookups\n", nchtotal); | | 1104 | (void)printf("%9" PRIu64 " total name lookups\n", nchtotal); |
1105 | (void)printf("%9" PRIu64 " good hits\n", nch_stats.ncs_goodhits); | | 1105 | (void)printf("%9" PRIu64 " good hits\n", nch_stats.ncs_goodhits); |
1106 | (void)printf("%9" PRIu64 " negative hits\n", nch_stats.ncs_neghits); | | 1106 | (void)printf("%9" PRIu64 " negative hits\n", nch_stats.ncs_neghits); |
1107 | (void)printf("%9" PRIu64 " bad hits\n", nch_stats.ncs_badhits); | | 1107 | (void)printf("%9" PRIu64 " bad hits\n", nch_stats.ncs_badhits); |
1108 | (void)printf("%9" PRIu64 " false hits\n", nch_stats.ncs_falsehits); | | 1108 | (void)printf("%9" PRIu64 " false hits\n", nch_stats.ncs_falsehits); |
1109 | (void)printf("%9" PRIu64 " miss\n", nch_stats.ncs_miss); | | 1109 | (void)printf("%9" PRIu64 " miss\n", nch_stats.ncs_miss); |
1110 | (void)printf("%9" PRIu64 " too long\n", nch_stats.ncs_long); | | 1110 | (void)printf("%9" PRIu64 " too long\n", nch_stats.ncs_long); |
1111 | (void)printf("%9" PRIu64 " pass2 hits\n", nch_stats.ncs_pass2); | | 1111 | (void)printf("%9" PRIu64 " pass2 hits\n", nch_stats.ncs_pass2); |
1112 | (void)printf("%9" PRIu64 " 2passes\n", nch_stats.ncs_2passes); | | 1112 | (void)printf("%9" PRIu64 " 2passes\n", nch_stats.ncs_2passes); |
1113 | (void)printf("%9" PRIu64 " reverse hits\n", nch_stats.ncs_revhits); | | 1113 | (void)printf("%9" PRIu64 " reverse hits\n", nch_stats.ncs_revhits); |
1114 | (void)printf("%9" PRIu64 " reverse miss\n", nch_stats.ncs_revmiss); | | 1114 | (void)printf("%9" PRIu64 " reverse miss\n", nch_stats.ncs_revmiss); |
1115 | (void)printf("%9" PRIu64 " access denied\n", nch_stats.ncs_denied); | | 1115 | (void)printf("%9" PRIu64 " access denied\n", nch_stats.ncs_denied); |
1116 | (void)printf( | | 1116 | (void)printf( |
1117 | "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n", | | 1117 | "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n", |
1118 | "", PCT(nch_stats.ncs_goodhits, nchtotal), | | 1118 | "", PCT(nch_stats.ncs_goodhits, nchtotal), |
1119 | PCT(nch_stats.ncs_neghits, nchtotal), | | 1119 | PCT(nch_stats.ncs_neghits, nchtotal), |
1120 | PCT(nch_stats.ncs_pass2, nchtotal)); | | 1120 | PCT(nch_stats.ncs_pass2, nchtotal)); |
1121 | (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "", | | 1121 | (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "", |
1122 | PCT(nch_stats.ncs_badhits, nchtotal), | | 1122 | PCT(nch_stats.ncs_badhits, nchtotal), |
1123 | PCT(nch_stats.ncs_falsehits, nchtotal), | | 1123 | PCT(nch_stats.ncs_falsehits, nchtotal), |
1124 | PCT(nch_stats.ncs_long, nchtotal)); | | 1124 | PCT(nch_stats.ncs_long, nchtotal)); |
1125 | } | | 1125 | } |
1126 | | | 1126 | |
1127 | void | | 1127 | void |
1128 | doforkst(void) | | 1128 | doforkst(void) |
1129 | { | | 1129 | { |
1130 | if (memf != NULL) { | | 1130 | if (memf != NULL) { |
1131 | struct uvmexp uvmexp_kernel; | | 1131 | struct uvmexp uvmexp_kernel; |
1132 | kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel)); | | 1132 | kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel)); |
1133 | #define COPY(field) uvmexp.field = uvmexp_kernel.field | | 1133 | #define COPY(field) uvmexp.field = uvmexp_kernel.field |
1134 | COPY(forks); | | 1134 | COPY(forks); |
1135 | COPY(forks_ppwait); | | 1135 | COPY(forks_ppwait); |
1136 | COPY(forks_sharevm); | | 1136 | COPY(forks_sharevm); |
1137 | #undef COPY | | 1137 | #undef COPY |
1138 | } else { | | 1138 | } else { |
1139 | size_t size = sizeof(uvmexp); | | 1139 | size_t size = sizeof(uvmexp); |
1140 | if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp, | | 1140 | if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp, |
1141 | &size, NULL, 0) == -1) | | 1141 | &size, NULL, 0) == -1) |
1142 | warn("sysctl vm.uvmexp2 failed"); | | 1142 | warn("sysctl vm.uvmexp2 failed"); |
1143 | } | | 1143 | } |
1144 | | | 1144 | |
1145 | (void)printf("%" PRIu64 " forks total\n", uvmexp.forks); | | 1145 | (void)printf("%" PRIu64 " forks total\n", uvmexp.forks); |
1146 | (void)printf("%" PRIu64 " forks blocked parent\n", uvmexp.forks_ppwait); | | 1146 | (void)printf("%" PRIu64 " forks blocked parent\n", uvmexp.forks_ppwait); |
1147 | (void)printf("%" PRIu64 " forks shared address space with parent\n", | | 1147 | (void)printf("%" PRIu64 " forks shared address space with parent\n", |
1148 | uvmexp.forks_sharevm); | | 1148 | uvmexp.forks_sharevm); |
1149 | } | | 1149 | } |
1150 | | | 1150 | |
1151 | void | | 1151 | void |
1152 | drvstats(int *ovflwp) | | 1152 | drvstats(int *ovflwp) |
1153 | { | | 1153 | { |
1154 | size_t dn; | | 1154 | size_t dn; |
1155 | double dtime; | | 1155 | double dtime; |
1156 | int ovflw = *ovflwp; | | 1156 | int ovflw = *ovflwp; |
1157 | | | 1157 | |
1158 | /* Calculate disk stat deltas. */ | | 1158 | /* Calculate disk stat deltas. */ |
1159 | cpuswap(); | | 1159 | cpuswap(); |
1160 | drvswap(); | | 1160 | drvswap(); |
1161 | tkswap(); | | 1161 | tkswap(); |
1162 | | | 1162 | |
1163 | for (dn = 0; dn < ndrive; ++dn) { | | 1163 | for (dn = 0; dn < ndrive; ++dn) { |
1164 | /* elapsed time for disk stats */ | | 1164 | /* elapsed time for disk stats */ |
1165 | dtime = cur.cp_etime; | | 1165 | dtime = cur.cp_etime; |
1166 | if (cur.timestamp[dn].tv_sec || cur.timestamp[dn].tv_usec) { | | 1166 | if (cur.timestamp[dn].tv_sec || cur.timestamp[dn].tv_usec) { |
1167 | dtime = (double)cur.timestamp[dn].tv_sec + | | 1167 | dtime = (double)cur.timestamp[dn].tv_sec + |
1168 | ((double)cur.timestamp[dn].tv_usec / (double)1000000); | | 1168 | ((double)cur.timestamp[dn].tv_usec / (double)1000000); |
1169 | } | | 1169 | } |
1170 | | | 1170 | |
1171 | if (!drv_select[dn]) | | 1171 | if (!drv_select[dn]) |
1172 | continue; | | 1172 | continue; |
1173 | PRWORD(ovflw, " %*.0f", 3, 1, | | 1173 | PRWORD(ovflw, " %*.0f", 3, 1, |
1174 | (cur.rxfer[dn] + cur.wxfer[dn]) / dtime); | | 1174 | (cur.rxfer[dn] + cur.wxfer[dn]) / dtime); |
1175 | } | | 1175 | } |
1176 | *ovflwp = ovflw; | | 1176 | *ovflwp = ovflw; |
1177 | } | | 1177 | } |
1178 | | | 1178 | |
1179 | void | | 1179 | void |
1180 | cpucounters(struct cpu_counter *cc) | | 1180 | cpucounters(struct cpu_counter *cc) |
1181 | { | | 1181 | { |
1182 | static struct cpu_info **cpu_infos; | | 1182 | static struct cpu_info **cpu_infos; |
1183 | static int initialised; | | 1183 | static int initialised; |
1184 | struct cpu_info **slot; | | 1184 | struct cpu_info **slot; |
1185 | | | 1185 | |
1186 | if (memf == NULL) { | | 1186 | if (memf == NULL) { |
1187 | cc->nintr = uvmexp.intrs; | | 1187 | cc->nintr = uvmexp.intrs; |
1188 | cc->nsyscall = uvmexp.syscalls; | | 1188 | cc->nsyscall = uvmexp.syscalls; |
1189 | cc->nswtch = uvmexp.swtch; | | 1189 | cc->nswtch = uvmexp.swtch; |
1190 | cc->nfault = uvmexp.faults; | | 1190 | cc->nfault = uvmexp.faults; |
1191 | cc->ntrap = uvmexp.traps; | | 1191 | cc->ntrap = uvmexp.traps; |
1192 | cc->nsoft = uvmexp.softs; | | 1192 | cc->nsoft = uvmexp.softs; |
1193 | return; | | 1193 | return; |
1194 | } | | 1194 | } |
1195 | | | 1195 | |
1196 | if (!initialised) { | | 1196 | if (!initialised) { |
1197 | kread(namelist, X_CPU_INFOS, &cpu_infos, sizeof(cpu_infos)); | | 1197 | kread(namelist, X_CPU_INFOS, &cpu_infos, sizeof(cpu_infos)); |
1198 | initialised = 1; | | 1198 | initialised = 1; |
1199 | } | | 1199 | } |
1200 | | | 1200 | |
1201 | slot = cpu_infos; | | 1201 | slot = cpu_infos; |
1202 | | | 1202 | |
1203 | memset(cc, 0, sizeof(*cc)); | | 1203 | memset(cc, 0, sizeof(*cc)); |
1204 | | | 1204 | |
1205 | for (;;) { | | 1205 | for (;;) { |
1206 | struct cpu_info tci, *ci = NULL; | | 1206 | struct cpu_info tci, *ci = NULL; |
1207 | | | 1207 | |
1208 | deref_kptr(slot++, &ci, sizeof(ci), "CPU array trashed"); | | 1208 | deref_kptr(slot++, &ci, sizeof(ci), "CPU array trashed"); |
1209 | if (!ci) { | | 1209 | if (!ci) { |
1210 | break; | | 1210 | break; |
1211 | } | | 1211 | } |
1212 | | | 1212 | |
1213 | if ((size_t)kvm_read(kd, (u_long)ci, &tci, sizeof(tci)) | | 1213 | if ((size_t)kvm_read(kd, (u_long)ci, &tci, sizeof(tci)) |
1214 | != sizeof(tci)) { | | 1214 | != sizeof(tci)) { |
1215 | warnx("Can't read cpu info from %p (%s)", | | 1215 | warnx("Can't read cpu info from %p (%s)", |
1216 | ci, kvm_geterr(kd)); | | 1216 | ci, kvm_geterr(kd)); |
1217 | memset(cc, 0, sizeof(*cc)); | | 1217 | memset(cc, 0, sizeof(*cc)); |
1218 | return; | | 1218 | return; |
1219 | } | | 1219 | } |
1220 | cc->nintr += tci.ci_data.cpu_nintr; | | 1220 | cc->nintr += tci.ci_data.cpu_nintr; |
1221 | cc->nsyscall += tci.ci_data.cpu_nsyscall; | | 1221 | cc->nsyscall += tci.ci_data.cpu_nsyscall; |
1222 | cc->nswtch = tci.ci_data.cpu_nswtch; | | 1222 | cc->nswtch = tci.ci_data.cpu_nswtch; |
1223 | cc->nfault = tci.ci_data.cpu_nfault; | | 1223 | cc->nfault = tci.ci_data.cpu_nfault; |
1224 | cc->ntrap = tci.ci_data.cpu_ntrap; | | 1224 | cc->ntrap = tci.ci_data.cpu_ntrap; |
1225 | cc->nsoft = tci.ci_data.cpu_nsoft; | | 1225 | cc->nsoft = tci.ci_data.cpu_nsoft; |
1226 | } | | 1226 | } |
1227 | } | | 1227 | } |
1228 | | | 1228 | |
1229 | void | | 1229 | void |
1230 | cpustats(int *ovflwp) | | 1230 | cpustats(int *ovflwp) |
1231 | { | | 1231 | { |
1232 | int state; | | 1232 | int state; |
1233 | double pcnt, total; | | 1233 | double pcnt, total; |
1234 | double stat_us, stat_sy, stat_id; | | 1234 | double stat_us, stat_sy, stat_id; |
1235 | int ovflw = *ovflwp; | | 1235 | int ovflw = *ovflwp; |
1236 | | | 1236 | |
1237 | total = 0; | | 1237 | total = 0; |
1238 | for (state = 0; state < CPUSTATES; ++state) | | 1238 | for (state = 0; state < CPUSTATES; ++state) |
1239 | total += cur.cp_time[state]; | | 1239 | total += cur.cp_time[state]; |
1240 | if (total) | | 1240 | if (total) |
1241 | pcnt = 100 / total; | | 1241 | pcnt = 100 / total; |
1242 | else | | 1242 | else |
1243 | pcnt = 0; | | 1243 | pcnt = 0; |
1244 | stat_us = (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * pcnt; | | 1244 | stat_us = (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * pcnt; |
1245 | stat_sy = (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * pcnt; | | 1245 | stat_sy = (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * pcnt; |
1246 | stat_id = cur.cp_time[CP_IDLE] * pcnt; | | 1246 | stat_id = cur.cp_time[CP_IDLE] * pcnt; |
1247 | PRWORD(ovflw, " %*.0f", ((stat_sy >= 100) ? 2 : 3), 1, stat_us); | | 1247 | PRWORD(ovflw, " %*.0f", ((stat_sy >= 100) ? 2 : 3), 1, stat_us); |
1248 | PRWORD(ovflw, " %*.0f", ((stat_us >= 100 || stat_id >= 100) ? 2 : 3), 1, | | 1248 | PRWORD(ovflw, " %*.0f", ((stat_us >= 100 || stat_id >= 100) ? 2 : 3), 1, |
1249 | stat_sy); | | 1249 | stat_sy); |
1250 | PRWORD(ovflw, " %*.0f", 3, 1, stat_id); | | 1250 | PRWORD(ovflw, " %*.0f", 3, 1, stat_id); |
1251 | *ovflwp = ovflw; | | 1251 | *ovflwp = ovflw; |
1252 | } | | 1252 | } |
1253 | | | 1253 | |
1254 | void | | 1254 | void |
1255 | dointr(int verbose) | | 1255 | dointr(int verbose) |
1256 | { | | 1256 | { |
1257 | unsigned long *intrcnt, *ointrcnt; | | 1257 | unsigned long *intrcnt, *ointrcnt; |
1258 | unsigned long long inttotal, uptime; | | 1258 | unsigned long long inttotal, uptime; |
1259 | int nintr, inamlen; | | 1259 | int nintr, inamlen; |
1260 | char *intrname, *ointrname; | | 1260 | char *intrname, *ointrname; |
1261 | | | 1261 | |
| | | 1262 | if (memf == NULL) { |
| | | 1263 | doevcnt(verbose, EVCNT_TYPE_INTR); |
| | | 1264 | return; |
| | | 1265 | } |
| | | 1266 | |
1262 | inttotal = 0; | | 1267 | inttotal = 0; |
1263 | uptime = getuptime(); | | 1268 | uptime = getuptime(); |
1264 | nintr = intrnl[X_EINTRCNT].n_value - intrnl[X_INTRCNT].n_value; | | 1269 | nintr = intrnl[X_EINTRCNT].n_value - intrnl[X_INTRCNT].n_value; |
1265 | inamlen = intrnl[X_EINTRNAMES].n_value - intrnl[X_INTRNAMES].n_value; | | 1270 | inamlen = intrnl[X_EINTRNAMES].n_value - intrnl[X_INTRNAMES].n_value; |
1266 | if (nintr != 0 && inamlen != 0) { | | 1271 | if (nintr != 0 && inamlen != 0) { |
1267 | (void)printf("%-34s %16s %8s\n", "interrupt", "total", "rate"); | | 1272 | (void)printf("%-34s %16s %8s\n", "interrupt", "total", "rate"); |
1268 | | | 1273 | |
1269 | ointrcnt = intrcnt = malloc((size_t)nintr); | | 1274 | ointrcnt = intrcnt = malloc((size_t)nintr); |
1270 | ointrname = intrname = malloc((size_t)inamlen); | | 1275 | ointrname = intrname = malloc((size_t)inamlen); |
1271 | if (intrcnt == NULL || intrname == NULL) | | 1276 | if (intrcnt == NULL || intrname == NULL) |
1272 | errx(1, "%s", ""); | | 1277 | errx(1, "%s", ""); |
1273 | kread(intrnl, X_INTRCNT, intrcnt, (size_t)nintr); | | 1278 | kread(intrnl, X_INTRCNT, intrcnt, (size_t)nintr); |
1274 | kread(intrnl, X_INTRNAMES, intrname, (size_t)inamlen); | | 1279 | kread(intrnl, X_INTRNAMES, intrname, (size_t)inamlen); |
1275 | nintr /= sizeof(long); | | 1280 | nintr /= sizeof(long); |
1276 | while (--nintr >= 0) { | | 1281 | while (--nintr >= 0) { |
1277 | if (*intrcnt || verbose) | | 1282 | if (*intrcnt || verbose) |
1278 | (void)printf("%-34s %16llu %8llu\n", intrname, | | 1283 | (void)printf("%-34s %16llu %8llu\n", intrname, |
1279 | (unsigned long long)*intrcnt, | | 1284 | (unsigned long long)*intrcnt, |
1280 | (unsigned long long) | | 1285 | (unsigned long long) |
1281 | (*intrcnt / uptime)); | | 1286 | (*intrcnt / uptime)); |
1282 | intrname += strlen(intrname) + 1; | | 1287 | intrname += strlen(intrname) + 1; |
1283 | inttotal += *intrcnt++; | | 1288 | inttotal += *intrcnt++; |
1284 | } | | 1289 | } |
1285 | free(ointrcnt); | | 1290 | free(ointrcnt); |
1286 | free(ointrname); | | 1291 | free(ointrname); |
1287 | } | | 1292 | } |
1288 | | | 1293 | |
1289 | doevcnt(verbose, EVCNT_TYPE_INTR); | | 1294 | doevcnt(verbose, EVCNT_TYPE_INTR); |
1290 | } | | 1295 | } |
1291 | | | 1296 | |
1292 | void | | 1297 | void |
1293 | doevcnt(int verbose, int type) | | 1298 | doevcnt(int verbose, int type) |
1294 | { | | 1299 | { |
1295 | static const char * const evtypes [] = { "misc", "intr", "trap" }; | | 1300 | static const char * const evtypes [] = { "misc", "intr", "trap" }; |
1296 | uint64_t counttotal, uptime; | | 1301 | uint64_t counttotal, uptime; |
1297 | struct evcntlist allevents; | | 1302 | struct evcntlist allevents; |
1298 | struct evcnt evcnt, *evptr; | | 1303 | struct evcnt evcnt, *evptr; |
1299 | size_t evlen_max, total_max, rate_max; | | 1304 | size_t evlen_max, total_max, rate_max; |
1300 | char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX]; | | 1305 | char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX]; |
1301 | | | 1306 | |
1302 | counttotal = 0; | | 1307 | counttotal = 0; |
1303 | uptime = getuptime(); | | 1308 | uptime = getuptime(); |
1304 | | | 1309 | |
1305 | if (memf == NULL) do { | | 1310 | if (memf == NULL) do { |
1306 | const int mib[4] = { CTL_KERN, KERN_EVCNT, type, | | 1311 | const int mib[4] = { CTL_KERN, KERN_EVCNT, type, |
1307 | verbose ? KERN_EVCNT_COUNT_ANY : KERN_EVCNT_COUNT_NONZERO }; | | 1312 | verbose ? KERN_EVCNT_COUNT_ANY : KERN_EVCNT_COUNT_NONZERO }; |
1308 | size_t buflen0, buflen = 0; | | 1313 | size_t buflen0, buflen = 0; |
1309 | void *buf0, *buf = NULL; | | 1314 | void *buf0, *buf = NULL; |
1310 | const struct evcnt_sysctl *evs, *last_evs; | | 1315 | const struct evcnt_sysctl *evs, *last_evs; |
1311 | for (;;) { | | 1316 | for (;;) { |
1312 | size_t newlen; | | 1317 | size_t newlen; |
1313 | int error; | | 1318 | int error; |
1314 | if (buflen) | | 1319 | if (buflen) |
1315 | buf = malloc(buflen); | | 1320 | buf = malloc(buflen); |
1316 | error = sysctl(mib, __arraycount(mib), | | 1321 | error = sysctl(mib, __arraycount(mib), |
1317 | buf, &newlen, NULL, 0); | | 1322 | buf, &newlen, NULL, 0); |
1318 | if (error) { | | 1323 | if (error) { |
1319 | err(1, "kern.evcnt"); | | 1324 | err(1, "kern.evcnt"); |
1320 | if (buf) | | 1325 | if (buf) |
1321 | free(buf); | | 1326 | free(buf); |
1322 | return; | | 1327 | return; |
1323 | } | | 1328 | } |
1324 | if (newlen <= buflen) { | | 1329 | if (newlen <= buflen) { |
1325 | buflen = newlen; | | 1330 | buflen = newlen; |
1326 | break; | | 1331 | break; |
1327 | } | | 1332 | } |
1328 | if (buf) | | 1333 | if (buf) |
1329 | free(buf); | | 1334 | free(buf); |
1330 | buflen = newlen; | | 1335 | buflen = newlen; |
1331 | } | | 1336 | } |
1332 | buflen0 = buflen; | | 1337 | buflen0 = buflen; |
1333 | evs = buf0 = buf; | | 1338 | evs = buf0 = buf; |
1334 | last_evs = (void *)((char *)buf + buflen); | | 1339 | last_evs = (void *)((char *)buf + buflen); |
1335 | buflen /= sizeof(uint64_t); | | 1340 | buflen /= sizeof(uint64_t); |
1336 | /* calc columns */ | | 1341 | /* calc columns */ |
1337 | evlen_max = 0; | | 1342 | evlen_max = 0; |
1338 | total_max = sizeof("total") - 1; | | 1343 | total_max = sizeof("total") - 1; |
1339 | rate_max = sizeof("rate") - 1; | | 1344 | rate_max = sizeof("rate") - 1; |
1340 | while (evs < last_evs | | 1345 | while (evs < last_evs |
1341 | && buflen >= sizeof(*evs)/sizeof(uint64_t) | | 1346 | && buflen >= sizeof(*evs)/sizeof(uint64_t) |
1342 | && buflen >= evs->ev_len) { | | 1347 | && buflen >= evs->ev_len) { |
1343 | char cbuf[64]; | | 1348 | char cbuf[64]; |
1344 | size_t len; | | 1349 | size_t len; |
1345 | len = strlen(evs->ev_strings + evs->ev_grouplen + 1); | | 1350 | len = strlen(evs->ev_strings + evs->ev_grouplen + 1); |
1346 | len += evs->ev_grouplen + 1; | | 1351 | len += evs->ev_grouplen + 1; |
1347 | if (evlen_max < len) | | 1352 | if (evlen_max < len) |
1348 | evlen_max= len; | | 1353 | evlen_max= len; |
1349 | len = snprintf(cbuf, sizeof(cbuf), "%"PRIu64, | | 1354 | len = snprintf(cbuf, sizeof(cbuf), "%"PRIu64, |
1350 | evs->ev_count); | | 1355 | evs->ev_count); |
1351 | if (total_max < len) | | 1356 | if (total_max < len) |
1352 | total_max = len; | | 1357 | total_max = len; |
1353 | len = snprintf(cbuf, sizeof(cbuf), "%"PRIu64, | | 1358 | len = snprintf(cbuf, sizeof(cbuf), "%"PRIu64, |
1354 | evs->ev_count / uptime); | | 1359 | evs->ev_count / uptime); |
1355 | if (rate_max < len) | | 1360 | if (rate_max < len) |
1356 | rate_max = len; | | 1361 | rate_max = len; |
1357 | buflen -= evs->ev_len; | | 1362 | buflen -= evs->ev_len; |
1358 | evs = (const void *) | | 1363 | evs = (const void *) |
1359 | ((const uint64_t *)evs + evs->ev_len); | | 1364 | ((const uint64_t *)evs + evs->ev_len); |
1360 | } | | 1365 | } |
1361 | | | 1366 | |
1362 | (void)printf(type == EVCNT_TYPE_ANY ? | | 1367 | (void)printf(type == EVCNT_TYPE_ANY ? |
1363 | "%-*s %*s %*s %s\n" : | | 1368 | "%-*s %*s %*s %s\n" : |
1364 | "%-*s %*s %*s\n", | | 1369 | "%-*s %*s %*s\n", |
1365 | (int)evlen_max, "interrupt", | | 1370 | (int)evlen_max, "interrupt", |
1366 | (int)total_max, "total", | | 1371 | (int)total_max, "total", |
1367 | (int)rate_max, "rate", | | 1372 | (int)rate_max, "rate", |
1368 | "type"); | | 1373 | "type"); |
1369 | | | 1374 | |
1370 | buflen = buflen0; | | 1375 | buflen = buflen0; |
1371 | evs = buf0; | | 1376 | evs = buf0; |
1372 | last_evs = (void *)((char *)buf + buflen); | | 1377 | last_evs = (void *)((char *)buf + buflen); |
1373 | buflen /= sizeof(uint64_t); | | 1378 | buflen /= sizeof(uint64_t); |
1374 | while (evs < last_evs | | 1379 | while (evs < last_evs |
1375 | && buflen >= sizeof(*evs)/sizeof(uint64_t) | | 1380 | && buflen >= sizeof(*evs)/sizeof(uint64_t) |
1376 | && buflen >= evs->ev_len) { | | 1381 | && buflen >= evs->ev_len) { |
1377 | (void)printf(type == EVCNT_TYPE_ANY ? | | 1382 | (void)printf(type == EVCNT_TYPE_ANY ? |
1378 | "%s %s%*s %*"PRIu64" %*"PRIu64" %s\n" : | | 1383 | "%s %s%*s %*"PRIu64" %*"PRIu64" %s\n" : |
1379 | "%s %s%*s %*"PRIu64" %*"PRIu64"\n", | | 1384 | "%s %s%*s %*"PRIu64" %*"PRIu64"\n", |
1380 | evs->ev_strings, | | 1385 | evs->ev_strings, |
1381 | evs->ev_strings + evs->ev_grouplen + 1, | | 1386 | evs->ev_strings + evs->ev_grouplen + 1, |
1382 | (int)evlen_max - (evs->ev_grouplen + 1 | | 1387 | (int)evlen_max - (evs->ev_grouplen + 1 |
1383 | + evs->ev_namelen), "", | | 1388 | + evs->ev_namelen), "", |
1384 | (int)total_max, evs->ev_count, | | 1389 | (int)total_max, evs->ev_count, |
1385 | (int)rate_max, evs->ev_count / uptime, | | 1390 | (int)rate_max, evs->ev_count / uptime, |
1386 | (evs->ev_type < __arraycount(evtypes) ? | | 1391 | (evs->ev_type < __arraycount(evtypes) ? |
1387 | evtypes[evs->ev_type] : "?")); | | 1392 | evtypes[evs->ev_type] : "?")); |
1388 | buflen -= evs->ev_len; | | 1393 | buflen -= evs->ev_len; |
1389 | counttotal += evs->ev_count; | | 1394 | counttotal += evs->ev_count; |
1390 | evs = (const void *) | | 1395 | evs = (const void *) |
1391 | ((const uint64_t *)evs + evs->ev_len); | | 1396 | ((const uint64_t *)evs + evs->ev_len); |
1392 | } | | 1397 | } |
1393 | free(buf); | | 1398 | free(buf); |
1394 | if (type != EVCNT_TYPE_ANY) | | 1399 | if (type != EVCNT_TYPE_ANY) |
1395 | (void)printf("%-*s %*"PRIu64" %*"PRIu64"\n", | | 1400 | (void)printf("%-*s %*"PRIu64" %*"PRIu64"\n", |
1396 | (int)evlen_max, "Total", | | 1401 | (int)evlen_max, "Total", |
1397 | (int)total_max, counttotal, | | 1402 | (int)total_max, counttotal, |
1398 | (int)rate_max, counttotal / uptime); | | 1403 | (int)rate_max, counttotal / uptime); |
1399 | return; | | 1404 | return; |
1400 | } while (/*CONSTCOND*/ 0); | | 1405 | } while (/*CONSTCOND*/ 0); |
1401 | | | 1406 | |
1402 | if (type == EVCNT_TYPE_ANY) | | 1407 | if (type == EVCNT_TYPE_ANY) |
1403 | (void)printf("%-34s %16s %8s %s\n", "event", "total", "rate", | | 1408 | (void)printf("%-34s %16s %8s %s\n", "event", "total", "rate", |
1404 | "type"); | | 1409 | "type"); |
1405 | | | 1410 | |
1406 | kread(namelist, X_ALLEVENTS, &allevents, sizeof allevents); | | 1411 | kread(namelist, X_ALLEVENTS, &allevents, sizeof allevents); |
1407 | evptr = TAILQ_FIRST(&allevents); | | 1412 | evptr = TAILQ_FIRST(&allevents); |
1408 | while (evptr) { | | 1413 | while (evptr) { |
1409 | deref_kptr(evptr, &evcnt, sizeof(evcnt), "event chain trashed"); | | 1414 | deref_kptr(evptr, &evcnt, sizeof(evcnt), "event chain trashed"); |
1410 | | | 1415 | |
1411 | evptr = TAILQ_NEXT(&evcnt, ev_list); | | 1416 | evptr = TAILQ_NEXT(&evcnt, ev_list); |
1412 | if (evcnt.ev_count == 0 && !verbose) | | 1417 | if (evcnt.ev_count == 0 && !verbose) |
1413 | continue; | | 1418 | continue; |
1414 | if (type != EVCNT_TYPE_ANY && evcnt.ev_type != type) | | 1419 | if (type != EVCNT_TYPE_ANY && evcnt.ev_type != type) |
1415 | continue; | | 1420 | continue; |
1416 | | | 1421 | |
1417 | deref_kptr(evcnt.ev_group, evgroup, | | 1422 | deref_kptr(evcnt.ev_group, evgroup, |
1418 | (size_t)evcnt.ev_grouplen + 1, "event chain trashed"); | | 1423 | (size_t)evcnt.ev_grouplen + 1, "event chain trashed"); |
1419 | deref_kptr(evcnt.ev_name, evname, | | 1424 | deref_kptr(evcnt.ev_name, evname, |
1420 | (size_t)evcnt.ev_namelen + 1, "event chain trashed"); | | 1425 | (size_t)evcnt.ev_namelen + 1, "event chain trashed"); |
1421 | | | 1426 | |
1422 | (void)printf(type == EVCNT_TYPE_ANY ? | | 1427 | (void)printf(type == EVCNT_TYPE_ANY ? |
1423 | "%s %s%*s %16"PRIu64" %8"PRIu64" %s\n" : | | 1428 | "%s %s%*s %16"PRIu64" %8"PRIu64" %s\n" : |
1424 | "%s %s%*s %16"PRIu64" %8"PRIu64"\n", | | 1429 | "%s %s%*s %16"PRIu64" %8"PRIu64"\n", |
1425 | evgroup, evname, | | 1430 | evgroup, evname, |
1426 | 34 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "", | | 1431 | 34 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "", |
1427 | evcnt.ev_count, | | 1432 | evcnt.ev_count, |
1428 | (evcnt.ev_count / uptime), | | 1433 | (evcnt.ev_count / uptime), |
1429 | (evcnt.ev_type < __arraycount(evtypes) ? | | 1434 | (evcnt.ev_type < __arraycount(evtypes) ? |
1430 | evtypes[evcnt.ev_type] : "?")); | | 1435 | evtypes[evcnt.ev_type] : "?")); |
1431 | | | 1436 | |
1432 | counttotal += evcnt.ev_count; | | 1437 | counttotal += evcnt.ev_count; |
1433 | } | | 1438 | } |
1434 | if (type != EVCNT_TYPE_ANY) | | 1439 | if (type != EVCNT_TYPE_ANY) |
1435 | (void)printf("%-34s %16"PRIu64" %8"PRIu64"\n", | | 1440 | (void)printf("%-34s %16"PRIu64" %8"PRIu64"\n", |
1436 | "Total", counttotal, counttotal / uptime); | | 1441 | "Total", counttotal, counttotal / uptime); |
1437 | } | | 1442 | } |
1438 | | | 1443 | |
1439 | static void | | 1444 | static void |
1440 | dopool_sysctl(int verbose, int wide) | | 1445 | dopool_sysctl(int verbose, int wide) |
1441 | { | | 1446 | { |
1442 | uint64_t total, inuse, this_total, this_inuse; | | 1447 | uint64_t total, inuse, this_total, this_inuse; |
1443 | struct { | | 1448 | struct { |
1444 | uint64_t pt_nget; | | 1449 | uint64_t pt_nget; |
1445 | uint64_t pt_nfail; | | 1450 | uint64_t pt_nfail; |
1446 | uint64_t pt_nput; | | 1451 | uint64_t pt_nput; |
1447 | uint64_t pt_nout; | | 1452 | uint64_t pt_nout; |
1448 | uint64_t pt_nitems; | | 1453 | uint64_t pt_nitems; |
1449 | uint64_t pt_npagealloc; | | 1454 | uint64_t pt_npagealloc; |
1450 | uint64_t pt_npagefree; | | 1455 | uint64_t pt_npagefree; |
1451 | uint64_t pt_npages; | | 1456 | uint64_t pt_npages; |
1452 | } pool_totals; | | 1457 | } pool_totals; |
1453 | size_t i, len; | | 1458 | size_t i, len; |
1454 | int name_len, ovflw; | | 1459 | int name_len, ovflw; |
1455 | struct pool_sysctl *pp, *data; | | 1460 | struct pool_sysctl *pp, *data; |
1456 | char maxp[32]; | | 1461 | char maxp[32]; |
1457 | | | 1462 | |
1458 | data = asysctlbyname("kern.pool", &len); | | 1463 | data = asysctlbyname("kern.pool", &len); |
1459 | if (data == NULL) | | 1464 | if (data == NULL) |
1460 | err(1, "failed to read kern.pool"); | | 1465 | err(1, "failed to read kern.pool"); |
1461 | | | 1466 | |
1462 | memset(&pool_totals, 0, sizeof pool_totals); | | 1467 | memset(&pool_totals, 0, sizeof pool_totals); |
1463 | total = inuse = 0; | | 1468 | total = inuse = 0; |
1464 | len /= sizeof(*data); | | 1469 | len /= sizeof(*data); |
1465 | | | 1470 | |
1466 | (void)printf("Memory resource pool statistics\n"); | | 1471 | (void)printf("Memory resource pool statistics\n"); |
1467 | (void)printf( | | 1472 | (void)printf( |
1468 | "%-*s%*s%*s%*s%*s%s%s%*s%*s%*s%s%*s%6s%*s%5s%s%s\n", | | 1473 | "%-*s%*s%*s%*s%*s%s%s%*s%*s%*s%s%*s%6s%*s%5s%s%s\n", |
1469 | wide ? 16 : 11, "Name", | | 1474 | wide ? 16 : 11, "Name", |
1470 | wide ? 7 : 5, "Size", | | 1475 | wide ? 7 : 5, "Size", |
1471 | wide ? 12 : 9, "Requests", | | 1476 | wide ? 12 : 9, "Requests", |
1472 | wide ? 8 : 5, "Fail", | | 1477 | wide ? 8 : 5, "Fail", |
1473 | wide ? 12 : 9, "Releases", | | 1478 | wide ? 12 : 9, "Releases", |
1474 | wide ? " InUse" : "", | | 1479 | wide ? " InUse" : "", |
1475 | wide ? " Avail" : "", | | 1480 | wide ? " Avail" : "", |
1476 | wide ? 11 : 6, "Pgreq", | | 1481 | wide ? 11 : 6, "Pgreq", |
1477 | wide ? 11 : 6, "Pgrel", | | 1482 | wide ? 11 : 6, "Pgrel", |
1478 | wide ? 8 : 6, "Npage", | | 1483 | wide ? 8 : 6, "Npage", |
1479 | wide ? " PageSz" : "", | | 1484 | wide ? " PageSz" : "", |
1480 | wide ? 7 : 6, "Hiwat", | | 1485 | wide ? 7 : 6, "Hiwat", |
1481 | "Minpg", | | 1486 | "Minpg", |
1482 | wide ? 7 : 6, "Maxpg", | | 1487 | wide ? 7 : 6, "Maxpg", |
1483 | "Idle", | | 1488 | "Idle", |
1484 | wide ? " Flags" : "", | | 1489 | wide ? " Flags" : "", |
1485 | wide ? " Util" : ""); | | 1490 | wide ? " Util" : ""); |
1486 | | | 1491 | |
1487 | name_len = MIN((int)sizeof(pp->pr_wchan), wide ? 16 : 11); | | 1492 | name_len = MIN((int)sizeof(pp->pr_wchan), wide ? 16 : 11); |
1488 | for (i = 0; i < len; ++i) { | | 1493 | for (i = 0; i < len; ++i) { |
1489 | pp = &data[i]; | | 1494 | pp = &data[i]; |
1490 | if (pp->pr_nget == 0 && !verbose) | | 1495 | if (pp->pr_nget == 0 && !verbose) |
1491 | continue; | | 1496 | continue; |
1492 | if (pp->pr_maxpages == UINT_MAX) | | 1497 | if (pp->pr_maxpages == UINT_MAX) |
1493 | (void)snprintf(maxp, sizeof(maxp), "inf"); | | 1498 | (void)snprintf(maxp, sizeof(maxp), "inf"); |
1494 | else | | 1499 | else |
1495 | (void)snprintf(maxp, sizeof(maxp), "%" PRIu64, | | 1500 | (void)snprintf(maxp, sizeof(maxp), "%" PRIu64, |
1496 | pp->pr_maxpages); | | 1501 | pp->pr_maxpages); |
1497 | ovflw = 0; | | 1502 | ovflw = 0; |
1498 | PRWORD(ovflw, "%-*s", name_len, 0, pp->pr_wchan); | | 1503 | PRWORD(ovflw, "%-*s", name_len, 0, pp->pr_wchan); |
1499 | PRWORD(ovflw, " %*" PRIu64, wide ? 7 : 5, 1, pp->pr_size); | | 1504 | PRWORD(ovflw, " %*" PRIu64, wide ? 7 : 5, 1, pp->pr_size); |
1500 | PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pp->pr_nget); | | 1505 | PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pp->pr_nget); |
1501 | pool_totals.pt_nget += pp->pr_nget; | | 1506 | pool_totals.pt_nget += pp->pr_nget; |
1502 | PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 5, 1, pp->pr_nfail); | | 1507 | PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 5, 1, pp->pr_nfail); |
1503 | pool_totals.pt_nfail += pp->pr_nfail; | | 1508 | pool_totals.pt_nfail += pp->pr_nfail; |
1504 | PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pp->pr_nput); | | 1509 | PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pp->pr_nput); |
1505 | pool_totals.pt_nput += pp->pr_nput; | | 1510 | pool_totals.pt_nput += pp->pr_nput; |
1506 | if (wide) { | | 1511 | if (wide) { |
1507 | PRWORD(ovflw, " %*" PRIu64, 9, 1, pp->pr_nout); | | 1512 | PRWORD(ovflw, " %*" PRIu64, 9, 1, pp->pr_nout); |
1508 | pool_totals.pt_nout += pp->pr_nout; | | 1513 | pool_totals.pt_nout += pp->pr_nout; |
1509 | PRWORD(ovflw, " %*" PRIu64, 9, 1, pp->pr_nitems); | | 1514 | PRWORD(ovflw, " %*" PRIu64, 9, 1, pp->pr_nitems); |
1510 | pool_totals.pt_nitems += pp->pr_nitems; | | 1515 | pool_totals.pt_nitems += pp->pr_nitems; |
1511 | } | | 1516 | } |
1512 | PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pp->pr_npagealloc); | | 1517 | PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pp->pr_npagealloc); |
1513 | pool_totals.pt_npagealloc += pp->pr_npagealloc; | | 1518 | pool_totals.pt_npagealloc += pp->pr_npagealloc; |
1514 | PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pp->pr_npagefree); | | 1519 | PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pp->pr_npagefree); |
1515 | pool_totals.pt_npagefree += pp->pr_npagefree; | | 1520 | pool_totals.pt_npagefree += pp->pr_npagefree; |
1516 | PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 6, 1, pp->pr_npages); | | 1521 | PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 6, 1, pp->pr_npages); |
1517 | pool_totals.pt_npages += pp->pr_npages; | | 1522 | pool_totals.pt_npages += pp->pr_npages; |
1518 | if (wide) | | 1523 | if (wide) |
1519 | PRWORD(ovflw, " %*" PRIu64, 7, 1, pp->pr_pagesize); | | 1524 | PRWORD(ovflw, " %*" PRIu64, 7, 1, pp->pr_pagesize); |
1520 | PRWORD(ovflw, " %*" PRIu64, wide ? 7 : 6, 1, pp->pr_hiwat); | | 1525 | PRWORD(ovflw, " %*" PRIu64, wide ? 7 : 6, 1, pp->pr_hiwat); |
1521 | PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_minpages); | | 1526 | PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_minpages); |
1522 | PRWORD(ovflw, " %*s", wide ? 7 : 6, 1, maxp); | | 1527 | PRWORD(ovflw, " %*s", wide ? 7 : 6, 1, maxp); |
1523 | PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_nidle); | | 1528 | PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_nidle); |
1524 | if (wide) | | 1529 | if (wide) |
1525 | PRWORD(ovflw, " 0x%0*" PRIx64, 6, 1, | | 1530 | PRWORD(ovflw, " 0x%0*" PRIx64, 6, 1, |
1526 | pp->pr_flags); | | 1531 | pp->pr_flags); |
1527 | | | 1532 | |
1528 | this_inuse = pp->pr_nout * pp->pr_size; | | 1533 | this_inuse = pp->pr_nout * pp->pr_size; |
1529 | this_total = pp->pr_npages * pp->pr_pagesize; | | 1534 | this_total = pp->pr_npages * pp->pr_pagesize; |
1530 | if (pp->pr_flags & PR_RECURSIVE) { | | 1535 | if (pp->pr_flags & PR_RECURSIVE) { |
1531 | /* | | 1536 | /* |
1532 | * Don't count in-use memory, since it's part | | 1537 | * Don't count in-use memory, since it's part |
1533 | * of another pool and will be accounted for | | 1538 | * of another pool and will be accounted for |
1534 | * there. | | 1539 | * there. |
1535 | */ | | 1540 | */ |
1536 | total += (this_total - this_inuse); | | 1541 | total += (this_total - this_inuse); |
1537 | } else { | | 1542 | } else { |
1538 | inuse += this_inuse; | | 1543 | inuse += this_inuse; |
1539 | total += this_total; | | 1544 | total += this_total; |
1540 | } | | 1545 | } |
1541 | if (wide) { | | 1546 | if (wide) { |
1542 | if (this_total == 0) | | 1547 | if (this_total == 0) |
1543 | (void)printf(" ---"); | | 1548 | (void)printf(" ---"); |
1544 | else | | 1549 | else |
1545 | (void)printf(" %5.1f%%", | | 1550 | (void)printf(" %5.1f%%", |
1546 | (100.0 * this_inuse) / this_total); | | 1551 | (100.0 * this_inuse) / this_total); |
1547 | } | | 1552 | } |
1548 | (void)printf("\n"); | | 1553 | (void)printf("\n"); |
1549 | } | | 1554 | } |
1550 | ovflw = 0; | | 1555 | ovflw = 0; |
1551 | PRWORD(ovflw, "%-*s", name_len, 0, "Totals"); | | 1556 | PRWORD(ovflw, "%-*s", name_len, 0, "Totals"); |
1552 | PRWORD(ovflw, " %*s", wide ? 7 : 5, 1, ""); | | 1557 | PRWORD(ovflw, " %*s", wide ? 7 : 5, 1, ""); |
1553 | PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pool_totals.pt_nget); | | 1558 | PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pool_totals.pt_nget); |
1554 | PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 5, 1, pool_totals.pt_nfail); | | 1559 | PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 5, 1, pool_totals.pt_nfail); |
1555 | PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pool_totals.pt_nput); | | 1560 | PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pool_totals.pt_nput); |
1556 | if (wide) { | | 1561 | if (wide) { |
1557 | PRWORD(ovflw, " %*" PRIu64, 9, 1, pool_totals.pt_nout); | | 1562 | PRWORD(ovflw, " %*" PRIu64, 9, 1, pool_totals.pt_nout); |
1558 | PRWORD(ovflw, " %*" PRIu64, 9, 1, pool_totals.pt_nitems); | | 1563 | PRWORD(ovflw, " %*" PRIu64, 9, 1, pool_totals.pt_nitems); |
1559 | } | | 1564 | } |
1560 | PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pool_totals.pt_npagealloc); | | 1565 | PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pool_totals.pt_npagealloc); |
1561 | PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pool_totals.pt_npagefree); | | 1566 | PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pool_totals.pt_npagefree); |
1562 | PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 6, 1, pool_totals.pt_npages); | | 1567 | PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 6, 1, pool_totals.pt_npages); |
1563 | (void)printf("\n"); | | 1568 | (void)printf("\n"); |
1564 | | | 1569 | |
1565 | inuse /= KILO; | | 1570 | inuse /= KILO; |
1566 | total /= KILO; | | 1571 | total /= KILO; |
1567 | (void)printf( | | 1572 | (void)printf( |
1568 | "\nIn use %" PRIu64 "K, " | | 1573 | "\nIn use %" PRIu64 "K, " |
1569 | "total allocated %" PRIu64 "K; utilization %.1f%%\n", | | 1574 | "total allocated %" PRIu64 "K; utilization %.1f%%\n", |
1570 | inuse, total, (100.0 * inuse) / total); | | 1575 | inuse, total, (100.0 * inuse) / total); |
1571 | | | 1576 | |
1572 | free(data); | | 1577 | free(data); |
1573 | } | | 1578 | } |
1574 | | | 1579 | |
1575 | void | | 1580 | void |
1576 | dopool(int verbose, int wide) | | 1581 | dopool(int verbose, int wide) |
1577 | { | | 1582 | { |
1578 | int first, ovflw; | | 1583 | int first, ovflw; |
1579 | void *addr; | | 1584 | void *addr; |
1580 | long total, inuse, this_total, this_inuse; | | 1585 | long total, inuse, this_total, this_inuse; |
1581 | struct { | | 1586 | struct { |
1582 | uint64_t pt_nget; | | 1587 | uint64_t pt_nget; |
1583 | uint64_t pt_nfail; | | 1588 | uint64_t pt_nfail; |
1584 | uint64_t pt_nput; | | 1589 | uint64_t pt_nput; |
1585 | uint64_t pt_nout; | | 1590 | uint64_t pt_nout; |
1586 | uint64_t pt_nitems; | | 1591 | uint64_t pt_nitems; |
1587 | uint64_t pt_npagealloc; | | 1592 | uint64_t pt_npagealloc; |
1588 | uint64_t pt_npagefree; | | 1593 | uint64_t pt_npagefree; |
1589 | uint64_t pt_npages; | | 1594 | uint64_t pt_npages; |
1590 | } pool_totals; | | 1595 | } pool_totals; |
1591 | TAILQ_HEAD(,pool) pool_head; | | 1596 | TAILQ_HEAD(,pool) pool_head; |
1592 | struct pool pool, *pp = &pool; | | 1597 | struct pool pool, *pp = &pool; |
1593 | struct pool_allocator pa; | | 1598 | struct pool_allocator pa; |
1594 | char maxp[32], name[32]; | | 1599 | char maxp[32], name[32]; |
1595 | | | 1600 | |
1596 | if (memf == NULL) | | 1601 | if (memf == NULL) |
1597 | return dopool_sysctl(verbose, wide); | | 1602 | return dopool_sysctl(verbose, wide); |
1598 | | | 1603 | |
1599 | memset(&pool_totals, 0, sizeof pool_totals); | | 1604 | memset(&pool_totals, 0, sizeof pool_totals); |
1600 | kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head)); | | 1605 | kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head)); |
1601 | addr = TAILQ_FIRST(&pool_head); | | 1606 | addr = TAILQ_FIRST(&pool_head); |
1602 | | | 1607 | |
1603 | total = inuse = 0; | | 1608 | total = inuse = 0; |
1604 | | | 1609 | |
1605 | for (first = 1; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist) ) { | | 1610 | for (first = 1; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist) ) { |
1606 | deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed"); | | 1611 | deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed"); |
1607 | deref_kptr(pp->pr_alloc, &pa, sizeof(pa), | | 1612 | deref_kptr(pp->pr_alloc, &pa, sizeof(pa), |
1608 | "pool allocator trashed"); | | 1613 | "pool allocator trashed"); |
1609 | deref_kptr(pp->pr_wchan, name, sizeof(name), | | 1614 | deref_kptr(pp->pr_wchan, name, sizeof(name), |
1610 | "pool wait channel trashed"); | | 1615 | "pool wait channel trashed"); |
1611 | name[sizeof(name)-1] = '\0'; | | 1616 | name[sizeof(name)-1] = '\0'; |
1612 | | | 1617 | |
1613 | if (first) { | | 1618 | if (first) { |
1614 | (void)printf("Memory resource pool statistics\n"); | | 1619 | (void)printf("Memory resource pool statistics\n"); |
1615 | (void)printf( | | 1620 | (void)printf( |
1616 | "%-*s%*s%*s%*s%*s%s%s%*s%*s%*s%s%*s%6s%*s%5s%s%s\n", | | 1621 | "%-*s%*s%*s%*s%*s%s%s%*s%*s%*s%s%*s%6s%*s%5s%s%s\n", |
1617 | wide ? 16 : 11, "Name", | | 1622 | wide ? 16 : 11, "Name", |
1618 | wide ? 7 : 5, "Size", | | 1623 | wide ? 7 : 5, "Size", |
1619 | wide ? 12 : 9, "Requests", | | 1624 | wide ? 12 : 9, "Requests", |
1620 | wide ? 8 : 5, "Fail", | | 1625 | wide ? 8 : 5, "Fail", |
1621 | wide ? 12 : 9, "Releases", | | 1626 | wide ? 12 : 9, "Releases", |
1622 | wide ? " InUse" : "", | | 1627 | wide ? " InUse" : "", |
1623 | wide ? " Avail" : "", | | 1628 | wide ? " Avail" : "", |
1624 | wide ? 11 : 6, "Pgreq", | | 1629 | wide ? 11 : 6, "Pgreq", |
1625 | wide ? 11 : 6, "Pgrel", | | 1630 | wide ? 11 : 6, "Pgrel", |
1626 | wide ? 8 : 6, "Npage", | | 1631 | wide ? 8 : 6, "Npage", |
1627 | wide ? " PageSz" : "", | | 1632 | wide ? " PageSz" : "", |
1628 | wide ? 7 : 6, "Hiwat", | | 1633 | wide ? 7 : 6, "Hiwat", |
1629 | "Minpg", | | 1634 | "Minpg", |
1630 | wide ? 7 : 6, "Maxpg", | | 1635 | wide ? 7 : 6, "Maxpg", |
1631 | "Idle", | | 1636 | "Idle", |
1632 | wide ? " Flags" : "", | | 1637 | wide ? " Flags" : "", |
1633 | wide ? " Util" : ""); | | 1638 | wide ? " Util" : ""); |
1634 | first = 0; | | 1639 | first = 0; |
1635 | } | | 1640 | } |
1636 | if (pp->pr_nget == 0 && !verbose) | | 1641 | if (pp->pr_nget == 0 && !verbose) |
1637 | continue; | | 1642 | continue; |
1638 | if (pp->pr_maxpages == UINT_MAX) | | 1643 | if (pp->pr_maxpages == UINT_MAX) |
1639 | (void)snprintf(maxp, sizeof(maxp), "inf"); | | 1644 | (void)snprintf(maxp, sizeof(maxp), "inf"); |
1640 | else | | 1645 | else |
1641 | (void)snprintf(maxp, sizeof(maxp), "%u", | | 1646 | (void)snprintf(maxp, sizeof(maxp), "%u", |
1642 | pp->pr_maxpages); | | 1647 | pp->pr_maxpages); |
1643 | ovflw = 0; | | 1648 | ovflw = 0; |
1644 | PRWORD(ovflw, "%-*s", wide ? 16 : 11, 0, name); | | 1649 | PRWORD(ovflw, "%-*s", wide ? 16 : 11, 0, name); |
1645 | PRWORD(ovflw, " %*u", wide ? 7 : 5, 1, pp->pr_size); | | 1650 | PRWORD(ovflw, " %*u", wide ? 7 : 5, 1, pp->pr_size); |
1646 | PRWORD(ovflw, " %*lu", wide ? 12 : 9, 1, pp->pr_nget); | | 1651 | PRWORD(ovflw, " %*lu", wide ? 12 : 9, 1, pp->pr_nget); |
1647 | pool_totals.pt_nget += pp->pr_nget; | | 1652 | pool_totals.pt_nget += pp->pr_nget; |
1648 | PRWORD(ovflw, " %*lu", wide ? 8 : 5, 1, pp->pr_nfail); | | 1653 | PRWORD(ovflw, " %*lu", wide ? 8 : 5, 1, pp->pr_nfail); |
1649 | pool_totals.pt_nfail += pp->pr_nfail; | | 1654 | pool_totals.pt_nfail += pp->pr_nfail; |
1650 | PRWORD(ovflw, " %*lu", wide ? 12 : 9, 1, pp->pr_nput); | | 1655 | PRWORD(ovflw, " %*lu", wide ? 12 : 9, 1, pp->pr_nput); |
1651 | pool_totals.pt_nput += pp->pr_nput; | | 1656 | pool_totals.pt_nput += pp->pr_nput; |
1652 | if (wide) { | | 1657 | if (wide) { |
1653 | PRWORD(ovflw, " %*u", 9, 1, pp->pr_nout); | | 1658 | PRWORD(ovflw, " %*u", 9, 1, pp->pr_nout); |
1654 | pool_totals.pt_nout += pp->pr_nout; | | 1659 | pool_totals.pt_nout += pp->pr_nout; |
1655 | PRWORD(ovflw, " %*u", 9, 1, pp->pr_nitems); | | 1660 | PRWORD(ovflw, " %*u", 9, 1, pp->pr_nitems); |
1656 | pool_totals.pt_nitems += pp->pr_nitems; | | 1661 | pool_totals.pt_nitems += pp->pr_nitems; |
1657 | } | | 1662 | } |
1658 | PRWORD(ovflw, " %*lu", wide ? 11 : 6, 1, pp->pr_npagealloc); | | 1663 | PRWORD(ovflw, " %*lu", wide ? 11 : 6, 1, pp->pr_npagealloc); |
1659 | pool_totals.pt_npagealloc += pp->pr_npagealloc; | | 1664 | pool_totals.pt_npagealloc += pp->pr_npagealloc; |
1660 | PRWORD(ovflw, " %*lu", wide ? 11 : 6, 1, pp->pr_npagefree); | | 1665 | PRWORD(ovflw, " %*lu", wide ? 11 : 6, 1, pp->pr_npagefree); |
1661 | pool_totals.pt_npagefree += pp->pr_npagefree; | | 1666 | pool_totals.pt_npagefree += pp->pr_npagefree; |
1662 | PRWORD(ovflw, " %*u", wide ? 8 : 6, 1, pp->pr_npages); | | 1667 | PRWORD(ovflw, " %*u", wide ? 8 : 6, 1, pp->pr_npages); |
1663 | pool_totals.pt_npages += pp->pr_npages; | | 1668 | pool_totals.pt_npages += pp->pr_npages; |
1664 | if (wide) | | 1669 | if (wide) |
1665 | PRWORD(ovflw, " %*u", 7, 1, pa.pa_pagesz); | | 1670 | PRWORD(ovflw, " %*u", 7, 1, pa.pa_pagesz); |
1666 | PRWORD(ovflw, " %*u", wide ? 7 : 6, 1, pp->pr_hiwat); | | 1671 | PRWORD(ovflw, " %*u", wide ? 7 : 6, 1, pp->pr_hiwat); |
1667 | PRWORD(ovflw, " %*u", 6, 1, pp->pr_minpages); | | 1672 | PRWORD(ovflw, " %*u", 6, 1, pp->pr_minpages); |
1668 | PRWORD(ovflw, " %*s", wide ? 7 : 6, 1, maxp); | | 1673 | PRWORD(ovflw, " %*s", wide ? 7 : 6, 1, maxp); |
1669 | PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nidle); | | 1674 | PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nidle); |
1670 | if (wide) | | 1675 | if (wide) |
1671 | PRWORD(ovflw, " 0x%0*x", 6, 1, | | 1676 | PRWORD(ovflw, " 0x%0*x", 6, 1, |
1672 | pp->pr_flags | pp->pr_roflags); | | 1677 | pp->pr_flags | pp->pr_roflags); |
1673 | | | 1678 | |
1674 | this_inuse = pp->pr_nout * pp->pr_size; | | 1679 | this_inuse = pp->pr_nout * pp->pr_size; |
1675 | this_total = pp->pr_npages * pa.pa_pagesz; | | 1680 | this_total = pp->pr_npages * pa.pa_pagesz; |
1676 | if (pp->pr_roflags & PR_RECURSIVE) { | | 1681 | if (pp->pr_roflags & PR_RECURSIVE) { |
1677 | /* | | 1682 | /* |
1678 | * Don't count in-use memory, since it's part | | 1683 | * Don't count in-use memory, since it's part |
1679 | * of another pool and will be accounted for | | 1684 | * of another pool and will be accounted for |
1680 | * there. | | 1685 | * there. |
1681 | */ | | 1686 | */ |
1682 | total += (this_total - this_inuse); | | 1687 | total += (this_total - this_inuse); |
1683 | } else { | | 1688 | } else { |
1684 | inuse += this_inuse; | | 1689 | inuse += this_inuse; |
1685 | total += this_total; | | 1690 | total += this_total; |
1686 | } | | 1691 | } |
1687 | if (wide) { | | 1692 | if (wide) { |
1688 | if (this_total == 0) | | 1693 | if (this_total == 0) |
1689 | (void)printf(" ---"); | | 1694 | (void)printf(" ---"); |
1690 | else | | 1695 | else |
1691 | (void)printf(" %5.1f%%", | | 1696 | (void)printf(" %5.1f%%", |
1692 | (100.0 * this_inuse) / this_total); | | 1697 | (100.0 * this_inuse) / this_total); |
1693 | } | | 1698 | } |
1694 | (void)printf("\n"); | | 1699 | (void)printf("\n"); |
1695 | } | | 1700 | } |
1696 | ovflw = 0; | | 1701 | ovflw = 0; |
1697 | PRWORD(ovflw, "%-*s", wide ? 16 : 11, 0, "Totals"); | | 1702 | PRWORD(ovflw, "%-*s", wide ? 16 : 11, 0, "Totals"); |
1698 | PRWORD(ovflw, " %*s", wide ? 7 : 5, 1, ""); | | 1703 | PRWORD(ovflw, " %*s", wide ? 7 : 5, 1, ""); |
1699 | PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pool_totals.pt_nget); | | 1704 | PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pool_totals.pt_nget); |
1700 | PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 5, 1, pool_totals.pt_nfail); | | 1705 | PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 5, 1, pool_totals.pt_nfail); |
1701 | PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pool_totals.pt_nput); | | 1706 | PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pool_totals.pt_nput); |
1702 | if (wide) { | | 1707 | if (wide) { |
1703 | PRWORD(ovflw, " %*" PRIu64, 9, 1, pool_totals.pt_nout); | | 1708 | PRWORD(ovflw, " %*" PRIu64, 9, 1, pool_totals.pt_nout); |
1704 | PRWORD(ovflw, " %*" PRIu64, 9, 1, pool_totals.pt_nitems); | | 1709 | PRWORD(ovflw, " %*" PRIu64, 9, 1, pool_totals.pt_nitems); |
1705 | } | | 1710 | } |
1706 | PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pool_totals.pt_npagealloc); | | 1711 | PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pool_totals.pt_npagealloc); |
1707 | PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pool_totals.pt_npagefree); | | 1712 | PRWORD(ovflw, " %*" PRIu64, wide ? 11 : 6, 1, pool_totals.pt_npagefree); |
1708 | PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 6, 1, pool_totals.pt_npages); | | 1713 | PRWORD(ovflw, " %*" PRIu64, wide ? 8 : 6, 1, pool_totals.pt_npages); |
1709 | (void)printf("\n"); | | 1714 | (void)printf("\n"); |
1710 | | | 1715 | |
1711 | inuse /= KILO; | | 1716 | inuse /= KILO; |
1712 | total /= KILO; | | 1717 | total /= KILO; |
1713 | (void)printf( | | 1718 | (void)printf( |
1714 | "\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n", | | 1719 | "\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n", |
1715 | inuse, total, (100.0 * inuse) / total); | | 1720 | inuse, total, (100.0 * inuse) / total); |
1716 | } | | 1721 | } |
1717 | | | 1722 | |
1718 | static void | | 1723 | static void |
1719 | dopoolcache_sysctl(int verbose) | | 1724 | dopoolcache_sysctl(int verbose) |
1720 | { | | 1725 | { |
1721 | struct pool_sysctl *data, *pp; | | 1726 | struct pool_sysctl *data, *pp; |
1722 | size_t i, len; | | 1727 | size_t i, len; |
1723 | bool first = true; | | 1728 | bool first = true; |
1724 | int ovflw; | | 1729 | int ovflw; |
1725 | uint64_t tot; | | 1730 | uint64_t tot; |
1726 | double p; | | 1731 | double p; |
1727 | | | 1732 | |
1728 | data = asysctlbyname("kern.pool", &len); | | 1733 | data = asysctlbyname("kern.pool", &len); |
1729 | if (data == NULL) | | 1734 | if (data == NULL) |
1730 | err(1, "failed to read kern.pool"); | | 1735 | err(1, "failed to read kern.pool"); |
1731 | len /= sizeof(*data); | | 1736 | len /= sizeof(*data); |
1732 | | | 1737 | |
1733 | for (i = 0; i < len; ++i) { | | 1738 | for (i = 0; i < len; ++i) { |
1734 | pp = &data[i]; | | 1739 | pp = &data[i]; |
1735 | if (pp->pr_cache_meta_size == 0) | | 1740 | if (pp->pr_cache_meta_size == 0) |
1736 | continue; | | 1741 | continue; |
1737 | | | 1742 | |
1738 | if (pp->pr_cache_nmiss_global == 0 && !verbose) | | 1743 | if (pp->pr_cache_nmiss_global == 0 && !verbose) |
1739 | continue; | | 1744 | continue; |
1740 | | | 1745 | |
1741 | if (first) { | | 1746 | if (first) { |
1742 | (void)printf("Pool cache statistics.\n"); | | 1747 | (void)printf("Pool cache statistics.\n"); |
1743 | (void)printf("%-*s%*s%*s%*s%*s%*s%*s%*s%*s%*s\n", | | 1748 | (void)printf("%-*s%*s%*s%*s%*s%*s%*s%*s%*s%*s\n", |
1744 | 12, "Name", | | 1749 | 12, "Name", |
1745 | 6, "Spin", | | 1750 | 6, "Spin", |
1746 | 6, "GrpSz", | | 1751 | 6, "GrpSz", |
1747 | 5, "Full", | | 1752 | 5, "Full", |
1748 | 5, "Emty", | | 1753 | 5, "Emty", |
1749 | 10, "PoolLayer", | | 1754 | 10, "PoolLayer", |
1750 | 11, "CacheLayer", | | 1755 | 11, "CacheLayer", |
1751 | 6, "Hit%", | | 1756 | 6, "Hit%", |
1752 | 12, "CpuLayer", | | 1757 | 12, "CpuLayer", |
1753 | 6, "Hit%" | | 1758 | 6, "Hit%" |
1754 | ); | | 1759 | ); |
1755 | first = false; | | 1760 | first = false; |
1756 | } | | 1761 | } |
1757 | | | 1762 | |
1758 | ovflw = 0; | | 1763 | ovflw = 0; |
1759 | PRWORD(ovflw, "%-*s", MIN((int)sizeof(pp->pr_wchan), 13), 1, | | 1764 | PRWORD(ovflw, "%-*s", MIN((int)sizeof(pp->pr_wchan), 13), 1, |
1760 | pp->pr_wchan); | | 1765 | pp->pr_wchan); |
1761 | PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_cache_ncontended); | | 1766 | PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_cache_ncontended); |
1762 | PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_cache_meta_size); | | 1767 | PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_cache_meta_size); |
1763 | PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_cache_nfull); | | 1768 | PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_cache_nfull); |
1764 | PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_cache_nempty); | | 1769 | PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_cache_nempty); |
1765 | PRWORD(ovflw, " %*" PRIu64, 10, 1, pp->pr_cache_nmiss_global); | | 1770 | PRWORD(ovflw, " %*" PRIu64, 10, 1, pp->pr_cache_nmiss_global); |
1766 | | | 1771 | |
1767 | tot = pp->pr_cache_nhit_global + pp->pr_cache_nmiss_global; | | 1772 | tot = pp->pr_cache_nhit_global + pp->pr_cache_nmiss_global; |
1768 | p = pp->pr_cache_nhit_global * 100.0 / tot; | | 1773 | p = pp->pr_cache_nhit_global * 100.0 / tot; |
1769 | PRWORD(ovflw, " %*" PRIu64, 11, 1, tot); | | 1774 | PRWORD(ovflw, " %*" PRIu64, 11, 1, tot); |
1770 | PRWORD(ovflw, " %*.1f", 6, 1, p); | | 1775 | PRWORD(ovflw, " %*.1f", 6, 1, p); |
1771 | | | 1776 | |
1772 | tot = pp->pr_cache_nhit_pcpu + pp->pr_cache_nmiss_pcpu; | | 1777 | tot = pp->pr_cache_nhit_pcpu + pp->pr_cache_nmiss_pcpu; |
1773 | p = pp->pr_cache_nhit_pcpu * 100.0 / tot; | | 1778 | p = pp->pr_cache_nhit_pcpu * 100.0 / tot; |
1774 | PRWORD(ovflw, " %*" PRIu64, 12, 1, tot); | | 1779 | PRWORD(ovflw, " %*" PRIu64, 12, 1, tot); |
1775 | PRWORD(ovflw, " %*.1f", 6, 1, p); | | 1780 | PRWORD(ovflw, " %*.1f", 6, 1, p); |
1776 | printf("\n"); | | 1781 | printf("\n"); |
1777 | } | | 1782 | } |
1778 | } | | 1783 | } |
1779 | | | 1784 | |
1780 | void | | 1785 | void |
1781 | dopoolcache(int verbose) | | 1786 | dopoolcache(int verbose) |
1782 | { | | 1787 | { |
1783 | struct pool_cache pool_cache, *pc = &pool_cache; | | 1788 | struct pool_cache pool_cache, *pc = &pool_cache; |
1784 | pool_cache_cpu_t cache_cpu, *cc = &cache_cpu; | | 1789 | pool_cache_cpu_t cache_cpu, *cc = &cache_cpu; |
1785 | TAILQ_HEAD(,pool) pool_head; | | 1790 | TAILQ_HEAD(,pool) pool_head; |
1786 | struct pool pool, *pp = &pool; | | 1791 | struct pool pool, *pp = &pool; |
1787 | char name[32]; | | 1792 | char name[32]; |
1788 | uint64_t cpuhit, cpumiss, pchit, pcmiss, contended, tot; | | 1793 | uint64_t cpuhit, cpumiss, pchit, pcmiss, contended, tot; |
1789 | uint32_t nfull; | | 1794 | uint32_t nfull; |
1790 | void *addr; | | 1795 | void *addr; |
1791 | int first, ovflw; | | 1796 | int first, ovflw; |
1792 | size_t i; | | 1797 | size_t i; |
1793 | double p; | | 1798 | double p; |
1794 | | | 1799 | |
1795 | if (memf == NULL) | | 1800 | if (memf == NULL) |
1796 | return dopoolcache_sysctl(verbose); | | 1801 | return dopoolcache_sysctl(verbose); |
1797 | | | 1802 | |
1798 | kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head)); | | 1803 | kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head)); |
1799 | addr = TAILQ_FIRST(&pool_head); | | 1804 | addr = TAILQ_FIRST(&pool_head); |
1800 | | | 1805 | |
1801 | for (first = 1; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist) ) { | | 1806 | for (first = 1; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist) ) { |
1802 | deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed"); | | 1807 | deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed"); |
1803 | if (pp->pr_cache == NULL) | | 1808 | if (pp->pr_cache == NULL) |
1804 | continue; | | 1809 | continue; |
1805 | deref_kptr(pp->pr_wchan, name, sizeof(name), | | 1810 | deref_kptr(pp->pr_wchan, name, sizeof(name), |
1806 | "pool wait channel trashed"); | | 1811 | "pool wait channel trashed"); |
1807 | deref_kptr(pp->pr_cache, pc, sizeof(*pc), "pool cache trashed"); | | 1812 | deref_kptr(pp->pr_cache, pc, sizeof(*pc), "pool cache trashed"); |
1808 | name[sizeof(name)-1] = '\0'; | | 1813 | name[sizeof(name)-1] = '\0'; |
1809 | | | 1814 | |
1810 | cpuhit = 0; | | 1815 | cpuhit = 0; |
1811 | cpumiss = 0; | | 1816 | cpumiss = 0; |
1812 | pcmiss = 0; | | 1817 | pcmiss = 0; |
1813 | contended = 0; | | 1818 | contended = 0; |
1814 | nfull = 0; | | 1819 | nfull = 0; |
1815 | for (i = 0; i < __arraycount(pc->pc_cpus); i++) { | | 1820 | for (i = 0; i < __arraycount(pc->pc_cpus); i++) { |
1816 | if ((addr = pc->pc_cpus[i]) == NULL) | | 1821 | if ((addr = pc->pc_cpus[i]) == NULL) |
1817 | continue; | | 1822 | continue; |
1818 | deref_kptr(addr, cc, sizeof(*cc), | | 1823 | deref_kptr(addr, cc, sizeof(*cc), |
1819 | "pool cache cpu trashed"); | | 1824 | "pool cache cpu trashed"); |
1820 | cpuhit += cc->cc_hits; | | 1825 | cpuhit += cc->cc_hits; |
1821 | cpumiss += cc->cc_misses; | | 1826 | cpumiss += cc->cc_misses; |
1822 | pcmiss += cc->cc_pcmisses; | | 1827 | pcmiss += cc->cc_pcmisses; |
1823 | nfull += cc->cc_nfull; | | 1828 | nfull += cc->cc_nfull; |
1824 | contended += cc->cc_contended; | | 1829 | contended += cc->cc_contended; |
1825 | } | | 1830 | } |
1826 | pchit = cpumiss - pcmiss; | | 1831 | pchit = cpumiss - pcmiss; |
1827 | | | 1832 | |
1828 | if (pcmiss == 0 && !verbose) | | 1833 | if (pcmiss == 0 && !verbose) |
1829 | continue; | | 1834 | continue; |
1830 | | | 1835 | |
1831 | if (first) { | | 1836 | if (first) { |
1832 | (void)printf("Pool cache statistics.\n"); | | 1837 | (void)printf("Pool cache statistics.\n"); |
1833 | (void)printf("%-*s%*s%*s%*s%*s%*s%*s%*s%*s%*s\n", | | 1838 | (void)printf("%-*s%*s%*s%*s%*s%*s%*s%*s%*s%*s\n", |
1834 | 12, "Name", | | 1839 | 12, "Name", |
1835 | 6, "Spin", | | 1840 | 6, "Spin", |
1836 | 6, "GrpSz", | | 1841 | 6, "GrpSz", |
1837 | 5, "Full", | | 1842 | 5, "Full", |
1838 | 5, "Emty", | | 1843 | 5, "Emty", |
1839 | 10, "PoolLayer", | | 1844 | 10, "PoolLayer", |
1840 | 11, "CacheLayer", | | 1845 | 11, "CacheLayer", |
1841 | 6, "Hit%", | | 1846 | 6, "Hit%", |
1842 | 12, "CpuLayer", | | 1847 | 12, "CpuLayer", |
1843 | 6, "Hit%" | | 1848 | 6, "Hit%" |
1844 | ); | | 1849 | ); |
1845 | first = 0; | | 1850 | first = 0; |
1846 | } | | 1851 | } |
1847 | | | 1852 | |
1848 | ovflw = 0; | | 1853 | ovflw = 0; |
1849 | PRWORD(ovflw, "%-*s", 13, 1, name); | | 1854 | PRWORD(ovflw, "%-*s", 13, 1, name); |
1850 | PRWORD(ovflw, " %*llu", 6, 1, (long long)contended); | | 1855 | PRWORD(ovflw, " %*llu", 6, 1, (long long)contended); |
1851 | PRWORD(ovflw, " %*u", 6, 1, pc->pc_pcgsize); | | 1856 | PRWORD(ovflw, " %*u", 6, 1, pc->pc_pcgsize); |
1852 | PRWORD(ovflw, " %*u", 5, 1, nfull); | | 1857 | PRWORD(ovflw, " %*u", 5, 1, nfull); |
1853 | PRWORD(ovflw, " %*u", 5, 1, 0); | | 1858 | PRWORD(ovflw, " %*u", 5, 1, 0); |
1854 | PRWORD(ovflw, " %*llu", 10, 1, (long long)pcmiss); | | 1859 | PRWORD(ovflw, " %*llu", 10, 1, (long long)pcmiss); |
1855 | | | 1860 | |
1856 | tot = pchit + pcmiss; | | 1861 | tot = pchit + pcmiss; |
1857 | p = pchit * 100.0 / (tot); | | 1862 | p = pchit * 100.0 / (tot); |
1858 | PRWORD(ovflw, " %*llu", 11, 1, (long long)tot); | | 1863 | PRWORD(ovflw, " %*llu", 11, 1, (long long)tot); |
1859 | PRWORD(ovflw, " %*.1f", 6, 1, p); | | 1864 | PRWORD(ovflw, " %*.1f", 6, 1, p); |
1860 | | | 1865 | |
1861 | tot = cpuhit + cpumiss; | | 1866 | tot = cpuhit + cpumiss; |
1862 | p = cpuhit * 100.0 / (tot); | | 1867 | p = cpuhit * 100.0 / (tot); |
1863 | PRWORD(ovflw, " %*llu", 12, 1, (long long)tot); | | 1868 | PRWORD(ovflw, " %*llu", 12, 1, (long long)tot); |
1864 | PRWORD(ovflw, " %*.1f", 6, 1, p); | | 1869 | PRWORD(ovflw, " %*.1f", 6, 1, p); |
1865 | printf("\n"); | | 1870 | printf("\n"); |
1866 | } | | 1871 | } |
1867 | } | | 1872 | } |
1868 | | | 1873 | |
1869 | enum hashtype { /* from <sys/systm.h> */ | | 1874 | enum hashtype { /* from <sys/systm.h> */ |
1870 | HASH_LIST, | | 1875 | HASH_LIST, |
1871 | HASH_SLIST, | | 1876 | HASH_SLIST, |
1872 | HASH_TAILQ, | | 1877 | HASH_TAILQ, |
1873 | HASH_PSLIST | | 1878 | HASH_PSLIST |
1874 | }; | | 1879 | }; |
1875 | | | 1880 | |
1876 | struct uidinfo { /* XXX: no kernel header file */ | | 1881 | struct uidinfo { /* XXX: no kernel header file */ |
1877 | LIST_ENTRY(uidinfo) ui_hash; | | 1882 | LIST_ENTRY(uidinfo) ui_hash; |
1878 | uid_t ui_uid; | | 1883 | uid_t ui_uid; |
1879 | long ui_proccnt; | | 1884 | long ui_proccnt; |
1880 | }; | | 1885 | }; |
1881 | | | 1886 | |
1882 | struct kernel_hash { | | 1887 | struct kernel_hash { |
1883 | const char * description; /* description */ | | 1888 | const char * description; /* description */ |
1884 | int hashsize; /* nlist index for hash size */ | | 1889 | int hashsize; /* nlist index for hash size */ |
1885 | int hashtbl; /* nlist index for hash table */ | | 1890 | int hashtbl; /* nlist index for hash table */ |
1886 | enum hashtype type; /* type of hash table */ | | 1891 | enum hashtype type; /* type of hash table */ |
1887 | size_t offset; /* offset of {LIST,TAILQ}_NEXT */ | | 1892 | size_t offset; /* offset of {LIST,TAILQ}_NEXT */ |
1888 | } khashes[] = | | 1893 | } khashes[] = |
1889 | { | | 1894 | { |
1890 | { | | 1895 | { |
1891 | "buffer hash", | | 1896 | "buffer hash", |
1892 | X_BUFHASH, X_BUFHASHTBL, | | 1897 | X_BUFHASH, X_BUFHASHTBL, |
1893 | HASH_LIST, offsetof(struct buf, b_hash) | | 1898 | HASH_LIST, offsetof(struct buf, b_hash) |
1894 | }, { | | 1899 | }, { |
1895 | "ipv4 address -> interface hash", | | 1900 | "ipv4 address -> interface hash", |
1896 | X_IFADDRHASH, X_IFADDRHASHTBL, | | 1901 | X_IFADDRHASH, X_IFADDRHASHTBL, |
1897 | HASH_LIST, offsetof(struct in_ifaddr, ia_hash), | | 1902 | HASH_LIST, offsetof(struct in_ifaddr, ia_hash), |
1898 | }, { | | 1903 | }, { |
1899 | "user info (uid -> used processes) hash", | | 1904 | "user info (uid -> used processes) hash", |
1900 | X_UIHASH, X_UIHASHTBL, | | 1905 | X_UIHASH, X_UIHASHTBL, |
1901 | HASH_LIST, offsetof(struct uidinfo, ui_hash), | | 1906 | HASH_LIST, offsetof(struct uidinfo, ui_hash), |
1902 | }, { | | 1907 | }, { |
1903 | "vnode cache hash", | | 1908 | "vnode cache hash", |
1904 | X_VCACHEHASH, X_VCACHETBL, | | 1909 | X_VCACHEHASH, X_VCACHETBL, |
1905 | HASH_SLIST, offsetof(struct vnode_impl, vi_hash), | | 1910 | HASH_SLIST, offsetof(struct vnode_impl, vi_hash), |
1906 | }, { | | 1911 | }, { |
1907 | NULL, -1, -1, 0, 0, | | 1912 | NULL, -1, -1, 0, 0, |
1908 | } | | 1913 | } |
1909 | }; | | 1914 | }; |
1910 | | | 1915 | |
1911 | void | | 1916 | void |
1912 | dohashstat(int verbose, int todo, const char *hashname) | | 1917 | dohashstat(int verbose, int todo, const char *hashname) |
1913 | { | | 1918 | { |
1914 | LIST_HEAD(, generic) *hashtbl_list; | | 1919 | LIST_HEAD(, generic) *hashtbl_list; |
1915 | SLIST_HEAD(, generic) *hashtbl_slist; | | 1920 | SLIST_HEAD(, generic) *hashtbl_slist; |
1916 | TAILQ_HEAD(, generic) *hashtbl_tailq; | | 1921 | TAILQ_HEAD(, generic) *hashtbl_tailq; |
1917 | struct kernel_hash *curhash; | | 1922 | struct kernel_hash *curhash; |
1918 | void *hashaddr, *hashbuf, *nhashbuf, *nextaddr; | | 1923 | void *hashaddr, *hashbuf, *nhashbuf, *nextaddr; |
1919 | size_t elemsize, hashbufsize, thissize; | | 1924 | size_t elemsize, hashbufsize, thissize; |
1920 | u_long hashsize, i; | | 1925 | u_long hashsize, i; |
1921 | int used, items, chain, maxchain; | | 1926 | int used, items, chain, maxchain; |
1922 | | | 1927 | |
1923 | hashbuf = NULL; | | 1928 | hashbuf = NULL; |
1924 | hashbufsize = 0; | | 1929 | hashbufsize = 0; |
1925 | | | 1930 | |
1926 | if (todo & HASHLIST) { | | 1931 | if (todo & HASHLIST) { |
1927 | (void)printf("Supported hashes:\n"); | | 1932 | (void)printf("Supported hashes:\n"); |
1928 | for (curhash = khashes; curhash->description; curhash++) { | | 1933 | for (curhash = khashes; curhash->description; curhash++) { |
1929 | if (hashnl[curhash->hashsize].n_value == 0 || | | 1934 | if (hashnl[curhash->hashsize].n_value == 0 || |
1930 | hashnl[curhash->hashtbl].n_value == 0) | | 1935 | hashnl[curhash->hashtbl].n_value == 0) |
1931 | continue; | | 1936 | continue; |
1932 | (void)printf("\t%-16s%s\n", | | 1937 | (void)printf("\t%-16s%s\n", |
1933 | hashnl[curhash->hashsize].n_name + 1, | | 1938 | hashnl[curhash->hashsize].n_name + 1, |
1934 | curhash->description); | | 1939 | curhash->description); |
1935 | } | | 1940 | } |
1936 | return; | | 1941 | return; |
1937 | } | | 1942 | } |
1938 | | | 1943 | |
1939 | if (hashname != NULL) { | | 1944 | if (hashname != NULL) { |
1940 | for (curhash = khashes; curhash->description; curhash++) { | | 1945 | for (curhash = khashes; curhash->description; curhash++) { |
1941 | if (strcmp(hashnl[curhash->hashsize].n_name + 1, | | 1946 | if (strcmp(hashnl[curhash->hashsize].n_name + 1, |
1942 | hashname) == 0 && | | 1947 | hashname) == 0 && |
1943 | hashnl[curhash->hashsize].n_value != 0 && | | 1948 | hashnl[curhash->hashsize].n_value != 0 && |
1944 | hashnl[curhash->hashtbl].n_value != 0) | | 1949 | hashnl[curhash->hashtbl].n_value != 0) |
1945 | break; | | 1950 | break; |
1946 | } | | 1951 | } |
1947 | if (curhash->description == NULL) { | | 1952 | if (curhash->description == NULL) { |
1948 | warnx("%s: no such hash", hashname); | | 1953 | warnx("%s: no such hash", hashname); |
1949 | return; | | 1954 | return; |
1950 | } | | 1955 | } |
1951 | } | | 1956 | } |
1952 | | | 1957 | |
1953 | (void)printf( | | 1958 | (void)printf( |
1954 | "%-16s %8s %8s %8s %8s %8s %8s\n" | | 1959 | "%-16s %8s %8s %8s %8s %8s %8s\n" |
1955 | "%-16s %8s %8s %8s %8s %8s %8s\n", | | 1960 | "%-16s %8s %8s %8s %8s %8s %8s\n", |
1956 | "", "total", "used", "util", "num", "average", "maximum", | | 1961 | "", "total", "used", "util", "num", "average", "maximum", |
1957 | "hash table", "buckets", "buckets", "%", "items", "chain", | | 1962 | "hash table", "buckets", "buckets", "%", "items", "chain", |
1958 | "chain"); | | 1963 | "chain"); |
1959 | | | 1964 | |
1960 | for (curhash = khashes; curhash->description; curhash++) { | | 1965 | for (curhash = khashes; curhash->description; curhash++) { |
1961 | if (hashnl[curhash->hashsize].n_value == 0 || | | 1966 | if (hashnl[curhash->hashsize].n_value == 0 || |
1962 | hashnl[curhash->hashtbl].n_value == 0) | | 1967 | hashnl[curhash->hashtbl].n_value == 0) |
1963 | continue; | | 1968 | continue; |
1964 | if (hashname != NULL && | | 1969 | if (hashname != NULL && |
1965 | strcmp(hashnl[curhash->hashsize].n_name + 1, hashname)) | | 1970 | strcmp(hashnl[curhash->hashsize].n_name + 1, hashname)) |
1966 | continue; | | 1971 | continue; |
1967 | switch (curhash->type) { | | 1972 | switch (curhash->type) { |
1968 | case HASH_LIST: | | 1973 | case HASH_LIST: |
1969 | elemsize = sizeof(*hashtbl_list); | | 1974 | elemsize = sizeof(*hashtbl_list); |
1970 | break; | | 1975 | break; |
1971 | case HASH_SLIST: | | 1976 | case HASH_SLIST: |
1972 | elemsize = sizeof(*hashtbl_slist); | | 1977 | elemsize = sizeof(*hashtbl_slist); |
1973 | break; | | 1978 | break; |
1974 | case HASH_TAILQ: | | 1979 | case HASH_TAILQ: |
1975 | elemsize = sizeof(*hashtbl_tailq); | | 1980 | elemsize = sizeof(*hashtbl_tailq); |
1976 | break; | | 1981 | break; |
1977 | default: | | 1982 | default: |
1978 | /* shouldn't get here */ | | 1983 | /* shouldn't get here */ |
1979 | continue; | | 1984 | continue; |
1980 | } | | 1985 | } |
1981 | deref_kptr((void *)hashnl[curhash->hashsize].n_value, | | 1986 | deref_kptr((void *)hashnl[curhash->hashsize].n_value, |
1982 | &hashsize, sizeof(hashsize), | | 1987 | &hashsize, sizeof(hashsize), |
1983 | hashnl[curhash->hashsize].n_name); | | 1988 | hashnl[curhash->hashsize].n_name); |
1984 | hashsize++; | | 1989 | hashsize++; |
1985 | deref_kptr((void *)hashnl[curhash->hashtbl].n_value, | | 1990 | deref_kptr((void *)hashnl[curhash->hashtbl].n_value, |
1986 | &hashaddr, sizeof(hashaddr), | | 1991 | &hashaddr, sizeof(hashaddr), |
1987 | hashnl[curhash->hashtbl].n_name); | | 1992 | hashnl[curhash->hashtbl].n_name); |
1988 | if (verbose) | | 1993 | if (verbose) |
1989 | (void)printf( | | 1994 | (void)printf( |
1990 | "%s %lu, %s %p, offset %ld, elemsize %llu\n", | | 1995 | "%s %lu, %s %p, offset %ld, elemsize %llu\n", |
1991 | hashnl[curhash->hashsize].n_name + 1, hashsize, | | 1996 | hashnl[curhash->hashsize].n_name + 1, hashsize, |
1992 | hashnl[curhash->hashtbl].n_name + 1, hashaddr, | | 1997 | hashnl[curhash->hashtbl].n_name + 1, hashaddr, |
1993 | (long)curhash->offset, | | 1998 | (long)curhash->offset, |
1994 | (unsigned long long)elemsize); | | 1999 | (unsigned long long)elemsize); |
1995 | thissize = hashsize * elemsize; | | 2000 | thissize = hashsize * elemsize; |
1996 | if (hashbuf == NULL || thissize > hashbufsize) { | | 2001 | if (hashbuf == NULL || thissize > hashbufsize) { |
1997 | if ((nhashbuf = realloc(hashbuf, thissize)) == NULL) | | 2002 | if ((nhashbuf = realloc(hashbuf, thissize)) == NULL) |
1998 | errx(1, "malloc hashbuf %llu", | | 2003 | errx(1, "malloc hashbuf %llu", |
1999 | (unsigned long long)hashbufsize); | | 2004 | (unsigned long long)hashbufsize); |
2000 | hashbuf = nhashbuf; | | 2005 | hashbuf = nhashbuf; |
2001 | hashbufsize = thissize; | | 2006 | hashbufsize = thissize; |
2002 | } | | 2007 | } |
2003 | deref_kptr(hashaddr, hashbuf, thissize, | | 2008 | deref_kptr(hashaddr, hashbuf, thissize, |
2004 | hashnl[curhash->hashtbl].n_name); | | 2009 | hashnl[curhash->hashtbl].n_name); |
2005 | used = 0; | | 2010 | used = 0; |
2006 | items = maxchain = 0; | | 2011 | items = maxchain = 0; |
2007 | if (curhash->type == HASH_LIST) { | | 2012 | if (curhash->type == HASH_LIST) { |
2008 | hashtbl_list = hashbuf; | | 2013 | hashtbl_list = hashbuf; |
2009 | hashtbl_slist = NULL; | | 2014 | hashtbl_slist = NULL; |
2010 | hashtbl_tailq = NULL; | | 2015 | hashtbl_tailq = NULL; |
2011 | } else if (curhash->type == HASH_SLIST) { | | 2016 | } else if (curhash->type == HASH_SLIST) { |
2012 | hashtbl_list = NULL; | | 2017 | hashtbl_list = NULL; |
2013 | hashtbl_slist = hashbuf; | | 2018 | hashtbl_slist = hashbuf; |
2014 | hashtbl_tailq = NULL; | | 2019 | hashtbl_tailq = NULL; |
2015 | } else { | | 2020 | } else { |
2016 | hashtbl_list = NULL; | | 2021 | hashtbl_list = NULL; |
2017 | hashtbl_slist = NULL; | | 2022 | hashtbl_slist = NULL; |
2018 | hashtbl_tailq = hashbuf; | | 2023 | hashtbl_tailq = hashbuf; |
2019 | } | | 2024 | } |
2020 | for (i = 0; i < hashsize; i++) { | | 2025 | for (i = 0; i < hashsize; i++) { |
2021 | if (curhash->type == HASH_LIST) | | 2026 | if (curhash->type == HASH_LIST) |
2022 | nextaddr = LIST_FIRST(&hashtbl_list[i]); | | 2027 | nextaddr = LIST_FIRST(&hashtbl_list[i]); |
2023 | else if (curhash->type == HASH_SLIST) | | 2028 | else if (curhash->type == HASH_SLIST) |
2024 | nextaddr = SLIST_FIRST(&hashtbl_slist[i]); | | 2029 | nextaddr = SLIST_FIRST(&hashtbl_slist[i]); |
2025 | else | | 2030 | else |
2026 | nextaddr = TAILQ_FIRST(&hashtbl_tailq[i]); | | 2031 | nextaddr = TAILQ_FIRST(&hashtbl_tailq[i]); |
2027 | if (nextaddr == NULL) | | 2032 | if (nextaddr == NULL) |
2028 | continue; | | 2033 | continue; |
2029 | if (verbose) | | 2034 | if (verbose) |
2030 | (void)printf("%5lu: %p\n", i, nextaddr); | | 2035 | (void)printf("%5lu: %p\n", i, nextaddr); |
2031 | used++; | | 2036 | used++; |
2032 | chain = 0; | | 2037 | chain = 0; |
2033 | do { | | 2038 | do { |
2034 | chain++; | | 2039 | chain++; |
2035 | deref_kptr((char *)nextaddr + curhash->offset, | | 2040 | deref_kptr((char *)nextaddr + curhash->offset, |
2036 | &nextaddr, sizeof(void *), | | 2041 | &nextaddr, sizeof(void *), |
2037 | "hash chain corrupted"); | | 2042 | "hash chain corrupted"); |
2038 | if (verbose > 1) | | 2043 | if (verbose > 1) |
2039 | (void)printf("got nextaddr as %p\n", | | 2044 | (void)printf("got nextaddr as %p\n", |
2040 | nextaddr); | | 2045 | nextaddr); |
2041 | } while (nextaddr != NULL); | | 2046 | } while (nextaddr != NULL); |
2042 | items += chain; | | 2047 | items += chain; |
2043 | if (verbose && chain > 1) | | 2048 | if (verbose && chain > 1) |
2044 | (void)printf("\tchain = %d\n", chain); | | 2049 | (void)printf("\tchain = %d\n", chain); |
2045 | if (chain > maxchain) | | 2050 | if (chain > maxchain) |
2046 | maxchain = chain; | | 2051 | maxchain = chain; |
2047 | } | | 2052 | } |
2048 | (void)printf("%-16s %8ld %8d %8.2f %8d %8.2f %8d\n", | | 2053 | (void)printf("%-16s %8ld %8d %8.2f %8d %8.2f %8d\n", |
2049 | hashnl[curhash->hashsize].n_name + 1, | | 2054 | hashnl[curhash->hashsize].n_name + 1, |
2050 | hashsize, used, used * 100.0 / hashsize, | | 2055 | hashsize, used, used * 100.0 / hashsize, |
2051 | items, used ? (double)items / used : 0.0, maxchain); | | 2056 | items, used ? (double)items / used : 0.0, maxchain); |
2052 | } | | 2057 | } |
2053 | } | | 2058 | } |
2054 | | | 2059 | |
2055 | /* | | 2060 | /* |
2056 | * kreadc like kread but returns 1 if successful, 0 otherwise | | 2061 | * kreadc like kread but returns 1 if successful, 0 otherwise |
2057 | */ | | 2062 | */ |
2058 | int | | 2063 | int |
2059 | kreadc(struct nlist *nl, int nlx, void *addr, size_t size) | | 2064 | kreadc(struct nlist *nl, int nlx, void *addr, size_t size) |
2060 | { | | 2065 | { |
2061 | const char *sym; | | 2066 | const char *sym; |
2062 | | | 2067 | |
2063 | sym = nl[nlx].n_name; | | 2068 | sym = nl[nlx].n_name; |
2064 | if (*sym == '_') | | 2069 | if (*sym == '_') |
2065 | ++sym; | | 2070 | ++sym; |
2066 | if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) | | 2071 | if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) |
2067 | return 0; | | 2072 | return 0; |
2068 | deref_kptr((void *)nl[nlx].n_value, addr, size, sym); | | 2073 | deref_kptr((void *)nl[nlx].n_value, addr, size, sym); |
2069 | return 1; | | 2074 | return 1; |
2070 | } | | 2075 | } |
2071 | | | 2076 | |
2072 | /* | | 2077 | /* |
2073 | * kread reads something from the kernel, given its nlist index in namelist[]. | | 2078 | * kread reads something from the kernel, given its nlist index in namelist[]. |
2074 | */ | | 2079 | */ |
2075 | void | | 2080 | void |
2076 | kread(struct nlist *nl, int nlx, void *addr, size_t size) | | 2081 | kread(struct nlist *nl, int nlx, void *addr, size_t size) |
2077 | { | | 2082 | { |
2078 | const char *sym; | | 2083 | const char *sym; |
2079 | | | 2084 | |
2080 | sym = nl[nlx].n_name; | | 2085 | sym = nl[nlx].n_name; |
2081 | if (*sym == '_') | | 2086 | if (*sym == '_') |
2082 | ++sym; | | 2087 | ++sym; |
2083 | if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) | | 2088 | if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) |
2084 | errx(1, "symbol %s not defined", sym); | | 2089 | errx(1, "symbol %s not defined", sym); |
2085 | deref_kptr((void *)nl[nlx].n_value, addr, size, sym); | | 2090 | deref_kptr((void *)nl[nlx].n_value, addr, size, sym); |
2086 | } | | 2091 | } |
2087 | | | 2092 | |
2088 | /* | | 2093 | /* |
2089 | * Dereference the kernel pointer `kptr' and fill in the local copy | | 2094 | * Dereference the kernel pointer `kptr' and fill in the local copy |
2090 | * pointed to by `ptr'. The storage space must be pre-allocated, | | 2095 | * pointed to by `ptr'. The storage space must be pre-allocated, |
2091 | * and the size of the copy passed in `len'. | | 2096 | * and the size of the copy passed in `len'. |
2092 | */ | | 2097 | */ |
2093 | void | | 2098 | void |
2094 | deref_kptr(const void *kptr, void *ptr, size_t len, const char *msg) | | 2099 | deref_kptr(const void *kptr, void *ptr, size_t len, const char *msg) |
2095 | { | | 2100 | { |
2096 | | | 2101 | |
2097 | if (*msg == '_') | | 2102 | if (*msg == '_') |
2098 | msg++; | | 2103 | msg++; |
2099 | if ((size_t)kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len) | | 2104 | if ((size_t)kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len) |
2100 | errx(1, "kptr %lx: %s: %s", (u_long)kptr, msg, kvm_geterr(kd)); | | 2105 | errx(1, "kptr %lx: %s: %s", (u_long)kptr, msg, kvm_geterr(kd)); |
2101 | } | | 2106 | } |
2102 | | | 2107 | |
2103 | /* | | 2108 | /* |
2104 | * Traverse the kernel history buffers, performing the requested action. | | 2109 | * Traverse the kernel history buffers, performing the requested action. |
2105 | * | | 2110 | * |
2106 | * Note, we assume that if we're not listing, we're dumping. | | 2111 | * Note, we assume that if we're not listing, we're dumping. |
2107 | */ | | 2112 | */ |
2108 | void | | 2113 | void |
2109 | hist_traverse(int todo, const char *histname) | | 2114 | hist_traverse(int todo, const char *histname) |
2110 | { | | 2115 | { |
2111 | struct kern_history_head histhead; | | 2116 | struct kern_history_head histhead; |
2112 | struct kern_history hist, *histkva; | | 2117 | struct kern_history hist, *histkva; |
2113 | char *name = NULL; | | 2118 | char *name = NULL; |
2114 | size_t namelen = 0; | | 2119 | size_t namelen = 0; |
2115 | | | 2120 | |
2116 | if (histnl[0].n_value == 0) { | | 2121 | if (histnl[0].n_value == 0) { |
2117 | warnx("kernel history is not compiled into the kernel."); | | 2122 | warnx("kernel history is not compiled into the kernel."); |
2118 | return; | | 2123 | return; |
2119 | } | | 2124 | } |
2120 | | | 2125 | |
2121 | deref_kptr((void *)histnl[X_KERN_HISTORIES].n_value, &histhead, | | 2126 | deref_kptr((void *)histnl[X_KERN_HISTORIES].n_value, &histhead, |
2122 | sizeof(histhead), histnl[X_KERN_HISTORIES].n_name); | | 2127 | sizeof(histhead), histnl[X_KERN_HISTORIES].n_name); |
2123 | | | 2128 | |
2124 | if (histhead.lh_first == NULL) { | | 2129 | if (histhead.lh_first == NULL) { |
2125 | warnx("No active kernel history logs."); | | 2130 | warnx("No active kernel history logs."); |
2126 | return; | | 2131 | return; |
2127 | } | | 2132 | } |
2128 | | | 2133 | |
2129 | if (todo & HISTLIST) | | 2134 | if (todo & HISTLIST) |
2130 | (void)printf("Active kernel histories:"); | | 2135 | (void)printf("Active kernel histories:"); |
2131 | | | 2136 | |
2132 | for (histkva = LIST_FIRST(&histhead); histkva != NULL; | | 2137 | for (histkva = LIST_FIRST(&histhead); histkva != NULL; |
2133 | histkva = LIST_NEXT(&hist, list)) { | | 2138 | histkva = LIST_NEXT(&hist, list)) { |
2134 | deref_kptr(histkva, &hist, sizeof(hist), "histkva"); | | 2139 | deref_kptr(histkva, &hist, sizeof(hist), "histkva"); |
2135 | if (name == NULL || hist.namelen > namelen) { | | 2140 | if (name == NULL || hist.namelen > namelen) { |
2136 | if (name != NULL) | | 2141 | if (name != NULL) |
2137 | free(name); | | 2142 | free(name); |
2138 | namelen = hist.namelen; | | 2143 | namelen = hist.namelen; |
2139 | if ((name = malloc(namelen + 1)) == NULL) | | 2144 | if ((name = malloc(namelen + 1)) == NULL) |
2140 | err(1, "malloc history name"); | | 2145 | err(1, "malloc history name"); |
2141 | } | | 2146 | } |
2142 | | | 2147 | |
2143 | deref_kptr(hist.name, name, namelen, "history name"); | | 2148 | deref_kptr(hist.name, name, namelen, "history name"); |
2144 | name[namelen] = '\0'; | | 2149 | name[namelen] = '\0'; |
2145 | if (todo & HISTLIST) | | 2150 | if (todo & HISTLIST) |
2146 | (void)printf(" %s", name); | | 2151 | (void)printf(" %s", name); |
2147 | else { | | 2152 | else { |
2148 | /* | | 2153 | /* |
2149 | * If we're dumping all histories, do it, else | | 2154 | * If we're dumping all histories, do it, else |
2150 | * check to see if this is the one we want. | | 2155 | * check to see if this is the one we want. |
2151 | */ | | 2156 | */ |
2152 | if (histname == NULL || strcmp(histname, name) == 0) { | | 2157 | if (histname == NULL || strcmp(histname, name) == 0) { |
2153 | if (histname == NULL) | | 2158 | if (histname == NULL) |
2154 | (void)printf( | | 2159 | (void)printf( |
2155 | "\nkernel history `%s':\n", name); | | 2160 | "\nkernel history `%s':\n", name); |
2156 | hist_dodump(&hist); | | 2161 | hist_dodump(&hist); |
2157 | } | | 2162 | } |
2158 | } | | 2163 | } |
2159 | } | | 2164 | } |
2160 | | | 2165 | |
2161 | if (todo & HISTLIST) | | 2166 | if (todo & HISTLIST) |
2162 | (void)putchar('\n'); | | 2167 | (void)putchar('\n'); |
2163 | | | 2168 | |
2164 | if (name != NULL) | | 2169 | if (name != NULL) |
2165 | free(name); | | 2170 | free(name); |
2166 | } | | 2171 | } |
2167 | | | 2172 | |
2168 | /* | | 2173 | /* |
2169 | * Actually dump the history buffer at the specified KVA. | | 2174 | * Actually dump the history buffer at the specified KVA. |
2170 | */ | | 2175 | */ |
2171 | void | | 2176 | void |
2172 | hist_dodump(struct kern_history *histp) | | 2177 | hist_dodump(struct kern_history *histp) |
2173 | { | | 2178 | { |
2174 | struct kern_history_ent *histents, *e; | | 2179 | struct kern_history_ent *histents, *e; |
2175 | struct timeval tv; | | 2180 | struct timeval tv; |
2176 | size_t histsize; | | 2181 | size_t histsize; |
2177 | char *fmt = NULL, *fn = NULL; | | 2182 | char *fmt = NULL, *fn = NULL; |
2178 | size_t fmtlen = 0, fnlen = 0; | | 2183 | size_t fmtlen = 0, fnlen = 0; |
2179 | unsigned i; | | 2184 | unsigned i; |
2180 | | | 2185 | |
2181 | histsize = sizeof(struct kern_history_ent) * histp->n; | | 2186 | histsize = sizeof(struct kern_history_ent) * histp->n; |
2182 | | | 2187 | |
2183 | if ((histents = malloc(histsize)) == NULL) | | 2188 | if ((histents = malloc(histsize)) == NULL) |
2184 | err(1, "malloc history entries"); | | 2189 | err(1, "malloc history entries"); |
2185 | | | 2190 | |
2186 | (void)memset(histents, 0, histsize); | | 2191 | (void)memset(histents, 0, histsize); |
2187 | | | 2192 | |
2188 | (void)printf("%"PRIu32" entries, next is %"PRIu32"\n", | | 2193 | (void)printf("%"PRIu32" entries, next is %"PRIu32"\n", |
2189 | histp->n, histp->f); | | 2194 | histp->n, histp->f); |
2190 | | | 2195 | |
2191 | deref_kptr(histp->e, histents, histsize, "history entries"); | | 2196 | deref_kptr(histp->e, histents, histsize, "history entries"); |
2192 | i = histp->f; | | 2197 | i = histp->f; |
2193 | do { | | 2198 | do { |
2194 | e = &histents[i]; | | 2199 | e = &histents[i]; |
2195 | if (e->fmt != NULL) { | | 2200 | if (e->fmt != NULL) { |
2196 | if (fmt == NULL || e->fmtlen > fmtlen) { | | 2201 | if (fmt == NULL || e->fmtlen > fmtlen) { |
2197 | free(fmt); | | 2202 | free(fmt); |
2198 | fmtlen = e->fmtlen; | | 2203 | fmtlen = e->fmtlen; |
2199 | if ((fmt = malloc(fmtlen + 1)) == NULL) | | 2204 | if ((fmt = malloc(fmtlen + 1)) == NULL) |
2200 | err(1, "malloc printf format"); | | 2205 | err(1, "malloc printf format"); |
2201 | } | | 2206 | } |
2202 | if (fn == NULL || e->fnlen > fnlen) { | | 2207 | if (fn == NULL || e->fnlen > fnlen) { |
2203 | free(fn); | | 2208 | free(fn); |
2204 | fnlen = e->fnlen; | | 2209 | fnlen = e->fnlen; |
2205 | if ((fn = malloc(fnlen + 1)) == NULL) | | 2210 | if ((fn = malloc(fnlen + 1)) == NULL) |
2206 | err(1, "malloc function name"); | | 2211 | err(1, "malloc function name"); |
2207 | } | | 2212 | } |
2208 | | | 2213 | |
2209 | deref_kptr(e->fmt, fmt, fmtlen, "printf format"); | | 2214 | deref_kptr(e->fmt, fmt, fmtlen, "printf format"); |
2210 | fmt[fmtlen] = '\0'; | | 2215 | fmt[fmtlen] = '\0'; |
2211 | for (unsigned z = 0; z < fmtlen - 1; z++) { | | 2216 | for (unsigned z = 0; z < fmtlen - 1; z++) { |
2212 | if (fmt[z] == '%' && fmt[z+1] == 's') | | 2217 | if (fmt[z] == '%' && fmt[z+1] == 's') |
2213 | fmt[z+1] = 'p'; | | 2218 | fmt[z+1] = 'p'; |
2214 | } | | 2219 | } |
2215 | | | 2220 | |
2216 | deref_kptr(e->fn, fn, fnlen, "function name"); | | 2221 | deref_kptr(e->fn, fn, fnlen, "function name"); |
2217 | fn[fnlen] = '\0'; | | 2222 | fn[fnlen] = '\0'; |
2218 | | | 2223 | |
2219 | bintime2timeval(&e->bt, &tv); | | 2224 | bintime2timeval(&e->bt, &tv); |
2220 | (void)printf("%06ld.%06ld ", (long int)tv.tv_sec, | | 2225 | (void)printf("%06ld.%06ld ", (long int)tv.tv_sec, |
2221 | (long int)tv.tv_usec); | | 2226 | (long int)tv.tv_usec); |
2222 | (void)printf("%s#%" PRId32 "@%" PRId32 "d: ", | | 2227 | (void)printf("%s#%" PRId32 "@%" PRId32 "d: ", |
2223 | fn, e->call, e->cpunum); | | 2228 | fn, e->call, e->cpunum); |
2224 | (void)printf(fmt, e->v[0], e->v[1], e->v[2], e->v[3]); | | 2229 | (void)printf(fmt, e->v[0], e->v[1], e->v[2], e->v[3]); |
2225 | (void)putchar('\n'); | | 2230 | (void)putchar('\n'); |
2226 | } | | 2231 | } |
2227 | i = (i + 1) % histp->n; | | 2232 | i = (i + 1) % histp->n; |
2228 | } while (i != histp->f); | | 2233 | } while (i != histp->f); |
2229 | | | 2234 | |
2230 | free(histents); | | 2235 | free(histents); |
2231 | free(fmt); | | 2236 | free(fmt); |
2232 | free(fn); | | 2237 | free(fn); |
2233 | } | | 2238 | } |
2234 | | | 2239 | |
2235 | void | | 2240 | void |
2236 | hist_traverse_sysctl(int todo, const char *histname) | | 2241 | hist_traverse_sysctl(int todo, const char *histname) |
2237 | { | | 2242 | { |
2238 | int error; | | 2243 | int error; |
2239 | int mib[4]; | | 2244 | int mib[4]; |
2240 | unsigned int i; | | 2245 | unsigned int i; |
2241 | size_t len, miblen; | | 2246 | size_t len, miblen; |
2242 | struct sysctlnode query, histnode[32]; | | 2247 | struct sysctlnode query, histnode[32]; |
2243 | | | 2248 | |
2244 | /* retrieve names of available histories */ | | 2249 | /* retrieve names of available histories */ |
2245 | miblen = __arraycount(mib); | | 2250 | miblen = __arraycount(mib); |
2246 | error = sysctlnametomib("kern.hist", mib, &miblen); | | 2251 | error = sysctlnametomib("kern.hist", mib, &miblen); |
2247 | if (error != 0) { | | 2252 | if (error != 0) { |
2248 | if (errno == ENOENT) { | | 2253 | if (errno == ENOENT) { |
2249 | warnx("kernel history is not compiled into the kernel."); | | 2254 | warnx("kernel history is not compiled into the kernel."); |
2250 | return; | | 2255 | return; |
2251 | } else | | 2256 | } else |
2252 | err(EXIT_FAILURE, "nametomib failed"); | | 2257 | err(EXIT_FAILURE, "nametomib failed"); |
2253 | } | | 2258 | } |
2254 | | | 2259 | |
2255 | /* get the list of nodenames below kern.hist */ | | 2260 | /* get the list of nodenames below kern.hist */ |
2256 | mib[2] = CTL_QUERY; | | 2261 | mib[2] = CTL_QUERY; |
2257 | memset(&query, 0, sizeof(query)); | | 2262 | memset(&query, 0, sizeof(query)); |
2258 | query.sysctl_flags = SYSCTL_VERSION; | | 2263 | query.sysctl_flags = SYSCTL_VERSION; |
2259 | len = sizeof(histnode); | | 2264 | len = sizeof(histnode); |
2260 | error = sysctl(mib, 3, &histnode[0], &len, &query, sizeof(query)); | | 2265 | error = sysctl(mib, 3, &histnode[0], &len, &query, sizeof(query)); |