1/* 2 * Copyright (c) 1999-2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights 7 * Reserved. This file contains Original Code and/or Modifications of 8 * Original Code as defined in and that are subject to the Apple Public 9 * Source License Version 1.0 (the 'License'). You may not use this file 10 * except in compliance with the License. Please obtain a copy of the 11 * License at http://www.apple.com/publicsource and read it before using 12 * this file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 19 * License for the specific language governing rights and limitations 20 * under the License." 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25/* 26cc -I. -DPRIVATE -D__APPLE_PRIVATE -O -o sc_usage sc_usage.c -lncurses 27*/ 28 29#define Default_DELAY 1 /* default delay interval */ 30 31#include <stdlib.h> 32#include <stdio.h> 33#include <signal.h> 34#include <strings.h> 35#include <nlist.h> 36#include <fcntl.h> 37#include <string.h> 38 39#include <sys/types.h> 40#include <sys/param.h> 41#include <sys/time.h> 42#include <sys/ptrace.h> 43 44#include <libc.h> 45#include <termios.h> 46#include <curses.h> 47 48#include <sys/ioctl.h> 49 50#ifndef KERNEL_PRIVATE 51#define KERNEL_PRIVATE 52#include <sys/kdebug.h> 53#undef KERNEL_PRIVATE 54#else 55#include <sys/kdebug.h> 56#endif /*KERNEL_PRIVATE*/ 57 58#include <sys/sysctl.h> 59#include <errno.h> 60#include <mach/mach_time.h> 61#include <err.h> 62#include <libutil.h> 63 64/* Number of lines of header information on the standard screen */ 65#define HEADER_LINES 5 66 67int newLINES = 0; 68int Header_lines = HEADER_LINES; 69 70int how_to_sort = 0; 71int no_screen_refresh = 0; 72int execute_flag = 0; 73int topn = 0; 74int pid; 75int called = 0; 76int sort_now = 0; 77int waiting_index = 0; 78FILE *dfp = 0; /*Debug output file */ 79long start_time = 0; 80 81#define SAMPLE_SIZE 20000 82 83#define DBG_ZERO_FILL_FAULT 1 84#define DBG_PAGEIN_FAULT 2 85#define DBG_COW_FAULT 3 86#define DBG_CACHE_HIT_FAULT 4 87 88#define MAX_SC 1024 89#define MAX_THREADS 16 90#define MAX_NESTED 8 91#define MAX_FAULTS 5 92 93 94#define NUMPARMS 23 95 96 97char *state_name[] = { 98 "Dont Know", 99 "Running S", 100 "Running U", 101 "Waiting", 102 "Pre-empted", 103}; 104 105#define DONT_KNOW 0 106#define KERNEL_MODE 1 107#define USER_MODE 2 108#define WAITING 3 109#define PREEMPTED 4 110 111struct entry { 112 int sc_state; 113 int type; 114 int code; 115 double otime; 116 double stime; 117 double ctime; 118 double wtime; 119}; 120 121struct th_info { 122 int thread; 123 int depth; 124 int vfslookup; 125 int curpri; 126 long *pathptr; 127 long pathname[NUMPARMS + 1]; 128 struct entry th_entry[MAX_NESTED]; 129}; 130 131struct sc_entry { 132 char name[32]; 133 int delta_count; 134 int total_count; 135 int waiting; 136 unsigned int stime_secs; 137 double stime_usecs; 138 unsigned int wtime_secs; 139 double wtime_usecs; 140 unsigned int delta_wtime_secs; 141 double delta_wtime_usecs; 142}; 143 144struct th_info th_state[MAX_THREADS]; 145struct sc_entry faults[MAX_FAULTS]; 146 147struct sc_entry *sc_tab; 148int *msgcode_tab; 149int msgcode_cnt; /* number of MSG_ codes */ 150 151int num_of_threads = 0; 152int now_collect_cpu_time = 0; 153 154unsigned int utime_secs; 155double utime_usecs; 156 157int in_idle = 0; 158unsigned int itime_secs; 159double itime_usecs; 160unsigned int delta_itime_secs; 161double delta_itime_usecs; 162double idle_start; 163 164int in_other = 0; 165unsigned int otime_secs; 166double otime_usecs; 167unsigned int delta_otime_secs; 168double delta_otime_usecs; 169double other_start; 170 171int max_sc = 0; 172int bsc_base = 0; 173int msc_base = 0; 174int mach_idle = 0; 175int mach_sched = 0; 176int mach_stkhandoff = 0; 177int vfs_lookup = 0; 178int mach_vmfault = 0; 179int bsc_exit = 0; 180int *sort_by_count; 181int *sort_by_wtime; 182 183char proc_name[32]; 184 185#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END) 186#define DBG_FUNC_MASK 0xfffffffc 187 188int preempted; 189int csw; 190int total_faults; 191int scalls; 192 193/* Default divisor */ 194#define DIVISOR 16.6666 /* Trace divisor converts to microseconds */ 195double divisor = DIVISOR; 196 197 198int mib[6]; 199size_t needed; 200char *my_buffer; 201 202kbufinfo_t bufinfo = {0, 0, 0, 0}; 203 204int trace_enabled = 0; 205int set_remove_flag = 1; 206 207struct kinfo_proc *kp_buffer = 0; 208int kp_nentries = 0; 209 210extern char **environ; 211 212void set_enable(); 213void set_pidcheck(); 214void set_remove(); 215void set_numbufs(); 216void set_init(); 217void quit(char *); 218int argtopid(char *); 219int argtoi(int, char*, char*, int); 220 221void get_bufinfo(kbufinfo_t *); 222 223 224/* 225 * signal handlers 226 */ 227 228void leave() /* exit under normal conditions -- INT handler */ 229{ 230 231 if (no_screen_refresh == 0) { 232 move(LINES - 1, 0); 233 refresh(); 234 endwin(); 235 } 236 set_enable(0); 237 set_pidcheck(pid, 0); 238 set_remove(); 239 exit(0); 240} 241 242void err_leave(s) /* exit under error conditions */ 243char *s; 244{ 245 246 if (no_screen_refresh == 0) { 247 move(LINES - 1, 0); 248 refresh(); 249 endwin(); 250 } 251 252 printf("sc_usage: "); 253 if (s) 254 printf("%s ", s); 255 256 set_enable(0); 257 set_pidcheck(pid, 0); 258 set_remove(); 259 260 exit(1); 261} 262 263void sigwinch() 264{ 265 if (no_screen_refresh == 0) 266 newLINES = 1; 267} 268 269int 270exit_usage(char *myname) { 271 272 fprintf(stderr, "Usage: %s [-c codefile] [-e] [-l] [-sn] pid | cmd | -E execute path\n", myname); 273 fprintf(stderr, " -c name of codefile containing mappings for syscalls\n"); 274 fprintf(stderr, " Default is /usr/share/misc/trace.codes\n"); 275 fprintf(stderr, " -e enable sort by call count\n"); 276 fprintf(stderr, " -l turn off top style output\n"); 277 fprintf(stderr, " -sn change sample rate to every n seconds\n"); 278 fprintf(stderr, " pid selects process to sample\n"); 279 fprintf(stderr, " cmd selects command to sample\n"); 280 fprintf(stderr, " -E Execute the given path and optional arguments\n"); 281 282 exit(1); 283} 284 285 286#define usec_to_1000ths(t) ((t) / 1000) 287 288void print_time(char *p, unsigned int useconds, unsigned int seconds) 289{ 290 long minutes, hours; 291 292 minutes = seconds / 60; 293 hours = minutes / 60; 294 295 if (minutes < 100) { // up to 100 minutes 296 sprintf(p, "%02ld:%02ld.%03ld", minutes, (unsigned long)(seconds % 60), 297 (unsigned long)usec_to_1000ths(useconds)); 298 } 299 else if (hours < 100) { // up to 100 hours 300 sprintf(p, "%02ld:%02ld:%02ld ", hours, (minutes % 60), 301 (unsigned long)(seconds % 60)); 302 } 303 else { 304 sprintf(p, "%4ld hrs ", hours); 305 } 306} 307 308int 309main(argc, argv) 310 int argc; 311 char *argv[]; 312{ 313 char *myname = "sc_usage"; 314 char *codefile = "/usr/share/misc/trace.codes"; 315 char ch; 316 char *ptr; 317 int delay = Default_DELAY; 318 void screen_update(); 319 void sort_scalls(); 320 void sc_tab_init(); 321 void getdivisor(); 322 void reset_counters(); 323 324 if ( geteuid() != 0 ) { 325 printf("'sc_usage' must be run as root...\n"); 326 exit(1); 327 } 328 329 if (0 != reexec_to_match_kernel()) { 330 fprintf(stderr, "Could not re-execute: %d\n", errno); 331 exit(1); 332 } 333 334 /* get our name */ 335 if (argc > 0) { 336 if ((myname = rindex(argv[0], '/')) == 0) { 337 myname = argv[0]; 338 } 339 else { 340 myname++; 341 } 342 } 343 344 while ((ch = getopt(argc, argv, "c:els:d:E")) != EOF) { 345 switch(ch) { 346 case 's': 347 delay = argtoi('s', "decimal number", optarg, 10); 348 break; 349 case 'e': 350 how_to_sort = 1; 351 break; 352 case 'l': 353 no_screen_refresh = 1; 354 break; 355 case 'c': 356 codefile = optarg; 357 break; 358 case 'E': 359 execute_flag = 1; 360 break; 361 default: 362 /* exit_usage(myname);*/ 363 exit_usage("default"); 364 } 365 } 366 argc -= optind; 367 //argv += optind; 368 369 sc_tab_init(codefile); 370 371 if (argc) 372 { 373 if (!execute_flag) 374 { 375 /* parse a pid or a command */ 376 if((pid = argtopid(argv[optind])) < 0 ) 377 exit_usage(myname); 378 } 379 else 380 { /* execute this command */ 381 382 uid_t uid, euid; 383 gid_t gid, egid; 384 385 ptr = strrchr(argv[optind], '/'); 386 if (ptr) 387 ptr++; 388 else 389 ptr = argv[optind]; 390 391 strncpy(proc_name, ptr, sizeof(proc_name)-1); 392 proc_name[sizeof(proc_name)-1] = '\0'; 393 394 uid= getuid(); 395 gid= getgid(); 396 euid= geteuid(); 397 egid= getegid(); 398 399 seteuid(uid); 400 setegid(gid); 401 402 fprintf(stderr, "Starting program: %s\n", argv[optind]); 403 fflush(stdout); 404 fflush(stderr); 405 switch ((pid = vfork())) 406 { 407 case -1: 408 perror("vfork: "); 409 exit(1); 410 case 0: /* child */ 411 setsid(); 412 ptrace(0,(pid_t)0,(caddr_t)0,0); /* PT_TRACE_ME */ 413 execve(argv[optind], &argv[optind], environ); 414 perror("execve:"); 415 exit(1); 416 } 417 418 seteuid(euid); 419 setegid(egid); 420 } 421 } 422 else 423 { 424 exit_usage(myname); 425 } 426 427 428 if (no_screen_refresh == 0) { 429 430 /* initializes curses and screen (last) */ 431 if (initscr() == (WINDOW *) 0) 432 { 433 printf("Unrecognized TERM type, try vt100\n"); 434 exit(1); 435 } 436 cbreak(); 437 timeout(100); 438 noecho(); 439 440 clear(); 441 refresh(); 442 } 443 444 445 /* set up signal handlers */ 446 signal(SIGINT, leave); 447 signal(SIGQUIT, leave); 448 signal(SIGHUP, leave); 449 signal(SIGTERM, leave); 450 signal(SIGWINCH, sigwinch); 451 452 if (no_screen_refresh == 0) 453 topn = LINES - Header_lines; 454 else { 455 topn = 1024; 456 COLS = 80; 457 } 458 459 set_remove(); 460 set_numbufs(SAMPLE_SIZE); 461 set_init(); 462 set_pidcheck(pid, 1); 463 set_enable(1); 464 if (execute_flag) 465 ptrace(7, pid, (caddr_t)1, 0); /* PT_CONTINUE */ 466 getdivisor(); 467 468 if (delay == 0) 469 delay = 1; 470 if ((sort_now = 10 / delay) < 2) 471 sort_now = 2; 472 473 get_bufinfo(&bufinfo); 474 475 my_buffer = malloc(bufinfo.nkdbufs * sizeof(kd_buf)); 476 if(my_buffer == (char *) 0) 477 quit("can't allocate memory for tracing info\n"); 478 479 (void)sort_scalls(); 480 (void)screen_update(); 481 482 /* main loop */ 483 484 while (1) { 485 int i; 486 char c; 487 void sample_sc(); 488 489 for (i = 0; i < (10 * delay) && newLINES == 0; i++) { 490 491 if (no_screen_refresh == 0) { 492 if ((c = getch()) != ERR && (char)c == 'q') 493 leave(); 494 if (c != ERR) 495 reset_counters(); 496 } else 497 usleep(100000); 498 sample_sc(); 499 } 500 (void)sort_scalls(); 501 502 if (newLINES) { 503 /* 504 No need to check for initscr error return. 505 We won't get here if it fails on the first call. 506 */ 507 endwin(); 508 clear(); 509 refresh(); 510 511 topn = LINES - Header_lines; 512 newLINES = 0; 513 } 514 (void)screen_update(); 515 } 516} 517 518void 519print_row(struct sc_entry *se, int no_wtime) { 520 char tbuf[256]; 521 int clen; 522 523 if (se->delta_count) 524 sprintf(tbuf, "%-23.23s %8d(%d)", se->name, se->total_count, se->delta_count); 525 else 526 sprintf(tbuf, "%-23.23s %8d", se->name, se->total_count); 527 clen = strlen(tbuf); 528 529 memset(&tbuf[clen], ' ', 45 - clen); 530 531 print_time(&tbuf[45], (unsigned long)(se->stime_usecs), se->stime_secs); 532 clen = strlen(tbuf); 533 534 if (no_wtime == 0 && (se->wtime_usecs || se->wtime_secs)) { 535 sprintf(&tbuf[clen], " "); 536 clen += strlen(&tbuf[clen]); 537 538 print_time(&tbuf[clen], (unsigned long)(se->wtime_usecs), se->wtime_secs); 539 clen += strlen(&tbuf[clen]); 540 541 if (se->waiting || se->delta_wtime_usecs || se->delta_wtime_secs) { 542 543 sprintf(&tbuf[clen], "("); 544 clen += strlen(&tbuf[clen]); 545 546 print_time(&tbuf[clen], (unsigned long)(se->delta_wtime_usecs), 547 se->delta_wtime_secs); 548 clen += strlen(&tbuf[clen]); 549 550 sprintf(&tbuf[clen], ")"); 551 clen += strlen(&tbuf[clen]); 552 553 if (se->waiting) { 554 if (se->waiting == 1) 555 sprintf(&tbuf[clen], " W"); 556 else 557 sprintf(&tbuf[clen], " %d", se->waiting); 558 clen += strlen(&tbuf[clen]); 559 } 560 } 561 } 562 sprintf(&tbuf[clen], "\n"); 563 if (no_screen_refresh) 564 printf("%s", tbuf); 565 else 566 printw(tbuf); 567} 568 569 570void screen_update() 571{ 572 char *p1, *p2, *p3; 573 char tbuf[256]; 574 int clen; 575 int plen; 576 int n, i, rows; 577 long curr_time; 578 long elapsed_secs; 579 int hours; 580 int minutes; 581 struct sc_entry *se; 582 int output_lf; 583 int max_rows; 584 struct th_info *ti; 585 586 if (no_screen_refresh == 0) { 587 /* clear for new display */ 588 erase(); 589 move(0, 0); 590 } 591 rows = 0; 592 593 sprintf(tbuf, "%-14.14s", proc_name); 594 clen = strlen(tbuf); 595 596 if (preempted == 1) 597 p1 = "preemption "; 598 else 599 p1 = "preemptions"; 600 if (csw == 1) 601 p2 = "context switch "; 602 else 603 p2 = "context switches"; 604 if (num_of_threads == 1) 605 p3 = "thread "; 606 else 607 p3 = "threads"; 608 609 sprintf(&tbuf[clen], " %4d %s %4d %s %4d %s", 610 preempted, p1, csw, p2, num_of_threads, p3); 611 clen += strlen(&tbuf[clen]); 612 613 /* 614 * Display the current time. 615 * "ctime" always returns a string that looks like this: 616 * 617 * Sun Sep 16 01:03:52 1973 618 * 012345678901234567890123 619 * 1 2 620 * 621 * We want indices 11 thru 18 (length 8). 622 */ 623 curr_time = time((long *)0); 624 625 if (start_time == 0) 626 start_time = curr_time; 627 628 elapsed_secs = curr_time - start_time; 629 minutes = elapsed_secs / 60; 630 hours = minutes / 60; 631 632 memset(&tbuf[clen], ' ', 78 - clen); 633 634 clen = 78 - 8; 635 636 sprintf(&tbuf[clen], "%-8.8s\n", &(ctime(&curr_time)[11])); 637 if (no_screen_refresh) 638 printf("%s", tbuf); 639 else 640 printw(tbuf); 641 642 if (total_faults == 1) 643 p1 = "fault "; 644 else 645 p1 = "faults"; 646 if (scalls == 1) 647 p2 = "system call "; 648 else 649 p2 = "system calls"; 650 sprintf(tbuf, " %4d %s %4d %s", 651 total_faults, p1, scalls, p2); 652 653 clen = strlen(tbuf); 654 sprintf(&tbuf[clen], " %3ld:%02ld:%02ld\n", 655 (long)hours, (long)(minutes % 60), (long)(elapsed_secs % 60)); 656 if (no_screen_refresh) 657 printf("%s", tbuf); 658 else 659 printw(tbuf); 660 661 662 663 sprintf(tbuf, "\nTYPE NUMBER CPU_TIME WAIT_TIME\n"); 664 if (no_screen_refresh) 665 printf("%s", tbuf); 666 else 667 printw(tbuf); 668 669 sprintf(tbuf, "------------------------------------------------------------------------------\n"); 670 if (no_screen_refresh) 671 printf("%s", tbuf); 672 else 673 printw(tbuf); 674 rows = 0; 675 676 677 678 sprintf(tbuf, "System Idle "); 679 clen = strlen(tbuf); 680 681 print_time(&tbuf[clen], (unsigned long)(itime_usecs), itime_secs); 682 clen += strlen(&tbuf[clen]); 683 684 if (delta_itime_usecs || delta_itime_secs) { 685 686 sprintf(&tbuf[clen], "("); 687 clen += strlen(&tbuf[clen]); 688 689 print_time(&tbuf[clen], (unsigned long)(delta_itime_usecs), delta_itime_secs); 690 clen += strlen(&tbuf[clen]); 691 692 sprintf(&tbuf[clen], ")"); 693 clen += strlen(&tbuf[clen]); 694 } 695 sprintf(&tbuf[clen], "\n"); 696 if (no_screen_refresh) 697 printf("%s", tbuf); 698 else 699 printw(tbuf); 700 rows++; 701 702 703 704 sprintf(tbuf, "System Busy "); 705 clen = strlen(tbuf); 706 707 print_time(&tbuf[clen], (unsigned long)(otime_usecs), otime_secs); 708 clen += strlen(&tbuf[clen]); 709 710 if (delta_otime_usecs || delta_otime_secs) { 711 712 sprintf(&tbuf[clen], "("); 713 clen += strlen(&tbuf[clen]); 714 715 print_time(&tbuf[clen], (unsigned long)(delta_otime_usecs), delta_otime_secs); 716 clen += strlen(&tbuf[clen]); 717 718 sprintf(&tbuf[clen], ")"); 719 clen += strlen(&tbuf[clen]); 720 } 721 sprintf(&tbuf[clen], "\n"); 722 if (no_screen_refresh) 723 printf("%s", tbuf); 724 else 725 printw(tbuf); 726 rows++; 727 728 729 sprintf(tbuf, "%-14.14s Usermode ", proc_name); 730 clen = strlen(tbuf); 731 732 print_time(&tbuf[clen], (unsigned long)(utime_usecs), utime_secs); 733 clen += strlen(&tbuf[clen]); 734 735 sprintf(&tbuf[clen], "\n"); 736 if (no_screen_refresh) 737 printf("%s", tbuf); 738 else 739 printw(tbuf); 740 rows++; 741 742 if (num_of_threads) 743 max_rows = topn - (num_of_threads + 3); 744 else 745 max_rows = topn; 746 747 for (output_lf = 1, n = 1; rows < max_rows && n < MAX_FAULTS; n++) { 748 se = &faults[n]; 749 750 if (se->total_count == 0) 751 continue; 752 if (output_lf == 1) { 753 sprintf(tbuf, "\n"); 754 if (no_screen_refresh) 755 printf("%s", tbuf); 756 else 757 printw(tbuf); 758 rows++; 759 760 if (rows >= max_rows) 761 break; 762 output_lf = 0; 763 } 764 print_row(se, 0); 765 rows++; 766 } 767 sprintf(tbuf, "\n"); 768 769 if (no_screen_refresh) 770 printf("%s", tbuf); 771 else 772 printw(tbuf); 773 rows++; 774 775 for (i = 0; rows < max_rows; i++) { 776 if (how_to_sort) 777 n = sort_by_count[i]; 778 else 779 n = sort_by_wtime[i]; 780 if (n == -1) 781 break; 782 print_row(&sc_tab[n], 0); 783 rows++; 784 } 785 786 787 sprintf(tbuf, "\n"); 788 if (no_screen_refresh == 0) { 789 while (rows++ < max_rows) 790 printw(tbuf); 791 } else 792 printf("%s", tbuf); 793 794 if (num_of_threads) { 795 sprintf(tbuf, "\nCURRENT_TYPE LAST_PATHNAME_WAITED_FOR CUR_WAIT_TIME THRD# PRI\n"); 796 797 if (no_screen_refresh) 798 printf("%s", tbuf); 799 else 800 printw(tbuf); 801 802 sprintf(tbuf, "------------------------------------------------------------------------------\n"); 803 if (no_screen_refresh) 804 printf("%s", tbuf); 805 else 806 printw(tbuf); 807 } 808 ti = &th_state[0]; 809 810 for (i = 0; i < num_of_threads; i++, ti++) { 811 struct entry *te; 812 char *p; 813 uint64_t now; 814 int secs, time_secs, time_usecs; 815 816 now = mach_absolute_time(); 817 818 while (ti->thread == 0 && ti < &th_state[MAX_THREADS]) 819 ti++; 820 if (ti == &th_state[MAX_THREADS]) 821 break; 822 823 if (ti->depth) { 824 te = &ti->th_entry[ti->depth - 1]; 825 826 if (te->sc_state == WAITING) { 827 if (te->code) 828 sprintf(tbuf, "%-23.23s", sc_tab[te->code].name); 829 else 830 sprintf(tbuf, "%-23.23s", "vm_fault"); 831 } else 832 sprintf(tbuf, "%-23.23s", state_name[te->sc_state]); 833 } else { 834 te = &ti->th_entry[0]; 835 sprintf(tbuf, "%-23.23s", state_name[te->sc_state]); 836 } 837 clen = strlen(tbuf); 838 839 /* print the tail end of the pathname */ 840 p = (char *)ti->pathname; 841 842 plen = strlen(p); 843 if (plen > 26) 844 plen -= 26; 845 else 846 plen = 0; 847 sprintf(&tbuf[clen], " %-26.26s ", &p[plen]); 848 849 clen += strlen(&tbuf[clen]); 850 851 time_usecs = (unsigned long)(((double)now - te->otime) / divisor); 852 secs = time_usecs / 1000000; 853 time_usecs -= secs * 1000000; 854 time_secs = secs; 855 856 print_time(&tbuf[clen], time_usecs, time_secs); 857 clen += strlen(&tbuf[clen]); 858 sprintf(&tbuf[clen], " %2d %3d\n", i, ti->curpri); 859 if (no_screen_refresh) 860 printf("%s", tbuf); 861 else 862 printw(tbuf); 863 } 864 if (no_screen_refresh == 0) { 865 move(0, 0); 866 refresh(); 867 } else 868 printf("\n=================\n"); 869 870 871 872 for (i = 0; i < (MAX_SC + msgcode_cnt); i++) { 873 if ((n = sort_by_count[i]) == -1) 874 break; 875 sc_tab[n].delta_count = 0; 876 sc_tab[n].waiting = 0; 877 sc_tab[n].delta_wtime_usecs = 0; 878 sc_tab[n].delta_wtime_secs = 0; 879 } 880 for (i = 1; i < MAX_FAULTS; i++) { 881 faults[i].delta_count = 0; 882 faults[i].waiting = 0; 883 faults[i].delta_wtime_usecs = 0; 884 faults[i].delta_wtime_secs = 0; 885 } 886 preempted = 0; 887 csw = 0; 888 total_faults = 0; 889 scalls = 0; 890 delta_itime_secs = 0; 891 delta_itime_usecs = 0; 892 delta_otime_secs = 0; 893 delta_otime_usecs = 0; 894} 895 896void 897reset_counters() { 898 int i; 899 900 for (i = 0; i < (MAX_SC + msgcode_cnt) ; i++) { 901 sc_tab[i].delta_count = 0; 902 sc_tab[i].total_count = 0; 903 sc_tab[i].waiting = 0; 904 sc_tab[i].delta_wtime_usecs = 0; 905 sc_tab[i].delta_wtime_secs = 0; 906 sc_tab[i].wtime_usecs = 0; 907 sc_tab[i].wtime_secs = 0; 908 sc_tab[i].stime_usecs = 0; 909 sc_tab[i].stime_secs = 0; 910 } 911 for (i = 1; i < MAX_FAULTS; i++) { 912 faults[i].delta_count = 0; 913 faults[i].total_count = 0; 914 faults[i].waiting = 0; 915 faults[i].delta_wtime_usecs = 0; 916 faults[i].delta_wtime_secs = 0; 917 faults[i].wtime_usecs = 0; 918 faults[i].wtime_secs = 0; 919 faults[i].stime_usecs = 0; 920 faults[i].stime_secs = 0; 921 } 922 preempted = 0; 923 csw = 0; 924 total_faults = 0; 925 scalls = 0; 926 called = 0; 927 928 utime_secs = 0; 929 utime_usecs = 0; 930 itime_secs = 0; 931 itime_usecs = 0; 932 delta_itime_secs = 0; 933 delta_itime_usecs = 0; 934 otime_secs = 0; 935 otime_usecs = 0; 936 delta_otime_secs = 0; 937 delta_otime_usecs = 0; 938} 939 940void 941sc_tab_init(char *codefile) { 942 int code; 943 int n, cnt; 944 int msgcode_indx=0; 945 char name[56]; 946 FILE *fp; 947 948 if ((fp = fopen(codefile,"r")) == (FILE *)0) { 949 printf("Failed to open code description file %s\n", codefile); 950 exit(1); 951 } 952 953 /* Count Mach message MSG_ codes */ 954 for (msgcode_cnt=0;;) { 955 n = fscanf(fp, "%x%55s\n", &code, &name[0]); 956 if (n != 2) 957 break; 958 if (strncmp ("MSG_", &name[0], 4) == 0) 959 msgcode_cnt++; 960 if (strcmp("TRACE_LAST_WRAPPER", &name[0]) == 0) 961 break; 962 } 963 964 sc_tab = (struct sc_entry *)malloc((MAX_SC+msgcode_cnt) * sizeof (struct sc_entry)); 965 if(!sc_tab) 966 quit("can't allocate memory for system call table\n"); 967 bzero(sc_tab,(MAX_SC+msgcode_cnt) * sizeof (struct sc_entry)); 968 969 msgcode_tab = (int *)malloc(msgcode_cnt * sizeof(int)); 970 if (!msgcode_tab) 971 quit("can't allocate memory for msgcode table\n"); 972 bzero(msgcode_tab,(msgcode_cnt * sizeof(int))); 973 974 sort_by_count = (int *)malloc((MAX_SC + msgcode_cnt + 1) * sizeof(int)); 975 if (!sort_by_count) 976 quit("can't allocate memory for sort_by_count table\n"); 977 bzero(sort_by_count,(MAX_SC + msgcode_cnt + 1) * sizeof(int)); 978 979 sort_by_wtime = (int *)malloc((MAX_SC + msgcode_cnt + 1) * sizeof(int)); 980 if (!sort_by_wtime) 981 quit("can't allocate memory for sort_by_wtime table\n"); 982 bzero(sort_by_wtime, (MAX_SC + msgcode_cnt + 1) * sizeof(int)); 983 984 985 rewind(fp); 986 987 for (;;) { 988 n = fscanf(fp, "%x%55s\n", &code, &name[0]); 989 990 if (n != 2) 991 break; 992 993 if (strcmp("MACH_vmfault", &name[0]) == 0) { 994 mach_vmfault = code; 995 continue; 996 } 997 if (strcmp("MACH_SCHED", &name[0]) == 0) { 998 mach_sched = code; 999 continue; 1000 } 1001 if (strcmp("MACH_STKHANDOFF", &name[0]) == 0) { 1002 mach_stkhandoff = code; 1003 continue; 1004 } 1005 if (strcmp("MACH_IDLE", &name[0]) == 0) { 1006 mach_idle = code; 1007 continue; 1008 } 1009 if (strcmp("VFS_LOOKUP", &name[0]) == 0) { 1010 vfs_lookup = code; 1011 continue; 1012 } 1013 if (strcmp("BSC_SysCall", &name[0]) == 0) { 1014 bsc_base = code; 1015 continue; 1016 } 1017 if (strcmp("MACH_SysCall", &name[0]) == 0) { 1018 msc_base = code; 1019 continue; 1020 } 1021 if (strcmp("BSC_exit", &name[0]) == 0) { 1022 bsc_exit = code; 1023 continue; 1024 } 1025 if (strncmp("MSG_", &name[0], 4) == 0) { 1026 msgcode_tab[msgcode_indx] = ((code & 0x00ffffff) >>2); 1027 n = MAX_SC + msgcode_indx; 1028 strncpy(&sc_tab[n].name[0], &name[4], 31 ); 1029 msgcode_indx++; 1030 continue; 1031 } 1032 if (strncmp("MSC_", &name[0], 4) == 0) { 1033 n = 512 + ((code>>2) & 0x1ff); 1034 strcpy(&sc_tab[n].name[0], &name[4]); 1035 continue; 1036 } 1037 if (strncmp("BSC_", &name[0], 4) == 0) { 1038 n = (code>>2) & 0x1ff; 1039 strcpy(&sc_tab[n].name[0], &name[4]); 1040 continue; 1041 } 1042 if (strcmp("TRACE_LAST_WRAPPER", &name[0]) == 0) 1043 break; 1044 } 1045 strcpy(&faults[1].name[0], "zero_fill"); 1046 strcpy(&faults[2].name[0], "pagein"); 1047 strcpy(&faults[3].name[0], "copy_on_write"); 1048 strcpy(&faults[4].name[0], "cache_hit"); 1049} 1050 1051void 1052find_proc_names() 1053{ 1054 size_t bufSize = 0; 1055 struct kinfo_proc *kp; 1056 1057 mib[0] = CTL_KERN; 1058 mib[1] = KERN_PROC; 1059 mib[2] = KERN_PROC_ALL; 1060 mib[3] = 0; 1061 1062 if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) 1063 quit("trace facility failure, KERN_PROC_ALL\n"); 1064 1065 if((kp = (struct kinfo_proc *)malloc(bufSize)) == (struct kinfo_proc *)0) 1066 quit("can't allocate memory for proc buffer\n"); 1067 1068 if (sysctl(mib, 4, kp, &bufSize, NULL, 0) < 0) 1069 quit("trace facility failure, KERN_PROC_ALL\n"); 1070 1071 kp_nentries = bufSize/ sizeof(struct kinfo_proc); 1072 kp_buffer = kp; 1073} 1074 1075struct th_info *find_thread(int thread) { 1076 struct th_info *ti; 1077 1078 for (ti = th_state; ti < &th_state[MAX_THREADS]; ti++) { 1079 if (ti->thread == thread) 1080 return(ti); 1081 } 1082 return ((struct th_info *)0); 1083} 1084 1085 1086int 1087cmp_wtime(struct sc_entry *s1, struct sc_entry *s2) { 1088 1089 if (s1->wtime_secs < s2->wtime_secs) 1090 return 0; 1091 if (s1->wtime_secs > s2->wtime_secs) 1092 return 1; 1093 if (s1->wtime_usecs <= s2->wtime_usecs) 1094 return 0; 1095 return 1; 1096} 1097 1098 1099void 1100sort_scalls() { 1101 int i, n, k, cnt, secs; 1102 struct th_info *ti; 1103 struct sc_entry *se; 1104 struct entry *te; 1105 uint64_t now; 1106 1107 now = mach_absolute_time(); 1108 1109 for (ti = th_state; ti < &th_state[MAX_THREADS]; ti++) { 1110 if (ti->thread == 0) 1111 continue; 1112 1113 if (ti->depth) { 1114 te = &ti->th_entry[ti->depth-1]; 1115 1116 if (te->sc_state == WAITING) { 1117 if (te->code) 1118 se = &sc_tab[te->code]; 1119 else 1120 se = &faults[DBG_PAGEIN_FAULT]; 1121 se->waiting++; 1122 se->wtime_usecs += ((double)now - te->stime) / divisor; 1123 se->delta_wtime_usecs += ((double)now - te->stime) / divisor; 1124 te->stime = (double)now; 1125 1126 secs = se->wtime_usecs / 1000000; 1127 se->wtime_usecs -= secs * 1000000; 1128 se->wtime_secs += secs; 1129 1130 secs = se->delta_wtime_usecs / 1000000; 1131 se->delta_wtime_usecs -= secs * 1000000; 1132 se->delta_wtime_secs += secs; 1133 } 1134 } else { 1135 te = &ti->th_entry[0]; 1136 1137 if (te->sc_state == PREEMPTED) { 1138 if ((unsigned long)(((double)now - te->otime) / divisor) > 5000000) { 1139 ti->thread = 0; 1140 ti->vfslookup = 0; 1141 ti->pathptr = (long *)NULL; 1142 ti->pathname[0] = 0; 1143 num_of_threads--; 1144 } 1145 } 1146 } 1147 } 1148 if ((called % sort_now) == 0) { 1149 sort_by_count[0] = -1; 1150 sort_by_wtime[0] = -1; 1151 for (cnt = 1, n = 1; n < (MAX_SC + msgcode_cnt); n++) { 1152 if (sc_tab[n].total_count) { 1153 for (i = 0; i < cnt; i++) { 1154 if ((k = sort_by_count[i]) == -1 || 1155 sc_tab[n].total_count > sc_tab[k].total_count) { 1156 1157 for (k = cnt - 1; k >= i; k--) 1158 sort_by_count[k+1] = sort_by_count[k]; 1159 sort_by_count[i] = n; 1160 break; 1161 } 1162 } 1163 if (how_to_sort == 0) { 1164 for (i = 0; i < cnt; i++) { 1165 if ((k = sort_by_wtime[i]) == -1 || 1166 cmp_wtime(&sc_tab[n], &sc_tab[k])) { 1167 1168 for (k = cnt - 1; k >= i; k--) 1169 sort_by_wtime[k+1] = sort_by_wtime[k]; 1170 sort_by_wtime[i] = n; 1171 break; 1172 } 1173 } 1174 } 1175 cnt++; 1176 } 1177 } 1178 } 1179 called++; 1180} 1181 1182void 1183set_enable(int val) 1184{ 1185 mib[0] = CTL_KERN; 1186 mib[1] = KERN_KDEBUG; 1187 mib[2] = KERN_KDENABLE; /* protocol */ 1188 mib[3] = val; 1189 mib[4] = 0; 1190 mib[5] = 0; /* no flags */ 1191 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) 1192 quit("trace facility failure, KERN_KDENABLE\n"); 1193 1194 if (val) 1195 trace_enabled = 1; 1196 else 1197 trace_enabled = 0; 1198} 1199 1200void 1201set_numbufs(int nbufs) 1202{ 1203 mib[0] = CTL_KERN; 1204 mib[1] = KERN_KDEBUG; 1205 mib[2] = KERN_KDSETBUF; 1206 mib[3] = nbufs; 1207 mib[4] = 0; 1208 mib[5] = 0; /* no flags */ 1209 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) 1210 quit("trace facility failure, KERN_KDSETBUF\n"); 1211 1212 mib[0] = CTL_KERN; 1213 mib[1] = KERN_KDEBUG; 1214 mib[2] = KERN_KDSETUP; 1215 mib[3] = 0; 1216 mib[4] = 0; 1217 mib[5] = 0; /* no flags */ 1218 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) 1219 quit("trace facility failure, KERN_KDSETUP\n"); 1220 1221} 1222 1223void 1224set_pidcheck(int pid, int on_off) 1225{ 1226 kd_regtype kr; 1227 1228 kr.type = KDBG_TYPENONE; 1229 kr.value1 = pid; 1230 kr.value2 = on_off; 1231 needed = sizeof(kd_regtype); 1232 mib[0] = CTL_KERN; 1233 mib[1] = KERN_KDEBUG; 1234 mib[2] = KERN_KDPIDTR; 1235 mib[3] = 0; 1236 mib[4] = 0; 1237 mib[5] = 0; 1238 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) { 1239 if (on_off == 1) { 1240 printf("pid %d does not exist\n", pid); 1241 set_remove(); 1242 exit(2); 1243 } 1244 } 1245} 1246 1247void 1248get_bufinfo(kbufinfo_t *val) 1249{ 1250 needed = sizeof (*val); 1251 mib[0] = CTL_KERN; 1252 mib[1] = KERN_KDEBUG; 1253 mib[2] = KERN_KDGETBUF; 1254 mib[3] = 0; 1255 mib[4] = 0; 1256 mib[5] = 0; /* no flags */ 1257 if (sysctl(mib, 3, val, &needed, 0, 0) < 0) 1258 quit("trace facility failure, KERN_KDGETBUF\n"); 1259 1260} 1261 1262void 1263set_remove() 1264{ 1265 extern int errno; 1266 1267 errno = 0; 1268 1269 mib[0] = CTL_KERN; 1270 mib[1] = KERN_KDEBUG; 1271 mib[2] = KERN_KDREMOVE; /* protocol */ 1272 mib[3] = 0; 1273 mib[4] = 0; 1274 mib[5] = 0; /* no flags */ 1275 1276 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) 1277 { 1278 set_remove_flag = 0; 1279 1280 if (errno == EBUSY) 1281 quit("The trace facility is currently in use...\n Note: fs_usage, sc_usage, and latency use this feature.\n\n"); 1282 else 1283 quit("trace facility failure, KERN_KDREMOVE\n"); 1284 } 1285} 1286 1287void 1288set_init() 1289{ kd_regtype kr; 1290 1291 kr.type = KDBG_RANGETYPE; 1292 kr.value1 = 0; 1293 kr.value2 = -1; 1294 needed = sizeof(kd_regtype); 1295 mib[0] = CTL_KERN; 1296 mib[1] = KERN_KDEBUG; 1297 mib[2] = KERN_KDSETREG; 1298 mib[3] = 0; 1299 mib[4] = 0; 1300 mib[5] = 0; /* no flags */ 1301 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) 1302 quit("trace facility failure, KERN_KDSETREG\n"); 1303 1304 mib[0] = CTL_KERN; 1305 mib[1] = KERN_KDEBUG; 1306 mib[2] = KERN_KDSETUP; 1307 mib[3] = 0; 1308 mib[4] = 0; 1309 mib[5] = 0; /* no flags */ 1310 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) 1311 quit("trace facility failure, KERN_KDSETUP\n"); 1312 1313} 1314 1315void 1316sample_sc() 1317{ 1318 kd_buf *kd; 1319 int i, count; 1320 int secs; 1321 int find_msgcode(); 1322 1323 int reenable; 1324 1325#ifdef OLD_KDEBUG 1326 set_enable(0); 1327#endif 1328 get_bufinfo(&bufinfo); 1329 1330 needed = bufinfo.nkdbufs * sizeof(kd_buf); 1331 mib[0] = CTL_KERN; 1332 mib[1] = KERN_KDEBUG; 1333 mib[2] = KERN_KDREADTR; 1334 mib[3] = 0; 1335 mib[4] = 0; 1336 mib[5] = 0; 1337 1338 if (sysctl(mib, 3, my_buffer, &needed, NULL, 0) < 0) 1339 quit("trace facility failure, KERN_KDREADTR\n"); 1340 1341 count = needed; 1342 1343 if (bufinfo.flags & KDBG_WRAPPED) { 1344 for (i = 0; i < MAX_THREADS; i++) { 1345 th_state[i].depth = 0; 1346 th_state[i].thread = 0; 1347 th_state[i].vfslookup = 0; 1348 th_state[i].pathptr = (long *)NULL; 1349 th_state[i].pathname[0] = 0; 1350 } 1351 num_of_threads = 0; 1352 } 1353 1354#ifdef OLD_KDEBUG 1355 set_remove(); 1356 set_init(); 1357 set_pidcheck(pid, 1); 1358 set_enable(1); /* re-enable kernel logging */ 1359#endif 1360 kd = (kd_buf *)my_buffer; 1361 1362 for (i = 0; i < count; i++) { 1363 int debugid, baseid, thread; 1364 int type, code; 1365 uint64_t now; 1366 struct th_info *ti, *switched_out, *switched_in; 1367 struct sc_entry *se; 1368 struct entry *te; 1369 1370 thread = kd[i].arg5; 1371 debugid = kd[i].debugid; 1372 type = kd[i].debugid & DBG_FUNC_MASK; 1373 1374 code = 0; 1375 switched_out = (struct th_info *)0; 1376 switched_in = (struct th_info *)0; 1377 1378 now = kd[i].timestamp & KDBG_TIMESTAMP_MASK; 1379 1380 baseid = debugid & 0xffff0000; 1381 1382 if (type == vfs_lookup) { 1383 long *sargptr; 1384 1385 if ((ti = find_thread(thread)) == (struct th_info *)0) 1386 continue; 1387 1388 if (ti->vfslookup == 1) { 1389 ti->vfslookup++; 1390 sargptr = ti->pathname; 1391 1392 *sargptr++ = kd[i].arg2; 1393 *sargptr++ = kd[i].arg3; 1394 *sargptr++ = kd[i].arg4; 1395 /* 1396 * NULL terminate the 'string' 1397 */ 1398 *sargptr = 0; 1399 1400 ti->pathptr = sargptr; 1401 1402 } else if (ti->vfslookup > 1) { 1403 ti->vfslookup++; 1404 sargptr = ti->pathptr; 1405 1406 /* 1407 We don't want to overrun our pathname buffer if the 1408 kernel sends us more VFS_LOOKUP entries than we can 1409 handle. 1410 */ 1411 1412 if (sargptr >= &ti->pathname[NUMPARMS]) 1413 continue; 1414 1415 /* 1416 We need to detect consecutive vfslookup entries. 1417 So, if we get here and find a START entry, 1418 fake the pathptr so we can bypass all further 1419 vfslookup entries. 1420 */ 1421 1422 if (debugid & DBG_FUNC_START) 1423 { 1424 ti->pathptr = &ti->pathname[NUMPARMS]; 1425 continue; 1426 } 1427 1428 *sargptr++ = kd[i].arg1; 1429 *sargptr++ = kd[i].arg2; 1430 *sargptr++ = kd[i].arg3; 1431 *sargptr++ = kd[i].arg4; 1432 /* 1433 * NULL terminate the 'string' 1434 */ 1435 *sargptr = 0; 1436 1437 ti->pathptr = sargptr; 1438 } 1439 continue; 1440 1441 } else if (baseid == bsc_base) 1442 code = (debugid >> 2) & 0x1ff; 1443 else if (baseid == msc_base) 1444 code = 512 + ((debugid >> 2) & 0x1ff); 1445 else if (type == mach_idle) { 1446 if (debugid & DBG_FUNC_START) { 1447 switched_out = find_thread(kd[i].arg5); 1448 switched_in = 0; 1449 } 1450 else 1451 if (debugid & DBG_FUNC_END) { 1452 switched_in = find_thread(kd[i].arg5); 1453 switched_out = 0; 1454 } 1455 1456 if (in_idle) { 1457 itime_usecs += ((double)now - idle_start) / divisor; 1458 delta_itime_usecs += ((double)now - idle_start) / divisor; 1459 in_idle = 0; 1460 } else if (in_other) { 1461 otime_usecs += ((double)now - other_start) / divisor; 1462 delta_otime_usecs += ((double)now - other_start) / divisor; 1463 in_other = 0; 1464 } 1465 if ( !switched_in) { 1466 /* 1467 * not one of the target proc's threads 1468 */ 1469 if (now_collect_cpu_time) { 1470 in_idle = 1; 1471 idle_start = (double)now; 1472 } 1473 } 1474 else { 1475 if (now_collect_cpu_time) { 1476 in_idle = 0; 1477 in_other = 1; 1478 other_start = (double)now; 1479 } 1480 } 1481 if ( !switched_in && !switched_out) 1482 continue; 1483 1484 } 1485 else if (type == mach_sched || type == mach_stkhandoff) { 1486 switched_out = find_thread(kd[i].arg5); 1487 switched_in = find_thread(kd[i].arg2); 1488 1489 if (in_idle) { 1490 itime_usecs += ((double)now - idle_start) / divisor; 1491 delta_itime_usecs += ((double)now - idle_start) / divisor; 1492 in_idle = 0; 1493 } else if (in_other) { 1494 otime_usecs += ((double)now - other_start) / divisor; 1495 delta_otime_usecs += ((double)now - other_start) / divisor; 1496 in_other = 0; 1497 } 1498 if ( !switched_in) { 1499 /* 1500 * not one of the target proc's threads 1501 */ 1502 if (now_collect_cpu_time) { 1503 in_other = 1; 1504 other_start = (double)now; 1505 } 1506 } 1507 if ( !switched_in && !switched_out) 1508 continue; 1509 1510 } 1511 else if ((baseid & 0xff000000) == 0xff000000) { 1512 code = find_msgcode (debugid); 1513 if (!code) 1514 continue; 1515 } else if (baseid != mach_vmfault) 1516 continue; 1517 1518 if (switched_out || switched_in) { 1519 if (switched_out) { 1520 ti = switched_out; 1521 ti->curpri = kd[i].arg3; 1522 1523 if (ti->depth) { 1524 te = &ti->th_entry[ti->depth-1]; 1525 1526 if (te->sc_state == KERNEL_MODE) 1527 te->ctime += (double)now - te->stime; 1528 te->sc_state = WAITING; 1529 1530 ti->vfslookup = 1; 1531 1532 } else { 1533 te = &ti->th_entry[0]; 1534 1535 if (te->sc_state == USER_MODE) 1536 utime_usecs += ((double)now - te->stime) / divisor; 1537 te->sc_state = PREEMPTED; 1538 preempted++; 1539 } 1540 te->stime = (double)now; 1541 te->otime = (double)now; 1542 now_collect_cpu_time = 1; 1543 csw++; 1544 } 1545 if (switched_in) { 1546 ti = switched_in; 1547 ti->curpri = kd[i].arg4; 1548 1549 if (ti->depth) { 1550 te = &ti->th_entry[ti->depth-1]; 1551 1552 if (te->sc_state == WAITING) 1553 te->wtime += (double)now - te->stime; 1554 te->sc_state = KERNEL_MODE; 1555 } else { 1556 te = &ti->th_entry[0]; 1557 1558 te->sc_state = USER_MODE; 1559 } 1560 te->stime = (double)now; 1561 te->otime = (double)now; 1562 } 1563 continue; 1564 } 1565 if ((ti = find_thread(thread)) == (struct th_info *)0) { 1566 for (ti = &th_state[0]; ti < &th_state[MAX_THREADS]; ti++) { 1567 if (ti->thread == 0) { 1568 ti->thread = thread; 1569 num_of_threads++; 1570 break; 1571 } 1572 } 1573 if (ti == &th_state[MAX_THREADS]) 1574 continue; 1575 } 1576 if (debugid & DBG_FUNC_START) { 1577 ti->vfslookup = 0; 1578 1579 if (ti->depth) { 1580 te = &ti->th_entry[ti->depth-1]; 1581 1582 if (te->sc_state == KERNEL_MODE) 1583 te->ctime += (double)now - te->stime; 1584 } else { 1585 te = &ti->th_entry[0]; 1586 1587 if (te->sc_state == USER_MODE) 1588 utime_usecs += ((double)now - te->stime) / divisor; 1589 } 1590 te->stime = (double)now; 1591 te->otime = (double)now; 1592 1593 if (ti->depth < MAX_NESTED) { 1594 te = &ti->th_entry[ti->depth]; 1595 1596 te->sc_state = KERNEL_MODE; 1597 te->type = type; 1598 te->code = code; 1599 te->stime = (double)now; 1600 te->otime = (double)now; 1601 te->ctime = (double)0; 1602 te->wtime = (double)0; 1603 ti->depth++; 1604 } 1605 1606 } else if (debugid & DBG_FUNC_END) { 1607 if (code) { 1608 se = &sc_tab[code]; 1609 scalls++; 1610 } else { 1611 se = &faults[kd[i].arg4]; 1612 total_faults++; 1613 } 1614 if (se->total_count == 0) 1615 called = 0; 1616 se->delta_count++; 1617 se->total_count++; 1618 1619 while (ti->depth) { 1620 te = &ti->th_entry[ti->depth-1]; 1621 1622 if (te->type == type) { 1623 se->stime_usecs += te->ctime / divisor; 1624 se->stime_usecs += ((double)now - te->stime) / divisor; 1625 1626 se->wtime_usecs += te->wtime / divisor; 1627 se->delta_wtime_usecs += te->wtime / divisor; 1628 1629 secs = se->stime_usecs / 1000000; 1630 se->stime_usecs -= secs * 1000000; 1631 se->stime_secs += secs; 1632 1633 secs = se->wtime_usecs / 1000000; 1634 se->wtime_usecs -= secs * 1000000; 1635 se->wtime_secs += secs; 1636 1637 secs = se->delta_wtime_usecs / 1000000; 1638 se->delta_wtime_usecs -= secs * 1000000; 1639 se->delta_wtime_secs += secs; 1640 1641 ti->depth--; 1642 1643 if (ti->depth == 0) { 1644 /* 1645 * headed back to user mode 1646 * start the time accumulation 1647 */ 1648 te = &ti->th_entry[0]; 1649 te->sc_state = USER_MODE; 1650 } else 1651 te = &ti->th_entry[ti->depth-1]; 1652 1653 te->stime = (double)now; 1654 te->otime = (double)now; 1655 1656 break; 1657 } 1658 ti->depth--; 1659 1660 if (ti->depth == 0) { 1661 /* 1662 * headed back to user mode 1663 * start the time accumulation 1664 */ 1665 te = &ti->th_entry[0]; 1666 te->sc_state = USER_MODE; 1667 te->stime = (double)now; 1668 te->otime = (double)now; 1669 } 1670 } 1671 } 1672 } 1673 secs = utime_usecs / 1000000; 1674 utime_usecs -= secs * 1000000; 1675 utime_secs += secs; 1676 1677 secs = itime_usecs / 1000000; 1678 itime_usecs -= secs * 1000000; 1679 itime_secs += secs; 1680 1681 secs = delta_itime_usecs / 1000000; 1682 delta_itime_usecs -= secs * 1000000; 1683 delta_itime_secs += secs; 1684 1685 secs = otime_usecs / 1000000; 1686 otime_usecs -= secs * 1000000; 1687 otime_secs += secs; 1688 1689 secs = delta_otime_usecs / 1000000; 1690 delta_otime_usecs -= secs * 1000000; 1691 delta_otime_secs += secs; 1692} 1693 1694void 1695quit(char *s) 1696{ 1697 if (trace_enabled) 1698 set_enable(0); 1699 1700 /* 1701 This flag is turned off when calling 1702 quit() due to a set_remove() failure. 1703 */ 1704 if (set_remove_flag) 1705 set_remove(); 1706 1707 if (no_screen_refresh == 0) { 1708 /* clear for new display */ 1709 erase(); 1710 move(0, 0); 1711 refresh(); 1712 endwin(); 1713 } 1714 1715 printf("sc_usage: "); 1716 if (s) 1717 printf("%s", s); 1718 1719 exit(1); 1720} 1721 1722void getdivisor() 1723{ 1724 mach_timebase_info_data_t info; 1725 1726 (void) mach_timebase_info (&info); 1727 1728 divisor = ( (double)info.denom / (double)info.numer) * 1000; 1729 1730} 1731 1732 1733int 1734argtopid(str) 1735 char *str; 1736{ 1737 char *cp; 1738 int ret; 1739 int i; 1740 1741 if (!kp_buffer) 1742 find_proc_names(); 1743 1744 ret = (int)strtol(str, &cp, 10); 1745 if (cp == str || *cp) { 1746 /* Assume this is a command string and find first matching pid */ 1747 for (i=0; i < kp_nentries; i++) { 1748 if(kp_buffer[i].kp_proc.p_stat == 0) 1749 continue; 1750 else { 1751 if(!strcmp(str, kp_buffer[i].kp_proc.p_comm)) 1752 { 1753 strncpy(proc_name, kp_buffer[i].kp_proc.p_comm, sizeof(proc_name)-1); 1754 proc_name[sizeof(proc_name)-1] = '\0'; 1755 return(kp_buffer[i].kp_proc.p_pid); 1756 } 1757 } 1758 } 1759 } 1760 else 1761 { 1762 for (i=0; i < kp_nentries; i++) 1763 { 1764 if(kp_buffer[i].kp_proc.p_stat == 0) 1765 continue; 1766 else if (kp_buffer[i].kp_proc.p_pid == ret) { 1767 strncpy(proc_name, kp_buffer[i].kp_proc.p_comm, sizeof(proc_name)-1); 1768 proc_name[sizeof(proc_name)-1] = '\0'; 1769 return(kp_buffer[i].kp_proc.p_pid); 1770 } 1771 } 1772 } 1773 return(-1); 1774} 1775 1776 1777/* Returns index into sc_tab for a mach msg entry */ 1778int 1779find_msgcode(int debugid) 1780{ 1781 1782 int indx; 1783 1784 for (indx=0; indx< msgcode_cnt; indx++) 1785 { 1786 if (msgcode_tab[indx] == ((debugid & 0x00ffffff) >>2)) 1787 return (MAX_SC+indx); 1788 } 1789 return (0); 1790} 1791 1792int 1793argtoi(flag, req, str, base) 1794 int flag; 1795 char *req, *str; 1796 int base; 1797{ 1798 char *cp; 1799 int ret; 1800 1801 ret = (int)strtol(str, &cp, base); 1802 if (cp == str || *cp) 1803 errx(EINVAL, "-%c flag requires a %s", flag, req); 1804 return (ret); 1805} 1806 1807