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