2 * block queue tracing parse application
4 * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
5 * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <sys/types.h>
39 static char blkparse_version[] = "1.2.0";
42 unsigned long start, end;
43 struct skip_info *prev, *next;
51 unsigned long long events;
52 unsigned long long first_reported_time;
53 unsigned long long last_reported_time;
54 unsigned long long last_read_time;
55 struct io_stats io_stats;
57 unsigned long long seq_skips;
58 unsigned int max_depth[2];
59 unsigned int cur_depth[2];
61 struct rb_root rb_track;
66 unsigned long *cpu_map;
67 unsigned int cpu_map_max;
69 struct per_cpu_info *cpus;
73 * some duplicated effort here, we can unify this hash and the ppi hash later
75 struct process_pid_map {
78 struct process_pid_map *hash_next, *list_next;
81 #define PPM_HASH_SHIFT (8)
82 #define PPM_HASH_SIZE (1 << PPM_HASH_SHIFT)
83 #define PPM_HASH_MASK (PPM_HASH_SIZE - 1)
84 static struct process_pid_map *ppm_hash_table[PPM_HASH_SIZE];
86 struct per_process_info {
87 struct process_pid_map *ppm;
88 struct io_stats io_stats;
89 struct per_process_info *hash_next, *list_next;
95 unsigned long long longest_allocation_wait[2];
96 unsigned long long longest_dispatch_wait[2];
97 unsigned long long longest_completion_wait[2];
100 #define PPI_HASH_SHIFT (8)
101 #define PPI_HASH_SIZE (1 << PPI_HASH_SHIFT)
102 #define PPI_HASH_MASK (PPI_HASH_SIZE - 1)
105 SORT_PROG_EVENT_N, /* Program Name */
106 SORT_PROG_EVENT_QKB, /* KB: Queued read and write */
107 SORT_PROG_EVENT_RKB, /* KB: Queued Read */
108 SORT_PROG_EVENT_WKB, /* KB: Queued Write */
109 SORT_PROG_EVENT_CKB, /* KB: Complete */
110 SORT_PROG_EVENT_QIO, /* IO: Queued read and write */
111 SORT_PROG_EVENT_RIO, /* IO: Queued Read */
112 SORT_PROG_EVENT_WIO, /* IO: Queued Write */
113 SORT_PROG_EVENT_CIO, /* IO: Complete */
116 static struct per_process_info *ppi_hash_table[PPI_HASH_SIZE];
117 static struct per_process_info *ppi_list;
118 static int ppi_list_entries;
120 static struct option l_opts[] = {
123 .has_arg = required_argument,
129 .has_arg = required_argument,
135 .has_arg = required_argument,
140 .name = "input-directory",
141 .has_arg = required_argument,
146 .name = "dump-binary",
147 .has_arg = required_argument,
153 .has_arg = required_argument,
158 .name = "format-spec",
159 .has_arg = required_argument,
164 .name = "hash-by-name",
165 .has_arg = no_argument,
171 .has_arg = required_argument,
177 .has_arg = no_argument,
183 .has_arg = required_argument,
188 .name = "no-text-output",
189 .has_arg = no_argument,
195 .has_arg = no_argument,
200 .name = "per-program-stats",
201 .has_arg = no_argument,
206 .name = "sort-program-stats",
207 .has_arg = required_argument,
213 .has_arg = no_argument,
219 .has_arg = required_argument,
225 .has_arg = no_argument,
231 .has_arg = no_argument,
241 * for sorting the displayed output
244 struct blk_io_trace *bit;
245 struct rb_node rb_node;
247 unsigned long read_sequence;
250 static struct rb_root rb_sort_root;
251 static unsigned long rb_sort_entries;
253 static struct trace *trace_list;
258 static struct blk_io_trace *bit_alloc_list;
259 static struct trace *t_alloc_list;
262 * for tracking individual ios
265 struct rb_node rb_node;
267 struct process_pid_map *ppm;
269 unsigned long long allocation_time;
270 unsigned long long queue_time;
271 unsigned long long dispatch_time;
272 unsigned long long completion_time;
276 static struct per_dev_info *devices;
277 static char *get_dev_name(struct per_dev_info *, char *, int);
278 static int trace_rb_insert_last(struct per_dev_info *, struct trace *);
281 static char *output_name;
282 static char *input_dir;
284 static unsigned long long genesis_time;
285 static unsigned long long last_allowed_time;
286 static unsigned long long stopwatch_start; /* start from zero by default */
287 static unsigned long long stopwatch_end = -1ULL; /* "infinity" */
288 static unsigned long read_sequence;
290 static int per_process_stats;
291 static int per_process_stats_event = SORT_PROG_EVENT_N;
292 static int per_device_and_cpu_stats = 1;
293 static int track_ios;
294 static int ppi_hash_by_pid = 1;
296 static unsigned int act_mask = -1U;
297 static int stats_printed;
298 static int bin_output_msgs = 1;
299 int data_is_native = -1;
301 static FILE *dump_fp;
302 static char *dump_binary;
304 static unsigned int t_alloc_cache;
305 static unsigned int bit_alloc_cache;
307 #define RB_BATCH_DEFAULT (512)
308 static unsigned int rb_batch = RB_BATCH_DEFAULT;
311 static char *pipename;
313 static int text_output = 1;
315 #define is_done() (*(volatile int *)(&done))
316 static volatile int done;
318 struct timespec abs_start_time;
319 static unsigned long long start_timestamp;
321 static int have_drv_data = 0;
323 #define JHASH_RANDOM (0x3af5f2ee)
325 #define CPUS_PER_LONG (8 * sizeof(unsigned long))
326 #define CPU_IDX(cpu) ((cpu) / CPUS_PER_LONG)
327 #define CPU_BIT(cpu) ((cpu) & (CPUS_PER_LONG - 1))
329 static void output_binary(void *buf, int len)
332 size_t n = fwrite(buf, len, 1, dump_fp);
341 static void resize_cpu_info(struct per_dev_info *pdi, int cpu)
343 struct per_cpu_info *cpus = pdi->cpus;
344 int ncpus = pdi->ncpus;
345 int new_count = cpu + 1;
349 size = new_count * sizeof(struct per_cpu_info);
350 cpus = realloc(cpus, size);
353 fprintf(stderr, "Out of memory, CPU info for device %s (%d)\n",
354 get_dev_name(pdi, name, sizeof(name)), size);
358 new_start = (char *)cpus + (ncpus * sizeof(struct per_cpu_info));
359 new_space = (new_count - ncpus) * sizeof(struct per_cpu_info);
360 memset(new_start, 0, new_space);
362 pdi->ncpus = new_count;
365 for (new_count = 0; new_count < pdi->ncpus; new_count++) {
366 struct per_cpu_info *pci = &pdi->cpus[new_count];
370 memset(&pci->rb_last, 0, sizeof(pci->rb_last));
371 pci->rb_last_entries = 0;
372 pci->last_sequence = -1;
377 static struct per_cpu_info *get_cpu_info(struct per_dev_info *pdi, int cpu)
379 struct per_cpu_info *pci;
381 if (cpu >= pdi->ncpus)
382 resize_cpu_info(pdi, cpu);
384 pci = &pdi->cpus[cpu];
390 static int resize_devices(char *name)
392 int size = (ndevices + 1) * sizeof(struct per_dev_info);
394 devices = realloc(devices, size);
396 fprintf(stderr, "Out of memory, device %s (%d)\n", name, size);
399 memset(&devices[ndevices], 0, sizeof(struct per_dev_info));
400 devices[ndevices].name = name;
405 static struct per_dev_info *get_dev_info(dev_t dev)
407 struct per_dev_info *pdi;
410 for (i = 0; i < ndevices; i++) {
412 devices[i].dev = dev;
413 if (devices[i].dev == dev)
417 if (resize_devices(NULL))
420 pdi = &devices[ndevices - 1];
422 pdi->first_reported_time = 0;
423 pdi->last_read_time = 0;
428 static void insert_skip(struct per_cpu_info *pci, unsigned long start,
431 struct skip_info *sip;
433 for (sip = pci->skips_tail; sip != NULL; sip = sip->prev) {
434 if (end == (sip->start - 1)) {
437 } else if (start == (sip->end + 1)) {
443 sip = malloc(sizeof(struct skip_info));
446 sip->prev = sip->next = NULL;
447 if (pci->skips_tail == NULL)
448 pci->skips_head = pci->skips_tail = sip;
450 sip->prev = pci->skips_tail;
451 pci->skips_tail->next = sip;
452 pci->skips_tail = sip;
456 static void remove_sip(struct per_cpu_info *pci, struct skip_info *sip)
458 if (sip->prev == NULL) {
459 if (sip->next == NULL)
460 pci->skips_head = pci->skips_tail = NULL;
462 pci->skips_head = sip->next;
463 sip->next->prev = NULL;
465 } else if (sip->next == NULL) {
466 pci->skips_tail = sip->prev;
467 sip->prev->next = NULL;
469 sip->prev->next = sip->next;
470 sip->next->prev = sip->prev;
473 sip->prev = sip->next = NULL;
477 #define IN_SKIP(sip,seq) (((sip)->start <= (seq)) && ((seq) <= sip->end))
478 static int check_current_skips(struct per_cpu_info *pci, unsigned long seq)
480 struct skip_info *sip;
482 for (sip = pci->skips_tail; sip != NULL; sip = sip->prev) {
483 if (IN_SKIP(sip, seq)) {
484 if (sip->start == seq) {
486 remove_sip(pci, sip);
489 } else if (sip->end == seq)
493 insert_skip(pci, seq + 1, sip->end);
502 static void collect_pdi_skips(struct per_dev_info *pdi)
504 struct skip_info *sip;
510 for (cpu = 0; cpu < pdi->ncpus; cpu++) {
511 struct per_cpu_info *pci = &pdi->cpus[cpu];
513 for (sip = pci->skips_head; sip != NULL; sip = sip->next) {
515 pdi->seq_skips += (sip->end - sip->start + 1);
517 fprintf(stderr,"(%d,%d): skipping %lu -> %lu\n",
518 MAJOR(pdi->dev), MINOR(pdi->dev),
519 sip->start, sip->end);
524 static void cpu_mark_online(struct per_dev_info *pdi, unsigned int cpu)
526 if (cpu >= pdi->cpu_map_max || !pdi->cpu_map) {
527 int new_max = (cpu + CPUS_PER_LONG) & ~(CPUS_PER_LONG - 1);
528 unsigned long *map = malloc(new_max / sizeof(long));
530 memset(map, 0, new_max / sizeof(long));
533 memcpy(map, pdi->cpu_map, pdi->cpu_map_max / sizeof(long));
538 pdi->cpu_map_max = new_max;
541 pdi->cpu_map[CPU_IDX(cpu)] |= (1UL << CPU_BIT(cpu));
544 static inline void cpu_mark_offline(struct per_dev_info *pdi, int cpu)
546 pdi->cpu_map[CPU_IDX(cpu)] &= ~(1UL << CPU_BIT(cpu));
549 static inline int cpu_is_online(struct per_dev_info *pdi, int cpu)
551 return (pdi->cpu_map[CPU_IDX(cpu)] & (1UL << CPU_BIT(cpu))) != 0;
554 static inline int ppm_hash_pid(pid_t pid)
556 return jhash_1word(pid, JHASH_RANDOM) & PPM_HASH_MASK;
559 static struct process_pid_map *find_ppm(pid_t pid)
561 const int hash_idx = ppm_hash_pid(pid);
562 struct process_pid_map *ppm;
564 ppm = ppm_hash_table[hash_idx];
569 ppm = ppm->hash_next;
575 static struct process_pid_map *add_ppm_hash(pid_t pid, const char *name)
577 const int hash_idx = ppm_hash_pid(pid);
578 struct process_pid_map *ppm;
582 ppm = malloc(sizeof(*ppm));
583 memset(ppm, 0, sizeof(*ppm));
585 memset(ppm->comm, 0, sizeof(ppm->comm));
586 strncpy(ppm->comm, name, sizeof(ppm->comm));
587 ppm->comm[sizeof(ppm->comm) - 1] = '\0';
588 ppm->hash_next = ppm_hash_table[hash_idx];
589 ppm_hash_table[hash_idx] = ppm;
595 static void handle_notify(struct blk_io_trace *bit)
597 void *payload = (caddr_t) bit + sizeof(*bit);
600 switch (bit->action) {
602 add_ppm_hash(bit->pid, payload);
605 case BLK_TN_TIMESTAMP:
606 if (bit->pdu_len != sizeof(two32))
608 memcpy(two32, payload, sizeof(two32));
609 if (!data_is_native) {
610 two32[0] = be32_to_cpu(two32[0]);
611 two32[1] = be32_to_cpu(two32[1]);
613 start_timestamp = bit->time;
614 abs_start_time.tv_sec = two32[0];
615 abs_start_time.tv_nsec = two32[1];
616 if (abs_start_time.tv_nsec < 0) {
617 abs_start_time.tv_sec--;
618 abs_start_time.tv_nsec += 1000000000;
624 if (bit->pdu_len > 0) {
625 char msg[bit->pdu_len+1];
627 memcpy(msg, (char *)payload, bit->pdu_len);
628 msg[bit->pdu_len] = '\0';
631 "%3d,%-3d %2d %8s %5d.%09lu %5u %2s %3s %s\n",
632 MAJOR(bit->device), MINOR(bit->device),
633 bit->cpu, "0", (int) SECONDS(bit->time),
634 (unsigned long) NANO_SECONDS(bit->time),
640 /* Ignore unknown notify events */
645 char *find_process_name(pid_t pid)
647 struct process_pid_map *ppm = find_ppm(pid);
655 static inline int ppi_hash_pid(pid_t pid)
657 return jhash_1word(pid, JHASH_RANDOM) & PPI_HASH_MASK;
660 static inline int ppi_hash_name(const char *name)
662 return jhash(name, 16, JHASH_RANDOM) & PPI_HASH_MASK;
665 static inline int ppi_hash(struct per_process_info *ppi)
667 struct process_pid_map *ppm = ppi->ppm;
670 return ppi_hash_pid(ppm->pid);
672 return ppi_hash_name(ppm->comm);
675 static inline void add_ppi_to_hash(struct per_process_info *ppi)
677 const int hash_idx = ppi_hash(ppi);
679 ppi->hash_next = ppi_hash_table[hash_idx];
680 ppi_hash_table[hash_idx] = ppi;
683 static inline void add_ppi_to_list(struct per_process_info *ppi)
685 ppi->list_next = ppi_list;
690 static struct per_process_info *find_ppi_by_name(char *name)
692 const int hash_idx = ppi_hash_name(name);
693 struct per_process_info *ppi;
695 ppi = ppi_hash_table[hash_idx];
697 struct process_pid_map *ppm = ppi->ppm;
699 if (!strcmp(ppm->comm, name))
702 ppi = ppi->hash_next;
708 static struct per_process_info *find_ppi_by_pid(pid_t pid)
710 const int hash_idx = ppi_hash_pid(pid);
711 struct per_process_info *ppi;
713 ppi = ppi_hash_table[hash_idx];
715 struct process_pid_map *ppm = ppi->ppm;
720 ppi = ppi->hash_next;
726 static struct per_process_info *find_ppi(pid_t pid)
728 struct per_process_info *ppi;
732 return find_ppi_by_pid(pid);
734 name = find_process_name(pid);
738 ppi = find_ppi_by_name(name);
739 if (ppi && ppi->ppm->pid != pid)
740 ppi->more_than_one = 1;
746 * struct trace and blktrace allocation cache, we do potentially
747 * millions of mallocs for these structures while only using at most
748 * a few thousand at the time
750 static inline void t_free(struct trace *t)
752 if (t_alloc_cache < 1024) {
753 t->next = t_alloc_list;
760 static inline struct trace *t_alloc(void)
762 struct trace *t = t_alloc_list;
765 t_alloc_list = t->next;
770 return malloc(sizeof(*t));
773 static inline void bit_free(struct blk_io_trace *bit)
775 if (bit_alloc_cache < 1024 && !bit->pdu_len) {
777 * abuse a 64-bit field for a next pointer for the free item
779 bit->time = (__u64) (unsigned long) bit_alloc_list;
780 bit_alloc_list = (struct blk_io_trace *) bit;
786 static inline struct blk_io_trace *bit_alloc(void)
788 struct blk_io_trace *bit = bit_alloc_list;
791 bit_alloc_list = (struct blk_io_trace *) (unsigned long) \
797 return malloc(sizeof(*bit));
800 static inline void __put_trace_last(struct per_dev_info *pdi, struct trace *t)
802 struct per_cpu_info *pci = get_cpu_info(pdi, t->bit->cpu);
804 rb_erase(&t->rb_node, &pci->rb_last);
805 pci->rb_last_entries--;
811 static void put_trace(struct per_dev_info *pdi, struct trace *t)
813 rb_erase(&t->rb_node, &rb_sort_root);
816 trace_rb_insert_last(pdi, t);
819 static inline int trace_rb_insert(struct trace *t, struct rb_root *root)
821 struct rb_node **p = &root->rb_node;
822 struct rb_node *parent = NULL;
828 __t = rb_entry(parent, struct trace, rb_node);
830 if (t->bit->time < __t->bit->time)
832 else if (t->bit->time > __t->bit->time)
834 else if (t->bit->device < __t->bit->device)
836 else if (t->bit->device > __t->bit->device)
838 else if (t->bit->sequence < __t->bit->sequence)
840 else /* >= sequence */
844 rb_link_node(&t->rb_node, parent, p);
845 rb_insert_color(&t->rb_node, root);
849 static inline int trace_rb_insert_sort(struct trace *t)
851 if (!trace_rb_insert(t, &rb_sort_root)) {
859 static int trace_rb_insert_last(struct per_dev_info *pdi, struct trace *t)
861 struct per_cpu_info *pci = get_cpu_info(pdi, t->bit->cpu);
863 if (trace_rb_insert(t, &pci->rb_last))
866 pci->rb_last_entries++;
868 if (pci->rb_last_entries > rb_batch * pdi->nfiles) {
869 struct rb_node *n = rb_first(&pci->rb_last);
871 t = rb_entry(n, struct trace, rb_node);
872 __put_trace_last(pdi, t);
878 static struct trace *trace_rb_find(dev_t device, unsigned long sequence,
879 struct rb_root *root, int order)
881 struct rb_node *n = root->rb_node;
882 struct rb_node *prev = NULL;
886 __t = rb_entry(n, struct trace, rb_node);
889 if (device < __t->bit->device)
891 else if (device > __t->bit->device)
893 else if (sequence < __t->bit->sequence)
895 else if (sequence > __t->bit->sequence)
902 * hack - the list may not be sequence ordered because some
903 * events don't have sequence and time matched. so we end up
904 * being a little off in the rb lookup here, because we don't
905 * know the time we are looking for. compensate by browsing
906 * a little ahead from the last entry to find the match
911 while (((n = rb_next(prev)) != NULL) && max--) {
912 __t = rb_entry(n, struct trace, rb_node);
914 if (__t->bit->device == device &&
915 __t->bit->sequence == sequence)
925 static inline struct trace *trace_rb_find_last(struct per_dev_info *pdi,
926 struct per_cpu_info *pci,
929 return trace_rb_find(pdi->dev, seq, &pci->rb_last, 0);
932 static inline int track_rb_insert(struct per_dev_info *pdi,struct io_track *iot)
934 struct rb_node **p = &pdi->rb_track.rb_node;
935 struct rb_node *parent = NULL;
936 struct io_track *__iot;
940 __iot = rb_entry(parent, struct io_track, rb_node);
942 if (iot->sector < __iot->sector)
944 else if (iot->sector > __iot->sector)
948 "sector alias (%Lu) on device %d,%d!\n",
949 (unsigned long long) iot->sector,
950 MAJOR(pdi->dev), MINOR(pdi->dev));
955 rb_link_node(&iot->rb_node, parent, p);
956 rb_insert_color(&iot->rb_node, &pdi->rb_track);
960 static struct io_track *__find_track(struct per_dev_info *pdi, __u64 sector)
962 struct rb_node *n = pdi->rb_track.rb_node;
963 struct io_track *__iot;
966 __iot = rb_entry(n, struct io_track, rb_node);
968 if (sector < __iot->sector)
970 else if (sector > __iot->sector)
979 static struct io_track *find_track(struct per_dev_info *pdi, pid_t pid,
982 struct io_track *iot;
984 iot = __find_track(pdi, sector);
986 iot = malloc(sizeof(*iot));
987 iot->ppm = find_ppm(pid);
989 iot->ppm = add_ppm_hash(pid, "unknown");
990 iot->sector = sector;
991 track_rb_insert(pdi, iot);
997 static void log_track_frontmerge(struct per_dev_info *pdi,
998 struct blk_io_trace *t)
1000 struct io_track *iot;
1005 iot = __find_track(pdi, t->sector + t_sec(t));
1008 fprintf(stderr, "merge not found for (%d,%d): %llu\n",
1009 MAJOR(pdi->dev), MINOR(pdi->dev),
1010 (unsigned long long) t->sector + t_sec(t));
1014 rb_erase(&iot->rb_node, &pdi->rb_track);
1015 iot->sector -= t_sec(t);
1016 track_rb_insert(pdi, iot);
1019 static void log_track_getrq(struct per_dev_info *pdi, struct blk_io_trace *t)
1021 struct io_track *iot;
1026 iot = find_track(pdi, t->pid, t->sector);
1027 iot->allocation_time = t->time;
1030 static inline int is_remapper(struct per_dev_info *pdi)
1032 int major = MAJOR(pdi->dev);
1034 return (major == 253 || major == 9);
1038 * for md/dm setups, the interesting cycle is Q -> C. So track queueing
1039 * time here, as dispatch time
1041 static void log_track_queue(struct per_dev_info *pdi, struct blk_io_trace *t)
1043 struct io_track *iot;
1047 if (!is_remapper(pdi))
1050 iot = find_track(pdi, t->pid, t->sector);
1051 iot->dispatch_time = t->time;
1055 * return time between rq allocation and insertion
1057 static unsigned long long log_track_insert(struct per_dev_info *pdi,
1058 struct blk_io_trace *t)
1060 unsigned long long elapsed;
1061 struct io_track *iot;
1066 iot = find_track(pdi, t->pid, t->sector);
1067 iot->queue_time = t->time;
1069 if (!iot->allocation_time)
1072 elapsed = iot->queue_time - iot->allocation_time;
1074 if (per_process_stats) {
1075 struct per_process_info *ppi = find_ppi(iot->ppm->pid);
1076 int w = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0;
1078 if (ppi && elapsed > ppi->longest_allocation_wait[w])
1079 ppi->longest_allocation_wait[w] = elapsed;
1086 * return time between queue and issue
1088 static unsigned long long log_track_issue(struct per_dev_info *pdi,
1089 struct blk_io_trace *t)
1091 unsigned long long elapsed;
1092 struct io_track *iot;
1096 if ((t->action & BLK_TC_ACT(BLK_TC_FS)) == 0)
1099 iot = __find_track(pdi, t->sector);
1102 fprintf(stderr, "issue not found for (%d,%d): %llu\n",
1103 MAJOR(pdi->dev), MINOR(pdi->dev),
1104 (unsigned long long) t->sector);
1108 iot->dispatch_time = t->time;
1109 elapsed = iot->dispatch_time - iot->queue_time;
1111 if (per_process_stats) {
1112 struct per_process_info *ppi = find_ppi(iot->ppm->pid);
1113 int w = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0;
1115 if (ppi && elapsed > ppi->longest_dispatch_wait[w])
1116 ppi->longest_dispatch_wait[w] = elapsed;
1123 * return time between dispatch and complete
1125 static unsigned long long log_track_complete(struct per_dev_info *pdi,
1126 struct blk_io_trace *t)
1128 unsigned long long elapsed;
1129 struct io_track *iot;
1134 iot = __find_track(pdi, t->sector);
1137 fprintf(stderr,"complete not found for (%d,%d): %llu\n",
1138 MAJOR(pdi->dev), MINOR(pdi->dev),
1139 (unsigned long long) t->sector);
1143 iot->completion_time = t->time;
1144 elapsed = iot->completion_time - iot->dispatch_time;
1146 if (per_process_stats) {
1147 struct per_process_info *ppi = find_ppi(iot->ppm->pid);
1148 int w = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0;
1150 if (ppi && elapsed > ppi->longest_completion_wait[w])
1151 ppi->longest_completion_wait[w] = elapsed;
1155 * kill the trace, we don't need it after completion
1157 rb_erase(&iot->rb_node, &pdi->rb_track);
1164 static struct io_stats *find_process_io_stats(pid_t pid)
1166 struct per_process_info *ppi = find_ppi(pid);
1169 ppi = malloc(sizeof(*ppi));
1170 memset(ppi, 0, sizeof(*ppi));
1171 ppi->ppm = find_ppm(pid);
1173 ppi->ppm = add_ppm_hash(pid, "unknown");
1174 add_ppi_to_hash(ppi);
1175 add_ppi_to_list(ppi);
1178 return &ppi->io_stats;
1181 static char *get_dev_name(struct per_dev_info *pdi, char *buffer, int size)
1184 snprintf(buffer, size, "%s", pdi->name);
1186 snprintf(buffer, size, "%d,%d",MAJOR(pdi->dev),MINOR(pdi->dev));
1190 static void check_time(struct per_dev_info *pdi, struct blk_io_trace *bit)
1192 unsigned long long this = bit->time;
1193 unsigned long long last = pdi->last_reported_time;
1195 pdi->backwards = (this < last) ? 'B' : ' ';
1196 pdi->last_reported_time = this;
1199 static inline void __account_m(struct io_stats *ios, struct blk_io_trace *t,
1204 ios->mwrite_kb += t_kb(t);
1205 ios->mwrite_b += t_b(t);
1208 ios->mread_kb += t_kb(t);
1209 ios->mread_b += t_b(t);
1213 static inline void account_m(struct blk_io_trace *t, struct per_cpu_info *pci,
1216 __account_m(&pci->io_stats, t, rw);
1218 if (per_process_stats) {
1219 struct io_stats *ios = find_process_io_stats(t->pid);
1221 __account_m(ios, t, rw);
1225 static inline void __account_pc_queue(struct io_stats *ios,
1226 struct blk_io_trace *t, int rw)
1230 ios->qwrite_kb_pc += t_kb(t);
1231 ios->qwrite_b_pc += t_b(t);
1234 ios->qread_kb += t_kb(t);
1235 ios->qread_b_pc += t_b(t);
1239 static inline void account_pc_queue(struct blk_io_trace *t,
1240 struct per_cpu_info *pci, int rw)
1242 __account_pc_queue(&pci->io_stats, t, rw);
1244 if (per_process_stats) {
1245 struct io_stats *ios = find_process_io_stats(t->pid);
1247 __account_pc_queue(ios, t, rw);
1251 static inline void __account_pc_issue(struct io_stats *ios, int rw,
1256 ios->iwrite_kb_pc += bytes >> 10;
1257 ios->iwrite_b_pc += bytes & 1023;
1260 ios->iread_kb_pc += bytes >> 10;
1261 ios->iread_b_pc += bytes & 1023;
1265 static inline void account_pc_issue(struct blk_io_trace *t,
1266 struct per_cpu_info *pci, int rw)
1268 __account_pc_issue(&pci->io_stats, rw, t->bytes);
1270 if (per_process_stats) {
1271 struct io_stats *ios = find_process_io_stats(t->pid);
1273 __account_pc_issue(ios, rw, t->bytes);
1277 static inline void __account_pc_requeue(struct io_stats *ios,
1278 struct blk_io_trace *t, int rw)
1282 ios->iwrite_kb_pc -= t_kb(t);
1283 ios->iwrite_b_pc -= t_b(t);
1286 ios->iread_kb_pc -= t_kb(t);
1287 ios->iread_b_pc -= t_b(t);
1291 static inline void account_pc_requeue(struct blk_io_trace *t,
1292 struct per_cpu_info *pci, int rw)
1294 __account_pc_requeue(&pci->io_stats, t, rw);
1296 if (per_process_stats) {
1297 struct io_stats *ios = find_process_io_stats(t->pid);
1299 __account_pc_requeue(ios, t, rw);
1303 static inline void __account_pc_c(struct io_stats *ios, int rw)
1311 static inline void account_pc_c(struct blk_io_trace *t,
1312 struct per_cpu_info *pci, int rw)
1314 __account_pc_c(&pci->io_stats, rw);
1316 if (per_process_stats) {
1317 struct io_stats *ios = find_process_io_stats(t->pid);
1319 __account_pc_c(ios, rw);
1323 static inline void __account_queue(struct io_stats *ios, struct blk_io_trace *t,
1328 ios->qwrite_kb += t_kb(t);
1329 ios->qwrite_b += t_b(t);
1332 ios->qread_kb += t_kb(t);
1333 ios->qread_b += t_b(t);
1337 static inline void account_queue(struct blk_io_trace *t,
1338 struct per_cpu_info *pci, int rw)
1340 __account_queue(&pci->io_stats, t, rw);
1342 if (per_process_stats) {
1343 struct io_stats *ios = find_process_io_stats(t->pid);
1345 __account_queue(ios, t, rw);
1349 static inline void __account_c(struct io_stats *ios, int rw, int bytes)
1353 ios->cwrite_kb += bytes >> 10;
1354 ios->cwrite_b += bytes & 1023;
1357 ios->cread_kb += bytes >> 10;
1358 ios->cread_b += bytes & 1023;
1362 static inline void account_c(struct blk_io_trace *t, struct per_cpu_info *pci,
1365 __account_c(&pci->io_stats, rw, bytes);
1367 if (per_process_stats) {
1368 struct io_stats *ios = find_process_io_stats(t->pid);
1370 __account_c(ios, rw, bytes);
1374 static inline void __account_issue(struct io_stats *ios, int rw,
1379 ios->iwrite_kb += bytes >> 10;
1380 ios->iwrite_b += bytes & 1023;
1383 ios->iread_kb += bytes >> 10;
1384 ios->iread_b += bytes & 1023;
1388 static inline void account_issue(struct blk_io_trace *t,
1389 struct per_cpu_info *pci, int rw)
1391 __account_issue(&pci->io_stats, rw, t->bytes);
1393 if (per_process_stats) {
1394 struct io_stats *ios = find_process_io_stats(t->pid);
1396 __account_issue(ios, rw, t->bytes);
1400 static inline void __account_unplug(struct io_stats *ios, int timer)
1403 ios->timer_unplugs++;
1408 static inline void account_unplug(struct blk_io_trace *t,
1409 struct per_cpu_info *pci, int timer)
1411 __account_unplug(&pci->io_stats, timer);
1413 if (per_process_stats) {
1414 struct io_stats *ios = find_process_io_stats(t->pid);
1416 __account_unplug(ios, timer);
1420 static inline void __account_requeue(struct io_stats *ios,
1421 struct blk_io_trace *t, int rw)
1425 ios->iwrite_kb -= t_kb(t);
1426 ios->iwrite_b -= t_b(t);
1429 ios->iread_kb -= t_kb(t);
1430 ios->iread_b -= t_b(t);
1434 static inline void account_requeue(struct blk_io_trace *t,
1435 struct per_cpu_info *pci, int rw)
1437 __account_requeue(&pci->io_stats, t, rw);
1439 if (per_process_stats) {
1440 struct io_stats *ios = find_process_io_stats(t->pid);
1442 __account_requeue(ios, t, rw);
1446 static void log_complete(struct per_dev_info *pdi, struct per_cpu_info *pci,
1447 struct blk_io_trace *t, char *act)
1449 process_fmt(act, pci, t, log_track_complete(pdi, t), 0, NULL);
1452 static void log_insert(struct per_dev_info *pdi, struct per_cpu_info *pci,
1453 struct blk_io_trace *t, char *act)
1455 process_fmt(act, pci, t, log_track_insert(pdi, t), 0, NULL);
1458 static void log_queue(struct per_cpu_info *pci, struct blk_io_trace *t,
1461 process_fmt(act, pci, t, -1, 0, NULL);
1464 static void log_issue(struct per_dev_info *pdi, struct per_cpu_info *pci,
1465 struct blk_io_trace *t, char *act)
1467 process_fmt(act, pci, t, log_track_issue(pdi, t), 0, NULL);
1470 static void log_merge(struct per_dev_info *pdi, struct per_cpu_info *pci,
1471 struct blk_io_trace *t, char *act)
1474 log_track_frontmerge(pdi, t);
1476 process_fmt(act, pci, t, -1ULL, 0, NULL);
1479 static void log_action(struct per_cpu_info *pci, struct blk_io_trace *t,
1482 process_fmt(act, pci, t, -1ULL, 0, NULL);
1485 static void log_generic(struct per_cpu_info *pci, struct blk_io_trace *t,
1488 process_fmt(act, pci, t, -1ULL, 0, NULL);
1491 static void log_unplug(struct per_cpu_info *pci, struct blk_io_trace *t,
1494 process_fmt(act, pci, t, -1ULL, 0, NULL);
1497 static void log_split(struct per_cpu_info *pci, struct blk_io_trace *t,
1500 process_fmt(act, pci, t, -1ULL, 0, NULL);
1503 static void log_pc(struct per_cpu_info *pci, struct blk_io_trace *t, char *act)
1505 unsigned char *buf = (unsigned char *) t + sizeof(*t);
1507 process_fmt(act, pci, t, -1ULL, t->pdu_len, buf);
1510 static void dump_trace_pc(struct blk_io_trace *t, struct per_dev_info *pdi,
1511 struct per_cpu_info *pci)
1513 int w = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0;
1514 int act = t->action & 0xffff;
1517 case __BLK_TA_QUEUE:
1518 log_generic(pci, t, "Q");
1519 account_pc_queue(t, pci, w);
1521 case __BLK_TA_GETRQ:
1522 log_generic(pci, t, "G");
1524 case __BLK_TA_SLEEPRQ:
1525 log_generic(pci, t, "S");
1527 case __BLK_TA_REQUEUE:
1529 * can happen if we miss traces, don't let it go
1532 if (pdi->cur_depth[w])
1533 pdi->cur_depth[w]--;
1534 account_pc_requeue(t, pci, w);
1535 log_generic(pci, t, "R");
1537 case __BLK_TA_ISSUE:
1538 account_pc_issue(t, pci, w);
1539 pdi->cur_depth[w]++;
1540 if (pdi->cur_depth[w] > pdi->max_depth[w])
1541 pdi->max_depth[w] = pdi->cur_depth[w];
1542 log_pc(pci, t, "D");
1544 case __BLK_TA_COMPLETE:
1545 if (pdi->cur_depth[w])
1546 pdi->cur_depth[w]--;
1547 log_pc(pci, t, "C");
1548 account_pc_c(t, pci, w);
1550 case __BLK_TA_INSERT:
1551 log_pc(pci, t, "I");
1554 fprintf(stderr, "Bad pc action %x\n", act);
1559 static void dump_trace_fs(struct blk_io_trace *t, struct per_dev_info *pdi,
1560 struct per_cpu_info *pci)
1562 int w = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0;
1563 int act = t->action & 0xffff;
1566 case __BLK_TA_QUEUE:
1567 log_track_queue(pdi, t);
1568 account_queue(t, pci, w);
1569 log_queue(pci, t, "Q");
1571 case __BLK_TA_INSERT:
1572 log_insert(pdi, pci, t, "I");
1574 case __BLK_TA_BACKMERGE:
1575 account_m(t, pci, w);
1576 log_merge(pdi, pci, t, "M");
1578 case __BLK_TA_FRONTMERGE:
1579 account_m(t, pci, w);
1580 log_merge(pdi, pci, t, "F");
1582 case __BLK_TA_GETRQ:
1583 log_track_getrq(pdi, t);
1584 log_generic(pci, t, "G");
1586 case __BLK_TA_SLEEPRQ:
1587 log_generic(pci, t, "S");
1589 case __BLK_TA_REQUEUE:
1591 * can happen if we miss traces, don't let it go
1594 if (pdi->cur_depth[w])
1595 pdi->cur_depth[w]--;
1596 account_requeue(t, pci, w);
1597 log_queue(pci, t, "R");
1599 case __BLK_TA_ISSUE:
1600 account_issue(t, pci, w);
1601 pdi->cur_depth[w]++;
1602 if (pdi->cur_depth[w] > pdi->max_depth[w])
1603 pdi->max_depth[w] = pdi->cur_depth[w];
1604 log_issue(pdi, pci, t, "D");
1606 case __BLK_TA_COMPLETE:
1607 if (pdi->cur_depth[w])
1608 pdi->cur_depth[w]--;
1609 account_c(t, pci, w, t->bytes);
1610 log_complete(pdi, pci, t, "C");
1613 log_action(pci, t, "P");
1615 case __BLK_TA_UNPLUG_IO:
1616 account_unplug(t, pci, 0);
1617 log_unplug(pci, t, "U");
1619 case __BLK_TA_UNPLUG_TIMER:
1620 account_unplug(t, pci, 1);
1621 log_unplug(pci, t, "UT");
1623 case __BLK_TA_SPLIT:
1624 log_split(pci, t, "X");
1626 case __BLK_TA_BOUNCE:
1627 log_generic(pci, t, "B");
1629 case __BLK_TA_REMAP:
1630 log_generic(pci, t, "A");
1632 case __BLK_TA_DRV_DATA:
1634 /* dump to binary file only */
1637 fprintf(stderr, "Bad fs action %x\n", t->action);
1642 static void dump_trace(struct blk_io_trace *t, struct per_cpu_info *pci,
1643 struct per_dev_info *pdi)
1646 if (t->action == BLK_TN_MESSAGE)
1648 else if (t->action & BLK_TC_ACT(BLK_TC_PC))
1649 dump_trace_pc(t, pdi, pci);
1651 dump_trace_fs(t, pdi, pci);
1655 pdi->first_reported_time = t->time;
1659 if (bin_output_msgs ||
1660 !(t->action & BLK_TC_ACT(BLK_TC_NOTIFY) &&
1661 t->action == BLK_TN_MESSAGE))
1662 output_binary(t, sizeof(*t) + t->pdu_len);
1666 * print in a proper way, not too small and not too big. if more than
1667 * 1000,000K, turn into M and so on
1669 static char *size_cnv(char *dst, unsigned long long num, int in_kb)
1671 char suff[] = { '\0', 'K', 'M', 'G', 'P' };
1677 while (num > 1000 * 1000ULL && (i < sizeof(suff) - 1)) {
1682 sprintf(dst, "%'8Lu%c", num, suff[i]);
1686 static void dump_io_stats(struct per_dev_info *pdi, struct io_stats *ios,
1689 static char x[256], y[256];
1691 fprintf(ofp, "%s\n", msg);
1693 fprintf(ofp, " Reads Queued: %s, %siB\t",
1694 size_cnv(x, ios->qreads, 0),
1695 size_cnv(y, ios->qread_kb + (ios->qread_b>>10), 1));
1696 fprintf(ofp, " Writes Queued: %s, %siB\n",
1697 size_cnv(x, ios->qwrites, 0),
1698 size_cnv(y, ios->qwrite_kb + (ios->qwrite_b>>10), 1));
1699 fprintf(ofp, " Read Dispatches: %s, %siB\t",
1700 size_cnv(x, ios->ireads, 0),
1701 size_cnv(y, ios->iread_kb + (ios->iread_b>>10), 1));
1702 fprintf(ofp, " Write Dispatches: %s, %siB\n",
1703 size_cnv(x, ios->iwrites, 0),
1704 size_cnv(y, ios->iwrite_kb + (ios->iwrite_b>>10), 1));
1705 fprintf(ofp, " Reads Requeued: %s\t\t", size_cnv(x, ios->rrqueue, 0));
1706 fprintf(ofp, " Writes Requeued: %s\n", size_cnv(x, ios->wrqueue, 0));
1707 fprintf(ofp, " Reads Completed: %s, %siB\t",
1708 size_cnv(x, ios->creads, 0),
1709 size_cnv(y, ios->cread_kb + (ios->cread_b>>10), 1));
1710 fprintf(ofp, " Writes Completed: %s, %siB\n",
1711 size_cnv(x, ios->cwrites, 0),
1712 size_cnv(y, ios->cwrite_kb + (ios->cwrite_b>>10), 1));
1713 fprintf(ofp, " Read Merges: %s, %siB\t",
1714 size_cnv(x, ios->mreads, 0),
1715 size_cnv(y, ios->mread_kb + (ios->mread_b>>10), 1));
1716 fprintf(ofp, " Write Merges: %s, %siB\n",
1717 size_cnv(x, ios->mwrites, 0),
1718 size_cnv(y, ios->mwrite_kb + (ios->mwrite_b>>10), 1));
1720 fprintf(ofp, " Read depth: %'8u%8c\t", pdi->max_depth[0], ' ');
1721 fprintf(ofp, " Write depth: %'8u\n", pdi->max_depth[1]);
1723 if (ios->qreads_pc || ios->qwrites_pc || ios->ireads_pc || ios->iwrites_pc ||
1724 ios->rrqueue_pc || ios->wrqueue_pc || ios->creads_pc || ios->cwrites_pc) {
1725 fprintf(ofp, " PC Reads Queued: %s, %siB\t",
1726 size_cnv(x, ios->qreads_pc, 0),
1728 ios->qread_kb_pc + (ios->qread_b_pc>>10), 1));
1729 fprintf(ofp, " PC Writes Queued: %s, %siB\n",
1730 size_cnv(x, ios->qwrites_pc, 0),
1732 ios->qwrite_kb_pc + (ios->qwrite_b_pc>>10), 1));
1733 fprintf(ofp, " PC Read Disp.: %s, %siB\t",
1734 size_cnv(x, ios->ireads_pc, 0),
1736 ios->iread_kb_pc + (ios->iread_b_pc>>10), 1));
1737 fprintf(ofp, " PC Write Disp.: %s, %siB\n",
1738 size_cnv(x, ios->iwrites_pc, 0),
1740 ios->iwrite_kb_pc + (ios->iwrite_b_pc>>10),
1742 fprintf(ofp, " PC Reads Req.: %s\t\t", size_cnv(x, ios->rrqueue_pc, 0));
1743 fprintf(ofp, " PC Writes Req.: %s\n", size_cnv(x, ios->wrqueue_pc, 0));
1744 fprintf(ofp, " PC Reads Compl.: %s\t\t", size_cnv(x, ios->creads_pc, 0));
1745 fprintf(ofp, " PC Writes Compl.: %s\n", size_cnv(x, ios->cwrites_pc, 0));
1747 fprintf(ofp, " IO unplugs: %'8lu%8c\t", ios->io_unplugs, ' ');
1748 fprintf(ofp, " Timer unplugs: %'8lu\n", ios->timer_unplugs);
1751 static void dump_wait_stats(struct per_process_info *ppi)
1753 unsigned long rawait = ppi->longest_allocation_wait[0] / 1000;
1754 unsigned long rdwait = ppi->longest_dispatch_wait[0] / 1000;
1755 unsigned long rcwait = ppi->longest_completion_wait[0] / 1000;
1756 unsigned long wawait = ppi->longest_allocation_wait[1] / 1000;
1757 unsigned long wdwait = ppi->longest_dispatch_wait[1] / 1000;
1758 unsigned long wcwait = ppi->longest_completion_wait[1] / 1000;
1760 fprintf(ofp, " Allocation wait: %'8lu%8c\t", rawait, ' ');
1761 fprintf(ofp, " Allocation wait: %'8lu\n", wawait);
1762 fprintf(ofp, " Dispatch wait: %'8lu%8c\t", rdwait, ' ');
1763 fprintf(ofp, " Dispatch wait: %'8lu\n", wdwait);
1764 fprintf(ofp, " Completion wait: %'8lu%8c\t", rcwait, ' ');
1765 fprintf(ofp, " Completion wait: %'8lu\n", wcwait);
1768 static int ppi_name_compare(const void *p1, const void *p2)
1770 struct per_process_info *ppi1 = *((struct per_process_info **) p1);
1771 struct per_process_info *ppi2 = *((struct per_process_info **) p2);
1774 res = strverscmp(ppi1->ppm->comm, ppi2->ppm->comm);
1776 res = ppi1->ppm->pid > ppi2->ppm->pid;
1781 static int ppi_event_compare(const void *p1, const void *p2)
1783 struct per_process_info *ppi1 = *((struct per_process_info **) p1);
1784 struct per_process_info *ppi2 = *((struct per_process_info **) p2);
1785 struct io_stats *ios1 = &ppi1->io_stats;
1786 struct io_stats *ios2 = &ppi2->io_stats;
1787 unsigned long io1, io2;
1788 unsigned long long kb1,kb2;
1794 switch (per_process_stats_event) {
1795 case SORT_PROG_EVENT_QKB: /* KB: Queued read and write */
1796 kb1 = ios1->qwrite_kb + (ios1->qwrite_b>>10) +
1797 ios1->qread_kb + (ios1->qread_b>>10);
1798 kb2 = ios2->qwrite_kb + (ios2->qwrite_b>>10) +
1799 ios2->qread_kb + (ios2->qread_b>>10);
1801 case SORT_PROG_EVENT_RKB: /* KB: Queued Read */
1802 kb1 = ios1->qread_kb + (ios1->qread_b>>10);
1803 kb2 = ios2->qread_kb + (ios2->qread_b>>10);
1805 case SORT_PROG_EVENT_WKB: /* KB: Queued Write */
1806 kb1 = ios1->qwrite_kb + (ios1->qwrite_b>>10);
1807 kb2 = ios2->qwrite_kb + (ios2->qwrite_b>>10);
1809 case SORT_PROG_EVENT_CKB: /* KB: Complete */
1810 kb1 = ios1->cwrite_kb + (ios1->cwrite_b>>10) +
1811 ios1->cread_kb + (ios1->cread_b>>10);
1812 kb2 = ios2->cwrite_kb + (ios2->cwrite_b>>10) +
1813 ios2->cread_kb + (ios2->cread_b>>10);
1815 case SORT_PROG_EVENT_QIO: /* IO: Queued read and write */
1817 io1 = ios1->qreads + ios1->qwrites;
1818 io2 = ios2->qreads + ios2->qwrites;
1820 case SORT_PROG_EVENT_RIO: /* IO: Queued Read */
1825 case SORT_PROG_EVENT_WIO: /* IO: Queued Write */
1827 io1 = ios1->qwrites;
1828 io2 = ios2->qwrites;
1830 case SORT_PROG_EVENT_CIO: /* IO: Complete */
1832 io1 = ios1->creads + ios1->cwrites;
1833 io2 = ios2->creads + ios2->cwrites;
1842 else if (kb1 == kb2)
1850 else if (io1 == io2)
1855 static int ppi_compare(const void *p1, const void *p2)
1857 if (per_process_stats_event == SORT_PROG_EVENT_N)
1858 return ppi_name_compare(p1, p2);
1860 return ppi_event_compare(p1, p2);
1863 static void sort_process_list(void)
1865 struct per_process_info **ppis;
1866 struct per_process_info *ppi;
1869 ppis = malloc(ppi_list_entries * sizeof(struct per_process_info *));
1874 ppi = ppi->list_next;
1877 qsort(ppis, ppi_list_entries, sizeof(ppi), ppi_compare);
1879 i = ppi_list_entries - 1;
1884 ppi->list_next = ppi_list;
1892 static void show_process_stats(void)
1894 struct per_process_info *ppi;
1896 sort_process_list();
1900 struct process_pid_map *ppm = ppi->ppm;
1903 if (ppi->more_than_one)
1904 sprintf(name, "%s (%u, ...)", ppm->comm, ppm->pid);
1906 sprintf(name, "%s (%u)", ppm->comm, ppm->pid);
1908 dump_io_stats(NULL, &ppi->io_stats, name);
1909 dump_wait_stats(ppi);
1910 ppi = ppi->list_next;
1916 static void show_device_and_cpu_stats(void)
1918 struct per_dev_info *pdi;
1919 struct per_cpu_info *pci;
1920 struct io_stats total, *ios;
1921 unsigned long long rrate, wrate, msec;
1922 int i, j, pci_events;
1923 char line[3 + 8/*cpu*/ + 2 + 32/*dev*/ + 3];
1927 for (pdi = devices, i = 0; i < ndevices; i++, pdi++) {
1929 memset(&total, 0, sizeof(total));
1935 for (pci = pdi->cpus, j = 0; j < pdi->ncpus; j++, pci++) {
1939 ios = &pci->io_stats;
1940 total.qreads += ios->qreads;
1941 total.qwrites += ios->qwrites;
1942 total.creads += ios->creads;
1943 total.cwrites += ios->cwrites;
1944 total.mreads += ios->mreads;
1945 total.mwrites += ios->mwrites;
1946 total.ireads += ios->ireads;
1947 total.iwrites += ios->iwrites;
1948 total.rrqueue += ios->rrqueue;
1949 total.wrqueue += ios->wrqueue;
1950 total.qread_kb += ios->qread_kb;
1951 total.qwrite_kb += ios->qwrite_kb;
1952 total.cread_kb += ios->cread_kb;
1953 total.cwrite_kb += ios->cwrite_kb;
1954 total.iread_kb += ios->iread_kb;
1955 total.iwrite_kb += ios->iwrite_kb;
1956 total.mread_kb += ios->mread_kb;
1957 total.mwrite_kb += ios->mwrite_kb;
1958 total.qread_b += ios->qread_b;
1959 total.qwrite_b += ios->qwrite_b;
1960 total.cread_b += ios->cread_b;
1961 total.cwrite_b += ios->cwrite_b;
1962 total.iread_b += ios->iread_b;
1963 total.iwrite_b += ios->iwrite_b;
1964 total.mread_b += ios->mread_b;
1965 total.mwrite_b += ios->mwrite_b;
1967 total.qreads_pc += ios->qreads_pc;
1968 total.qwrites_pc += ios->qwrites_pc;
1969 total.creads_pc += ios->creads_pc;
1970 total.cwrites_pc += ios->cwrites_pc;
1971 total.ireads_pc += ios->ireads_pc;
1972 total.iwrites_pc += ios->iwrites_pc;
1973 total.rrqueue_pc += ios->rrqueue_pc;
1974 total.wrqueue_pc += ios->wrqueue_pc;
1975 total.qread_kb_pc += ios->qread_kb_pc;
1976 total.qwrite_kb_pc += ios->qwrite_kb_pc;
1977 total.iread_kb_pc += ios->iread_kb_pc;
1978 total.iwrite_kb_pc += ios->iwrite_kb_pc;
1979 total.qread_b_pc += ios->qread_b_pc;
1980 total.qwrite_b_pc += ios->qwrite_b_pc;
1981 total.iread_b_pc += ios->iread_b_pc;
1982 total.iwrite_b_pc += ios->iwrite_b_pc;
1984 total.timer_unplugs += ios->timer_unplugs;
1985 total.io_unplugs += ios->io_unplugs;
1987 snprintf(line, sizeof(line) - 1, "CPU%d (%s):",
1988 j, get_dev_name(pdi, name, sizeof(name)));
1989 dump_io_stats(pdi, ios, line);
1993 if (pci_events > 1) {
1995 snprintf(line, sizeof(line) - 1, "Total (%s):",
1996 get_dev_name(pdi, name, sizeof(name)));
1997 dump_io_stats(NULL, &total, line);
2001 msec = (pdi->last_reported_time - pdi->first_reported_time) / 1000000;
2003 rrate = ((1000 * total.cread_kb) + total.cread_b) /
2005 wrate = ((1000 * total.cwrite_kb) + total.cwrite_b) /
2009 fprintf(ofp, "\nThroughput (R/W): %'LuKiB/s / %'LuKiB/s\n",
2011 fprintf(ofp, "Events (%s): %'Lu entries\n",
2012 get_dev_name(pdi, line, sizeof(line)), pdi->events);
2014 collect_pdi_skips(pdi);
2015 if (!pdi->skips && !pdi->events)
2018 ratio = 100.0 * ((double)pdi->seq_skips /
2019 (double)(pdi->events + pdi->seq_skips));
2020 fprintf(ofp, "Skips: %'lu forward (%'llu - %5.1lf%%)\n",
2021 pdi->skips, pdi->seq_skips, ratio);
2025 static void correct_abs_start_time(void)
2027 long delta = genesis_time - start_timestamp;
2029 abs_start_time.tv_sec += SECONDS(delta);
2030 abs_start_time.tv_nsec += NANO_SECONDS(delta);
2031 if (abs_start_time.tv_nsec < 0) {
2032 abs_start_time.tv_nsec += 1000000000;
2033 abs_start_time.tv_sec -= 1;
2035 if (abs_start_time.tv_nsec > 1000000000) {
2036 abs_start_time.tv_nsec -= 1000000000;
2037 abs_start_time.tv_sec += 1;
2041 static void find_genesis(void)
2043 struct trace *t = trace_list;
2045 genesis_time = -1ULL;
2047 if (t->bit->time < genesis_time)
2048 genesis_time = t->bit->time;
2053 /* The time stamp record will usually be the first
2054 * record in the trace, but not always.
2057 && start_timestamp != genesis_time) {
2058 correct_abs_start_time();
2062 static inline int check_stopwatch(struct blk_io_trace *bit)
2064 if (bit->time < stopwatch_end &&
2065 bit->time >= stopwatch_start)
2072 * return youngest entry read
2074 static int sort_entries(unsigned long long *youngest)
2076 struct per_dev_info *pdi = NULL;
2077 struct per_cpu_info *pci = NULL;
2084 while ((t = trace_list) != NULL) {
2085 struct blk_io_trace *bit = t->bit;
2087 trace_list = t->next;
2089 bit->time -= genesis_time;
2091 if (bit->time < *youngest || !*youngest)
2092 *youngest = bit->time;
2094 if (!pdi || pdi->dev != bit->device) {
2095 pdi = get_dev_info(bit->device);
2099 if (!pci || pci->cpu != bit->cpu)
2100 pci = get_cpu_info(pdi, bit->cpu);
2102 if (bit->sequence < pci->smallest_seq_read)
2103 pci->smallest_seq_read = bit->sequence;
2105 if (check_stopwatch(bit)) {
2111 if (trace_rb_insert_sort(t))
2119 * to continue, we must have traces from all online cpus in the tree
2121 static int check_cpu_map(struct per_dev_info *pdi)
2123 unsigned long *cpu_map;
2130 * create a map of the cpus we have traces for
2132 cpu_map = malloc(pdi->cpu_map_max / sizeof(long));
2133 memset(cpu_map, 0, sizeof(*cpu_map));
2134 n = rb_first(&rb_sort_root);
2136 __t = rb_entry(n, struct trace, rb_node);
2137 cpu = __t->bit->cpu;
2139 cpu_map[CPU_IDX(cpu)] |= (1UL << CPU_BIT(cpu));
2144 * we can't continue if pdi->cpu_map has entries set that we don't
2145 * have in the sort rbtree. the opposite is not a problem, though
2148 for (i = 0; i < pdi->cpu_map_max / CPUS_PER_LONG; i++) {
2149 if (pdi->cpu_map[i] & ~(cpu_map[i])) {
2159 static int check_sequence(struct per_dev_info *pdi, struct trace *t, int force)
2161 struct blk_io_trace *bit = t->bit;
2162 unsigned long expected_sequence;
2163 struct per_cpu_info *pci;
2166 pci = get_cpu_info(pdi, bit->cpu);
2167 expected_sequence = pci->last_sequence + 1;
2169 if (!expected_sequence) {
2171 * 1 should be the first entry, just allow it
2173 if (bit->sequence == 1)
2175 if (bit->sequence == pci->smallest_seq_read)
2178 return check_cpu_map(pdi);
2181 if (bit->sequence == expected_sequence)
2185 * we may not have seen that sequence yet. if we are not doing
2186 * the final run, break and wait for more entries.
2188 if (expected_sequence < pci->smallest_seq_read) {
2189 __t = trace_rb_find_last(pdi, pci, expected_sequence);
2193 __put_trace_last(pdi, __t);
2195 } else if (!force) {
2199 if (check_current_skips(pci, bit->sequence))
2202 if (expected_sequence < bit->sequence)
2203 insert_skip(pci, expected_sequence, bit->sequence - 1);
2208 static void show_entries_rb(int force)
2210 struct per_dev_info *pdi = NULL;
2211 struct per_cpu_info *pci = NULL;
2212 struct blk_io_trace *bit;
2216 while ((n = rb_first(&rb_sort_root)) != NULL) {
2217 if (is_done() && !force && !pipeline)
2220 t = rb_entry(n, struct trace, rb_node);
2223 if (read_sequence - t->read_sequence < 1 && !force)
2226 if (!pdi || pdi->dev != bit->device) {
2227 pdi = get_dev_info(bit->device);
2232 fprintf(stderr, "Unknown device ID? (%d,%d)\n",
2233 MAJOR(bit->device), MINOR(bit->device));
2237 if (!(bit->action == BLK_TN_MESSAGE) &&
2238 check_sequence(pdi, t, force))
2241 if (!force && bit->time > last_allowed_time)
2244 check_time(pdi, bit);
2246 if (!pci || pci->cpu != bit->cpu)
2247 pci = get_cpu_info(pdi, bit->cpu);
2249 if (!(bit->action == BLK_TN_MESSAGE))
2250 pci->last_sequence = bit->sequence;
2254 if (bit->action & (act_mask << BLK_TC_SHIFT))
2255 dump_trace(bit, pci, pdi);
2261 static int read_data(int fd, void *buffer, int bytes, int block, int *fdblock)
2263 int ret, bytes_left, fl;
2266 if (block != *fdblock) {
2267 fl = fcntl(fd, F_GETFL);
2271 fcntl(fd, F_SETFL, fl | O_NONBLOCK);
2274 fcntl(fd, F_SETFL, fl & ~O_NONBLOCK);
2280 while (bytes_left > 0) {
2281 ret = read(fd, p, bytes_left);
2285 if (errno != EAGAIN) {
2291 * never do partial reads. we can return if we
2292 * didn't read anything and we should not block,
2293 * otherwise wait for data
2295 if ((bytes_left == bytes) && !block)
2309 static inline __u16 get_pdulen(struct blk_io_trace *bit)
2312 return bit->pdu_len;
2314 return __bswap_16(bit->pdu_len);
2317 static inline __u32 get_magic(struct blk_io_trace *bit)
2322 return __bswap_32(bit->magic);
2325 static int read_events(int fd, int always_block, int *fdblock)
2327 struct per_dev_info *pdi = NULL;
2328 unsigned int events = 0;
2330 while (!is_done() && events < rb_batch) {
2331 struct blk_io_trace *bit;
2333 int pdu_len, should_block, ret;
2338 should_block = !events || always_block;
2340 ret = read_data(fd, bit, sizeof(*bit), should_block, fdblock);
2343 if (!events && ret < 0)
2349 * look at first trace to check whether we need to convert
2350 * data in the future
2352 if (data_is_native == -1 && check_data_endianness(bit->magic))
2355 magic = get_magic(bit);
2356 if ((magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) {
2357 fprintf(stderr, "Bad magic %x\n", magic);
2361 pdu_len = get_pdulen(bit);
2363 void *ptr = realloc(bit, sizeof(*bit) + pdu_len);
2365 if (read_data(fd, ptr + sizeof(*bit), pdu_len, 1, fdblock)) {
2375 if (verify_trace(bit)) {
2381 * not a real trace, so grab and handle it here
2383 if (bit->action & BLK_TC_ACT(BLK_TC_NOTIFY) && bit->action != BLK_TN_MESSAGE) {
2385 output_binary(bit, sizeof(*bit) + bit->pdu_len);
2390 memset(t, 0, sizeof(*t));
2392 t->read_sequence = read_sequence;
2394 t->next = trace_list;
2397 if (!pdi || pdi->dev != bit->device)
2398 pdi = get_dev_info(bit->device);
2400 if (bit->time > pdi->last_read_time)
2401 pdi->last_read_time = bit->time;
2410 * Managing input streams
2414 struct ms_stream *next;
2415 struct trace *first, *last;
2416 struct per_dev_info *pdi;
2420 #define MS_HASH(d, c) ((MAJOR(d) & 0xff) ^ (MINOR(d) & 0xff) ^ (cpu & 0xff))
2422 struct ms_stream *ms_head;
2423 struct ms_stream *ms_hash[256];
2425 static void ms_sort(struct ms_stream *msp);
2426 static int ms_prime(struct ms_stream *msp);
2428 static inline struct trace *ms_peek(struct ms_stream *msp)
2430 return (msp == NULL) ? NULL : msp->first;
2433 static inline __u64 ms_peek_time(struct ms_stream *msp)
2435 return ms_peek(msp)->bit->time;
2438 static inline void ms_resort(struct ms_stream *msp)
2440 if (msp->next && ms_peek_time(msp) > ms_peek_time(msp->next)) {
2441 ms_head = msp->next;
2447 static inline void ms_deq(struct ms_stream *msp)
2449 msp->first = msp->first->next;
2452 if (!ms_prime(msp)) {
2453 ms_head = msp->next;
2462 static void ms_sort(struct ms_stream *msp)
2464 __u64 msp_t = ms_peek_time(msp);
2465 struct ms_stream *this_msp = ms_head;
2467 if (this_msp == NULL)
2469 else if (msp_t < ms_peek_time(this_msp)) {
2470 msp->next = this_msp;
2474 while (this_msp->next && ms_peek_time(this_msp->next) < msp_t)
2475 this_msp = this_msp->next;
2477 msp->next = this_msp->next;
2478 this_msp->next = msp;
2482 static int ms_prime(struct ms_stream *msp)
2487 struct per_dev_info *pdi = msp->pdi;
2488 struct per_cpu_info *pci = get_cpu_info(pdi, msp->cpu);
2489 struct blk_io_trace *bit = NULL;
2490 int ret, pdu_len, ndone = 0;
2492 for (i = 0; !is_done() && pci->fd >= 0 && i < rb_batch; i++) {
2494 ret = read_data(pci->fd, bit, sizeof(*bit), 1, &pci->fdblock);
2498 if (data_is_native == -1 && check_data_endianness(bit->magic))
2501 magic = get_magic(bit);
2502 if ((magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) {
2503 fprintf(stderr, "Bad magic %x\n", magic);
2508 pdu_len = get_pdulen(bit);
2510 void *ptr = realloc(bit, sizeof(*bit) + pdu_len);
2511 ret = read_data(pci->fd, ptr + sizeof(*bit), pdu_len,
2523 if (verify_trace(bit))
2526 if (bit->cpu != pci->cpu) {
2527 fprintf(stderr, "cpu %d trace info has error cpu %d\n",
2528 pci->cpu, bit->cpu);
2532 if (bit->action & BLK_TC_ACT(BLK_TC_NOTIFY) && bit->action != BLK_TN_MESSAGE) {
2534 output_binary(bit, sizeof(*bit) + bit->pdu_len);
2541 if (bit->time > pdi->last_read_time)
2542 pdi->last_read_time = bit->time;
2545 memset(t, 0, sizeof(*t));
2548 if (msp->first == NULL)
2549 msp->first = msp->last = t;
2551 msp->last->next = t;
2561 if (bit) bit_free(bit);
2563 cpu_mark_offline(pdi, pci->cpu);
2570 static struct ms_stream *ms_alloc(struct per_dev_info *pdi, int cpu)
2572 struct ms_stream *msp = malloc(sizeof(*msp));
2575 msp->first = msp->last = NULL;
2585 static int setup_file(struct per_dev_info *pdi, int cpu)
2590 struct per_cpu_info *pci = get_cpu_info(pdi, cpu);
2595 p = strdup(pdi->name);
2597 if (strcmp(dname, ".")) {
2599 p = strdup(pdi->name);
2600 strcpy(pdi->name, basename(p));
2605 len = sprintf(pci->fname, "%s/", input_dir);
2607 snprintf(pci->fname + len, sizeof(pci->fname)-1-len,
2608 "%s.blktrace.%d", pdi->name, pci->cpu);
2609 if (stat(pci->fname, &st) < 0)
2614 pci->fd = open(pci->fname, O_RDONLY);
2620 printf("Input file %s added\n", pci->fname);
2621 cpu_mark_online(pdi, pci->cpu);
2624 ms_alloc(pdi, pci->cpu);
2629 static int handle(struct ms_stream *msp)
2632 struct per_dev_info *pdi;
2633 struct per_cpu_info *pci;
2634 struct blk_io_trace *bit;
2640 pci = get_cpu_info(pdi, msp->cpu);
2642 bit->time -= genesis_time;
2644 if (t->bit->time > stopwatch_end)
2647 pdi->last_reported_time = bit->time;
2648 if ((bit->action & (act_mask << BLK_TC_SHIFT))&&
2649 t->bit->time >= stopwatch_start)
2650 dump_trace(bit, pci, pdi);
2655 trace_rb_insert_last(pdi, t);
2665 * Check if we need to sanitize the name. We allow 'foo', or if foo.blktrace.X
2666 * is given, then strip back down to 'foo' to avoid missing files.
2668 static int name_fixup(char *name)
2675 b = strstr(name, ".blktrace.");
2682 static int do_file(void)
2685 struct per_dev_info *pdi;
2688 * first prepare all files for reading
2690 for (i = 0; i < ndevices; i++) {
2692 ret = name_fixup(pdi->name);
2696 for (cpu = 0; setup_file(pdi, cpu); cpu++)
2700 fprintf(stderr,"No input files found for %s\n",
2707 * Get the initial time stamp
2710 genesis_time = ms_peek_time(ms_head);
2713 * Keep processing traces while any are left
2715 while (!is_done() && ms_head && handle(ms_head))
2721 static void do_pipe(int fd)
2723 unsigned long long youngest;
2724 int events, fdblock;
2726 last_allowed_time = -1ULL;
2728 while ((events = read_events(fd, 0, &fdblock)) > 0) {
2732 smallest_seq_read = -1U;
2735 if (sort_entries(&youngest))
2738 if (youngest > stopwatch_end)
2744 if (rb_sort_entries)
2748 static int do_fifo(void)
2752 if (!strcmp(pipename, "-"))
2753 fd = dup(STDIN_FILENO);
2755 fd = open(pipename, O_RDONLY);
2758 perror("dup stdin");
2767 static void show_stats(void)
2776 if (per_process_stats)
2777 show_process_stats();
2779 if (per_device_and_cpu_stats)
2780 show_device_and_cpu_stats();
2785 static void handle_sigint(__attribute__((__unused__)) int sig)
2791 * Extract start and duration times from a string, allowing
2792 * us to specify a time interval of interest within a trace.
2793 * Format: "duration" (start is zero) or "start:duration".
2795 static int find_stopwatch_interval(char *string)
2800 value = strtod(string, &sp);
2802 fprintf(stderr,"Invalid stopwatch timer: %s\n", string);
2806 stopwatch_start = DOUBLE_TO_NANO_ULL(value);
2808 value = strtod(string, &sp);
2809 if (sp == string || *sp != '\0') {
2810 fprintf(stderr,"Invalid stopwatch duration time: %s\n",
2814 } else if (*sp != '\0') {
2815 fprintf(stderr,"Invalid stopwatch start timer: %s\n", string);
2818 stopwatch_end = DOUBLE_TO_NANO_ULL(value);
2819 if (stopwatch_end <= stopwatch_start) {
2820 fprintf(stderr, "Invalid stopwatch interval: %Lu -> %Lu\n",
2821 stopwatch_start, stopwatch_end);
2828 static int is_pipe(const char *str)
2832 if (!strcmp(str, "-"))
2834 if (!stat(str, &st) && S_ISFIFO(st.st_mode))
2840 static int get_program_sort_event(const char *str)
2846 per_process_stats_event = SORT_PROG_EVENT_N;
2849 per_process_stats_event = SORT_PROG_EVENT_QKB;
2852 per_process_stats_event = SORT_PROG_EVENT_QIO;
2855 per_process_stats_event = SORT_PROG_EVENT_RKB;
2858 per_process_stats_event = SORT_PROG_EVENT_RIO;
2861 per_process_stats_event = SORT_PROG_EVENT_WKB;
2864 per_process_stats_event = SORT_PROG_EVENT_WIO;
2867 per_process_stats_event = SORT_PROG_EVENT_CKB;
2870 per_process_stats_event = SORT_PROG_EVENT_CIO;
2879 #define S_OPTS "a:A:b:D:d:f:F:hi:o:OqsS:tw:vVM"
2880 static char usage_str[] = "\n\n" \
2881 "-i <file> | --input=<file>\n" \
2882 "[ -a <action field> | --act-mask=<action field> ]\n" \
2883 "[ -A <action mask> | --set-mask=<action mask> ]\n" \
2884 "[ -b <traces> | --batch=<traces> ]\n" \
2885 "[ -d <file> | --dump-binary=<file> ]\n" \
2886 "[ -D <dir> | --input-directory=<dir> ]\n" \
2887 "[ -f <format> | --format=<format> ]\n" \
2888 "[ -F <spec> | --format-spec=<spec> ]\n" \
2889 "[ -h | --hash-by-name ]\n" \
2890 "[ -o <file> | --output=<file> ]\n" \
2891 "[ -O | --no-text-output ]\n" \
2892 "[ -q | --quiet ]\n" \
2893 "[ -s | --per-program-stats ]\n" \
2894 "[ -S <event> | --sort-program-stats=<event> ]\n" \
2895 "[ -t | --track-ios ]\n" \
2896 "[ -w <time> | --stopwatch=<time> ]\n" \
2897 "[ -M | --no-msgs\n" \
2898 "[ -v | --verbose ]\n" \
2899 "[ -V | --version ]\n\n" \
2900 "\t-a Only trace specified actions. See documentation\n" \
2901 "\t-A Give trace mask as a single value. See documentation\n" \
2902 "\t-b stdin read batching\n" \
2903 "\t-d Output file. If specified, binary data is written to file\n" \
2904 "\t-D Directory to prepend to input file names\n" \
2905 "\t-f Output format. Customize the output format. The format field\n" \
2906 "\t identifies can be found in the documentation\n" \
2907 "\t-F Format specification. Can be found in the documentation\n" \
2908 "\t-h Hash processes by name, not pid\n" \
2909 "\t-i Input file containing trace data, or '-' for stdin\n" \
2910 "\t-o Output file. If not given, output is stdout\n" \
2911 "\t-O Do NOT output text data\n" \
2912 "\t-q Quiet. Don't display any stats at the end of the trace\n" \
2913 "\t-s Show per-program io statistics\n" \
2914 "\t-S Show per-program io statistics sorted by N/Q/q/R/r/W/w/C/c\n" \
2915 "\t N:Name, Q/q:Queued(read & write), R/r:Queued Read, W/w:Queued Write, C/c:Complete.\n" \
2916 "\t Sort programs by how much data(KB): Q,R,W,C.\n" \
2917 "\t Sort programs by how many IO operations: q,r,w,c.\n" \
2918 "\t if -S was used, the -s parameter will be ignored.\n" \
2919 "\t-t Track individual ios. Will tell you the time a request took\n" \
2920 "\t to get queued, to get dispatched, and to get completed\n" \
2921 "\t-w Only parse data between the given time interval in seconds.\n" \
2922 "\t If 'start' isn't given, blkparse defaults the start time to 0\n" \
2923 "\t-M Do not output messages to binary file\n" \
2924 "\t-v More verbose for marginal errors\n" \
2925 "\t-V Print program version info\n\n";
2927 static void usage(char *prog)
2929 fprintf(stderr, "Usage: %s %s", prog, usage_str);
2932 int main(int argc, char *argv[])
2934 int i, c, ret, mode;
2935 int act_mask_tmp = 0;
2936 char *ofp_buffer = NULL;
2937 char *bin_ofp_buffer = NULL;
2939 while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) != -1) {
2942 i = find_mask_map(optarg);
2944 fprintf(stderr,"Invalid action mask %s\n",
2952 if ((sscanf(optarg, "%x", &i) != 1) ||
2953 !valid_act_opt(i)) {
2955 "Invalid set action mask %s/0x%x\n",
2962 if (is_pipe(optarg) && !pipeline) {
2964 pipename = strdup(optarg);
2965 } else if (resize_devices(optarg) != 0)
2972 output_name = optarg;
2978 rb_batch = atoi(optarg);
2980 rb_batch = RB_BATCH_DEFAULT;
2983 per_process_stats = 1;
2986 per_process_stats = 1;
2987 if (get_program_sort_event(optarg))
2994 per_device_and_cpu_stats = 0;
2997 if (find_stopwatch_interval(optarg) != 0)
3001 set_all_format_specs(optarg);
3004 if (add_format_spec(optarg) != 0)
3008 ppi_hash_by_pid = 0;
3014 printf("%s version %s\n", argv[0], blkparse_version);
3017 dump_binary = optarg;
3020 bin_output_msgs = 0;
3028 while (optind < argc) {
3029 if (is_pipe(argv[optind]) && !pipeline) {
3031 pipename = strdup(argv[optind]);
3032 } else if (resize_devices(argv[optind]) != 0)
3037 if (!pipeline && !ndevices) {
3042 if (act_mask_tmp != 0)
3043 act_mask = act_mask_tmp;
3045 memset(&rb_sort_root, 0, sizeof(rb_sort_root));
3047 signal(SIGINT, handle_sigint);
3048 signal(SIGHUP, handle_sigint);
3049 signal(SIGTERM, handle_sigint);
3051 setlocale(LC_NUMERIC, "en_US");
3055 ofp = fdopen(STDOUT_FILENO, "w");
3058 char ofname[PATH_MAX];
3060 snprintf(ofname, sizeof(ofname) - 1, "%s", output_name);
3061 ofp = fopen(ofname, "w");
3070 ofp_buffer = malloc(4096);
3071 if (setvbuf(ofp, ofp_buffer, mode, 4096)) {
3078 if (!strcmp(dump_binary, "-"))
3081 dump_fp = fopen(dump_binary, "w");
3083 perror(dump_binary);
3088 bin_ofp_buffer = malloc(128 * 1024);
3089 if (setvbuf(dump_fp, bin_ofp_buffer, _IOFBF, 128 * 1024)) {
3090 perror("setvbuf binary");
3103 if (have_drv_data && !dump_binary)
3104 printf("\ndiscarded traces containing low-level device driver "
3105 "specific data (only available in binary output)\n");
3111 if (bin_ofp_buffer) {
3113 free(bin_ofp_buffer);