xref: /dragonfly/usr.bin/systat/vmmeter.c (revision 92fc8b5c)
1 #define _KERNEL_STRUCTURES
2 #include <sys/param.h>
3 #include <sys/sysctl.h>
4 #include <sys/vmmeter.h>
5 #include "symbols.h"
6 
7 #include <err.h>
8 #include <kinfo.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <devstat.h>
13 
14 #include "systat.h"
15 #include "extern.h"
16 
17 #define X_START		1
18 #define CPU_START	1
19 #define CPU_STARTX	(3 + vmm_ncpus)
20 #define CPU_LABEL_W	7
21 
22 #define DRAW_ROW(n, y, w, fmt, args...) \
23 do { \
24 	mvprintw(y, n, fmt, w, args); \
25 	n += w; \
26 } while (0)
27 
28 static int vmm_ncpus;
29 static int vmm_fetched;
30 static struct vmmeter *vmm_cur, *vmm_prev;
31 static struct kinfo_cputime *vmm_cptime_cur, *vmm_cptime_prev;
32 static struct save_ctx symctx;
33 static int symbols_read;
34 
35 static void
36 getvmm(void)
37 {
38 	size_t sz;
39 	int i;
40 
41 	for (i = 0; i < vmm_ncpus; ++i) {
42 		struct vmmeter *vmm = &vmm_cur[i];
43 		char buf[64];
44 
45 		sz = sizeof(*vmm);
46 		snprintf(buf, sizeof(buf), "vm.cpu%d.vmmeter", i);
47 		if (sysctlbyname(buf, vmm, &sz, NULL, 0))
48 			err(1, "sysctlbyname(cpu%d)", i);
49 
50 		vmm->v_intr -= (vmm->v_timer + vmm->v_ipi);
51 	}
52 
53 	sz = vmm_ncpus * sizeof(struct kinfo_cputime);
54 	if (sysctlbyname("kern.cputime", vmm_cptime_cur, &sz, NULL, 0))
55 		err(1, "kern.cputime");
56 }
57 
58 int
59 initvmm(void)
60 {
61 	return 1;
62 }
63 
64 void
65 showvmm(void)
66 {
67 	int i, n;
68 
69 	if (!vmm_fetched)
70 		return;
71 
72 	for (i = 0; i < vmm_ncpus; ++i) {
73 		struct kinfo_cputime d;
74 		uint64_t cp_total = 0;
75 
76 		n = X_START + CPU_LABEL_W;
77 
78 #define D(idx, field) \
79 	(vmm_cur[idx].field - vmm_prev[idx].field) / (u_int)naptime
80 
81 		DRAW_ROW(n, CPU_START + i, 6, "%*u", D(i, v_timer));
82 		DRAW_ROW(n, CPU_START + i, 8, "%*u", D(i, v_ipi));
83 		DRAW_ROW(n, CPU_START + i, 8, "%*u", D(i, v_intr));
84 
85 #undef D
86 
87 #define CPUD(dif, idx, field) \
88 do { \
89 	dif.cp_##field = vmm_cptime_cur[idx].cp_##field - \
90 			 vmm_cptime_prev[idx].cp_##field; \
91 	cp_total += dif.cp_##field; \
92 } while (0)
93 
94 #define CPUV(dif, field) \
95 	(dif.cp_##field * 100.0) / cp_total
96 
97 		CPUD(d, i, user);
98 		CPUD(d, i, idle);
99 		CPUD(d, i, intr);
100 		CPUD(d, i, nice);
101 		CPUD(d, i, sys);
102 
103 		if (cp_total == 0)
104 			cp_total = 1;
105 
106 		DRAW_ROW(n, CPU_START + i, 7, "%*.1f", CPUV(d, user));
107 		DRAW_ROW(n, CPU_START + i, 7, "%*.1f", CPUV(d, nice));
108 		DRAW_ROW(n, CPU_START + i, 7, "%*.1f", CPUV(d, sys));
109 		DRAW_ROW(n, CPU_START + i, 7, "%*.1f", CPUV(d, intr));
110 		DRAW_ROW(n, CPU_START + i, 7, "%*.1f", CPUV(d, idle));
111 
112 #undef CPUV
113 #undef CPUD
114 #define CPUC(idx, field) vmm_cptime_cur[idx].cp_##field
115 
116 		n = X_START + CPU_LABEL_W;
117 
118 		DRAW_ROW(n, CPU_STARTX + i, 15, "%-*s", CPUC(i, msg));
119 		DRAW_ROW(n, CPU_STARTX + i, 35, "%-*s",
120 			address_to_symbol((void *)(intptr_t)CPUC(i, stallpc),
121 					  &symctx));
122 #undef CPUC
123 	}
124 }
125 
126 void
127 fetchvmm(void)
128 {
129 	vmm_fetched = 1;
130 
131 	memcpy(vmm_prev, vmm_cur, sizeof(struct vmmeter) * vmm_ncpus);
132 	memcpy(vmm_cptime_prev, vmm_cptime_cur,
133 	       sizeof(struct kinfo_cputime) * vmm_ncpus);
134 	getvmm();
135 }
136 
137 void
138 labelvmm(void)
139 {
140 	int i, n;
141 
142 	clear();
143 
144 	n = X_START + CPU_LABEL_W;
145 
146 	DRAW_ROW(n, CPU_START - 1, 6, "%*s", "timer");
147 	DRAW_ROW(n, CPU_START - 1, 8, "%*s", "ipi");
148 	DRAW_ROW(n, CPU_START - 1, 8, "%*s", "extint");
149 	DRAW_ROW(n, CPU_START - 1, 7, "%*s", "user%");
150 	DRAW_ROW(n, CPU_START - 1, 7, "%*s", "nice%");
151 	DRAW_ROW(n, CPU_START - 1, 7, "%*s", "sys%");
152 	DRAW_ROW(n, CPU_START - 1, 7, "%*s", "intr%");
153 	DRAW_ROW(n, CPU_START - 1, 7, "%*s", "idle%");
154 
155 	for (i = 0; i < vmm_ncpus; ++i)
156 		mvprintw(CPU_START + i, X_START, "cpu%d", i);
157 
158 	n = X_START + CPU_LABEL_W;
159 	DRAW_ROW(n, CPU_STARTX - 1, 15, "%-*s", "contention");
160 	DRAW_ROW(n, CPU_STARTX - 1, 35, "%-*s", "function");
161 
162 	for (i = 0; i < vmm_ncpus; ++i)
163 		mvprintw(CPU_STARTX + i, X_START, "cpu%d", i);
164 }
165 
166 WINDOW *
167 openvmm(void)
168 {
169 	if (symbols_read == 0) {
170 		symbols_read = 1;
171 		read_symbols(NULL);
172 	}
173 
174 	if (kinfo_get_cpus(&vmm_ncpus))
175 		err(1, "kinfo_get_cpus");
176 
177 	vmm_cur = calloc(vmm_ncpus, sizeof(*vmm_cur));
178 	if (vmm_cur == NULL)
179 		err(1, "calloc vmm_cur");
180 
181 	vmm_prev = calloc(vmm_ncpus, sizeof(*vmm_prev));
182 	if (vmm_prev == NULL)
183 		err(1, "calloc vmm_prev");
184 
185 	vmm_cptime_cur = calloc(vmm_ncpus, sizeof(*vmm_cptime_cur));
186 	if (vmm_cptime_cur == NULL)
187 		err(1, "calloc vmm_cptime_cur");
188 
189 	vmm_cptime_prev = calloc(vmm_ncpus, sizeof(*vmm_cptime_prev));
190 	if (vmm_cptime_prev == NULL)
191 		err(1, "calloc vmm_cptime_prev");
192 
193 	getvmm();
194 
195 	return (stdscr);
196 }
197 
198 void
199 closevmm(WINDOW *w)
200 {
201 	if (vmm_cur != NULL)
202 		free(vmm_cur);
203 	if (vmm_prev != NULL)
204 		free(vmm_prev);
205 
206 	if (vmm_cptime_cur != NULL)
207 		free(vmm_cptime_cur);
208 	if (vmm_cptime_prev != NULL)
209 		free(vmm_cptime_prev);
210 
211 	vmm_fetched = 0;
212 
213 	if (w == NULL)
214 		return;
215 	wclear(w);
216 	wrefresh(w);
217 }
218