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