xref: /openbsd-src/usr.bin/systat/uvm.c (revision 8304c2525b687ea1cde1f5e35c6c1af5f8091220)
1*8304c252Smpi /*	$OpenBSD: uvm.c,v 1.11 2025/01/23 11:05:26 mpi Exp $	*/
24b6a654dSkrw /*
34b6a654dSkrw  * Copyright (c) 2008 Can Erkin Acar <canacar@openbsd.org>
44b6a654dSkrw  * Copyright (c) 2018 Kenneth R Westerback <krw@openbsd.org>
54b6a654dSkrw  *
64b6a654dSkrw  * Permission to use, copy, modify, and distribute this software for any
74b6a654dSkrw  * purpose with or without fee is hereby granted, provided that the above
84b6a654dSkrw  * copyright notice and this permission notice appear in all copies.
94b6a654dSkrw  *
104b6a654dSkrw  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
114b6a654dSkrw  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
124b6a654dSkrw  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
134b6a654dSkrw  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
144b6a654dSkrw  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
154b6a654dSkrw  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
164b6a654dSkrw  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
174b6a654dSkrw  */
184b6a654dSkrw 
194b6a654dSkrw #include <sys/types.h>
204b6a654dSkrw #include <sys/signal.h>
214b6a654dSkrw #include <sys/sysctl.h>
224b6a654dSkrw #include <sys/pool.h>
234b6a654dSkrw #include <ctype.h>
244b6a654dSkrw #include <err.h>
254b6a654dSkrw #include <errno.h>
264b6a654dSkrw #include <stdlib.h>
274b6a654dSkrw #include <string.h>
284b6a654dSkrw #include <limits.h>
294b6a654dSkrw 
304b6a654dSkrw #include "systat.h"
314b6a654dSkrw 
324b6a654dSkrw #ifndef nitems
334b6a654dSkrw #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
344b6a654dSkrw #endif
354b6a654dSkrw 
364b6a654dSkrw void print_uvm(void);
374b6a654dSkrw int  read_uvm(void);
384b6a654dSkrw int  select_uvm(void);
394b6a654dSkrw 
404b6a654dSkrw void print_uvmexp_field(field_def *, field_def *, int *, int *, const char *);
414b6a654dSkrw 
424b6a654dSkrw struct uvmexp uvmexp;
434b6a654dSkrw struct uvmexp last_uvmexp;
444b6a654dSkrw 
454b6a654dSkrw struct uvmline {
464b6a654dSkrw 	int	*v1;
474b6a654dSkrw 	int	*ov1;
484b6a654dSkrw 	char	*n1;
494b6a654dSkrw 	int	*v2;
504b6a654dSkrw 	int	*ov2;
514b6a654dSkrw 	char	*n2;
524b6a654dSkrw 	int	*v3;
534b6a654dSkrw 	int	*ov3;
544b6a654dSkrw 	char	*n3;
554b6a654dSkrw };
564b6a654dSkrw 
574b6a654dSkrw struct uvmline uvmline[] = {
584b6a654dSkrw 	{ NULL, NULL, "Page Counters",
594b6a654dSkrw 	  NULL, NULL, "Stats Counters",
604b6a654dSkrw 	  NULL, NULL, "Fault Counters" },
614b6a654dSkrw 	{ &uvmexp.npages, &last_uvmexp.npages, "npages",
624b6a654dSkrw 	  &uvmexp.faults, &last_uvmexp.faults, "faults",
634b6a654dSkrw 	  &uvmexp.fltnoram, &last_uvmexp.fltnoram, "fltnoram" },
644b6a654dSkrw 	{ &uvmexp.free, &last_uvmexp.free, "free",
654b6a654dSkrw 	  &uvmexp.traps, &last_uvmexp.traps, "traps",
664b6a654dSkrw 	  &uvmexp.fltnoanon, &last_uvmexp.fltnoanon, "fltnoanon" },
674b6a654dSkrw 	{ &uvmexp.active, &last_uvmexp.active, "active",
684b6a654dSkrw 	  &uvmexp.intrs, &last_uvmexp.intrs, "intrs",
694b6a654dSkrw 	  &uvmexp.fltnoamap, &last_uvmexp.fltnoamap, "fltnoamap" },
704b6a654dSkrw 	{ &uvmexp.inactive, &last_uvmexp.inactive, "inactive",
714b6a654dSkrw 	  &uvmexp.swtch, &last_uvmexp.swtch, "swtch",
724b6a654dSkrw 	  &uvmexp.fltpgwait, &last_uvmexp.fltpgwait, "fltpgwait" },
734b6a654dSkrw 	{ &uvmexp.paging, &last_uvmexp.paging, "paging",
744b6a654dSkrw 	  &uvmexp.softs, &last_uvmexp.softs, "softs",
754b6a654dSkrw 	  &uvmexp.fltpgrele, &last_uvmexp.fltpgrele, "fltpgrele" },
764b6a654dSkrw 	{ &uvmexp.wired, &last_uvmexp.wired, "wired",
774b6a654dSkrw 	  &uvmexp.syscalls, &last_uvmexp.syscalls, "syscalls",
784b6a654dSkrw 	  &uvmexp.fltrelck, &last_uvmexp.fltrelck, "fltrelck" },
794b6a654dSkrw 	{ &uvmexp.zeropages, &last_uvmexp.zeropages, "zeropages",
804b6a654dSkrw 	  &uvmexp.pageins, &last_uvmexp.pageins, "pageins",
814b6a654dSkrw 	  &uvmexp.fltrelckok, &last_uvmexp.fltrelckok, "fltrelckok" },
8282673a18Smpi 	{ &uvmexp.percpucaches, &last_uvmexp.percpucaches, "percpucaches",
83a1774ed1Skrw 	  &uvmexp.pgswapin, &last_uvmexp.pgswapin, "pgswapin",
844b6a654dSkrw 	  &uvmexp.fltanget, &last_uvmexp.fltanget, "fltanget" },
8582673a18Smpi 	{ NULL, NULL, NULL,
86a1774ed1Skrw 	  &uvmexp.pgswapout, &last_uvmexp.pgswapout, "pgswapout",
874b6a654dSkrw 	  &uvmexp.fltanretry, &last_uvmexp.fltanretry, "fltanretry" },
8865a05629Skrw 	{ NULL, NULL, NULL,
894b6a654dSkrw 	  &uvmexp.forks, &last_uvmexp.forks, "forks",
90a1774ed1Skrw 	  &uvmexp.fltamcopy, &last_uvmexp.fltamcopy, "fltamcopy" },
914b6a654dSkrw 	{ NULL, NULL, "Pageout Params",
92a1774ed1Skrw 	  &uvmexp.forks_ppwait, &last_uvmexp.forks_ppwait, "forks_ppwait",
93a1774ed1Skrw 	  &uvmexp.fltnamap, &last_uvmexp.fltnamap, "fltnamap" },
944b6a654dSkrw 	{ &uvmexp.freemin, &last_uvmexp.freemin, "freemin",
95a1774ed1Skrw 	  &uvmexp.forks_sharevm, &last_uvmexp.forks_sharevm, "forks_sharevm",
96a1774ed1Skrw 	  &uvmexp.fltnomap, &last_uvmexp.fltnomap, "fltnomap" },
974b6a654dSkrw 	{ &uvmexp.freetarg, &last_uvmexp.freetarg, "freetarg",
98a1774ed1Skrw 	  &uvmexp.pga_zerohit, &last_uvmexp.pga_zerohit, "pga_zerohit",
99a1774ed1Skrw 	  &uvmexp.fltlget, &last_uvmexp.fltlget, "fltlget" },
1004b6a654dSkrw 	{ &uvmexp.inactarg, &last_uvmexp.inactarg, "inactarg",
101a1774ed1Skrw 	  &uvmexp.pga_zeromiss, &last_uvmexp.pga_zeromiss, "pga_zeromiss",
102a1774ed1Skrw 	  &uvmexp.fltget, &last_uvmexp.fltget, "fltget" },
1034b6a654dSkrw 	{ &uvmexp.wiredmax, &last_uvmexp.wiredmax, "wiredmax",
1044b6a654dSkrw 	  NULL, NULL, NULL,
105a1774ed1Skrw 	  &uvmexp.flt_anon, &last_uvmexp.flt_anon, "flt_anon" },
106*8304c252Smpi 	{ NULL, NULL, NULL,
107*8304c252Smpi 	  NULL, NULL, NULL,
108a1774ed1Skrw 	  &uvmexp.flt_acow, &last_uvmexp.flt_acow, "flt_acow" },
109*8304c252Smpi 	{ NULL, NULL, NULL,
110*8304c252Smpi 	  NULL, NULL, "Daemon Counters",
111a1774ed1Skrw 	  &uvmexp.flt_obj, &last_uvmexp.flt_obj, "flt_obj" },
112*8304c252Smpi 	{ NULL, NULL, "Per-CPU Counters",
113*8304c252Smpi 	  &uvmexp.pdwoke, &last_uvmexp.pdwoke, "pdwoke",
114a1774ed1Skrw 	  &uvmexp.flt_prcopy, &last_uvmexp.flt_prcopy, "flt_prcopy" },
115*8304c252Smpi 	{ &uvmexp.pcphit, &last_uvmexp.pcphit, "pcphit",
116*8304c252Smpi 	  &uvmexp.pdrevs, &last_uvmexp.pdrevs, "pdrevs",
117a1774ed1Skrw 	  &uvmexp.flt_przero, &last_uvmexp.flt_przero, "flt_przero" },
118*8304c252Smpi 	{ &uvmexp.pcpmiss, &last_uvmexp.pcpmiss, "pcpmiss",
119*8304c252Smpi 	  &uvmexp.pdswout, &last_uvmexp.pdswout, "pdswout",
120a1774ed1Skrw 	  NULL, NULL, NULL },
121*8304c252Smpi 	{ NULL, NULL, NULL,
122a1774ed1Skrw 	  &uvmexp.pdfreed, &last_uvmexp.pdfreed, "pdfreed",
123*8304c252Smpi 	  NULL, NULL, NULL },
1244b6a654dSkrw 	{ NULL, NULL, NULL,
125a1774ed1Skrw 	  &uvmexp.pdscans, &last_uvmexp.pdscans, "pdscans",
126*8304c252Smpi 	  NULL, NULL, NULL },
1274b6a654dSkrw 	{ NULL, NULL, "Misc Counters",
128a1774ed1Skrw 	  &uvmexp.pdanscan, &last_uvmexp.pdanscan, "pdanscan",
129*8304c252Smpi 	  NULL, NULL, NULL },
1304b6a654dSkrw 	{ &uvmexp.fpswtch, &last_uvmexp.fpswtch, "fpswtch",
131a1774ed1Skrw 	  &uvmexp.pdobscan, &last_uvmexp.pdobscan, "pdobscan",
132*8304c252Smpi 	  NULL, NULL, NULL },
1334b6a654dSkrw 	{ &uvmexp.kmapent, &last_uvmexp.kmapent, "kmapent",
134a1774ed1Skrw 	  &uvmexp.pdreact, &last_uvmexp.pdreact, "pdreact",
135*8304c252Smpi 	  NULL, NULL, "Swap Counters" },
1364b6a654dSkrw 	{ NULL, NULL, NULL,
137a1774ed1Skrw 	  &uvmexp.pdbusy, &last_uvmexp.pdbusy, "pdbusy",
138*8304c252Smpi 	  &uvmexp.nswapdev, &last_uvmexp.nswapdev, "nswapdev" },
1394b6a654dSkrw 	{ NULL, NULL, "Constants",
140a1774ed1Skrw 	  &uvmexp.pdpageouts, &last_uvmexp.pdpageouts, "pdpageouts",
141*8304c252Smpi 	  &uvmexp.swpages, &last_uvmexp.swpages, "swpages" },
1424b6a654dSkrw 	{ &uvmexp.pagesize, &last_uvmexp.pagesize, "pagesize",
143a1774ed1Skrw 	  &uvmexp.pdpending, &last_uvmexp.pdpending, "pdpending",
144*8304c252Smpi 	  &uvmexp.swpginuse, &last_uvmexp.swpginuse, "swpginuse" },
1454b6a654dSkrw 	{ &uvmexp.pagemask, &last_uvmexp.pagemask, "pagemask",
146a1774ed1Skrw 	  &uvmexp.pddeact, &last_uvmexp.pddeact, "pddeact",
147*8304c252Smpi 	  &uvmexp.swpgonly, &last_uvmexp.swpgonly, "swpgonly" },
1484b6a654dSkrw 	{ &uvmexp.pageshift, &last_uvmexp.pageshift, "pageshift",
1494b6a654dSkrw 	  NULL, NULL, NULL,
150*8304c252Smpi 	  &uvmexp.nswget, &last_uvmexp.nswget, "nswget" }
1514b6a654dSkrw };
1524b6a654dSkrw 
1534b6a654dSkrw field_def fields_uvm[] = {
1544b6a654dSkrw 	{"",	 5,10,1, FLD_ALIGN_RIGHT,	-1,0,0,0 },
1554b6a654dSkrw 	{"",	18,19,1, FLD_ALIGN_LEFT,	-1,0,0,0 },
1564b6a654dSkrw 	{"",	 5,10,1, FLD_ALIGN_RIGHT,	-1,0,0,0 },
1574b6a654dSkrw 	{"",	18,19,1, FLD_ALIGN_LEFT,	-1,0,0,0 },
1584b6a654dSkrw 	{"",	 5,10,1, FLD_ALIGN_RIGHT,	-1,0,0,0 },
1594b6a654dSkrw 	{"",	18,19,1, FLD_ALIGN_LEFT,	-1,0,0,0 },
1604b6a654dSkrw };
1614b6a654dSkrw 
1624b6a654dSkrw #define	FLD_VALUE1		FIELD_ADDR(fields_uvm,  0)
1634b6a654dSkrw #define	FLD_NAME1		FIELD_ADDR(fields_uvm,  1)
1644b6a654dSkrw #define	FLD_VALUE2		FIELD_ADDR(fields_uvm,  2)
1654b6a654dSkrw #define	FLD_NAME2		FIELD_ADDR(fields_uvm,  3)
1664b6a654dSkrw #define	FLD_VALUE3		FIELD_ADDR(fields_uvm,  4)
1674b6a654dSkrw #define	FLD_NAME3		FIELD_ADDR(fields_uvm,  5)
1684b6a654dSkrw 
1694b6a654dSkrw /* Define views */
1704b6a654dSkrw field_def *view_uvm_0[] = {
1714b6a654dSkrw 	FLD_VALUE1, FLD_NAME1,
1724b6a654dSkrw 	FLD_VALUE2, FLD_NAME2,
1734b6a654dSkrw 	FLD_VALUE3, FLD_NAME3,
1744b6a654dSkrw 	NULL
1754b6a654dSkrw };
1764b6a654dSkrw 
1774b6a654dSkrw /* Define view managers */
1784b6a654dSkrw struct view_manager uvm_mgr = {
1794b6a654dSkrw 	"UVM", select_uvm, read_uvm, NULL, print_header,
1804b6a654dSkrw 	print_uvm, keyboard_callback, NULL, NULL
1814b6a654dSkrw };
1824b6a654dSkrw 
1834b6a654dSkrw field_view uvm_view = {
1844b6a654dSkrw 	view_uvm_0,
1854b6a654dSkrw 	"uvm",
1864b6a654dSkrw 	'5',
1874b6a654dSkrw 	&uvm_mgr
1884b6a654dSkrw };
1894b6a654dSkrw 
1904b6a654dSkrw int
1914b6a654dSkrw select_uvm(void)
1924b6a654dSkrw {
1934b6a654dSkrw 	return (0);
1944b6a654dSkrw }
1954b6a654dSkrw 
1964b6a654dSkrw int
1974b6a654dSkrw read_uvm(void)
1984b6a654dSkrw {
1994b6a654dSkrw 	static int uvmexp_mib[2] = { CTL_VM, VM_UVMEXP };
2004b6a654dSkrw 	size_t size;
2014b6a654dSkrw 
2024b6a654dSkrw 	num_disp = nitems(uvmline);
2034b6a654dSkrw 	memcpy(&last_uvmexp, &uvmexp, sizeof(uvmexp));
2044b6a654dSkrw 
2054b6a654dSkrw 	size = sizeof(uvmexp);
2063aaa63ebSderaadt 	if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) == -1) {
2074b6a654dSkrw 		error("Can't get VM_UVMEXP: %s\n", strerror(errno));
2084b6a654dSkrw 		memset(&uvmexp, 0, sizeof(uvmexp));
2094b6a654dSkrw 	}
2104b6a654dSkrw 
2114b6a654dSkrw 	return 0;
2124b6a654dSkrw }
2134b6a654dSkrw 
2144b6a654dSkrw void
2154b6a654dSkrw print_uvmexp_field(field_def *fvalue, field_def *fname, int *new, int *old,
2164b6a654dSkrw     const char *name)
2174b6a654dSkrw {
2184b6a654dSkrw 	char *uppername;
219c1a2d5c1Sbluhm 	size_t len, i;
2204b6a654dSkrw 
2214b6a654dSkrw 	if (new == NULL && name == NULL)
2224b6a654dSkrw 		return;
2234b6a654dSkrw 
2244b6a654dSkrw 	if (new == NULL) {
2254b6a654dSkrw 		print_fld_str(fvalue, "=====");
2264b6a654dSkrw 		print_fld_str(fname, name);
2274b6a654dSkrw 		return;
2284b6a654dSkrw 	}
2294b6a654dSkrw 
2304b6a654dSkrw 	if (*new != 0)
2314b6a654dSkrw 		print_fld_ssize(fvalue, *new);
2324b6a654dSkrw 	if (*new == *old) {
2334b6a654dSkrw 		print_fld_str(fname, name);
2344b6a654dSkrw 		return;
2354b6a654dSkrw 	}
236c1a2d5c1Sbluhm 	len = strlen(name);
237c1a2d5c1Sbluhm 	uppername = malloc(len + 1);
2384b6a654dSkrw 	if (uppername == NULL)
239c1a2d5c1Sbluhm 		err(1, "malloc");
240c1a2d5c1Sbluhm 	for (i = 0; i < len; i++)
2414b6a654dSkrw 		uppername[i] = toupper(name[i]);
242c1a2d5c1Sbluhm 	uppername[len] = '\0';
2434b6a654dSkrw 	print_fld_str(fname, uppername);
2444b6a654dSkrw 	free(uppername);
2454b6a654dSkrw }
2464b6a654dSkrw 
2474b6a654dSkrw void
2484b6a654dSkrw print_uvm(void)
2494b6a654dSkrw {
2504b6a654dSkrw 	struct uvmline *l;
2514b6a654dSkrw 	int i, maxline;
2524b6a654dSkrw 
2534b6a654dSkrw 	maxline = nitems(uvmline);
2544b6a654dSkrw 	if (maxline > (dispstart + maxprint))
2554b6a654dSkrw 		maxline = dispstart + maxprint;
2564b6a654dSkrw 
2574b6a654dSkrw 	for (i = dispstart; i < nitems(uvmline); i++) {
2584b6a654dSkrw 		l = &uvmline[i];
2594b6a654dSkrw 		print_uvmexp_field(FLD_VALUE1, FLD_NAME1, l->v1, l->ov1, l->n1);
2604b6a654dSkrw 		print_uvmexp_field(FLD_VALUE2, FLD_NAME2, l->v2, l->ov2, l->n2);
2614b6a654dSkrw 		print_uvmexp_field(FLD_VALUE3, FLD_NAME3, l->v3, l->ov3, l->n3);
2624b6a654dSkrw 		end_line();
2634b6a654dSkrw 	}
2644b6a654dSkrw }
2654b6a654dSkrw 
2664b6a654dSkrw int
2674b6a654dSkrw inituvm(void)
2684b6a654dSkrw {
2694b6a654dSkrw 	add_view(&uvm_view);
2704b6a654dSkrw 	read_uvm();
2714b6a654dSkrw 
2724b6a654dSkrw 	return(0);
2734b6a654dSkrw }
274