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