static unsigned int rt_threshold = 1000000;
static unsigned int ios_threshold = 10;
static int output_ascii = 1;
+static char *filename;
struct bs {
unsigned int bs;
uint64_t first_ttime;
uint64_t last_ttime;
- struct trace_file *files;
- int nr_files;
- unsigned int last_major, last_minor;
-
uint64_t start_delay;
};
struct flist_head hash_list;
struct flist_head pid_list;
pid_t pid;
+
+ struct trace_file *files;
+ int nr_files;
+ unsigned int last_major, last_minor;
+
struct btrace_out o;
};
static struct flist_head pid_hash[PID_HASH_SIZE];
static FLIST_HEAD(pid_list);
-static FLIST_HEAD(inflight_list);
+#define INFLIGHT_HASH_BITS 8
+#define INFLIGHT_HASH_SIZE (1U << INFLIGHT_HASH_BITS)
+static struct flist_head inflight_hash[INFLIGHT_HASH_SIZE];
static uint64_t first_ttime = -1ULL;
static struct inflight *inflight_find(uint64_t sector)
{
+ struct flist_head *inflight_list;
struct flist_head *e;
- flist_for_each(e, &inflight_list) {
+ inflight_list = &inflight_hash[hash_long(sector, INFLIGHT_HASH_BITS)];
+
+ flist_for_each(e, inflight_list) {
struct inflight *i = flist_entry(e, struct inflight, list);
if (i->end_sector == sector)
free(i);
}
-static void inflight_merge(struct inflight *i, int rw, unsigned int size)
+static void __inflight_add(struct inflight *i)
{
- i->p->o.merges[rw]++;
- if (size)
- i->end_sector += (size >> 9);
+ struct flist_head *list;
+
+ list = &inflight_hash[hash_long(i->end_sector, INFLIGHT_HASH_BITS)];
+ flist_add_tail(&i->list, list);
}
static void inflight_add(struct btrace_pid *p, uint64_t sector, uint32_t len)
o->inflight++;
o->depth = max((int) o->depth, o->inflight);
i->end_sector = sector + (len >> 9);
- flist_add_tail(&i->list, &inflight_list);
+ __inflight_add(i);
+}
+
+static void inflight_merge(struct inflight *i, int rw, unsigned int size)
+{
+ i->p->o.merges[rw]++;
+ if (size) {
+ i->end_sector += (size >> 9);
+ flist_del(&i->list);
+ __inflight_add(i);
+ }
}
/*
case BLK_TN_MESSAGE:
break;
default:
- fprintf(stderr, "unknown trace act %x\n", t->action);
+ log_err("unknown trace act %x\n", t->action);
break;
}
}
#define FMAJOR(dev) ((unsigned int) ((dev) >> FMINORBITS))
#define FMINOR(dev) ((unsigned int) ((dev) & FMINORMASK))
-static void btrace_add_file(struct btrace_out *o, uint32_t devno)
+static void btrace_add_file(struct btrace_pid *p, uint32_t devno)
{
unsigned int maj = FMAJOR(devno);
unsigned int min = FMINOR(devno);
unsigned int i;
char dev[256];
- if (o->last_major == maj && o->last_minor == min)
+ if (filename)
+ return;
+ if (p->last_major == maj && p->last_minor == min)
return;
- o->last_major = maj;
- o->last_minor = min;
+ p->last_major = maj;
+ p->last_minor = min;
/*
* check for this file in our list
*/
- for (i = 0; i < o->nr_files; i++) {
- f = &o->files[i];
+ for (i = 0; i < p->nr_files; i++) {
+ f = &p->files[i];
if (f->major == maj && f->minor == min)
return;
return;
}
- o->files = realloc(o->files, (o->nr_files + 1) * sizeof(*f));
- f = &o->files[o->nr_files];
+ p->files = realloc(p->files, (p->nr_files + 1) * sizeof(*f));
+ f = &p->files[p->nr_files];
f->name = strdup(dev);
f->major = maj;
f->minor = min;
- o->nr_files++;
+ p->nr_files++;
}
-static void handle_trace_discard(struct blk_io_trace *t, struct btrace_out *o)
+static void handle_trace_discard(struct blk_io_trace *t, struct btrace_pid *p)
{
- btrace_add_file(o, t->device);
+ struct btrace_out *o = &p->o;
+
+ btrace_add_file(p, t->device);
if (o->first_ttime == -1ULL)
o->first_ttime = t->time;
add_bs(o, t->bytes, DDIR_TRIM);
}
-static void handle_trace_fs(struct blk_io_trace *t, struct btrace_out *o)
+static void handle_trace_fs(struct blk_io_trace *t, struct btrace_pid *p)
{
+ struct btrace_out *o = &p->o;
int rw;
- btrace_add_file(o, t->device);
+ btrace_add_file(p, t->device);
first_ttime = min(first_ttime, (uint64_t) t->time);
o->last_end[rw] = t->sector + (t->bytes >> 9);
}
-static void handle_queue_trace(struct blk_io_trace *t, struct btrace_out *o)
+static void handle_queue_trace(struct blk_io_trace *t, struct btrace_pid *p)
{
if (t->action & BLK_TC_ACT(BLK_TC_NOTIFY))
handle_trace_notify(t);
else if (t->action & BLK_TC_ACT(BLK_TC_DISCARD))
- handle_trace_discard(t, o);
+ handle_trace_discard(t, p);
else
- handle_trace_fs(t, o);
+ handle_trace_fs(t, p);
}
static void handle_trace(struct blk_io_trace *t, struct btrace_pid *p)
if (act == __BLK_TA_QUEUE) {
inflight_add(p, t->sector, t->bytes);
- handle_queue_trace(t, &p->o);
+ handle_queue_trace(t, p);
} else if (act == __BLK_TA_REQUEUE) {
p->o.inflight--;
} else if (act == __BLK_TA_BACKMERGE) {
else if (!ret)
break;
else if (ret < (int) sizeof(t)) {
- fprintf(stderr, "fio: short fifo get\n");
+ log_err("fio: short fifo get\n");
break;
}
byteswap_trace(&t);
if ((t.magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) {
- fprintf(stderr, "fio: bad magic in blktrace data: %x\n",
- t.magic);
+ log_err("fio: bad magic in blktrace data: %x\n", t.magic);
goto err;
}
if ((t.magic & 0xff) != BLK_IO_TRACE_VERSION) {
- fprintf(stderr, "fio: bad blktrace version %d\n",
- t.magic & 0xff);
+ log_err("fio: bad blktrace version %d\n", t.magic & 0xff);
goto err;
}
ret = discard_pdu(fifo, fd, &t);
if (ret < 0) {
- fprintf(stderr, "blktrace lseek\n");
+ log_err("blktrace lseek\n");
goto err;
} else if (t.pdu_len != ret) {
- fprintf(stderr, "fio: discarded %d of %d\n", ret, t.pdu_len);
+ log_err("fio: discarded %d of %d\n", ret, t.pdu_len);
goto err;
}
printf("usec:\t%llu (delay=%llu)\n", (o->last_ttime - o->first_ttime) / 1000ULL, (unsigned long long) o->start_delay);
printf("files:\t");
- for (i = 0; i < o->nr_files; i++)
- printf("%s,", o->files[i].name);
+ for (i = 0; i < p->nr_files; i++)
+ printf("%s,", p->files[i].name);
printf("\n");
printf("\n");
printf("rwmixread=%u\n", (int) (perc + 0.99));
}
- printf("percentage_sequential=");
+ printf("percentage_random=");
for (i = 0; i < DDIR_RWDIR_CNT; i++) {
if (o->seq[i] && o->ios[i]) {
perc = ((float) o->seq[i] * 100.0) / (float) o->ios[i];
if (i)
printf(",");
+ perc = 100.0 - perc;
printf("%u", (int) perc);
}
printf("\n");
printf("filename=");
- for (i = 0; i < o->nr_files; i++) {
+ for (i = 0; i < p->nr_files; i++) {
if (i)
printf(":");
- printf("%s", o->files[i].name);
+ printf("%s", p->files[i].name);
}
printf("\n");
qsort(o->bs[i], o->nr_bs[i], sizeof(struct bs), bs_cmp);
}
+ if (filename) {
+ p->files = malloc(sizeof(struct trace_file));
+ p->nr_files++;
+ p->files[0].name = filename;
+ }
+
if (output_ascii)
__output_p_ascii(p, ios);
else
return ddir_rw_sum(pb->o.ios) - ddir_rw_sum(pa->o.ios);
}
+static void free_p(struct btrace_pid *p)
+{
+ struct btrace_out *o = &p->o;
+ int i;
+
+ for (i = 0; i < p->nr_files; i++) {
+ if (p->files[i].name && p->files[i].name != filename)
+ free(p->files[i].name);
+ }
+
+ for (i = 0; i < DDIR_RWDIR_CNT; i++)
+ free(o->bs[i]);
+
+ free(p->files);
+ flist_del(&p->pid_list);
+ flist_del(&p->hash_list);
+ free(p);
+}
+
static int output_p(void)
{
unsigned long ios[DDIR_RWDIR_CNT];
p = flist_entry(e, struct btrace_pid, pid_list);
if (prune_entry(&p->o)) {
- flist_del(&p->pid_list);
- flist_del(&p->hash_list);
- free(p);
+ free_p(p);
continue;
}
p->o.start_delay = (p->o.first_ttime / 1000ULL) - first_ttime;
static int usage(char *argv[])
{
- fprintf(stderr, "%s: <blktrace bin file>\n", argv[0]);
- fprintf(stderr, "\t-t\tUsec threshold to ignore task\n");
- fprintf(stderr, "\t-n\tNumber IOS threshold to ignore task\n");
- fprintf(stderr, "\t-f\tFio job file output\n");
+ log_err("%s: <blktrace bin file>\n", argv[0]);
+ log_err("\t-t\tUsec threshold to ignore task\n");
+ log_err("\t-n\tNumber IOS threshold to ignore task\n");
+ log_err("\t-f\tFio job file output\n");
+ log_err("\t-d\tUse this file/device for replay\n");
return 1;
}
-int main(int argc, char *argv[])
+static int trace_needs_swap(const char *trace_file, int *swap)
{
- int fd, ret, need_swap = -1;
struct blk_io_trace t;
- int i, c;
-
- if (argc < 2)
- return usage(argv);
-
- while ((c = getopt(argc, argv, "t:n:f")) != -1) {
- switch (c) {
- case 't':
- rt_threshold = atoi(optarg);
- break;
- case 'n':
- ios_threshold = atoi(optarg);
- break;
- case 'f':
- output_ascii = 0;
- break;
- case '?':
- default:
- return usage(argv);
- }
- }
+ int fd, ret;
- if (argc == optind)
- return usage(argv);
-
- fd = open(argv[optind], O_RDONLY);
+ *swap = -1;
+
+ fd = open(trace_file, O_RDONLY);
if (fd < 0) {
perror("open");
return 1;
perror("read");
return 1;
} else if (ret != sizeof(t)) {
- fprintf(stderr, "fio: short read on trace file\n");
+ log_err("fio: short read on trace file\n");
return 1;
}
close(fd);
if ((t.magic & 0xffffff00) == BLK_IO_TRACE_MAGIC)
- need_swap = 0;
+ *swap = 0;
else {
/*
* Maybe it needs to be endian swapped...
*/
t.magic = fio_swap32(t.magic);
if ((t.magic & 0xffffff00) == BLK_IO_TRACE_MAGIC)
- need_swap = 1;
+ *swap = 1;
}
- if (need_swap == -1) {
- fprintf(stderr, "fio: blktrace appears corrupt\n");
+ if (*swap == -1) {
+ log_err("fio: blktrace appears corrupt\n");
return 1;
}
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int need_swap, i, c;
+
+ if (argc < 2)
+ return usage(argv);
+
+ while ((c = getopt(argc, argv, "t:n:fd:")) != -1) {
+ switch (c) {
+ case 't':
+ rt_threshold = atoi(optarg);
+ break;
+ case 'n':
+ ios_threshold = atoi(optarg);
+ break;
+ case 'f':
+ output_ascii = 0;
+ break;
+ case 'd':
+ filename = strdup(optarg);
+ break;
+ case '?':
+ default:
+ return usage(argv);
+ }
+ }
+
+ if (argc == optind)
+ return usage(argv);
+
+ if (trace_needs_swap(argv[optind], &need_swap))
+ return 1;
+
for (i = 0; i < PID_HASH_SIZE; i++)
INIT_FLIST_HEAD(&pid_hash[i]);
+ for (i = 0; i < INFLIGHT_HASH_SIZE; i++)
+ INIT_FLIST_HEAD(&inflight_hash[i]);
load_blktrace(argv[optind], need_swap);
first_ttime /= 1000ULL;