blkparse: split off the timestamp correction code in to a separate function
[blktrace.git] / blkparse.c
index 817cb313ff26f7e1b52c327d99d649ac0fc06f65..cf7a87b262fed7c4e11a84eb848ac34c24963e81 100644 (file)
@@ -36,7 +36,7 @@
 #include "rbtree.h"
 #include "jhash.h"
 
-static char blkparse_version[] = "1.0.2";
+static char blkparse_version[] = "1.2.0";
 
 struct skip_info {
        unsigned long start, end;
@@ -100,6 +100,19 @@ 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;
@@ -189,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,
@@ -269,6 +288,7 @@ 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;
@@ -562,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;
        }
@@ -1180,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);
        }
 }
 
@@ -1204,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);
        }
 }
 
@@ -1228,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;
        }
 }
 
@@ -1252,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);
        }
 }
 
@@ -1296,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);
        }
 }
 
@@ -1319,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;
        }
 }
 
@@ -1343,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;
        }
 }
 
@@ -1387,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);
        }
 }
 
@@ -1652,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);
@@ -1711,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;
@@ -1725,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;
@@ -1806,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;
@@ -1819,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;
@@ -1839,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",
@@ -1859,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;
@@ -1876,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();
        }
 }
 
@@ -1962,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);
@@ -2668,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:vVM"
+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 <file>           | --input=<file>\n" \
        "[ -a <action field> | --act-mask=<action field> ]\n" \
@@ -2683,6 +2891,7 @@ static char usage_str[] =    "\n\n" \
        "[ -O                | --no-text-output ]\n" \
        "[ -q                | --quiet ]\n" \
        "[ -s                | --per-program-stats ]\n" \
+       "[ -S <event>        | --sort-program-stats=<event> ]\n" \
        "[ -t                | --track-ios ]\n" \
        "[ -w <time>         | --stopwatch=<time> ]\n" \
        "[ -M                | --no-msgs\n" \
@@ -2702,6 +2911,11 @@ static char usage_str[] =    "\n\n" \
        "\t-O Do NOT output text data\n" \
        "\t-q Quiet. Don't display any stats at the end of the trace\n" \
        "\t-s Show per-program io statistics\n" \
+       "\t-S Show per-program io statistics sorted by N/Q/q/R/r/W/w/C/c\n" \
+       "\t   N:Name, Q/q:Queued(read & write), R/r:Queued Read, W/w:Queued Write, C/c:Complete.\n" \
+       "\t   Sort programs by how much data(KB): Q,R,W,C.\n" \
+       "\t   Sort programs by how many IO operations: q,r,w,c.\n" \
+       "\t   if -S was used, the -s parameter will be ignored.\n" \
        "\t-t Track individual ios. Will tell you the time a request took\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" \
@@ -2768,6 +2982,11 @@ int main(int argc, char *argv[])
                case 's':
                        per_process_stats = 1;
                        break;
+               case 'S':
+                       per_process_stats = 1;
+                       if (get_program_sort_event(optarg))
+                               return 1;
+                       break;
                case 't':
                        track_ios = 1;
                        break;
@@ -2836,7 +3055,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");