#!/usr/bin/env python3
"""
Test for GPU contention between Soprano and RVC
Measures if running both models simultaneously slows them down
"""
import time
import threading
import requests
from statistics import mean

def test_soprano_solo(num_runs=3):
    """Test Soprano alone"""
    print("=" * 60)
    print("TEST 1: Soprano Solo (baseline)")
    print("=" * 60)
    
    text = "This is a comprehensive test of Soprano TTS performance to measure the true speed without any interference."
    times = []
    
    for i in range(num_runs):
        print(f"\nRun {i+1}/{num_runs}...")
        start = time.time()
        response = requests.get(
            f"http://localhost:8765/api/test_soprano_stream",
            params={"text": text},
            stream=True
        )
        # Consume the stream
        for chunk in response.iter_content(chunk_size=8192):
            pass
        elapsed = time.time() - start
        times.append(elapsed)
        print(f"  Elapsed: {elapsed:.2f}s")
        time.sleep(1)
    
    avg = mean(times)
    print(f"\n✓ Soprano Solo Average: {avg:.2f}s")
    return avg

def test_rvc_solo(num_runs=3):
    """Test RVC alone"""
    print("\n" + "=" * 60)
    print("TEST 2: RVC Solo (baseline)")
    print("=" * 60)
    
    times = []
    
    for i in range(num_runs):
        print(f"\nRun {i+1}/{num_runs}...")
        start = time.time()
        response = requests.get(
            f"http://localhost:8765/api/test_rvc_only",
            params={"input_file": "/tmp/soprano_test_3.wav"},
            stream=True
        )
        # Consume the stream
        for chunk in response.iter_content(chunk_size=8192):
            pass
        elapsed = time.time() - start
        times.append(elapsed)
        print(f"  Elapsed: {elapsed:.2f}s")
        time.sleep(1)
    
    avg = mean(times)
    print(f"\n✓ RVC Solo Average: {avg:.2f}s")
    return avg

def concurrent_soprano():
    """Run Soprano in thread"""
    text = "This is a comprehensive test of Soprano TTS performance to measure the true speed without any interference."
    start = time.time()
    response = requests.get(
        f"http://localhost:8765/api/test_soprano_stream",
        params={"text": text},
        stream=True
    )
    for chunk in response.iter_content(chunk_size=8192):
        pass
    return time.time() - start

def concurrent_rvc():
    """Run RVC in thread"""
    start = time.time()
    response = requests.get(
        f"http://localhost:8765/api/test_rvc_only",
        params={"input_file": "/tmp/soprano_test_3.wav"},
        stream=True
    )
    for chunk in response.iter_content(chunk_size=8192):
        pass
    return time.time() - start

def test_concurrent(num_runs=3):
    """Test Soprano and RVC running simultaneously"""
    print("\n" + "=" * 60)
    print("TEST 3: Soprano + RVC CONCURRENT (contention test)")
    print("=" * 60)
    
    soprano_times = []
    rvc_times = []
    
    for i in range(num_runs):
        print(f"\nRun {i+1}/{num_runs}...")
        print("  Starting both simultaneously...")
        
        # Create threads
        soprano_result = [None]
        rvc_result = [None]
        
        def run_soprano():
            soprano_result[0] = concurrent_soprano()
        
        def run_rvc():
            rvc_result[0] = concurrent_rvc()
        
        soprano_thread = threading.Thread(target=run_soprano)
        rvc_thread = threading.Thread(target=run_rvc)
        
        # Start both at the same time
        start = time.time()
        soprano_thread.start()
        time.sleep(0.1)  # Slight stagger to ensure both are running
        rvc_thread.start()
        
        # Wait for both to complete
        soprano_thread.join()
        rvc_thread.join()
        total_elapsed = time.time() - start
        
        soprano_time = soprano_result[0]
        rvc_time = rvc_result[0]
        
        soprano_times.append(soprano_time)
        rvc_times.append(rvc_time)
        
        print(f"  Soprano: {soprano_time:.2f}s")
        print(f"  RVC: {rvc_time:.2f}s")
        print(f"  Total: {total_elapsed:.2f}s")
        time.sleep(2)
    
    avg_soprano = mean(soprano_times)
    avg_rvc = mean(rvc_times)
    print(f"\n✓ Concurrent Soprano Average: {avg_soprano:.2f}s")
    print(f"✓ Concurrent RVC Average: {avg_rvc:.2f}s")
    return avg_soprano, avg_rvc

def main():
    print("\n" + "=" * 60)
    print("GPU CONTENTION TEST")
    print("=" * 60)
    print("\nThis test will:")
    print("1. Measure Soprano speed alone")
    print("2. Measure RVC speed alone")
    print("3. Measure both running simultaneously")
    print("4. Compare to detect GPU contention")
    print("\nStarting in 3 seconds...")
    time.sleep(3)
    
    # Run tests
    soprano_solo = test_soprano_solo(num_runs=3)
    rvc_solo = test_rvc_solo(num_runs=3)
    soprano_concurrent, rvc_concurrent = test_concurrent(num_runs=3)
    
    # Analysis
    print("\n" + "=" * 60)
    print("ANALYSIS")
    print("=" * 60)
    
    soprano_slowdown = ((soprano_concurrent - soprano_solo) / soprano_solo) * 100
    rvc_slowdown = ((rvc_concurrent - rvc_solo) / rvc_solo) * 100
    
    print(f"\nSoprano Solo:       {soprano_solo:.2f}s")
    print(f"Soprano Concurrent: {soprano_concurrent:.2f}s")
    print(f"Slowdown:          {soprano_slowdown:+.1f}%")
    
    print(f"\nRVC Solo:           {rvc_solo:.2f}s")
    print(f"RVC Concurrent:     {rvc_concurrent:.2f}s")
    print(f"Slowdown:          {rvc_slowdown:+.1f}%")
    
    print("\n" + "=" * 60)
    print("CONCLUSION")
    print("=" * 60)
    
    if soprano_slowdown > 10 or rvc_slowdown > 10:
        print("⚠️  SIGNIFICANT GPU CONTENTION DETECTED!")
        print(f"   Running both models simultaneously causes:")
        print(f"   - Soprano: {soprano_slowdown:+.1f}% slower")
        print(f"   - RVC: {rvc_slowdown:+.1f}% slower")
        print("\n   This explains why async pipeline doesn't improve performance.")
        print("   The GPU cannot efficiently run both models at full speed.")
    elif soprano_slowdown > 5 or rvc_slowdown > 5:
        print("⚠️  MODERATE GPU CONTENTION DETECTED")
        print(f"   Running both models simultaneously causes:")
        print(f"   - Soprano: {soprano_slowdown:+.1f}% slower")
        print(f"   - RVC: {rvc_slowdown:+.1f}% slower")
        print("\n   Some contention exists but may not be the main bottleneck.")
    else:
        print("✓ NO SIGNIFICANT GPU CONTENTION")
        print(f"   - Soprano: {soprano_slowdown:+.1f}% change")
        print(f"   - RVC: {rvc_slowdown:+.1f}% change")
        print("\n   GPU can handle both models simultaneously!")
        print("   The async pipeline slowdown has a different cause.")
    
    print("\n" + "=" * 60)

if __name__ == "__main__":
    main()
