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