1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <fcntl.h> 33 #include <errno.h> 34 #include <unistd.h> 35 #include <signal.h> 36 #include <strings.h> 37 #include <limits.h> 38 #include <sys/mman.h> 39 #include <sys/pset.h> 40 #include <sys/varargs.h> 41 #include <sys/trapstat.h> 42 #include <sys/wait.h> 43 #include <stddef.h> 44 #include <termio.h> 45 46 #define TSTAT_DEVICE "/dev/trapstat" 47 #define TSTAT_COMMAND "trapstat" 48 #define TSTAT_DELTA(data, old, member) g_absolute ? (data)->member : \ 49 (uint64_t)(0.5 + (g_interval / (double)((data)->tdata_snapts - \ 50 (old)->tdata_snapts)) * (double)((data)->member - (old)->member)) 51 52 #define TSTAT_PRINT_MISSDATA(diff, time) \ 53 (void) printf(" %9lld %4.1f", (diff), (time)); 54 55 #define TSTAT_PAGESIZE_MODIFIERS " kmgtp" 56 #define TSTAT_PAGESIZE_STRLEN 10 57 #define TSTAT_MAX_RATE 5000 58 #define TSTAT_COLUMN_OFFS 26 59 #define TSTAT_COLUMNS_PER_CPU 9 60 61 static tstat_data_t *g_data[2]; 62 static tstat_data_t *g_ndata, *g_odata; 63 static processorid_t g_max_cpus; 64 static int8_t *g_selected; 65 static timer_t g_tid; 66 static int g_interval = NANOSEC; 67 static int g_peffect = 1; 68 static int g_absolute = 0; 69 static sigset_t g_oset; 70 71 static psetid_t g_pset = PS_NONE; 72 static processorid_t *g_pset_cpus; 73 static uint_t g_pset_ncpus; 74 75 static int g_cpus_per_line = (80 - TSTAT_COLUMN_OFFS) / TSTAT_COLUMNS_PER_CPU; 76 static int g_winch; 77 78 static int g_pgsizes; 79 static size_t *g_pgsize; 80 static char **g_pgnames; 81 static size_t g_datasize; 82 83 static int g_gen; 84 static int g_fd; 85 static uint8_t g_active[TSTAT_NENT]; 86 87 static hrtime_t g_start; 88 89 static int g_exec_errno; 90 static int g_child_exited; 91 static int g_child_status; 92 93 static void (*g_process)(void *, uint64_t, double); 94 static void *g_arg; 95 96 typedef struct tstat_sum { 97 uint64_t tsum_diff; 98 double tsum_time; 99 } tstat_sum_t; 100 101 #define TSTAT_ENT_USED 0 102 #define TSTAT_ENT_RESERVED 1 103 #define TSTAT_ENT_UNUSED 2 104 #define TSTAT_ENT_CONTINUED 3 105 106 typedef struct tstat_ent { 107 char *tent_name; 108 char *tent_descr; 109 int tent_type; 110 } tstat_ent_t; 111 112 static tstat_ent_t g_traps[] = { 113 #ifndef sun4v 114 { NULL, NULL, TSTAT_ENT_RESERVED }, 115 { "power-on", "power on reset" }, 116 { "watchdog", "watchdog reset" }, 117 { "xir", "externally initiated reset" }, 118 { "sir", "software initiated reset" }, 119 { "red", "RED state exception" }, 120 { NULL, NULL, TSTAT_ENT_RESERVED }, 121 { NULL, NULL, TSTAT_ENT_RESERVED }, 122 { "immu-xcp", "instruction access exception" }, 123 { "immu-miss", "instruction access MMU miss" }, 124 { "immu-err", "instruction access error" }, 125 { NULL, NULL, TSTAT_ENT_RESERVED }, 126 { NULL, NULL, TSTAT_ENT_RESERVED }, 127 { NULL, NULL, TSTAT_ENT_RESERVED }, 128 { NULL, NULL, TSTAT_ENT_RESERVED }, 129 { NULL, NULL, TSTAT_ENT_RESERVED }, 130 { "ill-inst", "illegal instruction" }, 131 { "priv-inst", "privileged opcode" }, 132 { "unimp-ldd", "unimplemented LDD" }, 133 { "unimp-std", "unimplemented STD" }, 134 { NULL, NULL, TSTAT_ENT_RESERVED }, 135 { NULL, NULL, TSTAT_ENT_RESERVED }, 136 { NULL, NULL, TSTAT_ENT_RESERVED }, 137 { NULL, NULL, TSTAT_ENT_RESERVED }, 138 { NULL, NULL, TSTAT_ENT_RESERVED }, 139 { NULL, NULL, TSTAT_ENT_RESERVED }, 140 { NULL, NULL, TSTAT_ENT_RESERVED }, 141 { NULL, NULL, TSTAT_ENT_RESERVED }, 142 { NULL, NULL, TSTAT_ENT_RESERVED }, 143 { NULL, NULL, TSTAT_ENT_RESERVED }, 144 { NULL, NULL, TSTAT_ENT_RESERVED }, 145 { NULL, NULL, TSTAT_ENT_RESERVED }, 146 { "fp-disabled", "fp disabled" }, 147 { "fp-ieee754", "fp exception ieee754" }, 148 { "fp-xcp-other", "fp exception other" }, 149 { "tag-oflow", "tag overflow" }, 150 { "cleanwin", "clean window" }, 151 { NULL, NULL, TSTAT_ENT_CONTINUED }, 152 { NULL, NULL, TSTAT_ENT_CONTINUED }, 153 { NULL, NULL, TSTAT_ENT_CONTINUED }, 154 { "div-zero", "division by zero" }, 155 { "internal-err", "internal processor error" }, 156 { NULL, NULL, TSTAT_ENT_RESERVED }, 157 { NULL, NULL, TSTAT_ENT_RESERVED }, 158 { NULL, NULL, TSTAT_ENT_RESERVED }, 159 { NULL, NULL, TSTAT_ENT_RESERVED }, 160 { NULL, NULL, TSTAT_ENT_RESERVED }, 161 { NULL, NULL, TSTAT_ENT_RESERVED }, 162 { "dmmu-xcp", "data access exception" }, 163 { "dmmu-miss", "data access MMU miss" }, 164 { "dmmu-err", "data access error" }, 165 { "dmmu-prot", "data access protection" }, 166 { "unalign", "mem address not aligned" }, 167 { "lddf-unalign", "LDDF mem address not aligned" }, 168 { "stdf-unalign", "STDF mem address not aligned" }, 169 { "priv-act", "privileged action" }, 170 { "ldqf-unalign", "LDQF mem address not aligned" }, 171 { "stqf-unalign", "STQF mem address not aligned" }, 172 { NULL, NULL, TSTAT_ENT_RESERVED }, 173 { NULL, NULL, TSTAT_ENT_RESERVED }, 174 { NULL, NULL, TSTAT_ENT_RESERVED }, 175 { NULL, NULL, TSTAT_ENT_RESERVED }, 176 { NULL, NULL, TSTAT_ENT_RESERVED }, 177 { NULL, NULL, TSTAT_ENT_RESERVED }, 178 { "async-d-err", "async data error" }, 179 { "level-1", "interrupt level 1" }, 180 { "level-2", "interrupt level 2" }, 181 { "level-3", "interrupt level 3" }, 182 { "level-4", "interrupt level 4" }, 183 { "level-5", "interrupt level 5" }, 184 { "level-6", "interrupt level 6" }, 185 { "level-7", "interrupt level 7" }, 186 { "level-8", "interrupt level 8" }, 187 { "level-9", "interrupt level 9" }, 188 { "level-10", "interrupt level 10" }, 189 { "level-11", "interrupt level 11" }, 190 { "level-12", "interrupt level 12" }, 191 { "level-13", "interrupt level 13" }, 192 { "level-14", "interrupt level 14" }, 193 { "level-15", "interrupt level 15" }, 194 { NULL, NULL, TSTAT_ENT_RESERVED }, 195 { NULL, NULL, TSTAT_ENT_RESERVED }, 196 { NULL, NULL, TSTAT_ENT_RESERVED }, 197 { NULL, NULL, TSTAT_ENT_RESERVED }, 198 { NULL, NULL, TSTAT_ENT_RESERVED }, 199 { NULL, NULL, TSTAT_ENT_RESERVED }, 200 { NULL, NULL, TSTAT_ENT_RESERVED }, 201 { NULL, NULL, TSTAT_ENT_RESERVED }, 202 { NULL, NULL, TSTAT_ENT_RESERVED }, 203 { NULL, NULL, TSTAT_ENT_RESERVED }, 204 { NULL, NULL, TSTAT_ENT_RESERVED }, 205 { NULL, NULL, TSTAT_ENT_RESERVED }, 206 { NULL, NULL, TSTAT_ENT_RESERVED }, 207 { NULL, NULL, TSTAT_ENT_RESERVED }, 208 { NULL, NULL, TSTAT_ENT_RESERVED }, 209 { NULL, NULL, TSTAT_ENT_RESERVED }, 210 { "int-vec", "interrupt vector" }, 211 { "pa-watch", "PA watchpoint" }, 212 { "va-watch", "VA watchpoint" }, 213 { "ecc-err", "corrected ECC error" }, 214 { "itlb-miss", "instruction access MMU miss" }, 215 { NULL, NULL, TSTAT_ENT_CONTINUED }, 216 { NULL, NULL, TSTAT_ENT_CONTINUED }, 217 { NULL, NULL, TSTAT_ENT_CONTINUED }, 218 { "dtlb-miss", "data access MMU miss" }, 219 { NULL, NULL, TSTAT_ENT_CONTINUED }, 220 { NULL, NULL, TSTAT_ENT_CONTINUED }, 221 { NULL, NULL, TSTAT_ENT_CONTINUED }, 222 { "dtlb-prot", "data access protection" }, 223 { NULL, NULL, TSTAT_ENT_CONTINUED }, 224 { NULL, NULL, TSTAT_ENT_CONTINUED }, 225 { NULL, NULL, TSTAT_ENT_CONTINUED }, 226 { "fast-ecc", "fast ECC error" }, 227 { "dcache-parity", "D-cache parity error" }, 228 { "icache-parity", "I-cache parity error" }, 229 { NULL, NULL, TSTAT_ENT_RESERVED }, 230 { NULL, NULL, TSTAT_ENT_RESERVED }, 231 { NULL, NULL, TSTAT_ENT_RESERVED }, 232 { NULL, NULL, TSTAT_ENT_RESERVED }, 233 { NULL, NULL, TSTAT_ENT_RESERVED }, 234 { NULL, NULL, TSTAT_ENT_RESERVED }, 235 { NULL, NULL, TSTAT_ENT_RESERVED }, 236 { NULL, NULL, TSTAT_ENT_RESERVED }, 237 { NULL, NULL, TSTAT_ENT_RESERVED }, 238 { NULL, NULL, TSTAT_ENT_RESERVED }, 239 { NULL, NULL, TSTAT_ENT_RESERVED }, 240 { NULL, NULL, TSTAT_ENT_RESERVED }, 241 { NULL, NULL, TSTAT_ENT_RESERVED }, 242 #else /* sun4v */ 243 { NULL, NULL, TSTAT_ENT_RESERVED }, 244 { NULL, NULL, TSTAT_ENT_RESERVED }, 245 { "watchdog", "watchdog reset" }, 246 { NULL, NULL, TSTAT_ENT_RESERVED }, 247 { NULL, NULL, TSTAT_ENT_RESERVED }, 248 { NULL, NULL, TSTAT_ENT_RESERVED }, 249 { NULL, NULL, TSTAT_ENT_RESERVED }, 250 { NULL, NULL, TSTAT_ENT_RESERVED }, 251 { "immu-xcp", "instruction access exception" }, 252 { "immu-miss", "instruction access MMU miss" }, 253 { NULL, NULL, TSTAT_ENT_RESERVED }, 254 { NULL, NULL, TSTAT_ENT_RESERVED }, 255 { NULL, NULL, TSTAT_ENT_RESERVED }, 256 { NULL, NULL, TSTAT_ENT_RESERVED }, 257 { NULL, NULL, TSTAT_ENT_RESERVED }, 258 { NULL, NULL, TSTAT_ENT_RESERVED }, 259 { "ill-inst", "illegal instruction" }, 260 { "priv-inst", "privileged opcode" }, 261 { "unimp-ldd", "unimplemented LDD" }, 262 { "unimp-std", "unimplemented STD" }, 263 { NULL, NULL, TSTAT_ENT_RESERVED }, 264 { NULL, NULL, TSTAT_ENT_RESERVED }, 265 { NULL, NULL, TSTAT_ENT_RESERVED }, 266 { NULL, NULL, TSTAT_ENT_RESERVED }, 267 { NULL, NULL, TSTAT_ENT_RESERVED }, 268 { NULL, NULL, TSTAT_ENT_RESERVED }, 269 { NULL, NULL, TSTAT_ENT_RESERVED }, 270 { NULL, NULL, TSTAT_ENT_RESERVED }, 271 { NULL, NULL, TSTAT_ENT_RESERVED }, 272 { NULL, NULL, TSTAT_ENT_RESERVED }, 273 { NULL, NULL, TSTAT_ENT_RESERVED }, 274 { NULL, NULL, TSTAT_ENT_RESERVED }, 275 { "fp-disabled", "fp disabled" }, 276 { "fp-ieee754", "fp exception ieee754" }, 277 { "fp-xcp-other", "fp exception other" }, 278 { "tag-oflow", "tag overflow" }, 279 { "cleanwin", "clean window" }, 280 { NULL, NULL, TSTAT_ENT_CONTINUED }, 281 { NULL, NULL, TSTAT_ENT_CONTINUED }, 282 { NULL, NULL, TSTAT_ENT_CONTINUED }, 283 { "div-zero", "division by zero" }, 284 { NULL, NULL, TSTAT_ENT_RESERVED }, 285 { NULL, NULL, TSTAT_ENT_RESERVED }, 286 { NULL, NULL, TSTAT_ENT_RESERVED }, 287 { NULL, NULL, TSTAT_ENT_RESERVED }, 288 { NULL, NULL, TSTAT_ENT_RESERVED }, 289 { NULL, NULL, TSTAT_ENT_RESERVED }, 290 { NULL, NULL, TSTAT_ENT_RESERVED }, 291 { "dmmu-xcp", "data access exception" }, 292 { "dmmu-miss", "data access MMU miss" }, 293 { NULL, NULL, TSTAT_ENT_RESERVED }, 294 { "dmmu-prot", "data access protection" }, 295 { "unalign", "mem address not aligned" }, 296 { "lddf-unalign", "LDDF mem address not aligned" }, 297 { "stdf-unalign", "STDF mem address not aligned" }, 298 { "priv-act", "privileged action" }, 299 { "ldqf-unalign", "LDQF mem address not aligned" }, 300 { "stqf-unalign", "STQF mem address not aligned" }, 301 { NULL, NULL, TSTAT_ENT_RESERVED }, 302 { NULL, NULL, TSTAT_ENT_RESERVED }, 303 { NULL, NULL, TSTAT_ENT_RESERVED }, 304 { NULL, NULL, TSTAT_ENT_RESERVED }, 305 { NULL, NULL, TSTAT_ENT_RESERVED }, 306 { NULL, NULL, TSTAT_ENT_RESERVED }, 307 { NULL, NULL, TSTAT_ENT_RESERVED }, 308 { "level-1", "interrupt level 1" }, 309 { "level-2", "interrupt level 2" }, 310 { "level-3", "interrupt level 3" }, 311 { "level-4", "interrupt level 4" }, 312 { "level-5", "interrupt level 5" }, 313 { "level-6", "interrupt level 6" }, 314 { "level-7", "interrupt level 7" }, 315 { "level-8", "interrupt level 8" }, 316 { "level-9", "interrupt level 9" }, 317 { "level-10", "interrupt level 10" }, 318 { "level-11", "interrupt level 11" }, 319 { "level-12", "interrupt level 12" }, 320 { "level-13", "interrupt level 13" }, 321 { "level-14", "interrupt level 14" }, 322 { "level-15", "interrupt level 15" }, 323 { NULL, NULL, TSTAT_ENT_RESERVED }, 324 { NULL, NULL, TSTAT_ENT_RESERVED }, 325 { NULL, NULL, TSTAT_ENT_RESERVED }, 326 { NULL, NULL, TSTAT_ENT_RESERVED }, 327 { NULL, NULL, TSTAT_ENT_RESERVED }, 328 { NULL, NULL, TSTAT_ENT_RESERVED }, 329 { NULL, NULL, TSTAT_ENT_RESERVED }, 330 { NULL, NULL, TSTAT_ENT_RESERVED }, 331 { NULL, NULL, TSTAT_ENT_RESERVED }, 332 { NULL, NULL, TSTAT_ENT_RESERVED }, 333 { NULL, NULL, TSTAT_ENT_RESERVED }, 334 { NULL, NULL, TSTAT_ENT_RESERVED }, 335 { NULL, NULL, TSTAT_ENT_RESERVED }, 336 { NULL, NULL, TSTAT_ENT_RESERVED }, 337 { NULL, NULL, TSTAT_ENT_RESERVED }, 338 { NULL, NULL, TSTAT_ENT_RESERVED }, 339 { NULL, NULL, TSTAT_ENT_RESERVED }, 340 { "pa-watch", "PA watchpoint" }, 341 { "va-watch", "VA watchpoint" }, 342 { NULL, NULL, TSTAT_ENT_RESERVED }, 343 { "itlb-miss", "instruction access MMU miss" }, 344 { NULL, NULL, TSTAT_ENT_CONTINUED }, 345 { NULL, NULL, TSTAT_ENT_CONTINUED }, 346 { NULL, NULL, TSTAT_ENT_CONTINUED }, 347 { "dtlb-miss", "data access MMU miss" }, 348 { NULL, NULL, TSTAT_ENT_CONTINUED }, 349 { NULL, NULL, TSTAT_ENT_CONTINUED }, 350 { NULL, NULL, TSTAT_ENT_CONTINUED }, 351 { "dtlb-prot", "data access protection" }, 352 { NULL, NULL, TSTAT_ENT_CONTINUED }, 353 { NULL, NULL, TSTAT_ENT_CONTINUED }, 354 { NULL, NULL, TSTAT_ENT_CONTINUED }, 355 { NULL, NULL, TSTAT_ENT_RESERVED }, 356 { NULL, NULL, TSTAT_ENT_RESERVED }, 357 { NULL, NULL, TSTAT_ENT_RESERVED }, 358 { "ctl-xfer", "control transfer" }, 359 { NULL, NULL, TSTAT_ENT_RESERVED }, 360 { "instr-brkpt", "instruction breakpoint" }, 361 { NULL, NULL, TSTAT_ENT_RESERVED }, 362 { NULL, NULL, TSTAT_ENT_RESERVED }, 363 { NULL, NULL, TSTAT_ENT_RESERVED }, 364 { NULL, NULL, TSTAT_ENT_RESERVED }, 365 { NULL, NULL, TSTAT_ENT_RESERVED }, 366 { "hw-changed", "hardware changed" }, 367 { "cpu_mondo", "cpu mondo trap" }, 368 { "dev_mondo", "device mondo trap" }, 369 { "res-err", "resumable error" }, 370 { "nonres-err", "non-resumable error" }, 371 #endif /* sun4v */ 372 { "spill-0-normal", "spill 0 normal" }, 373 { NULL, NULL, TSTAT_ENT_CONTINUED }, 374 { NULL, NULL, TSTAT_ENT_CONTINUED }, 375 { NULL, NULL, TSTAT_ENT_CONTINUED }, 376 { "spill-user-32", "spill user window, 32-bit" }, 377 { NULL, NULL, TSTAT_ENT_CONTINUED }, 378 { NULL, NULL, TSTAT_ENT_CONTINUED }, 379 { NULL, NULL, TSTAT_ENT_CONTINUED }, 380 { "spill-user-64", "spill user window, 64-bit" }, 381 { NULL, NULL, TSTAT_ENT_CONTINUED }, 382 { NULL, NULL, TSTAT_ENT_CONTINUED }, 383 { NULL, NULL, TSTAT_ENT_CONTINUED }, 384 { "spill-user-32-cln", "spill, clean user window, 32-bit" }, 385 { NULL, NULL, TSTAT_ENT_CONTINUED }, 386 { NULL, NULL, TSTAT_ENT_CONTINUED }, 387 { NULL, NULL, TSTAT_ENT_CONTINUED }, 388 { "spill-user-64-cln", "spill, clean user window, 64-bit" }, 389 { NULL, NULL, TSTAT_ENT_CONTINUED }, 390 { NULL, NULL, TSTAT_ENT_CONTINUED }, 391 { NULL, NULL, TSTAT_ENT_CONTINUED }, 392 { "spill-kern-32", "spill kernel window, 32-bit" }, 393 { NULL, NULL, TSTAT_ENT_CONTINUED }, 394 { NULL, NULL, TSTAT_ENT_CONTINUED }, 395 { NULL, NULL, TSTAT_ENT_CONTINUED }, 396 { "spill-kern-64", "spill kernel window, 64-bit" }, 397 { NULL, NULL, TSTAT_ENT_CONTINUED }, 398 { NULL, NULL, TSTAT_ENT_CONTINUED }, 399 { NULL, NULL, TSTAT_ENT_CONTINUED }, 400 { "spill-mixed", "spill window, mixed 32-bit/64-bit" }, 401 { NULL, NULL, TSTAT_ENT_CONTINUED }, 402 { NULL, NULL, TSTAT_ENT_CONTINUED }, 403 { NULL, NULL, TSTAT_ENT_CONTINUED }, 404 { "spill-0-other", "spill 0 other" }, 405 { NULL, NULL, TSTAT_ENT_CONTINUED }, 406 { NULL, NULL, TSTAT_ENT_CONTINUED }, 407 { NULL, NULL, TSTAT_ENT_CONTINUED }, 408 { "spill-asuser-32", "spill user window as kernel, 32-bit" }, 409 { NULL, NULL, TSTAT_ENT_CONTINUED }, 410 { NULL, NULL, TSTAT_ENT_CONTINUED }, 411 { NULL, NULL, TSTAT_ENT_CONTINUED }, 412 { "spill-asuser-64", "spill user window as kernel, 64-bit" }, 413 { NULL, NULL, TSTAT_ENT_CONTINUED }, 414 { NULL, NULL, TSTAT_ENT_CONTINUED }, 415 { NULL, NULL, TSTAT_ENT_CONTINUED }, 416 { "spill-asuser-32-cln", "spill, clean user window as kernel, 32-bit" }, 417 { NULL, NULL, TSTAT_ENT_CONTINUED }, 418 { NULL, NULL, TSTAT_ENT_CONTINUED }, 419 { NULL, NULL, TSTAT_ENT_CONTINUED }, 420 { "spill-asuser-64-cln", "spill, clean user window as kernel, 64-bit" }, 421 { NULL, NULL, TSTAT_ENT_CONTINUED }, 422 { NULL, NULL, TSTAT_ENT_CONTINUED }, 423 { NULL, NULL, TSTAT_ENT_CONTINUED }, 424 { "spill-5-other", "spill 5 other" }, 425 { NULL, NULL, TSTAT_ENT_CONTINUED }, 426 { NULL, NULL, TSTAT_ENT_CONTINUED }, 427 { NULL, NULL, TSTAT_ENT_CONTINUED }, 428 { "spill-6-other", "spill 6 other" }, 429 { NULL, NULL, TSTAT_ENT_CONTINUED }, 430 { NULL, NULL, TSTAT_ENT_CONTINUED }, 431 { NULL, NULL, TSTAT_ENT_CONTINUED }, 432 { "spill-7-other", "spill 7 other" }, 433 { NULL, NULL, TSTAT_ENT_CONTINUED }, 434 { NULL, NULL, TSTAT_ENT_CONTINUED }, 435 { NULL, NULL, TSTAT_ENT_CONTINUED }, 436 { "fill-0-normal", "fill 0 normal" }, 437 { NULL, NULL, TSTAT_ENT_CONTINUED }, 438 { NULL, NULL, TSTAT_ENT_CONTINUED }, 439 { NULL, NULL, TSTAT_ENT_CONTINUED }, 440 { "fill-user-32", "fill user window, 32-bit" }, 441 { NULL, NULL, TSTAT_ENT_CONTINUED }, 442 { NULL, NULL, TSTAT_ENT_CONTINUED }, 443 { NULL, NULL, TSTAT_ENT_CONTINUED }, 444 { "fill-user-64", "fill user window, 64-bit" }, 445 { NULL, NULL, TSTAT_ENT_CONTINUED }, 446 { NULL, NULL, TSTAT_ENT_CONTINUED }, 447 { NULL, NULL, TSTAT_ENT_CONTINUED }, 448 { "fill-user-32-cln", "fill user window, 32-bit" }, 449 { NULL, NULL, TSTAT_ENT_CONTINUED }, 450 { NULL, NULL, TSTAT_ENT_CONTINUED }, 451 { NULL, NULL, TSTAT_ENT_CONTINUED }, 452 { "fill-user-64-cln", "fill user window, 64-bit" }, 453 { NULL, NULL, TSTAT_ENT_CONTINUED }, 454 { NULL, NULL, TSTAT_ENT_CONTINUED }, 455 { NULL, NULL, TSTAT_ENT_CONTINUED }, 456 { "fill-kern-32", "fill kernel window, 32-bit" }, 457 { NULL, NULL, TSTAT_ENT_CONTINUED }, 458 { NULL, NULL, TSTAT_ENT_CONTINUED }, 459 { NULL, NULL, TSTAT_ENT_CONTINUED }, 460 { "fill-kern-64", "fill kernel window, 64-bit" }, 461 { NULL, NULL, TSTAT_ENT_CONTINUED }, 462 { NULL, NULL, TSTAT_ENT_CONTINUED }, 463 { NULL, NULL, TSTAT_ENT_CONTINUED }, 464 { "fill-mixed", "fill window, mixed 32-bit/64-bit" }, 465 { NULL, NULL, TSTAT_ENT_CONTINUED }, 466 { NULL, NULL, TSTAT_ENT_CONTINUED }, 467 { NULL, NULL, TSTAT_ENT_CONTINUED }, 468 { "fill-0-other", "fill 0 other" }, 469 { NULL, NULL, TSTAT_ENT_CONTINUED }, 470 { NULL, NULL, TSTAT_ENT_CONTINUED }, 471 { NULL, NULL, TSTAT_ENT_CONTINUED }, 472 { "fill-asuser-32", "fill user window as kernel, 32-bit" }, 473 { NULL, NULL, TSTAT_ENT_CONTINUED }, 474 { NULL, NULL, TSTAT_ENT_CONTINUED }, 475 { NULL, NULL, TSTAT_ENT_CONTINUED }, 476 { "fill-asuser-64", "fill user window as kernel, 64-bit" }, 477 { NULL, NULL, TSTAT_ENT_CONTINUED }, 478 { NULL, NULL, TSTAT_ENT_CONTINUED }, 479 { NULL, NULL, TSTAT_ENT_CONTINUED }, 480 { "fill-asuser-32-cln", "fill user window as kernel, 32-bit" }, 481 { NULL, NULL, TSTAT_ENT_CONTINUED }, 482 { NULL, NULL, TSTAT_ENT_CONTINUED }, 483 { NULL, NULL, TSTAT_ENT_CONTINUED }, 484 { "fill-asuser-64-cln", "fill user window as kernel, 64-bit" }, 485 { NULL, NULL, TSTAT_ENT_CONTINUED }, 486 { NULL, NULL, TSTAT_ENT_CONTINUED }, 487 { NULL, NULL, TSTAT_ENT_CONTINUED }, 488 { "fill-5-other", "fill 5 other" }, 489 { NULL, NULL, TSTAT_ENT_CONTINUED }, 490 { NULL, NULL, TSTAT_ENT_CONTINUED }, 491 { NULL, NULL, TSTAT_ENT_CONTINUED }, 492 { "fill-6-other", "fill 6 other" }, 493 { NULL, NULL, TSTAT_ENT_CONTINUED }, 494 { NULL, NULL, TSTAT_ENT_CONTINUED }, 495 { NULL, NULL, TSTAT_ENT_CONTINUED }, 496 { "fill-7-other", "fill 7 other" }, 497 { NULL, NULL, TSTAT_ENT_CONTINUED }, 498 { NULL, NULL, TSTAT_ENT_CONTINUED }, 499 { NULL, NULL, TSTAT_ENT_CONTINUED }, 500 { "syscall-4x", "old system call" }, 501 { "usr-brkpt", "user breakpoint" }, 502 { "usr-div-zero", "user divide by zero" }, 503 { "flush-wins", "flush windows" }, 504 { "clean-wins", "clean windows" }, 505 { NULL, NULL, TSTAT_ENT_UNUSED }, 506 { "fix-align", "fix unaligned references" }, 507 { NULL, NULL, TSTAT_ENT_UNUSED }, 508 { "syscall-32", "ILP32 system call" }, 509 { "set-t0-addr", "set trap0 address" }, 510 { NULL, NULL, TSTAT_ENT_UNUSED }, 511 { NULL, NULL, TSTAT_ENT_UNUSED }, 512 { NULL, NULL, TSTAT_ENT_UNUSED }, 513 { NULL, NULL, TSTAT_ENT_UNUSED }, 514 { NULL, NULL, TSTAT_ENT_UNUSED }, 515 { NULL, NULL, TSTAT_ENT_UNUSED }, 516 { "trap-inst-16", "trap instruction 16", }, 517 { "trap-inst-17", "trap instruction 17", }, 518 { "trap-inst-18", "trap instruction 18", }, 519 { "trap-inst-19", "trap instruction 19", }, 520 { "trap-inst-20", "trap instruction 20", }, 521 { "trap-inst-21", "trap instruction 21", }, 522 { "trap-inst-22", "trap instruction 22", }, 523 { "trap-inst-23", "trap instruction 23", }, 524 { "trap-inst-24", "trap instruction 24", }, 525 { "trap-inst-25", "trap instruction 25", }, 526 { "trap-inst-26", "trap instruction 26", }, 527 { "trap-inst-27", "trap instruction 27", }, 528 { "trap-inst-28", "trap instruction 28", }, 529 { "trap-inst-29", "trap instruction 29", }, 530 { "trap-inst-30", "trap instruction 30", }, 531 { "trap-inst-31", "trap instruction 31", }, 532 { "get-cc", "get condition codes" }, 533 { "set-cc", "set condition codes" }, 534 { "get-psr", "get psr" }, 535 { "set-psr", "set psr (some fields)" }, 536 { "getts", "get timestamp" }, 537 { "gethrvtime", "get lwp virtual time" }, 538 { "self-xcall", "self xcall" }, 539 { "gethrtime", "get hrestime" }, 540 { NULL, NULL, TSTAT_ENT_UNUSED }, 541 { "getlgrp", "get lgrpid" }, 542 { NULL, NULL, TSTAT_ENT_UNUSED }, 543 { NULL, NULL, TSTAT_ENT_UNUSED }, 544 { NULL, NULL, TSTAT_ENT_UNUSED }, 545 { NULL, NULL, TSTAT_ENT_UNUSED }, 546 { NULL, NULL, TSTAT_ENT_UNUSED }, 547 { NULL, NULL, TSTAT_ENT_UNUSED }, 548 { NULL, NULL, TSTAT_ENT_UNUSED }, 549 { NULL, NULL, TSTAT_ENT_UNUSED }, 550 { NULL, NULL, TSTAT_ENT_UNUSED }, 551 { NULL, NULL, TSTAT_ENT_UNUSED }, 552 { NULL, NULL, TSTAT_ENT_UNUSED }, 553 { NULL, NULL, TSTAT_ENT_UNUSED }, 554 { NULL, NULL, TSTAT_ENT_UNUSED }, 555 { NULL, NULL, TSTAT_ENT_UNUSED }, 556 { "dtrace-pid", "DTrace pid provider" }, 557 { NULL, NULL, TSTAT_ENT_UNUSED }, 558 { "dtrace-return", "DTrace pid provider return" }, 559 { NULL, NULL, TSTAT_ENT_UNUSED }, 560 { NULL, NULL, TSTAT_ENT_UNUSED }, 561 { NULL, NULL, TSTAT_ENT_UNUSED }, 562 { NULL, NULL, TSTAT_ENT_UNUSED }, 563 { NULL, NULL, TSTAT_ENT_UNUSED }, 564 { "syscall-64", "LP64 system call" }, 565 { NULL, NULL, TSTAT_ENT_UNUSED }, 566 { "tt-freeze", "freeze traptrace" }, 567 { "tt-unfreeze", "unfreeze traptrace" }, 568 { NULL, NULL, TSTAT_ENT_UNUSED }, 569 { NULL, NULL, TSTAT_ENT_UNUSED }, 570 { NULL, NULL, TSTAT_ENT_UNUSED }, 571 { NULL, NULL, TSTAT_ENT_UNUSED }, 572 { NULL, NULL, TSTAT_ENT_UNUSED }, 573 { NULL, NULL, TSTAT_ENT_UNUSED }, 574 { NULL, NULL, TSTAT_ENT_UNUSED }, 575 { NULL, NULL, TSTAT_ENT_UNUSED }, 576 { NULL, NULL, TSTAT_ENT_UNUSED }, 577 { NULL, NULL, TSTAT_ENT_UNUSED }, 578 { NULL, NULL, TSTAT_ENT_UNUSED }, 579 { NULL, NULL, TSTAT_ENT_UNUSED }, 580 { NULL, NULL, TSTAT_ENT_UNUSED }, 581 { NULL, NULL, TSTAT_ENT_UNUSED }, 582 { NULL, NULL, TSTAT_ENT_UNUSED }, 583 { NULL, NULL, TSTAT_ENT_UNUSED }, 584 { NULL, NULL, TSTAT_ENT_UNUSED }, 585 { NULL, NULL, TSTAT_ENT_UNUSED }, 586 { NULL, NULL, TSTAT_ENT_UNUSED }, 587 { NULL, NULL, TSTAT_ENT_UNUSED }, 588 { NULL, NULL, TSTAT_ENT_UNUSED }, 589 { NULL, NULL, TSTAT_ENT_UNUSED }, 590 { NULL, NULL, TSTAT_ENT_UNUSED }, 591 { NULL, NULL, TSTAT_ENT_UNUSED }, 592 { NULL, NULL, TSTAT_ENT_UNUSED }, 593 { NULL, NULL, TSTAT_ENT_UNUSED }, 594 { NULL, NULL, TSTAT_ENT_UNUSED }, 595 { NULL, NULL, TSTAT_ENT_UNUSED }, 596 { NULL, NULL, TSTAT_ENT_UNUSED }, 597 { NULL, NULL, TSTAT_ENT_UNUSED }, 598 { NULL, NULL, TSTAT_ENT_UNUSED }, 599 { NULL, NULL, TSTAT_ENT_UNUSED }, 600 { NULL, NULL, TSTAT_ENT_UNUSED }, 601 { NULL, NULL, TSTAT_ENT_UNUSED }, 602 { NULL, NULL, TSTAT_ENT_UNUSED }, 603 { NULL, NULL, TSTAT_ENT_UNUSED }, 604 { NULL, NULL, TSTAT_ENT_UNUSED }, 605 { NULL, NULL, TSTAT_ENT_UNUSED }, 606 { NULL, NULL, TSTAT_ENT_UNUSED }, 607 { NULL, NULL, TSTAT_ENT_UNUSED }, 608 { NULL, NULL, TSTAT_ENT_UNUSED }, 609 { NULL, NULL, TSTAT_ENT_UNUSED }, 610 { NULL, NULL, TSTAT_ENT_UNUSED }, 611 { NULL, NULL, TSTAT_ENT_UNUSED }, 612 { NULL, NULL, TSTAT_ENT_UNUSED }, 613 { NULL, NULL, TSTAT_ENT_UNUSED }, 614 { NULL, NULL, TSTAT_ENT_UNUSED }, 615 { NULL, NULL, TSTAT_ENT_UNUSED }, 616 { NULL, NULL, TSTAT_ENT_UNUSED }, 617 { NULL, NULL, TSTAT_ENT_UNUSED }, 618 { NULL, NULL, TSTAT_ENT_UNUSED }, 619 { NULL, NULL, TSTAT_ENT_UNUSED }, 620 { NULL, NULL, TSTAT_ENT_UNUSED }, 621 { NULL, NULL, TSTAT_ENT_UNUSED }, 622 { NULL, NULL, TSTAT_ENT_UNUSED }, 623 { NULL, NULL, TSTAT_ENT_UNUSED }, 624 { "ptl1-panic", "test ptl1-panic" }, 625 { "kmdb-enter", "kmdb enter (L1-A)" }, 626 { "kmdb-brkpt", "kmdb breakpoint" }, 627 { "obp-brkpt", "obp breakpoint" }, 628 { NULL, NULL, TSTAT_ENT_RESERVED }, 629 { NULL, NULL, TSTAT_ENT_RESERVED }, 630 { NULL, NULL, TSTAT_ENT_RESERVED }, 631 { NULL, NULL, TSTAT_ENT_RESERVED }, 632 { NULL, NULL, TSTAT_ENT_RESERVED }, 633 { NULL, NULL, TSTAT_ENT_RESERVED }, 634 { NULL, NULL, TSTAT_ENT_RESERVED }, 635 { NULL, NULL, TSTAT_ENT_RESERVED }, 636 { NULL, NULL, TSTAT_ENT_RESERVED }, 637 { NULL, NULL, TSTAT_ENT_RESERVED }, 638 { NULL, NULL, TSTAT_ENT_RESERVED }, 639 { NULL, NULL, TSTAT_ENT_RESERVED }, 640 { NULL, NULL, TSTAT_ENT_RESERVED }, 641 { NULL, NULL, TSTAT_ENT_RESERVED }, 642 { NULL, NULL, TSTAT_ENT_RESERVED }, 643 { NULL, NULL, TSTAT_ENT_RESERVED }, 644 { NULL, NULL, TSTAT_ENT_RESERVED }, 645 { NULL, NULL, TSTAT_ENT_RESERVED }, 646 { NULL, NULL, TSTAT_ENT_RESERVED }, 647 { NULL, NULL, TSTAT_ENT_RESERVED }, 648 { NULL, NULL, TSTAT_ENT_RESERVED }, 649 { NULL, NULL, TSTAT_ENT_RESERVED }, 650 { NULL, NULL, TSTAT_ENT_RESERVED }, 651 { NULL, NULL, TSTAT_ENT_RESERVED }, 652 { NULL, NULL, TSTAT_ENT_RESERVED }, 653 { NULL, NULL, TSTAT_ENT_RESERVED }, 654 { NULL, NULL, TSTAT_ENT_RESERVED }, 655 { NULL, NULL, TSTAT_ENT_RESERVED }, 656 { NULL, NULL, TSTAT_ENT_RESERVED }, 657 { NULL, NULL, TSTAT_ENT_RESERVED }, 658 { NULL, NULL, TSTAT_ENT_RESERVED }, 659 { NULL, NULL, TSTAT_ENT_RESERVED }, 660 { NULL, NULL, TSTAT_ENT_RESERVED }, 661 { NULL, NULL, TSTAT_ENT_RESERVED }, 662 { NULL, NULL, TSTAT_ENT_RESERVED }, 663 { NULL, NULL, TSTAT_ENT_RESERVED }, 664 { NULL, NULL, TSTAT_ENT_RESERVED }, 665 { NULL, NULL, TSTAT_ENT_RESERVED }, 666 { NULL, NULL, TSTAT_ENT_RESERVED }, 667 { NULL, NULL, TSTAT_ENT_RESERVED }, 668 { NULL, NULL, TSTAT_ENT_RESERVED }, 669 { NULL, NULL, TSTAT_ENT_RESERVED }, 670 { NULL, NULL, TSTAT_ENT_RESERVED }, 671 { NULL, NULL, TSTAT_ENT_RESERVED }, 672 { NULL, NULL, TSTAT_ENT_RESERVED }, 673 { NULL, NULL, TSTAT_ENT_RESERVED }, 674 { NULL, NULL, TSTAT_ENT_RESERVED }, 675 { NULL, NULL, TSTAT_ENT_RESERVED }, 676 { NULL, NULL, TSTAT_ENT_RESERVED }, 677 { NULL, NULL, TSTAT_ENT_RESERVED }, 678 { NULL, NULL, TSTAT_ENT_RESERVED }, 679 { NULL, NULL, TSTAT_ENT_RESERVED }, 680 { NULL, NULL, TSTAT_ENT_RESERVED }, 681 { NULL, NULL, TSTAT_ENT_RESERVED }, 682 { NULL, NULL, TSTAT_ENT_RESERVED }, 683 { NULL, NULL, TSTAT_ENT_RESERVED }, 684 { NULL, NULL, TSTAT_ENT_RESERVED }, 685 { NULL, NULL, TSTAT_ENT_RESERVED }, 686 { NULL, NULL, TSTAT_ENT_RESERVED }, 687 { NULL, NULL, TSTAT_ENT_RESERVED }, 688 { NULL, NULL, TSTAT_ENT_RESERVED }, 689 { NULL, NULL, TSTAT_ENT_RESERVED }, 690 { NULL, NULL, TSTAT_ENT_RESERVED }, 691 { NULL, NULL, TSTAT_ENT_RESERVED }, 692 { NULL, NULL, TSTAT_ENT_RESERVED }, 693 { NULL, NULL, TSTAT_ENT_RESERVED }, 694 { NULL, NULL, TSTAT_ENT_RESERVED }, 695 { NULL, NULL, TSTAT_ENT_RESERVED }, 696 { NULL, NULL, TSTAT_ENT_RESERVED }, 697 { NULL, NULL, TSTAT_ENT_RESERVED }, 698 { NULL, NULL, TSTAT_ENT_RESERVED }, 699 { NULL, NULL, TSTAT_ENT_RESERVED }, 700 { NULL, NULL, TSTAT_ENT_RESERVED }, 701 { NULL, NULL, TSTAT_ENT_RESERVED }, 702 { NULL, NULL, TSTAT_ENT_RESERVED }, 703 { NULL, NULL, TSTAT_ENT_RESERVED }, 704 { NULL, NULL, TSTAT_ENT_RESERVED }, 705 { NULL, NULL, TSTAT_ENT_RESERVED }, 706 { NULL, NULL, TSTAT_ENT_RESERVED }, 707 { NULL, NULL, TSTAT_ENT_RESERVED }, 708 { NULL, NULL, TSTAT_ENT_RESERVED }, 709 { NULL, NULL, TSTAT_ENT_RESERVED }, 710 { NULL, NULL, TSTAT_ENT_RESERVED }, 711 { NULL, NULL, TSTAT_ENT_RESERVED }, 712 { NULL, NULL, TSTAT_ENT_RESERVED }, 713 { NULL, NULL, TSTAT_ENT_RESERVED }, 714 { NULL, NULL, TSTAT_ENT_RESERVED }, 715 { NULL, NULL, TSTAT_ENT_RESERVED }, 716 { NULL, NULL, TSTAT_ENT_RESERVED }, 717 { NULL, NULL, TSTAT_ENT_RESERVED }, 718 { NULL, NULL, TSTAT_ENT_RESERVED }, 719 { NULL, NULL, TSTAT_ENT_RESERVED }, 720 { NULL, NULL, TSTAT_ENT_RESERVED }, 721 { NULL, NULL, TSTAT_ENT_RESERVED }, 722 { NULL, NULL, TSTAT_ENT_RESERVED }, 723 { NULL, NULL, TSTAT_ENT_RESERVED }, 724 { NULL, NULL, TSTAT_ENT_RESERVED }, 725 { NULL, NULL, TSTAT_ENT_RESERVED }, 726 { NULL, NULL, TSTAT_ENT_RESERVED }, 727 { NULL, NULL, TSTAT_ENT_RESERVED }, 728 { NULL, NULL, TSTAT_ENT_RESERVED }, 729 { NULL, NULL, TSTAT_ENT_RESERVED }, 730 { NULL, NULL, TSTAT_ENT_RESERVED }, 731 { NULL, NULL, TSTAT_ENT_RESERVED }, 732 { NULL, NULL, TSTAT_ENT_RESERVED }, 733 { NULL, NULL, TSTAT_ENT_RESERVED }, 734 { NULL, NULL, TSTAT_ENT_RESERVED }, 735 { NULL, NULL, TSTAT_ENT_RESERVED }, 736 { NULL, NULL, TSTAT_ENT_RESERVED }, 737 { NULL, NULL, TSTAT_ENT_RESERVED }, 738 { NULL, NULL, TSTAT_ENT_RESERVED }, 739 { NULL, NULL, TSTAT_ENT_RESERVED }, 740 { NULL, NULL, TSTAT_ENT_RESERVED }, 741 { NULL, NULL, TSTAT_ENT_RESERVED }, 742 { NULL, NULL, TSTAT_ENT_RESERVED }, 743 { NULL, NULL, TSTAT_ENT_RESERVED }, 744 { NULL, NULL, TSTAT_ENT_RESERVED }, 745 { NULL, NULL, TSTAT_ENT_RESERVED }, 746 { NULL, NULL, TSTAT_ENT_RESERVED }, 747 { NULL, NULL, TSTAT_ENT_RESERVED }, 748 { NULL, NULL, TSTAT_ENT_RESERVED }, 749 { NULL, NULL, TSTAT_ENT_RESERVED }, 750 { NULL, NULL, TSTAT_ENT_RESERVED }, 751 { NULL, NULL, TSTAT_ENT_RESERVED }, 752 { NULL, NULL, TSTAT_ENT_RESERVED }, 753 { NULL, NULL, TSTAT_ENT_RESERVED }, 754 { NULL, NULL, TSTAT_ENT_RESERVED }, 755 { NULL, NULL, TSTAT_ENT_RESERVED } 756 }; 757 758 static void 759 usage(void) 760 { 761 (void) fprintf(stderr, 762 "\nusage: trapstat [ -t | -T | -e entrylist ]\n" 763 " [ -C psrset | -c cpulist ]\n" 764 " [ -P ] [ -a ] [ -r rate ] [[ interval [ count ] ] | " 765 "command [ args ] ]\n\n" 766 "Trap selection options:\n\n" 767 " -t TLB statistics\n" 768 " -T TLB statistics, with pagesize information\n" 769 " -e entrylist Enable statistics only for entries specified " 770 "by entrylist\n\n" 771 "CPU selection options:\n\n" 772 " -c cpulist Enable statistics only for specified CPU list\n" 773 " -C psrset Enable statistics only for specified processor " 774 "set\n\n" 775 "Other options:\n\n" 776 " -a Display trap values as accumulating values " 777 "instead of rates\n" 778 " -l List trap table entries and exit\n" 779 " -P Display output in parsable format\n" 780 " -r hz Set sampling rate to be hz samples " 781 "per second\n\n"); 782 783 exit(EXIT_FAILURE); 784 } 785 786 static void 787 fatal(char *fmt, ...) 788 { 789 va_list ap; 790 int error = errno; 791 792 va_start(ap, fmt); 793 794 (void) fprintf(stderr, TSTAT_COMMAND ": "); 795 (void) vfprintf(stderr, fmt, ap); 796 797 if (fmt[strlen(fmt) - 1] != '\n') 798 (void) fprintf(stderr, ": %s\n", strerror(error)); 799 800 exit(EXIT_FAILURE); 801 } 802 803 static void 804 set_width(void) 805 { 806 struct winsize win; 807 808 if (!isatty(fileno(stdout))) 809 return; 810 811 if (ioctl(fileno(stdout), TIOCGWINSZ, &win) == -1) 812 return; 813 814 if (win.ws_col == 0) { 815 /* 816 * If TIOCGWINSZ returned 0 for the columns, just return -- 817 * thereby using the default value of g_cpus_per_line. (This 818 * happens, e.g., when running over a tip line.) 819 */ 820 return; 821 } 822 823 g_cpus_per_line = (win.ws_col - TSTAT_COLUMN_OFFS) / 824 TSTAT_COLUMNS_PER_CPU; 825 826 if (g_cpus_per_line < 1) 827 g_cpus_per_line = 1; 828 } 829 830 static void 831 intr(int signo) 832 { 833 int error = errno; 834 835 switch (signo) { 836 case SIGWINCH: 837 g_winch = 1; 838 set_width(); 839 break; 840 841 case SIGCHLD: 842 g_child_exited = 1; 843 844 while (wait(&g_child_status) == -1 && errno == EINTR) 845 continue; 846 break; 847 848 default: 849 break; 850 } 851 852 errno = error; 853 } 854 855 static void 856 setup(void) 857 { 858 struct sigaction act; 859 struct sigevent ev; 860 sigset_t set; 861 int i; 862 863 for (i = 0; i < TSTAT_NENT; i++) { 864 if (g_traps[i].tent_type == TSTAT_ENT_RESERVED) 865 g_traps[i].tent_name = "reserved"; 866 867 if (g_traps[i].tent_type == TSTAT_ENT_UNUSED) 868 g_traps[i].tent_name = "unused"; 869 } 870 871 g_max_cpus = (processorid_t)sysconf(_SC_CPUID_MAX) + 1; 872 873 if ((g_selected = malloc(sizeof (int8_t) * g_max_cpus)) == NULL) 874 fatal("could not allocate g_selected"); 875 876 bzero(g_selected, sizeof (int8_t) * g_max_cpus); 877 878 g_pset_cpus = malloc(sizeof (processorid_t) * g_max_cpus); 879 if (g_pset_cpus == NULL) 880 fatal("could not allocate g_pset_cpus"); 881 882 bzero(g_pset_cpus, sizeof (processorid_t) * g_max_cpus); 883 884 if ((g_pgsizes = getpagesizes(NULL, 0)) == -1) 885 fatal("getpagesizes()"); 886 887 if ((g_pgsize = malloc(sizeof (size_t) * g_pgsizes)) == NULL) 888 fatal("could not allocate g_pgsize array"); 889 890 if (getpagesizes(g_pgsize, g_pgsizes) == -1) 891 fatal("getpagesizes(%d)", g_pgsizes); 892 893 if ((g_pgnames = malloc(sizeof (char *) * g_pgsizes)) == NULL) 894 fatal("could not allocate g_pgnames"); 895 896 for (i = 0; i < g_pgsizes; i++) { 897 size_t j, mul; 898 size_t sz = g_pgsize[i]; 899 900 if ((g_pgnames[i] = malloc(TSTAT_PAGESIZE_STRLEN)) == NULL) 901 fatal("could not allocate g_pgnames[%d]", i); 902 903 for (j = 0, mul = 10; (1 << mul) <= sz; j++, mul += 10) 904 continue; 905 906 (void) snprintf(g_pgnames[i], TSTAT_PAGESIZE_STRLEN, 907 "%d%c", sz >> (mul - 10), " kmgtpe"[j]); 908 } 909 910 g_datasize = 911 sizeof (tstat_data_t) + (g_pgsizes - 1) * sizeof (tstat_pgszdata_t); 912 913 if ((g_data[0] = malloc(g_datasize * g_max_cpus)) == NULL) 914 fatal("could not allocate data buffer 0"); 915 916 if ((g_data[1] = malloc(g_datasize * g_max_cpus)) == NULL) 917 fatal("could not allocate data buffer 1"); 918 919 (void) sigemptyset(&act.sa_mask); 920 act.sa_flags = 0; 921 act.sa_handler = intr; 922 (void) sigaction(SIGUSR1, &act, NULL); 923 (void) sigaction(SIGCHLD, &act, NULL); 924 925 (void) sigaddset(&act.sa_mask, SIGCHLD); 926 (void) sigaddset(&act.sa_mask, SIGUSR1); 927 (void) sigaction(SIGWINCH, &act, NULL); 928 set_width(); 929 930 (void) sigemptyset(&set); 931 (void) sigaddset(&set, SIGCHLD); 932 (void) sigaddset(&set, SIGUSR1); 933 (void) sigaddset(&set, SIGWINCH); 934 (void) sigprocmask(SIG_BLOCK, &set, &g_oset); 935 936 ev.sigev_notify = SIGEV_SIGNAL; 937 ev.sigev_signo = SIGUSR1; 938 939 if (timer_create(CLOCK_HIGHRES, &ev, &g_tid) == -1) 940 fatal("cannot create CLOCK_HIGHRES timer"); 941 } 942 943 static void 944 set_interval(hrtime_t nsec) 945 { 946 struct itimerspec ts; 947 948 /* 949 * If the interval is less than one second, we'll report the 950 * numbers in terms of rate-per-interval. If the interval is 951 * greater than one second, we'll report numbers in terms of 952 * rate-per-second. 953 */ 954 g_interval = nsec < NANOSEC ? nsec : NANOSEC; 955 956 ts.it_value.tv_sec = nsec / NANOSEC; 957 ts.it_value.tv_nsec = nsec % NANOSEC; 958 ts.it_interval.tv_sec = nsec / NANOSEC; 959 ts.it_interval.tv_nsec = nsec % NANOSEC; 960 961 if (timer_settime(g_tid, TIMER_RELTIME, &ts, NULL) == -1) 962 fatal("cannot set time on CLOCK_HIGHRES timer"); 963 } 964 965 static void 966 print_entries(FILE *stream, int parsable) 967 { 968 int entno; 969 970 if (!parsable) { 971 (void) fprintf(stream, " %3s %3s | %-20s | %s\n", "hex", 972 "dec", "entry name", "description"); 973 974 (void) fprintf(stream, "----------+----------------------" 975 "+-----------------------\n"); 976 } 977 978 for (entno = 0; entno < TSTAT_NENT; entno++) { 979 if (g_traps[entno].tent_type != TSTAT_ENT_USED) 980 continue; 981 982 (void) fprintf(stream, "0x%03x %3d %s%-20s %s%s\n", 983 entno, entno, 984 parsable ? "" : "| ", g_traps[entno].tent_name, 985 parsable ? "" : "| ", g_traps[entno].tent_descr); 986 } 987 } 988 989 static void 990 select_entry(char *entry) 991 { 992 ulong_t entno; 993 char *end; 994 995 /* 996 * The entry may be specified as a number (e.g., "0x68", "104") or 997 * as a name ("dtlb-miss"). 998 */ 999 entno = strtoul(entry, &end, 0); 1000 1001 if (*end == '\0') { 1002 if (entno >= TSTAT_NENT) 1003 goto bad_entry; 1004 } else { 1005 for (entno = 0; entno < TSTAT_NENT; entno++) { 1006 if (g_traps[entno].tent_type != TSTAT_ENT_USED) 1007 continue; 1008 1009 if (strcmp(entry, g_traps[entno].tent_name) == 0) 1010 break; 1011 } 1012 1013 if (entno == TSTAT_NENT) 1014 goto bad_entry; 1015 } 1016 1017 if (ioctl(g_fd, TSTATIOC_ENTRY, entno) == -1) 1018 fatal("TSTATIOC_ENTRY failed for entry 0x%x", entno); 1019 1020 g_active[entno] = 1; 1021 return; 1022 1023 bad_entry: 1024 (void) fprintf(stderr, TSTAT_COMMAND ": invalid entry '%s'", entry); 1025 (void) fprintf(stderr, "; valid entries:\n\n"); 1026 print_entries(stderr, 0); 1027 exit(EXIT_FAILURE); 1028 } 1029 1030 static void 1031 select_cpu(processorid_t cpu) 1032 { 1033 if (g_pset != PS_NONE) 1034 fatal("cannot specify both a processor set and a processor\n"); 1035 1036 if (cpu < 0 || cpu >= g_max_cpus) 1037 fatal("cpu %d out of range\n", cpu); 1038 1039 if (p_online(cpu, P_STATUS) == -1) { 1040 if (errno != EINVAL) 1041 fatal("could not get status for cpu %d", cpu); 1042 fatal("cpu %d not present\n", cpu); 1043 } 1044 1045 g_selected[cpu] = 1; 1046 } 1047 1048 static void 1049 select_cpus(processorid_t low, processorid_t high) 1050 { 1051 if (g_pset != PS_NONE) 1052 fatal("cannot specify both a processor set and processors\n"); 1053 1054 if (low < 0 || low >= g_max_cpus) 1055 fatal("invalid cpu '%d'\n", low); 1056 1057 if (high < 0 || high >= g_max_cpus) 1058 fatal("invalid cpu '%d'\n", high); 1059 1060 if (low >= high) 1061 fatal("invalid range '%d' to '%d'\n", low, high); 1062 1063 do { 1064 if (p_online(low, P_STATUS) != -1) 1065 g_selected[low] = 1; 1066 } while (++low <= high); 1067 } 1068 1069 static void 1070 select_pset(psetid_t pset) 1071 { 1072 processorid_t i; 1073 1074 if (pset < 0) 1075 fatal("processor set %d is out of range\n", pset); 1076 1077 /* 1078 * Only one processor set can be specified. 1079 */ 1080 if (g_pset != PS_NONE) 1081 fatal("at most one processor set may be specified\n"); 1082 1083 /* 1084 * One cannot select processors _and_ a processor set. 1085 */ 1086 for (i = 0; i < g_max_cpus; i++) 1087 if (g_selected[i]) 1088 break; 1089 1090 if (i != g_max_cpus) 1091 fatal("cannot specify both a processor and a processor set\n"); 1092 1093 g_pset = pset; 1094 g_pset_ncpus = g_max_cpus; 1095 1096 if (pset_info(g_pset, NULL, &g_pset_ncpus, g_pset_cpus) == -1) 1097 fatal("invalid processor set: %d\n", g_pset); 1098 1099 if (g_pset_ncpus == 0) 1100 fatal("processor set %d empty\n", g_pset); 1101 1102 if (ioctl(g_fd, TSTATIOC_NOCPU) == -1) 1103 fatal("TSTATIOC_NOCPU failed"); 1104 1105 for (i = 0; i < g_pset_ncpus; i++) 1106 g_selected[g_pset_cpus[i]] = 1; 1107 } 1108 1109 static void 1110 check_pset(void) 1111 { 1112 uint_t ncpus = g_max_cpus; 1113 processorid_t i; 1114 1115 if (g_pset == PS_NONE) 1116 return; 1117 1118 if (pset_info(g_pset, NULL, &ncpus, g_pset_cpus) == -1) { 1119 if (errno == EINVAL) 1120 fatal("processor set %d destroyed\n", g_pset); 1121 1122 fatal("couldn't get info for processor set %d", g_pset); 1123 } 1124 1125 if (ncpus == 0) 1126 fatal("processor set %d empty\n", g_pset); 1127 1128 if (ncpus == g_pset_ncpus) { 1129 for (i = 0; i < g_pset_ncpus; i++) { 1130 if (!g_selected[g_pset_cpus[i]]) 1131 break; 1132 } 1133 1134 /* 1135 * If the number of CPUs hasn't changed, and every CPU 1136 * in the processor set is also selected, we know that the 1137 * processor set itself hasn't changed. 1138 */ 1139 if (i == g_pset_ncpus) 1140 return; 1141 } 1142 1143 /* 1144 * If we're here, we have a new processor set. First, we need 1145 * to zero out the selection array. 1146 */ 1147 bzero(g_selected, sizeof (int8_t) * g_max_cpus); 1148 1149 g_pset_ncpus = ncpus; 1150 1151 if (ioctl(g_fd, TSTATIOC_STOP) == -1) 1152 fatal("TSTATIOC_STOP failed"); 1153 1154 if (ioctl(g_fd, TSTATIOC_NOCPU) == -1) 1155 fatal("TSATIOC_NOCPU failed"); 1156 1157 for (i = 0; i < g_pset_ncpus; i++) { 1158 g_selected[g_pset_cpus[i]] = 1; 1159 if (ioctl(g_fd, TSTATIOC_CPU, g_pset_cpus[i]) == -1) 1160 fatal("TSTATIOC_CPU failed for cpu %d", i); 1161 } 1162 1163 /* 1164 * Now that we have selected the CPUs, we're going to reenable 1165 * trapstat, and reread the data for the current generation. 1166 */ 1167 if (ioctl(g_fd, TSTATIOC_GO) == -1) 1168 fatal("TSTATIOC_GO failed"); 1169 1170 if (ioctl(g_fd, TSTATIOC_READ, g_data[g_gen]) == -1) 1171 fatal("TSTATIOC_READ failed"); 1172 } 1173 1174 static void 1175 missdata(tstat_missdata_t *miss, tstat_missdata_t *omiss) 1176 { 1177 hrtime_t ts = g_ndata->tdata_snapts - g_odata->tdata_snapts; 1178 hrtime_t tick = g_ndata->tdata_snaptick - g_odata->tdata_snaptick; 1179 uint64_t raw = miss->tmiss_count - omiss->tmiss_count; 1180 uint64_t diff = g_absolute ? miss->tmiss_count : 1181 (uint64_t)(0.5 + g_interval / 1182 (double)ts * (double)(miss->tmiss_count - omiss->tmiss_count)); 1183 hrtime_t peffect = raw * g_ndata->tdata_peffect * g_peffect, time; 1184 double p; 1185 1186 /* 1187 * Now we need to account for the trapstat probe effect. Take 1188 * the amount of time spent in the handler, and add the 1189 * amount of time known to be due to the trapstat probe effect. 1190 */ 1191 time = miss->tmiss_time - omiss->tmiss_time + peffect; 1192 1193 if (time >= tick) { 1194 /* 1195 * This really shouldn't happen unless our calculation of 1196 * the probe effect was vastly incorrect. In any case, 1197 * print 99.9 for the time instead of printing negative 1198 * values... 1199 */ 1200 time = tick / 1000 * 999; 1201 } 1202 1203 p = (double)time / (double)tick * (double)100.0; 1204 1205 (*g_process)(g_arg, diff, p); 1206 } 1207 1208 static void 1209 tlbdata(tstat_tlbdata_t *tlb, tstat_tlbdata_t *otlb) 1210 { 1211 missdata(&tlb->ttlb_tlb, &otlb->ttlb_tlb); 1212 missdata(&tlb->ttlb_tsb, &otlb->ttlb_tsb); 1213 } 1214 1215 static void 1216 print_missdata(double *ttl, uint64_t diff, double p) 1217 { 1218 TSTAT_PRINT_MISSDATA(diff, p); 1219 1220 if (ttl != NULL) 1221 *ttl += p; 1222 } 1223 1224 static void 1225 print_modepgsz(char *prefix, tstat_modedata_t *data, tstat_modedata_t *odata) 1226 { 1227 int ps; 1228 size_t incr = sizeof (tstat_pgszdata_t); 1229 1230 for (ps = 0; ps < g_pgsizes; ps++) { 1231 double ttl = 0.0; 1232 1233 g_process = (void(*)(void *, uint64_t, double))print_missdata; 1234 g_arg = &ttl; 1235 1236 (void) printf("%s %4s|", prefix, g_pgnames[ps]); 1237 tlbdata(&data->tmode_itlb, &odata->tmode_itlb); 1238 (void) printf(" |"); 1239 tlbdata(&data->tmode_dtlb, &odata->tmode_dtlb); 1240 1241 (void) printf(" |%4.1f\n", ttl); 1242 1243 data = (tstat_modedata_t *)((uintptr_t)data + incr); 1244 odata = (tstat_modedata_t *)((uintptr_t)odata + incr); 1245 } 1246 } 1247 1248 static void 1249 parsable_modepgsz(char *prefix, tstat_modedata_t *data, tstat_modedata_t *odata) 1250 { 1251 int ps; 1252 size_t incr = sizeof (tstat_pgszdata_t); 1253 1254 g_process = (void(*)(void *, uint64_t, double))print_missdata; 1255 g_arg = NULL; 1256 1257 for (ps = 0; ps < g_pgsizes; ps++) { 1258 (void) printf("%s %7d", prefix, g_pgsize[ps]); 1259 tlbdata(&data->tmode_itlb, &odata->tmode_itlb); 1260 tlbdata(&data->tmode_dtlb, &odata->tmode_dtlb); 1261 (void) printf("\n"); 1262 1263 data = (tstat_modedata_t *)((uintptr_t)data + incr); 1264 odata = (tstat_modedata_t *)((uintptr_t)odata + incr); 1265 } 1266 } 1267 1268 static void 1269 sum_missdata(void *sump, uint64_t diff, double p) 1270 { 1271 tstat_sum_t *sum = *((tstat_sum_t **)sump); 1272 1273 sum->tsum_diff += diff; 1274 sum->tsum_time += p; 1275 1276 (*(tstat_sum_t **)sump)++; 1277 } 1278 1279 static void 1280 sum_modedata(tstat_modedata_t *data, tstat_modedata_t *odata, tstat_sum_t *sum) 1281 { 1282 int ps, incr = sizeof (tstat_pgszdata_t); 1283 tstat_sum_t *sump; 1284 1285 for (ps = 0; ps < g_pgsizes; ps++) { 1286 sump = sum; 1287 1288 g_process = sum_missdata; 1289 g_arg = &sump; 1290 1291 tlbdata(&data->tmode_itlb, &odata->tmode_itlb); 1292 tlbdata(&data->tmode_dtlb, &odata->tmode_dtlb); 1293 1294 data = (tstat_modedata_t *)((uintptr_t)data + incr); 1295 odata = (tstat_modedata_t *)((uintptr_t)odata + incr); 1296 } 1297 } 1298 1299 static void 1300 print_sum(tstat_sum_t *sum, int divisor) 1301 { 1302 int i; 1303 double ttl = 0.0; 1304 1305 for (i = 0; i < 4; i++) { 1306 if (i == 2) 1307 (void) printf(" |"); 1308 1309 sum[i].tsum_time /= divisor; 1310 1311 TSTAT_PRINT_MISSDATA(sum[i].tsum_diff, sum[i].tsum_time); 1312 ttl += sum[i].tsum_time; 1313 } 1314 1315 (void) printf(" |%4.1f\n", ttl); 1316 } 1317 1318 static void 1319 print_tlbpgsz(tstat_data_t *data, tstat_data_t *odata) 1320 { 1321 int i, cpu, ncpus = 0; 1322 char pre[12]; 1323 tstat_sum_t sum[4]; 1324 1325 (void) printf("cpu m size| %9s %4s %9s %4s | %9s %4s %9s %4s |%4s\n" 1326 "----------+-------------------------------+-----------------------" 1327 "--------+----\n", "itlb-miss", "%tim", "itsb-miss", "%tim", 1328 "dtlb-miss", "%tim", "dtsb-miss", "%tim", "%tim"); 1329 1330 bzero(sum, sizeof (sum)); 1331 1332 for (i = 0; i < g_max_cpus; i++) { 1333 tstat_pgszdata_t *pgsz = data->tdata_pgsz; 1334 tstat_pgszdata_t *opgsz = odata->tdata_pgsz; 1335 1336 if ((cpu = data->tdata_cpuid) == -1) 1337 break; 1338 1339 if (i != 0) 1340 (void) printf("----------+-----------------------------" 1341 "--+-------------------------------+----\n"); 1342 1343 g_ndata = data; 1344 g_odata = odata; 1345 1346 (void) sprintf(pre, "%3d u", cpu); 1347 print_modepgsz(pre, &pgsz->tpgsz_user, &opgsz->tpgsz_user); 1348 sum_modedata(&pgsz->tpgsz_user, &opgsz->tpgsz_user, sum); 1349 1350 (void) printf("- - - - - + - - - - - - - - - - - - - -" 1351 " - + - - - - - - - - - - - - - - - + - -\n"); 1352 1353 (void) sprintf(pre, "%3d k", cpu); 1354 print_modepgsz(pre, &pgsz->tpgsz_kernel, &opgsz->tpgsz_kernel); 1355 sum_modedata(&pgsz->tpgsz_kernel, &opgsz->tpgsz_kernel, sum); 1356 1357 data = (tstat_data_t *)((uintptr_t)data + g_datasize); 1358 odata = (tstat_data_t *)((uintptr_t)odata + g_datasize); 1359 ncpus++; 1360 } 1361 1362 (void) printf("==========+===============================+=========" 1363 "======================+====\n"); 1364 (void) printf(" ttl |"); 1365 print_sum(sum, ncpus); 1366 (void) printf("\n"); 1367 } 1368 1369 static void 1370 parsable_tlbpgsz(tstat_data_t *data, tstat_data_t *odata) 1371 { 1372 int i, cpu; 1373 char pre[30]; 1374 1375 for (i = 0; i < g_max_cpus; i++) { 1376 tstat_pgszdata_t *pgsz = data->tdata_pgsz; 1377 tstat_pgszdata_t *opgsz = odata->tdata_pgsz; 1378 1379 if ((cpu = data->tdata_cpuid) == -1) 1380 break; 1381 1382 g_ndata = data; 1383 g_odata = odata; 1384 1385 (void) sprintf(pre, "%lld %3d u", 1386 data->tdata_snapts - g_start, cpu); 1387 parsable_modepgsz(pre, &pgsz->tpgsz_user, &opgsz->tpgsz_user); 1388 1389 pre[strlen(pre) - 1] = 'k'; 1390 parsable_modepgsz(pre, &pgsz->tpgsz_kernel, 1391 &opgsz->tpgsz_kernel); 1392 1393 data = (tstat_data_t *)((uintptr_t)data + g_datasize); 1394 odata = (tstat_data_t *)((uintptr_t)odata + g_datasize); 1395 } 1396 } 1397 1398 static void 1399 print_modedata(tstat_modedata_t *data, tstat_modedata_t *odata, int parsable) 1400 { 1401 int ps, i; 1402 size_t incr = sizeof (tstat_pgszdata_t); 1403 tstat_sum_t sum[4], *sump = sum; 1404 double ttl = 0.0; 1405 1406 bzero(sum, sizeof (sum)); 1407 g_process = sum_missdata; 1408 g_arg = &sump; 1409 1410 for (ps = 0; ps < g_pgsizes; ps++) { 1411 tlbdata(&data->tmode_itlb, &odata->tmode_itlb); 1412 tlbdata(&data->tmode_dtlb, &odata->tmode_dtlb); 1413 1414 data = (tstat_modedata_t *)((uintptr_t)data + incr); 1415 odata = (tstat_modedata_t *)((uintptr_t)odata + incr); 1416 sump = sum; 1417 } 1418 1419 for (i = 0; i < 4; i++) { 1420 if (i == 2 && !parsable) 1421 (void) printf(" |"); 1422 1423 TSTAT_PRINT_MISSDATA(sum[i].tsum_diff, sum[i].tsum_time); 1424 ttl += sum[i].tsum_time; 1425 } 1426 1427 if (parsable) { 1428 (void) printf("\n"); 1429 return; 1430 } 1431 1432 (void) printf(" |%4.1f\n", ttl); 1433 } 1434 1435 static void 1436 print_tlb(tstat_data_t *data, tstat_data_t *odata) 1437 { 1438 int i, cpu, ncpus = 0; 1439 tstat_sum_t sum[4]; 1440 1441 (void) printf("cpu m| %9s %4s %9s %4s | %9s %4s %9s %4s |%4s\n" 1442 "-----+-------------------------------+-----------------------" 1443 "--------+----\n", "itlb-miss", "%tim", "itsb-miss", "%tim", 1444 "dtlb-miss", "%tim", "dtsb-miss", "%tim", "%tim"); 1445 1446 bzero(sum, sizeof (sum)); 1447 1448 for (i = 0; i < g_max_cpus; i++) { 1449 tstat_pgszdata_t *pgsz = data->tdata_pgsz; 1450 tstat_pgszdata_t *opgsz = odata->tdata_pgsz; 1451 1452 if ((cpu = data->tdata_cpuid) == -1) 1453 break; 1454 1455 if (i != 0) 1456 (void) printf("-----+-------------------------------+-" 1457 "------------------------------+----\n"); 1458 1459 g_ndata = data; 1460 g_odata = odata; 1461 1462 (void) printf("%3d u|", cpu); 1463 print_modedata(&pgsz->tpgsz_user, &opgsz->tpgsz_user, 0); 1464 sum_modedata(&pgsz->tpgsz_user, &opgsz->tpgsz_user, sum); 1465 1466 (void) printf("%3d k|", cpu); 1467 print_modedata(&pgsz->tpgsz_kernel, &opgsz->tpgsz_kernel, 0); 1468 sum_modedata(&pgsz->tpgsz_kernel, &opgsz->tpgsz_kernel, sum); 1469 1470 data = (tstat_data_t *)((uintptr_t)data + g_datasize); 1471 odata = (tstat_data_t *)((uintptr_t)odata + g_datasize); 1472 ncpus++; 1473 } 1474 1475 (void) printf("=====+===============================+=========" 1476 "======================+====\n"); 1477 1478 (void) printf(" ttl |"); 1479 print_sum(sum, ncpus); 1480 (void) printf("\n"); 1481 } 1482 1483 static void 1484 parsable_tlb(tstat_data_t *data, tstat_data_t *odata) 1485 { 1486 int i, cpu; 1487 1488 for (i = 0; i < g_max_cpus; i++) { 1489 tstat_pgszdata_t *pgsz = data->tdata_pgsz; 1490 tstat_pgszdata_t *opgsz = odata->tdata_pgsz; 1491 1492 if ((cpu = data->tdata_cpuid) == -1) 1493 break; 1494 1495 g_ndata = data; 1496 g_odata = odata; 1497 1498 (void) printf("%lld %3d u ", data->tdata_snapts - g_start, cpu); 1499 print_modedata(&pgsz->tpgsz_user, &opgsz->tpgsz_user, 1); 1500 (void) printf("%lld %3d k ", data->tdata_snapts - g_start, cpu); 1501 print_modedata(&pgsz->tpgsz_kernel, &opgsz->tpgsz_kernel, 1); 1502 1503 data = (tstat_data_t *)((uintptr_t)data + g_datasize); 1504 odata = (tstat_data_t *)((uintptr_t)odata + g_datasize); 1505 } 1506 } 1507 1508 static void 1509 print_stats(tstat_data_t *data, tstat_data_t *odata) 1510 { 1511 int i, j, k, done; 1512 processorid_t id; 1513 tstat_data_t *base = data; 1514 1515 /* 1516 * First, blast through all of the data updating our array 1517 * of active traps. We keep an array of active traps to prevent 1518 * printing lines for traps that are never seen -- while still printing 1519 * lines for traps that have been seen only once on some CPU. 1520 */ 1521 for (i = 0; i < g_max_cpus; i++) { 1522 if (data[i].tdata_cpuid == -1) 1523 break; 1524 1525 for (j = 0; j < TSTAT_NENT; j++) { 1526 if (!data[i].tdata_traps[j] || g_active[j]) 1527 continue; 1528 1529 g_active[j] = 1; 1530 } 1531 } 1532 1533 data = base; 1534 1535 for (done = 0; !done; data += g_cpus_per_line) { 1536 for (i = 0; i < g_cpus_per_line; i++) { 1537 if (&data[i] - base >= g_max_cpus) 1538 break; 1539 1540 if ((id = data[i].tdata_cpuid) == -1) 1541 break; 1542 1543 if (i == 0) 1544 (void) printf("vct name |"); 1545 1546 (void) printf(" %scpu%d", id >= 100 ? "" : 1547 id >= 10 ? " " : " ", id); 1548 } 1549 1550 if (i == 0) 1551 break; 1552 1553 if (i != g_cpus_per_line) 1554 done = 1; 1555 1556 (void) printf("\n------------------------+"); 1557 1558 for (j = 0; j < i; j++) 1559 (void) printf("---------"); 1560 (void) printf("\n"); 1561 1562 for (j = 0; j < TSTAT_NENT; j++) { 1563 if (!g_active[j]) 1564 continue; 1565 1566 (void) printf("%3x %-20s|", j, g_traps[j].tent_name); 1567 for (k = 0; k < i; k++) { 1568 (void) printf(" %8lld", TSTAT_DELTA(&data[k], 1569 &odata[data - base + k], tdata_traps[j])); 1570 } 1571 (void) printf("\n"); 1572 } 1573 (void) printf("\n"); 1574 } 1575 } 1576 1577 static void 1578 parsable_stats(tstat_data_t *data, tstat_data_t *odata) 1579 { 1580 tstat_data_t *base; 1581 int i; 1582 1583 for (base = data; data - base < g_max_cpus; data++, odata++) { 1584 if (data->tdata_cpuid == -1) 1585 break; 1586 1587 for (i = 0; i < TSTAT_NENT; i++) { 1588 if (!data->tdata_traps[i] && !g_active[i]) 1589 continue; 1590 1591 (void) printf("%lld %d %x %s ", 1592 data->tdata_snapts - g_start, data->tdata_cpuid, i, 1593 g_traps[i].tent_name); 1594 1595 (void) printf("%lld\n", TSTAT_DELTA(data, odata, 1596 tdata_traps[i])); 1597 } 1598 } 1599 } 1600 1601 static void 1602 check_data(tstat_data_t *data, tstat_data_t *odata) 1603 { 1604 tstat_data_t *ndata; 1605 int i; 1606 1607 if (data->tdata_cpuid == -1) { 1608 /* 1609 * The last CPU we were watching must have been DR'd out 1610 * of the system. Print a vaguely useful message and exit. 1611 */ 1612 fatal("all initially selected CPUs have been unconfigured\n"); 1613 } 1614 1615 /* 1616 * If a CPU is DR'd out of the system, we'll stop receiving data 1617 * for it. CPUs are never added, however (that is, if a CPU is 1618 * DR'd into the system, we won't automatically start receiving 1619 * data for it). We check for this by making sure that all of 1620 * the CPUs present in the old data are present in the new data. 1621 * If we find one missing in the new data, we correct the old data 1622 * by removing the old CPU. This assures that delta are printed 1623 * correctly. 1624 */ 1625 for (i = 0; i < g_max_cpus; i++) { 1626 if (odata->tdata_cpuid == -1) 1627 return; 1628 1629 if (data->tdata_cpuid != odata->tdata_cpuid) 1630 break; 1631 1632 data = (tstat_data_t *)((uintptr_t)data + g_datasize); 1633 odata = (tstat_data_t *)((uintptr_t)odata + g_datasize); 1634 } 1635 1636 if (i == g_max_cpus) 1637 return; 1638 1639 /* 1640 * If we're here, we know that the odata is a CPU which has been 1641 * DR'd out. We'll now smoosh it out of the old data. 1642 */ 1643 for (odata->tdata_cpuid = -1; i < g_max_cpus - 1; i++) { 1644 ndata = (tstat_data_t *)((uintptr_t)odata + g_datasize); 1645 bcopy(ndata, odata, g_datasize); 1646 ndata->tdata_cpuid = -1; 1647 } 1648 1649 /* 1650 * There may be other CPUs DR'd out; tail-call recurse. 1651 */ 1652 check_data(data, odata); 1653 } 1654 1655 int 1656 main(int argc, char **argv) 1657 { 1658 processorid_t id; 1659 char c, *end; 1660 ulong_t indefinite; 1661 long count = 0, rate = 0; 1662 int list = 0, parsable = 0; 1663 void (*print)(tstat_data_t *, tstat_data_t *); 1664 sigset_t set; 1665 1666 struct { 1667 char opt; 1668 void (*print)(tstat_data_t *, tstat_data_t *); 1669 void (*parsable)(tstat_data_t *, tstat_data_t *); 1670 int repeat; 1671 } tab[] = { 1672 { '\0', print_stats, parsable_stats, 0 }, 1673 { 'e', print_stats, parsable_stats, 1 }, 1674 { 't', print_tlb, parsable_tlb, 0 }, 1675 { 'T', print_tlbpgsz, parsable_tlbpgsz, 0 }, 1676 { -1, NULL, NULL, 0 } 1677 }, *tabent = NULL, *iter; 1678 1679 uintptr_t offs = (uintptr_t)&tab->print - (uintptr_t)tab; 1680 1681 /* 1682 * If argv[0] is non-NULL, set argv[0] to keep any getopt(3C) output 1683 * consistent with other error output. 1684 */ 1685 if (argv[0] != NULL) 1686 argv[0] = TSTAT_COMMAND; 1687 1688 if ((g_fd = open(TSTAT_DEVICE, O_RDWR)) == -1) 1689 fatal("couldn't open " TSTAT_DEVICE); 1690 1691 setup(); 1692 1693 while ((c = getopt(argc, argv, "alnNtTc:C:r:e:P")) != EOF) { 1694 /* 1695 * First, check to see if this option changes our printing 1696 * function. 1697 */ 1698 for (iter = tab; iter->opt >= 0; iter++) { 1699 if (c != iter->opt) 1700 continue; 1701 1702 if (tabent != NULL) { 1703 if (tabent == iter) { 1704 if (tabent->repeat) { 1705 /* 1706 * This option is allowed to 1707 * have repeats; break out. 1708 */ 1709 break; 1710 } 1711 1712 fatal("expected -%c at most once\n", c); 1713 } 1714 1715 fatal("only one of -%c, -%c expected\n", 1716 tabent->opt, c); 1717 } 1718 1719 tabent = iter; 1720 break; 1721 } 1722 1723 switch (c) { 1724 case 'a': 1725 g_absolute = 1; 1726 break; 1727 1728 case 'e': { 1729 char *s = strtok(optarg, ","); 1730 1731 while (s != NULL) { 1732 select_entry(s); 1733 s = strtok(NULL, ","); 1734 } 1735 1736 break; 1737 } 1738 1739 case 'l': 1740 list = 1; 1741 break; 1742 1743 case 'n': 1744 /* 1745 * This undocumented option prevents trapstat from 1746 * actually switching the %tba to point to the 1747 * interposing trap table. It's very useful when 1748 * debugging trapstat bugs: one can specify "-n" 1749 * and then examine the would-be interposing trap 1750 * table without running the risk of RED stating. 1751 */ 1752 if (ioctl(g_fd, TSTATIOC_NOGO) == -1) 1753 fatal("TSTATIOC_NOGO"); 1754 break; 1755 1756 case 'N': 1757 /* 1758 * This undocumented option forces trapstat to ignore 1759 * its determined probe effect. This may be useful 1760 * if it is believed that the probe effect has been 1761 * grossly overestimated. 1762 */ 1763 g_peffect = 0; 1764 break; 1765 1766 case 't': 1767 case 'T': 1768 /* 1769 * When running with TLB statistics, we want to 1770 * minimize probe effect by running with all other 1771 * entries explicitly disabled. 1772 */ 1773 if (ioctl(g_fd, TSTATIOC_NOENTRY) == -1) 1774 fatal("TSTATIOC_NOENTRY"); 1775 1776 if (ioctl(g_fd, TSTATIOC_TLBDATA) == -1) 1777 fatal("TSTATIOC_TLBDATA"); 1778 break; 1779 1780 case 'c': { 1781 /* 1782 * We allow CPUs to be specified as an optionally 1783 * comma separated list of either CPU IDs or ranges 1784 * of CPU IDs. 1785 */ 1786 char *s = strtok(optarg, ","); 1787 1788 while (s != NULL) { 1789 id = strtoul(s, &end, 0); 1790 1791 if (id == ULONG_MAX && errno == ERANGE) { 1792 *end = '\0'; 1793 fatal("invalid cpu '%s'\n", s); 1794 } 1795 1796 if (*(s = end) != '\0') { 1797 processorid_t p; 1798 1799 if (*s != '-') 1800 fatal("invalid cpu '%s'\n", s); 1801 p = strtoul(++s, &end, 0); 1802 1803 if (*end != '\0' || 1804 (p == ULONG_MAX && errno == ERANGE)) 1805 fatal("invalid cpu '%s'\n", s); 1806 1807 select_cpus(id, p); 1808 } else { 1809 select_cpu(id); 1810 } 1811 1812 s = strtok(NULL, ","); 1813 } 1814 1815 break; 1816 } 1817 1818 case 'C': { 1819 psetid_t pset = strtoul(optarg, &end, 0); 1820 1821 if (*end != '\0' || 1822 (pset == ULONG_MAX && errno == ERANGE)) 1823 fatal("invalid processor set '%s'\n", optarg); 1824 1825 select_pset(pset); 1826 break; 1827 } 1828 1829 case 'r': { 1830 rate = strtol(optarg, &end, 0); 1831 1832 if (*end != '\0' || 1833 (rate == LONG_MAX && errno == ERANGE)) 1834 fatal("invalid rate '%s'\n", optarg); 1835 1836 if (rate <= 0) 1837 fatal("rate must be greater than zero\n"); 1838 1839 if (rate > TSTAT_MAX_RATE) 1840 fatal("rate may not exceed %d\n", 1841 TSTAT_MAX_RATE); 1842 1843 set_interval(NANOSEC / rate); 1844 break; 1845 } 1846 1847 case 'P': 1848 offs = (uintptr_t)&tab->parsable - (uintptr_t)tab; 1849 parsable = 1; 1850 break; 1851 1852 default: 1853 usage(); 1854 } 1855 } 1856 1857 if (list) { 1858 print_entries(stdout, parsable); 1859 exit(EXIT_SUCCESS); 1860 } 1861 1862 if (optind != argc) { 1863 1864 int interval = strtol(argv[optind], &end, 0); 1865 1866 if (*end != '\0') { 1867 /* 1868 * That wasn't a valid number. It must be that we're 1869 * to execute this command. 1870 */ 1871 switch (vfork()) { 1872 case 0: 1873 (void) close(g_fd); 1874 (void) sigprocmask(SIG_SETMASK, &g_oset, NULL); 1875 (void) execvp(argv[optind], &argv[optind]); 1876 1877 /* 1878 * No luck. Set errno. 1879 */ 1880 g_exec_errno = errno; 1881 _exit(EXIT_FAILURE); 1882 /*NOTREACHED*/ 1883 case -1: 1884 fatal("cannot fork"); 1885 /*NOTREACHED*/ 1886 default: 1887 break; 1888 } 1889 } else { 1890 if (interval <= 0) 1891 fatal("interval must be greater than zero.\n"); 1892 1893 if (interval == LONG_MAX && errno == ERANGE) 1894 fatal("invalid interval '%s'\n", argv[optind]); 1895 1896 set_interval(NANOSEC * (hrtime_t)interval); 1897 1898 if (++optind != argc) { 1899 char *s = argv[optind]; 1900 1901 count = strtol(s, &end, 0); 1902 1903 if (*end != '\0' || count <= 0 || 1904 (count == LONG_MAX && errno == ERANGE)) 1905 fatal("invalid count '%s'\n", s); 1906 } 1907 } 1908 } else { 1909 if (!rate) 1910 set_interval(NANOSEC); 1911 } 1912 1913 if (tabent == NULL) 1914 tabent = tab; 1915 1916 print = *(void(**)(tstat_data_t *, tstat_data_t *)) 1917 ((uintptr_t)tabent + offs); 1918 1919 for (id = 0; id < g_max_cpus; id++) { 1920 if (!g_selected[id]) 1921 continue; 1922 1923 if (ioctl(g_fd, TSTATIOC_CPU, id) == -1) 1924 fatal("TSTATIOC_CPU failed for cpu %d", id); 1925 } 1926 1927 g_start = gethrtime(); 1928 1929 if (ioctl(g_fd, TSTATIOC_GO) == -1) 1930 fatal("TSTATIOC_GO failed"); 1931 1932 if (ioctl(g_fd, TSTATIOC_READ, g_data[g_gen ^ 1]) == -1) 1933 fatal("initial TSTATIOC_READ failed"); 1934 1935 (void) sigemptyset(&set); 1936 1937 for (indefinite = (count == 0); indefinite || count; count--) { 1938 1939 (void) sigsuspend(&set); 1940 1941 if (g_winch) { 1942 g_winch = 0; 1943 continue; 1944 } 1945 1946 if (g_child_exited && g_exec_errno != 0) { 1947 errno = g_exec_errno; 1948 fatal("could not execute %s", argv[optind]); 1949 } 1950 1951 if (ioctl(g_fd, TSTATIOC_READ, g_data[g_gen]) == -1) 1952 fatal("TSTATIOC_READ failed"); 1953 1954 /* 1955 * Before we blithely print the data, we need to 1956 * make sure that we haven't lost a CPU. 1957 */ 1958 check_data(g_data[g_gen], g_data[g_gen ^ 1]); 1959 (*print)(g_data[g_gen], g_data[g_gen ^ 1]); 1960 (void) fflush(stdout); 1961 1962 if (g_child_exited) { 1963 if (WIFEXITED(g_child_status)) { 1964 if (WEXITSTATUS(g_child_status) == 0) 1965 break; 1966 1967 (void) fprintf(stderr, TSTAT_COMMAND ": " 1968 "warning: %s exited with code %d\n", 1969 argv[optind], WEXITSTATUS(g_child_status)); 1970 } else { 1971 (void) fprintf(stderr, TSTAT_COMMAND ": " 1972 "warning: %s died on signal %d\n", 1973 argv[optind], WTERMSIG(g_child_status)); 1974 } 1975 break; 1976 } 1977 1978 check_pset(); 1979 1980 g_gen ^= 1; 1981 } 1982 1983 return (0); 1984 } 1985