]> git.saurik.com Git - apple/system_cmds.git/blame - latency.tproj/latency.c
system_cmds-671.10.3.tar.gz
[apple/system_cmds.git] / latency.tproj / latency.c
CommitLineData
1815bff5 1/*
8459d725 2 * Copyright (c) 1999-2010 Apple Inc. All rights reserved.
1815bff5
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
8459d725
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
1815bff5
A
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
8459d725
A
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
1815bff5
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
1815bff5 24/*
8459d725 25 cc -I/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -DPRIVATE -D__APPLE_PRIVATE -arch x86_64 -arch i386 -O -o latency latency.c -lncurses -lutil
1815bff5
A
26*/
27
28#include <mach/mach.h>
29#include <stdlib.h>
30#include <stdio.h>
34d340d7 31#include <unistd.h>
1815bff5
A
32#include <signal.h>
33#include <strings.h>
34#include <nlist.h>
35#include <fcntl.h>
36#include <string.h>
8459d725
A
37#include <libc.h>
38#include <termios.h>
39#include <curses.h>
40#include <libutil.h>
41#include <errno.h>
42#include <err.h>
1815bff5
A
43
44#include <sys/types.h>
45#include <sys/param.h>
46#include <sys/time.h>
8459d725 47#include <sys/sysctl.h>
1815bff5
A
48#include <sys/ioctl.h>
49
50#ifndef KERNEL_PRIVATE
51#define KERNEL_PRIVATE
52#include <sys/kdebug.h>
53#undef KERNEL_PRIVATE
54#else
55#include <sys/kdebug.h>
56#endif /*KERNEL_PRIVATE*/
57
1815bff5
A
58#include <mach/mach_error.h>
59#include <mach/mach_types.h>
60#include <mach/message.h>
61#include <mach/mach_syscalls.h>
1815bff5 62#include <mach/clock_types.h>
1c51fdde 63#include <mach/mach_time.h>
1815bff5
A
64
65#include <libkern/OSTypes.h>
66
1815bff5
A
67
68int s_usec_10_bins[10];
69int s_usec_100_bins[10];
70int s_msec_1_bins[10];
71int s_msec_10_bins[5];
72int s_too_slow;
73int s_max_latency;
74int s_min_latency = 0;
75long long s_total_latency = 0;
8459d725 76int s_total_samples = 0;
1815bff5
A
77long s_thresh_hold;
78int s_exceeded_threshold = 0;
79
8459d725
A
80
81#define N_HIGH_RES_BINS 500
82int use_high_res_bins = false;
83
84struct i_latencies {
85 int i_usec_10_bins[10];
86 int i_usec_100_bins[10];
87 int i_msec_1_bins[10];
88 int i_msec_10_bins[5];
89 int i_too_slow;
90 int i_max_latency;
91 int i_min_latency;
92 int i_total_samples;
93 int i_total;
94 int i_exceeded_threshold;
95 uint64_t i_total_latency;
96};
97
98struct i_latencies *i_lat;
99boolean_t i_latency_per_cpu = FALSE;
100
101int i_high_res_bins[N_HIGH_RES_BINS];
102
1815bff5 103long i_thresh_hold;
8459d725 104
1a7e3f61
A
105int watch_priority_min = 97;
106int watch_priority_max = 97;
1815bff5
A
107
108long start_time;
109long curr_time;
110long refresh_time;
111
c03df0e9 112
8459d725 113char *kernelpath = NULL;
1815bff5
A
114
115typedef struct {
8459d725
A
116 void *k_sym_addr; /* kernel symbol address from nm */
117 u_int k_sym_len; /* length of kernel symbol string */
118 char *k_sym_name; /* kernel symbol string from nm */
1815bff5
A
119} kern_sym_t;
120
8459d725
A
121kern_sym_t *kern_sym_tbl; /* pointer to the nm table */
122int kern_sym_count; /* number of entries in nm table */
123
124
1815bff5 125
8459d725
A
126#define MAX_ENTRIES 4096
127struct ct {
128 int type;
129 char name[32];
130} codes_tab[MAX_ENTRIES];
1815bff5 131
8459d725
A
132char *code_file = NULL;
133int num_of_codes = 0;
1815bff5 134
b51d5b5f 135
8459d725
A
136double divisor;
137sig_atomic_t gotSIGWINCH = 0;
138int trace_enabled = 0;
139int need_new_map = 1;
140int set_remove_flag = 1; /* By default, remove trace buffer */
1815bff5 141
8459d725
A
142int RAW_flag = 0;
143int RAW_fd = 0;
1815bff5 144
8459d725
A
145uint64_t first_now = 0;
146uint64_t last_now = 0;
147int first_read = 1;
148
149
150#define SAMPLE_TIME_USECS 50000
151#define SAMPLE_SIZE 300000
152#define MAX_LOG_COUNT 30 /* limits the number of entries dumped in log_decrementer */
1815bff5
A
153
154kbufinfo_t bufinfo = {0, 0, 0};
155
8459d725 156FILE *log_fp = NULL;
1815bff5 157
8459d725
A
158uint64_t sample_TOD_secs;
159uint32_t sample_TOD_usecs;
160
fc6d9e4b
A
161uint64_t cpu_mask;
162
8459d725
A
163int sample_generation = 0;
164int num_i_latency_cpus = 1;
165int num_cpus;
166char *my_buffer;
167int num_entries;
168
169kd_buf **last_decrementer_kd; /* last DECR_TRAP per cpu */
1815bff5 170
09fd88e4 171
1c51fdde 172#define NUMPARMS 23
1815bff5 173
8459d725
A
174typedef struct event *event_t;
175
176struct event {
177 event_t ev_next;
178
179 uintptr_t ev_thread;
180 uint32_t ev_type;
181 uint64_t ev_timestamp;
182};
183
184
185typedef struct lookup *lookup_t;
186
187struct lookup {
188 lookup_t lk_next;
189
190 uintptr_t lk_thread;
191 uintptr_t lk_dvp;
192 long *lk_pathptr;
193 long lk_pathname[NUMPARMS + 1];
194};
195
196
197typedef struct threadmap *threadmap_t;
198
199struct threadmap {
200 threadmap_t tm_next;
201
202 uintptr_t tm_thread;
203 uintptr_t tm_pthread;
204 char tm_command[MAXCOMLEN + 1];
205 char tm_orig_command[MAXCOMLEN + 1];
206};
207
208
209typedef struct threadrun *threadrun_t;
210
211struct threadrun {
212 threadrun_t tr_next;
213
214 uintptr_t tr_thread;
215 kd_buf *tr_entry;
216 uint64_t tr_timestamp;
1a7e3f61 217 int tr_priority;
8459d725
A
218};
219
220
221typedef struct thread_entry *thread_entry_t;
222
223struct thread_entry {
224 thread_entry_t te_next;
225
226 uintptr_t te_thread;
1815bff5 227};
8459d725
A
228
229
230#define HASH_SIZE 1024
231#define HASH_MASK 1023
232
233event_t event_hash[HASH_SIZE];
234lookup_t lookup_hash[HASH_SIZE];
235threadmap_t threadmap_hash[HASH_SIZE];
236threadrun_t threadrun_hash[HASH_SIZE];
237
238event_t event_freelist;
239lookup_t lookup_freelist;
240threadrun_t threadrun_freelist;
241threadmap_t threadmap_freelist;
242threadmap_t threadmap_temp;
243
244thread_entry_t thread_entry_freelist;
245thread_entry_t thread_delete_list;
246thread_entry_t thread_reset_list;
247thread_entry_t thread_event_list;
248thread_entry_t thread_lookup_list;
249thread_entry_t thread_run_list;
250
251
252#ifndef RAW_VERSION1
253typedef struct {
254 int version_no;
255 int thread_count;
256 uint64_t TOD_secs;
257 uint32_t TOD_usecs;
258} RAW_header;
259
260#define RAW_VERSION0 0x55aa0000
261#define RAW_VERSION1 0x55aa0101
262#endif
263
1815bff5 264
8459d725
A
265#define USER_MODE 0
266#define KERNEL_MODE 1
1815bff5 267
1815bff5 268
8459d725
A
269#define TRACE_DATA_NEWTHREAD 0x07000004
270#define TRACE_STRING_NEWTHREAD 0x07010004
271#define TRACE_STRING_EXEC 0x07010008
1815bff5 272
8459d725
A
273#define INTERRUPT 0x01050000
274#define DECR_TRAP 0x01090000
275#define DECR_SET 0x01090004
276#define MACH_vmfault 0x01300008
277#define MACH_sched 0x01400000
278#define MACH_stkhandoff 0x01400008
279#define MACH_makerunnable 0x01400018
280#define MACH_idle 0x01400024
281#define VFS_LOOKUP 0x03010090
282#define IES_action 0x050b0018
283#define IES_filter 0x050b001c
284#define TES_action 0x050c0010
285#define CQ_action 0x050d0018
286#define CPUPM_CPUSTER_RUNCOUNT 0x05310144
1815bff5 287
8459d725
A
288#define BSC_exit 0x040C0004
289#define BSC_thread_terminate 0x040c05a4
1815bff5 290
8459d725 291#define DBG_FUNC_MASK ~(DBG_FUNC_START | DBG_FUNC_END)
1815bff5 292
ef8ad44b 293#define CPU_NUMBER(kp) kdbg_get_cpu(kp)
83f6dbe8 294
8459d725 295#define EMPTYSTRING ""
1815bff5 296
8459d725
A
297
298const char *fault_name[] = {
299 "",
1815bff5
A
300 "ZeroFill",
301 "PageIn",
302 "COW",
303 "CacheHit",
ef8ad44b
A
304 "NoZeroFill",
305 "Guard",
306 "PageInFile",
307 "PageInAnon"
1815bff5
A
308};
309
8459d725
A
310const char *sched_reasons[] = {
311 "N",
312 "P",
313 "Q",
314 "?",
315 "u",
316 "U",
317 "?",
318 "?",
319 "H",
320 "?",
321 "?",
322 "?",
323 "?",
324 "?",
325 "?",
326 "?",
327 "Y"
328};
b51d5b5f 329
8459d725
A
330#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x)))
331#define MAX_REASON ARRAYSIZE(sched_reasons)
332
333static double handle_decrementer(kd_buf *, int);
334static kd_buf *log_decrementer(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, double i_latency);
335static void read_command_map(void);
336static void enter_syscall(FILE *fp, kd_buf *kd, int thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, int print_info);
337static void exit_syscall(FILE *fp, kd_buf *kd, int thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, int print_info);
338static void print_entry(FILE *fp, kd_buf *kd, int thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, kd_buf *kd_note);
339static void log_info(uint64_t now, uint64_t idelta, uint64_t start_bias, kd_buf *kd, kd_buf *kd_note);
340static char *find_code(int);
341static void pc_to_string(char *pcstring, uintptr_t pc, int max_len, int mode);
342static void getdivisor(void);
343static int sample_sc(void);
344static void init_code_file(void);
345static void do_kernel_nm(void);
346static void open_logfile(const char*);
347static int binary_search(kern_sym_t *list, int low, int high, uintptr_t addr);
348
349static void create_map_entry(uintptr_t, char *);
350static void check_for_thread_update(uintptr_t thread, int debugid_base, kd_buf *kbufp, char **command);
1a7e3f61
A
351static void log_scheduler(kd_buf *kd_start, kd_buf *kd_stop, kd_buf *end_of_sample, int s_priority, double s_latency, uintptr_t thread);
352static int check_for_scheduler_latency(int type, uintptr_t *thread, uint64_t now, kd_buf *kd, kd_buf **kd_start, int *priority, double *latency);
8459d725
A
353static void open_rawfile(const char *path);
354
355static void screen_update(FILE *);
356
357static void set_enable(int);
358static void set_remove(void);
359
360static int
361quit(char *s)
1815bff5 362{
8459d725
A
363 if (!RAW_flag) {
364 if (trace_enabled) {
365 set_enable(0);
366 }
367 /*
368 * This flag is turned off when calling
369 * quit() due to a set_remove() failure.
370 */
371 if (set_remove_flag) {
372 set_remove();
373 }
374 }
375 printf("latency: ");
376 if (s) {
1815bff5 377 printf("%s", s);
8459d725 378 }
1815bff5
A
379 exit(1);
380}
381
382void
383set_enable(int val)
384{
8459d725
A
385 int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDENABLE, val };
386 size_t needed;
387
388 if (sysctl(mib, ARRAYSIZE(mib), NULL, &needed, NULL, 0) < 0) {
389 quit("trace facility failure, KERN_KDENABLE\n");
390 }
1815bff5
A
391}
392
393void
394set_numbufs(int nbufs)
395{
8459d725
A
396 int mib1[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSETBUF, nbufs };
397 int mib2[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSETUP };
398 size_t needed;
1815bff5 399
8459d725
A
400 if (sysctl(mib1, ARRAYSIZE(mib1), NULL, &needed, NULL, 0) < 0) {
401 quit("trace facility failure, KERN_KDSETBUF\n");
402 }
403 if (sysctl(mib2, ARRAYSIZE(mib2), NULL, &needed, NULL, 0) < 0) {
404 quit("trace facility failure, KERN_KDSETUP\n");
405 }
1815bff5
A
406}
407
408void
409set_pidexclude(int pid, int on_off)
410{
8459d725
A
411 int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDPIDEX };
412 size_t needed = sizeof(kd_regtype);
1815bff5 413
8459d725
A
414 kd_regtype kr = {
415 .type = KDBG_TYPENONE,
416 .value1 = pid,
417 .value2 = on_off
418 };
1815bff5 419
8459d725 420 sysctl(mib, ARRAYSIZE(mib), &kr, &needed, NULL, 0);
1815bff5
A
421}
422
1815bff5
A
423void
424get_bufinfo(kbufinfo_t *val)
425{
8459d725
A
426 int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDGETBUF };
427 size_t needed = sizeof (*val);
428
429 if (sysctl(mib, ARRAYSIZE(mib), val, &needed, 0, 0) < 0) {
430 quit("trace facility failure, KERN_KDGETBUF\n");
431 }
1815bff5
A
432}
433
434void
8459d725 435set_remove(void)
1815bff5 436{
8459d725
A
437 int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDREMOVE };
438 size_t needed;
1815bff5
A
439
440 errno = 0;
441
8459d725
A
442 if (sysctl(mib, ARRAYSIZE(mib), NULL, &needed, NULL, 0) < 0) {
443 set_remove_flag = 0;
444 if (errno == EBUSY) {
445 quit("the trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n");
446 } else {
447 quit("trace facility failure, KERN_KDREMOVE\n");
448 }
449 }
1815bff5
A
450}
451
8459d725 452
1815bff5 453void
8459d725 454write_high_res_latencies(void)
1815bff5 455{
8459d725
A
456 int i;
457 FILE *f;
1815bff5 458
8459d725
A
459 if (use_high_res_bins) {
460 if ((f = fopen("latencies.csv","w"))) {
461 for (i = 0; i < N_HIGH_RES_BINS; i++) {
462 fprintf(f, "%d,%d\n", i, i_high_res_bins[i]);
463 }
464 fclose(f);
465 }
466 }
1815bff5
A
467}
468
c03df0e9 469void
8459d725 470sigintr(int signo __attribute__((unused)))
c03df0e9 471{
8459d725 472 write_high_res_latencies();
1815bff5 473
8459d725
A
474 set_enable(0);
475 set_pidexclude(getpid(), 0);
476 screen_update(log_fp);
477 endwin();
478 set_remove();
479
480 exit(1);
1815bff5
A
481}
482
8459d725
A
483/* exit under normal conditions -- signal handler */
484void
485leave(int signo __attribute__((unused)))
1815bff5 486{
8459d725 487 write_high_res_latencies();
1815bff5 488
8459d725 489 set_enable(0);
1815bff5 490 set_pidexclude(getpid(), 0);
20e66415 491 endwin();
1815bff5
A
492 set_remove();
493
8459d725 494 exit(1);
1815bff5
A
495}
496
8459d725
A
497void
498sigwinch(int signo __attribute__((unused)))
1815bff5 499{
8459d725
A
500 gotSIGWINCH = 1;
501}
c03df0e9 502
8459d725
A
503void
504print_total(FILE *fp, char *s, int total)
505{
506 int cpu;
507 int clen;
508 int itotal;
509 struct i_latencies *il;
510 char tbuf[512];
511
512 for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
513 il = &i_lat[cpu];
514 itotal += il->i_total;
515 }
516 clen = sprintf(tbuf, "%s %10d %9d", s, total, itotal);
517
518 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
519 il = &i_lat[cpu];
520
521 if (i_latency_per_cpu == TRUE) {
522 clen += sprintf(&tbuf[clen], " %9d", il->i_total);
523 }
524
525 il->i_total = 0;
526 }
527 sprintf(&tbuf[clen], "\n");
528 if (fp) {
529 fprintf(fp, "%s", tbuf);
530 } else {
531 printw(tbuf);
532 }
1815bff5
A
533}
534
8459d725
A
535
536
1815bff5
A
537void
538screen_update(FILE *fp)
539{
8459d725
A
540 int i;
541 int cpu;
542 int clen;
543 int itotal, stotal;
544 int elapsed_secs;
545 int elapsed_mins;
546 int elapsed_hours;
547 int min_lat, max_lat;
548 uint64_t tot_lat;
1815bff5
A
549 unsigned int average_s_latency;
550 unsigned int average_i_latency;
8459d725
A
551 struct i_latencies *il;
552 char tbuf[1024];
1815bff5 553
8459d725
A
554 if (fp == NULL) {
555 erase();
1815bff5 556 move(0, 0);
8459d725
A
557 } else {
558 fprintf(fp,"\n\n===================================================================================================\n");
559 }
1815bff5
A
560 /*
561 * Display the current time.
562 * "ctime" always returns a string that looks like this:
563 *
564 * Sun Sep 16 01:03:52 1973
565 * 012345678901234567890123
566 * 1 2
567 *
568 * We want indices 11 thru 18 (length 8).
569 */
8459d725
A
570 if (RAW_flag) {
571 curr_time = sample_TOD_secs;
572 elapsed_secs = ((last_now - first_now) / divisor) / 1000000;
573 } else {
574 elapsed_secs = curr_time - start_time;
575 }
576
1815bff5
A
577 elapsed_hours = elapsed_secs / 3600;
578 elapsed_secs -= elapsed_hours * 3600;
579 elapsed_mins = elapsed_secs / 60;
580 elapsed_secs -= elapsed_mins * 60;
581
582 sprintf(tbuf, "%-19.19s %2ld:%02ld:%02ld\n", &(ctime(&curr_time)[0]),
83f6dbe8 583 (long)elapsed_hours, (long)elapsed_mins, (long)elapsed_secs);
8459d725
A
584 if (fp) {
585 fprintf(fp, "%s", tbuf);
586 } else {
587 printw(tbuf);
c03df0e9 588 }
1815bff5
A
589
590 sprintf(tbuf, " SCHEDULER INTERRUPTS\n");
8459d725
A
591 if (fp) {
592 fprintf(fp, "%s", tbuf);
593 } else {
594 printw(tbuf);
595 }
1815bff5 596
8459d725
A
597 if (i_latency_per_cpu == TRUE) {
598 clen = sprintf(tbuf, " Total");
1815bff5 599
8459d725
A
600 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
601 if (cpu <= 9) {
602 clen += sprintf(&tbuf[clen], " CPU %d", cpu);
603 } else {
604 clen += sprintf(&tbuf[clen], " CPU %d", cpu);
605 }
606 }
607 if (fp) {
608 fprintf(fp, "%s", tbuf);
609 } else {
610 printw(tbuf);
611 }
1815bff5 612
8459d725 613 clen = sprintf(tbuf, "\n-------------------------------------------------------");
1815bff5 614
8459d725
A
615 for (cpu = 1; cpu < num_i_latency_cpus; cpu++) {
616 clen += sprintf(&tbuf[clen], "----------");
617 }
618 if (fp) {
619 fprintf(fp, "%s", tbuf);
620 } else {
621 printw(tbuf);
622 }
623 } else {
624 sprintf(tbuf, "---------------------------------------------");
625 if (fp) {
626 fprintf(fp, "%s", tbuf);
627 } else {
628 printw(tbuf);
629 }
630 }
631 for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
632 il = &i_lat[cpu];
633 itotal += il->i_total_samples;
634 }
635 clen = sprintf(tbuf, "\ntotal_samples %10d %9d", s_total_samples, itotal);
1815bff5 636
8459d725
A
637 if (i_latency_per_cpu == TRUE) {
638 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
639 il = &i_lat[cpu];
1815bff5 640
8459d725
A
641 clen += sprintf(&tbuf[clen], " %9d", il->i_total_samples);
642 }
643 }
644 sprintf(&tbuf[clen], "\n");
645 if (fp) {
646 fprintf(fp, "%s", tbuf);
647 } else {
648 printw(tbuf);
649 }
1815bff5
A
650
651
8459d725
A
652 for (stotal = 0, i = 0; i < 10; i++) {
653 for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
654 il = &i_lat[cpu];
1815bff5 655
8459d725
A
656 itotal += il->i_usec_10_bins[i];
657 il->i_total += il->i_usec_10_bins[i];
658 }
659 clen = sprintf(tbuf, "\ndelays < %3d usecs %10d %9d", (i + 1) * 10, s_usec_10_bins[i], itotal);
1815bff5
A
660
661 stotal += s_usec_10_bins[i];
1815bff5 662
8459d725
A
663 if (i_latency_per_cpu == TRUE) {
664 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
665 il = &i_lat[cpu];
666
667 clen += sprintf(&tbuf[clen], " %9d", il->i_usec_10_bins[i]);
668 }
669 }
670 if (fp) {
671 fprintf(fp, "%s", tbuf);
672 } else {
673 printw(tbuf);
674 }
675 }
676 print_total(fp, "\ntotal < 100 usecs", stotal);
1815bff5 677
8459d725
A
678 for (stotal = 0, i = 1; i < 10; i++) {
679 for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
680 il = &i_lat[cpu];
1815bff5 681
8459d725
A
682 itotal += il->i_usec_100_bins[i];
683 il->i_total += il->i_usec_100_bins[i];
684 }
685 if (i < 9) {
686 clen = sprintf(tbuf, "\ndelays < %3d usecs %10d %9d", (i + 1) * 100, s_usec_100_bins[i], itotal);
687 } else {
688 clen = sprintf(tbuf, "\ndelays < 1 msec %10d %9d", s_usec_100_bins[i], itotal);
689 }
1815bff5
A
690
691 stotal += s_usec_100_bins[i];
1815bff5 692
8459d725
A
693 if (i_latency_per_cpu == TRUE) {
694 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
695 il = &i_lat[cpu];
1815bff5 696
8459d725
A
697 clen += sprintf(&tbuf[clen], " %9d", il->i_usec_100_bins[i]);
698 }
699 }
700 if (fp) {
701 fprintf(fp, "%s", tbuf);
702 } else {
703 printw(tbuf);
704 }
705 }
706 print_total(fp, "\ntotal < 1 msec ", stotal);
1815bff5
A
707
708
8459d725
A
709 for (stotal = 0, i = 1; i < 10; i++) {
710 for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
711 il = &i_lat[cpu];
1815bff5 712
8459d725
A
713 itotal += il->i_msec_1_bins[i];
714 il->i_total += il->i_msec_1_bins[i];
715 }
716 clen = sprintf(tbuf, "\ndelays < %3d msecs %10d %9d", (i + 1), s_msec_1_bins[i], itotal);
1815bff5
A
717
718 stotal += s_msec_1_bins[i];
1815bff5 719
8459d725
A
720 if (i_latency_per_cpu == TRUE) {
721 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
722 il = &i_lat[cpu];
1815bff5 723
8459d725
A
724 clen += sprintf(&tbuf[clen], " %9d", il->i_msec_1_bins[i]);
725 }
726 }
727 if (fp) {
728 fprintf(fp, "%s", tbuf);
729 } else {
730 printw(tbuf);
731 }
732 }
733 print_total(fp, "\ntotal < 10 msecs", stotal);
1815bff5 734
8459d725
A
735 for (stotal = 0, i = 1; i < 5; i++) {
736 for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
737 il = &i_lat[cpu];
1815bff5 738
8459d725
A
739 itotal += il->i_msec_10_bins[i];
740 il->i_total += il->i_msec_10_bins[i];
741 }
742 clen = sprintf(tbuf, "\ndelays < %3d msecs %10d %9d", (i + 1)*10, s_msec_10_bins[i], itotal);
1815bff5 743
8459d725 744 stotal += s_msec_10_bins[i];
1815bff5 745
8459d725
A
746 if (i_latency_per_cpu == TRUE) {
747 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
748 il = &i_lat[cpu];
1815bff5 749
8459d725
A
750 clen += sprintf(&tbuf[clen], " %9d", il->i_msec_10_bins[i]);
751 }
752 }
753 if (fp) {
754 fprintf(fp, "%s", tbuf);
755 } else {
756 printw(tbuf);
757 }
1815bff5 758 }
8459d725 759 print_total(fp, "\ntotal < 50 msecs", stotal);
1815bff5 760
1815bff5 761
8459d725
A
762 for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
763 il = &i_lat[cpu];
764 itotal += il->i_too_slow;
765 }
766 clen = sprintf(tbuf, "\ndelays > 50 msecs %10d %9d", s_too_slow, itotal);
1815bff5 767
8459d725
A
768 if (i_latency_per_cpu == TRUE) {
769 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
770 il = &i_lat[cpu];
771
772 clen += sprintf(&tbuf[clen], " %9d", il->i_too_slow);
773 }
774 }
775 if (fp) {
776 fprintf(fp, "%s", tbuf);
777 } else {
778 printw(tbuf);
779 }
1815bff5 780
8459d725
A
781 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
782 il = &i_lat[cpu];
1815bff5 783
8459d725
A
784 if (cpu == 0 || (il->i_min_latency < min_lat)) {
785 min_lat = il->i_min_latency;
786 }
787 }
788 clen = sprintf(tbuf, "\n\nminimum latency(usecs) %7d %9d", s_min_latency, min_lat);
1815bff5 789
8459d725
A
790 if (i_latency_per_cpu == TRUE) {
791 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
792 il = &i_lat[cpu];
793
794 clen += sprintf(&tbuf[clen], " %9d", il->i_min_latency);
795 }
796 }
797 if (fp) {
798 fprintf(fp, "%s", tbuf);
799 } else {
800 printw(tbuf);
801 }
1815bff5 802
1815bff5 803
8459d725
A
804 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
805 il = &i_lat[cpu];
1815bff5 806
8459d725
A
807 if (cpu == 0 || (il->i_max_latency > max_lat)) {
808 max_lat = il->i_max_latency;
809 }
810 }
811 clen = sprintf(tbuf, "\nmaximum latency(usecs) %7d %9d", s_max_latency, max_lat);
1815bff5 812
8459d725
A
813 if (i_latency_per_cpu == TRUE) {
814 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
815 il = &i_lat[cpu];
816
817 clen += sprintf(&tbuf[clen], " %9d", il->i_max_latency);
818 }
819 }
820 if (fp) {
821 fprintf(fp, "%s", tbuf);
822 } else {
823 printw(tbuf);
824 }
825
826 if (s_total_samples) {
827 average_s_latency = (unsigned int)(s_total_latency/s_total_samples);
828 } else {
829 average_s_latency = 0;
830 }
1815bff5 831
8459d725
A
832 for (itotal = 0, tot_lat = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
833 il = &i_lat[cpu];
834
835 itotal += il->i_total_samples;
836 tot_lat += il->i_total_latency;
837 }
838 if (itotal) {
839 average_i_latency = (unsigned)(tot_lat/itotal);
840 } else {
841 average_i_latency = 0;
842 }
1815bff5 843
8459d725 844 clen = sprintf(tbuf, "\naverage latency(usecs) %7d %9d", average_s_latency, average_i_latency);
1815bff5 845
8459d725
A
846 if (i_latency_per_cpu == TRUE) {
847 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
848 il = &i_lat[cpu];
849
850 if (il->i_total_samples) {
851 average_i_latency = (unsigned int)(il->i_total_latency/il->i_total_samples);
852 } else {
853 average_i_latency = 0;
854 }
1815bff5 855
8459d725
A
856 clen += sprintf(&tbuf[clen], " %9d", average_i_latency);
857 }
858 }
859 if (fp) {
860 fprintf(fp, "%s", tbuf);
861 } else {
862 printw(tbuf);
863 }
864
865 for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
866 il = &i_lat[cpu];
867
868 itotal += il->i_exceeded_threshold;
869 }
870 clen = sprintf(tbuf, "\nexceeded threshold %7d %9d", s_exceeded_threshold, itotal);
1815bff5 871
8459d725
A
872 if (i_latency_per_cpu == TRUE) {
873 for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
874 il = &i_lat[cpu];
875
876 clen += sprintf(&tbuf[clen], " %9d", il->i_exceeded_threshold);
877 }
878 }
879 sprintf(&tbuf[clen], "\n");
880
881 if (fp) {
882 fprintf(fp, "%s", tbuf);
883 } else {
884 printw(tbuf);
885 }
886
887 if (fp == NULL) {
888 refresh();
889 } else {
890 fflush(fp);
891 }
1815bff5
A
892}
893
894int
8459d725 895exit_usage(void)
1815bff5 896{
1a7e3f61
A
897 fprintf(stderr, "Usage: latency [-p <priority>] [-h] [-m] [-st <threshold>] [-it <threshold>]\n");
898 fprintf(stderr, " [-c <codefile>] [-l <logfile>] [-R <rawfile>] [-n <kernel>]\n\n");
8459d725 899
1a7e3f61 900 fprintf(stderr, " -p specify scheduling priority to watch... default is realtime. Can also be a range, e.g. \"31-47\".\n");
c03df0e9 901 fprintf(stderr, " -h Display high resolution interrupt latencies and write them to latencies.csv (truncate existing file) upon exit.\n");
1815bff5 902 fprintf(stderr, " -st set scheduler latency threshold in microseconds... if latency exceeds this, then log trace\n");
8459d725 903 fprintf(stderr, " -m specify per-CPU interrupt latency reporting\n");
1815bff5 904 fprintf(stderr, " -it set interrupt latency threshold in microseconds... if latency exceeds this, then log trace\n");
8459d725
A
905 fprintf(stderr, " -c specify name of codes file... default is /usr/share/misc/trace.codes\n");
906 fprintf(stderr, " -l specify name of file to log trace entries to when the specified threshold is exceeded\n");
907 fprintf(stderr, " -R specify name of raw trace file to process\n");
1a7e3f61 908 fprintf(stderr, " -n specify kernel... default is /System/Library/Kernels/kernel.development\n");
1815bff5
A
909
910 fprintf(stderr, "\nlatency must be run as root\n\n");
911
912 exit(1);
913}
914
915
83f6dbe8 916int
ef8ad44b 917main(int argc, char *argv[])
1815bff5 918{
fc6d9e4b
A
919 int i;
920
ef8ad44b
A
921 if (0 != reexec_to_match_kernel()) {
922 fprintf(stderr, "Could not re-execute: %d\n", errno);
923 exit(1);
924 }
8459d725 925 while (argc > 1) {
ef8ad44b 926
8459d725
A
927 if (strcmp(argv[1], "-R") == 0) {
928 argc--;
929 argv++;
1815bff5 930
8459d725
A
931 if (argc > 1) {
932 open_rawfile(argv[1]);
933 } else {
934 exit_usage();
935 }
1815bff5 936
8459d725
A
937 RAW_flag = 1;
938
939 } else if (strcmp(argv[1], "-p") == 0) {
940 argc--;
941 argv++;
942
943 if (argc > 1) {
1a7e3f61
A
944 if (2 == sscanf(argv[1], "%d-%d", &watch_priority_min, &watch_priority_max)) {
945 if (watch_priority_min > watch_priority_max) {
946 exit_usage();
947 } else if (watch_priority_min < 0) {
948 exit_usage();
949 }
950 } else {
951 if (1 == sscanf(argv[1], "%d", &watch_priority_min)) {
952 watch_priority_max = watch_priority_min;
953 } else {
954 exit_usage();
955 }
956 }
8459d725
A
957 } else {
958 exit_usage();
959 }
1815bff5
A
960 } else if (strcmp(argv[1], "-st") == 0) {
961 argc--;
962 argv++;
963
8459d725
A
964 if (argc > 1) {
965 s_thresh_hold = atoi(argv[1]);
966 } else {
967 exit_usage();
968 }
1815bff5
A
969 } else if (strcmp(argv[1], "-it") == 0) {
970 argc--;
971 argv++;
972
8459d725
A
973 if (argc > 1) {
974 i_thresh_hold = atoi(argv[1]);
975 } else {
976 exit_usage();
977 }
1815bff5
A
978 } else if (strcmp(argv[1], "-c") == 0) {
979 argc--;
980 argv++;
981
8459d725
A
982 if (argc > 1) {
983 code_file = argv[1];
984 } else {
985 exit_usage();
986 }
1815bff5
A
987 } else if (strcmp(argv[1], "-l") == 0) {
988 argc--;
989 argv++;
990
8459d725
A
991 if (argc > 1) {
992 open_logfile(argv[1]);
993 } else {
994 exit_usage();
995 }
996 } else if (strcmp(argv[1], "-n") == 0) {
1815bff5
A
997 argc--;
998 argv++;
999
8459d725
A
1000 if (argc > 1) {
1001 kernelpath = argv[1];
1002 } else {
1003 exit_usage();
1004 }
1005 } else if (strcmp(argv[1], "-h") == 0) {
1006 use_high_res_bins = TRUE;
1815bff5 1007
8459d725
A
1008 } else if (strcmp(argv[1], "-m") == 0) {
1009 i_latency_per_cpu = TRUE;
1815bff5 1010
8459d725 1011 } else {
1815bff5 1012 exit_usage();
8459d725 1013 }
1815bff5
A
1014
1015 argc--;
1016 argv++;
1017 }
8459d725
A
1018 if (!RAW_flag) {
1019 if (geteuid() != 0) {
1020 printf("'latency' must be run as root...\n");
1021 exit(1);
1022 }
1023 }
1024 if (kernelpath == NULL) {
1a7e3f61 1025 kernelpath = "/System/Library/Kernels/kernel.development";
8459d725 1026 }
1815bff5 1027
8459d725
A
1028 if (code_file == NULL) {
1029 code_file = "/usr/share/misc/trace.codes";
1030 }
1815bff5
A
1031
1032 do_kernel_nm();
1033
1815bff5 1034 getdivisor();
1815bff5
A
1035
1036 init_code_file();
1037
8459d725
A
1038 if (!RAW_flag) {
1039 if (initscr() == NULL) {
1040 printf("Unrecognized TERM type, try vt100\n");
1041 exit(1);
1815bff5 1042 }
8459d725
A
1043 clear();
1044 refresh();
1815bff5 1045
8459d725
A
1046 signal(SIGWINCH, sigwinch);
1047 signal(SIGINT, sigintr);
1048 signal(SIGQUIT, leave);
1049 signal(SIGTERM, leave);
1050 signal(SIGHUP, leave);
1815bff5 1051
8459d725
A
1052 /*
1053 * grab the number of cpus and scale the buffer size
1054 */
1055 int mib[] = { CTL_HW, HW_NCPU };
1056 size_t len = sizeof(num_cpus);
1815bff5 1057
8459d725 1058 sysctl(mib, ARRAYSIZE(mib), &num_cpus, &len, NULL, 0);
1815bff5 1059
8459d725
A
1060 set_remove();
1061 set_numbufs(SAMPLE_SIZE * num_cpus);
1815bff5 1062
8459d725 1063 get_bufinfo(&bufinfo);
1815bff5 1064
8459d725 1065 set_enable(0);
1815bff5 1066
8459d725
A
1067 set_pidexclude(getpid(), 1);
1068 set_enable(1);
1815bff5 1069
8459d725
A
1070 num_entries = bufinfo.nkdbufs;
1071 } else {
1072 num_entries = 50000;
1073 num_cpus = 128;
1074 }
1815bff5 1075
fc6d9e4b
A
1076 for (cpu_mask = 0, i = 0; i < num_cpus; i++)
1077 cpu_mask |= ((uint64_t)1 << i);
1078
8459d725
A
1079 if ((my_buffer = malloc(num_entries * sizeof(kd_buf))) == NULL) {
1080 quit("can't allocate memory for tracing info\n");
1081 }
1815bff5 1082
8459d725
A
1083 if ((last_decrementer_kd = (kd_buf **)malloc(num_cpus * sizeof(kd_buf *))) == NULL) {
1084 quit("can't allocate memory for decrementer tracing info\n");
1085 }
1815bff5 1086
8459d725
A
1087 if (i_latency_per_cpu == FALSE) {
1088 num_i_latency_cpus = 1;
1089 } else {
1090 num_i_latency_cpus = num_cpus;
1091 }
1815bff5 1092
8459d725
A
1093 if ((i_lat = (struct i_latencies *)malloc(num_i_latency_cpus * sizeof(struct i_latencies))) == NULL) {
1094 quit("can't allocate memory for interrupt latency info\n");
1095 }
1815bff5 1096
8459d725 1097 bzero((char *)i_lat, num_i_latency_cpus * sizeof(struct i_latencies));
1815bff5 1098
8459d725
A
1099 if (RAW_flag) {
1100 while (sample_sc()) {
1101 continue;
1102 }
1815bff5 1103
8459d725
A
1104 if (log_fp) {
1105 screen_update(log_fp);
1106 }
1815bff5 1107
8459d725 1108 screen_update(stdout);
1815bff5 1109
8459d725
A
1110 } else {
1111 uint64_t adelay;
1112 double fdelay;
1113 double nanosecs_to_sleep;
1815bff5 1114
8459d725
A
1115 nanosecs_to_sleep = (double)(SAMPLE_TIME_USECS * 1000);
1116 fdelay = nanosecs_to_sleep * (divisor /1000);
1117 adelay = (uint64_t)fdelay;
1815bff5 1118
8459d725 1119 trace_enabled = 1;
1815bff5 1120
8459d725
A
1121 start_time = time(NULL);
1122 refresh_time = start_time;
1815bff5 1123
8459d725
A
1124 for (;;) {
1125 curr_time = time(NULL);
1815bff5 1126
8459d725
A
1127 if (curr_time >= refresh_time) {
1128 screen_update(NULL);
1129 refresh_time = curr_time + 1;
1130 }
1131 mach_wait_until(mach_absolute_time() + adelay);
1815bff5 1132
8459d725 1133 sample_sc();
1815bff5 1134
8459d725
A
1135 if (gotSIGWINCH) {
1136 /*
1137 * No need to check for initscr error return.
1138 * We won't get here if it fails on the first call.
1139 */
1140 endwin();
1141 clear();
1142 refresh();
1815bff5 1143
8459d725
A
1144 gotSIGWINCH = 0;
1145 }
1146 }
1815bff5 1147 }
1815bff5
A
1148}
1149
1150
8459d725
A
1151
1152void
1153read_command_map(void)
1815bff5 1154{
8459d725
A
1155 kd_threadmap *mapptr = 0;
1156 int total_threads = 0;
1157 size_t size;
1158 off_t offset;
1159 int i;
1160 RAW_header header = {0};
1161
1162 if (RAW_flag) {
1163 if (read(RAW_fd, &header, sizeof(RAW_header)) != sizeof(RAW_header)) {
1164 perror("read failed");
1165 exit(2);
1166 }
1167 if (header.version_no != RAW_VERSION1) {
1168 header.version_no = RAW_VERSION0;
1169 header.TOD_secs = time(NULL);
1170 header.TOD_usecs = 0;
1171
1172 lseek(RAW_fd, (off_t)0, SEEK_SET);
1173
1174 if (read(RAW_fd, &header.thread_count, sizeof(int)) != sizeof(int)) {
1175 perror("read failed");
1176 exit(2);
1177 }
1815bff5 1178 }
8459d725 1179 total_threads = header.thread_count;
1815bff5 1180
8459d725
A
1181 sample_TOD_secs = header.TOD_secs;
1182 sample_TOD_usecs = header.TOD_usecs;
1815bff5 1183
8459d725
A
1184 if (total_threads == 0 && header.version_no != RAW_VERSION0) {
1185 offset = lseek(RAW_fd, (off_t)0, SEEK_CUR);
1186 offset = (offset + (4095)) & ~4095;
1815bff5 1187
8459d725 1188 lseek(RAW_fd, offset, SEEK_SET);
1815bff5 1189 }
8459d725
A
1190 } else {
1191 total_threads = bufinfo.nkdthreads;
1815bff5 1192 }
8459d725
A
1193
1194 size = total_threads * sizeof(kd_threadmap);
1815bff5 1195
8459d725
A
1196 if (size == 0 || ((mapptr = (kd_threadmap *) malloc(size)) == 0)) {
1197 return;
1198 }
1199 bzero (mapptr, size);
1200
1201 /*
1202 * Now read the threadmap
1203 */
1204 if (RAW_flag) {
1205 if (read(RAW_fd, mapptr, size) != size) {
1206 printf("Can't read the thread map -- this is not fatal\n");
1815bff5 1207 }
8459d725
A
1208 if (header.version_no != RAW_VERSION0) {
1209 offset = lseek(RAW_fd, (off_t)0, SEEK_CUR);
1210 offset = (offset + (4095)) & ~4095;
1211
1212 lseek(RAW_fd, offset, SEEK_SET);
1815bff5 1213 }
8459d725
A
1214 } else {
1215 int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDTHRMAP};
1216 if (sysctl(mib, ARRAYSIZE(mib), mapptr, &size, NULL, 0) < 0) {
1217 /*
1218 * This is not fatal -- just means I cant map command strings
1219 */
1220 printf("Can't read the thread map -- this is not fatal\n");
1815bff5 1221
8459d725
A
1222 total_threads = 0;
1223 }
1224 }
1225 for (i = 0; i < total_threads; i++) {
1226 create_map_entry(mapptr[i].thread, &mapptr[i].command[0]);
1227 }
1228 free(mapptr);
1229}
1815bff5 1230
8459d725
A
1231void
1232create_map_entry(uintptr_t thread, char *command)
1233{
1234 threadmap_t tme;
1815bff5 1235
8459d725
A
1236 if ((tme = threadmap_freelist)) {
1237 threadmap_freelist = tme->tm_next;
1238 } else {
1239 tme = (threadmap_t)malloc(sizeof(struct threadmap));
1240 }
1815bff5 1241
8459d725 1242 tme->tm_thread = thread;
1815bff5 1243
8459d725
A
1244 (void)strncpy (tme->tm_command, command, MAXCOMLEN);
1245 tme->tm_command[MAXCOMLEN] = '\0';
1246 tme->tm_orig_command[0] = '\0';
1815bff5 1247
8459d725 1248 int hashid = thread & HASH_MASK;
1815bff5 1249
8459d725
A
1250 tme->tm_next = threadmap_hash[hashid];
1251 threadmap_hash[hashid] = tme;
1252}
1815bff5 1253
8459d725
A
1254void
1255delete_thread_entry(uintptr_t thread)
1256{
1257 threadmap_t tme;
1815bff5 1258
8459d725 1259 int hashid = thread & HASH_MASK;
1815bff5 1260
8459d725
A
1261 if ((tme = threadmap_hash[hashid])) {
1262 if (tme->tm_thread == thread) {
1263 threadmap_hash[hashid] = tme->tm_next;
1264 } else {
1265 threadmap_t tme_prev = tme;
1815bff5 1266
8459d725
A
1267 for (tme = tme->tm_next; tme; tme = tme->tm_next) {
1268 if (tme->tm_thread == thread) {
1269 tme_prev->tm_next = tme->tm_next;
1270 break;
1271 }
1272 tme_prev = tme;
1273 }
1274 }
1275 if (tme) {
1276 tme->tm_next = threadmap_freelist;
1277 threadmap_freelist = tme;
1278 }
1279 }
1280}
1815bff5 1281
8459d725
A
1282void
1283find_and_insert_tmp_map_entry(uintptr_t pthread, char *command)
1284{
1285 threadmap_t tme;
1286
1287 if ((tme = threadmap_temp)) {
1288 if (tme->tm_pthread == pthread) {
1289 threadmap_temp = tme->tm_next;
1290 } else {
1291 threadmap_t tme_prev = tme;
1292
1293 for (tme = tme->tm_next; tme; tme = tme->tm_next) {
1294 if (tme->tm_pthread == pthread) {
1295 tme_prev->tm_next = tme->tm_next;
1296 break;
1297 }
1298 tme_prev = tme;
1299 }
1300 }
1301 if (tme) {
1302 (void)strncpy (tme->tm_command, command, MAXCOMLEN);
1303 tme->tm_command[MAXCOMLEN] = '\0';
1304 tme->tm_orig_command[0] = '\0';
1305
1306 int hashid = tme->tm_thread & HASH_MASK;
1307 tme->tm_next = threadmap_hash[hashid];
1308 threadmap_hash[hashid] = tme;
1309 }
1310 }
1311}
1815bff5 1312
8459d725
A
1313void
1314create_tmp_map_entry(uintptr_t thread, uintptr_t pthread)
1315{
1316 threadmap_t tme;
1815bff5 1317
8459d725
A
1318 if ((tme = threadmap_freelist)) {
1319 threadmap_freelist = tme->tm_next;
1320 } else {
1321 tme = malloc(sizeof(struct threadmap));
1322 }
1815bff5 1323
8459d725
A
1324 tme->tm_thread = thread;
1325 tme->tm_pthread = pthread;
1326 tme->tm_command[0] = '\0';
1327 tme->tm_orig_command[0] = '\0';
1815bff5 1328
8459d725
A
1329 tme->tm_next = threadmap_temp;
1330 threadmap_temp = tme;
1331}
1815bff5 1332
8459d725
A
1333threadmap_t
1334find_thread_entry(uintptr_t thread)
1335{
1336 threadmap_t tme;
1815bff5 1337
8459d725 1338 int hashid = thread & HASH_MASK;
1815bff5 1339
8459d725
A
1340 for (tme = threadmap_hash[hashid]; tme; tme = tme->tm_next) {
1341 if (tme->tm_thread == thread) {
1342 return tme;
1343 }
1344 }
1345 return 0;
1346}
1815bff5 1347
8459d725
A
1348void
1349find_thread_name(uintptr_t thread, char **command)
1350{
1351 threadmap_t tme;
1815bff5 1352
8459d725
A
1353 if ((tme = find_thread_entry(thread))) {
1354 *command = tme->tm_command;
1355 } else {
1356 *command = EMPTYSTRING;
1357 }
1358}
1815bff5 1359
8459d725
A
1360void
1361add_thread_entry_to_list(thread_entry_t *list, uintptr_t thread)
1362{
1363 thread_entry_t te;
1815bff5 1364
8459d725
A
1365 if ((te = thread_entry_freelist)) {
1366 thread_entry_freelist = te->te_next;
1367 } else {
1368 te = (thread_entry_t)malloc(sizeof(struct thread_entry));
1369 }
1815bff5 1370
8459d725
A
1371 te->te_thread = thread;
1372 te->te_next = *list;
1373 *list = te;
1374}
1815bff5 1375
8459d725
A
1376void
1377exec_thread_entry(uintptr_t thread, char *command)
1378{
1379 threadmap_t tme;
1815bff5 1380
8459d725
A
1381 if ((tme = find_thread_entry(thread))) {
1382 if (tme->tm_orig_command[0] == '\0') {
1383 (void)strncpy (tme->tm_orig_command, tme->tm_command, MAXCOMLEN);
1384 tme->tm_orig_command[MAXCOMLEN] = '\0';
1385 }
1386 (void)strncpy (tme->tm_command, command, MAXCOMLEN);
1387 tme->tm_command[MAXCOMLEN] = '\0';
1c51fdde 1388
8459d725
A
1389 add_thread_entry_to_list(&thread_reset_list, thread);
1390 } else {
1391 create_map_entry(thread, command);
1392 }
1393}
1c51fdde 1394
8459d725
A
1395void
1396record_thread_entry_for_gc(uintptr_t thread)
1397{
1398 add_thread_entry_to_list(&thread_delete_list, thread);
1399}
1c51fdde 1400
8459d725
A
1401void
1402gc_thread_entries(void)
1403{
1404 thread_entry_t te;
1405 thread_entry_t te_next;
1406 int count = 0;
09fd88e4 1407
8459d725
A
1408 for (te = thread_delete_list; te; te = te_next) {
1409 delete_thread_entry(te->te_thread);
1815bff5 1410
8459d725
A
1411 te_next = te->te_next;
1412 te->te_next = thread_entry_freelist;
1413 thread_entry_freelist = te;
1815bff5 1414
8459d725 1415 count++;
1815bff5 1416 }
8459d725 1417 thread_delete_list = 0;
1815bff5
A
1418}
1419
1420void
8459d725 1421gc_reset_entries(void)
1815bff5 1422{
8459d725
A
1423 thread_entry_t te;
1424 thread_entry_t te_next;
1425 int count = 0;
1815bff5 1426
8459d725
A
1427 for (te = thread_reset_list; te; te = te_next) {
1428 te_next = te->te_next;
1429 te->te_next = thread_entry_freelist;
1430 thread_entry_freelist = te;
1c51fdde 1431
8459d725
A
1432 count++;
1433 }
1434 thread_reset_list = 0;
1815bff5
A
1435}
1436
1815bff5 1437void
8459d725 1438reset_thread_names(void)
1815bff5 1439{
8459d725
A
1440 thread_entry_t te;
1441 thread_entry_t te_next;
1442 int count = 0;
1443
1444 for (te = thread_reset_list; te; te = te_next) {
1445 threadmap_t tme;
1446
1447 if ((tme = find_thread_entry(te->te_thread))) {
1448 if (tme->tm_orig_command[0]) {
1449 (void)strncpy (tme->tm_command, tme->tm_orig_command, MAXCOMLEN);
1450 tme->tm_command[MAXCOMLEN] = '\0';
1451 tme->tm_orig_command[0] = '\0';
1452 }
1453 }
1454 te_next = te->te_next;
1455 te->te_next = thread_entry_freelist;
1456 thread_entry_freelist = te;
83f6dbe8 1457
8459d725
A
1458 count++;
1459 }
1460 thread_reset_list = 0;
1815bff5
A
1461}
1462
1463void
8459d725 1464delete_all_thread_entries(void)
1815bff5 1465{
8459d725
A
1466 threadmap_t tme = 0;
1467 threadmap_t tme_next = 0;
1468 int i;
1469
1470 for (i = 0; i < HASH_SIZE; i++) {
1471 for (tme = threadmap_hash[i]; tme; tme = tme_next) {
1472 tme_next = tme->tm_next;
1473 tme->tm_next = threadmap_freelist;
1474 threadmap_freelist = tme;
1475 }
1476 threadmap_hash[i] = 0;
1477 }
1478}
1815bff5 1479
1815bff5 1480
1815bff5 1481
8459d725
A
1482
1483static void
1a7e3f61 1484insert_run_event(uintptr_t thread, int priority, kd_buf *kd, uint64_t now)
1815bff5 1485{
8459d725 1486 threadrun_t trp;
1815bff5 1487
8459d725 1488 int hashid = thread & HASH_MASK;
1815bff5 1489
8459d725
A
1490 for (trp = threadrun_hash[hashid]; trp; trp = trp->tr_next) {
1491 if (trp->tr_thread == thread) {
1492 break;
1493 }
1494 }
1495 if (trp == NULL) {
1496 if ((trp = threadrun_freelist)) {
1497 threadrun_freelist = trp->tr_next;
1498 } else {
1499 trp = (threadrun_t)malloc(sizeof(struct threadrun));
1500 }
1815bff5 1501
8459d725 1502 trp->tr_thread = thread;
1815bff5 1503
8459d725
A
1504 trp->tr_next = threadrun_hash[hashid];
1505 threadrun_hash[hashid] = trp;
1815bff5 1506
8459d725
A
1507 add_thread_entry_to_list(&thread_run_list, thread);
1508 }
1509 trp->tr_entry = kd;
1510 trp->tr_timestamp = now;
1a7e3f61 1511 trp->tr_priority = priority;
8459d725 1512}
1815bff5 1513
8459d725
A
1514static threadrun_t
1515find_run_event(uintptr_t thread)
1516{
1517 threadrun_t trp;
1518 int hashid = thread & HASH_MASK;
1815bff5 1519
8459d725
A
1520 for (trp = threadrun_hash[hashid]; trp; trp = trp->tr_next) {
1521 if (trp->tr_thread == thread) {
1522 return trp;
1523 }
1815bff5 1524 }
8459d725 1525 return 0;
1815bff5
A
1526}
1527
8459d725
A
1528static void
1529delete_run_event(uintptr_t thread)
1815bff5 1530{
8459d725
A
1531 threadrun_t trp = 0;
1532 threadrun_t trp_prev;
1815bff5 1533
8459d725 1534 int hashid = thread & HASH_MASK;
1815bff5 1535
8459d725
A
1536 if ((trp = threadrun_hash[hashid])) {
1537 if (trp->tr_thread == thread) {
1538 threadrun_hash[hashid] = trp->tr_next;
1539 } else {
1540 trp_prev = trp;
1815bff5 1541
8459d725
A
1542 for (trp = trp->tr_next; trp; trp = trp->tr_next) {
1543 if (trp->tr_thread == thread) {
1544 trp_prev->tr_next = trp->tr_next;
1545 break;
1546 }
1547 trp_prev = trp;
1548 }
1549 }
1550 if (trp) {
1551 trp->tr_next = threadrun_freelist;
1552 threadrun_freelist = trp;
1553 }
1554 }
1555}
b51d5b5f 1556
8459d725
A
1557static void
1558gc_run_events(void) {
1559 thread_entry_t te;
1560 thread_entry_t te_next;
1561 threadrun_t trp;
1562 threadrun_t trp_next;
1563 int count = 0;
1564
1565 for (te = thread_run_list; te; te = te_next) {
1566 int hashid = te->te_thread & HASH_MASK;
1567
1568 for (trp = threadrun_hash[hashid]; trp; trp = trp_next) {
1569 trp_next = trp->tr_next;
1570 trp->tr_next = threadrun_freelist;
1571 threadrun_freelist = trp;
1572 count++;
1573 }
1574 threadrun_hash[hashid] = 0;
b51d5b5f 1575
8459d725
A
1576 te_next = te->te_next;
1577 te->te_next = thread_entry_freelist;
1578 thread_entry_freelist = te;
1815bff5 1579 }
8459d725
A
1580 thread_run_list = 0;
1581}
b51d5b5f 1582
1815bff5 1583
b51d5b5f 1584
8459d725
A
1585static void
1586insert_start_event(uintptr_t thread, int type, uint64_t now)
1587{
1588 event_t evp;
b51d5b5f 1589
8459d725 1590 int hashid = thread & HASH_MASK;
b51d5b5f 1591
8459d725
A
1592 for (evp = event_hash[hashid]; evp; evp = evp->ev_next) {
1593 if (evp->ev_thread == thread && evp->ev_type == type) {
1594 break;
1595 }
1815bff5 1596 }
8459d725
A
1597 if (evp == NULL) {
1598 if ((evp = event_freelist)) {
1599 event_freelist = evp->ev_next;
1600 } else {
1601 evp = (event_t)malloc(sizeof(struct event));
1602 }
b51d5b5f 1603
8459d725
A
1604 evp->ev_thread = thread;
1605 evp->ev_type = type;
1606
1607 evp->ev_next = event_hash[hashid];
1608 event_hash[hashid] = evp;
1609
1610 add_thread_entry_to_list(&thread_event_list, thread);
1611 }
1612 evp->ev_timestamp = now;
1613}
1815bff5 1614
1815bff5 1615
8459d725
A
1616static uint64_t
1617consume_start_event(uintptr_t thread, int type, uint64_t now)
1618{
1619 event_t evp;
1620 event_t evp_prev;
1621 uint64_t elapsed = 0;
1622
1623 int hashid = thread & HASH_MASK;
1624
1625 if ((evp = event_hash[hashid])) {
1626 if (evp->ev_thread == thread && evp->ev_type == type) {
1627 event_hash[hashid] = evp->ev_next;
1628 } else {
1629 evp_prev = evp;
1630
1631 for (evp = evp->ev_next; evp; evp = evp->ev_next) {
1632 if (evp->ev_thread == thread && evp->ev_type == type) {
1633 evp_prev->ev_next = evp->ev_next;
1634 break;
1635 }
1636 evp_prev = evp;
1637 }
1638 }
1639 if (evp) {
1640 elapsed = now - evp->ev_timestamp;
1815bff5 1641
8459d725
A
1642 if (now < evp->ev_timestamp) {
1643 printf("consume: now = %qd, timestamp = %qd\n", now, evp->ev_timestamp);
1644 elapsed = 0;
1645 }
1646 evp->ev_next = event_freelist;
1647 event_freelist = evp;
1815bff5
A
1648 }
1649 }
8459d725
A
1650 return elapsed;
1651}
1815bff5 1652
8459d725
A
1653static void
1654gc_start_events(void)
1655{
1656 thread_entry_t te;
1657 thread_entry_t te_next;
1658 event_t evp;
1659 event_t evp_next;
1660 int count = 0;
1661 int hashid;
1662
1663 for (te = thread_event_list; te; te = te_next) {
1664
1665 hashid = te->te_thread & HASH_MASK;
1666
1667 for (evp = event_hash[hashid]; evp; evp = evp_next) {
1668 evp_next = evp->ev_next;
1669 evp->ev_next = event_freelist;
1670 event_freelist = evp;
1671 count++;
1672 }
1673 event_hash[hashid] = 0;
1815bff5 1674
8459d725
A
1675 te_next = te->te_next;
1676 te->te_next = thread_entry_freelist;
1677 thread_entry_freelist = te;
1678 }
1679 thread_event_list = 0;
1680}
1681
1682int
1683thread_in_user_mode(uintptr_t thread, char *command)
1684{
1685 event_t evp;
1686
1687 if (strcmp(command, "kernel_task") == 0) {
1688 return 0;
1689 }
1690
1691 int hashid = thread & HASH_MASK;
1692
1693 for (evp = event_hash[hashid]; evp; evp = evp->ev_next) {
1694 if (evp->ev_thread == thread) {
1695 return 0;
1696 }
1697 }
1698 return 1;
1699}
1700
1701
1702
1703static lookup_t
1704handle_lookup_event(uintptr_t thread, int debugid, kd_buf *kdp)
1705{
1706 lookup_t lkp;
1707 boolean_t first_record = FALSE;
1708
1709 int hashid = thread & HASH_MASK;
1710
1711 if (debugid & DBG_FUNC_START) {
1712 first_record = TRUE;
1713 }
1714
1715 for (lkp = lookup_hash[hashid]; lkp; lkp = lkp->lk_next) {
1716 if (lkp->lk_thread == thread) {
1717 break;
1718 }
1719 }
1720 if (lkp == NULL) {
1721 if (first_record == FALSE) {
1722 return 0;
1723 }
1724
1725 if ((lkp = lookup_freelist)) {
1726 lookup_freelist = lkp->lk_next;
1727 } else {
1728 lkp = (lookup_t)malloc(sizeof(struct lookup));
1729 }
1730
1731 lkp->lk_thread = thread;
1732
1733 lkp->lk_next = lookup_hash[hashid];
1734 lookup_hash[hashid] = lkp;
1735
1736 add_thread_entry_to_list(&thread_lookup_list, thread);
1737 }
1738
1739 if (first_record == TRUE) {
1740 lkp->lk_pathptr = lkp->lk_pathname;
1741 lkp->lk_dvp = kdp->arg1;
1742 } else {
1743 if (lkp->lk_pathptr > &lkp->lk_pathname[NUMPARMS-4]) {
1744 return lkp;
1745 }
1746 *lkp->lk_pathptr++ = kdp->arg1;
1747 }
1748 *lkp->lk_pathptr++ = kdp->arg2;
1749 *lkp->lk_pathptr++ = kdp->arg3;
1750 *lkp->lk_pathptr++ = kdp->arg4;
1751 *lkp->lk_pathptr = 0;
1752
1753 if (debugid & DBG_FUNC_END) {
1754 return lkp;
1755 }
1756
1757 return 0;
1758}
1759
1760static void
1761delete_lookup_event(uintptr_t thread, lookup_t lkp_to_delete)
1762{
1763 lookup_t lkp;
1764 lookup_t lkp_prev;
1765 int hashid;
1766
1767 hashid = thread & HASH_MASK;
1768
1769 if ((lkp = lookup_hash[hashid])) {
1770 if (lkp == lkp_to_delete) {
1771 lookup_hash[hashid] = lkp->lk_next;
1772 } else {
1773 lkp_prev = lkp;
1774
1775 for (lkp = lkp->lk_next; lkp; lkp = lkp->lk_next) {
1776 if (lkp == lkp_to_delete) {
1777 lkp_prev->lk_next = lkp->lk_next;
1778 break;
1779 }
1780 lkp_prev = lkp;
1781 }
1782 }
1783 if (lkp) {
1784 lkp->lk_next = lookup_freelist;
1785 lookup_freelist = lkp;
1786 }
1787 }
1788}
1789
1790static void
1791gc_lookup_events(void) {
1792 thread_entry_t te;
1793 thread_entry_t te_next;
1794 lookup_t lkp;
1795 lookup_t lkp_next;
1796 int count = 0;
1797 int hashid;
1798
1799 for (te = thread_lookup_list; te; te = te_next) {
1800 hashid = te->te_thread & HASH_MASK;
1801
1802 for (lkp = lookup_hash[hashid]; lkp; lkp = lkp_next) {
1803 lkp_next = lkp->lk_next;
1804 lkp->lk_next = lookup_freelist;
1805 lookup_freelist = lkp;
1806 count++;
1807 }
1808 lookup_hash[hashid] = 0;
1809
1810 te_next = te->te_next;
1811 te->te_next = thread_entry_freelist;
1812 thread_entry_freelist = te;
1813 }
1814 thread_lookup_list = 0;
1815}
1816
1817int
1818sample_sc(void)
1819{
1820 kd_buf *kd, *end_of_sample;
1821 int keep_going = 1;
1822 int count, i;
1823
1824 if (!RAW_flag) {
1825 /*
1826 * Get kernel buffer information
1827 */
1828 get_bufinfo(&bufinfo);
1829 }
1830 if (need_new_map) {
1831 delete_all_thread_entries();
1832 read_command_map();
1833 need_new_map = 0;
1834 }
1835 if (RAW_flag) {
1836 uint32_t bytes_read;
1837
1838 bytes_read = read(RAW_fd, my_buffer, num_entries * sizeof(kd_buf));
1839
1840 if (bytes_read == -1) {
1841 perror("read failed");
1842 exit(2);
1843 }
1844 count = bytes_read / sizeof(kd_buf);
1845
1846 if (count != num_entries) {
1847 keep_going = 0;
1848 }
1849
1850 if (first_read) {
1851 kd = (kd_buf *)my_buffer;
1852 first_now = kd->timestamp & KDBG_TIMESTAMP_MASK;
1853 first_read = 0;
1854 }
1855
1856 } else {
1857 int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDREADTR };
1858 size_t needed = bufinfo.nkdbufs * sizeof(kd_buf);
1859
1860 if (sysctl(mib, ARRAYSIZE(mib), my_buffer, &needed, NULL, 0) < 0) {
1861 quit("trace facility failure, KERN_KDREADTR\n");
1862 }
1863
1864 count = needed;
1865 sample_generation++;
1866
1867 if (bufinfo.flags & KDBG_WRAPPED) {
1868 need_new_map = 1;
1869
1870 if (log_fp) {
1871 fprintf(log_fp, "\n\n%-19.19s sample = %d <<<<<<< trace buffer wrapped >>>>>>>\n\n",
1872 &(ctime(&curr_time)[0]), sample_generation);
1873 }
1874 set_enable(0);
1875 set_enable(1);
1876 }
1877 }
1878 end_of_sample = &((kd_buf *)my_buffer)[count];
1879
1880 /*
1881 * Always reinitialize the DECR_TRAP array
1882 */
1883 for (i = 0; i < num_cpus; i++) {
1884 last_decrementer_kd[i] = (kd_buf *)my_buffer;
1885 }
1886
1887 for (kd = (kd_buf *)my_buffer; kd < end_of_sample; kd++) {
1888 kd_buf *kd_start;
1889 uintptr_t thread = kd->arg5;
1890 int type = kd->debugid & DBG_FUNC_MASK;
1891
1892 (void)check_for_thread_update(thread, type, kd, NULL);
1893
1894 uint64_t now = kd->timestamp & KDBG_TIMESTAMP_MASK;
1895 last_now = now;
1896
1897 if (type == DECR_TRAP) {
1898 int cpunum = CPU_NUMBER(kd);
1899 double i_latency = handle_decrementer(kd, cpunum);
1900
1901 if (log_fp) {
1902 if (i_thresh_hold && (int)i_latency > i_thresh_hold) {
1903 kd_start = last_decrementer_kd[cpunum];
1904
1905 log_decrementer(kd_start, kd, end_of_sample, i_latency);
1906 }
1907 last_decrementer_kd[cpunum] = kd;
1908 }
1909 } else {
1910 double s_latency;
1a7e3f61
A
1911 int s_priority;
1912 if (check_for_scheduler_latency(type, &thread, now, kd, &kd_start, &s_priority, &s_latency)) {
1913 log_scheduler(kd_start, kd, end_of_sample, s_priority, s_latency, thread);
8459d725
A
1914 }
1915 }
1916 }
1917 if (log_fp) {
1918 fflush(log_fp);
1919 }
1920
1921 gc_thread_entries();
1922 gc_reset_entries();
1923 gc_run_events();
1924
1925 return keep_going;
1926}
1927
1928
1929
1930void
1931enter_syscall(FILE *fp, kd_buf *kd, int thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, int print_info)
1932{
1933 char *p;
1934 double timestamp;
1935 double delta;
1936 char pcstring[128];
1937
1938 int cpunum = CPU_NUMBER(kd);
1939
1940 if (print_info && fp) {
1941 timestamp = (double)(now - start_bias) / divisor;
1942 delta = (double)idelta / divisor;
1943
1944 if ((p = find_code(type))) {
1945 if (type == INTERRUPT) {
1946 int mode;
1947
1948 if (kd->arg3) {
1949 mode = USER_MODE;
1950 } else {
1951 mode = KERNEL_MODE;
1952 }
1953
1954 pc_to_string(&pcstring[0], kd->arg2, 58, mode);
1955
fc6d9e4b 1956 fprintf(fp, "%9.1f %8.1f\t\tINTERRUPT[%2lx] @ %-58.58s %8x %2d %s\n",
8459d725
A
1957 timestamp, delta, kd->arg1, &pcstring[0], thread, cpunum, command);
1958 } else if (type == MACH_vmfault) {
fc6d9e4b 1959 fprintf(fp, "%9.1f %8.1f\t\t%-28.28s %8x %2d %s\n",
8459d725
A
1960 timestamp, delta, p, thread, cpunum, command);
1961 } else {
fc6d9e4b 1962 fprintf(fp, "%9.1f %8.1f\t\t%-28.28s %-16lx %-16lx %-16lx %-16lx %8x %2d %s\n",
8459d725
A
1963 timestamp, delta, p, kd->arg1, kd->arg2, kd->arg3, kd->arg4,
1964 thread, cpunum, command);
1965 }
1966 } else {
fc6d9e4b 1967 fprintf(fp, "%9.1f %8.1f\t\t%-8x %-16lx %-16lx %-16lx %-16lx %8x %2d %s\n",
8459d725
A
1968 timestamp, delta, type, kd->arg1, kd->arg2, kd->arg3, kd->arg4,
1969 thread, cpunum, command);
1970 }
1971 }
1972 if (type != BSC_thread_terminate && type != BSC_exit) {
1973 insert_start_event(thread, type, now);
1974 }
1975}
1976
1977
1978void
1979exit_syscall(FILE *fp, kd_buf *kd, int thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, int print_info)
1980{
1981 char *p;
1982 uint64_t user_addr;
1983 double timestamp;
1984 double delta;
1985 double elapsed_timestamp;
1986
1987 elapsed_timestamp = (double)consume_start_event(thread, type, now) / divisor;
1988
1989 if (print_info && fp) {
1990 int cpunum = CPU_NUMBER(kd);
1991
1992 timestamp = (double)(now - start_bias) / divisor;
1993 delta = (double)idelta / divisor;
1994
1995 fprintf(fp, "%9.1f %8.1f(%.1f) \t", timestamp, delta, elapsed_timestamp);
1996
1997 if ((p = find_code(type))) {
1998 if (type == INTERRUPT) {
fc6d9e4b 1999 fprintf(fp, "INTERRUPT %8x %2d %s\n", thread, cpunum, command);
8459d725
A
2000 } else if (type == MACH_vmfault && kd->arg4 <= DBG_PAGEIND_FAULT) {
2001 user_addr = ((uint64_t)kd->arg1 << 32) | (uint32_t)kd->arg2;
2002
fc6d9e4b 2003 fprintf(fp, "%-28.28s %-10.10s %-16qx %8x %2d %s\n",
8459d725
A
2004 p, fault_name[kd->arg4], user_addr,
2005 thread, cpunum, command);
2006 } else {
fc6d9e4b 2007 fprintf(fp, "%-28.28s %-16lx %-16lx %8x %2d %s\n",
8459d725
A
2008 p, kd->arg1, kd->arg2,
2009 thread, cpunum, command);
2010 }
2011 } else {
fc6d9e4b 2012 fprintf(fp, "%-8x %-16lx %-16lx %8x %2d %s\n",
8459d725
A
2013 type, kd->arg1, kd->arg2,
2014 thread, cpunum, command);
2015 }
2016 }
2017}
2018
2019
2020void
2021print_entry(FILE *fp, kd_buf *kd, int thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, kd_buf *kd_note)
2022{
2023 char *p;
2024
2025 if (!fp) {
2026 return;
2027 }
1815bff5 2028
8459d725 2029 int cpunum = CPU_NUMBER(kd);
1815bff5 2030
8459d725
A
2031 double timestamp = (double)(now - start_bias) / divisor;
2032 double delta = (double)idelta / divisor;
2033
2034 if ((p = find_code(type))) {
2035 if (kd == kd_note) {
2036 fprintf(fp, "%9.1f %8.1f\t**\t", timestamp, delta);
2037 } else {
2038 fprintf(fp, "%9.1f %8.1f\t\t", timestamp, delta);
1815bff5 2039 }
fc6d9e4b 2040 fprintf(fp, "%-28.28s %-16lx %-16lx %-16lx %-16lx %8x %2d %s\n",
8459d725
A
2041 p, kd->arg1, kd->arg2, kd->arg3, kd->arg4, thread, cpunum, command);
2042 } else {
fc6d9e4b 2043 fprintf(fp, "%9.1f %8.1f\t\t%-8x %-16lx %-16lx %-16lx %-16lx %8x %2d %s\n",
8459d725
A
2044 timestamp, delta, type, kd->arg1, kd->arg2, kd->arg3, kd->arg4,
2045 thread, cpunum, command);
2046 }
2047}
1815bff5 2048
1815bff5 2049
8459d725
A
2050void
2051check_for_thread_update(uintptr_t thread, int debugid_base, kd_buf *kbufp, char **command)
2052{
2053 if (debugid_base == TRACE_DATA_NEWTHREAD) {
2054 /*
2055 * Save the create thread data
2056 */
2057 create_tmp_map_entry(kbufp->arg1, thread);
2058 } else if (debugid_base == TRACE_STRING_NEWTHREAD) {
2059 /*
2060 * process new map entry
2061 */
2062 find_and_insert_tmp_map_entry(thread, (char *)&kbufp->arg1);
2063 } else if (debugid_base == TRACE_STRING_EXEC) {
2064 exec_thread_entry(thread, (char *)&kbufp->arg1);
2065 } else {
2066 if (debugid_base == BSC_exit || debugid_base == BSC_thread_terminate) {
2067 record_thread_entry_for_gc(thread);
2068 }
2069 if (command) {
2070 find_thread_name(thread, command);
2071 }
2072 }
2073}
1815bff5 2074
8459d725
A
2075
2076void
2077log_info(uint64_t now, uint64_t idelta, uint64_t start_bias, kd_buf *kd, kd_buf *kd_note)
2078{
2079 lookup_t lkp;
2080 int mode;
2081 int reason;
2082 char *p;
2083 char *command;
2084 char *command1;
2085 char command_buf[32];
2086 char sched_info[64];
2087 char pcstring[128];
2088 const char *sched_reason;
2089 double i_latency;
2090 double timestamp;
2091 double delta;
2092 char joe[32];
2093
2094 int thread = kd->arg5;
2095 int cpunum = CPU_NUMBER(kd);
2096 int debugid = kd->debugid;
2097 int type = kd->debugid & DBG_FUNC_MASK;
2098
2099 (void)check_for_thread_update(thread, type, kd, &command);
2100
2101 if ((type >> 24) == DBG_TRACE) {
2102 if (((type >> 16) & 0xff) != DBG_TRACE_INFO) {
2103 return;
2104 }
2105 }
2106 timestamp = (double)(now - start_bias) / divisor;
2107 delta = (double)idelta / divisor;
2108
2109 switch (type) {
1815bff5
A
2110
2111 case CQ_action:
fc6d9e4b 2112 pc_to_string(&pcstring[0], kd->arg1, 84, KERNEL_MODE);
1815bff5 2113
fc6d9e4b 2114 fprintf(log_fp, "%9.1f %8.1f\t\tCQ_action @ %-84.84s %8x %2d %s\n",
8459d725
A
2115 timestamp, delta, &pcstring[0], thread, cpunum, command);
2116 break;
1815bff5 2117
8459d725 2118 case TES_action:
fc6d9e4b 2119 pc_to_string(&pcstring[0], kd->arg1, 83, KERNEL_MODE);
8459d725 2120
fc6d9e4b 2121 fprintf(log_fp, "%9.1f %8.1f\t\tTES_action @ %-83.83s %8x %2d %s\n",
8459d725
A
2122 timestamp, delta, &pcstring[0], thread, cpunum, command);
2123 break;
2124
2125 case IES_action:
fc6d9e4b 2126 pc_to_string(&pcstring[0], kd->arg1, 83, KERNEL_MODE);
8459d725 2127
fc6d9e4b 2128 fprintf(log_fp, "%9.1f %8.1f\t\tIES_action @ %-83.83s %8x %2d %s\n",
8459d725
A
2129 timestamp, delta, &pcstring[0], thread, cpunum, command);
2130 break;
2131
2132 case IES_filter:
fc6d9e4b 2133 pc_to_string(&pcstring[0], kd->arg1, 83, KERNEL_MODE);
1815bff5 2134
fc6d9e4b 2135 fprintf(log_fp, "%9.1f %8.1f\t\tIES_filter @ %-83.83s %8x %2d %s\n",
8459d725
A
2136 timestamp, delta, &pcstring[0], thread, cpunum, command);
2137 break;
1815bff5 2138
8459d725
A
2139 case DECR_TRAP:
2140 if ((int)kd->arg1 >= 0) {
2141 i_latency = 0;
2142 } else {
2143 i_latency = (((double)(-1 - kd->arg1)) / divisor);
2144 }
1815bff5 2145
8459d725
A
2146 if (i_thresh_hold && (int)i_latency > i_thresh_hold) {
2147 p = "*";
2148 } else {
2149 p = " ";
2150 }
1815bff5 2151
8459d725
A
2152 if (kd->arg3) {
2153 mode = USER_MODE;
2154 } else {
2155 mode = KERNEL_MODE;
2156 }
1815bff5 2157
fc6d9e4b 2158 pc_to_string(&pcstring[0], kd->arg2, 84, mode);
1815bff5 2159
fc6d9e4b 2160 fprintf(log_fp, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-84.84s %8x %2d %s\n",
8459d725
A
2161 timestamp, delta, i_latency, p, &pcstring[0], thread, cpunum, command);
2162 break;
2163
2164 case DECR_SET:
fc6d9e4b 2165 fprintf(log_fp, "%9.1f %8.1f[%.1f] \t%-28.28s %8x %2d %s\n",
8459d725
A
2166 timestamp, delta, (double)kd->arg1/divisor, "DECR_SET", thread, cpunum, command);
2167 break;
1815bff5
A
2168
2169 case MACH_sched:
2170 case MACH_stkhandoff:
1815bff5 2171
8459d725
A
2172 find_thread_name(kd->arg2, &command1);
2173
2174 if (command1 == EMPTYSTRING) {
2175 command1 = command_buf;
2176 sprintf(command1, "%-8lx", kd->arg2);
2177 }
2178 if (thread_in_user_mode(kd->arg2, command1)) {
2179 p = "U";
2180 } else {
2181 p = "K";
2182 }
1815bff5 2183
8459d725 2184 reason = kd->arg1;
1815bff5 2185
8459d725
A
2186 if (reason > MAX_REASON) {
2187 sched_reason = "?";
2188 } else {
2189 sched_reason = sched_reasons[reason];
2190 }
1815bff5 2191
8459d725
A
2192 if (sched_reason[0] == '?') {
2193 sprintf(joe, "%x", reason);
2194 sched_reason = joe;
2195 }
fc6d9e4b 2196 sprintf(sched_info, "%16.16s @ pri %3lu --> %16.16s @ pri %3lu%s", command, kd->arg3, command1, kd->arg4, p);
1815bff5 2197
fc6d9e4b 2198 fprintf(log_fp, "%9.1f %8.1f\t\t%-10.10s[%s] %s %8x %2d\n",
8459d725
A
2199 timestamp, delta, "MACH_SCHED", sched_reason, sched_info, thread, cpunum);
2200 break;
1815bff5
A
2201
2202 case VFS_LOOKUP:
8459d725
A
2203 if ((lkp = handle_lookup_event(thread, debugid, kd))) {
2204 /*
2205 * print the tail end of the pathname
2206 */
2207 p = (char *)lkp->lk_pathname;
2208 int clen = strlen(p);
2209
2210 if (clen > 45) {
2211 clen -= 45;
2212 } else {
2213 clen = 0;
2214 }
1815bff5 2215
fc6d9e4b 2216 fprintf(log_fp, "%9.1f %8.1f\t\t%-14.14s %-59s %-16lx %8x %2d %s\n",
8459d725
A
2217 timestamp, delta, "VFS_LOOKUP",
2218 &p[clen], lkp->lk_dvp, thread, cpunum, command);
09fd88e4 2219
8459d725
A
2220 delete_lookup_event(thread, lkp);
2221 }
2222 break;
1c51fdde 2223
8459d725
A
2224 default:
2225 if (debugid & DBG_FUNC_START) {
2226 enter_syscall(log_fp, kd, thread, type, command, now, idelta, start_bias, 1);
2227 } else if (debugid & DBG_FUNC_END) {
2228 exit_syscall(log_fp, kd, thread, type, command, now, idelta, start_bias, 1);
b51d5b5f 2229 } else {
8459d725
A
2230 print_entry(log_fp, kd, thread, type, command, now, idelta, start_bias, kd_note);
2231 }
2232 break;
2233 }
2234}
2235
1c51fdde 2236
1c51fdde 2237
8459d725
A
2238void
2239log_range(kd_buf *kd_buffer, kd_buf *kd_start, kd_buf *kd_stop, kd_buf *kd_note, char *buf1)
2240{
2241 uint64_t last_timestamp = 0;
2242 uint64_t delta = 0;
2243 uint64_t start_bias = 0;
2244 uint64_t now;
2245 kd_buf *kd;
2246 int clen;
2247 char buf2[128];
2248
2249 clen = strlen(buf1);
2250 memset(buf2, '-', clen);
2251 buf2[clen] = 0;
2252 fprintf(log_fp, "\n\n%s\n", buf2);
2253 fprintf(log_fp, "%s\n\n", buf1);
2254
fc6d9e4b 2255 fprintf(log_fp, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
8459d725
A
2256
2257 reset_thread_names();
2258
2259 last_timestamp = kd_start->timestamp & KDBG_TIMESTAMP_MASK;
2260 start_bias = last_timestamp;
2261
2262 for (kd = kd_buffer; kd <= kd_stop; kd++) {
2263 now = kd->timestamp & KDBG_TIMESTAMP_MASK;
2264
2265 if (kd >= kd_start) {
2266 delta = now - last_timestamp;
2267
2268 log_info(now, delta, start_bias, kd, kd_note);
2269
2270 last_timestamp = now;
2271 } else {
2272 int debugid = kd->debugid;
2273 int thread = kd->arg5;
2274 int type = kd->debugid & DBG_FUNC_MASK;
2275
2276 if ((type >> 24) == DBG_TRACE) {
2277 if (((type >> 16) & 0xff) != DBG_TRACE_INFO) {
2278 continue;
2279 }
2280 }
2281 if (type == BSC_thread_terminate || type == BSC_exit) {
b51d5b5f 2282 continue;
8459d725 2283 }
09fd88e4 2284
8459d725
A
2285 if (debugid & DBG_FUNC_START) {
2286 insert_start_event(thread, type, now);
2287 } else if (debugid & DBG_FUNC_END) {
2288 (void)consume_start_event(thread, type, now);
b51d5b5f 2289 }
8459d725
A
2290 }
2291 }
2292 gc_start_events();
2293 gc_lookup_events();
2294}
1815bff5 2295
1815bff5 2296
8459d725
A
2297kd_buf *
2298log_decrementer(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, double i_latency)
2299{
2300 kd_buf *kd_start, *kd_stop;
2301 int kd_count; /* Limit the boundary of kd_start */
2302 uint64_t now;
2303 double sample_timestamp;
2304 char buf1[128];
2305
2306 int thread = kd_beg->arg5;
2307 int cpunum = CPU_NUMBER(kd_end);
2308
2309 for (kd_count = 0, kd_start = kd_beg - 1; (kd_start >= (kd_buf *)my_buffer); kd_start--, kd_count++) {
2310 if (kd_count == MAX_LOG_COUNT) {
2311 break;
2312 }
2313
2314 if (CPU_NUMBER(kd_start) != cpunum) {
2315 continue;
2316 }
2317
2318 if ((kd_start->debugid & DBG_FUNC_MASK) == DECR_TRAP) {
2319 break;
2320 }
2321
2322 if (kd_start->arg5 != thread) {
2323 break;
2324 }
2325 }
2326 if (kd_start < (kd_buf *)my_buffer) {
2327 kd_start = (kd_buf *)my_buffer;
2328 }
2329
2330 thread = kd_end->arg5;
2331
2332 for (kd_stop = kd_end + 1; kd_stop < end_of_sample; kd_stop++) {
2333 if (CPU_NUMBER(kd_stop) != cpunum) {
2334 continue;
2335 }
2336
2337 if ((kd_stop->debugid & DBG_FUNC_MASK) == INTERRUPT) {
2338 break;
2339 }
2340
2341 if (kd_stop->arg5 != thread) {
2342 break;
2343 }
2344 }
2345 if (kd_stop >= end_of_sample) {
2346 kd_stop = end_of_sample - 1;
2347 }
2348
2349 if (RAW_flag) {
2350 time_t TOD_secs;
2351 uint64_t TOD_usecs;
2352
2353 now = kd_start->timestamp & KDBG_TIMESTAMP_MASK;
2354 sample_timestamp = (double)(now - first_now) / divisor;
2355
2356 TOD_usecs = (uint64_t)sample_timestamp;
2357 TOD_secs = sample_TOD_secs + ((sample_TOD_usecs + TOD_usecs) / 1000000);
2358
2359 sprintf(buf1, "%-19.19s interrupt latency = %.1fus [timestamp %.1f]", ctime(&TOD_secs), i_latency, sample_timestamp);
2360 } else {
2361 sprintf(buf1, "%-19.19s interrupt latency = %.1fus [sample %d]", &(ctime(&curr_time)[0]), i_latency, sample_generation);
2362 }
2363
2364 log_range((kd_buf *)my_buffer, kd_start, kd_stop, 0, buf1);
2365
2366 return kd_stop;
2367}
2368
2369
2370void
1a7e3f61 2371log_scheduler(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, int s_priority, double s_latency, uintptr_t thread)
8459d725
A
2372{
2373 kd_buf *kd_start, *kd_stop;
2374 uint64_t now;
fc6d9e4b
A
2375 int count;
2376 int cpunum;
2377 uint64_t cmask = 0;
8459d725
A
2378 double sample_timestamp;
2379 char buf1[128];
2380
fc6d9e4b
A
2381 for (count = 0, kd_start = kd_beg; (kd_start >= (kd_buf *)my_buffer); kd_start--) {
2382 cpunum = CPU_NUMBER(kd_start);
2383
2384 cmask |= ((uint64_t)1 << cpunum);
2385
2386 if (cmask == cpu_mask) {
2387 if (count++ > 100)
2388 break;
8459d725
A
2389 }
2390 }
2391 if (kd_start < (kd_buf *)my_buffer) {
2392 kd_start = (kd_buf *)my_buffer;
2393 }
2394
2395 for (kd_stop = kd_end + 1; kd_stop < end_of_sample; kd_stop++) {
2396 if (kd_stop->arg5 == thread) {
2397 break;
2398 }
2399 }
2400 if (kd_stop >= end_of_sample) {
2401 kd_stop = end_of_sample - 1;
2402 }
2403
2404 if (RAW_flag) {
2405 time_t TOD_secs;
2406 uint64_t TOD_usecs;
2407
2408 now = kd_start->timestamp & KDBG_TIMESTAMP_MASK;
2409 sample_timestamp = (double)(now - first_now) / divisor;
2410
2411 TOD_usecs = (uint64_t)sample_timestamp;
2412 TOD_secs = sample_TOD_secs + ((sample_TOD_usecs + TOD_usecs) / 1000000);
2413
1a7e3f61 2414 sprintf(buf1, "%-19.19s priority = %d, scheduling latency = %.1fus [timestamp %.1f]", ctime(&TOD_secs), s_priority, s_latency, sample_timestamp);
8459d725 2415 } else {
1a7e3f61 2416 sprintf(buf1, "%-19.19s priority = %d, scheduling latency = %.1fus [sample %d]", &(ctime(&curr_time)[0]), s_priority, s_latency, sample_generation);
8459d725
A
2417 }
2418
2419 log_range((kd_buf *)my_buffer, kd_start, kd_stop, kd_beg, buf1);
2420}
2421
2422
2423
2424int
1a7e3f61 2425check_for_scheduler_latency(int type, uintptr_t *thread, uint64_t now, kd_buf *kd, kd_buf **kd_start, int *priority, double *latency)
8459d725
A
2426{
2427 int found_latency = 0;
2428
2429 if (type == MACH_makerunnable) {
1a7e3f61
A
2430 if (watch_priority_min <= kd->arg2 && kd->arg2 <= watch_priority_max) {
2431 insert_run_event(kd->arg1, (int)kd->arg2, kd, now);
8459d725
A
2432 }
2433 } else if (type == MACH_sched || type == MACH_stkhandoff) {
1a7e3f61 2434 threadrun_t trp = find_run_event(kd->arg2);
8459d725
A
2435
2436 if (type == MACH_sched || type == MACH_stkhandoff) {
2437 *thread = kd->arg2;
2438 }
2439
2440 if ((trp = find_run_event(*thread))) {
2441 double d_s_latency = (((double)(now - trp->tr_timestamp)) / divisor);
2442 int s_latency = (int)d_s_latency;
2443
2444 if (s_latency) {
2445 if (s_latency < 100) {
2446 s_usec_10_bins[s_latency/10]++;
2447 }
2448 if (s_latency < 1000) {
2449 s_usec_100_bins[s_latency/100]++;
2450 } else if (s_latency < 10000) {
2451 s_msec_1_bins[s_latency/1000]++;
2452 } else if (s_latency < 50000) {
2453 s_msec_10_bins[s_latency/10000]++;
2454 } else {
2455 s_too_slow++;
2456 }
2457
2458 if (s_latency > s_max_latency) {
2459 s_max_latency = s_latency;
2460 }
2461 if (s_latency < s_min_latency || s_total_samples == 0) {
2462 s_min_latency = s_latency;
2463 }
2464 s_total_latency += s_latency;
2465 s_total_samples++;
2466
2467 if (s_thresh_hold && s_latency > s_thresh_hold) {
2468 s_exceeded_threshold++;
2469
2470 if (log_fp) {
2471 *kd_start = trp->tr_entry;
1a7e3f61 2472 *priority = trp->tr_priority;
8459d725
A
2473 *latency = d_s_latency;
2474 found_latency = 1;
2475 }
2476 }
2477 }
2478 delete_run_event(*thread);
1815bff5
A
2479 }
2480 }
8459d725 2481 return found_latency;
1815bff5
A
2482}
2483
2484
8459d725
A
2485double
2486handle_decrementer(kd_buf *kd, int cpunum)
1815bff5 2487{
8459d725
A
2488 struct i_latencies *il;
2489 double latency;
ef8ad44b 2490 long elapsed_usecs;
1815bff5 2491
8459d725
A
2492 if (i_latency_per_cpu == FALSE) {
2493 cpunum = 0;
2494 }
2495
2496 il = &i_lat[cpunum];
2497
2498 if ((long)(kd->arg1) >= 0) {
2499 latency = 1;
2500 } else {
2501 latency = (((double)(-1 - kd->arg1)) / divisor);
2502 }
ef8ad44b 2503 elapsed_usecs = (long)latency;
1815bff5 2504
8459d725
A
2505 if (elapsed_usecs < 100) {
2506 il->i_usec_10_bins[elapsed_usecs/10]++;
2507 }
2508
2509 if (elapsed_usecs < 1000) {
2510 il->i_usec_100_bins[elapsed_usecs/100]++;
2511 } else if (elapsed_usecs < 10000) {
2512 il->i_msec_1_bins[elapsed_usecs/1000]++;
2513 } else if (elapsed_usecs < 50000) {
2514 il->i_msec_10_bins[elapsed_usecs/10000]++;
2515 } else {
2516 il->i_too_slow++;
2517 }
2518
2519 if (use_high_res_bins && elapsed_usecs < N_HIGH_RES_BINS) {
2520 i_high_res_bins[elapsed_usecs]++;
2521 }
2522 if (i_thresh_hold && elapsed_usecs > i_thresh_hold) {
2523 il->i_exceeded_threshold++;
2524 }
2525 if (elapsed_usecs > il->i_max_latency) {
2526 il->i_max_latency = elapsed_usecs;
2527 }
2528 if (elapsed_usecs < il->i_min_latency || il->i_total_samples == 0) {
2529 il->i_min_latency = elapsed_usecs;
2530 }
2531 il->i_total_latency += elapsed_usecs;
2532 il->i_total_samples++;
2533
2534 return latency;
1815bff5
A
2535}
2536
2537
8459d725
A
2538
2539char *
2540find_code(int type)
2541{
2542 int i;
2543 for (i = 0; i < num_of_codes; i++) {
2544 if (codes_tab[i].type == type) {
2545 return codes_tab[i].name;
2546 }
2547 }
2548 return NULL;
2549}
2550
2551
2552void
2553init_code_file(void)
1815bff5 2554{
8459d725
A
2555 FILE *fp;
2556 int i;
1815bff5 2557
8459d725
A
2558 if ((fp = fopen(code_file, "r")) == NULL) {
2559 if (log_fp) {
2560 fprintf(log_fp, "open of %s failed\n", code_file);
2561 }
2562 return;
1815bff5 2563 }
1815bff5 2564 for (i = 0; i < MAX_ENTRIES; i++) {
8459d725
A
2565 int code;
2566 char name[128];
2567 int n = fscanf(fp, "%x%127s\n", &code, name);
1815bff5 2568
c03df0e9
A
2569 if (n == 1 && i == 0) {
2570 /*
2571 * old code file format, just skip
2572 */
2573 continue;
2574 }
8459d725
A
2575 if (n != 2) {
2576 break;
2577 }
1815bff5
A
2578
2579 strncpy(codes_tab[i].name, name, 32);
2580 codes_tab[i].type = code;
2581 }
2582 num_of_codes = i;
2583
2584 fclose(fp);
2585}
2586
2587
2588void
8459d725 2589do_kernel_nm(void)
1815bff5 2590{
8459d725
A
2591 int i, len;
2592 FILE *fp = NULL;
2593 char tmp_nm_file[128];
2594 char tmpstr[1024];
2595 char inchr;
2596
2597 bzero(tmp_nm_file, 128);
2598 bzero(tmpstr, 1024);
2599
2600 /*
2601 * Build the temporary nm file path
2602 */
2603 strcpy(tmp_nm_file,"/tmp/knm.out.XXXXXX");
2604
2605 if (!mktemp(tmp_nm_file)) {
2606 fprintf(stderr, "Error in mktemp call\n");
2607 return;
2608 }
2609
2610 /*
2611 * Build the nm command and create a tmp file with the output
2612 */
2613 sprintf (tmpstr, "/usr/bin/nm -f -n -s __TEXT __text %s > %s",
2614 kernelpath, tmp_nm_file);
2615 system(tmpstr);
1815bff5 2616
8459d725
A
2617 /*
2618 * Parse the output from the nm command
2619 */
2620 if ((fp = fopen(tmp_nm_file, "r")) == NULL) {
2621 /* Hmmm, let's not treat this as fatal */
2622 fprintf(stderr, "Failed to open nm symbol file [%s]\n", tmp_nm_file);
2623 return;
2624 }
2625 /*
2626 * Count the number of symbols in the nm symbol table
2627 */
2628 kern_sym_count = 0;
2629
2630 while ((inchr = getc(fp)) != -1) {
2631 if (inchr == '\n') {
2632 kern_sym_count++;
2633 }
2634 }
2635 rewind(fp);
2636
2637 /*
2638 * Malloc the space for symbol table
2639 */
2640 if (kern_sym_count > 0) {
2641 kern_sym_tbl = malloc(kern_sym_count * sizeof(kern_sym_t));
2642
2643 if (!kern_sym_tbl) {
2644 /*
2645 * Hmmm, lets not treat this as fatal
2646 */
2647 fprintf(stderr, "Can't allocate memory for kernel symbol table\n");
2648 } else {
2649 bzero(kern_sym_tbl, kern_sym_count * sizeof(kern_sym_t));
2650 }
2651 } else {
2652 /*
2653 * Hmmm, lets not treat this as fatal
2654 */
2655 fprintf(stderr, "No kernel symbol table \n");
2656 }
2657 for (i = 0; i < kern_sym_count; i++) {
2658 bzero(tmpstr, 1024);
2659
2660 if (fscanf(fp, "%p %c %s", &kern_sym_tbl[i].k_sym_addr, &inchr, tmpstr) != 3) {
2661 break;
2662 } else {
2663 len = strlen(tmpstr);
2664 kern_sym_tbl[i].k_sym_name = malloc(len + 1);
2665
2666 if (kern_sym_tbl[i].k_sym_name == NULL) {
2667 fprintf(stderr, "Can't allocate memory for symbol name [%s]\n", tmpstr);
2668 kern_sym_tbl[i].k_sym_name = NULL;
2669 len = 0;
2670 } else {
2671 strcpy(kern_sym_tbl[i].k_sym_name, tmpstr);
2672 }
2673
2674 kern_sym_tbl[i].k_sym_len = len;
2675 }
2676 }
2677 if (i != kern_sym_count) {
2678 /*
2679 * Hmmm, didn't build up entire table from nm
2680 * scrap the entire thing
2681 */
2682 free(kern_sym_tbl);
2683 kern_sym_tbl = NULL;
2684 kern_sym_count = 0;
2685 }
2686 fclose(fp);
1815bff5 2687
8459d725
A
2688 /*
2689 * Remove the temporary nm file
2690 */
2691 unlink(tmp_nm_file);
1815bff5 2692#if 0
8459d725
A
2693 /*
2694 * Dump the kernel symbol table
2695 */
2696 for (i = 0; i < kern_sym_count; i++) {
2697 if (kern_sym_tbl[i].k_sym_name) {
2698 printf ("[%d] %-16p %s\n", i,
2699 kern_sym_tbl[i].k_sym_addr, kern_sym_tbl[i].k_sym_name);
2700 } else {
2701 printf ("[%d] %-16p %s\n", i,
2702 kern_sym_tbl[i].k_sym_addr, "No symbol name");
2703 }
2704 }
1815bff5
A
2705#endif
2706}
2707
8459d725
A
2708void
2709pc_to_string(char *pcstring, uintptr_t pc, int max_len, int mode)
1815bff5 2710{
8459d725
A
2711 int ret;
2712 int len;
2713
2714 if (mode == USER_MODE) {
2715 sprintf(pcstring, "%-16lx [usermode addr]", pc);
2716 return;
2717 }
2718 ret = binary_search(kern_sym_tbl, 0, kern_sym_count-1, pc);
2719
2720 if (ret == -1 || kern_sym_tbl[ret].k_sym_name == NULL) {
2721 sprintf(pcstring, "%-16lx", pc);
2722 return;
2723 }
2724 if ((len = kern_sym_tbl[ret].k_sym_len) > (max_len - 8)) {
2725 len = max_len - 8;
2726 }
2727
2728 memcpy(pcstring, kern_sym_tbl[ret].k_sym_name, len);
2729
2730 sprintf(&pcstring[len], "+0x%-5lx", pc - (uintptr_t)kern_sym_tbl[ret].k_sym_addr);
1815bff5
A
2731}
2732
2733
8459d725
A
2734/*
2735 * Return -1 if not found, else return index
2736 */
2737int
2738binary_search(kern_sym_t *list, int low, int high, uintptr_t addr)
1815bff5 2739{
8459d725 2740 int mid;
1815bff5 2741
8459d725
A
2742 if (kern_sym_count == 0) {
2743 return -1;
2744 }
2745
2746 if (low > high) {
2747 return -1; /* failed */
2748 }
2749
2750 if (low + 1 == high) {
2751 if ((uintptr_t)list[low].k_sym_addr <= addr && addr < (uintptr_t)list[high].k_sym_addr) {
2752 /*
2753 * We have a range match
2754 */
2755 return low;
2756 }
2757 if ((uintptr_t)list[high].k_sym_addr <= addr) {
2758 return high;
2759 }
2760 /*
2761 * Failed
2762 */
2763 return -1;
2764 }
2765 mid = (low + high) / 2;
2766
2767 if (addr < (uintptr_t)list[mid].k_sym_addr) {
2768 return binary_search(list, low, mid, addr);
2769 }
2770
2771 return binary_search(list, mid, high, addr);
1815bff5
A
2772}
2773
8459d725 2774
1815bff5 2775void
8459d725 2776open_logfile(const char *path)
1815bff5 2777{
8459d725
A
2778 log_fp = fopen(path, "a");
2779
2780 if (!log_fp) {
2781 /*
2782 * failed to open path
2783 */
2784 fprintf(stderr, "latency: failed to open logfile [%s]\n", path);
2785 exit_usage();
2786 }
2787}
2788
2789
2790void
2791open_rawfile(const char *path)
2792{
2793 RAW_fd = open(path, O_RDONLY);
2794
2795 if (RAW_fd == -1) {
2796 /*
2797 * failed to open path
2798 */
2799 fprintf(stderr, "latency: failed to open RAWfile [%s]\n", path);
2800 exit_usage();
2801 }
2802}
2803
2804
2805void
2806getdivisor(void)
2807{
2808 mach_timebase_info_data_t info;
2809
2810 (void)mach_timebase_info(&info);
2811
2812 divisor = ((double)info.denom / (double)info.numer) * 1000;
1815bff5 2813}