ca13734bf0
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.
216 lines
7.2 KiB
Python
Executable File
216 lines
7.2 KiB
Python
Executable File
#!/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()
|