]>
git.saurik.com Git - apple/system_cmds.git/blob - sc_usage.tproj/sc_usage.c
86ed4916c223aafc05510f8158d3cc48836e9602
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
26 cc -I. -DKERNEL_PRIVATE -O -o sc_usage sc_usage.c
29 #define Default_DELAY 1 /* default delay interval */
39 #include <sys/types.h>
40 #include <sys/param.h>
45 #include <bsd/curses.h>
47 #include <sys/ioctl.h>
49 #ifndef KERNEL_PRIVATE
50 #define KERNEL_PRIVATE
51 #include <sys/kdebug.h>
54 #include <sys/kdebug.h>
55 #endif /*KERNEL_PRIVATE*/
57 #include <sys/sysctl.h>
59 #import <mach/clock_types.h>
63 /* Number of lines of header information on the standard screen */
64 #define HEADER_LINES 5
67 int Header_lines
= HEADER_LINES
;
70 int no_screen_refresh
= 0;
76 int waiting_index
= 0;
77 FILE *dfp
= 0; /*Debug output file */
80 #define SAMPLE_SIZE 20000
82 #define DBG_ZERO_FILL_FAULT 1
83 #define DBG_PAGEIN_FAULT 2
84 #define DBG_COW_FAULT 3
85 #define DBG_CACHE_HIT_FAULT 4
88 #define MAX_THREADS 16
93 char *state_name
[] = {
102 #define KERNEL_MODE 1
129 struct entry th_entry
[MAX_NESTED
];
137 unsigned int stime_secs
;
139 unsigned int wtime_secs
;
141 unsigned int delta_wtime_secs
;
142 double delta_wtime_usecs
;
145 struct th_info th_state
[MAX_THREADS
];
146 struct sc_entry faults
[MAX_FAULTS
];
148 struct sc_entry
*sc_tab
;
150 int msgcode_cnt
; /* number of MSG_ codes */
152 int num_of_threads
= 0;
153 int now_collect_cpu_time
= 0;
155 unsigned int utime_secs
;
159 unsigned int itime_secs
;
161 unsigned int delta_itime_secs
;
162 double delta_itime_usecs
;
166 unsigned int otime_secs
;
168 unsigned int delta_otime_secs
;
169 double delta_otime_usecs
;
176 int mach_stkhandoff
= 0;
178 int mach_vmfault
= 0;
185 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
186 #define DBG_FUNC_MASK 0xfffffffc
193 /* Default divisor */
194 #define DIVISOR 16.6666 /* Trace divisor converts to microseconds */
195 double divisor
= DIVISOR
;
197 struct termios tmode
, omode
;
203 kbufinfo_t bufinfo
= {0, 0, 0, 0};
205 int trace_enabled
= 0;
206 int set_remove_flag
= 1;
208 struct kinfo_proc
*kp_buffer
= 0;
211 extern char **environ
;
224 void leave() /* exit under normal conditions -- INT handler */
227 if (no_screen_refresh
== 0) {
232 tcsetattr(0, TCSANOW
, &omode
);
235 set_pidcheck(pid
, 0);
240 void err_leave(s
) /* exit under error conditions */
244 if (no_screen_refresh
== 0) {
249 tcsetattr(0, TCSANOW
, &omode
);
252 printf("sc_usage: ");
257 set_pidcheck(pid
, 0);
265 if (no_screen_refresh
== 0)
270 /* raw read of the timebase register */
271 void clock_get_uptime(
272 AbsoluteTime
*result
)
276 natural_t hi
, lo
, hic
;
279 asm volatile(" mftbu %0" : "=r" (hi
));
280 asm volatile(" mftb %0" : "=r" (lo
));
281 asm volatile(" mftbu %0" : "=r" (hic
));
295 fprintf(stderr
, "Usage: %s [-c codefile] [-e] [-l] [-sn] pid | cmd | -E execute path\n", myname
);
296 fprintf(stderr
, " -c name of codefile containing mappings for syscalls\n");
297 fprintf(stderr
, " Default is /usr/share/misc/trace.codes\n");
298 fprintf(stderr
, " -e enable sort by call count\n");
299 fprintf(stderr
, " -l turn off top style output\n");
300 fprintf(stderr
, " -sn change sample rate to every n seconds\n");
301 fprintf(stderr
, " pid selects process to sample\n");
302 fprintf(stderr
, " cmd selects command to sample\n");
303 fprintf(stderr
, " -E Execute the given path and optional arguments\n");
309 #define usec_to_1000ths(t) ((t) / 1000)
311 void print_time(char *p
, unsigned int useconds
, unsigned int seconds
)
315 minutes
= seconds
/ 60;
316 hours
= minutes
/ 60;
318 if (minutes
< 100) { // up to 100 minutes
319 sprintf(p
, "%2ld:%02ld.%03ld", minutes
, seconds
% 60,
320 usec_to_1000ths(useconds
));
322 else if (hours
< 100) { // up to 100 hours
323 sprintf(p
, "%2ld:%02ld:%02ld ", hours
, minutes
% 60,
327 sprintf(p
, "%4ld hrs ", hours
);
336 char *myname
= "sc_usage";
337 char *codefile
= "/usr/share/misc/trace.codes";
340 int delay
= Default_DELAY
;
342 void screen_update();
346 void reset_counters();
351 if ( geteuid() != 0 ) {
352 printf("'sc_usage' must be run as root...\n");
358 if ((myname
= rindex(argv
[0], '/')) == 0) {
366 while ((ch
= getopt(argc
, argv
, "c:els:d:E")) != EOF
) {
369 delay
= argtoi('s', "decimal number", optarg
, 10);
375 no_screen_refresh
= 1;
384 /* exit_usage(myname);*/
385 exit_usage("default");
391 sc_tab_init(codefile
);
397 /* parse a pid or a command */
398 if((pid
= argtopid(argv
[optind
])) < 0 )
402 { /* execute this command */
407 ptr
= strrchr(argv
[optind
], '/');
413 strncpy(proc_name
, ptr
, sizeof(proc_name
)-1);
414 proc_name
[sizeof(proc_name
)-1] = '\0';
424 fprintf(stderr
, "Starting program: %s\n", argv
[optind
]);
427 switch ((pid
= vfork()))
434 ptrace(0,0,0,0); /* PT_TRACE_ME */
435 execve(argv
[optind
], &argv
[optind
], environ
);
450 if (no_screen_refresh
== 0) {
451 if (tcgetattr(0, &tmode
) < 0) {
452 printf("can't get terminal attributes\n");
457 tmode
.c_lflag
&= ~ICANON
;
458 tmode
.c_cc
[VMIN
] = 0;
459 tmode
.c_cc
[VTIME
] = 1;
461 if (tcsetattr(0, TCSANOW
, &tmode
) < 0) {
462 printf("can't set terminal attributes\n");
465 /* initializes curses and screen (last) */
472 /* set up signal handlers */
473 signal(SIGINT
, leave
);
474 signal(SIGQUIT
, leave
);
475 signal(SIGWINCH
, sigwinch
);
477 if (no_screen_refresh
== 0)
478 topn
= LINES
- Header_lines
;
483 if ((my_buffer
= malloc(SAMPLE_SIZE
* sizeof(kd_buf
))) == (char *)0)
484 quit("can't allocate memory for tracing info\n");
487 set_numbufs(SAMPLE_SIZE
);
489 set_pidcheck(pid
, 1);
492 ptrace(7, pid
, 1, 0); /* PT_CONTINUE */
497 if ((sort_now
= 10 / delay
) < 2)
501 (void)screen_update();
511 for (i
= 0; i
< (10 * delay
) && newLINES
== 0; i
++) {
513 if (no_screen_refresh
== 0) {
514 if ((cnt
= read(0, &ibuf
, 128)) > 0) {
517 for (n
= 0; n
< cnt
; n
++)
534 topn
= LINES
- Header_lines
;
537 (void)screen_update();
542 print_row(struct sc_entry
*se
, int no_wtime
) {
547 sprintf(tbuf
, "%-23.23s %8d(%d)", se
->name
, se
->total_count
, se
->delta_count
);
549 sprintf(tbuf
, "%-23.23s %8d", se
->name
, se
->total_count
);
552 memset(&tbuf
[clen
], ' ', 45 - clen
);
554 print_time(&tbuf
[45], (unsigned long)(se
->stime_usecs
), se
->stime_secs
);
557 if (no_wtime
== 0 && (se
->wtime_usecs
|| se
->wtime_secs
)) {
558 sprintf(&tbuf
[clen
], " ");
559 clen
+= strlen(&tbuf
[clen
]);
561 print_time(&tbuf
[clen
], (unsigned long)(se
->wtime_usecs
), se
->wtime_secs
);
562 clen
+= strlen(&tbuf
[clen
]);
564 if (se
->waiting
|| se
->delta_wtime_usecs
|| se
->delta_wtime_secs
) {
566 sprintf(&tbuf
[clen
], "(");
567 clen
+= strlen(&tbuf
[clen
]);
569 print_time(&tbuf
[clen
], (unsigned long)(se
->delta_wtime_usecs
),
570 se
->delta_wtime_secs
);
571 clen
+= strlen(&tbuf
[clen
]);
573 sprintf(&tbuf
[clen
], ")");
574 clen
+= strlen(&tbuf
[clen
]);
577 if (se
->waiting
== 1)
578 sprintf(&tbuf
[clen
], " W");
580 sprintf(&tbuf
[clen
], " %d", se
->waiting
);
581 clen
+= strlen(&tbuf
[clen
]);
585 sprintf(&tbuf
[clen
], "\n");
587 if (tbuf
[COLS
-2] != '\n') {
591 if (no_screen_refresh
)
613 if (no_screen_refresh
== 0) {
614 /* clear for new display */
620 sprintf(tbuf
, "%-14.14s", proc_name
);
628 p2
= "context switch ";
630 p2
= "context switches";
631 if (num_of_threads
== 1)
636 sprintf(&tbuf
[clen
], " %4d %s %4d %s %4d %s",
637 preempted
, p1
, csw
, p2
, num_of_threads
, p3
);
638 clen
+= strlen(&tbuf
[clen
]);
641 * Display the current time.
642 * "ctime" always returns a string that looks like this:
644 * Sun Sep 16 01:03:52 1973
645 * 012345678901234567890123
648 * We want indices 11 thru 18 (length 8).
650 curr_time
= time((long *)0);
653 start_time
= curr_time
;
655 elapsed_secs
= curr_time
- start_time
;
656 minutes
= elapsed_secs
/ 60;
657 hours
= minutes
/ 60;
659 memset(&tbuf
[clen
], ' ', 78 - clen
);
663 sprintf(&tbuf
[clen
], "%-8.8s\n", &(ctime(&curr_time
)[11]));
665 if (tbuf
[COLS
-2] != '\n') {
669 if (no_screen_refresh
)
674 if (total_faults
== 1)
682 sprintf(tbuf
, " %4d %s %4d %s",
683 total_faults
, p1
, scalls
, p2
);
686 sprintf(&tbuf
[clen
], " %3ld:%02ld:%02ld\n",
687 hours
, minutes
% 60, elapsed_secs
% 60);
689 if (tbuf
[COLS
-2] != '\n') {
693 if (no_screen_refresh
)
700 sprintf(tbuf
, "\nTYPE NUMBER CPU_TIME WAIT_TIME\n");
702 if (tbuf
[COLS
-2] != '\n') {
706 if (no_screen_refresh
)
711 sprintf(tbuf
, "------------------------------------------------------------------------------\n");
712 if (tbuf
[COLS
-2] != '\n') {
716 if (no_screen_refresh
)
724 sprintf(tbuf
, "System Idle ");
727 print_time(&tbuf
[clen
], (unsigned long)(itime_usecs
), itime_secs
);
728 clen
+= strlen(&tbuf
[clen
]);
730 if (delta_itime_usecs
|| delta_itime_secs
) {
732 sprintf(&tbuf
[clen
], "(");
733 clen
+= strlen(&tbuf
[clen
]);
735 print_time(&tbuf
[clen
], (unsigned long)(delta_itime_usecs
), delta_itime_secs
);
736 clen
+= strlen(&tbuf
[clen
]);
738 sprintf(&tbuf
[clen
], ")");
739 clen
+= strlen(&tbuf
[clen
]);
741 sprintf(&tbuf
[clen
], "\n");
743 if (tbuf
[COLS
-2] != '\n') {
747 if (no_screen_refresh
)
755 sprintf(tbuf
, "System Busy ");
758 print_time(&tbuf
[clen
], (unsigned long)(otime_usecs
), otime_secs
);
759 clen
+= strlen(&tbuf
[clen
]);
761 if (delta_otime_usecs
|| delta_otime_secs
) {
763 sprintf(&tbuf
[clen
], "(");
764 clen
+= strlen(&tbuf
[clen
]);
766 print_time(&tbuf
[clen
], (unsigned long)(delta_otime_usecs
), delta_otime_secs
);
767 clen
+= strlen(&tbuf
[clen
]);
769 sprintf(&tbuf
[clen
], ")");
770 clen
+= strlen(&tbuf
[clen
]);
772 sprintf(&tbuf
[clen
], "\n");
774 if (tbuf
[COLS
-2] != '\n') {
778 if (no_screen_refresh
)
785 sprintf(tbuf
, "%-14.14s Usermode ", proc_name
);
788 print_time(&tbuf
[clen
], (unsigned long)(utime_usecs
), utime_secs
);
789 clen
+= strlen(&tbuf
[clen
]);
790 sprintf(&tbuf
[clen
], "\n");
792 if (tbuf
[COLS
-2] != '\n') {
796 if (no_screen_refresh
)
803 max_rows
= topn
- (num_of_threads
+ 3);
807 for (output_lf
= 1, n
= 1; rows
< max_rows
&& n
< MAX_FAULTS
; n
++) {
810 if (se
->total_count
== 0)
812 if (output_lf
== 1) {
814 if (no_screen_refresh
)
820 if (rows
>= max_rows
)
829 if (no_screen_refresh
)
835 for (i
= 0; rows
< max_rows
; i
++) {
837 n
= sort_by_count
[i
];
839 n
= sort_by_wtime
[i
];
842 print_row(&sc_tab
[n
], 0);
845 if (no_screen_refresh
== 0) {
848 while (rows
++ < max_rows
)
853 if (num_of_threads
) {
854 sprintf(tbuf
, "\nCURRENT_TYPE LAST_PATHNAME_WAITED_FOR CUR_WAIT_TIME THRD# PRI\n");
856 if (tbuf
[COLS
-2] != '\n') {
860 if (no_screen_refresh
)
865 sprintf(tbuf
, "------------------------------------------------------------------------------\n");
866 if (tbuf
[COLS
-2] != '\n') {
870 if (no_screen_refresh
)
877 for (i
= 0; i
< num_of_threads
; i
++, ti
++) {
879 unsigned long long now
;
880 AbsoluteTime timestamp
;
881 int secs
, time_secs
, time_usecs
;
883 clock_get_uptime(×tamp
);
885 now
= (((unsigned long long)timestamp
.hi
) << 32) |
886 (unsigned long long)((unsigned int)(timestamp
.lo
));
888 while (ti
->thread
== 0 && ti
< &th_state
[MAX_THREADS
])
890 if (ti
== &th_state
[MAX_THREADS
])
894 te
= &ti
->th_entry
[ti
->depth
- 1];
896 if (te
->sc_state
== WAITING
) {
898 sprintf(tbuf
, "%-23.23s", sc_tab
[te
->code
].name
);
900 sprintf(tbuf
, "%-23.23s", "vm_fault");
902 sprintf(tbuf
, "%-23.23s", state_name
[te
->sc_state
]);
904 te
= &ti
->th_entry
[0];
905 sprintf(tbuf
, "%-23.23s", state_name
[te
->sc_state
]);
909 sprintf(&tbuf
[clen
], " %-28.28s ", ti
->pathname
);
911 clen
+= strlen(&tbuf
[clen
]);
913 time_usecs
= (unsigned long)(((double)now
- te
->otime
) / divisor
);
914 secs
= time_usecs
/ 1000000;
915 time_usecs
-= secs
* 1000000;
918 print_time(&tbuf
[clen
], time_usecs
, time_secs
);
919 clen
+= strlen(&tbuf
[clen
]);
920 sprintf(&tbuf
[clen
], " %2d %3d\n", i
, ti
->curpri
);
922 if (tbuf
[COLS
-2] != '\n') {
926 if (no_screen_refresh
)
931 if (no_screen_refresh
== 0) {
935 printf("\n=================\n");
939 for (i
= 0; i
< (MAX_SC
+ msgcode_cnt
); i
++) {
940 if ((n
= sort_by_count
[i
]) == -1)
942 sc_tab
[n
].delta_count
= 0;
943 sc_tab
[n
].waiting
= 0;
944 sc_tab
[n
].delta_wtime_usecs
= 0;
945 sc_tab
[n
].delta_wtime_secs
= 0;
947 for (i
= 1; i
< MAX_FAULTS
; i
++) {
948 faults
[i
].delta_count
= 0;
949 faults
[i
].waiting
= 0;
950 faults
[i
].delta_wtime_usecs
= 0;
951 faults
[i
].delta_wtime_secs
= 0;
957 delta_itime_secs
= 0;
958 delta_itime_usecs
= 0;
959 delta_otime_secs
= 0;
960 delta_otime_usecs
= 0;
967 for (i
= 0; i
< (MAX_SC
+ msgcode_cnt
) ; i
++) {
968 sc_tab
[i
].delta_count
= 0;
969 sc_tab
[i
].total_count
= 0;
970 sc_tab
[i
].waiting
= 0;
971 sc_tab
[i
].delta_wtime_usecs
= 0;
972 sc_tab
[i
].delta_wtime_secs
= 0;
973 sc_tab
[i
].wtime_usecs
= 0;
974 sc_tab
[i
].wtime_secs
= 0;
975 sc_tab
[i
].stime_usecs
= 0;
976 sc_tab
[i
].stime_secs
= 0;
978 for (i
= 1; i
< MAX_FAULTS
; i
++) {
979 faults
[i
].delta_count
= 0;
980 faults
[i
].total_count
= 0;
981 faults
[i
].waiting
= 0;
982 faults
[i
].delta_wtime_usecs
= 0;
983 faults
[i
].delta_wtime_secs
= 0;
984 faults
[i
].wtime_usecs
= 0;
985 faults
[i
].wtime_secs
= 0;
986 faults
[i
].stime_usecs
= 0;
987 faults
[i
].stime_secs
= 0;
999 delta_itime_secs
= 0;
1000 delta_itime_usecs
= 0;
1003 delta_otime_secs
= 0;
1004 delta_otime_usecs
= 0;
1008 sc_tab_init(char *codefile
) {
1016 if ((fp
= fopen(codefile
,"r")) == (FILE *)0) {
1017 printf("Failed to open code description file %s\n", codefile
);
1021 n
= fscanf(fp
, "%d\n", &cnt
);
1025 /* Count Mach message MSG_ codes */
1026 for (msgcode_cnt
=0;;) {
1027 n
= fscanf(fp
, "%x%s\n", &code
, &name
[0]);
1030 if (strncmp ("MSG_", &name
[0], 4) == 0)
1032 if (strcmp("USER_TEST", &name
[0]) == 0)
1036 sc_tab
= (struct sc_entry
*)malloc((MAX_SC
+msgcode_cnt
) * sizeof (struct sc_entry
));
1038 quit("can't allocate memory for system call table\n");
1039 bzero(sc_tab
,(MAX_SC
+msgcode_cnt
) * sizeof (struct sc_entry
));
1041 msgcode_tab
= (int *)malloc(msgcode_cnt
* sizeof(int));
1043 quit("can't allocate memory for msgcode table\n");
1044 bzero(msgcode_tab
,(msgcode_cnt
* sizeof(int)));
1046 sort_by_count
= (int *)malloc((MAX_SC
+ msgcode_cnt
+ 1) * sizeof(int));
1048 quit("can't allocate memory for sort_by_count table\n");
1049 bzero(sort_by_count
,(MAX_SC
+ msgcode_cnt
+ 1) * sizeof(int));
1051 sort_by_wtime
= (int *)malloc((MAX_SC
+ msgcode_cnt
+ 1) * sizeof(int));
1053 quit("can't allocate memory for sort_by_wtime table\n");
1054 bzero(sort_by_wtime
, (MAX_SC
+ msgcode_cnt
+ 1) * sizeof(int));
1059 n
= fscanf(fp
, "%d\n", &cnt
);
1065 n
= fscanf(fp
, "%x%s\n", &code
, &name
[0]);
1070 if (strcmp("MACH_vmfault", &name
[0]) == 0) {
1071 mach_vmfault
= code
;
1074 if (strcmp("MACH_SCHED", &name
[0]) == 0) {
1078 if (strcmp("MACH_STKHANDOFF", &name
[0]) == 0) {
1079 mach_stkhandoff
= code
;
1082 if (strcmp("VFS_LOOKUP", &name
[0]) == 0) {
1086 if (strcmp("BSC_SysCall", &name
[0]) == 0) {
1090 if (strcmp("MACH_SysCall", &name
[0]) == 0) {
1094 if (strcmp("BSC_exit", &name
[0]) == 0) {
1098 if (strncmp("MSG_", &name
[0], 4) == 0) {
1099 msgcode_tab
[msgcode_indx
] = ((code
& 0x00ffffff) >>2);
1100 n
= MAX_SC
+ msgcode_indx
;
1101 strncpy(&sc_tab
[n
].name
[0], &name
[4], 31 );
1105 if (strncmp("MSC_", &name
[0], 4) == 0) {
1106 n
= 512 + ((code
>>2) & 0x1ff);
1107 strcpy(&sc_tab
[n
].name
[0], &name
[4]);
1110 if (strncmp("BSC_", &name
[0], 4) == 0) {
1111 n
= (code
>>2) & 0x1ff;
1112 strcpy(&sc_tab
[n
].name
[0], &name
[4]);
1115 if (strcmp("USER_TEST", &name
[0]) == 0)
1118 strcpy(&faults
[1].name
[0], "zero_fill");
1119 strcpy(&faults
[2].name
[0], "pagein");
1120 strcpy(&faults
[3].name
[0], "copy_on_write");
1121 strcpy(&faults
[4].name
[0], "cache_hit");
1128 struct kinfo_proc
*kp
;
1132 mib
[2] = KERN_PROC_ALL
;
1135 if (sysctl(mib
, 4, NULL
, &bufSize
, NULL
, 0) < 0)
1136 quit("trace facility failure, KERN_PROC_ALL\n");
1138 if((kp
= (struct kinfo_proc
*)malloc(bufSize
)) == (struct kinfo_proc
*)0)
1139 quit("can't allocate memory for proc buffer\n");
1141 if (sysctl(mib
, 4, kp
, &bufSize
, NULL
, 0) < 0)
1142 quit("trace facility failure, KERN_PROC_ALL\n");
1144 kp_nentries
= bufSize
/ sizeof(struct kinfo_proc
);
1148 struct th_info
*find_thread(int thread
) {
1151 for (ti
= th_state
; ti
< &th_state
[MAX_THREADS
]; ti
++) {
1152 if (ti
->thread
== thread
)
1155 return ((struct th_info
*)0);
1160 cmp_wtime(struct sc_entry
*s1
, struct sc_entry
*s2
) {
1162 if (s1
->wtime_secs
< s2
->wtime_secs
)
1164 if (s1
->wtime_secs
> s2
->wtime_secs
)
1166 if (s1
->wtime_usecs
<= s2
->wtime_usecs
)
1174 int i
, n
, k
, cnt
, secs
;
1176 struct sc_entry
*se
;
1178 unsigned long long now
;
1179 AbsoluteTime timestamp
;
1181 clock_get_uptime(×tamp
);
1183 now
= (((unsigned long long)timestamp
.hi
) << 32) |
1184 (unsigned long long)((unsigned int)(timestamp
.lo
));
1186 for (ti
= th_state
; ti
< &th_state
[MAX_THREADS
]; ti
++) {
1187 if (ti
->thread
== 0)
1191 te
= &ti
->th_entry
[ti
->depth
-1];
1193 if (te
->sc_state
== WAITING
) {
1195 se
= &sc_tab
[te
->code
];
1197 se
= &faults
[DBG_PAGEIN_FAULT
];
1199 se
->wtime_usecs
+= ((double)now
- te
->stime
) / divisor
;
1200 se
->delta_wtime_usecs
+= ((double)now
- te
->stime
) / divisor
;
1201 te
->stime
= (double)now
;
1203 secs
= se
->wtime_usecs
/ 1000000;
1204 se
->wtime_usecs
-= secs
* 1000000;
1205 se
->wtime_secs
+= secs
;
1207 secs
= se
->delta_wtime_usecs
/ 1000000;
1208 se
->delta_wtime_usecs
-= secs
* 1000000;
1209 se
->delta_wtime_secs
+= secs
;
1212 te
= &ti
->th_entry
[0];
1214 if (te
->sc_state
== PREEMPTED
) {
1215 if ((unsigned long)(((double)now
- te
->otime
) / divisor
) > 5000000) {
1218 ti
->pathname
[0] = 0;
1224 if ((called
% sort_now
) == 0) {
1225 sort_by_count
[0] = -1;
1226 sort_by_wtime
[0] = -1;
1227 for (cnt
= 1, n
= 1; n
< (MAX_SC
+ msgcode_cnt
); n
++) {
1228 if (sc_tab
[n
].total_count
) {
1229 for (i
= 0; i
< cnt
; i
++) {
1230 if ((k
= sort_by_count
[i
]) == -1 ||
1231 sc_tab
[n
].total_count
> sc_tab
[k
].total_count
) {
1233 for (k
= cnt
- 1; k
>= i
; k
--)
1234 sort_by_count
[k
+1] = sort_by_count
[k
];
1235 sort_by_count
[i
] = n
;
1239 if (how_to_sort
== 0) {
1240 for (i
= 0; i
< cnt
; i
++) {
1241 if ((k
= sort_by_wtime
[i
]) == -1 ||
1242 cmp_wtime(&sc_tab
[n
], &sc_tab
[k
])) {
1244 for (k
= cnt
- 1; k
>= i
; k
--)
1245 sort_by_wtime
[k
+1] = sort_by_wtime
[k
];
1246 sort_by_wtime
[i
] = n
;
1262 mib
[1] = KERN_KDEBUG
;
1263 mib
[2] = KERN_KDENABLE
; /* protocol */
1266 mib
[5] = 0; /* no flags */
1267 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
1268 quit("trace facility failure, KERN_KDENABLE\n");
1277 set_numbufs(int nbufs
)
1280 mib
[1] = KERN_KDEBUG
;
1281 mib
[2] = KERN_KDSETBUF
;
1284 mib
[5] = 0; /* no flags */
1285 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
1286 quit("trace facility failure, KERN_KDSETBUF\n");
1289 mib
[1] = KERN_KDEBUG
;
1290 mib
[2] = KERN_KDSETUP
;
1293 mib
[5] = 0; /* no flags */
1294 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
1295 quit("trace facility failure, KERN_KDSETUP\n");
1300 set_pidcheck(int pid
, int on_off
)
1304 kr
.type
= KDBG_TYPENONE
;
1307 needed
= sizeof(kd_regtype
);
1309 mib
[1] = KERN_KDEBUG
;
1310 mib
[2] = KERN_KDPIDTR
;
1314 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0) {
1316 printf("pid %d does not exist\n", pid
);
1324 get_bufinfo(kbufinfo_t
*val
)
1326 needed
= sizeof (*val
);
1328 mib
[1] = KERN_KDEBUG
;
1329 mib
[2] = KERN_KDGETBUF
;
1332 mib
[5] = 0; /* no flags */
1333 if (sysctl(mib
, 3, val
, &needed
, 0, 0) < 0)
1334 quit("trace facility failure, KERN_KDGETBUF\n");
1346 mib
[1] = KERN_KDEBUG
;
1347 mib
[2] = KERN_KDREMOVE
; /* protocol */
1350 mib
[5] = 0; /* no flags */
1352 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
1354 set_remove_flag
= 0;
1357 quit("the trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n");
1359 quit("trace facility failure, KERN_KDREMOVE\n");
1367 kr
.type
= KDBG_RANGETYPE
;
1370 needed
= sizeof(kd_regtype
);
1372 mib
[1] = KERN_KDEBUG
;
1373 mib
[2] = KERN_KDSETREG
;
1376 mib
[5] = 0; /* no flags */
1377 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
1378 quit("trace facility failure, KERN_KDSETREG\n");
1381 mib
[1] = KERN_KDEBUG
;
1382 mib
[2] = KERN_KDSETUP
;
1385 mib
[5] = 0; /* no flags */
1386 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
1387 quit("trace facility failure, KERN_KDSETUP\n");
1399 /* Get kernel buffer information */
1400 get_bufinfo(&bufinfo
);
1404 needed
= bufinfo
.nkdbufs
* sizeof(kd_buf
);
1406 mib
[1] = KERN_KDEBUG
;
1407 mib
[2] = KERN_KDREADTR
;
1410 mib
[5] = 0; /* no flags */
1411 if (sysctl(mib
, 3, my_buffer
, &needed
, NULL
, 0) < 0)
1412 quit("trace facility failure, KERN_KDREADTR\n");
1415 if (bufinfo
.flags
& KDBG_WRAPPED
) {
1416 for (i
= 0; i
< MAX_THREADS
; i
++) {
1417 th_state
[i
].depth
= 0;
1418 th_state
[i
].thread
= 0;
1419 th_state
[i
].vfslookup
= 0;
1420 th_state
[i
].pathname
[0] = 0;
1427 set_pidcheck(pid
, 1);
1428 set_enable(1); /* re-enable kernel logging */
1430 kd
= (kd_buf
*)my_buffer
;
1432 for (i
= 0; i
< count
; i
++) {
1433 int debugid
, baseid
, thread
;
1435 unsigned long long now
;
1436 struct th_info
*ti
, *switched_out
, *switched_in
;
1437 struct sc_entry
*se
;
1440 thread
= kd
[i
].arg5
& KDBG_THREAD_MASK
;
1441 debugid
= kd
[i
].debugid
;
1442 type
= kd
[i
].debugid
& DBG_FUNC_MASK
;
1445 switched_out
= (struct th_info
*)0;
1446 switched_in
= (struct th_info
*)0;
1448 now
= (((unsigned long long)kd
[i
].timestamp
.tv_sec
) << 32) |
1449 (unsigned long long)((unsigned int)(kd
[i
].timestamp
.tv_nsec
));
1450 baseid
= debugid
& 0xffff0000;
1452 if (debugid
== vfs_lookup
) {
1455 if ((ti
= find_thread(thread
)) == (struct th_info
*)0)
1457 if (ti
->vfslookup
== 1) {
1459 memset(&ti
->pathname
[0], 0, 32);
1460 sargptr
= (long *)&ti
->pathname
[0];
1462 *sargptr
++ = kd
[i
].arg2
;
1463 *sargptr
++ = kd
[i
].arg3
;
1464 *sargptr
++ = kd
[i
].arg4
;
1466 } else if (ti
->vfslookup
== 2) {
1469 sargptr
= (long *)&ti
->pathname
[12];
1470 *sargptr
++ = kd
[i
].arg1
;
1471 *sargptr
++ = kd
[i
].arg2
;
1472 *sargptr
++ = kd
[i
].arg3
;
1473 *sargptr
++ = kd
[i
].arg4
;
1477 } else if (baseid
== bsc_base
)
1478 code
= (debugid
>> 2) & 0x1ff;
1479 else if (baseid
== msc_base
)
1480 code
= 512 + ((debugid
>> 2) & 0x1ff);
1481 else if (baseid
== mach_sched
|| baseid
== mach_stkhandoff
) {
1482 switched_out
= find_thread(kd
[i
].arg1
);
1483 switched_in
= find_thread(kd
[i
].arg2
);
1486 itime_usecs
+= ((double)now
- idle_start
) / divisor
;
1487 delta_itime_usecs
+= ((double)now
- idle_start
) / divisor
;
1489 } else if (in_other
) {
1490 otime_usecs
+= ((double)now
- other_start
) / divisor
;
1491 delta_otime_usecs
+= ((double)now
- other_start
) / divisor
;
1494 if ( !switched_in
) {
1496 * not one of the target proc's threads
1498 if (now_collect_cpu_time
) {
1499 if (kd
[i
].arg4
== 0) {
1501 idle_start
= (double)now
;
1504 other_start
= (double)now
;
1508 if ( !switched_in
&& !switched_out
)
1512 else if ((baseid
& 0xff000000) == 0xff000000) {
1513 code
= find_msgcode (debugid
);
1516 } else if (baseid
!= mach_vmfault
)
1519 if (switched_out
|| switched_in
) {
1522 ti
->curpri
= kd
[i
].arg3
;
1525 te
= &ti
->th_entry
[ti
->depth
-1];
1527 if (te
->sc_state
== KERNEL_MODE
)
1528 te
->ctime
+= (double)now
- te
->stime
;
1529 te
->sc_state
= WAITING
;
1534 te
= &ti
->th_entry
[0];
1536 if (te
->sc_state
== USER_MODE
)
1537 utime_usecs
+= ((double)now
- te
->stime
) / divisor
;
1538 te
->sc_state
= PREEMPTED
;
1541 te
->stime
= (double)now
;
1542 te
->otime
= (double)now
;
1543 now_collect_cpu_time
= 1;
1548 ti
->curpri
= kd
[i
].arg4
;
1551 te
= &ti
->th_entry
[ti
->depth
-1];
1553 if (te
->sc_state
== WAITING
)
1554 te
->wtime
+= (double)now
- te
->stime
;
1555 te
->sc_state
= KERNEL_MODE
;
1557 te
= &ti
->th_entry
[0];
1559 te
->sc_state
= USER_MODE
;
1561 te
->stime
= (double)now
;
1562 te
->otime
= (double)now
;
1566 if ((ti
= find_thread(thread
)) == (struct th_info
*)0) {
1567 for (ti
= &th_state
[0]; ti
< &th_state
[MAX_THREADS
]; ti
++) {
1568 if (ti
->thread
== 0) {
1569 ti
->thread
= thread
;
1574 if (ti
== &th_state
[MAX_THREADS
])
1577 if (debugid
& DBG_FUNC_START
) {
1581 te
= &ti
->th_entry
[ti
->depth
-1];
1583 if (te
->sc_state
== KERNEL_MODE
)
1584 te
->ctime
+= (double)now
- te
->stime
;
1586 te
= &ti
->th_entry
[0];
1588 if (te
->sc_state
== USER_MODE
)
1589 utime_usecs
+= ((double)now
- te
->stime
) / divisor
;
1591 te
->stime
= (double)now
;
1592 te
->otime
= (double)now
;
1594 if (ti
->depth
< MAX_NESTED
) {
1595 te
= &ti
->th_entry
[ti
->depth
];
1597 te
->sc_state
= KERNEL_MODE
;
1600 te
->stime
= (double)now
;
1601 te
->otime
= (double)now
;
1602 te
->ctime
= (double)0;
1603 te
->wtime
= (double)0;
1607 } else if (debugid
& DBG_FUNC_END
) {
1612 se
= &faults
[kd
[i
].arg2
];
1615 if (se
->total_count
== 0)
1621 te
= &ti
->th_entry
[ti
->depth
-1];
1623 if (te
->type
== type
) {
1624 se
->stime_usecs
+= te
->ctime
/ divisor
;
1625 se
->stime_usecs
+= ((double)now
- te
->stime
) / divisor
;
1627 se
->wtime_usecs
+= te
->wtime
/ divisor
;
1628 se
->delta_wtime_usecs
+= te
->wtime
/ divisor
;
1630 secs
= se
->stime_usecs
/ 1000000;
1631 se
->stime_usecs
-= secs
* 1000000;
1632 se
->stime_secs
+= secs
;
1634 secs
= se
->wtime_usecs
/ 1000000;
1635 se
->wtime_usecs
-= secs
* 1000000;
1636 se
->wtime_secs
+= secs
;
1638 secs
= se
->delta_wtime_usecs
/ 1000000;
1639 se
->delta_wtime_usecs
-= secs
* 1000000;
1640 se
->delta_wtime_secs
+= secs
;
1644 if (ti
->depth
== 0) {
1646 * headed back to user mode
1647 * start the time accumulation
1649 te
= &ti
->th_entry
[0];
1650 te
->sc_state
= USER_MODE
;
1652 te
= &ti
->th_entry
[ti
->depth
-1];
1654 te
->stime
= (double)now
;
1655 te
->otime
= (double)now
;
1660 secs
= utime_usecs
/ 1000000;
1661 utime_usecs
-= secs
* 1000000;
1664 secs
= itime_usecs
/ 1000000;
1665 itime_usecs
-= secs
* 1000000;
1668 secs
= delta_itime_usecs
/ 1000000;
1669 delta_itime_usecs
-= secs
* 1000000;
1670 delta_itime_secs
+= secs
;
1672 secs
= otime_usecs
/ 1000000;
1673 otime_usecs
-= secs
* 1000000;
1676 secs
= delta_otime_usecs
/ 1000000;
1677 delta_otime_usecs
-= secs
* 1000000;
1678 delta_otime_secs
+= secs
;
1689 This flag is turned off when calling
1690 quit() due to a set_remove() failure.
1692 if (set_remove_flag
)
1695 printf("sc_usage: ");
1707 unsigned int abs_to_ns_num
;
1708 unsigned int abs_to_ns_denom
;
1709 unsigned int proc_to_abs_num
;
1710 unsigned int proc_to_abs_denom
;
1712 MKGetTimeBaseInfo (&delta
, &abs_to_ns_num
, &abs_to_ns_denom
,
1713 &proc_to_abs_num
, &proc_to_abs_denom
);
1715 divisor
= ((double)abs_to_ns_denom
/ (double)abs_to_ns_num
) * 1000;
1729 ret
= (int)strtol(str
, &cp
, 10);
1730 if (cp
== str
|| *cp
) {
1731 /* Assume this is a command string and find first matching pid */
1732 for (i
=0; i
< kp_nentries
; i
++) {
1733 if(kp_buffer
[i
].kp_proc
.p_stat
== 0)
1736 if(!strcmp(str
, kp_buffer
[i
].kp_proc
.p_comm
))
1738 strncpy(proc_name
, kp_buffer
[i
].kp_proc
.p_comm
, sizeof(proc_name
)-1);
1739 proc_name
[sizeof(proc_name
)-1] = '\0';
1740 return(kp_buffer
[i
].kp_proc
.p_pid
);
1747 for (i
=0; i
< kp_nentries
; i
++)
1749 if(kp_buffer
[i
].kp_proc
.p_stat
== 0)
1751 else if (kp_buffer
[i
].kp_proc
.p_pid
== ret
) {
1752 strncpy(proc_name
, kp_buffer
[i
].kp_proc
.p_comm
, sizeof(proc_name
)-1);
1753 proc_name
[sizeof(proc_name
)-1] = '\0';
1754 return(kp_buffer
[i
].kp_proc
.p_pid
);
1762 /* Returns index into sc_tab for a mach msg entry */
1764 find_msgcode(int debugid
)
1769 for (indx
=0; indx
< msgcode_cnt
; indx
++)
1771 if (msgcode_tab
[indx
] == ((debugid
& 0x00ffffff) >>2))
1772 return (MAX_SC
+indx
);
1777 argtoi(flag
, req
, str
, base
)
1785 ret
= (int)strtol(str
, &cp
, base
);
1786 if (cp
== str
|| *cp
)
1787 errx(EINVAL
, "-%c flag requires a %s", flag
, req
);