""" Linux BenchTools - Scoring Utilities New normalized scoring formulas (0-100 scale): - CPU: events_per_second / 100 - Memory: throughput_mib_s / 1000 - Disk: (read_mb_s + write_mb_s) / 20 - Network: (upload_mbps + download_mbps) / 20 - GPU: glmark2_score / 50 """ from app.core.config import settings def calculate_cpu_score(events_per_second: float = None) -> float: """ Calculate CPU score from sysbench events per second. Formula: events_per_second / 100 Range: 0-100 (capped) Example: 3409.87 events/s → 34.1 score """ if events_per_second is None or events_per_second <= 0: return 0.0 score = events_per_second / 100.0 return min(100.0, max(0.0, score)) def calculate_memory_score(throughput_mib_s: float = None) -> float: """ Calculate Memory score from sysbench throughput. Formula: throughput_mib_s / 1000 Range: 0-100 (capped) Example: 13806.03 MiB/s → 13.8 score """ if throughput_mib_s is None or throughput_mib_s <= 0: return 0.0 score = throughput_mib_s / 1000.0 return min(100.0, max(0.0, score)) def calculate_disk_score(read_mb_s: float = None, write_mb_s: float = None) -> float: """ Calculate Disk score from fio read/write bandwidth. Formula: (read_mb_s + write_mb_s) / 20 Range: 0-100 (capped) Example: (695 + 695) MB/s → 69.5 score """ if read_mb_s is None and write_mb_s is None: return 0.0 read = read_mb_s if read_mb_s is not None and read_mb_s > 0 else 0.0 write = write_mb_s if write_mb_s is not None and write_mb_s > 0 else 0.0 score = (read + write) / 20.0 return min(100.0, max(0.0, score)) def calculate_network_score(upload_mbps: float = None, download_mbps: float = None) -> float: """ Calculate Network score from iperf3 upload/download speeds. Formula: (upload_mbps + download_mbps) / 20 Range: 0-100 (capped) Example: (484.67 + 390.13) Mbps → 43.7 score """ if upload_mbps is None and download_mbps is None: return 0.0 upload = upload_mbps if upload_mbps is not None and upload_mbps > 0 else 0.0 download = download_mbps if download_mbps is not None and download_mbps > 0 else 0.0 score = (upload + download) / 20.0 return min(100.0, max(0.0, score)) def calculate_gpu_score(glmark2_score: int = None) -> float: """ Calculate GPU score from glmark2 benchmark. Formula: glmark2_score / 50 Range: 0-100 (capped) Example: 2500 glmark2 → 50.0 score """ if glmark2_score is None or glmark2_score <= 0: return 0.0 score = glmark2_score / 50.0 return min(100.0, max(0.0, score)) def calculate_global_score( cpu_score: float = None, memory_score: float = None, disk_score: float = None, network_score: float = None, gpu_score: float = None ) -> float: """ Calculate global score from component scores using configured weights. Returns: float: Global score (0-100) """ scores = [] weights = [] if cpu_score is not None: scores.append(cpu_score) weights.append(settings.SCORE_WEIGHT_CPU) if memory_score is not None: scores.append(memory_score) weights.append(settings.SCORE_WEIGHT_MEMORY) if disk_score is not None: scores.append(disk_score) weights.append(settings.SCORE_WEIGHT_DISK) if network_score is not None: scores.append(network_score) weights.append(settings.SCORE_WEIGHT_NETWORK) if gpu_score is not None: scores.append(gpu_score) weights.append(settings.SCORE_WEIGHT_GPU) if not scores: return 0.0 # Normalize weights if not all components are present total_weight = sum(weights) if total_weight == 0: return 0.0 # Calculate weighted average weighted_sum = sum(score * weight for score, weight in zip(scores, weights)) global_score = weighted_sum / total_weight # Clamp to 0-100 range return max(0.0, min(100.0, global_score)) def validate_score(score: float) -> bool: """ Validate that a score is within acceptable range. Args: score: Score value to validate Returns: bool: True if score is valid (0-100 or None) """ if score is None: return True return 0.0 <= score <= 100.0