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 } 313