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