mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 19:19:32 +03:00
02730c333c
Enable picky cstyle checks and resolve the new warnings. The vast majority of the changes needed were to handle minor issues with whitespace formatting. This patch contains no functional changes. Non-whitespace changes are as follows: * 8 times ; to { } in for/while loop * fix missing ; in cmd/zed/agents/zfs_diagnosis.c * comment (confim -> confirm) * change endline , to ; in cmd/zpool/zpool_main.c * a number of /* BEGIN CSTYLED */ /* END CSTYLED */ blocks * /* CSTYLED */ markers * change == 0 to ! * ulong to unsigned long in module/zfs/dsl_scan.c * rearrangement of module_param lines in module/zfs/metaslab.c * add { } block around statement after for_each_online_node Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov> Reviewed-by: Håkan Johansson <f96hajo@chalmers.se> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #5465
477 lines
12 KiB
C
477 lines
12 KiB
C
/*
|
|
* ZPIOS is a heavily modified version of the original PIOS test code.
|
|
* It is designed to have the test code running in the Linux kernel
|
|
* against ZFS while still being flexibly controled from user space.
|
|
*
|
|
* Copyright (C) 2008-2010 Lawrence Livermore National Security, LLC.
|
|
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
|
|
* Written by Brian Behlendorf <behlendorf1@llnl.gov>.
|
|
* LLNL-CODE-403049
|
|
*
|
|
* Original PIOS Test Code
|
|
* Copyright (C) 2004 Cluster File Systems, Inc.
|
|
* Written by Peter Braam <braam@clusterfs.com>
|
|
* Atul Vidwansa <atul@clusterfs.com>
|
|
* Milind Dumbare <milind@clusterfs.com>
|
|
*
|
|
* This file is part of ZFS on Linux.
|
|
* For details, see <http://zfsonlinux.org/>.
|
|
*
|
|
* ZPIOS 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.
|
|
*
|
|
* ZPIOS 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 ZPIOS. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Copyright (c) 2015, Intel Corporation.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
#include <regex.h>
|
|
#include "zpios.h"
|
|
|
|
/* extracts an unsigned int (64) and K,M,G,T from the string */
|
|
/* and returns a 64 bit value converted to the proper units */
|
|
static int
|
|
kmgt_to_uint64(const char *str, uint64_t *val)
|
|
{
|
|
char *endptr;
|
|
int rc = 0;
|
|
|
|
*val = strtoll(str, &endptr, 0);
|
|
if ((str == endptr) && (*val == 0))
|
|
return (EINVAL);
|
|
|
|
switch (endptr[0]) {
|
|
case 'k': case 'K':
|
|
*val = (*val) << 10;
|
|
break;
|
|
case 'm': case 'M':
|
|
*val = (*val) << 20;
|
|
break;
|
|
case 'g': case 'G':
|
|
*val = (*val) << 30;
|
|
break;
|
|
case 't': case 'T':
|
|
*val = (*val) << 40;
|
|
break;
|
|
case '\0':
|
|
break;
|
|
default:
|
|
rc = EINVAL;
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
static char *
|
|
uint64_to_kmgt(char *str, uint64_t val)
|
|
{
|
|
char postfix[] = "kmgt";
|
|
int i = -1;
|
|
|
|
while ((val >= KB) && (i < 4)) {
|
|
val = (val >> 10);
|
|
i++;
|
|
}
|
|
|
|
if (i >= 4)
|
|
(void) snprintf(str, KMGT_SIZE-1, "inf");
|
|
else
|
|
(void) snprintf(str, KMGT_SIZE-1, "%lu%c", (unsigned long)val,
|
|
(i == -1) ? '\0' : postfix[i]);
|
|
|
|
return (str);
|
|
}
|
|
|
|
static char *
|
|
kmgt_per_sec(char *str, uint64_t v, double t)
|
|
{
|
|
char postfix[] = "kmgt";
|
|
double val = ((double)v) / t;
|
|
int i = -1;
|
|
|
|
while ((val >= (double)KB) && (i < 4)) {
|
|
val /= (double)KB;
|
|
i++;
|
|
}
|
|
|
|
if (i >= 4)
|
|
(void) snprintf(str, KMGT_SIZE-1, "inf");
|
|
else
|
|
(void) snprintf(str, KMGT_SIZE-1, "%.2f%c", val,
|
|
(i == -1) ? '\0' : postfix[i]);
|
|
|
|
return (str);
|
|
}
|
|
|
|
static char *
|
|
print_flags(char *str, uint32_t flags)
|
|
{
|
|
str[0] = (flags & DMU_WRITE) ? 'w' : '-';
|
|
str[1] = (flags & DMU_READ) ? 'r' : '-';
|
|
str[2] = (flags & DMU_VERIFY) ? 'v' : '-';
|
|
str[3] = (flags & DMU_REMOVE) ? 'c' : '-';
|
|
str[4] = (flags & DMU_FPP) ? 'p' : 's';
|
|
str[5] = (flags & (DMU_WRITE_ZC | DMU_READ_ZC)) ? 'z' : '-';
|
|
str[6] = (flags & DMU_WRITE_NOWAIT) ? 'O' : '-';
|
|
str[7] = '\0';
|
|
|
|
return (str);
|
|
}
|
|
|
|
static int
|
|
regex_match(const char *string, char *pattern)
|
|
{
|
|
regex_t re = { 0 };
|
|
int rc;
|
|
|
|
rc = regcomp(&re, pattern, REG_EXTENDED | REG_NOSUB | REG_ICASE);
|
|
if (rc) {
|
|
fprintf(stderr, "Error: Couldn't do regcomp, %d\n", rc);
|
|
return (rc);
|
|
}
|
|
|
|
rc = regexec(&re, string, (size_t)0, NULL, 0);
|
|
regfree(&re);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
/* fills the pios_range_repeat structure of comma separated values */
|
|
static int
|
|
split_string(const char *optarg, char *pattern, range_repeat_t *range)
|
|
{
|
|
const char comma[] = ",";
|
|
char *cp, *token[32];
|
|
int rc, i = 0;
|
|
|
|
if ((rc = regex_match(optarg, pattern)))
|
|
return (rc);
|
|
|
|
cp = strdup(optarg);
|
|
if (cp == NULL)
|
|
return (ENOMEM);
|
|
|
|
do {
|
|
/*
|
|
* STRTOK(3) Each subsequent call, with a null pointer as the
|
|
* value of the * first argument, starts searching from the
|
|
* saved pointer and behaves as described above.
|
|
*/
|
|
if (i == 0) {
|
|
token[i] = strtok(cp, comma);
|
|
} else {
|
|
token[i] = strtok(NULL, comma);
|
|
}
|
|
} while ((token[i++] != NULL) && (i < 32));
|
|
|
|
range->val_count = i - 1;
|
|
|
|
for (i = 0; i < range->val_count; i++)
|
|
kmgt_to_uint64(token[i], &range->val[i]);
|
|
|
|
free(cp);
|
|
return (0);
|
|
}
|
|
|
|
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;
|
|
|
|
range->next_val = 0;
|
|
|
|
if (regex_match(optarg, pattern1) == 0) {
|
|
kmgt_to_uint64(optarg, &range->val[0]);
|
|
range->val_count = 1;
|
|
} else if (split_string(optarg, pattern2, range) < 0) {
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* Validates the value with regular expression and sets low, high, incr
|
|
* according to value at which flag will be set. Sets the flag after.
|
|
*/
|
|
int
|
|
set_lhi(char *pattern, range_repeat_t *range, char *optarg,
|
|
int flag, uint32_t *flag_thread, char *arg)
|
|
{
|
|
int rc;
|
|
|
|
if ((rc = regex_match(optarg, pattern))) {
|
|
fprintf(stderr, "Error: Wrong pattern in %s, '%s'\n",
|
|
arg, optarg);
|
|
return (rc);
|
|
}
|
|
|
|
switch (flag) {
|
|
case FLAG_LOW:
|
|
kmgt_to_uint64(optarg, &range->val_low);
|
|
break;
|
|
case FLAG_HIGH:
|
|
kmgt_to_uint64(optarg, &range->val_high);
|
|
break;
|
|
case FLAG_INCR:
|
|
kmgt_to_uint64(optarg, &range->val_inc_perc);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
|
|
*flag_thread |= flag;
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
set_noise(uint64_t *noise, char *optarg, char *arg)
|
|
{
|
|
if (regex_match(optarg, REGEX_NUMBERS) == 0) {
|
|
kmgt_to_uint64(optarg, noise);
|
|
} else {
|
|
fprintf(stderr, "Error: Incorrect pattern for %s\n", arg);
|
|
return (EINVAL);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
set_load_params(cmd_args_t *args, char *optarg)
|
|
{
|
|
char *param, *search, *searchdup, comma[] = ",";
|
|
int rc = 0;
|
|
|
|
search = strdup(optarg);
|
|
if (search == NULL)
|
|
return (ENOMEM);
|
|
searchdup = search;
|
|
|
|
while ((param = strtok(search, comma)) != NULL) {
|
|
search = NULL;
|
|
|
|
if (strcmp("fpp", param) == 0) {
|
|
args->flags |= DMU_FPP; /* File Per Process/Thread */
|
|
} else if (strcmp("ssf", param) == 0) {
|
|
args->flags &= ~DMU_FPP; /* Single Shared File */
|
|
} else if (strcmp("dmuio", param) == 0) {
|
|
args->io_type |= DMU_IO;
|
|
args->flags |= (DMU_WRITE | DMU_READ);
|
|
} else {
|
|
fprintf(stderr, "Invalid load: %s\n", param);
|
|
rc = EINVAL;
|
|
}
|
|
}
|
|
|
|
free(searchdup);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
/*
|
|
* Checks the low, high, increment values against the single value for
|
|
* mutual exclusion, for e.g threadcount is mutually exclusive to
|
|
* threadcount_low, ..._high, ..._incr
|
|
*/
|
|
int
|
|
check_mutual_exclusive_command_lines(uint32_t flag, char *arg)
|
|
{
|
|
if ((flag & FLAG_SET) && (flag & (FLAG_LOW | FLAG_HIGH | FLAG_INCR))) {
|
|
fprintf(stderr, "Error: --%s can not be given with --%s_low, "
|
|
"--%s_high or --%s_incr.\n", arg, arg, arg, arg);
|
|
return (0);
|
|
}
|
|
|
|
if ((flag & (FLAG_LOW | FLAG_HIGH | FLAG_INCR)) && !(flag & FLAG_SET)) {
|
|
if (flag != (FLAG_LOW | FLAG_HIGH | FLAG_INCR)) {
|
|
fprintf(stderr, "Error: One or more values missing "
|
|
"from --%s_low, --%s_high, --%s_incr.\n",
|
|
arg, arg, arg);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
void
|
|
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\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");
|
|
} else {
|
|
printf(
|
|
"status name id\t"
|
|
"wr-data\twr-ch\twr-bw\t"
|
|
"rd-data\trd-ch\trd-bw\n");
|
|
printf(
|
|
"-----------------------------------------"
|
|
"--------------------------------------\n");
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_stats_human_readable(cmd_args_t *args, zpios_cmd_t *cmd)
|
|
{
|
|
zpios_stats_t *summary_stats;
|
|
double t_time, wr_time, rd_time, cr_time, rm_time;
|
|
char str[KMGT_SIZE];
|
|
|
|
if (args->rc)
|
|
printf("FAIL: %3d ", args->rc);
|
|
else
|
|
printf("PASS: ");
|
|
|
|
printf("%-12s", args->name ? args->name : ZPIOS_NAME);
|
|
printf("%2u\t", cmd->cmd_id);
|
|
|
|
if (args->verbose) {
|
|
printf("%u\t", cmd->cmd_thread_count);
|
|
printf("%u\t", cmd->cmd_region_count);
|
|
printf("%s\t", uint64_to_kmgt(str, cmd->cmd_region_size));
|
|
printf("%s\t", uint64_to_kmgt(str, cmd->cmd_chunk_size));
|
|
printf("%s\t", uint64_to_kmgt(str, cmd->cmd_offset));
|
|
printf("%s\t", uint64_to_kmgt(str, cmd->cmd_region_noise));
|
|
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) {
|
|
printf("\n");
|
|
return;
|
|
}
|
|
|
|
summary_stats = (zpios_stats_t *)cmd->cmd_data_str;
|
|
t_time = zpios_timespec_to_double(summary_stats->total_time.delta);
|
|
wr_time = zpios_timespec_to_double(summary_stats->wr_time.delta);
|
|
rd_time = zpios_timespec_to_double(summary_stats->rd_time.delta);
|
|
cr_time = zpios_timespec_to_double(summary_stats->cr_time.delta);
|
|
rm_time = zpios_timespec_to_double(summary_stats->rm_time.delta);
|
|
|
|
if (args->verbose) {
|
|
printf("%.2f\t", t_time);
|
|
printf("%.3f\t", cr_time);
|
|
printf("%.3f\t", rm_time);
|
|
printf("%.2f\t", wr_time);
|
|
printf("%.2f\t", rd_time);
|
|
}
|
|
|
|
printf("%s\t", uint64_to_kmgt(str, summary_stats->wr_data));
|
|
printf("%s\t", uint64_to_kmgt(str, summary_stats->wr_chunks));
|
|
printf("%s\t", kmgt_per_sec(str, summary_stats->wr_data, wr_time));
|
|
|
|
printf("%s\t", uint64_to_kmgt(str, summary_stats->rd_data));
|
|
printf("%s\t", uint64_to_kmgt(str, summary_stats->rd_chunks));
|
|
printf("%s\n", kmgt_per_sec(str, summary_stats->rd_data, rd_time));
|
|
fflush(stdout);
|
|
}
|
|
|
|
static void
|
|
print_stats_table(cmd_args_t *args, zpios_cmd_t *cmd)
|
|
{
|
|
zpios_stats_t *summary_stats;
|
|
double wr_time, rd_time;
|
|
|
|
if (args->rc)
|
|
printf("FAIL: %3d ", args->rc);
|
|
else
|
|
printf("PASS: ");
|
|
|
|
printf("%-12s", args->name ? args->name : ZPIOS_NAME);
|
|
printf("%2u\t", cmd->cmd_id);
|
|
|
|
if (args->verbose) {
|
|
printf("%u\t", cmd->cmd_thread_count);
|
|
printf("%u\t", cmd->cmd_region_count);
|
|
printf("%llu\t", (long long unsigned)cmd->cmd_region_size);
|
|
printf("%llu\t", (long long unsigned)cmd->cmd_chunk_size);
|
|
printf("%llu\t", (long long unsigned)cmd->cmd_offset);
|
|
printf("%u\t", cmd->cmd_region_noise);
|
|
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) {
|
|
printf("\n");
|
|
return;
|
|
}
|
|
|
|
summary_stats = (zpios_stats_t *)cmd->cmd_data_str;
|
|
wr_time = zpios_timespec_to_double(summary_stats->wr_time.delta);
|
|
rd_time = zpios_timespec_to_double(summary_stats->rd_time.delta);
|
|
|
|
if (args->verbose) {
|
|
printf("%ld.%02ld\t",
|
|
(long)summary_stats->total_time.delta.ts_sec,
|
|
(long)summary_stats->total_time.delta.ts_nsec);
|
|
printf("%ld.%02ld\t",
|
|
(long)summary_stats->cr_time.delta.ts_sec,
|
|
(long)summary_stats->cr_time.delta.ts_nsec);
|
|
printf("%ld.%02ld\t",
|
|
(long)summary_stats->rm_time.delta.ts_sec,
|
|
(long)summary_stats->rm_time.delta.ts_nsec);
|
|
printf("%ld.%02ld\t",
|
|
(long)summary_stats->wr_time.delta.ts_sec,
|
|
(long)summary_stats->wr_time.delta.ts_nsec);
|
|
printf("%ld.%02ld\t",
|
|
(long)summary_stats->rd_time.delta.ts_sec,
|
|
(long)summary_stats->rd_time.delta.ts_nsec);
|
|
}
|
|
|
|
printf("%lld\t", (long long unsigned)summary_stats->wr_data);
|
|
printf("%lld\t", (long long unsigned)summary_stats->wr_chunks);
|
|
printf("%.4f\t", (double)summary_stats->wr_data / wr_time);
|
|
|
|
printf("%lld\t", (long long unsigned)summary_stats->rd_data);
|
|
printf("%lld\t", (long long unsigned)summary_stats->rd_chunks);
|
|
printf("%.4f\n", (double)summary_stats->rd_data / rd_time);
|
|
fflush(stdout);
|
|
}
|
|
|
|
void
|
|
print_stats(cmd_args_t *args, zpios_cmd_t *cmd)
|
|
{
|
|
if (args->human_readable)
|
|
print_stats_human_readable(args, cmd);
|
|
else
|
|
print_stats_table(args, cmd);
|
|
}
|