1 /*****************************************************************************\
2 * ZPIOS is a heavily modified version of the original PIOS test code.
3 * It is designed to have the test code running in the Linux kernel
4 * against ZFS while still being flexibly controled from user space.
6 * Copyright (C) 2008-2010 Lawrence Livermore National Security, LLC.
7 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
8 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
11 * Original PIOS Test Code
12 * Copyright (C) 2004 Cluster File Systems, Inc.
13 * Written by Peter Braam <braam@clusterfs.com>
14 * Atul Vidwansa <atul@clusterfs.com>
15 * Milind Dumbare <milind@clusterfs.com>
17 * This file is part of ZFS on Linux.
18 * For details, see <http://github.com/behlendorf/zfs/>.
20 * ZPIOS is free software; you can redistribute it and/or modify it
21 * under the terms of the GNU General Public License as published by the
22 * Free Software Foundation; either version 2 of the License, or (at your
23 * option) any later version.
25 * ZPIOS is distributed in the hope that it will be useful, but WITHOUT
26 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
27 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
30 * You should have received a copy of the GNU General Public License along
31 * with ZPIOS. If not, see <http://www.gnu.org/licenses/>.
32 \*****************************************************************************/
42 /* extracts an unsigned int (64) and K,M,G,T from the string */
43 /* and returns a 64 bit value converted to the proper units */
45 kmgt_to_uint64(const char *str, uint64_t *val)
50 *val = strtoll(str, &endptr, 0);
51 if ((str == endptr) && (*val == 0))
77 uint64_to_kmgt(char *str, uint64_t val)
79 char postfix[] = "kmgt";
82 while ((val >= KB) && (i < 4)) {
88 (void)snprintf(str, KMGT_SIZE-1, "inf");
90 (void)snprintf(str, KMGT_SIZE-1, "%lu%c", (unsigned long)val,
91 (i == -1) ? '\0' : postfix[i]);
97 kmgt_per_sec(char *str, uint64_t v, double t)
99 char postfix[] = "kmgt";
100 double val = ((double)v) / t;
103 while ((val >= (double)KB) && (i < 4)) {
109 (void)snprintf(str, KMGT_SIZE-1, "inf");
111 (void)snprintf(str, KMGT_SIZE-1, "%.2f%c", val,
112 (i == -1) ? '\0' : postfix[i]);
118 print_flags(char *str, uint32_t flags)
120 str[0] = (flags & DMU_WRITE) ? 'w' : '-';
121 str[1] = (flags & DMU_READ) ? 'r' : '-';
122 str[2] = (flags & DMU_VERIFY) ? 'v' : '-';
123 str[3] = (flags & DMU_REMOVE) ? 'c' : '-';
124 str[4] = (flags & DMU_FPP) ? 'p' : 's';
125 str[5] = (flags & (DMU_WRITE_ZC | DMU_READ_ZC)) ? 'z' : '-';
126 str[6] = (flags & DMU_WRITE_NOWAIT) ? 'O' : '-';
133 regex_match(const char *string, char *pattern)
138 rc = regcomp(&re, pattern, REG_EXTENDED | REG_NOSUB | REG_ICASE);
140 fprintf(stderr, "Error: Couldn't do regcomp, %d\n", rc);
144 rc = regexec(&re, string, (size_t) 0, NULL, 0);
150 /* fills the pios_range_repeat structure of comma separated values */
152 split_string(const char *optarg, char *pattern, range_repeat_t *range)
154 const char comma[] = ",";
155 char *cp, *token[32];
158 if ((rc = regex_match(optarg, pattern)))
166 /* STRTOK(3) Each subsequent call, with a null pointer as the
167 * value of the * first argument, starts searching from the
168 * saved pointer and behaves as described above.
170 token[i] = strtok(cp, comma);
172 } while ((token[i++] != NULL) && (i < 32));
174 range->val_count = i - 1;
176 for (i = 0; i < range->val_count; i++)
177 kmgt_to_uint64(token[i], &range->val[i]);
184 set_count(char *pattern1, char *pattern2, range_repeat_t *range,
185 char *optarg, uint32_t *flags, char *arg)
192 if (regex_match(optarg, pattern1) == 0) {
193 kmgt_to_uint64(optarg, &range->val[0]);
194 range->val_count = 1;
195 } else if (split_string(optarg, pattern2, range) < 0) {
196 fprintf(stderr, "Error: Incorrect pattern for %s, '%s'\n",
204 /* validates the value with regular expression and sets low, high, incr
205 * according to value at which flag will be set. Sets the flag after. */
207 set_lhi(char *pattern, range_repeat_t *range, char *optarg,
208 int flag, uint32_t *flag_thread, char *arg)
212 if ((rc = regex_match(optarg, pattern))) {
213 fprintf(stderr, "Error: Wrong pattern in %s, '%s'\n",
220 kmgt_to_uint64(optarg, &range->val_low);
223 kmgt_to_uint64(optarg, &range->val_high);
226 kmgt_to_uint64(optarg, &range->val_inc_perc);
232 *flag_thread |= flag;
238 set_noise(uint64_t *noise, char *optarg, char *arg)
240 if (regex_match(optarg, REGEX_NUMBERS) == 0) {
241 kmgt_to_uint64(optarg, noise);
243 fprintf(stderr, "Error: Incorrect pattern for %s\n", arg);
251 set_load_params(cmd_args_t *args, char *optarg)
253 char *param, *search, comma[] = ",";
256 search = strdup(optarg);
260 while ((param = strtok(search, comma)) != NULL) {
263 if (strcmp("fpp", param) == 0) {
264 args->flags |= DMU_FPP; /* File Per Process/Thread */
265 } else if (strcmp("ssf", param) == 0) {
266 args->flags &= ~DMU_FPP; /* Single Shared File */
267 } else if (strcmp("dmuio", param) == 0) {
268 args->io_type |= DMU_IO;
269 args->flags |= (DMU_WRITE | DMU_READ);
271 fprintf(stderr, "Invalid load: %s\n", param);
282 /* checks the low, high, increment values against the single value for
283 * mutual exclusion, for e.g threadcount is mutually exclusive to
284 * threadcount_low, ..._high, ..._incr */
286 check_mutual_exclusive_command_lines(uint32_t flag, char *arg)
288 if ((flag & FLAG_SET) && (flag & (FLAG_LOW | FLAG_HIGH | FLAG_INCR))) {
289 fprintf(stderr, "Error: --%s can not be given with --%s_low, "
290 "--%s_high or --%s_incr.\n", arg, arg, arg, arg);
294 if ((flag & (FLAG_LOW | FLAG_HIGH | FLAG_INCR)) && !(flag & FLAG_SET)){
295 if (flag != (FLAG_LOW | FLAG_HIGH | FLAG_INCR)) {
296 fprintf(stderr, "Error: One or more values missing "
297 "from --%s_low, --%s_high, --%s_incr.\n",
307 print_stats_header(cmd_args_t *args)
310 printf("status name id\tth-cnt\trg-cnt\trg-sz\t"
311 "ch-sz\toffset\trg-no\tch-no\tth-dly\tflags\ttime\t"
312 "cr-time\trm-time\twr-time\trd-time\twr-data\twr-ch\t"
313 "wr-bw\trd-data\trd-ch\trd-bw\n");
314 printf("------------------------------------------------"
315 "------------------------------------------------"
316 "------------------------------------------------"
317 "----------------------------------------------\n");
319 printf("status name id\t"
320 "wr-data\twr-ch\twr-bw\t"
321 "rd-data\trd-ch\trd-bw\n");
322 printf("-----------------------------------------"
323 "--------------------------------------\n");
328 print_stats_human_readable(cmd_args_t *args, zpios_cmd_t *cmd)
330 zpios_stats_t *summary_stats;
331 double t_time, wr_time, rd_time, cr_time, rm_time;
335 printf("FAIL: %3d ", args->rc);
339 printf("%-12s", args->name ? args->name : ZPIOS_NAME);
340 printf("%2u\t", cmd->cmd_id);
343 printf("%u\t", cmd->cmd_thread_count);
344 printf("%u\t", cmd->cmd_region_count);
345 printf("%s\t", uint64_to_kmgt(str, cmd->cmd_region_size));
346 printf("%s\t", uint64_to_kmgt(str, cmd->cmd_chunk_size));
347 printf("%s\t", uint64_to_kmgt(str, cmd->cmd_offset));
348 printf("%s\t", uint64_to_kmgt(str, cmd->cmd_region_noise));
349 printf("%s\t", uint64_to_kmgt(str, cmd->cmd_chunk_noise));
350 printf("%s\t", uint64_to_kmgt(str, cmd->cmd_thread_delay));
351 printf("%s\t", print_flags(str, cmd->cmd_flags));
359 summary_stats = (zpios_stats_t *)cmd->cmd_data_str;
360 t_time = zpios_timespec_to_double(summary_stats->total_time.delta);
361 wr_time = zpios_timespec_to_double(summary_stats->wr_time.delta);
362 rd_time = zpios_timespec_to_double(summary_stats->rd_time.delta);
363 cr_time = zpios_timespec_to_double(summary_stats->cr_time.delta);
364 rm_time = zpios_timespec_to_double(summary_stats->rm_time.delta);
367 printf("%.2f\t", t_time);
368 printf("%.3f\t", cr_time);
369 printf("%.3f\t", rm_time);
370 printf("%.2f\t", wr_time);
371 printf("%.2f\t", rd_time);
374 printf("%s\t", uint64_to_kmgt(str, summary_stats->wr_data));
375 printf("%s\t", uint64_to_kmgt(str, summary_stats->wr_chunks));
376 printf("%s\t", kmgt_per_sec(str, summary_stats->wr_data, wr_time));
378 printf("%s\t", uint64_to_kmgt(str, summary_stats->rd_data));
379 printf("%s\t", uint64_to_kmgt(str, summary_stats->rd_chunks));
380 printf("%s\n", kmgt_per_sec(str, summary_stats->rd_data, rd_time));
385 print_stats_table(cmd_args_t *args, zpios_cmd_t *cmd)
387 zpios_stats_t *summary_stats;
388 double wr_time, rd_time;
391 printf("FAIL: %3d ", args->rc);
395 printf("%-12s", args->name ? args->name : ZPIOS_NAME);
396 printf("%2u\t", cmd->cmd_id);
399 printf("%u\t", cmd->cmd_thread_count);
400 printf("%u\t", cmd->cmd_region_count);
401 printf("%llu\t", (long long unsigned)cmd->cmd_region_size);
402 printf("%llu\t", (long long unsigned)cmd->cmd_chunk_size);
403 printf("%llu\t", (long long unsigned)cmd->cmd_offset);
404 printf("%u\t", cmd->cmd_region_noise);
405 printf("%u\t", cmd->cmd_chunk_noise);
406 printf("%u\t", cmd->cmd_thread_delay);
407 printf("0x%x\t", cmd->cmd_flags);
415 summary_stats = (zpios_stats_t *)cmd->cmd_data_str;
416 wr_time = zpios_timespec_to_double(summary_stats->wr_time.delta);
417 rd_time = zpios_timespec_to_double(summary_stats->rd_time.delta);
420 printf("%ld.%02ld\t",
421 (long)summary_stats->total_time.delta.ts_sec,
422 (long)summary_stats->total_time.delta.ts_nsec);
423 printf("%ld.%02ld\t",
424 (long)summary_stats->cr_time.delta.ts_sec,
425 (long)summary_stats->cr_time.delta.ts_nsec);
426 printf("%ld.%02ld\t",
427 (long)summary_stats->rm_time.delta.ts_sec,
428 (long)summary_stats->rm_time.delta.ts_nsec);
429 printf("%ld.%02ld\t",
430 (long)summary_stats->wr_time.delta.ts_sec,
431 (long)summary_stats->wr_time.delta.ts_nsec);
432 printf("%ld.%02ld\t",
433 (long)summary_stats->rd_time.delta.ts_sec,
434 (long)summary_stats->rd_time.delta.ts_nsec);
437 printf("%lld\t", (long long unsigned)summary_stats->wr_data);
438 printf("%lld\t", (long long unsigned)summary_stats->wr_chunks);
439 printf("%.4f\t", (double)summary_stats->wr_data / wr_time);
441 printf("%lld\t", (long long unsigned)summary_stats->rd_data);
442 printf("%lld\t", (long long unsigned)summary_stats->rd_chunks);
443 printf("%.4f\n", (double)summary_stats->rd_data / rd_time);
448 print_stats(cmd_args_t *args, zpios_cmd_t *cmd)
450 if (args->human_readable)
451 print_stats_human_readable(args, cmd);
453 print_stats_table(args, cmd);