内核调试方法

内核调试方法

基于 ARM64 开发板 (5.10.0-openeuler aarch64) 实机验证,所有命令均带有实际输出示例。


目录

  1. 基础环境查看命令
  2. [/proc 文件系统调试](#/proc 文件系统调试)
  3. [/sys 缓存几何信息](#/sys 缓存几何信息)
  4. [ftrace 内核跟踪](#ftrace 内核跟踪)
  5. [cache-stat 缓存统计工具](#cache-stat 缓存统计工具)
  6. [dmesg 内核日志](#dmesg 内核日志)
  7. [Magic SysRq 魔术键](#Magic SysRq 魔术键)
  8. [Dynamic Debug 动态调试](#Dynamic Debug 动态调试)
  9. [printk 内核日志系统](#printk 内核日志系统)
  10. [lockup 检测器](#lockup 检测器)
  11. [KASAN/KFENCE/kmemleak 内存调试](#KASAN/KFENCE/kmemleak 内存调试)
  12. [RCU 调试与测试](#RCU 调试与测试)
  13. 内核启动参数调试
  14. [taskset CPU 亲和性](#taskset CPU 亲和性)
  15. [chrt 实时调度策略](#chrt 实时调度策略)
  16. [cyclictest 实时延迟测试](#cyclictest 实时延迟测试)
  17. [stress-ng 压力测试](#stress-ng 压力测试)
  18. [fw_printenv/fw_setenv U-Boot 环境变量](#fw_printenv/fw_setenv U-Boot 环境变量)
  19. [proc/sys 内核参数调优](#proc/sys 内核参数调优)
  20. 自定义调试工具

1. 基础环境查看命令

1.1 查看内核版本

bash 复制代码
root@board:~# uname -a
Linux board 5.10.0-openeuler #22 SMP PREEMPT Mon Jun 1 01:58:33 CST 2026 aarch64 aarch64 aarch64 GNU/Linux
#         ^     ^               ^        ^           ^                        ^       ^
#         |     |               |        |           |                        |       +-- GNU/Linux
#         |     |               |        |           |                        +-- CPU架构(aarch64)
#         |     |               |        |           +-- 编译时间
#         |     |               |        +-- 内核版本号(第22次编译, PREEMPT)
#         |     |               +-- 内核名称
#         |     +-- 主机名
#         +-- 内核类型(Linux)

root@board:~# cat /proc/version
Linux version 5.10.0-openeuler (builder@build-host) (aarch64-openeuler-linux-gnu-gcc 10.3.1, GNU ld 2.37) #22 SMP PREEMPT Mon Jun 1 01:58:33 CST 2026
#                     ^                   ^                ^                                    ^
#                     |                   |                |                                    +-- 编译时间
#                     |                   |                +-- 编译器版本
#                     |                   +-- 编译主机
#                     +-- 内核版本

1.2 查看 CPU 信息

bash 复制代码
root@board:~# cat /proc/cpuinfo | head -10
processor       : 0         # CPU逻辑编号(0-7, 共8核)
BogoMIPS        : 48.00     # 估算的CPU每秒百万指令数(用于性能参考)
Features        : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
#                  ^    ^      ^      ^     ^    ^    ^     ^       ^    ^       ^     ^     ^      ^      ^
#                  |    |      |      |     |    |    |     |       |    |       |     |     |      |      +-- asimd dot product
#                  |    |      |      |     |    |    |     |       |    |       |     |     |      +-- LRCPC指令
#                  |    |      |      |     |    |    |     |       |    |       |     |     +-- 原子指令(LSE)
#                  |    |      |      |     |    |    |     |       |    |       |     +-- CRC32
#                  |    |      |      |     |    |    |     |       |    |       +-- SHA2
#                  |    |      |      |     |    |    |     |       |    +-- SHA1
#                  |    |      |      |     |    |    |     |       +-- 半精度浮点(FP16)
#                  |    |      |      |     |    |    |     +-- 单精度/双精度浮点
#                  |    |      |      |     |    |    +-- 原子操作(AArch32)
#                  |    |      |      |     |    +-- CRC32(AArch32)
#                  |    |      |      |     +-- SHA2(AArch32)
#                  |    |      |      +-- SHA1(AArch32)
#                  |    |      +-- PMULL(多项式乘法,用于加密)
#                  |    +-- AES加密指令
#                  +-- 浮点/NEON
CPU implementer : 0x41       # CPU厂商: 0x41=ARM, 0x42=Broadcom, 0x43= Cavium
CPU architecture: 8          # ARM架构版本: 8=ARMv8, 9=ARMv9
CPU variant     : 0x3        # CPU变体(内部版本)
CPU part        : 0xd0d      # CPU型号: 0xd0d=Cortex-A76, 0xd0e=Cortex-A77
CPU revision    : 1          # CPU修订版本

root@board:~# nproc
7                              # 返回7表示用户态可见7核

root@board:~# cat /sys/devices/system/cpu/possible
0-7                           # 系统实际有8核(0-7),CPU7被isolcpus隔离

说明nproc 返回 7 是因为 CPU7 被 isolcpus 隔离,但 possible 显示 0-7 共 8 个核。

1.3 查看内核启动参数 (cmdline)

bash 复制代码
root@board:~# cat /proc/cmdline
uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=/dev/mmcblk0p5 rw rootwait nohz=on nohz_full=7 isolcpus=domain,managed_irq,7 rcu_nocbs=7 irqaffinity=0-6
# ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# |                        |               |                          |                   +-- irqaffinity=0-6: 中断只发到CPU0-6,保护CPU7
# |                        |               |                          +-- RCU回调卸载到非隔离核
# |                        |               +-- isolcpus=domain,managed_irq,7: 隔离CPU7
# |                        |                    domain=从调度域移除; managed_irq=不接收托管中断
# |                        +-- nohz_full=7: CPU7关闭定期时钟tick
# +-- earlycon=uart8250,mmio32,0xfeb50000: 早期串口调试输出
#    console=ttyFIQ0: 控制台输出到FIQ串口
#    irqchip.gicv3_pseudo_nmi=0: 禁用伪NMI
#    root=/dev/mmcblk0p5: 根文件系统在eMMC分区5
#    rw: 根文件系统读写挂载
#    rootwait: 等待根设备就绪
#    nohz=on: 启用动态时钟(dyntick)

1.4 查看内存信息

bash 复制代码
root@board:~# cat /proc/meminfo | head -10
MemTotal:        3992272 kB   # 物理内存总量(约3.8GB)
MemFree:         3677960 kB   # 完全空闲的内存(约3.5GB,系统刚启动)
MemAvailable:    3815448 kB   # 可用于启动新程序的估算值(含可回收缓存)
Buffers:           46764 kB   # 块设备缓冲区(raw disk)
Cached:           112624 kB   # 页面缓存(文件读缓存)
SwapCached:            0 kB   # 交换缓存(未启用swap所以为0)
Active:           116112 kB   # 最近被访问过的内存(不易回收)
Inactive:          55028 kB   # 最近未访问的内存(可优先回收)
Active(anon):        584 kB   # 活跃的匿名页(进程堆栈等)
Inactive(anon):    26636 kB   # 不活跃的匿名页(可换出)

1.5 查看系统运行时间和负载

bash 复制代码
root@board:~# cat /proc/uptime
692527.23 5284485.38
# ^^^^^^^^ ^^^^^^^^
# |        +-- 所有CPU空闲时间总和(秒), 5284485/(8核*692527)≈95.4%空闲
# +-- 系统已运行时间(秒), 692527秒≈8天

root@board:~# cat /proc/loadavg
0.07 0.02 0.00 1/184 728080
# ^^^^ ^^^^ ^^^^ ^^^^^ ^^^^^^
#  |    |    |    |      +-- 最后创建的PID(进程ID)
#  |    |    |    +-- 正在运行的进程数/总进程数(1个在跑,184个总进程)
#  |    |    +-- 15分钟平均负载
#  |    +-- 5分钟平均负载
#  +-- 1分钟平均负载(0.07,系统非常空闲)
#  负载含义: 单核CPU负载1.0=满载,8核CPU负载8.0=满载。当前0.07表示极空闲。

root@board:~# cat /proc/version
Linux version 5.10.0-openeuler ...

2. /proc 文件系统调试

2.1 查看中断分布 (/proc/interrupts)

查看每个 CPU 的中断处理数量,用于判断中断是否均衡分布。

bash 复制代码
root@board:~# cat /proc/interrupts | head -12
           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
 11:  692545722   37899191   54126437   39191535   39096395   38223640   37408833   36000462     GICv3  30 Level     arch_timer
#  ^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^    ^^^^^  ^^ ^^^^^    ^^^^^^^^^^
#  |              |                                                                             |     |  |        +-- 中断源名称(arch_timer=架构定时器)
#  |              |                                                                             |     |  +-- 触发方式(Level=电平触发, Edge=边沿触发)
#  |              |                                                                             |     +-- 中断号(GIC内部的中断ID=30)
#  |              |                                                                             +-- 中断控制器(GICv3)
#  |              +-- 各CPU处理此中断的次数(CPU0约6.9亿次,CPU7仅3600万次,说明分配不均)
#  +-- 中断向量号(Linux内部IRQ号)
 14:          0     493916   14192146     992788    1843754    1389806    1912844          7     GICv3 321 Level     rk_timer
 15:      52554      51468      51504      51463      97363      97451      96568        397     GICv3  23 Level     arm-pmu
#                                                                                                                    ^^^^^^^^
#                                                                                                                    +-- arm-pmu=性能监视单元
 17:          3          0          0          0          0          0          0          0     GICv3 126 Level     fb000000.gpu
#                                                                                                                    ^^^^^^^^^^^^
#                                                                                                                    +-- GPU设备中断
 22:        328          0          0          0          0          0          0          0     GICv3 250 Level     ehci_hcd:usb2
 27:        459          0          0          0          0          0          0          0     GICv3 349 Level     fd880000.i2c

2.2 查看软中断分布 (/proc/softirqs)

bash 复制代码
root@board:~# cat /proc/softirqs
                    CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
          HI:          1         70         67         15         15          0          0          0   # 高优先级tasklet
       TIMER:   13167256    2741982   19976962    3371045    3970589    2891871    5163948          9   # 定时器软中断(CPU7仅9次!)
      NET_TX:      97879          0         44      27576          0          2          0          0   # 网络发送
      NET_RX:       5262         76        156         92        402         36        184          0   # 网络接收
       BLOCK:    1958935          0          0          0     391382     181157     146065          0   # 块设备IO(磁盘读写)
     TASKLET:        312        175         74         30         30          0          1          0   # tasklet/小任务
       SCHED:  100557916     953737   16327919    1491408    2471045    2274322    3348199          0   # 调度器(负载均衡)
         RCU:   13158781   19841256   17802903   19672186   14472393   14234901   18944186         29   # RCU回调(CPU7仅29次)
#        ^       ^                                                                                   ^
#        |       |                                                                                   +-- CPU7几乎为0, 隔离效果显著
#        |       +-- 各CPU处理此软中断的总次数
#        +-- 软中断类型名称

关键观察:CPU7 的软中断几乎全部为 0(只有 RCU 有极少触发),证明了隔离核的有效性。

2.3 查看系统统计 (/proc/stat)

bash 复制代码
root@board:~# cat /proc/stat | grep -E 'ctxt|btime|processes|procs_running|procs_blocked'
ctxt 283396533      # 上下文切换总数(从开机到现在)
btime 1780505989    # 系统启动的Unix时间戳
processes 727892    # 创建的进程总数(含线程)
procs_running 2     # 当前正在运行(或可运行)的进程数
procs_blocked 0     # 当前阻塞在I/O上的进程数(若持续>0表示I/O瓶颈)

root@board:~# cat /proc/stat | head -5
cpu  20550138 5476 4649018 527653961 7498 0 13423 0 0 0   # 所有CPU合计
#    ^^^^^^^^ ^^^^ ^^^^^^^ ^^^^^^^^^ ^^^^ ^ ^^^^^ ^ ^ ^
#    |        |       |        |      |   |   |   | +-- steal(被虚拟化偷走的时间)
#    |        |       |        |      |   |   |   +-- softirq(软中断时间)
#    |        |       |        |      |   |   +-- irq(硬中断时间)
#    |        |       |        |      |   +-- iowait(等待IO完成时间)
#    |        |       |        |      +-- idle(空闲时间,占绝大部分)
#    |        |       |        +-- system(内核态时间)
#    |        |       +-- nice(低优先级用户态时间)
#    |        +-- user(用户态时间)
#    +-- 列标签(单位: 百分之一秒,即jiffies*10ms)
cpu0 2865332 267 723868 65328769 980 0 12130 0 0 0   # CPU0单独统计
cpu1 2808219 191 791726 65546641 1637 0 43 0 0 0

2.4 查看虚拟内存统计 (/proc/vmstat)

bash 复制代码
root@board:~# cat /proc/vmstat | head -10
nr_free_pages 919123           # 空闲页数(每页4KB, 919123*4KB≈3.5GB)
nr_zone_inactive_anon 6774     # 非活跃匿名页(进程栈/堆,可swap换出)
nr_zone_active_anon 146        # 活跃匿名页(频繁访问的进程内存)
nr_zone_inactive_file 7115    # 非活跃文件页(读缓存,可回收)
nr_zone_active_file 28899     # 活跃文件页(频繁访问的文件缓存)
nr_zone_unevictable 1280      # 不可换出页(mlock锁定)
nr_zone_write_pending 0       # 正在回写磁盘的页数
nr_mlock 0                     # mlock锁定的页数
nr_page_table_pages 320       # 页表占用的页数(320*4KB=1.25MB)
nr_bounce 0                    # 反弹缓冲区的页数(低端内存兼容)

2.5 cache_color 自定义统计 (/proc/cache_color_stats)

当内核启用了 cache color 功能时,可通过此接口查看策略执行统计:

bash 复制代码
root@board:~# cat /proc/cache_color_stats
# cache_color P0 stats
iso_alloc_ok 0              # 隔离核从自己颜色池分配成功的次数
iso_alloc_miss 0            # 隔离核在目标颜色上分配失败(需回退)的次数
noniso_alloc_into_iso 0     # 非隔离核分配到了隔离颜色(颜色泄露)
policy_fallback 0           # 因目标颜色无空闲页而回退到任意颜色的次数
pcp_refill_from_nonpreferred 0  # 每CPU页缓存从非偏好颜色补货次数(越高说明颜色策略被稀释)

3. /sys 缓存几何信息

3.1 查看 L3 (LLC) 缓存参数

bash 复制代码
root@board:~# cat /sys/devices/system/cpu/cpu0/cache/index3/size
3072K

root@board:~# cat /sys/devices/system/cpu/cpu0/cache/index3/ways_of_associativity
12

root@board:~# cat /sys/devices/system/cpu/cpu0/cache/index3/coherency_line_size
64

root@board:~# cat /sys/devices/system/cpu/cpu0/cache/index3/number_of_sets
4096
参数 含义
size 3072K (3MB) L3 缓存总大小
ways_of_associativity 12 12 路组相联
coherency_line_size 64B 缓存行大小
number_of_sets 4096 set 数量

推导公式

复制代码
set 重复周期 = number_of_sets × line_size = 4096 × 64B = 256KB
缓存总大小 = set 数 × 路数 × line_size = 4096 × 12 × 64B = 3MB

3.2 查看 L1/L2 缓存

bash 复制代码
root@board:~# cat /sys/devices/system/cpu/cpu0/cache/index0/size   # L1 data
64K
root@board:~# cat /sys/devices/system/cpu/cpu0/cache/index1/size   # L1 instruction
64K
root@board:~# cat /sys/devices/system/cpu/cpu0/cache/index2/size   # L2
512K

4. ftrace 内核跟踪

ftrace 是 Linux 内核内置的跟踪框架,TL3588 上通过 tracefs(挂载在 /sys/kernel/tracing/)访问。

4.1 查看可用的跟踪器

bash 复制代码
root@board:~# cat /sys/kernel/tracing/available_tracers
blk function_graph function nop

4.2 函数跟踪 (function tracer)

跟踪内核函数调用,用于定位热点路径。

bash 复制代码
# 步骤
root@board:~# echo function > /sys/kernel/tracing/current_tracer
root@board:~# echo 1 > /sys/kernel/tracing/tracing_on
root@board:~# sleep 1
root@board:~# echo 0 > /sys/kernel/tracing/tracing_on
root@board:~# cat /sys/kernel/tracing/trace | head -15

# tracer: function
# entries-in-buffer/entries-written: 85723/189231   #P:8   (缓冲区中/总写入, #P=CPU数)
#           TASK-PID     CPU#  |||||||  TIMESTAMP  FUNCTION
#              | |         |   |||||||      |         |
          <idle>-0       [006] d...2.. 691564.100842: _raw_spin_unlock_irqrestore <-hrtimer_get_next_event
#         ^      ^         ^    ^                       ^                               ^
#         |      |         |    |                       |                               +-- 调用者函数(谁调用了它)
#         |      |         |    |                       +-- 被跟踪的函数
#         |      |         |    +-- 跟踪标记: d=关中断, .=开中断 | h=硬中断内 | s=软中断内 | 数字=preempt深度
#         |      |         +-- CPU编号[006]
#         |      +-- 进程PID
#         +-- 进程名(<idle>=空闲进程)
            bash-727917  [004] ....... 691564.100842: mutex_unlock <-tracing_set_tracer
          <idle>-0       [002] d...2.. 691564.100843: clockevents_switch_state <-__tick_broadcast_oneshot_control
          <idle>-0       [001] d...1.. 691564.100843: cpuidle_not_available <-do_idle
          <idle>-0       [003] d...1.. 691564.100843: cpuidle_select <-do_idle

注意 :function tracer 产生的数据量非常大,建议使用 tracing_cpumask 限制 CPU 范围。

4.3 函数调用图跟踪 (function_graph tracer)

跟踪函数的进入和退出,显示函数调用关系和执行耗时。

bash 复制代码
root@board:~# echo function_graph > /sys/kernel/tracing/current_tracer
root@board:~# echo 1 > /sys/kernel/tracing/tracing_on
root@board:~# sleep 1
root@board:~# echo 0 > /sys/kernel/tracing/tracing_on
root@board:~# cat /sys/kernel/tracing/trace | head -20

# tracer: function_graph
#
# CPU  DURATION                  FUNCTION CALLS
# |     |   |                     |   |   |   |
# 5)               |  cpu_pm_exit() {
# ^    ^          |  ^
# |    |          |  +-- 函数名: cpu_pm_exit() 开始执行, { 表示函数入口
# |    |          +-- 竖线: 调用深度标记(越深缩进越多)
# |    +-- 执行耗时(us): 空表示函数尚未返回, 数字如0.583us表示耗时
# +-- CPU编号[5]
 5)   0.583 us    |    rcu_irq_enter_irqson();
 5)   0.292 us    |    __rcu_read_lock();
 5)               |    raw_notifier_call_chain() {
 5)               |      gic_cpu_pm_notifier() {
 5)               |        gic_cpu_sys_reg_init() {
 5)   0.291 us    |          cpu_logical_map();
 5)   0.291 us    |          cpu_logical_map();
 5)   0.292 us    |          cpu_logical_map();
 5)   0.292 us    |          cpu_logical_map();
 5)   0.291 us    |          cpu_logical_map();
 5)   0.291 us    |          cpu_logical_map();
 5)   6.125 us    |        }

延迟标记+=超过10us, !=超过100us, #=超过1ms, *=超过10ms, @=超过100ms, $=超过1s

4.4 事件跟踪 (event tracing) --- 调度切换

跟踪 CPU 上的进程切换,用于分析延迟抖动来源。

bash 复制代码
# 仅跟踪 sched_switch 事件
root@board:~# echo nop > /sys/kernel/tracing/current_tracer
root@board:~# echo 1 > /sys/kernel/tracing/events/sched/sched_switch/enable
root@board:~# echo 1 > /sys/kernel/tracing/tracing_on
root@board:~# sleep 2
root@board:~# echo 0 > /sys/kernel/tracing/tracing_on
root@board:~# cat /sys/kernel/tracing/trace | head -20

# tracer: nop
#           TASK-PID     CPU#  |||||||  TIMESTAMP  FUNCTION
#              | |         |   |||||||      |         |
          <idle>-0       [000] d...2.. 691566.578057: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=bash next_pid=727927 next_prio=139
#                                                   ^                                                                                       ^
#                                                   |                                                                                       +-- 下一个进程: bash(PID=727927,优先级139,120=普通,99=RT)
#                                                   +-- 上一个进程: swapper/0(PID=0,优先级120,状态R=Running)
#                                                    ==> 表示切换方向: 从prev切换到next
            bash-727926  [005] d...2.. 691566.578100: sched_switch: prev_comm=bash prev_pid=727926 prev_prio=139 prev_state=S ==> next_comm=swapper/5 next_pid=0 next_prio=120
#                                                                                                                           ^
#                                                                                                                           +-- prev_state=S=Sleep(自愿睡眠)
          <idle>-0       [002] d...2.. 691566.578512: sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=rcu_preempt next_pid=13 next_prio=120
     rcu_preempt-13      [002] d...2.. 691566.578523: sched_switch: prev_comm=rcu_preempt prev_pid=13 prev_prio=120 prev_state=I ==> next_comm=swapper/2 next_pid=0 next_prio=120
           sleep-727927  [000] d...2.. 691566.579570: sched_switch: prev_comm=sleep prev_pid=727927 prev_prio=139 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120

用途:检查隔离核上是否有意外进程运行(prev_prio=120 表示普通进程,99 表示 RT 进程)。如果 CPU7 上出现非 idle 进程的切换记录,说明隔离不彻底。

4.5 事件跟踪 --- 中断处理

bash 复制代码
root@board:~# echo 1 > /sys/kernel/tracing/events/irq/irq_handler_entry/enable
root@board:~# echo 1 > /sys/kernel/tracing/tracing_on
root@board:~# sleep 1
root@board:~# echo 0 > /sys/kernel/tracing/tracing_on
root@board:~# cat /sys/kernel/tracing/trace | head -10

          <idle>-0       [000] dn.h1.. 691591.123353: irq_handler_entry: irq=1 name=IPI
#                                                                           ^^^ ^^^^
#                                                                           |   +-- 中断名: IPI=核间中断(CPU之间通信)
#                                                                           +-- Linux IRQ号
          <idle>-0       [003] dn.h1.. 691591.123355: irq_handler_entry: irq=1 name=IPI

4.6 可用的事件分类

bash 复制代码
root@board:~# ls /sys/kernel/tracing/events/
alarmtimer  avc     block     bpf_trace  bridge    btrfs     cfg80211  cgroup    clk       cma       compaction
context_tracking  cpuhp   devfreq   dma_fence drm       dwc3      enable    filter    i2c       iommu     irq
ipi       kgsl     kmem      kvm        lock      maple_tree  mct      mdio     memleak   migrate   mmap
module    napi     net       oom        page_isolation  pagemap  percpu   power    printk    ras       rcu
regmap    regulator  resctrl  rpmsg     rpm       rseq      rtc       sched     scmi      scsi      signal
skb       smbus    smmu      sock       spi       swiotlb   sync_trace  task    tcp       thermal   timer
udp       v4l2     vb2       vmscan     workqueue writeback xdp       xfs      xhci-hcd

4.7 跟踪实例 (trace instances)

使用 trace instance 可以独立配置跟踪,不影响全局跟踪状态。这是 rt_init_debug.sh 中使用的方法。

bash 复制代码
# 创建实例
root@board:~# mkdir -p /sys/kernel/tracing/instances/my-test

# 配置实例:只跟踪 CPU7 (mask=0x80)
root@board:~# echo 0 > /sys/kernel/tracing/instances/my-test/tracing_on
root@board:~# echo 16384 > /sys/kernel/tracing/instances/my-test/buffer_size_kb
root@board:~# echo 80 > /sys/kernel/tracing/instances/my-test/tracing_cpumask

# 启用事件
root@board:~# echo 1 > /sys/kernel/tracing/instances/my-test/events/sched/sched_switch/enable
root@board:~# echo 1 > /sys/kernel/tracing/instances/my-test/events/irq/irq_handler_entry/enable
root@board:~# echo 1 > /sys/kernel/tracing/instances/my-test/events/irq/irq_handler_exit/enable

# 开始跟踪
root@board:~# echo 1 > /sys/kernel/tracing/instances/my-test/tracing_on
root@board:~# sleep 5
root@board:~# echo 0 > /sys/kernel/tracing/instances/my-test/tracing_on

# 读取跟踪结果
root@board:~# cat /sys/kernel/tracing/instances/my-test/trace

# 清理
root@board:~# echo 0 > /sys/kernel/tracing/instances/my-test/events/enable
root@board:~# rmdir /sys/kernel/tracing/instances/my-test

同时跟踪多个事件的完整配置(生产环境常用):

bash 复制代码
INST=/sys/kernel/tracing/instances/cpu7-latency
mkdir -p $INST
echo 0 > $INST/tracing_on
echo 16384 > $INST/buffer_size_kb
echo 80 > $INST/tracing_cpumask    # CPU7 only

# 启用关键事件组
echo 1 > $INST/events/sched/sched_switch/enable
echo 1 > $INST/events/sched/sched_wakeup/enable
echo 1 > $INST/events/irq/irq_handler_entry/enable
echo 1 > $INST/events/irq/irq_handler_exit/enable
echo 1 > $INST/events/irq/softirq_entry/enable
echo 1 > $INST/events/irq/softirq_exit/enable
echo 1 > $INST/events/timer/hrtimer_expire_entry/enable
echo 1 > $INST/events/timer/hrtimer_expire_exit/enable
echo 1 > $INST/events/ipi/ipi_entry/enable
echo 1 > $INST/events/ipi/ipi_exit/enable
echo 1 > $INST/events/power/cpu_idle/enable

: > $INST/trace               # 清空缓冲区
echo 1 > $INST/tracing_on     # 开始跟踪
# ... 运行测试 ...
echo 0 > $INST/tracing_on     # 停止跟踪
cat $INST/trace > /tmp/trace_output.txt

4.8 trace_marker --- 手动插入标记

在跟踪流中插入自定义标记,便于定位代码执行点:

bash 复制代码
# 先确保 markers 选项已启用
root@board:~# cat /sys/kernel/tracing/options/markers
1     # 1=已启用

# 清空缓冲区并写入标记
root@board:~# echo nop > /sys/kernel/tracing/current_tracer
root@board:~# : > /sys/kernel/tracing/trace
root@board:~# echo "my_test_marker: trace_start" > /sys/kernel/tracing/trace_marker
root@board:~# sleep 0.3
root@board:~# echo "my_test_marker: trace_end" > /sys/kernel/tracing/trace_marker
root@board:~# cat /sys/kernel/tracing/trace | grep my_test_marker
           <...>-728111  [003] ....... 692534.071945: tracing_mark_write: my_test_marker: trace_start
           <...>-728111  [003] ....... 692534.373900: tracing_mark_write: my_test_marker: trace_end

5. cache-stat 缓存统计工具

TL3588 上未安装 perf,但提供了自定义的 cache-stat 工具,基于 perf_event_open 系统调用直接读取 PMU 计数器。

5.1 基本用法

bash 复制代码
root@board:~# /usr/local/bin/cache-stat --help
Usage: /usr/local/bin/cache-stat --cpu-list LIST --duration SECONDS --output PATH

5.2 监控 CPU7 (隔离核) 缓存统计

bash 复制代码
root@board:~# /usr/local/bin/cache-stat --cpu-list 7 --duration 3 --output /tmp/perf.csv && cat /tmp/perf.csv
event,value
cycles,27776              # CPU时钟周期数
instructions,19125       # 执行的指令数
cache-references,4920    # 缓存访问总次数
cache-misses,126         # 缓存未命中次数
LLC-loads,456            # 最后一级缓存(L3)加载次数
LLC-load-misses,21       # L3加载未命中次数
cache-hit-pct,97.44      # 总体缓存命中率 = (1 - 126/4920) × 100% = 97.44%
llc-load-hit-pct,95.39   # L3命中率 = (1 - 21/456) × 100% = 95.39%

指标含义

指标 含义
cycles CPU 周期数
instructions 执行的指令数
cache-references 缓存总访问次数
cache-misses 缓存未命中次数
LLC-loads 最后一级缓存(L3)加载次数
LLC-load-misses LLC 加载未命中次数
cache-hit-pct 总体缓存命中率 = (1 - misses/references) × 100%
llc-load-hit-pct LLC 加载命中率 = (1 - llc-misses/llc-loads) × 100%

5.3 同时监控隔离核和 housekeeping 核

bash 复制代码
# 监控 CPU7
/usr/local/bin/cache-stat --cpu-list 7 --duration 120 --output /tmp/perf-iso.csv &

# 监控 CPU0-6
/usr/local/bin/cache-stat --cpu-list 0-6 --duration 120 --output /tmp/perf-hk.csv &

6. dmesg 内核日志

bash 复制代码
root@board:~# dmesg | tail -10
[  134.107043] perf: interrupt took too long (2507 > 2500), lowering kernel.perf_event_max_sample_rate to 79000
# ^^^^^^^^^^ ^
# |          +-- 日志级别(数字越大越不紧急)
# +-- 内核时间戳(秒.微秒)
[  152.821696] perf: interrupt took too long (3157 > 3133), lowering kernel.perf_event_max_sample_rate to 63000
[  230.577447] perf: interrupt took too long (3954 > 3946), lowering kernel.perf_event_max_sample_rate to 50000
[ 5209.639310] perf: interrupt took too long (4967 > 4942), lowering kernel.perf_event_max_sample_rate to 40000
[540010.273575] rk_gmac-dwmac fe1b0000.ethernet end0: Link is Down
[540013.347411] rk_gmac-dwmac fe1b0000.ethernet end0: Link is Up - 100Mbps/Full - flow control rx/tx
#                                                                          ^^^^^^^^ ^^^^^^
#                                                                          |        +-- 双工模式(Full=全双工)
#                                                                          +-- 链路速度(100Mbps)

提示 :可以使用 dmesg -w 实时查看内核日志输出(类似 tail -f)。


7. Magic SysRq 魔术键

Magic SysRq 是内核内置的紧急调试工具,即使系统看似挂死,只要内核还在运行就能响应。

7.1 启用方式

bash 复制代码
# 查看当前 sysrq 功能掩码 (16=允许同步等操作)
root@board:~# cat /proc/sys/kernel/sysrq
16

值含义:0=禁用, 1=全部启用, >1=按位掩码启用

7.2 常用命令 (通过 /proc/sysrq-trigger)

bash 复制代码
# 查看当前所有任务列表(输出会进dmesg)
root@board:~# echo t > /proc/sysrq-trigger

# 输出被写入 dmesg,分两部分:
# 第一部分:每个进程一行简略信息
root@board:~# dmesg | grep 'task:' | head -5
task:systemd         state:S stack:    0 pid:    1 ppid:     0 flags:0x00000004
task:rcu_preempt     state:I stack:    0 pid:   13 ppid:     2 flags:0x00000000
task:ksoftirqd/1    state:S stack:    0 pid:   27 ppid:     2 flags:0x00000000
task:spi1           state:S stack:    0 pid:  288 ppid:     2 flags:0x00000000
task:bash           state:S stack:    0 pid:728080 ppid:727954 flags:0x00000000
#  解读: task=进程名 | state:S(Sleep)/R(Running)/D(不可中断)/I(Idle)/Z(Zombie)
#       | stack=内核栈使用量(bytes) | pid/ppid=进程/父进程ID

# 第二部分:每个CPU的调度器状态 + 可运行任务列表
root@board:~# dmesg | grep -A 20 'runnable tasks:' | head -25
runnable tasks:
 S            task   PID         tree-key  switches  prio     wait-time      sum-exec        sum-sleep
-------------------------------------------------------------------------------------------------------
 S         cpuhp/6    41       442.071844         9   120     0.000000      0.156627       0.000000 /
 S     migration/6    42         0.000000     63973     0     0.000000    713.687594       0.000000 /
 S     ksoftirqd/6    43  12802026.988321    230735   120     0.000000   9689.865378       0.000000 /
 I   kworker/u17:1   287       531.362388         2   100     0.000000      0.017208       0.000000 /
>R systemd-journal   317  12802494.012100     11202   120     0.000000   1452.889992       0.000000 /
# 第一列: 状态(S=Sleep,R=Running,I=Idle,D=不可中断,>=正在运行)
# tree-key: 调度虚拟时间 | switches: 上下文切换次数 | prio: 优先级(120=普通,99=RT)
# wait-time: 总等待时间 | sum-exec: 总执行时间 | sum-sleep: 总睡眠时间(均为秒)

# 查看当前内存信息
root@board:~# echo m > /proc/sysrq-trigger
root@board:~# dmesg | grep -E 'DMA free|Normal free|Free swap' | head -5
[692516.105443] DMA free:3652136kB min:30600kB low:34420kB high:38240kB ...
[692516.105496] Normal free:4548kB min:4420kB low:4580kB high:4740kB ...
[692516.105515] DMA: 5996*4kB (UMEC) 11909*8kB (UMEC) 11556*16kB (UMEC) ...
[692516.105603] Free swap  = 0kB
# 输出各内存区域的空闲/最小/低/高水位线,以及内存碎片情况

# 查看所有CPU的栈回溯(排查CPU卡死、死锁)
root@board:~# echo l > /proc/sysrq-trigger
root@board:~# dmesg | grep -A 10 'Call trace:'
Call trace:
  secondary_start_kernel+0x134/0x194
  cpu_startup_entry+0x30/0x80
  cpuidle_enter_state+0xcc/0x430
  cpuidle_enter+0x40/0x6c
  call_cpuidle+0x3c/0xa0
  do_idle+0x28c/0x340
  cpu_startup_entry+0x30/0x80
  rest_init+0xdc/0x100
  start_kernel+0x5b4/0x600
# 输出每个CPU当前执行的函数调用栈,可以帮助定位哪个CPU卡在哪个函数里
# 上例显示所有CPU都在idle循环(do_idle),系统正常

# 显示所有hrtimer信息
root@board:~# echo q > /proc/sysrq-trigger
root@board:~# dmesg | tail -5
[692527.186507]  clock 6:
[692527.186521]  clock 7:
[692527.186531] ktime_get_clocktai

# 显示所有D状态(阻塞)任务
root@board:~# echo w > /proc/sysrq-trigger
root@board:~# dmesg | tail -3
[693439.865144] sysrq: Show Blocked State
# 如果没有任何D状态任务,就只有这行提示

# 设置控制台日志级别 (0-9)
echo 9 > /proc/sysrq-trigger    # 最高日志级别
echo 0 > /proc/sysrq-trigger    # 只有emerg消息

# 紧急同步所有文件系统
echo s > /proc/sysrq-trigger

# 紧急重启(不同步磁盘!)
echo b > /proc/sysrq-trigger

# 触发crash(如果配置了kdump)
echo c > /proc/sysrq-trigger

# 导出ftrace缓冲区
echo z > /proc/sysrq-trigger

7.3 功能说明速查

功能 适用场景
b 立即重启 系统完全挂死
c 触发crash dump kdump调试
d 显示所有锁 死锁诊断
e 发SIGTERM给所有进程 清理失控进程
f 触发OOM killer 内存耗尽恢复
i 发SIGKILL给所有进程 进程完全失控
l 所有CPU栈回溯 定位CPU卡住位置
m 输出内存信息 内存调试
q 显示hrtimer信息 定时器调试
s 同步挂载的文件系统 紧急同步
t 显示所有任务 查看进程状态
w 显示D状态任务 排查hung task
z 导出ftrace缓冲区 ftrace数据抢救
0-9 设置console loglevel 控制日志输出量

8. Dynamic Debug 动态调试

Dynamic Debug 允许在运行时动态启用/禁用内核中的 pr_debug() / dev_dbg() / print_hex_dump_debug() 打印,无需重新编译内核。

8.1 检查是否可用

bash 复制代码
root@board:~# ls /proc/dynamic_debug/control
/proc/dynamic_debug/control

如果存在此文件,说明内核已启用 CONFIG_DYNAMIC_DEBUG

8.2 查看所有可控制的调试点

bash 复制代码
# 统计数量
root@board:~# cat /proc/dynamic_debug/control | wc -l
6608

# 查看前几行了解格式
root@board:~# cat /proc/dynamic_debug/control | head -5
# filename:lineno [module]function flags format
net/mac80211/main.c:1283 [mac80211]ieee80211_register_hw =p "copying sband ..."
net/mac80211/rate.c:291 [mac80211]ieee80211_check_rate_mask =p "%s: no overlap ..."
net/mac80211/mlme.c:1654 [mac80211]ieee80211_handle_pwr_constr =p "%s: Limiting ..."
net/mac80211/mlme.c:1664 [mac80211]ieee80211_handle_pwr_constr =p "%s: Limiting ..."

# 查看 main 模块(内核核心)的调试点
root@board:~# grep 'module main' /proc/dynamic_debug/control | head -5
init/main.c:1178 [main]initcall_blacklist =_ "blacklisting initcall %s\012"
init/main.c:1217 [main]initcall_blacklisted =_ "initcall %s blacklisted\012"
init/main.c:1423 [main]run_init_process =_ "  with arguments:\012"
init/main.c:1425 [main]run_init_process =_ "    %s\012"
init/main.c:1426 [main]run_init_process =_ "  with environment:\012"

8.3 启用/禁用调试打印

bash 复制代码
# 启用某个文件的pr_debug
echo 'file svcsock.c +p' > /proc/dynamic_debug/control

# 启用某个模块的所有pr_debug
echo 'module xfs +p' > /proc/dynamic_debug/control

# 启用某个函数中的pr_debug
echo 'func svc_process +p' > /proc/dynamic_debug/control

# 禁用
echo 'module xfs -p' > /proc/dynamic_debug/control

# 启用并附加函数名和模块名到输出
echo 'func svc_process +pfm' > /proc/dynamic_debug/control

8.4 通过内核启动参数启用

在 bootargs 中添加:

bash 复制代码
# 在内核启动时就启用某个模块的调试
dyndbg="file ec.c +p"

# 模块特定的调试
xfs.dyndbg="func xfs_bmap* +p"

注意 :你可能需要同时调整 loglevel 才能在控制台看到输出。


9. printk 内核日志系统

9.1 控制台日志级别

bash 复制代码
root@board:~# cat /proc/sys/kernel/printk
7       4       1       7

四列分别表示:控制台日志级别默认消息日志级别最小控制台级别默认控制台级别

级别 含义
0 KERN_EMERG 系统不可用
1 KERN_ALERT 必须立即处理
2 KERN_CRIT 严重条件
3 KERN_ERR 错误条件
4 KERN_WARNING 警告条件
5 KERN_NOTICE 正常但重要
6 KERN_INFO 信息性
7 KERN_DEBUG 调试级别

9.2 控制台日志控制

bash 复制代码
# 设置控制台日志级别(数字越小越紧急)
echo 8 > /proc/sys/kernel/printk     # 显示所有消息包括debug
echo 3 > /proc/sys/kernel/printk     # 只显示ERR及以上

# 启动时忽略日志级别(显示所有内核消息)
# 在 bootargs 中添加:ignore_loglevel

# 增大内核日志缓冲区(启动参数)
# log_buf_len=4M

# 在Oops/panic时自动升高日志级别
# printk.always_kmsg_dump=1

9.3 从用户空间写入内核日志

bash 复制代码
echo "my_debug_tag: test message" > /dev/kmsg

9.4 内核崩溃时调试辅助

bash 复制代码
# panic时打印所有任务信息
# panic_print=1 在bootargs中添加

# 触发panic后自动重启(秒数)
echo 10 > /proc/sys/kernel/panic

# panic或oops时自动dump ftrace(启动参数)
# ftrace_dump_on_oops=1

10. lockup 检测器

内核内置了软锁(soft lockup)和硬锁(hard lockup/NMI watchdog)检测器。

10.1 检查是否启用

bash 复制代码
# 当前内核未编译 LOCKUP_DETECTOR,相关文件不存在
root@board:~# cat /proc/sys/kernel/watchdog_thresh
cat: /proc/sys/kernel/watchdog_thresh: No such file or directory

root@board:~# cat /proc/sys/kernel/hung_task_timeout_secs
cat: /proc/sys/kernel/hung_task_timeout_secs: No such file or directory

# 检查内核编译选项
root@board:~# zcat /proc/config.gz 2>/dev/null | grep LOCKUP
# CONFIG_LOCKUP_DETECTOR is not set

说明 :当前 TL3588 内核未启用 CONFIG_LOCKUP_DETECTOR。如需使用需重新编译内核。

10.2 启用方法 (内核重编译)

在 defconfig 中添加:

bash 复制代码
CONFIG_LOCKUP_DETECTOR=y
CONFIG_SOFTLOCKUP_DETECTOR=y
CONFIG_HARDLOCKUP_DETECTOR=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120

10.3 启用后的常用命令

bash 复制代码
# 查看/设置阈值
cat /proc/sys/kernel/watchdog_thresh       # 默认10秒
echo 30 > /proc/sys/kernel/watchdog_thresh  # 改为30秒

# 配置 panic 行为
echo 1 > /proc/sys/kernel/softlockup_panic   # softlockup时panic
echo 0 > /proc/sys/kernel/nmi_watchdog        # 禁用hardlockup检测

# hung task 检测 (需 CONFIG_DETECT_HUNG_TASK=y)
cat /proc/sys/kernel/hung_task_timeout_secs   # 默认120秒
echo 1 > /proc/sys/kernel/hung_task_panic      # 检测到hung task时panic

# dmesg 检测到 lockup 时的输出示例
# watchdog: BUG: soft lockup - CPU#7 stuck for 22s! [stress-ng:1234]
# INFO: task bash:12345 blocked for more than 120 seconds.

10.4 替代方案:SysRq 手动排查

即使没有 lockup 检测器,仍可用 SysRq 排查:

bash 复制代码
# 查看所有任务状态(含 D 状态)
root@board:~# echo t > /proc/sysrq-trigger
root@board:~# dmesg | grep -E 'task:|state:D' | head -10
# 输出示例:
# sysrq: Show State
# task:systemd state:S stack:0 pid:1 ppid:0 flags:0x00000004

# 查看所有 CPU 栈回溯
root@board:~# echo l > /proc/sysrq-trigger
root@board:~# dmesg | grep -A 20 'CPU#0' | head -25

11. KASAN/KFENCE/kmemleak 内存调试

11.1 检查可用性

bash 复制代码
# kmemleak: 当前内核未编译 CONFIG_DEBUG_KMEMLEAK
root@board:~# ls /sys/kernel/debug/kmemleak 2>/dev/null
ls: /sys/kernel/debug/kmemleak: No such file or directory

# page_owner: 当前内核未启用
root@board:~# ls /sys/kernel/debug/page_owner 2>/dev/null
ls: /sys/kernel/debug/page_owner: No such file or directory

# 内核 debug 功能总览
root@board:~# ls /sys/kernel/debug/ | head -15
asoc              dri         kprobes
bdi               dma_buf     mmc0
block             dmaengine   pm_qos
bluetooth         dma_pools   regmap
cec               extfrag

11.2 KFENCE (低开销内存错误检测器)

需要在 bootargs 中添加启动参数:

bash 复制代码
# 启用 KFENCE,100ms 采样间隔
kfence.sample_interval=100

# 检测到错误时的 dmesg 输出示例:
# ==================================================================
# BUG: KFENCE: use-after-free in xxx+0xYY/0xZZ
# ==================================================================

注意:需要内核开启 CONFIG_KFENCE=y

11.3 kmemleak (内核内存泄漏检测)

需要在 bootargs 中添加启用:

bash 复制代码
# 启动参数启用
kmemleak=on

# 运行时触发扫描
echo scan > /sys/kernel/debug/kmemleak

# 查看泄漏报告
cat /sys/kernel/debug/kmemleak

# 启动时禁用(如果编译了但不想用)
# kmemleak=off

注意:需要内核开启 CONFIG_DEBUG_KMEMLEAK=y

11.4 slab 调试

bash 复制代码
# 查看 slab 分配器信息(无需额外内核选项)
root@board:~# cat /proc/slabinfo | head -8
slabinfo - version: 2.1
# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables ...
ext4_groupinfo_4k     56     56    144   28    1 : tunables    0    0    0 : slabdata      2      2      0
#                   ^^   ^^    ^^^    ^^    ^
#                   |    |     |     |     +-- 每个slab占用页数(1页=4KB)
#                   |    |     |     +-- 每个slab中对象数(28个)
#                   |    |     +-- 每个对象大小(144字节)
#                   |    +-- 已分配的对象数(56个)
#                   +-- 活跃对象数(56个,都在用)
btrfs_path             0      0    112   36    1 : tunables    0    0    0 : slabdata      0      0      0
#         ^             ^     ^     ^
#         |             |     |     +-- 对象大小(112字节)
#         |             |     +-- 预留对象数
#         |             +-- 活跃对象数(0表示无btrfs活动)
#         +-- slab缓存名称(按用途命名)

# 查看 slab 缓存使用详情
root@board:~# cat /sys/kernel/slab/kmalloc-128/alloc_calls 2>/dev/null | head -5

# 启动参数启用 slab 检查
# slab_debug=zp   (z=poison对象, p=追踪alloc/free)

12. RCU 调试与测试

RCU(Read-Copy-Update)是内核的核心同步机制,以下参数用于调试RCU相关问题。

12.1 RCU CPU Stall 检测

bash 复制代码
# 查看当前RCU stall超时设置
# 注意:当前内核未导出此 sysctl
root@board:~# cat /proc/sys/kernel/rcu_cpu_stall_timeout
cat: /proc/sys/kernel/rcu_cpu_stall_timeout: No such file or directory

# 通过内核启动参数设置
# rcupdate.rcu_cpu_stall_timeout=30   # 30秒超时

# 抑制RCU stall告警
# rcupdate.rcu_cpu_stall_suppress=1

# 发生RCU stall时dump ftrace
# rcupdate.rcu_cpu_stall_ftrace_dump=1

12.2 RCU 相关内核参数 (bootargs)

bash 复制代码
# 将CPU7的RCU回调卸载到其他CPU(减少隔离核抖动)
rcu_nocbs=7

# 设置RCU kthread优先级
# rcutree.kthread_prio=1   # SCHED_FIFO 优先级1

# 强制使用expedited RCU(减少延迟)
# rcupdate.rcu_expedited=1

# 启动RCU自检
# rcupdate.rcu_self_test=1

12.3 在 /proc 中查看RCU状态

bash 复制代码
root@board:~# cat /proc/stat | grep -E 'cpu.*'
# CPU时间中的softirq包含了RCU处理时间

root@board:~# cat /proc/softirqs
# RCU软中断在每个CPU上的分布

13. 内核启动参数调试

以下启动参数可在 U-Boot 的 bootargs 中使用,用于调试内核启动问题。

13.1 跟踪启动过程

bash 复制代码
# 显示所有initcall执行过程
initcall_debug

# 只跟踪特定函数(需FTRACE支持)
ftrace=function
ftrace_filter="initcall*"

# 启动时分配ftrace快照缓冲区(可在启动完成后读取snapshot)
alloc_snapshot

# 启用特定trace event
trace_event=sched:sched_switch,irq:irq_handler_entry

# 禁用KASLR(便于地址关联调试信息)
nokaslr

# 忽略日志级别(显示所有日志)
ignore_loglevel

13.2 调试特定子系统

bash 复制代码
# ACPI调试
acpi.debug_layer=0xffffffff acpi.debug_level=0xffffffff

# 调度器调试
sched_verbose

# 内存初始化调试
mminit_loglevel=4

# DMA API调试
dma_debug=on

# 中断调试
# irqhandler.duration_warn_us=1000   # IRQ处理超过1000us时告警

13.3 内核崩溃/Oops 调试

bash 复制代码
# 在Oops时panic
oops=panic

# WARN()时panic
panic_on_warn=1

# panic时打印所有任务信息
panic_print=0x7f    # 打印任务/内存/定时器/锁/ftrace等信息

# panic后自动重启
panic=10            # 10秒后重启

# 崩溃时自动dump ftrace缓冲区
ftrace_dump_on_oops=1

# 禁用哈希指针(显示真实地址)
no_hash_pointers

13.4 TL3588 常用调试 bootargs 组合

bash 复制代码
# 轻度调试:只增加启动跟踪
bootargs=... initcall_debug ignore_loglevel

# 中度调试:增加ftrace和panic后重启
bootargs=... initcall_debug ignore_loglevel ftrace_dump_on_oops panic=10

# 重度调试:全部开启
bootargs=... initcall_debug ignore_loglevel ftrace_dump_on_oops panic=10 nokaslr no_hash_pointers panic_on_warn=1 oops=panic

# 检查当前cmdline中是否包含调试参数
dmesg | grep "command line"

14. taskset CPU 亲和性

将进程绑定到指定 CPU 运行。

7.1 启动时绑定

bash 复制代码
# 将进程绑定到 CPU7
taskset -c 7 /usr/local/bin/cyclictest -p 99 -m -a 7 -t 1 -D 60s

# 将 stress 绑定到 CPU0-6
taskset -c 0-6 /usr/local/bin/stress-ng --cpu 7 --io 7 --timeout 30s

7.2 运行时绑定

bash 复制代码
# 查看进程当前 CPU 亲和性
taskset -pc <PID>

# 运行时修改
taskset -pc 0-6 <PID>

7.3 实际测试场景

这是 cache-color 项目中 cyclictest 的标准用法:

bash 复制代码
# 隔离核 CPU7 运行 cyclictest,主线程绑定到 0-6
taskset -c 7 /usr/local/bin/cyclictest -p 99 -m -q -a 7 --mainaffinity=0-6 -t 1 -i 200 -D 60

# housekeeping CPU 0-6 运行压力
taskset -c 0-6 /usr/local/bin/stress-ng --cpu 7 --io 7 --vm 7 --vm-bytes 80% --hdd 7 --hdd-bytes 512M --timeout 70s

15. chrt 实时调度策略

15.1 查看进程调度策略

bash 复制代码
root@board:~# chrt -p 1
pid 1's current scheduling policy: SCHED_OTHER
pid 1's current scheduling priority: 0

15.2 修改为 FIFO 实时调度

bash 复制代码
# 将 ksoftirqd/7 设为 SCHED_FIFO 优先级 1
root@board:~# chrt -f -p 1 $(pgrep -x 'ksoftirqd/7')

15.3 实际场景(rt_init.sh 中的用法)

bash 复制代码
# 提升隔离核关键内核线程到实时调度
for tname in "ksoftirqd/7" "rcuc/7" "irq_work/7"; do
  pid=$(pgrep -x "$tname" 2>/dev/null)
  [ -n "$pid" ] && chrt -f -p 1 $pid
done

16. cyclictest 实时延迟测试

cyclictest 是 RT 测试的核心工具,用于测量系统的调度延迟。

16.1 基本用法

bash 复制代码
# CPU7 上运行,周期 200us,持续 60 秒
root@board:~# /usr/local/bin/cyclictest -p 99 -m -q -a 7 --mainaffinity=0-6 -t 1 -i 200 -D 60s
T: 0 (  560) P:99 I:200 C: 300000 Min:      1 Act:    2 Avg:    2 Max:      97

输出字段T=线程编号, P=优先级, I=间隔(us), C=计数, Min/Act/Avg/Max=最小/当前/平均/最大延迟(us)

16.2 参数说明

参数 含义
-p 99 实时优先级 99 (最高)
-m 锁定内存 (mlockall)
-q 安静模式,只输出最终统计
-a 7 绑定到 CPU7
--mainaffinity=0-6 主线程绑定到 CPU0-6
-t 1 1 个测试线程
-i 200 间隔 200 微秒
-D 60s 持续 60 秒
-h 71 直方图桶数 71

17. stress-ng 压力测试

17.1 常用压力模式

bash 复制代码
# CPU 压力
stress-ng --cpu 7 --cpu-method matrixprod --timeout 30s

# 内存压力 (80%)
stress-ng --vm 7 --vm-bytes 80% --timeout 30s

# IO 压力
stress-ng --io 7 --hdd 7 --hdd-bytes 512M --timeout 30s

# 缓存抖动
stress-ng --cache 7 --timeout 30s

# 混合压力 (cache-color 项目标准配置)
stress-ng --cpu 7 --io 7 --vm 7 --vm-bytes 80% --hdd 7 --hdd-bytes 512M

17.2 配合隔离核使用

bash 复制代码
# 压力运行在 housekeeping CPU,隔离核不受影响
taskset -c 0-6 /usr/local/bin/stress-ng --cpu 7 --io 7 --vm 7 --vm-bytes 80% --hdd 7 --hdd-bytes 512M --timeout 70s

18. fw_printenv/fw_setenv U-Boot 环境变量

18.1 查看环境变量

bash 复制代码
root@board:~# fw_printenv | head -10
arch=arm                    # CPU架构
baudrate=115200             # 串口波特率
board=evb_rk3588            # 板卡型号
board_name=evb_rk3588       # 板卡名称
boot_partition=bootA        # 启动分区(双分区切换)
boot_targets=mmc1 mmc0 nvme scsi usb pxe dhcp spi  # 启动设备搜索顺序
bootcmd=fboot               # U-Boot启动命令
bootdelay=0                 # 启动延迟(秒),0=不等待
cpu=armv8                   # CPU架构
fdt_addr_r=0x12000000       # 设备树(Device Tree)加载地址

18.2 查看和设置 bootargs (内核启动参数)

bash 复制代码
# 查看所有与 bootargs 相关的环境变量
root@board:~# fw_printenv | grep bootargs
bootargs_iso=earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=/dev/mmcblk0p5 rw rootwait nohz=on nohz_full=7 isolcpus=domain,managed_irq,7 rcu_nocbs=7 irqaffinity=0-6
bootargs_iso_color=earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=/dev/mmcblk0p5 rw rootwait nohz=on nohz_full=7 isolcpus=domain,managed_irq,7 rcu_nocbs=7 irqaffinity=0-6 cache_color_num_colors=8 cache_color_iso_cpu=7 cache_color_iso_color=1 cache_color_iso_count=1 cache_color_iso_strict=1
bootargs=earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=/dev/mmcblk0p5 rw rootwait nohz=on nohz_full=7 isolcpus=domain,managed_irq,7 rcu_nocbs=7 irqaffinity=0-6

# 设置新的 bootargs
root@board:~# fw_setenv bootargs "<新的启动参数>"

# 例如:启用 cache-color 隔离
root@board:~# fw_setenv bootargs "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=/dev/mmcblk0p5 rw rootwait nohz=on nohz_full=7 isolcpus=domain,managed_irq,7 rcu_nocbs=7 irqaffinity=0-6 cache_color_num_colors=8 cache_color_iso_cpu=7 cache_color_iso_color=1 cache_color_iso_count=1 cache_color_iso_strict=1"

设置 bootargs 后需要重启板子才能生效。


19. proc/sys 内核参数调优

实时优化常用的内核参数调整(来自 rt_init.sh):

19.1 内核调度参数 (查看当前值)

bash 复制代码
root@board:~# cat /proc/sys/kernel/timer_migration
0          # 0=禁用timer迁移到隔离核
root@board:~# cat /proc/sys/kernel/sched_rt_runtime_us
-1         # -1=无限制, RT进程可用100% CPU
root@board:~# cat /proc/sys/vm/swappiness
0          # 0=不主动使用swap
root@board:~# cat /proc/sys/kernel/sched_schedstats
0          # 0=禁用调度统计(减少开销)

19.2 中断亲和性

bash 复制代码
# 查看默认中断亲和性
root@board:~# cat /proc/irq/default_smp_affinity
7f         # 0x7f = CPU0-6

# 查看某个具体中断的亲和性
root@board:~# cat /proc/irq/11/smp_affinity
7f         # arch_timer 中断被限制在 CPU0-6

19.3 workqueue 绑定

bash 复制代码
# 查看当前 workqueue CPU 掩码
root@board:~# cat /sys/devices/virtual/workqueue/cpumask
7f         # 0x7f = CPU0-6, 不会在 CPU7 上运行

# 手动设置
echo "7f" > /sys/devices/virtual/workqueue/cpumask

19.4 VM 统计间隔

bash 复制代码
root@board:~# cat /proc/sys/vm/stat_interval
120        # 120秒更新一次vmstat
root@board:~# cat /proc/sys/vm/dirty_writeback_centisecs
1500       # 1500厘秒=15秒回写一次脏页
root@board:~# cat /proc/sys/kernel/perf_event_max_sample_rate
40000      # perf事件最大采样率

19.5 查看所有调度相关参数

bash 复制代码
root@board:~# ls /proc/sys/kernel/ | grep -E 'sched|timer|rt'
sched_cfs_bandwidth_slice_us
sched_child_runs_first
sched_deadline_period_max_us
sched_deadline_period_min_us
sched_domain
sched_energy_aware
sched_latency_ns
sched_migration_cost_ns
sched_min_granularity_ns
sched_nr_migrate
sched_rr_timeslice_ms
sched_rt_period_us
sched_rt_runtime_us
sched_schedstats
sched_tunable_scaling
sched_util_clamp_max
sched_util_clamp_min
sched_util_clamp_min_rt_default
sched_wakeup_granularity_ns
timer_migration

19.6 systemd 服务隔离

将系统服务限制到指定的 CPU 集合:

bash 复制代码
# 限制 system 和 user 服务到 housekeeping CPU
systemctl set-property --runtime system.slice AllowedCPUs="0-6"
systemctl set-property --runtime user.slice    AllowedCPUs="0-6"
systemctl set-property --runtime init.scope    AllowedCPUs="0-6"

# 对所有 service 单元逐一设置
for svc in $(systemctl list-units --type=service --all --no-legend --no-pager | awk '{print $1}'); do
  [ -n "$svc" ] && systemctl set-property --runtime "$svc" AllowedCPUs="0-6"
done

20. 自定义调试工具

20.1 l3-victim-chase --- LLC 命中率测量

在隔离核上运行,测量特定工作集大小的 LLC 命中率。

bash 复制代码
# 测量 384KB 工作集,步长 64B,持续 120 秒,锁定内存
root@board:~# /usr/local/bin/l3-victim-chase --size-bytes 393216 --duration 120 --stride 64 --mlock
size_bytes=393216
stride_bytes=64
duration_s=120
iterations=4879526255
checksum=...
参数 说明
--size-bytes 工作集大小 (字节),393216 = 384KB
--duration 测试持续时间 (秒)
--stride 访问步长 (字节),64B = 1 cache line
--mlock 锁定内存防止换出

20.2 l3-hk-aggressor --- LLC 压力生成

在 housekeeping CPU 上运行,产生缓存压力。

bash 复制代码
# 7 个线程,48MB 工作集,步长 128B,读写模式
root@board:~# /usr/local/bin/l3-hk-aggressor --threads 7 --size-bytes 50331648 --stride 128 --mode rw --timeout 130s
参数 说明
--threads 线程数
--size-bytes 工作集大小,50331648 = 48MB
--stride 访问步长
--mode read/rw/chase
--timeout 超时时间

21.5 缓存命中率计算公式

复制代码
cache-hit-pct   = (1 - cache-misses / cache-references) × 100%
llc-load-hit-pct = (1 - LLC-load-misses / LLC-loads) × 100%
相关推荐
風清掦1 小时前
【STM32学习笔记-15】FLASH 闪存(Claude)
笔记·stm32·单片机·嵌入式硬件·学习
我想我不够好。1 小时前
贝利亚 扎克
学习
墨痕诉清风2 小时前
Linux系统设置上海时间(24小时制)
linux·运维·服务器
MartinYeung52 小时前
[论文学习]CAMIA:基于上下文感知的成员资格推断攻击:针对预训练大型语言模型的深度分析
人工智能·学习·语言模型
utf8mb4安全女神2 小时前
脚本模块化
linux·运维·服务器
daad7772 小时前
纪录无人机PID参数配置
linux
chase。2 小时前
【学习笔记】Unified World Models:基于视频-动作耦合扩散的机器人预训练新范式
笔记·学习·音视频
noipp2 小时前
推荐题目:洛谷 P1737 [NOI2016] 旷野大计算
linux·数据结构·算法
枕星而眠2 小时前
Linux守护进程完全指南:从原理到实战
linux·运维·服务器·c++·后端