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