docs: update README.md test
🔥 基于 RISC-V Vector 扩展的 LLM 推理 V 状态感知调度优化
本项目是为”第三届中国研究生操作系统开源创新大赛”设计的参赛作品,在国产 RISC-V 硬件平台(Milk-V Jupiter / SpacemiT K1)上,通过 eBPF/bpftrace 量化分析 + sched_ext 自定义调度器,优化 LLM 推理场景下 RISC-V Vector 寄存器状态切换开销导致的吞吐下降与尾延迟恶化问题。
LLM 推理是典型的高强度持续向量计算场景。在 RISC-V 架构中,每个 hart 拥有 32 个向量寄存器(v0–v31),单次完整 V 状态保存需要 512 字节以上的内存写入。Linux 默认调度策略(CFS)对向量密集型推理线程与普通线程一视同仁,导致推理线程在计算关键路径上被频繁抢占,不断累积的 V 状态切换开销造成整体吞吐下降与尾延迟恶化。
本项目的核心目标是:量化 V 状态上下文切换开销,优化推理的 TTFT 和 TPS。
在 Milk-V Jupiter(SpacemiT K1,RVV 1.0,VLEN=256)上用 llama.cpp 的 llama-server 做多请求并发推理,同时板上还有系统任务或其他 CPU 负载。推理线程被抢占时要保存、恢复向量寄存器。本仓库用来统计这类 V 状态切换,并把它和同一次运行的吞吐、TTFT 放在一起比较;再用绑核、cgroup 或 sched_ext 把矩阵乘 worker 与普通任务分开。
llama-server
riscv-llm-scheduler/ ├── README.md ├── src/ # 🎯 核心源代码 │ ├── tracker/ # 📊 量化分析工具(bpftrace 脚本) │ │ ├── vstate_trace.bt # 基础版:全局 V 状态统计 │ │ ├── vstate_trace_cpu.bt # per-CPU 增强版:核级别 V 状态分布 │ │ ├── vstate_trace_llama_server.bt # llama-server 专用:save/restore 与切换耗时 │ │ └── README.md │ ├── scheduler/ # ⚙️ 调度优化实现 │ │ ├── vec_affine_sched.bpf.c # sched_ext BPF 内核态调度引擎 │ │ ├── vec_affine_sched.c # sched_ext 用户态 Loader │ │ ├── 自定义调度.md # sched_ext 设计文档 │ │ └── README.md │ └── benchmark/ # 🧪 性能评测脚本 │ ├── benchmark_llama.py # 基准测试主脚本(QEMU/本机/远程) │ ├── bench_runner.py # 自动化测试运行器(单配置) │ ├── bench_runner_all.py # 自动化测试运行器(多配置批量) │ ├── bench_runner_final.py # 终版场景运行器 │ ├── cb_ab.py # Continuous Batching 开关对照 │ ├── plot_cb_ab.py # CB 对照结果绘图 │ ├── quantification.py # V 状态量化统计脚本 │ ├── README.md │ └── README_bench_runner.md ├── docs/ # 📖 提交文档与技术调研 │ ├── 项目说明书.pdf │ ├── 项目创新说明.pdf │ ├── 成员分工及主要贡献说明.pdf │ ├── 人工智能及第三方工具使用说明.pdf │ ├── competition/ # 赛题说明与任务拆解 │ ├── scheduler/ # 调度器调研(CFS、其他策略、llama-server 请求调度) │ ├── tracker/ # 跟踪工具与性能指标调研 │ ├── setup/ # 环境搭建指南(QEMU、板卡选型、OS 移植、llama.cpp) │ ├── benchmark/ # 性能评测方法与指标定义 │ ├── x86-vstate/ # x86 "V"状态 横向对比调研 │ └── llama-server-cr-fix/ # llama-server -Cr/-Crb 修复方案 ├── tests/ # 📈 测试及验证材料 │ ├── rvv/ # 真实 RVV 板卡 benchmark 数据(1B/3B/8B 与 3B 并发) │ ├── quantification/ # V 状态量化实验结果 │ ├── sched_ext/ # 自定义调度器实验结果(CFS / 两种时间片,含高负载) │ ├── test/ # 绑核/调度策略对比测试(group1~10) │ ├── final_test/ # 终版场景;stress_test/ 为 stress-ng 分级负载 │ ├── benchmark/ # CB 开关对照原始结果与图 │ └── README.md ├── demo/ # 🎥 实机运行录像(索引见 demo/README.md) │ ├── 绑核+策略方法/ │ └── 自定义调度/ ├── presentation/ # 🎤 决赛演示材料 │ ├── 决赛现场演示PPT.pptx │ └── 决赛演示视频.mp4 ├── hardware/ # 🔌 硬件配置与使用说明 │ └── README.md ├── 作品原创承诺书.pdf └── .github/ # 🔄 CI 工作流与 PR 模板
项目管理使用飞书,代码仓库托管在 GitLink。成员分工见 docs/成员分工及主要贡献说明.pdf。
通过 bpftrace 挂载 sched:sched_switch tracepoint,在内核上下文切换时从内核栈指定偏移读取 pt_regs.status 的 VS 域,判断被切换进程的 V 状态是否 dirty,从而量化统计 V 状态 save/restore 次数。
sched:sched_switch
pt_regs.status
vstate_trace.bt
vstate_trace_cpu.bt
vstate_trace_llama_server.bt
💡 不依赖 riscv_vstate_save 的具体内核符号,通过 tracepoint 接口采集,兼容性更好。
riscv_vstate_save
已实现多种 V 状态感知的调度优化策略:
taskset -c X-Y
cpuset.cpus
cpuset.cpus.partition=root
AllowedCPUs
systemd-run --scope
taskset
chrt -b 0
chrt -f 90
-Cr
--cpu-range
vec_affine_sched
基于 Linux sched_ext 框架实现的 RISC-V 异构核心感知调度器。通过 eBPF + Uprobe 实现 LLM 推理线程的精准识别与硬隔离:
ggml_compute_forward_mul_mat
完整的自动化测试工具链,支持多模型、多并发、多策略的对比测试:
benchmark_llama.py
bench_runner.py
bench_runner_all.py
bench_runner_final.py
cb_ab.py
quantification.py
📊 输出指标:
CONFIG_SCHED_CLASS_EXT
CONFIG_BPF
实验板卡为 openEuler,内核 6.18.38。开启 sched_ext 的移植步骤见 OS移植方法。
qemu-system-riscv64 -cpu rv64,v=true,vlen=256,elen=64,vext_spec=v1.0
CONFIG_BPF_EVENTS
CONFIG_DEBUG_INFO_BTF
bpftrace
clang
bpftool
gcc
python3
python3-requests
curl
python3-numpy
stress-ng
pip install paramiko requests numpy
matplotlib
bpftrace 脚本和 Python 评测脚本没有单独的安装包。llama-server 不在本仓库内编译。
追踪脚本与评测脚本无需编译。需要在板卡上编译的是 src/scheduler/ 中的 vec_affine_sched。在该目录执行:
src/scheduler/
# 1. 从运行中的内核导出类型 bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h # 2. 编译 BPF 字节码(include 换成当前内核树) clang -g -O2 -target bpf -D__TARGET_ARCH_riscv \ -I/path/to/linux/tools/sched_ext/include \ -I. -c vec_affine_sched.bpf.c -o vec_affine_sched.bpf.o # 3. 生成 skeleton bpftool gen skeleton vec_affine_sched.bpf.o > vec_affine_sched.skel.h # 4. 编译 loader(libbpf 与头文件路径换成当前内核树) gcc -g -O2 -Wall -I. \ -I/path/to/linux/tools/include \ -I/path/to/linux/tools/lib \ vec_affine_sched.c /path/to/linux/tools/lib/bpf/libbpf.a \ -lelf -lz -o vec_affine_sched
实验机上的完整 include 路径见 src/scheduler/README.md。内核配置与交叉编译见 OS移植方法。
终版实验使用两套已装到板卡上的 llama.cpp:优化版(spacemit)和普通版(通用 RVV)。二进制与 libggml-cpu.so 路径写在 src/benchmark/bench_runner_final.py 的 LLAMA_BUILDS 中,换环境时改这里。
libggml-cpu.so
src/benchmark/bench_runner_final.py
LLAMA_BUILDS
本项目使用 Llama-3.2 Instruct Q4_K_M GGUF 量化模型:
/root/Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf
# 下载示例 huggingface-cli download hugging-quants/Llama-3.2-3B-Instruct-Q4_K_M-GGUF \ llama-3.2-3b-instruct-q4_k_m.gguf --local-dir /path/to/models
追踪和 llama-server、sched_ext 在板卡上运行。评测脚本在宿主机运行,通过 SSH 操作板卡。调度器需先按上一节编译。
测试前固定到 performance 模式:
performance
sudo cpupower frequency-set -g performance
测试完成后恢复:
sudo cpupower frequency-set -g conservative
# 基础版 — 全局统计 sudo bpftrace src/tracker/vstate_trace.bt # per-CPU 增强版 — 推荐 sudo bpftrace src/tracker/vstate_trace_cpu.bt # llama-server 专用版 — 只统计该进程,并记录切换耗时 sudo bpftrace src/tracker/vstate_trace_llama_server.bt # 输出重定向到文件 sudo bpftrace src/tracker/vstate_trace_cpu.bt > /tmp/vstate_result.log
# 基础启动 ./llama-server-rvv -m Llama-3.2-3B-Instruct-Q4_K_M.gguf \ --port 8080 -c 8192 --host 0.0.0.0 --parallel 8 # 带绑核启动(优化方案) taskset -c 4-7 ./llama-server-rvv -m Llama-3.2-3B-Instruct-Q4_K_M.gguf \ --port 8080 -c 8192 --host 0.0.0.0 --parallel 4 -t 4
# 基本运行(无 Uprobe 精准标记) ./vec_affine_sched # 挂载 Uprobe 到 libggml-cpu.so,精准识别推理线程 ./vec_affine_sched -t /path/to/libggml-cpu.so
# 宿主机安装依赖 pip install paramiko requests numpy # 本机模式 python src/benchmark/benchmark_llama.py --mode local --concurrency 2,4,8 --trials 3 # 远程板卡(普通模式) python src/benchmark/benchmark_llama.py \ --mode remote --host <板卡IP> --ssh-user root \ --concurrency 2,4,8 --trials 3 # 自动化实验矩阵(远程板卡) python src/benchmark/benchmark_llama.py \ --mode remote --host <板卡IP> --ssh-user root \ --experiment-matrix full \ --server-binary /root/llama-server-rvv \ --server-threads 4 --context-per-slot 1024 \ --output-dir results # 一键多组对比测试 python src/benchmark/bench_runner_all.py # 终版场景(先改 SCENARIOS / RUN 和板卡路径) python src/benchmark/bench_runner_final.py
运行前把 bench_runner.py、bench_runner_all.py、bench_runner_final.py 顶部的板卡地址、SSH、模型路径和结果目录改成当前环境。
bench_runner.py (宿主机) │ ├─ SSH → 板卡: 启动 llama-server(带绑核/调度参数) ├─ SSH → 板卡: 启动 bpftrace(vstate_trace_cpu.bt) ├─ SSH → 板卡: 部署并运行 HTTP 并发请求脚本 ├─ SSH → 板卡: 轮询等待请求完成 ├─ SSH → 板卡: 停止 bpftrace + 拉取 V 状态数据 └─ 本地: 解析 JSON → 计算 TPS/TTFT/P95 → 输出 CSV
sched_switch
python src/benchmark/bench_runner_all.py
python src/benchmark/bench_runner.py
python src/benchmark/bench_runner_final.py
benchmark_llama.py --experiment-matrix full
python src/benchmark/cb_ab.py
bench_runner*.py 的 CSV 写到脚本里的结果目录(实验时为宿主机上的 D:/比赛/results/)。仓库里的 tests/ 是归档副本。
bench_runner*.py
D:/比赛/results/
tests/
CB 对照在宿主机设置 BOARD_HOST、BOARD_USER、BOARD_PASS、LLAMA_SERVER_BIN、LLAMA_MODEL_PATH 后执行。绘图:
BOARD_HOST
BOARD_USER
BOARD_PASS
LLAMA_SERVER_BIN
LLAMA_MODEL_PATH
python src/benchmark/cb_ab.py --concurrency 8 --requests 24 --trials 3 --warmup 1 --tag cb8 python src/benchmark/plot_cb_ab.py
指标口径、控制变量和字段见 性能评测指南。单配置运行器的方法顺序见 README_bench_runner.md。
功能验证确认四个环节可以进入集成测试:llama-server 在 Milk-V Jupiter 上加载 Llama 3.2 1B 与 3B,启动日志含 RISCV_V = 1,/health 返回 200,单次请求能返回流式结果;vstate_trace_cpu.bt 能输出 saves_total、restores_total 以及进程级和 per-CPU 计数,这些计数是 V 状态条件事件,不是寄存器保存函数的直接调用次数;benchmark_llama.py 能写出吞吐、TTFT、E2E、token 数和 V 状态字段;taskset / chrt / cgroup 的允许 CPU 与调度属性可核对,vec_affine_sched 能完成加载、回调执行和卸载。
RISCV_V = 1
/health
saves_total
restores_total
chrt
taskset、cpuset、partition-root、systemd-scope、taskset-chrt-b(SCHED_BATCH)、taskset-chrt-f(SCHED_FIFO)各在 6 组参数下跑 3 次,共 108 轮、5400 条请求。每轮开头通常有 2–4 个请求的 TTFT 明显高于稳态,约占 4%,为稳态值的 15–61 倍,稳态分析中单独处理。下表以 taskset 的一组数据为例。
排除冷启动后,六种方法的稳态结果如下。
无外部负载时,默认调度与 vec_affine_sched 在 --parallel 2 / 4 / 8 下各重复 3 次,其余参数相同。原始数据在 tests/final_test/。
--parallel
par 2:
par 4:
par 8:
三档并发的聚合吞吐差异都不足 1%,平均 TTFT 与 P95 TTFT 的差距在 5% 以内。V 状态保存次数在 par 2、par 4 下 sched_ext 分别高出 49% 与 23%(90880 对 135451,63452 对 78225),par 8 时低约 23%(83863 对 64787)。两类切换的单次耗时为数十微秒(V 状态 27–33 µs,非 V 状态 13–16 µs)。
该场景不存在需要调度器裁决的 CPU 竞争:推理线程数为 4,板卡有 8 个核,稳态时每个可运行线程都能立即获得 CPU,端到端延迟由 prefill 与 decode 的计算量决定。27–33 µs 的 V 状态切换相对数百毫秒的 TTFT 可忽略。保存次数和前四核保存占比有差别,说明调度行为被改变,但未反映到端到端指标。收益需在有 CPU 竞争时才能体现。
在同样的推理配置上叠加 stress-ng,对全部 8 个核施加占空比 20%、40%、60%、80%、100% 的忙循环。有外部负载时,sched_ext 下的推理性能较默认调度明显改善,且随负载率提升,对 TPS 与 TTFT 的优化越大。60% 负载起两条曲线分开。100% 负载下,sched_ext 的吞吐是默认调度的 2.8 / 2.5 / 2.0 倍(par 2 / 4 / 8),P95 TTFT 低 4.6 / 3.4 / 2.7 倍;相对无负载基线,sched_ext 仍保留 66% / 71% / 74% 的吞吐,默认调度保留 23% / 29% / 37%。
V 状态切换开销在端到端时延中的占比很小,这决定了各类绑核与调度手段能够带来的性能改善上限。
六种绑核与基础调度方法可以改变 V 状态保存次数,但对 TPS 与 TTFT 均未带来可见改善。V 状态切换单次耗时约 27–33 µs,V 状态与非 V 状态切换的整轮累计耗时约 4–8 s,仅占整轮墙钟时间(465–588 s)的 0.8%–1.4%。减少保存次数本身不能带来明显的性能收益。
无外部负载时不存在 CPU 争用,sched_ext 在默认调度基础上基本无优化。外部负载造成算力争用后,调度的价值在于优先保障推理线程:无争用或低负载时,绑核和自定义调度都不改变端到端性能;当出现资源竞争,影响才会传到 TPS 与 TTFT 上,满负载时,TPS达到原来的1.99–2.82 倍,P95 TTFT降低62.8%–78.0%。
决赛材料在仓库内:
分方法的实机录像在 demo/:绑核与调度策略(taskset、cpuset、partition-root、systemd-scope、SCHED_BATCH、SCHED_FIFO、-Cr),以及 CFS / sched_ext 在正常负载和高负载下的对照。对应数值在 tests/。
finish_task_switch
task_struct
tests/sched_ext/
src/scheduler/README.md
stress-ng --cpu-method all
本项目基于 MIT License 开源协议。
🏆 第三届中国研究生操作系统开源创新大赛 参赛作品
Built with ❤️ for RISC-V & Open Source Community
版权所有:中国计算机学会技术支持:开源发展技术委员会 京ICP备13000930号-9 京公网安备 11010802047560号
🚀 面向 RISC-V Vector 扩展的大语言模型推理并发调度优化
🔥 基于 RISC-V Vector 扩展的 LLM 推理 V 状态感知调度优化
本项目是为”第三届中国研究生操作系统开源创新大赛”设计的参赛作品,在国产 RISC-V 硬件平台(Milk-V Jupiter / SpacemiT K1)上,通过 eBPF/bpftrace 量化分析 + sched_ext 自定义调度器,优化 LLM 推理场景下 RISC-V Vector 寄存器状态切换开销导致的吞吐下降与尾延迟恶化问题。
📚 项目概述
LLM 推理是典型的高强度持续向量计算场景。在 RISC-V 架构中,每个 hart 拥有 32 个向量寄存器(v0–v31),单次完整 V 状态保存需要 512 字节以上的内存写入。Linux 默认调度策略(CFS)对向量密集型推理线程与普通线程一视同仁,导致推理线程在计算关键路径上被频繁抢占,不断累积的 V 状态切换开销造成整体吞吐下降与尾延迟恶化。
本项目的核心目标是:量化 V 状态上下文切换开销,优化推理的 TTFT 和 TPS。
应用场景
在 Milk-V Jupiter(SpacemiT K1,RVV 1.0,VLEN=256)上用 llama.cpp 的
llama-server做多请求并发推理,同时板上还有系统任务或其他 CPU 负载。推理线程被抢占时要保存、恢复向量寄存器。本仓库用来统计这类 V 状态切换,并把它和同一次运行的吞吐、TTFT 放在一起比较;再用绑核、cgroup 或 sched_ext 把矩阵乘 worker 与普通任务分开。⭐ 核心亮点
🏗️ 项目结构
📋 赛题要求与完成进度
项目代码(40 分)
技术报告(40 分)
开发过程(20 分)
项目管理使用飞书,代码仓库托管在 GitLink。成员分工见 docs/成员分工及主要贡献说明.pdf。
⭐ 主要功能
📊 量化分析工具
通过 bpftrace 挂载
sched:sched_switchtracepoint,在内核上下文切换时从内核栈指定偏移读取pt_regs.status的 VS 域,判断被切换进程的 V 状态是否 dirty,从而量化统计 V 状态 save/restore 次数。vstate_trace.btvstate_trace_cpu.btvstate_trace_llama_server.btllama-server的切换,并区分 V 状态与非 V 状态切换耗时⚙️ 调度优化实现
已实现多种 V 状态感知的调度优化策略:
taskset -c X-Y将推理线程绑定到指定核心cpuset.cpus+ PID 移入cpuset.cpus.partition=root,独占核心AllowedCPUs+systemd-run --scopetaskset+chrt -b 0taskset+chrt -f 90-Cr--cpu-range,只约束计算线程vec_affine_sched— BPF 可编程调度器,异构核心硬隔离🧠 vec_affine_sched — sched_ext 自定义调度器
基于 Linux sched_ext 框架实现的 RISC-V 异构核心感知调度器。通过 eBPF + Uprobe 实现 LLM 推理线程的精准识别与硬隔离:
ggml_compute_forward_mul_mat函数,标记真正的矩阵乘法推理线程🧪 性能评测框架
完整的自动化测试工具链,支持多模型、多并发、多策略的对比测试:
benchmark_llama.pybench_runner.pybench_runner_all.pybench_runner_final.py-Cr、sched_ext、stress-ngcb_ab.pyquantification.py📊 输出指标:
🛠️ 系统环境
🔌 硬件要求
💻 软件环境
CONFIG_SCHED_CLASS_EXT、CONFIG_BPF)实验板卡为 openEuler,内核 6.18.38。开启 sched_ext 的移植步骤见 OS移植方法。
🔬 QEMU 验证环境
依赖要求
CONFIG_BPF、CONFIG_BPF_EVENTS、CONFIG_DEBUG_INFO_BTF;使用 sched_ext 时再开启CONFIG_SCHED_CLASS_EXTbpftrace、clang、bpftool、gcc、libbpf、libelf、zlib;python3、python3-requests、curl;绑核批量测试另需python3-numpy;分级负载测试另需stress-ngpip install paramiko requests numpy。重绘 CB 对照图另需matplotlibllama-server,以及 Llama-3.2 Instruct Q4_K_M GGUFbpftrace 脚本和 Python 评测脚本没有单独的安装包。
llama-server不在本仓库内编译。构建方法
追踪脚本与评测脚本无需编译。需要在板卡上编译的是
src/scheduler/中的vec_affine_sched。在该目录执行:实验机上的完整 include 路径见 src/scheduler/README.md。内核配置与交叉编译见 OS移植方法。
终版实验使用两套已装到板卡上的 llama.cpp:优化版(spacemit)和普通版(通用 RVV)。二进制与
libggml-cpu.so路径写在src/benchmark/bench_runner_final.py的LLAMA_BUILDS中,换环境时改这里。📦 模型下载
本项目使用 Llama-3.2 Instruct Q4_K_M GGUF 量化模型:
/root/Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf,见 性能评测指南🚀 运行方法
追踪和
llama-server、sched_ext 在板卡上运行。评测脚本在宿主机运行,通过 SSH 操作板卡。调度器需先按上一节编译。⚡ 1. 性能 Governor 设置
测试前固定到
performance模式:测试完成后恢复:
📡 2. V 状态追踪
🦙 3. 推理服务启动
🧠 4. sched_ext 调度器部署
🧪 5. Benchmark 测试
运行前把
bench_runner.py、bench_runner_all.py、bench_runner_final.py顶部的板卡地址、SSH、模型路径和结果目录改成当前环境。🔄 数据流
💡 技术特色
🏆 创新点
sched_switchtracepoint 读取pt_regs.status的 VS 域,通用性优于 kprobe 挂载特定内核符号-Cr与 sched_ext 放在同一评测框架里比较🎯 技术优势
测试方法
python src/benchmark/bench_runner_all.pypython src/benchmark/bench_runner.py-Cr、sched_ext、stress-ngpython src/benchmark/bench_runner_final.pybenchmark_llama.py --experiment-matrix fullpython src/benchmark/cb_ab.pyvec_affine_sched,再用评测脚本bench_runner*.py的 CSV 写到脚本里的结果目录(实验时为宿主机上的D:/比赛/results/)。仓库里的tests/是归档副本。CB 对照在宿主机设置
BOARD_HOST、BOARD_USER、BOARD_PASS、LLAMA_SERVER_BIN、LLAMA_MODEL_PATH后执行。绘图:指标口径、控制变量和字段见 性能评测指南。单配置运行器的方法顺序见 README_bench_runner.md。
🧪 测试验证
功能验证确认四个环节可以进入集成测试:llama-server 在 Milk-V Jupiter 上加载 Llama 3.2 1B 与 3B,启动日志含
RISCV_V = 1,/health返回 200,单次请求能返回流式结果;vstate_trace_cpu.bt能输出saves_total、restores_total以及进程级和 per-CPU 计数,这些计数是 V 状态条件事件,不是寄存器保存函数的直接调用次数;benchmark_llama.py能写出吞吐、TTFT、E2E、token 数和 V 状态字段;taskset/chrt/ cgroup 的允许 CPU 与调度属性可核对,vec_affine_sched能完成加载、回调执行和卸载。六种通用方法
taskset、cpuset、partition-root、systemd-scope、taskset-chrt-b(SCHED_BATCH)、taskset-chrt-f(SCHED_FIFO)各在 6 组参数下跑 3 次,共 108 轮、5400 条请求。每轮开头通常有 2–4 个请求的 TTFT 明显高于稳态,约占 4%,为稳态值的 15–61 倍,稳态分析中单独处理。下表以 taskset 的一组数据为例。
排除冷启动后,六种方法的稳态结果如下。
sched_ext
无外部负载时,默认调度与
vec_affine_sched在--parallel2 / 4 / 8 下各重复 3 次,其余参数相同。原始数据在 tests/final_test/。par 2:
par 4:
par 8:
三档并发的聚合吞吐差异都不足 1%,平均 TTFT 与 P95 TTFT 的差距在 5% 以内。V 状态保存次数在 par 2、par 4 下 sched_ext 分别高出 49% 与 23%(90880 对 135451,63452 对 78225),par 8 时低约 23%(83863 对 64787)。两类切换的单次耗时为数十微秒(V 状态 27–33 µs,非 V 状态 13–16 µs)。
该场景不存在需要调度器裁决的 CPU 竞争:推理线程数为 4,板卡有 8 个核,稳态时每个可运行线程都能立即获得 CPU,端到端延迟由 prefill 与 decode 的计算量决定。27–33 µs 的 V 状态切换相对数百毫秒的 TTFT 可忽略。保存次数和前四核保存占比有差别,说明调度行为被改变,但未反映到端到端指标。收益需在有 CPU 竞争时才能体现。
在同样的推理配置上叠加 stress-ng,对全部 8 个核施加占空比 20%、40%、60%、80%、100% 的忙循环。有外部负载时,sched_ext 下的推理性能较默认调度明显改善,且随负载率提升,对 TPS 与 TTFT 的优化越大。60% 负载起两条曲线分开。100% 负载下,sched_ext 的吞吐是默认调度的 2.8 / 2.5 / 2.0 倍(par 2 / 4 / 8),P95 TTFT 低 4.6 / 3.4 / 2.7 倍;相对无负载基线,sched_ext 仍保留 66% / 71% / 74% 的吞吐,默认调度保留 23% / 29% / 37%。
测试结论
V 状态切换开销在端到端时延中的占比很小,这决定了各类绑核与调度手段能够带来的性能改善上限。
六种绑核与基础调度方法可以改变 V 状态保存次数,但对 TPS 与 TTFT 均未带来可见改善。V 状态切换单次耗时约 27–33 µs,V 状态与非 V 状态切换的整轮累计耗时约 4–8 s,仅占整轮墙钟时间(465–588 s)的 0.8%–1.4%。减少保存次数本身不能带来明显的性能收益。
无外部负载时不存在 CPU 争用,sched_ext 在默认调度基础上基本无优化。外部负载造成算力争用后,调度的价值在于优先保障推理线程:无争用或低负载时,绑核和自定义调度都不改变端到端性能;当出现资源竞争,影响才会传到 TPS 与 TTFT 上,满负载时,TPS达到原来的1.99–2.82 倍,P95 TTFT降低62.8%–78.0%。
🎥 演示视频
决赛材料在仓库内:
分方法的实机录像在 demo/:绑核与调度策略(taskset、cpuset、partition-root、systemd-scope、SCHED_BATCH、SCHED_FIFO、
-Cr),以及 CFS / sched_ext 在正常负载和高负载下的对照。对应数值在tests/。已知限制
vec_affine_sched按 K1 的核分组编写:矩阵乘 worker 放在 CPU 0–3,普通任务放在 CPU 4–7。vstate_trace_llama_server.bt在finish_task_switch上另行统计。更换内核、板卡或厂商补丁后,需要重新核对 BTF、task_struct和内核栈布局。说明见 性能评测指南。tests/sched_ext/与六种绑核方法的内核和参数不同,只在组内比较。bench_runner.py、bench_runner_all.py、bench_runner_final.py把 SSH、板上路径和结果目录写在脚本里。src/scheduler/README.md里的编译 include 路径对应当时的实验机内核树。换环境需要自行修改。stress-ng --cpu-method all。同一矩阵内参数一致,但单次负载稳定性低于固定压力方法。📚 参考资料
📄 许可证
本项目基于 MIT License 开源协议。
🏆 第三届中国研究生操作系统开源创新大赛 参赛作品
Built with ❤️ for RISC-V & Open Source Community