性能测试用例和结果更新

This commit is contained in:
1iaan
2026-03-30 21:17:25 +08:00
parent 224d813499
commit ea64511f95
17 changed files with 706 additions and 65 deletions

262
scripts/run_fio_matrix.sh Executable file
View File

@@ -0,0 +1,262 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
FIO_CASE_DIR="${ROOT_DIR}/zvfs_fio_test"
RESULTS_ROOT="${ROOT_DIR}/results/fio"
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
RUN_DIR="${RESULTS_ROOT}/${TIMESTAMP}"
FIO_BIN="${FIO_BIN:-$(command -v fio 2>/dev/null || true)}"
PYTHON_BIN="${PYTHON_BIN:-$(command -v python3 2>/dev/null || true)}"
LD_PRELOAD_PATH="${LD_PRELOAD_PATH:-${ROOT_DIR}/src/libzvfs.so}"
ZVFS_LD_PRELOAD_VALUE="${ZVFS_LD_PRELOAD_VALUE:-${LD_PRELOAD_PATH}}"
SYS_PARENT_DIR="/tmp/zvfs_sys_fio"
ZVFS_PARENT_DIR="/zvfs/zvfs_sys_fio"
SYS_TEST_FILE="${SYS_PARENT_DIR}/testfile"
ZVFS_TEST_FILE="${ZVFS_PARENT_DIR}/testfile"
WORKLOADS=(
"prepare_fill"
"randread_4k"
"randwrite_4k"
"randrw_4k"
)
MODES=(
"sys"
"zvfs"
)
require_bin() {
local bin_path="$1"
local name="$2"
if [[ -z "${bin_path}" || ! -x "${bin_path}" ]]; then
echo "未找到 ${name},请先安装或通过环境变量指定路径。" >&2
exit 1
fi
}
ensure_paths() {
mkdir -p "${SYS_PARENT_DIR}"
if [[ ! -d "${ZVFS_PARENT_DIR}" ]]; then
echo "未找到 ZVFS 测试目录:${ZVFS_PARENT_DIR}" >&2
echo "请先准备好对应目录,再执行脚本。" >&2
exit 1
fi
if [[ -z "${ZVFS_LD_PRELOAD_VALUE}" ]]; then
echo "ZVFS_LD_PRELOAD_VALUE 不能为空。" >&2
exit 1
fi
local zvfs_preload_file="${ZVFS_LD_PRELOAD_VALUE%%:*}"
if [[ ! -f "${zvfs_preload_file}" ]]; then
echo "未找到 libzvfs.so${zvfs_preload_file}" >&2
exit 1
fi
}
cleanup_test_file() {
local mode="$1"
if [[ "${mode}" == "zvfs" ]]; then
env LD_PRELOAD="${ZVFS_LD_PRELOAD_VALUE}" rm -f "${ZVFS_TEST_FILE}"
else
rm -f "${SYS_TEST_FILE}"
fi
}
cleanup_all_test_files() {
cleanup_test_file "sys"
cleanup_test_file "zvfs"
}
run_case() {
local mode="$1"
local workload="$2"
local fio_file="${FIO_CASE_DIR}/${mode}/${workload}.fio"
local output_file="${RUN_DIR}/${mode}_${workload}.json"
if [[ ! -f "${fio_file}" ]]; then
echo "未找到 fio 配置:${fio_file}" >&2
exit 1
fi
echo "[run] mode=${mode} workload=${workload}"
if [[ "${workload}" == "prepare_fill" ]]; then
cleanup_test_file "${mode}"
fi
if [[ "${mode}" == "zvfs" ]]; then
env LD_PRELOAD="${ZVFS_LD_PRELOAD_VALUE}" \
"${FIO_BIN}" --output-format=json --output="${output_file}" "${fio_file}"
else
"${FIO_BIN}" --output-format=json --output="${output_file}" "${fio_file}"
fi
}
write_summary() {
local summary_file="${RUN_DIR}/summary.md"
local parser_script
parser_script="$(cat <<'PY'
import json
import os
import sys
run_dir = sys.argv[1]
modes = ["sys", "zvfs"]
workloads = ["prepare_fill", "randread_4k", "randwrite_4k", "randrw_4k"]
def load_job(path):
with open(path, "r", encoding="utf-8") as f:
content = f.read()
start = content.find("{")
if start == -1:
raise RuntimeError(f"fio output is not JSON: {path}")
data = json.loads(content[start:])
jobs = data.get("jobs", [])
if not jobs:
raise RuntimeError(f"fio output has no jobs: {path}")
return data, jobs[0]
def mib_per_sec(io_part):
value = io_part.get("bw_bytes", 0)
if not value:
return "-"
return f"{value / 1024 / 1024:.2f}"
def iops(io_part):
value = io_part.get("iops", 0)
if not value:
return "-"
return f"{value:.2f}"
def lat_us(io_part):
clat_ns = io_part.get("clat_ns", {})
value = clat_ns.get("mean", 0)
if not value:
return "-"
return f"{value / 1000:.2f}"
def disk_util(data):
parts = []
for item in data.get("disk_util", []):
name = item.get("name")
util = item.get("util")
if not name or util is None:
continue
parts.append(f"{name}={util:.2f}%")
return ", ".join(parts) if parts else "-"
lines = [
"# FIO Summary",
"",
f"run_dir: `{run_dir}`",
"",
"| mode | workload | bw(MiB/s) | iops | avg_lat(us) | read_iops | write_iops | read_avg_lat(us) | write_avg_lat(us) | disk_util |",
"| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |",
]
for mode in modes:
for workload in workloads:
path = os.path.join(run_dir, f"{mode}_{workload}.json")
data, job = load_job(path)
read_part = job.get("read", {})
write_part = job.get("write", {})
util_col = disk_util(data)
if workload == "prepare_fill":
row = [
mode,
workload,
mib_per_sec(write_part),
"-",
"-",
"-",
"-",
"-",
"-",
util_col,
]
elif workload == "randread_4k":
row = [
mode,
workload,
mib_per_sec(read_part),
iops(read_part),
lat_us(read_part),
"-",
"-",
"-",
"-",
util_col,
]
elif workload == "randwrite_4k":
row = [
mode,
workload,
mib_per_sec(write_part),
iops(write_part),
lat_us(write_part),
"-",
"-",
"-",
"-",
util_col,
]
else:
row = [
mode,
workload,
"-",
"-",
"-",
iops(read_part),
iops(write_part),
lat_us(read_part),
lat_us(write_part),
util_col,
]
lines.append("| " + " | ".join(row) + " |")
print("\n".join(lines))
PY
)"
"${PYTHON_BIN}" -c "${parser_script}" "${RUN_DIR}" > "${summary_file}"
echo
echo "[summary] ${summary_file}"
sed -n '1,200p' "${summary_file}"
}
main() {
require_bin "${FIO_BIN}" "fio"
require_bin "${PYTHON_BIN}" "python3"
ensure_paths
mkdir -p "${RUN_DIR}"
echo "结果目录:${RUN_DIR}"
echo "fio 配置目录:${FIO_CASE_DIR}"
echo "LD_PRELOAD${ZVFS_LD_PRELOAD_VALUE}"
echo
cleanup_all_test_files
for mode in "${MODES[@]}"; do
for workload in "${WORKLOADS[@]}"; do
run_case "${mode}" "${workload}"
done
done
write_summary
cleanup_all_test_files
}
main "$@"