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