kernel - VM rework part 2 - Replace backing_object with backing_ba
[dragonfly.git] / usr.bin / systat / vmmeter.c
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
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
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
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, 18, "%*.*s", "");
163                 } else {
164                         DRAW_ROW2(n, CPU_START + i, 18, "%*.*s",
165                                   vmm_cur[i].v_lock_name);
166                 }
167
168                 if (vmm_cptime_cur[i].cp_sample_pc) {
169                         void *rip;
170
171                         rip = (void *)(intptr_t)CPUC(i, sample_pc);
172                         DRAW_ROW2(n, CPU_START + i, 30, "%*.*s",
173                                   address_to_symbol(rip, &symctx));
174                 }
175         }
176
177         /*
178          * Top row totals and averages
179          */
180         if (cp_total_all == 0)
181                 cp_total_all = 1;
182
183         n = X_START + CPU_LABEL_W;
184         DRAW_ROW(n, TOT_START, 6, "%*u", DTOT(v_timer));        /* timer */
185         DRAW_ROW(n, TOT_START, 8, "%*u", DTOT(v_ipi));          /* ipi  */
186         DRAW_ROW(n, TOT_START, 8, "%*u", DTOT(v_intr));         /* extint */
187
188         DRAW_ROW(n, TOT_START, 6, "%*.1f", CPUVTOT(user) +      /* user */
189                                            CPUVTOT(nice));
190         DRAW_ROW(n, TOT_START, 6, "%*.1f", CPUVTOT(sys));       /* sys */
191         DRAW_ROW(n, TOT_START, 6, "%*.1f", CPUVTOT(intr));      /* intr */
192         DRAW_ROW(n, TOT_START, 6, "%*.1f", CPUVTOT(idle));      /* idle */
193
194         DRAW_ROWX(n, TOT_START, 8, "%7u", DTOT(v_lock_colls));
195         DRAW_ROWX(n, TOT_START, 0, " (%5.2f%% coltot)",
196                 (double)DTOT(v_lock_colls) / 1000000.0);
197 }
198
199 void
200 fetchvmm(void)
201 {
202         vmm_fetched = 1;
203
204         memcpy(vmm_prev, vmm_cur, sizeof(struct vmmeter) * vmm_ncpus);
205         memcpy(vmm_cptime_prev, vmm_cptime_cur,
206                sizeof(struct kinfo_cputime) * vmm_ncpus);
207         vmm_totprev = vmm_totcur;
208         getvmm();
209 }
210
211 void
212 labelvmm(void)
213 {
214         int i, n;
215
216         clear();
217
218         n = X_START + CPU_LABEL_W;
219
220         DRAW_ROW(n, TOT_START - 1, 6, "%*s", "timer");
221         DRAW_ROW(n, TOT_START - 1, 8, "%*s", "ipi");
222         DRAW_ROW(n, TOT_START - 1, 8, "%*s", "extint");
223         DRAW_ROW(n, TOT_START - 1, 6, "%*s", "user%");
224         DRAW_ROW(n, TOT_START - 1, 6, "%*s", "sys%");
225         DRAW_ROW(n, TOT_START - 1, 6, "%*s", "intr%");
226         DRAW_ROW(n, TOT_START - 1, 6, "%*s", "idle%");
227         DRAW_ROW(n, TOT_START - 1, 8, "%*s", "smpcol");
228         DRAW_ROW(n, TOT_START - 1, 18, "%*s", "label");
229         if (getuid() == 0) {
230                 DRAW_ROW(n, TOT_START - 1, 30, "%*s", "sample_pc");
231         }
232
233         n = X_START + CPU_LABEL_W;
234         DRAW_ROW(n, TOT_START + 1, 6, "%*s", "-----");
235         DRAW_ROW(n, TOT_START + 1, 8, "%*s", "-------");
236         DRAW_ROW(n, TOT_START + 1, 8, "%*s", "-------");
237         DRAW_ROW(n, TOT_START + 1, 6, "%*s", "-----");
238         DRAW_ROW(n, TOT_START + 1, 6, "%*s", "-----");
239         DRAW_ROW(n, TOT_START + 1, 6, "%*s", "-----");
240         DRAW_ROW(n, TOT_START + 1, 6, "%*s", "-----");
241         DRAW_ROW(n, TOT_START + 1, 8, "%*s", "-------");
242         DRAW_ROW(n, TOT_START + 1, 18, "%*s", "-----------------");
243         if (getuid() == 0) {
244                 DRAW_ROW(n, TOT_START - 1, 30, "%*s", "---------");
245         }
246
247         mvprintw(TOT_START, X_START, "total");
248         for (i = 0; i < vmm_ncpus; ++i)
249                 mvprintw(CPU_START + i, X_START, "cpu%d", i);
250
251 #if 0
252         n = X_START + CPU_LABEL_W;
253         DRAW_ROW(n, TOT_STARTX - 1, 15, "%-*s", "contention");
254         DRAW_ROW(n, TOT_STARTX - 1, 35, "%-*s", "function");
255
256         for (i = 0; i < vmm_ncpus; ++i)
257                 mvprintw(CPU_STARTX + i, X_START, "cpu%d", i);
258 #endif
259 }
260
261 WINDOW *
262 openvmm(void)
263 {
264         if (symbols_read == 0) {
265                 symbols_read = 1;
266                 read_symbols(NULL);
267         }
268
269         if (kinfo_get_cpus(&vmm_ncpus))
270                 err(1, "kinfo_get_cpus");
271
272         vmm_cur = calloc(vmm_ncpus, sizeof(*vmm_cur));
273         if (vmm_cur == NULL)
274                 err(1, "calloc vmm_cur");
275
276         vmm_prev = calloc(vmm_ncpus, sizeof(*vmm_prev));
277         if (vmm_prev == NULL)
278                 err(1, "calloc vmm_prev");
279
280         vmm_cptime_cur = calloc(vmm_ncpus, sizeof(*vmm_cptime_cur));
281         if (vmm_cptime_cur == NULL)
282                 err(1, "calloc vmm_cptime_cur");
283
284         vmm_cptime_prev = calloc(vmm_ncpus, sizeof(*vmm_cptime_prev));
285         if (vmm_cptime_prev == NULL)
286                 err(1, "calloc vmm_cptime_prev");
287
288         getvmm();
289
290         return (stdscr);
291 }
292
293 void
294 closevmm(WINDOW *w)
295 {
296         if (vmm_cur != NULL)
297                 free(vmm_cur);
298         if (vmm_prev != NULL)
299                 free(vmm_prev);
300
301         if (vmm_cptime_cur != NULL)
302                 free(vmm_cptime_cur);
303         if (vmm_cptime_prev != NULL)
304                 free(vmm_cptime_prev);
305
306         vmm_fetched = 0;
307
308         if (w == NULL)
309                 return;
310         wclear(w);
311         wrefresh(w);
312 }