【树莓派学习】002 gpio trace
使用 ftrace 观测 GPIO 从用户调用到驱动的完整轨迹需要跟踪系统调用、VFS 层、设备驱动等多个层次。以下是详细的观测方案:
1. 准备环境和测试程序
1.1 简单的 GPIO 测试程序
1 | // trace_gpio_test.c |
编译运行: 1
2
3cd ~/code
gcc trace_gpio_test.c -o trace_gpio
./trace_gpio
2. 配置 ftrace 跟踪点
2.1 实际可用的跟踪脚本
1 |
|
3. 详细的函数跟踪配置
3.1 完整的已验证函数列表
1 |
|
4. 使用 trace-cmd 进行更精细控制
4.1 trace-cmd 配置(针对 GPIO)
1 | # 安装 trace-cmd |
1 |
|
或者使用更简单的方法: 1
2sudo trace-cmd record -e 'syscalls:*mmap*' -p function -F /home/pi/code/trace_gpio
sudo trace-cmd report
5. 分析 ftrace 输出日志
5.1 关键路径识别方法
根据 /tmp/gpio_mmap_complete_trace.log 分析 GPIO mmap
完整轨迹:
1. 识别系统调用入口 1
2# 查找 mmap 系统调用开始
grep -n "__arm64_sys_mmap\|ksys_mmap" /tmp/gpio_mmap_complete_trace.log
2. 跟踪内存管理调用链 1
2# 查看内存管理核心函数
grep -A10 -B5 "do_mmap\|mmap_region\|__mmap_region" /tmp/gpio_mmap_complete_trace.log
3. 定位驱动特定函数 1
2# 查找 GPIO 驱动函数
grep -A20 -B10 "rpi_gpiomem_mmap\|rpi_gpiomem_open" /tmp/gpio_mmap_complete_trace.log
5.2 性能热点分析
分析页表操作频率: 1
2
3# 统计 __pte_offset_map_lock 调用次数和总耗时
grep "__pte_offset_map_lock" /tmp/gpio_mmap_complete_trace.log | wc -l
grep "__pte_offset_map_lock" /tmp/gpio_mmap_complete_trace.log | awk '{sum += $3} END {print "总耗时:", sum, "us"}'
识别内存分配瓶颈: 1
2# 查看 VMA 分配耗时
grep -A5 "vm_area_alloc\|kmem_cache_alloc" /tmp/gpio_mmap_complete_trace.log
5.3 调用深度分析
重建完整调用路径: 1
2# 提取关键函数的时间线
awk '/__arm64_sys_mmap/,/rpi_gpiomem_mmap/' /tmp/gpio_mmap_complete_trace.log | head -50
验证驱动映射成功: 1
2# 检查 remap_pfn_range 是否执行
grep -A10 "remap_pfn_range" /tmp/gpio_mmap_complete_trace.log
1 | tail -100 /tmp/gpio_mmap_complete_trace.log |
当用户调用mmap()的时候,内核会进行如下处理 1. 在进程的虚拟空间查找一块VMA 2. 将这块VMA进行映射 3. 如果设备驱动程序或者文件系统的file_operations定义了mmap()操作,则调用它。 4. 将这个VMA插入进程的VMA链表中
从 ftrace 输出可以清晰地验证 mmap 处理的四个步骤:
1. 查找 VMA (虚拟内存区域)
1 | # 在进程虚拟空间查找空闲区域 |
2. 分配和设置 VMA
1 | vm_area_alloc() { # 分配 VMA 结构体 |
3. 调用驱动/文件系统的 mmap 操作
1 | ext4_file_mmap() { # 文件系统的 mmap 操作 |
4. 将 VMA 插入进程链表
1 | vma_link_file() { # 将 VMA 链接到进程的 VMA 链表 |
关键证据总结:
- VMA 查找:
__get_unmapped_area()和vm_unmapped_area()负责在进程地址空间找到合适区域 - VMA 分配:
vm_area_alloc()明确分配了 VMA 结构体 - 驱动 mmap 调用:
ext4_file_mmap()显示了文件操作的具体 mmap 实现(在你的 GPIO 案例中应该是rpi_gpiomem_mmap) - VMA 链表插入:
vma_link_file()和vma_interval_tree_insert()完成了 VMA 到进程数据结构的链接
这个 trace 完美印证了 mmap 的四个处理步骤。


