From a70d47bef0857d9f507c3c3b6dcafc1387aed23a Mon Sep 17 00:00:00 2001 From: Karol Latecki Date: Wed, 25 Mar 2020 14:49:18 +0100 Subject: [PATCH] test/vhost: remove run_fio.py script run_fio.py was initially added (as the name suggests) to run fio workloads on VM guests in client-server mode during vhost tests. Over time some of it's functionality was moved to test/vhost/common.sh, so at the moment this script just creates a command string and starts it. Using separate Python script is just an overkill. run_fio.py also contained an option to measure VMEXITS on the guest side, which is never run in tests. If needed we can re-add it in other commits. Change-Id: I87a4c824dc09220bb6ce709355ee2d65e0ce3540 Signed-off-by: Karol Latecki Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/1460 Reviewed-by: Darek Stojaczyk Reviewed-by: Tomasz Zawadzki Reviewed-by: Shuhei Matsumoto Tested-by: SPDK CI Jenkins --- test/vhost/common.sh | 25 ++++-- test/vhost/common/run_fio.py | 168 ----------------------------------- 2 files changed, 18 insertions(+), 175 deletions(-) delete mode 100755 test/vhost/common/run_fio.py diff --git a/test/vhost/common.sh b/test/vhost/common.sh index 5b0ff4989..b18c1f7e9 100644 --- a/test/vhost/common.sh +++ b/test/vhost/common.sh @@ -1037,9 +1037,10 @@ function run_fio() local fio_bin="" local vms=() local out="" - local fio_disks="" local vm local run_server_mode=true + local fio_start_cmd + local fio_output_format="normal" for arg in "$@"; do case "$arg" in @@ -1051,7 +1052,8 @@ function run_fio() mkdir -p $out ;; --local) run_server_mode=false ;; - --json) json="--json" ;; + --json) fio_output_format="json" ;; + --hide-results) hide_results=true ;; *) error "Invalid argument '$arg'" return 1 @@ -1069,17 +1071,24 @@ function run_fio() return 1 fi + fio_start_cmd="$fio_bin --eta=never " + local job_fname job_fname=$(basename "$job_file") + fio_start_cmd+=" --output=$out/$job_fname --output-format=$fio_output_format " + # prepare job file for each VM for vm in "${vms[@]}"; do local vm_num=${vm%%:*} local vmdisks=${vm#*:} sed "s@filename=@filename=$vmdisks@" $job_file | vm_exec $vm_num "cat > /root/$job_fname" - fio_disks+="127.0.0.1:$(vm_fio_socket $vm_num):$vmdisks," - vm_exec $vm_num cat /root/$job_fname + + if $run_server_mode; then + fio_start_cmd+="--client=127.0.0.1,$(vm_fio_socket $vm_num) --remote-config /root/$job_fname" + fi + if ! $run_server_mode; then if [[ -n "$fio_bin" ]]; then vm_exec $vm_num 'cat > /root/fio; chmod +x /root/fio' < $fio_bin @@ -1096,9 +1105,11 @@ function run_fio() return 0 fi - $rootdir/test/vhost/common/run_fio.py --job-file=/root/$job_fname \ - $([[ -n "$fio_bin" ]] && echo "--fio-bin=$fio_bin") \ - --out=$out $json ${fio_disks%,} + $fio_start_cmd + + if [[ ! $hide_results ]]; then + cat $out/$job_fname + fi } # Shutdown or kill any running VM and SPDK APP. diff --git a/test/vhost/common/run_fio.py b/test/vhost/common/run_fio.py deleted file mode 100755 index 4624a2f28..000000000 --- a/test/vhost/common/run_fio.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -import getopt -import subprocess -import signal -import re - -fio_bin = "fio" - - -def show_help(): - print("""Usage: {} run_fio.py [options] [args] - Description: - Run FIO job file 'fio.job' on remote machines. - NOTE: The job file must exist on remote machines on '/root/' directory. - Args: - [VMs] (ex. vm1_IP:vm1_port:vm1_disk1:vm_disk2,vm2_IP:vm2_port:vm2_disk1,etc...) - Options: - -h, --help Show this message. - -j, --job-file Paths to file with FIO job configuration on remote host. - -f, --fio-bin Location of FIO binary on local host (Default "fio") - -o, --out Directory used to save generated job files and - files with test results - -J, --json Use JSON format for output - -p, --perf-vmex Enable aggregating statistic for VMEXITS for VMs - """.format(os.path.split(sys.executable)[-1])) - - -def exec_cmd(cmd, blocking): - # Print result to STDOUT for now, we don't have json support yet. - p = subprocess.Popen(cmd.split(" "), stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, stdin=subprocess.PIPE) - if blocking is True: - out, _ = p.communicate() - return p.returncode, out.decode() - return p - - -def save_file(path, mode, contents): - with open(path, mode) as fh: - fh.write(contents) - fh.close() - - -def run_fio(vms, fio_cfg_fname, out_path, perf_vmex=False, json=False): - global fio_bin - job_name = os.path.splitext(os.path.basename(fio_cfg_fname))[0] - - # Build command for FIO - fio_cmd = " ".join([fio_bin, "--eta=never"]) - if json: - fio_cmd = " ".join([fio_bin, "--output-format=json"]) - for vm in vms: - # vm[0] = IP address, vm[1] = Port number - fio_cmd = " ".join([fio_cmd, - "--client={vm_ip},{vm_port}".format(vm_ip=vm[0], vm_port=vm[1]), - "--remote-config {cfg}".format(cfg=fio_cfg_fname)]) - print(fio_cmd) - - if perf_vmex: - perf_dir = os.path.join(out_path, "perf_stats") - try: - os.mkdir(perf_dir) - except OSError: - pass - - # Start gathering perf statistics for host and VM guests - perf_rec_file = os.path.join(perf_dir, "perf.data.kvm") - perf_run_cmd = "perf kvm --host --guest " + \ - "-o {0} stat record -a".format(perf_rec_file) - print(perf_run_cmd) - perf_p = exec_cmd(perf_run_cmd, blocking=False) - - # Run FIO test on VMs - rc, out = exec_cmd(fio_cmd, blocking=True) - - # if for some reason output contains lines with "eta" - remove them - out = re.sub(r'.+\[eta\s+\d{2}m:\d{2}s\]', '', out) - - print(out) - - if rc != 0: - print("ERROR! While executing FIO jobs - RC: {rc}".format(rc=rc, out=out)) - sys.exit(rc) - else: - save_file(os.path.join(out_path, ".".join([job_name, "log"])), "w", out) - - if perf_vmex: - # Stop gathering perf statistics and prepare some result files - perf_p.send_signal(signal.SIGINT) - perf_p.wait() - - perf_stat_cmd = "perf kvm --host -i {perf_rec} stat report --event vmexit"\ - .format(perf_rec=perf_rec_file) - - rc, out = exec_cmd(" ".join([perf_stat_cmd, "--event vmexit"]), - blocking=True) - print("VMexit host stats:") - print("{perf_out}".format(perf_out=out)) - save_file(os.path.join(perf_dir, "vmexit_stats_" + job_name), - "w", "{perf_out}".format(perf_out=out)) - try: - os.remove(perf_rec_file) - except OSError: - pass - - -def main(): - global fio_bin - - abspath = os.path.abspath(__file__) - dname = os.path.dirname(abspath) - - vms = [] - fio_cfg = None - out_dir = None - perf_vmex = False - json = False - - try: - opts, args = getopt.getopt(sys.argv[1:], "hJj:f:o:p", - ["help", "job-file=", "fio-bin=", - "out=", "perf-vmex", "json"]) - except getopt.GetoptError: - show_help() - sys.exit(1) - - if len(args) < 1: - show_help() - sys.exit(1) - - for o, a in opts: - if o in ("-j", "--job-file"): - fio_cfg = a - elif o in ("-h", "--help"): - show_help() - sys.exit(1) - elif o in ("-p", "--perf-vmex"): - perf_vmex = True - elif o in ("-o", "--out"): - out_dir = a - elif o in ("-f", "--fio-bin"): - fio_bin = a - elif o in ("-J", "--json"): - json = True - - if fio_cfg is None: - print("ERROR! No FIO job provided!") - sys.exit(1) - - if out_dir is None or not os.path.exists(out_dir): - print("ERROR! Folder {out_dir} does not exist ".format(out_dir=out_dir)) - sys.exit(1) - - # Get IP, port and fio 'filename' information from positional args - for arg in args[0].split(","): - _ = arg.split(":") - ip, port, filenames = _[0], _[1], ":".join(_[2:]) - vms.append((ip, port, filenames)) - - print("Running job file: {0}".format(fio_cfg)) - run_fio(vms, fio_cfg, out_dir, perf_vmex, json) - - -if __name__ == "__main__": - sys.exit(main())