xref: /dragonfly/usr.bin/systat/vmmeter.c (revision 3525c8d74d4e5def7280ed7d9bcc7ccc744bd025)
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   3
21 #define CPU_STARTX  (CPU_START + 1 + 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 #define DRAW_ROWX(n, y, w, fmt, args...)          \
37 do {                                                        \
38           mvprintw(y, n, fmt, args);              \
39           n += w;                                           \
40 } while (0)
41 
42 static int vmm_ncpus;
43 static int vmm_fetched;
44 static struct vmmeter vmm_totcur, vmm_totprev;
45 static struct vmmeter *vmm_cur, *vmm_prev;
46 static struct kinfo_cputime *vmm_cptime_cur, *vmm_cptime_prev;
47 static struct save_ctx symctx;
48 static int symbols_read;
49 
50 static void
getvmm(void)51 getvmm(void)
52 {
53           size_t sz;
54           int i;
55 
56           vmm_totcur.v_timer = 0;
57           vmm_totcur.v_ipi = 0;
58           vmm_totcur.v_intr = 0;
59           vmm_totcur.v_lock_colls = 0;
60 
61           for (i = 0; i < vmm_ncpus; ++i) {
62                     struct vmmeter *vmm = &vmm_cur[i];
63                     char buf[64];
64 
65                     sz = sizeof(*vmm);
66                     snprintf(buf, sizeof(buf), "vm.cpu%d.vmmeter", i);
67                     if (sysctlbyname(buf, vmm, &sz, NULL, 0))
68                               err(1, "sysctlbyname(cpu%d)", i);
69 
70                     vmm->v_intr -= (vmm->v_timer + vmm->v_ipi);
71 
72                     vmm_totcur.v_timer += vmm->v_timer;
73                     vmm_totcur.v_ipi += vmm->v_ipi;
74                     vmm_totcur.v_intr += vmm->v_intr;
75                     vmm_totcur.v_lock_colls += vmm->v_lock_colls;
76           }
77 
78           sz = vmm_ncpus * sizeof(struct kinfo_cputime);
79           if (sysctlbyname("kern.cputime", vmm_cptime_cur, &sz, NULL, 0))
80                     err(1, "kern.cputime");
81 }
82 
83 int
initvmm(void)84 initvmm(void)
85 {
86           return 1;
87 }
88 
89 #define D(idx, field)                                                           \
90           (u_int)((vmm_cur[idx].field - vmm_prev[idx].field) / naptime)
91 
92 #define CPUD(dif, idx, field)                                         \
93 do {                                                                            \
94           dif.cp_##field = vmm_cptime_cur[idx].cp_##field - \
95                                vmm_cptime_prev[idx].cp_##field;       \
96           dtot.cp_##field += vmm_cptime_cur[idx].cp_##field -         \
97                                vmm_cptime_prev[idx].cp_##field;       \
98           cp_total += dif.cp_##field;                                 \
99           cp_total_all += dif.cp_##field;                                       \
100 } while (0)
101 
102 #define CPUV(dif, field)                                              \
103           (dif.cp_##field * 100.0) / cp_total
104 
105 #define CPUC(idx, field) vmm_cptime_cur[idx].cp_##field
106 
107 #define CPUVTOT(field)                                                          \
108           (dtot.cp_##field * 100.0) / cp_total_all
109 
110 #define DTOT(field)                                                   \
111           (u_int)((vmm_totcur.field - vmm_totprev.field) / naptime)
112 
113 
114 void
showvmm(void)115 showvmm(void)
116 {
117           struct kinfo_cputime dtot;
118           uint64_t cp_total_all = 0;
119           int i, n;
120 
121           if (!vmm_fetched)
122                     return;
123 
124           bzero(&dtot, sizeof(dtot));
125 
126           for (i = 0; i < vmm_ncpus; ++i) {
127                     struct kinfo_cputime d;
128                     uint64_t cp_total = 0;
129 
130                     n = X_START + CPU_LABEL_W;
131 
132                     DRAW_ROW(n, CPU_START + i, 6, "%*u", D(i, v_timer));
133                     DRAW_ROW(n, CPU_START + i, 8, "%*u", D(i, v_ipi));
134                     DRAW_ROW(n, CPU_START + i, 8, "%*u", D(i, v_intr));
135 
136                     CPUD(d, i, user);
137                     CPUD(d, i, idle);
138                     CPUD(d, i, intr);
139                     CPUD(d, i, nice);
140                     CPUD(d, i, sys);
141 
142                     if (cp_total == 0)
143                               cp_total = 1;
144 
145                     DRAW_ROW(n, CPU_START + i, 6, "%*.1f",
146                                CPUV(d, user) + 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, (WideMode ? 24 : 16),
163                                           "%*.*s", "");
164                               if (WideMode)
165                                         DRAW_ROW2(n, CPU_START + i, 17, "%*.*s", "");
166                     } else {
167                               DRAW_ROW2(n, CPU_START + i, (WideMode ? 24 : 16),
168                                           "%*.*s",
169                                           vmm_cur[i].v_lock_name);
170                               if (WideMode) {
171                                         DRAW_ROWX(n, CPU_START + i, 17,
172                                                     "%016lx",
173                                                     (uintmax_t)(uintptr_t)
174                                                             vmm_cur[i].v_lock_addr);
175                               }
176                     }
177 
178                     if (WideMode && vmm_cptime_cur[i].cp_sample_pc) {
179                               void *rip;
180 
181                               rip = (void *)(intptr_t)CPUC(i, sample_pc);
182                               DRAW_ROW2(n, CPU_START + i, 30, "%*.*s",
183                                           address_to_symbol(rip, &symctx));
184                     }
185           }
186 
187           /*
188            * Top row totals and averages
189            */
190           if (cp_total_all == 0)
191                     cp_total_all = 1;
192 
193           n = X_START + CPU_LABEL_W;
194           DRAW_ROW(n, TOT_START, 6, "%*u", DTOT(v_timer));  /* timer */
195           DRAW_ROW(n, TOT_START, 8, "%*u", DTOT(v_ipi));              /* ipi    */
196           DRAW_ROW(n, TOT_START, 8, "%*u", DTOT(v_intr));             /* extint */
197 
198           DRAW_ROW(n, TOT_START, 6, "%*.1f", CPUVTOT(user) +          /* user */
199                                                      CPUVTOT(nice));
200           DRAW_ROW(n, TOT_START, 6, "%*.1f", CPUVTOT(sys)); /* sys */
201           DRAW_ROW(n, TOT_START, 6, "%*.1f", CPUVTOT(intr));          /* intr */
202           DRAW_ROW(n, TOT_START, 6, "%*.1f", CPUVTOT(idle));          /* idle */
203 
204           DRAW_ROWX(n, TOT_START, 8, "%7u", DTOT(v_lock_colls));
205           DRAW_ROWX(n, TOT_START, 0, " (%5.2f%% coltot)",
206                     (double)DTOT(v_lock_colls) / 1000000.0);
207 }
208 
209 void
fetchvmm(void)210 fetchvmm(void)
211 {
212           vmm_fetched = 1;
213 
214           memcpy(vmm_prev, vmm_cur, sizeof(struct vmmeter) * vmm_ncpus);
215           memcpy(vmm_cptime_prev, vmm_cptime_cur,
216                  sizeof(struct kinfo_cputime) * vmm_ncpus);
217           vmm_totprev = vmm_totcur;
218           getvmm();
219 }
220 
221 void
labelvmm(void)222 labelvmm(void)
223 {
224           int i, n;
225 
226           clear();
227 
228           n = X_START + CPU_LABEL_W;
229 
230           DRAW_ROW(n, TOT_START - 1, 6, "%*s", "timer");
231           DRAW_ROW(n, TOT_START - 1, 8, "%*s", "ipi");
232           DRAW_ROW(n, TOT_START - 1, 8, "%*s", "extint");
233           DRAW_ROW(n, TOT_START - 1, 6, "%*s", "user%");
234           DRAW_ROW(n, TOT_START - 1, 6, "%*s", "sys%");
235           DRAW_ROW(n, TOT_START - 1, 6, "%*s", "intr%");
236           DRAW_ROW(n, TOT_START - 1, 6, "%*s", "idle%");
237           DRAW_ROW(n, TOT_START - 1, 8, "%*s", "smpcol");
238           DRAW_ROW(n, TOT_START - 1, (WideMode ? 24 : 16), "%*s", "contention");
239           if (WideMode) {
240                     DRAW_ROW(n, TOT_START - 1, 17, "%*s", "lockaddr");
241           }
242           if (WideMode && getuid() == 0) {
243                     DRAW_ROW(n, TOT_START - 1, 30, "%*s", "sample_pc");
244           }
245 
246           n = X_START + CPU_LABEL_W;
247           DRAW_ROW(n, TOT_START + 1, 6, "%*s", "-----");
248           DRAW_ROW(n, TOT_START + 1, 8, "%*s", "-------");
249           DRAW_ROW(n, TOT_START + 1, 8, "%*s", "-------");
250           DRAW_ROW(n, TOT_START + 1, 6, "%*s", "-----");
251           DRAW_ROW(n, TOT_START + 1, 6, "%*s", "-----");
252           DRAW_ROW(n, TOT_START + 1, 6, "%*s", "-----");
253           DRAW_ROW(n, TOT_START + 1, 6, "%*s", "-----");
254           DRAW_ROW(n, TOT_START + 1, 8, "%*s", "-------");
255           DRAW_ROW(n, TOT_START + 1, (WideMode ? 24 : 16),
256                      "%*s",
257                      (WideMode ? "-----------------------" : "---------------"));
258           if (WideMode)
259                     DRAW_ROW(n, TOT_START + 1, 17, "%*s", "---------------");
260           if (WideMode && getuid() == 0) {
261                     DRAW_ROW(n, TOT_START + 1, 30,
262                                "%*s", "-----------------------------");
263           }
264 
265           mvprintw(TOT_START, X_START, "total");
266           for (i = 0; i < vmm_ncpus; ++i)
267                     mvprintw(CPU_START + i, X_START, "cpu%d", i);
268 
269 #if 0
270           n = X_START + CPU_LABEL_W;
271           DRAW_ROW(n, TOT_STARTX - 1, 15, "%-*s", "contention");
272           DRAW_ROW(n, TOT_STARTX - 1, 35, "%-*s", "function");
273 
274           for (i = 0; i < vmm_ncpus; ++i)
275                     mvprintw(CPU_STARTX + i, X_START, "cpu%d", i);
276 #endif
277 }
278 
279 WINDOW *
openvmm(void)280 openvmm(void)
281 {
282           if (symbols_read == 0) {
283                     symbols_read = 1;
284                     read_symbols(NULL);
285           }
286 
287           if (kinfo_get_cpus(&vmm_ncpus))
288                     err(1, "kinfo_get_cpus");
289 
290           vmm_cur = calloc(vmm_ncpus, sizeof(*vmm_cur));
291           if (vmm_cur == NULL)
292                     err(1, "calloc vmm_cur");
293 
294           vmm_prev = calloc(vmm_ncpus, sizeof(*vmm_prev));
295           if (vmm_prev == NULL)
296                     err(1, "calloc vmm_prev");
297 
298           vmm_cptime_cur = calloc(vmm_ncpus, sizeof(*vmm_cptime_cur));
299           if (vmm_cptime_cur == NULL)
300                     err(1, "calloc vmm_cptime_cur");
301 
302           vmm_cptime_prev = calloc(vmm_ncpus, sizeof(*vmm_cptime_prev));
303           if (vmm_cptime_prev == NULL)
304                     err(1, "calloc vmm_cptime_prev");
305 
306           getvmm();
307 
308           return (stdscr);
309 }
310 
311 void
closevmm(WINDOW * w)312 closevmm(WINDOW *w)
313 {
314           if (vmm_cur != NULL)
315                     free(vmm_cur);
316           if (vmm_prev != NULL)
317                     free(vmm_prev);
318 
319           if (vmm_cptime_cur != NULL)
320                     free(vmm_cptime_cur);
321           if (vmm_cptime_prev != NULL)
322                     free(vmm_cptime_prev);
323 
324           vmm_fetched = 0;
325 
326           if (w == NULL)
327                     return;
328           wclear(w);
329           wrefresh(w);
330 }
331