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