bench: add speedup metrics vs rsync and theoretical uncompressed throughput
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import filecmp
|
import filecmp
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@@ -129,6 +130,7 @@ def generate_test_files(source_dir):
|
|||||||
|
|
||||||
total_mb = written / (1024 * 1024)
|
total_mb = written / (1024 * 1024)
|
||||||
print(f" Generated {total_mb:.1f} MB of test data in {source_dir}")
|
print(f" Generated {total_mb:.1f} MB of test data in {source_dir}")
|
||||||
|
return written
|
||||||
|
|
||||||
|
|
||||||
def verify_transfer(source_dir, received_dir):
|
def verify_transfer(source_dir, received_dir):
|
||||||
@@ -414,6 +416,31 @@ read only = yes
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def parse_rate_to_bytes_per_sec(rate_str):
|
||||||
|
m = re.match(r'(\d+)\s*(mbit|gbit|kbit|bit)', rate_str)
|
||||||
|
if not m:
|
||||||
|
return None
|
||||||
|
val = int(m.group(1))
|
||||||
|
unit = m.group(2)
|
||||||
|
bits_per_sec = {
|
||||||
|
'bit': val,
|
||||||
|
'kbit': val * 1000,
|
||||||
|
'mbit': val * 1_000_000,
|
||||||
|
'gbit': val * 1_000_000_000,
|
||||||
|
}.get(unit)
|
||||||
|
return bits_per_sec / 8 if bits_per_sec is not None else None
|
||||||
|
|
||||||
|
|
||||||
|
def format_throughput(bps):
|
||||||
|
if bps >= 1_000_000_000:
|
||||||
|
return f"{bps/1_000_000_000:.1f} GB/s"
|
||||||
|
if bps >= 1_000_000:
|
||||||
|
return f"{bps/1_000_000:.1f} MB/s"
|
||||||
|
if bps >= 1_000:
|
||||||
|
return f"{bps/1_000:.1f} KB/s"
|
||||||
|
return f"{bps:.0f} B/s"
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="FastSync integration test / benchmark")
|
parser = argparse.ArgumentParser(description="FastSync integration test / benchmark")
|
||||||
parser.add_argument("--source-dir", default=DEFAULT_SOURCE_DIR,
|
parser.add_argument("--source-dir", default=DEFAULT_SOURCE_DIR,
|
||||||
@@ -434,7 +461,7 @@ def main():
|
|||||||
print("Build failed")
|
print("Build failed")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
generate_test_files(args.source_dir)
|
total_bytes = generate_test_files(args.source_dir)
|
||||||
if os.path.exists(args.dest_dir):
|
if os.path.exists(args.dest_dir):
|
||||||
shutil.rmtree(args.dest_dir)
|
shutil.rmtree(args.dest_dir)
|
||||||
os.makedirs(args.dest_dir, exist_ok=True)
|
os.makedirs(args.dest_dir, exist_ok=True)
|
||||||
@@ -465,6 +492,57 @@ def main():
|
|||||||
f"{res['name']:<45} | {res['suite']:<12} | {res['status']:<8} | {res['time']:<10} | {res['error']}"
|
f"{res['name']:<45} | {res['suite']:<12} | {res['status']:<8} | {res['time']:<10} | {res['error']}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# --- Additional metrics per profile ---
|
||||||
|
profiles_results = {}
|
||||||
|
for res in all_results:
|
||||||
|
profiles_results.setdefault(res["suite"], []).append(res)
|
||||||
|
|
||||||
|
for profile_name, results in profiles_results.items():
|
||||||
|
params = NETWORK_PROFILES.get(profile_name)
|
||||||
|
if not params or "rate" not in params:
|
||||||
|
continue
|
||||||
|
|
||||||
|
client_times = []
|
||||||
|
rsync_times = {}
|
||||||
|
for r in results:
|
||||||
|
if r["status"] != "Success" or r["time"] == "N/A":
|
||||||
|
continue
|
||||||
|
t = float(r["time"].rstrip("s"))
|
||||||
|
if r["name"].startswith("rsync"):
|
||||||
|
rsync_times[r["name"]] = t
|
||||||
|
else:
|
||||||
|
client_times.append((t, r["name"]))
|
||||||
|
|
||||||
|
if not client_times or len(rsync_times) < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
best_time, best_name = min(client_times, key=lambda x: x[0])
|
||||||
|
|
||||||
|
rate_Bps = parse_rate_to_bytes_per_sec(params["rate"])
|
||||||
|
theoretical_max_time = None
|
||||||
|
speedup_vs_theoretical = None
|
||||||
|
if rate_Bps is not None:
|
||||||
|
theoretical_max_time = total_bytes / rate_Bps
|
||||||
|
speedup_vs_theoretical = theoretical_max_time / best_time
|
||||||
|
|
||||||
|
print(f"\n {'─' * 90}")
|
||||||
|
print(f" Profile: {profile_name}")
|
||||||
|
print(f" {'─' * 90}")
|
||||||
|
print(f" Total data size: {total_bytes / (1024*1024):.1f} MB")
|
||||||
|
print(f" Network rate: {params['rate']} ({format_throughput(rate_Bps)})" if rate_Bps else "")
|
||||||
|
print(f" Best client configuration: {best_name}")
|
||||||
|
print(f" Best client time: {best_time:.4f}s")
|
||||||
|
if theoretical_max_time is not None:
|
||||||
|
print(f" Theoretical max (uncompressed): {theoretical_max_time:.4f}s")
|
||||||
|
print(f" Speedup vs theoretical max: {speedup_vs_theoretical:.2f}x")
|
||||||
|
|
||||||
|
rsync_archive = rsync_times.get("rsync (archive)")
|
||||||
|
rsync_compress = rsync_times.get("rsync (archive + compress)")
|
||||||
|
if rsync_archive:
|
||||||
|
print(f" Speedup vs rsync (archive): {rsync_archive / best_time:.2f}x")
|
||||||
|
if rsync_compress:
|
||||||
|
print(f" Speedup vs rsync (compress): {rsync_compress / best_time:.2f}x")
|
||||||
|
|
||||||
failed = [r for r in all_results if r["status"] != "Success"]
|
failed = [r for r in all_results if r["status"] != "Success"]
|
||||||
if failed:
|
if failed:
|
||||||
print(f"\n {len(failed)} test(s) FAILED")
|
print(f"\n {len(failed)} test(s) FAILED")
|
||||||
|
|||||||
Reference in New Issue
Block a user