kernel - Fix Xinvltlb issue, fix ipiq issue, add Xsniff
[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 <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 static struct save_ctx symctx;
41 static int symbols_read;
42
43 static void
44 getvmm(void)
45 {
46         size_t sz;
47         int i;
48
49         vmm_totcur.v_ipi = 0;
50         vmm_totcur.v_intr = 0;
51         vmm_totcur.v_lock_colls = 0;
52
53         for (i = 0; i < vmm_ncpus; ++i) {
54                 struct vmmeter *vmm = &vmm_cur[i];
55                 char buf[64];
56
57                 sz = sizeof(*vmm);
58                 snprintf(buf, sizeof(buf), "vm.cpu%d.vmmeter", i);
59                 if (sysctlbyname(buf, vmm, &sz, NULL, 0))
60                         err(1, "sysctlbyname(cpu%d)", i);
61
62                 vmm->v_intr -= (vmm->v_timer + vmm->v_ipi);
63
64                 vmm_totcur.v_ipi += vmm->v_ipi;
65                 vmm_totcur.v_intr += vmm->v_intr;
66                 vmm_totcur.v_lock_colls += vmm->v_lock_colls;
67         }
68
69         sz = vmm_ncpus * sizeof(struct kinfo_cputime);
70         if (sysctlbyname("kern.cputime", vmm_cptime_cur, &sz, NULL, 0))
71                 err(1, "kern.cputime");
72 }
73
74 int
75 initvmm(void)
76 {
77         return 1;
78 }
79
80 void
81 showvmm(void)
82 {
83         int i, n;
84
85         if (!vmm_fetched)
86                 return;
87
88         n = X_START + CPU_LABEL_W;
89
90 #define DTOT(field) \
91         (u_int)((vmm_totcur.field - vmm_totprev.field) / naptime)
92
93         DRAW_ROW(n, TOT_START, 6, "%*s", "");   /* timer */
94         DRAW_ROW(n, TOT_START, 8, "%*u", DTOT(v_ipi));
95         DRAW_ROW(n, TOT_START, 8, "%*u", DTOT(v_intr));
96
97         DRAW_ROW(n, TOT_START, 6, "%*s", "");   /* user */
98 /*      DRAW_ROW(n, TOT_START, 6, "%*s", "");      nice */
99         DRAW_ROW(n, TOT_START, 6, "%*s", "");   /* sys */
100         DRAW_ROW(n, TOT_START, 6, "%*s", "");   /* intr */
101         DRAW_ROW(n, TOT_START, 6, "%*s", "");   /* idle */
102         if (DTOT(v_lock_colls) > 9999999)
103                 DRAW_ROW(n, TOT_START, 8, "%*u", 9999999);
104         else
105                 DRAW_ROW(n, TOT_START, 8, "%*u", DTOT( v_lock_colls));
106         DRAW_ROW2(n, TOT_START, 18, "%*.*s", ""); /* label */
107         DRAW_ROW2(n, TOT_START, 30, "%*.*s", ""); /* sample_pc */
108 #if 0
109         DRAW_ROW2(n, TOT_START, 20, "%*.*s", ""); /* sample_sp */
110 #endif
111
112 #undef DTOT
113
114         for (i = 0; i < vmm_ncpus; ++i) {
115                 struct kinfo_cputime d;
116                 uint64_t cp_total = 0;
117
118                 n = X_START + CPU_LABEL_W;
119
120 #define D(idx, field) \
121         (u_int)((vmm_cur[idx].field - vmm_prev[idx].field) / naptime)
122
123                 DRAW_ROW(n, CPU_START + i, 6, "%*u", D(i, v_timer));
124                 DRAW_ROW(n, CPU_START + i, 8, "%*u", D(i, v_ipi));
125                 DRAW_ROW(n, CPU_START + i, 8, "%*u", D(i, v_intr));
126
127 #define CPUD(dif, idx, field) \
128 do { \
129         dif.cp_##field = vmm_cptime_cur[idx].cp_##field - \
130                          vmm_cptime_prev[idx].cp_##field; \
131         cp_total += dif.cp_##field; \
132 } while (0)
133
134 #define CPUV(dif, field) \
135         (dif.cp_##field * 100.0) / cp_total
136
137                 CPUD(d, i, user);
138                 CPUD(d, i, idle);
139                 CPUD(d, i, intr);
140                 CPUD(d, i, nice);
141                 CPUD(d, i, sys);
142
143                 if (cp_total == 0)
144                         cp_total = 1;
145
146                 DRAW_ROW(n, CPU_START + i, 6, "%*.1f",
147                          CPUV(d, user) + CPUV(d, nice));
148 /*              DRAW_ROW(n, CPU_START + i, 6, "%*.1f", CPUV(d, nice));*/
149                 DRAW_ROW(n, CPU_START + i, 6, "%*.1f", CPUV(d, sys));
150                 DRAW_ROW(n, CPU_START + i, 6, "%*.1f", CPUV(d, intr));
151                 DRAW_ROW(n, CPU_START + i, 6, "%*.1f", CPUV(d, idle));
152
153                 /*
154                  * Display token collision count and the last-colliding
155                  * token name.
156                  */
157                 if (D(i, v_lock_colls) > 9999999)
158                         DRAW_ROW(n, CPU_START + i, 8, "%*u", 9999999);
159                 else
160                         DRAW_ROW(n, CPU_START + i, 8, "%*u",
161                                  D(i, v_lock_colls));
162
163                 if (D(i, v_lock_colls) == 0) {
164                         DRAW_ROW2(n, CPU_START + i, 18, "%*.*s", "");
165                 } else {
166                         DRAW_ROW2(n, CPU_START + i, 18, "%*.*s",
167                                   vmm_cur[i].v_lock_name);
168                 }
169
170 #undef D
171 #undef CPUV
172 #undef CPUD
173
174 #define CPUC(idx, field) vmm_cptime_cur[idx].cp_##field
175                 DRAW_ROW2(n, CPU_START + i, 30, "%*.*s",
176                          address_to_symbol((void *)(intptr_t)CPUC(i, sample_pc),
177                                            &symctx));
178 #if 0
179                 DRAW_ROW(n, CPU_START + i, 19, " %016jx", CPUC(i, sample_sp));
180 #endif
181 #undef CPUC
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         DRAW_ROW(n, TOT_START - 1, 30, "%*s", "sample_pc");
217 #if 0
218         DRAW_ROW(n, TOT_START - 1, 18, "%*s", "sample_sp");
219 #endif
220
221         mvprintw(TOT_START, X_START, "total");
222         for (i = 0; i < vmm_ncpus; ++i)
223                 mvprintw(CPU_START + i, X_START, "cpu%d", i);
224
225 #if 0
226         n = X_START + CPU_LABEL_W;
227         DRAW_ROW(n, TOT_STARTX - 1, 15, "%-*s", "contention");
228         DRAW_ROW(n, TOT_STARTX - 1, 35, "%-*s", "function");
229
230         for (i = 0; i < vmm_ncpus; ++i)
231                 mvprintw(CPU_STARTX + i, X_START, "cpu%d", i);
232 #endif
233 }
234
235 WINDOW *
236 openvmm(void)
237 {
238         if (symbols_read == 0) {
239                 symbols_read = 1;
240                 read_symbols(NULL);
241         }
242
243         if (kinfo_get_cpus(&vmm_ncpus))
244                 err(1, "kinfo_get_cpus");
245
246         vmm_cur = calloc(vmm_ncpus, sizeof(*vmm_cur));
247         if (vmm_cur == NULL)
248                 err(1, "calloc vmm_cur");
249
250         vmm_prev = calloc(vmm_ncpus, sizeof(*vmm_prev));
251         if (vmm_prev == NULL)
252                 err(1, "calloc vmm_prev");
253
254         vmm_cptime_cur = calloc(vmm_ncpus, sizeof(*vmm_cptime_cur));
255         if (vmm_cptime_cur == NULL)
256                 err(1, "calloc vmm_cptime_cur");
257
258         vmm_cptime_prev = calloc(vmm_ncpus, sizeof(*vmm_cptime_prev));
259         if (vmm_cptime_prev == NULL)
260                 err(1, "calloc vmm_cptime_prev");
261
262         getvmm();
263
264         return (stdscr);
265 }
266
267 void
268 closevmm(WINDOW *w)
269 {
270         if (vmm_cur != NULL)
271                 free(vmm_cur);
272         if (vmm_prev != NULL)
273                 free(vmm_prev);
274
275         if (vmm_cptime_cur != NULL)
276                 free(vmm_cptime_cur);
277         if (vmm_cptime_prev != NULL)
278                 free(vmm_cptime_prev);
279
280         vmm_fetched = 0;
281
282         if (w == NULL)
283                 return;
284         wclear(w);
285         wrefresh(w);
286 }