mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-10-29 03:34:44 +08:00
Document fsession latency workflow
This commit is contained in:
@@ -88,6 +88,7 @@ Tracing:
|
||||
- [lesson 39-nginx](src/39-nginx/README.md) Using eBPF to Trace Nginx Requests
|
||||
- [lesson 40-mysql](src/40-mysql/README.md) Using eBPF to Trace MySQL Queries
|
||||
- [lesson 48-energy](src/48-energy/README.md) Energy Monitoring for Process-Level Power Analysis
|
||||
- [lesson 52-fsession-latency](src/52-fsession-latency/README.md) Trace Slow vfs_read Calls with fsession
|
||||
|
||||
|
||||
Security:
|
||||
|
||||
@@ -87,6 +87,7 @@ GPU:
|
||||
- [lesson 39-nginx](src/39-nginx/README.zh.md) 使用 eBPF 跟踪 Nginx 请求
|
||||
- [lesson 40-mysql](src/40-mysql/README.zh.md) 使用 eBPF 跟踪 MySQL 查询
|
||||
- [lesson 48-energy](src/48-energy/README.zh.md) eBPF 教程:进程级能源监控与功耗分析
|
||||
- [lesson 52-fsession-latency](src/52-fsession-latency/README.zh.md) 使用 fsession 追踪慢速 vfs_read 调用
|
||||
|
||||
|
||||
安全:
|
||||
|
||||
@@ -15,6 +15,7 @@ TRACING_LESSONS = {
|
||||
"src/39-nginx",
|
||||
"src/40-mysql",
|
||||
"src/48-energy",
|
||||
"src/52-fsession-latency",
|
||||
}
|
||||
|
||||
|
||||
|
||||
219
src/52-fsession-latency/README.md
Normal file
219
src/52-fsession-latency/README.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# eBPF Tutorial by Example: Trace Slow vfs_read Calls with fsession
|
||||
|
||||
A file-backed service shows read-latency spikes in its application metrics, but the metrics cannot distinguish a blocked kernel read from work above the syscall boundary. The operator needs to answer: which specific `vfs_read` invocations are slow, for which threads, and by how much?
|
||||
|
||||
`fsession_latency` attaches a single BPF program to `vfs_read` that timestamps entry, measures return latency, and reports only calls at or above a configurable threshold. It uses the Linux 7.0 fsession mechanism, which eliminates the hash-map correlation that traditional fentry/fexit pairs require.
|
||||
|
||||
> Complete source code: <https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/52-fsession-latency>
|
||||
|
||||
## Quick Start
|
||||
|
||||
Build the tool from source (requires libbpf 1.7.0 and bpftool v7.7.0, both vendored in this repository):
|
||||
|
||||
```bash
|
||||
cd src/52-fsession-latency
|
||||
make clean
|
||||
make -j2
|
||||
```
|
||||
|
||||
Trace a specific service process for 30 seconds, reporting reads that take 10 ms or longer:
|
||||
|
||||
```bash
|
||||
SERVICE_PID=$(pgrep -n my-service)
|
||||
sudo ./fsession_latency --pid "$SERVICE_PID" --threshold-us 10000 --duration 30
|
||||
```
|
||||
|
||||
CLI usage:
|
||||
|
||||
```text
|
||||
Usage: ./fsession_latency [--threshold-us USEC] [--duration SEC] [--pid TGID] [--verbose]
|
||||
```
|
||||
|
||||
Defaults: threshold 1000 microseconds, duration 10 seconds, all processes.
|
||||
|
||||
## Verified Test Output
|
||||
|
||||
The integration test performs 64 ordinary file reads plus one pipe read delayed by 50 ms. The pipe read crosses the 10 ms threshold and appears as an event. This output was captured on a KVM guest running kernel `7.0.0-rc2+`:
|
||||
|
||||
```console
|
||||
Tracing vfs_read for 1 seconds; threshold=10000 us; pid=selected
|
||||
EVENT comm=python3 tgid=1257 pid=1257 requested=1 result=1 latency_us=50160
|
||||
SUMMARY calls=66 slow=1 errors=0 dropped=0 events=1
|
||||
TEST-SUMMARY miss_calls=0 high_threshold_calls=66 high_threshold_slow=0 threshold_calls=66 threshold_slow=1 events=1 dropped=0
|
||||
PASS: PID filtering, threshold miss, and slow-read reporting behaved as expected
|
||||
```
|
||||
|
||||
The exact counts and latency are specific to that test environment; your numbers will differ.
|
||||
|
||||
## How It Works
|
||||
|
||||
### The fsession Mechanism
|
||||
|
||||
Traditional fentry/fexit tracing attaches two separate BPF programs. Correlating entry and return requires a per-thread hash map lookup on both sides. The fsession program type, introduced in Linux 7.0, runs one BPF program at both entry and return of a traced function. Two kfuncs make this work:
|
||||
|
||||
- `bpf_session_cookie(ctx)` returns a pointer to an 8-byte scratch space that persists from entry to return of one function invocation. No map allocation, no lookup, no cleanup.
|
||||
- `bpf_session_is_return(ctx)` returns true on the return invocation.
|
||||
|
||||
On return, the program receives the original function arguments plus the return value. This means the tool can report `count` (requested bytes) and `ret` (actual result or error) without storing them in a map.
|
||||
|
||||
### BPF Program
|
||||
|
||||
The entire BPF program is a single function in `fsession_latency.bpf.c`:
|
||||
|
||||
```c
|
||||
SEC("fsession/vfs_read")
|
||||
int BPF_PROG(measure_vfs_read, struct file *file, char *buf, size_t count,
|
||||
loff_t *pos, ssize_t ret)
|
||||
{
|
||||
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
__u64 *started = bpf_session_cookie(ctx);
|
||||
struct latency_event *event;
|
||||
__u64 latency;
|
||||
|
||||
if (!bpf_session_is_return(ctx)) {
|
||||
if (target_tgid && pid_tgid >> 32 != target_tgid) {
|
||||
*started = 0;
|
||||
return 0;
|
||||
}
|
||||
*started = bpf_ktime_get_ns();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!*started)
|
||||
return 0;
|
||||
|
||||
latency = bpf_ktime_get_ns() - *started;
|
||||
__sync_fetch_and_add(&stats.calls, 1);
|
||||
if (ret < 0)
|
||||
__sync_fetch_and_add(&stats.errors, 1);
|
||||
if (latency < threshold_ns)
|
||||
return 0;
|
||||
|
||||
__sync_fetch_and_add(&stats.slow, 1);
|
||||
event = bpf_ringbuf_reserve(&events, sizeof(*event), 0);
|
||||
if (!event) {
|
||||
__sync_fetch_and_add(&stats.dropped, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
event->pid = (__u32)pid_tgid;
|
||||
event->tgid = pid_tgid >> 32;
|
||||
event->requested = count;
|
||||
event->result = ret;
|
||||
event->latency_ns = latency;
|
||||
bpf_get_current_comm(event->comm, sizeof(event->comm));
|
||||
bpf_ringbuf_submit(event, 0);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
The flow works like this:
|
||||
|
||||
1. On entry, check the TGID filter. If the process does not match, store zero in the session cookie so the return side skips it. Otherwise, store the current nanosecond timestamp.
|
||||
2. On return, if the cookie is zero the call was filtered out. Otherwise compute latency from the stored timestamp.
|
||||
3. Increment the atomic `calls` counter. If the return value is negative, increment `errors`.
|
||||
4. If latency is below the threshold, stop. Otherwise increment `slow`, reserve a ring-buffer slot, populate the event, and submit.
|
||||
|
||||
### Shared Structures
|
||||
|
||||
The header `fsession_latency.h` defines the event and stats structures shared between BPF and user space:
|
||||
|
||||
```c
|
||||
struct latency_event {
|
||||
unsigned int pid;
|
||||
unsigned int tgid;
|
||||
unsigned long long requested;
|
||||
long long result;
|
||||
unsigned long long latency_ns;
|
||||
char comm[FSESSION_COMM_LEN];
|
||||
};
|
||||
|
||||
struct latency_stats {
|
||||
unsigned long long calls;
|
||||
unsigned long long slow;
|
||||
unsigned long long errors;
|
||||
unsigned long long dropped;
|
||||
};
|
||||
```
|
||||
|
||||
### User-Space Loader
|
||||
|
||||
The user-space program in `fsession_latency.c` performs these steps:
|
||||
|
||||
1. Parse CLI arguments (threshold, duration, PID filter).
|
||||
2. Open the BPF skeleton and set `rodata` constants (`threshold_ns`, `target_tgid`) before loading.
|
||||
3. Load and attach the fsession program to `vfs_read`.
|
||||
4. Create a ring buffer and poll it with a 100 ms timeout until the duration expires or a signal arrives.
|
||||
5. Print each event as it arrives (comm, tgid, pid, requested bytes, result, latency in microseconds).
|
||||
6. Print a summary line with aggregate counters from BSS.
|
||||
|
||||
The summary line exposes ring-buffer drops so the operator knows if events were lost under load.
|
||||
|
||||
### vmlinux.h Compatibility
|
||||
|
||||
The repository's `vmlinux.h` snapshot predates the ctx argument on `bpf_session_is_return` and `bpf_session_cookie`. The BPF source works around this by renaming those stale declarations during the include, then declaring the correct Linux 7.0 signatures:
|
||||
|
||||
```c
|
||||
#define bpf_session_is_return bpf_session_is_return_vmlinux_snapshot
|
||||
#define bpf_session_cookie bpf_session_cookie_vmlinux_snapshot
|
||||
#include "vmlinux.h"
|
||||
#undef bpf_session_is_return
|
||||
#undef bpf_session_cookie
|
||||
|
||||
extern bool bpf_session_is_return(void *ctx) __ksym;
|
||||
extern __u64 *bpf_session_cookie(void *ctx) __ksym;
|
||||
```
|
||||
|
||||
This avoids hand-editing the generated header. A regenerated `vmlinux.h` from a 7.0+ kernel would not need the workaround.
|
||||
|
||||
### libbpf Section Recognition
|
||||
|
||||
The repository uses bpftool v7.7.0, whose nested libbpf is v1.7.0. libbpf 1.7.0 recognizes `fsession/` as a valid program section, so no private numeric attach-type workaround is needed.
|
||||
|
||||
## Running the Tests
|
||||
|
||||
The integration test runs three scenarios against the built binary:
|
||||
|
||||
```bash
|
||||
sudo make test
|
||||
```
|
||||
|
||||
The test validates:
|
||||
|
||||
1. An unmatched PID (2^32 - 1) produces zero calls, proving the TGID filter works.
|
||||
2. A 10-second threshold (10,000,000 us) produces no slow events even though reads complete, proving the threshold comparison works.
|
||||
3. A 10 ms threshold with a pipe read delayed by 50 ms produces at least one slow event, proving the end-to-end reporting path works.
|
||||
|
||||
## Requirements
|
||||
|
||||
| Requirement | Value |
|
||||
|---|---|
|
||||
| Minimum kernel | Linux 7.0 |
|
||||
| Minimum libbpf | 1.7.0 |
|
||||
| Architecture | x86_64 (tested) |
|
||||
| BTF | Required |
|
||||
| Privilege | root |
|
||||
| Kernel configs | `CONFIG_BPF=y`, `CONFIG_BPF_SYSCALL=y`, `CONFIG_BPF_JIT=y`, `CONFIG_BPF_EVENTS=y`, `CONFIG_DEBUG_INFO_BTF=y`, `CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y` |
|
||||
| Runtime | BPF JIT enabled; `vfs_read` present in kernel BTF and traceable |
|
||||
|
||||
## Limitations
|
||||
|
||||
- Measures time inside `vfs_read` only. This is not full request latency, storage-device service time, or application p99.
|
||||
- Covers only paths that invoke `vfs_read`. mmap and other paths that bypass it are invisible.
|
||||
- Exact TGID filter only. No cgroup, process-tree, path, inode, mount, or container selector.
|
||||
- One-shot duration. Not a daemon, alerting system, or metrics exporter.
|
||||
- Ring buffer can drop matching events under load. The `dropped` counter exposes that condition; other counters remain aggregate observations.
|
||||
- Command names can repeat and PID reuse is possible outside the bounded tracing window.
|
||||
- No user/kernel stack capture and no filename/path resolution.
|
||||
|
||||
## References
|
||||
|
||||
- [Linux fsession merge commit](https://github.com/torvalds/linux/commit/f17b474e36647c23801ef8fdaf2255ab66dd2973)
|
||||
- [Upstream fsession BPF selftest (prog)](https://github.com/torvalds/linux/blob/v7.1/tools/testing/selftests/bpf/progs/fsession_test.c)
|
||||
- [Upstream fsession BPF selftest (runner)](https://github.com/torvalds/linux/blob/v7.1/tools/testing/selftests/bpf/prog_tests/fsession_test.c)
|
||||
- [libbpf 1.7.0 release](https://github.com/libbpf/libbpf/releases/tag/v1.7.0)
|
||||
|
||||
## More eBPF Tutorials
|
||||
|
||||
- Tutorial repository: <https://github.com/eunomia-bpf/bpf-developer-tutorial>
|
||||
- Tutorial site: <https://eunomia.dev/tutorials/>
|
||||
219
src/52-fsession-latency/README.zh.md
Normal file
219
src/52-fsession-latency/README.zh.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# eBPF 实践教程: 使用 fsession 追踪慢速 vfs_read 调用
|
||||
|
||||
一个文件服务出现了读延迟尖峰,但应用层指标无法区分是内核读操作阻塞还是系统调用之上的业务逻辑耗时。运维人员需要确定:哪些具体的 `vfs_read` 调用慢了、发生在哪个线程、慢了多少。
|
||||
|
||||
`fsession_latency` 将一个 BPF 程序附加到 `vfs_read`,在进入时记录时间戳、返回时计算延迟,只上报达到或超过阈值的调用。它使用 Linux 7.0 引入的 fsession 机制,免去了传统 fentry/fexit 需要的哈希表关联。
|
||||
|
||||
> 完整源代码: <https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/52-fsession-latency>
|
||||
|
||||
## 快速开始
|
||||
|
||||
从源码构建(需要 libbpf 1.7.0 和 bpftool v7.7.0,均已在仓库中内置):
|
||||
|
||||
```bash
|
||||
cd src/52-fsession-latency
|
||||
make clean
|
||||
make -j2
|
||||
```
|
||||
|
||||
追踪指定服务进程 30 秒,上报 10 ms 以上的读操作:
|
||||
|
||||
```bash
|
||||
SERVICE_PID=$(pgrep -n my-service)
|
||||
sudo ./fsession_latency --pid "$SERVICE_PID" --threshold-us 10000 --duration 30
|
||||
```
|
||||
|
||||
命令行用法:
|
||||
|
||||
```text
|
||||
Usage: ./fsession_latency [--threshold-us USEC] [--duration SEC] [--pid TGID] [--verbose]
|
||||
```
|
||||
|
||||
默认值:阈值 1000 微秒,持续时间 10 秒,追踪所有进程。
|
||||
|
||||
## 验证测试输出
|
||||
|
||||
集成测试执行 64 次普通文件读取加一次延迟 50 ms 的管道读取。管道读超过 10 ms 阈值,出现在事件输出中。此输出在运行内核 `7.0.0-rc2+` 的 KVM 虚拟机中采集:
|
||||
|
||||
```console
|
||||
Tracing vfs_read for 1 seconds; threshold=10000 us; pid=selected
|
||||
EVENT comm=python3 tgid=1257 pid=1257 requested=1 result=1 latency_us=50160
|
||||
SUMMARY calls=66 slow=1 errors=0 dropped=0 events=1
|
||||
TEST-SUMMARY miss_calls=0 high_threshold_calls=66 high_threshold_slow=0 threshold_calls=66 threshold_slow=1 events=1 dropped=0
|
||||
PASS: PID filtering, threshold miss, and slow-read reporting behaved as expected
|
||||
```
|
||||
|
||||
具体的调用次数和延迟数值取决于测试环境,你的结果会有所不同。
|
||||
|
||||
## 工作原理
|
||||
|
||||
### fsession 机制
|
||||
|
||||
传统的 fentry/fexit 追踪需要附加两个独立的 BPF 程序,通过每线程哈希表在进入和返回之间关联数据。fsession 程序类型(Linux 7.0 引入)让同一个 BPF 程序在被追踪函数的进入和返回阶段都执行,通过两个 kfunc 实现:
|
||||
|
||||
- `bpf_session_cookie(ctx)` 返回一个 8 字节暂存区的指针,从函数进入到返回期间持续有效。无需分配 map、无需查找、无需清理。
|
||||
- `bpf_session_is_return(ctx)` 在返回阶段返回 true。
|
||||
|
||||
返回时,程序接收到原始函数参数加上返回值。因此工具可以直接报告 `count`(请求字节数)和 `ret`(实际结果或错误),不需要将它们存入 map。
|
||||
|
||||
### BPF 程序
|
||||
|
||||
整个 BPF 程序在 `fsession_latency.bpf.c` 中是一个函数:
|
||||
|
||||
```c
|
||||
SEC("fsession/vfs_read")
|
||||
int BPF_PROG(measure_vfs_read, struct file *file, char *buf, size_t count,
|
||||
loff_t *pos, ssize_t ret)
|
||||
{
|
||||
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
__u64 *started = bpf_session_cookie(ctx);
|
||||
struct latency_event *event;
|
||||
__u64 latency;
|
||||
|
||||
if (!bpf_session_is_return(ctx)) {
|
||||
if (target_tgid && pid_tgid >> 32 != target_tgid) {
|
||||
*started = 0;
|
||||
return 0;
|
||||
}
|
||||
*started = bpf_ktime_get_ns();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!*started)
|
||||
return 0;
|
||||
|
||||
latency = bpf_ktime_get_ns() - *started;
|
||||
__sync_fetch_and_add(&stats.calls, 1);
|
||||
if (ret < 0)
|
||||
__sync_fetch_and_add(&stats.errors, 1);
|
||||
if (latency < threshold_ns)
|
||||
return 0;
|
||||
|
||||
__sync_fetch_and_add(&stats.slow, 1);
|
||||
event = bpf_ringbuf_reserve(&events, sizeof(*event), 0);
|
||||
if (!event) {
|
||||
__sync_fetch_and_add(&stats.dropped, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
event->pid = (__u32)pid_tgid;
|
||||
event->tgid = pid_tgid >> 32;
|
||||
event->requested = count;
|
||||
event->result = ret;
|
||||
event->latency_ns = latency;
|
||||
bpf_get_current_comm(event->comm, sizeof(event->comm));
|
||||
bpf_ringbuf_submit(event, 0);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
执行流程:
|
||||
|
||||
1. 进入时检查 TGID 过滤器。如果不匹配,在 session cookie 中存 0,返回时跳过。匹配则存入当前纳秒时间戳。
|
||||
2. 返回时,如果 cookie 为 0 则表示该调用已被过滤。否则用当前时间减去存储的时间戳得到延迟。
|
||||
3. 原子递增 `calls` 计数器。如果返回值为负数,递增 `errors`。
|
||||
4. 如果延迟低于阈值,结束。否则递增 `slow`,在 ring buffer 中预留空间,填充事件并提交。
|
||||
|
||||
### 共享数据结构
|
||||
|
||||
头文件 `fsession_latency.h` 定义了 BPF 和用户空间共享的事件和统计结构:
|
||||
|
||||
```c
|
||||
struct latency_event {
|
||||
unsigned int pid;
|
||||
unsigned int tgid;
|
||||
unsigned long long requested;
|
||||
long long result;
|
||||
unsigned long long latency_ns;
|
||||
char comm[FSESSION_COMM_LEN];
|
||||
};
|
||||
|
||||
struct latency_stats {
|
||||
unsigned long long calls;
|
||||
unsigned long long slow;
|
||||
unsigned long long errors;
|
||||
unsigned long long dropped;
|
||||
};
|
||||
```
|
||||
|
||||
### 用户空间加载器
|
||||
|
||||
`fsession_latency.c` 中的用户空间程序执行以下步骤:
|
||||
|
||||
1. 解析命令行参数(阈值、持续时间、PID 过滤器)。
|
||||
2. 打开 BPF skeleton,在加载前设置 `rodata` 常量(`threshold_ns`、`target_tgid`)。
|
||||
3. 加载并附加 fsession 程序到 `vfs_read`。
|
||||
4. 创建 ring buffer,以 100 ms 超时轮询,直到持续时间到期或收到信号。
|
||||
5. 每收到一个事件立即打印(comm、tgid、pid、请求字节数、结果、延迟微秒数)。
|
||||
6. 打印汇总行,包含从 BSS 读取的聚合计数器。
|
||||
|
||||
汇总行中的 `dropped` 字段暴露 ring buffer 丢失事件的情况,让运维人员知道是否有数据丢失。
|
||||
|
||||
### vmlinux.h 兼容性处理
|
||||
|
||||
仓库的 `vmlinux.h` 快照中 `bpf_session_is_return` 和 `bpf_session_cookie` 的声明早于 ctx 参数版本。BPF 源码通过在 include 时重命名这些旧声明来解决,然后声明正确的 Linux 7.0 签名:
|
||||
|
||||
```c
|
||||
#define bpf_session_is_return bpf_session_is_return_vmlinux_snapshot
|
||||
#define bpf_session_cookie bpf_session_cookie_vmlinux_snapshot
|
||||
#include "vmlinux.h"
|
||||
#undef bpf_session_is_return
|
||||
#undef bpf_session_cookie
|
||||
|
||||
extern bool bpf_session_is_return(void *ctx) __ksym;
|
||||
extern __u64 *bpf_session_cookie(void *ctx) __ksym;
|
||||
```
|
||||
|
||||
这样避免了手动编辑生成的头文件。如果从 7.0+ 内核重新生成 `vmlinux.h`,则不需要这个处理。
|
||||
|
||||
### libbpf 段名识别
|
||||
|
||||
仓库使用 bpftool v7.7.0,其内置的 libbpf 版本为 v1.7.0。libbpf 1.7.0 能识别 `fsession/` 作为有效的程序段名,因此不需要私有的数字 attach-type 变通方案。
|
||||
|
||||
## 运行测试
|
||||
|
||||
集成测试对构建产物运行三个场景:
|
||||
|
||||
```bash
|
||||
sudo make test
|
||||
```
|
||||
|
||||
测试验证:
|
||||
|
||||
1. 不匹配的 PID (2^32 - 1) 产生零次调用,证明 TGID 过滤器有效。
|
||||
2. 10 秒阈值 (10,000,000 us) 即使有读操作完成也不产生慢事件,证明阈值比较逻辑正确。
|
||||
3. 10 ms 阈值加上延迟 50 ms 的管道读产生至少一个慢事件,证明端到端上报路径正常工作。
|
||||
|
||||
## 环境要求
|
||||
|
||||
| 要求 | 值 |
|
||||
|---|---|
|
||||
| 最低内核版本 | Linux 7.0 |
|
||||
| 最低 libbpf | 1.7.0 |
|
||||
| 架构 | x86_64(已测试) |
|
||||
| BTF | 必须 |
|
||||
| 权限 | root |
|
||||
| 内核配置 | `CONFIG_BPF=y`、`CONFIG_BPF_SYSCALL=y`、`CONFIG_BPF_JIT=y`、`CONFIG_BPF_EVENTS=y`、`CONFIG_DEBUG_INFO_BTF=y`、`CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y` |
|
||||
| 运行时 | BPF JIT 已启用;`vfs_read` 在内核 BTF 中存在且可追踪 |
|
||||
|
||||
## 局限性
|
||||
|
||||
- 仅测量 `vfs_read` 内部的时间,不等于完整请求延迟、存储设备服务时间或应用 p99。
|
||||
- 仅覆盖调用 `vfs_read` 的路径。mmap 和其他绕过 `vfs_read` 的路径不可见。
|
||||
- 仅支持精确 TGID 过滤,不支持 cgroup、进程树、路径、inode、挂载点或容器选择器。
|
||||
- 单次运行,不是守护进程、告警系统或指标导出器。
|
||||
- Ring buffer 在高负载下可能丢失匹配事件。`dropped` 计数器暴露该情况,其他计数器为聚合观察值。
|
||||
- 命令名称可能重复,PID 在有界追踪窗口外可能被复用。
|
||||
- 不采集用户/内核栈,不解析文件名或路径。
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [Linux fsession 合并提交](https://github.com/torvalds/linux/commit/f17b474e36647c23801ef8fdaf2255ab66dd2973)
|
||||
- [上游 fsession BPF 自测试 (prog)](https://github.com/torvalds/linux/blob/v7.1/tools/testing/selftests/bpf/progs/fsession_test.c)
|
||||
- [上游 fsession BPF 自测试 (runner)](https://github.com/torvalds/linux/blob/v7.1/tools/testing/selftests/bpf/prog_tests/fsession_test.c)
|
||||
- [libbpf 1.7.0 发布](https://github.com/libbpf/libbpf/releases/tag/v1.7.0)
|
||||
|
||||
## 更多 eBPF 教程
|
||||
|
||||
- 教程仓库: <https://github.com/eunomia-bpf/bpf-developer-tutorial>
|
||||
- 教程网站: <https://eunomia.dev/tutorials/>
|
||||
@@ -79,6 +79,7 @@ Tracing:
|
||||
- [lesson 39-nginx](39-nginx/README.md) Using eBPF to Trace Nginx Requests
|
||||
- [lesson 40-mysql](40-mysql/README.md) Using eBPF to Trace MySQL Queries
|
||||
- [lesson 48-energy](48-energy/README.md) Energy Monitoring for Process-Level Power Analysis
|
||||
- [lesson 52-fsession-latency](52-fsession-latency/README.md) Trace Slow vfs_read Calls with fsession
|
||||
|
||||
|
||||
Security:
|
||||
|
||||
@@ -79,6 +79,7 @@ GPU:
|
||||
- [lesson 39-nginx](39-nginx/README.zh.md) 使用 eBPF 跟踪 Nginx 请求
|
||||
- [lesson 40-mysql](40-mysql/README.zh.md) 使用 eBPF 跟踪 MySQL 查询
|
||||
- [lesson 48-energy](48-energy/README.zh.md) eBPF 教程:进程级能源监控与功耗分析
|
||||
- [lesson 52-fsession-latency](52-fsession-latency/README.zh.md) 使用 fsession 追踪慢速 vfs_read 调用
|
||||
|
||||
|
||||
安全:
|
||||
|
||||
@@ -57,6 +57,7 @@ This table is generated from each tutorial's `.config` metadata. `Minimum kernel
|
||||
| [eBPF Tutorial: Energy Monitoring for Process-Level Power Analysis](48-energy/README.md) | 5.8 | Required feature | x86_64, arm64 | Required | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_BPF_EVENTS=y, CONFIG_DEBUG_INFO_BTF=y, CONFIG_TRACEPOINTS=y | None | Required | CI build |
|
||||
| [eBPF Tutorial: Fixing Broken HID Devices Without Kernel Patches](49-hid/README.md) | 6.3 | Tutorial docs | x86_64, arm64 | Required | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_DEBUG_INFO_BTF=y, CONFIG_HID_BPF=y, CONFIG_UHID=y\|m | None | Required | CI build |
|
||||
| [eBPF Tutorial by Example 50: Composable Traffic Control with TCX Links](50-tcx/README.md) | 6.6 | Tutorial docs | x86_64, arm64 | Optional | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_NET_XGRESS=y | Network interface | Required | CI build |
|
||||
| [eBPF Tutorial by Example: Trace Slow vfs_read Calls with fsession](52-fsession-latency/README.md) | 7.0 | Tutorial docs | x86_64 | Required | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_BPF_JIT=y, CONFIG_BPF_EVENTS=y, CONFIG_DEBUG_INFO_BTF=y, CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y | None | Required | CI build |
|
||||
| [eBPF Tutorial: cgroup-based Policy Control](cgroup/README.md) | 5.8 | Required feature | x86_64, arm64 | Required | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_CGROUPS=y, CONFIG_CGROUP_BPF=y, CONFIG_CGROUP_DEVICE=y, CONFIG_DEBUG_INFO_BTF=y | None | Required | CI build |
|
||||
| [eBPF Tutorial by Example: BPF Arena for Zero-Copy Shared Memory](features/bpf_arena/README.md) | 6.9 | Tutorial docs | x86_64, arm64 | Required | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_BPF_JIT=y, CONFIG_DEBUG_INFO_BTF=y | None | Required | CI build |
|
||||
| [eBPF Tutorial: BPF Iterators for Kernel Data Export](features/bpf_iters/README.md) | 5.8 | Tutorial docs | x86_64, arm64 | Required | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_DEBUG_INFO_BTF=y | None | Required | CI build |
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
| [eBPF 教程:进程级能源监控与功耗分析](48-energy/README.zh.md) | 5.8 | 必需特性 | x86_64, arm64 | 需要 | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_BPF_EVENTS=y, CONFIG_DEBUG_INFO_BTF=y, CONFIG_TRACEPOINTS=y | 无 | 需要 | CI 构建测试 |
|
||||
| [eBPF 教程:无需内核补丁修复故障的 HID 设备](49-hid/README.zh.md) | 6.3 | 教程文档 | x86_64, arm64 | 需要 | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_DEBUG_INFO_BTF=y, CONFIG_HID_BPF=y, CONFIG_UHID=y\|m | 无 | 需要 | CI 构建测试 |
|
||||
| [eBPF 入门实践教程第五十篇:使用 TCX Link 实现可组合的流量控制](50-tcx/README.zh.md) | 6.6 | 教程文档 | x86_64, arm64 | 可选 | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_NET_XGRESS=y | 网络接口 | 需要 | CI 构建测试 |
|
||||
| [eBPF 实践教程: 使用 fsession 追踪慢速 vfs_read 调用](52-fsession-latency/README.zh.md) | 7.0 | 教程文档 | x86_64 | 需要 | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_BPF_JIT=y, CONFIG_BPF_EVENTS=y, CONFIG_DEBUG_INFO_BTF=y, CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y | 无 | 需要 | CI 构建测试 |
|
||||
| [eBPF 实例教程:基于 cgroup 的策略控制](cgroup/README.zh.md) | 5.8 | 必需特性 | x86_64, arm64 | 需要 | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_CGROUPS=y, CONFIG_CGROUP_BPF=y, CONFIG_CGROUP_DEVICE=y, CONFIG_DEBUG_INFO_BTF=y | 无 | 需要 | CI 构建测试 |
|
||||
| [eBPF 实例教程:BPF Arena 零拷贝共享内存](features/bpf_arena/README.zh.md) | 6.9 | 教程文档 | x86_64, arm64 | 需要 | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_BPF_JIT=y, CONFIG_DEBUG_INFO_BTF=y | 无 | 需要 | CI 构建测试 |
|
||||
| [eBPF 教程:BPF 迭代器用于内核数据导出](features/bpf_iters/README.zh.md) | 5.8 | 教程文档 | x86_64, arm64 | 需要 | CONFIG_BPF=y, CONFIG_BPF_SYSCALL=y, CONFIG_DEBUG_INFO_BTF=y | 无 | 需要 | CI 构建测试 |
|
||||
|
||||
Reference in New Issue
Block a user