Commit bbf8dfb7 authored by Eugene Kobyak's avatar Eugene Kobyak Committed by Tomasz Zawadzki
Browse files

bdevperf: introduce params to "perform_tests" RPC



allow users to configure the test run using the "perform_tests" RPC

Change-Id: Ie246832f94adce3d8813fd4792b7ea86ab528a60
Signed-off-by: default avatarEugene Kobyak <eugene.kobyak@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/20978


Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent 4348ccc0
Loading
Loading
Loading
Loading
+89 −6
Original line number Diff line number Diff line
@@ -78,6 +78,9 @@ static struct spdk_poller *g_perf_timer = NULL;

static void bdevperf_submit_single(struct bdevperf_job *job, struct bdevperf_task *task);
static void rpc_perform_tests_cb(void);
static int bdevperf_parse_arg(int ch, char *arg);
static int verify_test_params(void);
static void bdevperf_usage(void);

static uint32_t g_bdev_count = 0;
static uint32_t g_latency_display_level;
@@ -2462,20 +2465,96 @@ rpc_perform_tests_cb(void)
	rpc_perform_tests_reset();
}

struct rpc_bdevperf_params {
	int	time_in_sec;
	char	*workload_type;
	int	queue_depth;
	char	*io_size;
	int	rw_percentage;
};

static const struct spdk_json_object_decoder rpc_bdevperf_params_decoders[] = {
	{"time_in_sec", offsetof(struct rpc_bdevperf_params, time_in_sec), spdk_json_decode_int32, true},
	{"workload_type", offsetof(struct rpc_bdevperf_params, workload_type), spdk_json_decode_string, true},
	{"queue_depth", offsetof(struct rpc_bdevperf_params, queue_depth), spdk_json_decode_int32, true},
	{"io_size", offsetof(struct rpc_bdevperf_params, io_size), spdk_json_decode_string, true},
	{"rw_percentage", offsetof(struct rpc_bdevperf_params, rw_percentage), spdk_json_decode_int32, true},
};

static void
rpc_perform_tests(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
rpc_apply_bdevperf_params(struct rpc_bdevperf_params *params)
{
	if (params != NULL) {
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
						 "perform_tests method requires no parameters");
		return;
	if (params->workload_type) {
		/* we need to clear previously settled parameter to avoid memory leak */
		free(g_workload_type);
		g_workload_type = strdup(params->workload_type);
	}
	if (params->queue_depth) {
		g_queue_depth = params->queue_depth;
	}
	if (params->io_size) {
		bdevperf_parse_arg('o', params->io_size);
	}
	if (params->time_in_sec) {
		g_time_in_sec = params->time_in_sec;
	}
	if (params->rw_percentage) {
		g_rw_percentage = params->rw_percentage;
		g_mix_specified = true;
	} else {
		g_mix_specified = false;
	}
}

static void
rpc_perform_tests(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
{
	struct rpc_bdevperf_params req = {}, backup = {};
	int rc;

	if (g_request != NULL) {
		fprintf(stderr, "Another test is already in progress.\n");
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
						 spdk_strerror(-EINPROGRESS));
		return;
	}

	if (params) {
		if (spdk_json_decode_object_relaxed(params, rpc_bdevperf_params_decoders,
						    SPDK_COUNTOF(rpc_bdevperf_params_decoders),
						    &req)) {
			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_PARSE_ERROR,
							 "spdk_json_decode_object failed");
			return;
		}

		if (g_workload_type) {
			backup.workload_type = strdup(g_workload_type);
		}
		backup.queue_depth = g_queue_depth;
		if (asprintf(&backup.io_size, "%d", g_io_size) < 0) {
			fprintf(stderr, "Couldn't allocate memory for queue depth");
			goto rpc_error;
		}
		backup.time_in_sec = g_time_in_sec;
		backup.rw_percentage = g_rw_percentage;

		rpc_apply_bdevperf_params(&req);

		free(req.workload_type);
		free(req.io_size);
	}

	rc = verify_test_params();

	if (rc) {
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_PARSE_ERROR,
						 "Invalid parameters provided");
		/* restore old params on error */
		rpc_apply_bdevperf_params(&backup);
		goto rpc_error;
	}

	g_request = request;

	/* Only construct job configs at the first test run.  */
@@ -2484,6 +2563,10 @@ rpc_perform_tests(struct spdk_jsonrpc_request *request, const struct spdk_json_v
	} else {
		bdevperf_construct_jobs();
	}

rpc_error:
	free(backup.io_size);
	free(backup.workload_type);
}
SPDK_RPC_REGISTER("perform_tests", rpc_perform_tests, SPDK_RPC_RUNTIME)

@@ -2774,7 +2857,7 @@ main(int argc, char **argv)
		opts.rpc_log_file = g_rpc_log_file;
	}

	if (verify_test_params() != 0) {
	if (verify_test_params() != 0 && !g_wait_for_tests) {
		spdk_app_usage();
		bdevperf_usage();
		bdevperf_fini();
+24 −6
Original line number Diff line number Diff line
@@ -22,13 +22,16 @@ try:
except ImportError:
    from pipes import quote

PATTERN_TYPES_STR = ("read", "write", "randread", "randwrite", "rw", "randrw", "verify", "reset",
                     "unmap", "flush", "write_zeroes")


def print_array(a):
    print(" ".join((quote(v) for v in a)))


def perform_tests_func(client):
    """Perform bdevperf tests according to command line arguments when application was started.
def perform_tests_func(args):
    """Perform bdevperf tests with command line arguments.

    Args:
        none
@@ -36,7 +39,9 @@ def perform_tests_func(client):
    Returns:
        On success, 0 is returned. On error, -1 is returned.
    """
    params = {}
    client = args.client
    param_names = ['queue_depth', 'time_in_sec', 'workload_type', 'io_size', 'rw_percentage']
    params = {name: getattr(args, name) for name in param_names if getattr(args, name, None)}
    return client.call('perform_tests', params)


@@ -58,9 +63,22 @@ if __name__ == "__main__":
    subparsers = parser.add_subparsers(help='RPC methods')

    def perform_tests(args):
        print_dict(perform_tests_func(args.client))

    p = subparsers.add_parser('perform_tests', help='Perform bdevperf tests')
        print_dict(perform_tests_func(args))

    perform_tests_help_string = '''
    Perform bdevperf tests
    All parameters are optional.
    If any parameter provided it will overwrite ones from prior run or command line.
    If job config file was used no parameter should be provided.
    '''
    p = subparsers.add_parser('perform_tests', help=perform_tests_help_string)
    p.add_argument('-q', dest="queue_depth", help='io depth', type=int)
    p.add_argument('-o', dest="io_size", help='Size in bytes', type=str)
    p.add_argument('-t', dest="time_in_sec", help='Time in seconds', type=int)
    p.add_argument('-M', dest="rw_percentage", help='rwmixread (100 for reads, 0 for writes)',
                   type=int, choices=range(0, 101), metavar="[0-100]")
    p.add_argument('-w', dest="workload_type", choices=PATTERN_TYPES_STR, type=str.lower,
                   help=f'io pattern type, must be one of {PATTERN_TYPES_STR}',)
    p.set_defaults(func=perform_tests)

    def call_rpc_func(args):
+19 −19
Original line number Diff line number Diff line
@@ -8,16 +8,14 @@ rootdir=$(readlink -f $testdir/../..)
source $rootdir/test/common/autotest_common.sh
source $testdir/common.sh

tests=('-q 1 -w randwrite -t 4 -o 69632' '-q 128 -w randwrite -t 4 -o 4096' '-q 128 -w verify -t 4 -o 4096')
device=$1
cache_device=$2
use_append=$3
rpc_py=$rootdir/scripts/rpc.py
timeout=240

for ((i = 0; i < ${#tests[@]}; i++)); do
	timing_enter "${tests[$i]}"
	"$rootdir/build/examples/bdevperf" -z -T ftl0 ${tests[$i]} &
timing_enter "$rootdir/build/examples/bdevperf -z -T ftl0"
"$rootdir/build/examples/bdevperf" -z -T ftl0 &
bdevperf_pid=$!

trap 'killprocess $bdevperf_pid; exit 1' SIGINT SIGTERM EXIT
@@ -30,12 +28,14 @@ for ((i = 0; i < ${#tests[@]}; i++)); do
# Check ftl0 was created properly
$rpc_py bdev_ftl_get_stats -b ftl0 | jq -r '.name' | grep -qw ftl0

	$rootdir/examples/bdev/bdevperf/bdevperf.py perform_tests
$rootdir/examples/bdev/bdevperf/bdevperf.py perform_tests -q 1 -w randwrite -t 4 -o 69632
$rootdir/examples/bdev/bdevperf/bdevperf.py perform_tests -q 128 -w randwrite -t 4 -o 4096
$rootdir/examples/bdev/bdevperf/bdevperf.py perform_tests -q 128 -w verify -t 4 -o 4096

$rpc_py bdev_ftl_delete -b ftl0

killprocess $bdevperf_pid
trap - SIGINT SIGTERM EXIT
	timing_exit "${tests[$i]}"
done
timing_exit "$rootdir/build/examples/bdevperf -z -T ftl0"

remove_shm