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