blktrace: don't stop tracer if not setup trace successfully
[blktrace.git] / blkparse.c
index 457e6e7d6c2734f1770d6fc6f8efa661fc350101..227cc444c280660eee4441c0d8e9f7ae80f36b17 100644 (file)
@@ -36,7 +36,7 @@
 #include "rbtree.h"
 #include "jhash.h"
 
-static char blkparse_version[] = "0.99.2";
+static char blkparse_version[] = "1.2.0";
 
 struct skip_info {
        unsigned long start, end;
@@ -104,7 +104,6 @@ static struct per_process_info *ppi_hash_table[PPI_HASH_SIZE];
 static struct per_process_info *ppi_list;
 static int ppi_list_entries;
 
-#define S_OPTS  "a:A:b:D:d:f:F:hi:o:Oqstw:vV"
 static struct option l_opts[] = {
        {
                .name = "act-mask",
@@ -160,6 +159,12 @@ static struct option l_opts[] = {
                .flag = NULL,
                .val = 'i'
        },
+       {
+               .name = "no-msgs",
+               .has_arg = no_argument,
+               .flag = NULL,
+               .val = 'M'
+       },
        {
                .name = "output",
                .has_arg = required_argument,
@@ -270,6 +275,7 @@ static int ppi_hash_by_pid = 1;
 static int verbose;
 static unsigned int act_mask = -1U;
 static int stats_printed;
+static int bin_output_msgs = 1;
 int data_is_native = -1;
 
 static FILE *dump_fp;
@@ -292,6 +298,8 @@ static volatile int done;
 struct timespec                abs_start_time;
 static unsigned long long start_timestamp;
 
+static int have_drv_data = 0;
+
 #define JHASH_RANDOM   (0x3af5f2ee)
 
 #define CPUS_PER_LONG  (8 * sizeof(unsigned long))
@@ -544,7 +552,7 @@ static struct process_pid_map *find_ppm(pid_t pid)
        return NULL;
 }
 
-static void add_ppm_hash(pid_t pid, const char *name)
+static struct process_pid_map *add_ppm_hash(pid_t pid, const char *name)
 {
        const int hash_idx = ppm_hash_pid(pid);
        struct process_pid_map *ppm;
@@ -554,10 +562,14 @@ static void add_ppm_hash(pid_t pid, const char *name)
                ppm = malloc(sizeof(*ppm));
                memset(ppm, 0, sizeof(*ppm));
                ppm->pid = pid;
-               strcpy(ppm->comm, name);
+               memset(ppm->comm, 0, sizeof(ppm->comm));
+               strncpy(ppm->comm, name, sizeof(ppm->comm));
+               ppm->comm[sizeof(ppm->comm) - 1] = '\0';
                ppm->hash_next = ppm_hash_table[hash_idx];
                ppm_hash_table[hash_idx] = ppm;
        }
+
+       return ppm;
 }
 
 static void handle_notify(struct blk_io_trace *bit)
@@ -588,6 +600,22 @@ static void handle_notify(struct blk_io_trace *bit)
 
                break;
 
+       case BLK_TN_MESSAGE:
+               if (bit->pdu_len > 0) {
+                       char msg[bit->pdu_len+1];
+
+                       memcpy(msg, (char *)payload, bit->pdu_len);
+                       msg[bit->pdu_len] = '\0';
+
+                       fprintf(ofp,
+                               "%3d,%-3d %2d %8s %5d.%09lu %5u %2s %3s %s\n",
+                               MAJOR(bit->device), MINOR(bit->device),
+                               bit->cpu, "0", (int) SECONDS(bit->time),
+                               (unsigned long) NANO_SECONDS(bit->time),
+                               0, "m", "N", msg);
+               }
+               break;
+
        default:
                /* Ignore unknown notify events */
                ;
@@ -937,6 +965,8 @@ static struct io_track *find_track(struct per_dev_info *pdi, pid_t pid,
        if (!iot) {
                iot = malloc(sizeof(*iot));
                iot->ppm = find_ppm(pid);
+               if (!iot->ppm)
+                       iot->ppm = add_ppm_hash(pid, "unknown");
                iot->sector = sector;
                track_rb_insert(pdi, iot);
        }
@@ -1119,6 +1149,8 @@ static struct io_stats *find_process_io_stats(pid_t pid)
                ppi = malloc(sizeof(*ppi));
                memset(ppi, 0, sizeof(*ppi));
                ppi->ppm = find_ppm(pid);
+               if (!ppi->ppm)
+                       ppi->ppm = add_ppm_hash(pid, "unknown");
                add_ppi_to_hash(ppi);
                add_ppi_to_list(ppi);
        }
@@ -1150,9 +1182,11 @@ static inline void __account_m(struct io_stats *ios, struct blk_io_trace *t,
        if (rw) {
                ios->mwrites++;
                ios->mwrite_kb += t_kb(t);
+               ios->mwrite_b += t_b(t);
        } else {
                ios->mreads++;
                ios->mread_kb += t_kb(t);
+               ios->mread_b += t_b(t);
        }
 }
 
@@ -1168,15 +1202,115 @@ static inline void account_m(struct blk_io_trace *t, struct per_cpu_info *pci,
        }
 }
 
+static inline void __account_pc_queue(struct io_stats *ios,
+                                     struct blk_io_trace *t, int rw)
+{
+       if (rw) {
+               ios->qwrites_pc++;
+               ios->qwrite_kb_pc += t_kb(t);
+               ios->qwrite_b_pc += t_b(t);
+       } else {
+               ios->qreads_pc++;
+               ios->qread_kb += t_kb(t);
+               ios->qread_b_pc += t_b(t);
+       }
+}
+
+static inline void account_pc_queue(struct blk_io_trace *t,
+                                   struct per_cpu_info *pci, int rw)
+{
+       __account_pc_queue(&pci->io_stats, t, rw);
+
+       if (per_process_stats) {
+               struct io_stats *ios = find_process_io_stats(t->pid);
+
+               __account_pc_queue(ios, t, rw);
+       }
+}
+
+static inline void __account_pc_issue(struct io_stats *ios, int rw,
+                                     unsigned int bytes)
+{
+       if (rw) {
+               ios->iwrites_pc++;
+               ios->iwrite_kb_pc += bytes >> 10;
+               ios->iwrite_b_pc += bytes & 1023;
+       } else {
+               ios->ireads_pc++;
+               ios->iread_kb_pc += bytes >> 10;
+               ios->iread_b_pc += bytes & 1023;
+       }
+}
+
+static inline void account_pc_issue(struct blk_io_trace *t,
+                                   struct per_cpu_info *pci, int rw)
+{
+       __account_pc_issue(&pci->io_stats, rw, t->bytes);
+
+       if (per_process_stats) {
+               struct io_stats *ios = find_process_io_stats(t->pid);
+
+               __account_pc_issue(ios, rw, t->bytes);
+       }
+}
+
+static inline void __account_pc_requeue(struct io_stats *ios,
+                                       struct blk_io_trace *t, int rw)
+{
+       if (rw) {
+               ios->wrqueue_pc++;
+               ios->iwrite_kb_pc -= t_kb(t);
+               ios->iwrite_b_pc -= t_b(t);
+       } else {
+               ios->rrqueue_pc++;
+               ios->iread_kb_pc -= t_kb(t);
+               ios->iread_b_pc -= t_b(t);
+       }
+}
+
+static inline void account_pc_requeue(struct blk_io_trace *t,
+                                     struct per_cpu_info *pci, int rw)
+{
+       __account_pc_requeue(&pci->io_stats, t, rw);
+
+       if (per_process_stats) {
+               struct io_stats *ios = find_process_io_stats(t->pid);
+
+               __account_pc_requeue(ios, t, rw);
+       }
+}
+
+static inline void __account_pc_c(struct io_stats *ios, int rw)
+{
+       if (rw)
+               ios->cwrites_pc++;
+       else
+               ios->creads_pc++;
+}
+
+static inline void account_pc_c(struct blk_io_trace *t,
+                               struct per_cpu_info *pci, int rw)
+{
+       __account_pc_c(&pci->io_stats, rw);
+
+       if (per_process_stats) {
+               struct io_stats *ios = find_process_io_stats(t->pid);
+
+               __account_pc_c(ios, rw);
+       }
+}
+
 static inline void __account_queue(struct io_stats *ios, struct blk_io_trace *t,
                                   int rw)
 {
        if (rw) {
                ios->qwrites++;
                ios->qwrite_kb += t_kb(t);
+               ios->qwrite_b += t_b(t);
        } else {
                ios->qreads++;
                ios->qread_kb += t_kb(t);
+               ios->qread_b += t_b(t);
        }
 }
 
@@ -1197,9 +1331,11 @@ static inline void __account_c(struct io_stats *ios, int rw, int bytes)
        if (rw) {
                ios->cwrites++;
                ios->cwrite_kb += bytes >> 10;
+               ios->cwrite_b += bytes & 1023;
        } else {
                ios->creads++;
                ios->cread_kb += bytes >> 10;
+               ios->cread_b += bytes & 1023;
        }
 }
 
@@ -1221,9 +1357,11 @@ static inline void __account_issue(struct io_stats *ios, int rw,
        if (rw) {
                ios->iwrites++;
                ios->iwrite_kb += bytes >> 10;
+               ios->iwrite_b  += bytes & 1023;
        } else {
                ios->ireads++;
                ios->iread_kb += bytes >> 10;
+               ios->iread_b  += bytes & 1023;
        }
 }
 
@@ -1265,9 +1403,11 @@ static inline void __account_requeue(struct io_stats *ios,
        if (rw) {
                ios->wrqueue++;
                ios->iwrite_kb -= t_kb(t);
+               ios->iwrite_b -= t_b(t);
        } else {
                ios->rrqueue++;
                ios->iread_kb -= t_kb(t);
+               ios->iread_b -= t_b(t);
        }
 }
 
@@ -1347,13 +1487,16 @@ static void log_pc(struct per_cpu_info *pci, struct blk_io_trace *t, char *act)
        process_fmt(act, pci, t, -1ULL, t->pdu_len, buf);
 }
 
-static void dump_trace_pc(struct blk_io_trace *t, struct per_cpu_info *pci)
+static void dump_trace_pc(struct blk_io_trace *t, struct per_dev_info *pdi,
+                         struct per_cpu_info *pci)
 {
+       int w = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0;
        int act = t->action & 0xffff;
 
        switch (act) {
                case __BLK_TA_QUEUE:
                        log_generic(pci, t, "Q");
+                       account_pc_queue(t, pci, w);
                        break;
                case __BLK_TA_GETRQ:
                        log_generic(pci, t, "G");
@@ -1362,13 +1505,27 @@ static void dump_trace_pc(struct blk_io_trace *t, struct per_cpu_info *pci)
                        log_generic(pci, t, "S");
                        break;
                case __BLK_TA_REQUEUE:
+                       /*
+                        * can happen if we miss traces, don't let it go
+                        * below zero
+                        */
+                       if (pdi->cur_depth[w])
+                               pdi->cur_depth[w]--;
+                       account_pc_requeue(t, pci, w);
                        log_generic(pci, t, "R");
                        break;
                case __BLK_TA_ISSUE:
+                       account_pc_issue(t, pci, w);
+                       pdi->cur_depth[w]++;
+                       if (pdi->cur_depth[w] > pdi->max_depth[w])
+                               pdi->max_depth[w] = pdi->cur_depth[w];
                        log_pc(pci, t, "D");
                        break;
                case __BLK_TA_COMPLETE:
+                       if (pdi->cur_depth[w])
+                               pdi->cur_depth[w]--;
                        log_pc(pci, t, "C");
+                       account_pc_c(t, pci, w);
                        break;
                case __BLK_TA_INSERT:
                        log_pc(pci, t, "I");
@@ -1452,6 +1609,10 @@ static void dump_trace_fs(struct blk_io_trace *t, struct per_dev_info *pdi,
                case __BLK_TA_REMAP:
                        log_generic(pci, t, "A");
                        break;
+               case __BLK_TA_DRV_DATA:
+                       have_drv_data = 1;
+                       /* dump to binary file only */
+                       break;
                default:
                        fprintf(stderr, "Bad fs action %x\n", t->action);
                        break;
@@ -1462,8 +1623,10 @@ static void dump_trace(struct blk_io_trace *t, struct per_cpu_info *pci,
                       struct per_dev_info *pdi)
 {
        if (text_output) {
-               if (t->action & BLK_TC_ACT(BLK_TC_PC))
-                       dump_trace_pc(t, pci);
+               if (t->action == BLK_TN_MESSAGE)
+                       handle_notify(t);
+               else if (t->action & BLK_TC_ACT(BLK_TC_PC))
+                       dump_trace_pc(t, pdi, pci);
                else
                        dump_trace_fs(t, pdi, pci);
        }
@@ -1473,7 +1636,10 @@ static void dump_trace(struct blk_io_trace *t, struct per_cpu_info *pci,
 
        pdi->events++;
 
-       output_binary(t, sizeof(*t) + t->pdu_len);
+       if (bin_output_msgs ||
+                           !(t->action & BLK_TC_ACT(BLK_TC_NOTIFY) &&
+                             t->action == BLK_TN_MESSAGE))
+               output_binary(t, sizeof(*t) + t->pdu_len);
 }
 
 /*
@@ -1504,20 +1670,60 @@ static void dump_io_stats(struct per_dev_info *pdi, struct io_stats *ios,
 
        fprintf(ofp, "%s\n", msg);
 
-       fprintf(ofp, " Reads Queued:    %s, %siB\t", size_cnv(x, ios->qreads, 0), size_cnv(y, ios->qread_kb, 1));
-       fprintf(ofp, " Writes Queued:    %s, %siB\n", size_cnv(x, ios->qwrites, 0), size_cnv(y, ios->qwrite_kb, 1));
-       fprintf(ofp, " Read Dispatches: %s, %siB\t", size_cnv(x, ios->ireads, 0), size_cnv(y, ios->iread_kb, 1));
-       fprintf(ofp, " Write Dispatches: %s, %siB\n", size_cnv(x, ios->iwrites, 0), size_cnv(y, ios->iwrite_kb, 1));
+       fprintf(ofp, " Reads Queued:    %s, %siB\t",
+                       size_cnv(x, ios->qreads, 0),
+                       size_cnv(y, ios->qread_kb + (ios->qread_b>>10), 1));
+       fprintf(ofp, " Writes Queued:    %s, %siB\n",
+                       size_cnv(x, ios->qwrites, 0),
+                       size_cnv(y, ios->qwrite_kb + (ios->qwrite_b>>10), 1));
+       fprintf(ofp, " Read Dispatches: %s, %siB\t",
+                       size_cnv(x, ios->ireads, 0),
+                       size_cnv(y, ios->iread_kb + (ios->iread_b>>10), 1));
+       fprintf(ofp, " Write Dispatches: %s, %siB\n",
+                       size_cnv(x, ios->iwrites, 0),
+                       size_cnv(y, ios->iwrite_kb + (ios->iwrite_b>>10), 1));
        fprintf(ofp, " Reads Requeued:  %s\t\t", size_cnv(x, ios->rrqueue, 0));
        fprintf(ofp, " Writes Requeued:  %s\n", size_cnv(x, ios->wrqueue, 0));
-       fprintf(ofp, " Reads Completed: %s, %siB\t", size_cnv(x, ios->creads, 0), size_cnv(y, ios->cread_kb, 1));
-       fprintf(ofp, " Writes Completed: %s, %siB\n", size_cnv(x, ios->cwrites, 0), size_cnv(y, ios->cwrite_kb, 1));
-       fprintf(ofp, " Read Merges:     %s, %siB\t", size_cnv(x, ios->mreads, 0), size_cnv(y, ios->mread_kb, 1));
-       fprintf(ofp, " Write Merges:     %s, %siB\n", size_cnv(x, ios->mwrites, 0), size_cnv(y, ios->mwrite_kb, 1));
+       fprintf(ofp, " Reads Completed: %s, %siB\t",
+                       size_cnv(x, ios->creads, 0),
+                       size_cnv(y, ios->cread_kb + (ios->cread_b>>10), 1));
+       fprintf(ofp, " Writes Completed: %s, %siB\n",
+                       size_cnv(x, ios->cwrites, 0),
+                       size_cnv(y, ios->cwrite_kb + (ios->cwrite_b>>10), 1));
+       fprintf(ofp, " Read Merges:     %s, %siB\t",
+                       size_cnv(x, ios->mreads, 0),
+                       size_cnv(y, ios->mread_kb + (ios->mread_b>>10), 1));
+       fprintf(ofp, " Write Merges:     %s, %siB\n",
+                       size_cnv(x, ios->mwrites, 0),
+                       size_cnv(y, ios->mwrite_kb + (ios->mwrite_b>>10), 1));
        if (pdi) {
                fprintf(ofp, " Read depth:      %'8u%8c\t", pdi->max_depth[0], ' ');
                fprintf(ofp, " Write depth:      %'8u\n", pdi->max_depth[1]);
        }
+       if (ios->qreads_pc || ios->qwrites_pc || ios->ireads_pc || ios->iwrites_pc ||
+           ios->rrqueue_pc || ios->wrqueue_pc || ios->creads_pc || ios->cwrites_pc) {
+               fprintf(ofp, " PC Reads Queued: %s, %siB\t",
+                       size_cnv(x, ios->qreads_pc, 0),
+                       size_cnv(y,
+                               ios->qread_kb_pc + (ios->qread_b_pc>>10), 1));
+               fprintf(ofp, " PC Writes Queued: %s, %siB\n",
+                       size_cnv(x, ios->qwrites_pc, 0),
+                       size_cnv(y,
+                               ios->qwrite_kb_pc + (ios->qwrite_b_pc>>10), 1));
+               fprintf(ofp, " PC Read Disp.:   %s, %siB\t",
+                       size_cnv(x, ios->ireads_pc, 0),
+                       size_cnv(y,
+                               ios->iread_kb_pc + (ios->iread_b_pc>>10), 1));
+               fprintf(ofp, " PC Write Disp.:   %s, %siB\n",
+                       size_cnv(x, ios->iwrites_pc, 0),
+                       size_cnv(y,
+                               ios->iwrite_kb_pc + (ios->iwrite_b_pc>>10),
+                               1));
+               fprintf(ofp, " PC Reads Req.:   %s\t\t", size_cnv(x, ios->rrqueue_pc, 0));
+               fprintf(ofp, " PC Writes Req.:   %s\n", size_cnv(x, ios->wrqueue_pc, 0));
+               fprintf(ofp, " PC Reads Compl.: %s\t\t", size_cnv(x, ios->creads_pc, 0));
+               fprintf(ofp, " PC Writes Compl.: %s\n", size_cnv(x, ios->cwrites_pc, 0));
+       }
        fprintf(ofp, " IO unplugs:      %'8lu%8c\t", ios->io_unplugs, ' ');
        fprintf(ofp, " Timer unplugs:    %'8lu\n", ios->timer_unplugs);
 }
@@ -1647,6 +1853,32 @@ static void show_device_and_cpu_stats(void)
                        total.iwrite_kb += ios->iwrite_kb;
                        total.mread_kb += ios->mread_kb;
                        total.mwrite_kb += ios->mwrite_kb;
+                       total.qread_b += ios->qread_b;
+                       total.qwrite_b += ios->qwrite_b;
+                       total.cread_b += ios->cread_b;
+                       total.cwrite_b += ios->cwrite_b;
+                       total.iread_b += ios->iread_b;
+                       total.iwrite_b += ios->iwrite_b;
+                       total.mread_b += ios->mread_b;
+                       total.mwrite_b += ios->mwrite_b;
+
+                       total.qreads_pc += ios->qreads_pc;
+                       total.qwrites_pc += ios->qwrites_pc;
+                       total.creads_pc += ios->creads_pc;
+                       total.cwrites_pc += ios->cwrites_pc;
+                       total.ireads_pc += ios->ireads_pc;
+                       total.iwrites_pc += ios->iwrites_pc;
+                       total.rrqueue_pc += ios->rrqueue_pc;
+                       total.wrqueue_pc += ios->wrqueue_pc;
+                       total.qread_kb_pc += ios->qread_kb_pc;
+                       total.qwrite_kb_pc += ios->qwrite_kb_pc;
+                       total.iread_kb_pc += ios->iread_kb_pc;
+                       total.iwrite_kb_pc += ios->iwrite_kb_pc;
+                       total.qread_b_pc += ios->qread_b_pc;
+                       total.qwrite_b_pc += ios->qwrite_b_pc;
+                       total.iread_b_pc += ios->iread_b_pc;
+                       total.iwrite_b_pc += ios->iwrite_b_pc;
+
                        total.timer_unplugs += ios->timer_unplugs;
                        total.io_unplugs += ios->io_unplugs;
 
@@ -1666,8 +1898,10 @@ static void show_device_and_cpu_stats(void)
                wrate = rrate = 0;
                msec = (pdi->last_reported_time - pdi->first_reported_time) / 1000000;
                if (msec) {
-                       rrate = 1000 * total.cread_kb / msec;
-                       wrate = 1000 * total.cwrite_kb / msec;
+                       rrate = ((1000 * total.cread_kb) + total.cread_b) /
+                                                                       msec;
+                       wrate = ((1000 * total.cwrite_kb) + total.cwrite_b) /
+                                                                       msec;
                }
 
                fprintf(ofp, "\nThroughput (R/W): %'LuKiB/s / %'LuKiB/s\n",
@@ -1789,6 +2023,7 @@ static int check_cpu_map(struct per_dev_info *pdi)
         * create a map of the cpus we have traces for
         */
        cpu_map = malloc(pdi->cpu_map_max / sizeof(long));
+       memset(cpu_map, 0, sizeof(*cpu_map));
        n = rb_first(&rb_sort_root);
        while (n) {
                __t = rb_entry(n, struct trace, rb_node);
@@ -1892,7 +2127,8 @@ static void show_entries_rb(int force)
                        break;
                }
 
-               if (check_sequence(pdi, t, force))
+               if (!(bit->action == BLK_TN_MESSAGE) &&
+                   check_sequence(pdi, t, force))
                        break;
 
                if (!force && bit->time > last_allowed_time)
@@ -1903,7 +2139,8 @@ static void show_entries_rb(int force)
                if (!pci || pci->cpu != bit->cpu)
                        pci = get_cpu_info(pdi, bit->cpu);
 
-               pci->last_sequence = bit->sequence;
+               if (!(bit->action == BLK_TN_MESSAGE))
+                       pci->last_sequence = bit->sequence;
 
                pci->nelems++;
 
@@ -2036,7 +2273,7 @@ static int read_events(int fd, int always_block, int *fdblock)
                /*
                 * not a real trace, so grab and handle it here
                 */
-               if (bit->action & BLK_TC_ACT(BLK_TC_NOTIFY)) {
+               if (bit->action & BLK_TC_ACT(BLK_TC_NOTIFY) && bit->action != BLK_TN_MESSAGE) {
                        handle_notify(bit);
                        output_binary(bit, sizeof(*bit) + bit->pdu_len);
                        continue;
@@ -2179,7 +2416,13 @@ static int ms_prime(struct ms_stream *msp)
                if (verify_trace(bit))
                        goto err;
 
-               if (bit->action & BLK_TC_ACT(BLK_TC_NOTIFY)) {
+               if (bit->cpu != pci->cpu) {
+                       fprintf(stderr, "cpu %d trace info has error cpu %d\n",
+                               pci->cpu, bit->cpu);
+                       continue;
+               }
+
+               if (bit->action & BLK_TC_ACT(BLK_TC_NOTIFY) && bit->action != BLK_TN_MESSAGE) {
                        handle_notify(bit);
                        output_binary(bit, sizeof(*bit) + bit->pdu_len);
                        bit_free(bit);
@@ -2284,17 +2527,19 @@ static int handle(struct ms_stream *msp)
        struct blk_io_trace *bit;
 
        t = ms_peek(msp);
-       if (t->bit->time > stopwatch_end)
-               return 0;
 
        bit = t->bit;
        pdi = msp->pdi;
        pci = get_cpu_info(pdi, msp->cpu);
        pci->nelems++;
-
        bit->time -= genesis_time;
+
+       if (t->bit->time > stopwatch_end)
+               return 0;
+
        pdi->last_reported_time = bit->time;
-       if (bit->action & (act_mask << BLK_TC_SHIFT))
+       if ((bit->action & (act_mask << BLK_TC_SHIFT))&&
+           t->bit->time >= stopwatch_start)
                dump_trace(bit, pci, pdi);
 
        ms_deq(msp);
@@ -2343,6 +2588,12 @@ static int do_file(void)
 
                for (cpu = 0; setup_file(pdi, cpu); cpu++)
                        ;
+
+               if (!cpu) {
+                       fprintf(stderr,"No input files found for %s\n",
+                               pdi->name);
+                       return 1;
+               }
        }
 
        /*
@@ -2479,7 +2730,7 @@ static int is_pipe(const char *str)
        return 0;
 }
 
-#define S_OPTS  "a:A:b:D:d:f:F:hi:o:Oqstw:vV"
+#define S_OPTS  "a:A:b:D:d:f:F:hi:o:Oqstw:vVM"
 static char usage_str[] =    "\n\n" \
        "-i <file>           | --input=<file>\n" \
        "[ -a <action field> | --act-mask=<action field> ]\n" \
@@ -2496,8 +2747,11 @@ static char usage_str[] =    "\n\n" \
        "[ -s                | --per-program-stats ]\n" \
        "[ -t                | --track-ios ]\n" \
        "[ -w <time>         | --stopwatch=<time> ]\n" \
+       "[ -M                | --no-msgs\n" \
        "[ -v                | --verbose ]\n" \
        "[ -V                | --version ]\n\n" \
+       "\t-a Only trace specified actions. See documentation\n" \
+       "\t-A Give trace mask as a single value. See documentation\n" \
        "\t-b stdin read batching\n" \
        "\t-d Output file. If specified, binary data is written to file\n" \
        "\t-D Directory to prepend to input file names\n" \
@@ -2514,12 +2768,13 @@ static char usage_str[] =    "\n\n" \
        "\t   to get queued, to get dispatched, and to get completed\n" \
        "\t-w Only parse data between the given time interval in seconds.\n" \
        "\t   If 'start' isn't given, blkparse defaults the start time to 0\n" \
+       "\t-M Do not output messages to binary file\n" \
        "\t-v More verbose for marginal errors\n" \
        "\t-V Print program version info\n\n";
 
 static void usage(char *prog)
 {
-       fprintf(stderr, "Usage: %s %s %s", prog, blkparse_version, usage_str);
+       fprintf(stderr, "Usage: %s %s", prog, usage_str);
 }
 
 int main(int argc, char *argv[])
@@ -2604,6 +2859,9 @@ int main(int argc, char *argv[])
                case 'd':
                        dump_binary = optarg;
                        break;
+               case 'M':
+                       bin_output_msgs = 0;
+                       break;
                default:
                        usage(argv[0]);
                        return 1;
@@ -2640,7 +2898,7 @@ int main(int argc, char *argv[])
                        ofp = fdopen(STDOUT_FILENO, "w");
                        mode = _IOLBF;
                } else {
-                       char ofname[128];
+                       char ofname[PATH_MAX];
 
                        snprintf(ofname, sizeof(ofname) - 1, "%s", output_name);
                        ofp = fopen(ofname, "w");
@@ -2660,11 +2918,15 @@ int main(int argc, char *argv[])
        }
 
        if (dump_binary) {
-               dump_fp = fopen(dump_binary, "w");
-               if (!dump_fp) {
-                       perror(dump_binary);
-                       dump_binary = NULL;
-                       return 1;
+               if (!strcmp(dump_binary, "-"))
+                       dump_fp = stdout;
+               else {
+                       dump_fp = fopen(dump_binary, "w");
+                       if (!dump_fp) {
+                               perror(dump_binary);
+                               dump_binary = NULL;
+                               return 1;
+                       }
                }
                bin_ofp_buffer = malloc(128 * 1024);
                if (setvbuf(dump_fp, bin_ofp_buffer, _IOFBF, 128 * 1024)) {
@@ -2681,6 +2943,10 @@ int main(int argc, char *argv[])
        if (!ret)
                show_stats();
 
+       if (have_drv_data && !dump_binary)
+               printf("\ndiscarded traces containing low-level device driver "
+                      "specific data (only available in binary output)\n");
+
        if (ofp_buffer) {
                fflush(ofp);
                free(ofp_buffer);