Fixed plug/unplug logic in btt
[blktrace.git] / btt / seek.c
index 3003611a8e8d595b2c80ebc5d080e3ef992e5665..4a03fbea97d6f74fe976b73f5e8922eebea13850 100644 (file)
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
+#include <float.h>
 #include "globals.h"
 
-static struct file_info *all_files = NULL;
-
 struct seek_bkt {
+       struct rb_node rb_node;
        long long sectors;
        int nseeks;
 };
 
+/* Seeks per second */
+struct sps_bkt {
+       double t_start, t_last;
+       unsigned long nseeks;
+};
+
 struct seeki {
-       FILE *rfp, *wfp;
-       struct seek_bkt *seek_bkts;
-       int nseek_bkts;
-       long long total_seeks;
+       FILE *rfp, *wfp, *cfp, *sps_fp;
+       struct rb_root root;
+       struct sps_bkt sps;
+       long long tot_seeks;
        double total_sectors;
        long long last_start, last_end;
 };
 
-FILE *seek_open(__u32 device, char rw)
+static FILE *seek_open(char *str, char rw)
 {
        FILE *fp;
        char *oname;
-       int mjr, mnr;
 
        if (seek_name == NULL) return NULL;
 
-       mjr = device >> MINORBITS;
-       mnr = device & ((1 << MINORBITS) - 1);
-
-       oname = malloc(strlen(seek_name)+32);
-       sprintf(oname, "%s_%03d,%03d_%c.dat", seek_name, mjr, mnr, rw);
-       if ((fp = fopen(oname, "w")) == NULL)
+       oname = malloc(strlen(seek_name) + strlen(str) + 32);
+       sprintf(oname, "%s_%s_%c.dat", seek_name, str, rw);
+       if ((fp = my_fopen(oname, "w")) == NULL)
                perror(oname);
        else
-               add_file(&all_files, fp, oname);
+               add_file(fp, oname);
 
        return fp;
 }
 
-void seek_clean(void)
+static void __insert(struct rb_root *root, long long sectors)
+{
+       struct seek_bkt *sbp;
+       struct rb_node *parent = NULL;
+       struct rb_node **p = &root->rb_node;
+
+       while (*p) {
+               parent = *p;
+               sbp = rb_entry(parent, struct seek_bkt, rb_node);
+               if (sectors < sbp->sectors)
+                       p = &(*p)->rb_left;
+               else if (sectors > sbp->sectors)
+                       p = &(*p)->rb_right;
+               else {
+                       sbp->nseeks++;
+                       return;
+               }
+       }
+
+       sbp = malloc(sizeof(struct seek_bkt));
+       sbp->nseeks = 1;
+       sbp->sectors = sectors;
+
+       rb_link_node(&sbp->rb_node, parent, p);
+       rb_insert_color(&sbp->rb_node, root);
+}
+
+static void __destroy(struct rb_node *n)
+{
+       if (n) {
+               struct seek_bkt *sbp = rb_entry(n, struct seek_bkt, rb_node);
+
+               __destroy(n->rb_left);
+               __destroy(n->rb_right);
+               free(sbp);
+       }
+}
+
+static void sps_emit(struct seeki *sip)
+{
+       double tstamp, s_p_s;
+       struct sps_bkt *sps = &sip->sps;
+       double delta = sps->t_last - sps->t_start;
+
+       if ((sps->nseeks == 1) || (delta < DBL_EPSILON)) {
+               s_p_s = (double)(sps->nseeks);
+               tstamp = sps->t_start;
+       } else {
+
+               s_p_s = (double)(sps->nseeks) / delta;
+               tstamp = sps->t_start + (delta / 2);
+       }
+
+       fprintf(sip->sps_fp, "%15.9lf %.2lf\n", sps->t_start, s_p_s);
+
+       sps->t_start = 0;
+       sps->nseeks = 0;
+}
+
+static void sps_add(struct seeki *sip, double t)
+{
+       if (sip->sps_fp) {
+               struct sps_bkt *sps = &sip->sps;
+
+               if (sps->nseeks != 0 && ((t - sps->t_start) >= 1.0))
+                       sps_emit(sip);
+
+               sps->t_last = t;
+               if (sps->nseeks == 0) {
+                       sps->t_start = t;
+                       sps->nseeks = 1;
+               } else
+                       sps->nseeks++;
+       }
+}
+
+static int __median(struct rb_node *n, long long sofar, long long target,
+                   long long *rvp)
+{
+       struct seek_bkt *sbp;
+
+       sbp = rb_entry(n, struct seek_bkt, rb_node);
+       if ((sofar + sbp->nseeks) >= target) {
+               *rvp = sbp->sectors;
+               return 1;
+       }
+
+       if (n->rb_left && __median(n->rb_left, sofar, target, rvp))
+               return 1;
+
+       if (n->rb_right && __median(n->rb_right, sofar, target, rvp))
+               return 1;
+
+       return 0;
+
+}
+
+static void __mode(struct rb_node *n, struct mode *mp)
 {
-       clean_files(&all_files);
+       struct seek_bkt *sbp;
+
+       if (n->rb_left)
+               __mode(n->rb_left, mp);
+       if (n->rb_right)
+               __mode(n->rb_right, mp);
+
+       sbp = rb_entry(n, struct seek_bkt, rb_node);
+       if (mp->modes == NULL) {
+               mp->modes = malloc(sizeof(long long));
+               mp->nmds = 0;
+       } else if (sbp->nseeks > mp->most_seeks)
+               mp->nmds = 0;
+       else if (sbp->nseeks == mp->most_seeks)
+               mp->modes = realloc(mp->modes, (mp->nmds + 1) *
+                                                       sizeof(long long));
+       else
+               return;
+
+       mp->most_seeks = sbp->nseeks;
+       mp->modes[mp->nmds++] = sbp->sectors;
 }
 
 long long seek_dist(struct seeki *sip, struct io *iop)
@@ -67,127 +186,120 @@ long long seek_dist(struct seeki *sip, struct io *iop)
        long long dist;
        long long start = BIT_START(iop), end = BIT_END(iop);
 
-       /* Some overlap means no seek */
-       if (((sip->last_start <= start) && (start <= sip->last_end)) ||
-           ((sip->last_start <= end) && (end <= sip->last_end)))
-               dist = 0;
-       else if (start > sip->last_end)
+       if (seek_absolute)
                dist = start - sip->last_end;
-       else
-               dist = start - sip->last_start;
+       else {
+               /* Some overlap means no seek */
+               if (((sip->last_start <= start) && (start <= sip->last_end)) ||
+                   ((sip->last_start <= end) && (end <= sip->last_end)))
+                       dist = 0;
+               else if (start > sip->last_end)
+                       dist = start - sip->last_end;
+               else
+                       dist = start - sip->last_start;
+
+       }
 
        sip->last_start = start;
        sip->last_end = end;
        return dist;
 }
 
-void *seeki_init(__u32 device)
+void *seeki_alloc(char *str)
 {
        struct seeki *sip = malloc(sizeof(struct seeki));
 
-       sip->rfp = seek_open(device, 'r');
-       sip->wfp = seek_open(device, 'w');
-       sip->seek_bkts = NULL;
-       sip->nseek_bkts = 0;
-       sip->total_seeks = 0;
+       sip->rfp = seek_open(str, 'r');
+       sip->wfp = seek_open(str, 'w');
+       sip->cfp = seek_open(str, 'c');
+       sip->tot_seeks = 0;
        sip->total_sectors = 0.0;
        sip->last_start = sip->last_end = 0;
+       memset(&sip->root, 0, sizeof(sip->root));
+
+       if (sps_name) {
+               char *oname;
+
+               memset(&sip->sps, 0, sizeof(sip->sps));
+
+               oname = malloc(strlen(sps_name) + strlen(str) + 32);
+               sprintf(oname, "%s_%s.dat", sps_name, str);
+               if ((sip->sps_fp = my_fopen(oname, "w")) == NULL)
+                       perror(oname);
+               else
+                       add_file(sip->sps_fp, oname);
+       } else
+               sip->sps_fp = NULL;
 
        return sip;
 }
 
+void seeki_free(void *param)
+{
+       struct seeki *sip = param;
+
+       if (sip->sps_fp && sip->sps.nseeks != 0)
+               sps_emit(sip);
+
+       /*
+        * Associated files are cleaned up by seek_clean
+        */
+       __destroy(sip->root.rb_node);
+       free(sip);
+}
+
 void seeki_add(void *handle, struct io *iop)
 {
-       int left, mid, right;
-       struct seek_bkt *bkt;
        struct seeki *sip = handle;
+       char rw = IOP_READ(iop) ? 'r' : 'w';
        long long dist = seek_dist(sip, iop);
+       double tstamp = BIT_TIME(iop->t.time);
        FILE *fp = IOP_READ(iop) ? sip->rfp : sip->wfp;
 
        if (fp)
-               fprintf(fp, "%15.9lf %13lld\n", BIT_TIME(iop->t.time), dist);
+               fprintf(fp, "%15.9lf %13lld %c\n", tstamp, dist, rw);
+       if (sip->cfp)
+               fprintf(sip->cfp, "%15.9lf %13lld %c\n", tstamp, dist, rw);
 
        dist = llabs(dist);
-       sip->total_seeks++;
+       sip->tot_seeks++;
        sip->total_sectors += dist;
+       __insert(&sip->root, dist);
 
-       left = 0;
-       right = sip->nseek_bkts-1;
-       while (left <= right) {
-               mid = (left+right)/2;
-               bkt = &sip->seek_bkts[mid];
-               if (dist == bkt->sectors) {
-                       bkt->nseeks++;
-                       return;
-               }
-
-               if (dist > bkt->sectors)
-                       left = mid + 1;
-               else
-                       right = mid - 1;
-       }
-
-       sip->seek_bkts = realloc(sip->seek_bkts, 
-                                (sip->nseek_bkts+1) * sizeof(struct seek_bkt));
-       if (sip->nseek_bkts > left)
-               memmove(&sip->seek_bkts[left+1], &sip->seek_bkts[left], 
-                       (sip->nseek_bkts - left) * sizeof(struct seek_bkt));
-       (bkt = &sip->seek_bkts[left])->sectors = dist;
-       bkt->nseeks = 1;
-       sip->nseek_bkts++;
+       sps_add(sip, tstamp);
 }
 
 long long seeki_nseeks(void *handle)
 {
-       return ((struct seeki *)handle)->total_seeks;
+       return ((struct seeki *)handle)->tot_seeks;
 }
 
 double seeki_mean(void *handle)
 {
        struct seeki *sip = handle;
-       return sip->total_sectors / sip->total_seeks;
+       return sip->total_sectors / sip->tot_seeks;
 }
 
 long long seeki_median(void *handle)
 {
-       int i;
-       struct seek_bkt *p;
+       long long rval = 0LL;
        struct seeki *sip = handle;
-       long long sofar = 0, target = sip->total_seeks / 2;
 
-       if (sip->total_seeks == 0) return 0;
-       for (i = 0, p = sip->seek_bkts; i < sip->nseek_bkts; i++, p++)
-               if ((sofar + p->nseeks) < target)
-                       sofar += p->nseeks;
-               else
-                       break;
+       if (sip->root.rb_node)
+               (void)__median(sip->root.rb_node, 0LL, sip->tot_seeks / 2,
+                              &rval);
 
-       return p->sectors;
+       return rval;
 }
 
-int seeki_mode(void *handle, long long **modes_p, int *nseeks_p)
+int seeki_mode(void *handle, struct mode *mp)
 {
-       int i;
-       struct seek_bkt *p;
-       int most_seeks = 0;
        struct seeki *sip = handle;
-       int nmodes = 0;
-       long long *modes = NULL;
-
-       for (i = 0, p = sip->seek_bkts; i < sip->nseek_bkts; i++, p++)
-               if ((modes == NULL) || (p->nseeks > most_seeks)) {
-                       most_seeks = p->nseeks;
-                       modes = realloc(modes, sizeof(long long));
-                       *modes = p->sectors;
-                       nmodes = 1;
-               }
-               else if (p->nseeks == most_seeks) {
-                       most_seeks = p->nseeks;
-                       modes = realloc(modes, (nmodes+1) * sizeof(long long));
-                       modes[nmodes++] = p->sectors;
-               }
+       struct rb_root *root = &sip->root;
+
+       memset(mp, 0, sizeof(struct mode));
+       if (root->rb_node)
+               __mode(root->rb_node, mp);
 
-       *nseeks_p = most_seeks;
-       *modes_p = modes;
-       return nmodes;
+       return mp->nmds;
 }