0/11 已展开

LLM 分析

selftests/lib.bpf.mk:把 BPF selftest 工具链统一到一处

系列概况

字段内容
标题[PATCH v3 0/4] selftests: shared lib.bpf.mk for building BPF progs and skeletons
作者Ziyang Men <ziyang.meme@gmail.com> (Meta Platforms)
版本v3,2026-08-14 首发;与 v2/v1 的差异在封面信里逐条列出
规模4 个 patch,13 个文件,+1204/−302 行
修改文件tools/testing/selftests/lib.bpf.mk(新增 296 行);selftests/cgroup/{Makefile,.gitignore,config,lib/cgroup_util.{c,h},test_memcontrol.c};selftests/cgroup/{memcg_stat_cross_cpu.bpf.c,*.h,test_memcg_stat_cross_cpu.c}(新增);selftests/hid/{Makefile,.gitignore};selftests/sched_ext/Makefile
代码统计patch 1 新增 296 行;patch 2 新增 cgroup 正确性测试 + 三个 cgroup_util helper;patch 3 hid/Makefile 180 行→~30 行;patch 4 sched_ext/Makefile 146 行→~30 行
Message-ID20260814075054.507089-1 ~ -5(封面+4 patch);外加 sashiko-bot、bpf-ci、Andrew Morton 共 7 封回复
完整性完整:封面信 + 4 个 patch + 7 封自动/人工回复

补丁目的

selftests/{bpf,sched_ext,hid}/ 各自维护一份近乎相同的 BPF 工具链(libbpf 子构建、bpftool 子构建、vmlinux.h 生成、skeleton/subskeleton 生成),合计约 450 行重复 Makefile。本系列:

  1. 把工具链抽到公共片段 tools/testing/selftests/lib.bpf.mk
  2. 让 hid、sched_ext 改用 include 复用,自身 Makefile 缩到 ~30 行。
  3. 顺手新增 cgroup 的 memcg flush 真正正确性测试——对比 BPF kfunc 读数与 memory.stat 文件读数,弥补旧 bpf/cgroup_iter_memcg 只校验"非零"的弱点。

旧流程的问题

  • 三套 Makefile 各自计算 vmlinux/BTF 路径、Clang 系统 include、bpftool 输出位置,长期漂移。
  • 缺 vmlinux 时在 parse 阶段 $(error …) 直接挡死 make clean
  • sched_ext 用 3 次 bpftool gen object 链式生成 linked1/2/3.o 再 diff,hid 只生成 1 次,风格分裂。
  • 手工维护的 vpath 是全局规则,会污染 caller 自己的 %.c 规则。
  • HOSTCC/HOSTLD 过去通过 Makefile.include,副作用是连带改 caller 的 AR/LD/CXX。

新流程

  • lib.bpf.mk 把 libbpf、bpftool、vmlinux.h、BPF 对象、skeleton/subskeleton 集中在一处,caller 只需声明少量变量:BPF_SRCSBPF_PROG_EXTBPF_EXTRA_HDRSBPF_EXTRA_CFLAGSBPF_SKEL_EXTBPF_GEN_SUBSKELBPF_OBJ_DIRBPF_SKEL_DIR
  • hid:设 BPF_PROG_EXT := .c 兼容老的 progs/*.c 布局。
  • sched_ext:用现代 *.bpf.c + BPF_SKEL_EXT := .bpf.skel.h + BPF_GEN_SUBSKEL := 1,并保留旧 $(OUTPUT)/build/... 路径。
  • cgroup:作为新消费者加入。
  • 缺 vmlinux 延迟到真正构建 vmlinux.h 的 recipe 里报错,make clean 不再被挡。
  • HOSTCC/HOSTLD 直接从 lib.mk 来,避免 include Makefile.include 带来的 AR/LD 副作用。

Patch 概览

#标题关键改动
1add shared lib.bpf.mk新建 selftests/lib.bpf.mk,296 行
2cgroup: memcg_stat_cross_cpu flush 正确性测试BPF kfunc flush + 文件读数比对
3hid: 用 lib.bpf.mkhid/Makefile 180 → ~30 行
4sched_ext: 用 lib.bpf.mksched_ext/Makefile 146 → ~30 行;28 skel + 28 subskel

关键实现

核心分层变量 + per-source rule:

BUILD_DIR       := $(OUTPUT)/tools/build
BPFOBJ          := $(BUILD_DIR)/libbpf/libbpf.a
HOST_BPFOBJ     := (cross ? HOST_BUILD_DIR : BUILD_DIR)/libbpf/libbpf.a
DEFAULT_BPFTOOL := $(HOST_SCRATCH_DIR)/sbin/bpftool

caller 接入示例:

BPF_SRCS := memcg_stat_cross_cpu.bpf.c
OVERRIDE_TARGETS := 1
include ../lib.mk
include ../lib.bpf.mk
$(OUTPUT)/test_memcg_stat_cross_cpu: test_memcg_stat_cross_cpu.c $(BPF_SKELS) $(LIBCGROUP_O) $(BPFOBJ)
	$(call bpf_link,$@,$< $(LIBCGROUP_O))

每个 BPF 源一条独立 bpf_obj_rule,避免 vpath 串扰;get_sys_includesclang -v -E 抓系统头加 -idirafter 后置以免覆盖项目头;CLANG_BPF_CPU 自动探测 v3 支持,不支持则退到 v2;cross-compile 时 USERCFLAGS 只传给 target libbpf;缺 vmlinux 延迟到 vmlinux.h recipe 报错。BPF_CFLAGS-fms-extensions 以接受 vmlinux.h 中的匿名 struct/union,-MMD -MP 记录所有包含头。

cgroup 测试核心:

SEC("iter.s/cgroup")
int cgroup_memcg_stat_cross_cpu(struct bpf_iter__cgroup *ctx)
{
    struct cgroup *cgrp = ctx->cgroup;
    /* iter.s 因为 flush kfunc 可能睡眠 */
    bpf_mem_cgroup_flush_stats(memcg);
    /* 读 anon/file/shmem/pgfault,写到 HASH map by cg_id */
}

新 cgroup_util 加 cg_get_idname_to_handle_at 取 cgroupfs handle 即内核 cgrp->kn->id,注意不是 st_ino)、cg_touch_pages(写一遍触发 resident fault)、cg_alloc_anon(malloc + fault-in)。测试只建一棵 cgroup 树、一次 flush、然后 BPF 读与 memory.stat 文件读对比。

构建关系图:

caller Makefile (hid/sched_ext/cgroup)
   |
   +-- include ../lib.mk      (OUTPUT, top_srcdir, CC, Q, msg)
   |
   +-- include ../lib.bpf.mk  (BPFOBJ, BPFTOOL, BPF_OBJS, BPF_SKELS, BPF_LDLIBS)
          |
          +-- libbpf sub-make    -> $(OUTPUT)/tools/build/libbpf/libbpf.a
          +-- bpftool sub-make   -> $(OUTPUT)/host-tools/sbin/bpftool
          +-- BPF object rule    -> $(OUTPUT)/foo.bpf.o
          +-- skeleton rule      -> $(OUTPUT)/foo.skel.h (+ foo.subskel.h)
          +-- vmlinux.h rule     -> $(OUTPUT)/tools/include/vmlinux.h

类比

旧流程像三家餐馆各买一套相同的锅、刀、砧板,任意一家换品牌另两家就跟不上,菜刀型号不齐切出来的菜大小不一。新流程是开一个中央厨房货架lib.bpf.mk),餐馆只声明要做什么菜(BPF_SRCS),货架自动按规格送工具。cgroup 是新分店,直接领到刀;cgroup 那边的新 BPF 测试像给中央厨房配了支温度计,不再只看"开没开火"(数字非零),而是核对"实际做熟了几道"(BPF 读数与文件读数完全相等)。

Highlight:风险与注意点

  • 增量依赖:sashiko-bot 提示 BPFOBJ 变更时 BPF_OBJS 未必触发重链接;当前依赖 bpf_obj_rule$(BPFOBJ) 列作 order-only 前置,改 libbpf 源码需手动 make clean
  • flags 漂移:bpf-ci 指出 hid patch 的 changelog 应说明 BPF 编译 flags 实际变了(多了 -Wall/-std=gnu11/-fno-strict-aliasing、新增若干 include 路径、-mcpu 由硬编码 v3 改为自动探测),而不是描述成"行为一致"。
  • 架构 include 探测get_sys_includes 缺 LoongArch 和 MIPS 的 __riscv_xlen-style 探测,sashiko-bot 标记 Low。
  • HAVE_BPF 隔离:cgroup 端用 ifneq ($(HAVE_BPF),) 包住 BPF 路径,无 clang/BTF 时同目录其它 cgroup 测试照常编译,设计稳健。
  • uapi 隔离private CFLAGS += -I$(top_srcdir)/tools/include/uapi 仅加到 test_memcg_stat_cross_cpu,避免污染同目录其它测试对 <linux/*.h> 的解析。
  • review 状态:v3 撞上 merge window,bpfbot 和 sashiko 都提了不少问题;Andrew Morton 在 8-31 已回信"预期多数评审者会等下一版(v4)"。

版本变化

版本关键变化
v1 → v2通用化 lib.bpf.mk(源后缀、extra hdrs/cflags、skel 后缀、subskel、可配置输出目录),能服务 hid/sched_ext 而非仅 cgroup;新增 patch 3(hid)、patch 4(sched_ext)。
v2 → v3共享 Makefile:USERCFLAGS/USERLDFLAGSCFLAGS/LDFLAGSOPT_FLAGS/RELEASE/EXTRA_CFLAGS 透传到 libbpf/bpftool 子 make;每个 BPF 源一条独立 rule 弃用 vpath;HOSTCC/HOSTLD 改从 lib.mk 来;缺 vmlinux 延迟到 recipe 报错保证 make clean 可用。cgroup selftest:只建一棵 cgroup 树、只 flush 一次;用 cg_read_key_long/value_close 等公共 helper;cpu_set_t 替手写 cpu 列表;anon allocator 从 test_memcontrol.c 移到 cgroup_util;修复 bot 评审。

一句话总结

把 selftests 中分散在 bpf/sched_ext/hid 的 ~450 行 BPF 工具链 Makefile 抽成共享片段 tools/testing/selftests/lib.bpf.mk,让 hid/sched_ext 各缩到 ~30 行,并新增 cgroup 端真正的 memcg_stat_cross_cpu flush 跨 CPU 正确性测试;v3 因撞 merge window + bot 反馈,正在等 v4。