Commit a70d47be authored by Karol Latecki's avatar Karol Latecki Committed by Tomasz Zawadzki
Browse files

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: default avatarKarol Latecki <karol.latecki@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/1460


Reviewed-by: default avatarDarek Stojaczyk <dariusz.stojaczyk@intel.com>
Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent d848418d
Loading
Loading
Loading
Loading
+18 −7
Original line number Diff line number Diff line
@@ -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.

test/vhost/common/run_fio.py

deleted100755 → 0
+0 −168
Original line number Diff line number Diff line
#!/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())