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