#PLIBS = -lpthread
LIBS = $(PLIBS) $(ELIBS)
OBJS = bt_timeline.o args.o output.o proc.o trace.o misc.o devs.o \
- traverse.o iofree.o devmap.o cylist.o seek.o iostat.o latency.o
+ devmap.o seek.o iostat.o latency.o dip_rb.o rbtree.o
all: depend $(PROGS)
+rbtree.o: ../rbtree.c
+ $(CC) -o $*.o -c $(ALL_CFLAGS) $<
+
depend:
@$(CC) -MM $(ALL_CFLAGS) -I.. *.c 1> .depend
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
-
#include "globals.h"
#define S_OPTS "d:D:e:hi:I:l:M:o:q:s:S:Vv"
void handle_args(int argc, char *argv[])
{
int c;
- char *dev_map_fname = NULL;
while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) != -1) {
switch (c) {
sscanf(optarg, "%lf", &range_delta);
break;
case 'D':
- devices = optarg;
+ devices = strdup(optarg);
break;
case 'e':
- exes = optarg;
+ exes = strdup(optarg);
break;
case 'h':
usage(argv[0]);
exit(0);
case 'i':
- input_name = optarg;
+ input_name = strdup(optarg);
break;
case 'l':
- d2c_name = optarg;
+ d2c_name = strdup(optarg);
break;
case 'I':
- iostat_name = optarg;
+ iostat_name = strdup(optarg);
break;
case 'M':
- dev_map_fname = optarg;
+ if (dev_map_read(optarg))
+ exit(1);
break;
case 'o':
- output_name = optarg;
+ output_name = strdup(optarg);
break;
case 'q':
- q2c_name = optarg;
+ q2c_name = strdup(optarg);
break;
case 's':
- seek_name = optarg;
+ seek_name = strdup(optarg);
break;
case 'S': {
unsigned int interval;
sscanf(optarg, "%u", &interval);
- iostat_interval = (__u64)interval * (1000 * 1000 * 1000);
+ iostat_interval = (__u64)interval * 1000000000LL;
break;
}
case 'v':
exit(1);
}
- if (dev_map_fname && dev_map_read(dev_map_fname))
- exit(1);
-
if (output_name == NULL)
ranges_ofp = avgs_ofp = stdout;
else {
- char *fname = malloc(sizeof(output_name) + 20);
+ char *fname = malloc(strlen(output_name) + 32);
sprintf(fname, "%s.dat", output_name);
ranges_ofp = fopen(fname, "w");
exit(1);
}
if (verbose)
- printf("Sending range data to %s\n", output_name);
+ printf("Sending range data to %s.dat\n", output_name);
sprintf(fname, "%s.avg", output_name);
avgs_ofp = fopen(fname, "w");
exit(1);
}
if (verbose)
- printf("Sending stats data to %s\n", output_name);
+ printf("Sending stats data to %s.avg\n", output_name);
free(fname);
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
-
#include "globals.h"
char bt_timeline_version[] = "0.99";
-char *devices = NULL;
-char *exes = NULL;
-char *input_name = NULL;
-char *output_name = NULL;
-char *seek_name = NULL;
-char *d2c_name = NULL;
-char *q2c_name = NULL;
+char *devices, *exes, *input_name, *output_name, *seek_name;
+char *d2c_name, *q2c_name;
double range_delta = 0.1;
FILE *ranges_ofp, *avgs_ofp;
-int verbose = 0;
-int ifd;
-unsigned long n_traces, n_io_allocs, n_io_frees;
+int ifd, verbose = 0;
+unsigned long n_traces;
struct avgs_info all_avgs;
__u64 last_q = (__u64)-1;
-unsigned int pending_xs;
-
unsigned int n_devs;
+time_t genesis, last_vtrace;
LIST_HEAD(all_devs);
-LIST_HEAD(all_ios);
LIST_HEAD(all_procs);
-struct my_mem *free_ios = NULL;
-struct my_mem *free_bits = NULL;
+LIST_HEAD(free_ios);
struct region_info all_regions = {
.qranges = LIST_HEAD_INIT(all_regions.qranges),
.cr_cur = NULL
};
-char iop_map[] = { 'Q', 'X', 'A', 'M', 'I', 'D', 'C', 'Y' };
-
-struct blk_io_trace *convert_to_cpu(struct blk_io_trace *t);
int process(void);
int main(int argc, char *argv[])
{
handle_args(argc, argv);
- cy_init();
+ init_dev_heads();
iostat_init();
if (process() || output_avgs(avgs_ofp) || output_ranges(ranges_ofp))
return 1;
{
int ret = 0;
struct blk_io_trace *t;
- struct io *iop = IO_ZALLOC();
+ struct io *iop = io_alloc();
- while (!do_read(ifd, &iop->t, sizeof(iop->t))) {
+ genesis = last_vtrace = time(NULL);
+ while (!do_read(ifd, &iop->t, sizeof(struct blk_io_trace))) {
t = convert_to_cpu(&iop->t);
if (t->pdu_len > 0) {
iop->pdu = malloc(t->pdu_len);
if (do_read(ifd, iop->pdu, t->pdu_len)) {
- free(iop->pdu);
ret = 1;
break;
}
}
add_trace(iop);
- iop = IO_ZALLOC();
+ iop = io_alloc();
}
- IO_FREE(iop);
+ io_release(iop);
if (iostat_ofp) {
fprintf(iostat_ofp, "\n");
seek_clean();
latency_clean();
- if (verbose)
- printf("\n%10lu traces, %10lu mallocs %1lu frees\n",
- n_traces, n_io_allocs, n_io_frees);
+ if (verbose) {
+ double tps = (double)n_traces / (double)(time(NULL) - genesis);
+ printf("%10lu traces @ %.1lf Ktps\n", n_traces, tps/1000.0);
+ }
- cy_shutdown();
return ret;
}
+++ /dev/null
-/*
- * blktrace output analysis: generate a timeline & gather statistics
- *
- * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-#include "globals.h"
-
-struct cy_list {
- struct list_head head;
- struct list_head list;
-};
-
-struct cy_list *pending_cys;
-
-static inline void __rem_cy(struct io_list *iolp)
-{
- io_unlink(&iolp->iop);
- if (--iolp->cy_users == 0) {
- LIST_DEL(&iolp->head);
- free(iolp);
- }
-}
-
-void rem_c(struct io *iop)
-{
- struct list_head *p, *q;
- struct io_list *iolp;
-
- ASSERT(iop->type == IOP_C);
-
- list_for_each_safe(p, q, &pending_cys->list) {
- iolp = list_entry(p, struct io_list, head);
-
- if (iolp->iop == iop) {
- __rem_cy(iolp);
- break;
- }
- }
-}
-
-void run_cy_list(struct list_head *list)
-{
- struct list_head *p, *q;
- struct io_list *iolp;
-
- list_for_each_safe(p, q, list) {
- iolp = list_entry(p, struct io_list, head);
- traverse(iolp->iop);
- __rem_cy(iolp);
- }
-}
-
-void add_cy(struct io *iop)
-{
- struct io_list *iolp = malloc(sizeof(*iolp));
-
- ASSERT(iop->type == IOP_C || iop->type == IOP_Y);
-
- iolp->cy_users = 1;
- io_link(&iolp->iop, iop);
-
- list_add_tail(&iolp->head, &pending_cys->list);
- if (pending_xs == 0)
- run_cy_list(&pending_cys->list);
-}
-
-void cy_init(void)
-{
- pending_cys = zmalloc(sizeof(*pending_cys));
- INIT_LIST_HEAD(&pending_cys->list);
-}
-
-void cy_shutdown(void)
-{
- ASSERT(list_empty(&pending_cys->list));
- free(pending_cys);
-}
*
*/
#include <stdio.h>
-
#include "globals.h"
+
struct devmap *all_devmaps = NULL;
+
void dev_map_add(struct devmap *dmp)
{
- struct devmap *this = zmalloc(sizeof(*this));
+ struct devmap *this = malloc(sizeof(struct devmap));
*this = *dmp;
this->next = all_devmaps;
*
*/
#include <stdio.h>
-
#include "globals.h"
#define N_DEV_HASH 128
#define DEV_HASH(dev) ((MAJOR(dev) ^ MINOR(dev)) & (N_DEV_HASH - 1))
-struct list_head *dev_heads = NULL;
+struct list_head dev_heads[N_DEV_HASH];
-static void init_dev_heads(void)
+void init_dev_heads(void)
{
int i;
-
- dev_heads = zmalloc(N_DEV_HASH * sizeof(struct list_head));
for (i = 0; i < N_DEV_HASH; i++)
INIT_LIST_HEAD(&dev_heads[i]);
}
struct list_head *p;
struct d_info *dip;
- if (dev_heads == NULL) {
- init_dev_heads();
- return NULL;
- }
-
__list_for_each(p, &dev_heads[DEV_HASH(device)]) {
dip = list_entry(p, struct d_info, hash_head);
if (device == dip->device)
return NULL;
}
-struct d_info *dip_add(__u32 device, struct io *iop)
+struct d_info *dip_add(__u32 device, struct io *iop, int link)
{
struct d_info *dip = __dip_find(device);
if (dip == NULL) {
- int i;
-
- dip = zmalloc(sizeof(*dip));
+ dip = malloc(sizeof(struct d_info));
+ dip->heads = dip_rb_mkhds();
+ init_region(&dip->regions);
dip->device = device;
dip->last_q = (__u64)-1;
- for (i = 0; i < N_IOP_TYPES; i++)
- INIT_LIST_HEAD(&dip->iop_heads[i]);
- init_region(&dip->regions);
dip->map = dev_map_find(device);
dip->seek_handle = seeki_init(device);
latency_init(dip);
memset(&dip->stats, 0, sizeof(dip->stats));
memset(&dip->all_stats, 0, sizeof(dip->all_stats));
-
- if (dev_heads == NULL) init_dev_heads();
list_add_tail(&dip->hash_head, &dev_heads[DEV_HASH(device)]);
-
- list_add_tail(&dip->head, &all_devs);
+ list_add_tail(&dip->all_head, &all_devs);
n_devs++;
}
- list_add(&iop->dev_head, dip_get_head(dip, iop->type));
+ if (link)
+ dip_rb_ins(dip, iop);
return dip;
}
+
+void dip_rem(struct io *iop)
+{
+ dip_rb_rem(iop);
+}
+
+void dip_foreach(struct io *iop, enum iop_type type,
+ void (*fnc)(struct io *iop, struct io *this), int rm_after)
+{
+ if (rm_after) {
+ LIST_HEAD(head);
+ struct io *this;
+ struct list_head *p, *q;
+
+ dip_rb_fe(iop->dip, type, iop, fnc, &head);
+ list_for_each_safe(p, q, &head) {
+ this = list_entry(p, struct io, f_head);
+ LIST_DEL(&this->f_head);
+ io_release(this);
+ }
+ }
+ else
+ dip_rb_fe(iop->dip, type, iop, fnc, NULL);
+}
+
+struct io *dip_find_sec(struct d_info *dip, enum iop_type type, __u64 sec)
+{
+ return dip_rb_find_sec(dip, type, sec);
+}
+
+void dip_foreach_out(void (*func)(struct d_info *, void *), void *arg)
+{
+ if (devices == NULL) {
+ struct list_head *p;
+ __list_for_each(p, &all_devs)
+ func(list_entry(p, struct d_info, all_head), arg);
+ }
+ else {
+ int i;
+ struct d_info *dip;
+ unsigned int mjr, mnr;
+ char *p = devices;
+
+ while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
+ dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
+ ASSERT(dip);
+
+ func(dip, arg);
+
+ p = strchr(p, ';');
+ if (p) p++;
+ }
+ }
+}
--- /dev/null
+/*
+ * blktrace output analysis: generate a timeline & gather statistics
+ *
+ * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <stdio.h>
+#include "globals.h"
+
+void rb_insert(struct rb_root *root, struct io *iop)
+{
+ struct io *__iop;
+ struct rb_node *parent = NULL;
+ struct rb_node **p = &root->rb_node;
+ __u64 __s, s = BIT_START(iop);
+
+ ASSERT(root != NULL && iop != NULL);
+ while (*p) {
+ parent = *p;
+ __iop = rb_entry(parent, struct io, rb_node);
+ __s = BIT_START(__iop);
+
+ if (s < __s)
+ p = &(*p)->rb_left;
+ else if (s > __s)
+ p = &(*p)->rb_right;
+ else
+ p = &(*p)->rb_right;
+ }
+
+ rb_link_node(&iop->rb_node, parent, p);
+ rb_insert_color(&iop->rb_node, root);
+}
+
+struct io *rb_find_sec(struct rb_root *root, __u64 sec)
+{
+ struct io *__iop;
+ struct rb_node *n = root->rb_node;
+
+ while (n) {
+ __iop = rb_entry(n, struct io, rb_node);
+ if (sec < BIT_START(__iop))
+ n = n->rb_left;
+ else if (sec >= BIT_END(__iop))
+ n = n->rb_right;
+ else
+ return __iop;
+ }
+
+ return NULL;
+}
+
+void rb_foreach(struct rb_node *n, struct io *iop,
+ void (*fnc)(struct io *iop, struct io *this),
+ struct list_head *head)
+{
+ if (n) {
+ struct io *this = rb_entry(n, struct io, rb_node);
+ __u64 iop_s = BIT_START(iop), iop_e = BIT_END(iop);
+ __u64 this_s = BIT_START(this), this_e = BIT_END(this);
+
+ if ((iop_s <= this_s) && (this_e <= iop_e)) {
+ if (fnc) fnc(iop, this);
+ if (head) list_add_tail(&this->f_head, head);
+ }
+ if (iop_s < this_s)
+ rb_foreach(n->rb_left, iop, fnc, head);
+ if (this_e < iop_e)
+ rb_foreach(n->rb_right, iop, fnc, head);
+ }
+}
#include <assert.h>
#include <stdio.h>
#include <string.h>
+#include <time.h>
#include "blktrace.h"
+#include "rbtree.h"
#include "list.h"
-#define pdu_start(t) (((void *) (t) + sizeof(struct blk_io_trace)))
-
#define BIT_TIME(t) ((double)SECONDS(t) + ((double)NANO_SECONDS(t) / 1.0e9))
#define BIT_START(iop) ((iop)->t.sector)
#define TO_MSEC(nanosec) (1000.0 * TO_SEC(nanosec))
#if defined(DEBUG)
+#define DBG_PING() dbg_ping()
#define ASSERT(truth) do { \
if (!(truth)) { \
DBG_PING(); \
} \
} while (0)
-#define DBG_PING() dbg_ping()
#define LIST_DEL(hp) list_del(hp)
-
#else
#define ASSERT(truth)
#define DBG_PING()
-
#define LIST_DEL(hp) do { \
if (((hp)->next != NULL) && \
((hp)->next != LIST_POISON1)) \
} while (0)
#endif
-#define IO_ZALLOC() my_zmalloc(&free_ios, sizeof(struct io))
-#define IO_FREE(iop) my_free(&free_ios, iop)
-
enum iop_type {
IOP_Q = 0,
IOP_X = 1,
IOP_I = 4,
IOP_D = 5,
IOP_C = 6,
- IOP_Y = 7,
+ IOP_R = 7,
};
-#define N_IOP_TYPES (IOP_Y + 1)
+#define N_IOP_TYPES (IOP_R + 1)
struct file_info {
struct file_info *next;
FILE *ofp;
- char *oname;
+ char oname[1];
};
-struct my_mem {
- struct my_mem *next;
+struct mode {
+ int most_seeks, nmds;
+ long long *modes;
};
struct io;
struct range_info *qr_cur, *cr_cur;
};
-struct p_info;
-struct p_pid {
- struct list_head head;
- struct p_info *pip;
- __u32 pid;
-};
-
struct p_info {
- struct list_head head;
struct region_info regions;
struct avgs_info avgs;
- char *name;
__u64 last_q;
+ __u32 pid;
+ char name[1];
};
struct devmap {
struct devmap *next;
- char device[32];
+ unsigned int host, bus, target, lun, irq, cpu;
char model[64];
- unsigned int host, bus, target, lun;
- char node[32], pci[32];
- unsigned int irq, cpu;
- char devno[32];
+ char device[32], node[32], pci[32], devno[32];
};
struct stats {
- __u64 rqm[2];
- __u64 ios[2];
- __u64 sec[2];
- __u64 wait;
- __u64 svctm;
-
- int cur_qusz, cur_dev;
+ __u64 rqm[2], ios[2], sec[2], wait, svctm;
double last_qu_change, last_dev_change, tot_qusz, idle_time;
+ int cur_qusz, cur_dev;
};
struct d_info {
- struct list_head head, hash_head;
- struct list_head iop_heads[N_IOP_TYPES];
+ struct list_head all_head, hash_head;
+ void *heads;
struct region_info regions;
- struct avgs_info avgs;
- __u64 last_q;
- __u32 device;
- __u64 n_ds;
struct devmap *map;
void *seek_handle;
FILE *d2c_ofp, *q2c_ofp;
+ struct avgs_info avgs;
struct stats stats, all_stats;
+ __u64 last_q, n_ds;
+ __u32 device;
};
struct io {
- struct list_head all_head, dev_head;
+ struct rb_node rb_node;
+ struct list_head f_head;
struct d_info *dip;
struct p_info *pip;
- void *pdu;
-
struct blk_io_trace t;
-
- int users, traversed;
+ void *pdu;
enum iop_type type;
-
- union {
- struct {
- union {
- struct io *q_a;
- struct io *q_x;
- } qp;
- enum {
- Q_NONE = 10,
- Q_A = 20,
- Q_X = 30,
- } qp_type;
- } q;
- struct {
- union {
- struct io *a_q;
- struct io *a_a;
- } ap;
- enum {
- A_NONE = 10,
- A_A = 20,
- A_Q = 30,
- } ap_type;
- } a;
- struct { struct io *x_q; } x;
- struct { struct io *m_q; } m;
- struct { struct list_head i_qs_head; } i;
- struct { struct list_head d_im_head; } d;
- struct { struct io *c_d; } c;
- struct { struct io *y_c1, *y_c2; } y;
- } u;
+ int linked;
};
+/* bt_timeline.c */
+
extern char bt_timeline_version[], *devices, *exes, *input_name, *output_name;
extern char *seek_name, *iostat_name, *d2c_name, *q2c_name;
extern double range_delta;
extern FILE *ranges_ofp, *avgs_ofp, *iostat_ofp;
extern int verbose, ifd;
extern unsigned int n_devs;
-extern unsigned long n_traces, n_io_allocs, n_io_frees;
-extern struct list_head all_devs, all_ios, all_procs;
+extern unsigned long n_traces;
+extern struct list_head all_devs, all_procs;
extern struct avgs_info all_avgs;
extern __u64 last_q;
extern struct region_info all_regions;
-extern struct my_mem *free_ios, *free_bits;
-extern char iop_map[];
-extern unsigned int pending_xs;
+extern struct list_head free_ios;
extern __u64 iostat_interval, iostat_last_stamp;
+extern time_t genesis, last_vtrace;
-void add_trace(struct io *iop);
-int in_devices(struct blk_io_trace *t);
-char *make_dev_hdr(char *pad, size_t len, struct d_info *dip);
-int output_avgs(FILE *ofp);
-int output_ranges(FILE *ofp);
-unsigned int do_read(int ifd, void *buf, int len);
-void add_process(__u32 pid, char *name);
-struct p_info *find_process(__u32 pid, char *name);
-void pip_update_q(struct io *iop);
+/* args.c */
void handle_args(int argc, char *argv[]);
-struct devmap *dev_map_find(__u32 device);
+
+/* dev_map.c */
int dev_map_read(char *fname);
-void add_cy(struct io *iop);
-void rem_c(struct io *iop);
-void cy_init(void);
-void cy_shutdown(void);
-struct d_info *__dip_find(__u32 device);
-struct d_info *dip_add(__u32 device, struct io *iop);
-void traverse(struct io *iop);
-void io_free_resources(struct io *iop);
-void *seeki_init(__u32 device);
-void seek_clean(void);
-void seeki_add(void *handle, struct io *iop);
-double seeki_mean(void *handle);
-long long seeki_nseeks(void *handle);
-long long seeki_median(void *handle);
-int seeki_mode(void *handle, long long **modes_p, int *nseeks_p);
-void add_file(struct file_info **fipp, FILE *fp, char *oname);
-void clean_files(struct file_info **fipp);
+struct devmap *dev_map_find(__u32 device);
+/* devs.c */
+void init_dev_heads(void);
+struct d_info *dip_add(__u32 device, struct io *iop, int link);
+void dip_rem(struct io *iop);
+struct d_info *__dip_find(__u32 device);
+void dip_foreach(struct io *iop, enum iop_type type,
+ void (*fnc)(struct io *iop, struct io *this), int rm_after);
+struct io *dip_find_sec(struct d_info *dip, enum iop_type type, __u64 sec);
+void dip_foreach_out(void (*func)(struct d_info *, void *), void *arg);
+
+/* dip_rb.c */
+void rb_insert(struct rb_root *root, struct io *iop);
+struct io *rb_find_sec(struct rb_root *root, __u64 sec);
+void rb_foreach(struct rb_node *n, struct io *iop,
+ void (*fnc)(struct io *iop, struct io *this),
+ struct list_head *head);
+
+/* iostat.c */
void iostat_init(void);
void iostat_insert(struct io *iop);
void iostat_merge(struct io *iop);
void iostat_issue(struct io *iop);
-void iostat_complete(struct io *iop);
+void iostat_unissue(struct io *iop);
+void iostat_complete(struct io *d_iop, struct io *c_iop);
void iostat_check_time(__u64 stamp);
void iostat_dump_stats(__u64 stamp, int all);
+/* latency.c */
void latency_init(struct d_info *dip);
void latency_clean(void);
void latency_d2c(struct d_info *dip, __u64 tstamp, __u64 latency);
void latency_q2c(struct d_info *dip, __u64 tstamp, __u64 latency);
+/* misc.c */
+struct blk_io_trace *convert_to_cpu(struct blk_io_trace *t);
+int in_devices(struct blk_io_trace *t);
+unsigned int do_read(int ifd, void *buf, int len);
+void add_file(struct file_info **fipp, FILE *fp, char *oname);
+void clean_files(struct file_info **fipp);
+void dbg_ping(void);
+
+/* output.c */
+int output_avgs(FILE *ofp);
+int output_ranges(FILE *ofp);
+char *make_dev_hdr(char *pad, size_t len, struct d_info *dip);
+
+/* proc.c */
+void add_process(__u32 pid, char *name);
+struct p_info *find_process(__u32 pid, char *name);
+void pip_update_q(struct io *iop);
+void pip_foreach_out(void (*f)(struct p_info *, void *), void *arg);
+
+/* seek.c */
+void *seeki_init(__u32 device);
+void seek_clean(void);
+void seeki_add(void *handle, struct io *iop);
+double seeki_mean(void *handle);
+long long seeki_nseeks(void *handle);
+long long seeki_median(void *handle);
+int seeki_mode(void *handle, struct mode *mp);
+
+/* trace.c */
+void add_trace(struct io *iop);
+
#include "inlines.h"
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-static inline void dbg_ping(void) { }
-
-static inline void *zmalloc(size_t len)
-{
- return memset(malloc(len), 0, len);
-}
-
-static inline int is_dev(struct io *iop, unsigned int mjr, unsigned int mnr)
-{
- return MAJOR(iop->t.device) == mjr && MINOR(iop->t.device) == mnr;
-}
-
-static inline int in_bit(struct io *in, struct io *out)
-{
- return (BIT_START(out) <= BIT_START(in)) &&
- (BIT_END(in) <= BIT_END(out));
-}
-
-static inline int is_bit(struct io *i1, struct io *i2)
-{
- return (BIT_START(i1) == BIT_START(i2)) && (BIT_END(i1) == BIT_END(i2));
-}
static inline struct range_info *new_cur(__u64 time)
{
- struct range_info *cur = zmalloc(sizeof(*cur));
+ struct range_info *cur = malloc(sizeof(struct range_info));
INIT_LIST_HEAD(&cur->head);
cur->start = time;
return cur;
}
-static inline void update_range(struct list_head *head_p,
- struct range_info **cur_p, __u64 time)
+static inline void update_range(struct list_head *head_p,
+ struct range_info **cur_p, __u64 time)
{
if (*cur_p == NULL)
*cur_p = new_cur(time);
}
}
+static inline void avg_unupdate(struct avg_info *ap, __u64 t)
+{
+ ap->n--;
+ ap->total -= t;
+}
+
static inline void update_lq(__u64 *last_q, struct avg_info *avg, __u64 time)
{
if (*last_q != ((__u64)-1))
*last_q = time;
}
-static inline struct list_head *dip_get_head(struct d_info *dip,
- enum iop_type type)
-{
- return &dip->iop_heads[type];
-}
-
-static inline struct list_head *dip_get_head_dev(__u32 dev, enum iop_type type)
-{
- struct d_info *dip = __dip_find(dev);
-
- if (!dip)
- return NULL;
- return dip_get_head(__dip_find(dev), type);
-}
-
static inline void dip_update_q(struct d_info *dip, struct io *iop)
{
update_lq(&dip->last_q, &dip->avgs.q2q, iop->t.time);
update_qregion(&dip->regions, iop->t.time);
}
-static inline void dip_rem(struct io *iop)
-{
- LIST_DEL(&iop->dev_head);
-}
-
-static inline void *my_malloc(struct my_mem **head_p, size_t len)
+static inline struct io *io_alloc(void)
{
- struct my_mem *this = *head_p;
+ struct io *iop;
- if (this)
- *head_p = this->next;
+ if (!list_empty(&free_ios)) {
+ iop = list_entry(free_ios.next, struct io, f_head);
+ LIST_DEL(&iop->f_head);
+ }
else
- this = malloc(len);
+ iop = malloc(sizeof(struct io));
- return this;
+ return memset(iop, 0, sizeof(struct io));
}
-static inline void *my_zmalloc(struct my_mem **head_p, size_t len)
-{
- return memset(my_malloc(head_p, len), 0, len);
-}
-
-static inline void my_free(struct my_mem **head_p, void *p)
+static inline void io_free(struct io *iop)
{
- struct my_mem *this = p;
-
- this->next = *head_p;
- *head_p = this;
+ list_add_tail(&iop->f_head, &free_ios);
}
-static inline void io_setup(struct io *iop, enum iop_type type)
+static inline void io_setup(struct io *iop, enum iop_type type, int link)
{
iop->type = type;
- iop->dip = dip_add(iop->t.device, iop);
+ iop->dip = dip_add(iop->t.device, iop, link);
iop->pip = find_process(iop->t.pid, NULL);
-
- n_io_allocs++;
- list_add_tail(&iop->all_head, &all_ios);
-}
-
-static inline void io_free(struct io *iop)
-{
- ASSERT(iop->users == 0);
-
- LIST_DEL(&iop->all_head);
- dip_rem(iop);
- IO_FREE(iop);
- n_io_frees++;
+ iop->linked = link;
}
-static inline void io_get(struct io *iop)
+static inline void io_release(struct io *iop)
{
- iop->users++;
-}
-
-
-static inline int __io_put(struct io *iop)
-{
- return --iop->users;
-}
-
-static inline void io_put(struct io *iop)
-{
- if (__io_put(iop) == 0) {
- io_free_resources(iop);
- io_free(iop);
+ if (iop->linked) {
+ dip_rem(iop);
+ iop->linked = 0;
}
-}
-
-static inline void io_link(struct io **p_dst, struct io *iop)
-{
- ASSERT(iop != NULL);
- io_get(iop);
- *p_dst = iop;
-}
-
-static inline void io_unlink(struct io **p_dst)
-{
- ASSERT(*p_dst != NULL);
- io_put(*p_dst);
-
-#if defined(DEBUG)
- *p_dst = NULL;
-#endif
+ if (iop->pdu)
+ free(iop->pdu);
+ io_free(iop);
}
#define UPDATE_AVGS(_avg, _iop, _pip, _time) do { \
if (_pip) avg_update(&_pip->avgs. _avg , _time); \
} while (0)
+#define UNUPDATE_AVGS(_avg, _iop, _pip, _time) do { \
+ avg_unupdate(&all_avgs. _avg , _time); \
+ avg_unupdate(&_iop->dip->avgs. _avg , _time); \
+ if (_pip) avg_unupdate(&_pip->avgs. _avg , _time); \
+ } while (0)
+
static inline void update_q2c(struct io *iop, __u64 c_time)
{
UPDATE_AVGS(q2c, iop, iop->pip, c_time);
UPDATE_AVGS(i2d, iop, iop->pip, d_time);
}
+static inline void unupdate_i2d(struct io *iop, __u64 d_time)
+{
+ UNUPDATE_AVGS(i2d, iop, iop->pip, d_time);
+}
+
static inline void update_d2c(struct io *iop, __u64 c_time)
{
UPDATE_AVGS(d2c, iop, iop->pip, c_time);
{
__u64 nblks = iop->t.bytes >> 9;
avg_update(&all_avgs.blks, nblks);
+ ASSERT(iop->dip != NULL);
avg_update(&iop->dip->avgs.blks, nblks);
if (iop->pip)
avg_update(&iop->pip->avgs.blks, nblks);
}
+
+static inline struct rb_root *__get_root(struct d_info *dip, enum iop_type type)
+{
+ struct rb_root *roots = dip->heads;
+ return &roots[type];
+}
+
+static inline void *dip_rb_mkhds(void)
+{
+ size_t len = N_IOP_TYPES * sizeof(struct rb_root);
+ return memset(malloc(len), 0, len);
+}
+
+static inline void dip_rb_ins(struct d_info *dip, struct io *iop)
+{
+ rb_insert(__get_root(dip, iop->type), iop);
+}
+
+static inline void dip_rb_rem(struct io *iop)
+{
+ rb_erase(&iop->rb_node, __get_root(iop->dip, iop->type));
+}
+
+static inline void dip_rb_fe(struct d_info *dip, enum iop_type type,
+ struct io *iop,
+ void (*fnc)(struct io *iop, struct io *this),
+ struct list_head *head)
+{
+ rb_foreach(__get_root(dip, type)->rb_node, iop, fnc, head);
+}
+
+static inline struct io *dip_rb_find_sec(struct d_info *dip,
+ enum iop_type type, __u64 sec)
+{
+ return rb_find_sec(__get_root(dip, type), sec);
+}
+++ /dev/null
-/*
- * blktrace output analysis: generate a timeline & gather statistics
- *
- * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-#include <stdio.h>
-
-#include "globals.h"
-
-void io_free_resources(struct io *iop)
-{
- switch (iop->type) {
- case IOP_X: io_unlink(&iop->u.x.x_q); break;
- case IOP_M: io_unlink(&iop->u.m.m_q); break;
- case IOP_C: io_unlink(&iop->u.c.c_d); break;
-
- case IOP_A:
- switch (iop->u.a.ap_type) {
- case A_NONE: break;
- case A_Q: io_unlink(&iop->u.a.ap.a_q); break;
- case A_A: io_unlink(&iop->u.a.ap.a_a); break;
- default:
- ASSERT(0);
- /*NOTREACHED*/
- }
- break;
-
- case IOP_Q:
- switch (iop->u.q.qp_type) {
- case Q_NONE: break;
- case Q_A: io_unlink(&iop->u.q.qp.q_a); break;
- case Q_X: io_unlink(&iop->u.q.qp.q_x); break;
- default:
- ASSERT(0);
- /*NOTREACHED*/
- }
- break;
-
- case IOP_D: {
- struct io_list *iolp;
- struct list_head *p, *q;
-
- list_for_each_safe(p, q, &iop->u.d.d_im_head) {
- iolp = list_entry(p, struct io_list, head);
- io_unlink(&iolp->iop);
-
- LIST_DEL(&iolp->head);
- free(iolp);
- }
- break;
- }
-
- case IOP_I: {
- struct io_list *iolp;
- struct list_head *p, *q;
-
- list_for_each_safe(p, q, &iop->u.i.i_qs_head) {
- iolp = list_entry(p, struct io_list, head);
- io_unlink(&iolp->iop);
-
- LIST_DEL(&iolp->head);
- free(iolp);
- }
- break;
- }
-
- case IOP_Y:
- io_unlink(&iop->u.y.y_c1);
- io_unlink(&iop->u.y.y_c2);
- break;
-
- default:
- ASSERT(0);
- /*NOTREACHED*/
- }
-}
char *iostat_name = NULL;
FILE *iostat_ofp = NULL;
-void calc_waits(struct io *d_iop, __u64 c_time)
-{
- __u64 waits = 0;
- struct list_head *p;
- struct io_list *iolp;
-
- __list_for_each(p, &d_iop->u.d.d_im_head) {
- iolp = list_entry(p, struct io_list, head);
- waits += (c_time - iolp->iop->t.time);
- }
- ADD_STAT(d_iop->dip, wait, waits);
-}
-
void dump_hdr(void)
{
fprintf(iostat_ofp, "Device: rrqm/s wrqm/s r/s w/s "
"avgrq-sz avgqu-sz await svctm %%util Stamp\n");
}
+void im2d2c_func(struct io *c_iop, struct io *im_iop)
+{
+ ADD_STAT(c_iop->dip, wait, c_iop->t.time - im_iop->t.time);
+}
+
void iostat_init(void)
{
last_start = (__u64)-1;
struct list_head *p;
__list_for_each(p, &all_devs) {
- dip = list_entry(p, struct d_info, head);
+ dip = list_entry(p, struct d_info, all_head);
__dump_stats(stamp, all, dip);
}
}
}
if (!all && iostat_ofp)
fprintf(iostat_ofp, "\n");
-
}
void iostat_check_time(__u64 stamp)
INC_STAT(dip, cur_dev);
}
-void iostat_complete(struct io *iop)
+void iostat_unissue(struct io *iop)
{
- struct io *d_iop;
+ int rw = IOP_RW(iop);
struct d_info *dip = iop->dip;
- if ((d_iop = iop->u.c.c_d) != NULL) {
- double now = TO_SEC(iop->t.time);
- calc_waits(d_iop, iop->t.time);
+ DEC_STAT(dip, ios[rw]);
+ SUB_STAT(dip, sec[rw], iop->t.bytes >> 9);
+ DEC_STAT(dip, cur_dev);
+}
- update_tot_qusz(dip, now);
- DEC_STAT(dip, cur_qusz);
+void iostat_complete(struct io *d_iop, struct io *c_iop)
+{
+ double now = TO_SEC(c_iop->t.time);
+ struct d_info *dip = d_iop->dip;
- update_idle_time(dip, now, 0);
- DEC_STAT(dip, cur_dev);
+ dip_foreach(d_iop, IOP_I, im2d2c_func, 0);
+ dip_foreach(d_iop, IOP_M, im2d2c_func, 0);
- ADD_STAT(dip, svctm, iop->t.time - d_iop->t.time);
- }
+ update_tot_qusz(dip, now);
+ DEC_STAT(dip, cur_qusz);
+
+ update_idle_time(dip, now, 0);
+ DEC_STAT(dip, cur_dev);
+
+ ADD_STAT(dip, svctm, c_iop->t.time - d_iop->t.time);
}
void add_file(struct file_info **fipp, FILE *fp, char *oname)
{
- struct file_info *fip = malloc(sizeof(struct file_info));
+ struct file_info *fip;
+
+ fip = malloc(sizeof(struct file_info) + strlen(oname) + 1);
- fip->ofp = fp;
- fip->oname = oname;
fip->next = *fipp;
*fipp = fip;
+
+ fip->ofp = fp;
+ strcpy(fip->oname, oname);
}
void clean_files(struct file_info **fipp)
fclose(fip->ofp);
if (!stat(fip->oname, &buf) && (buf.st_size == 0))
unlink(fip->oname);
- free(fip->oname);
free(fip);
}
}
+
+void dbg_ping(void) {}
}
}
+void __pip_output_avg2(struct p_info *pip, void *arg)
+{
+ __output_avg2((FILE *)arg, pip->name, &pip->avgs);
+}
+
+void __dip_output_avg2(struct d_info *dip, void *arg)
+{
+ char dev_info[12];
+ __output_avg2((FILE *)arg, make_dev_hdr(dev_info, 12, dip), &dip->avgs);
+}
+
char *make_dev_hdr(char *pad, size_t len, struct d_info *dip)
{
if (dip->map == NULL)
return pad;
}
-void __output_dip_avg(FILE *ofp, struct d_info *dip, struct avg_info *ap)
+struct __oda {
+ FILE *ofp;
+ ai_dip_t (*func)(struct d_info *);
+};
+void __output_dip_avg(struct d_info *dip, void *arg)
{
+ struct __oda *odap = arg;
+ ai_dip_t ap = odap->func(dip);
if (ap->n > 0) {
char dev_info[12];
ap->avg = BIT_TIME(ap->total) / (double)ap->n;
- __output_avg(ofp, make_dev_hdr(dev_info, 12, dip), ap);
+ __output_avg(odap->ofp, make_dev_hdr(dev_info, 12, dip), ap);
}
}
void output_dip_avg(FILE *ofp, char *hdr, ai_dip_t (*func)(struct d_info *))
{
- struct d_info *dip;
-
+ struct __oda oda = { .ofp = ofp, .func = func};
output_hdr(ofp, hdr);
- if (devices == NULL) {
- struct list_head *p;
-
- __list_for_each(p, &all_devs) {
- dip = list_entry(p, struct d_info, head);
- __output_dip_avg(ofp, dip, func(dip));
- }
- }
- else {
- int i;
- unsigned int mjr, mnr;
- char *p = devices;
-
- while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
- dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
- __output_dip_avg(ofp, dip, func(dip));
-
- p = strchr(p, ';');
- if (p) p++;
- }
- }
-
+ dip_foreach_out(__output_dip_avg, &oda);
fprintf(ofp, "\n");
}
-void __output_dip_merge_ratio(FILE *ofp, struct d_info *dip)
+void __output_dip_merge_ratio(struct d_info *dip, void *arg)
{
double blks_avg;
char scratch[12];
if (q2c_n > 0.0 && d2c_n > 0.0) {
ratio = q2c_n / d2c_n;
blks_avg = (double)dip->avgs.blks.total / d2c_n;
- fprintf(ofp, "%10s | %8llu %8llu %7.1lf | %8llu %8llu %8llu %8llu\n",
+ fprintf((FILE *)arg,
+ "%10s | %8llu %8llu %7.1lf | %8llu %8llu %8llu %8llu\n",
make_dev_hdr(scratch, 12, dip),
(unsigned long long)dip->avgs.q2c.n,
(unsigned long long)dip->n_ds,
void output_dip_merge_ratio(FILE *ofp)
{
- struct d_info *dip;
-
fprintf(ofp, "%10s | %8s %8s %7s | %8s %8s %8s %8s\n", "DEV", "#Q", "#D", "Ratio", "BLKmin", "BLKavg", "BLKmax", "Total");
fprintf(ofp, "---------- | -------- -------- ------- | -------- -------- -------- --------\n");
- if (devices == NULL) {
- struct list_head *p;
-
- __list_for_each(p, &all_devs) {
- dip = list_entry(p, struct d_info, head);
- __output_dip_merge_ratio(ofp, dip);
- }
- }
- else {
- int i;
- unsigned int mjr, mnr;
- char *p = devices;
-
- while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
- dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
- __output_dip_merge_ratio(ofp, dip);
-
- p = strchr(p, ';');
- if (p) p++;
- }
- }
-
+ dip_foreach_out(__output_dip_merge_ratio, ofp);
fprintf(ofp, "\n");
}
return s;
}
-void __output_dip_prep_ohead(FILE *ofp, struct d_info *dip)
+void __output_dip_prep_ohead(struct d_info *dip, void *arg)
{
char dev_info[12];
char s1[16], s2[16], s3[16];
CALC_AVG(&dip->avgs.i2d);
CALC_AVG(&dip->avgs.d2c);
- fprintf(ofp, "%10s | %6s %6s %6s\n",
+ fprintf((FILE *)arg, "%10s | %6s %6s %6s\n",
make_dev_hdr(dev_info, 12, dip),
q2i_v_q2C(dip, s1), i2d_v_q2C(dip, s2),
d2c_v_q2C(dip, s3));
void output_dip_prep_ohead(FILE *ofp)
{
- struct d_info *dip;
-
fprintf(ofp, "%10s | %6s %6s %6s\n", "DEV", "Q2I", "I2D", "D2C");
fprintf(ofp, "---------- | ------ ------ ------\n");
-
- if (devices == NULL) {
- struct list_head *p;
-
- __list_for_each(p, &all_devs) {
- dip = list_entry(p, struct d_info, head);
- __output_dip_prep_ohead(ofp, dip);
- }
- }
- else {
- int i;
- unsigned int mjr, mnr;
- char *p = devices;
-
- while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
- dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
- __output_dip_prep_ohead(ofp, dip);
-
- p = strchr(p, ';');
- if (p) p++;
- }
- }
-
+ dip_foreach_out(__output_dip_prep_ohead, ofp);
fprintf(ofp, "\n");
}
-void __output_dip_seek_info(FILE *ofp, struct d_info *dip)
+void __output_dip_seek_info(struct d_info *dip, void *arg)
{
double mean;
- int i, nmodes, most_seeks;
+ int i, nmodes;
long long nseeks;
char dev_info[12];
- long long median, *modes;
+ long long median;
+ struct mode m;
+ FILE *ofp = arg;
nseeks = seeki_nseeks(dip->seek_handle);
if (nseeks > 0) {
mean = seeki_mean(dip->seek_handle);
median = seeki_median(dip->seek_handle);
- nmodes = seeki_mode(dip->seek_handle, &modes, &most_seeks);
+ nmodes = seeki_mode(dip->seek_handle, &m);
fprintf(ofp, "%10s | %15lld %15.1lf %15lld | %lld(%d)",
make_dev_hdr(dev_info, 12, dip), nseeks, mean, median,
- nmodes > 0 ? modes[0] : 0, most_seeks);
+ nmodes > 0 ? m.modes[0] : 0, m.most_seeks);
for (i = 1; i < nmodes; i++)
- fprintf(ofp, " %lld", modes[i]);
+ fprintf(ofp, " %lld", m.modes[i]);
fprintf(ofp, "\n");
}
}
void output_dip_seek_info(FILE *ofp)
{
- struct d_info *dip;
-
fprintf(ofp, "%10s | %15s %15s %15s | %-15s\n", "DEV", "NSEEKS",
"MEAN", "MEDIAN", "MODE");
fprintf(ofp, "---------- "
"| --------------- --------------- --------------- "
"| ---------------\n");
-
- if (devices == NULL) {
- struct list_head *p;
-
- __list_for_each(p, &all_devs) {
- dip = list_entry(p, struct d_info, head);
- __output_dip_seek_info(ofp, dip);
- }
- }
- else {
- int i;
- unsigned int mjr, mnr;
- char *p = devices;
-
- while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
- dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
- __output_dip_seek_info(ofp, dip);
-
- p = strchr(p, ';');
- if (p) p++;
- }
- }
-
+ dip_foreach_out(__output_dip_seek_info, ofp);
fprintf(ofp, "\n");
}
-void __output_pip_avg(FILE *ofp, struct p_info *pip, struct avg_info *ap)
+struct __opa {
+ FILE *ofp;
+ ai_pip_t (*func)(struct p_info *);
+};
+
+void __output_pip_avg(struct p_info *pip, void *arg)
{
+ struct __opa *opap = arg;
+ ai_pip_t ap = opap->func(pip);
+
if (ap->n > 0) {
char proc_name[12];
snprintf(proc_name, 12, pip->name);
ap->avg = BIT_TIME(ap->total) / (double)ap->n;
- __output_avg(ofp, proc_name, ap);
+ __output_avg(opap->ofp, proc_name, ap);
}
}
void output_pip_avg(FILE *ofp, char *hdr, ai_pip_t (*func)(struct p_info *))
{
- struct p_info *pip;
+ struct __opa opa = { .ofp = ofp, .func = func };
output_hdr(ofp, hdr);
- if (exes == NULL) {
- struct list_head *p;
-
- __list_for_each(p, &all_procs) {
- pip = list_entry(p, struct p_info, head);
- __output_pip_avg(ofp, pip, func(pip));
- }
- }
- else {
- char *exe, *p, *next, *exes_save = strdup(exes);
-
- p = exes_save;
- while (exes_save != NULL) {
- exe = exes_save;
- if ((next = strchr(exes_save, ',')) != NULL) {
- *next = '\0';
- exes_save = next+1;
- }
- else
- exes_save = NULL;
-
- pip = find_process((__u32)-1, exe);
- if (pip)
- __output_pip_avg(ofp, pip, func(pip));
- }
- }
-
+ pip_foreach_out(__output_pip_avg, &opa);
fprintf(ofp, "\n");
}
void output_dip_avgs(FILE *ofp)
{
- char dev_info[12];
- struct d_info *dip;
-
output_hdr2(ofp,"Dev");
- if (devices == NULL) {
- struct list_head *p;
-
- __list_for_each(p, &all_devs) {
- dip = list_entry(p, struct d_info, head);
- __output_avg2(ofp, make_dev_hdr(dev_info, 12, dip),
- &dip->avgs);
- }
- }
- else {
- int i;
- unsigned int mjr, mnr;
- char *p = devices;
-
- while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
- dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
- __output_avg2(ofp, make_dev_hdr(dev_info, 12, dip),
- &dip->avgs);
-
- p = strchr(p, ';');
- if (p) p++;
- }
- }
-
+ dip_foreach_out(__dip_output_avg2, ofp);
fprintf(ofp, "\n");
}
void output_pip_avgs(FILE *ofp)
{
- char exe[16];
- struct p_info *pip;
-
output_hdr2(ofp,"Exe");
- if (exes == NULL) {
- struct list_head *p;
-
- __list_for_each(p, &all_procs) {
- pip = list_entry(p, struct p_info, head);
- snprintf(exe, 12, pip->name);
- __output_avg2(ofp, exe, &pip->avgs);
- }
- }
- else {
- char *exe, *p, *next, *exes_save = strdup(exes);
-
- p = exes_save;
- while (exes_save != NULL && *exes_save != '\0') {
- exe = exes_save;
- if ((next = strchr(exes_save, ',')) != NULL) {
- *next = '\0';
- exes_save = next+1;
- }
- else
- exes_save = NULL;
-
- pip = find_process((__u32)-1, exe);
- if (pip) {
- snprintf(exe, 12, pip->name);
- __output_avg2(ofp, exe, &pip->avgs);
- }
- }
- }
-
+ pip_foreach_out(__pip_output_avg2, ofp);
fprintf(ofp, "\n");
}
output_section_hdr(ofp, "Device Overhead");
output_dip_prep_ohead(ofp);
- output_section_hdr(ofp, "Device Seek Information");
- output_dip_seek_info(ofp);
+ if (seek_name) {
+ output_section_hdr(ofp, "Device Seek Information");
+ output_dip_seek_info(ofp);
+ }
return 0;
}
return 1;
}
-float __output_dev(FILE *ofp, struct d_info *dip, float base)
+struct __od {
+ FILE *ofp;
+ float base;
+};
+void __output_dev(struct d_info *dip, void *arg)
{
char header[128];
- sprintf(header, "%d,%d", MAJOR(dip->device), MINOR(dip->device));
- if (output_regions(ofp, header, &dip->regions, base))
- base += 1.0;
+ struct __od *odp = arg;
- return base;
+ sprintf(header, "%d,%d", MAJOR(dip->device), MINOR(dip->device));
+ if (output_regions(odp->ofp, header, &dip->regions, odp->base))
+ odp->base += 1.0;
}
float output_devs(FILE *ofp, float base)
{
- struct d_info *dip;
+ struct __od od = { .ofp = ofp, .base = base };
fprintf(ofp, "# Per device\n" );
- if (devices == NULL) {
- struct list_head *p;
- __list_for_each(p, &all_devs) {
- dip = list_entry(p, struct d_info, head);
- base = __output_dev(ofp, dip, base);
- }
- }
- else {
- int i;
- unsigned int mjr, mnr;
- char *p = devices;
-
- while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
- dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
- ASSERT(dip);
-
- base = __output_dev(ofp, dip, base);
-
- p = strchr(p, ';');
- if (p) p++;
- }
- }
-
- return base;
+ dip_foreach_out(__output_dev, &od);
+ return od.base;
}
static inline int exe_match(char *exe, char *name)
return (exe == NULL) || (strstr(name, exe) != NULL);
}
-float __output_procs(FILE *ofp, float base, char *match)
+struct __op {
+ FILE *ofp;
+ float base;
+};
+void __output_procs(struct p_info *pip, void *arg)
{
- struct p_info *pip;
- struct list_head *p;
-
- __list_for_each(p, &all_procs) {
- pip = list_entry(p, struct p_info, head);
-
- if (exe_match(match, pip->name) &&
- output_regions(ofp, pip->name,
- &pip->regions, base))
- base += 1.0;
- }
-
- return base;
+ struct __op *opp = arg;
+ output_regions(opp->ofp, pip->name, &pip->regions, opp->base);
+ opp->base += 1.0;
}
float output_procs(FILE *ofp, float base)
{
- fprintf(ofp, "# Per process\n" );
- if (exes == NULL)
- base = __output_procs(ofp, base, NULL);
- else {
- char *exe, *next, *p, *exes_save = strdup(exes);
-
- p = exes_save;
- while (exes_save != NULL) {
- exe = exes_save;
- if ((next = strchr(exes_save, ',')) != NULL) {
- *next = '\0';
- exes_save = next+1;
- }
- else
- exes_save = NULL;
-
- base = __output_procs(ofp, base, exe);
- }
- free(p);
- }
+ struct __op op = { .ofp = ofp, .base = base };
- return base;
+ fprintf(ofp, "# Per process\n" );
+ pip_foreach_out(__output_procs, &op);
+ return op.base;
}
int output_ranges(FILE *ofp)
#include "globals.h"
-#define N_PID_HASH 128
-#define PID_HASH(pid) ((pid) & (N_PID_HASH-1))
-struct list_head *pid_heads = NULL;
+struct pn_info {
+ struct rb_node rb_node;
+ struct p_info *pip;
+ union {
+ char *name;
+ __u32 pid;
+ } u;
+};
+
+struct rb_root root_pid, root_name;
-static void init_pid_heads(void)
+struct p_info * __find_process_pid(__u32 pid)
{
- int i;
+ struct pn_info *this;
+ struct rb_node *n = root_pid.rb_node;
+
+ while (n) {
+ this = rb_entry(n, struct pn_info, rb_node);
+ if (pid < this->u.pid)
+ n = n->rb_left;
+ else if (pid > this->u.pid)
+ n = n->rb_right;
+ else
+ return this->pip;
+ }
- pid_heads = zmalloc(N_PID_HASH * sizeof(struct list_head));
- for (i = 0; i < N_PID_HASH; i++)
- INIT_LIST_HEAD(&pid_heads[i]);
+ return NULL;
}
-static inline struct p_info *pid_to_proc(__u32 pid)
+struct p_info *__find_process_name(char *name)
{
- struct p_pid *pp;
- struct list_head *p, *head;
-
- if (pid_heads == NULL) init_pid_heads();
-
- head = &pid_heads[PID_HASH(pid)];
- __list_for_each(p, head) {
- pp = list_entry(p, struct p_pid, head);
- if (pp->pid == pid)
- return pp->pip;
+ int cmp;
+ struct pn_info *this;
+ struct rb_node *n = root_name.rb_node;
+
+ while (n) {
+ this = rb_entry(n, struct pn_info, rb_node);
+ cmp = strcmp(name, this->u.name);
+ if (cmp < 0)
+ n = n->rb_left;
+ else if (cmp > 0)
+ n = n->rb_right;
+ else
+ return this->pip;
}
return NULL;
}
-void insert_proc_hash(struct p_info *pip, __u32 pid)
+struct p_info *find_process(__u32 pid, char *name)
{
- struct p_pid *pp = zmalloc(sizeof(*pp));
+ struct p_info *pip;
- if (pid_heads == NULL) init_pid_heads();
+ if (pid != ((__u32)-1) && ((pip = __find_process_pid(pid)) != NULL))
+ return pip;
- pp->pip = pip;
- pp->pid = pid;
+ if (name)
+ return __find_process_name(name);
- list_add_tail(&pp->head, &pid_heads[PID_HASH(pid)]);
+ return NULL;
}
-int __find_process_pid(__u32 pid)
+static void insert_pid(struct p_info *that)
{
- return pid_to_proc(pid) != NULL;
+ struct pn_info *this;
+ struct rb_node *parent = NULL;
+ struct rb_node **p = &root_pid.rb_node;
+
+ while (*p) {
+ parent = *p;
+ this = rb_entry(parent, struct pn_info, rb_node);
+
+ if (that->pid < this->u.pid)
+ p = &(*p)->rb_left;
+ else if (that->pid > this->u.pid)
+ p = &(*p)->rb_right;
+ else {
+ ASSERT(strcmp(that->name, this->pip->name) == 0);
+ return; // Already there
+ }
+ }
+
+ this = malloc(sizeof(struct pn_info));
+ this->u.pid = that->pid;
+ this->pip = that;
+
+ rb_link_node(&this->rb_node, parent, p);
+ rb_insert_color(&this->rb_node, &root_pid);
}
-struct p_info *find_process(__u32 pid, char *name)
+static void insert_name(struct p_info *that)
{
- struct p_info *pip;
- struct list_head *p;
+ int cmp;
+ struct pn_info *this;
+ struct rb_node *parent = NULL;
+ struct rb_node **p = &root_name.rb_node;
+
+ while (*p) {
+ parent = *p;
+ this = rb_entry(parent, struct pn_info, rb_node);
+ cmp = strcmp(that->name, this->u.name);
+
+ if (cmp < 0)
+ p = &(*p)->rb_left;
+ else if (cmp > 0)
+ p = &(*p)->rb_right;
+ else
+ return; // Already there...
+ }
- if (pid != ((__u32)-1) && (pip = pid_to_proc(pid)))
- return pip;
+ this = malloc(sizeof(struct pn_info));
+ this->u.name = strdup(that->name);
+ this->pip = that;
- if (name) {
- __list_for_each(p, &all_procs) {
- pip = list_entry(p, struct p_info, head);
- if (name && !strcmp(pip->name, name)) {
- if (pid != ((__u32)-1))
- insert_proc_hash(pip, pid);
- return pip;
- }
- }
- }
+ rb_link_node(&this->rb_node, parent, p);
+ rb_insert_color(&this->rb_node, &root_name);
+}
- return NULL;
+static void insert(struct p_info *pip)
+{
+ insert_pid(pip);
+ insert_name(pip);
}
void add_process(__u32 pid, char *name)
struct p_info *pip = find_process(pid, name);
if (pip == NULL) {
- pip = zmalloc(sizeof(*pip));
+ size_t len = sizeof(struct p_info) + strlen(name) + 1;
- list_add_tail(&pip->head, &all_procs);
- insert_proc_hash(pip, pid);
- pip->last_q = (__u64)-1;
- pip->name = strdup(name);
+ pip = memset(malloc(len), 0, len);
+ pip->pid = pid;
init_region(&pip->regions);
+ pip->last_q = (__u64)-1;
+ strcpy(pip->name, name);
+
+ insert(pip);
}
}
update_qregion(&iop->pip->regions, iop->t.time);
}
}
+
+void __foreach(struct rb_node *n, void (*f)(struct p_info *, void *), void *arg)
+{
+ if (n) {
+ __foreach(n->rb_left, f, arg);
+ f(rb_entry(n, struct pn_info, rb_node)->pip, arg);
+ __foreach(n->rb_right, f, arg);
+ }
+}
+
+void pip_foreach_out(void (*f)(struct p_info *, void *), void *arg)
+{
+ if (exes == NULL)
+ __foreach(root_name.rb_node, f, arg);
+ else {
+ struct p_info *pip;
+ char *exe, *p, *next, *exes_save = strdup(exes);
+
+ p = exes_save;
+ while (exes_save != NULL) {
+ exe = exes_save;
+ if ((next = strchr(exes_save, ',')) != NULL) {
+ *next = '\0';
+ exes_save = next+1;
+ }
+ else
+ exes_save = NULL;
+
+ pip = __find_process_name(exe);
+ if (pip)
+ f(pip, arg);
+ }
+ }
+}
*/
#include "globals.h"
-static struct file_info *all_files = NULL;
+static struct file_info *seek_files = NULL;
struct seek_bkt {
+ struct rb_node rb_node;
long long sectors;
int nseeks;
};
struct seeki {
FILE *rfp, *wfp;
- struct seek_bkt *seek_bkts;
- int nseek_bkts;
- long long total_seeks;
+ struct rb_root root;
+ long long tot_seeks;
double total_sectors;
long long last_start, last_end;
};
-FILE *seek_open(__u32 device, char rw)
+static FILE *seek_open(__u32 device, char rw)
{
FILE *fp;
char *oname;
if ((fp = fopen(oname, "w")) == NULL)
perror(oname);
else
- add_file(&all_files, fp, oname);
+ add_file(&seek_files, fp, oname);
return fp;
}
+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);
+}
+
void seek_clean(void)
{
- clean_files(&all_files);
+ clean_files(&seek_files);
}
long long seek_dist(struct seeki *sip, struct io *iop)
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->tot_seeks = 0;
sip->total_sectors = 0.0;
sip->last_start = sip->last_end = 0;
+ memset(&sip->root, 0, sizeof(sip->root));
return sip;
}
void seeki_add(void *handle, struct io *iop)
{
- int left, mid, right;
- struct seek_bkt *bkt;
struct seeki *sip = handle;
long long dist = seek_dist(sip, iop);
FILE *fp = IOP_READ(iop) ? sip->rfp : sip->wfp;
fprintf(fp, "%15.9lf %13lld\n", BIT_TIME(iop->t.time), dist);
dist = llabs(dist);
- sip->total_seeks++;
+ sip->tot_seeks++;
sip->total_sectors += 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++;
+ __insert(&sip->root, dist);
}
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;
+}
+
+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;
+
}
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)
+void __mode(struct rb_node *n, struct mode *mp)
+{
+ 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;
+}
+
+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;
}
*/
#include "globals.h"
-static inline void release_iop(struct io *iop)
+void im2d_func(struct io *d_iop, struct io *im_iop)
{
- if (iop->pdu) free(iop->pdu);
- IO_FREE(iop);
+ update_i2d(im_iop, d_iop->t.time - im_iop->t.time);
}
-struct io *dip_find_exact(struct list_head *head, struct io *iop_in)
+void q2c_func(struct io *c_iop, struct io *q_iop)
{
- struct io *iop;
- struct list_head *p;
+ __u64 q2c = c_iop->t.time - q_iop->t.time;
- if (head != NULL) __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;
-
- if (head != NULL) __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;
-
- if (head != NULL) __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;
-
- if (head != NULL) __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;
-
- if (head != NULL) __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;
-
- if (head != NULL) __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;
+ update_q2c(q_iop, q2c);
+ latency_q2c(q_iop->dip, q_iop->t.time, q2c);
}
-void dip_add_ms(struct list_head *head, struct io *d_iop)
-{
- struct io *m_iop;
- struct list_head *p;
- struct io_list *iolp;
-
- if (head != NULL) __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)
+static inline void handle_im(struct io *im_iop)
{
struct io *q_iop;
- struct list_head *p;
- struct io_list *iolp;
- if (head != NULL) __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);
- }
- }
+ q_iop = dip_find_sec(im_iop->dip, IOP_Q, BIT_START(im_iop));
+ if (q_iop)
+ update_q2i(q_iop, im_iop->t.time - q_iop->t.time);
}
-void handle_queue(struct io *iop)
+void handle_queue(struct io *q_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;
+ io_setup(q_iop, IOP_Q, 1);
+ update_lq(&last_q, &all_avgs.q2q, q_iop->t.time);
+ update_qregion(&all_regions, q_iop->t.time);
+ dip_update_q(q_iop->dip, q_iop);
+ pip_update_q(q_iop);
}
-void handle_merge(struct io *iop)
+void handle_remap(struct io *a_iop)
{
struct io *q_iop;
+ struct blk_io_trace_remap *rp = a_iop->pdu;
+ struct d_info *dip = __dip_find(be32_to_cpu(rp->device));
- io_setup(iop, IOP_M);
-
- q_iop = dip_find_exact(dip_get_head(iop->dip, IOP_Q), iop);
+ io_setup(a_iop, IOP_A, 0);
+ q_iop = dip_find_sec(dip, IOP_Q, be64_to_cpu(rp->sector));
if (q_iop)
- io_link(&iop->u.m.m_q, q_iop);
-
- iostat_merge(iop);
+ update_q2a(q_iop, a_iop->t.time - q_iop->t.time);
+ io_release(a_iop);
}
-void handle_insert(struct io *iop)
+void handle_insert(struct io *i_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);
-
- iostat_insert(iop);
+ io_setup(i_iop, IOP_I, 1);
+ iostat_insert(i_iop);
+ handle_im(i_iop);
}
-void handle_complete(struct io *iop)
+void handle_merge(struct io *m_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);
- iostat_complete(iop);
- add_cy(iop);
- }
- else
- io_free(iop);
+ io_setup(m_iop, IOP_M, 1);
+ iostat_merge(m_iop);
+ handle_im(m_iop);
}
-void handle_issue(struct io *iop)
+void handle_issue(struct io *d_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);
- seeki_add(iop->dip->seek_handle, iop);
-
- iostat_issue(iop);
-}
-
-void handle_split(struct io *iop)
-{
- struct io *q_iop;
+ io_setup(d_iop, IOP_D, 1);
+ d_iop->dip->n_ds++;
- pending_xs++;
- io_setup(iop, IOP_X);
+ dip_foreach(d_iop, IOP_I, im2d_func, 0);
+ dip_foreach(d_iop, IOP_M, im2d_func, 0);
- 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 (seek_name)
+ seeki_add(d_iop->dip->seek_handle, d_iop);
+ iostat_issue(d_iop);
}
-void handle_remap(struct io *iop)
+void handle_complete(struct io *c_iop)
{
- struct io *q_iop, *a_iop;
- struct blk_io_trace_remap *rp = iop->pdu;
- __u32 dev = be32_to_cpu(rp->device);
- __u64 sector = be64_to_cpu(rp->sector);
+ struct io *d_iop;
- io_setup(iop, IOP_A);
- q_iop = dip_find_in_sec(dip_get_head_dev(dev, IOP_Q), sector);
- if (q_iop) {
- iop->u.a.ap_type = A_Q;
- io_link(&iop->u.a.ap.a_q, q_iop);
- return;
- }
+ io_setup(c_iop, IOP_C, 0);
+ update_blks(c_iop);
+ update_cregion(&all_regions, c_iop->t.time);
+ update_cregion(&c_iop->dip->regions, c_iop->t.time);
+ if (c_iop->pip)
+ update_cregion(&c_iop->pip->regions, c_iop->t.time);
- a_iop = dip_find_in_sec(dip_get_head_dev(dev, IOP_A), sector);
- if (a_iop) {
- iop->u.a.ap_type = A_A;
- io_link(&iop->u.a.ap.a_a, a_iop);
- return;
+ d_iop = dip_find_sec(c_iop->dip, IOP_D, BIT_START(c_iop));
+ if (d_iop) {
+ __u64 d2c = c_iop->t.time - d_iop->t.time;
+ update_d2c(d_iop, d2c);
+ latency_d2c(d_iop->dip, c_iop->t.time, d2c);
+ iostat_complete(d_iop, c_iop);
+ dip_foreach(d_iop, IOP_I, NULL, 1);
+ dip_foreach(d_iop, IOP_M, NULL, 1);
+ io_release(d_iop);
}
- iop->u.a.ap_type = A_NONE;
+ dip_foreach(c_iop, IOP_Q, q2c_func, 1);
+ io_release(c_iop);
}
-void extract_i(struct io *i_iop)
+void rq_im2d_func(struct io *d_iop, struct io *im_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);
- }
+ unupdate_i2d(im_iop, d_iop->t.time - im_iop->t.time);
}
/*
* 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)
+ * (2) Need to leave I's Q and M's Q's
+ * (3) XXX: Need to downward adjust stats, but we don't carry PREVIOUS
+ * XXX: min/maxes?! We'll just adjust what we can, and hope that
+ * XXX: the min/maxes are "pretty close". (REQUEUEs are rare, right?)
*/
-void handle_requeue(struct io *iop)
+void handle_requeue(struct io *r_iop)
{
struct io *d_iop;
- struct io_list *iolp;
- struct list_head *p, *q;
- d_iop = dip_find_start(dip_get_head_dev(iop->t.device, IOP_D),
- iop->t.sector);
+ io_setup(r_iop, IOP_R, 0);
+ d_iop = dip_find_sec(r_iop->dip, IOP_D, BIT_START(r_iop));
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 (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);
+ dip_foreach(d_iop, IOP_I, rq_im2d_func, 1);
+ dip_foreach(d_iop, IOP_M, rq_im2d_func, 1);
+ iostat_unissue(d_iop);
+ io_release(d_iop);
}
-
- release_iop(iop);
-
+ io_release(r_iop);
}
void __add_trace(struct io *iop)
{
- n_traces++;
+ time_t now = time(NULL);
+ n_traces++;
iostat_check_time(iop->t.time);
- 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 (verbose && ((now - last_vtrace) > 0)) {
+ printf("%10lu t\r", n_traces);
if ((n_traces % 1000000) == 0) printf("\n");
+ fflush(stdout);
+ last_vtrace = now;
}
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;
- case __BLK_TA_REMAP: handle_remap(iop); break;
- case __BLK_TA_REQUEUE: handle_requeue(iop); break;
+ 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_REMAP: handle_remap(iop); break;
+ case __BLK_TA_REQUEUE: handle_requeue(iop); break;
+ default: io_release(iop); break;
}
}
if (slash)
*slash = '\0';
+
add_process(iop->t.pid, iop->pdu);
- release_iop(iop);
+ io_release(iop);
}
else if (iop->t.action & BLK_TC_ACT(BLK_TC_PC))
- release_iop(iop);
+ io_release(iop);
else
__add_trace(iop);
}
+++ /dev/null
-/*
- * blktrace output analysis: generate a timeline & gather statistics
- *
- * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-#include "globals.h"
-
-int tl_map[] = {
- IOP_Q,
- IOP_A, /* IOP_X */
- IOP_A,
- IOP_I, /* IOP_M */
- IOP_I,
- IOP_D,
- IOP_C,
- IOP_Y,
-};
-
-
-typedef void (*iop_func_t)(__u64 *, struct io*);
-
-void iop_q_func(__u64 *timeline, struct io *iop);
-void iop_x_func(__u64 *timeline, struct io *iop);
-void iop_a_func(__u64 *timeline, struct io *iop);
-void iop_m_func(__u64 *timeline, struct io *iop);
-void iop_i_func(__u64 *timeline, struct io *iop);
-void iop_d_func(__u64 *timeline, struct io *iop);
-void iop_c_func(__u64 *timeline, struct io *iop);
-void iop_y_func(__u64 *timeline, struct io *iop);
-
-iop_func_t traverse_func[] = {
- iop_q_func,
- iop_x_func,
- iop_a_func,
- iop_m_func,
- iop_i_func,
- iop_d_func,
- iop_c_func,
- iop_y_func,
-};
-
-void __traverse(__u64 *timeline, struct io *iop)
-{
- if (iop != NULL && !iop->traversed) {
- iop->traversed++;
- timeline[tl_map[iop->type]] = iop->t.time;
- (traverse_func[iop->type])(timeline, iop);
- timeline[tl_map[iop->type]] = 0;
- }
-}
-
-void traverse(struct io *iop)
-{
- __u64 timeline[N_IOP_TYPES];
-
- memset(timeline, 0, N_IOP_TYPES * sizeof(__u64));
- __traverse(timeline, iop);
-}
-
-void iop_q_update(__u64 *timeline, struct io *iop, __u64 q_time)
-{
- __u64 q2c = timeline[IOP_C] - q_time;
-
- update_q2c(iop, q2c);
- latency_q2c(iop->dip, iop->t.time, q2c);
-
- if (timeline[IOP_A] > 0.0) // IOP_X too
- update_q2a(iop, timeline[IOP_A] - q_time);
- else //IOP_M too
- update_q2i(iop, timeline[IOP_I] - q_time);
-
- update_i2d(iop, timeline[IOP_D] - timeline[IOP_I]);
-}
-
-void iop_q_func(__u64 *timeline, struct io *iop)
-{
- iop_q_update(timeline, iop, iop->t.time);
- if (iop->u.q.qp_type == Q_A)
- __traverse(timeline, iop->u.q.qp.q_a);
- else if (iop->u.q.qp_type == Q_X)
- __traverse(timeline, iop->u.q.qp.q_x);
-}
-
-void iop_x_func(__u64 *timeline, struct io *iop)
-{
- __traverse(timeline, iop->u.x.x_q);
-}
-
-void iop_a_func(__u64 *timeline, struct io *iop)
-{
- if (iop->u.a.ap_type == A_Q)
- __traverse(timeline, iop->u.a.ap.a_q);
- else if (iop->u.a.ap_type == A_A)
- __traverse(timeline, iop->u.a.ap.a_a);
-}
-
-void iop_m_func(__u64 *timeline, struct io *iop)
-{
- __traverse(timeline, iop->u.m.m_q);
-}
-
-void iop_i_func(__u64 *timeline, struct io *iop)
-{
- struct list_head *p;
- struct io_list *iolp;
-
- __list_for_each(p, &iop->u.i.i_qs_head) {
- iolp = list_entry(p, struct io_list, head);
- __traverse(timeline, iolp->iop);
- }
-}
-
-void iop_d_func(__u64 *timeline, struct io *iop)
-{
- struct list_head *p;
- struct io_list *iolp;
- __u64 d2c = timeline[IOP_C] - iop->t.time;
-
- __list_for_each(p, &iop->u.d.d_im_head) {
- iolp = list_entry(p, struct io_list, head);
- __traverse(timeline, iolp->iop);
- }
-
- update_d2c(iop, d2c);
- latency_d2c(iop->dip, iop->t.time, d2c);
-}
-
-void iop_c_func(__u64 *timeline, struct io *iop)
-{
- __traverse(timeline, iop->u.c.c_d);
-}
-
-void iop_y_func(__u64 *timeline, struct io *iop)
-{
- __traverse(timeline, iop->u.y.y_c1);
- __traverse(timeline, iop->u.y.y_c2);
-}