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