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