Added in running stats for btt
[blktrace.git] / btt / trace.c
index 0008ffa563caeb3829495c22ce42ebba6835cc47..48f4f99f754524cda107a1c63d72dd5c587edd86 100644 (file)
  */
 #include "globals.h"
 
-static inline void release_iop(struct io *iop)
+static void __add_trace(struct io *iop)
 {
-       if (iop->pdu) free(iop->pdu);
-       IO_FREE(iop);
-}
-
-struct io *dip_find_exact(struct list_head *head, struct io *iop_in)
-{
-       struct io *iop;
-       struct list_head *p;
-
-       __list_for_each(p, head) {
-               iop = list_entry(p, struct io, dev_head);
-               if (is_bit(iop_in, iop))
-                       return iop;
-       }
-       return NULL;
-}
-
-struct io *dip_find_in(struct list_head *head, struct io *iop_in)
-{
-       struct io *iop;
-       struct list_head *p;
-
-       __list_for_each(p, head) {
-               iop = list_entry(p, struct io, dev_head);
-               if (in_bit(iop, iop_in))
-                       return iop;
-       }
-       return NULL;
-}
-
-struct io *dip_find_start(struct list_head *head, __u64 sector)
-{
-       struct io *iop;
-       struct list_head *p;
-
-       __list_for_each(p, head) {
-               iop = list_entry(p, struct io, dev_head);
-               if (BIT_START(iop) == sector)
-                       return iop;
-       }
-       return NULL;
-}
-
-struct io *dip_find_end(struct list_head *head, __u64 sector)
-{
-       struct io *iop;
-       struct list_head *p;
-
-       __list_for_each(p, head) {
-               iop = list_entry(p, struct io, dev_head);
-               if (BIT_END(iop) == sector)
-                       return iop;
-       }
-       return NULL;
-}
-
-struct io *dip_find_in_sec(struct list_head *head, __u64 sector)
-{
-       struct io *iop;
-       struct list_head *p;
-
-       __list_for_each(p, head) {
-               iop = list_entry(p, struct io, dev_head);
-               if (BIT_START(iop) <= sector && sector <= BIT_END(iop))
-                       return iop;
-       }
-       return NULL;
-}
-
-struct io *dip_find_qa(struct list_head *head, struct blk_io_trace *t)
-{
-       struct io *iop;
-       struct list_head *p;
-
-       __list_for_each(p, head) {
-               iop = list_entry(p, struct io, dev_head);
-               if (iop->t.cpu == t->cpu && iop->t.sequence == (t->sequence-1))
-                       return iop;
-       }
-       return NULL;
-}
-
-void dip_add_ms(struct list_head *head, struct io *d_iop)
-{
-       struct io *m_iop;
-       struct list_head *p;
-       struct io_list *iolp;
-
-       __list_for_each(p, head) {
-               m_iop = list_entry(p, struct io, dev_head);
-               if (in_bit(m_iop, d_iop)) {
-                       iolp = malloc(sizeof(*iolp));
-                       io_link(&iolp->iop, m_iop);
-                       list_add_tail(&iolp->head, &d_iop->u.d.d_im_head);
-               }
-       }
-}
-
-void dip_add_qs(struct list_head *head, struct io *i_iop)
-{
-       struct io *q_iop;
-       struct list_head *p;
-       struct io_list *iolp;
-
-       __list_for_each(p, head) {
-               q_iop = list_entry(p, struct io, dev_head);
-               if (in_bit(q_iop, i_iop)) {
-                       iolp = malloc(sizeof(*iolp));
-                       io_link(&iolp->iop, q_iop);
-                       list_add_tail(&iolp->head, &i_iop->u.i.i_qs_head);
-               }
-       }
-}
-
-void handle_queue(struct io *iop)
-{
-       struct io *tmp;
-
-       io_setup(iop, IOP_Q);
-
-       update_lq(&last_q, &all_avgs.q2q, iop->t.time);
-       update_qregion(&all_regions, iop->t.time);
-       dip_update_q(iop->dip, iop);
-       pip_update_q(iop);
-
-       tmp = dip_find_exact(dip_get_head(iop->dip, IOP_A), iop);
-       if (tmp) {
-               iop->u.q.qp_type = Q_A;
-               io_link(&iop->u.q.qp.q_a, tmp);
-       }
-       else
-               iop->u.q.qp_type = Q_NONE;
-
-#if defined(LVM_REMAP_WORKAROUND)
-       if (is_lvm) {
-               tmp = dip_find_qa(dip_get_head(iop->dip, IOP_A), &iop->t);
-               if (tmp) {
-                       iop->u.q.qp_type = Q_A;
-                       io_link(&iop->u.q.qp.q_a, tmp);
-               }
-       }
-#endif
-}
-
-void handle_merge(struct io *iop)
-{
-       struct io *q_iop;
-
-       io_setup(iop, IOP_M);
-
-       q_iop = dip_find_exact(dip_get_head(iop->dip, IOP_Q), iop);
-       if (q_iop)
-               io_link(&iop->u.m.m_q, q_iop);
-}
-
-void handle_insert(struct io *iop)
-{
-       struct io_list *iolp = malloc(sizeof(*iolp));
-
-       io_setup(iop, IOP_I);
-       INIT_LIST_HEAD(&iop->u.i.i_qs_head);
-       dip_add_qs(dip_get_head(iop->dip, IOP_Q), iop);
-}
-
-void handle_complete(struct io *iop)
-{
-       struct io *d_iop;
-
-       io_setup(iop, IOP_C);
-       update_blks(iop);
-       update_cregion(&all_regions, iop->t.time);
-       update_cregion(&iop->dip->regions, iop->t.time);
-       if (iop->pip)
-               update_cregion(&iop->pip->regions, iop->t.time);
-
-       d_iop = dip_find_exact(dip_get_head(iop->dip, IOP_D), iop);
-       if (d_iop) {
-               io_link(&iop->u.c.c_d, d_iop);
+       time_t now = time(NULL);
 
-               add_cy(iop);
-       }
-       else
-               io_free(iop);
-}
-
-void handle_issue(struct io *iop)
-{
-       struct io *i_iop;
-       struct io_list *iolp = malloc(sizeof(*iolp));
-
-       io_setup(iop, IOP_D);
-       iop->dip->n_ds++;
-
-       INIT_LIST_HEAD(&iop->u.d.d_im_head);
-       i_iop = dip_find_in(dip_get_head(iop->dip, IOP_I), iop);
-       if (i_iop) {
-               io_link(&iolp->iop, i_iop);
-               list_add_tail(&iolp->head, &iop->u.d.d_im_head);
-       }
-
-       dip_add_ms(dip_get_head(iop->dip, IOP_M), iop);
-}
-
-void handle_split(struct io *iop)
-{
-       struct io *q_iop;
-
-       pending_xs++;
-       io_setup(iop, IOP_X);
-
-       q_iop = dip_find_exact(dip_get_head(iop->dip, IOP_Q), iop);
-       if (q_iop)
-               io_link(&iop->u.x.x_q, q_iop);
-}
-
-#if 0
-void __x_add_c(struct io *y_iop, struct io *x_iop,
-              struct blk_io_trace_split_end *rp, int which)
-{
-       __u32 dev;
-       __u64 sector;
-       struct d_info *dip;
-       struct io **y_cp, *q_iop, *c_iop;
-
-       if (which == 1) {
-               y_cp = &y_iop->u.y.y_c1;
-               dev = be32_to_cpu(rp->dev1);
-               sector = be64_to_cpu(rp->sector1);
-       }
-       else {
-               y_cp = &y_iop->u.y.y_c2;
-               dev = be32_to_cpu(rp->dev2);
-               sector = be64_to_cpu(rp->sector2);
-       }
-
-       dip = __dip_find(dev);
-       ASSERT(dip != NULL);
-
-       q_iop = dip_find_end(dip_get_head(dip, IOP_Q), sector);
-       if (q_iop) {
-               q_iop->u.q.qp_type = Q_X;
-               io_link(&q_iop->u.q.qp.q_x, x_iop);
-       }
-
-       c_iop = dip_find_in_sec(dip_get_head(dip, IOP_C), sector);
-       if (c_iop)
-               io_link(y_cp, c_iop);
-}
-
-void handle_split_end(struct io *iop)
-{
-       struct io *x_iop;
-       struct blk_io_trace_split_end *rp = iop->pdu;
-
-       pending_xs--;
-       io_setup(iop, IOP_Y);
-
-       x_iop = dip_find_exact(dip_get_head(iop->dip, IOP_X), iop);
-       if (x_iop) {
-               __x_add_c(iop, x_iop, rp, 1);
-               __x_add_c(iop, x_iop, rp, 2);
-
-               rem_c(iop->u.y.y_c1);
-               rem_c(iop->u.y.y_c2);
-
-               add_cy(iop);
-       }
-       else
-               release_iop(iop);
-}
-#endif
-
-void handle_remap(struct io *iop)
-{
-       struct io *q_iop;
-       struct blk_io_trace_remap *rp = iop->pdu;
-       __u32 dev = be32_to_cpu(rp->device);
-       __u64 sector = be64_to_cpu(rp->sector);
+       last_t_seen = BIT_TIME(iop->t.time);
 
-       q_iop = dip_find_in_sec(dip_get_head_dev(dev, IOP_Q), sector);
-       if (q_iop) {
-               io_setup(iop, IOP_A);
+       n_traces++;
+       iostat_check_time(iop->t.time);
 
-#if defined(LVM_REMAP_WORKAROUND)
-               if (is_lvm) {
-                       sector = iop->t.sector;
-                       iop->t.sector = be64_to_cpu(rp->sector);
-               }
-#endif
-               io_link(&iop->u.a.a_q, q_iop);
+       if (verbose && ((now - last_vtrace) > 0)) {
+               printf("%10lu t (%6.2lf%%)\r", n_traces, pct_done());
+               if ((n_traces % 1000000) == 0) printf("\n");
+               fflush(stdout);
+               last_vtrace = now;
        }
-       else
-               release_iop(iop);
-}
-
-void extract_i(struct io *i_iop)
-{
-       struct io_list *iolp;
-       struct list_head *p, *q;
-
-       ASSERT(i_iop != NULL && i_iop->type == IOP_I);
-       list_for_each_safe(p, q, &i_iop->u.i.i_qs_head) {
-               iolp = list_entry(p, struct io_list, head);
-               LIST_DEL(&iolp->head);
 
-               ASSERT(iolp->iop->type == IOP_Q);
-               (void)__io_put(iolp->iop);
-
-               free(iolp);
+       switch (iop->t.action & 0xffff) {
+       case __BLK_TA_QUEUE:            trace_queue(iop); break;
+       case __BLK_TA_REMAP:            trace_remap(iop); break;
+       case __BLK_TA_INSERT:           trace_insert(iop); break;
+       case __BLK_TA_GETRQ:            trace_getrq(iop); break;
+       case __BLK_TA_BACKMERGE:        trace_merge(iop); break;
+       case __BLK_TA_FRONTMERGE:       trace_merge(iop); break;
+       case __BLK_TA_REQUEUE:          trace_requeue(iop); break;
+       case __BLK_TA_ISSUE:            trace_issue(iop); break;
+       case __BLK_TA_COMPLETE:         trace_complete(iop); break;
+       case __BLK_TA_PLUG:             trace_plug(iop); break;
+       case __BLK_TA_UNPLUG_IO:        trace_unplug_io(iop); break;
+       case __BLK_TA_UNPLUG_TIMER:     trace_unplug_timer(iop); break;
+       case __BLK_TA_SLEEPRQ:          trace_sleeprq(iop); break;
+       default:
+               io_release(iop);
+               return;
        }
 }
 
-/*
- * Careful surgery
- * (1) Need to remove D & its I & M's
- * (2) Need to leave I's Q and M's Q's -- *no* io_put (__io_put instead)
- */
-void handle_requeue(struct io *iop)
+static void trace_message(struct io *iop)
 {
-       struct io *d_iop;
-       struct io_list *iolp;
-       struct list_head *p, *q;
+       char scratch[15];
+       char msg[iop->t.pdu_len + 1];
 
-       d_iop = dip_find_start(dip_get_head_dev(iop->t.device, IOP_D),
-                              iop->t.sector);
-       if (d_iop) {
-               list_for_each_safe(p, q, &d_iop->u.d.d_im_head) {
-                       iolp = list_entry(p, struct io_list, head);
-                       LIST_DEL(&iolp->head);
+       if (!io_setup(iop, IOP_M))
+               return;
 
-                       if (iolp->iop->type == IOP_M)
-                               (void)__io_put(iolp->iop->u.m.m_q);
-                       else
-                               extract_i(iolp->iop);
-
-                       iolp->iop->users = 0;
-                       io_free(iolp->iop);
-                       free(iolp);
-               }
-
-               d_iop->users = 0;
-               io_free(d_iop);
-       }
+       memcpy(msg, iop->pdu, iop->t.pdu_len);
+       msg[iop->t.pdu_len] = '\0';
 
-       release_iop(iop);
-
-}
-
-void __add_trace(struct io *iop)
-{
-       n_traces++;
-
-       if (verbose && (n_traces % 10000) == 0) {
-               printf("%10lu t, %10lu m %1lu f\r",
-                      n_traces, n_io_allocs, n_io_frees);
-               fflush(stdout);
-               if ((n_traces % 1000000) == 0) printf("\n");
-       }
-
-       switch (iop->t.action & 0xffff) {
-       case __BLK_TA_QUEUE:            handle_queue(iop);      break;
-       case __BLK_TA_BACKMERGE:        handle_merge(iop);      break;
-       case __BLK_TA_FRONTMERGE:       handle_merge(iop);      break;
-       case __BLK_TA_ISSUE:            handle_issue(iop);      break;
-       case __BLK_TA_COMPLETE:         handle_complete(iop);   break;
-       case __BLK_TA_INSERT:           handle_insert(iop);     break;
-       case __BLK_TA_SPLIT:            handle_split(iop);      break;
-#if 0
-       case __BLK_TA_SPLIT_END:        handle_split_end(iop);  break;
-#endif
-       case __BLK_TA_REMAP:            handle_remap(iop);      break;
-       case __BLK_TA_REQUEUE:          handle_requeue(iop);    break;
-       }
+       fprintf(msgs_ofp, "%s %5d.%09lu %s\n",
+               make_dev_hdr(scratch, 15, iop->dip, 1),
+               (int)SECONDS(iop->t.time),
+               (unsigned long)NANO_SECONDS(iop->t.time), msg);
 }
 
 void add_trace(struct io *iop)
 {
        if (iop->t.action & BLK_TC_ACT(BLK_TC_NOTIFY)) {
-               char *slash = strchr(iop->pdu, '/');
-
-               if (slash)
-                       *slash = '\0';
-               add_process(iop->t.pid, iop->pdu);
-               release_iop(iop);
-       }
-       else if (iop->t.action & BLK_TC_ACT(BLK_TC_PC))
-               release_iop(iop);
-       else
+               if (iop->t.action == BLK_TN_PROCESS) {
+                       if (iop->t.pid == 0)
+                               process_alloc(0, "kernel");
+                       else {
+                               char *slash = strchr(iop->pdu, '/');
+                               if (slash)
+                                       *slash = '\0';
+
+                               process_alloc(iop->t.pid, iop->pdu);
+                       }
+               } else if (iop->t.action == BLK_TN_MESSAGE)
+                       trace_message(iop);
+               io_release(iop);
+       } else if (iop->t.action & BLK_TC_ACT(BLK_TC_PC)) {
+               io_release(iop);
+       } else {
+               if (time_bounded) {
+                       if (BIT_TIME(iop->t.time) < t_astart) {
+                               io_release(iop);
+                               return;
+                       } else if (BIT_TIME(iop->t.time) > t_aend) {
+                               io_release(iop);
+                               done = 1;
+                               return;
+                       }
+               }
                __add_trace(iop);
+       }
 }