From 7478d050e3f96b21258b19c4b7764aab5978ff9b Mon Sep 17 00:00:00 2001 From: Theo Tappe Date: Thu, 11 Jun 2026 15:41:37 +0200 Subject: [PATCH] Improved testing capabilities and fixed missing finished status in multithreading --- src/client/client.c | 8 +- test.py | 272 ++++++++++++++++++++++++++------------------ 2 files changed, 167 insertions(+), 113 deletions(-) diff --git a/src/client/client.c b/src/client/client.c index 367f78c..5c48c2e 100644 --- a/src/client/client.c +++ b/src/client/client.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -7,7 +8,6 @@ #include "config.h" #include "log.h" #include "multiprocessing.h" -#include "pipeline.h" #include "queue.h" #include "scanner.h" #include "socket.h" @@ -87,11 +87,15 @@ int send_chunks_multithreaded(void *pipeline_context) { &context->condition_not_empty_loader, &context->condition_not_full_loader, &context->loader_done); if (current_chunk == NULL) { + send_status(client->file_descriptor, FINISHED); client_disconnect(client); client_delete(client); return thrd_success; } - send_chunk(client, current_chunk, use_compression); + if (send_chunk(client, current_chunk, use_compression) != 0) { + perror("Something unexpected happend while sending the chunk"); + exit(EXIT_FAILURE); + } chunk_destroy(current_chunk); } } diff --git a/test.py b/test.py index ad0297a..681af42 100644 --- a/test.py +++ b/test.py @@ -21,8 +21,6 @@ NET_LIMIT_CMD = f"sudo tc qdisc add dev {NETWORK_INTERFACE} root netem rate {NET NET_RESET_CMD = f"sudo tc qdisc del dev {NETWORK_INTERFACE} root".split() # --- Build the client command prefix with throttling --- -# This uses systemd-run to wrap the original client command with I/O limits. -# The entire command must be run with sudo. CLIENT_CMD_PREFIX = [ "sudo", "systemd-run", @@ -48,118 +46,170 @@ TEST_CASES = [ }, ] -results = [] -print("🚀 Starting benchmark...") -print(f"Limiting Disk I/O: Reads <= {READ_BPS_MAX}, Writes <= {WRITE_BPS_MAX}") -print("Limiting Network: Simulating low bandwidth and high latency") +def run_suite(env_name, apply_limits): + results = [] + print(f"\n{'=' * 60}") + print(f"🚀 Starting Suite: {env_name}") + print(f"{'=' * 60}") -try: - # # SETUP: Apply network limit - print("Applying network limits...") - subprocess.run(NET_LIMIT_CMD, check=True) + if apply_limits: + print( + f"Applying Disk I/O Limits: Reads <= {READ_BPS_MAX}, Writes <= {WRITE_BPS_MAX}" + ) + print(f"Applying Network Limits: {NET_LIMIT}, {NET_DELAY} delay") + client_prefix = CLIENT_CMD_PREFIX + else: + print("Running Baseline (No limits applied)") + client_prefix = [] # Run normally without systemd-run/limits - for case in TEST_CASES: - name = case["name"] - flags = case["flags"] - - print(f"\n--- Running: {name} ---") - - server_process = None - try: - # 1. Start the server - print(" Starting server...") - server_process = subprocess.Popen( - SERVER_CMD, stdout=subprocess.DEVNULL, stderr=None - ) - time.sleep(5) # Allow server to bind to port - - # 2. Build and run the client - client_cmd = CLIENT_CMD_PREFIX + base_client_cmd + flags - print(f" Running client: {' '.join(client_cmd)}") - - start_time = time.monotonic() - client_result = subprocess.run(client_cmd, text=True, capture_output=True) - end_time = time.monotonic() - - duration = end_time - start_time - - if client_result.returncode == 0: - results.append( - { - "name": name, - "status": "Success", - "time": f"{duration:.4f}s", - "error": "", - } - ) - else: - print(f" ⚠️ Failed (code: {client_result.returncode})") - err_msg = ( - client_result.stderr.strip().split("\n")[0] - if client_result.stderr - else ( - client_result.stdout.strip().split("\n")[0] - if client_result.stdout - else "No output" - ) - ) - results.append( - { - "name": name, - "status": "Failed", - "time": "N/A", - "error": f"Exit code {client_result.returncode}: {err_msg[:40]}", - } - ) - - except subprocess.TimeoutExpired: - print(" ⚠️ Timeout (exceeded 15s)") - results.append( - { - "name": name, - "status": "Timeout", - "time": "N/A", - "error": "Exceeded 15 seconds", - } - ) - except Exception as e: - print(f" ❌ Error: {e}") - results.append( - {"name": name, "status": "Error", "time": "N/A", "error": str(e)} - ) - finally: - # Clean up the server for this test case - if server_process: - print(" Stopping server...") - try: - server_process.terminate() - server_process.wait(timeout=5) - except subprocess.TimeoutExpired: - server_process.kill() - server_process.wait() - -except subprocess.CalledProcessError as e: - print(f"❌ Error running system limit command: {' '.join(e.cmd)}") - print("Are you running this script with 'sudo'?") - -finally: - # TEARDOWN: Remove network limits - print("\nCleaning up...") try: - print("Removing network limit...") - subprocess.run(NET_RESET_CMD, check=True, capture_output=True) - except Exception as e: - print(f"⚠️ Could not reset network settings: {e}") - print("Cleanup complete.") + # SETUP: Apply or ensure clean network limits + if apply_limits: + subprocess.run(NET_LIMIT_CMD, check=True) + else: + # Silently attempt to clear any leftover rules just to ensure a clean baseline + subprocess.run(NET_RESET_CMD, capture_output=True) -# Print comparison table -print("\n" + "=" * 80) -print(f"{'fastSync BENCHMARK RESULTS':^80}") -print("=" * 80) -print(f"{'Configuration':<45} | {'Status':<10} | {'Time':<10} | {'Details/Error':<20}") -print("-" * 80) -for res in results: + for case in TEST_CASES: + name = case["name"] + flags = case["flags"] + + print(f"\n--- Running: {name} ---") + + server_process = None + try: + # 1. Start the server + print(" Starting server...") + server_process = subprocess.Popen( + SERVER_CMD, stdout=subprocess.DEVNULL, stderr=None + ) + time.sleep(0.5) # Allow server to bind to port + + # 2. Build and run the client + client_cmd = client_prefix + base_client_cmd + flags + print(f" Running client: {' '.join(client_cmd)}") + + start_time = time.monotonic() + client_result = subprocess.run( + client_cmd, text=True, capture_output=True + ) + end_time = time.monotonic() + + duration = end_time - start_time + + if client_result.returncode == 0: + results.append( + { + "environment": env_name, + "name": name, + "status": "Success", + "time": f"{duration:.4f}s", + "error": "", + } + ) + else: + print(f" ⚠️ Failed (code: {client_result.returncode})") + err_msg = ( + client_result.stderr.strip().split("\n")[0] + if client_result.stderr + else ( + client_result.stdout.strip().split("\n")[0] + if client_result.stdout + else "No output" + ) + ) + results.append( + { + "environment": env_name, + "name": name, + "status": "Failed", + "time": "N/A", + "error": f"Exit code {client_result.returncode}: {err_msg[:40]}", + } + ) + + except subprocess.TimeoutExpired: + print(" ⚠️ Timeout (exceeded 15s)") + results.append( + { + "environment": env_name, + "name": name, + "status": "Timeout", + "time": "N/A", + "error": "Exceeded 15 seconds", + } + ) + except Exception as e: + print(f" ❌ Error: {e}") + results.append( + { + "environment": env_name, + "name": name, + "status": "Error", + "time": "N/A", + "error": str(e), + } + ) + finally: + # Clean up the server for this test case + if server_process: + print(" Stopping server...") + try: + server_process.terminate() + server_process.wait(timeout=5) + except subprocess.TimeoutExpired: + server_process.kill() + server_process.wait() + + except subprocess.CalledProcessError as e: + print(f"❌ Error running system limit command: {' '.join(e.cmd)}") + print("Are you running this script with 'sudo' privileges?") + + finally: + # TEARDOWN: Remove network limits if they were applied + if apply_limits: + print("\nCleaning up limits for this suite...") + try: + subprocess.run(NET_RESET_CMD, check=True, capture_output=True) + print("Network limits removed.") + except Exception as e: + print(f"⚠️ Could not reset network settings: {e}") + + return results + + +# --- Main Execution --- +all_results = [] + +# 1. Run Baseline (No Limits) +all_results.extend(run_suite("Unlimited", apply_limits=False)) + +# # 2. Run Throttled (With Limits) +all_results.extend(run_suite("Throttled", apply_limits=True)) + +# --- Print Comparison Table --- +print("\n" + "=" * 105) +print(f"{'fastSync BENCHMARK RESULTS (COMPARISON)':^105}") +print("=" * 105) +print( + f"{'Configuration':<45} | {'Environment':<12} | {'Status':<10} | {'Time':<10} | {'Details/Error':<20}" +) +print("-" * 105) + +# Sort results by test case name first, then environment to easily compare +# This groups the baseline and throttled results for the same test next to each other +# sorted_results = sorted( +# all_results, +# key=lambda x: ( +# TEST_CASES.index( +# next(item for item in TEST_CASES if item["name"] == x["name"]) +# ), +# x["environment"], +# ), +# ) + +for res in all_results: status_symbol = ( "✅" if res["status"] == "Success" @@ -167,6 +217,6 @@ for res in results: ) status_str = f"{status_symbol} {res['status']}" print( - f"{res['name']:<45} | {status_str:<10} | {res['time']:<10} | {res['error']:<20}" + f"{res['name']:<45} | {res['environment']:<12} | {status_str:<10} | {res['time']:<10} | {res['error']:<20}" ) -print("=" * 80) +print("=" * 105)