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>
39 #include <sys/types.h>
40 #include <sys/param.h>
46 #include <sys/ioctl.h>
48 #ifndef KERNEL_PRIVATE
49 #define KERNEL_PRIVATE
50 #include <sys/kdebug.h>
53 #include <sys/kdebug.h>
54 #endif /*KERNEL_PRIVATE*/
56 #include <sys/sysctl.h>
60 #include <mach/host_info.h>
61 #include <mach/mach_error.h>
62 #include <mach/mach_types.h>
63 #include <mach/message.h>
64 #include <mach/mach_syscalls.h>
65 #include <mach/clock_types.h>
66 #include <mach/mach_time.h>
68 #include <libkern/OSTypes.h>
70 extern mach_port_t clock_port
;
72 #define KERN_KDPIDEX 14
75 int s_usec_10_bins
[10];
76 int s_usec_100_bins
[10];
77 int s_msec_1_bins
[10];
78 int s_msec_10_bins
[5];
81 int s_min_latency
= 0;
82 long long s_total_latency
= 0;
85 int s_exceeded_threshold
= 0;
87 int i_usec_10_bins
[10];
88 int i_usec_100_bins
[10];
89 int i_msec_1_bins
[10];
90 int i_msec_10_bins
[5];
93 int i_min_latency
= 0;
94 long long i_total_latency
= 0;
97 int i_exceeded_threshold
= 0;
106 int num_of_usecs_to_sleep
= 1000;
108 char *kernelpath
= (char *)0;
109 char *code_file
= (char *)0;
112 u_long k_sym_addr
; /* kernel symbol address from nm */
113 u_int k_sym_len
; /* length of kernel symbol string */
114 char *k_sym_name
; /* kernel symbol string from nm */
117 kern_sym_t
*kern_sym_tbl
; /* pointer to the nm table */
118 int kern_sym_count
; /* number of entries in nm table */
121 #define UNKNOWN "Can't find symbol name"
126 int trace_enabled
= 0;
127 struct host_basic_info hi
;
130 #define SAMPLE_SIZE 300000
136 kbufinfo_t bufinfo
= {0, 0, 0};
138 FILE *log_fp
= (FILE *)0;
139 int num_of_codes
= 0;
140 int need_new_map
= 0;
141 int total_threads
= 0;
142 kd_threadmap
*mapptr
= 0;
144 #define MAX_ENTRIES 1024
148 } codes_tab
[MAX_ENTRIES
];
160 long pathname
[NUMPARMS
+ 1];
163 #define MAX_THREADS 512
164 struct th_info th_state
[MAX_THREADS
];
168 #define TRACE_DATA_NEWTHREAD 0x07000004
169 #define TRACE_STRING_NEWTHREAD 0x07010004
170 #define TRACE_STRING_EXEC 0x07010008
172 #define INTERRUPT 0x01050000
173 #define DECR_TRAP 0x01090000
174 #define DECR_SET 0x01090004
175 #define MACH_vmfault 0x01300000
176 #define MACH_sched 0x01400000
177 #define MACH_stkhandoff 0x01400008
178 #define VFS_LOOKUP 0x03010090
179 #define BSC_exit 0x040C0004
180 #define IES_action 0x050b0018
181 #define IES_filter 0x050b001c
182 #define TES_action 0x050c0010
183 #define CQ_action 0x050d0018
186 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
187 #define DBG_FUNC_MASK 0xfffffffc
189 #define CPU_NUMBER(ts) ((ts & KDBG_CPU_MASK) >> KDBG_CPU_SHIFT)
191 #define DBG_ZERO_FILL_FAULT 1
192 #define DBG_PAGEIN_FAULT 2
193 #define DBG_COW_FAULT 3
194 #define DBG_CACHE_HIT_FAULT 4
196 char *fault_name
[5] = {
204 char *pc_to_string();
205 static kern_return_t
set_time_constraint_policy(void);
206 static kern_return_t
set_standard_policy(void);
208 int decrementer_val
= 0; /* Value used to reset decrementer */
209 int set_remove_flag
= 1; /* By default, remove trace buffer */
211 kd_buf
**last_decrementer_kd
; /* last DECR_TRAP per cpu */
212 #define MAX_LOG_COUNT 30 /* limits the number of entries dumped in log_decrementer */
226 This flag is turned off when calling
227 quit() due to a set_remove() failure.
246 mib
[1] = KERN_KDEBUG
;
247 mib
[2] = KERN_KDENABLE
; /* protocol */
250 mib
[5] = 0; /* no flags */
252 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
253 quit("trace facility failure, KERN_KDENABLE\n");
257 set_numbufs(int nbufs
)
260 mib
[1] = KERN_KDEBUG
;
261 mib
[2] = KERN_KDSETBUF
;
264 mib
[5] = 0; /* no flags */
265 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
266 quit("trace facility failure, KERN_KDSETBUF\n");
269 mib
[1] = KERN_KDEBUG
;
270 mib
[2] = KERN_KDSETUP
;
273 mib
[5] = 0; /* no flags */
274 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
275 quit("trace facility failure, KERN_KDSETUP\n");
280 set_pidexclude(int pid
, int on_off
)
284 kr
.type
= KDBG_TYPENONE
;
287 needed
= sizeof(kd_regtype
);
289 mib
[1] = KERN_KDEBUG
;
290 mib
[2] = KERN_KDPIDEX
;
295 sysctl(mib
, 3, &kr
, &needed
, NULL
, 0);
298 void set_rtcdec(decval
)
304 kr
.type
= KDBG_TYPENONE
;
306 needed
= sizeof(kd_regtype
);
308 mib
[1] = KERN_KDEBUG
;
309 mib
[2] = KERN_KDSETRTCDEC
; /* protocol */
310 mib
[3] = 0; /* wildcard address family */
312 mib
[5] = 0; /* no flags */
315 if ((ret
=sysctl(mib
, 3, &kr
, &needed
, NULL
, 0)) < 0)
318 /* ignore this sysctl error if it's not supported */
322 quit("trace facility failure, KERN_KDSETRTCDEC\n");
328 get_bufinfo(kbufinfo_t
*val
)
330 needed
= sizeof (*val
);
332 mib
[1] = KERN_KDEBUG
;
333 mib
[2] = KERN_KDGETBUF
;
336 mib
[5] = 0; /* no flags */
338 if (sysctl(mib
, 3, val
, &needed
, 0, 0) < 0)
339 quit("trace facility failure, KERN_KDGETBUF\n");
349 mib
[1] = KERN_KDEBUG
;
350 mib
[2] = KERN_KDREMOVE
; /* protocol */
353 mib
[5] = 0; /* no flags */
357 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
361 quit("the trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n");
363 quit("trace facility failure, KERN_KDREMOVE\n");
370 /* When we aren't logging, only collect the DECR_TRAP trace points */
372 kr
.type
= KDBG_VALCHECK
;
373 kr
.value1
= DECR_TRAP
;
377 needed
= sizeof(kd_regtype
);
379 mib
[1] = KERN_KDEBUG
;
380 mib
[2] = KERN_KDSETREG
;
383 mib
[5] = 0; /* no flags */
384 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
385 quit("trace facility failure, KERN_KDSETREG\n");
388 mib
[1] = KERN_KDEBUG
;
389 mib
[2] = KERN_KDSETUP
;
392 mib
[5] = 0; /* no flags */
394 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
395 quit("trace facility failure, KERN_KDSETUP\n");
402 kr
.type
= KDBG_RANGETYPE
;
405 needed
= sizeof(kd_regtype
);
407 mib
[1] = KERN_KDEBUG
;
408 mib
[2] = KERN_KDSETREG
;
411 mib
[5] = 0; /* no flags */
413 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
414 quit("trace facility failure, KERN_KDSETREG\n");
417 mib
[1] = KERN_KDEBUG
;
418 mib
[2] = KERN_KDSETUP
;
421 mib
[5] = 0; /* no flags */
423 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
424 quit("trace facility failure, KERN_KDSETUP\n");
435 void screen_update();
438 set_pidexclude(getpid(), 0);
439 screen_update(log_fp
);
447 void leave() /* exit under normal conditions -- signal handler */
450 set_pidexclude(getpid(), 0);
459 screen_update(FILE *fp
)
466 unsigned int average_s_latency
;
467 unsigned int average_i_latency
;
470 if (fp
== (FILE *)0) {
474 fprintf(fp
,"\n\n===================================================================================================\n");
476 * Display the current time.
477 * "ctime" always returns a string that looks like this:
479 * Sun Sep 16 01:03:52 1973
480 * 012345678901234567890123
483 * We want indices 11 thru 18 (length 8).
485 elapsed_secs
= curr_time
- start_time
;
486 elapsed_hours
= elapsed_secs
/ 3600;
487 elapsed_secs
-= elapsed_hours
* 3600;
488 elapsed_mins
= elapsed_secs
/ 60;
489 elapsed_secs
-= elapsed_mins
* 60;
491 sprintf(tbuf
, "%-19.19s %2ld:%02ld:%02ld\n", &(ctime(&curr_time
)[0]),
492 (long)elapsed_hours
, (long)elapsed_mins
, (long)elapsed_secs
);
494 fprintf(fp
, "%s", tbuf
);
500 sprintf(tbuf
, " SCHEDULER INTERRUPTS\n");
503 fprintf(fp
, "%s", tbuf
);
507 sprintf(tbuf
, "---------------------------------------------\n");
510 fprintf(fp
, "%s", tbuf
);
516 sprintf(tbuf
, "total_samples %10d %10d\n\n", s_total_samples
, i_total_samples
);
519 fprintf(fp
, "%s", tbuf
);
525 for (itotal
= 0, stotal
= 0, i
= 0; i
< 10; i
++) {
526 sprintf(tbuf
, "delays < %3d usecs %10d %10d\n", (i
+ 1) * 10, s_usec_10_bins
[i
], i_usec_10_bins
[i
]);
529 fprintf(fp
, "%s", tbuf
);
533 stotal
+= s_usec_10_bins
[i
];
534 itotal
+= i_usec_10_bins
[i
];
536 sprintf(tbuf
, "total < 100 usecs %10d %10d\n\n", stotal
, itotal
);
539 fprintf(fp
, "%s", tbuf
);
545 for (itotal
= 0, stotal
= 0, i
= 1; i
< 10; i
++) {
547 sprintf(tbuf
, "delays < %3d usecs %10d %10d\n", (i
+ 1) * 100, s_usec_100_bins
[i
], i_usec_100_bins
[i
]);
549 sprintf(tbuf
, "delays < 1 msec %10d %10d\n", s_usec_100_bins
[i
], i_usec_100_bins
[i
]);
552 fprintf(fp
, "%s", tbuf
);
556 stotal
+= s_usec_100_bins
[i
];
557 itotal
+= i_usec_100_bins
[i
];
559 sprintf(tbuf
, "total < 1 msec %10d %10d\n\n", stotal
, itotal
);
562 fprintf(fp
, "%s", tbuf
);
568 for (itotal
= 0, stotal
= 0, i
= 1; i
< 10; i
++) {
569 sprintf(tbuf
, "delays < %3d msecs %10d %10d\n", (i
+ 1), s_msec_1_bins
[i
], i_msec_1_bins
[i
]);
572 fprintf(fp
, "%s", tbuf
);
576 stotal
+= s_msec_1_bins
[i
];
577 itotal
+= i_msec_1_bins
[i
];
579 sprintf(tbuf
, "total < 10 msecs %10d %10d\n\n", stotal
, itotal
);
582 fprintf(fp
, "%s", tbuf
);
589 for (itotal
= 0, stotal
= 0, i
= 1; i
< 5; i
++) {
590 sprintf(tbuf
, "delays < %3d msecs %10d %10d\n", (i
+ 1)*10, s_msec_10_bins
[i
], i_msec_10_bins
[i
]);
593 fprintf(fp
, "%s", tbuf
);
597 stotal
+= s_msec_10_bins
[i
];
598 itotal
+= i_msec_10_bins
[i
];
600 sprintf(tbuf
, "total < 50 msecs %10d %10d\n\n", stotal
, itotal
);
603 fprintf(fp
, "%s", tbuf
);
607 sprintf(tbuf
, "delays > 50 msecs %10d %10d\n", s_too_slow
, i_too_slow
);
610 fprintf(fp
, "%s", tbuf
);
616 sprintf(tbuf
, "\nminimum latency(usecs) %7d %7d\n", s_min_latency
, i_min_latency
);
619 fprintf(fp
, "%s", tbuf
);
623 sprintf(tbuf
, "maximum latency(usecs) %7d %7d\n", s_max_latency
, i_max_latency
);
626 fprintf(fp
, "%s", tbuf
);
631 average_s_latency
= (unsigned int)(s_total_latency
/s_total_samples
);
633 average_s_latency
= 0;
636 average_i_latency
= (unsigned int)(i_total_latency
/i_total_samples
);
638 average_i_latency
= 0;
640 sprintf(tbuf
, "average latency(usecs) %7d %7d\n", average_s_latency
, average_i_latency
);
643 fprintf(fp
, "%s", tbuf
);
647 sprintf(tbuf
, "exceeded threshold %7d %7d\n", s_exceeded_threshold
, i_exceeded_threshold
);
650 fprintf(fp
, "%s", tbuf
);
664 fprintf(stderr
, "Usage: latency [-rt] [-c codefile] [-l logfile] [-st threshold]\n");
666 #if defined (__i386__)
667 fprintf(stderr
, " [-it threshold] [-s sleep_in_usecs] [-n kernel]\n\n");
669 fprintf(stderr
, " [-it threshold] [-s sleep_in_usecs]\n");
670 fprintf(stderr
, " [-d decrementer_in_usecs] [-n kernel]\n\n");
674 fprintf(stderr
, " -rt Set realtime scheduling policy. Default is timeshare.\n");
675 fprintf(stderr
, " -c specify name of codes file\n");
676 fprintf(stderr
, " -l specify name of file to log trace entries to when threshold is exceeded\n");
677 fprintf(stderr
, " -st set scheduler latency threshold in microseconds... if latency exceeds this, then log trace\n");
678 fprintf(stderr
, " -it set interrupt latency threshold in microseconds... if latency exceeds this, then log trace\n");
679 fprintf(stderr
, " -s set sleep time in microseconds\n");
680 #if !defined (__i386__)
681 fprintf(stderr
, " -d set decrementer in microseconds.\n");
683 fprintf(stderr
, " -n specify kernel, default is /mach_kernel\n");
685 fprintf(stderr
, "\nlatency must be run as root\n\n");
696 uint64_t start
, stop
;
699 uint64_t adeadline
, adelay
;
702 double nanosecs_to_sleep
;
703 int loop_cnt
, sample_sc_now
;
704 int decrementer_usec
= 0;
707 host_name_port_t host
;
710 void init_code_file();
714 my_policy
= THREAD_STANDARD_POLICY
;
715 policy_name
= "TIMESHARE";
718 if (strcmp(argv
[1], "-rt") == 0) {
719 my_policy
= THREAD_TIME_CONSTRAINT_POLICY
; /* the real time band */
720 policy_name
= "REALTIME";
722 } else if (strcmp(argv
[1], "-st") == 0) {
727 s_thresh_hold
= atoi(argv
[1]);
731 } else if (strcmp(argv
[1], "-it") == 0) {
736 i_thresh_hold
= atoi(argv
[1]);
739 } else if (strcmp(argv
[1], "-c") == 0) {
747 } else if (strcmp(argv
[1], "-l") == 0) {
752 open_logfile(argv
[1]);
756 } else if (strcmp(argv
[1], "-s") == 0) {
761 num_of_usecs_to_sleep
= atoi(argv
[1]);
765 else if (strcmp(argv
[1], "-d") == 0) {
770 decrementer_usec
= atoi(argv
[1]);
773 #if defined(__i386__)
774 /* ignore this option - setting the decrementer has no effect */
775 decrementer_usec
= 0;
778 else if (strcmp(argv
[1], "-n") == 0) {
783 kernelpath
= argv
[1];
793 if ( geteuid() != 0 ) {
794 printf("'latency' must be run as root...\n");
798 if (kernelpath
== (char *) 0)
799 kernelpath
= "/mach_kernel";
801 if (code_file
== (char *) 0)
802 code_file
= "/usr/share/misc/trace.codes";
806 sample_sc_now
= 25000 / num_of_usecs_to_sleep
;
809 decrementer_val
= decrementer_usec
* divisor
;
811 /* get the cpu countfor the DECR_TRAP array */
812 host
= mach_host_self();
813 size
= sizeof(hi
)/sizeof(int);
814 ret
= host_info(host
, HOST_BASIC_INFO
, (host_info_t
)&hi
, &size
);
815 if (ret
!= KERN_SUCCESS
) {
816 mach_error(argv
[0], ret
);
820 if ((last_decrementer_kd
= (kd_buf
**)malloc(hi
.avail_cpus
* sizeof(kd_buf
*))) == (kd_buf
**)0)
821 quit("can't allocate memory for decrementer tracing info\n");
823 nanosecs_to_sleep
= (double)(num_of_usecs_to_sleep
* 1000);
824 fdelay
= nanosecs_to_sleep
* (divisor
/1000);
825 adelay
= (uint64_t)fdelay
;
830 When the decrementer isn't set in the options,
831 decval will be zero and this call will reset
832 the system default ...
834 set_rtcdec(decrementer_val
);
836 if (initscr() == (WINDOW
*) 0)
838 printf("Unrecognized TERM type, try vt100\n");
844 signal(SIGWINCH
, sigwinch
);
845 signal(SIGINT
, sigintr
);
846 signal(SIGQUIT
, leave
);
847 signal(SIGTERM
, leave
);
848 signal(SIGHUP
, leave
);
851 if ((my_buffer
= malloc(SAMPLE_SIZE
* sizeof(kd_buf
))) == (char *)0)
852 quit("can't allocate memory for tracing info\n");
854 set_numbufs(SAMPLE_SIZE
);
859 set_init_nologging();
860 set_pidexclude(getpid(), 1);
866 start_time
= time((long *)0);
867 refresh_time
= start_time
;
869 if (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
)
871 /* the realtime band */
872 if(set_time_constraint_policy() != KERN_SUCCESS
)
873 quit("Failed to set realtime policy.\n");
877 curr_time
= time((long *)0);
879 if (curr_time
>= refresh_time
) {
880 if (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
)
882 /* set standard timeshare policy during screen update */
883 if(set_standard_policy() != KERN_SUCCESS
)
884 quit("Failed to set standard policy.\n");
886 screen_update((FILE *)0);
887 if (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
)
889 /* set back to realtime band */
890 if(set_time_constraint_policy() != KERN_SUCCESS
)
891 quit("Failed to set time_constraint policy.\n");
893 refresh_time
= curr_time
+ 1;
896 timestamp1
= mach_absolute_time();
897 adeadline
= timestamp1
+ adelay
;
898 mach_wait_until(adeadline
);
899 timestamp2
= mach_absolute_time();
905 elapsed_usecs
= (int)(((double)(stop
- start
)) / divisor
);
907 if ((elapsed_usecs
-= num_of_usecs_to_sleep
) <= 0)
910 if (elapsed_usecs
< 100)
911 s_usec_10_bins
[elapsed_usecs
/10]++;
912 if (elapsed_usecs
< 1000)
913 s_usec_100_bins
[elapsed_usecs
/100]++;
914 else if (elapsed_usecs
< 10000)
915 s_msec_1_bins
[elapsed_usecs
/1000]++;
916 else if (elapsed_usecs
< 50000)
917 s_msec_10_bins
[elapsed_usecs
/10000]++;
921 if (elapsed_usecs
> s_max_latency
)
922 s_max_latency
= elapsed_usecs
;
923 if (elapsed_usecs
< s_min_latency
|| s_total_samples
== 0)
924 s_min_latency
= elapsed_usecs
;
925 s_total_latency
+= elapsed_usecs
;
928 if (s_thresh_hold
&& elapsed_usecs
> s_thresh_hold
)
929 s_exceeded_threshold
++;
932 if (log_fp
&& s_thresh_hold
&& elapsed_usecs
> s_thresh_hold
)
933 sample_sc(start
, stop
);
935 if (loop_cnt
>= sample_sc_now
) {
936 sample_sc((long long)0, (long long)0);
942 No need to check for initscr error return.
943 We won't get here if it fails on the first call.
957 mach_timebase_info_data_t info
;
959 (void) mach_timebase_info (&info
);
961 divisor
= ( (double)info
.denom
/ (double)info
.numer
) * 1000;
965 /* This is the realtime band */
967 set_time_constraint_policy()
969 kern_return_t result
;
970 thread_time_constraint_policy_data_t info
;
971 mach_msg_type_number_t count
;
972 boolean_t get_default
;
975 count
= THREAD_TIME_CONSTRAINT_POLICY_COUNT
;
976 result
= thread_policy_get(mach_thread_self(), THREAD_TIME_CONSTRAINT_POLICY
,
977 (thread_policy_t
)&info
, &count
, &get_default
);
978 if (result
!= KERN_SUCCESS
)
981 result
= thread_policy_set(mach_thread_self(), THREAD_TIME_CONSTRAINT_POLICY
,
982 (thread_policy_t
)&info
, THREAD_TIME_CONSTRAINT_POLICY_COUNT
);
987 /* This is the timeshare mode */
989 set_standard_policy()
991 kern_return_t result
;
992 thread_standard_policy_data_t info
;
993 mach_msg_type_number_t count
;
994 boolean_t get_default
;
997 count
= THREAD_STANDARD_POLICY_COUNT
;
998 result
= thread_policy_get(mach_thread_self(), THREAD_STANDARD_POLICY
,
999 (thread_policy_t
)&info
, &count
, &get_default
);
1000 if (result
!= KERN_SUCCESS
)
1003 result
= thread_policy_set(mach_thread_self(), THREAD_STANDARD_POLICY
,
1004 (thread_policy_t
)&info
, THREAD_STANDARD_POLICY_COUNT
);
1010 void read_command_map()
1019 total_threads
= bufinfo
.nkdthreads
;
1020 size
= bufinfo
.nkdthreads
* sizeof(kd_threadmap
);
1023 if ((mapptr
= (kd_threadmap
*) malloc(size
)))
1024 bzero (mapptr
, size
);
1027 printf("Thread map is not initialized -- this is not fatal\n");
1032 /* Now read the threadmap */
1034 mib
[1] = KERN_KDEBUG
;
1035 mib
[2] = KERN_KDTHRMAP
;
1038 mib
[5] = 0; /* no flags */
1039 if (sysctl(mib
, 3, mapptr
, &size
, NULL
, 0) < 0)
1041 /* This is not fatal -- just means I cant map command strings */
1043 printf("Can't read the thread map -- this is not fatal\n");
1052 void create_map_entry(int thread
, char *command
)
1060 for (i
= 0, map
= 0; !map
&& i
< total_threads
; i
++)
1062 if (mapptr
[i
].thread
== thread
)
1063 map
= &mapptr
[i
]; /* Reuse this entry, the thread has been reassigned */
1066 if (!map
) /* look for invalid entries that I can reuse*/
1068 for (i
= 0, map
= 0; !map
&& i
< total_threads
; i
++)
1070 if (mapptr
[i
].valid
== 0 )
1071 map
= &mapptr
[i
]; /* Reuse this invalid entry */
1077 /* If reach here, then this is a new thread and
1078 * there are no invalid entries to reuse
1079 * Double the size of the thread map table.
1082 n
= total_threads
* 2;
1083 mapptr
= (kd_threadmap
*) realloc(mapptr
, n
* sizeof(kd_threadmap
));
1084 bzero(&mapptr
[total_threads
], total_threads
*sizeof(kd_threadmap
));
1085 map
= &mapptr
[total_threads
];
1089 fprintf(log_fp
, "MAP: increasing thread map to %d entries\n", total_threads
);
1094 fprintf(log_fp
, "MAP: adding thread %x with name %s\n", thread
, command
);
1097 map
->thread
= thread
;
1099 The trace entry that returns the command name will hold
1100 at most, MAXCOMLEN chars, and in that case, is not
1101 guaranteed to be null terminated.
1103 (void)strncpy (map
->command
, command
, MAXCOMLEN
);
1104 map
->command
[MAXCOMLEN
] = '\0';
1108 kd_threadmap
*find_thread_map(int thread
)
1114 return((kd_threadmap
*)0);
1116 for (i
= 0; i
< total_threads
; i
++)
1119 if (map
->valid
&& (map
->thread
== thread
))
1124 return ((kd_threadmap
*)0);
1128 kill_thread_map(int thread
)
1132 if ((map
= find_thread_map(thread
))) {
1136 fprintf(log_fp
, "MAP: deleting thread %x with name %s\n", thread
, map
->command
);
1140 map
->command
[0] = '\0';
1145 struct th_info
*find_thread(int thread
, int type1
, int type2
) {
1148 for (ti
= th_state
; ti
< &th_state
[cur_max
]; ti
++) {
1149 if (ti
->thread
== thread
) {
1152 if (type1
== ti
->type
)
1154 if (type2
== ti
->type
)
1158 return ((struct th_info
*)0);
1162 char *find_code(type
)
1166 for (i
= 0; i
< num_of_codes
; i
++) {
1167 if (codes_tab
[i
].type
== type
)
1168 return(codes_tab
[i
].name
);
1174 void sample_sc(uint64_t start
, uint64_t stop
)
1176 kd_buf
*kd
, *last_mach_sched
, *start_kd
, *end_of_sample
;
1179 int first_entry
= 1;
1180 double timestamp
= 0.0;
1181 double last_timestamp
= 0.0;
1183 double start_bias
= 0.0;
1185 void read_command_map();
1187 if (log_fp
&& (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
))
1189 /* set standard timeshare policy when logging */
1190 if(set_standard_policy() != KERN_SUCCESS
)
1191 quit("Failed to set standard policy.\n");
1194 /* Get kernel buffer information */
1195 get_bufinfo(&bufinfo
);
1201 needed
= bufinfo
.nkdbufs
* sizeof(kd_buf
);
1203 mib
[1] = KERN_KDEBUG
;
1204 mib
[2] = KERN_KDREADTR
;
1207 mib
[5] = 0; /* no flags */
1209 if (sysctl(mib
, 3, my_buffer
, &needed
, NULL
, 0) < 0)
1210 quit("trace facility failure, KERN_KDREADTR\n");
1214 if (bufinfo
.flags
& KDBG_WRAPPED
) {
1215 for (i
= 0; i
< cur_max
; i
++) {
1216 th_state
[i
].thread
= 0;
1217 th_state
[i
].type
= -1;
1218 th_state
[i
].pathptr
= (long *)NULL
;
1219 th_state
[i
].pathname
[0] = 0;
1230 latency
= (double)(stop
- start
) / divisor
;
1231 latency
-= (double)num_of_usecs_to_sleep
;
1233 fprintf(log_fp
, "\n\n%-19.19s scheduling latency = %.1fus num_of_traces = %d <<<<<<< trace buffer wrapped >>>>>>>\n\n",
1234 &(ctime(&curr_time
)[0]), latency
, count
);
1237 end_of_sample
= &((kd_buf
*)my_buffer
)[count
];
1239 /* Always reinitialize the DECR_TRAP array */
1240 for (i
=0; i
< hi
.avail_cpus
; i
++)
1241 last_decrementer_kd
[i
] = (kd_buf
*)my_buffer
;
1243 last_mach_sched
= (kd_buf
*)0;
1245 for (kd
= (kd_buf
*)my_buffer
; kd
< end_of_sample
; kd
++) {
1246 int debugid
, thread
, cpunum
;
1247 int type
, clen
, mode
;
1252 double i_latency
= 0.0;
1255 char sched_info
[64];
1257 kd_threadmap
*find_thread_map();
1258 double handle_decrementer();
1259 kd_buf
*log_decrementer();
1260 int check_for_thread_update();
1261 void enter_syscall();
1262 void exit_syscall();
1266 cpunum
= CPU_NUMBER(kd
->timestamp
);
1267 debugid
= kd
->debugid
;
1268 type
= kd
->debugid
& DBG_FUNC_MASK
;
1270 if (check_for_thread_update(thread
, type
, kd
))
1273 if (type
== DECR_TRAP
)
1274 i_latency
= handle_decrementer(kd
);
1276 now
= kd
->timestamp
& KDBG_TIMESTAMP_MASK
;
1278 timestamp
= ((double)now
) / divisor
;
1280 if (now
< start
|| now
> stop
) {
1281 if (debugid
& DBG_FUNC_START
)
1282 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 0);
1283 else if (debugid
& DBG_FUNC_END
)
1284 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 0);
1285 else if (type
== DECR_TRAP
) {
1287 if (log_fp
&& i_thresh_hold
&& (int)i_latency
> i_thresh_hold
) {
1288 start_kd
= last_decrementer_kd
[cpunum
];
1289 kd
= log_decrementer(start_kd
, kd
, end_of_sample
, i_latency
);
1290 if (kd
>= end_of_sample
)
1293 if ((kd
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1295 cpunum
= CPU_NUMBER(kd
->timestamp
);
1296 last_decrementer_kd
[cpunum
] = kd
;
1299 last_decrementer_kd
[cpunum
] = cur_kd
;
1308 latency
= (double)(stop
- start
) / divisor
;
1309 latency
-= (double)num_of_usecs_to_sleep
;
1312 sprintf(buf2
, "default");
1314 sprintf(buf2
, "%d", my_pri
);
1315 sprintf(buf1
, "%-19.19s scheduling latency = %.1fus sleep_request = %dus policy = %s priority = %s",
1316 &(ctime(&curr_time
)[0]), latency
, num_of_usecs_to_sleep
, policy_name
, buf2
);
1317 clen
= strlen(buf1
);
1318 memset(buf2
, '-', clen
);
1322 fprintf(log_fp
, "\n\n%s\n", buf2
);
1323 fprintf(log_fp
, "%s\n\n", buf1
);
1324 fprintf(log_fp
, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
1326 start_bias
= ((double)start
) / divisor
;
1327 last_timestamp
= timestamp
;
1330 delta
= timestamp
- last_timestamp
;
1332 if ((map
= find_thread_map(thread
)))
1333 strcpy(command
, map
->command
);
1341 fprintf(log_fp
, "%9.1f %8.1f\t\tCQ_action @ %-59.59s %-8x %d %s\n",
1342 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 59, 1) , thread
, cpunum
, command
);
1344 last_timestamp
= timestamp
;
1349 fprintf(log_fp
, "%9.1f %8.1f\t\tTES_action @ %-58.58s %-8x %d %s\n",
1350 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 58, 1) , thread
, cpunum
, command
);
1353 last_timestamp
= timestamp
;
1358 fprintf(log_fp
, "%9.1f %8.1f\t\tIES_action @ %-58.58s %-8x %d %s\n",
1359 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 58, 1) , thread
, cpunum
, command
);
1362 last_timestamp
= timestamp
;
1367 fprintf(log_fp
, "%9.1f %8.1f\t\tIES_filter @ %-58.58s %-8x %d %s\n",
1368 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 58, 1) , thread
, cpunum
, command
);
1371 last_timestamp
= timestamp
;
1375 last_decrementer_kd
[cpunum
] = kd
;
1377 if (i_thresh_hold
&& (int)i_latency
> i_thresh_hold
)
1384 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1385 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1390 fprintf(log_fp
, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-59.59s %-8x %d %s\n",
1391 timestamp
- start_bias
, delta
, i_latency
, p
, pc_to_string(kd
->arg2
, 59, mode
) , thread
, cpunum
, command
);
1394 last_timestamp
= timestamp
;
1399 fprintf(log_fp
, "%9.1f %8.1f[%.1f] \t%-28.28s %-8x %d %s\n",
1400 timestamp
- start_bias
, delta
, (double)kd
->arg1
/divisor
, "DECR_SET", thread
, cpunum
, command
);
1403 last_timestamp
= timestamp
;
1407 case MACH_stkhandoff
:
1408 last_mach_sched
= kd
;
1410 if ((map
= find_thread_map(kd
->arg2
)))
1411 strcpy(command1
, map
->command
);
1413 sprintf(command1
, "%-8x", kd
->arg2
);
1415 if ((ti
= find_thread(kd
->arg2
, 0, 0))) {
1416 if (ti
->type
== -1 && strcmp(command1
, "kernel_task"))
1422 memset(sched_info
, ' ', sizeof(sched_info
));
1424 sprintf(sched_info
, "%14.14s", command
);
1425 clen
= strlen(sched_info
);
1426 sched_info
[clen
] = ' ';
1428 sprintf(&sched_info
[14], " @ pri %3d --> %14.14s", kd
->arg3
, command1
);
1429 clen
= strlen(sched_info
);
1430 sched_info
[clen
] = ' ';
1432 sprintf(&sched_info
[45], " @ pri %3d%s", kd
->arg4
, p
);
1435 fprintf(log_fp
, "%9.1f %8.1f\t\t%-10.10s %s %-8x %d\n",
1436 timestamp
- start_bias
, delta
, "MACH_SCHED", sched_info
, thread
, cpunum
);
1439 last_timestamp
= timestamp
;
1443 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1444 if (cur_max
>= MAX_THREADS
)
1446 ti
= &th_state
[cur_max
++];
1448 ti
->thread
= thread
;
1450 ti
->pathptr
= (long *)0;
1451 ti
->child_thread
= 0;
1453 while ( (kd
< end_of_sample
) && ((kd
->debugid
& DBG_FUNC_MASK
) == VFS_LOOKUP
))
1455 if (ti
->pathptr
== NULL
) {
1456 ti
->arg1
= kd
->arg1
;
1457 sargptr
= ti
->pathname
;
1459 *sargptr
++ = kd
->arg2
;
1460 *sargptr
++ = kd
->arg3
;
1461 *sargptr
++ = kd
->arg4
;
1463 * NULL terminate the 'string'
1466 ti
->pathptr
= sargptr
;
1469 sargptr
= ti
->pathptr
;
1472 We don't want to overrun our pathname buffer if the
1473 kernel sends us more VFS_LOOKUP entries than we can
1477 if (sargptr
>= &ti
->pathname
[NUMPARMS
])
1484 We need to detect consecutive vfslookup entries.
1485 So, if we get here and find a START entry,
1486 fake the pathptr so we can bypass all further
1490 if (kd
->debugid
& DBG_FUNC_START
)
1492 ti
->pathptr
= &ti
->pathname
[NUMPARMS
];
1496 *sargptr
++ = kd
->arg1
;
1497 *sargptr
++ = kd
->arg2
;
1498 *sargptr
++ = kd
->arg3
;
1499 *sargptr
++ = kd
->arg4
;
1501 * NULL terminate the 'string'
1505 ti
->pathptr
= sargptr
;
1510 p
= (char *)ti
->pathname
;
1514 /* print the tail end of the pathname */
1522 fprintf(log_fp
, "%9.1f %8.1f\t\t%-14.14s %-42s %-8x %-8x %d %s\n",
1523 timestamp
- start_bias
, delta
, "VFS_LOOKUP",
1524 &p
[len
], ti
->arg1
, thread
, cpunum
, command
);
1527 last_timestamp
= timestamp
;
1531 if (debugid
& DBG_FUNC_START
)
1532 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
1533 else if (debugid
& DBG_FUNC_END
)
1534 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
1536 print_entry(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
);
1538 last_timestamp
= timestamp
;
1542 if (last_mach_sched
&& log_fp
)
1543 fprintf(log_fp
, "\nblocked by %s @ priority %d\n", command
, last_mach_sched
->arg3
);
1545 if (first_entry
== 0 && log_fp
)
1546 fprintf(log_fp
, "\n start = %qd stop = %qd count = %d now = %qd\n", start
, stop
, count
, now
);
1551 if (log_fp
&& (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
))
1553 /* set back to realtime band */
1554 if(set_time_constraint_policy() != KERN_SUCCESS
)
1555 quit("Failed to set time_constraint policy.\n");
1560 enter_syscall(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
, int print_info
)
1567 cpunum
= CPU_NUMBER(kd
->timestamp
);
1569 if (print_info
&& fp
) {
1570 if ((p
= find_code(type
))) {
1571 if (type
== INTERRUPT
) {
1574 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1575 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1579 fprintf(fp
, "%9.1f %8.1f\t\tINTERRUPT @ %-59.59s %-8x %d %s\n",
1580 timestamp
- bias
, delta
, pc_to_string(kd
->arg2
, 59, mode
), thread
, cpunum
, command
);
1581 } else if (type
== MACH_vmfault
) {
1582 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %d %s\n",
1583 timestamp
- bias
, delta
, p
, thread
, cpunum
, command
);
1585 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %-8x %-8x %-8x %-8x %d %s\n",
1586 timestamp
- bias
, delta
, p
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1587 thread
, cpunum
, command
);
1590 fprintf(fp
, "%9.1f %8.1f\t\t%-8x %-8x %-8x %-8x %-8x %-8x %d %s\n",
1591 timestamp
- bias
, delta
, type
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1592 thread
, cpunum
, command
);
1595 if ((ti
= find_thread(thread
, -1, type
)) == (struct th_info
*)0) {
1596 if (cur_max
>= MAX_THREADS
) {
1597 static int do_this_once
= 1;
1600 for (i
= 0; i
< cur_max
; i
++) {
1603 fprintf(fp
, "thread = %x, type = %x\n",
1604 th_state
[i
].thread
, th_state
[i
].type
);
1611 ti
= &th_state
[cur_max
++];
1613 ti
->thread
= thread
;
1614 ti
->child_thread
= 0;
1616 if (type
!= BSC_exit
)
1620 ti
->stime
= timestamp
;
1621 ti
->pathptr
= (long *)NULL
;
1624 if (print_info
&& fp
)
1625 fprintf(fp
, "cur_max = %d, ti = %x, type = %x, thread = %x\n", cur_max
, ti
, ti
->type
, ti
->thread
);
1631 exit_syscall(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
, int print_info
)
1637 cpunum
= CPU_NUMBER(kd
->timestamp
);
1639 ti
= find_thread(thread
, type
, type
);
1641 if (print_info
&& fp
)
1642 fprintf(fp
, "cur_max = %d, ti = %x, type = %x, thread = %x\n", cur_max
, ti
, type
, thread
);
1644 if (print_info
&& fp
) {
1646 fprintf(fp
, "%9.1f %8.1f(%.1f) \t", timestamp
- bias
, delta
, timestamp
- ti
->stime
);
1648 fprintf(fp
, "%9.1f %8.1f() \t", timestamp
- bias
, delta
);
1650 if ((p
= find_code(type
))) {
1651 if (type
== INTERRUPT
) {
1652 fprintf(fp
, "INTERRUPT %-8x %d %s\n", thread
, cpunum
, command
);
1653 } else if (type
== MACH_vmfault
&& kd
->arg2
<= DBG_CACHE_HIT_FAULT
) {
1654 fprintf(fp
, "%-28.28s %-8.8s %-8x %-8x %d %s\n",
1655 p
, fault_name
[kd
->arg2
], kd
->arg1
,
1656 thread
, cpunum
, command
);
1658 fprintf(fp
, "%-28.28s %-8x %-8x %-8x %d %s\n",
1659 p
, kd
->arg1
, kd
->arg2
,
1660 thread
, cpunum
, command
);
1663 fprintf(fp
, "%-8x %-8x %-8x %-8x %d %s\n",
1664 type
, kd
->arg1
, kd
->arg2
,
1665 thread
, cpunum
, command
);
1668 if (ti
== (struct th_info
*)0) {
1669 if ((ti
= find_thread(thread
, -1, -1)) == (struct th_info
*)0) {
1670 if (cur_max
>= MAX_THREADS
)
1672 ti
= &th_state
[cur_max
++];
1674 ti
->thread
= thread
;
1675 ti
->child_thread
= 0;
1676 ti
->pathptr
= (long *)NULL
;
1683 print_entry(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
)
1691 cpunum
= CPU_NUMBER(kd
->timestamp
);
1693 fprintf(fp
, "cur_max = %d, type = %x, thread = %x, cpunum = %d\n", cur_max
, type
, thread
, cpunum
);
1695 if ((p
= find_code(type
))) {
1696 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %-8x %-8x %-8x %-8x %d %s\n",
1697 timestamp
- bias
, delta
, p
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1698 thread
, cpunum
, command
);
1700 fprintf(fp
, "%9.1f %8.1f\t\t%-8x %-8x %-8x %-8x %-8x %-8x %d %s\n",
1701 timestamp
- bias
, delta
, type
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1702 thread
, cpunum
, command
);
1707 check_for_thread_update(int thread
, int type
, kd_buf
*kd
)
1710 void create_map_entry();
1714 case TRACE_DATA_NEWTHREAD
:
1715 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1716 if (cur_max
>= MAX_THREADS
)
1718 ti
= &th_state
[cur_max
++];
1720 ti
->thread
= thread
;
1722 ti
->pathptr
= (long *)NULL
;
1724 ti
->child_thread
= kd
->arg1
;
1727 case TRACE_STRING_NEWTHREAD
:
1728 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0)
1730 if (ti
->child_thread
== 0)
1732 create_map_entry(ti
->child_thread
, (char *)&kd
->arg1
);
1734 ti
->child_thread
= 0;
1737 case TRACE_STRING_EXEC
:
1738 create_map_entry(thread
, (char *)&kd
->arg1
);
1746 kd_buf
*log_decrementer(kd_buf
*kd_beg
, kd_buf
*kd_end
, kd_buf
*end_of_sample
, double i_latency
)
1748 kd_buf
*kd
, *kd_start
, *kd_stop
;
1749 int kd_count
; /* Limit the boundary of kd_start */
1750 double timestamp
= 0.0;
1751 double last_timestamp
= 0.0;
1753 double start_bias
= 0.0;
1755 int debugid
, type
, clen
;
1763 char sched_info
[64];
1767 kd_threadmap
*find_thread_map();
1769 sprintf(buf1
, "%-19.19s interrupt latency = %.1fus", &(ctime(&curr_time
)[0]), i_latency
);
1770 clen
= strlen(buf1
);
1771 memset(buf2
, '-', clen
);
1773 fprintf(log_fp
, "\n\n%s\n", buf2
);
1774 fprintf(log_fp
, "%s\n\n", buf1
);
1776 fprintf(log_fp
, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
1778 thread
= kd_beg
->arg5
;
1779 cpunum
= CPU_NUMBER(kd_end
->timestamp
);
1781 for (kd_count
= 0, kd_start
= kd_beg
- 1; (kd_start
>= (kd_buf
*)my_buffer
); kd_start
--, kd_count
++) {
1782 if (kd_count
== MAX_LOG_COUNT
)
1785 if (CPU_NUMBER(kd_start
->timestamp
) != cpunum
)
1788 if ((kd_start
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1791 if (kd_start
->arg5
!= thread
)
1795 if (kd_start
< (kd_buf
*)my_buffer
)
1796 kd_start
= (kd_buf
*)my_buffer
;
1798 thread
= kd_end
->arg5
;
1800 for (kd_stop
= kd_end
+ 1; kd_stop
< end_of_sample
; kd_stop
++) {
1802 if ((kd_stop
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1805 if (CPU_NUMBER(kd_stop
->timestamp
) != cpunum
)
1808 if (kd_stop
->arg5
!= thread
)
1812 if (kd_stop
>= end_of_sample
)
1813 kd_stop
= end_of_sample
- 1;
1815 now
= kd_start
->timestamp
& KDBG_TIMESTAMP_MASK
;
1816 timestamp
= ((double)now
) / divisor
;
1818 for (kd
= kd_start
; kd
<= kd_stop
; kd
++) {
1819 type
= kd
->debugid
& DBG_FUNC_MASK
;
1821 if ((ti
= find_thread(kd
->arg5
, type
, type
))) {
1822 if (ti
->stime
>= timestamp
)
1826 for (kd
= kd_start
; kd
<= kd_stop
; kd
++) {
1830 cpunum
= CPU_NUMBER(kd
->timestamp
);
1831 debugid
= kd
->debugid
;
1832 type
= kd
->debugid
& DBG_FUNC_MASK
;
1834 now
= kd
->timestamp
& KDBG_TIMESTAMP_MASK
;
1836 timestamp
= ((double)now
) / divisor
;
1838 if (kd
== kd_start
) {
1839 start_bias
= timestamp
;
1840 last_timestamp
= timestamp
;
1842 delta
= timestamp
- last_timestamp
;
1844 if ((map
= find_thread_map(thread
)))
1845 strcpy(command
, map
->command
);
1853 fprintf(log_fp
, "%9.1f %8.1f\t\tCQ_action @ %-59.59s %-8x %d %s\n",
1854 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 59, 1) , thread
, cpunum
, command
);
1856 last_timestamp
= timestamp
;
1860 if ((int)(kd
->arg1
) >= 0)
1863 i_latency
= (((double)(-1 - kd
->arg1
)) / divisor
);
1865 if (i_thresh_hold
&& (int)i_latency
> i_thresh_hold
)
1872 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1873 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1876 fprintf(log_fp
, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-59.59s %-8x %d %s\n",
1877 timestamp
- start_bias
, delta
, i_latency
, p
, pc_to_string(kd
->arg2
, 59, mode
) , thread
, cpunum
, command
);
1879 last_timestamp
= timestamp
;
1883 fprintf(log_fp
, "%9.1f %8.1f[%.1f] \t%-28.28s %-8x %d %s\n",
1884 timestamp
- start_bias
, delta
, (double)kd
->arg1
/divisor
,
1885 "DECR_SET", thread
, cpunum
, command
);
1887 last_timestamp
= timestamp
;
1891 case MACH_stkhandoff
:
1892 if ((map
= find_thread_map(kd
->arg2
)))
1893 strcpy(command1
, map
->command
);
1895 sprintf(command1
, "%-8x", kd
->arg2
);
1897 if ((ti
= find_thread(kd
->arg2
, 0, 0))) {
1898 if (ti
->type
== -1 && strcmp(command1
, "kernel_task"))
1904 memset(sched_info
, ' ', sizeof(sched_info
));
1906 sprintf(sched_info
, "%14.14s", command
);
1907 clen
= strlen(sched_info
);
1908 sched_info
[clen
] = ' ';
1910 sprintf(&sched_info
[14], " @ pri %3d --> %14.14s", kd
->arg3
, command1
);
1911 clen
= strlen(sched_info
);
1912 sched_info
[clen
] = ' ';
1914 sprintf(&sched_info
[45], " @ pri %3d%s", kd
->arg4
, p
);
1916 fprintf(log_fp
, "%9.1f %8.1f\t\t%-10.10s %s %-8x %d\n",
1917 timestamp
- start_bias
, delta
, "MACH_SCHED", sched_info
, thread
, cpunum
);
1919 last_timestamp
= timestamp
;
1923 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1924 if (cur_max
>= MAX_THREADS
)
1926 ti
= &th_state
[cur_max
++];
1928 ti
->thread
= thread
;
1930 ti
->pathptr
= (long *)NULL
;
1931 ti
->child_thread
= 0;
1934 while ( (kd
<= kd_stop
) && (kd
->debugid
& DBG_FUNC_MASK
) == VFS_LOOKUP
)
1936 if (ti
->pathptr
== NULL
) {
1937 ti
->arg1
= kd
->arg1
;
1938 sargptr
= ti
->pathname
;
1940 *sargptr
++ = kd
->arg2
;
1941 *sargptr
++ = kd
->arg3
;
1942 *sargptr
++ = kd
->arg4
;
1944 * NULL terminate the 'string'
1948 ti
->pathptr
= sargptr
;
1951 sargptr
= ti
->pathptr
;
1954 We don't want to overrun our pathname buffer if the
1955 kernel sends us more VFS_LOOKUP entries than we can
1959 if (sargptr
>= &ti
->pathname
[NUMPARMS
])
1966 We need to detect consecutive vfslookup entries.
1967 So, if we get here and find a START entry,
1968 fake the pathptr so we can bypass all further
1972 if (kd
->debugid
& DBG_FUNC_START
)
1974 ti
->pathptr
= &ti
->pathname
[NUMPARMS
];
1978 *sargptr
++ = kd
->arg1
;
1979 *sargptr
++ = kd
->arg2
;
1980 *sargptr
++ = kd
->arg3
;
1981 *sargptr
++ = kd
->arg4
;
1983 * NULL terminate the 'string'
1987 ti
->pathptr
= sargptr
;
1992 p
= (char *)ti
->pathname
;
1995 /* print the tail end of the pathname */
2002 fprintf(log_fp
, "%9.1f %8.1f\t\t%-14.14s %-42s %-8x %-8x %d %s\n",
2003 timestamp
- start_bias
, delta
, "VFS_LOOKUP",
2004 &p
[len
], ti
->arg1
, thread
, cpunum
, command
);
2006 last_timestamp
= timestamp
;
2010 if (debugid
& DBG_FUNC_START
)
2011 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
2012 else if (debugid
& DBG_FUNC_END
)
2013 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
2015 print_entry(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
);
2017 last_timestamp
= timestamp
;
2025 double handle_decrementer(kd_buf
*kd
)
2030 if ((int)(kd
->arg1
) >= 0)
2033 latency
= (((double)(-1 - kd
->arg1
)) / divisor
);
2034 elapsed_usecs
= (int)latency
;
2036 if (elapsed_usecs
< 100)
2037 i_usec_10_bins
[elapsed_usecs
/10]++;
2038 if (elapsed_usecs
< 1000)
2039 i_usec_100_bins
[elapsed_usecs
/100]++;
2040 else if (elapsed_usecs
< 10000)
2041 i_msec_1_bins
[elapsed_usecs
/1000]++;
2042 else if (elapsed_usecs
< 50000)
2043 i_msec_10_bins
[elapsed_usecs
/10000]++;
2047 if (i_thresh_hold
&& elapsed_usecs
> i_thresh_hold
)
2048 i_exceeded_threshold
++;
2049 if (elapsed_usecs
> i_max_latency
)
2050 i_max_latency
= elapsed_usecs
;
2051 if (elapsed_usecs
< i_min_latency
|| i_total_samples
== 0)
2052 i_min_latency
= elapsed_usecs
;
2053 i_total_latency
+= elapsed_usecs
;
2060 void init_code_file()
2063 int i
, n
, cnt
, code
;
2066 if ((fp
= fopen(code_file
, "r")) == (FILE *)0) {
2068 fprintf(log_fp
, "open of %s failed\n", code_file
);
2071 n
= fscanf(fp
, "%d\n", &cnt
);
2075 fprintf(log_fp
, "bad format found in %s\n", code_file
);
2078 for (i
= 0; i
< MAX_ENTRIES
; i
++) {
2079 n
= fscanf(fp
, "%x%s\n", &code
, name
);
2084 strncpy(codes_tab
[i
].name
, name
, 32);
2085 codes_tab
[i
].type
= code
;
2097 FILE *fp
= (FILE *)0;
2098 char tmp_nm_file
[128];
2102 bzero(tmp_nm_file
, 128);
2103 bzero(tmpstr
, 1024);
2105 /* Build the temporary nm file path */
2106 sprintf(tmp_nm_file
, "/tmp/knm.out.%d", getpid());
2108 /* Build the nm command and create a tmp file with the output*/
2109 sprintf (tmpstr
, "/usr/bin/nm -f -n -s __TEXT __text %s > %s",
2110 kernelpath
, tmp_nm_file
);
2113 /* Parse the output from the nm command */
2114 if ((fp
=fopen(tmp_nm_file
, "r")) == (FILE *)0)
2116 /* Hmmm, let's not treat this as fatal */
2117 fprintf(stderr
, "Failed to open nm symbol file [%s]\n", tmp_nm_file
);
2121 /* Count the number of symbols in the nm symbol table */
2123 while ( (inchr
= getc(fp
)) != -1)
2131 /* Malloc the space for symbol table */
2132 if (kern_sym_count
> 0)
2134 kern_sym_tbl
= (kern_sym_t
*)malloc(kern_sym_count
* sizeof (kern_sym_t
));
2137 /* Hmmm, lets not treat this as fatal */
2138 fprintf(stderr
, "Can't allocate memory for kernel symbol table\n");
2141 bzero(kern_sym_tbl
, (kern_sym_count
* sizeof(kern_sym_t
)));
2145 /* Hmmm, lets not treat this as fatal */
2146 fprintf(stderr
, "No kernel symbol table \n");
2149 for (i
=0; i
<kern_sym_count
; i
++)
2151 bzero(tmpstr
, 1024);
2152 if (fscanf(fp
, "%lx %c %s", &kern_sym_tbl
[i
].k_sym_addr
, &inchr
, tmpstr
) != 3)
2156 len
= strlen(tmpstr
);
2157 kern_sym_tbl
[i
].k_sym_name
= malloc(len
+ 1);
2159 if (kern_sym_tbl
[i
].k_sym_name
== (char *)0)
2161 fprintf(stderr
, "Can't allocate memory for symbol name [%s]\n", tmpstr
);
2162 kern_sym_tbl
[i
].k_sym_name
= (char *)0;
2166 strcpy(kern_sym_tbl
[i
].k_sym_name
, tmpstr
);
2168 kern_sym_tbl
[i
].k_sym_len
= len
;
2172 if (i
!= kern_sym_count
)
2174 /* Hmmm, didn't build up entire table from nm */
2175 /* scrap the entire thing */
2177 free (kern_sym_tbl
);
2178 kern_sym_tbl
= (kern_sym_t
*)0;
2184 /* Remove the temporary nm file */
2185 unlink(tmp_nm_file
);
2188 /* Dump the kernel symbol table */
2189 for (i
=0; i
< kern_sym_count
; i
++)
2191 if (kern_sym_tbl
[i
].k_sym_name
)
2192 printf ("[%d] 0x%x %s\n", i
,
2193 kern_sym_tbl
[i
].k_sym_addr
, kern_sym_tbl
[i
].k_sym_name
);
2195 printf ("[%d] 0x%x %s\n", i
,
2196 kern_sym_tbl
[i
].k_sym_addr
, "No symbol name");
2202 pc_to_string(unsigned int pc
, int max_len
, int mode
)
2207 int binary_search();
2211 sprintf(pcstring
, "0x%-8x [usermode addr]", pc
);
2216 ret
= binary_search(kern_sym_tbl
, 0, kern_sym_count
-1, pc
);
2220 sprintf(pcstring
, "0x%x", pc
);
2223 else if (kern_sym_tbl
[ret
].k_sym_name
== (char *)0)
2225 sprintf(pcstring
, "0x%x", pc
);
2230 if ((len
= kern_sym_tbl
[ret
].k_sym_len
) > (max_len
- 8))
2233 memcpy(pcstring
, kern_sym_tbl
[ret
].k_sym_name
, len
);
2234 sprintf(&pcstring
[len
], "+0x%-5lx", pc
- kern_sym_tbl
[ret
].k_sym_addr
);
2241 /* Return -1 if not found, else return index */
2242 int binary_search(list
, low
, high
, addr
)
2249 mid
= (low
+ high
) / 2;
2252 return (-1); /* failed */
2253 else if (low
+ 1 == high
)
2255 if (list
[low
].k_sym_addr
<= addr
&&
2256 addr
< list
[high
].k_sym_addr
)
2258 /* We have a range match */
2261 else if (list
[high
].k_sym_addr
<= addr
)
2266 return(-1); /* Failed */
2268 else if (addr
< list
[mid
].k_sym_addr
)
2270 return(binary_search (list
, low
, mid
, addr
));
2274 return(binary_search (list
, mid
, high
, addr
));
2279 open_logfile(char *path
)
2281 log_fp
= fopen(path
, "a");
2285 /* failed to open path */
2286 fprintf(stderr
, "latency: failed to open logfile [%s]\n", path
);