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@
27 cc -I. -DPRIVATE -D__APPLE_PRIVATE -O -o latency latency.c -lncurses
30 #include <mach/mach.h>
40 #include <sys/types.h>
41 #include <sys/param.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*/
59 #include <sys/sysctl.h>
63 #include <mach/host_info.h>
64 #include <mach/mach_error.h>
65 #include <mach/mach_types.h>
66 #include <mach/message.h>
67 #include <mach/mach_syscalls.h>
68 #include <mach/clock_types.h>
69 #include <mach/mach_time.h>
71 #include <libkern/OSTypes.h>
73 extern mach_port_t clock_port
;
75 #define KERN_KDPIDEX 14
78 int s_usec_10_bins
[10];
79 int s_usec_100_bins
[10];
80 int s_msec_1_bins
[10];
81 int s_msec_10_bins
[5];
84 int s_min_latency
= 0;
85 long long s_total_latency
= 0;
88 int s_exceeded_threshold
= 0;
90 int i_usec_10_bins
[10];
91 int i_usec_100_bins
[10];
92 int i_msec_1_bins
[10];
93 int i_msec_10_bins
[5];
96 int i_min_latency
= 0;
97 long long i_total_latency
= 0;
100 int i_exceeded_threshold
= 0;
109 int num_of_usecs_to_sleep
= 1000;
111 #define N_HIGH_RES_BINS 500
112 int use_high_res_bins
= false;
113 int i_high_res_bins
[N_HIGH_RES_BINS
];
114 int i_highest_latency
= 0;
116 char *kernelpath
= (char *)0;
117 char *code_file
= (char *)0;
120 u_long k_sym_addr
; /* kernel symbol address from nm */
121 u_int k_sym_len
; /* length of kernel symbol string */
122 char *k_sym_name
; /* kernel symbol string from nm */
125 kern_sym_t
*kern_sym_tbl
; /* pointer to the nm table */
126 int kern_sym_count
; /* number of entries in nm table */
129 #define UNKNOWN "Can't find symbol name"
134 int trace_enabled
= 0;
135 struct host_basic_info hi
;
138 #define SAMPLE_SIZE 300000
144 kbufinfo_t bufinfo
= {0, 0, 0};
146 FILE *log_fp
= (FILE *)0;
147 int num_of_codes
= 0;
148 int need_new_map
= 0;
149 int total_threads
= 0;
150 kd_threadmap
*mapptr
= 0;
152 #define MAX_ENTRIES 4096
156 } codes_tab
[MAX_ENTRIES
];
164 uintptr_t child_thread
;
168 long pathname
[NUMPARMS
+ 1];
171 #define MAX_THREADS 512
172 struct th_info th_state
[MAX_THREADS
];
176 #define TRACE_DATA_NEWTHREAD 0x07000004
177 #define TRACE_STRING_NEWTHREAD 0x07010004
178 #define TRACE_STRING_EXEC 0x07010008
180 #define INTERRUPT 0x01050000
181 #define DECR_TRAP 0x01090000
182 #define DECR_SET 0x01090004
183 #define MACH_vmfault 0x01300008
184 #define MACH_sched 0x01400000
185 #define MACH_stkhandoff 0x01400008
186 #define VFS_LOOKUP 0x03010090
187 #define BSC_exit 0x040C0004
188 #define IES_action 0x050b0018
189 #define IES_filter 0x050b001c
190 #define TES_action 0x050c0010
191 #define CQ_action 0x050d0018
194 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
195 #define DBG_FUNC_MASK 0xfffffffc
197 #define CPU_NUMBER(kp) kdbg_get_cpu(kp)
200 char *fault_name
[9] = {
212 char *pc_to_string();
213 static kern_return_t
set_time_constraint_policy(void);
214 static kern_return_t
set_standard_policy(void);
216 int decrementer_val
= 0; /* Value used to reset decrementer */
217 int set_remove_flag
= 1; /* By default, remove trace buffer */
219 kd_buf
**last_decrementer_kd
; /* last DECR_TRAP per cpu */
220 #define MAX_LOG_COUNT 30 /* limits the number of entries dumped in log_decrementer */
234 This flag is turned off when calling
235 quit() due to a set_remove() failure.
254 mib
[1] = KERN_KDEBUG
;
255 mib
[2] = KERN_KDENABLE
; /* protocol */
258 mib
[5] = 0; /* no flags */
260 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
261 quit("trace facility failure, KERN_KDENABLE\n");
265 set_numbufs(int nbufs
)
268 mib
[1] = KERN_KDEBUG
;
269 mib
[2] = KERN_KDSETBUF
;
272 mib
[5] = 0; /* no flags */
273 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
274 quit("trace facility failure, KERN_KDSETBUF\n");
277 mib
[1] = KERN_KDEBUG
;
278 mib
[2] = KERN_KDSETUP
;
281 mib
[5] = 0; /* no flags */
282 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
283 quit("trace facility failure, KERN_KDSETUP\n");
288 set_pidexclude(int pid
, int on_off
)
292 kr
.type
= KDBG_TYPENONE
;
295 needed
= sizeof(kd_regtype
);
297 mib
[1] = KERN_KDEBUG
;
298 mib
[2] = KERN_KDPIDEX
;
303 sysctl(mib
, 3, &kr
, &needed
, NULL
, 0);
306 void set_rtcdec(decval
)
312 kr
.type
= KDBG_TYPENONE
;
314 needed
= sizeof(kd_regtype
);
316 mib
[1] = KERN_KDEBUG
;
317 mib
[2] = KERN_KDSETRTCDEC
; /* protocol */
318 mib
[3] = 0; /* wildcard address family */
320 mib
[5] = 0; /* no flags */
323 if ((ret
=sysctl(mib
, 3, &kr
, &needed
, NULL
, 0)) < 0)
326 /* ignore this sysctl error if it's not supported */
330 quit("trace facility failure, KERN_KDSETRTCDEC\n");
336 get_bufinfo(kbufinfo_t
*val
)
338 needed
= sizeof (*val
);
340 mib
[1] = KERN_KDEBUG
;
341 mib
[2] = KERN_KDGETBUF
;
344 mib
[5] = 0; /* no flags */
346 if (sysctl(mib
, 3, val
, &needed
, 0, 0) < 0)
347 quit("trace facility failure, KERN_KDGETBUF\n");
357 mib
[1] = KERN_KDEBUG
;
358 mib
[2] = KERN_KDREMOVE
; /* protocol */
361 mib
[5] = 0; /* no flags */
365 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
369 quit("the trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n");
371 quit("trace facility failure, KERN_KDREMOVE\n");
378 /* When we aren't logging, only collect the DECR_TRAP trace points */
380 kr
.type
= KDBG_VALCHECK
;
381 kr
.value1
= DECR_TRAP
;
385 needed
= sizeof(kd_regtype
);
387 mib
[1] = KERN_KDEBUG
;
388 mib
[2] = KERN_KDSETREG
;
391 mib
[5] = 0; /* no flags */
392 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
393 quit("trace facility failure, KERN_KDSETREG\n");
396 mib
[1] = KERN_KDEBUG
;
397 mib
[2] = KERN_KDSETUP
;
400 mib
[5] = 0; /* no flags */
402 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
403 quit("trace facility failure, KERN_KDSETUP\n");
410 kr
.type
= KDBG_RANGETYPE
;
413 needed
= sizeof(kd_regtype
);
415 mib
[1] = KERN_KDEBUG
;
416 mib
[2] = KERN_KDSETREG
;
419 mib
[5] = 0; /* no flags */
421 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
422 quit("trace facility failure, KERN_KDSETREG\n");
425 mib
[1] = KERN_KDEBUG
;
426 mib
[2] = KERN_KDSETUP
;
429 mib
[5] = 0; /* no flags */
431 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
432 quit("trace facility failure, KERN_KDSETUP\n");
436 write_high_res_latencies()
440 if(use_high_res_bins
)
442 f
= fopen("latencies.csv","w");
443 for(i
=0;i
<N_HIGH_RES_BINS
;i
++)
445 fprintf(f
,"%d,%d\n", i
, i_high_res_bins
[i
]);
458 void screen_update();
460 write_high_res_latencies();
463 set_pidexclude(getpid(), 0);
464 screen_update(log_fp
);
472 void leave() /* exit under normal conditions -- signal handler */
474 write_high_res_latencies();
477 set_pidexclude(getpid(), 0);
486 screen_update(FILE *fp
)
493 unsigned int average_s_latency
;
494 unsigned int average_i_latency
;
497 if (fp
== (FILE *)0) {
501 fprintf(fp
,"\n\n===================================================================================================\n");
503 * Display the current time.
504 * "ctime" always returns a string that looks like this:
506 * Sun Sep 16 01:03:52 1973
507 * 012345678901234567890123
510 * We want indices 11 thru 18 (length 8).
512 elapsed_secs
= curr_time
- start_time
;
513 elapsed_hours
= elapsed_secs
/ 3600;
514 elapsed_secs
-= elapsed_hours
* 3600;
515 elapsed_mins
= elapsed_secs
/ 60;
516 elapsed_secs
-= elapsed_mins
* 60;
518 sprintf(tbuf
, "%-19.19s %2ld:%02ld:%02ld\n", &(ctime(&curr_time
)[0]),
519 (long)elapsed_hours
, (long)elapsed_mins
, (long)elapsed_secs
);
521 fprintf(fp
, "%s", tbuf
);
525 if (use_high_res_bins
) {
526 sprintf(tbuf
, "INTERRUPTS(HIGH RESOLUTION)\n");
529 fprintf(fp
, "%s", tbuf
);
533 if(use_high_res_bins
)
535 for(i
=0;i
<N_HIGH_RES_BINS
;i
++) {
539 fprintf(fp
, "%s", tbuf
);
543 #define INDEX(i) ((i%10)*50 + (i/10))
544 if(INDEX(i
) <= i_highest_latency
)
545 sprintf(tbuf
,"[%3d]: %6d ", INDEX(i
), i_high_res_bins
[INDEX(i
)]);
550 fprintf(fp
, "%s", tbuf
);
554 sprintf(tbuf
,"\n\n");
556 fprintf(fp
, "%s", tbuf
);
561 sprintf(tbuf
, " SCHEDULER INTERRUPTS\n");
564 fprintf(fp
, "%s", tbuf
);
568 sprintf(tbuf
, "---------------------------------------------\n");
571 fprintf(fp
, "%s", tbuf
);
577 sprintf(tbuf
, "total_samples %10d %10d\n\n", s_total_samples
, i_total_samples
);
580 fprintf(fp
, "%s", tbuf
);
586 for (itotal
= 0, stotal
= 0, i
= 0; i
< 10; i
++) {
587 sprintf(tbuf
, "delays < %3d usecs %10d %10d\n", (i
+ 1) * 10, s_usec_10_bins
[i
], i_usec_10_bins
[i
]);
590 fprintf(fp
, "%s", tbuf
);
594 stotal
+= s_usec_10_bins
[i
];
595 itotal
+= i_usec_10_bins
[i
];
597 sprintf(tbuf
, "total < 100 usecs %10d %10d\n\n", stotal
, itotal
);
600 fprintf(fp
, "%s", tbuf
);
606 for (itotal
= 0, stotal
= 0, i
= 1; i
< 10; i
++) {
608 sprintf(tbuf
, "delays < %3d usecs %10d %10d\n", (i
+ 1) * 100, s_usec_100_bins
[i
], i_usec_100_bins
[i
]);
610 sprintf(tbuf
, "delays < 1 msec %10d %10d\n", s_usec_100_bins
[i
], i_usec_100_bins
[i
]);
613 fprintf(fp
, "%s", tbuf
);
617 stotal
+= s_usec_100_bins
[i
];
618 itotal
+= i_usec_100_bins
[i
];
620 sprintf(tbuf
, "total < 1 msec %10d %10d\n\n", stotal
, itotal
);
623 fprintf(fp
, "%s", tbuf
);
629 for (itotal
= 0, stotal
= 0, i
= 1; i
< 10; i
++) {
630 sprintf(tbuf
, "delays < %3d msecs %10d %10d\n", (i
+ 1), s_msec_1_bins
[i
], i_msec_1_bins
[i
]);
633 fprintf(fp
, "%s", tbuf
);
637 stotal
+= s_msec_1_bins
[i
];
638 itotal
+= i_msec_1_bins
[i
];
640 sprintf(tbuf
, "total < 10 msecs %10d %10d\n\n", stotal
, itotal
);
643 fprintf(fp
, "%s", tbuf
);
650 for (itotal
= 0, stotal
= 0, i
= 1; i
< 5; i
++) {
651 sprintf(tbuf
, "delays < %3d msecs %10d %10d\n", (i
+ 1)*10, s_msec_10_bins
[i
], i_msec_10_bins
[i
]);
654 fprintf(fp
, "%s", tbuf
);
658 stotal
+= s_msec_10_bins
[i
];
659 itotal
+= i_msec_10_bins
[i
];
661 sprintf(tbuf
, "total < 50 msecs %10d %10d\n\n", stotal
, itotal
);
664 fprintf(fp
, "%s", tbuf
);
668 sprintf(tbuf
, "delays > 50 msecs %10d %10d\n", s_too_slow
, i_too_slow
);
671 fprintf(fp
, "%s", tbuf
);
677 sprintf(tbuf
, "\nminimum latency(usecs) %7d %7d\n", s_min_latency
, i_min_latency
);
680 fprintf(fp
, "%s", tbuf
);
684 sprintf(tbuf
, "maximum latency(usecs) %7d %7d\n", s_max_latency
, i_max_latency
);
687 fprintf(fp
, "%s", tbuf
);
692 average_s_latency
= (unsigned int)(s_total_latency
/s_total_samples
);
694 average_s_latency
= 0;
697 average_i_latency
= (unsigned int)(i_total_latency
/i_total_samples
);
699 average_i_latency
= 0;
701 sprintf(tbuf
, "average latency(usecs) %7d %7d\n", average_s_latency
, average_i_latency
);
704 fprintf(fp
, "%s", tbuf
);
708 sprintf(tbuf
, "exceeded threshold %7d %7d\n", s_exceeded_threshold
, i_exceeded_threshold
);
711 fprintf(fp
, "%s", tbuf
);
725 fprintf(stderr
, "Usage: latency [-rt] [-h] [-c codefile] [-l logfile] [-st threshold]\n");
727 #if defined (__i386__)
728 fprintf(stderr
, " [-it threshold] [-s sleep_in_usecs] [-n kernel]\n\n");
730 fprintf(stderr
, " [-it threshold] [-s sleep_in_usecs]\n");
731 fprintf(stderr
, " [-d decrementer_in_usecs] [-n kernel]\n\n");
735 fprintf(stderr
, " -rt Set realtime scheduling policy. Default is timeshare.\n");
736 fprintf(stderr
, " -h Display high resolution interrupt latencies and write them to latencies.csv (truncate existing file) upon exit.\n");
737 fprintf(stderr
, " -c specify name of codes file\n");
738 fprintf(stderr
, " -l specify name of file to log trace entries to when threshold is exceeded\n");
739 fprintf(stderr
, " -st set scheduler latency threshold in microseconds... if latency exceeds this, then log trace\n");
740 fprintf(stderr
, " -it set interrupt latency threshold in microseconds... if latency exceeds this, then log trace\n");
741 fprintf(stderr
, " -s set sleep time in microseconds\n");
742 #if !defined (__i386__)
743 fprintf(stderr
, " -d set decrementer in microseconds.\n");
745 fprintf(stderr
, " -n specify kernel, default is /mach_kernel\n");
747 fprintf(stderr
, "\nlatency must be run as root\n\n");
754 main(int argc
, char *argv
[])
756 uint64_t start
, stop
;
759 uint64_t adeadline
, adelay
;
762 double nanosecs_to_sleep
;
763 int loop_cnt
, sample_sc_now
;
764 int decrementer_usec
= 0;
767 host_name_port_t host
;
770 void init_code_file();
774 if (0 != reexec_to_match_kernel()) {
775 fprintf(stderr
, "Could not re-execute: %d\n", errno
);
779 my_policy
= THREAD_STANDARD_POLICY
;
780 policy_name
= "TIMESHARE";
783 if (strcmp(argv
[1], "-rt") == 0) {
784 my_policy
= THREAD_TIME_CONSTRAINT_POLICY
; /* the real time band */
785 policy_name
= "REALTIME";
787 } else if (strcmp(argv
[1], "-st") == 0) {
792 s_thresh_hold
= atoi(argv
[1]);
796 } else if (strcmp(argv
[1], "-it") == 0) {
801 i_thresh_hold
= atoi(argv
[1]);
804 } else if (strcmp(argv
[1], "-c") == 0) {
812 } else if (strcmp(argv
[1], "-l") == 0) {
817 open_logfile(argv
[1]);
821 } else if (strcmp(argv
[1], "-s") == 0) {
826 num_of_usecs_to_sleep
= atoi(argv
[1]);
830 else if (strcmp(argv
[1], "-d") == 0) {
835 decrementer_usec
= atoi(argv
[1]);
838 #if defined(__i386__)
839 /* ignore this option - setting the decrementer has no effect */
840 decrementer_usec
= 0;
843 else if (strcmp(argv
[1], "-n") == 0) {
848 kernelpath
= argv
[1];
851 } else if (strcmp(argv
[1], "-h") == 0) {
852 use_high_res_bins
= true;
860 if ( geteuid() != 0 ) {
861 printf("'latency' must be run as root...\n");
865 if (kernelpath
== (char *) 0)
866 kernelpath
= "/mach_kernel";
868 if (code_file
== (char *) 0)
869 code_file
= "/usr/share/misc/trace.codes";
873 sample_sc_now
= 25000 / num_of_usecs_to_sleep
;
876 decrementer_val
= decrementer_usec
* divisor
;
878 /* get the cpu countfor the DECR_TRAP array */
879 host
= mach_host_self();
880 size
= sizeof(hi
)/sizeof(int);
881 ret
= host_info(host
, HOST_BASIC_INFO
, (host_info_t
)&hi
, &size
);
882 if (ret
!= KERN_SUCCESS
) {
883 mach_error(argv
[0], ret
);
887 if ((last_decrementer_kd
= (kd_buf
**)malloc(hi
.max_cpus
* sizeof(kd_buf
*))) == (kd_buf
**)0)
888 quit("can't allocate memory for decrementer tracing info\n");
890 nanosecs_to_sleep
= (double)(num_of_usecs_to_sleep
* 1000);
891 fdelay
= nanosecs_to_sleep
* (divisor
/1000);
892 adelay
= (uint64_t)fdelay
;
897 When the decrementer isn't set in the options,
898 decval will be zero and this call will reset
899 the system default ...
901 set_rtcdec(decrementer_val
);
903 if (initscr() == (WINDOW
*) 0)
905 printf("Unrecognized TERM type, try vt100\n");
911 signal(SIGWINCH
, sigwinch
);
912 signal(SIGINT
, sigintr
);
913 signal(SIGQUIT
, leave
);
914 signal(SIGTERM
, leave
);
915 signal(SIGHUP
, leave
);
918 if ((my_buffer
= malloc(SAMPLE_SIZE
* sizeof(kd_buf
))) == (char *)0)
919 quit("can't allocate memory for tracing info\n");
921 set_numbufs(SAMPLE_SIZE
);
926 set_init_nologging();
927 set_pidexclude(getpid(), 1);
933 start_time
= time((long *)0);
934 refresh_time
= start_time
;
936 if (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
)
938 /* the realtime band */
939 if(set_time_constraint_policy() != KERN_SUCCESS
)
940 quit("Failed to set realtime policy.\n");
944 curr_time
= time((long *)0);
946 if (curr_time
>= refresh_time
) {
947 if (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
)
949 /* set standard timeshare policy during screen update */
950 if(set_standard_policy() != KERN_SUCCESS
)
951 quit("Failed to set standard policy.\n");
953 screen_update((FILE *)0);
954 if (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
)
956 /* set back to realtime band */
957 if(set_time_constraint_policy() != KERN_SUCCESS
)
958 quit("Failed to set time_constraint policy.\n");
960 refresh_time
= curr_time
+ 1;
963 timestamp1
= mach_absolute_time();
964 adeadline
= timestamp1
+ adelay
;
965 mach_wait_until(adeadline
);
966 timestamp2
= mach_absolute_time();
972 elapsed_usecs
= (int)(((double)(stop
- start
)) / divisor
);
974 if ((elapsed_usecs
-= num_of_usecs_to_sleep
) <= 0)
977 if (elapsed_usecs
< 100)
978 s_usec_10_bins
[elapsed_usecs
/10]++;
979 if (elapsed_usecs
< 1000)
980 s_usec_100_bins
[elapsed_usecs
/100]++;
981 else if (elapsed_usecs
< 10000)
982 s_msec_1_bins
[elapsed_usecs
/1000]++;
983 else if (elapsed_usecs
< 50000)
984 s_msec_10_bins
[elapsed_usecs
/10000]++;
988 if (elapsed_usecs
> s_max_latency
)
989 s_max_latency
= elapsed_usecs
;
990 if (elapsed_usecs
< s_min_latency
|| s_total_samples
== 0)
991 s_min_latency
= elapsed_usecs
;
992 s_total_latency
+= elapsed_usecs
;
995 if (s_thresh_hold
&& elapsed_usecs
> s_thresh_hold
)
996 s_exceeded_threshold
++;
999 if (log_fp
&& s_thresh_hold
&& elapsed_usecs
> s_thresh_hold
)
1000 sample_sc(start
, stop
);
1002 if (loop_cnt
>= sample_sc_now
) {
1003 sample_sc((long long)0, (long long)0);
1009 No need to check for initscr error return.
1010 We won't get here if it fails on the first call.
1024 mach_timebase_info_data_t info
;
1026 (void) mach_timebase_info (&info
);
1028 divisor
= ( (double)info
.denom
/ (double)info
.numer
) * 1000;
1032 /* This is the realtime band */
1033 static kern_return_t
1034 set_time_constraint_policy()
1036 kern_return_t result
;
1037 thread_time_constraint_policy_data_t info
;
1038 mach_msg_type_number_t count
;
1039 boolean_t get_default
;
1042 count
= THREAD_TIME_CONSTRAINT_POLICY_COUNT
;
1043 result
= thread_policy_get(mach_thread_self(), THREAD_TIME_CONSTRAINT_POLICY
,
1044 (thread_policy_t
)&info
, &count
, &get_default
);
1045 if (result
!= KERN_SUCCESS
)
1048 result
= thread_policy_set(mach_thread_self(), THREAD_TIME_CONSTRAINT_POLICY
,
1049 (thread_policy_t
)&info
, THREAD_TIME_CONSTRAINT_POLICY_COUNT
);
1054 /* This is the timeshare mode */
1055 static kern_return_t
1056 set_standard_policy()
1058 kern_return_t result
;
1059 thread_standard_policy_data_t info
;
1060 mach_msg_type_number_t count
;
1061 boolean_t get_default
;
1064 count
= THREAD_STANDARD_POLICY_COUNT
;
1065 result
= thread_policy_get(mach_thread_self(), THREAD_STANDARD_POLICY
,
1066 (thread_policy_t
)&info
, &count
, &get_default
);
1067 if (result
!= KERN_SUCCESS
)
1070 result
= thread_policy_set(mach_thread_self(), THREAD_STANDARD_POLICY
,
1071 (thread_policy_t
)&info
, THREAD_STANDARD_POLICY_COUNT
);
1077 void read_command_map()
1086 total_threads
= bufinfo
.nkdthreads
;
1087 size
= bufinfo
.nkdthreads
* sizeof(kd_threadmap
);
1090 if ((mapptr
= (kd_threadmap
*) malloc(size
)))
1091 bzero (mapptr
, size
);
1094 printf("Thread map is not initialized -- this is not fatal\n");
1099 /* Now read the threadmap */
1101 mib
[1] = KERN_KDEBUG
;
1102 mib
[2] = KERN_KDTHRMAP
;
1105 mib
[5] = 0; /* no flags */
1106 if (sysctl(mib
, 3, mapptr
, &size
, NULL
, 0) < 0)
1108 /* This is not fatal -- just means I cant map command strings */
1110 printf("Can't read the thread map -- this is not fatal\n");
1119 void create_map_entry(uintptr_t thread
, char *command
)
1127 for (i
= 0, map
= 0; !map
&& i
< total_threads
; i
++)
1129 if (mapptr
[i
].thread
== thread
)
1130 map
= &mapptr
[i
]; /* Reuse this entry, the thread has been reassigned */
1133 if (!map
) /* look for invalid entries that I can reuse*/
1135 for (i
= 0, map
= 0; !map
&& i
< total_threads
; i
++)
1137 if (mapptr
[i
].valid
== 0 )
1138 map
= &mapptr
[i
]; /* Reuse this invalid entry */
1144 /* If reach here, then this is a new thread and
1145 * there are no invalid entries to reuse
1146 * Double the size of the thread map table.
1149 n
= total_threads
* 2;
1150 mapptr
= (kd_threadmap
*) realloc(mapptr
, n
* sizeof(kd_threadmap
));
1151 bzero(&mapptr
[total_threads
], total_threads
*sizeof(kd_threadmap
));
1152 map
= &mapptr
[total_threads
];
1156 fprintf(log_fp
, "MAP: increasing thread map to %d entries\n", total_threads
);
1161 fprintf(log_fp
, "MAP: adding thread %x with name %s\n", thread
, command
);
1164 map
->thread
= thread
;
1166 The trace entry that returns the command name will hold
1167 at most, MAXCOMLEN chars, and in that case, is not
1168 guaranteed to be null terminated.
1170 (void)strncpy (map
->command
, command
, MAXCOMLEN
);
1171 map
->command
[MAXCOMLEN
] = '\0';
1175 kd_threadmap
*find_thread_map(uintptr_t thread
)
1181 return((kd_threadmap
*)0);
1183 for (i
= 0; i
< total_threads
; i
++)
1186 if (map
->valid
&& (map
->thread
== thread
))
1191 return ((kd_threadmap
*)0);
1195 kill_thread_map(uintptr_t thread
)
1199 if ((map
= find_thread_map(thread
))) {
1203 fprintf(log_fp
, "MAP: deleting thread %x with name %s\n", thread
, map
->command
);
1207 map
->command
[0] = '\0';
1212 struct th_info
*find_thread(uintptr_t thread
, int type1
, int type2
) {
1215 for (ti
= th_state
; ti
< &th_state
[cur_max
]; ti
++) {
1216 if (ti
->thread
== thread
) {
1219 if (type1
== ti
->type
)
1221 if (type2
== ti
->type
)
1225 return ((struct th_info
*)0);
1229 char *find_code(type
)
1233 for (i
= 0; i
< num_of_codes
; i
++) {
1234 if (codes_tab
[i
].type
== type
)
1235 return(codes_tab
[i
].name
);
1241 void sample_sc(uint64_t start
, uint64_t stop
)
1243 kd_buf
*kd
, *last_mach_sched
, *start_kd
, *end_of_sample
;
1246 int first_entry
= 1;
1247 double timestamp
= 0.0;
1248 double last_timestamp
= 0.0;
1250 double start_bias
= 0.0;
1252 void read_command_map();
1254 if (log_fp
&& (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
))
1256 /* set standard timeshare policy when logging */
1257 if(set_standard_policy() != KERN_SUCCESS
)
1258 quit("Failed to set standard policy.\n");
1261 /* Get kernel buffer information */
1262 get_bufinfo(&bufinfo
);
1268 needed
= bufinfo
.nkdbufs
* sizeof(kd_buf
);
1270 mib
[1] = KERN_KDEBUG
;
1271 mib
[2] = KERN_KDREADTR
;
1274 mib
[5] = 0; /* no flags */
1276 if (sysctl(mib
, 3, my_buffer
, &needed
, NULL
, 0) < 0)
1277 quit("trace facility failure, KERN_KDREADTR\n");
1281 if (bufinfo
.flags
& KDBG_WRAPPED
) {
1282 for (i
= 0; i
< cur_max
; i
++) {
1283 th_state
[i
].thread
= 0;
1284 th_state
[i
].type
= -1;
1285 th_state
[i
].pathptr
= (long *)NULL
;
1286 th_state
[i
].pathname
[0] = 0;
1297 latency
= (double)(stop
- start
) / divisor
;
1298 latency
-= (double)num_of_usecs_to_sleep
;
1300 fprintf(log_fp
, "\n\n%-19.19s scheduling latency = %.1fus num_of_traces = %d <<<<<<< trace buffer wrapped >>>>>>>\n\n",
1301 &(ctime(&curr_time
)[0]), latency
, count
);
1304 end_of_sample
= &((kd_buf
*)my_buffer
)[count
];
1306 /* Always reinitialize the DECR_TRAP array */
1307 for (i
=0; i
< hi
.max_cpus
; i
++)
1308 last_decrementer_kd
[i
] = (kd_buf
*)my_buffer
;
1310 last_mach_sched
= (kd_buf
*)0;
1312 for (kd
= (kd_buf
*)my_buffer
; kd
< end_of_sample
; kd
++) {
1313 int debugid
, thread
, cpunum
;
1314 int type
, clen
, mode
;
1319 double i_latency
= 0.0;
1322 char sched_info
[64];
1324 kd_threadmap
*find_thread_map();
1325 double handle_decrementer();
1326 kd_buf
*log_decrementer();
1327 int check_for_thread_update();
1328 void enter_syscall();
1329 void exit_syscall();
1333 cpunum
= CPU_NUMBER(kd
);
1334 debugid
= kd
->debugid
;
1335 type
= kd
->debugid
& DBG_FUNC_MASK
;
1337 if (check_for_thread_update(thread
, type
, kd
))
1340 if (type
== DECR_TRAP
)
1341 i_latency
= handle_decrementer(kd
);
1343 now
= kd
->timestamp
& KDBG_TIMESTAMP_MASK
;
1345 timestamp
= ((double)now
) / divisor
;
1347 if (now
< start
|| now
> stop
) {
1348 if (debugid
& DBG_FUNC_START
)
1349 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 0);
1350 else if (debugid
& DBG_FUNC_END
)
1351 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 0);
1352 else if (type
== DECR_TRAP
) {
1354 if (log_fp
&& i_thresh_hold
&& (int)i_latency
> i_thresh_hold
) {
1355 start_kd
= last_decrementer_kd
[cpunum
];
1356 kd
= log_decrementer(start_kd
, kd
, end_of_sample
, i_latency
);
1357 if (kd
>= end_of_sample
)
1360 if ((kd
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1362 cpunum
= CPU_NUMBER(kd
);
1363 last_decrementer_kd
[cpunum
] = kd
;
1366 last_decrementer_kd
[cpunum
] = cur_kd
;
1375 latency
= (double)(stop
- start
) / divisor
;
1376 latency
-= (double)num_of_usecs_to_sleep
;
1379 sprintf(buf2
, "default");
1381 sprintf(buf2
, "%d", my_pri
);
1382 sprintf(buf1
, "%-19.19s scheduling latency = %.1fus sleep_request = %dus policy = %s priority = %s",
1383 &(ctime(&curr_time
)[0]), latency
, num_of_usecs_to_sleep
, policy_name
, buf2
);
1384 clen
= strlen(buf1
);
1385 memset(buf2
, '-', clen
);
1389 fprintf(log_fp
, "\n\n%s\n", buf2
);
1390 fprintf(log_fp
, "%s\n\n", buf1
);
1391 fprintf(log_fp
, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
1393 start_bias
= ((double)start
) / divisor
;
1394 last_timestamp
= timestamp
;
1397 delta
= timestamp
- last_timestamp
;
1399 if ((map
= find_thread_map(thread
)))
1400 strcpy(command
, map
->command
);
1408 fprintf(log_fp
, "%9.1f %8.1f\t\tCQ_action @ %-59.59s %-8x %d %s\n",
1409 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 59, 1) , thread
, cpunum
, command
);
1411 last_timestamp
= timestamp
;
1416 fprintf(log_fp
, "%9.1f %8.1f\t\tTES_action @ %-58.58s %-8x %d %s\n",
1417 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 58, 1) , thread
, cpunum
, command
);
1420 last_timestamp
= timestamp
;
1425 fprintf(log_fp
, "%9.1f %8.1f\t\tIES_action @ %-58.58s %-8x %d %s\n",
1426 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 58, 1) , thread
, cpunum
, command
);
1429 last_timestamp
= timestamp
;
1434 fprintf(log_fp
, "%9.1f %8.1f\t\tIES_filter @ %-58.58s %-8x %d %s\n",
1435 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 58, 1) , thread
, cpunum
, command
);
1438 last_timestamp
= timestamp
;
1442 last_decrementer_kd
[cpunum
] = kd
;
1444 if (i_thresh_hold
&& (int)i_latency
> i_thresh_hold
)
1451 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1452 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1457 fprintf(log_fp
, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-59.59s %-8x %d %s\n",
1458 timestamp
- start_bias
, delta
, i_latency
, p
, pc_to_string(kd
->arg2
, 59, mode
) , thread
, cpunum
, command
);
1461 last_timestamp
= timestamp
;
1466 fprintf(log_fp
, "%9.1f %8.1f[%.1f] \t%-28.28s %-8x %d %s\n",
1467 timestamp
- start_bias
, delta
, (double)kd
->arg1
/divisor
, "DECR_SET", thread
, cpunum
, command
);
1470 last_timestamp
= timestamp
;
1474 case MACH_stkhandoff
:
1475 last_mach_sched
= kd
;
1477 if ((map
= find_thread_map(kd
->arg2
)))
1478 strcpy(command1
, map
->command
);
1480 sprintf(command1
, "%-8x", kd
->arg2
);
1482 if ((ti
= find_thread(kd
->arg2
, 0, 0))) {
1483 if (ti
->type
== -1 && strcmp(command1
, "kernel_task"))
1489 memset(sched_info
, ' ', sizeof(sched_info
));
1491 sprintf(sched_info
, "%14.14s", command
);
1492 clen
= strlen(sched_info
);
1493 sched_info
[clen
] = ' ';
1495 sprintf(&sched_info
[14], " @ pri %3d --> %14.14s", kd
->arg3
, command1
);
1496 clen
= strlen(sched_info
);
1497 sched_info
[clen
] = ' ';
1499 sprintf(&sched_info
[45], " @ pri %3d%s", kd
->arg4
, p
);
1502 fprintf(log_fp
, "%9.1f %8.1f\t\t%-10.10s %s %-8x %d\n",
1503 timestamp
- start_bias
, delta
, "MACH_SCHED", sched_info
, thread
, cpunum
);
1506 last_timestamp
= timestamp
;
1510 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1511 if (cur_max
>= MAX_THREADS
)
1513 ti
= &th_state
[cur_max
++];
1515 ti
->thread
= thread
;
1517 ti
->pathptr
= (long *)0;
1518 ti
->child_thread
= 0;
1520 while ( (kd
< end_of_sample
) && ((kd
->debugid
& DBG_FUNC_MASK
) == VFS_LOOKUP
))
1522 if (ti
->pathptr
== NULL
) {
1523 ti
->arg1
= kd
->arg1
;
1524 sargptr
= ti
->pathname
;
1526 *sargptr
++ = kd
->arg2
;
1527 *sargptr
++ = kd
->arg3
;
1528 *sargptr
++ = kd
->arg4
;
1530 * NULL terminate the 'string'
1533 ti
->pathptr
= sargptr
;
1536 sargptr
= ti
->pathptr
;
1539 We don't want to overrun our pathname buffer if the
1540 kernel sends us more VFS_LOOKUP entries than we can
1544 if (sargptr
>= &ti
->pathname
[NUMPARMS
])
1551 We need to detect consecutive vfslookup entries.
1552 So, if we get here and find a START entry,
1553 fake the pathptr so we can bypass all further
1557 if (kd
->debugid
& DBG_FUNC_START
)
1559 ti
->pathptr
= &ti
->pathname
[NUMPARMS
];
1563 *sargptr
++ = kd
->arg1
;
1564 *sargptr
++ = kd
->arg2
;
1565 *sargptr
++ = kd
->arg3
;
1566 *sargptr
++ = kd
->arg4
;
1568 * NULL terminate the 'string'
1572 ti
->pathptr
= sargptr
;
1577 p
= (char *)ti
->pathname
;
1581 /* print the tail end of the pathname */
1589 fprintf(log_fp
, "%9.1f %8.1f\t\t%-14.14s %-42s %-8x %-8x %d %s\n",
1590 timestamp
- start_bias
, delta
, "VFS_LOOKUP",
1591 &p
[len
], ti
->arg1
, thread
, cpunum
, command
);
1594 last_timestamp
= timestamp
;
1598 if (debugid
& DBG_FUNC_START
)
1599 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
1600 else if (debugid
& DBG_FUNC_END
)
1601 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
1603 print_entry(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
);
1605 last_timestamp
= timestamp
;
1609 if (last_mach_sched
&& log_fp
)
1610 fprintf(log_fp
, "\nblocked by %s @ priority %d\n", command
, last_mach_sched
->arg3
);
1612 if (first_entry
== 0 && log_fp
)
1613 fprintf(log_fp
, "\n start = %qd stop = %qd count = %d now = %qd\n", start
, stop
, count
, now
);
1618 if (log_fp
&& (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
))
1620 /* set back to realtime band */
1621 if(set_time_constraint_policy() != KERN_SUCCESS
)
1622 quit("Failed to set time_constraint policy.\n");
1627 enter_syscall(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
, int print_info
)
1634 cpunum
= CPU_NUMBER(kd
);
1636 if (print_info
&& fp
) {
1637 if ((p
= find_code(type
))) {
1638 if (type
== INTERRUPT
) {
1641 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1642 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1646 fprintf(fp
, "%9.1f %8.1f\t\tINTERRUPT @ %-59.59s %-8x %d %s\n",
1647 timestamp
- bias
, delta
, pc_to_string(kd
->arg2
, 59, mode
), thread
, cpunum
, command
);
1648 } else if (type
== MACH_vmfault
) {
1649 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %d %s\n",
1650 timestamp
- bias
, delta
, p
, thread
, cpunum
, command
);
1652 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %-8x %-8x %-8x %-8x %d %s\n",
1653 timestamp
- bias
, delta
, p
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1654 thread
, cpunum
, command
);
1657 fprintf(fp
, "%9.1f %8.1f\t\t%-8x %-8x %-8x %-8x %-8x %-8x %d %s\n",
1658 timestamp
- bias
, delta
, type
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1659 thread
, cpunum
, command
);
1662 if ((ti
= find_thread(thread
, -1, type
)) == (struct th_info
*)0) {
1663 if (cur_max
>= MAX_THREADS
) {
1664 static int do_this_once
= 1;
1667 for (i
= 0; i
< cur_max
; i
++) {
1670 fprintf(fp
, "thread = %x, type = %x\n",
1671 th_state
[i
].thread
, th_state
[i
].type
);
1678 ti
= &th_state
[cur_max
++];
1680 ti
->thread
= thread
;
1681 ti
->child_thread
= 0;
1683 if (type
!= BSC_exit
)
1687 ti
->stime
= timestamp
;
1688 ti
->pathptr
= (long *)NULL
;
1691 if (print_info
&& fp
)
1692 fprintf(fp
, "cur_max = %d, ti = %x, type = %x, thread = %x\n", cur_max
, ti
, ti
->type
, ti
->thread
);
1698 exit_syscall(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
, int print_info
)
1705 cpunum
= CPU_NUMBER(kd
);
1707 ti
= find_thread(thread
, type
, type
);
1709 if (print_info
&& fp
)
1710 fprintf(fp
, "cur_max = %d, ti = %x, type = %x, thread = %x\n", cur_max
, ti
, type
, thread
);
1712 if (print_info
&& fp
) {
1714 fprintf(fp
, "%9.1f %8.1f(%.1f) \t", timestamp
- bias
, delta
, timestamp
- ti
->stime
);
1716 fprintf(fp
, "%9.1f %8.1f() \t", timestamp
- bias
, delta
);
1718 if ((p
= find_code(type
))) {
1719 if (type
== INTERRUPT
) {
1720 fprintf(fp
, "INTERRUPT %-8x %d %s\n", thread
, cpunum
, command
);
1721 } else if (type
== MACH_vmfault
&& kd
->arg4
<= DBG_PAGEIND_FAULT
) {
1722 user_addr
= ((uint64_t)kd
->arg1
<< 32) | (uint32_t)kd
->arg2
;
1724 fprintf(fp
, "%-28.28s %-10.10s %-16qx %-8x %d %s\n",
1725 p
, fault_name
[kd
->arg4
], user_addr
,
1726 thread
, cpunum
, command
);
1728 fprintf(fp
, "%-28.28s %-8x %-8x %-8x %d %s\n",
1729 p
, kd
->arg1
, kd
->arg2
,
1730 thread
, cpunum
, command
);
1733 fprintf(fp
, "%-8x %-8x %-8x %-8x %d %s\n",
1734 type
, kd
->arg1
, kd
->arg2
,
1735 thread
, cpunum
, command
);
1738 if (ti
== (struct th_info
*)0) {
1739 if ((ti
= find_thread(thread
, -1, -1)) == (struct th_info
*)0) {
1740 if (cur_max
>= MAX_THREADS
)
1742 ti
= &th_state
[cur_max
++];
1744 ti
->thread
= thread
;
1745 ti
->child_thread
= 0;
1746 ti
->pathptr
= (long *)NULL
;
1753 print_entry(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
)
1761 cpunum
= CPU_NUMBER(kd
);
1763 fprintf(fp
, "cur_max = %d, type = %x, thread = %x, cpunum = %d\n", cur_max
, type
, thread
, cpunum
);
1765 if ((p
= find_code(type
))) {
1766 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %-8x %-8x %-8x %-8x %d %s\n",
1767 timestamp
- bias
, delta
, p
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1768 thread
, cpunum
, command
);
1770 fprintf(fp
, "%9.1f %8.1f\t\t%-8x %-8x %-8x %-8x %-8x %-8x %d %s\n",
1771 timestamp
- bias
, delta
, type
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1772 thread
, cpunum
, command
);
1777 check_for_thread_update(int thread
, int type
, kd_buf
*kd
)
1780 void create_map_entry();
1784 case TRACE_DATA_NEWTHREAD
:
1785 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1786 if (cur_max
>= MAX_THREADS
)
1788 ti
= &th_state
[cur_max
++];
1790 ti
->thread
= thread
;
1792 ti
->pathptr
= (long *)NULL
;
1794 ti
->child_thread
= kd
->arg1
;
1797 case TRACE_STRING_NEWTHREAD
:
1798 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0)
1800 if (ti
->child_thread
== 0)
1802 create_map_entry(ti
->child_thread
, (char *)&kd
->arg1
);
1804 ti
->child_thread
= 0;
1807 case TRACE_STRING_EXEC
:
1808 create_map_entry(thread
, (char *)&kd
->arg1
);
1816 kd_buf
*log_decrementer(kd_buf
*kd_beg
, kd_buf
*kd_end
, kd_buf
*end_of_sample
, double i_latency
)
1818 kd_buf
*kd
, *kd_start
, *kd_stop
;
1819 int kd_count
; /* Limit the boundary of kd_start */
1820 double timestamp
= 0.0;
1821 double last_timestamp
= 0.0;
1823 double start_bias
= 0.0;
1825 int debugid
, type
, clen
;
1833 char sched_info
[64];
1837 kd_threadmap
*find_thread_map();
1839 sprintf(buf1
, "%-19.19s interrupt latency = %.1fus", &(ctime(&curr_time
)[0]), i_latency
);
1840 clen
= strlen(buf1
);
1841 memset(buf2
, '-', clen
);
1843 fprintf(log_fp
, "\n\n%s\n", buf2
);
1844 fprintf(log_fp
, "%s\n\n", buf1
);
1846 fprintf(log_fp
, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
1848 thread
= kd_beg
->arg5
;
1849 cpunum
= CPU_NUMBER(kd_end
);
1851 for (kd_count
= 0, kd_start
= kd_beg
- 1; (kd_start
>= (kd_buf
*)my_buffer
); kd_start
--, kd_count
++) {
1852 if (kd_count
== MAX_LOG_COUNT
)
1855 if (CPU_NUMBER(kd_start
) != cpunum
)
1858 if ((kd_start
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1861 if (kd_start
->arg5
!= thread
)
1865 if (kd_start
< (kd_buf
*)my_buffer
)
1866 kd_start
= (kd_buf
*)my_buffer
;
1868 thread
= kd_end
->arg5
;
1870 for (kd_stop
= kd_end
+ 1; kd_stop
< end_of_sample
; kd_stop
++) {
1872 if ((kd_stop
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1875 if (CPU_NUMBER(kd_stop
) != cpunum
)
1878 if (kd_stop
->arg5
!= thread
)
1882 if (kd_stop
>= end_of_sample
)
1883 kd_stop
= end_of_sample
- 1;
1885 now
= kd_start
->timestamp
& KDBG_TIMESTAMP_MASK
;
1886 timestamp
= ((double)now
) / divisor
;
1888 for (kd
= kd_start
; kd
<= kd_stop
; kd
++) {
1889 type
= kd
->debugid
& DBG_FUNC_MASK
;
1891 if ((ti
= find_thread(kd
->arg5
, type
, type
))) {
1892 if (ti
->stime
>= timestamp
)
1896 for (kd
= kd_start
; kd
<= kd_stop
; kd
++) {
1900 cpunum
= CPU_NUMBER(kd
);
1901 debugid
= kd
->debugid
;
1902 type
= kd
->debugid
& DBG_FUNC_MASK
;
1904 now
= kd
->timestamp
& KDBG_TIMESTAMP_MASK
;
1906 timestamp
= ((double)now
) / divisor
;
1908 if (kd
== kd_start
) {
1909 start_bias
= timestamp
;
1910 last_timestamp
= timestamp
;
1912 delta
= timestamp
- last_timestamp
;
1914 if ((map
= find_thread_map(thread
)))
1915 strcpy(command
, map
->command
);
1923 fprintf(log_fp
, "%9.1f %8.1f\t\tCQ_action @ %-59.59s %-8x %d %s\n",
1924 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 59, 1) , thread
, cpunum
, command
);
1926 last_timestamp
= timestamp
;
1930 if ((int)(kd
->arg1
) >= 0)
1933 i_latency
= (((double)(-1 - kd
->arg1
)) / divisor
);
1935 if (i_thresh_hold
&& (int)i_latency
> i_thresh_hold
)
1942 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1943 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1946 fprintf(log_fp
, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-59.59s %-8x %d %s\n",
1947 timestamp
- start_bias
, delta
, i_latency
, p
, pc_to_string(kd
->arg2
, 59, mode
) , thread
, cpunum
, command
);
1949 last_timestamp
= timestamp
;
1953 fprintf(log_fp
, "%9.1f %8.1f[%.1f] \t%-28.28s %-8x %d %s\n",
1954 timestamp
- start_bias
, delta
, (double)kd
->arg1
/divisor
,
1955 "DECR_SET", thread
, cpunum
, command
);
1957 last_timestamp
= timestamp
;
1961 case MACH_stkhandoff
:
1962 if ((map
= find_thread_map(kd
->arg2
)))
1963 strcpy(command1
, map
->command
);
1965 sprintf(command1
, "%-8x", kd
->arg2
);
1967 if ((ti
= find_thread(kd
->arg2
, 0, 0))) {
1968 if (ti
->type
== -1 && strcmp(command1
, "kernel_task"))
1974 memset(sched_info
, ' ', sizeof(sched_info
));
1976 sprintf(sched_info
, "%14.14s", command
);
1977 clen
= strlen(sched_info
);
1978 sched_info
[clen
] = ' ';
1980 sprintf(&sched_info
[14], " @ pri %3d --> %14.14s", kd
->arg3
, command1
);
1981 clen
= strlen(sched_info
);
1982 sched_info
[clen
] = ' ';
1984 sprintf(&sched_info
[45], " @ pri %3d%s", kd
->arg4
, p
);
1986 fprintf(log_fp
, "%9.1f %8.1f\t\t%-10.10s %s %-8x %d\n",
1987 timestamp
- start_bias
, delta
, "MACH_SCHED", sched_info
, thread
, cpunum
);
1989 last_timestamp
= timestamp
;
1993 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1994 if (cur_max
>= MAX_THREADS
)
1996 ti
= &th_state
[cur_max
++];
1998 ti
->thread
= thread
;
2000 ti
->pathptr
= (long *)NULL
;
2001 ti
->child_thread
= 0;
2004 while ( (kd
<= kd_stop
) && (kd
->debugid
& DBG_FUNC_MASK
) == VFS_LOOKUP
)
2006 if (ti
->pathptr
== NULL
) {
2007 ti
->arg1
= kd
->arg1
;
2008 sargptr
= ti
->pathname
;
2010 *sargptr
++ = kd
->arg2
;
2011 *sargptr
++ = kd
->arg3
;
2012 *sargptr
++ = kd
->arg4
;
2014 * NULL terminate the 'string'
2018 ti
->pathptr
= sargptr
;
2021 sargptr
= ti
->pathptr
;
2024 We don't want to overrun our pathname buffer if the
2025 kernel sends us more VFS_LOOKUP entries than we can
2029 if (sargptr
>= &ti
->pathname
[NUMPARMS
])
2036 We need to detect consecutive vfslookup entries.
2037 So, if we get here and find a START entry,
2038 fake the pathptr so we can bypass all further
2042 if (kd
->debugid
& DBG_FUNC_START
)
2044 ti
->pathptr
= &ti
->pathname
[NUMPARMS
];
2048 *sargptr
++ = kd
->arg1
;
2049 *sargptr
++ = kd
->arg2
;
2050 *sargptr
++ = kd
->arg3
;
2051 *sargptr
++ = kd
->arg4
;
2053 * NULL terminate the 'string'
2057 ti
->pathptr
= sargptr
;
2062 p
= (char *)ti
->pathname
;
2065 /* print the tail end of the pathname */
2072 fprintf(log_fp
, "%9.1f %8.1f\t\t%-14.14s %-42s %-8x %-8x %d %s\n",
2073 timestamp
- start_bias
, delta
, "VFS_LOOKUP",
2074 &p
[len
], ti
->arg1
, thread
, cpunum
, command
);
2076 last_timestamp
= timestamp
;
2080 if (debugid
& DBG_FUNC_START
)
2081 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
2082 else if (debugid
& DBG_FUNC_END
)
2083 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
2085 print_entry(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
);
2087 last_timestamp
= timestamp
;
2095 double handle_decrementer(kd_buf
*kd
)
2100 if ((long)(kd
->arg1
) >= 0)
2103 latency
= (((double)(-1 - kd
->arg1
)) / divisor
);
2104 elapsed_usecs
= (long)latency
;
2106 if (elapsed_usecs
< 100)
2107 i_usec_10_bins
[elapsed_usecs
/10]++;
2108 if (elapsed_usecs
< 1000)
2109 i_usec_100_bins
[elapsed_usecs
/100]++;
2110 else if (elapsed_usecs
< 10000)
2111 i_msec_1_bins
[elapsed_usecs
/1000]++;
2112 else if (elapsed_usecs
< 50000)
2113 i_msec_10_bins
[elapsed_usecs
/10000]++;
2117 if(use_high_res_bins
&& elapsed_usecs
< N_HIGH_RES_BINS
) {
2118 if(elapsed_usecs
> i_highest_latency
)
2119 i_highest_latency
= elapsed_usecs
;
2120 i_high_res_bins
[elapsed_usecs
]++;
2123 if (i_thresh_hold
&& elapsed_usecs
> i_thresh_hold
)
2124 i_exceeded_threshold
++;
2125 if (elapsed_usecs
> i_max_latency
)
2126 i_max_latency
= elapsed_usecs
;
2127 if (elapsed_usecs
< i_min_latency
|| i_total_samples
== 0)
2128 i_min_latency
= elapsed_usecs
;
2129 i_total_latency
+= elapsed_usecs
;
2136 void init_code_file()
2142 if ((fp
= fopen(code_file
, "r")) == (FILE *)0) {
2144 fprintf(log_fp
, "open of %s failed\n", code_file
);
2147 for (i
= 0; i
< MAX_ENTRIES
; i
++) {
2148 n
= fscanf(fp
, "%x%127s\n", &code
, name
);
2150 if (n
== 1 && i
== 0) {
2152 * old code file format, just skip
2159 strncpy(codes_tab
[i
].name
, name
, 32);
2160 codes_tab
[i
].type
= code
;
2172 FILE *fp
= (FILE *)0;
2173 char tmp_nm_file
[128];
2177 bzero(tmp_nm_file
, 128);
2178 bzero(tmpstr
, 1024);
2180 /* Build the temporary nm file path */
2181 strcpy(tmp_nm_file
,"/tmp/knm.out.XXXXXX");
2182 if (!mktemp(tmp_nm_file
)) {
2183 fprintf(stderr
, "Error in mktemp call\n");
2187 /* Build the nm command and create a tmp file with the output*/
2188 sprintf (tmpstr
, "/usr/bin/nm -f -n -s __TEXT __text %s > %s",
2189 kernelpath
, tmp_nm_file
);
2192 /* Parse the output from the nm command */
2193 if ((fp
=fopen(tmp_nm_file
, "r")) == (FILE *)0)
2195 /* Hmmm, let's not treat this as fatal */
2196 fprintf(stderr
, "Failed to open nm symbol file [%s]\n", tmp_nm_file
);
2200 /* Count the number of symbols in the nm symbol table */
2202 while ( (inchr
= getc(fp
)) != -1)
2210 /* Malloc the space for symbol table */
2211 if (kern_sym_count
> 0)
2213 kern_sym_tbl
= (kern_sym_t
*)malloc(kern_sym_count
* sizeof (kern_sym_t
));
2216 /* Hmmm, lets not treat this as fatal */
2217 fprintf(stderr
, "Can't allocate memory for kernel symbol table\n");
2220 bzero(kern_sym_tbl
, (kern_sym_count
* sizeof(kern_sym_t
)));
2224 /* Hmmm, lets not treat this as fatal */
2225 fprintf(stderr
, "No kernel symbol table \n");
2228 for (i
=0; i
<kern_sym_count
; i
++)
2230 bzero(tmpstr
, 1024);
2231 if (fscanf(fp
, "%lx %c %s", &kern_sym_tbl
[i
].k_sym_addr
, &inchr
, tmpstr
) != 3)
2235 len
= strlen(tmpstr
);
2236 kern_sym_tbl
[i
].k_sym_name
= malloc(len
+ 1);
2238 if (kern_sym_tbl
[i
].k_sym_name
== (char *)0)
2240 fprintf(stderr
, "Can't allocate memory for symbol name [%s]\n", tmpstr
);
2241 kern_sym_tbl
[i
].k_sym_name
= (char *)0;
2245 strcpy(kern_sym_tbl
[i
].k_sym_name
, tmpstr
);
2247 kern_sym_tbl
[i
].k_sym_len
= len
;
2251 if (i
!= kern_sym_count
)
2253 /* Hmmm, didn't build up entire table from nm */
2254 /* scrap the entire thing */
2256 free (kern_sym_tbl
);
2257 kern_sym_tbl
= (kern_sym_t
*)0;
2263 /* Remove the temporary nm file */
2264 unlink(tmp_nm_file
);
2267 /* Dump the kernel symbol table */
2268 for (i
=0; i
< kern_sym_count
; i
++)
2270 if (kern_sym_tbl
[i
].k_sym_name
)
2271 printf ("[%d] 0x%x %s\n", i
,
2272 kern_sym_tbl
[i
].k_sym_addr
, kern_sym_tbl
[i
].k_sym_name
);
2274 printf ("[%d] 0x%x %s\n", i
,
2275 kern_sym_tbl
[i
].k_sym_addr
, "No symbol name");
2281 pc_to_string(unsigned int pc
, int max_len
, int mode
)
2286 int binary_search();
2290 sprintf(pcstring
, "0x%-8x [usermode addr]", pc
);
2295 ret
= binary_search(kern_sym_tbl
, 0, kern_sym_count
-1, pc
);
2299 sprintf(pcstring
, "0x%x", pc
);
2302 else if (kern_sym_tbl
[ret
].k_sym_name
== (char *)0)
2304 sprintf(pcstring
, "0x%x", pc
);
2309 if ((len
= kern_sym_tbl
[ret
].k_sym_len
) > (max_len
- 8))
2312 memcpy(pcstring
, kern_sym_tbl
[ret
].k_sym_name
, len
);
2313 sprintf(&pcstring
[len
], "+0x%-5lx", pc
- kern_sym_tbl
[ret
].k_sym_addr
);
2320 /* Return -1 if not found, else return index */
2321 int binary_search(list
, low
, high
, addr
)
2328 mid
= (low
+ high
) / 2;
2331 return (-1); /* failed */
2332 else if (low
+ 1 == high
)
2334 if (list
[low
].k_sym_addr
<= addr
&&
2335 addr
< list
[high
].k_sym_addr
)
2337 /* We have a range match */
2340 else if (list
[high
].k_sym_addr
<= addr
)
2345 return(-1); /* Failed */
2347 else if (addr
< list
[mid
].k_sym_addr
)
2349 return(binary_search (list
, low
, mid
, addr
));
2353 return(binary_search (list
, mid
, high
, addr
));
2358 open_logfile(char *path
)
2360 log_fp
= fopen(path
, "a");
2364 /* failed to open path */
2365 fprintf(stderr
, "latency: failed to open logfile [%s]\n", path
);