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