#!/usr/bin/env python3 """ Standalone test for metrics collection - tests modules directly without importing unsloth package. """ import sys import os import time # Add project root to path project_root = os.path.dirname( os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ) sys.path.insert(0, os.path.join(project_root, "unsloth", "metrics")) # Import metrics modules directly import importlib.util def load_module(filepath, module_name): """Load a Python module directly from file.""" spec = importlib.util.spec_from_file_location(module_name, filepath) module = importlib.util.module_from_spec(spec) sys.modules[module_name] = module spec.loader.exec_module(module) return module # Load modules metrics_dir = os.path.join(project_root, "unsloth", "metrics") stats = load_module(os.path.join(metrics_dir, "stats.py"), "stats") print("=" * 60) print("Unsloth Metrics Collection - Standalone Test") print("=" * 60) # Test 1: InferenceStats print("\n1. Testing InferenceStats...") inference_stats = stats.InferenceStats() request_id = "test_1" inference_stats.start_request(request_id, num_prompt_tokens = 10, max_tokens = 20) time.sleep(0.01) inference_stats.record_scheduled(request_id) time.sleep(0.01) inference_stats.record_first_token(request_id) for i in range(5): inference_stats.record_token(request_id) time.sleep(0.01) inference_stats.finish_request( request_id, finish_reason = "stop", num_generation_tokens = 5 ) stats_dict = inference_stats.get_stats() print(f" ✅ Total requests: {stats_dict['total_requests']}") print(f" ✅ Prompt tokens: {stats_dict['total_prompt_tokens']}") print(f" ✅ Generation tokens: {stats_dict['total_generation_tokens']}") print(f" ✅ Avg latency: {stats_dict['avg_e2e_latency']:.3f}s") assert stats_dict["total_requests"] == 1 assert stats_dict["total_prompt_tokens"] == 10 assert stats_dict["total_generation_tokens"] == 5 # Test 2: TrainingStats print("\n2. Testing TrainingStats...") training_stats = stats.TrainingStats() for step in range(3): training_stats.record_batch( step = step, batch_size = 4, forward_time = 0.1, backward_time = 0.15, loss = 0.5 - (step * 0.05), learning_rate = 2e-4, grad_norm = 1.0, ) stats_dict = training_stats.get_stats() print(f" ✅ Total steps: {stats_dict['total_steps']}") print(f" ✅ Total samples: {stats_dict['total_samples']}") print(f" ✅ Avg loss: {stats_dict['avg_loss']:.4f}") assert stats_dict["total_steps"] == 3 assert stats_dict["total_samples"] == 12 # Test 3: StatsCollector print("\n3. Testing StatsCollector...") collector = stats.StatsCollector() collector.enable() assert collector.is_enabled() all_stats = collector.get_all_stats() assert "inference" in all_stats assert "training" in all_stats print(" ✅ StatsCollector working") # Test 4: Prometheus (if available) print("\n4. Testing Prometheus export...") try: # Check if prometheus_client is available try: import prometheus_client prometheus_available = True except ImportError: prometheus_available = False print(f" ℹ️ prometheus_client not installed (optional dependency)") print(f" ✅ Metrics collection works without it") if prometheus_available: # Create a minimal test without importing the full prometheus module # (since it imports stats which triggers package init) print(f" ✅ Prometheus client available") print(f" ℹ️ Full Prometheus export test requires GPU environment") except Exception as e: print(f" ⚠️ Prometheus test skipped: {e}") import traceback traceback.print_exc() print("\n" + "=" * 60) print("✅ All metrics tests passed!") print("=" * 60)