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. -DKERNEL_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
];
150 /* If NUMPARMS changes from the kernel, then PATHLENGTH will also reflect the change */
152 #define PATHLENGTH (NUMPARMS*sizeof(long))
161 char pathname
[PATHLENGTH
+ 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 0x01300000
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 *)0;
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
))
1457 ti
->arg1
= kd
->arg1
;
1458 memset(&ti
->pathname
[0], 0, (PATHLENGTH
+ 1));
1459 sargptr
= (long *)&ti
->pathname
[0];
1461 *sargptr
++ = kd
->arg2
;
1462 *sargptr
++ = kd
->arg3
;
1463 *sargptr
++ = kd
->arg4
;
1464 ti
->pathptr
= sargptr
;
1467 sargptr
= ti
->pathptr
;
1470 We don't want to overrun our pathname buffer if the
1471 kernel sends us more VFS_LOOKUP entries than we can
1475 if ((long *)sargptr
>= (long *)&ti
->pathname
[PATHLENGTH
])
1482 We need to detect consecutive vfslookup entries.
1483 So, if we get here and find a START entry,
1484 fake the pathptr so we can bypass all further
1488 if (kd
->debugid
& DBG_FUNC_START
)
1490 (long *)ti
->pathptr
= (long *)&ti
->pathname
[PATHLENGTH
];
1494 *sargptr
++ = kd
->arg1
;
1495 *sargptr
++ = kd
->arg2
;
1496 *sargptr
++ = kd
->arg3
;
1497 *sargptr
++ = kd
->arg4
;
1498 ti
->pathptr
= sargptr
;
1506 /* print the tail end of the pathname */
1507 len
= strlen(ti
->pathname
);
1514 fprintf(log_fp
, "%9.1f %8.1f\t\t%-14.14s %-42s %-8x %-8x %d %s\n",
1515 timestamp
- start_bias
, delta
, "VFS_LOOKUP",
1516 &ti
->pathname
[len
], ti
->arg1
, thread
, cpunum
, command
);
1519 last_timestamp
= timestamp
;
1523 if (debugid
& DBG_FUNC_START
)
1524 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
1525 else if (debugid
& DBG_FUNC_END
)
1526 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
1528 print_entry(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
);
1530 last_timestamp
= timestamp
;
1534 if (last_mach_sched
&& log_fp
)
1535 fprintf(log_fp
, "\nblocked by %s @ priority %d\n", command
, last_mach_sched
->arg3
);
1537 if (first_entry
== 0 && log_fp
)
1538 fprintf(log_fp
, "\n start = %qd stop = %qd count = %d now = %qd\n", start
, stop
, count
, now
);
1543 if (log_fp
&& (my_policy
== THREAD_TIME_CONSTRAINT_POLICY
))
1545 /* set back to realtime band */
1546 if(set_time_constraint_policy() != KERN_SUCCESS
)
1547 quit("Failed to set time_constraint policy.\n");
1552 enter_syscall(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
, int print_info
)
1559 cpunum
= CPU_NUMBER(kd
->timestamp
);
1561 if (print_info
&& fp
) {
1562 if ((p
= find_code(type
))) {
1563 if (type
== INTERRUPT
) {
1566 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1567 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1571 fprintf(fp
, "%9.1f %8.1f\t\tINTERRUPT @ %-59.59s %-8x %d %s\n",
1572 timestamp
- bias
, delta
, pc_to_string(kd
->arg2
, 59, mode
), thread
, cpunum
, command
);
1573 } else if (type
== MACH_vmfault
) {
1574 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %d %s\n",
1575 timestamp
- bias
, delta
, p
, thread
, cpunum
, command
);
1577 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %-8x %-8x %-8x %-8x %d %s\n",
1578 timestamp
- bias
, delta
, p
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1579 thread
, cpunum
, command
);
1582 fprintf(fp
, "%9.1f %8.1f\t\t%-8x %-8x %-8x %-8x %-8x %-8x %d %s\n",
1583 timestamp
- bias
, delta
, type
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1584 thread
, cpunum
, command
);
1587 if ((ti
= find_thread(thread
, -1, type
)) == (struct th_info
*)0) {
1588 if (cur_max
>= MAX_THREADS
) {
1589 static int do_this_once
= 1;
1592 for (i
= 0; i
< cur_max
; i
++) {
1595 fprintf(fp
, "thread = %x, type = %x\n",
1596 th_state
[i
].thread
, th_state
[i
].type
);
1603 ti
= &th_state
[cur_max
++];
1605 ti
->thread
= thread
;
1606 ti
->child_thread
= 0;
1608 if (type
!= BSC_exit
)
1612 ti
->stime
= timestamp
;
1613 ti
->pathptr
= (long *)0;
1616 if (print_info
&& fp
)
1617 fprintf(fp
, "cur_max = %d, ti = %x, type = %x, thread = %x\n", cur_max
, ti
, ti
->type
, ti
->thread
);
1623 exit_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 ti
= find_thread(thread
, type
, type
);
1633 if (print_info
&& fp
)
1634 fprintf(fp
, "cur_max = %d, ti = %x, type = %x, thread = %x\n", cur_max
, ti
, type
, thread
);
1636 if (print_info
&& fp
) {
1638 fprintf(fp
, "%9.1f %8.1f(%.1f) \t", timestamp
- bias
, delta
, timestamp
- ti
->stime
);
1640 fprintf(fp
, "%9.1f %8.1f() \t", timestamp
- bias
, delta
);
1642 if ((p
= find_code(type
))) {
1643 if (type
== INTERRUPT
) {
1644 fprintf(fp
, "INTERRUPT %-8x %d %s\n", thread
, cpunum
, command
);
1645 } else if (type
== MACH_vmfault
&& kd
->arg2
<= DBG_CACHE_HIT_FAULT
) {
1646 fprintf(fp
, "%-28.28s %-8.8s %-8x %-8x %d %s\n",
1647 p
, fault_name
[kd
->arg2
], kd
->arg1
,
1648 thread
, cpunum
, command
);
1650 fprintf(fp
, "%-28.28s %-8x %-8x %-8x %d %s\n",
1651 p
, kd
->arg1
, kd
->arg2
,
1652 thread
, cpunum
, command
);
1655 fprintf(fp
, "%-8x %-8x %-8x %-8x %d %s\n",
1656 type
, kd
->arg1
, kd
->arg2
,
1657 thread
, cpunum
, command
);
1660 if (ti
== (struct th_info
*)0) {
1661 if ((ti
= find_thread(thread
, -1, -1)) == (struct th_info
*)0) {
1662 if (cur_max
>= MAX_THREADS
)
1664 ti
= &th_state
[cur_max
++];
1666 ti
->thread
= thread
;
1667 ti
->child_thread
= 0;
1668 ti
->pathptr
= (long *)0;
1675 print_entry(FILE *fp
, kd_buf
*kd
, int thread
, int type
, char *command
, double timestamp
, double delta
, double bias
)
1683 cpunum
= CPU_NUMBER(kd
->timestamp
);
1685 fprintf(fp
, "cur_max = %d, type = %x, thread = %x, cpunum = %d\n", cur_max
, type
, thread
, cpunum
);
1687 if ((p
= find_code(type
))) {
1688 fprintf(fp
, "%9.1f %8.1f\t\t%-28.28s %-8x %-8x %-8x %-8x %-8x %d %s\n",
1689 timestamp
- bias
, delta
, p
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1690 thread
, cpunum
, command
);
1692 fprintf(fp
, "%9.1f %8.1f\t\t%-8x %-8x %-8x %-8x %-8x %-8x %d %s\n",
1693 timestamp
- bias
, delta
, type
, kd
->arg1
, kd
->arg2
, kd
->arg3
, kd
->arg4
,
1694 thread
, cpunum
, command
);
1699 check_for_thread_update(int thread
, int type
, kd_buf
*kd
)
1702 void create_map_entry();
1706 case TRACE_DATA_NEWTHREAD
:
1707 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1708 if (cur_max
>= MAX_THREADS
)
1710 ti
= &th_state
[cur_max
++];
1712 ti
->thread
= thread
;
1714 ti
->pathptr
= (long *)0;
1716 ti
->child_thread
= kd
->arg1
;
1719 case TRACE_STRING_NEWTHREAD
:
1720 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0)
1722 if (ti
->child_thread
== 0)
1724 create_map_entry(ti
->child_thread
, (char *)&kd
->arg1
);
1726 ti
->child_thread
= 0;
1729 case TRACE_STRING_EXEC
:
1730 create_map_entry(thread
, (char *)&kd
->arg1
);
1738 kd_buf
*log_decrementer(kd_buf
*kd_beg
, kd_buf
*kd_end
, kd_buf
*end_of_sample
, double i_latency
)
1740 kd_buf
*kd
, *kd_start
, *kd_stop
;
1741 int kd_count
; /* Limit the boundary of kd_start */
1742 double timestamp
= 0.0;
1743 double last_timestamp
= 0.0;
1745 double start_bias
= 0.0;
1747 int debugid
, type
, clen
;
1755 char sched_info
[64];
1759 kd_threadmap
*find_thread_map();
1761 sprintf(buf1
, "%-19.19s interrupt latency = %.1fus", &(ctime(&curr_time
)[0]), i_latency
);
1762 clen
= strlen(buf1
);
1763 memset(buf2
, '-', clen
);
1765 fprintf(log_fp
, "\n\n%s\n", buf2
);
1766 fprintf(log_fp
, "%s\n\n", buf1
);
1768 fprintf(log_fp
, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
1770 thread
= kd_beg
->arg5
;
1771 cpunum
= CPU_NUMBER(kd_end
->timestamp
);
1773 for (kd_count
= 0, kd_start
= kd_beg
- 1; (kd_start
>= (kd_buf
*)my_buffer
); kd_start
--, kd_count
++) {
1774 if (kd_count
== MAX_LOG_COUNT
)
1777 if (CPU_NUMBER(kd_start
->timestamp
) != cpunum
)
1780 if ((kd_start
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1783 if (kd_start
->arg5
!= thread
)
1787 if (kd_start
< (kd_buf
*)my_buffer
)
1788 kd_start
= (kd_buf
*)my_buffer
;
1790 thread
= kd_end
->arg5
;
1792 for (kd_stop
= kd_end
+ 1; kd_stop
< end_of_sample
; kd_stop
++) {
1794 if ((kd_stop
->debugid
& DBG_FUNC_MASK
) == DECR_TRAP
)
1797 if (CPU_NUMBER(kd_stop
->timestamp
) != cpunum
)
1800 if (kd_stop
->arg5
!= thread
)
1804 if (kd_stop
>= end_of_sample
)
1805 kd_stop
= end_of_sample
- 1;
1807 now
= kd_start
->timestamp
& KDBG_TIMESTAMP_MASK
;
1808 timestamp
= ((double)now
) / divisor
;
1810 for (kd
= kd_start
; kd
<= kd_stop
; kd
++) {
1811 type
= kd
->debugid
& DBG_FUNC_MASK
;
1813 if ((ti
= find_thread(kd
->arg5
, type
, type
))) {
1814 if (ti
->stime
>= timestamp
)
1818 for (kd
= kd_start
; kd
<= kd_stop
; kd
++) {
1822 cpunum
= CPU_NUMBER(kd
->timestamp
);
1823 debugid
= kd
->debugid
;
1824 type
= kd
->debugid
& DBG_FUNC_MASK
;
1826 now
= kd
->timestamp
& KDBG_TIMESTAMP_MASK
;
1828 timestamp
= ((double)now
) / divisor
;
1830 if (kd
== kd_start
) {
1831 start_bias
= timestamp
;
1832 last_timestamp
= timestamp
;
1834 delta
= timestamp
- last_timestamp
;
1836 if ((map
= find_thread_map(thread
)))
1837 strcpy(command
, map
->command
);
1845 fprintf(log_fp
, "%9.1f %8.1f\t\tCQ_action @ %-59.59s %-8x %d %s\n",
1846 timestamp
- start_bias
, delta
, pc_to_string(kd
->arg1
, 59, 1) , thread
, cpunum
, command
);
1848 last_timestamp
= timestamp
;
1852 if ((int)(kd
->arg1
) >= 0)
1855 i_latency
= (((double)(-1 - kd
->arg1
)) / divisor
);
1857 if (i_thresh_hold
&& (int)i_latency
> i_thresh_hold
)
1864 if ((ti
= find_thread(kd
->arg5
, 0, 0))) {
1865 if (ti
->type
== -1 && strcmp(command
, "kernel_task"))
1868 fprintf(log_fp
, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-59.59s %-8x %d %s\n",
1869 timestamp
- start_bias
, delta
, i_latency
, p
, pc_to_string(kd
->arg2
, 59, mode
) , thread
, cpunum
, command
);
1871 last_timestamp
= timestamp
;
1875 fprintf(log_fp
, "%9.1f %8.1f[%.1f] \t%-28.28s %-8x %d %s\n",
1876 timestamp
- start_bias
, delta
, (double)kd
->arg1
/divisor
,
1877 "DECR_SET", thread
, cpunum
, command
);
1879 last_timestamp
= timestamp
;
1883 case MACH_stkhandoff
:
1884 if ((map
= find_thread_map(kd
->arg2
)))
1885 strcpy(command1
, map
->command
);
1887 sprintf(command1
, "%-8x", kd
->arg2
);
1889 if ((ti
= find_thread(kd
->arg2
, 0, 0))) {
1890 if (ti
->type
== -1 && strcmp(command1
, "kernel_task"))
1896 memset(sched_info
, ' ', sizeof(sched_info
));
1898 sprintf(sched_info
, "%14.14s", command
);
1899 clen
= strlen(sched_info
);
1900 sched_info
[clen
] = ' ';
1902 sprintf(&sched_info
[14], " @ pri %3d --> %14.14s", kd
->arg3
, command1
);
1903 clen
= strlen(sched_info
);
1904 sched_info
[clen
] = ' ';
1906 sprintf(&sched_info
[45], " @ pri %3d%s", kd
->arg4
, p
);
1908 fprintf(log_fp
, "%9.1f %8.1f\t\t%-10.10s %s %-8x %d\n",
1909 timestamp
- start_bias
, delta
, "MACH_SCHED", sched_info
, thread
, cpunum
);
1911 last_timestamp
= timestamp
;
1915 if ((ti
= find_thread(thread
, 0, 0)) == (struct th_info
*)0) {
1916 if (cur_max
>= MAX_THREADS
)
1918 ti
= &th_state
[cur_max
++];
1920 ti
->thread
= thread
;
1922 ti
->pathptr
= (long *)0;
1923 ti
->child_thread
= 0;
1926 while ( (kd
<= kd_stop
) && (kd
->debugid
& DBG_FUNC_MASK
) == VFS_LOOKUP
)
1929 ti
->arg1
= kd
->arg1
;
1930 memset(&ti
->pathname
[0], 0, (PATHLENGTH
+ 1));
1931 sargptr
= (long *)&ti
->pathname
[0];
1933 *sargptr
++ = kd
->arg2
;
1934 *sargptr
++ = kd
->arg3
;
1935 *sargptr
++ = kd
->arg4
;
1936 ti
->pathptr
= sargptr
;
1939 sargptr
= ti
->pathptr
;
1942 We don't want to overrun our pathname buffer if the
1943 kernel sends us more VFS_LOOKUP entries than we can
1947 if ((long *)sargptr
>= (long *)&ti
->pathname
[PATHLENGTH
])
1954 We need to detect consecutive vfslookup entries.
1955 So, if we get here and find a START entry,
1956 fake the pathptr so we can bypass all further
1960 if (kd
->debugid
& DBG_FUNC_START
)
1962 (long *)ti
->pathptr
= (long *)&ti
->pathname
[PATHLENGTH
];
1966 *sargptr
++ = kd
->arg1
;
1967 *sargptr
++ = kd
->arg2
;
1968 *sargptr
++ = kd
->arg3
;
1969 *sargptr
++ = kd
->arg4
;
1970 ti
->pathptr
= sargptr
;
1977 /* print the tail end of the pathname */
1978 len
= strlen(ti
->pathname
);
1984 fprintf(log_fp
, "%9.1f %8.1f\t\t%-14.14s %-42s %-8x %-8x %d %s\n",
1985 timestamp
- start_bias
, delta
, "VFS_LOOKUP",
1986 &ti
->pathname
[len
], ti
->arg1
, thread
, cpunum
, command
);
1988 last_timestamp
= timestamp
;
1992 if (debugid
& DBG_FUNC_START
)
1993 enter_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
1994 else if (debugid
& DBG_FUNC_END
)
1995 exit_syscall(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
, 1);
1997 print_entry(log_fp
, kd
, thread
, type
, command
, timestamp
, delta
, start_bias
);
1999 last_timestamp
= timestamp
;
2007 double handle_decrementer(kd_buf
*kd
)
2012 if ((int)(kd
->arg1
) >= 0)
2015 latency
= (((double)(-1 - kd
->arg1
)) / divisor
);
2016 elapsed_usecs
= (int)latency
;
2018 if (elapsed_usecs
< 100)
2019 i_usec_10_bins
[elapsed_usecs
/10]++;
2020 if (elapsed_usecs
< 1000)
2021 i_usec_100_bins
[elapsed_usecs
/100]++;
2022 else if (elapsed_usecs
< 10000)
2023 i_msec_1_bins
[elapsed_usecs
/1000]++;
2024 else if (elapsed_usecs
< 50000)
2025 i_msec_10_bins
[elapsed_usecs
/10000]++;
2029 if (i_thresh_hold
&& elapsed_usecs
> i_thresh_hold
)
2030 i_exceeded_threshold
++;
2031 if (elapsed_usecs
> i_max_latency
)
2032 i_max_latency
= elapsed_usecs
;
2033 if (elapsed_usecs
< i_min_latency
|| i_total_samples
== 0)
2034 i_min_latency
= elapsed_usecs
;
2035 i_total_latency
+= elapsed_usecs
;
2042 void init_code_file()
2045 int i
, n
, cnt
, code
;
2048 if ((fp
= fopen(code_file
, "r")) == (FILE *)0) {
2050 fprintf(log_fp
, "open of %s failed\n", code_file
);
2053 n
= fscanf(fp
, "%d\n", &cnt
);
2057 fprintf(log_fp
, "bad format found in %s\n", code_file
);
2060 for (i
= 0; i
< MAX_ENTRIES
; i
++) {
2061 n
= fscanf(fp
, "%x%s\n", &code
, name
);
2066 strncpy(codes_tab
[i
].name
, name
, 32);
2067 codes_tab
[i
].type
= code
;
2079 FILE *fp
= (FILE *)0;
2080 char tmp_nm_file
[128];
2084 bzero(tmp_nm_file
, 128);
2085 bzero(tmpstr
, 1024);
2087 /* Build the temporary nm file path */
2088 sprintf(tmp_nm_file
, "/tmp/knm.out.%d", getpid());
2090 /* Build the nm command and create a tmp file with the output*/
2091 sprintf (tmpstr
, "/usr/bin/nm -f -n -s __TEXT __text %s > %s",
2092 kernelpath
, tmp_nm_file
);
2095 /* Parse the output from the nm command */
2096 if ((fp
=fopen(tmp_nm_file
, "r")) == (FILE *)0)
2098 /* Hmmm, let's not treat this as fatal */
2099 fprintf(stderr
, "Failed to open nm symbol file [%s]\n", tmp_nm_file
);
2103 /* Count the number of symbols in the nm symbol table */
2105 while ( (inchr
= getc(fp
)) != -1)
2113 /* Malloc the space for symbol table */
2114 if (kern_sym_count
> 0)
2116 kern_sym_tbl
= (kern_sym_t
*)malloc(kern_sym_count
* sizeof (kern_sym_t
));
2119 /* Hmmm, lets not treat this as fatal */
2120 fprintf(stderr
, "Can't allocate memory for kernel symbol table\n");
2123 bzero(kern_sym_tbl
, (kern_sym_count
* sizeof(kern_sym_t
)));
2127 /* Hmmm, lets not treat this as fatal */
2128 fprintf(stderr
, "No kernel symbol table \n");
2131 for (i
=0; i
<kern_sym_count
; i
++)
2133 bzero(tmpstr
, 1024);
2134 if (fscanf(fp
, "%lx %c %s", &kern_sym_tbl
[i
].k_sym_addr
, &inchr
, tmpstr
) != 3)
2138 len
= strlen(tmpstr
);
2139 kern_sym_tbl
[i
].k_sym_name
= malloc(len
+ 1);
2141 if (kern_sym_tbl
[i
].k_sym_name
== (char *)0)
2143 fprintf(stderr
, "Can't allocate memory for symbol name [%s]\n", tmpstr
);
2144 kern_sym_tbl
[i
].k_sym_name
= (char *)0;
2148 strcpy(kern_sym_tbl
[i
].k_sym_name
, tmpstr
);
2150 kern_sym_tbl
[i
].k_sym_len
= len
;
2154 if (i
!= kern_sym_count
)
2156 /* Hmmm, didn't build up entire table from nm */
2157 /* scrap the entire thing */
2159 free (kern_sym_tbl
);
2160 kern_sym_tbl
= (kern_sym_t
*)0;
2166 /* Remove the temporary nm file */
2167 unlink(tmp_nm_file
);
2170 /* Dump the kernel symbol table */
2171 for (i
=0; i
< kern_sym_count
; i
++)
2173 if (kern_sym_tbl
[i
].k_sym_name
)
2174 printf ("[%d] 0x%x %s\n", i
,
2175 kern_sym_tbl
[i
].k_sym_addr
, kern_sym_tbl
[i
].k_sym_name
);
2177 printf ("[%d] 0x%x %s\n", i
,
2178 kern_sym_tbl
[i
].k_sym_addr
, "No symbol name");
2184 pc_to_string(unsigned int pc
, int max_len
, int mode
)
2189 int binary_search();
2193 sprintf(pcstring
, "0x%-8x [usermode addr]", pc
);
2198 ret
= binary_search(kern_sym_tbl
, 0, kern_sym_count
-1, pc
);
2202 sprintf(pcstring
, "0x%x", pc
);
2205 else if (kern_sym_tbl
[ret
].k_sym_name
== (char *)0)
2207 sprintf(pcstring
, "0x%x", pc
);
2212 if ((len
= kern_sym_tbl
[ret
].k_sym_len
) > (max_len
- 8))
2215 memcpy(pcstring
, kern_sym_tbl
[ret
].k_sym_name
, len
);
2216 sprintf(&pcstring
[len
], "+0x%-5lx", pc
- kern_sym_tbl
[ret
].k_sym_addr
);
2223 /* Return -1 if not found, else return index */
2224 int binary_search(list
, low
, high
, addr
)
2231 mid
= (low
+ high
) / 2;
2234 return (-1); /* failed */
2235 else if (low
+ 1 == high
)
2237 if (list
[low
].k_sym_addr
<= addr
&&
2238 addr
< list
[high
].k_sym_addr
)
2240 /* We have a range match */
2243 else if (list
[high
].k_sym_addr
<= addr
)
2248 return(-1); /* Failed */
2250 else if (addr
< list
[mid
].k_sym_addr
)
2252 return(binary_search (list
, low
, mid
, addr
));
2256 return(binary_search (list
, mid
, high
, addr
));
2261 open_logfile(char *path
)
2263 log_fp
= fopen(path
, "a");
2267 /* failed to open path */
2268 fprintf(stderr
, "latency: failed to open logfile [%s]\n", path
);