]> git.saurik.com Git - apple/system_cmds.git/blob - sc_usage.tproj/sc_usage.c
965d369ed17dac7bfee2e6f56ff90541e0205aca
[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
43 #include <libc.h>
44 #include <termios.h>
45 #include <curses.h>
46
47 #include <sys/ioctl.h>
48
49 #ifndef KERNEL_PRIVATE
50 #define KERNEL_PRIVATE
51 #include <sys/kdebug.h>
52 #undef KERNEL_PRIVATE
53 #else
54 #include <sys/kdebug.h>
55 #endif /*KERNEL_PRIVATE*/
56
57 #include <sys/sysctl.h>
58 #include <errno.h>
59 #include <mach/mach_time.h>
60 #include <err.h>
61
62
63 /* Number of lines of header information on the standard screen */
64 #define HEADER_LINES 5
65
66 int newLINES = 0;
67 int Header_lines = HEADER_LINES;
68
69 int how_to_sort = 0;
70 int no_screen_refresh = 0;
71 int execute_flag = 0;
72 int topn = 0;
73 int pid;
74 int called = 0;
75 int sort_now = 0;
76 int waiting_index = 0;
77 FILE *dfp = 0; /*Debug output file */
78 long start_time = 0;
79
80 #define SAMPLE_SIZE 20000
81
82 #define DBG_ZERO_FILL_FAULT 1
83 #define DBG_PAGEIN_FAULT 2
84 #define DBG_COW_FAULT 3
85 #define DBG_CACHE_HIT_FAULT 4
86
87 #define MAX_SC 1024
88 #define MAX_THREADS 16
89 #define MAX_NESTED 8
90 #define MAX_FAULTS 5
91
92 /* If NUMPARMS from kernel changes, it will be reflected in PATHLENGTH as well */
93 #define NUMPARMS 23
94 #define PATHLENGTH (NUMPARMS*sizeof(long))
95
96 char *state_name[] = {
97 "Dont Know",
98 "Running S",
99 "Running U",
100 "Waiting",
101 "Pre-empted",
102 };
103
104 #define DONT_KNOW 0
105 #define KERNEL_MODE 1
106 #define USER_MODE 2
107 #define WAITING 3
108 #define PREEMPTED 4
109
110 struct entry {
111 int sc_state;
112 int type;
113 int code;
114 double otime;
115 double stime;
116 double ctime;
117 double wtime;
118 };
119
120 struct th_info {
121 int thread;
122 int depth;
123 int vfslookup;
124 int curpri;
125 long *pathptr;
126 char pathname[PATHLENGTH + 1];
127 struct entry th_entry[MAX_NESTED];
128 };
129
130 struct sc_entry {
131 char name[32];
132 int delta_count;
133 int total_count;
134 int waiting;
135 unsigned int stime_secs;
136 double stime_usecs;
137 unsigned int wtime_secs;
138 double wtime_usecs;
139 unsigned int delta_wtime_secs;
140 double delta_wtime_usecs;
141 };
142
143 struct th_info th_state[MAX_THREADS];
144 struct sc_entry faults[MAX_FAULTS];
145
146 struct sc_entry *sc_tab;
147 int *msgcode_tab;
148 int msgcode_cnt; /* number of MSG_ codes */
149
150 int num_of_threads = 0;
151 int now_collect_cpu_time = 0;
152
153 unsigned int utime_secs;
154 double utime_usecs;
155
156 int in_idle = 0;
157 unsigned int itime_secs;
158 double itime_usecs;
159 unsigned int delta_itime_secs;
160 double delta_itime_usecs;
161 double idle_start;
162
163 int in_other = 0;
164 unsigned int otime_secs;
165 double otime_usecs;
166 unsigned int delta_otime_secs;
167 double delta_otime_usecs;
168 double other_start;
169
170 int max_sc = 0;
171 int bsc_base = 0;
172 int msc_base = 0;
173 int mach_sched = 0;
174 int mach_stkhandoff = 0;
175 int vfs_lookup = 0;
176 int mach_vmfault = 0;
177 int bsc_exit = 0;
178 int *sort_by_count;
179 int *sort_by_wtime;
180
181 char proc_name[32];
182
183 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
184 #define DBG_FUNC_MASK 0xfffffffc
185
186 int preempted;
187 int csw;
188 int total_faults;
189 int scalls;
190
191 /* Default divisor */
192 #define DIVISOR 16.6666 /* Trace divisor converts to microseconds */
193 double divisor = DIVISOR;
194
195
196 int mib[6];
197 size_t needed;
198 char *my_buffer;
199
200 kbufinfo_t bufinfo = {0, 0, 0, 0};
201
202 int trace_enabled = 0;
203 int set_remove_flag = 1;
204
205 struct kinfo_proc *kp_buffer = 0;
206 int kp_nentries = 0;
207
208 extern char **environ;
209
210 void set_enable();
211 void set_pidcheck();
212 void set_remove();
213 void set_numbufs();
214 void set_init();
215
216
217 /*
218 * signal handlers
219 */
220
221 void leave() /* exit under normal conditions -- INT handler */
222 {
223
224 if (no_screen_refresh == 0) {
225 move(LINES - 1, 0);
226 refresh();
227 endwin();
228 }
229 set_enable(0);
230 set_pidcheck(pid, 0);
231 set_remove();
232 exit(0);
233 }
234
235 void err_leave(s) /* exit under error conditions */
236 char *s;
237 {
238
239 if (no_screen_refresh == 0) {
240 move(LINES - 1, 0);
241 refresh();
242 endwin();
243 }
244
245 printf("sc_usage: ");
246 if (s)
247 printf("%s ", s);
248
249 set_enable(0);
250 set_pidcheck(pid, 0);
251 set_remove();
252
253 exit(1);
254 }
255
256 void sigwinch()
257 {
258 if (no_screen_refresh == 0)
259 newLINES = 1;
260 }
261
262 int
263 exit_usage(myname) {
264
265 fprintf(stderr, "Usage: %s [-c codefile] [-e] [-l] [-sn] pid | cmd | -E execute path\n", myname);
266 fprintf(stderr, " -c name of codefile containing mappings for syscalls\n");
267 fprintf(stderr, " Default is /usr/share/misc/trace.codes\n");
268 fprintf(stderr, " -e enable sort by call count\n");
269 fprintf(stderr, " -l turn off top style output\n");
270 fprintf(stderr, " -sn change sample rate to every n seconds\n");
271 fprintf(stderr, " pid selects process to sample\n");
272 fprintf(stderr, " cmd selects command to sample\n");
273 fprintf(stderr, " -E Execute the given path and optional arguments\n");
274
275 exit(1);
276 }
277
278
279 #define usec_to_1000ths(t) ((t) / 1000)
280
281 void print_time(char *p, unsigned int useconds, unsigned int seconds)
282 {
283 long minutes, hours;
284
285 minutes = seconds / 60;
286 hours = minutes / 60;
287
288 if (minutes < 100) { // up to 100 minutes
289 sprintf(p, "%2ld:%02ld.%03ld", minutes, seconds % 60,
290 usec_to_1000ths(useconds));
291 }
292 else if (hours < 100) { // up to 100 hours
293 sprintf(p, "%2ld:%02ld:%02ld ", hours, minutes % 60,
294 seconds % 60);
295 }
296 else {
297 sprintf(p, "%4ld hrs ", hours);
298 }
299 }
300
301
302 main(argc, argv)
303 int argc;
304 char *argv[];
305 {
306 char *myname = "sc_usage";
307 char *codefile = "/usr/share/misc/trace.codes";
308 char ch;
309 char *ptr;
310 int delay = Default_DELAY;
311 int length;
312 void screen_update();
313 void sort_scalls();
314 void sc_tab_init();
315 void getdivisor();
316 void reset_counters();
317 int argtopid();
318 int argtoi();
319 int quit();
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,0,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, 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 int cnt;
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 hours, minutes % 60, 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 int quit();
984
985 if ((fp = fopen(codefile,"r")) == (FILE *)0) {
986 printf("Failed to open code description file %s\n", codefile);
987 exit(1);
988 }
989
990 n = fscanf(fp, "%d\n", &cnt);
991 if (n != 1)
992 return;
993
994 /* Count Mach message MSG_ codes */
995 for (msgcode_cnt=0;;) {
996 n = fscanf(fp, "%x%s\n", &code, &name[0]);
997 if (n != 2)
998 break;
999 if (strncmp ("MSG_", &name[0], 4) == 0)
1000 msgcode_cnt++;
1001 if (strcmp("USER_TEST", &name[0]) == 0)
1002 break;
1003 }
1004
1005 sc_tab = (struct sc_entry *)malloc((MAX_SC+msgcode_cnt) * sizeof (struct sc_entry));
1006 if(!sc_tab)
1007 quit("can't allocate memory for system call table\n");
1008 bzero(sc_tab,(MAX_SC+msgcode_cnt) * sizeof (struct sc_entry));
1009
1010 msgcode_tab = (int *)malloc(msgcode_cnt * sizeof(int));
1011 if (!msgcode_tab)
1012 quit("can't allocate memory for msgcode table\n");
1013 bzero(msgcode_tab,(msgcode_cnt * sizeof(int)));
1014
1015 sort_by_count = (int *)malloc((MAX_SC + msgcode_cnt + 1) * sizeof(int));
1016 if (!sort_by_count)
1017 quit("can't allocate memory for sort_by_count table\n");
1018 bzero(sort_by_count,(MAX_SC + msgcode_cnt + 1) * sizeof(int));
1019
1020 sort_by_wtime = (int *)malloc((MAX_SC + msgcode_cnt + 1) * sizeof(int));
1021 if (!sort_by_wtime)
1022 quit("can't allocate memory for sort_by_wtime table\n");
1023 bzero(sort_by_wtime, (MAX_SC + msgcode_cnt + 1) * sizeof(int));
1024
1025
1026 rewind(fp);
1027
1028 n = fscanf(fp, "%d\n", &cnt);
1029
1030 if (n != 1)
1031 return;
1032
1033 for (;;) {
1034 n = fscanf(fp, "%x%s\n", &code, &name[0]);
1035
1036 if (n != 2)
1037 break;
1038
1039 if (strcmp("MACH_vmfault", &name[0]) == 0) {
1040 mach_vmfault = code;
1041 continue;
1042 }
1043 if (strcmp("MACH_SCHED", &name[0]) == 0) {
1044 mach_sched = code;
1045 continue;
1046 }
1047 if (strcmp("MACH_STKHANDOFF", &name[0]) == 0) {
1048 mach_stkhandoff = code;
1049 continue;
1050 }
1051 if (strcmp("VFS_LOOKUP", &name[0]) == 0) {
1052 vfs_lookup = code;
1053 continue;
1054 }
1055 if (strcmp("BSC_SysCall", &name[0]) == 0) {
1056 bsc_base = code;
1057 continue;
1058 }
1059 if (strcmp("MACH_SysCall", &name[0]) == 0) {
1060 msc_base = code;
1061 continue;
1062 }
1063 if (strcmp("BSC_exit", &name[0]) == 0) {
1064 bsc_exit = code;
1065 continue;
1066 }
1067 if (strncmp("MSG_", &name[0], 4) == 0) {
1068 msgcode_tab[msgcode_indx] = ((code & 0x00ffffff) >>2);
1069 n = MAX_SC + msgcode_indx;
1070 strncpy(&sc_tab[n].name[0], &name[4], 31 );
1071 msgcode_indx++;
1072 continue;
1073 }
1074 if (strncmp("MSC_", &name[0], 4) == 0) {
1075 n = 512 + ((code>>2) & 0x1ff);
1076 strcpy(&sc_tab[n].name[0], &name[4]);
1077 continue;
1078 }
1079 if (strncmp("BSC_", &name[0], 4) == 0) {
1080 n = (code>>2) & 0x1ff;
1081 strcpy(&sc_tab[n].name[0], &name[4]);
1082 continue;
1083 }
1084 if (strcmp("USER_TEST", &name[0]) == 0)
1085 break;
1086 }
1087 strcpy(&faults[1].name[0], "zero_fill");
1088 strcpy(&faults[2].name[0], "pagein");
1089 strcpy(&faults[3].name[0], "copy_on_write");
1090 strcpy(&faults[4].name[0], "cache_hit");
1091 }
1092
1093 void
1094 find_proc_names()
1095 {
1096 size_t bufSize = 0;
1097 struct kinfo_proc *kp;
1098
1099 mib[0] = CTL_KERN;
1100 mib[1] = KERN_PROC;
1101 mib[2] = KERN_PROC_ALL;
1102 mib[3] = 0;
1103
1104 if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0)
1105 quit("trace facility failure, KERN_PROC_ALL\n");
1106
1107 if((kp = (struct kinfo_proc *)malloc(bufSize)) == (struct kinfo_proc *)0)
1108 quit("can't allocate memory for proc buffer\n");
1109
1110 if (sysctl(mib, 4, kp, &bufSize, NULL, 0) < 0)
1111 quit("trace facility failure, KERN_PROC_ALL\n");
1112
1113 kp_nentries = bufSize/ sizeof(struct kinfo_proc);
1114 kp_buffer = kp;
1115 }
1116
1117 struct th_info *find_thread(int thread) {
1118 struct th_info *ti;
1119
1120 for (ti = th_state; ti < &th_state[MAX_THREADS]; ti++) {
1121 if (ti->thread == thread)
1122 return(ti);
1123 }
1124 return ((struct th_info *)0);
1125 }
1126
1127
1128 int
1129 cmp_wtime(struct sc_entry *s1, struct sc_entry *s2) {
1130
1131 if (s1->wtime_secs < s2->wtime_secs)
1132 return 0;
1133 if (s1->wtime_secs > s2->wtime_secs)
1134 return 1;
1135 if (s1->wtime_usecs <= s2->wtime_usecs)
1136 return 0;
1137 return 1;
1138 }
1139
1140
1141 void
1142 sort_scalls() {
1143 int i, n, k, cnt, secs;
1144 struct th_info *ti;
1145 struct sc_entry *se;
1146 struct entry *te;
1147 uint64_t now;
1148
1149 now = mach_absolute_time();
1150
1151 for (ti = th_state; ti < &th_state[MAX_THREADS]; ti++) {
1152 if (ti->thread == 0)
1153 continue;
1154
1155 if (ti->depth) {
1156 te = &ti->th_entry[ti->depth-1];
1157
1158 if (te->sc_state == WAITING) {
1159 if (te->code)
1160 se = &sc_tab[te->code];
1161 else
1162 se = &faults[DBG_PAGEIN_FAULT];
1163 se->waiting++;
1164 se->wtime_usecs += ((double)now - te->stime) / divisor;
1165 se->delta_wtime_usecs += ((double)now - te->stime) / divisor;
1166 te->stime = (double)now;
1167
1168 secs = se->wtime_usecs / 1000000;
1169 se->wtime_usecs -= secs * 1000000;
1170 se->wtime_secs += secs;
1171
1172 secs = se->delta_wtime_usecs / 1000000;
1173 se->delta_wtime_usecs -= secs * 1000000;
1174 se->delta_wtime_secs += secs;
1175 }
1176 } else {
1177 te = &ti->th_entry[0];
1178
1179 if (te->sc_state == PREEMPTED) {
1180 if ((unsigned long)(((double)now - te->otime) / divisor) > 5000000) {
1181 ti->thread = 0;
1182 ti->vfslookup = 0;
1183 ti->pathptr = (long *)0;
1184 ti->pathname[0] = 0;
1185 num_of_threads--;
1186 }
1187 }
1188 }
1189 }
1190 if ((called % sort_now) == 0) {
1191 sort_by_count[0] = -1;
1192 sort_by_wtime[0] = -1;
1193 for (cnt = 1, n = 1; n < (MAX_SC + msgcode_cnt); n++) {
1194 if (sc_tab[n].total_count) {
1195 for (i = 0; i < cnt; i++) {
1196 if ((k = sort_by_count[i]) == -1 ||
1197 sc_tab[n].total_count > sc_tab[k].total_count) {
1198
1199 for (k = cnt - 1; k >= i; k--)
1200 sort_by_count[k+1] = sort_by_count[k];
1201 sort_by_count[i] = n;
1202 break;
1203 }
1204 }
1205 if (how_to_sort == 0) {
1206 for (i = 0; i < cnt; i++) {
1207 if ((k = sort_by_wtime[i]) == -1 ||
1208 cmp_wtime(&sc_tab[n], &sc_tab[k])) {
1209
1210 for (k = cnt - 1; k >= i; k--)
1211 sort_by_wtime[k+1] = sort_by_wtime[k];
1212 sort_by_wtime[i] = n;
1213 break;
1214 }
1215 }
1216 }
1217 cnt++;
1218 }
1219 }
1220 }
1221 called++;
1222 }
1223
1224 void
1225 set_enable(int val)
1226 {
1227 mib[0] = CTL_KERN;
1228 mib[1] = KERN_KDEBUG;
1229 mib[2] = KERN_KDENABLE; /* protocol */
1230 mib[3] = val;
1231 mib[4] = 0;
1232 mib[5] = 0; /* no flags */
1233 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
1234 quit("trace facility failure, KERN_KDENABLE\n");
1235
1236 if (val)
1237 trace_enabled = 1;
1238 else
1239 trace_enabled = 0;
1240 }
1241
1242 void
1243 set_numbufs(int nbufs)
1244 {
1245 mib[0] = CTL_KERN;
1246 mib[1] = KERN_KDEBUG;
1247 mib[2] = KERN_KDSETBUF;
1248 mib[3] = nbufs;
1249 mib[4] = 0;
1250 mib[5] = 0; /* no flags */
1251 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
1252 quit("trace facility failure, KERN_KDSETBUF\n");
1253
1254 mib[0] = CTL_KERN;
1255 mib[1] = KERN_KDEBUG;
1256 mib[2] = KERN_KDSETUP;
1257 mib[3] = 0;
1258 mib[4] = 0;
1259 mib[5] = 0; /* no flags */
1260 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
1261 quit("trace facility failure, KERN_KDSETUP\n");
1262
1263 }
1264
1265 void
1266 set_pidcheck(int pid, int on_off)
1267 {
1268 kd_regtype kr;
1269
1270 kr.type = KDBG_TYPENONE;
1271 kr.value1 = pid;
1272 kr.value2 = on_off;
1273 needed = sizeof(kd_regtype);
1274 mib[0] = CTL_KERN;
1275 mib[1] = KERN_KDEBUG;
1276 mib[2] = KERN_KDPIDTR;
1277 mib[3] = 0;
1278 mib[4] = 0;
1279 mib[5] = 0;
1280 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) {
1281 if (on_off == 1) {
1282 printf("pid %d does not exist\n", pid);
1283 set_remove();
1284 exit(2);
1285 }
1286 }
1287 }
1288
1289 void
1290 get_bufinfo(kbufinfo_t *val)
1291 {
1292 needed = sizeof (*val);
1293 mib[0] = CTL_KERN;
1294 mib[1] = KERN_KDEBUG;
1295 mib[2] = KERN_KDGETBUF;
1296 mib[3] = 0;
1297 mib[4] = 0;
1298 mib[5] = 0; /* no flags */
1299 if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
1300 quit("trace facility failure, KERN_KDGETBUF\n");
1301
1302 }
1303
1304 void
1305 set_remove()
1306 {
1307 extern int errno;
1308
1309 errno = 0;
1310
1311 mib[0] = CTL_KERN;
1312 mib[1] = KERN_KDEBUG;
1313 mib[2] = KERN_KDREMOVE; /* protocol */
1314 mib[3] = 0;
1315 mib[4] = 0;
1316 mib[5] = 0; /* no flags */
1317
1318 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
1319 {
1320 set_remove_flag = 0;
1321
1322 if (errno == EBUSY)
1323 quit("the trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n");
1324 else
1325 quit("trace facility failure, KERN_KDREMOVE\n");
1326 }
1327 }
1328
1329 void
1330 set_init()
1331 { kd_regtype kr;
1332
1333 kr.type = KDBG_RANGETYPE;
1334 kr.value1 = 0;
1335 kr.value2 = -1;
1336 needed = sizeof(kd_regtype);
1337 mib[0] = CTL_KERN;
1338 mib[1] = KERN_KDEBUG;
1339 mib[2] = KERN_KDSETREG;
1340 mib[3] = 0;
1341 mib[4] = 0;
1342 mib[5] = 0; /* no flags */
1343 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
1344 quit("trace facility failure, KERN_KDSETREG\n");
1345
1346 mib[0] = CTL_KERN;
1347 mib[1] = KERN_KDEBUG;
1348 mib[2] = KERN_KDSETUP;
1349 mib[3] = 0;
1350 mib[4] = 0;
1351 mib[5] = 0; /* no flags */
1352 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
1353 quit("trace facility failure, KERN_KDSETUP\n");
1354
1355 }
1356
1357 void
1358 sample_sc()
1359 {
1360 kd_buf *kd;
1361 int i, count;
1362 int secs;
1363 int find_msgcode();
1364
1365 /* Get kernel buffer information */
1366 get_bufinfo(&bufinfo);
1367 #ifdef OLD_KDEBUG
1368 set_enable(0);
1369 #endif
1370 needed = bufinfo.nkdbufs * sizeof(kd_buf);
1371 mib[0] = CTL_KERN;
1372 mib[1] = KERN_KDEBUG;
1373 mib[2] = KERN_KDREADTR;
1374 mib[3] = 0;
1375 mib[4] = 0;
1376 mib[5] = 0; /* no flags */
1377 if (sysctl(mib, 3, my_buffer, &needed, NULL, 0) < 0)
1378 quit("trace facility failure, KERN_KDREADTR\n");
1379 count = needed;
1380
1381 if (bufinfo.flags & KDBG_WRAPPED) {
1382 for (i = 0; i < MAX_THREADS; i++) {
1383 th_state[i].depth = 0;
1384 th_state[i].thread = 0;
1385 th_state[i].vfslookup = 0;
1386 th_state[i].pathptr = (long *)0;
1387 th_state[i].pathname[0] = 0;
1388 }
1389 num_of_threads = 0;
1390 }
1391 #ifdef OLD_KDEBUG
1392 set_remove();
1393 set_init();
1394 set_pidcheck(pid, 1);
1395 set_enable(1); /* re-enable kernel logging */
1396 #endif
1397 kd = (kd_buf *)my_buffer;
1398
1399 for (i = 0; i < count; i++) {
1400 int debugid, baseid, thread;
1401 int type, code;
1402 uint64_t now;
1403 struct th_info *ti, *switched_out, *switched_in;
1404 struct sc_entry *se;
1405 struct entry *te;
1406
1407 thread = kd[i].arg5 & KDBG_THREAD_MASK;
1408 debugid = kd[i].debugid;
1409 type = kd[i].debugid & DBG_FUNC_MASK;
1410
1411 code = 0;
1412 switched_out = (struct th_info *)0;
1413 switched_in = (struct th_info *)0;
1414
1415 now = (((uint64_t)kd[i].timestamp.tv_sec) << 32) |
1416 (uint64_t)((unsigned int)(kd[i].timestamp.tv_nsec));
1417 baseid = debugid & 0xffff0000;
1418
1419 if (type == vfs_lookup) {
1420 long *sargptr;
1421
1422 if ((ti = find_thread(thread)) == (struct th_info *)0)
1423 continue;
1424
1425 if (ti->vfslookup == 1) {
1426 ti->vfslookup++;
1427 memset(&ti->pathname[0], 0, (PATHLENGTH + 1));
1428 sargptr = (long *)&ti->pathname[0];
1429
1430 *sargptr++ = kd[i].arg2;
1431 *sargptr++ = kd[i].arg3;
1432 *sargptr++ = kd[i].arg4;
1433 ti->pathptr = sargptr;
1434
1435 } else if (ti->vfslookup > 1) {
1436 ti->vfslookup++;
1437 sargptr = ti->pathptr;
1438
1439 /*
1440 We don't want to overrun our pathname buffer if the
1441 kernel sends us more VFS_LOOKUP entries than we can
1442 handle.
1443 */
1444
1445 if ((long *)sargptr >= (long *)&ti->pathname[PATHLENGTH])
1446 continue;
1447
1448 /*
1449 We need to detect consecutive vfslookup entries.
1450 So, if we get here and find a START entry,
1451 fake the pathptr so we can bypass all further
1452 vfslookup entries.
1453 */
1454
1455 if (debugid & DBG_FUNC_START)
1456 {
1457 (long *)ti->pathptr = (long *)&ti->pathname[PATHLENGTH];
1458 continue;
1459 }
1460
1461 *sargptr++ = kd[i].arg1;
1462 *sargptr++ = kd[i].arg2;
1463 *sargptr++ = kd[i].arg3;
1464 *sargptr++ = kd[i].arg4;
1465 ti->pathptr = sargptr;
1466 }
1467 continue;
1468
1469 } else if (baseid == bsc_base)
1470 code = (debugid >> 2) & 0x1ff;
1471 else if (baseid == msc_base)
1472 code = 512 + ((debugid >> 2) & 0x1ff);
1473 else if (baseid == mach_sched || baseid == mach_stkhandoff) {
1474 switched_out = find_thread(kd[i].arg1);
1475 switched_in = find_thread(kd[i].arg2);
1476
1477 if (in_idle) {
1478 itime_usecs += ((double)now - idle_start) / divisor;
1479 delta_itime_usecs += ((double)now - idle_start) / divisor;
1480 in_idle = 0;
1481 } else if (in_other) {
1482 otime_usecs += ((double)now - other_start) / divisor;
1483 delta_otime_usecs += ((double)now - other_start) / divisor;
1484 in_other = 0;
1485 }
1486 if ( !switched_in) {
1487 /*
1488 * not one of the target proc's threads
1489 */
1490 if (now_collect_cpu_time) {
1491 if (kd[i].arg4 == 0) {
1492 in_idle = 1;
1493 idle_start = (double)now;
1494 } else {
1495 in_other = 1;
1496 other_start = (double)now;
1497 }
1498 }
1499 }
1500 if ( !switched_in && !switched_out)
1501 continue;
1502
1503 }
1504 else if ((baseid & 0xff000000) == 0xff000000) {
1505 code = find_msgcode (debugid);
1506 if (!code)
1507 continue;
1508 } else if (baseid != mach_vmfault)
1509 continue;
1510
1511 if (switched_out || switched_in) {
1512 if (switched_out) {
1513 ti = switched_out;
1514 ti->curpri = kd[i].arg3;
1515
1516 if (ti->depth) {
1517 te = &ti->th_entry[ti->depth-1];
1518
1519 if (te->sc_state == KERNEL_MODE)
1520 te->ctime += (double)now - te->stime;
1521 te->sc_state = WAITING;
1522
1523 ti->vfslookup = 1;
1524
1525 } else {
1526 te = &ti->th_entry[0];
1527
1528 if (te->sc_state == USER_MODE)
1529 utime_usecs += ((double)now - te->stime) / divisor;
1530 te->sc_state = PREEMPTED;
1531 preempted++;
1532 }
1533 te->stime = (double)now;
1534 te->otime = (double)now;
1535 now_collect_cpu_time = 1;
1536 csw++;
1537 }
1538 if (switched_in) {
1539 ti = switched_in;
1540 ti->curpri = kd[i].arg4;
1541
1542 if (ti->depth) {
1543 te = &ti->th_entry[ti->depth-1];
1544
1545 if (te->sc_state == WAITING)
1546 te->wtime += (double)now - te->stime;
1547 te->sc_state = KERNEL_MODE;
1548 } else {
1549 te = &ti->th_entry[0];
1550
1551 te->sc_state = USER_MODE;
1552 }
1553 te->stime = (double)now;
1554 te->otime = (double)now;
1555 }
1556 continue;
1557 }
1558 if ((ti = find_thread(thread)) == (struct th_info *)0) {
1559 for (ti = &th_state[0]; ti < &th_state[MAX_THREADS]; ti++) {
1560 if (ti->thread == 0) {
1561 ti->thread = thread;
1562 num_of_threads++;
1563 break;
1564 }
1565 }
1566 if (ti == &th_state[MAX_THREADS])
1567 continue;
1568 }
1569 if (debugid & DBG_FUNC_START) {
1570 ti->vfslookup = 0;
1571
1572 if (ti->depth) {
1573 te = &ti->th_entry[ti->depth-1];
1574
1575 if (te->sc_state == KERNEL_MODE)
1576 te->ctime += (double)now - te->stime;
1577 } else {
1578 te = &ti->th_entry[0];
1579
1580 if (te->sc_state == USER_MODE)
1581 utime_usecs += ((double)now - te->stime) / divisor;
1582 }
1583 te->stime = (double)now;
1584 te->otime = (double)now;
1585
1586 if (ti->depth < MAX_NESTED) {
1587 te = &ti->th_entry[ti->depth];
1588
1589 te->sc_state = KERNEL_MODE;
1590 te->type = type;
1591 te->code = code;
1592 te->stime = (double)now;
1593 te->otime = (double)now;
1594 te->ctime = (double)0;
1595 te->wtime = (double)0;
1596 ti->depth++;
1597 }
1598
1599 } else if (debugid & DBG_FUNC_END) {
1600 if (code) {
1601 se = &sc_tab[code];
1602 scalls++;
1603 } else {
1604 se = &faults[kd[i].arg2];
1605 total_faults++;
1606 }
1607 if (se->total_count == 0)
1608 called = 0;
1609 se->delta_count++;
1610 se->total_count++;
1611
1612 while (ti->depth) {
1613 te = &ti->th_entry[ti->depth-1];
1614
1615 if (te->type == type) {
1616 se->stime_usecs += te->ctime / divisor;
1617 se->stime_usecs += ((double)now - te->stime) / divisor;
1618
1619 se->wtime_usecs += te->wtime / divisor;
1620 se->delta_wtime_usecs += te->wtime / divisor;
1621
1622 secs = se->stime_usecs / 1000000;
1623 se->stime_usecs -= secs * 1000000;
1624 se->stime_secs += secs;
1625
1626 secs = se->wtime_usecs / 1000000;
1627 se->wtime_usecs -= secs * 1000000;
1628 se->wtime_secs += secs;
1629
1630 secs = se->delta_wtime_usecs / 1000000;
1631 se->delta_wtime_usecs -= secs * 1000000;
1632 se->delta_wtime_secs += secs;
1633
1634 ti->depth--;
1635
1636 if (ti->depth == 0) {
1637 /*
1638 * headed back to user mode
1639 * start the time accumulation
1640 */
1641 te = &ti->th_entry[0];
1642 te->sc_state = USER_MODE;
1643 } else
1644 te = &ti->th_entry[ti->depth-1];
1645
1646 te->stime = (double)now;
1647 te->otime = (double)now;
1648
1649 break;
1650 }
1651 ti->depth--;
1652
1653 if (ti->depth == 0) {
1654 /*
1655 * headed back to user mode
1656 * start the time accumulation
1657 */
1658 te = &ti->th_entry[0];
1659 te->sc_state = USER_MODE;
1660 te->stime = (double)now;
1661 te->otime = (double)now;
1662 }
1663 }
1664 }
1665 }
1666 secs = utime_usecs / 1000000;
1667 utime_usecs -= secs * 1000000;
1668 utime_secs += secs;
1669
1670 secs = itime_usecs / 1000000;
1671 itime_usecs -= secs * 1000000;
1672 itime_secs += secs;
1673
1674 secs = delta_itime_usecs / 1000000;
1675 delta_itime_usecs -= secs * 1000000;
1676 delta_itime_secs += secs;
1677
1678 secs = otime_usecs / 1000000;
1679 otime_usecs -= secs * 1000000;
1680 otime_secs += secs;
1681
1682 secs = delta_otime_usecs / 1000000;
1683 delta_otime_usecs -= secs * 1000000;
1684 delta_otime_secs += secs;
1685 }
1686
1687
1688 quit(s)
1689 char *s;
1690 {
1691 if (trace_enabled)
1692 set_enable(0);
1693
1694 /*
1695 This flag is turned off when calling
1696 quit() due to a set_remove() failure.
1697 */
1698 if (set_remove_flag)
1699 set_remove();
1700
1701 printf("sc_usage: ");
1702 if (s)
1703 printf("%s ", s);
1704
1705 exit(1);
1706 }
1707
1708 void getdivisor()
1709 {
1710 mach_timebase_info_data_t info;
1711
1712 (void) mach_timebase_info (&info);
1713
1714 divisor = ( (double)info.denom / (double)info.numer) * 1000;
1715
1716 }
1717
1718
1719 argtopid(str)
1720 char *str;
1721 {
1722 char *cp;
1723 int ret;
1724 int i;
1725
1726 if (!kp_buffer)
1727 find_proc_names();
1728
1729 ret = (int)strtol(str, &cp, 10);
1730 if (cp == str || *cp) {
1731 /* Assume this is a command string and find first matching pid */
1732 for (i=0; i < kp_nentries; i++) {
1733 if(kp_buffer[i].kp_proc.p_stat == 0)
1734 continue;
1735 else {
1736 if(!strcmp(str, kp_buffer[i].kp_proc.p_comm))
1737 {
1738 strncpy(proc_name, kp_buffer[i].kp_proc.p_comm, sizeof(proc_name)-1);
1739 proc_name[sizeof(proc_name)-1] = '\0';
1740 return(kp_buffer[i].kp_proc.p_pid);
1741 }
1742 }
1743 }
1744 }
1745 else
1746 {
1747 for (i=0; i < kp_nentries; i++)
1748 {
1749 if(kp_buffer[i].kp_proc.p_stat == 0)
1750 continue;
1751 else if (kp_buffer[i].kp_proc.p_pid == ret) {
1752 strncpy(proc_name, kp_buffer[i].kp_proc.p_comm, sizeof(proc_name)-1);
1753 proc_name[sizeof(proc_name)-1] = '\0';
1754 return(kp_buffer[i].kp_proc.p_pid);
1755 }
1756 }
1757 }
1758 return(-1);
1759 }
1760
1761
1762 /* Returns index into sc_tab for a mach msg entry */
1763 int
1764 find_msgcode(int debugid)
1765 {
1766
1767 int indx;
1768
1769 for (indx=0; indx< msgcode_cnt; indx++)
1770 {
1771 if (msgcode_tab[indx] == ((debugid & 0x00ffffff) >>2))
1772 return (MAX_SC+indx);
1773 }
1774 return (0);
1775 }
1776
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