#!/usr/bin/env python3 """ @file timing_analyzer.py @brief Timing analyzer for Automotive RTOS """ import os import re import sys import argparse import json from collections import defaultdict from pathlib import Path class TimingAnalyzer: """Analyze timing requirements and performance""" def __init__(self, project_root): self.project_root = Path(project_root) self.tasks = {} self.timing_data = defaultdict(list) self.violations = [] def analyze_task_configuration(self): """Analyze task timing configuration""" print("Analyzing task configuration...") task_config_file = self.project_root / 'config' / 'task_config.h' if not task_config_file.exists(): print("Task configuration file not found") return with open(task_config_file, 'r') as f: content = f.read() # Parse task priorities and periods task_pattern = re.compile( r'\{"([^"]+)",\s*(\d+),\s*(\d+),\s*(\d+),\s*(\d+),\s*(true|false),\s*(true|false)\}' ) print("\nTask Configuration:") print("-" * 80) print(f"{'Task Name':25s} {'Priority':>8s} {'Period':>8s} {'Deadline':>8s}") print("-" * 80) for match in task_pattern.finditer(content): task_name = match.group(1) priority = int(match.group(2)) period = int(match.group(3)) deadline = int(match.group(5)) self.tasks[task_name] = { 'priority': priority, 'period': period, 'deadline': deadline } print(f"{task_name:25s} {priority:8d} {period:8d} {deadline:8d}") print("-" * 80) def analyze_schedulability(self): """Analyze task schedulability""" print("\nSchedulability Analysis:") print("-" * 60) # Calculate CPU utilization total_utilization = 0 for task_name, config in self.tasks.items(): if config['period'] > 0: utilization = config['deadline'] / config['period'] total_utilization += utilization print(f"{task_name:25s} {utilization*100:6.2f}%") print("-" * 60) print(f"Total CPU Utilization: {total_utilization*100:.2f}%") # Check schedulability if total_utilization < 0.69: # Liu & Layland bound for RM print("✓ System is schedulable (Rate Monotonic)") else: print("⚠ System may not be schedulable") self.violations.append("High CPU utilization") def analyze_timing_logs(self, log_file): """Analyze timing logs""" if not os.path.exists(log_file): print(f"Timing log not found: {log_file}") return print(f"\nAnalyzing timing log: {log_file}") with open(log_file, 'r') as f: for line in f: # Parse timing data match = re.match( r'\[(\d+)\]\s+(\w+):\s+start=(\d+)\s+end=(\d+)\s+duration=(\d+)' , line) if match: timestamp = int(match.group(1)) task_name = match.group(2) duration = int(match.group(5)) self.timing_data[task_name].append({ 'timestamp': timestamp, 'duration': duration }) # Calculate statistics print("\nTiming Statistics:") print("-" * 80) print(f"{'Task Name':25s} {'Count':>6s} {'Min':>8s} {'Max':>8s} {'Avg':>8s} {'Jitter':>8s}") print("-" * 80) for task_name, measurements in self.timing_data.items(): if measurements: durations = [m['duration'] for m in measurements] count = len(durations) min_duration = min(durations) max_duration = max(durations) avg_duration = sum(durations) / count jitter = max_duration - min_duration print(f"{task_name:25s} {count:6d} {min_duration:8d} " f"{max_duration:8d} {avg_duration:8.1f} {jitter:8d}") # Check for violations if task_name in self.tasks: deadline = self.tasks[task_name]['deadline'] if max_duration > deadline: self.violations.append( f"{task_name} exceeds deadline: {max_duration} > {deadline}" ) def analyze_interrupt_timing(self): """Analyze interrupt timing""" print("\nInterrupt Timing Analysis:") print("-" * 40) # Common interrupt latencies interrupts = { 'SysTick': {'priority': 15, 'typical_latency': 1}, 'CAN': {'priority': 5, 'typical_latency': 2}, 'UART': {'priority': 6, 'typical_latency': 1}, 'SPI': {'priority': 7, 'typical_latency': 1}, 'I2C': {'priority': 7, 'typical_latency': 2}, 'ADC': {'priority': 8, 'typical_latency': 3}, 'Timer': {'priority': 8, 'typical_latency': 1}, } for irq_name, config in interrupts.items(): print(f"{irq_name:15s} Priority: {config['priority']:2d} " f"Latency: {config['typical_latency']}ms") def generate_report(self, output_file): """Generate timing analysis report""" print(f"\nGenerating report: {output_file}") with open(output_file, 'w') as f: f.write("=" * 80 + "\n") f.write("Timing Analysis Report\n") f.write("=" * 80 + "\n\n") # Task configuration f.write("Task Configuration:\n") f.write("-" * 40 + "\n") for task_name, config in self.tasks.items(): f.write(f"{task_name}: Priority={config['priority']}, " f"Period={config['period']}ms, Deadline={config['deadline']}ms\n") f.write("\n") # Violations if self.violations: f.write("Timing Violations:\n") f.write("-" * 40 + "\n") for violation in self.violations: f.write(f"✗ {violation}\n") else: f.write("No timing violations detected.\n") def analyze(self, timing_log=None): """Run complete analysis""" print("=" * 60) print("Timing Analyzer") print("=" * 60) self.analyze_task_configuration() self.analyze_schedulability() self.analyze_interrupt_timing() if timing_log: self.analyze_timing_logs(timing_log) # Generate report report_file = self.project_root / 'build' / 'timing_report.txt' report_file.parent.mkdir(parents=True, exist_ok=True) self.generate_report(report_file) print(f"\nReport saved to: {report_file}") def main(): parser = argparse.ArgumentParser(description='Timing analyzer') parser.add_argument('--project', default='.', help='Project root directory') parser.add_argument('--timing-log', help='Timing log file') args = parser.parse_args() analyzer = TimingAnalyzer(args.project) analyzer.analyze(args.timing_log) if __name__ == '__main__': main()