摘要
本次训练营我的工作主线是:围绕 StarryOS 的 Linux 网络应用兼容性,持续做「应用驱动测试 -> 问题定位修复 -> 测试框架固化」。
阶段性成果可概括为三点:
- 完成 Nginx 和 Apache 测试框架从零到一的构建,建立 smoke/phase/debug 三层测试体系。
- 构建网络性能测试基础设施(net-bench),集成 eBPF 观测工具,为网络栈持续优化提供工具支撑。
- 完成 OS 功能赛 proj57(ACT 推理)QEMU 和 RK3588 两阶段交付,NPU 执行性能已优于 Linux。
一、训练营阶段工作
1.1 第一阶段:系统调用测试基础
在第一阶段以单一系统调用为目标,完成了事件复用和文件同步两个方向的测试与修复。
具体工作
事件复用系统调用
- 实现
epoll_create1、epoll_ctl、epoll_pwait、epoll_pwait2测试 - 修复
sigsetsize检查与 Linux ABI 不一致问题
- 实现
文件同步系统调用
- 对齐
fsync、fdatasync、sync_file_range、sync、syncfs的 Linux 语义 - 修复返回值和错误码偏差
- 对齐
对应 PR
- https://github.com/rcore-os/tgoskits/pull/658 (Merged)
- https://github.com/rcore-os/tgoskits/pull/900 (Merged)
- https://github.com/rcore-os/tgoskits/pull/903 (Merged)
1.2 第二阶段:Nginx 测试框架与多架构适配
这一阶段从龙同学(LetsWalkInLine)手中接过初步的 Nginx 支持,将其发展为完整的测试框架。
1.2.1 统一测试入口与分层架构
问题背景:
- 初始版本测试脚本分散,QEMU 配置冗余
- 缺少统一的测试模式切换机制
- 难以在 smoke/phase/debug 间快速切换
解决方案:
- 实现
nginx-runner.sh统一 guest 入口,支持:smoke:CI 快速验证(APK 安装 + 基础启动)phase:阶段性功能测试(phase20-70)debug:问题定位(单步调试、日志增强)stress:性能压力测试
- 建立三层 QEMU 配置结构:
qemu/all/:完整功能测试配置qemu/phase/:单个 phase 快速验证qemu/debug/:调试专用配置(更多内存、日志输出)
代码组织:
1 | test-suit/starryos/normal/nginx/ |
1.2.2 关键问题定位与修复
问题一:多 worker 卡死
- 现象:
worker_processes 4时概率性卡死 - 根因:信号中断处理和
EPOLLEXCLUSIVE语义不完整 - 修复:
- 补齐
EPOLLEXCLUSIVE在epoll_ctl中的正确处理 - 修正
accept()被信号中断时的返回值和重试逻辑
- 补齐
- PR:https://github.com/rcore-os/tgoskits/pull/1018 (Merged)
问题二:x86_64 短连接超时
- 现象:phase31(短连接压测)在 x86_64 上偶发 HTTP 超时
- 初步怀疑:网络栈性能问题
- 深入定位:
- 通过分段计时发现瓶颈在 guest 侧
curl进程启动 - x86 QEMU 下外部命令启动开销高达 1-3 秒
- Nginx 响应时间实际在毫秒级,非瓶颈
- 通过分段计时发现瓶颈在 guest 侧
- 解决:将
curl超时从 5 秒放宽到 15 秒,匹配 x86 实际开销 - 教训:性能问题需要分段计时,避免误判根因
问题三:loongarch64 内存不足
- 现象:loongarch64 启动后 OOM
- 根因:默认内存配置 1GB 不足以运行完整测试
- 修复:提升到 2GB,并规范化各架构内存配置
1.2.3 稳定性改进
固定 APK 镜像版本
- 问题:使用
edge仓库导致 glibc ABI 漂移,测试不稳定 - 修复:固定到与 rootfs 一致的 Alpine 版本(3.19)
- 问题:使用
动态启动路径修复
- 问题:Starry app qemu 未走动态平台启动,导致部分架构失败
- 修复:统一通过
axbuild动态启动路径 - PR:https://github.com/rcore-os/tgoskits/pull/1267 (Merged)
对应 PR
- https://github.com/rcore-os/tgoskits/pull/1014 (Merged) - 初始 CI 实现
- https://github.com/rcore-os/tgoskits/pull/1018 (Merged) - 多 worker 修复
- https://github.com/rcore-os/tgoskits/pull/1038 (Merged) - 完整测试框架
1.3 第二阶段:Apache 测试实现
在 Nginx 测试框架稳定后,我参照同样的架构从零实现了 Apache MPM prefork 测试。
1.3.1 测试覆盖设计
Apache 测试分为 7 个 phase,覆盖从基础到高级的完整生命周期:
| Phase | 覆盖内容 | 关键验证点 |
|---|---|---|
| phase20 | 多进程管理 | prefork MPM、graceful 重启、worker 数量控制 |
| phase30 | HTTP 静态文件 | GET 请求、Content-Type、Last-Modified |
| phase40 | 目录访问 | DirectoryIndex、FancyIndexing、.htaccess |
| phase50 | 日志生命周期 | access_log/error_log、graceful 后日志追加 |
| phase55 | sendfile 与 range | 大文件传输、HTTP Range、mmap/sendfile 路径 |
| phase70 | CGI | 脚本执行、环境变量、管道通信 |
| phase80 | 模块特性 | mod_rewrite、mod_alias、mod_headers |
1.3.2 关键问题定位:TCP_DEFER_ACCEPT
问题背景:
- reviewer 环境下 Apache 启动失败,日志显示
AH00076警告 - 警告内容:
setsockopt(TCP_DEFER_ACCEPT) failed: errno 92
深度调查:
- 编写 C 语言探针
tcp-defer-accept-probe.c(172 行) - 验证三个关键问题:
setsockopt()返回值:-1errno:92(协议不支持)- 监听 socket 是否可用:可用,能正常
accept()
结论:
TCP_DEFER_ACCEPT失败是警告而非错误- Apache 能正常回退到标准
accept()路径 - 监听 socket 完全可用,不影响功能
smoke 范围调整:
- 基于此结论,将 smoke 收敛到前 4 步:
- package(APK 安装)
- files(配置文件就位)
- environment(环境变量)
- config test(
apachectl configtest)
- 移除 HTTP 测试到
debug/apache-smoke-full.sh
1.3.3 调试工具集
为问题定位实现了 9 个 debug 脚本:
mpm-prefork-wait.sh:观测 prefork worker 启动和等待accept-mutex.sh:验证 accept mutex 行为graceful-signal.sh:测试 graceful 重启的信号传递htaccess-path-walk.sh:追踪.htaccess路径遍历sendfile-mmap-range.sh:对比 sendfile/mmap 性能cgi-pipe-exec.sh:验证 CGI 管道和脚本执行log-append-reopen.sh:测试日志追加和重开phase20-restart.sh:单步调试 phase20 重启逻辑tcp-defer-accept-probe.c:setsockopt 系统调用探针
当前状态
- PR:https://github.com/rcore-os/tgoskits/pull/1311 (Open)
- 代码量:2367+ 行(测试脚本 + C 探针 + 配置)
- 状态:等待 review,尚未合并
1.4 网络性能测试基础设施(net-bench)
在方案二与方案三之间,我构建了网络性能测试框架,为网络栈持续优化提供工具支撑。
1.4.1 设计目标与理念
- “入口 + 参数明确”的严肃测试架构:
run.sh为唯一严肃入口,显式指定场景(--scenario)、架构(--arch)、加速器(--accel)、重复次数(--repeat),保证可复现、可对照 - 智能入口实验化:自动检测环境后委托
run.sh执行,属于开发期便捷能力,不参与严肃测试 - 多拓扑支持:vhost(主力性能)、tap(降级方案)、slirp(功能冒烟),新增 tap-smp4 和 vhost-smp4 多核扩展场景
- 全流程自动化:一键宿主机配置、测试执行、结果汇总、清理回退
1.4.2 实现架构
统一入口与公共流程:
围绕 run.sh 构建两级入口体系:
- 严肃入口:
run.sh显式接收参数,获取公共流程封装后逐轮启动 iperf3 服务端、执行 guest 测试、收集结果、调用汇总脚本 - 实验性入口:自动检测平台(WSL2/裸 Linux)、架构、KVM 和 vhost-net 可用性,推断参数后委托
run.sh(确保行为一致),测试结束自动清理;另有 WSL2 快捷封装
公共流程封装集中在一处,消除散落硬编码:
- 常量:网段、端口、拓扑定义
- 配置矩阵解析:根据 scenario/arch/accel 自动推导 QEMU 配置文件路径
- iperf3 生命周期:启动、停止、进程级信号兜底(EXIT/INT/TERM)
- 前置检查:KVM 可用性、vhost-net 可用性、TAP 设备就绪、DHCP 服务端监听校验(:67 端口)
- 环境指纹:记录硬件/OS/内核/编译参数
- 结果汇总:mean/stddev,NOISY 标记 >10% stddev
补齐配置矩阵:
QEMU 配置文件按 <scenario>-<arch>-<accel>.toml 命名规范覆盖 20 个组合:
- 场景:slirp、tap、vhost、tap-smp4、vhost-smp4
- 架构:x86_64、aarch64
- 加速模式:kvm(同架构硬件加速)、tcg(跨架构或 KVM 不可用,仅功能验证)
一键宿主机配置:
bin/setup 实现全自动配置:
- 自动安装缺失依赖(iperf3、brctl、jq、dnsmasq)
- 自动加载 vhost_net 模块并放开
/dev/vhost-net和/dev/kvm权限 - 创建桥接 br0、tap0 设备,启动 dnsmasq DHCP(iperf3 服务端由 run.sh 自管生命周期)
- 资源与进程状态写入状态文件
bin/teardown 读取状态文件,逆序清理进程和设备,实现状态化回滚。
测试覆盖:
| Test ID | 说明 | iperf3 参数 |
|———|——|————-|
| tcp1 | TCP 单流上行 | -c $HOST |
| tcp4 | TCP 4 并发流 | -P 4 |
| tcp1r | TCP 单流下行 | -R (reverse) |
| udp1g | UDP 大包 1Gbps | -u -b 1G |
| udp64 | UDP 64B 小包 | -u -l 64 |
每个测试:1 次 warmup + 5 次正式测量。延迟与短连接由 netperf(TCP_RR/UDP_RR/TCP_CRR)补充。
基于 WSL2 端到端测试发现的 4 个真实缺陷:
AX_IP/AX_GW环境变量注入无效:guest 内核在 xtask 路径下只支持 DHCP 获取地址(axruntime未解析静态 IP 环境变量),移除误导性环境变量注入并文档化 DHCP 依赖- DHCP 服务端未校验:缺少 DHCP 时 guest 静默
DHCP timed out,现已对 :67 端口监听校验,缺失时直接报错 - iperf3 服务端残留:失败运行后
trap RETURN在set -e下未触发,改为进程级 EXIT/INT/TERM 兜底 - iperf3 服务端冲突:setup 自启 iperf3 导致与 run.sh 争用端口,改为仅由 run.sh 自管 iperf3 生命周期
1.4.3 eBPF 网络观测工具
依托 CN-TangLin 同学的 eBPF 内核运行时(#848、#850、#886),实现了 net_stats 观测工具。
实现原理:
- kprobe 入口:统计调用次数(
*_pkts) - kretprobe 出口:统计字节数(
*_bytes) - 探测符号:
ax_net::tcp::TcpSocket::sendax_net::tcp::TcpSocket::recvax_net::udp::UdpSocket::sendax_net::udp::UdpSocket::recv
技术特点:
- Rust v0 mangled 符号解析
- Multi-symbol attach(同一探针 attach 到多个 monomorphized 符号)
- 内置 loopback 自测(
--test模式)
已知限制:
*_pkts实际是调用次数,非真实包数- 统计层级是 socket 层,不含 TCP/IP header
- SMP 并发计数非原子,高并发可能丢失增量
当前状态:
- x86_64 self-test 通过
- x86_64 WSL2 端到端(slirp/tap/vhost/vhost-smp4/tap-smp4 全场景)全部 PASS
- eBPF 与 net-bench 的自动集成尚在完善
对应分支
- PR:https://github.com/rcore-os/tgoskits/pull/1417 (Open)
feat/net-enhance(未合并)- 提交:
c30afcc60、394bb6414、7e11d94e4、78fd92817
1.5 OS 功能赛 proj57:ACT 推理
1.5.1 赛题背景
在 rk3588/sg2002 开发板上实现 ACT(Action Chunking Transformer)模型推理,为移动机器人提供感知-决策能力。
推理规格:
- 输入:RGB 图像 224x224 + 机器人状态
[left_vel, right_vel] - 输出:8 步动作序列
[left_vel, right_vel, gripper_target] - 预处理:ImageNet 归一化 + QUANTILES 归一化
- 后处理:动作反归一化 + 方向判断
1.5.2 QEMU 阶段(5月28日)
快速原型:
- 第一天即在 QEMU StarryOS 中跑通 ACT 推理
- 推理引擎:
tract(纯 Rust ONNX runtime) - 平台:QEMU riscv64 + musl
关键指标:
- 模型:193.25 MiB ONNX
- 二进制:~17.26 MiB (riscv64)
- 推理耗时:~25,233 ms
- 验证:golden 对照通过
1.5.3 RK3588 阶段(6月2日-6月13日)
6月2日:rk3588 到货
6月3日-6月7日:镜像构建探索
- 研究香橙派官方镜像结构
- 分析 FIT image、U-Boot、DTB 布局
- 手动构建 StarryOS 启动链
6月8日-6月9日:RKNN 推理实现
- 集成 RKNPU2 runtime SDK
- 实现 ONNX → RKNN 转换
- 完成用户态推理程序
6月10日:多核与局部更新
- 更新 StarryOS 镜像支持多核
- 实现镜像局部更新脚本(避免完整重刷)
6月11日:突破与验证
- 关键决策:更换为官方香橙派 DTB 以支持 NPU 驱动
- 在板上跑通 ACT 推理,输出正确
- 验证:golden 对照通过,左转/右转样例通过
6月13日-6月15日:性能对比与文档
- 实现分阶段计时(模型加载/预处理/NPU 执行/后处理)
- StarryOS vs Linux 对比测试
- 固化镜像构建工作流(rootfs overlay + FIT repack)
- 撰写交付报告和复现文档
1.5.4 关键技术突破
镜像构建固化:
1 | # 工作流 |
性能优化:
| 阶段 | Linux | StarryOS | 倍数 |
|——|——-|———-|——|
| NPU 执行 | 32.4ms | 28.6ms | 0.88x |
| 端到端 | 22.3ms | 29.9ms | 1.34x |
| 模型加载 | 37ms | 228ms | 6.17x |
结论:
- NPU 执行阶段 StarryOS 已优于 Linux
- 瓶颈在模型加载和预处理,非推理核心
1.5.5 SG2002 计划
- 当前状态:尚未开始
- 后续:申请 sg2002 开发板
- 技术路径:ONNX → CVITEK TPU,参考 rk3588 流程
对应分支
proj57(未合并)- 位置:
wt-proj57/proj57/{qemu,rk3588}/
二、方法与经验
2.1 测试框架设计模式
在 Nginx 和 Apache 测试中形成的可复用模式:
三层测试体系
- smoke:CI 快速验证,覆盖基础功能
- phase:阶段性递进测试,覆盖完整生命周期
- debug:自由度高的问题定位脚本
统一 runner 架构
- 单一入口脚本
- 模式切换通过参数控制
- 超时和清理统一处理
分层 QEMU 配置
qemu/all/:完整测试(CI 默认)qemu/phase/:单阶段快速验证qemu/debug/:调试配置(更多资源)
2.2 典型教训
性能问题需分段计时
- x86 短连接超时案例:误判为网络栈问题,实际是进程启动开销
- 教训:先做分段计时,再下结论
smoke 测试范围要保守
- Apache
TCP_DEFER_ACCEPT案例:在 reviewer 环境失败 - 策略:smoke 只覆盖确定可用的功能,可选特性放到 debug
- Apache
小步快跑的重要性
- 反面案例:方案三很多想法(网络命名空间、流水线推理)未落地
- 原因:步子太大,未及时拆分和提交
2.3 工具建设的价值
net-bench 和 eBPF 工具虽然尚未完全成熟,但建立了方法论:
- 自动化环境配置和清理
- 状态跟踪和回退保护
- 内核态观测能力(eBPF)
这些为后续网络栈持续优化提供了基础。
三、产出索引
3.1 已合并 PR(共 9 个)
- #658: epoll 测试
- #900: epoll/sigmask sigsetsize 修复
- #903: 文件同步系统调用对齐
- #1014: Nginx CI 初始实现
- #1018: 多 worker 信号中断修复
- #1038: Nginx 完整测试框架
- #1267: 动态启动路径修复
- #1297: x86 IPI 修复
- #1316: VmPeak & VmHWM 增强
3.2 开放 PR(共 2 个)
- #1311: Apache 测试框架 (Open)
- #1417: net-bench 网络性能测试框架 (Open)
3.3 独立分支(未合并)
test/alpine-nginx:Nginx 测试最新版本test/alpine-apache:Apache 测试feat/net-enhance:网络性能测试框架proj57:ACT 推理 QEMU + RK3588
3.4 工作仓库
四、致谢与总结
感谢助教 Mr Graveyard(方案一)、Ajax(rk3588)、周睿老师(rk3588 NPU 优化和 PR review)的帮助。感谢同组学员 aptacc2421、WellDown64 的讨论交流,感谢龙同学(LetsWalkInLine)交接的初步 Nginx 支持。特别感谢 CN-TangLin 同学的 eBPF 内核运行时工作,为网络观测工具提供了基础。
这次训练营让我从”写测试”进阶到”建框架”,从”跑通功能”深入到”定位根因”。最大的收获不是代码量,而是工程方法上的变化:更重视测试覆盖、问题跟踪和工具建设,也更能把复杂问题拆成可验证的小问题逐步推进。
后续计划:完善 net-bench 集成、推动 Apache 测试合并、完成 sg2002 ACT 推理、参与网络栈持续优化。