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*/
57 #include <sys/sysctl.h>
61 #include <mach/host_info.h>
62 #include <mach/mach_error.h>
63 #include <mach/mach_types.h>
64 #include <mach/message.h>
65 #include <mach/mach_syscalls.h>
66 #include <mach/clock_types.h>
67 #include <mach/mach_time.h>
69 #include <libkern/OSTypes.h>
71 extern mach_port_t clock_port
;
73 #define KERN_KDPIDEX 14
76 int s_usec_10_bins
[10];
77 int s_usec_100_bins
[10];
78 int s_msec_1_bins
[10];
79 int s_msec_10_bins
[5];
82 int s_min_latency
= 0;
83 long long s_total_latency
= 0;
86 int s_exceeded_threshold
= 0;
88 int i_usec_10_bins
[10];
89 int i_usec_100_bins
[10];
90 int i_msec_1_bins
[10];
91 int i_msec_10_bins
[5];
94 int i_min_latency
= 0;
95 long long i_total_latency
= 0;
98 int i_exceeded_threshold
= 0;
107 int num_of_usecs_to_sleep
= 1000;
109 #define N_HIGH_RES_BINS 500
110 int use_high_res_bins
= false;
111 int i_high_res_bins
[N_HIGH_RES_BINS
];
112 int i_highest_latency
= 0;
114 char *kernelpath
= (char *)0;
115 char *code_file
= (char *)0;
118 u_long k_sym_addr
; /* kernel symbol address from nm */
119 u_int k_sym_len
; /* length of kernel symbol string */
120 char *k_sym_name
; /* kernel symbol string from nm */
123 kern_sym_t
*kern_sym_tbl
; /* pointer to the nm table */
124 int kern_sym_count
; /* number of entries in nm table */
127 #define UNKNOWN "Can't find symbol name"
132 int trace_enabled
= 0;
133 struct host_basic_info hi
;
136 #define SAMPLE_SIZE 300000
142 kbufinfo_t bufinfo
= {0, 0, 0};
144 FILE *log_fp
= (FILE *)0;
145 int num_of_codes
= 0;
146 int need_new_map
= 0;
147 int total_threads
= 0;
148 kd_threadmap
*mapptr
= 0;
150 #define MAX_ENTRIES 4096
154 } codes_tab
[MAX_ENTRIES
];
166 long pathname
[NUMPARMS
+ 1];
169 #define MAX_THREADS 512
170 struct th_info th_state
[MAX_THREADS
];
174 #define TRACE_DATA_NEWTHREAD 0x07000004
175 #define TRACE_STRING_NEWTHREAD 0x07010004
176 #define TRACE_STRING_EXEC 0x07010008
178 #define INTERRUPT 0x01050000
179 #define DECR_TRAP 0x01090000
180 #define DECR_SET 0x01090004
181 #define MACH_vmfault 0x01300008
182 #define MACH_sched 0x01400000
183 #define MACH_stkhandoff 0x01400008
184 #define VFS_LOOKUP 0x03010090
185 #define BSC_exit 0x040C0004
186 #define IES_action 0x050b0018
187 #define IES_filter 0x050b001c
188 #define TES_action 0x050c0010
189 #define CQ_action 0x050d0018
192 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
193 #define DBG_FUNC_MASK 0xfffffffc
195 #define CPU_NUMBER(ts) ((ts & KDBG_CPU_MASK) >> KDBG_CPU_SHIFT)
197 #define DBG_ZERO_FILL_FAULT 1
198 #define DBG_PAGEIN_FAULT 2
199 #define DBG_COW_FAULT 3
200 #define DBG_CACHE_HIT_FAULT 4
202 char *fault_name
[5] = {
210 char *pc_to_string();
211 static kern_return_t
set_time_constraint_policy(void);
212 static kern_return_t
set_standard_policy(void);
214 int decrementer_val
= 0; /* Value used to reset decrementer */
215 int set_remove_flag
= 1; /* By default, remove trace buffer */
217 kd_buf
**last_decrementer_kd
; /* last DECR_TRAP per cpu */
218 #define MAX_LOG_COUNT 30 /* limits the number of entries dumped in log_decrementer */
232 This flag is turned off when calling
233 quit() due to a set_remove() failure.
252 mib
[1] = KERN_KDEBUG
;
253 mib
[2] = KERN_KDENABLE
; /* protocol */
256 mib
[5] = 0; /* no flags */
258 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
259 quit("trace facility failure, KERN_KDENABLE\n");
263 set_numbufs(int nbufs
)
266 mib
[1] = KERN_KDEBUG
;
267 mib
[2] = KERN_KDSETBUF
;
270 mib
[5] = 0; /* no flags */
271 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
272 quit("trace facility failure, KERN_KDSETBUF\n");
275 mib
[1] = KERN_KDEBUG
;
276 mib
[2] = KERN_KDSETUP
;
279 mib
[5] = 0; /* no flags */
280 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
281 quit("trace facility failure, KERN_KDSETUP\n");
286 set_pidexclude(int pid
, int on_off
)
290 kr
.type
= KDBG_TYPENONE
;
293 needed
= sizeof(kd_regtype
);
295 mib
[1] = KERN_KDEBUG
;
296 mib
[2] = KERN_KDPIDEX
;
301 sysctl(mib
, 3, &kr
, &needed
, NULL
, 0);
304 void set_rtcdec(decval
)
310 kr
.type
= KDBG_TYPENONE
;
312 needed
= sizeof(kd_regtype
);
314 mib
[1] = KERN_KDEBUG
;
315 mib
[2] = KERN_KDSETRTCDEC
; /* protocol */
316 mib
[3] = 0; /* wildcard address family */
318 mib
[5] = 0; /* no flags */
321 if ((ret
=sysctl(mib
, 3, &kr
, &needed
, NULL
, 0)) < 0)
324 /* ignore this sysctl error if it's not supported */
328 quit("trace facility failure, KERN_KDSETRTCDEC\n");
334 get_bufinfo(kbufinfo_t
*val
)
336 needed
= sizeof (*val
);
338 mib
[1] = KERN_KDEBUG
;
339 mib
[2] = KERN_KDGETBUF
;
342 mib
[5] = 0; /* no flags */
344 if (sysctl(mib
, 3, val
, &needed
, 0, 0) < 0)
345 quit("trace facility failure, KERN_KDGETBUF\n");
355 mib
[1] = KERN_KDEBUG
;
356 mib
[2] = KERN_KDREMOVE
; /* protocol */
359 mib
[5] = 0; /* no flags */
363 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
367 quit("the trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n");
369 quit("trace facility failure, KERN_KDREMOVE\n");
376 /* When we aren't logging, only collect the DECR_TRAP trace points */
378 kr
.type
= KDBG_VALCHECK
;
379 kr
.value1
= DECR_TRAP
;
383 needed
= sizeof(kd_regtype
);
385 mib
[1] = KERN_KDEBUG
;
386 mib
[2] = KERN_KDSETREG
;
389 mib
[5] = 0; /* no flags */
390 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
391 quit("trace facility failure, KERN_KDSETREG\n");
394 mib
[1] = KERN_KDEBUG
;
395 mib
[2] = KERN_KDSETUP
;
398 mib
[5] = 0; /* no flags */
400 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
401 quit("trace facility failure, KERN_KDSETUP\n");
408 kr
.type
= KDBG_RANGETYPE
;
411 needed
= sizeof(kd_regtype
);
413 mib
[1] = KERN_KDEBUG
;
414 mib
[2] = KERN_KDSETREG
;
417 mib
[5] = 0; /* no flags */
419 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
420 quit("trace facility failure, KERN_KDSETREG\n");
423 mib
[1] = KERN_KDEBUG
;
424 mib
[2] = KERN_KDSETUP
;
427 mib
[5] = 0; /* no flags */
429 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
430 quit("trace facility failure, KERN_KDSETUP\n");
434 write_high_res_latencies()
438 if(use_high_res_bins
)
440 f
= fopen("latencies.csv","w");
441 for(i
=0;i
<N_HIGH_RES_BINS
;i
++)
443 fprintf(f
,"%d,%d\n", i
, i_high_res_bins
[i
]);
456 void screen_update();
458 write_high_res_latencies();
461 set_pidexclude(getpid(), 0);
462 screen_update(log_fp
);
470 void leave() /* exit under normal conditions -- signal handler */
472 write_high_res_latencies();
475 set_pidexclude(getpid(), 0);
484 screen_update(FILE *fp
)
491 unsigned int average_s_latency
;
492 unsigned int average_i_latency
;
495 if (fp
== (FILE *)0) {
499 fprintf(fp
,"\n\n===================================================================================================\n");
501 * Display the current time.
502 * "ctime" always returns a string that looks like this:
504 * Sun Sep 16 01:03:52 1973
505 * 012345678901234567890123
508 * We want indices 11 thru 18 (length 8).
510 elapsed_secs
= curr_time
- start_time
;
511 elapsed_hours
= elapsed_secs
/ 3600;
512 elapsed_secs
-= elapsed_hours
* 3600;
513 elapsed_mins
= elapsed_secs
/ 60;
514 elapsed_secs
-= elapsed_mins
* 60;
516 sprintf(tbuf
, "%-19.19s %2ld:%02ld:%02ld\n", &(ctime(&curr_time
)[0]),
517 (long)elapsed_hours
, (long)elapsed_mins
, (long)elapsed_secs
);
519 fprintf(fp
, "%s", tbuf
);
523 if (use_high_res_bins
) {
524 sprintf(tbuf
, "INTERRUPTS(HIGH RESOLUTION)\n");
527 fprintf(fp
, "%s", tbuf
);
531 if(use_high_res_bins
)
533 for(i
=0;i
<N_HIGH_RES_BINS
;i
++) {
537 fprintf(fp
, "%s", tbuf
);
541 #define INDEX(i) ((i%10)*50 + (i/10))
542 if(INDEX(i
) <= i_highest_latency
)
543 sprintf(tbuf
,"[%3d]: %6d ", INDEX(i
), i_high_res_bins
[INDEX(i
)]);
548 fprintf(fp
, "%s", tbuf
);
552 sprintf(tbuf
,"\n\n");
554 fprintf(fp
, "%s", tbuf
);
559 sprintf(tbuf
, " SCHEDULER INTERRUPTS\n");
562 fprintf(fp
, "%s", tbuf
);
566 sprintf(tbuf
, "---------------------------------------------\n");
569 fprintf(fp
, "%s", tbuf
);
575 sprintf(tbuf
, "total_samples %10d %10d\n\n", s_total_samples
, i_total_samples
);
578 fprintf(fp
, "%s", tbuf
);
584 for (itotal
= 0, stotal
= 0, i
= 0; i
< 10; i
++) {
585 sprintf(tbuf
, "delays < %3d usecs %10d %10d\n", (i
+ 1) * 10, s_usec_10_bins
[i
], i_usec_10_bins
[i
]);
588 fprintf(fp
, "%s", tbuf
);
592 stotal
+= s_usec_10_bins
[i
];
593 itotal
+= i_usec_10_bins
[i
];
595 sprintf(tbuf
, "total < 100 usecs %10d %10d\n\n", stotal
, itotal
);
598 fprintf(fp
, "%s", tbuf
);
604 for (itotal
= 0, stotal
= 0, i
= 1; i
< 10; i
++) {
606 sprintf(tbuf
, "delays < %3d usecs %10d %10d\n", (i
+ 1) * 100, s_usec_100_bins
[i
], i_usec_100_bins
[i
]);
608 sprintf(tbuf
, "delays < 1 msec %10d %10d\n", s_usec_100_bins
[i
], i_usec_100_bins
[i
]);
611 fprintf(fp
, "%s", tbuf
);
615 stotal
+= s_usec_100_bins
[i
];
616 itotal
+= i_usec_100_bins
[i
];
618 sprintf(tbuf
, "total < 1 msec %10d %10d\n\n", stotal
, itotal
);
621 fprintf(fp
, "%s", tbuf
);
627 for (itotal
= 0, stotal
= 0, i
= 1; i
< 10; i
++) {
628 sprintf(tbuf
, "delays < %3d msecs %10d %10d\n", (i
+ 1), s_msec_1_bins
[i
], i_msec_1_bins
[i
]);
631 fprintf(fp
, "%s", tbuf
);
635 stotal
+= s_msec_1_bins
[i
];
636 itotal
+= i_msec_1_bins
[i
];
638 sprintf(tbuf
, "total < 10 msecs %10d %10d\n\n", stotal
, itotal
);
641 fprintf(fp
, "%s", tbuf
);
648 for (itotal
= 0, stotal
= 0, i
= 1; i
< 5; i
++) {
649 sprintf(tbuf
, "delays < %3d msecs %10d %10d\n", (i
+ 1)*10, s_msec_10_bins
[i
], i_msec_10_bins
[i
]);
652 fprintf(fp
, "%s", tbuf
);
656 stotal
+= s_msec_10_bins
[i
];
657 itotal
+= i_msec_10_bins
[i
];
659 sprintf(tbuf
, "total < 50 msecs %10d %10d\n\n", stotal
, itotal
);
662 fprintf(fp
, "%s", tbuf
);
666 sprintf(tbuf
, "delays > 50 msecs %10d %10d\n", s_too_slow
, i_too_slow
);
669 fprintf(fp
, "%s", tbuf
);
675 sprintf(tbuf
, "\nminimum latency(usecs) %7d %7d\n", s_min_latency
, i_min_latency
);
678 fprintf(fp
, "%s", tbuf
);
682 sprintf(tbuf
, "maximum latency(usecs) %7d %7d\n", s_max_latency
, i_max_latency
);
685 fprintf(fp
, "%s", tbuf
);
690 average_s_latency
= (unsigned int)(s_total_latency
/s_total_samples
);
692 average_s_latency
= 0;
695 average_i_latency
= (unsigned int)(i_total_latency
/i_total_samples
);
697 average_i_latency
= 0;
699 sprintf(tbuf
, "average latency(usecs) %7d %7d\n", average_s_latency
, average_i_latency
);
702 fprintf(fp
, "%s", tbuf
);
706 sprintf(tbuf
, "exceeded threshold %7d %7d\n", s_exceeded_threshold
, i_exceeded_threshold
);
709 fprintf(fp
, "%s", tbuf
);
723 fprintf(stderr
, "Usage: latency [-rt] [-h] [-c codefile] [-l logfile] [-st threshold]\n");
725 #if defined (__i386__)
726 fprintf(stderr
, " [-it threshold] [-s sleep_in_usecs] [-n kernel]\n\n");
728 fprintf(stderr
, " [-it threshold] [-s sleep_in_usecs]\n");
729 fprintf(stderr
, " [-d decrementer_in_usecs] [-n kernel]\n\n");
733 fprintf(stderr
, " -rt Set realtime scheduling policy. Default is timeshare.\n");
734 fprintf(stderr
, " -h Display high resolution interrupt latencies and write them to latencies.csv (truncate existing file) upon exit.\n");
735 fprintf(stderr
, " -c specify name of codes file\n");
736 fprintf(stderr
, " -l specify name of file to log trace entries to when threshold is exceeded\n");
737 fprintf(stderr
, " -st set scheduler latency threshold in microseconds... if latency exceeds this, then log trace\n");
738 fprintf(stderr
, " -it set interrupt latency threshold in microseconds... if latency exceeds this, then log trace\n");
739 fprintf(stderr
, " -s set sleep time in microseconds\n");
740 #if !defined (__i386__)
741 fprintf(stderr
, " -d set decrementer in microseconds.\n");
743 fprintf(stderr
, " -n specify kernel, default is /mach_kernel\n");
745 fprintf(stderr
, "\nlatency must be run as root\n\n");
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 my_policy
= THREAD_STANDARD_POLICY
;
775 policy_name
= "TIMESHARE";
778 if (strcmp(argv
[1], "-rt") == 0) {
779 my_policy
= THREAD_TIME_CONSTRAINT_POLICY
; /* the real time band */
780 policy_name
= "REALTIME";
782 } else if (strcmp(argv
[1], "-st") == 0) {
787 s_thresh_hold
= atoi(argv
[1]);
791 } else if (strcmp(argv
[1], "-it") == 0) {
796 i_thresh_hold
= atoi(argv
[1]);
799 } else if (strcmp(argv
[1], "-c") == 0) {
807 } else if (strcmp(argv
[1], "-l") == 0) {
812 open_logfile(argv
[1]);
816 } else if (strcmp(argv
[1], "-s") == 0) {
821 num_of_usecs_to_sleep
= atoi(argv
[1]);
825 else if (strcmp(argv
[1], "-d") == 0) {
830 decrementer_usec
= atoi(argv
[1]);
833 #if defined(__i386__)
834 /* ignore this option - setting the decrementer has no effect */
835 decrementer_usec
= 0;
838 else if (strcmp(argv
[1], "-n") == 0) {
843 kernelpath
= argv
[1];
846 } else if (strcmp(argv
[1], "-h") == 0) {
847 use_high_res_bins
= true;
855 if ( geteuid() != 0 ) {
856 printf("'latency' must be run as root...\n");
860 if (kernelpath
== (char *) 0)
861 kernelpath
= "/mach_kernel";
863 if (code_file
== (char *) 0)
864 code_file
= "/usr/share/misc/trace.codes";
868 sample_sc_now
= 25000 / num_of_usecs_to_sleep
;
871 decrementer_val
= decrementer_usec
* divisor
;
873 /* get the cpu countfor the DECR_TRAP array */
874 host
= mach_host_self();
875 size
= sizeof(hi
)/sizeof(int);
876 ret
= host_info(host
, HOST_BASIC_INFO
, (host_info_t
)&hi
, &size
);
877 if (ret
!= KERN_SUCCESS
) {
878 mach_error(argv
[0], ret
);
882 if ((last_decrementer_kd
= (kd_buf
**)malloc(hi
.avail_cpus
* sizeof(kd_buf
*))) == (kd_buf
**)0)
883 quit("can't allocate memory for decrementer tracing info\n");
885 nanosecs_to_sleep
= (double)(num_of_usecs_to_sleep
* 1000);
886 fdelay
= nanosecs_to_sleep
* (divisor
/1000);
887 adelay
= (uint64_t)fdelay
;
892 When the decrementer isn't set in the options,
893 decval will be zero and this call will reset
894 the system default ...
896 set_rtcdec(decrementer_val
);
898 if (initscr() == (WINDOW
*) 0)
900 printf("Unrecognized TERM type, try vt100\n");
906 signal(SIGWINCH
, sigwinch
);
907 signal(SIGINT
, sigintr
);
908 signal(SIGQUIT
, leave
);
909 signal(SIGTERM
, leave
);
910 signal(SIGHUP
, leave
);
913 if ((my_buffer
= malloc(SAMPLE_SIZE
* sizeof(kd_buf
))) == (char *)0)
914 quit("can't allocate memory for tracing info\n");
916 set_numbufs(SAMPLE_SIZE
);
921 set_init_nologging();
922 set_pidexclude(getpid(), 1);
928 start_time
= time((long *)0);
929 refresh_time
= start_time
;
931 if (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
)
933 /* the realtime band */
934 if(set_time_constraint_policy() != KERN_SUCCESS
)
935 quit("Failed to set realtime policy.\n");
939 curr_time
= time((long *)0);
941 if (curr_time
>= refresh_time
) {
942 if (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
)
944 /* set standard timeshare policy during screen update */
945 if(set_standard_policy() != KERN_SUCCESS
)
946 quit("Failed to set standard policy.\n");
948 screen_update((FILE *)0);
949 if (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
)
951 /* set back to realtime band */
952 if(set_time_constraint_policy() != KERN_SUCCESS
)
953 quit("Failed to set time_constraint policy.\n");
955 refresh_time
= curr_time
+ 1;
958 timestamp1
= mach_absolute_time();
959 adeadline
= timestamp1
+ adelay
;
960 mach_wait_until(adeadline
);
961 timestamp2
= mach_absolute_time();
967 elapsed_usecs
= (int)(((double)(stop
- start
)) / divisor
);
969 if ((elapsed_usecs
-= num_of_usecs_to_sleep
) <= 0)
972 if (elapsed_usecs
< 100)
973 s_usec_10_bins
[elapsed_usecs
/10]++;
974 if (elapsed_usecs
< 1000)
975 s_usec_100_bins
[elapsed_usecs
/100]++;
976 else if (elapsed_usecs
< 10000)
977 s_msec_1_bins
[elapsed_usecs
/1000]++;
978 else if (elapsed_usecs
< 50000)
979 s_msec_10_bins
[elapsed_usecs
/10000]++;
983 if (elapsed_usecs
> s_max_latency
)
984 s_max_latency
= elapsed_usecs
;
985 if (elapsed_usecs
< s_min_latency
|| s_total_samples
== 0)
986 s_min_latency
= elapsed_usecs
;
987 s_total_latency
+= elapsed_usecs
;
990 if (s_thresh_hold
&& elapsed_usecs
> s_thresh_hold
)
991 s_exceeded_threshold
++;
994 if (log_fp
&& s_thresh_hold
&& elapsed_usecs
> s_thresh_hold
)
995 sample_sc(start
, stop
);
997 if (loop_cnt
>= sample_sc_now
) {
998 sample_sc((long long)0, (long long)0);
1004 No need to check for initscr error return.
1005 We won't get here if it fails on the first call.
1019 mach_timebase_info_data_t info
;
1021 (void) mach_timebase_info (&info
);
1023 divisor
= ( (double)info
.denom
/ (double)info
.numer
) * 1000;
1027 /* This is the realtime band */
1028 static kern_return_t
1029 set_time_constraint_policy()
1031 kern_return_t result
;
1032 thread_time_constraint_policy_data_t info
;
1033 mach_msg_type_number_t count
;
1034 boolean_t get_default
;
1037 count
= THREAD_TIME_CONSTRAINT_POLICY_COUNT
;
1038 result
= thread_policy_get(mach_thread_self(), THREAD_TIME_CONSTRAINT_POLICY
,
1039 (thread_policy_t
)&info
, &count
, &get_default
);
1040 if (result
!= KERN_SUCCESS
)
1043 result
= thread_policy_set(mach_thread_self(), THREAD_TIME_CONSTRAINT_POLICY
,
1044 (thread_policy_t
)&info
, THREAD_TIME_CONSTRAINT_POLICY_COUNT
);
1049 /* This is the timeshare mode */
1050 static kern_return_t
1051 set_standard_policy()
1053 kern_return_t result
;
1054 thread_standard_policy_data_t info
;
1055 mach_msg_type_number_t count
;
1056 boolean_t get_default
;
1059 count
= THREAD_STANDARD_POLICY_COUNT
;
1060 result
= thread_policy_get(mach_thread_self(), THREAD_STANDARD_POLICY
,
1061 (thread_policy_t
)&info
, &count
, &get_default
);
1062 if (result
!= KERN_SUCCESS
)
1065 result
= thread_policy_set(mach_thread_self(), THREAD_STANDARD_POLICY
,
1066 (thread_policy_t
)&info
, THREAD_STANDARD_POLICY_COUNT
);
1072 void read_command_map()
1081 total_threads
= bufinfo
.nkdthreads
;
1082 size
= bufinfo
.nkdthreads
* sizeof(kd_threadmap
);
1085 if ((mapptr
= (kd_threadmap
*) malloc(size
)))
1086 bzero (mapptr
, size
);
1089 printf("Thread map is not initialized -- this is not fatal\n");
1094 /* Now read the threadmap */
1096 mib
[1] = KERN_KDEBUG
;
1097 mib
[2] = KERN_KDTHRMAP
;
1100 mib
[5] = 0; /* no flags */
1101 if (sysctl(mib
, 3, mapptr
, &size
, NULL
, 0) < 0)
1103 /* This is not fatal -- just means I cant map command strings */
1105 printf("Can't read the thread map -- this is not fatal\n");
1114 void create_map_entry(int thread
, char *command
)
1122 for (i
= 0, map
= 0; !map
&& i
< total_threads
; i
++)
1124 if (mapptr
[i
].thread
== thread
)
1125 map
= &mapptr
[i
]; /* Reuse this entry, the thread has been reassigned */
1128 if (!map
) /* look for invalid entries that I can reuse*/
1130 for (i
= 0, map
= 0; !map
&& i
< total_threads
; i
++)
1132 if (mapptr
[i
].valid
== 0 )
1133 map
= &mapptr
[i
]; /* Reuse this invalid entry */
1139 /* If reach here, then this is a new thread and
1140 * there are no invalid entries to reuse
1141 * Double the size of the thread map table.
1144 n
= total_threads
* 2;
1145 mapptr
= (kd_threadmap
*) realloc(mapptr
, n
* sizeof(kd_threadmap
));
1146 bzero(&mapptr
[total_threads
], total_threads
*sizeof(kd_threadmap
));
1147 map
= &mapptr
[total_threads
];
1151 fprintf(log_fp
, "MAP: increasing thread map to %d entries\n", total_threads
);
1156 fprintf(log_fp
, "MAP: adding thread %x with name %s\n", thread
, command
);
1159 map
->thread
= thread
;
1161 The trace entry that returns the command name will hold
1162 at most, MAXCOMLEN chars, and in that case, is not
1163 guaranteed to be null terminated.
1165 (void)strncpy (map
->command
, command
, MAXCOMLEN
);
1166 map
->command
[MAXCOMLEN
] = '\0';
1170 kd_threadmap
*find_thread_map(int thread
)
1176 return((kd_threadmap
*)0);
1178 for (i
= 0; i
< total_threads
; i
++)
1181 if (map
->valid
&& (map
->thread
== thread
))
1186 return ((kd_threadmap
*)0);
1190 kill_thread_map(int thread
)
1194 if ((map
= find_thread_map(thread
))) {
1198 fprintf(log_fp
, "MAP: deleting thread %x with name %s\n", thread
, map
->command
);
1202 map
->command
[0] = '\0';
1207 struct th_info
*find_thread(int thread
, int type1
, int type2
) {
1210 for (ti
= th_state
; ti
< &th_state
[cur_max
]; ti
++) {
1211 if (ti
->thread
== thread
) {
1214 if (type1
== ti
->type
)
1216 if (type2
== ti
->type
)
1220 return ((struct th_info
*)0);
1224 char *find_code(type
)
1228 for (i
= 0; i
< num_of_codes
; i
++) {
1229 if (codes_tab
[i
].type
== type
)
1230 return(codes_tab
[i
].name
);
1236 void sample_sc(uint64_t start
, uint64_t stop
)
1238 kd_buf
*kd
, *last_mach_sched
, *start_kd
, *end_of_sample
;
1241 int first_entry
= 1;
1242 double timestamp
= 0.0;
1243 double last_timestamp
= 0.0;
1245 double start_bias
= 0.0;
1247 void read_command_map();
1249 if (log_fp
&& (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
))
1251 /* set standard timeshare policy when logging */
1252 if(set_standard_policy() != KERN_SUCCESS
)
1253 quit("Failed to set standard policy.\n");
1256 /* Get kernel buffer information */
1257 get_bufinfo(&bufinfo
);
1263 needed
= bufinfo
.nkdbufs
* sizeof(kd_buf
);
1265 mib
[1] = KERN_KDEBUG
;
1266 mib
[2] = KERN_KDREADTR
;
1269 mib
[5] = 0; /* no flags */
1271 if (sysctl(mib
, 3, my_buffer
, &needed
, NULL
, 0) < 0)
1272 quit("trace facility failure, KERN_KDREADTR\n");
1276 if (bufinfo
.flags
& KDBG_WRAPPED
) {
1277 for (i
= 0; i
< cur_max
; i
++) {
1278 th_state
[i
].thread
= 0;
1279 th_state
[i
].type
= -1;
1280 th_state
[i
].pathptr
= (long *)NULL
;
1281 th_state
[i
].pathname
[0] = 0;
1292 latency
= (double)(stop
- start
) / divisor
;
1293 latency
-= (double)num_of_usecs_to_sleep
;
1295 fprintf(log_fp
, "\n\n%-19.19s scheduling latency = %.1fus num_of_traces = %d <<<<<<< trace buffer wrapped >>>>>>>\n\n",
1296 &(ctime(&curr_time
)[0]), latency
, count
);
1299 end_of_sample
= &((kd_buf
*)my_buffer
)[count
];
1301 /* Always reinitialize the DECR_TRAP array */
1302 for (i
=0; i
< hi
.avail_cpus
; i
++)
1303 last_decrementer_kd
[i
] = (kd_buf
*)my_buffer
;
1305 last_mach_sched
= (kd_buf
*)0;
1307 for (kd
= (kd_buf
*)my_buffer
; kd
< end_of_sample
; kd
++) {
1308 int debugid
, thread
, cpunum
;
1309 int type
, clen
, mode
;
1314 double i_latency
= 0.0;
1317 char sched_info
[64];
1319 kd_threadmap
*find_thread_map();
1320 double handle_decrementer();
1321 kd_buf
*log_decrementer();
1322 int check_for_thread_update();
1323 void enter_syscall();
1324 void exit_syscall();
1328 cpunum
= CPU_NUMBER(kd
->timestamp
);
1329 debugid
= kd
->debugid
;
1330 type
= kd
->debugid
& DBG_FUNC_MASK
;
1332 if (check_for_thread_update(thread
, type
, kd
))
1335 if (type
== DECR_TRAP
)
1336 i_latency
= handle_decrementer(kd
);
1338 now
= kd
->timestamp
& KDBG_TIMESTAMP_MASK
;
1340 timestamp
= ((double)now
) / divisor
;
1342 if (now
< start
|| now
> stop
) {
1343 if (debugid
& DBG_FUNC_START
)
1344 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 0);
1345 else if (debugid
& DBG_FUNC_END
)
1346 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 0);
1347 else if (type
== DECR_TRAP
) {
1349 if (log_fp
&& i_thresh_hold
&& (int)i_latency
> i_thresh_hold
) {
1350 start_kd
= last_decrementer_kd
[cpunum
];
1351 kd
= log_decrementer(start_kd
, kd
, end_of_sample
, i_latency
);
1352 if (kd
>= end_of_sample
)
1355 if ((kd
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1357 cpunum
= CPU_NUMBER(kd
->timestamp
);
1358 last_decrementer_kd
[cpunum
] = kd
;
1361 last_decrementer_kd
[cpunum
] = cur_kd
;
1370 latency
= (double)(stop
- start
) / divisor
;
1371 latency
-= (double)num_of_usecs_to_sleep
;
1374 sprintf(buf2
, "default");
1376 sprintf(buf2
, "%d", my_pri
);
1377 sprintf(buf1
, "%-19.19s scheduling latency = %.1fus sleep_request = %dus policy = %s priority = %s",
1378 &(ctime(&curr_time
)[0]), latency
, num_of_usecs_to_sleep
, policy_name
, buf2
);
1379 clen
= strlen(buf1
);
1380 memset(buf2
, '-', clen
);
1384 fprintf(log_fp
, "\n\n%s\n", buf2
);
1385 fprintf(log_fp
, "%s\n\n", buf1
);
1386 fprintf(log_fp
, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
1388 start_bias
= ((double)start
) / divisor
;
1389 last_timestamp
= timestamp
;
1392 delta
= timestamp
- last_timestamp
;
1394 if ((map
= find_thread_map(thread
)))
1395 strcpy(command
, map
->command
);
1403 fprintf(log_fp
, "%9.1f %8.1f\t\tCQ_action @ %-59.59s %-8x %d %s\n",
1404 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 59, 1) , thread
, cpunum
, command
);
1406 last_timestamp
= timestamp
;
1411 fprintf(log_fp
, "%9.1f %8.1f\t\tTES_action @ %-58.58s %-8x %d %s\n",
1412 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 58, 1) , thread
, cpunum
, command
);
1415 last_timestamp
= timestamp
;
1420 fprintf(log_fp
, "%9.1f %8.1f\t\tIES_action @ %-58.58s %-8x %d %s\n",
1421 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 58, 1) , thread
, cpunum
, command
);
1424 last_timestamp
= timestamp
;
1429 fprintf(log_fp
, "%9.1f %8.1f\t\tIES_filter @ %-58.58s %-8x %d %s\n",
1430 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 58, 1) , thread
, cpunum
, command
);
1433 last_timestamp
= timestamp
;
1437 last_decrementer_kd
[cpunum
] = kd
;
1439 if (i_thresh_hold
&& (int)i_latency
> i_thresh_hold
)
1446 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1447 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1452 fprintf(log_fp
, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-59.59s %-8x %d %s\n",
1453 timestamp
- start_bias
, delta
, i_latency
, p
, pc_to_string(kd
->arg2
, 59, mode
) , thread
, cpunum
, command
);
1456 last_timestamp
= timestamp
;
1461 fprintf(log_fp
, "%9.1f %8.1f[%.1f] \t%-28.28s %-8x %d %s\n",
1462 timestamp
- start_bias
, delta
, (double)kd
->arg1
/divisor
, "DECR_SET", thread
, cpunum
, command
);
1465 last_timestamp
= timestamp
;
1469 case MACH_stkhandoff
:
1470 last_mach_sched
= kd
;
1472 if ((map
= find_thread_map(kd
->arg2
)))
1473 strcpy(command1
, map
->command
);
1475 sprintf(command1
, "%-8x", kd
->arg2
);
1477 if ((ti
= find_thread(kd
->arg2
, 0, 0))) {
1478 if (ti
->type
== -1 && strcmp(command1
, "kernel_task"))
1484 memset(sched_info
, ' ', sizeof(sched_info
));
1486 sprintf(sched_info
, "%14.14s", command
);
1487 clen
= strlen(sched_info
);
1488 sched_info
[clen
] = ' ';
1490 sprintf(&sched_info
[14], " @ pri %3d --> %14.14s", kd
->arg3
, command1
);
1491 clen
= strlen(sched_info
);
1492 sched_info
[clen
] = ' ';
1494 sprintf(&sched_info
[45], " @ pri %3d%s", kd
->arg4
, p
);
1497 fprintf(log_fp
, "%9.1f %8.1f\t\t%-10.10s %s %-8x %d\n",
1498 timestamp
- start_bias
, delta
, "MACH_SCHED", sched_info
, thread
, cpunum
);
1501 last_timestamp
= timestamp
;
1505 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1506 if (cur_max
>= MAX_THREADS
)
1508 ti
= &th_state
[cur_max
++];
1510 ti
->thread
= thread
;
1512 ti
->pathptr
= (long *)0;
1513 ti
->child_thread
= 0;
1515 while ( (kd
< end_of_sample
) && ((kd
->debugid
& DBG_FUNC_MASK
) == VFS_LOOKUP
))
1517 if (ti
->pathptr
== NULL
) {
1518 ti
->arg1
= kd
->arg1
;
1519 sargptr
= ti
->pathname
;
1521 *sargptr
++ = kd
->arg2
;
1522 *sargptr
++ = kd
->arg3
;
1523 *sargptr
++ = kd
->arg4
;
1525 * NULL terminate the 'string'
1528 ti
->pathptr
= sargptr
;
1531 sargptr
= ti
->pathptr
;
1534 We don't want to overrun our pathname buffer if the
1535 kernel sends us more VFS_LOOKUP entries than we can
1539 if (sargptr
>= &ti
->pathname
[NUMPARMS
])
1546 We need to detect consecutive vfslookup entries.
1547 So, if we get here and find a START entry,
1548 fake the pathptr so we can bypass all further
1552 if (kd
->debugid
& DBG_FUNC_START
)
1554 ti
->pathptr
= &ti
->pathname
[NUMPARMS
];
1558 *sargptr
++ = kd
->arg1
;
1559 *sargptr
++ = kd
->arg2
;
1560 *sargptr
++ = kd
->arg3
;
1561 *sargptr
++ = kd
->arg4
;
1563 * NULL terminate the 'string'
1567 ti
->pathptr
= sargptr
;
1572 p
= (char *)ti
->pathname
;
1576 /* print the tail end of the pathname */
1584 fprintf(log_fp
, "%9.1f %8.1f\t\t%-14.14s %-42s %-8x %-8x %d %s\n",
1585 timestamp
- start_bias
, delta
, "VFS_LOOKUP",
1586 &p
[len
], ti
->arg1
, thread
, cpunum
, command
);
1589 last_timestamp
= timestamp
;
1593 if (debugid
& DBG_FUNC_START
)
1594 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
1595 else if (debugid
& DBG_FUNC_END
)
1596 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
1598 print_entry(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
);
1600 last_timestamp
= timestamp
;
1604 if (last_mach_sched
&& log_fp
)
1605 fprintf(log_fp
, "\nblocked by %s @ priority %d\n", command
, last_mach_sched
->arg3
);
1607 if (first_entry
== 0 && log_fp
)
1608 fprintf(log_fp
, "\n start = %qd stop = %qd count = %d now = %qd\n", start
, stop
, count
, now
);
1613 if (log_fp
&& (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
))
1615 /* set back to realtime band */
1616 if(set_time_constraint_policy() != KERN_SUCCESS
)
1617 quit("Failed to set time_constraint policy.\n");
1622 enter_syscall(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
, int print_info
)
1629 cpunum
= CPU_NUMBER(kd
->timestamp
);
1631 if (print_info
&& fp
) {
1632 if ((p
= find_code(type
))) {
1633 if (type
== INTERRUPT
) {
1636 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1637 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1641 fprintf(fp
, "%9.1f %8.1f\t\tINTERRUPT @ %-59.59s %-8x %d %s\n",
1642 timestamp
- bias
, delta
, pc_to_string(kd
->arg2
, 59, mode
), thread
, cpunum
, command
);
1643 } else if (type
== MACH_vmfault
) {
1644 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %d %s\n",
1645 timestamp
- bias
, delta
, p
, thread
, cpunum
, command
);
1647 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %-8x %-8x %-8x %-8x %d %s\n",
1648 timestamp
- bias
, delta
, p
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1649 thread
, cpunum
, command
);
1652 fprintf(fp
, "%9.1f %8.1f\t\t%-8x %-8x %-8x %-8x %-8x %-8x %d %s\n",
1653 timestamp
- bias
, delta
, type
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1654 thread
, cpunum
, command
);
1657 if ((ti
= find_thread(thread
, -1, type
)) == (struct th_info
*)0) {
1658 if (cur_max
>= MAX_THREADS
) {
1659 static int do_this_once
= 1;
1662 for (i
= 0; i
< cur_max
; i
++) {
1665 fprintf(fp
, "thread = %x, type = %x\n",
1666 th_state
[i
].thread
, th_state
[i
].type
);
1673 ti
= &th_state
[cur_max
++];
1675 ti
->thread
= thread
;
1676 ti
->child_thread
= 0;
1678 if (type
!= BSC_exit
)
1682 ti
->stime
= timestamp
;
1683 ti
->pathptr
= (long *)NULL
;
1686 if (print_info
&& fp
)
1687 fprintf(fp
, "cur_max = %d, ti = %x, type = %x, thread = %x\n", cur_max
, ti
, ti
->type
, ti
->thread
);
1693 exit_syscall(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
, int print_info
)
1700 cpunum
= CPU_NUMBER(kd
->timestamp
);
1702 ti
= find_thread(thread
, type
, type
);
1704 if (print_info
&& fp
)
1705 fprintf(fp
, "cur_max = %d, ti = %x, type = %x, thread = %x\n", cur_max
, ti
, type
, thread
);
1707 if (print_info
&& fp
) {
1709 fprintf(fp
, "%9.1f %8.1f(%.1f) \t", timestamp
- bias
, delta
, timestamp
- ti
->stime
);
1711 fprintf(fp
, "%9.1f %8.1f() \t", timestamp
- bias
, delta
);
1713 if ((p
= find_code(type
))) {
1714 if (type
== INTERRUPT
) {
1715 fprintf(fp
, "INTERRUPT %-8x %d %s\n", thread
, cpunum
, command
);
1716 } else if (type
== MACH_vmfault
&& kd
->arg4
<= DBG_CACHE_HIT_FAULT
) {
1717 user_addr
= ((uint64_t)kd
->arg1
<< 32) | (uint32_t)kd
->arg2
;
1719 fprintf(fp
, "%-28.28s %-8.8s %-16qx %-8x %d %s\n",
1720 p
, fault_name
[kd
->arg4
], user_addr
,
1721 thread
, cpunum
, command
);
1723 fprintf(fp
, "%-28.28s %-8x %-8x %-8x %d %s\n",
1724 p
, kd
->arg1
, kd
->arg2
,
1725 thread
, cpunum
, command
);
1728 fprintf(fp
, "%-8x %-8x %-8x %-8x %d %s\n",
1729 type
, kd
->arg1
, kd
->arg2
,
1730 thread
, cpunum
, command
);
1733 if (ti
== (struct th_info
*)0) {
1734 if ((ti
= find_thread(thread
, -1, -1)) == (struct th_info
*)0) {
1735 if (cur_max
>= MAX_THREADS
)
1737 ti
= &th_state
[cur_max
++];
1739 ti
->thread
= thread
;
1740 ti
->child_thread
= 0;
1741 ti
->pathptr
= (long *)NULL
;
1748 print_entry(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
)
1756 cpunum
= CPU_NUMBER(kd
->timestamp
);
1758 fprintf(fp
, "cur_max = %d, type = %x, thread = %x, cpunum = %d\n", cur_max
, type
, thread
, cpunum
);
1760 if ((p
= find_code(type
))) {
1761 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %-8x %-8x %-8x %-8x %d %s\n",
1762 timestamp
- bias
, delta
, p
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1763 thread
, cpunum
, command
);
1765 fprintf(fp
, "%9.1f %8.1f\t\t%-8x %-8x %-8x %-8x %-8x %-8x %d %s\n",
1766 timestamp
- bias
, delta
, type
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1767 thread
, cpunum
, command
);
1772 check_for_thread_update(int thread
, int type
, kd_buf
*kd
)
1775 void create_map_entry();
1779 case TRACE_DATA_NEWTHREAD
:
1780 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1781 if (cur_max
>= MAX_THREADS
)
1783 ti
= &th_state
[cur_max
++];
1785 ti
->thread
= thread
;
1787 ti
->pathptr
= (long *)NULL
;
1789 ti
->child_thread
= kd
->arg1
;
1792 case TRACE_STRING_NEWTHREAD
:
1793 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0)
1795 if (ti
->child_thread
== 0)
1797 create_map_entry(ti
->child_thread
, (char *)&kd
->arg1
);
1799 ti
->child_thread
= 0;
1802 case TRACE_STRING_EXEC
:
1803 create_map_entry(thread
, (char *)&kd
->arg1
);
1811 kd_buf
*log_decrementer(kd_buf
*kd_beg
, kd_buf
*kd_end
, kd_buf
*end_of_sample
, double i_latency
)
1813 kd_buf
*kd
, *kd_start
, *kd_stop
;
1814 int kd_count
; /* Limit the boundary of kd_start */
1815 double timestamp
= 0.0;
1816 double last_timestamp
= 0.0;
1818 double start_bias
= 0.0;
1820 int debugid
, type
, clen
;
1828 char sched_info
[64];
1832 kd_threadmap
*find_thread_map();
1834 sprintf(buf1
, "%-19.19s interrupt latency = %.1fus", &(ctime(&curr_time
)[0]), i_latency
);
1835 clen
= strlen(buf1
);
1836 memset(buf2
, '-', clen
);
1838 fprintf(log_fp
, "\n\n%s\n", buf2
);
1839 fprintf(log_fp
, "%s\n\n", buf1
);
1841 fprintf(log_fp
, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
1843 thread
= kd_beg
->arg5
;
1844 cpunum
= CPU_NUMBER(kd_end
->timestamp
);
1846 for (kd_count
= 0, kd_start
= kd_beg
- 1; (kd_start
>= (kd_buf
*)my_buffer
); kd_start
--, kd_count
++) {
1847 if (kd_count
== MAX_LOG_COUNT
)
1850 if (CPU_NUMBER(kd_start
->timestamp
) != cpunum
)
1853 if ((kd_start
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1856 if (kd_start
->arg5
!= thread
)
1860 if (kd_start
< (kd_buf
*)my_buffer
)
1861 kd_start
= (kd_buf
*)my_buffer
;
1863 thread
= kd_end
->arg5
;
1865 for (kd_stop
= kd_end
+ 1; kd_stop
< end_of_sample
; kd_stop
++) {
1867 if ((kd_stop
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1870 if (CPU_NUMBER(kd_stop
->timestamp
) != cpunum
)
1873 if (kd_stop
->arg5
!= thread
)
1877 if (kd_stop
>= end_of_sample
)
1878 kd_stop
= end_of_sample
- 1;
1880 now
= kd_start
->timestamp
& KDBG_TIMESTAMP_MASK
;
1881 timestamp
= ((double)now
) / divisor
;
1883 for (kd
= kd_start
; kd
<= kd_stop
; kd
++) {
1884 type
= kd
->debugid
& DBG_FUNC_MASK
;
1886 if ((ti
= find_thread(kd
->arg5
, type
, type
))) {
1887 if (ti
->stime
>= timestamp
)
1891 for (kd
= kd_start
; kd
<= kd_stop
; kd
++) {
1895 cpunum
= CPU_NUMBER(kd
->timestamp
);
1896 debugid
= kd
->debugid
;
1897 type
= kd
->debugid
& DBG_FUNC_MASK
;
1899 now
= kd
->timestamp
& KDBG_TIMESTAMP_MASK
;
1901 timestamp
= ((double)now
) / divisor
;
1903 if (kd
== kd_start
) {
1904 start_bias
= timestamp
;
1905 last_timestamp
= timestamp
;
1907 delta
= timestamp
- last_timestamp
;
1909 if ((map
= find_thread_map(thread
)))
1910 strcpy(command
, map
->command
);
1918 fprintf(log_fp
, "%9.1f %8.1f\t\tCQ_action @ %-59.59s %-8x %d %s\n",
1919 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 59, 1) , thread
, cpunum
, command
);
1921 last_timestamp
= timestamp
;
1925 if ((int)(kd
->arg1
) >= 0)
1928 i_latency
= (((double)(-1 - kd
->arg1
)) / divisor
);
1930 if (i_thresh_hold
&& (int)i_latency
> i_thresh_hold
)
1937 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1938 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1941 fprintf(log_fp
, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-59.59s %-8x %d %s\n",
1942 timestamp
- start_bias
, delta
, i_latency
, p
, pc_to_string(kd
->arg2
, 59, mode
) , thread
, cpunum
, command
);
1944 last_timestamp
= timestamp
;
1948 fprintf(log_fp
, "%9.1f %8.1f[%.1f] \t%-28.28s %-8x %d %s\n",
1949 timestamp
- start_bias
, delta
, (double)kd
->arg1
/divisor
,
1950 "DECR_SET", thread
, cpunum
, command
);
1952 last_timestamp
= timestamp
;
1956 case MACH_stkhandoff
:
1957 if ((map
= find_thread_map(kd
->arg2
)))
1958 strcpy(command1
, map
->command
);
1960 sprintf(command1
, "%-8x", kd
->arg2
);
1962 if ((ti
= find_thread(kd
->arg2
, 0, 0))) {
1963 if (ti
->type
== -1 && strcmp(command1
, "kernel_task"))
1969 memset(sched_info
, ' ', sizeof(sched_info
));
1971 sprintf(sched_info
, "%14.14s", command
);
1972 clen
= strlen(sched_info
);
1973 sched_info
[clen
] = ' ';
1975 sprintf(&sched_info
[14], " @ pri %3d --> %14.14s", kd
->arg3
, command1
);
1976 clen
= strlen(sched_info
);
1977 sched_info
[clen
] = ' ';
1979 sprintf(&sched_info
[45], " @ pri %3d%s", kd
->arg4
, p
);
1981 fprintf(log_fp
, "%9.1f %8.1f\t\t%-10.10s %s %-8x %d\n",
1982 timestamp
- start_bias
, delta
, "MACH_SCHED", sched_info
, thread
, cpunum
);
1984 last_timestamp
= timestamp
;
1988 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1989 if (cur_max
>= MAX_THREADS
)
1991 ti
= &th_state
[cur_max
++];
1993 ti
->thread
= thread
;
1995 ti
->pathptr
= (long *)NULL
;
1996 ti
->child_thread
= 0;
1999 while ( (kd
<= kd_stop
) && (kd
->debugid
& DBG_FUNC_MASK
) == VFS_LOOKUP
)
2001 if (ti
->pathptr
== NULL
) {
2002 ti
->arg1
= kd
->arg1
;
2003 sargptr
= ti
->pathname
;
2005 *sargptr
++ = kd
->arg2
;
2006 *sargptr
++ = kd
->arg3
;
2007 *sargptr
++ = kd
->arg4
;
2009 * NULL terminate the 'string'
2013 ti
->pathptr
= sargptr
;
2016 sargptr
= ti
->pathptr
;
2019 We don't want to overrun our pathname buffer if the
2020 kernel sends us more VFS_LOOKUP entries than we can
2024 if (sargptr
>= &ti
->pathname
[NUMPARMS
])
2031 We need to detect consecutive vfslookup entries.
2032 So, if we get here and find a START entry,
2033 fake the pathptr so we can bypass all further
2037 if (kd
->debugid
& DBG_FUNC_START
)
2039 ti
->pathptr
= &ti
->pathname
[NUMPARMS
];
2043 *sargptr
++ = kd
->arg1
;
2044 *sargptr
++ = kd
->arg2
;
2045 *sargptr
++ = kd
->arg3
;
2046 *sargptr
++ = kd
->arg4
;
2048 * NULL terminate the 'string'
2052 ti
->pathptr
= sargptr
;
2057 p
= (char *)ti
->pathname
;
2060 /* print the tail end of the pathname */
2067 fprintf(log_fp
, "%9.1f %8.1f\t\t%-14.14s %-42s %-8x %-8x %d %s\n",
2068 timestamp
- start_bias
, delta
, "VFS_LOOKUP",
2069 &p
[len
], ti
->arg1
, thread
, cpunum
, command
);
2071 last_timestamp
= timestamp
;
2075 if (debugid
& DBG_FUNC_START
)
2076 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
2077 else if (debugid
& DBG_FUNC_END
)
2078 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
2080 print_entry(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
);
2082 last_timestamp
= timestamp
;
2090 double handle_decrementer(kd_buf
*kd
)
2095 if ((int)(kd
->arg1
) >= 0)
2098 latency
= (((double)(-1 - kd
->arg1
)) / divisor
);
2099 elapsed_usecs
= (int)latency
;
2101 if (elapsed_usecs
< 100)
2102 i_usec_10_bins
[elapsed_usecs
/10]++;
2103 if (elapsed_usecs
< 1000)
2104 i_usec_100_bins
[elapsed_usecs
/100]++;
2105 else if (elapsed_usecs
< 10000)
2106 i_msec_1_bins
[elapsed_usecs
/1000]++;
2107 else if (elapsed_usecs
< 50000)
2108 i_msec_10_bins
[elapsed_usecs
/10000]++;
2112 if(use_high_res_bins
&& elapsed_usecs
< N_HIGH_RES_BINS
) {
2113 if(elapsed_usecs
> i_highest_latency
)
2114 i_highest_latency
= elapsed_usecs
;
2115 i_high_res_bins
[elapsed_usecs
]++;
2118 if (i_thresh_hold
&& elapsed_usecs
> i_thresh_hold
)
2119 i_exceeded_threshold
++;
2120 if (elapsed_usecs
> i_max_latency
)
2121 i_max_latency
= elapsed_usecs
;
2122 if (elapsed_usecs
< i_min_latency
|| i_total_samples
== 0)
2123 i_min_latency
= elapsed_usecs
;
2124 i_total_latency
+= elapsed_usecs
;
2131 void init_code_file()
2137 if ((fp
= fopen(code_file
, "r")) == (FILE *)0) {
2139 fprintf(log_fp
, "open of %s failed\n", code_file
);
2142 for (i
= 0; i
< MAX_ENTRIES
; i
++) {
2143 n
= fscanf(fp
, "%x%127s\n", &code
, name
);
2145 if (n
== 1 && i
== 0) {
2147 * old code file format, just skip
2154 strncpy(codes_tab
[i
].name
, name
, 32);
2155 codes_tab
[i
].type
= code
;
2167 FILE *fp
= (FILE *)0;
2168 char tmp_nm_file
[128];
2172 bzero(tmp_nm_file
, 128);
2173 bzero(tmpstr
, 1024);
2175 /* Build the temporary nm file path */
2176 strcpy(tmp_nm_file
,"/tmp/knm.out.XXXXXX");
2177 if (!mktemp(tmp_nm_file
)) {
2178 fprintf(stderr
, "Error in mktemp call\n");
2182 /* Build the nm command and create a tmp file with the output*/
2183 sprintf (tmpstr
, "/usr/bin/nm -f -n -s __TEXT __text %s > %s",
2184 kernelpath
, tmp_nm_file
);
2187 /* Parse the output from the nm command */
2188 if ((fp
=fopen(tmp_nm_file
, "r")) == (FILE *)0)
2190 /* Hmmm, let's not treat this as fatal */
2191 fprintf(stderr
, "Failed to open nm symbol file [%s]\n", tmp_nm_file
);
2195 /* Count the number of symbols in the nm symbol table */
2197 while ( (inchr
= getc(fp
)) != -1)
2205 /* Malloc the space for symbol table */
2206 if (kern_sym_count
> 0)
2208 kern_sym_tbl
= (kern_sym_t
*)malloc(kern_sym_count
* sizeof (kern_sym_t
));
2211 /* Hmmm, lets not treat this as fatal */
2212 fprintf(stderr
, "Can't allocate memory for kernel symbol table\n");
2215 bzero(kern_sym_tbl
, (kern_sym_count
* sizeof(kern_sym_t
)));
2219 /* Hmmm, lets not treat this as fatal */
2220 fprintf(stderr
, "No kernel symbol table \n");
2223 for (i
=0; i
<kern_sym_count
; i
++)
2225 bzero(tmpstr
, 1024);
2226 if (fscanf(fp
, "%lx %c %s", &kern_sym_tbl
[i
].k_sym_addr
, &inchr
, tmpstr
) != 3)
2230 len
= strlen(tmpstr
);
2231 kern_sym_tbl
[i
].k_sym_name
= malloc(len
+ 1);
2233 if (kern_sym_tbl
[i
].k_sym_name
== (char *)0)
2235 fprintf(stderr
, "Can't allocate memory for symbol name [%s]\n", tmpstr
);
2236 kern_sym_tbl
[i
].k_sym_name
= (char *)0;
2240 strcpy(kern_sym_tbl
[i
].k_sym_name
, tmpstr
);
2242 kern_sym_tbl
[i
].k_sym_len
= len
;
2246 if (i
!= kern_sym_count
)
2248 /* Hmmm, didn't build up entire table from nm */
2249 /* scrap the entire thing */
2251 free (kern_sym_tbl
);
2252 kern_sym_tbl
= (kern_sym_t
*)0;
2258 /* Remove the temporary nm file */
2259 unlink(tmp_nm_file
);
2262 /* Dump the kernel symbol table */
2263 for (i
=0; i
< kern_sym_count
; i
++)
2265 if (kern_sym_tbl
[i
].k_sym_name
)
2266 printf ("[%d] 0x%x %s\n", i
,
2267 kern_sym_tbl
[i
].k_sym_addr
, kern_sym_tbl
[i
].k_sym_name
);
2269 printf ("[%d] 0x%x %s\n", i
,
2270 kern_sym_tbl
[i
].k_sym_addr
, "No symbol name");
2276 pc_to_string(unsigned int pc
, int max_len
, int mode
)
2281 int binary_search();
2285 sprintf(pcstring
, "0x%-8x [usermode addr]", pc
);
2290 ret
= binary_search(kern_sym_tbl
, 0, kern_sym_count
-1, pc
);
2294 sprintf(pcstring
, "0x%x", pc
);
2297 else if (kern_sym_tbl
[ret
].k_sym_name
== (char *)0)
2299 sprintf(pcstring
, "0x%x", pc
);
2304 if ((len
= kern_sym_tbl
[ret
].k_sym_len
) > (max_len
- 8))
2307 memcpy(pcstring
, kern_sym_tbl
[ret
].k_sym_name
, len
);
2308 sprintf(&pcstring
[len
], "+0x%-5lx", pc
- kern_sym_tbl
[ret
].k_sym_addr
);
2315 /* Return -1 if not found, else return index */
2316 int binary_search(list
, low
, high
, addr
)
2323 mid
= (low
+ high
) / 2;
2326 return (-1); /* failed */
2327 else if (low
+ 1 == high
)
2329 if (list
[low
].k_sym_addr
<= addr
&&
2330 addr
< list
[high
].k_sym_addr
)
2332 /* We have a range match */
2335 else if (list
[high
].k_sym_addr
<= addr
)
2340 return(-1); /* Failed */
2342 else if (addr
< list
[mid
].k_sym_addr
)
2344 return(binary_search (list
, low
, mid
, addr
));
2348 return(binary_search (list
, mid
, high
, addr
));
2353 open_logfile(char *path
)
2355 log_fp
= fopen(path
, "a");
2359 /* failed to open path */
2360 fprintf(stderr
, "latency: failed to open logfile [%s]\n", path
);