系统工具

Linux 系统工具功能与底层实现

目录


1. 进程与线程调试工具

1.1 gdb

功能:GNU 调试器,支持断点、单步、变量查看、内存检查、远程调试等。

底层实现

gdb 的核心机制是 ptrace 系统调用:

gdb 启动调试目标:
  fork() → 子进程调用 ptrace(PTRACE_TRACEME) → exec() 加载目标程序
  父进程(gdb)通过 ptrace 控制子进程

gdb 附加到已有进程:
  ptrace(PTRACE_ATTACH, pid) → 目标进程收到 SIGSTOP 暂停

关键 ptrace 操作:

┌──────────────────────────┬───────────────────────────────────────┐
│ ptrace 请求               │ 作用                                   │
├──────────────────────────┼───────────────────────────────────────┤
│ PTRACE_TRACEME           │ 标记自己被追踪(子进程调用)             │
│ PTRACE_ATTACH            │ 附加到指定进程                          │
│ PTRACE_CONT              │ 让被追踪进程继续执行                    │
│ PTRACE_SINGLESTEP        │ 单步执行一条指令                        │
│ PTRACE_PEEKTEXT/DATA     │ 读取目标进程内存                        │
│ PTRACE_POKETEXT/DATA     │ 写入目标进程内存                        │
│ PTRACE_GETREGS           │ 读取寄存器                              │
│ PTRACE_SETREGS           │ 写入寄存器                              │
│ PTRACE_SET_SYSCALL       │ 修改系统调用号                          │
└──────────────────────────┴───────────────────────────────────────┘

断点实现

软件断点:
  1. gdb 读取目标地址的原始指令字节,保存到内部表
  2. 将目标地址的第一个字节替换为 INT 3(0xCC)
  3. 进程执行到 INT 3 → 触发 SIGTRAP → gdb 收到信号
  4. gdb 恢复原始指令字节,回退 PC,等待用户命令

硬件断点:
  1. 使用 CPU 的调试寄存器(DR0-DR3 存地址,DR7 存控制位)
  2. CPU 执行到对应地址时自动触发调试异常
  3. 最多 4 个硬件断点(DR0-DR3)
  4. 优势:不修改代码段,可用于 ROM/只读内存

单步实现

指令级单步:
  设置 EFLAGS 的 TF(Trap Flag)位 → CPU 每执行一条指令后触发调试异常

源码级单步:
  gdb 内部计算下一行源码对应的地址,在该地址设临时断点,然后 CONT
  如果下一行有函数调用,step-into 会在函数入口设断点,step-over 会在返回点设断点

1.2 gcore

功能:在不停止进程的情况下生成 core dump 文件。

底层实现

gcore 的执行流程:

1. ptrace(PTRACE_ATTACH, pid)
   → 目标进程暂停(发送 SIGSTOP)

2. 读取进程状态
   → /proc/pid/maps  → 内存映射布局
   → /proc/pid/stat  → 进程状态信息
   → ptrace(PTRACE_GETREGS) → 寄存器

3. 生成 ELF core 文件
   → 写入 ELF Header(类型 ET_CORE)
   → 写入 Program Headers(每个内存段一个 LOAD 段)
   → 遍历 /proc/pid/maps 中的每个内存区域
   → 通过 ptrace(PTRACE_PEEKDATA) 或 /proc/pid/mem 读取内存内容
   → 写入 Note 段(寄存器、信号、文件描述符等辅助信息)

4. ptrace(PTRACE_DETACH, pid)
   → 目标进程恢复执行

ELF Core 文件结构

┌──────────────────────────────┐
│ ELF Header (ET_CORE)         │
├──────────────────────────────┤
│ Program Headers              │
│  ├─ NOTE segment (prstatus)  │  ← 寄存器、信号信息
│  ├─ NOTE segment (prpsinfo)  │  ← 进程信息
│  ├─ NOTE segment (auxv)      │  ← 辅助向量
│  ├─ LOAD segment (代码段)     │  ← 对应 /proc/pid/maps 中的可读段
│  ├─ LOAD segment (数据段)     │
│  ├─ LOAD segment (堆)        │
│  ├─ LOAD segment (栈)        │
│  └─ ...                      │
├──────────────────────────────┤
│ Note Data                    │
├──────────────────────────────┤
│ Memory Segments Data         │  ← 实际内存内容
└──────────────────────────────┘

与 gdb 配合

# 生成 core dump
gcore <pid>

# 事后分析
gdb ./executable core.<pid>

1.3 pstack

功能:打印进程的线程调用栈。

底层实现

pstack 的执行流程:

1. ptrace(PTRACE_ATTACH, pid) → 暂停目标进程
2. 读取 /proc/pid/task/ 获取所有线程 tid
3. 对每个线程:
   a. ptrace(PTRACE_GETREGS) → 获取 PC、SP、FP 等寄存器
   b. 从 FP 开始,沿栈帧链回溯:
      当前 FP → [上一级 FP, 返回地址]
      读取下一级 FP → [再上一级 FP, 返回地址]
      ... 直到 FP 为 0 或无效
   c. 查找 ELF 的 .eh_frame / .debug_frame 段获取 DWARF unwind 信息
      (如果可用,DWARF 信息比 FP 链更准确)
   d. 通过返回地址查 ELF 符号表(.symtab / .dynsym)得到函数名
4. ptrace(PTRACE_DETACH, pid) → 恢复目标进程

栈回溯的两种方式

方式一:帧指针链(Frame Pointer Chaining)

  栈布局(x86-64):
  ┌──────────────┐ ← 高地址
  │ ...          │
  │ arg n        │
  │ arg 1        │
  │ return addr  │  ← 调用者返回地址
  │ saved RBP    │  ← 指向调用者的栈帧
  ├──────────────┤ ← 当前 RBP
  │ local var 1  │
  │ local var 2  │
  ├──────────────┤ ← 当前 RSP
  │ ...          │
  └──────────────┘ ← 低地址

  回溯:RBP → [saved_RBP, ret_addr] → saved_RBP → [saved_RBP', ret_addr'] → ...

方式二:DWARF Unwind Info(-fomit-frame-pointer 编译时)

  .eh_frame 段记录了每个 PC 范围内的栈回溯规则:
  → 如何恢复上一级的 CFA(Canonical Frame Address)
  → 各个寄存器保存在栈的哪个偏移
  → 基于当前 PC 查表,按规则计算上一级栈帧位置

1.4 strace

功能:追踪进程的系统调用和信号。

底层实现

strace 的核心机制:ptrace + PTRACE_SYSCALL

执行流程:
1. ptrace(PTRACE_ATTACH, pid) 或 fork + PTRACE_TRACEME
2. ptrace(PTRACE_SYSCALL, pid) → 让进程继续运行直到下一个系统调用
3. 进程进入内核(syscall entry)→ 触发 SIGTRAP → strace 被通知
4. strace 读取寄存器获取系统调用号和参数
   → x86-64: RAX=系统调用号, RDI/RSI/RDX/R10/R8/R9=参数
5. ptrace(PTRACE_SYSCALL, pid) → 继续运行
6. 进程从内核返回(syscall exit)→ 再次触发 SIGTRAP
7. strace 读取 RAX 获取返回值
8. 重复 2-7

每个系统调用被拦截两次:entry 和 exit

开销来源

每次系统调用:
  1. 进程暂停(SIGTRAP)
  2. 上下文切换到 strace
  3. strace 通过 ptrace 读取寄存器
  4. 上下文切换回目标进程

开销:每个系统调用增加约 5-20μs
对频繁系统调用的程序,strace 可导致 10-100x 性能下降

新内核的替代方案

seccomp-bpf 过滤:
  → 不需要 ptrace,在内核中用 BPF 程序过滤系统调用
  → 开销极低,但只能过滤不能读取参数

perf trace:
  → 基于 tracepoint 而非 ptrace
  → 开销更低,但信息不如 strace 完整

2. 系统级监控工具

2.1 top

功能:实时显示系统中各进程的 CPU、内存使用情况。

底层实现

top 的数据来源全部来自 /proc 文件系统:

┌─────────────────────┬──────────────────────────────────────────┐
│ 数据                 │ 来源                                     │
├─────────────────────┼──────────────────────────────────────────┤
│ CPU 整体使用率       │ /proc/stat                               │
│                     │ user, nice, system, idle, iowait,        │
│                     │ irq, softirq, steal, guest               │
├─────────────────────┼──────────────────────────────────────────┤
│ 内存使用             │ /proc/meminfo                            │
│                     │ MemTotal, MemFree, Buffers, Cached,      │
│                     │ Slab, SReclaimable                       │
├─────────────────────┼──────────────────────────────────────────┤
│ 交换分区             │ /proc/meminfo                            │
│                     │ SwapTotal, SwapFree                      │
├─────────────────────┼──────────────────────────────────────────┤
│ 进程信息             │ /proc/[pid]/stat                         │
│                     │ pid, state, utime, stime, rss, ...       │
├─────────────────────┼──────────────────────────────────────────┤
│ 进程命令行           │ /proc/[pid]/cmdline                      │
├─────────────────────┼──────────────────────────────────────────┤
│ 进程内存映射         │ /proc/[pid]/statm                        │
└─────────────────────┴──────────────────────────────────────────┘

CPU 使用率计算

/proc/stat 格式:
cpu  user nice system idle iowait irq softirq steal guest

两次采样间:
  d_user   = user[t2] - user[t1]
  d_nice   = nice[t2] - nice[t1]
  d_system = system[t2] - system[t1]
  d_idle   = idle[t2] - idle[t1]
  d_total  = d_user + d_nice + d_system + d_idle + d_iowait + ...

  CPU% = (d_total - d_idle) / d_total * 100

进程 CPU%:
  /proc/[pid]/stat 中的 utime + stime(单位:clock ticks)
  进程CPU% = (d_utime + d_stime) / (d_total / ncpu) / interval

进程状态

/proc/[pid]/stat 第 3 个字段:

R  Running       → 正在运行或就绪等待 CPU
S  Sleeping      → 可中断睡眠(等待事件)
D  Disk Sleep    → 不可中断睡眠(通常是 I/O 等待)
Z  Zombie        → 已退出但父进程未 wait
T  Stopped       → 被信号停止
t  Tracing Stop  → 被追踪器停止
X  Dead          → 已死亡(不应看到)

2.2 htop

功能:top 的增强版,支持鼠标、树状视图、快捷杀进程等。

底层实现

与 top 相同的数据来源(/proc),差异在于:

1. 使用 ncurses 库实现交互式 TUI
2. 读取 /proc/[pid]/io 获取 I/O 信息(top 不显示)
3. 读取 /proc/[pid]/fd 统计打开的文件描述符数
4. 通过 libc 的 getpwuid() / getgrgid() 解析用户名/组名
5. 杀进程:kill(pid, signal) 系统调用
6. CPU 栏的彩色分段:
   → 蓝色 = low-priority (nice > 0)
   → 绿色 = normal (user)
   → 红色 = kernel (system)
   → 青色 = steal (虚拟化环境被其他 VM 偷走的时间)
   → 品红 = IRQ / soft IRQ

2.3 uptime

功能:显示系统运行时间、登录用户数、1/5/15 分钟平均负载。

底层实现

数据来源:

运行时间:/proc/uptime
  第一个字段:系统启动后的秒数(含小数)
  第二个字段:系统空闲的累计秒数

平均负载:/proc/loadavg
  前三个数字:1分钟、5分钟、15分钟平均负载
  第四个数字:当前运行进程数 / 总进程数
  第五个数字:最近创建的进程 PID

平均负载的含义:
  load average = 运行队列中的进程数 + 不可中断睡眠(D状态)的进程数
  → 包含 CPU 等待 + I/O 等待
  → 单核:1.0 表示满载;4核:4.0 表示满载
  → 计算方式:指数衰减移动平均
    load1  = load1 * exp(-1/60)  + n * (1 - exp(-1/60))
    load5  = load5 * exp(-1/300) + n * (1 - exp(-1/300))
    load15 = load15 * exp(-1/900) + n * (1 - exp(-1/900))
    其中 n = 当前运行队列 + D状态进程数

3. 进程级监控工具

3.1 pidstat

功能:按进程显示 CPU、内存、I/O、线程、上下文切换等统计。

底层实现

pidstat 是 sysstat 套件的一部分,数据来源:

┌──────────────────┬──────────────────────────────────────────────┐
│ 选项              │ 数据来源                                     │
├──────────────────┼──────────────────────────────────────────────┤
│ 默认(CPU统计)   │ /proc/[pid]/stat                            │
│                  │ utime, stime, cutime, cstime, processor      │
├──────────────────┼──────────────────────────────────────────────┤
│ -r(内存统计)    │ /proc/[pid]/statm + /proc/[pid]/status      │
│                  │ VSS, RSS, %MEM, minflt, majflt              │
├──────────────────┼──────────────────────────────────────────────┤
│ -d(I/O统计)    │ /proc/[pid]/io                              │
│                  │ read_bytes, write_bytes, cancelled_write_bytes│
├──────────────────┼──────────────────────────────────────────────┤
│ -w(上下文切换)  │ /proc/[pid]/status                          │
│                  │ voluntary_ctxt_switches, nonvoluntary_ctxt... │
├──────────────────┼──────────────────────────────────────────────┤
│ -t(线程统计)    │ /proc/[pid]/task/[tid]/stat                 │
└──────────────────┴──────────────────────────────────────────────┘

/proc/[pid]/io 的内核实现

内核为每个 task_struct 维护 I/O 计数器:

struct task_struct {
    ...
    u64 acct_rss_mem1;       // RSS 增量
    u64 acct_vm_mem1;        // 虚拟内存增量
    u64 acct_timexpd;        // I/O 等待时间
    ...
};

struct io_accounting {
    u64 rchar;               // 读字节数(含缓存命中)
    u64 wchar;               // 写字节数(含缓存命中)
    u64 syscr;               // 读系统调用次数
    u64 syscw;               // 写系统调用次数
    u64 read_bytes;          // 实际从块设备读取的字节数
    u64 write_bytes;         // 实际写入块设备的字节数
    u64 cancelled_write_bytes; // 取消写入的字节数
};

read_bytes 在以下时机递增:
  → submit_bio() 提交读请求时
  → 仅统计实际到达块设备的 I/O,不包含页缓存命中

write_bytes 在以下时机递增:
  → 页面被标记为脏页时(mark_buffer_dirty())
  → 或直接 I/O 提交时

3.2 mpstat

功能:按 CPU 核心显示统计信息。

底层实现

数据来源:/proc/stat

逐行解析:
cpu  : user nice system idle iowait irq softirq steal guest guest_nice
cpu0 : ...
cpu1 : ...
cpuN : ...

mpstat 读取两次 /proc/stat,计算差值得到各核的使用率

关键指标计算:
  %usr    = d_user / d_total * 100
  %sys    = d_system / d_total * 100
  %iowait = d_iowait / d_total * 100
  %irq    = d_irq / d_total * 100
  %soft   = d_softirq / d_total * 100
  %steal  = d_steal / d_total * 100
  %idle   = d_idle / d_total * 100

内核更新 /proc/stat 的时机:
  每次 tick(通常 1ms,CONFIG_HZ=1000)中断时
  account_process_tick() → 更新当前进程的 utime/stime
  account_idle_ticks()  → 更新全局 idle 计数

4. I/O 与存储工具

4.1 iostat

功能:显示 CPU 使用率和磁盘 I/O 统计。

底层实现

CPU 统计:/proc/stat(同 top/mpstat)

磁盘 I/O 统计:/proc/diskstats 或 /sys/block/<dev>/stat

/proc/diskstats 格式(每个设备一行):
  Field 1: 主设备号
  Field 2: 次设备号
  Field 3: 设备名
  Field 4: 读完成次数
  Field 5: 读合并次数
  Field 6: 读扇区数
  Field 7: 读花费时间(ms)
  Field 8: 写完成次数
  Field 9: 写合并次数
  Field 10: 写扇区数
  Field 11: 写花费时间(ms)
  Field 12: 正在进行的 I/O 数
  Field 13: I/O 总花费时间(ms)
  Field 14: 加权 I/O 时间(ms)

关键指标计算

两次采样间:

  tps       = (d_reads + d_writes) / interval
              每秒传输次数(含合并后的)

  kB_read/s = d_sectors_read * 512 / 1024 / interval
  kB_wrtn/s = d_sectors_written * 512 / 1024 / interval

  await     = (d_read_ms + d_write_ms) / (d_reads + d_writes)
              平均 I/O 响应时间(ms),含排队时间

  svctm     = d_io_time / (d_reads + d_writes)
              平均服务时间(ms),不含排队

  %util    = d_io_time / (interval * 1000) * 100
              设备利用率(>80% 通常表示饱和)

  aqu-sz   = d_weighted_io_time / (interval * 1000)
              平均队列深度

内核如何收集 diskstats

内核 I/O 栈中的统计点:

  应用层 → VFS → 块层 → 设备驱动

  块层(block layer)关键函数:
  → blk_account_io_start()  : I/O 开始,递增 in_flight,记录开始时间
  → blk_account_io_completion() : I/O 完成,更新完成次数、扇区数、耗时

  每个 request_queue 维护统计计数器:
  struct request_queue {
      struct disk_stats stats;
      ...
  };

  /proc/diskstats 由 diskstats_show() 函数生成
  → 遍历所有块设备的 request_queue
  → 读取 stats 计数器

4.2 iotop

功能:按进程显示实时磁盘 I/O 使用率。

底层实现

iotop 使用两种机制获取数据:

机制一:/proc/[pid]/io(I/O 字节数)
  → read_bytes, write_bytes(实际块设备 I/O)
  → 两次采样差值计算速率

机制二:/proc/task/[tid]/io(线程级 I/O)
  → 遍历 /proc/[pid]/task/ 获取每个线程的 I/O

I/O 百分比计算:
  → 内核通过 taskstats 接口提供延迟统计
  → netlink 接口:TASKSTATS_CMD_GET
  → 返回 struct taskstats 中的 delay accounting 数据
    .blkio_delay_total    : 等待块 I/O 的累计时间(纳秒)
    .swapin_delay_total   : 等待换入的累计时间(纳秒)

  I/O% = d_blkio_delay / interval / ncpu * 100
  Swap% = d_swapin_delay / interval / ncpu * 100

taskstats 的内核实现

内核延迟统计(Delay Accounting):

  在以下节点记录时间戳:
  → schedule() 切换到进程时:记开始时间
  → 从 I/O 等待唤醒时:记结束时间,累加到 blkio_delay_total
  → 页面换入完成时:累加到 swapin_delay_total

  通过 netlink 接口导出:
  → 用户空间发送 TASKSTATS_CMD_GET + pid
  → 内核填充 struct taskstats 返回
  → iotop 解析 blkio_delay_total 计算百分比

注意:需要内核编译时开启 CONFIG_TASK_DELAY_ACCT=y
      否则 iotop 无法显示 I/O 百分比

4.3 blktrace

功能:追踪块层 I/O 事件的详细过程,配合 blkparse 分析。

底层实现

blktrace 的架构:

  内核模块(blktrace.ko)→ 在块层关键点插入 tracepoint
  用户空间(blktrace 命令)→ 通过 relayfs 读取 trace 数据

内核侧 tracepoint:

  块层 I/O 路径:
  应用 → VFS → __generic_file_aio_write / generic_file_read
       → 块层 submit_bio → 请求调度 → 设备驱动 → 中断完成

  blktrace 捕获的事件:
  ┌──────────┬──────────────────────────────────────────┐
  │ 事件标识  │ 含义                                      │
  ├──────────┼──────────────────────────────────────────┤
  │ Q (Queue)│ I/O 请求进入块层(submit_bio)             │
  │ G (Get)  │ 请求从调度器获取                           │
  │ I (Issue)│ 请求发送给设备驱动                         │
  │ D (Done) │ 设备完成 I/O(中断处理)                   │
  │ C (Comp) │ 请求完成回调                               │
  │ M (Merge)│ 请求被合并                                 │
  │ P (Plug) │ 队列被插入(蓄流)                         │
  │ U (Unplug)│ 队列被拔出(发送蓄积的请求)              │
  │ S (Sleep)│ 等待 I/O 完成                              │
  │ R (Remap)│ 请求被映射到其他设备(DM/MD)              │
  └──────────┴──────────────────────────────────────────┘

数据传输机制

relayfs(relay filesystem):

  内核侧:
  1. blktrace 在块层注册 tracepoint 回调
  2. 回调函数将事件写入 per-CPU relay 缓冲区
     → 每个 CPU 一个独立的环形缓冲区
     → 无锁写入(per-CPU),零拷贝

  用户空间侧:
  1. blktrace 打开 /sys/kernel/debug/block/<dev>/trace
  2. 通过 relayfs 读取每个 CPU 的缓冲区
  3. 写入磁盘文件(<dev>.blktrace.<cpu>)
  4. blkparse 解析二进制数据输出可读格式

blkparse 输出示例

8,0    3     1171    0.000000000  1171  Q  WS 3492848 + 8 [kworker]
8,0    3     1171    0.000001234  1171  G  WS 3492848 + 8 [kworker]
8,0    3     1171    0.000002345  1171  I  WS 3492848 + 8 [kworker]
8,0    3     1171    0.000543210  1171  D  WS 3492848 + 8 [kworker]
8,0    3     1171    0.000654321  1171  C  WS 3492848 + 8 [0]

字段含义:
  8,0        → 主:次设备号
  3          → CPU 编号
  1171       → 序列号
  0.000...   → 时间戳(秒)
  1171       → 进程 PID
  Q/G/I/D/C  → 事件类型
  WS         → 写同步(Write Sync)
  3492848 + 8 → 起始扇区 + 扇区数
  [kworker]  → 进程名
  [0]        → 完成时的错误码

I/O 延迟分析

Q → I:排队延迟(scheduler latency)
I → D:设备服务时间(device service time)
Q → C:端到端 I/O 延迟(total latency)

blkparse -w 10 -d /dev/sda 输出统计:
  → 按事件类型汇总平均延迟
  → 识别 I/O 调度器瓶颈(Q→I 过长)vs 设备瓶颈(I→D 过长)

4.4 dstat

功能:综合系统资源统计工具,替代 vmstat/iostat/ifstat 等。

底层实现

dstat 的数据来源汇总:

┌──────────────────┬──────────────────────────────────────┐
│ 插件              │ 数据来源                              │
├──────────────────┼──────────────────────────────────────┤
│ cpu               │ /proc/stat                           │
│ cpu-adv           │ /proc/stat(含 steal/guest)         │
│ disk              │ /proc/diskstats                      │
│ net               │ /proc/net/dev                        │
│ page              │ /proc/vmstat                         │
│ swap              │ /proc/vmstat                         │
│ sys               │ /proc/stat + /proc/interrupts        │
│ proc              │ /proc/stat(进程创建数)              │
│ mem               │ /proc/meminfo                        │
│ vm                │ /proc/vmstat                         │
│ inode             │ /proc/sys/fs/inode-state             │
│ socket            │ /proc/net/sockstat                   │
│ tcp               │ /proc/net/snmp                       │
│ udp               │ /proc/net/snmp                       │
│ unix              │ /proc/net/unix                       │
│ ipc               │ ipcs 命令输出                        │
│ top-cpu           │ /proc/[pid]/stat                     │
│ top-bio           │ /proc/[pid]/io                       │
│ top-io            │ /proc/[pid]/io                       │
│ top-oom           │ /proc/[pid]/oom_score                │
│ latency           │ /proc/interrupts + 计算中断延迟       │
└──────────────────┴──────────────────────────────────────┘

dstat 的核心循环:
  1. 读取所有启用的插件的数据源
  2. 计算与上一次采样的差值
  3. 格式化输出一行
  4. sleep(delay) → 默认 1 秒
  5. 重复

5. 网络工具

5.1 sar

功能:System Activity Reporter,sysstat 套件核心工具,采集和报告系统活动。

底层实现

sar 的工作架构:

  1. 后台守护进程 sadc(System Activity Data Collector)
     → 定期(默认 10 分钟)采集数据写入 /var/log/sa/saDD
     → 由 cron 任务 /etc/cron.d/sysstat 触发
     → 数据源同 dstat(全部来自 /proc)

  2. sar 命令读取二进制日志文件并格式化输出
     → sar -u  → CPU
     → sar -r  → 内存
     → sar -b  → I/O
     → sar -n DEV → 网络
     → sar -W  → 交换
     → sar -q  → 队列长度和平均负载
     → sar -w  → 上下文切换
     → sar -x  → 指定进程

sadc 内核数据采集路径:
  → 打开 /proc/stat, /proc/vmstat, /proc/diskstats, /proc/net/dev 等
  → 读取计数器快照
  → 写入二进制格式的日志文件
  → 文件格式:struct sa_file_header + sa_record 数组

5.2 nicstat

功能:网卡流量统计,显示每秒读写字节数、包数、利用率。

底层实现

数据来源:/proc/net/dev

格式:
Inter-|   Receive                                       |  Transmit
 face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
  eth0: 12345  200    0    0    0     0       0          0  54321  150    0    0    0     0       0          0

利用率计算:
  %util = (d_bytes / interval) / interface_speed * 100
  → 对全双工网卡,分别计算读/写利用率
  → 需要知道网卡速率(从 /sys/class/net/<dev>/speed 读取,单位 Mbps)

关键指标:
  rKB/s   : 每秒接收 KB
  wKB/s   : 每秒发送 KB
  rPk/s   : 每秒接收包数
  wPk/s   : 每秒发送包数
  rAvs    : 平均接收包大小(字节)
  wAvs    : 平均发送包大小(字节)
  %Util   : 网卡利用率
  Sat     : 饱和度(基于丢包/错误)

6. 内存工具

6.1 vmstat

功能:报告虚拟内存统计,包含进程、内存、交换、I/O、系统、CPU。

底层实现

数据来源:

┌──────────────┬────────────────────────────────────────────┐
│ vmstat 字段   │ 来源                                       │
├──────────────┼────────────────────────────────────────────┤
│ procs-r      │ /proc/stat 中的 running 进程数              │
│ procs-b      │ /proc/stat 中的 blocked (D state) 进程数   │
├──────────────┼────────────────────────────────────────────┤
│ memory-swpd  │ /proc/meminfo SwapUsed                     │
│ memory-free  │ /proc/meminfo MemFree                      │
│ memory-buff  │ /proc/meminfo Buffers                      │
│ memory-cache │ /proc/meminfo Cached                       │
├──────────────┼────────────────────────────────────────────┤
│ swap-si      │ /proc/vmstat pswpin(换入页数/s)           │
│ swap-so      │ /proc/vmstat pswpout(换出页数/s)          │
├──────────────┼────────────────────────────────────────────┤
│ io-bi        │ /proc/vmstat pgpgin(读入页数/s)           │
│ io-bo        │ /proc/vmstat pgpgout(写出页数/s)          │
├──────────────┼────────────────────────────────────────────┤
│ system-in    │ /proc/stat intr(中断数/s)                 │
│ system-cs    │ /proc/stat ctxt(上下文切换数/s)           │
├──────────────┼────────────────────────────────────────────┤
│ cpu-us/sy/id/wa/st │ /proc/stat 同 top                    │
└──────────────┴────────────────────────────────────────────┘

内核如何统计 pswpin/pswpout:
  → do_swap_page() 完成换入时递增 pswpin
  → shrink_page_list() 将页面写回交换区时递增 pswpout
  → 单位:页(通常 4KB)

6.2 free

功能:显示系统内存使用和交换分区使用。

底层实现

数据来源:/proc/meminfo

              total        used        free      shared  buff/cache   available
Mem:       16384000    8192000     2048000      512000     6144000     7168000
Swap:       4096000      512000     3584000

计算公式:
  total     = MemTotal
  free      = MemFree
  buff/cache= Buffers + Cached + SReclaimable
  shared    = Shmem(tmpfs + 共享内存段)
  available = MemAvailable(内核估算的可用于启动新进程的内存)
  used      = total - free - buff/cache

MemAvailable 的内核计算(mm/page_alloc.c: si_mem_available()):
  → 可用内存 = Free + PageCache - 不可回收部分 + 可回收 slab
  → 考虑了水位线(watermark)限制
  → 比 free 更准确反映"实际可用"内存

6.3 pmap

功能:显示进程的内存映射详情。

底层实现

数据来源:/proc/[pid]/maps + /proc/[pid]/smaps

/proc/[pid]/maps 格式:
  地址范围           权限  偏移     设备   inode  路径
  00400000-0040d000  r-xp  00000000 fd:00 12345  /usr/bin/ls
  0060c000-0060d000  r--p  0000c000 fd:00 12345  /usr/bin/ls
  0060d000-0060e000  rw-p  0000d000 fd:00 12345  /usr/bin/ls
  7f000000000-7f000200000 rw-p 00000000 00:00 0   [heap]
  7fff1234000-7fff1255000 rw-p 00000000 00:00 0   [stack]

/proc/[pid]/smaps 额外信息(每个映射区域):
  Size:                812 kB    ← 虚拟内存大小
  Rss:                 460 kB    ← 实际物理内存
  Pss:                 230 kB    ← 比例分摊(共享页按进程数均分)
  Shared_Clean:        200 kB    ← 共享的干净页
  Shared_Dirty:          0 kB    ← 共享的脏页
  Private_Clean:        60 kB    ← 私有的干净页
  Private_Dirty:       200 kB    ← 私有的脏页
  Referenced:          460 kB    ← 最近被访问的页
  Anonymous:           200 kB    ← 匿名页(无文件后端)
  AnonHugePages:       2048 kB   ← 透明大页
  Swap:                  0 kB    ← 被换出的页
  KernelPageSize:        4 kB    ← 内核页大小
  MMUPageSize:           4 kB    ← MMU 页大小
  Locked:                0 kB    ← mlock 锁定的页

pmap -x <pid> 读取 smaps 汇总输出
pmap -XX <pid> 显示最详细信息

7. 性能分析工具

7.1 perf

功能:Linux 性能分析框架,支持 CPU profiling、硬件计数器、tracepoint、kprobe 等。

底层实现

perf 的架构:

  用户空间:perf 命令
  内核空间:perf_event 子系统

  ┌───────────────────────────────────────────────────┐
  │                  perf 命令                         │
  │  stat / record / top / report / annotate          │
  └────────────────────┬──────────────────────────────┘
                       │ perf_event_open() 系统调用
  ┌────────────────────▼──────────────────────────────┐
  │              perf_event 子系统                      │
  │                                                    │
  │  ┌─────────────┐  ┌──────────────┐  ┌───────────┐ │
  │  │ 硬件计数器   │  │ tracepoint   │  │ kprobe/   │ │
  │  │ (PMC/MSR)   │  │ (ftrace)     │  │ uprobe    │ │
  │  └──────┬──────┘  └──────┬───────┘  └─────┬─────┘ │
  │         │                │                 │        │
  │         ▼                ▼                 ▼        │
  │  ┌──────────────────────────────────────────────┐  │
  │  │         perf_event_context                    │  │
  │  │  per-task 或 per-CPU 的事件上下文              │  │
  │  │  管理 PMC 寄存器分配、采样、溢出中断           │  │
  │  └──────────────────┬───────────────────────────┘  │
  │                     │                              │
  │  ┌──────────────────▼───────────────────────────┐  │
  │  │         ring buffer (mmap)                    │  │
  │  │  perf_mmap → 用户空间直接读取采样数据          │  │
  │  └──────────────────────────────────────────────┘  │
  └────────────────────────────────────────────────────┘

perf_event_open 系统调用

int perf_event_open(struct perf_event_attr *attr,
                    pid_t pid, int cpu, int group_fd, unsigned long flags);

参数含义:
  pid      : 监控的进程(-1 = 当前,0 = 所有)
  cpu      : 监控的 CPU 核心(-1 = 所有)
  group_fd : 事件组(-1 = 新组)
  attr     : 事件配置
    .type     : PERF_TYPE_HARDWARE/SOFTWARE/TRACEPOINT/HW_CACHE/RAW
    .config   : 具体事件编号
    .sample_period/freq : 采样周期/频率
    .mmap     : 是否记录 mmap 事件
    .task     : 是否记录 task 事件
    .precise_ip : 采样精度(0-3,越高越精确)

采样模式(perf record)的实现

1. 用户调用 perf_event_open() 创建事件
2. 内核配置 PMC 寄存器:
   → 写入 PERF_EVTSEL MSR(事件选择 + 配置)
   → 设置计数器初始值(2^48 - sample_period)
3. 进程运行,PMC 递增
4. PMC 溢出 → 触发 PMI(Performance Monitoring Interrupt)
5. PMI 处理程序(intel_pmu_handle_irq):
   a. 读取触发溢出的 PMC
   b. 采集样本:
      → IP(指令指针)
      → TID(线程 ID)
      → 时间戳
      → 调用栈(如果启用 -g,通过遍历栈帧或使用 DWARF)
   c. 写入 per-CPU ring buffer
   d. 重置计数器
6. 用户空间通过 mmap 读取 ring buffer
7. perf record 将样本写入 perf.data 文件

硬件计数器(PMC)的内核驱动

x86 架构:

  Intel CPU: intel_pmu 驱动
    → x86_pmu.enable  = intel_pmu_enable_event()  → 写 MSR
    → x86_pmu.disable = intel_pmu_disable_event()  → 写 MSR
    → x86_pmu.read   = intel_pmu_read_event()     → 读 MSR

  AMD CPU: amd_pmu 驱动
    → 类似结构,操作 AMD 的 PERF_CTL/PERF_CTR MSR

ARM 架构:
  → arm_pmu 驱动
  → 操作 PMU 系统寄存器(PMXEVTYPER_EL0, PMXEVCNTR_EL0)
  → 溢出中断由 PMU IRQ 处理

7.2 perf 常用子命令

┌──────────────────┬──────────────────────────────────────────┐
│ 子命令            │ 功能与底层实现                             │
├──────────────────┼──────────────────────────────────────────┤
│ perf stat        │ 计数模式:读取 PMC 差值,不采样            │
│                  → perf_event_open(COUNT_MODE)              │
│                  → ioctl(PERF_EVENT_IOC_ENABLE)             │
│                  → ioctl(PERF_EVENT_IOC_DISABLE)            │
│                  → read(fd) 读取计数器值                     │
├──────────────────┼──────────────────────────────────────────┤
│ perf record      │ 采样模式:PMC 溢出中断采集样本             │
│                  → perf_event_open(SAMPLE_MODE)             │
│                  → mmap() 映射 ring buffer                  │
│                  → PMC 溢出 → PMI → 写入 ring buffer        │
│                  → 用户空间 poll ring buffer 写入文件        │
├──────────────────┼──────────────────────────────────────────┤
│ perf top         │ 实时采样:类似 record 但实时显示热点       │
│                  → 采样机制同 record                         │
│                  → 每 2-3 秒刷新直方图                       │
├──────────────────┼──────────────────────────────────────────┤
│ perf annotate    │ 反汇编 + 样本分布标注                     │
│                  → 读取 perf.data 中的样本                   │
│                  → 解析 ELF 的 .text 段                      │
│                  → 用 objdump 反汇编                         │
│                  → 将样本数映射到每条指令                     │
├──────────────────┼──────────────────────────────────────────┤
│ perf trace       │ 追踪系统调用,类似 strace                 │
│                  → 基于 tracepoint 而非 ptrace               │
│                  → 开销远低于 strace                          │
└──────────────────┴──────────────────────────────────────────┘

8. 追踪工具

8.1 ftrace

功能:内核函数追踪框架,支持函数追踪、函数图谱、事件追踪等。

底层实现

ftrace 的架构:

  ┌───────────────────────────────────────────┐
  │              用户接口                       │
  │  /sys/kernel/debug/tracing/               │
  │    trace                                  │
  │    set_ftrace_filter                      │
  │    available_tracers                      │
  │    current_tracer                         │
  ├───────────────────────────────────────────┤
  │              追踪器                        │
  │  function   → 函数调用追踪                 │
  │  function_graph → 函数调用图谱              │
  │  wakeup     → 唤醒延迟追踪                 │
  │  irqsoff    → 中断关闭时间追踪             │
  │  preemptoff → 抢占关闭时间追踪             │
  ├───────────────────────────────────────────┤
  │              基础设施                      │
  │  mcount / __fentry__ → 编译器插入的钩子     │
  │  tracepoint → 静态插桩点                   │
  │  ring buffer → 追踪数据存储                │
  └───────────────────────────────────────────┘

函数追踪的编译时插桩

GCC 的 -pg 选项会在每个函数入口插入调用:

  x86:  call mcount      (旧版)
  x86:  call __fentry__  (新版,CONFIG_FUNCTION_TRACER)

原始代码:
  void my_func(void) {
      do_something();
  }

编译后:
  my_func:
      call __fentry__    ← 编译器自动插入
      ... (函数体)
      ret

未启用 ftrace 时:
  __fentry__ 的实现是简单的 ret 指令(1 条指令开销 ≈ 0)

启用 ftrace 时:
  内核将 __fentry__ 的入口替换为跳转到追踪处理函数
  → 使用 text_poke_bp() 修改内核代码段
  → 替换为 jmp ftrace_caller 或 call ftrace_caller

动态过滤

set_ftrace_filter 的实现:
  → 内核维护一个 ftrace_func_hash 哈希表
  → 写入函数名时,查找对应的符号地址
  → 将该地址对应的 ftrace_rec 标记为 enabled
  → ftrace_caller 执行时检查当前函数是否在 hash 中
  → 只追踪匹配的函数,减少开销

8.2 eBPF / bpftrace

功能:在内核中安全运行用户编写的程序,实现自定义追踪和监控。

底层实现

eBPF 的架构:

  ┌───────────────────────────────────────────────┐
  │              用户空间                           │
  │  bpftrace / BCC / libbpf                      │
  │    → 编写 eBPF 程序(类 C 语法)               │
  │    → 编译为 BPF 字节码                         │
  │    → bpf() 系统调用加载到内核                   │
  ├───────────────────────────────────────────────┤
  │              内核验证器                         │
  │  verifier.c                                    │
  │    → 确保程序安全(不会崩溃内核)               │
  │    → 检查:无无限循环、无越界访问、栈大小限制    │
  │    → 验证通过后 JIT 编译为本机指令              │
  ├───────────────────────────────────────────────┤
  │              挂载点                             │
  │  kprobe   → 内核函数入口/返回                   │
  │  tracepoint → 静态追踪点                       │
  │  perf_event → PMC 溢出                         │
  │  XDP      → 网卡收包路径                       │
  │  tc        → 流量控制                          │
  │  cgroup   → cgroup 事件                        │
  │  socket   → socket 操作                        │
  ├───────────────────────────────────────────────┤
  │              数据传递                           │
  │  BPF_MAP → 内核-用户空间共享数据结构            │
  │  perf_event → 采样数据传递                     │
  └───────────────────────────────────────────────┘

eBPF 程序的执行流程

1. 用户编写 eBPF 程序
   bpftrace -e 'kprobe:do_sys_open { @opens = count(); }'

2. 编译为 BPF 字节码
   → bpftrace 内部使用 LLVM 将脚本编译为 BPF 字节码

3. bpf(BPF_PROG_LOAD) 系统调用加载到内核

4. 内核验证器检查:
   → DAG 验证(无环)
   → 寄存器状态追踪(每个分支的所有可能值)
   → 内存访问边界检查
   → 最大指令数限制(1M 条)
   → 最大栈深度(512 字节)

5. JIT 编译为本机指令
   → bpf_int_jit_compile() 将 BPF 字节码翻译为 x86/ARM 机器码
   → 替换 BPF 指令为原生 CPU 指令
   → 性能接近原生内核代码

6. 挂载到 kprobe/tracepoint
   → 当 do_sys_open 被调用时,JIT 编译后的 BPF 程序执行
   → 更新 BPF_MAP 中的计数器

7. 用户空间通过 bpf(BPF_MAP_LOOKUP_ELEM) 读取结果

BPF Map 类型

┌──────────────────┬──────────────────────────────────────┐
│ Map 类型          │ 用途                                 │
├──────────────────┼──────────────────────────────────────┤
│ BPF_MAP_TYPE_HASH│ 通用哈希表                           │
│ BPF_MAP_TYPE_ARRAY│ 通用数组                             │
│ BPF_MAP_TYPE_PERF_EVENT_ARRAY │ per-CPU 事件缓冲区     │
│ BPF_MAP_TYPE_PERCPU_HASH │ per-CPU 哈希表(无锁)       │
│ BPF_MAP_TYPE_RINGBUF │ 可变大小环形缓冲区               │
│ BPF_MAP_TYPE_STACK_TRACE │ 调用栈追踪                  │
│ BPF_MAP_TYPE_LRU_HASH │ 带 LRU 淘汰的哈希表            │
└──────────────────┴──────────────────────────────────────┘

8.3 SystemTap

功能:内核动态追踪框架,用脚本语言编写探测点。

底层实现

SystemTap 的执行流程:

1. 用户编写 .stp 脚本
   probe syscall.open { printf("%s opened %s\n", execname(), user_string($filename)); }

2. stap 编译器将脚本翻译为 C 代码
   → 解析脚本语法
   → 生成内核模块的 C 源码
   → 插入 probe handler 函数

3. 调用 GCC 编译为内核模块(.ko)

4. insmod 加载内核模块
   → 注册 kprobe 探测点
   → kprobe 在目标函数入口插入断点(INT 3 或 ftrace 钩子)

5. 探测点触发时:
   → kprobe 回调执行 probe handler
   → handler 读取参数、收集数据
   → 数据写入 relayfs 缓冲区

6. 用户空间 stap 进程从 relayfs 读取并输出

7. Ctrl+C 时 rmmod 卸载模块

与 eBPF 的对比

┌──────────────┬──────────────────┬──────────────────┐
│              │ SystemTap        │ eBPF             │
├──────────────┼──────────────────┼──────────────────┤
│ 安全性       │ 需要加载 .ko     │ 验证器保证安全    │
│              │ 可能崩溃内核     │ 不会崩溃内核      │
├──────────────┼──────────────────┼──────────────────┤
│ 权限         │ root             │ root / CAP_BPF   │
├──────────────┼──────────────────┼──────────────────┤
│ 编译         │ GCC 编译 .ko     │ LLVM → BPF 字节码│
│              │ 需要内核头文件    │ 不需要内核头文件  │
├──────────────┼──────────────────┼──────────────────┤
│ 性能         │ 中等(kprobe)   │ 高(JIT 编译)   │
├──────────────┼──────────────────┼──────────────────┤
│ 功能范围     │ 更灵活           │ 受验证器限制      │
├──────────────┼──────────────────┼──────────────────┤
│ 生产可用性   │ 风险较高         │ 适合生产环境      │
└──────────────┴──────────────────┴──────────────────┘

8.4 bcc 工具集

功能:基于 eBPF 的性能分析工具集,提供数十个现成工具。

常用工具与底层实现

┌──────────────────┬──────────────────────────────────────────────────┐
│ 工具              │ 功能 + 底层 eBPF 挂载点                          │
├──────────────────┼──────────────────────────────────────────────────┤
│ execsnoop        │ 追踪新进程执行                                    │
│                  → kprobe:do_execve / tracepoint:sched:sched_process_exec│
├──────────────────┼──────────────────────────────────────────────────┤
│ opensnoop        │ 追踪文件打开                                      │
│                  → kprobe:do_sys_open / tracepoint:syscalls:sys_enter_open│
├──────────────────┼──────────────────────────────────────────────────┤
│ biolatency       │ 块 I/O 延迟直方图                                 │
│                  → tracepoint:block:block_rq_issue (记录开始时间)    │
│                  → tracepoint:block:block_rq_complete (计算延迟)     │
│                  → BPF_MAP_TYPE_HASH 存储进行中的请求                │
│                  → BPF_MAP_TYPE_PERCPU_ARRAY/LRU_HASH 存直方图      │
├──────────────────┼──────────────────────────────────────────────────┤
│ biosnoop         │ 追踪每个块 I/O 请求                               │
│                  → 同 biolatency 的 tracepoint                       │
│                  → perf_event 输出每条 I/O 详情                      │
├──────────────────┼──────────────────────────────────────────────────┤
│ cachestat        │ 页缓存统计                                        │
│                  → kprobe:mark_page_accessed (缓存命中)              │
│                  → kprobe:mark_buffer_dirty (脏页)                   │
│                  → kprobe:add_to_page_cache_lru (缓存添加)          │
│                  → kprobe:__remove_mapping (缓存移除)               │
├──────────────────┼──────────────────────────────────────────────────┤
│ tcpconnect       │ 追踪 TCP 主动连接                                 │
│                  → kprobe:tcp_v4_connect / tcp_v6_connect           │
├──────────────────┼──────────────────────────────────────────────────┤
│ tcpaccept        │ 追踪 TCP 被动接受                                 │
│                  → kprobe:inet_csk_accept                           │
├──────────────────┼──────────────────────────────────────────────────┤
│ offcputime       │ 追踪 CPU 外等待时间                               │
│                  → kprobe:schedule (记录离开 CPU 时间)               │
│                  → kprobe:finish_task_switch (记录回到 CPU 时间)     │
│                  → BPF_MAP_TYPE_STACK_TRACE 采集调用栈               │
├──────────────────┼──────────────────────────────────────────────────┤
│ memleak          │ 内存泄漏检测                                      │
│                  → kprobe:kmalloc / kmem_cache_alloc (记录分配)     │
│                  → kprobe:kfree / kmem_cache_free (记录释放)        │
│                  → BPF_MAP_TYPE_HASH 存储未释放的分配                │
│                  → 定期扫描,长时间未释放的视为泄漏                   │
├──────────────────┼──────────────────────────────────────────────────┤
│ profile          │ CPU profiling(基于定时器采样)                    │
│                  → perf_event (CPU 周期采样)                         │
│                  → BPF_MAP_TYPE_STACK_TRACE 采集调用栈               │
│                  → BPF_MAP_TYPE_PERCPU_HASH 统计栈出现次数           │
└──────────────────┴──────────────────────────────────────────────────┘

8.5 kprobe / uprobe

功能:内核/用户空间动态插桩机制,是 ftrace、eBPF、SystemTap 的底层基础设施。

kprobe 底层实现

x86 上 kprobe 的实现:

1. 注册 kprobe:
   → 用户指定目标函数地址
   → 保存目标地址的原始指令
   → 将目标地址第一个字节替换为 INT 3(0xCC,断点指令)

2. 执行到 INT 3:
   → CPU 触发 #DB 异常 → 进入 kprobe_handler()
   → 单步执行原始指令(设置 TF 位)
   → 执行 pre_handler 回调
   → 执行后恢复执行

优化:kprobe 跳转优化
  → 如果目标函数开头 ≥ 5 字节,直接替换为 JMP 指令
  → 跳转到 kprobe 的处理代码
  → 避免 INT 3 的异常处理开销
  → 需要启用 CONFIG_OPTPROBES

uprobe 底层实现

用户空间插桩:

1. 注册 uprobe:
   → 指定可执行文件 + 偏移量
   → 内核在目标文件的 page cache 中找到对应页
   → 将目标地址替换为 INT 3(写时拷贝 COW)

2. 进程执行到 INT 3:
   → 触发 #DB 异常
   → 内核检查是否是 uprobe 断点
   → 执行 uprobe handler
   → 单步执行原始指令
   → 恢复执行

3. uprobe 与 kprobe 的区别:
   → kprobe 修改内核代码段(所有进程共享)
   → uprobe 修改用户空间页(通过 COW,只影响目标进程)
   → uprobe 需要处理进程 fork 时的断点继承

8.6 tracepoint

功能:内核中预定义的静态追踪点,比 kprobe 开销更低、更稳定。

底层实现

tracepoint 的定义(内核源码中):

  TRACE_EVENT(sched_switch,
      TP_PROTO(struct task_struct *prev, struct task_struct *next),
      TP_ARGS(prev, next),
      TP_STRUCT__entry(
          __field(pid_t, prev_pid)
          __field(pid_t, next_pid)
          __field(unsigned int, prev_prio)
          __field(unsigned int, next_prio)
      ),
      TP_fast_assign(
          __entry->prev_pid = prev->pid;
          __entry->next_pid = next->pid;
          __entry->prev_prio = prev->prio;
          __entry->next_prio = next->prio;
      ),
      TP_printk("prev_pid=%d next_pid=%d prev_prio=%d next_prio=%d",
          __entry->prev_pid, __entry->next_pid,
          __entry->prev_prio, __entry->next_prio)
  );

编译后展开为:

  // 函数入口的钩子
  static inline void trace_sched_switch(struct task_struct *prev,
                                         struct task_struct *next) {
      if (trace_sched_switch_enabled()) {    ← 快速检查(分支预测优化)
          __trace_sched_switch(prev, next);  ← 慢路径:写入 ring buffer
      }
  }

  // 未启用时:trace_sched_switch_enabled() 返回 false
  // 开销:一次条件判断 + 分支预测正确 ≈ 0

tracepoint vs kprobe

┌──────────────┬─────────────────────┬──────────────────────┐
│              │ tracepoint          │ kprobe               │
├──────────────┼─────────────────────┼──────────────────────┤
│ 插桩方式     │ 编译时静态插入       │ 运行时动态替换指令    │
│ 稳定性      │ ABI 稳定            │ 依赖内核内部实现      │
│ 未启用开销   │ ≈ 0(条件跳转)     │ ≈ 0(ftrace nop)    │
│ 启用开销     │ 低(直接调用)      │ 中(INT 3 → 异常)   │
│ 可追踪位置   │ 仅预定义位置        │ 任意函数入口/返回     │
│ 参数访问     │ 结构化(有类型)     │ 需要知道寄存器/栈布局 │
└──────────────┴─────────────────────┴──────────────────────┘

8.7 常用 tracepoint 列表

┌──────────────────────┬───────────────────────────────────────────┐
│ 子系统                │ 关键 tracepoint                            │
├──────────────────────┼───────────────────────────────────────────┤
│ sched(调度)         │ sched_switch     → 进程切换               │
│                      │ sched_wakeup     → 进程唤醒               │
│                      │ sched_process_fork → 进程创建              │
│                      │ sched_process_exit → 进程退出              │
│                      │ sched_migrate_task → 进程迁移              │
├──────────────────────┼───────────────────────────────────────────┤
│ block(块层)         │ block_rq_issue   → I/O 请求提交           │
│                      │ block_rq_complete → I/O 请求完成           │
│                      │ block_rq_requeue → I/O 请求重入队列        │
│                      │ block_bio_merge  → bio 合并               │
├──────────────────────┼───────────────────────────────────────────┤
│ syscalls(系统调用)  │ sys_enter_openat → open 系统调用入口      │
│                      │ sys_exit_openat  → open 系统调用返回      │
│                      │ sys_enter_read / write / ...              │
├──────────────────────┼───────────────────────────────────────────┤
│ net(网络)           │ net_dev_xmit     → 网络包发送             │
│                      │ netif_receive_skb → 网络包接收             │
│                      │ napi_poll        → NAPI 轮询              │
├──────────────────────┼───────────────────────────────────────────┤
│ irq(中断)           │ irq_handler_entry → 中断处理入口          │
│                      │ irq_handler_exit  → 中断处理退出          │
│                      │ softirq_entry/exit → 软中断处理           │
├──────────────────────┼───────────────────────────────────────────┤
│ rpm(电源管理)       │ rpm_idle/suspend/resume → 运行时电源管理   │
├──────────────────────┼───────────────────────────────────────────┤
│ writeback(回写)     │ writeback_start  → 回写开始               │
│                      │ writeback_written → 回写完成               │
│                      │ writeback_wait    → 回写等待              │
└──────────────────────┴───────────────────────────────────────────┘

查看所有可用 tracepoint:
  ls /sys/kernel/debug/tracing/available_events
  或 perf list tracepoint
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容