xref: /spdk/examples/bdev/bdevperf/bdevperf.py (revision db0266882d4346f7e46089f00a0a199f19299e3c)
129784f35SKrzysztof Karas#!/usr/bin/env python3
229784f35SKrzysztof Karas#  SPDX-License-Identifier: BSD-3-Clause
329784f35SKrzysztof Karas#  Copyright (C) 2019 Intel Corporation
429784f35SKrzysztof Karas#  All rights reserved.
529784f35SKrzysztof Karas#
629784f35SKrzysztof Karas
729784f35SKrzysztof Karasimport logging
829784f35SKrzysztof Karasimport argparse
929784f35SKrzysztof Karasimport sys
1029784f35SKrzysztof Karasimport shlex
1129784f35SKrzysztof Karas
1229784f35SKrzysztof Karastry:
1329784f35SKrzysztof Karas    from spdk.rpc.client import print_dict, JSONRPCException
1429784f35SKrzysztof Karas    import spdk.rpc as rpc
1529784f35SKrzysztof Karasexcept ImportError:
1629784f35SKrzysztof Karas    print("SPDK RPC library missing. Please add spdk/python directory to PYTHONPATH:")
1729784f35SKrzysztof Karas    print("'export PYTHONPATH=$PYTHONPATH:spdk/python'")
1829784f35SKrzysztof Karas    exit(1)
1929784f35SKrzysztof Karas
2029784f35SKrzysztof Karastry:
2129784f35SKrzysztof Karas    from shlex import quote
2229784f35SKrzysztof Karasexcept ImportError:
2329784f35SKrzysztof Karas    from pipes import quote
2429784f35SKrzysztof Karas
25bbf8dfb7SEugene KobyakPATTERN_TYPES_STR = ("read", "write", "randread", "randwrite", "rw", "randrw", "verify", "reset",
26bbf8dfb7SEugene Kobyak                     "unmap", "flush", "write_zeroes")
27bbf8dfb7SEugene Kobyak
2829784f35SKrzysztof Karas
2929784f35SKrzysztof Karasdef print_array(a):
3029784f35SKrzysztof Karas    print(" ".join((quote(v) for v in a)))
3129784f35SKrzysztof Karas
3229784f35SKrzysztof Karas
33bbf8dfb7SEugene Kobyakdef perform_tests_func(args):
34bbf8dfb7SEugene Kobyak    """Perform bdevperf tests with command line arguments.
3529784f35SKrzysztof Karas
3629784f35SKrzysztof Karas    Args:
3729784f35SKrzysztof Karas        none
3829784f35SKrzysztof Karas
3929784f35SKrzysztof Karas    Returns:
4029784f35SKrzysztof Karas        On success, 0 is returned. On error, -1 is returned.
4129784f35SKrzysztof Karas    """
42bbf8dfb7SEugene Kobyak    client = args.client
43bbf8dfb7SEugene Kobyak    param_names = ['queue_depth', 'time_in_sec', 'workload_type', 'io_size', 'rw_percentage']
44bbf8dfb7SEugene Kobyak    params = {name: getattr(args, name) for name in param_names if getattr(args, name, None)}
4529784f35SKrzysztof Karas    return client.call('perform_tests', params)
4629784f35SKrzysztof Karas
4729784f35SKrzysztof Karas
4829784f35SKrzysztof Karasif __name__ == "__main__":
4929784f35SKrzysztof Karas    parser = argparse.ArgumentParser(
5029784f35SKrzysztof Karas        description='SPDK RPC command line interface. NOTE: spdk/python is expected in PYTHONPATH')
5129784f35SKrzysztof Karas    parser.add_argument('-s', dest='server_addr',
5229784f35SKrzysztof Karas                        help='RPC domain socket path or IP address', default='/var/tmp/spdk.sock')
5329784f35SKrzysztof Karas    parser.add_argument('-p', dest='port',
5429784f35SKrzysztof Karas                        help='RPC port number (if server_addr is IP address)',
5529784f35SKrzysztof Karas                        default=5260, type=int)
5629784f35SKrzysztof Karas    parser.add_argument('-t', dest='timeout',
5729784f35SKrzysztof Karas                        help='Timeout as a floating point number expressed in seconds waiting for response. Default: 60.0',
5829784f35SKrzysztof Karas                        default=60.0, type=float)
5929784f35SKrzysztof Karas    parser.add_argument('-v', dest='verbose', action='store_const', const="INFO",
6029784f35SKrzysztof Karas                        help='Set verbose mode to INFO', default="ERROR")
6129784f35SKrzysztof Karas    parser.add_argument('--verbose', dest='verbose', choices=['DEBUG', 'INFO', 'ERROR'],
6229784f35SKrzysztof Karas                        help="""Set verbose level. """)
6329784f35SKrzysztof Karas    subparsers = parser.add_subparsers(help='RPC methods')
6429784f35SKrzysztof Karas
6529784f35SKrzysztof Karas    def perform_tests(args):
66bbf8dfb7SEugene Kobyak        print_dict(perform_tests_func(args))
6729784f35SKrzysztof Karas
68bbf8dfb7SEugene Kobyak    perform_tests_help_string = '''
69bbf8dfb7SEugene Kobyak    Perform bdevperf tests
70bbf8dfb7SEugene Kobyak    All parameters are optional.
71bbf8dfb7SEugene Kobyak    If any parameter provided it will overwrite ones from prior run or command line.
72bbf8dfb7SEugene Kobyak    If job config file was used no parameter should be provided.
73bbf8dfb7SEugene Kobyak    '''
74bbf8dfb7SEugene Kobyak    p = subparsers.add_parser('perform_tests', help=perform_tests_help_string)
75bbf8dfb7SEugene Kobyak    p.add_argument('-q', dest="queue_depth", help='io depth', type=int)
76bbf8dfb7SEugene Kobyak    p.add_argument('-o', dest="io_size", help='Size in bytes', type=str)
77bbf8dfb7SEugene Kobyak    p.add_argument('-t', dest="time_in_sec", help='Time in seconds', type=int)
78bbf8dfb7SEugene Kobyak    p.add_argument('-M', dest="rw_percentage", help='rwmixread (100 for reads, 0 for writes)',
79bbf8dfb7SEugene Kobyak                   type=int, choices=range(0, 101), metavar="[0-100]")
80bbf8dfb7SEugene Kobyak    p.add_argument('-w', dest="workload_type", choices=PATTERN_TYPES_STR, type=str.lower,
81bbf8dfb7SEugene Kobyak                   help=f'io pattern type, must be one of {PATTERN_TYPES_STR}',)
8229784f35SKrzysztof Karas    p.set_defaults(func=perform_tests)
8329784f35SKrzysztof Karas
8429784f35SKrzysztof Karas    def call_rpc_func(args):
8529784f35SKrzysztof Karas        try:
8629784f35SKrzysztof Karas            args.func(args)
8729784f35SKrzysztof Karas        except JSONRPCException as ex:
8829784f35SKrzysztof Karas            print(ex.message)
8929784f35SKrzysztof Karas            exit(1)
9029784f35SKrzysztof Karas
9129784f35SKrzysztof Karas    def execute_script(parser, client, fd):
9229784f35SKrzysztof Karas        for rpc_call in map(str.rstrip, fd):
9329784f35SKrzysztof Karas            if not rpc_call.strip():
9429784f35SKrzysztof Karas                continue
9529784f35SKrzysztof Karas            args = parser.parse_args(shlex.split(rpc_call))
9629784f35SKrzysztof Karas            args.client = client
9729784f35SKrzysztof Karas            call_rpc_func(args)
9829784f35SKrzysztof Karas
9929784f35SKrzysztof Karas    args = parser.parse_args()
100*db026688SMarcin Spiewak    if args.time_in_sec is not None:
101*db026688SMarcin Spiewak        args.timeout = max(float(args.time_in_sec + 5), args.timeout)
10229784f35SKrzysztof Karas    args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.timeout, log_level=getattr(logging, args.verbose.upper()))
10329784f35SKrzysztof Karas    if hasattr(args, 'func'):
10429784f35SKrzysztof Karas        call_rpc_func(args)
10529784f35SKrzysztof Karas    elif sys.stdin.isatty():
10629784f35SKrzysztof Karas        # No arguments and no data piped through stdin
10729784f35SKrzysztof Karas        parser.print_help()
10829784f35SKrzysztof Karas        exit(1)
10929784f35SKrzysztof Karas    else:
11029784f35SKrzysztof Karas        execute_script(parser, args.client, sys.stdin)
111