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;
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;
}
}
unsigned int i;
char dev[256];
+ if (filename)
+ return;
if (o->last_major == maj && o->last_minor == min)
return;
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;
}
{
struct btrace_out *o = &p->o;
unsigned long total;
+ unsigned long long time;
float perc;
int i, j;
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("startdelay=%llus\n", o->start_delay / 1000000ULL);
+ time = o->last_ttime - o->first_ttime;
+ time = (time + 1000000000ULL - 1) / 1000000000ULL;
+ printf("runtime=%llus\n", time);
+
printf("bssplit=");
for (i = 0; i < DDIR_RWDIR_CNT; i++) {
qsort(o->bs[i], o->nr_bs[i], sizeof(struct bs), bs_cmp);
}
+ if (filename) {
+ o->files = malloc(sizeof(struct trace_file));
+ o->nr_files++;
+ o->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 < o->nr_files; i++) {
+ if (o->files[i].name && o->files[i].name != filename)
+ free(o->files[i].name);
+ }
+
+ for (i = 0; i < DDIR_RWDIR_CNT; i++)
+ free(o->bs[i]);
+
+ free(o->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;