From e28875637094451a3c5ec4071f964c1a02dd8f5b Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 16 May 2007 09:25:09 +0200 Subject: [PATCH] blktrace support: speedup reading of data We used to read in data in really small chunks (48 bytes at the time, the size of the trace). This is really slow for large traces, so add a fifo frontend to refill the cache in much larger sizes. Signed-off-by: Jens Axboe --- Makefile | 2 +- blktrace.c | 75 ++++++++++++++++++++++++++++++++++++++-------- fifo.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fifo.h | 48 +++++++++++++++++++++++++++++ fio.h | 8 +---- 5 files changed, 200 insertions(+), 21 deletions(-) create mode 100644 fifo.c create mode 100644 fifo.h diff --git a/Makefile b/Makefile index 5858ab09..9effdaa4 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ PROGS = fio SCRIPTS = fio_generate_plots OBJS = gettime.o fio.o ioengines.o init.o stat.o log.o time.o md5.o crc32.o \ filesetup.o eta.o verify.o memory.o io_u.o parse.o mutex.o options.o \ - rbtree.o diskutil.o blktrace.o + rbtree.o diskutil.o fifo.o blktrace.o OBJS += engines/cpu.o OBJS += engines/libaio.o diff --git a/blktrace.c b/blktrace.c index afa699cd..fc980918 100644 --- a/blktrace.c +++ b/blktrace.c @@ -8,6 +8,59 @@ #include "fio.h" #include "blktrace_api.h" +#define TRACE_FIFO_SIZE (sizeof(struct blk_io_trace) * 1000) + +/* + * fifo refill frontend, to avoid reading data in trace sized bites + */ +static int refill_fifo(struct thread_data *td, struct fifo *fifo, int fd) +{ + char buf[TRACE_FIFO_SIZE]; + unsigned int total, left; + void *ptr; + int ret; + + total = 0; + ptr = buf; + while (total < TRACE_FIFO_SIZE) { + left = TRACE_FIFO_SIZE - total; + + ret = read(fd, ptr, left); + if (ret < 0) { + td_verror(td, errno, "read blktrace file"); + return -1; + } else if (!ret) + break; + + fifo_put(fifo, ptr, ret); + ptr += ret; + total += ret; + } + + return 0; +} + +/* + * Retrieve 'len' bytes from the fifo, refilling if necessary. + */ +static int trace_fifo_get(struct thread_data *td, struct fifo *fifo, int fd, + void *buf, unsigned int len) +{ + int ret; + + if (fifo_len(fifo) >= len) + return fifo_get(fifo, buf, len); + + ret = refill_fifo(td, fifo, fd); + if (ret < 0) + return ret; + + if (fifo_len(fifo) < len) + return 0; + + return fifo_get(fifo, buf, len); +} + /* * Just discard the pdu by seeking past it. */ @@ -120,6 +173,7 @@ int load_blktrace(struct thread_data *td, const char *filename) unsigned long ios[2]; unsigned int cpu; unsigned int rw_bs[2]; + struct fifo *fifo; int fd; fd = open(filename, O_RDONLY); @@ -128,6 +182,8 @@ int load_blktrace(struct thread_data *td, const char *filename) return 1; } + fifo = fifo_alloc(TRACE_FIFO_SIZE); + td->o.size = 0; cpu = 0; @@ -135,22 +191,15 @@ int load_blktrace(struct thread_data *td, const char *filename) ios[0] = ios[1] = 0; rw_bs[0] = rw_bs[1] = 0; do { - /* - * Once this is working fully, I'll add a layer between - * here and read to cache trace data. Then we can avoid - * doing itsy bitsy reads, but instead pull in a larger - * chunk of data at the time. - */ - int ret = read(fd, &t, sizeof(t)); + int ret = trace_fifo_get(td, fifo, fd, &t, sizeof(t)); - if (ret < 0) { - td_verror(td, errno, "read blktrace file"); + if (ret < 0) goto err; - } else if (!ret) { + else if (!ret) + break; + else if (ret < (int) sizeof(t)) { + log_err("fio: short fifo get\n"); break; - } else if (ret != sizeof(t)) { - log_err("fio: short read on blktrace file\n"); - goto err; } if ((t.magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) { diff --git a/fifo.c b/fifo.c new file mode 100644 index 00000000..1e55b634 --- /dev/null +++ b/fifo.c @@ -0,0 +1,88 @@ +/* + * A simple kernel FIFO implementation. + * + * Copyright (C) 2004 Stelian Pop + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include + +#include "fifo.h" + +struct fifo *fifo_alloc(unsigned int size) +{ + struct fifo *fifo; + + fifo = malloc(sizeof(struct fifo)); + if (!fifo) + return 0; + + fifo->buffer = malloc(size); + fifo->size = size; + fifo->in = fifo->out = 0xffff0000; + + return fifo; +} + +void fifo_free(struct fifo *fifo) +{ + free(fifo->buffer); + free(fifo); +} + +unsigned int fifo_put(struct fifo *fifo, void *buffer, unsigned int len) +{ + unsigned int l; + + len = min(len, fifo->size - fifo->in + fifo->out); + + /* first put the data starting from fifo->in to buffer end */ + l = min(len, fifo->size - (fifo->in & (fifo->size - 1))); + memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l); + + /* then put the rest (if any) at the beginning of the buffer */ + memcpy(fifo->buffer, buffer + l, len - l); + + /* + * Ensure that we add the bytes to the fifo -before- + * we update the fifo->in index. + */ + + fifo->in += len; + + return len; +} + +unsigned int fifo_get(struct fifo *fifo, void *buffer, unsigned int len) +{ + unsigned int l; + + len = min(len, fifo->in - fifo->out); + + /* first get the data from fifo->out until the end of the buffer */ + l = min(len, fifo->size - (fifo->out & (fifo->size - 1))); + memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l); + + /* then get the rest (if any) from the beginning of the buffer */ + memcpy(buffer + l, fifo->buffer, len - l); + + fifo->out += len; + + return len; +} diff --git a/fifo.h b/fifo.h new file mode 100644 index 00000000..6a9115d4 --- /dev/null +++ b/fifo.h @@ -0,0 +1,48 @@ +/* + * A simple FIFO implementation. + * + * Copyright (C) 2004 Stelian Pop + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +struct fifo { + unsigned char *buffer; /* the buffer holding the data */ + unsigned int size; /* the size of the allocated buffer */ + unsigned int in; /* data is added at offset (in % size) */ + unsigned int out; /* data is extracted from off. (out % size) */ +}; + +struct fifo *fifo_alloc(unsigned int); +unsigned int fifo_put(struct fifo *, void *, unsigned int); +unsigned int fifo_get(struct fifo *, void *, unsigned int); + +static inline unsigned int fifo_len(struct fifo *fifo) +{ + return fifo->in - fifo->out; +} + +#define min(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; }) + +#define max(x,y) ({ \ + typeof(x) _x = (x); \ + typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) + diff --git a/fio.h b/fio.h index fa0edb1e..bcd188b3 100644 --- a/fio.h +++ b/fio.h @@ -15,6 +15,7 @@ #include "compiler/compiler.h" #include "list.h" +#include "fifo.h" #include "rbtree.h" #include "md5.h" #include "crc32.h" @@ -665,13 +666,6 @@ struct disk_util { #define DISK_UTIL_MSEC (250) -#ifndef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#endif -#ifndef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#endif - /* * Log exports */ -- 2.25.1