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