X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=blkparse.c;h=cf7a87b262fed7c4e11a84eb848ac34c24963e81;hb=d025d6c67760a52e34e6c7352f33ad5dbbb4f6f4;hp=517dde5841ab6f2c26edfa0890615bbd65edec6c;hpb=ebe2d1aa7f334fc526a97f8acf62f1fe7dac9a8a;p=blktrace.git diff --git a/blkparse.c b/blkparse.c index 517dde5..cf7a87b 100644 --- a/blkparse.c +++ b/blkparse.c @@ -36,7 +36,7 @@ #include "rbtree.h" #include "jhash.h" -static char blkparse_version[] = "0.99.3"; +static char blkparse_version[] = "1.2.0"; struct skip_info { unsigned long start, end; @@ -100,11 +100,23 @@ struct per_process_info { #define PPI_HASH_SHIFT (8) #define PPI_HASH_SIZE (1 << PPI_HASH_SHIFT) #define PPI_HASH_MASK (PPI_HASH_SIZE - 1) + +enum { + SORT_PROG_EVENT_N, /* Program Name */ + SORT_PROG_EVENT_QKB, /* KB: Queued read and write */ + SORT_PROG_EVENT_RKB, /* KB: Queued Read */ + SORT_PROG_EVENT_WKB, /* KB: Queued Write */ + SORT_PROG_EVENT_CKB, /* KB: Complete */ + SORT_PROG_EVENT_QIO, /* IO: Queued read and write */ + SORT_PROG_EVENT_RIO, /* IO: Queued Read */ + SORT_PROG_EVENT_WIO, /* IO: Queued Write */ + SORT_PROG_EVENT_CIO, /* IO: Complete */ +}; + 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 +172,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, @@ -184,6 +202,12 @@ static struct option l_opts[] = { .flag = NULL, .val = 's' }, + { + .name = "sort-program-stats", + .has_arg = required_argument, + .flag = NULL, + .val = 'S' + }, { .name = "track-ios", .has_arg = no_argument, @@ -264,12 +288,14 @@ static unsigned long long stopwatch_end = -1ULL; /* "infinity" */ static unsigned long read_sequence; static int per_process_stats; +static int per_process_stats_event = SORT_PROG_EVENT_N; static int per_device_and_cpu_stats = 1; static int track_ios; 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 +318,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)) @@ -554,7 +582,9 @@ static struct process_pid_map *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; } @@ -590,6 +620,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 */ ; @@ -1156,9 +1202,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); } } @@ -1180,9 +1228,11 @@ static inline void __account_pc_queue(struct io_stats *ios, 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); } } @@ -1204,9 +1254,11 @@ static inline void __account_pc_issue(struct io_stats *ios, int rw, 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; } } @@ -1228,9 +1280,11 @@ static inline void __account_pc_requeue(struct io_stats *ios, 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); } } @@ -1272,9 +1326,11 @@ static inline void __account_queue(struct io_stats *ios, struct blk_io_trace *t, 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); } } @@ -1295,9 +1351,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; } } @@ -1319,9 +1377,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; } } @@ -1363,9 +1423,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); } } @@ -1567,6 +1629,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; @@ -1577,7 +1643,9 @@ 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)) + 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); @@ -1588,7 +1656,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); } /* @@ -1619,30 +1690,59 @@ 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, 1)); - fprintf(ofp, " PC Writes Queued: %s, %siB\n", size_cnv(x, ios->qwrites_pc, 0), size_cnv(y, ios->qwrite_kb_pc, 1)); - fprintf(ofp, " PC Read Disp.: %s, %siB\t", size_cnv(x, ios->ireads_pc, 0), size_cnv(y, ios->iread_kb_pc, 1)); - fprintf(ofp, " PC Write Disp.: %s, %siB\n", size_cnv(x, ios->iwrites_pc, 0), size_cnv(y, ios->iwrite_kb_pc, 1)); + 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, 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); @@ -1678,6 +1778,88 @@ static int ppi_name_compare(const void *p1, const void *p2) return res; } +static int ppi_event_compare(const void *p1, const void *p2) +{ + struct per_process_info *ppi1 = *((struct per_process_info **) p1); + struct per_process_info *ppi2 = *((struct per_process_info **) p2); + struct io_stats *ios1 = &ppi1->io_stats; + struct io_stats *ios2 = &ppi2->io_stats; + unsigned long io1, io2; + unsigned long long kb1,kb2; + int sort_by_kb = 1; + + io1 = io2 = 0; + kb1 = kb2 = 0; + + switch (per_process_stats_event) { + case SORT_PROG_EVENT_QKB: /* KB: Queued read and write */ + kb1 = ios1->qwrite_kb + (ios1->qwrite_b>>10) + + ios1->qread_kb + (ios1->qread_b>>10); + kb2 = ios2->qwrite_kb + (ios2->qwrite_b>>10) + + ios2->qread_kb + (ios2->qread_b>>10); + break; + case SORT_PROG_EVENT_RKB: /* KB: Queued Read */ + kb1 = ios1->qread_kb + (ios1->qread_b>>10); + kb2 = ios2->qread_kb + (ios2->qread_b>>10); + break; + case SORT_PROG_EVENT_WKB: /* KB: Queued Write */ + kb1 = ios1->qwrite_kb + (ios1->qwrite_b>>10); + kb2 = ios2->qwrite_kb + (ios2->qwrite_b>>10); + break; + case SORT_PROG_EVENT_CKB: /* KB: Complete */ + kb1 = ios1->cwrite_kb + (ios1->cwrite_b>>10) + + ios1->cread_kb + (ios1->cread_b>>10); + kb2 = ios2->cwrite_kb + (ios2->cwrite_b>>10) + + ios2->cread_kb + (ios2->cread_b>>10); + break; + case SORT_PROG_EVENT_QIO: /* IO: Queued read and write */ + sort_by_kb = 0; + io1 = ios1->qreads + ios1->qwrites; + io2 = ios2->qreads + ios2->qwrites; + break; + case SORT_PROG_EVENT_RIO: /* IO: Queued Read */ + sort_by_kb = 0; + io1 = ios1->qreads; + io2 = ios2->qreads; + break; + case SORT_PROG_EVENT_WIO: /* IO: Queued Write */ + sort_by_kb = 0; + io1 = ios1->qwrites; + io2 = ios2->qwrites; + break; + case SORT_PROG_EVENT_CIO: /* IO: Complete */ + sort_by_kb = 0; + io1 = ios1->creads + ios1->cwrites; + io2 = ios2->creads + ios2->cwrites; + break; + } + + + /* compare kb */ + if (sort_by_kb) { + if (kb1 > kb2) + return 1; + else if (kb1 == kb2) + return 0; + return -1; + } + + /* compare io */ + if (io1 > io2) + return 1; + else if (io1 == io2) + return 0; + return -1; +} + +static int ppi_compare(const void *p1, const void *p2) +{ + if (per_process_stats_event == SORT_PROG_EVENT_N) + return ppi_name_compare(p1, p2); + + return ppi_event_compare(p1, p2); +} + static void sort_process_list(void) { struct per_process_info **ppis; @@ -1692,7 +1874,7 @@ static void sort_process_list(void) ppi = ppi->list_next; } - qsort(ppis, ppi_list_entries, sizeof(ppi), ppi_name_compare); + qsort(ppis, ppi_list_entries, sizeof(ppi), ppi_compare); i = ppi_list_entries - 1; ppi_list = NULL; @@ -1773,6 +1955,14 @@ 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; @@ -1786,6 +1976,10 @@ static void show_device_and_cpu_stats(void) 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; @@ -1806,8 +2000,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", @@ -1826,6 +2022,22 @@ static void show_device_and_cpu_stats(void) } } +static void correct_abs_start_time(void) +{ + long delta = genesis_time - start_timestamp; + + abs_start_time.tv_sec += SECONDS(delta); + abs_start_time.tv_nsec += NANO_SECONDS(delta); + if (abs_start_time.tv_nsec < 0) { + abs_start_time.tv_nsec += 1000000000; + abs_start_time.tv_sec -= 1; + } else + if (abs_start_time.tv_nsec > 1000000000) { + abs_start_time.tv_nsec -= 1000000000; + abs_start_time.tv_sec += 1; + } +} + static void find_genesis(void) { struct trace *t = trace_list; @@ -1843,18 +2055,7 @@ static void find_genesis(void) */ if (start_timestamp && start_timestamp != genesis_time) { - long delta = genesis_time - start_timestamp; - - abs_start_time.tv_sec += SECONDS(delta); - abs_start_time.tv_nsec += NANO_SECONDS(delta); - if (abs_start_time.tv_nsec < 0) { - abs_start_time.tv_nsec += 1000000000; - abs_start_time.tv_sec -= 1; - } else - if (abs_start_time.tv_nsec > 1000000000) { - abs_start_time.tv_nsec -= 1000000000; - abs_start_time.tv_sec += 1; - } + correct_abs_start_time(); } } @@ -1929,6 +2130,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); @@ -2032,7 +2234,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) @@ -2043,7 +2246,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++; @@ -2176,7 +2380,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; @@ -2319,7 +2523,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); @@ -2485,6 +2695,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; + } } /* @@ -2621,7 +2837,46 @@ static int is_pipe(const char *str) return 0; } -#define S_OPTS "a:A:b:D:d:f:F:hi:o:Oqstw:vV" +static int get_program_sort_event(const char *str) +{ + char evt = str[0]; + + switch (evt) { + case 'N': + per_process_stats_event = SORT_PROG_EVENT_N; + break; + case 'Q': + per_process_stats_event = SORT_PROG_EVENT_QKB; + break; + case 'q': + per_process_stats_event = SORT_PROG_EVENT_QIO; + break; + case 'R': + per_process_stats_event = SORT_PROG_EVENT_RKB; + break; + case 'r': + per_process_stats_event = SORT_PROG_EVENT_RIO; + break; + case 'W': + per_process_stats_event = SORT_PROG_EVENT_WKB; + break; + case 'w': + per_process_stats_event = SORT_PROG_EVENT_WIO; + break; + case 'C': + per_process_stats_event = SORT_PROG_EVENT_CKB; + break; + case 'c': + per_process_stats_event = SORT_PROG_EVENT_CIO; + break; + default: + return 1; + } + + return 0; +} + +#define S_OPTS "a:A:b:D:d:f:F:hi:o:OqsS:tw:vVM" static char usage_str[] = "\n\n" \ "-i | --input=\n" \ "[ -a | --act-mask= ]\n" \ @@ -2636,10 +2891,14 @@ static char usage_str[] = "\n\n" \ "[ -O | --no-text-output ]\n" \ "[ -q | --quiet ]\n" \ "[ -s | --per-program-stats ]\n" \ + "[ -S | --sort-program-stats= ]\n" \ "[ -t | --track-ios ]\n" \ "[ -w