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