#!/usr/bin/env python3 """ @file trace_analyzer.py @brief Trace analyzer for Automotive RTOS debugging """ import os import re import sys import argparse import json from collections import defaultdict from datetime import datetime from pathlib import Path class TraceAnalyzer: """Analyze RTOS trace data""" def __init__(self, trace_file): self.trace_file = Path(trace_file) self.events = [] self.task_timeline = defaultdict(list) self.context_switches = [] self.interrupts = [] def parse_trace_file(self): """Parse trace file""" print(f"Parsing trace file: {self.trace_file}") if not self.trace_file.exists(): print(f"Error: Trace file not found") return False event_pattern = re.compile( r'\[(\d+\.?\d*)\]\s+(\w+):\s+(.*)' ) with open(self.trace_file, 'r') as f: for line in f: match = event_pattern.match(line) if match: timestamp = float(match.group(1)) event_type = match.group(2) event_data = match.group(3) event = { 'timestamp': timestamp, 'type': event_type, 'data': event_data } self.events.append(event) # Categorize events if event_type == 'TASK_SWITCH': self.context_switches.append(event) elif event_type == 'IRQ_ENTER': self.interrupts.append(event) elif event_type == 'TASK_START': task_name = event_data.split(':')[0].strip() self.task_timeline[task_name].append({ 'type': 'start', 'timestamp': timestamp }) elif event_type == 'TASK_END': task_name = event_data.split(':')[0].strip() self.task_timeline[task_name].append({ 'type': 'end', 'timestamp': timestamp }) print(f"Parsed {len(self.events)} events") return True def analyze_context_switches(self): """Analyze context switches""" print("\nContext Switch Analysis:") print("-" * 60) if not self.context_switches: print("No context switches found") return # Calculate intervals intervals = [] for i in range(1, len(self.context_switches)): interval = (self.context_switches[i]['timestamp'] - self.context_switches[i-1]['timestamp']) intervals.append(interval) if intervals: avg_interval = sum(intervals) / len(intervals) min_interval = min(intervals) max_interval = max(intervals) print(f"Total context switches: {len(self.context_switches)}") print(f"Average interval: {avg_interval:.3f} ms") print(f"Minimum interval: {min_interval:.3f} ms") print(f"Maximum interval: {max_interval:.3f} ms") def analyze_task_execution(self): """Analyze task execution times""" print("\nTask Execution Analysis:") print("-" * 60) print(f"{'Task Name':25s} {'Executions':>10s} {'Total Time':>10s} {'Avg Time':>10s}") print("-" * 60) for task_name, events in self.task_timeline.items(): executions = 0 total_time = 0 for i in range(0, len(events) - 1, 2): if i + 1 < len(events): if events[i]['type'] == 'start' and events[i+1]['type'] == 'end': duration = events[i+1]['timestamp'] - events[i]['timestamp'] total_time += duration executions += 1 if executions > 0: avg_time = total_time / executions print(f"{task_name:25s} {executions:10d} {total_time:10.3f} {avg_time:10.3f}") def analyze_interrupts(self): """Analyze interrupt handling""" print("\nInterrupt Analysis:") print("-" * 40) if not self.interrupts: print("No interrupts found") return irq_count = defaultdict(int) for irq in self.interrupts: irq_name = irq['data'].strip() irq_count[irq_name] += 1 for irq_name, count in irq_count.items(): print(f"{irq_name:20s} {count:5d} occurrences") def generate_timeline(self, output_file): """Generate task timeline visualization""" print(f"\nGenerating timeline: {output_file}") with open(output_file, 'w') as f: f.write("RTOS Task Timeline\n") f.write("=" * 80 + "\n\n") # Find time range if not self.events: return start_time = self.events[0]['timestamp'] end_time = self.events[-1]['timestamp'] duration = end_time - start_time f.write(f"Time range: {start_time:.3f} to {end_time:.3f} ms\n") f.write(f"Duration: {duration:.3f} ms\n\n") # Generate ASCII timeline timeline_width = 80 time_per_char = duration / timeline_width if duration > 0 else 1 for task_name, events in self.task_timeline.items(): f.write(f"\n{task_name}:\n") # Create timeline timeline = [' '] * timeline_width for i in range(0, len(events) - 1, 2): if i + 1 < len(events): start_pos = int((events[i]['timestamp'] - start_time) / time_per_char) end_pos = int((events[i+1]['timestamp'] - start_time) / time_per_char) for pos in range(start_pos, min(end_pos, timeline_width)): if 0 <= pos < timeline_width: timeline[pos] = '#' f.write(''.join(timeline) + '\n') f.write("\nLegend: '#' = task running, ' ' = task not running\n") def analyze(self): """Run complete analysis""" print("=" * 60) print("Trace Analyzer") print("=" * 60) if not self.parse_trace_file(): return self.analyze_context_switches() self.analyze_task_execution() self.analyze_interrupts() # Generate timeline output_dir = self.trace_file.parent timeline_file = output_dir / 'timeline.txt' self.generate_timeline(timeline_file) print(f"\nTimeline saved to: {timeline_file}") def main(): parser = argparse.ArgumentParser(description='Trace analyzer') parser.add_argument('trace_file', help='Trace file to analyze') parser.add_argument('--output', help='Output directory') args = parser.parse_args() analyzer = TraceAnalyzer(args.trace_file) analyzer.analyze() if __name__ == '__main__': main()