From ce35b1ece06ce27ebff111e47c2a6610c311a92b Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 14 Jan 2014 15:35:58 -0700 Subject: [PATCH] Add option for specifically setting buffer contents Fio can use zeroes, slightly scrambled data, full random data, or specifically compressible data. With this option, the user can now fully control the pattern written, similarly to how verify_pattern works for verify=meta. Signed-off-by: Jens Axboe --- HOWTO | 5 ++++ backend.c | 2 +- fio.1 | 6 +++++ io_u.c | 4 ++- options.c | 70 ++++++++++++++++++++++++++++++++++++------------ thread_options.h | 4 +++ verify.c | 62 +++++++++++++++++++++++++----------------- verify.h | 3 ++- 8 files changed, 112 insertions(+), 44 deletions(-) diff --git a/HOWTO b/HOWTO index 2183be10..c3672d85 100644 --- a/HOWTO +++ b/HOWTO @@ -547,6 +547,11 @@ buffer_compress_chunk=int See buffer_compress_percentage. This alternate random and zeroed data throughout the IO buffer. +buffer_pattern=str If set, fio will fill the io buffers with this pattern. + If not set, the contents of io buffers is defined by the other + options related to buffer contents. The setting can be any + pattern of bytes, and can be prefixed with 0x for hex values. + nrfiles=int Number of files to use for this job. Defaults to 1. openfiles=int Number of files to keep open at the same time. Defaults to diff --git a/backend.c b/backend.c index 101024d1..c9a20a3b 100644 --- a/backend.c +++ b/backend.c @@ -989,7 +989,7 @@ static int init_io_u(struct thread_data *td) * Fill the buffer with the pattern if we are * going to be doing writes. */ - fill_pattern(td, io_u->buf, max_bs, io_u, 0, 0); + fill_verify_pattern(td, io_u->buf, max_bs, io_u, 0, 0); } } diff --git a/fio.1 b/fio.1 index 6c3dd21b..82d05b77 100644 --- a/fio.1 +++ b/fio.1 @@ -426,6 +426,12 @@ provide \fBbuffer_compress_percentage\fR of blocksize random data, followed by the remaining zeroed. With this set to some chunk size smaller than the block size, fio can alternate random and zeroed data throughout the IO buffer. .TP +.BI buffer_pattern \fR=\fPstr +If set, fio will fill the io buffers with this pattern. If not set, the contents +of io buffers is defined by the other options related to buffer contents. The +setting can be any pattern of bytes, and can be prefixed with 0x for hex +values. +.TP .BI nrfiles \fR=\fPint Number of files to use for this job. Default: 1. .TP diff --git a/io_u.c b/io_u.c index ea6c2518..518d884f 100644 --- a/io_u.c +++ b/io_u.c @@ -1770,7 +1770,9 @@ void io_u_queued(struct thread_data *td, struct io_u *io_u) void fill_io_buffer(struct thread_data *td, void *buf, unsigned int min_write, unsigned int max_bs) { - if (!td->o.zero_buffers) { + if (td->o.buffer_pattern_bytes) + fill_buffer_pattern(td, buf, max_bs); + else if (!td->o.zero_buffers) { unsigned int perc = td->o.compress_percentage; if (perc) { diff --git a/options.c b/options.c index 16b66369..b1b6c8e9 100644 --- a/options.c +++ b/options.c @@ -834,11 +834,12 @@ static int str_opendir_cb(void *data, const char fio_unused *str) return add_dir_files(td, td->o.opendir); } -static int str_verify_pattern_cb(void *data, const char *input) +static int pattern_cb(char *pattern, unsigned int max_size, + const char *input, unsigned int *pattern_bytes) { - struct thread_data *td = data; long off; - int i = 0, j = 0, len, k, base = 10, pattern_length; + int i = 0, j = 0, len, k, base = 10; + uint32_t pattern_length; char *loc1, *loc2; loc1 = strstr(input, "0x"); @@ -848,7 +849,7 @@ static int str_verify_pattern_cb(void *data, const char *input) off = strtol(input, NULL, base); if (off != LONG_MAX || errno != ERANGE) { while (off) { - td->o.verify_pattern[i] = off & 0xff; + pattern[i] = off & 0xff; off >>= 8; i++; } @@ -862,13 +863,13 @@ static int str_verify_pattern_cb(void *data, const char *input) j = loc2 - input + 2; } else return 1; - if (len - j < MAX_PATTERN_SIZE * 2) { + if (len - j < max_size * 2) { while (k >= j) { off = converthexchartoint(input[k--]); if (k >= j) off += (converthexchartoint(input[k--]) * 16); - td->o.verify_pattern[i++] = (char) off; + pattern[i++] = (char) off; } } } @@ -878,19 +879,19 @@ static int str_verify_pattern_cb(void *data, const char *input) * the number of memcpy's we have to do when verifying the IO. */ pattern_length = i; - while (i > 1 && i * 2 <= MAX_PATTERN_SIZE) { - memcpy(&td->o.verify_pattern[i], &td->o.verify_pattern[0], i); + while (i > 1 && i * 2 <= max_size) { + memcpy(&pattern[i], &pattern[0], i); i *= 2; } /* * Fill remainder, if the pattern multiple ends up not being - * MAX_PATTERN_SIZE. + * max_size. */ - while (i > 1 && i < MAX_PATTERN_SIZE) { - unsigned int b = min(pattern_length, MAX_PATTERN_SIZE - i); + while (i > 1 && i < max_size) { + unsigned int b = min(pattern_length, max_size - i); - memcpy(&td->o.verify_pattern[i], &td->o.verify_pattern[0], b); + memcpy(&pattern[i], &pattern[0], b); i += b; } @@ -899,19 +900,45 @@ static int str_verify_pattern_cb(void *data, const char *input) * The code in verify_io_u_pattern assumes a single byte pattern * fills the whole verify pattern buffer. */ - memset(td->o.verify_pattern, td->o.verify_pattern[0], - MAX_PATTERN_SIZE); + memset(pattern, pattern[0], max_size); + } + + *pattern_bytes = i; + return 0; +} + +static int str_buffer_pattern_cb(void *data, const char *input) +{ + struct thread_data *td = data; + int ret; + + ret = pattern_cb(td->o.buffer_pattern, MAX_PATTERN_SIZE, input, + &td->o.buffer_pattern_bytes); + + if (!ret) { + td->o.refill_buffers = 0; + td->o.scramble_buffers = 0; + td->o.zero_buffers = 0; } - td->o.verify_pattern_bytes = i; + return ret; +} + +static int str_verify_pattern_cb(void *data, const char *input) +{ + struct thread_data *td = data; + int ret; + + ret = pattern_cb(td->o.verify_pattern, MAX_PATTERN_SIZE, input, + &td->o.verify_pattern_bytes); /* * VERIFY_META could already be set */ - if (td->o.verify == VERIFY_NONE) + if (!ret && td->o.verify == VERIFY_NONE) td->o.verify = VERIFY_PATTERN; - return 0; + return ret; } static int str_gtod_reduce_cb(void *data, int *il) @@ -2946,6 +2973,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = { .category = FIO_OPT_C_IO, .group = FIO_OPT_G_IO_BUF, }, + { + .name = "buffer_pattern", + .lname = "Buffer pattern", + .type = FIO_OPT_STR, + .cb = str_buffer_pattern_cb, + .help = "Fill pattern for IO buffers", + .category = FIO_OPT_C_IO, + .group = FIO_OPT_G_IO_BUF, + }, { .name = "buffer_compress_percentage", .lname = "Buffer compression percentage", diff --git a/thread_options.h b/thread_options.h index e2c6e885..f40a9927 100644 --- a/thread_options.h +++ b/thread_options.h @@ -170,6 +170,8 @@ struct thread_options { unsigned int zero_buffers; unsigned int refill_buffers; unsigned int scramble_buffers; + char buffer_pattern[MAX_PATTERN_SIZE]; + unsigned int buffer_pattern_bytes; unsigned int compress_percentage; unsigned int compress_chunk; unsigned int time_based; @@ -381,6 +383,8 @@ struct thread_options_pack { uint32_t zero_buffers; uint32_t refill_buffers; uint32_t scramble_buffers; + uint8_t buffer_pattern[MAX_PATTERN_SIZE]; + uint32_t buffer_pattern_bytes; unsigned int compress_percentage; unsigned int compress_chunk; uint32_t time_based; diff --git a/verify.c b/verify.c index 0d38c0e9..721aeb46 100644 --- a/verify.c +++ b/verify.c @@ -28,51 +28,65 @@ static void populate_hdr(struct thread_data *td, struct io_u *io_u, struct verify_header *hdr, unsigned int header_num, unsigned int header_len); -void fill_pattern(struct thread_data *td, void *p, unsigned int len, struct io_u *io_u, unsigned long seed, int use_seed) +static void fill_pattern(struct thread_data *td, void *p, unsigned int len, + char *pattern, unsigned int pattern_bytes) { - switch (td->o.verify_pattern_bytes) { + switch (pattern_bytes) { case 0: - dprint(FD_VERIFY, "fill random bytes len=%u\n", len); - if (use_seed) - __fill_random_buf(p, len, seed); - else - io_u->rand_seed = fill_random_buf(&td->buf_state, p, len); + assert(0); break; case 1: - if (io_u->buf_filled_len >= len) { - dprint(FD_VERIFY, "using already filled verify pattern b=0 len=%u\n", len); - return; - } dprint(FD_VERIFY, "fill verify pattern b=0 len=%u\n", len); - memset(p, td->o.verify_pattern[0], len); - io_u->buf_filled_len = len; + memset(p, pattern[0], len); break; default: { unsigned int i = 0, size = 0; unsigned char *b = p; - if (io_u->buf_filled_len >= len) { - dprint(FD_VERIFY, "using already filled verify pattern b=%d len=%u\n", - td->o.verify_pattern_bytes, len); - return; - } - dprint(FD_VERIFY, "fill verify pattern b=%d len=%u\n", - td->o.verify_pattern_bytes, len); + pattern_bytes, len); while (i < len) { - size = td->o.verify_pattern_bytes; + size = pattern_bytes; if (size > (len - i)) size = len - i; - memcpy(b+i, td->o.verify_pattern, size); + memcpy(b+i, pattern, size); i += size; } - io_u->buf_filled_len = len; break; } } } +void fill_buffer_pattern(struct thread_data *td, void *p, unsigned int len) +{ + fill_pattern(td, p, len, td->o.buffer_pattern, td->o.buffer_pattern_bytes); +} + +void fill_verify_pattern(struct thread_data *td, void *p, unsigned int len, + struct io_u *io_u, unsigned long seed, int use_seed) +{ + if (!td->o.verify_pattern_bytes) { + dprint(FD_VERIFY, "fill random bytes len=%u\n", len); + + if (use_seed) + __fill_random_buf(p, len, seed); + else + io_u->rand_seed = fill_random_buf(&td->buf_state, p, len); + return; + } + + if (io_u->buf_filled_len >= len) { + dprint(FD_VERIFY, "using already filled verify pattern b=%d len=%u\n", + td->o.verify_pattern_bytes, len); + return; + } + + fill_pattern(td, p, len, td->o.verify_pattern, td->o.verify_pattern_bytes); + + io_u->buf_filled_len = len; +} + static unsigned int get_hdr_inc(struct thread_data *td, struct io_u *io_u) { unsigned int hdr_inc; @@ -91,7 +105,7 @@ static void fill_pattern_headers(struct thread_data *td, struct io_u *io_u, struct verify_header *hdr; void *p = io_u->buf; - fill_pattern(td, p, io_u->buflen, io_u, seed, use_seed); + fill_verify_pattern(td, p, io_u->buflen, io_u, seed, use_seed); hdr_inc = get_hdr_inc(td, io_u); header_num = 0; diff --git a/verify.h b/verify.h index 6a81e9b0..05d7b81b 100644 --- a/verify.h +++ b/verify.h @@ -74,7 +74,8 @@ extern void populate_verify_io_u(struct thread_data *, struct io_u *); extern int __must_check get_next_verify(struct thread_data *td, struct io_u *); extern int __must_check verify_io_u(struct thread_data *, struct io_u *); extern int verify_io_u_async(struct thread_data *, struct io_u *); -extern void fill_pattern(struct thread_data *td, void *p, unsigned int len, struct io_u *io_u, unsigned long seed, int use_seed); +extern void fill_verify_pattern(struct thread_data *td, void *p, unsigned int len, struct io_u *io_u, unsigned long seed, int use_seed); +extern void fill_buffer_pattern(struct thread_data *td, void *p, unsigned int len); extern void fio_verify_init(struct thread_data *td); /* -- 2.25.1