Merge branch 'add-P'
[blktrace.git] / blkiomon.c
index 3ac43606ec3895376c8663d46e69de01e667412e..2066006c9a5ff58efbd28e3ab103891d08f8fee9 100644 (file)
@@ -78,7 +78,6 @@ static int interval = -1;
 
 static struct trace *vacant_traces_list = NULL;
 static int vacant_traces = 0;
-static struct rb_root trace_tree = RB_ROOT;
 
 #define TRACE_HASH_SIZE 128
 struct trace *thash[TRACE_HASH_SIZE] = {};
@@ -88,7 +87,7 @@ static struct rb_root dstat_tree[2] = { RB_ROOT, RB_ROOT };
 static struct dstat *dstat_list[2] = {};
 static int dstat_curr = 0;
 
-static struct output human, binary, debug;
+static struct output drvdata, human, binary, debug;
 
 static char *msg_q_name = NULL;
 static int msg_q_id = -1, msg_q = -1;
@@ -164,7 +163,8 @@ static struct dstat *blkiomon_alloc_dstat(void)
        } else
                dstat = malloc(sizeof(*dstat));
        if (!dstat) {
-               perror("blkiomon: could not allocate device statistic");
+               fprintf(stderr,
+                       "blkiomon: could not allocate device statistic");
                return NULL;
        }
 
@@ -211,8 +211,10 @@ static struct dstat *blkiomon_get_dstat(__u32 device)
                goto out;
 
        dstat->msg.stat.device = device;
-       dstat->msg.stat.size_mm.min = -1ULL;
-       dstat->msg.stat.d2c_mm.min = -1ULL;
+       dstat->msg.stat.size_r.min = -1ULL;
+       dstat->msg.stat.size_w.min = -1ULL;
+       dstat->msg.stat.d2c_r.min = -1ULL;
+       dstat->msg.stat.d2c_w.min = -1ULL;
 
        rb_link_node(&dstat->node, search.parent, search.node_ptr);
        rb_insert_color(&dstat->node, &dstat_tree[dstat_curr]);
@@ -280,7 +282,7 @@ static void *blkiomon_interval(void *data)
        while (1) {
                wake.tv_sec += interval;
                if (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &wake, &r)) {
-                       perror("blkiomon: interrupted sleep");
+                       fprintf(stderr, "blkiomon: interrupted sleep");
                        continue;
                }
 
@@ -314,23 +316,26 @@ static int blkiomon_account(struct blk_io_trace *bit_d,
        struct blkiomon_stat *p;
        __u64 d2c = (bit_c->time - bit_d->time) / 1000; /* ns -> us */
        __u32 size = bit_d->bytes;
+       __u64 thrput = size * 1000 / d2c;
 
        dstat = blkiomon_get_dstat(bit_d->device);
        if (!dstat)
                return 1;
        p = &dstat->msg.stat;
 
-       if (BLK_DATADIR(bit_c->action) & BLK_TC_READ)
-               p->read++;
-       else if (BLK_DATADIR(bit_c->action) & BLK_TC_WRITE)
-               p->write++;
-       else
+       if (BLK_DATADIR(bit_c->action) & BLK_TC_READ) {
+               minmax_account(&p->thrput_r, thrput);
+               minmax_account(&p->size_r, size);
+               minmax_account(&p->d2c_r, d2c);
+       } else if (BLK_DATADIR(bit_c->action) & BLK_TC_WRITE) {
+               minmax_account(&p->thrput_w, thrput);
+               minmax_account(&p->size_w, size);
+               minmax_account(&p->d2c_w, d2c);
+       } else
                p->bidir++;
 
        histlog2_account(p->size_hist, size, &size_hist);
        histlog2_account(p->d2c_hist, d2c, &d2c_hist);
-       minmax_account(&p->size_mm, size);
-       minmax_account(&p->d2c_mm, d2c);
        return 0;
 }
 
@@ -427,6 +432,26 @@ static struct trace *blkiomon_do_trace(struct trace *t)
        return t_old;
 }
 
+static int blkiomon_dump_drvdata(struct blk_io_trace *bit, void *pdu_buf)
+{
+       if (!drvdata.fn)
+               return 0;
+
+       if (fwrite(bit, sizeof(*bit), 1, drvdata.fp) != 1)
+               goto failed;
+       if (fwrite(pdu_buf, bit->pdu_len, 1, drvdata.fp) != 1)
+               goto failed;
+       if (drvdata.pipe && fflush(drvdata.fp))
+               goto failed;
+       return 0;
+
+failed:
+       fprintf(stderr, "blkiomon: could not write to %s\n", drvdata.fn);
+       fclose(drvdata.fp);
+       drvdata.fn = NULL;
+       return 1;
+}
+
 static int blkiomon_do_fifo(void)
 {
        struct trace *t;
@@ -447,17 +472,19 @@ static int blkiomon_do_fifo(void)
                }
                if (ferror(ifp)) {
                        clearerr(ifp);
-                       perror("blkiomon: error while reading trace");
+                       fprintf(stderr, "blkiomon: error while reading trace");
                        break;
                }
 
-               if (data_is_native == -1 && check_data_endianness(bit->magic))
+               if (data_is_native == -1 && check_data_endianness(bit->magic)) {
+                       fprintf(stderr, "blkiomon: endianess problem\n");
                        break;
+               }
 
                /* endianess */
                trace_to_cpu(bit);
                if (verify_trace(bit)) {
-                       perror("blkiomon: bad trace");
+                       fprintf(stderr, "blkiomon: bad trace\n");
                        break;
                }
 
@@ -466,20 +493,32 @@ static int blkiomon_do_fifo(void)
                        pdu_buf = realloc(pdu_buf, bit->pdu_len);
                        if (fread(pdu_buf, bit->pdu_len, 1, ifp) != 1) {
                                clearerr(ifp);
-                               perror("blkiomon: could not read payload");
+                               fprintf(stderr, "blkiomon: could not read payload\n");
                                break;
                        }
                }
 
                t->sequence = sequence++;
 
+               /* forward low-level device driver trace to other tool */
+               if (bit->action & BLK_TC_ACT(BLK_TC_DRV_DATA)) {
+                       driverdata++;
+                       if (blkiomon_dump_drvdata(bit, pdu_buf)) {
+                               fprintf(stderr, "blkiomon: could not send trace\n");
+                               break;
+                       }
+                       continue;
+               }
+
                if (!(bit->action & BLK_TC_ACT(BLK_TC_ISSUE | BLK_TC_COMPLETE)))
                        continue;
 
                /* try to find matching trace and update statistics */
                t = blkiomon_do_trace(t);
-               if (!t)
+               if (!t) {
+                       fprintf(stderr, "blkiomon: could not alloc trace\n");
                        break;
+               }
                bit = &t->bit;
                /* t and bit will be recycled for next incoming trace */
        }
@@ -541,23 +580,24 @@ static int blkiomon_open_msg_q(void)
 
 static void blkiomon_debug(void)
 {
-       struct rb_node *n;
+       int i;
        struct trace *t;
 
        if (!debug.fn)
                return;
 
-       for (n = rb_first(&trace_tree); n; n = rb_next(n)) {
-               t = rb_entry(n, struct trace, node);
-               dump_bit(t, "leftover");
-               leftover++;
-       }
+       for (i = 0; i < TRACE_HASH_SIZE; i++)
+               for (t = thash[i]; t; t = t->next) {
+                       dump_bit(t, "leftover");
+                       leftover++;
+               }
+
        fprintf(debug.fp, "%ld leftover, %ld match, %ld mismatch, "
                "%ld driverdata, %ld overall\n",
                leftover, match, mismatch, driverdata, sequence);
 }
 
-#define S_OPTS "b:D:h:I:Q:q:m:V"
+#define S_OPTS "b:d:D:h:I:Q:q:m:V"
 
 static char usage_str[] = "\n\nblkiomon " \
        "-I <interval>       | --interval=<interval>\n" \
@@ -571,6 +611,7 @@ static char usage_str[] = "\n\nblkiomon " \
        "\t-I   Sample interval.\n" \
        "\t-h   Human-readable output file.\n" \
        "\t-b   Binary output file.\n" \
+       "\t-d   Output file for data emitted by low level device driver.\n" \
        "\t-D   Output file for debugging data.\n" \
        "\t-Qqm Output to message queue using given ID for messages.\n" \
        "\t-V   Print program version.\n\n";
@@ -588,6 +629,12 @@ static struct option l_opts[] = {
                .flag = NULL,
                .val = 'b'
        },
+       {
+               .name = "dump-lldd",
+               .has_arg = required_argument,
+               .flag = NULL,
+               .val = 'd'
+       },
        {
                .name = "debug",
                .has_arg = required_argument,
@@ -652,6 +699,9 @@ int main(int argc, char *argv[])
                case 'b':
                        binary.fn = optarg;
                        break;
+               case 'd':
+                       drvdata.fn = optarg;
+                       break;
                case 'D':
                        debug.fn = optarg;
                        break;
@@ -691,13 +741,15 @@ int main(int argc, char *argv[])
                return 1;
        if (blkiomon_open_output(&binary))
                return 1;
+       if (blkiomon_open_output(&drvdata))
+               return 1;
        if (blkiomon_open_output(&debug))
                return 1;
        if (blkiomon_open_msg_q())
                return 1;
 
        if (pthread_create(&interval_thread, NULL, blkiomon_interval, NULL)) {
-               perror("blkiomon: could not create thread");
+               fprintf(stderr, "blkiomon: could not create thread");
                return 1;
        }