Thu Apr 1 06:23:15 2021 UTC ()
Use kernel sysctl hashstat collection instead of kmem grovelling
directly.  Also GC a few old hash nlist entries that no longer exist.


(simonb)
diff -r1.244 -r1.245 src/usr.bin/vmstat/vmstat.c

cvs diff -r1.244 -r1.245 src/usr.bin/vmstat/vmstat.c (expand / switch to unified diff)

--- src/usr.bin/vmstat/vmstat.c 2021/04/01 05:33:50 1.244
+++ src/usr.bin/vmstat/vmstat.c 2021/04/01 06:23:14 1.245
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: vmstat.c,v 1.244 2021/04/01 05:33:50 simonb Exp $ */ 1/* $NetBSD: vmstat.c,v 1.245 2021/04/01 06:23:14 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
@@ -61,27 +61,27 @@ @@ -61,27 +61,27 @@
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
72static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95"; 72static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95";
73#else 73#else
74__RCSID("$NetBSD: vmstat.c,v 1.244 2021/04/01 05:33:50 simonb Exp $"); 74__RCSID("$NetBSD: vmstat.c,v 1.245 2021/04/01 06:23:14 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>
@@ -103,26 +103,27 @@ __RCSID("$NetBSD: vmstat.c,v 1.244 2021/ @@ -103,26 +103,27 @@ __RCSID("$NetBSD: vmstat.c,v 1.244 2021/
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 <assert.h>
116#include <ctype.h> 117#include <ctype.h>
117#include <err.h> 118#include <err.h>
118#include <errno.h> 119#include <errno.h>
119#include <fcntl.h> 120#include <fcntl.h>
120#include <kvm.h> 121#include <kvm.h>
121#include <limits.h> 122#include <limits.h>
122#include <nlist.h> 123#include <nlist.h>
123#undef n_hash 124#undef n_hash
124#include <paths.h> 125#include <paths.h>
125#include <signal.h> 126#include <signal.h>
126#include <stdio.h> 127#include <stdio.h>
127#include <stddef.h> 128#include <stddef.h>
128#include <stdlib.h> 129#include <stdlib.h>
@@ -197,51 +198,43 @@ struct nlist intrnl[] = @@ -197,51 +198,43 @@ struct nlist intrnl[] =
197 { .n_name = "_intrcnt" }, 198 { .n_name = "_intrcnt" },
198#define X_EINTRCNT 3 199#define X_EINTRCNT 3
199 { .n_name = "_eintrcnt" }, 200 { .n_name = "_eintrcnt" },
200#define X_INTRNL_SIZE 4 201#define X_INTRNL_SIZE 4
201 { .n_name = NULL }, 202 { .n_name = NULL },
202}; 203};
203 204
204 205
205/* 206/*
206 * Namelist for hash statistics 207 * Namelist for hash statistics
207 */ 208 */
208struct nlist hashnl[] = 209struct nlist hashnl[] =
209{ 210{
210#define X_NFSNODE 0 211#define X_BUFHASH 0
211 { .n_name = "_nfsnodehash" }, 
212#define X_NFSNODETBL 1 
213 { .n_name = "_nfsnodehashtbl" }, 
214#define X_IHASH 2 
215 { .n_name = "_ihash" }, 
216#define X_IHASHTBL 3 
217 { .n_name = "_ihashtbl" }, 
218#define X_BUFHASH 4 
219 { .n_name = "_bufhash" }, 212 { .n_name = "_bufhash" },
220#define X_BUFHASHTBL 5 213#define X_BUFHASHTBL 1
221 { .n_name = "_bufhashtbl" }, 214 { .n_name = "_bufhashtbl" },
222#define X_UIHASH 6 215#define X_UIHASH 2
223 { .n_name = "_uihash" }, 216 { .n_name = "_uihash" },
224#define X_UIHASHTBL 7 217#define X_UIHASHTBL 3
225 { .n_name = "_uihashtbl" }, 218 { .n_name = "_uihashtbl" },
226#define X_IFADDRHASH 8 219#define X_IFADDRHASH 4
227 { .n_name = "_in_ifaddrhash" }, 220 { .n_name = "_in_ifaddrhash" },
228#define X_IFADDRHASHTBL 9 221#define X_IFADDRHASHTBL 5
229 { .n_name = "_in_ifaddrhashtbl" }, 222 { .n_name = "_in_ifaddrhashtbl" },
230#define X_VCACHEHASH 10 223#define X_VCACHEHASH 6
231 { .n_name = "_vcache_hashmask" }, 224 { .n_name = "_vcache_hashmask" },
232#define X_VCACHETBL 11 225#define X_VCACHETBL 7
233 { .n_name = "_vcache_hashtab" }, 226 { .n_name = "_vcache_hashtab" },
234#define X_HASHNL_SIZE 12 /* must be last */ 227#define X_HASHNL_SIZE 8 /* must be last */
235 { .n_name = NULL }, 228 { .n_name = NULL },
236}; 229};
237 230
238/* 231/*
239 * Namelist for kernel histories 232 * Namelist for kernel histories
240 */ 233 */
241struct nlist histnl[] = 234struct nlist histnl[] =
242{ 235{
243 { .n_name = "_kern_histories" }, 236 { .n_name = "_kern_histories" },
244#define X_KERN_HISTORIES 0 237#define X_KERN_HISTORIES 0
245 { .n_name = NULL }, 238 { .n_name = NULL },
246}; 239};
247 240
@@ -290,26 +283,27 @@ kvm_t *kd; @@ -290,26 +283,27 @@ kvm_t *kd;
290 (width) - (fixed) - (ovflw) > 0 ? \ 283 (width) - (fixed) - (ovflw) > 0 ? \
291 (width) - (fixed) - (ovflw) : 0, \ 284 (width) - (fixed) - (ovflw) : 0, \
292 (val)) - (width); \ 285 (val)) - (width); \
293 if ((ovflw) < 0) \ 286 if ((ovflw) < 0) \
294 (ovflw) = 0; \ 287 (ovflw) = 0; \
295} while (/* CONSTCOND */0) 288} while (/* CONSTCOND */0)
296 289
297void cpustats(int *); 290void cpustats(int *);
298void cpucounters(struct cpu_counter *); 291void cpucounters(struct cpu_counter *);
299void deref_kptr(const void *, void *, size_t, const char *); 292void deref_kptr(const void *, void *, size_t, const char *);
300void drvstats(int *); 293void drvstats(int *);
301void doevcnt(int verbose, int type); 294void doevcnt(int verbose, int type);
302void dohashstat(int, int, const char *); 295void dohashstat(int, int, const char *);
 296void dohashstat_sysctl(int, int, const char *);
303void dointr(int verbose); 297void dointr(int verbose);
304void dopool(int, int); 298void dopool(int, int);
305void dopoolcache(int); 299void dopoolcache(int);
306void dosum(void); 300void dosum(void);
307void dovmstat(struct timespec *, int); 301void dovmstat(struct timespec *, int);
308void print_total_hdr(void); 302void print_total_hdr(void);
309void dovmtotal(struct timespec *, int); 303void dovmtotal(struct timespec *, int);
310void kread(struct nlist *, int, void *, size_t); 304void kread(struct nlist *, int, void *, size_t);
311int kreadc(struct nlist *, int, void *, size_t); 305int kreadc(struct nlist *, int, void *, size_t);
312void needhdr(int); 306void needhdr(int);
313void getnlist(int); 307void getnlist(int);
314long getuptime(void); 308long getuptime(void);
315void printhdr(void); 309void printhdr(void);
@@ -1915,26 +1909,29 @@ struct kernel_hash { @@ -1915,26 +1909,29 @@ struct kernel_hash {
1915 1909
1916void 1910void
1917dohashstat(int verbose, int todo, const char *hashname) 1911dohashstat(int verbose, int todo, const char *hashname)
1918{ 1912{
1919 LIST_HEAD(, generic) *hashtbl_list; 1913 LIST_HEAD(, generic) *hashtbl_list;
1920 SLIST_HEAD(, generic) *hashtbl_slist; 1914 SLIST_HEAD(, generic) *hashtbl_slist;
1921 TAILQ_HEAD(, generic) *hashtbl_tailq; 1915 TAILQ_HEAD(, generic) *hashtbl_tailq;
1922 struct kernel_hash *curhash; 1916 struct kernel_hash *curhash;
1923 void *hashaddr, *hashbuf, *nhashbuf, *nextaddr; 1917 void *hashaddr, *hashbuf, *nhashbuf, *nextaddr;
1924 size_t elemsize, hashbufsize, thissize; 1918 size_t elemsize, hashbufsize, thissize;
1925 u_long hashsize, i; 1919 u_long hashsize, i;
1926 int used, items, chain, maxchain; 1920 int used, items, chain, maxchain;
1927 1921
 1922 if (memf == NULL)
 1923 return dohashstat_sysctl(verbose, todo, hashname);
 1924
1928 hashbuf = NULL; 1925 hashbuf = NULL;
1929 hashbufsize = 0; 1926 hashbufsize = 0;
1930 1927
1931 if (todo & HASHLIST) { 1928 if (todo & HASHLIST) {
1932 (void)printf("Supported hashes:\n"); 1929 (void)printf("Supported hashes:\n");
1933 for (curhash = khashes; curhash->description; curhash++) { 1930 for (curhash = khashes; curhash->description; curhash++) {
1934 if (hashnl[curhash->hashsize].n_value == 0 || 1931 if (hashnl[curhash->hashsize].n_value == 0 ||
1935 hashnl[curhash->hashtbl].n_value == 0) 1932 hashnl[curhash->hashtbl].n_value == 0)
1936 continue; 1933 continue;
1937 (void)printf("\t%-16s%s\n", 1934 (void)printf("\t%-16s%s\n",
1938 hashnl[curhash->hashsize].n_name + 1, 1935 hashnl[curhash->hashsize].n_name + 1,
1939 curhash->description); 1936 curhash->description);
1940 } 1937 }
@@ -2047,26 +2044,95 @@ dohashstat(int verbose, int todo, const  @@ -2047,26 +2044,95 @@ dohashstat(int verbose, int todo, const
2047 items += chain; 2044 items += chain;
2048 if (verbose && chain > 1) 2045 if (verbose && chain > 1)
2049 (void)printf("\tchain = %d\n", chain); 2046 (void)printf("\tchain = %d\n", chain);
2050 if (chain > maxchain) 2047 if (chain > maxchain)
2051 maxchain = chain; 2048 maxchain = chain;
2052 } 2049 }
2053 (void)printf("%-16s %8ld %8d %8.2f %8d %8.2f %8d\n", 2050 (void)printf("%-16s %8ld %8d %8.2f %8d %8.2f %8d\n",
2054 hashnl[curhash->hashsize].n_name + 1, 2051 hashnl[curhash->hashsize].n_name + 1,
2055 hashsize, used, used * 100.0 / hashsize, 2052 hashsize, used, used * 100.0 / hashsize,
2056 items, used ? (double)items / used : 0.0, maxchain); 2053 items, used ? (double)items / used : 0.0, maxchain);
2057 } 2054 }
2058} 2055}
2059 2056
 2057void
 2058dohashstat_sysctl(int verbose, int todo, const char *hashname)
 2059{
 2060 struct hashstat_sysctl hash, *data, *hs;
 2061 int mib[3];
 2062 int error;
 2063 size_t i, len, miblen;
 2064
 2065
 2066 miblen = __arraycount(mib);
 2067 error = sysctlnametomib("kern.hashstat", mib, &miblen);
 2068 if (error)
 2069 err(EXIT_FAILURE, "nametomib kern.hashstat failed");
 2070 assert(miblen < 3);
 2071
 2072 if (todo & HASHLIST) {
 2073 mib[miblen] = CTL_DESCRIBE;
 2074 miblen++;
 2075 };
 2076
 2077 if (hashname) {
 2078 mib[miblen] = CTL_QUERY;
 2079 miblen++;
 2080 memset(&hash, 0, sizeof(hash));
 2081 strlcpy(hash.hash_name, hashname, sizeof(hash.hash_name));
 2082 len = sizeof(hash);
 2083 error = sysctl(mib, miblen, &hash, &len, &hash, len);
 2084 if (error == ENOENT) {
 2085 err(1, "hash '%s' not found", hashname);
 2086 return;
 2087 } else if (error) {
 2088 err(1, "sysctl kern.hashstat query failed");
 2089 return;
 2090 }
 2091
 2092 data = &hash;
 2093 len = 1;
 2094 } else {
 2095 data = asysctl(mib, miblen, &len);
 2096 if (data == NULL)
 2097 err(1, "failed to read kern.hashstat");
 2098 len /= sizeof(*data);
 2099 }
 2100
 2101 if (todo & HASHLIST) {
 2102 printf("Supported hashes:\n");
 2103 for (i = 0, hs = data; i < len; i++, hs++) {
 2104 printf("\t%-16s%s\n", hs->hash_name, hs->hash_desc);
 2105 }
 2106 } else {
 2107 printf("%-16s %8s %8s %8s %8s %8s %8s\n"
 2108 "%-16s %8s %8s %8s %8s %8s %8s\n",
 2109 "", "total", "used", "util", "num", "average", "maximum",
 2110 "hash table", "buckets", "buckets", "%", "items", "chain",
 2111 "chain");
 2112 for (i = 0, hs = data; i < len; i++, hs++) {
 2113 printf("%-16s %8"PRId64" %8"PRId64" %8.2f %8"PRId64
 2114 " %8.2f %8"PRId64"\n",
 2115 hs->hash_name, hs->hash_size, hs->hash_used,
 2116 hs->hash_used * 100.0 / hs->hash_size, hs->hash_items,
 2117 hs->hash_used ? (double)hs->hash_items / hs->hash_used : 0.0,
 2118 hs->hash_maxchain);
 2119 }
 2120 }
 2121
 2122 if (!hashname && (data != NULL))
 2123 free(data);
 2124}
 2125
2060/* 2126/*
2061 * kreadc like kread but returns 1 if successful, 0 otherwise 2127 * kreadc like kread but returns 1 if successful, 0 otherwise
2062 */ 2128 */
2063int 2129int
2064kreadc(struct nlist *nl, int nlx, void *addr, size_t size) 2130kreadc(struct nlist *nl, int nlx, void *addr, size_t size)
2065{ 2131{
2066 const char *sym; 2132 const char *sym;
2067 2133
2068 sym = nl[nlx].n_name; 2134 sym = nl[nlx].n_name;
2069 if (*sym == '_') 2135 if (*sym == '_')
2070 ++sym; 2136 ++sym;
2071 if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) 2137 if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0)
2072 return 0; 2138 return 0;
@@ -2244,27 +2310,27 @@ hist_traverse_sysctl(int todo, const cha @@ -2244,27 +2310,27 @@ hist_traverse_sysctl(int todo, const cha
2244 int mib[4]; 2310 int mib[4];
2245 unsigned int i; 2311 unsigned int i;
2246 size_t len, miblen; 2312 size_t len, miblen;
2247 struct sysctlnode query, histnode[32]; 2313 struct sysctlnode query, histnode[32];
2248 2314
2249 /* retrieve names of available histories */ 2315 /* retrieve names of available histories */
2250 miblen = __arraycount(mib); 2316 miblen = __arraycount(mib);
2251 error = sysctlnametomib("kern.hist", mib, &miblen); 2317 error = sysctlnametomib("kern.hist", mib, &miblen);
2252 if (error != 0) { 2318 if (error != 0) {
2253 if (errno == ENOENT) { 2319 if (errno == ENOENT) {
2254 warnx("kernel history is not compiled into the kernel."); 2320 warnx("kernel history is not compiled into the kernel.");
2255 return; 2321 return;
2256 } else 2322 } else
2257 err(EXIT_FAILURE, "nametomib failed"); 2323 err(EXIT_FAILURE, "nametomib kern.hist failed");
2258 } 2324 }
2259  2325
2260 /* get the list of nodenames below kern.hist */ 2326 /* get the list of nodenames below kern.hist */
2261 mib[2] = CTL_QUERY; 2327 mib[2] = CTL_QUERY;
2262 memset(&query, 0, sizeof(query)); 2328 memset(&query, 0, sizeof(query));
2263 query.sysctl_flags = SYSCTL_VERSION; 2329 query.sysctl_flags = SYSCTL_VERSION;
2264 len = sizeof(histnode); 2330 len = sizeof(histnode);
2265 error = sysctl(mib, 3, &histnode[0], &len, &query, sizeof(query)); 2331 error = sysctl(mib, 3, &histnode[0], &len, &query, sizeof(query));
2266 if (error != 0) { 2332 if (error != 0) {
2267 err(1, "query failed"); 2333 err(1, "query failed");
2268 return; 2334 return;
2269 } 2335 }
2270 if (len == 0) { 2336 if (len == 0) {