import os
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
import zakuro as zk
from zakuro.processors.registry import get_processor
BROKER_URL = "zc://localhost:9001"
NUM_REQUESTS = 100
CONCURRENCY = 10
def simple_task(x: int) -> int:
return x * 2 + 1
def run_benchmark():
print(f"╔═══════════════════════════════════════════╗")
print(f"║ Zakuro Worker Benchmark ║")
print(f"╚═══════════════════════════════════════════╝\n")
print(f"Target: {BROKER_URL}")
print(f"Concurrency: {CONCURRENCY}")
print(f"Requests: {NUM_REQUESTS}")
print()
compute = zk.Compute(uri=BROKER_URL, cpus=0.1, memory="100Mi")
processor = get_processor(BROKER_URL, compute)
print(f"DEBUG: Processor type = {type(processor).__name__}")
print("Connecting to broker... ", end="", flush=True)
try:
with processor:
print(f"DEBUG: Processor type after connect = {type(processor).__name__}")
print(f"DEBUG: API Key = {getattr(processor, '_api_key', 'NOT SET')}")
print(f"DEBUG: User ID = {getattr(processor, '_user_id', 'NOT SET')}")
if processor.ping():
print("OK ✓")
credits_info = processor.get_credits()
print(f"User: {credits_info['user_id']}")
print(f"Balance: {credits_info['balance']:.2f} credits")
workers = processor.list_workers()
print(f"Workers: {len(workers)} available")
for w in workers:
print(f" - {w['name']} ({w['status']})")
print()
else:
print("FAILED ✗")
return
except Exception as e:
print(f"FAILED ✗\n Error: {e}")
return
print("Starting benchmark...\n")
successful = 0
failed = 0
latencies = []
start_time = time.time()
with ThreadPoolExecutor(max_workers=CONCURRENCY) as executor:
futures = []
for i in range(NUM_REQUESTS):
future = executor.submit(run_single_request, i, compute)
futures.append(future)
for future in as_completed(futures):
try:
latency = future.result()
successful += 1
latencies.append(latency)
except Exception as e:
failed += 1
print(f" Request failed: {e}")
duration = time.time() - start_time
if latencies:
latencies.sort()
min_lat = min(latencies) * 1000
max_lat = max(latencies) * 1000
avg_lat = sum(latencies) / len(latencies) * 1000
p50_lat = latencies[len(latencies) // 2] * 1000
p95_lat = latencies[int(len(latencies) * 0.95)] * 1000
p99_lat = latencies[int(len(latencies) * 0.99)] * 1000
else:
min_lat = max_lat = avg_lat = p50_lat = p95_lat = p99_lat = 0
throughput = NUM_REQUESTS / duration
print("\n" + "="*60)
print("◆ Benchmark Results")
print("="*60)
print()
print("Summary")
print("-"*40)
print(f" Total Requests: {NUM_REQUESTS}")
print(f" Successful: {successful} ({successful/NUM_REQUESTS*100:.1f}%)")
print(f" Failed: {failed} ({failed/NUM_REQUESTS*100:.1f}%)")
print(f" Duration: {duration:.2f}s")
print(f" Throughput: {throughput:.2f} req/s")
print()
print("Latency (ms)")
print("-"*40)
print(f" Min: {min_lat:.2f}")
print(f" Avg: {avg_lat:.2f}")
print(f" Max: {max_lat:.2f}")
print(f" p50: {p50_lat:.2f}")
print(f" p95: {p95_lat:.2f}")
print(f" p99: {p99_lat:.2f}")
print()
def run_single_request(i: int, compute):
start = time.time()
remote_fn = zk.fn(simple_task).to(compute)
result = remote_fn(i)
latency = time.time() - start
expected = i * 2 + 1
if result != expected:
raise RuntimeError(f"Unexpected result: {result} != {expected}")
return latency
if __name__ == "__main__":
run_benchmark()