systat - Ensure vmmeter output separates fields by at least one space.
[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 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", CPUV(d, user));
113                 DRAW_ROW(n, CPU_START + i, 6, "%*.1f", CPUV(d, nice));
114                 DRAW_ROW(n, CPU_START + i, 6, "%*.1f", CPUV(d, sys));
115                 DRAW_ROW(n, CPU_START + i, 6, "%*.1f", CPUV(d, intr));
116                 DRAW_ROW(n, CPU_START + i, 6, "%*.1f", CPUV(d, idle));
117
118                 /*
119                  * Display token collision count and the last-colliding
120                  * token name.
121                  */
122                 if (D(i, v_token_colls) > 9999999)
123                         DRAW_ROW(n, CPU_START + i, 8, "%*u", 9999999);
124                 else
125                         DRAW_ROW(n, CPU_START + i, 8, "%*u",
126                                  D(i, v_token_colls));
127
128                 if (D(i, v_token_colls) == 0) {
129                         DRAW_ROW2(n, CPU_START + i, 8, "%*.*s", "");
130                 } else {
131                         DRAW_ROW2(n, CPU_START + i, 8, "%*.*s",
132                                   vmm_cur[i].v_token_name);
133                 }
134
135 #undef D
136 #undef CPUV
137 #undef CPUD
138 #define CPUC(idx, field) vmm_cptime_cur[idx].cp_##field
139
140 #if 0
141                 n = X_START + CPU_LABEL_W;
142
143                 DRAW_ROW(n, CPU_STARTX + i, 15, "%-*s", CPUC(i, msg));
144                 DRAW_ROW(n, CPU_STARTX + i, 35, "%-*s",
145                         address_to_symbol((void *)(intptr_t)CPUC(i, stallpc),
146                                           &symctx));
147 #endif
148 #undef CPUC
149         }
150 }
151
152 void
153 fetchvmm(void)
154 {
155         vmm_fetched = 1;
156
157         memcpy(vmm_prev, vmm_cur, sizeof(struct vmmeter) * vmm_ncpus);
158         memcpy(vmm_cptime_prev, vmm_cptime_cur,
159                sizeof(struct kinfo_cputime) * vmm_ncpus);
160         getvmm();
161 }
162
163 void
164 labelvmm(void)
165 {
166         int i, n;
167
168         clear();
169
170         n = X_START + CPU_LABEL_W;
171
172         DRAW_ROW(n, CPU_START - 1, 6, "%*s", "timer");
173         DRAW_ROW(n, CPU_START - 1, 8, "%*s", "ipi");
174         DRAW_ROW(n, CPU_START - 1, 8, "%*s", "extint");
175         DRAW_ROW(n, CPU_START - 1, 6, "%*s", "user%");
176         DRAW_ROW(n, CPU_START - 1, 6, "%*s", "nice%");
177         DRAW_ROW(n, CPU_START - 1, 6, "%*s", "sys%");
178         DRAW_ROW(n, CPU_START - 1, 6, "%*s", "intr%");
179         DRAW_ROW(n, CPU_START - 1, 6, "%*s", "idle%");
180         DRAW_ROW(n, CPU_START - 1, 8, "%*s", "tokcol");
181         DRAW_ROW(n, CPU_START - 1, 8, "%*s", "token");
182
183         for (i = 0; i < vmm_ncpus; ++i)
184                 mvprintw(CPU_START + i, X_START, "cpu%d", i);
185
186 #if 0
187         n = X_START + CPU_LABEL_W;
188         DRAW_ROW(n, CPU_STARTX - 1, 15, "%-*s", "contention");
189         DRAW_ROW(n, CPU_STARTX - 1, 35, "%-*s", "function");
190
191         for (i = 0; i < vmm_ncpus; ++i)
192                 mvprintw(CPU_STARTX + i, X_START, "cpu%d", i);
193 #endif
194 }
195
196 WINDOW *
197 openvmm(void)
198 {
199         if (symbols_read == 0) {
200                 symbols_read = 1;
201                 read_symbols(NULL);
202         }
203
204         if (kinfo_get_cpus(&vmm_ncpus))
205                 err(1, "kinfo_get_cpus");
206
207         vmm_cur = calloc(vmm_ncpus, sizeof(*vmm_cur));
208         if (vmm_cur == NULL)
209                 err(1, "calloc vmm_cur");
210
211         vmm_prev = calloc(vmm_ncpus, sizeof(*vmm_prev));
212         if (vmm_prev == NULL)
213                 err(1, "calloc vmm_prev");
214
215         vmm_cptime_cur = calloc(vmm_ncpus, sizeof(*vmm_cptime_cur));
216         if (vmm_cptime_cur == NULL)
217                 err(1, "calloc vmm_cptime_cur");
218
219         vmm_cptime_prev = calloc(vmm_ncpus, sizeof(*vmm_cptime_prev));
220         if (vmm_cptime_prev == NULL)
221                 err(1, "calloc vmm_cptime_prev");
222
223         getvmm();
224
225         return (stdscr);
226 }
227
228 void
229 closevmm(WINDOW *w)
230 {
231         if (vmm_cur != NULL)
232                 free(vmm_cur);
233         if (vmm_prev != NULL)
234                 free(vmm_prev);
235
236         if (vmm_cptime_cur != NULL)
237                 free(vmm_cptime_cur);
238         if (vmm_cptime_prev != NULL)
239                 free(vmm_cptime_prev);
240
241         vmm_fetched = 0;
242
243         if (w == NULL)
244                 return;
245         wclear(w);
246         wrefresh(w);
247 }