]> git.saurik.com Git - apple/system_cmds.git/blob - sc_usage.tproj/sc_usage.c
system_cmds-433.8.tar.gz
[apple/system_cmds.git] / sc_usage.tproj / sc_usage.c
1 /*
2 * Copyright (c) 1999-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 /*
26 cc -I. -DPRIVATE -D__APPLE_PRIVATE -O -o sc_usage sc_usage.c -lncurses
27 */
28
29 #define Default_DELAY 1 /* default delay interval */
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <signal.h>
34 #include <strings.h>
35 #include <nlist.h>
36 #include <fcntl.h>
37 #include <string.h>
38
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/time.h>
42 #include <sys/ptrace.h>
43
44 #include <libc.h>
45 #include <termios.h>
46 #include <curses.h>
47
48 #include <sys/ioctl.h>
49
50 #ifndef KERNEL_PRIVATE
51 #define KERNEL_PRIVATE
52 #include <sys/kdebug.h>
53 #undef KERNEL_PRIVATE
54 #else
55 #include <sys/kdebug.h>
56 #endif /*KERNEL_PRIVATE*/
57
58 #include <sys/sysctl.h>
59 #include <errno.h>
60 #include <mach/mach_time.h>
61 #include <err.h>
62
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
94 #define NUMPARMS 23
95
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 long pathname[NUMPARMS + 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_idle = 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 char *p;
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 p = (char *)ti->pathname;
875
876 plen = strlen(p);
877 if (plen > 34)
878 plen -= 34;
879 else
880 plen = 0;
881 sprintf(&tbuf[clen], " %-34.34s ", &p[plen]);
882
883 clen += strlen(&tbuf[clen]);
884
885 time_usecs = (unsigned long)(((double)now - te->otime) / divisor);
886 secs = time_usecs / 1000000;
887 time_usecs -= secs * 1000000;
888 time_secs = secs;
889
890 print_time(&tbuf[clen], time_usecs, time_secs);
891 clen += strlen(&tbuf[clen]);
892 sprintf(&tbuf[clen], " %2d %3d\n", i, ti->curpri);
893
894 if (tbuf[COLS-2] != '\n') {
895 tbuf[COLS-1] = '\n';
896 tbuf[COLS] = 0;
897 }
898 if (no_screen_refresh)
899 printf("%s", tbuf);
900 else
901 printw(tbuf);
902 }
903 if (no_screen_refresh == 0) {
904 move(0, 0);
905 refresh();
906 } else
907 printf("\n=================\n");
908
909
910
911 for (i = 0; i < (MAX_SC + msgcode_cnt); i++) {
912 if ((n = sort_by_count[i]) == -1)
913 break;
914 sc_tab[n].delta_count = 0;
915 sc_tab[n].waiting = 0;
916 sc_tab[n].delta_wtime_usecs = 0;
917 sc_tab[n].delta_wtime_secs = 0;
918 }
919 for (i = 1; i < MAX_FAULTS; i++) {
920 faults[i].delta_count = 0;
921 faults[i].waiting = 0;
922 faults[i].delta_wtime_usecs = 0;
923 faults[i].delta_wtime_secs = 0;
924 }
925 preempted = 0;
926 csw = 0;
927 total_faults = 0;
928 scalls = 0;
929 delta_itime_secs = 0;
930 delta_itime_usecs = 0;
931 delta_otime_secs = 0;
932 delta_otime_usecs = 0;
933 }
934
935 void
936 reset_counters() {
937 int i;
938
939 for (i = 0; i < (MAX_SC + msgcode_cnt) ; i++) {
940 sc_tab[i].delta_count = 0;
941 sc_tab[i].total_count = 0;
942 sc_tab[i].waiting = 0;
943 sc_tab[i].delta_wtime_usecs = 0;
944 sc_tab[i].delta_wtime_secs = 0;
945 sc_tab[i].wtime_usecs = 0;
946 sc_tab[i].wtime_secs = 0;
947 sc_tab[i].stime_usecs = 0;
948 sc_tab[i].stime_secs = 0;
949 }
950 for (i = 1; i < MAX_FAULTS; i++) {
951 faults[i].delta_count = 0;
952 faults[i].total_count = 0;
953 faults[i].waiting = 0;
954 faults[i].delta_wtime_usecs = 0;
955 faults[i].delta_wtime_secs = 0;
956 faults[i].wtime_usecs = 0;
957 faults[i].wtime_secs = 0;
958 faults[i].stime_usecs = 0;
959 faults[i].stime_secs = 0;
960 }
961 preempted = 0;
962 csw = 0;
963 total_faults = 0;
964 scalls = 0;
965 called = 0;
966
967 utime_secs = 0;
968 utime_usecs = 0;
969 itime_secs = 0;
970 itime_usecs = 0;
971 delta_itime_secs = 0;
972 delta_itime_usecs = 0;
973 otime_secs = 0;
974 otime_usecs = 0;
975 delta_otime_secs = 0;
976 delta_otime_usecs = 0;
977 }
978
979 void
980 sc_tab_init(char *codefile) {
981 int code;
982 int n, cnt;
983 int msgcode_indx=0;
984 char name[56];
985 FILE *fp;
986
987 if ((fp = fopen(codefile,"r")) == (FILE *)0) {
988 printf("Failed to open code description file %s\n", codefile);
989 exit(1);
990 }
991
992 n = fscanf(fp, "%d\n", &cnt);
993 if (n != 1)
994 return;
995
996 /* Count Mach message MSG_ codes */
997 for (msgcode_cnt=0;;) {
998 n = fscanf(fp, "%x%55s\n", &code, &name[0]);
999 if (n != 2)
1000 break;
1001 if (strncmp ("MSG_", &name[0], 4) == 0)
1002 msgcode_cnt++;
1003 if (strcmp("USER_TEST", &name[0]) == 0)
1004 break;
1005 }
1006
1007 sc_tab = (struct sc_entry *)malloc((MAX_SC+msgcode_cnt) * sizeof (struct sc_entry));
1008 if(!sc_tab)
1009 quit("can't allocate memory for system call table\n");
1010 bzero(sc_tab,(MAX_SC+msgcode_cnt) * sizeof (struct sc_entry));
1011
1012 msgcode_tab = (int *)malloc(msgcode_cnt * sizeof(int));
1013 if (!msgcode_tab)
1014 quit("can't allocate memory for msgcode table\n");
1015 bzero(msgcode_tab,(msgcode_cnt * sizeof(int)));
1016
1017 sort_by_count = (int *)malloc((MAX_SC + msgcode_cnt + 1) * sizeof(int));
1018 if (!sort_by_count)
1019 quit("can't allocate memory for sort_by_count table\n");
1020 bzero(sort_by_count,(MAX_SC + msgcode_cnt + 1) * sizeof(int));
1021
1022 sort_by_wtime = (int *)malloc((MAX_SC + msgcode_cnt + 1) * sizeof(int));
1023 if (!sort_by_wtime)
1024 quit("can't allocate memory for sort_by_wtime table\n");
1025 bzero(sort_by_wtime, (MAX_SC + msgcode_cnt + 1) * sizeof(int));
1026
1027
1028 rewind(fp);
1029
1030 n = fscanf(fp, "%d\n", &cnt);
1031
1032 if (n != 1)
1033 return;
1034
1035 for (;;) {
1036 n = fscanf(fp, "%x%55s\n", &code, &name[0]);
1037
1038 if (n != 2)
1039 break;
1040
1041 if (strcmp("MACH_vmfault", &name[0]) == 0) {
1042 mach_vmfault = code;
1043 continue;
1044 }
1045 if (strcmp("MACH_SCHED", &name[0]) == 0) {
1046 mach_sched = code;
1047 continue;
1048 }
1049 if (strcmp("MACH_STKHANDOFF", &name[0]) == 0) {
1050 mach_stkhandoff = code;
1051 continue;
1052 }
1053 if (strcmp("MACH_IDLE", &name[0]) == 0) {
1054 mach_idle = code;
1055 continue;
1056 }
1057 if (strcmp("VFS_LOOKUP", &name[0]) == 0) {
1058 vfs_lookup = code;
1059 continue;
1060 }
1061 if (strcmp("BSC_SysCall", &name[0]) == 0) {
1062 bsc_base = code;
1063 continue;
1064 }
1065 if (strcmp("MACH_SysCall", &name[0]) == 0) {
1066 msc_base = code;
1067 continue;
1068 }
1069 if (strcmp("BSC_exit", &name[0]) == 0) {
1070 bsc_exit = code;
1071 continue;
1072 }
1073 if (strncmp("MSG_", &name[0], 4) == 0) {
1074 msgcode_tab[msgcode_indx] = ((code & 0x00ffffff) >>2);
1075 n = MAX_SC + msgcode_indx;
1076 strncpy(&sc_tab[n].name[0], &name[4], 31 );
1077 msgcode_indx++;
1078 continue;
1079 }
1080 if (strncmp("MSC_", &name[0], 4) == 0) {
1081 n = 512 + ((code>>2) & 0x1ff);
1082 strcpy(&sc_tab[n].name[0], &name[4]);
1083 continue;
1084 }
1085 if (strncmp("BSC_", &name[0], 4) == 0) {
1086 n = (code>>2) & 0x1ff;
1087 strcpy(&sc_tab[n].name[0], &name[4]);
1088 continue;
1089 }
1090 if (strcmp("USER_TEST", &name[0]) == 0)
1091 break;
1092 }
1093 strcpy(&faults[1].name[0], "zero_fill");
1094 strcpy(&faults[2].name[0], "pagein");
1095 strcpy(&faults[3].name[0], "copy_on_write");
1096 strcpy(&faults[4].name[0], "cache_hit");
1097 }
1098
1099 void
1100 find_proc_names()
1101 {
1102 size_t bufSize = 0;
1103 struct kinfo_proc *kp;
1104
1105 mib[0] = CTL_KERN;
1106 mib[1] = KERN_PROC;
1107 mib[2] = KERN_PROC_ALL;
1108 mib[3] = 0;
1109
1110 if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0)
1111 quit("trace facility failure, KERN_PROC_ALL\n");
1112
1113 if((kp = (struct kinfo_proc *)malloc(bufSize)) == (struct kinfo_proc *)0)
1114 quit("can't allocate memory for proc buffer\n");
1115
1116 if (sysctl(mib, 4, kp, &bufSize, NULL, 0) < 0)
1117 quit("trace facility failure, KERN_PROC_ALL\n");
1118
1119 kp_nentries = bufSize/ sizeof(struct kinfo_proc);
1120 kp_buffer = kp;
1121 }
1122
1123 struct th_info *find_thread(int thread) {
1124 struct th_info *ti;
1125
1126 for (ti = th_state; ti < &th_state[MAX_THREADS]; ti++) {
1127 if (ti->thread == thread)
1128 return(ti);
1129 }
1130 return ((struct th_info *)0);
1131 }
1132
1133
1134 int
1135 cmp_wtime(struct sc_entry *s1, struct sc_entry *s2) {
1136
1137 if (s1->wtime_secs < s2->wtime_secs)
1138 return 0;
1139 if (s1->wtime_secs > s2->wtime_secs)
1140 return 1;
1141 if (s1->wtime_usecs <= s2->wtime_usecs)
1142 return 0;
1143 return 1;
1144 }
1145
1146
1147 void
1148 sort_scalls() {
1149 int i, n, k, cnt, secs;
1150 struct th_info *ti;
1151 struct sc_entry *se;
1152 struct entry *te;
1153 uint64_t now;
1154
1155 now = mach_absolute_time();
1156
1157 for (ti = th_state; ti < &th_state[MAX_THREADS]; ti++) {
1158 if (ti->thread == 0)
1159 continue;
1160
1161 if (ti->depth) {
1162 te = &ti->th_entry[ti->depth-1];
1163
1164 if (te->sc_state == WAITING) {
1165 if (te->code)
1166 se = &sc_tab[te->code];
1167 else
1168 se = &faults[DBG_PAGEIN_FAULT];
1169 se->waiting++;
1170 se->wtime_usecs += ((double)now - te->stime) / divisor;
1171 se->delta_wtime_usecs += ((double)now - te->stime) / divisor;
1172 te->stime = (double)now;
1173
1174 secs = se->wtime_usecs / 1000000;
1175 se->wtime_usecs -= secs * 1000000;
1176 se->wtime_secs += secs;
1177
1178 secs = se->delta_wtime_usecs / 1000000;
1179 se->delta_wtime_usecs -= secs * 1000000;
1180 se->delta_wtime_secs += secs;
1181 }
1182 } else {
1183 te = &ti->th_entry[0];
1184
1185 if (te->sc_state == PREEMPTED) {
1186 if ((unsigned long)(((double)now - te->otime) / divisor) > 5000000) {
1187 ti->thread = 0;
1188 ti->vfslookup = 0;
1189 ti->pathptr = (long *)NULL;
1190 ti->pathname[0] = 0;
1191 num_of_threads--;
1192 }
1193 }
1194 }
1195 }
1196 if ((called % sort_now) == 0) {
1197 sort_by_count[0] = -1;
1198 sort_by_wtime[0] = -1;
1199 for (cnt = 1, n = 1; n < (MAX_SC + msgcode_cnt); n++) {
1200 if (sc_tab[n].total_count) {
1201 for (i = 0; i < cnt; i++) {
1202 if ((k = sort_by_count[i]) == -1 ||
1203 sc_tab[n].total_count > sc_tab[k].total_count) {
1204
1205 for (k = cnt - 1; k >= i; k--)
1206 sort_by_count[k+1] = sort_by_count[k];
1207 sort_by_count[i] = n;
1208 break;
1209 }
1210 }
1211 if (how_to_sort == 0) {
1212 for (i = 0; i < cnt; i++) {
1213 if ((k = sort_by_wtime[i]) == -1 ||
1214 cmp_wtime(&sc_tab[n], &sc_tab[k])) {
1215
1216 for (k = cnt - 1; k >= i; k--)
1217 sort_by_wtime[k+1] = sort_by_wtime[k];
1218 sort_by_wtime[i] = n;
1219 break;
1220 }
1221 }
1222 }
1223 cnt++;
1224 }
1225 }
1226 }
1227 called++;
1228 }
1229
1230 void
1231 set_enable(int val)
1232 {
1233 mib[0] = CTL_KERN;
1234 mib[1] = KERN_KDEBUG;
1235 mib[2] = KERN_KDENABLE; /* protocol */
1236 mib[3] = val;
1237 mib[4] = 0;
1238 mib[5] = 0; /* no flags */
1239 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
1240 quit("trace facility failure, KERN_KDENABLE\n");
1241
1242 if (val)
1243 trace_enabled = 1;
1244 else
1245 trace_enabled = 0;
1246 }
1247
1248 void
1249 set_numbufs(int nbufs)
1250 {
1251 mib[0] = CTL_KERN;
1252 mib[1] = KERN_KDEBUG;
1253 mib[2] = KERN_KDSETBUF;
1254 mib[3] = nbufs;
1255 mib[4] = 0;
1256 mib[5] = 0; /* no flags */
1257 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
1258 quit("trace facility failure, KERN_KDSETBUF\n");
1259
1260 mib[0] = CTL_KERN;
1261 mib[1] = KERN_KDEBUG;
1262 mib[2] = KERN_KDSETUP;
1263 mib[3] = 0;
1264 mib[4] = 0;
1265 mib[5] = 0; /* no flags */
1266 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
1267 quit("trace facility failure, KERN_KDSETUP\n");
1268
1269 }
1270
1271 void
1272 set_pidcheck(int pid, int on_off)
1273 {
1274 kd_regtype kr;
1275
1276 kr.type = KDBG_TYPENONE;
1277 kr.value1 = pid;
1278 kr.value2 = on_off;
1279 needed = sizeof(kd_regtype);
1280 mib[0] = CTL_KERN;
1281 mib[1] = KERN_KDEBUG;
1282 mib[2] = KERN_KDPIDTR;
1283 mib[3] = 0;
1284 mib[4] = 0;
1285 mib[5] = 0;
1286 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) {
1287 if (on_off == 1) {
1288 printf("pid %d does not exist\n", pid);
1289 set_remove();
1290 exit(2);
1291 }
1292 }
1293 }
1294
1295 void
1296 get_bufinfo(kbufinfo_t *val)
1297 {
1298 needed = sizeof (*val);
1299 mib[0] = CTL_KERN;
1300 mib[1] = KERN_KDEBUG;
1301 mib[2] = KERN_KDGETBUF;
1302 mib[3] = 0;
1303 mib[4] = 0;
1304 mib[5] = 0; /* no flags */
1305 if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
1306 quit("trace facility failure, KERN_KDGETBUF\n");
1307
1308 }
1309
1310 void
1311 set_remove()
1312 {
1313 extern int errno;
1314
1315 errno = 0;
1316
1317 mib[0] = CTL_KERN;
1318 mib[1] = KERN_KDEBUG;
1319 mib[2] = KERN_KDREMOVE; /* protocol */
1320 mib[3] = 0;
1321 mib[4] = 0;
1322 mib[5] = 0; /* no flags */
1323
1324 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
1325 {
1326 set_remove_flag = 0;
1327
1328 if (errno == EBUSY)
1329 quit("the trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n");
1330 else
1331 quit("trace facility failure, KERN_KDREMOVE\n");
1332 }
1333 }
1334
1335 void
1336 set_init()
1337 { kd_regtype kr;
1338
1339 kr.type = KDBG_RANGETYPE;
1340 kr.value1 = 0;
1341 kr.value2 = -1;
1342 needed = sizeof(kd_regtype);
1343 mib[0] = CTL_KERN;
1344 mib[1] = KERN_KDEBUG;
1345 mib[2] = KERN_KDSETREG;
1346 mib[3] = 0;
1347 mib[4] = 0;
1348 mib[5] = 0; /* no flags */
1349 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
1350 quit("trace facility failure, KERN_KDSETREG\n");
1351
1352 mib[0] = CTL_KERN;
1353 mib[1] = KERN_KDEBUG;
1354 mib[2] = KERN_KDSETUP;
1355 mib[3] = 0;
1356 mib[4] = 0;
1357 mib[5] = 0; /* no flags */
1358 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
1359 quit("trace facility failure, KERN_KDSETUP\n");
1360
1361 }
1362
1363 void
1364 sample_sc()
1365 {
1366 kd_buf *kd;
1367 int i, count;
1368 int secs;
1369 int find_msgcode();
1370
1371 /* Get kernel buffer information */
1372 get_bufinfo(&bufinfo);
1373 #ifdef OLD_KDEBUG
1374 set_enable(0);
1375 #endif
1376 needed = bufinfo.nkdbufs * sizeof(kd_buf);
1377 mib[0] = CTL_KERN;
1378 mib[1] = KERN_KDEBUG;
1379 mib[2] = KERN_KDREADTR;
1380 mib[3] = 0;
1381 mib[4] = 0;
1382 mib[5] = 0; /* no flags */
1383 if (sysctl(mib, 3, my_buffer, &needed, NULL, 0) < 0)
1384 quit("trace facility failure, KERN_KDREADTR\n");
1385 count = needed;
1386
1387 if (bufinfo.flags & KDBG_WRAPPED) {
1388 for (i = 0; i < MAX_THREADS; i++) {
1389 th_state[i].depth = 0;
1390 th_state[i].thread = 0;
1391 th_state[i].vfslookup = 0;
1392 th_state[i].pathptr = (long *)NULL;
1393 th_state[i].pathname[0] = 0;
1394 }
1395 num_of_threads = 0;
1396 }
1397 #ifdef OLD_KDEBUG
1398 set_remove();
1399 set_init();
1400 set_pidcheck(pid, 1);
1401 set_enable(1); /* re-enable kernel logging */
1402 #endif
1403 kd = (kd_buf *)my_buffer;
1404
1405 for (i = 0; i < count; i++) {
1406 int debugid, baseid, thread;
1407 int type, code;
1408 uint64_t now;
1409 struct th_info *ti, *switched_out, *switched_in;
1410 struct sc_entry *se;
1411 struct entry *te;
1412
1413 thread = kd[i].arg5;
1414 debugid = kd[i].debugid;
1415 type = kd[i].debugid & DBG_FUNC_MASK;
1416
1417 code = 0;
1418 switched_out = (struct th_info *)0;
1419 switched_in = (struct th_info *)0;
1420
1421 now = kd[i].timestamp & KDBG_TIMESTAMP_MASK;
1422
1423 baseid = debugid & 0xffff0000;
1424
1425 if (type == vfs_lookup) {
1426 long *sargptr;
1427
1428 if ((ti = find_thread(thread)) == (struct th_info *)0)
1429 continue;
1430
1431 if (ti->vfslookup == 1) {
1432 ti->vfslookup++;
1433 sargptr = ti->pathname;
1434
1435 *sargptr++ = kd[i].arg2;
1436 *sargptr++ = kd[i].arg3;
1437 *sargptr++ = kd[i].arg4;
1438 /*
1439 * NULL terminate the 'string'
1440 */
1441 *sargptr = 0;
1442
1443 ti->pathptr = sargptr;
1444
1445 } else if (ti->vfslookup > 1) {
1446 ti->vfslookup++;
1447 sargptr = ti->pathptr;
1448
1449 /*
1450 We don't want to overrun our pathname buffer if the
1451 kernel sends us more VFS_LOOKUP entries than we can
1452 handle.
1453 */
1454
1455 if (sargptr >= &ti->pathname[NUMPARMS])
1456 continue;
1457
1458 /*
1459 We need to detect consecutive vfslookup entries.
1460 So, if we get here and find a START entry,
1461 fake the pathptr so we can bypass all further
1462 vfslookup entries.
1463 */
1464
1465 if (debugid & DBG_FUNC_START)
1466 {
1467 ti->pathptr = &ti->pathname[NUMPARMS];
1468 continue;
1469 }
1470
1471 *sargptr++ = kd[i].arg1;
1472 *sargptr++ = kd[i].arg2;
1473 *sargptr++ = kd[i].arg3;
1474 *sargptr++ = kd[i].arg4;
1475 /*
1476 * NULL terminate the 'string'
1477 */
1478 *sargptr = 0;
1479
1480 ti->pathptr = sargptr;
1481 }
1482 continue;
1483
1484 } else if (baseid == bsc_base)
1485 code = (debugid >> 2) & 0x1ff;
1486 else if (baseid == msc_base)
1487 code = 512 + ((debugid >> 2) & 0x1ff);
1488 else if (type == mach_idle) {
1489 if (debugid & DBG_FUNC_START) {
1490 switched_out = find_thread(kd[i].arg5);
1491 switched_in = 0;
1492 }
1493 else
1494 if (debugid & DBG_FUNC_END) {
1495 switched_in = find_thread(kd[i].arg5);
1496 switched_out = 0;
1497 }
1498
1499 if (in_idle) {
1500 itime_usecs += ((double)now - idle_start) / divisor;
1501 delta_itime_usecs += ((double)now - idle_start) / divisor;
1502 in_idle = 0;
1503 } else if (in_other) {
1504 otime_usecs += ((double)now - other_start) / divisor;
1505 delta_otime_usecs += ((double)now - other_start) / divisor;
1506 in_other = 0;
1507 }
1508 if ( !switched_in) {
1509 /*
1510 * not one of the target proc's threads
1511 */
1512 if (now_collect_cpu_time) {
1513 in_idle = 1;
1514 idle_start = (double)now;
1515 }
1516 }
1517 else {
1518 if (now_collect_cpu_time) {
1519 in_idle = 0;
1520 in_other = 1;
1521 other_start = (double)now;
1522 }
1523 }
1524 if ( !switched_in && !switched_out)
1525 continue;
1526
1527 }
1528 else if (type == mach_sched || type == mach_stkhandoff) {
1529 switched_out = find_thread(kd[i].arg5);
1530 switched_in = find_thread(kd[i].arg2);
1531
1532 if (in_idle) {
1533 itime_usecs += ((double)now - idle_start) / divisor;
1534 delta_itime_usecs += ((double)now - idle_start) / divisor;
1535 in_idle = 0;
1536 } else if (in_other) {
1537 otime_usecs += ((double)now - other_start) / divisor;
1538 delta_otime_usecs += ((double)now - other_start) / divisor;
1539 in_other = 0;
1540 }
1541 if ( !switched_in) {
1542 /*
1543 * not one of the target proc's threads
1544 */
1545 if (now_collect_cpu_time) {
1546 in_other = 1;
1547 other_start = (double)now;
1548 }
1549 }
1550 if ( !switched_in && !switched_out)
1551 continue;
1552
1553 }
1554 else if ((baseid & 0xff000000) == 0xff000000) {
1555 code = find_msgcode (debugid);
1556 if (!code)
1557 continue;
1558 } else if (baseid != mach_vmfault)
1559 continue;
1560
1561 if (switched_out || switched_in) {
1562 if (switched_out) {
1563 ti = switched_out;
1564 ti->curpri = kd[i].arg3;
1565
1566 if (ti->depth) {
1567 te = &ti->th_entry[ti->depth-1];
1568
1569 if (te->sc_state == KERNEL_MODE)
1570 te->ctime += (double)now - te->stime;
1571 te->sc_state = WAITING;
1572
1573 ti->vfslookup = 1;
1574
1575 } else {
1576 te = &ti->th_entry[0];
1577
1578 if (te->sc_state == USER_MODE)
1579 utime_usecs += ((double)now - te->stime) / divisor;
1580 te->sc_state = PREEMPTED;
1581 preempted++;
1582 }
1583 te->stime = (double)now;
1584 te->otime = (double)now;
1585 now_collect_cpu_time = 1;
1586 csw++;
1587 }
1588 if (switched_in) {
1589 ti = switched_in;
1590 ti->curpri = kd[i].arg4;
1591
1592 if (ti->depth) {
1593 te = &ti->th_entry[ti->depth-1];
1594
1595 if (te->sc_state == WAITING)
1596 te->wtime += (double)now - te->stime;
1597 te->sc_state = KERNEL_MODE;
1598 } else {
1599 te = &ti->th_entry[0];
1600
1601 te->sc_state = USER_MODE;
1602 }
1603 te->stime = (double)now;
1604 te->otime = (double)now;
1605 }
1606 continue;
1607 }
1608 if ((ti = find_thread(thread)) == (struct th_info *)0) {
1609 for (ti = &th_state[0]; ti < &th_state[MAX_THREADS]; ti++) {
1610 if (ti->thread == 0) {
1611 ti->thread = thread;
1612 num_of_threads++;
1613 break;
1614 }
1615 }
1616 if (ti == &th_state[MAX_THREADS])
1617 continue;
1618 }
1619 if (debugid & DBG_FUNC_START) {
1620 ti->vfslookup = 0;
1621
1622 if (ti->depth) {
1623 te = &ti->th_entry[ti->depth-1];
1624
1625 if (te->sc_state == KERNEL_MODE)
1626 te->ctime += (double)now - te->stime;
1627 } else {
1628 te = &ti->th_entry[0];
1629
1630 if (te->sc_state == USER_MODE)
1631 utime_usecs += ((double)now - te->stime) / divisor;
1632 }
1633 te->stime = (double)now;
1634 te->otime = (double)now;
1635
1636 if (ti->depth < MAX_NESTED) {
1637 te = &ti->th_entry[ti->depth];
1638
1639 te->sc_state = KERNEL_MODE;
1640 te->type = type;
1641 te->code = code;
1642 te->stime = (double)now;
1643 te->otime = (double)now;
1644 te->ctime = (double)0;
1645 te->wtime = (double)0;
1646 ti->depth++;
1647 }
1648
1649 } else if (debugid & DBG_FUNC_END) {
1650 if (code) {
1651 se = &sc_tab[code];
1652 scalls++;
1653 } else {
1654 se = &faults[kd[i].arg4];
1655 total_faults++;
1656 }
1657 if (se->total_count == 0)
1658 called = 0;
1659 se->delta_count++;
1660 se->total_count++;
1661
1662 while (ti->depth) {
1663 te = &ti->th_entry[ti->depth-1];
1664
1665 if (te->type == type) {
1666 se->stime_usecs += te->ctime / divisor;
1667 se->stime_usecs += ((double)now - te->stime) / divisor;
1668
1669 se->wtime_usecs += te->wtime / divisor;
1670 se->delta_wtime_usecs += te->wtime / divisor;
1671
1672 secs = se->stime_usecs / 1000000;
1673 se->stime_usecs -= secs * 1000000;
1674 se->stime_secs += secs;
1675
1676 secs = se->wtime_usecs / 1000000;
1677 se->wtime_usecs -= secs * 1000000;
1678 se->wtime_secs += secs;
1679
1680 secs = se->delta_wtime_usecs / 1000000;
1681 se->delta_wtime_usecs -= secs * 1000000;
1682 se->delta_wtime_secs += secs;
1683
1684 ti->depth--;
1685
1686 if (ti->depth == 0) {
1687 /*
1688 * headed back to user mode
1689 * start the time accumulation
1690 */
1691 te = &ti->th_entry[0];
1692 te->sc_state = USER_MODE;
1693 } else
1694 te = &ti->th_entry[ti->depth-1];
1695
1696 te->stime = (double)now;
1697 te->otime = (double)now;
1698
1699 break;
1700 }
1701 ti->depth--;
1702
1703 if (ti->depth == 0) {
1704 /*
1705 * headed back to user mode
1706 * start the time accumulation
1707 */
1708 te = &ti->th_entry[0];
1709 te->sc_state = USER_MODE;
1710 te->stime = (double)now;
1711 te->otime = (double)now;
1712 }
1713 }
1714 }
1715 }
1716 secs = utime_usecs / 1000000;
1717 utime_usecs -= secs * 1000000;
1718 utime_secs += secs;
1719
1720 secs = itime_usecs / 1000000;
1721 itime_usecs -= secs * 1000000;
1722 itime_secs += secs;
1723
1724 secs = delta_itime_usecs / 1000000;
1725 delta_itime_usecs -= secs * 1000000;
1726 delta_itime_secs += secs;
1727
1728 secs = otime_usecs / 1000000;
1729 otime_usecs -= secs * 1000000;
1730 otime_secs += secs;
1731
1732 secs = delta_otime_usecs / 1000000;
1733 delta_otime_usecs -= secs * 1000000;
1734 delta_otime_secs += secs;
1735 }
1736
1737 void
1738 quit(char *s)
1739 {
1740 if (trace_enabled)
1741 set_enable(0);
1742
1743 /*
1744 This flag is turned off when calling
1745 quit() due to a set_remove() failure.
1746 */
1747 if (set_remove_flag)
1748 set_remove();
1749
1750 printf("sc_usage: ");
1751 if (s)
1752 printf("%s ", s);
1753
1754 exit(1);
1755 }
1756
1757 void getdivisor()
1758 {
1759 mach_timebase_info_data_t info;
1760
1761 (void) mach_timebase_info (&info);
1762
1763 divisor = ( (double)info.denom / (double)info.numer) * 1000;
1764
1765 }
1766
1767
1768 int
1769 argtopid(str)
1770 char *str;
1771 {
1772 char *cp;
1773 int ret;
1774 int i;
1775
1776 if (!kp_buffer)
1777 find_proc_names();
1778
1779 ret = (int)strtol(str, &cp, 10);
1780 if (cp == str || *cp) {
1781 /* Assume this is a command string and find first matching pid */
1782 for (i=0; i < kp_nentries; i++) {
1783 if(kp_buffer[i].kp_proc.p_stat == 0)
1784 continue;
1785 else {
1786 if(!strcmp(str, kp_buffer[i].kp_proc.p_comm))
1787 {
1788 strncpy(proc_name, kp_buffer[i].kp_proc.p_comm, sizeof(proc_name)-1);
1789 proc_name[sizeof(proc_name)-1] = '\0';
1790 return(kp_buffer[i].kp_proc.p_pid);
1791 }
1792 }
1793 }
1794 }
1795 else
1796 {
1797 for (i=0; i < kp_nentries; i++)
1798 {
1799 if(kp_buffer[i].kp_proc.p_stat == 0)
1800 continue;
1801 else if (kp_buffer[i].kp_proc.p_pid == ret) {
1802 strncpy(proc_name, kp_buffer[i].kp_proc.p_comm, sizeof(proc_name)-1);
1803 proc_name[sizeof(proc_name)-1] = '\0';
1804 return(kp_buffer[i].kp_proc.p_pid);
1805 }
1806 }
1807 }
1808 return(-1);
1809 }
1810
1811
1812 /* Returns index into sc_tab for a mach msg entry */
1813 int
1814 find_msgcode(int debugid)
1815 {
1816
1817 int indx;
1818
1819 for (indx=0; indx< msgcode_cnt; indx++)
1820 {
1821 if (msgcode_tab[indx] == ((debugid & 0x00ffffff) >>2))
1822 return (MAX_SC+indx);
1823 }
1824 return (0);
1825 }
1826
1827 int
1828 argtoi(flag, req, str, base)
1829 int flag;
1830 char *req, *str;
1831 int base;
1832 {
1833 char *cp;
1834 int ret;
1835
1836 ret = (int)strtol(str, &cp, base);
1837 if (cp == str || *cp)
1838 errx(EINVAL, "-%c flag requires a %s", flag, req);
1839 return (ret);
1840 }
1841