xref: /dragonfly/usr.bin/systat/vmmeter.c (revision 65cc0652)
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 <unistd.h>
12 #include <string.h>
13 #include <devstat.h>
14 
15 #include "systat.h"
16 #include "extern.h"
17 
18 #define X_START		1
19 #define TOT_START	1
20 #define CPU_START	2
21 #define CPU_STARTX	(3 + vmm_ncpus)
22 #define CPU_LABEL_W	7
23 
24 #define DRAW_ROW(n, y, w, fmt, args...) \
25 do { \
26 	mvprintw(y, n, fmt, w - 1, args); \
27 	n += w; \
28 } while (0)
29 
30 #define DRAW_ROW2(n, y, w, fmt, args...) \
31 do { \
32 	mvprintw(y, n, fmt, w - 1, w - 1, args); \
33 	n += w; \
34 } while (0)
35 
36 static int vmm_ncpus;
37 static int vmm_fetched;
38 static struct vmmeter vmm_totcur, vmm_totprev;
39 static struct vmmeter *vmm_cur, *vmm_prev;
40 static struct kinfo_cputime *vmm_cptime_cur, *vmm_cptime_prev;
41 static struct save_ctx symctx;
42 static int symbols_read;
43 
44 static void
45 getvmm(void)
46 {
47 	size_t sz;
48 	int i;
49 
50 	vmm_totcur.v_ipi = 0;
51 	vmm_totcur.v_intr = 0;
52 	vmm_totcur.v_lock_colls = 0;
53 
54 	for (i = 0; i < vmm_ncpus; ++i) {
55 		struct vmmeter *vmm = &vmm_cur[i];
56 		char buf[64];
57 
58 		sz = sizeof(*vmm);
59 		snprintf(buf, sizeof(buf), "vm.cpu%d.vmmeter", i);
60 		if (sysctlbyname(buf, vmm, &sz, NULL, 0))
61 			err(1, "sysctlbyname(cpu%d)", i);
62 
63 		vmm->v_intr -= (vmm->v_timer + vmm->v_ipi);
64 
65 		vmm_totcur.v_ipi += vmm->v_ipi;
66 		vmm_totcur.v_intr += vmm->v_intr;
67 		vmm_totcur.v_lock_colls += vmm->v_lock_colls;
68 	}
69 
70 	sz = vmm_ncpus * sizeof(struct kinfo_cputime);
71 	if (sysctlbyname("kern.cputime", vmm_cptime_cur, &sz, NULL, 0))
72 		err(1, "kern.cputime");
73 }
74 
75 int
76 initvmm(void)
77 {
78 	return 1;
79 }
80 
81 void
82 showvmm(void)
83 {
84 	int i, n;
85 
86 	if (!vmm_fetched)
87 		return;
88 
89 	n = X_START + CPU_LABEL_W;
90 
91 #define DTOT(field) \
92 	(u_int)((vmm_totcur.field - vmm_totprev.field) / naptime)
93 
94 	DRAW_ROW(n, TOT_START, 6, "%*s", "");	/* timer */
95 	DRAW_ROW(n, TOT_START, 8, "%*u", DTOT(v_ipi));
96 	DRAW_ROW(n, TOT_START, 8, "%*u", DTOT(v_intr));
97 
98 	DRAW_ROW(n, TOT_START, 6, "%*s", "");	/* user */
99 /*	DRAW_ROW(n, TOT_START, 6, "%*s", "");	   nice */
100 	DRAW_ROW(n, TOT_START, 6, "%*s", "");	/* sys */
101 	DRAW_ROW(n, TOT_START, 6, "%*s", "");	/* intr */
102 	DRAW_ROW(n, TOT_START, 6, "%*s", "");	/* idle */
103 	if (DTOT(v_lock_colls) > 9999999)
104 		DRAW_ROW(n, TOT_START, 8, "%*u", 9999999);
105 	else
106 		DRAW_ROW(n, TOT_START, 8, "%*u", DTOT( v_lock_colls));
107 	DRAW_ROW2(n, TOT_START, 18, "%*.*s", ""); /* label */
108 	if (getuid() == 0) {
109 		DRAW_ROW2(n, TOT_START, 30, "%*.*s", ""); /* sample_pc */
110 #if 0
111 		DRAW_ROW2(n, TOT_START, 20, "%*.*s", ""); /* sample_sp */
112 #endif
113 	}
114 
115 #undef DTOT
116 
117 	for (i = 0; i < vmm_ncpus; ++i) {
118 		struct kinfo_cputime d;
119 		uint64_t cp_total = 0;
120 
121 		n = X_START + CPU_LABEL_W;
122 
123 #define D(idx, field) \
124 	(u_int)((vmm_cur[idx].field - vmm_prev[idx].field) / naptime)
125 
126 		DRAW_ROW(n, CPU_START + i, 6, "%*u", D(i, v_timer));
127 		DRAW_ROW(n, CPU_START + i, 8, "%*u", D(i, v_ipi));
128 		DRAW_ROW(n, CPU_START + i, 8, "%*u", D(i, v_intr));
129 
130 #define CPUD(dif, idx, field) \
131 do { \
132 	dif.cp_##field = vmm_cptime_cur[idx].cp_##field - \
133 			 vmm_cptime_prev[idx].cp_##field; \
134 	cp_total += dif.cp_##field; \
135 } while (0)
136 
137 #define CPUV(dif, field) \
138 	(dif.cp_##field * 100.0) / cp_total
139 
140 		CPUD(d, i, user);
141 		CPUD(d, i, idle);
142 		CPUD(d, i, intr);
143 		CPUD(d, i, nice);
144 		CPUD(d, i, sys);
145 
146 		if (cp_total == 0)
147 			cp_total = 1;
148 
149 		DRAW_ROW(n, CPU_START + i, 6, "%*.1f",
150 			 CPUV(d, user) + CPUV(d, nice));
151 /*		DRAW_ROW(n, CPU_START + i, 6, "%*.1f", CPUV(d, nice));*/
152 		DRAW_ROW(n, CPU_START + i, 6, "%*.1f", CPUV(d, sys));
153 		DRAW_ROW(n, CPU_START + i, 6, "%*.1f", CPUV(d, intr));
154 		DRAW_ROW(n, CPU_START + i, 6, "%*.1f", CPUV(d, idle));
155 
156 		/*
157 		 * Display token collision count and the last-colliding
158 		 * token name.
159 		 */
160 		if (D(i, v_lock_colls) > 9999999)
161 			DRAW_ROW(n, CPU_START + i, 8, "%*u", 9999999);
162 		else
163 			DRAW_ROW(n, CPU_START + i, 8, "%*u",
164 				 D(i, v_lock_colls));
165 
166 		if (D(i, v_lock_colls) == 0) {
167 			DRAW_ROW2(n, CPU_START + i, 18, "%*.*s", "");
168 		} else {
169 			DRAW_ROW2(n, CPU_START + i, 18, "%*.*s",
170 				  vmm_cur[i].v_lock_name);
171 		}
172 
173 #undef D
174 #undef CPUV
175 #undef CPUD
176 
177 #define CPUC(idx, field) vmm_cptime_cur[idx].cp_##field
178 
179 		if (vmm_cptime_cur[i].cp_sample_pc) {
180 			void *rip;
181 
182 			rip = (void *)(intptr_t)CPUC(i, sample_pc);
183 			DRAW_ROW2(n, CPU_START + i, 30, "%*.*s",
184 				  address_to_symbol(rip, &symctx));
185 #if 0
186 			DRAW_ROW(n, CPU_START + i, 19, " %016jx",
187 				 CPUC(i, sample_sp));
188 #endif
189 		}
190 #undef CPUC
191 	}
192 }
193 
194 void
195 fetchvmm(void)
196 {
197 	vmm_fetched = 1;
198 
199 	memcpy(vmm_prev, vmm_cur, sizeof(struct vmmeter) * vmm_ncpus);
200 	memcpy(vmm_cptime_prev, vmm_cptime_cur,
201 	       sizeof(struct kinfo_cputime) * vmm_ncpus);
202 	vmm_totprev = vmm_totcur;
203 	getvmm();
204 }
205 
206 void
207 labelvmm(void)
208 {
209 	int i, n;
210 
211 	clear();
212 
213 	n = X_START + CPU_LABEL_W;
214 
215 	DRAW_ROW(n, TOT_START - 1, 6, "%*s", "timer");
216 	DRAW_ROW(n, TOT_START - 1, 8, "%*s", "ipi");
217 	DRAW_ROW(n, TOT_START - 1, 8, "%*s", "extint");
218 	DRAW_ROW(n, TOT_START - 1, 6, "%*s", "user%");
219 /*	DRAW_ROW(n, TOT_START - 1, 6, "%*s", "nice%");*/
220 	DRAW_ROW(n, TOT_START - 1, 6, "%*s", "sys%");
221 	DRAW_ROW(n, TOT_START - 1, 6, "%*s", "intr%");
222 	DRAW_ROW(n, TOT_START - 1, 6, "%*s", "idle%");
223 	DRAW_ROW(n, TOT_START - 1, 8, "%*s", "smpcol");
224 	DRAW_ROW(n, TOT_START - 1, 18, "%*s", "label");
225 	if (getuid() == 0) {
226 		DRAW_ROW(n, TOT_START - 1, 30, "%*s", "sample_pc");
227 #if 0
228 		DRAW_ROW(n, TOT_START - 1, 18, "%*s", "sample_sp");
229 #endif
230 	}
231 
232 	mvprintw(TOT_START, X_START, "total");
233 	for (i = 0; i < vmm_ncpus; ++i)
234 		mvprintw(CPU_START + i, X_START, "cpu%d", i);
235 
236 #if 0
237 	n = X_START + CPU_LABEL_W;
238 	DRAW_ROW(n, TOT_STARTX - 1, 15, "%-*s", "contention");
239 	DRAW_ROW(n, TOT_STARTX - 1, 35, "%-*s", "function");
240 
241 	for (i = 0; i < vmm_ncpus; ++i)
242 		mvprintw(CPU_STARTX + i, X_START, "cpu%d", i);
243 #endif
244 }
245 
246 WINDOW *
247 openvmm(void)
248 {
249 	if (symbols_read == 0) {
250 		symbols_read = 1;
251 		read_symbols(NULL);
252 	}
253 
254 	if (kinfo_get_cpus(&vmm_ncpus))
255 		err(1, "kinfo_get_cpus");
256 
257 	vmm_cur = calloc(vmm_ncpus, sizeof(*vmm_cur));
258 	if (vmm_cur == NULL)
259 		err(1, "calloc vmm_cur");
260 
261 	vmm_prev = calloc(vmm_ncpus, sizeof(*vmm_prev));
262 	if (vmm_prev == NULL)
263 		err(1, "calloc vmm_prev");
264 
265 	vmm_cptime_cur = calloc(vmm_ncpus, sizeof(*vmm_cptime_cur));
266 	if (vmm_cptime_cur == NULL)
267 		err(1, "calloc vmm_cptime_cur");
268 
269 	vmm_cptime_prev = calloc(vmm_ncpus, sizeof(*vmm_cptime_prev));
270 	if (vmm_cptime_prev == NULL)
271 		err(1, "calloc vmm_cptime_prev");
272 
273 	getvmm();
274 
275 	return (stdscr);
276 }
277 
278 void
279 closevmm(WINDOW *w)
280 {
281 	if (vmm_cur != NULL)
282 		free(vmm_cur);
283 	if (vmm_prev != NULL)
284 		free(vmm_prev);
285 
286 	if (vmm_cptime_cur != NULL)
287 		free(vmm_cptime_cur);
288 	if (vmm_cptime_prev != NULL)
289 		free(vmm_cptime_prev);
290 
291 	vmm_fetched = 0;
292 
293 	if (w == NULL)
294 		return;
295 	wclear(w);
296 	wrefresh(w);
297 }
298