diff --git a/cmd/zpios/zpios.h b/cmd/zpios/zpios.h index 92d96fcbe1..4a69b9e54c 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 971a886a33..e6e88f60d9 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 b226322b0b..2d248ed9ae 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 9a47ff91d5..aee4f0a501 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 4b99b4ce31..dd2bd2343a 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 4b362b09d2..4334c03c04 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 e3a85c1686..8f4a8fd69b 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;