xref: /spdk/examples/bdev/bdevperf/bdevperf.py (revision 552eaa9c3d45fbf8e8f5ba64c42aa2b13131d1ec)
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
9*552eaa9cSKonrad Sztyberimport os
1029784f35SKrzysztof Karasimport sys
1129784f35SKrzysztof Karasimport shlex
1229784f35SKrzysztof Karas
1329784f35SKrzysztof Karastry:
1429784f35SKrzysztof Karas    from shlex import quote
1529784f35SKrzysztof Karasexcept ImportError:
1629784f35SKrzysztof Karas    from pipes import quote
1729784f35SKrzysztof Karas
18*552eaa9cSKonrad Sztybertry:
19*552eaa9cSKonrad Sztyber    sys.path.append(os.path.dirname(__file__) + '/../../../python')
20*552eaa9cSKonrad Sztyber    from spdk.rpc.client import print_dict, JSONRPCException  # noqa
21*552eaa9cSKonrad Sztyber    import spdk.rpc as rpc  # noqa
22*552eaa9cSKonrad Sztyberexcept ImportError:
23*552eaa9cSKonrad Sztyber    print("SPDK RPC library missing. Please add spdk/python directory to PYTHONPATH:")
24*552eaa9cSKonrad Sztyber    print("'export PYTHONPATH=$PYTHONPATH:spdk/python'")
25*552eaa9cSKonrad Sztyber    exit(1)
26*552eaa9cSKonrad Sztyber
27*552eaa9cSKonrad Sztyber
28bbf8dfb7SEugene KobyakPATTERN_TYPES_STR = ("read", "write", "randread", "randwrite", "rw", "randrw", "verify", "reset",
29bbf8dfb7SEugene Kobyak                     "unmap", "flush", "write_zeroes")
30bbf8dfb7SEugene Kobyak
3129784f35SKrzysztof Karas
3229784f35SKrzysztof Karasdef print_array(a):
3329784f35SKrzysztof Karas    print(" ".join((quote(v) for v in a)))
3429784f35SKrzysztof Karas
3529784f35SKrzysztof Karas
36bbf8dfb7SEugene Kobyakdef perform_tests_func(args):
37bbf8dfb7SEugene Kobyak    """Perform bdevperf tests with command line arguments.
3829784f35SKrzysztof Karas
3929784f35SKrzysztof Karas    Args:
4029784f35SKrzysztof Karas        none
4129784f35SKrzysztof Karas
4229784f35SKrzysztof Karas    Returns:
4329784f35SKrzysztof Karas        On success, 0 is returned. On error, -1 is returned.
4429784f35SKrzysztof Karas    """
45bbf8dfb7SEugene Kobyak    client = args.client
46bbf8dfb7SEugene Kobyak    param_names = ['queue_depth', 'time_in_sec', 'workload_type', 'io_size', 'rw_percentage']
47bbf8dfb7SEugene Kobyak    params = {name: getattr(args, name) for name in param_names if getattr(args, name, None)}
4829784f35SKrzysztof Karas    return client.call('perform_tests', params)
4929784f35SKrzysztof Karas
5029784f35SKrzysztof Karas
5129784f35SKrzysztof Karasif __name__ == "__main__":
5229784f35SKrzysztof Karas    parser = argparse.ArgumentParser(
5329784f35SKrzysztof Karas        description='SPDK RPC command line interface. NOTE: spdk/python is expected in PYTHONPATH')
5429784f35SKrzysztof Karas    parser.add_argument('-s', dest='server_addr',
5529784f35SKrzysztof Karas                        help='RPC domain socket path or IP address', default='/var/tmp/spdk.sock')
5629784f35SKrzysztof Karas    parser.add_argument('-p', dest='port',
5729784f35SKrzysztof Karas                        help='RPC port number (if server_addr is IP address)',
5829784f35SKrzysztof Karas                        default=5260, type=int)
5929784f35SKrzysztof Karas    parser.add_argument('-t', dest='timeout',
6029784f35SKrzysztof Karas                        help='Timeout as a floating point number expressed in seconds waiting for response. Default: 60.0',
6129784f35SKrzysztof Karas                        default=60.0, type=float)
6229784f35SKrzysztof Karas    parser.add_argument('-v', dest='verbose', action='store_const', const="INFO",
6329784f35SKrzysztof Karas                        help='Set verbose mode to INFO', default="ERROR")
6429784f35SKrzysztof Karas    parser.add_argument('--verbose', dest='verbose', choices=['DEBUG', 'INFO', 'ERROR'],
6529784f35SKrzysztof Karas                        help="""Set verbose level. """)
6629784f35SKrzysztof Karas    subparsers = parser.add_subparsers(help='RPC methods')
6729784f35SKrzysztof Karas
6829784f35SKrzysztof Karas    def perform_tests(args):
69bbf8dfb7SEugene Kobyak        print_dict(perform_tests_func(args))
7029784f35SKrzysztof Karas
71bbf8dfb7SEugene Kobyak    perform_tests_help_string = '''
72bbf8dfb7SEugene Kobyak    Perform bdevperf tests
73bbf8dfb7SEugene Kobyak    All parameters are optional.
74bbf8dfb7SEugene Kobyak    If any parameter provided it will overwrite ones from prior run or command line.
75bbf8dfb7SEugene Kobyak    If job config file was used no parameter should be provided.
76bbf8dfb7SEugene Kobyak    '''
77bbf8dfb7SEugene Kobyak    p = subparsers.add_parser('perform_tests', help=perform_tests_help_string)
78bbf8dfb7SEugene Kobyak    p.add_argument('-q', dest="queue_depth", help='io depth', type=int)
79bbf8dfb7SEugene Kobyak    p.add_argument('-o', dest="io_size", help='Size in bytes', type=str)
80bbf8dfb7SEugene Kobyak    p.add_argument('-t', dest="time_in_sec", help='Time in seconds', type=int)
81bbf8dfb7SEugene Kobyak    p.add_argument('-M', dest="rw_percentage", help='rwmixread (100 for reads, 0 for writes)',
82bbf8dfb7SEugene Kobyak                   type=int, choices=range(0, 101), metavar="[0-100]")
83bbf8dfb7SEugene Kobyak    p.add_argument('-w', dest="workload_type", choices=PATTERN_TYPES_STR, type=str.lower,
84bbf8dfb7SEugene Kobyak                   help=f'io pattern type, must be one of {PATTERN_TYPES_STR}',)
8529784f35SKrzysztof Karas    p.set_defaults(func=perform_tests)
8629784f35SKrzysztof Karas
8729784f35SKrzysztof Karas    def call_rpc_func(args):
8829784f35SKrzysztof Karas        try:
8929784f35SKrzysztof Karas            args.func(args)
9029784f35SKrzysztof Karas        except JSONRPCException as ex:
9129784f35SKrzysztof Karas            print(ex.message)
9229784f35SKrzysztof Karas            exit(1)
9329784f35SKrzysztof Karas
9429784f35SKrzysztof Karas    def execute_script(parser, client, fd):
9529784f35SKrzysztof Karas        for rpc_call in map(str.rstrip, fd):
9629784f35SKrzysztof Karas            if not rpc_call.strip():
9729784f35SKrzysztof Karas                continue
9829784f35SKrzysztof Karas            args = parser.parse_args(shlex.split(rpc_call))
9929784f35SKrzysztof Karas            args.client = client
10029784f35SKrzysztof Karas            call_rpc_func(args)
10129784f35SKrzysztof Karas
10229784f35SKrzysztof Karas    args = parser.parse_args()
103db026688SMarcin Spiewak    if args.time_in_sec is not None:
104db026688SMarcin Spiewak        args.timeout = max(float(args.time_in_sec + 5), args.timeout)
10529784f35SKrzysztof Karas    args.client = rpc.client.JSONRPCClient(args.server_addr, args.port, args.timeout, log_level=getattr(logging, args.verbose.upper()))
10629784f35SKrzysztof Karas    if hasattr(args, 'func'):
10729784f35SKrzysztof Karas        call_rpc_func(args)
10829784f35SKrzysztof Karas    elif sys.stdin.isatty():
10929784f35SKrzysztof Karas        # No arguments and no data piped through stdin
11029784f35SKrzysztof Karas        parser.print_help()
11129784f35SKrzysztof Karas        exit(1)
11229784f35SKrzysztof Karas    else:
11329784f35SKrzysztof Karas        execute_script(parser, args.client, sys.stdin)
114