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