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.
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
# GDB initialization script for Automotive RTOS debugging
|
||||
|
||||
# Set target architecture
|
||||
set architecture arm
|
||||
set endian little
|
||||
|
||||
# Configure remote target
|
||||
# target remote localhost:3333
|
||||
# target remote :2331
|
||||
|
||||
# Set program counter
|
||||
set $pc = Reset_Handler
|
||||
|
||||
# Break at main
|
||||
break main
|
||||
continue
|
||||
|
||||
# RTOS-specific commands
|
||||
define rtos_tasks
|
||||
echo === RTOS Tasks ===\n
|
||||
set $task = task_list_head
|
||||
while $task != 0
|
||||
printf "Task: %s\n", $task->name
|
||||
printf " ID: %d\n", $task->task_id
|
||||
printf " Priority: %d\n", $task->priority
|
||||
printf " State: %d\n", $task->state
|
||||
printf " Stack: 0x%08x\n", $task->stack_pointer
|
||||
printf " Stack Base: 0x%08x\n", $task->stack_base
|
||||
printf " Stack Size: %d\n", $task->stack_size
|
||||
printf "\n"
|
||||
set $task = $task->next
|
||||
end
|
||||
end
|
||||
|
||||
define rtos_task_info
|
||||
if $argc != 1
|
||||
echo Usage: rtos_task_info <task_name>\n
|
||||
else
|
||||
set $task = task_list_head
|
||||
while $task != 0
|
||||
if $_streq($task->name, $arg0)
|
||||
printf "Task Information:\n"
|
||||
printf " Name: %s\n", $task->name
|
||||
printf " ID: %d\n", $task->task_id
|
||||
printf " Priority: %d\n", $task->priority
|
||||
printf " State: %d\n", $task->state
|
||||
printf " Stack Pointer: 0x%08x\n", $task->stack_pointer
|
||||
printf " Stack Base: 0x%08x\n", $task->stack_base
|
||||
printf " Stack Size: %d\n", $task->stack_size
|
||||
printf " Stack Used: %d\n", $task->stack_high_water_mark
|
||||
printf " Execution Count: %d\n", $task->statistics.execution_count
|
||||
printf " Last Execution: %d\n", $task->statistics.last_execution_time
|
||||
break
|
||||
end
|
||||
set $task = $task->next
|
||||
end
|
||||
if $task == 0
|
||||
echo Task not found\n
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
define rtos_scheduler_stats
|
||||
echo === Scheduler Statistics ===\n
|
||||
printf "Context Switches: %d\n", scheduler_state.statistics.context_switches
|
||||
printf "Preemptions: %d\n", scheduler_state.statistics.preemptions
|
||||
printf "Max Latency: %d\n", scheduler_state.statistics.max_scheduling_latency
|
||||
printf "Total Idle Time: %d\n", scheduler_state.statistics.total_idle_time
|
||||
end
|
||||
|
||||
define rtos_semaphores
|
||||
echo === Semaphores ===\n
|
||||
# Iterate through semaphore list
|
||||
echo Semaphore information not available in this build\n
|
||||
end
|
||||
|
||||
define rtos_mutexes
|
||||
echo === Mutexes ===\n
|
||||
# Iterate through mutex list
|
||||
echo Mutex information not available in this build\n
|
||||
end
|
||||
|
||||
define rtos_queues
|
||||
echo === Message Queues ===\n
|
||||
# Iterate through queue list
|
||||
echo Queue information not available in this build\n
|
||||
end
|
||||
|
||||
define rtos_stack_check
|
||||
echo === Stack Usage ===\n
|
||||
set $task = task_list_head
|
||||
while $task != 0
|
||||
printf "%s: %d/%d bytes used\n", $task->name, $task->stack_high_water_mark, $task->stack_size
|
||||
set $task = $task->next
|
||||
end
|
||||
end
|
||||
|
||||
# Pretty printing
|
||||
set print pretty on
|
||||
set print array on
|
||||
set print elements 20
|
||||
set print demangle on
|
||||
|
||||
# History
|
||||
set history save on
|
||||
set history size 1000
|
||||
set history filename .gdb_history
|
||||
|
||||
# Convenience
|
||||
set pagination off
|
||||
set confirm off
|
||||
set verbose off
|
||||
|
||||
# Display on stop
|
||||
display/10i $pc
|
||||
Executable
+213
@@ -0,0 +1,213 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user