zc2 0.0.28

P2P compute broker with credit-based billing, WAL, and broker mesh support
#!/usr/bin/env python3
"""Benchmark worker via zakuro library."""

import os
import time
from concurrent.futures import ThreadPoolExecutor, as_completed

import zakuro as zk
from zakuro.processors.registry import get_processor

# Configuration
BROKER_URL = "zc://localhost:9001"
NUM_REQUESTS = 100
CONCURRENCY = 10


def simple_task(x: int) -> int:
    """Simple compute task."""
    return x * 2 + 1


def run_benchmark():
    """Run benchmark with concurrent requests."""
    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()

    # Create compute target
    compute = zk.Compute(uri=BROKER_URL, cpus=0.1, memory="100Mi")

    # Get processor
    processor = get_processor(BROKER_URL, compute)
    print(f"DEBUG: Processor type = {type(processor).__name__}")

    # Check broker connectivity
    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')}")
            # Test connection
            if processor.ping():
                print("OK ✓")

                # Get credits
                credits_info = processor.get_credits()
                print(f"User:         {credits_info['user_id']}")
                print(f"Balance:      {credits_info['balance']:.2f} credits")

                # List workers
                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

    # Run benchmark
    print("Starting benchmark...\n")

    successful = 0
    failed = 0
    latencies = []

    start_time = time.time()

    with ThreadPoolExecutor(max_workers=CONCURRENCY) as executor:
        # Submit all tasks
        futures = []
        for i in range(NUM_REQUESTS):
            future = executor.submit(run_single_request, i, compute)
            futures.append(future)

        # Collect results
        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

    # Calculate statistics
    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 results
    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):
    """Run a single request and return latency."""
    start = time.time()
    remote_fn = zk.fn(simple_task).to(compute)
    result = remote_fn(i)
    latency = time.time() - start

    # Verify result
    expected = i * 2 + 1
    if result != expected:
        raise RuntimeError(f"Unexpected result: {result} != {expected}")

    return latency


if __name__ == "__main__":
    run_benchmark()