sched-ext discussion
[PATCH] selftests/bpf: Remove duplicate copies of the arena spinlock qnodes
LLM 分析
selftests/bpf libarena:清理 arena spinlock qnodes 的重复副本
系列概况
- 标题:[PATCH] selftests/bpf: Remove duplicate copies of the arena spinlock qnodes
- 作者:Changwoo Min changwoo@igalia.com
- 版本:v1(单封 patch,尚未发布 v2)
- 规模:1 patch / 3 files changed, 15 insertions(+), 6 deletions(-)
- 修改文件:
tools/testing/selftests/bpf/libarena/include/bpf_arena_spin_lock.htools/testing/selftests/bpf/libarena/src/common.bpf.ctools/testing/selftests/bpf/progs/arena_spin_lock.c
- 代码统计:3 files / +15 / -6
- Message-ID:
20260803001807.646357-1-changwoo@igalia.com - 完整性:完整。作者已同意基于 bpf-next HEAD rebase 发 v2,并已收到 Emil 的 Reviewed-by 标签。
补丁目的
本补丁是 selftests/bpf 下 libarena 的 cleanup。
bpf_arena_spin_lock.h 头文件里直接定义了一个 64KB 的 qnodes[_Q_MAX_CPUS][_Q_MAX_NODES] 数组,导致任何 #include 该头文件的 BPF 翻译单元都会各自产出一份相同的数据副本。
虽然 __weak 在符号层面让所有副本解析为同一个 instance,但 BPF 的 bpftool gen object 合并策略和常规 ld 不一样:它只合并符号表,然后直接按顺序拼接每个输入的 .addr_space.1 字节。最终 .o / skel 文件里仍然带着 10 份未被任何符号引用的死数据。
实际数字对比(commit message 自带):
object before after
-----------------------------------------------------
.addr_space.1 in libarena.bpf.o 676200 86376
libarena.skel.h 2100123 892371
libarena_asan.skel.h 2641124 1466477
旧流程的问题
bpf_arena_spin_lock.h
+-------------------------------------------------+
| struct arena_qnode __weak __arena __hidden |
| qnodes[_Q_MAX_CPUS][_Q_MAX_NODES]; | <- 64KB defined in header
+-------------------------------------------------+
| | | |
v v v v
common.bpf.c global.bpf.c ... TU-10 copies
| | | |
+------ each TU emits its own 64KB copy ------+
|
v
bpftool gen object (concatenates .addr_space.1 bytes)
|
v
libarena.bpf.o (~676KB of dead bytes)
__weak 让符号消解为一份,但拼接策略不识别 __weak,10 份里只有 1 份真正被引用,剩下 9 份是纯字节浪费。
新流程
bpf_arena_spin_lock.h
+-------------------------------------------------+
| extern struct arena_qnode __arena __hidden |
| qnodes[_Q_MAX_CPUS][_Q_MAX_NODES]; | <- extern declaration
+-------------------------------------------------+
| |
v v
libarena/src/common.bpf.c progs/arena_spin_lock.c
+----------------------------+ +----------------------------+
| struct arena_qnode ... | | struct arena_qnode ... |
| qnodes[...]; sole def | | qnodes[...]; test copy |
+----------------------------+ +----------------------------+
| |
+-----------------+---------------------+
v
each contributes exactly one copy
|
v
libarena.bpf.o (~86KB, ~87% smaller)
每个真正需要 qnodes 的程序 / libarena 自己显式提供一份定义,让 64KB 数据段只出现一次。
Patch 概览
/* libarena/include/bpf_arena_spin_lock.h (修改) */
-struct arena_qnode __weak __arena __hidden
- qnodes[_Q_MAX_CPUS][_Q_MAX_NODES];
+extern struct arena_qnode __arena __hidden
+ qnodes[_Q_MAX_CPUS][_Q_MAX_NODES];
/* libarena/src/common.bpf.c (新增) */
+struct arena_qnode __arena __hidden
+ qnodes[_Q_MAX_CPUS][_Q_MAX_NODES];
/* progs/arena_spin_lock.c (新增,让测试自带 qnodes) */
+struct arena_qnode __arena __hidden
+ qnodes[_Q_MAX_CPUS][_Q_MAX_NODES];
关键实现
- 头文件改成
extern声明:删除__weak,把数组变成普通外部符号声明,避免每个 TU 实例化一份 storage。 - libarena 公共 TU 提供唯一存储:
src/common.bpf.c是 libarena 编译时一定会包含的 TU,把qnodes的实体放这里,所有 libarena 内部 TU 共享同一份。 - 测试程序自给自足:
arena_spin_lock.c测试目标单独再放一份定义,让它脱离 libarena 时也能独立编译/链接(BPF selftest 目标不一定和 libarena 一起链接)。 - 修饰符保持一致:依旧带
__arena __hidden,确保进入 BPF arena 地址空间并对 verifier 隐藏符号。
类比
把这事想成小区公告栏:旧实现里 10 个单元每家门口贴一份"今日停电通知",大家看的是同一张通知,但墙面上总共有 10 张一模一样的纸。清洁阿姨(gen object)只管把所有纸张叠在一起塞进文件袋,不管是不是同一张。
新方案只在物业前台(common.bpf.c)放一份底稿,每个单元需要时复印一张带走,省下 9 张纸;测试小屋(arena_spin_lock.c)因为不在物业系统里,自己也单独留一张底稿。
Highlight:风险与注意点
__weak不等于数据段去重:BPFgen object的合并只到符号层,.addr_space.1是字节级拼接,"看起来只有一份"和"实际只有一份"是两件事。后续如果有人把别的__weak数组也写到 libarena 头里,需要警惕同样的膨胀。- 测试程序必须自带定义:
arena_spin_lock.c单独复制了一份 qnodes;如果将来又新增#include bpf_arena_spin_lock.h但没有附上定义的目标,链接阶段会缺符号,需要在 commit log / 注释里继续强调这个约定。 - asan 与非 asan 都要测:commit message 只说了
-t arena_spin_lock -t libarena,但 asan skel 才是体积收益最大的一份(约 -1.17 MB),后续 review 可以追加 ASan 构建的字节对比作为佐证。 - v2 需要 rebase:Daniel 反馈无法干净应用到 bpf-next HEAD,需注意同期是否有针对
__arena/__hidden的语义变动,否则 v2 在重写过程中可能引入风格偏移。 - 作者与审阅进度:Kumar 的两封回复都只是引用原文,没有提技术意见;正式 review 意见目前只有 Emil 给的
Reviewed-by和 Daniel 的 rebase 要求,v2 一出即可合入。
版本变化
- v1 -> v2(未发布):作者承诺基于
bpf-nextHEAD rebase 后重发;Emil 在 reply #5 给出Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>,v2 应保留该 tag。
一句话总结
把 libarena 头里 64KB 的 qnodes 定义改成 extern,由 common.bpf.c 与 arena_spin_lock.c 各自提供一份,把 .addr_space.1 段砍掉约 87%、asan 版 skel 直接砍掉 1.1 MB,等 v2 rebase 后即可合入。