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 char *kernelpath
= (char *)0;
110 char *code_file
= (char *)0;
113 u_long k_sym_addr
; /* kernel symbol address from nm */
114 u_int k_sym_len
; /* length of kernel symbol string */
115 char *k_sym_name
; /* kernel symbol string from nm */
118 kern_sym_t
*kern_sym_tbl
; /* pointer to the nm table */
119 int kern_sym_count
; /* number of entries in nm table */
122 #define UNKNOWN "Can't find symbol name"
127 int trace_enabled
= 0;
128 struct host_basic_info hi
;
131 #define SAMPLE_SIZE 300000
137 kbufinfo_t bufinfo
= {0, 0, 0};
139 FILE *log_fp
= (FILE *)0;
140 int num_of_codes
= 0;
141 int need_new_map
= 0;
142 int total_threads
= 0;
143 kd_threadmap
*mapptr
= 0;
145 #define MAX_ENTRIES 4096
149 } codes_tab
[MAX_ENTRIES
];
161 long pathname
[NUMPARMS
+ 1];
164 #define MAX_THREADS 512
165 struct th_info th_state
[MAX_THREADS
];
169 #define TRACE_DATA_NEWTHREAD 0x07000004
170 #define TRACE_STRING_NEWTHREAD 0x07010004
171 #define TRACE_STRING_EXEC 0x07010008
173 #define INTERRUPT 0x01050000
174 #define DECR_TRAP 0x01090000
175 #define DECR_SET 0x01090004
176 #define MACH_vmfault 0x01300008
177 #define MACH_sched 0x01400000
178 #define MACH_stkhandoff 0x01400008
179 #define VFS_LOOKUP 0x03010090
180 #define BSC_exit 0x040C0004
181 #define IES_action 0x050b0018
182 #define IES_filter 0x050b001c
183 #define TES_action 0x050c0010
184 #define CQ_action 0x050d0018
187 #define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
188 #define DBG_FUNC_MASK 0xfffffffc
190 #define CPU_NUMBER(ts) ((ts & KDBG_CPU_MASK) >> KDBG_CPU_SHIFT)
192 #define DBG_ZERO_FILL_FAULT 1
193 #define DBG_PAGEIN_FAULT 2
194 #define DBG_COW_FAULT 3
195 #define DBG_CACHE_HIT_FAULT 4
197 char *fault_name
[5] = {
205 char *pc_to_string();
206 static kern_return_t
set_time_constraint_policy(void);
207 static kern_return_t
set_standard_policy(void);
209 int decrementer_val
= 0; /* Value used to reset decrementer */
210 int set_remove_flag
= 1; /* By default, remove trace buffer */
212 kd_buf
**last_decrementer_kd
; /* last DECR_TRAP per cpu */
213 #define MAX_LOG_COUNT 30 /* limits the number of entries dumped in log_decrementer */
227 This flag is turned off when calling
228 quit() due to a set_remove() failure.
247 mib
[1] = KERN_KDEBUG
;
248 mib
[2] = KERN_KDENABLE
; /* protocol */
251 mib
[5] = 0; /* no flags */
253 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
254 quit("trace facility failure, KERN_KDENABLE\n");
258 set_numbufs(int nbufs
)
261 mib
[1] = KERN_KDEBUG
;
262 mib
[2] = KERN_KDSETBUF
;
265 mib
[5] = 0; /* no flags */
266 if (sysctl(mib
, 4, NULL
, &needed
, NULL
, 0) < 0)
267 quit("trace facility failure, KERN_KDSETBUF\n");
270 mib
[1] = KERN_KDEBUG
;
271 mib
[2] = KERN_KDSETUP
;
274 mib
[5] = 0; /* no flags */
275 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
276 quit("trace facility failure, KERN_KDSETUP\n");
281 set_pidexclude(int pid
, int on_off
)
285 kr
.type
= KDBG_TYPENONE
;
288 needed
= sizeof(kd_regtype
);
290 mib
[1] = KERN_KDEBUG
;
291 mib
[2] = KERN_KDPIDEX
;
296 sysctl(mib
, 3, &kr
, &needed
, NULL
, 0);
299 void set_rtcdec(decval
)
305 kr
.type
= KDBG_TYPENONE
;
307 needed
= sizeof(kd_regtype
);
309 mib
[1] = KERN_KDEBUG
;
310 mib
[2] = KERN_KDSETRTCDEC
; /* protocol */
311 mib
[3] = 0; /* wildcard address family */
313 mib
[5] = 0; /* no flags */
316 if ((ret
=sysctl(mib
, 3, &kr
, &needed
, NULL
, 0)) < 0)
319 /* ignore this sysctl error if it's not supported */
323 quit("trace facility failure, KERN_KDSETRTCDEC\n");
329 get_bufinfo(kbufinfo_t
*val
)
331 needed
= sizeof (*val
);
333 mib
[1] = KERN_KDEBUG
;
334 mib
[2] = KERN_KDGETBUF
;
337 mib
[5] = 0; /* no flags */
339 if (sysctl(mib
, 3, val
, &needed
, 0, 0) < 0)
340 quit("trace facility failure, KERN_KDGETBUF\n");
350 mib
[1] = KERN_KDEBUG
;
351 mib
[2] = KERN_KDREMOVE
; /* protocol */
354 mib
[5] = 0; /* no flags */
358 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
362 quit("the trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n");
364 quit("trace facility failure, KERN_KDREMOVE\n");
371 /* When we aren't logging, only collect the DECR_TRAP trace points */
373 kr
.type
= KDBG_VALCHECK
;
374 kr
.value1
= DECR_TRAP
;
378 needed
= sizeof(kd_regtype
);
380 mib
[1] = KERN_KDEBUG
;
381 mib
[2] = KERN_KDSETREG
;
384 mib
[5] = 0; /* no flags */
385 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
386 quit("trace facility failure, KERN_KDSETREG\n");
389 mib
[1] = KERN_KDEBUG
;
390 mib
[2] = KERN_KDSETUP
;
393 mib
[5] = 0; /* no flags */
395 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
396 quit("trace facility failure, KERN_KDSETUP\n");
403 kr
.type
= KDBG_RANGETYPE
;
406 needed
= sizeof(kd_regtype
);
408 mib
[1] = KERN_KDEBUG
;
409 mib
[2] = KERN_KDSETREG
;
412 mib
[5] = 0; /* no flags */
414 if (sysctl(mib
, 3, &kr
, &needed
, NULL
, 0) < 0)
415 quit("trace facility failure, KERN_KDSETREG\n");
418 mib
[1] = KERN_KDEBUG
;
419 mib
[2] = KERN_KDSETUP
;
422 mib
[5] = 0; /* no flags */
424 if (sysctl(mib
, 3, NULL
, &needed
, NULL
, 0) < 0)
425 quit("trace facility failure, KERN_KDSETUP\n");
436 void screen_update();
439 set_pidexclude(getpid(), 0);
440 screen_update(log_fp
);
448 void leave() /* exit under normal conditions -- signal handler */
451 set_pidexclude(getpid(), 0);
460 screen_update(FILE *fp
)
467 unsigned int average_s_latency
;
468 unsigned int average_i_latency
;
471 if (fp
== (FILE *)0) {
475 fprintf(fp
,"\n\n===================================================================================================\n");
477 * Display the current time.
478 * "ctime" always returns a string that looks like this:
480 * Sun Sep 16 01:03:52 1973
481 * 012345678901234567890123
484 * We want indices 11 thru 18 (length 8).
486 elapsed_secs
= curr_time
- start_time
;
487 elapsed_hours
= elapsed_secs
/ 3600;
488 elapsed_secs
-= elapsed_hours
* 3600;
489 elapsed_mins
= elapsed_secs
/ 60;
490 elapsed_secs
-= elapsed_mins
* 60;
492 sprintf(tbuf
, "%-19.19s %2ld:%02ld:%02ld\n", &(ctime(&curr_time
)[0]),
493 (long)elapsed_hours
, (long)elapsed_mins
, (long)elapsed_secs
);
495 fprintf(fp
, "%s", tbuf
);
501 sprintf(tbuf
, " SCHEDULER INTERRUPTS\n");
504 fprintf(fp
, "%s", tbuf
);
508 sprintf(tbuf
, "---------------------------------------------\n");
511 fprintf(fp
, "%s", tbuf
);
517 sprintf(tbuf
, "total_samples %10d %10d\n\n", s_total_samples
, i_total_samples
);
520 fprintf(fp
, "%s", tbuf
);
526 for (itotal
= 0, stotal
= 0, i
= 0; i
< 10; i
++) {
527 sprintf(tbuf
, "delays < %3d usecs %10d %10d\n", (i
+ 1) * 10, s_usec_10_bins
[i
], i_usec_10_bins
[i
]);
530 fprintf(fp
, "%s", tbuf
);
534 stotal
+= s_usec_10_bins
[i
];
535 itotal
+= i_usec_10_bins
[i
];
537 sprintf(tbuf
, "total < 100 usecs %10d %10d\n\n", stotal
, itotal
);
540 fprintf(fp
, "%s", tbuf
);
546 for (itotal
= 0, stotal
= 0, i
= 1; i
< 10; i
++) {
548 sprintf(tbuf
, "delays < %3d usecs %10d %10d\n", (i
+ 1) * 100, s_usec_100_bins
[i
], i_usec_100_bins
[i
]);
550 sprintf(tbuf
, "delays < 1 msec %10d %10d\n", s_usec_100_bins
[i
], i_usec_100_bins
[i
]);
553 fprintf(fp
, "%s", tbuf
);
557 stotal
+= s_usec_100_bins
[i
];
558 itotal
+= i_usec_100_bins
[i
];
560 sprintf(tbuf
, "total < 1 msec %10d %10d\n\n", stotal
, itotal
);
563 fprintf(fp
, "%s", tbuf
);
569 for (itotal
= 0, stotal
= 0, i
= 1; i
< 10; i
++) {
570 sprintf(tbuf
, "delays < %3d msecs %10d %10d\n", (i
+ 1), s_msec_1_bins
[i
], i_msec_1_bins
[i
]);
573 fprintf(fp
, "%s", tbuf
);
577 stotal
+= s_msec_1_bins
[i
];
578 itotal
+= i_msec_1_bins
[i
];
580 sprintf(tbuf
, "total < 10 msecs %10d %10d\n\n", stotal
, itotal
);
583 fprintf(fp
, "%s", tbuf
);
590 for (itotal
= 0, stotal
= 0, i
= 1; i
< 5; i
++) {
591 sprintf(tbuf
, "delays < %3d msecs %10d %10d\n", (i
+ 1)*10, s_msec_10_bins
[i
], i_msec_10_bins
[i
]);
594 fprintf(fp
, "%s", tbuf
);
598 stotal
+= s_msec_10_bins
[i
];
599 itotal
+= i_msec_10_bins
[i
];
601 sprintf(tbuf
, "total < 50 msecs %10d %10d\n\n", stotal
, itotal
);
604 fprintf(fp
, "%s", tbuf
);
608 sprintf(tbuf
, "delays > 50 msecs %10d %10d\n", s_too_slow
, i_too_slow
);
611 fprintf(fp
, "%s", tbuf
);
617 sprintf(tbuf
, "\nminimum latency(usecs) %7d %7d\n", s_min_latency
, i_min_latency
);
620 fprintf(fp
, "%s", tbuf
);
624 sprintf(tbuf
, "maximum latency(usecs) %7d %7d\n", s_max_latency
, i_max_latency
);
627 fprintf(fp
, "%s", tbuf
);
632 average_s_latency
= (unsigned int)(s_total_latency
/s_total_samples
);
634 average_s_latency
= 0;
637 average_i_latency
= (unsigned int)(i_total_latency
/i_total_samples
);
639 average_i_latency
= 0;
641 sprintf(tbuf
, "average latency(usecs) %7d %7d\n", average_s_latency
, average_i_latency
);
644 fprintf(fp
, "%s", tbuf
);
648 sprintf(tbuf
, "exceeded threshold %7d %7d\n", s_exceeded_threshold
, i_exceeded_threshold
);
651 fprintf(fp
, "%s", tbuf
);
665 fprintf(stderr
, "Usage: latency [-rt] [-c codefile] [-l logfile] [-st threshold]\n");
667 #if defined (__i386__)
668 fprintf(stderr
, " [-it threshold] [-s sleep_in_usecs] [-n kernel]\n\n");
670 fprintf(stderr
, " [-it threshold] [-s sleep_in_usecs]\n");
671 fprintf(stderr
, " [-d decrementer_in_usecs] [-n kernel]\n\n");
675 fprintf(stderr
, " -rt Set realtime scheduling policy. Default is timeshare.\n");
676 fprintf(stderr
, " -c specify name of codes file\n");
677 fprintf(stderr
, " -l specify name of file to log trace entries to when threshold is exceeded\n");
678 fprintf(stderr
, " -st set scheduler latency threshold in microseconds... if latency exceeds this, then log trace\n");
679 fprintf(stderr
, " -it set interrupt latency threshold in microseconds... if latency exceeds this, then log trace\n");
680 fprintf(stderr
, " -s set sleep time in microseconds\n");
681 #if !defined (__i386__)
682 fprintf(stderr
, " -d set decrementer in microseconds.\n");
684 fprintf(stderr
, " -n specify kernel, default is /mach_kernel\n");
686 fprintf(stderr
, "\nlatency must be run as root\n\n");
697 uint64_t start
, stop
;
700 uint64_t adeadline
, adelay
;
703 double nanosecs_to_sleep
;
704 int loop_cnt
, sample_sc_now
;
705 int decrementer_usec
= 0;
708 host_name_port_t host
;
711 void init_code_file();
715 my_policy
= THREAD_STANDARD_POLICY
;
716 policy_name
= "TIMESHARE";
719 if (strcmp(argv
[1], "-rt") == 0) {
720 my_policy
= THREAD_TIME_CONSTRAINT_POLICY
; /* the real time band */
721 policy_name
= "REALTIME";
723 } else if (strcmp(argv
[1], "-st") == 0) {
728 s_thresh_hold
= atoi(argv
[1]);
732 } else if (strcmp(argv
[1], "-it") == 0) {
737 i_thresh_hold
= atoi(argv
[1]);
740 } else if (strcmp(argv
[1], "-c") == 0) {
748 } else if (strcmp(argv
[1], "-l") == 0) {
753 open_logfile(argv
[1]);
757 } else if (strcmp(argv
[1], "-s") == 0) {
762 num_of_usecs_to_sleep
= atoi(argv
[1]);
766 else if (strcmp(argv
[1], "-d") == 0) {
771 decrementer_usec
= atoi(argv
[1]);
774 #if defined(__i386__)
775 /* ignore this option - setting the decrementer has no effect */
776 decrementer_usec
= 0;
779 else if (strcmp(argv
[1], "-n") == 0) {
784 kernelpath
= argv
[1];
794 if ( geteuid() != 0 ) {
795 printf("'latency' must be run as root...\n");
799 if (kernelpath
== (char *) 0)
800 kernelpath
= "/mach_kernel";
802 if (code_file
== (char *) 0)
803 code_file
= "/usr/share/misc/trace.codes";
807 sample_sc_now
= 25000 / num_of_usecs_to_sleep
;
810 decrementer_val
= decrementer_usec
* divisor
;
812 /* get the cpu countfor the DECR_TRAP array */
813 host
= mach_host_self();
814 size
= sizeof(hi
)/sizeof(int);
815 ret
= host_info(host
, HOST_BASIC_INFO
, (host_info_t
)&hi
, &size
);
816 if (ret
!= KERN_SUCCESS
) {
817 mach_error(argv
[0], ret
);
821 if ((last_decrementer_kd
= (kd_buf
**)malloc(hi
.avail_cpus
* sizeof(kd_buf
*))) == (kd_buf
**)0)
822 quit("can't allocate memory for decrementer tracing info\n");
824 nanosecs_to_sleep
= (double)(num_of_usecs_to_sleep
* 1000);
825 fdelay
= nanosecs_to_sleep
* (divisor
/1000);
826 adelay
= (uint64_t)fdelay
;
831 When the decrementer isn't set in the options,
832 decval will be zero and this call will reset
833 the system default ...
835 set_rtcdec(decrementer_val
);
837 if (initscr() == (WINDOW
*) 0)
839 printf("Unrecognized TERM type, try vt100\n");
845 signal(SIGWINCH
, sigwinch
);
846 signal(SIGINT
, sigintr
);
847 signal(SIGQUIT
, leave
);
848 signal(SIGTERM
, leave
);
849 signal(SIGHUP
, leave
);
852 if ((my_buffer
= malloc(SAMPLE_SIZE
* sizeof(kd_buf
))) == (char *)0)
853 quit("can't allocate memory for tracing info\n");
855 set_numbufs(SAMPLE_SIZE
);
860 set_init_nologging();
861 set_pidexclude(getpid(), 1);
867 start_time
= time((long *)0);
868 refresh_time
= start_time
;
870 if (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
)
872 /* the realtime band */
873 if(set_time_constraint_policy() != KERN_SUCCESS
)
874 quit("Failed to set realtime policy.\n");
878 curr_time
= time((long *)0);
880 if (curr_time
>= refresh_time
) {
881 if (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
)
883 /* set standard timeshare policy during screen update */
884 if(set_standard_policy() != KERN_SUCCESS
)
885 quit("Failed to set standard policy.\n");
887 screen_update((FILE *)0);
888 if (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
)
890 /* set back to realtime band */
891 if(set_time_constraint_policy() != KERN_SUCCESS
)
892 quit("Failed to set time_constraint policy.\n");
894 refresh_time
= curr_time
+ 1;
897 timestamp1
= mach_absolute_time();
898 adeadline
= timestamp1
+ adelay
;
899 mach_wait_until(adeadline
);
900 timestamp2
= mach_absolute_time();
906 elapsed_usecs
= (int)(((double)(stop
- start
)) / divisor
);
908 if ((elapsed_usecs
-= num_of_usecs_to_sleep
) <= 0)
911 if (elapsed_usecs
< 100)
912 s_usec_10_bins
[elapsed_usecs
/10]++;
913 if (elapsed_usecs
< 1000)
914 s_usec_100_bins
[elapsed_usecs
/100]++;
915 else if (elapsed_usecs
< 10000)
916 s_msec_1_bins
[elapsed_usecs
/1000]++;
917 else if (elapsed_usecs
< 50000)
918 s_msec_10_bins
[elapsed_usecs
/10000]++;
922 if (elapsed_usecs
> s_max_latency
)
923 s_max_latency
= elapsed_usecs
;
924 if (elapsed_usecs
< s_min_latency
|| s_total_samples
== 0)
925 s_min_latency
= elapsed_usecs
;
926 s_total_latency
+= elapsed_usecs
;
929 if (s_thresh_hold
&& elapsed_usecs
> s_thresh_hold
)
930 s_exceeded_threshold
++;
933 if (log_fp
&& s_thresh_hold
&& elapsed_usecs
> s_thresh_hold
)
934 sample_sc(start
, stop
);
936 if (loop_cnt
>= sample_sc_now
) {
937 sample_sc((long long)0, (long long)0);
943 No need to check for initscr error return.
944 We won't get here if it fails on the first call.
958 mach_timebase_info_data_t info
;
960 (void) mach_timebase_info (&info
);
962 divisor
= ( (double)info
.denom
/ (double)info
.numer
) * 1000;
966 /* This is the realtime band */
968 set_time_constraint_policy()
970 kern_return_t result
;
971 thread_time_constraint_policy_data_t info
;
972 mach_msg_type_number_t count
;
973 boolean_t get_default
;
976 count
= THREAD_TIME_CONSTRAINT_POLICY_COUNT
;
977 result
= thread_policy_get(mach_thread_self(), THREAD_TIME_CONSTRAINT_POLICY
,
978 (thread_policy_t
)&info
, &count
, &get_default
);
979 if (result
!= KERN_SUCCESS
)
982 result
= thread_policy_set(mach_thread_self(), THREAD_TIME_CONSTRAINT_POLICY
,
983 (thread_policy_t
)&info
, THREAD_TIME_CONSTRAINT_POLICY_COUNT
);
988 /* This is the timeshare mode */
990 set_standard_policy()
992 kern_return_t result
;
993 thread_standard_policy_data_t info
;
994 mach_msg_type_number_t count
;
995 boolean_t get_default
;
998 count
= THREAD_STANDARD_POLICY_COUNT
;
999 result
= thread_policy_get(mach_thread_self(), THREAD_STANDARD_POLICY
,
1000 (thread_policy_t
)&info
, &count
, &get_default
);
1001 if (result
!= KERN_SUCCESS
)
1004 result
= thread_policy_set(mach_thread_self(), THREAD_STANDARD_POLICY
,
1005 (thread_policy_t
)&info
, THREAD_STANDARD_POLICY_COUNT
);
1011 void read_command_map()
1020 total_threads
= bufinfo
.nkdthreads
;
1021 size
= bufinfo
.nkdthreads
* sizeof(kd_threadmap
);
1024 if ((mapptr
= (kd_threadmap
*) malloc(size
)))
1025 bzero (mapptr
, size
);
1028 printf("Thread map is not initialized -- this is not fatal\n");
1033 /* Now read the threadmap */
1035 mib
[1] = KERN_KDEBUG
;
1036 mib
[2] = KERN_KDTHRMAP
;
1039 mib
[5] = 0; /* no flags */
1040 if (sysctl(mib
, 3, mapptr
, &size
, NULL
, 0) < 0)
1042 /* This is not fatal -- just means I cant map command strings */
1044 printf("Can't read the thread map -- this is not fatal\n");
1053 void create_map_entry(int thread
, char *command
)
1061 for (i
= 0, map
= 0; !map
&& i
< total_threads
; i
++)
1063 if (mapptr
[i
].thread
== thread
)
1064 map
= &mapptr
[i
]; /* Reuse this entry, the thread has been reassigned */
1067 if (!map
) /* look for invalid entries that I can reuse*/
1069 for (i
= 0, map
= 0; !map
&& i
< total_threads
; i
++)
1071 if (mapptr
[i
].valid
== 0 )
1072 map
= &mapptr
[i
]; /* Reuse this invalid entry */
1078 /* If reach here, then this is a new thread and
1079 * there are no invalid entries to reuse
1080 * Double the size of the thread map table.
1083 n
= total_threads
* 2;
1084 mapptr
= (kd_threadmap
*) realloc(mapptr
, n
* sizeof(kd_threadmap
));
1085 bzero(&mapptr
[total_threads
], total_threads
*sizeof(kd_threadmap
));
1086 map
= &mapptr
[total_threads
];
1090 fprintf(log_fp
, "MAP: increasing thread map to %d entries\n", total_threads
);
1095 fprintf(log_fp
, "MAP: adding thread %x with name %s\n", thread
, command
);
1098 map
->thread
= thread
;
1100 The trace entry that returns the command name will hold
1101 at most, MAXCOMLEN chars, and in that case, is not
1102 guaranteed to be null terminated.
1104 (void)strncpy (map
->command
, command
, MAXCOMLEN
);
1105 map
->command
[MAXCOMLEN
] = '\0';
1109 kd_threadmap
*find_thread_map(int thread
)
1115 return((kd_threadmap
*)0);
1117 for (i
= 0; i
< total_threads
; i
++)
1120 if (map
->valid
&& (map
->thread
== thread
))
1125 return ((kd_threadmap
*)0);
1129 kill_thread_map(int thread
)
1133 if ((map
= find_thread_map(thread
))) {
1137 fprintf(log_fp
, "MAP: deleting thread %x with name %s\n", thread
, map
->command
);
1141 map
->command
[0] = '\0';
1146 struct th_info
*find_thread(int thread
, int type1
, int type2
) {
1149 for (ti
= th_state
; ti
< &th_state
[cur_max
]; ti
++) {
1150 if (ti
->thread
== thread
) {
1153 if (type1
== ti
->type
)
1155 if (type2
== ti
->type
)
1159 return ((struct th_info
*)0);
1163 char *find_code(type
)
1167 for (i
= 0; i
< num_of_codes
; i
++) {
1168 if (codes_tab
[i
].type
== type
)
1169 return(codes_tab
[i
].name
);
1175 void sample_sc(uint64_t start
, uint64_t stop
)
1177 kd_buf
*kd
, *last_mach_sched
, *start_kd
, *end_of_sample
;
1180 int first_entry
= 1;
1181 double timestamp
= 0.0;
1182 double last_timestamp
= 0.0;
1184 double start_bias
= 0.0;
1186 void read_command_map();
1188 if (log_fp
&& (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
))
1190 /* set standard timeshare policy when logging */
1191 if(set_standard_policy() != KERN_SUCCESS
)
1192 quit("Failed to set standard policy.\n");
1195 /* Get kernel buffer information */
1196 get_bufinfo(&bufinfo
);
1202 needed
= bufinfo
.nkdbufs
* sizeof(kd_buf
);
1204 mib
[1] = KERN_KDEBUG
;
1205 mib
[2] = KERN_KDREADTR
;
1208 mib
[5] = 0; /* no flags */
1210 if (sysctl(mib
, 3, my_buffer
, &needed
, NULL
, 0) < 0)
1211 quit("trace facility failure, KERN_KDREADTR\n");
1215 if (bufinfo
.flags
& KDBG_WRAPPED
) {
1216 for (i
= 0; i
< cur_max
; i
++) {
1217 th_state
[i
].thread
= 0;
1218 th_state
[i
].type
= -1;
1219 th_state
[i
].pathptr
= (long *)NULL
;
1220 th_state
[i
].pathname
[0] = 0;
1231 latency
= (double)(stop
- start
) / divisor
;
1232 latency
-= (double)num_of_usecs_to_sleep
;
1234 fprintf(log_fp
, "\n\n%-19.19s scheduling latency = %.1fus num_of_traces = %d <<<<<<< trace buffer wrapped >>>>>>>\n\n",
1235 &(ctime(&curr_time
)[0]), latency
, count
);
1238 end_of_sample
= &((kd_buf
*)my_buffer
)[count
];
1240 /* Always reinitialize the DECR_TRAP array */
1241 for (i
=0; i
< hi
.avail_cpus
; i
++)
1242 last_decrementer_kd
[i
] = (kd_buf
*)my_buffer
;
1244 last_mach_sched
= (kd_buf
*)0;
1246 for (kd
= (kd_buf
*)my_buffer
; kd
< end_of_sample
; kd
++) {
1247 int debugid
, thread
, cpunum
;
1248 int type
, clen
, mode
;
1253 double i_latency
= 0.0;
1256 char sched_info
[64];
1258 kd_threadmap
*find_thread_map();
1259 double handle_decrementer();
1260 kd_buf
*log_decrementer();
1261 int check_for_thread_update();
1262 void enter_syscall();
1263 void exit_syscall();
1267 cpunum
= CPU_NUMBER(kd
->timestamp
);
1268 debugid
= kd
->debugid
;
1269 type
= kd
->debugid
& DBG_FUNC_MASK
;
1271 if (check_for_thread_update(thread
, type
, kd
))
1274 if (type
== DECR_TRAP
)
1275 i_latency
= handle_decrementer(kd
);
1277 now
= kd
->timestamp
& KDBG_TIMESTAMP_MASK
;
1279 timestamp
= ((double)now
) / divisor
;
1281 if (now
< start
|| now
> stop
) {
1282 if (debugid
& DBG_FUNC_START
)
1283 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 0);
1284 else if (debugid
& DBG_FUNC_END
)
1285 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 0);
1286 else if (type
== DECR_TRAP
) {
1288 if (log_fp
&& i_thresh_hold
&& (int)i_latency
> i_thresh_hold
) {
1289 start_kd
= last_decrementer_kd
[cpunum
];
1290 kd
= log_decrementer(start_kd
, kd
, end_of_sample
, i_latency
);
1291 if (kd
>= end_of_sample
)
1294 if ((kd
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1296 cpunum
= CPU_NUMBER(kd
->timestamp
);
1297 last_decrementer_kd
[cpunum
] = kd
;
1300 last_decrementer_kd
[cpunum
] = cur_kd
;
1309 latency
= (double)(stop
- start
) / divisor
;
1310 latency
-= (double)num_of_usecs_to_sleep
;
1313 sprintf(buf2
, "default");
1315 sprintf(buf2
, "%d", my_pri
);
1316 sprintf(buf1
, "%-19.19s scheduling latency = %.1fus sleep_request = %dus policy = %s priority = %s",
1317 &(ctime(&curr_time
)[0]), latency
, num_of_usecs_to_sleep
, policy_name
, buf2
);
1318 clen
= strlen(buf1
);
1319 memset(buf2
, '-', clen
);
1323 fprintf(log_fp
, "\n\n%s\n", buf2
);
1324 fprintf(log_fp
, "%s\n\n", buf1
);
1325 fprintf(log_fp
, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
1327 start_bias
= ((double)start
) / divisor
;
1328 last_timestamp
= timestamp
;
1331 delta
= timestamp
- last_timestamp
;
1333 if ((map
= find_thread_map(thread
)))
1334 strcpy(command
, map
->command
);
1342 fprintf(log_fp
, "%9.1f %8.1f\t\tCQ_action @ %-59.59s %-8x %d %s\n",
1343 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 59, 1) , thread
, cpunum
, command
);
1345 last_timestamp
= timestamp
;
1350 fprintf(log_fp
, "%9.1f %8.1f\t\tTES_action @ %-58.58s %-8x %d %s\n",
1351 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 58, 1) , thread
, cpunum
, command
);
1354 last_timestamp
= timestamp
;
1359 fprintf(log_fp
, "%9.1f %8.1f\t\tIES_action @ %-58.58s %-8x %d %s\n",
1360 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 58, 1) , thread
, cpunum
, command
);
1363 last_timestamp
= timestamp
;
1368 fprintf(log_fp
, "%9.1f %8.1f\t\tIES_filter @ %-58.58s %-8x %d %s\n",
1369 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 58, 1) , thread
, cpunum
, command
);
1372 last_timestamp
= timestamp
;
1376 last_decrementer_kd
[cpunum
] = kd
;
1378 if (i_thresh_hold
&& (int)i_latency
> i_thresh_hold
)
1385 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1386 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1391 fprintf(log_fp
, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-59.59s %-8x %d %s\n",
1392 timestamp
- start_bias
, delta
, i_latency
, p
, pc_to_string(kd
->arg2
, 59, mode
) , thread
, cpunum
, command
);
1395 last_timestamp
= timestamp
;
1400 fprintf(log_fp
, "%9.1f %8.1f[%.1f] \t%-28.28s %-8x %d %s\n",
1401 timestamp
- start_bias
, delta
, (double)kd
->arg1
/divisor
, "DECR_SET", thread
, cpunum
, command
);
1404 last_timestamp
= timestamp
;
1408 case MACH_stkhandoff
:
1409 last_mach_sched
= kd
;
1411 if ((map
= find_thread_map(kd
->arg2
)))
1412 strcpy(command1
, map
->command
);
1414 sprintf(command1
, "%-8x", kd
->arg2
);
1416 if ((ti
= find_thread(kd
->arg2
, 0, 0))) {
1417 if (ti
->type
== -1 && strcmp(command1
, "kernel_task"))
1423 memset(sched_info
, ' ', sizeof(sched_info
));
1425 sprintf(sched_info
, "%14.14s", command
);
1426 clen
= strlen(sched_info
);
1427 sched_info
[clen
] = ' ';
1429 sprintf(&sched_info
[14], " @ pri %3d --> %14.14s", kd
->arg3
, command1
);
1430 clen
= strlen(sched_info
);
1431 sched_info
[clen
] = ' ';
1433 sprintf(&sched_info
[45], " @ pri %3d%s", kd
->arg4
, p
);
1436 fprintf(log_fp
, "%9.1f %8.1f\t\t%-10.10s %s %-8x %d\n",
1437 timestamp
- start_bias
, delta
, "MACH_SCHED", sched_info
, thread
, cpunum
);
1440 last_timestamp
= timestamp
;
1444 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1445 if (cur_max
>= MAX_THREADS
)
1447 ti
= &th_state
[cur_max
++];
1449 ti
->thread
= thread
;
1451 ti
->pathptr
= (long *)0;
1452 ti
->child_thread
= 0;
1454 while ( (kd
< end_of_sample
) && ((kd
->debugid
& DBG_FUNC_MASK
) == VFS_LOOKUP
))
1456 if (ti
->pathptr
== NULL
) {
1457 ti
->arg1
= kd
->arg1
;
1458 sargptr
= ti
->pathname
;
1460 *sargptr
++ = kd
->arg2
;
1461 *sargptr
++ = kd
->arg3
;
1462 *sargptr
++ = kd
->arg4
;
1464 * NULL terminate the 'string'
1467 ti
->pathptr
= sargptr
;
1470 sargptr
= ti
->pathptr
;
1473 We don't want to overrun our pathname buffer if the
1474 kernel sends us more VFS_LOOKUP entries than we can
1478 if (sargptr
>= &ti
->pathname
[NUMPARMS
])
1485 We need to detect consecutive vfslookup entries.
1486 So, if we get here and find a START entry,
1487 fake the pathptr so we can bypass all further
1491 if (kd
->debugid
& DBG_FUNC_START
)
1493 ti
->pathptr
= &ti
->pathname
[NUMPARMS
];
1497 *sargptr
++ = kd
->arg1
;
1498 *sargptr
++ = kd
->arg2
;
1499 *sargptr
++ = kd
->arg3
;
1500 *sargptr
++ = kd
->arg4
;
1502 * NULL terminate the 'string'
1506 ti
->pathptr
= sargptr
;
1511 p
= (char *)ti
->pathname
;
1515 /* print the tail end of the pathname */
1523 fprintf(log_fp
, "%9.1f %8.1f\t\t%-14.14s %-42s %-8x %-8x %d %s\n",
1524 timestamp
- start_bias
, delta
, "VFS_LOOKUP",
1525 &p
[len
], ti
->arg1
, thread
, cpunum
, command
);
1528 last_timestamp
= timestamp
;
1532 if (debugid
& DBG_FUNC_START
)
1533 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
1534 else if (debugid
& DBG_FUNC_END
)
1535 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
1537 print_entry(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
);
1539 last_timestamp
= timestamp
;
1543 if (last_mach_sched
&& log_fp
)
1544 fprintf(log_fp
, "\nblocked by %s @ priority %d\n", command
, last_mach_sched
->arg3
);
1546 if (first_entry
== 0 && log_fp
)
1547 fprintf(log_fp
, "\n start = %qd stop = %qd count = %d now = %qd\n", start
, stop
, count
, now
);
1552 if (log_fp
&& (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
))
1554 /* set back to realtime band */
1555 if(set_time_constraint_policy() != KERN_SUCCESS
)
1556 quit("Failed to set time_constraint policy.\n");
1561 enter_syscall(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
, int print_info
)
1568 cpunum
= CPU_NUMBER(kd
->timestamp
);
1570 if (print_info
&& fp
) {
1571 if ((p
= find_code(type
))) {
1572 if (type
== INTERRUPT
) {
1575 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1576 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1580 fprintf(fp
, "%9.1f %8.1f\t\tINTERRUPT @ %-59.59s %-8x %d %s\n",
1581 timestamp
- bias
, delta
, pc_to_string(kd
->arg2
, 59, mode
), thread
, cpunum
, command
);
1582 } else if (type
== MACH_vmfault
) {
1583 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %d %s\n",
1584 timestamp
- bias
, delta
, p
, thread
, cpunum
, command
);
1586 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %-8x %-8x %-8x %-8x %d %s\n",
1587 timestamp
- bias
, delta
, p
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1588 thread
, cpunum
, command
);
1591 fprintf(fp
, "%9.1f %8.1f\t\t%-8x %-8x %-8x %-8x %-8x %-8x %d %s\n",
1592 timestamp
- bias
, delta
, type
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1593 thread
, cpunum
, command
);
1596 if ((ti
= find_thread(thread
, -1, type
)) == (struct th_info
*)0) {
1597 if (cur_max
>= MAX_THREADS
) {
1598 static int do_this_once
= 1;
1601 for (i
= 0; i
< cur_max
; i
++) {
1604 fprintf(fp
, "thread = %x, type = %x\n",
1605 th_state
[i
].thread
, th_state
[i
].type
);
1612 ti
= &th_state
[cur_max
++];
1614 ti
->thread
= thread
;
1615 ti
->child_thread
= 0;
1617 if (type
!= BSC_exit
)
1621 ti
->stime
= timestamp
;
1622 ti
->pathptr
= (long *)NULL
;
1625 if (print_info
&& fp
)
1626 fprintf(fp
, "cur_max = %d, ti = %x, type = %x, thread = %x\n", cur_max
, ti
, ti
->type
, ti
->thread
);
1632 exit_syscall(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
, int print_info
)
1639 cpunum
= CPU_NUMBER(kd
->timestamp
);
1641 ti
= find_thread(thread
, type
, type
);
1643 if (print_info
&& fp
)
1644 fprintf(fp
, "cur_max = %d, ti = %x, type = %x, thread = %x\n", cur_max
, ti
, type
, thread
);
1646 if (print_info
&& fp
) {
1648 fprintf(fp
, "%9.1f %8.1f(%.1f) \t", timestamp
- bias
, delta
, timestamp
- ti
->stime
);
1650 fprintf(fp
, "%9.1f %8.1f() \t", timestamp
- bias
, delta
);
1652 if ((p
= find_code(type
))) {
1653 if (type
== INTERRUPT
) {
1654 fprintf(fp
, "INTERRUPT %-8x %d %s\n", thread
, cpunum
, command
);
1655 } else if (type
== MACH_vmfault
&& kd
->arg4
<= DBG_CACHE_HIT_FAULT
) {
1656 user_addr
= ((uint64_t)kd
->arg1
<< 32) | (uint32_t)kd
->arg2
;
1658 fprintf(fp
, "%-28.28s %-8.8s %-16qx %-8x %d %s\n",
1659 p
, fault_name
[kd
->arg4
], user_addr
,
1660 thread
, cpunum
, command
);
1662 fprintf(fp
, "%-28.28s %-8x %-8x %-8x %d %s\n",
1663 p
, kd
->arg1
, kd
->arg2
,
1664 thread
, cpunum
, command
);
1667 fprintf(fp
, "%-8x %-8x %-8x %-8x %d %s\n",
1668 type
, kd
->arg1
, kd
->arg2
,
1669 thread
, cpunum
, command
);
1672 if (ti
== (struct th_info
*)0) {
1673 if ((ti
= find_thread(thread
, -1, -1)) == (struct th_info
*)0) {
1674 if (cur_max
>= MAX_THREADS
)
1676 ti
= &th_state
[cur_max
++];
1678 ti
->thread
= thread
;
1679 ti
->child_thread
= 0;
1680 ti
->pathptr
= (long *)NULL
;
1687 print_entry(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
)
1695 cpunum
= CPU_NUMBER(kd
->timestamp
);
1697 fprintf(fp
, "cur_max = %d, type = %x, thread = %x, cpunum = %d\n", cur_max
, type
, thread
, cpunum
);
1699 if ((p
= find_code(type
))) {
1700 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %-8x %-8x %-8x %-8x %d %s\n",
1701 timestamp
- bias
, delta
, p
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1702 thread
, cpunum
, command
);
1704 fprintf(fp
, "%9.1f %8.1f\t\t%-8x %-8x %-8x %-8x %-8x %-8x %d %s\n",
1705 timestamp
- bias
, delta
, type
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1706 thread
, cpunum
, command
);
1711 check_for_thread_update(int thread
, int type
, kd_buf
*kd
)
1714 void create_map_entry();
1718 case TRACE_DATA_NEWTHREAD
:
1719 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1720 if (cur_max
>= MAX_THREADS
)
1722 ti
= &th_state
[cur_max
++];
1724 ti
->thread
= thread
;
1726 ti
->pathptr
= (long *)NULL
;
1728 ti
->child_thread
= kd
->arg1
;
1731 case TRACE_STRING_NEWTHREAD
:
1732 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0)
1734 if (ti
->child_thread
== 0)
1736 create_map_entry(ti
->child_thread
, (char *)&kd
->arg1
);
1738 ti
->child_thread
= 0;
1741 case TRACE_STRING_EXEC
:
1742 create_map_entry(thread
, (char *)&kd
->arg1
);
1750 kd_buf
*log_decrementer(kd_buf
*kd_beg
, kd_buf
*kd_end
, kd_buf
*end_of_sample
, double i_latency
)
1752 kd_buf
*kd
, *kd_start
, *kd_stop
;
1753 int kd_count
; /* Limit the boundary of kd_start */
1754 double timestamp
= 0.0;
1755 double last_timestamp
= 0.0;
1757 double start_bias
= 0.0;
1759 int debugid
, type
, clen
;
1767 char sched_info
[64];
1771 kd_threadmap
*find_thread_map();
1773 sprintf(buf1
, "%-19.19s interrupt latency = %.1fus", &(ctime(&curr_time
)[0]), i_latency
);
1774 clen
= strlen(buf1
);
1775 memset(buf2
, '-', clen
);
1777 fprintf(log_fp
, "\n\n%s\n", buf2
);
1778 fprintf(log_fp
, "%s\n\n", buf1
);
1780 fprintf(log_fp
, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
1782 thread
= kd_beg
->arg5
;
1783 cpunum
= CPU_NUMBER(kd_end
->timestamp
);
1785 for (kd_count
= 0, kd_start
= kd_beg
- 1; (kd_start
>= (kd_buf
*)my_buffer
); kd_start
--, kd_count
++) {
1786 if (kd_count
== MAX_LOG_COUNT
)
1789 if (CPU_NUMBER(kd_start
->timestamp
) != cpunum
)
1792 if ((kd_start
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1795 if (kd_start
->arg5
!= thread
)
1799 if (kd_start
< (kd_buf
*)my_buffer
)
1800 kd_start
= (kd_buf
*)my_buffer
;
1802 thread
= kd_end
->arg5
;
1804 for (kd_stop
= kd_end
+ 1; kd_stop
< end_of_sample
; kd_stop
++) {
1806 if ((kd_stop
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1809 if (CPU_NUMBER(kd_stop
->timestamp
) != cpunum
)
1812 if (kd_stop
->arg5
!= thread
)
1816 if (kd_stop
>= end_of_sample
)
1817 kd_stop
= end_of_sample
- 1;
1819 now
= kd_start
->timestamp
& KDBG_TIMESTAMP_MASK
;
1820 timestamp
= ((double)now
) / divisor
;
1822 for (kd
= kd_start
; kd
<= kd_stop
; kd
++) {
1823 type
= kd
->debugid
& DBG_FUNC_MASK
;
1825 if ((ti
= find_thread(kd
->arg5
, type
, type
))) {
1826 if (ti
->stime
>= timestamp
)
1830 for (kd
= kd_start
; kd
<= kd_stop
; kd
++) {
1834 cpunum
= CPU_NUMBER(kd
->timestamp
);
1835 debugid
= kd
->debugid
;
1836 type
= kd
->debugid
& DBG_FUNC_MASK
;
1838 now
= kd
->timestamp
& KDBG_TIMESTAMP_MASK
;
1840 timestamp
= ((double)now
) / divisor
;
1842 if (kd
== kd_start
) {
1843 start_bias
= timestamp
;
1844 last_timestamp
= timestamp
;
1846 delta
= timestamp
- last_timestamp
;
1848 if ((map
= find_thread_map(thread
)))
1849 strcpy(command
, map
->command
);
1857 fprintf(log_fp
, "%9.1f %8.1f\t\tCQ_action @ %-59.59s %-8x %d %s\n",
1858 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 59, 1) , thread
, cpunum
, command
);
1860 last_timestamp
= timestamp
;
1864 if ((int)(kd
->arg1
) >= 0)
1867 i_latency
= (((double)(-1 - kd
->arg1
)) / divisor
);
1869 if (i_thresh_hold
&& (int)i_latency
> i_thresh_hold
)
1876 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1877 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1880 fprintf(log_fp
, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-59.59s %-8x %d %s\n",
1881 timestamp
- start_bias
, delta
, i_latency
, p
, pc_to_string(kd
->arg2
, 59, mode
) , thread
, cpunum
, command
);
1883 last_timestamp
= timestamp
;
1887 fprintf(log_fp
, "%9.1f %8.1f[%.1f] \t%-28.28s %-8x %d %s\n",
1888 timestamp
- start_bias
, delta
, (double)kd
->arg1
/divisor
,
1889 "DECR_SET", thread
, cpunum
, command
);
1891 last_timestamp
= timestamp
;
1895 case MACH_stkhandoff
:
1896 if ((map
= find_thread_map(kd
->arg2
)))
1897 strcpy(command1
, map
->command
);
1899 sprintf(command1
, "%-8x", kd
->arg2
);
1901 if ((ti
= find_thread(kd
->arg2
, 0, 0))) {
1902 if (ti
->type
== -1 && strcmp(command1
, "kernel_task"))
1908 memset(sched_info
, ' ', sizeof(sched_info
));
1910 sprintf(sched_info
, "%14.14s", command
);
1911 clen
= strlen(sched_info
);
1912 sched_info
[clen
] = ' ';
1914 sprintf(&sched_info
[14], " @ pri %3d --> %14.14s", kd
->arg3
, command1
);
1915 clen
= strlen(sched_info
);
1916 sched_info
[clen
] = ' ';
1918 sprintf(&sched_info
[45], " @ pri %3d%s", kd
->arg4
, p
);
1920 fprintf(log_fp
, "%9.1f %8.1f\t\t%-10.10s %s %-8x %d\n",
1921 timestamp
- start_bias
, delta
, "MACH_SCHED", sched_info
, thread
, cpunum
);
1923 last_timestamp
= timestamp
;
1927 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1928 if (cur_max
>= MAX_THREADS
)
1930 ti
= &th_state
[cur_max
++];
1932 ti
->thread
= thread
;
1934 ti
->pathptr
= (long *)NULL
;
1935 ti
->child_thread
= 0;
1938 while ( (kd
<= kd_stop
) && (kd
->debugid
& DBG_FUNC_MASK
) == VFS_LOOKUP
)
1940 if (ti
->pathptr
== NULL
) {
1941 ti
->arg1
= kd
->arg1
;
1942 sargptr
= ti
->pathname
;
1944 *sargptr
++ = kd
->arg2
;
1945 *sargptr
++ = kd
->arg3
;
1946 *sargptr
++ = kd
->arg4
;
1948 * NULL terminate the 'string'
1952 ti
->pathptr
= sargptr
;
1955 sargptr
= ti
->pathptr
;
1958 We don't want to overrun our pathname buffer if the
1959 kernel sends us more VFS_LOOKUP entries than we can
1963 if (sargptr
>= &ti
->pathname
[NUMPARMS
])
1970 We need to detect consecutive vfslookup entries.
1971 So, if we get here and find a START entry,
1972 fake the pathptr so we can bypass all further
1976 if (kd
->debugid
& DBG_FUNC_START
)
1978 ti
->pathptr
= &ti
->pathname
[NUMPARMS
];
1982 *sargptr
++ = kd
->arg1
;
1983 *sargptr
++ = kd
->arg2
;
1984 *sargptr
++ = kd
->arg3
;
1985 *sargptr
++ = kd
->arg4
;
1987 * NULL terminate the 'string'
1991 ti
->pathptr
= sargptr
;
1996 p
= (char *)ti
->pathname
;
1999 /* print the tail end of the pathname */
2006 fprintf(log_fp
, "%9.1f %8.1f\t\t%-14.14s %-42s %-8x %-8x %d %s\n",
2007 timestamp
- start_bias
, delta
, "VFS_LOOKUP",
2008 &p
[len
], ti
->arg1
, thread
, cpunum
, command
);
2010 last_timestamp
= timestamp
;
2014 if (debugid
& DBG_FUNC_START
)
2015 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
2016 else if (debugid
& DBG_FUNC_END
)
2017 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
2019 print_entry(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
);
2021 last_timestamp
= timestamp
;
2029 double handle_decrementer(kd_buf
*kd
)
2034 if ((int)(kd
->arg1
) >= 0)
2037 latency
= (((double)(-1 - kd
->arg1
)) / divisor
);
2038 elapsed_usecs
= (int)latency
;
2040 if (elapsed_usecs
< 100)
2041 i_usec_10_bins
[elapsed_usecs
/10]++;
2042 if (elapsed_usecs
< 1000)
2043 i_usec_100_bins
[elapsed_usecs
/100]++;
2044 else if (elapsed_usecs
< 10000)
2045 i_msec_1_bins
[elapsed_usecs
/1000]++;
2046 else if (elapsed_usecs
< 50000)
2047 i_msec_10_bins
[elapsed_usecs
/10000]++;
2051 if (i_thresh_hold
&& elapsed_usecs
> i_thresh_hold
)
2052 i_exceeded_threshold
++;
2053 if (elapsed_usecs
> i_max_latency
)
2054 i_max_latency
= elapsed_usecs
;
2055 if (elapsed_usecs
< i_min_latency
|| i_total_samples
== 0)
2056 i_min_latency
= elapsed_usecs
;
2057 i_total_latency
+= elapsed_usecs
;
2064 void init_code_file()
2067 int i
, n
, cnt
, code
;
2070 if ((fp
= fopen(code_file
, "r")) == (FILE *)0) {
2072 fprintf(log_fp
, "open of %s failed\n", code_file
);
2075 n
= fscanf(fp
, "%d\n", &cnt
);
2079 fprintf(log_fp
, "bad format found in %s\n", code_file
);
2082 for (i
= 0; i
< MAX_ENTRIES
; i
++) {
2083 n
= fscanf(fp
, "%x%127s\n", &code
, name
);
2088 strncpy(codes_tab
[i
].name
, name
, 32);
2089 codes_tab
[i
].type
= code
;
2101 FILE *fp
= (FILE *)0;
2102 char tmp_nm_file
[128];
2106 bzero(tmp_nm_file
, 128);
2107 bzero(tmpstr
, 1024);
2109 /* Build the temporary nm file path */
2110 strcpy(tmp_nm_file
,"/tmp/knm.out.XXXXXX");
2111 if (!mktemp(tmp_nm_file
)) {
2112 fprintf(stderr
, "Error in mktemp call\n");
2116 /* Build the nm command and create a tmp file with the output*/
2117 sprintf (tmpstr
, "/usr/bin/nm -f -n -s __TEXT __text %s > %s",
2118 kernelpath
, tmp_nm_file
);
2121 /* Parse the output from the nm command */
2122 if ((fp
=fopen(tmp_nm_file
, "r")) == (FILE *)0)
2124 /* Hmmm, let's not treat this as fatal */
2125 fprintf(stderr
, "Failed to open nm symbol file [%s]\n", tmp_nm_file
);
2129 /* Count the number of symbols in the nm symbol table */
2131 while ( (inchr
= getc(fp
)) != -1)
2139 /* Malloc the space for symbol table */
2140 if (kern_sym_count
> 0)
2142 kern_sym_tbl
= (kern_sym_t
*)malloc(kern_sym_count
* sizeof (kern_sym_t
));
2145 /* Hmmm, lets not treat this as fatal */
2146 fprintf(stderr
, "Can't allocate memory for kernel symbol table\n");
2149 bzero(kern_sym_tbl
, (kern_sym_count
* sizeof(kern_sym_t
)));
2153 /* Hmmm, lets not treat this as fatal */
2154 fprintf(stderr
, "No kernel symbol table \n");
2157 for (i
=0; i
<kern_sym_count
; i
++)
2159 bzero(tmpstr
, 1024);
2160 if (fscanf(fp
, "%lx %c %s", &kern_sym_tbl
[i
].k_sym_addr
, &inchr
, tmpstr
) != 3)
2164 len
= strlen(tmpstr
);
2165 kern_sym_tbl
[i
].k_sym_name
= malloc(len
+ 1);
2167 if (kern_sym_tbl
[i
].k_sym_name
== (char *)0)
2169 fprintf(stderr
, "Can't allocate memory for symbol name [%s]\n", tmpstr
);
2170 kern_sym_tbl
[i
].k_sym_name
= (char *)0;
2174 strcpy(kern_sym_tbl
[i
].k_sym_name
, tmpstr
);
2176 kern_sym_tbl
[i
].k_sym_len
= len
;
2180 if (i
!= kern_sym_count
)
2182 /* Hmmm, didn't build up entire table from nm */
2183 /* scrap the entire thing */
2185 free (kern_sym_tbl
);
2186 kern_sym_tbl
= (kern_sym_t
*)0;
2192 /* Remove the temporary nm file */
2193 unlink(tmp_nm_file
);
2196 /* Dump the kernel symbol table */
2197 for (i
=0; i
< kern_sym_count
; i
++)
2199 if (kern_sym_tbl
[i
].k_sym_name
)
2200 printf ("[%d] 0x%x %s\n", i
,
2201 kern_sym_tbl
[i
].k_sym_addr
, kern_sym_tbl
[i
].k_sym_name
);
2203 printf ("[%d] 0x%x %s\n", i
,
2204 kern_sym_tbl
[i
].k_sym_addr
, "No symbol name");
2210 pc_to_string(unsigned int pc
, int max_len
, int mode
)
2215 int binary_search();
2219 sprintf(pcstring
, "0x%-8x [usermode addr]", pc
);
2224 ret
= binary_search(kern_sym_tbl
, 0, kern_sym_count
-1, pc
);
2228 sprintf(pcstring
, "0x%x", pc
);
2231 else if (kern_sym_tbl
[ret
].k_sym_name
== (char *)0)
2233 sprintf(pcstring
, "0x%x", pc
);
2238 if ((len
= kern_sym_tbl
[ret
].k_sym_len
) > (max_len
- 8))
2241 memcpy(pcstring
, kern_sym_tbl
[ret
].k_sym_name
, len
);
2242 sprintf(&pcstring
[len
], "+0x%-5lx", pc
- kern_sym_tbl
[ret
].k_sym_addr
);
2249 /* Return -1 if not found, else return index */
2250 int binary_search(list
, low
, high
, addr
)
2257 mid
= (low
+ high
) / 2;
2260 return (-1); /* failed */
2261 else if (low
+ 1 == high
)
2263 if (list
[low
].k_sym_addr
<= addr
&&
2264 addr
< list
[high
].k_sym_addr
)
2266 /* We have a range match */
2269 else if (list
[high
].k_sym_addr
<= addr
)
2274 return(-1); /* Failed */
2276 else if (addr
< list
[mid
].k_sym_addr
)
2278 return(binary_search (list
, low
, mid
, addr
));
2282 return(binary_search (list
, mid
, high
, addr
));
2287 open_logfile(char *path
)
2289 log_fp
= fopen(path
, "a");
2293 /* failed to open path */
2294 fprintf(stderr
, "latency: failed to open logfile [%s]\n", path
);