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