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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 #include <sys/time.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <inttypes.h> 31 #include <unistd.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <limits.h> 35 #include <libintl.h> 36 #include <locale.h> 37 #include <errno.h> 38 #include <kstat.h> 39 #include <libcpc.h> 40 41 #include "cpucmds.h" 42 43 static struct options { 44 int debug; 45 int verbose; 46 int dotitle; 47 int dohelp; 48 int dotick; 49 int cpuver; 50 char *pgmname; 51 uint_t mseconds; 52 uint_t nsamples; 53 uint_t nsets; 54 cpc_setgrp_t *master; 55 int followfork; 56 int followexec; 57 pid_t pid; 58 FILE *log; 59 } __options; 60 61 static const struct options *opts = (const struct options *)&__options; 62 63 static cpc_t *cpc; 64 65 /* 66 * How many signals caught from terminal 67 * We bail out as soon as possible when interrupt is set 68 */ 69 static int interrupt = 0; 70 71 /*ARGSUSED*/ 72 static void 73 cputrack_errfn(const char *fn, int subcode, const char *fmt, va_list ap) 74 { 75 (void) fprintf(stderr, "%s: ", opts->pgmname); 76 if (opts->debug) 77 (void) fprintf(stderr, "%s: ", fn); 78 (void) vfprintf(stderr, fmt, ap); 79 } 80 81 static void 82 cputrack_pctx_errfn(const char *fn, const char *fmt, va_list ap) 83 { 84 cputrack_errfn(fn, -1, fmt, ap); 85 } 86 87 static int cputrack(int argc, char *argv[], int optind); 88 static void intr(int); 89 90 #if !defined(TEXT_DOMAIN) 91 #define TEXT_DOMAIN "SYS_TEST" 92 #endif 93 94 int 95 main(int argc, char *argv[]) 96 { 97 struct options *opts = &__options; 98 int c, errcnt = 0; 99 int nsamples; 100 cpc_setgrp_t *sgrp; 101 char *errstr; 102 int ret; 103 104 (void) setlocale(LC_ALL, ""); 105 (void) textdomain(TEXT_DOMAIN); 106 107 if ((opts->pgmname = strrchr(argv[0], '/')) == NULL) 108 opts->pgmname = argv[0]; 109 else 110 opts->pgmname++; 111 112 if ((cpc = cpc_open(CPC_VER_CURRENT)) == NULL) { 113 errstr = strerror(errno); 114 (void) fprintf(stderr, gettext("%s: cannot access performance " 115 "counter library - %s\n"), opts->pgmname, errstr); 116 return (1); 117 } 118 119 (void) cpc_seterrhndlr(cpc, cputrack_errfn); 120 strtoset_errfn = cputrack_errfn; 121 122 /* 123 * Establish (non-zero) defaults 124 */ 125 opts->mseconds = 1000; 126 opts->dotitle = 1; 127 opts->log = stdout; 128 if ((opts->master = cpc_setgrp_new(cpc, 0)) == NULL) { 129 (void) fprintf(stderr, gettext("%s: no memory available\n"), 130 opts->pgmname); 131 exit(1); 132 } 133 134 while ((c = getopt(argc, argv, "T:N:Defhntvo:r:c:p:")) != EOF) 135 switch (c) { 136 case 'T': /* sample time, seconds */ 137 opts->mseconds = (uint_t)(atof(optarg) * 1000.0); 138 break; 139 case 'N': /* number of samples */ 140 nsamples = atoi(optarg); 141 if (nsamples < 0) 142 errcnt++; 143 else 144 opts->nsamples = (uint_t)nsamples; 145 break; 146 case 'D': /* enable debugging */ 147 opts->debug++; 148 break; 149 case 'f': /* follow fork */ 150 opts->followfork++; 151 break; 152 case 'e': /* follow exec */ 153 opts->followexec++; 154 break; 155 case 'n': /* no titles */ 156 opts->dotitle = 0; 157 break; 158 case 't': /* print %tick */ 159 opts->dotick = 1; 160 break; 161 case 'v': 162 opts->verbose = 1; /* more chatty */ 163 break; 164 case 'o': 165 if (optarg == NULL) { 166 errcnt++; 167 break; 168 } 169 if ((opts->log = fopen(optarg, "w")) == NULL) { 170 (void) fprintf(stderr, gettext( 171 "%s: cannot open '%s' for writing\n"), 172 opts->pgmname, optarg); 173 return (1); 174 } 175 break; 176 case 'c': /* specify statistics */ 177 if ((sgrp = cpc_setgrp_newset(opts->master, 178 optarg, &errcnt)) != NULL) 179 opts->master = sgrp; 180 break; 181 case 'p': /* grab given pid */ 182 if ((opts->pid = atoi(optarg)) <= 0) 183 errcnt++; 184 break; 185 case 'h': 186 opts->dohelp = 1; 187 break; 188 case '?': 189 default: 190 errcnt++; 191 break; 192 } 193 194 if (opts->nsamples == 0) 195 opts->nsamples = UINT_MAX; 196 197 if (errcnt != 0 || 198 opts->dohelp || 199 (argc == optind && opts->pid == 0) || 200 (argc > optind && opts->pid != 0) || 201 (opts->nsets = cpc_setgrp_numsets(opts->master)) == 0) { 202 (void) fprintf(opts->dohelp ? stdout : stderr, gettext( 203 "Usage:\n\t%s [-T secs] [-N count] [-Defhnv] [-o file]\n" 204 "\t\t-c events [command [args] | -p pid]\n\n" 205 "\t-T secs\t seconds between samples, default 1\n" 206 "\t-N count number of samples, default unlimited\n" 207 "\t-D\t enable debug mode\n" 208 "\t-e\t follow exec(2), and execve(2)\n" 209 "\t-f\t follow fork(2), fork1(2), and vfork(2)\n" 210 "\t-h\t print extended usage information\n" 211 "\t-n\t suppress titles\n" 212 "\t-t\t include virtualized %s register\n" 213 "\t-v\t verbose mode\n" 214 "\t-o file\t write cpu statistics to this file\n" 215 "\t-c events specify processor events to be monitored\n" 216 "\t-p pid\t pid of existing process to capture\n\n" 217 "\tUse cpustat(8) to monitor system-wide statistics.\n"), 218 opts->pgmname, CPC_TICKREG_NAME); 219 if (opts->dohelp) { 220 (void) putchar('\n'); 221 (void) capabilities(cpc, stdout); 222 exit(0); 223 } 224 exit(2); 225 } 226 227 /* 228 * Catch signals from terminal, so they can be handled asynchronously 229 * when we're ready instead of when we're not (;-) 230 */ 231 if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) 232 (void) sigset(SIGHUP, intr); 233 if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 234 (void) sigset(SIGINT, intr); 235 if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) 236 (void) sigset(SIGQUIT, intr); 237 (void) sigset(SIGPIPE, intr); 238 (void) sigset(SIGTERM, intr); 239 240 cpc_setgrp_reset(opts->master); 241 (void) setvbuf(opts->log, NULL, _IOLBF, 0); 242 ret = cputrack(argc, argv, optind); 243 (void) cpc_close(cpc); 244 return (ret); 245 } 246 247 static void 248 print_title(cpc_setgrp_t *sgrp) 249 { 250 (void) fprintf(opts->log, "%7s ", "time"); 251 if (opts->followfork) 252 (void) fprintf(opts->log, "%6s ", "pid"); 253 (void) fprintf(opts->log, "%3s %10s ", "lwp", "event"); 254 if (opts->dotick) 255 (void) fprintf(opts->log, "%9s ", CPC_TICKREG_NAME); 256 (void) fprintf(opts->log, "%s\n", cpc_setgrp_gethdr(sgrp)); 257 (void) fflush(opts->log); 258 } 259 260 static void 261 print_exec(float now, pid_t pid, char *name) 262 { 263 if (name == NULL) 264 name = "(unknown)"; 265 266 (void) fprintf(opts->log, "%7.3f ", now); 267 if (opts->followfork) 268 (void) fprintf(opts->log, "%6d ", (int)pid); 269 (void) fprintf(opts->log, "%3d %10s ", 1, "exec"); 270 if (opts->dotick) 271 (void) fprintf(opts->log, "%9s ", ""); 272 (void) fprintf(opts->log, "%9s %9s # '%s'\n", "", "", name); 273 (void) fflush(opts->log); 274 } 275 276 static void 277 print_fork(float now, pid_t newpid, id_t lwpid, pid_t oldpid) 278 { 279 (void) fprintf(opts->log, "%7.3f ", now); 280 if (opts->followfork) 281 (void) fprintf(opts->log, "%6d ", (int)oldpid); 282 (void) fprintf(opts->log, "%3d %10s ", (int)lwpid, "fork"); 283 if (opts->dotick) 284 (void) fprintf(opts->log, "%9s ", ""); 285 (void) fprintf(opts->log, "%9s %9s # %d\n", "", "", (int)newpid); 286 (void) fflush(opts->log); 287 } 288 289 static void 290 print_sample(pid_t pid, id_t lwpid, 291 char *pevent, cpc_buf_t *buf, int nreq, const char *evname) 292 { 293 uint64_t val; 294 int i; 295 296 (void) fprintf(opts->log, "%7.3f ", 297 mstimestamp(cpc_buf_hrtime(cpc, buf))); 298 if (opts->followfork) 299 (void) fprintf(opts->log, "%6d ", (int)pid); 300 (void) fprintf(opts->log, "%3d %10s ", (int)lwpid, pevent); 301 if (opts->dotick) 302 (void) fprintf(opts->log, "%9" PRId64 " ", 303 cpc_buf_tick(cpc, buf)); 304 for (i = 0; i < nreq; i++) { 305 (void) cpc_buf_get(cpc, buf, i, &val); 306 (void) fprintf(opts->log, "%9" PRId64 " ", val); 307 } 308 if (opts->nsets > 1) 309 (void) fprintf(opts->log, " # %s\n", evname); 310 else 311 (void) fputc('\n', opts->log); 312 } 313 314 struct pstate { 315 cpc_setgrp_t *accum; 316 cpc_setgrp_t **sgrps; 317 int maxlwpid; 318 }; 319 320 static int 321 pinit_lwp(pctx_t *pctx, pid_t pid, id_t lwpid, void *arg) 322 { 323 struct pstate *state = arg; 324 cpc_setgrp_t *sgrp; 325 cpc_set_t *set; 326 cpc_buf_t **data1, **data2, **scratch; 327 char *errstr; 328 int nreq; 329 330 if (interrupt) 331 return (0); 332 333 if (state->maxlwpid < lwpid) { 334 state->sgrps = realloc(state->sgrps, 335 lwpid * sizeof (state->sgrps)); 336 if (state->sgrps == NULL) { 337 (void) fprintf(stderr, gettext( 338 "%6d: init_lwp: out of memory\n"), (int)pid); 339 return (-1); 340 } 341 while (state->maxlwpid < lwpid) { 342 state->sgrps[state->maxlwpid] = NULL; 343 state->maxlwpid++; 344 } 345 } 346 347 if ((sgrp = state->sgrps[lwpid-1]) == NULL) { 348 if ((sgrp = cpc_setgrp_clone(opts->master)) == NULL) { 349 (void) fprintf(stderr, gettext( 350 "%6d: init_lwp: out of memory\n"), (int)pid); 351 return (-1); 352 } 353 state->sgrps[lwpid-1] = sgrp; 354 set = cpc_setgrp_getset(sgrp); 355 } else { 356 cpc_setgrp_reset(sgrp); 357 set = cpc_setgrp_getset(sgrp); 358 } 359 360 nreq = cpc_setgrp_getbufs(sgrp, &data1, &data2, &scratch); 361 362 if (cpc_bind_pctx(cpc, pctx, lwpid, set, 0) != 0 || 363 cpc_set_sample(cpc, set, *data2) != 0) { 364 errstr = strerror(errno); 365 if (errno == EAGAIN) { 366 (void) cpc_unbind(cpc, set); 367 } 368 369 (void) fprintf(stderr, gettext( 370 "%6d: init_lwp: can't bind perf counters " 371 "to lwp%d - %s\n"), (int)pid, (int)lwpid, errstr); 372 return (-1); 373 } 374 375 if (opts->verbose) 376 print_sample(pid, lwpid, "init_lwp", 377 *data2, nreq, cpc_setgrp_getname(sgrp)); 378 return (0); 379 } 380 381 /*ARGSUSED*/ 382 static int 383 pfini_lwp(pctx_t *pctx, pid_t pid, id_t lwpid, void *arg) 384 { 385 struct pstate *state = arg; 386 cpc_setgrp_t *sgrp = state->sgrps[lwpid-1]; 387 cpc_set_t *set; 388 char *errstr; 389 cpc_buf_t **data1, **data2, **scratch; 390 int nreq; 391 392 if (interrupt) 393 return (0); 394 395 set = cpc_setgrp_getset(sgrp); 396 nreq = cpc_setgrp_getbufs(sgrp, &data1, &data2, &scratch); 397 if (cpc_set_sample(cpc, set, *scratch) == 0) { 398 if (opts->nsets == 1) { 399 /* 400 * When we only have one set of counts, the sample 401 * gives us the accumulated count. 402 */ 403 *data1 = *scratch; 404 } else { 405 /* 406 * When we have more than one set of counts, the 407 * sample gives us the count for the latest sample 408 * period. *data1 contains the accumulated count but 409 * does not include the count for the latest sample 410 * period for this set of counters. 411 */ 412 cpc_buf_add(cpc, *data1, *data1, *scratch); 413 } 414 if (opts->verbose) 415 print_sample(pid, lwpid, "fini_lwp", 416 *data1, nreq, cpc_setgrp_getname(sgrp)); 417 cpc_setgrp_accum(state->accum, sgrp); 418 if (cpc_unbind(cpc, set) == 0) 419 return (0); 420 } 421 422 switch (errno) { 423 case EAGAIN: 424 (void) fprintf(stderr, gettext("%6d: fini_lwp: " 425 "lwp%d: perf counter contents invalidated\n"), 426 (int)pid, (int)lwpid); 427 break; 428 default: 429 errstr = strerror(errno); 430 (void) fprintf(stderr, gettext("%6d: fini_lwp: " 431 "lwp%d: can't access perf counters - %s\n"), 432 (int)pid, (int)lwpid, errstr); 433 break; 434 } 435 return (-1); 436 } 437 438 /*ARGSUSED*/ 439 static int 440 plwp_create(pctx_t *pctx, pid_t pid, id_t lwpid, void *arg) 441 { 442 cpc_setgrp_t *sgrp = opts->master; 443 cpc_buf_t **data1, **data2, **scratch; 444 int nreq; 445 446 if (interrupt) 447 return (0); 448 449 nreq = cpc_setgrp_getbufs(sgrp, &data1, &data2, &scratch); 450 451 print_sample(pid, lwpid, "lwp_create", 452 *data1, nreq, cpc_setgrp_getname(sgrp)); 453 454 return (0); 455 } 456 457 /*ARGSUSED*/ 458 static int 459 plwp_exit(pctx_t *pctx, pid_t pid, id_t lwpid, void *arg) 460 { 461 struct pstate *state = arg; 462 cpc_setgrp_t *sgrp = state->sgrps[lwpid-1]; 463 cpc_set_t *start; 464 int nreq; 465 cpc_buf_t **data1, **data2, **scratch; 466 467 if (interrupt) 468 return (0); 469 470 start = cpc_setgrp_getset(sgrp); 471 do { 472 nreq = cpc_setgrp_getbufs(sgrp, &data1, &data2, &scratch); 473 if (cpc_buf_hrtime(cpc, *data1) == 0) 474 continue; 475 print_sample(pid, lwpid, "lwp_exit", 476 *data1, nreq, cpc_setgrp_getname(sgrp)); 477 } while (cpc_setgrp_nextset(sgrp) != start); 478 479 return (0); 480 } 481 482 /*ARGSUSED*/ 483 static int 484 pexec(pctx_t *pctx, pid_t pid, id_t lwpid, char *name, void *arg) 485 { 486 struct pstate *state = arg; 487 float now = 0.0; 488 cpc_set_t *start; 489 int nreq; 490 cpc_buf_t **data1, **data2, **scratch; 491 hrtime_t hrt; 492 493 if (interrupt) 494 return (0); 495 496 /* 497 * Print the accumulated results from the previous program image 498 */ 499 cpc_setgrp_reset(state->accum); 500 start = cpc_setgrp_getset(state->accum); 501 do { 502 nreq = cpc_setgrp_getbufs(state->accum, &data1, &data2, 503 &scratch); 504 hrt = cpc_buf_hrtime(cpc, *data1); 505 if (hrt == 0) 506 continue; 507 print_sample(pid, lwpid, "exec", 508 *data1, nreq, cpc_setgrp_getname(state->accum)); 509 if (now < mstimestamp(hrt)) 510 now = mstimestamp(hrt); 511 } while (cpc_setgrp_nextset(state->accum) != start); 512 513 print_exec(now, pid, name); 514 515 if (state->accum != NULL) { 516 cpc_setgrp_free(state->accum); 517 state->accum = NULL; 518 } 519 520 if (opts->followexec) { 521 state->accum = cpc_setgrp_clone(opts->master); 522 return (0); 523 } 524 return (-1); 525 } 526 527 /*ARGSUSED*/ 528 static void 529 pexit(pctx_t *pctx, pid_t pid, id_t lwpid, int status, void *arg) 530 { 531 struct pstate *state = arg; 532 cpc_set_t *start; 533 int nreq; 534 cpc_buf_t **data1, **data2, **scratch; 535 536 if (interrupt) 537 return; 538 539 cpc_setgrp_reset(state->accum); 540 start = cpc_setgrp_getset(state->accum); 541 do { 542 nreq = cpc_setgrp_getbufs(state->accum, &data1, &data2, 543 &scratch); 544 if (cpc_buf_hrtime(cpc, *data1) == 0) 545 continue; 546 print_sample(pid, lwpid, "exit", 547 *data1, nreq, cpc_setgrp_getname(state->accum)); 548 } while (cpc_setgrp_nextset(state->accum) != start); 549 550 cpc_setgrp_free(state->accum); 551 state->accum = NULL; 552 553 for (lwpid = 1; lwpid < state->maxlwpid; lwpid++) 554 if (state->sgrps[lwpid-1] != NULL) { 555 cpc_setgrp_free(state->sgrps[lwpid-1]); 556 state->sgrps[lwpid-1] = NULL; 557 } 558 free(state->sgrps); 559 state->sgrps = NULL; 560 } 561 562 static int 563 ptick(pctx_t *pctx, pid_t pid, id_t lwpid, void *arg) 564 { 565 struct pstate *state = arg; 566 cpc_setgrp_t *sgrp = state->sgrps[lwpid-1]; 567 cpc_set_t *this = cpc_setgrp_getset(sgrp); 568 const char *name = cpc_setgrp_getname(sgrp); 569 cpc_buf_t **data1, **data2, **scratch, *tmp; 570 char *errstr; 571 int nreqs; 572 573 if (interrupt) 574 return (0); 575 576 nreqs = cpc_setgrp_getbufs(sgrp, &data1, &data2, &scratch); 577 578 if (opts->nsets == 1) { 579 /* 580 * If we're dealing with one set, buffer usage is: 581 * 582 * data1 = most recent data snapshot 583 * data2 = previous data snapshot 584 * scratch = used for diffing data1 and data2 585 * 586 * Save the snapshot from the previous sample in data2 587 * before putting the current sample in data1. 588 */ 589 tmp = *data1; 590 *data1 = *data2; 591 *data2 = tmp; 592 if (cpc_set_sample(cpc, this, *data1) != 0) 593 goto broken; 594 cpc_buf_sub(cpc, *scratch, *data1, *data2); 595 } else { 596 cpc_set_t *next = cpc_setgrp_nextset(sgrp); 597 /* 598 * If there is more than set in use, we will need to 599 * unbind and re-bind on each go-around because each 600 * time a counter is bound, it is preset to 0 (as it was 601 * specified when the requests were added to the set). 602 * 603 * Buffer usage in this case is: 604 * 605 * data1 = total counts for this set since program began 606 * data2 = unused 607 * scratch = most recent data snapshot 608 */ 609 610 if (cpc_set_sample(cpc, this, *scratch) != 0) 611 goto broken; 612 cpc_buf_add(cpc, *data1, *data1, *scratch); 613 614 /* 615 * No need to unbind the previous set, as binding another set 616 * automatically unbinds the most recently bound set. 617 */ 618 if (cpc_bind_pctx(cpc, pctx, lwpid, next, 0) != 0) 619 goto broken; 620 } 621 print_sample(pid, lwpid, "tick", *scratch, nreqs, name); 622 623 return (0); 624 625 broken: 626 switch (errno) { 627 case EAGAIN: 628 (void) fprintf(stderr, gettext( 629 "%6d: tick: lwp%d: perf counter contents invalidated\n"), 630 (int)pid, (int)lwpid); 631 break; 632 default: 633 errstr = strerror(errno); 634 (void) fprintf(stderr, gettext( 635 "%6d: tick: lwp%d: can't access perf counter - %s\n"), 636 (int)pid, (int)lwpid, errstr); 637 break; 638 } 639 (void) cpc_unbind(cpc, this); 640 return (-1); 641 } 642 643 /* 644 * The system has just created a new address space that has a new pid. 645 * We're running in a child of the controlling process, with a new 646 * pctx handle already opened on the child of the original controlled process. 647 */ 648 static void 649 pfork(pctx_t *pctx, pid_t oldpid, pid_t pid, id_t lwpid, void *arg) 650 { 651 struct pstate *state = arg; 652 653 print_fork(mstimestamp(0), pid, lwpid, oldpid); 654 655 if (!opts->followfork) 656 return; 657 658 if (pctx_set_events(pctx, 659 PCTX_SYSC_EXEC_EVENT, pexec, 660 PCTX_SYSC_FORK_EVENT, pfork, 661 PCTX_SYSC_EXIT_EVENT, pexit, 662 PCTX_SYSC_LWP_CREATE_EVENT, plwp_create, 663 PCTX_INIT_LWP_EVENT, pinit_lwp, 664 PCTX_FINI_LWP_EVENT, pfini_lwp, 665 PCTX_SYSC_LWP_EXIT_EVENT, plwp_exit, 666 PCTX_NULL_EVENT) == 0) { 667 state->accum = cpc_setgrp_clone(opts->master); 668 (void) pctx_run(pctx, opts->mseconds, opts->nsamples, ptick); 669 if (state->accum) { 670 free(state->accum); 671 state->accum = NULL; 672 } 673 } 674 } 675 676 /* 677 * Translate the incoming options into actions, and get the 678 * tool and the process to control running. 679 */ 680 static int 681 cputrack(int argc, char *argv[], int optind) 682 { 683 struct pstate __state, *state = &__state; 684 pctx_t *pctx; 685 int err; 686 687 bzero(state, sizeof (*state)); 688 689 if (opts->pid == 0) { 690 if (argc <= optind) { 691 (void) fprintf(stderr, "%s: %s\n", 692 opts->pgmname, 693 gettext("no program to start")); 694 return (1); 695 } 696 pctx = pctx_create(argv[optind], 697 &argv[optind], state, 1, cputrack_pctx_errfn); 698 if (pctx == NULL) { 699 (void) fprintf(stderr, "%s: %s '%s'\n", 700 opts->pgmname, 701 gettext("failed to start program"), 702 argv[optind]); 703 return (1); 704 } 705 } else { 706 pctx = pctx_capture(opts->pid, state, 1, cputrack_pctx_errfn); 707 if (pctx == NULL) { 708 (void) fprintf(stderr, "%s: %s %d\n", 709 opts->pgmname, 710 gettext("failed to capture pid"), 711 (int)opts->pid); 712 return (1); 713 } 714 } 715 716 err = pctx_set_events(pctx, 717 PCTX_SYSC_EXEC_EVENT, pexec, 718 PCTX_SYSC_FORK_EVENT, pfork, 719 PCTX_SYSC_EXIT_EVENT, pexit, 720 PCTX_SYSC_LWP_CREATE_EVENT, plwp_create, 721 PCTX_INIT_LWP_EVENT, pinit_lwp, 722 PCTX_FINI_LWP_EVENT, pfini_lwp, 723 PCTX_SYSC_LWP_EXIT_EVENT, plwp_exit, 724 PCTX_NULL_EVENT); 725 726 if (err != 0) { 727 (void) fprintf(stderr, "%s: %s\n", 728 opts->pgmname, 729 gettext("can't bind process context ops to process")); 730 } else { 731 if (opts->dotitle) 732 print_title(opts->master); 733 state->accum = cpc_setgrp_clone(opts->master); 734 zerotime(); 735 err = pctx_run(pctx, opts->mseconds, opts->nsamples, ptick); 736 if (state->accum) { 737 cpc_setgrp_free(state->accum); 738 state->accum = NULL; 739 } 740 } 741 742 return (err != 0 ? 1 : 0); 743 } 744 745 /*ARGSUSED*/ 746 static void 747 intr(int sig) 748 { 749 interrupt++; 750 if (cpc != NULL) 751 cpc_terminate(cpc); 752 } 753