Files
RTOS/tools/debugging/trace_analyzer.py
T
root ca13734bf0 Add full automotive RTOS project
Add kernel (Cortex-M0/M3/M4, Tricore, S32K, RISC-V ports), drivers,
middleware (CAN stack, diagnostics, safety), applications, board
support, build/test tooling, and documentation.
2026-08-23 03:35:29 -04:00

214 lines
7.0 KiB
Python
Executable File

#!/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()