From 56b3986316365d997cb381d3295b99612e18ab6e Mon Sep 17 00:00:00 2001 From: Don Brady Date: Thu, 17 Sep 2015 17:55:22 -0600 Subject: [PATCH] Add large block support to zpios(1) benchmark As part of the large block support effort, it makes sense to add support for large blocks to **zpios(1)**. The specifying of a zfs block size for zpios is optional and will default to 128K if the block size is not specified. `zpios ... -S size | --blocksize size ...` This will use *size* ZFS blocks for each test, specified as a comma delimited list with an optional unit suffix. The supported range is powers of two from 128K through 16M. A range of block sizes can be tested as follows: `-S 128K,256K,512K,1M` Example run below (non realistic results from a VM and output abbreviated for space) ``` --regioncount=750 --regionsize=8M --chunksize=1M --offset=4K --threaddelay=0 --cleanup --human-readable --verbose --cleanup --blocksize=128K,256K,512K,1M th-cnt rg-cnt rg-sz ch-sz blksz wr-data wr-bw rd-data rd-bw --------------------------------------------------------------------- 4 750 8m 1m 128k 5g 90.06m 5g 93.37m 4 750 8m 1m 256k 5g 79.71m 5g 99.81m 4 750 8m 1m 512k 5g 42.20m 5g 93.14m 4 750 8m 1m 1m 5g 35.51m 5g 89.36m 8 750 8m 1m 128k 5g 85.49m 5g 90.81m 8 750 8m 1m 256k 5g 61.42m 5g 99.24m 8 750 8m 1m 512k 5g 49.09m 5g 108.78m 16 750 8m 1m 128k 5g 86.28m 5g 88.73m 16 750 8m 1m 256k 5g 64.34m 5g 93.47m 16 750 8m 1m 512k 5g 68.84m 5g 124.47m 16 750 8m 1m 1m 5g 53.97m 5g 97.20m --------------------------------------------------------------------- ``` Signed-off-by: Don Brady Signed-off-by: Brian Behlendorf Closes #3795 Closes #2071 --- cmd/zpios/zpios.h | 11 +++++--- cmd/zpios/zpios_main.c | 55 ++++++++++++++++++++++++++++++++++++---- cmd/zpios/zpios_util.c | 19 ++++++++++---- include/zpios-ctl.h | 3 +++ include/zpios-internal.h | 3 +++ man/man1/zpios.1 | 35 +++++++++++++++++++++++-- module/zpios/pios.c | 18 +++++++++++-- 7 files changed, 127 insertions(+), 17 deletions(-) diff --git a/cmd/zpios/zpios.h b/cmd/zpios/zpios.h index 92d96fcbe..4a69b9e54 100644 --- a/cmd/zpios/zpios.h +++ b/cmd/zpios/zpios.h @@ -29,6 +29,8 @@ * * You should have received a copy of the GNU General Public License along * with ZPIOS. If not, see . + * + * Copyright (c) 2015, Intel Corporation. */ #ifndef _ZPIOS_H @@ -39,10 +41,10 @@ #define VERSION_SIZE 64 /* Regular expressions */ -#define REGEX_NUMBERS "^[0-9]*[0-9]$" +#define REGEX_NUMBERS "^[0-9]+$" #define REGEX_NUMBERS_COMMA "^([0-9]+,)*[0-9]+$" -#define REGEX_SIZE "^[0-9][0-9]*[kmgt]$" -#define REGEX_SIZE_COMMA "^([0-9][0-9]*[kmgt]+,)*[0-9][0-9]*[kmgt]$" +#define REGEX_SIZE "^[0-9]+[kKmMgGtT]?$" +#define REGEX_SIZE_COMMA "^([0-9]+[kKmMgGtT]?,)*[0-9]+[kKmMgGtT]?$" /* Flags for low, high, incr */ #define FLAG_SET 0x01 @@ -82,10 +84,12 @@ typedef struct cmd_args { range_repeat_t O; /* Offset count */ range_repeat_t C; /* Chunksize */ range_repeat_t S; /* Regionsize */ + range_repeat_t B; /* Blocksize */ const char *pool; /* Pool */ const char *name; /* Name */ uint32_t flags; /* Flags */ + uint32_t block_size; /* ZFS block size */ uint32_t io_type; /* DMUIO only */ uint32_t verbose; /* Verbose */ uint32_t human_readable; /* Human readable output */ @@ -105,6 +109,7 @@ typedef struct cmd_args { uint64_t current_C; uint64_t current_S; uint64_t current_O; + uint64_t current_B; uint32_t rc; } cmd_args_t; diff --git a/cmd/zpios/zpios_main.c b/cmd/zpios/zpios_main.c index 971a886a3..e6e88f60d 100644 --- a/cmd/zpios/zpios_main.c +++ b/cmd/zpios/zpios_main.c @@ -29,6 +29,8 @@ * * You should have received a copy of the GNU General Public License along * with ZPIOS. If not, see . + * + * Copyright (c) 2015, Intel Corporation. */ #include @@ -44,7 +46,7 @@ static const char short_opt[] = "t:l:h:e:n:i:j:k:o:m:q:r:c:a:b:g:s:A:B:C:" - "L:p:M:xP:R:G:I:N:T:VzOfHv?"; + "S:L:p:M:xP:R:G:I:N:T:VzOfHv?"; static const struct option long_opt[] = { {"threadcount", required_argument, 0, 't' }, {"threadcount_low", required_argument, 0, 'l' }, @@ -66,6 +68,7 @@ static const struct option long_opt[] = { {"regionsize_low", required_argument, 0, 'A' }, {"regionsize_high", required_argument, 0, 'B' }, {"regionsize_incr", required_argument, 0, 'C' }, + {"blocksize", required_argument, 0, 'S' }, {"load", required_argument, 0, 'L' }, {"pool", required_argument, 0, 'p' }, {"name", required_argument, 0, 'M' }, @@ -116,6 +119,7 @@ usage(void) " --regionsize_low -A =value\n" " --regionsize_high -B =value\n" " --regionsize_incr -C =value\n" + " --blocksize -S =values\n" " --load -L =dmuio|ssf|fpp\n" " --pool -p =pool name\n" " --name -M =test name\n" @@ -143,6 +147,11 @@ static void args_fini(cmd_args_t *args) free(args); } +/* block size is 128K to 16M, power of 2 */ +#define MIN_BLKSIZE (128ULL << 10) +#define MAX_BLKSIZE (16ULL << 20) +#define POW_OF_TWO(x) (((x) & ((x) - 1)) == 0) + static cmd_args_t * args_init(int argc, char **argv) { @@ -152,7 +161,8 @@ args_init(int argc, char **argv) uint32_t fl_of = 0; uint32_t fl_rs = 0; uint32_t fl_cs = 0; - int c, rc; + uint32_t fl_bs = 0; + int c, rc, i; if (argc == 1) { usage(); @@ -166,6 +176,11 @@ args_init(int argc, char **argv) memset(args, 0, sizeof (*args)); + /* provide a default block size of 128K */ + args->B.next_val = 0; + args->B.val[0] = MIN_BLKSIZE; + args->B.val_count = 1; + while ((c = getopt_long(argc, argv, short_opt, long_opt, NULL)) != -1) { rc = 0; @@ -250,6 +265,10 @@ args_init(int argc, char **argv) rc = set_lhi(REGEX_NUMBERS, &args->S, optarg, FLAG_INCR, &fl_rs, "regionsize_incr"); break; + case 'S': /* --blocksize */ + rc = set_count(REGEX_SIZE, REGEX_SIZE_COMMA, + &args->B, optarg, &fl_bs, "blocksize"); + break; case 'L': /* --load */ rc = set_load_params(args, optarg); break; @@ -339,6 +358,17 @@ args_init(int argc, char **argv) return (NULL); } + /* validate block size(s) */ + for (i = 0; i < args->B.val_count; i++) { + int bs = args->B.val[i]; + + if (bs < MIN_BLKSIZE || bs > MAX_BLKSIZE || !POW_OF_TWO(bs)) { + fprintf(stderr, "Error: invalid block size %d\n", bs); + args_fini(args); + return (NULL); + } + } + return (args); } @@ -480,7 +510,7 @@ get_next(uint64_t *val, range_repeat_t *range) static int run_one(cmd_args_t *args, uint32_t id, uint32_t T, uint32_t N, - uint64_t C, uint64_t S, uint64_t O) + uint64_t C, uint64_t S, uint64_t O, uint64_t B) { zpios_cmd_t *cmd; int rc, rc2, cmd_size; @@ -506,6 +536,7 @@ run_one(cmd_args_t *args, uint32_t id, uint32_t T, uint32_t N, cmd->cmd_region_count = N; cmd->cmd_region_size = S; cmd->cmd_offset = O; + cmd->cmd_block_size = B; cmd->cmd_region_noise = args->regionnoise; cmd->cmd_chunk_noise = args->chunknoise; cmd->cmd_thread_delay = args->thread_delay; @@ -541,7 +572,7 @@ run_offsets(cmd_args_t *args) while (rc == 0 && get_next(&args->current_O, &args->O)) { rc = run_one(args, args->current_id, args->current_T, args->current_N, args->current_C, - args->current_S, args->current_O); + args->current_S, args->current_O, args->current_B); args->current_id++; } @@ -593,13 +624,27 @@ run_chunk_sizes(cmd_args_t *args) return (rc); } +static int +run_block_sizes(cmd_args_t *args) +{ + int rc = 0; + + while (rc == 0 && get_next(&args->current_B, &args->B)) { + rc = run_chunk_sizes(args); + } + + args->B.next_val = 0; + return (rc); +} + + static int run_thread_counts(cmd_args_t *args) { int rc = 0; while (rc == 0 && get_next((uint64_t *)&args->current_T, &args->T)) - rc = run_chunk_sizes(args); + rc = run_block_sizes(args); return (rc); } diff --git a/cmd/zpios/zpios_util.c b/cmd/zpios/zpios_util.c index b226322b0..2d248ed9a 100644 --- a/cmd/zpios/zpios_util.c +++ b/cmd/zpios/zpios_util.c @@ -29,6 +29,8 @@ * * You should have received a copy of the GNU General Public License along * with ZPIOS. If not, see . + * + * Copyright (c) 2015, Intel Corporation. */ #include @@ -185,6 +187,8 @@ int set_count(char *pattern1, char *pattern2, range_repeat_t *range, char *optarg, uint32_t *flags, char *arg) { + uint64_t count = range->val_count; + if (flags) *flags |= FLAG_SET; @@ -197,6 +201,9 @@ set_count(char *pattern1, char *pattern2, range_repeat_t *range, fprintf(stderr, "Error: Incorrect pattern for %s, '%s'\n", arg, optarg); return (EINVAL); + } else if (count == range->val_count) { + fprintf(stderr, "Error: input ignored for %s, '%s'\n", + arg, optarg); } return (0); @@ -314,14 +321,14 @@ print_stats_header(cmd_args_t *args) if (args->verbose) { printf( "status name id\tth-cnt\trg-cnt\trg-sz\t" - "ch-sz\toffset\trg-no\tch-no\tth-dly\tflags\ttime\t" + "ch-sz\toffset\trg-no\tch-no\tth-dly\tflags\tblksz\ttime\t" "cr-time\trm-time\twr-time\trd-time\twr-data\twr-ch\t" "wr-bw\trd-data\trd-ch\trd-bw\n"); printf( - "------------------------------------------------" - "------------------------------------------------" - "------------------------------------------------" - "----------------------------------------------\n"); + "-------------------------------------------------" + "-------------------------------------------------" + "-------------------------------------------------" + "--------------------------------------------------\n"); } else { printf( "status name id\t" @@ -358,6 +365,7 @@ print_stats_human_readable(cmd_args_t *args, zpios_cmd_t *cmd) printf("%s\t", uint64_to_kmgt(str, cmd->cmd_chunk_noise)); printf("%s\t", uint64_to_kmgt(str, cmd->cmd_thread_delay)); printf("%s\t", print_flags(str, cmd->cmd_flags)); + printf("%s\t", uint64_to_kmgt(str, cmd->cmd_block_size)); } if (args->rc) { @@ -414,6 +422,7 @@ print_stats_table(cmd_args_t *args, zpios_cmd_t *cmd) printf("%u\t", cmd->cmd_chunk_noise); printf("%u\t", cmd->cmd_thread_delay); printf("0x%x\t", cmd->cmd_flags); + printf("%u\t", cmd->cmd_block_size); } if (args->rc) { diff --git a/include/zpios-ctl.h b/include/zpios-ctl.h index 9a47ff91d..aee4f0a50 100644 --- a/include/zpios-ctl.h +++ b/include/zpios-ctl.h @@ -29,6 +29,8 @@ * * You should have received a copy of the GNU General Public License along * with ZPIOS. If not, see . + * + * Copyright (c) 2015, Intel Corporation. */ #ifndef _ZPIOS_CTL_H @@ -116,6 +118,7 @@ typedef struct zpios_cmd { uint32_t cmd_chunk_noise; /* Chunk noise */ uint32_t cmd_thread_delay; /* Thread delay */ uint32_t cmd_flags; /* Test flags */ + uint32_t cmd_block_size; /* ZFS block size */ char cmd_pre[ZPIOS_PATH_SIZE]; /* Pre-exec hook */ char cmd_post[ZPIOS_PATH_SIZE]; /* Post-exec hook */ char cmd_log[ZPIOS_PATH_SIZE]; /* Requested log dir */ diff --git a/include/zpios-internal.h b/include/zpios-internal.h index 4b99b4ce3..dd2bd2343 100644 --- a/include/zpios-internal.h +++ b/include/zpios-internal.h @@ -29,6 +29,8 @@ * * You should have received a copy of the GNU General Public License along * with ZPIOS. If not, see . + * + * Copyright (c) 2015, Intel Corporation. */ #ifndef _ZPIOS_INTERNAL_H @@ -79,6 +81,7 @@ typedef struct run_args { __u32 chunk_noise; __u32 thread_delay; __u32 flags; + __u32 block_size; char pre[ZPIOS_PATH_SIZE]; char post[ZPIOS_PATH_SIZE]; char log[ZPIOS_PATH_SIZE]; diff --git a/man/man1/zpios.1 b/man/man1/zpios.1 index 4b362b09d..4334c03c0 100644 --- a/man/man1/zpios.1 +++ b/man/man1/zpios.1 @@ -22,6 +22,8 @@ .\" .\" Copyright 2013 Darik Horn . All rights reserved. .\" +.\" Copyright (c) 2015, Intel Corporation. +.\" .TH zpios 1 "2013 FEB 28" "ZFS on Linux" "User Commands" .SH NAME @@ -36,10 +38,10 @@ not depend on the ZFS Posix Layer ("ZPL"). .SH OPTIONS .HP -.BI "\-s" " regex" ", \-\-threadcount" " regex" +.BI "\-t" " regex" ", \-\-threadcount" " regex" .IP Start this many threads for each test series, specified as a comma -delimited regular expression. (eg: "-s 1,2,3") +delimited regular expression. (eg: "-t 1,2,3") .IP This option is mutually exclusive with the \fBthreadcount_*\fR options. @@ -120,6 +122,35 @@ chunk size for the last test. These three options must be specified together and are mutually exclusive with the \fBchunksize\fR option. .HP +.BI "\-s" " size" ", \-\-regionsize" " size" +.IP +Use \fIsize\fR regions for each test, specified as a comma delimited +regular expression with an optional unit suffix. (eg: "-s 1M" means +one megabyte.) +.IP +This option is mutually exclusive with the \fBregionsize_*\fB options. +.HP +.BI "\-A" " size_low" ", \-\-regionsize_low" " size_low" +.HP +.BI "\-B" " size_high" ", \-\-regionsize_high" " size_high" +.HP +.BI "\-C" " size_incr" ", \-\-regionsize_incr" " size_incr" +.IP +Use a \fIsize_low\fR region size for the first test, add \fIsize_incr\fR +to the region size for each subsequent test, and use a \fIsize_high\fR +region size for the last test. +.IP +These three options must be specified together and are mutually +exclusive with the \fBregionsize\fR option. +.HP +.BI "\-S" " size | sizes" ", \-\-blocksize" " size | sizes" +.IP +Use \fIsize\fR ZFS blocks for each test, specified as a comma delimited +regular expression with an optional unit suffix. (eg: "-S 1M" means +one megabyte.) The supported range is powers of two from 128K through 16M. +A range of blocks can be tested as follows: "-S 128K,256K,512K,1M". +.IP +.HP .BI "\-L" " dmu_flags" ", \-\-load" " dmu_flags" .IP Specify \fIdmuio\fR for regular DMU_IO, \fIssf\fR for single shared diff --git a/module/zpios/pios.c b/module/zpios/pios.c index e3a85c168..8f4a8fd69 100644 --- a/module/zpios/pios.c +++ b/module/zpios/pios.c @@ -29,10 +29,13 @@ * * You should have received a copy of the GNU General Public License along * with ZPIOS. If not, see . + * + * Copyright (c) 2015, Intel Corporation. */ #include #include +#include #include #include #include @@ -129,8 +132,17 @@ zpios_dmu_object_create(run_args_t *run_args, objset_t *os) { struct dmu_tx *tx; uint64_t obj = 0ULL; + uint64_t blksize = run_args->block_size; int rc; + if (blksize < SPA_MINBLOCKSIZE || + blksize > spa_maxblocksize(dmu_objset_spa(os)) || + !ISP2(blksize)) { + zpios_print(run_args->file, + "invalid block size for pool: %d\n", (int)blksize); + return (obj); + } + tx = dmu_tx_create(os); dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, OBJ_SIZE); rc = dmu_tx_assign(tx, TXG_WAIT); @@ -142,10 +154,11 @@ zpios_dmu_object_create(run_args_t *run_args, objset_t *os) } obj = dmu_object_alloc(os, DMU_OT_UINT64_OTHER, 0, DMU_OT_NONE, 0, tx); - rc = dmu_object_set_blocksize(os, obj, 128ULL << 10, 0, tx); + rc = dmu_object_set_blocksize(os, obj, blksize, 0, tx); if (rc) { zpios_print(run_args->file, - "dmu_object_set_blocksize() failed: %d\n", rc); + "dmu_object_set_blocksize to %d failed: %d\n", + (int)blksize, rc); dmu_tx_abort(tx); return (obj); } @@ -295,6 +308,7 @@ zpios_setup_run(run_args_t **run_args, zpios_cmd_t *kcmd, struct file *file) ra->chunk_noise = kcmd->cmd_chunk_noise; ra->thread_delay = kcmd->cmd_thread_delay; ra->flags = kcmd->cmd_flags; + ra->block_size = kcmd->cmd_block_size; ra->stats.wr_data = 0; ra->stats.wr_chunks = 0; ra->stats.rd_data = 0;