目录

🚀 面向 RISC-V Vector 扩展的大语言模型推理并发调度优化

Platform RVV Language Scheduler License

🔥 基于 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 与普通任务分开。

⭐ 核心亮点

  • ✅ 完整的量化分析工具链:基于 bpftrace 的 V 状态切换追踪,支持 per-CPU 细粒度统计
  • ✅ 多层级调度优化方案:CPU affinity / cgroup cpuset / sched_ext 自定义调度器全覆盖
  • ✅ 自动化性能评测框架:一键完成多模型、多并发、多策略的对比测试
  • ✅ 异构核心硬隔离:sched_ext 调度器实现推理线程与普通任务的物理核心隔离
  • ✅ 国产化 RISC-V 方案:基于 SpacemiT K1(RVV 1.0, VLEN=256)真实硬件验证

🏗️ 项目结构

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 模板

📋 赛题要求与完成进度

项目代码(40 分)

子项 分值 评分标准 状态
a) 代码功能实现度 15 分 实现 V 状态上下文切换开销的量化分析工具,统计 V 状态保存/恢复次数、riscv_vstate_save 调用频次、dirty V 线程被抢占事件,并量化其开销 ✅ 已完成
a) 代码功能实现度 10 分 实现至少一种 V 状态感知调度优化策略,功能完整、可正常运行 ✅ 已完成
b) 代码实现正确性与性能 10 分 在不少于 2 种并发场景下,TPS / 平均 TTFT / P95 TTFT 相比统一基线有稳定、可重复的改善 ✅ 已完成
c) 代码质量与风格 5 分 代码结构清晰,关键逻辑有注释,提供完整的构建与运行说明 ✅ 已完成

技术报告(40 分)

子项 分值 评分标准 状态
a) 设计方案 10 分 V 状态切换问题分析准确,调度优化方案设计清晰,说明与现有 Linux 调度机制(CFS、lazy save)的关系 ✅ 已完成
b) 实现方案 10 分 实现细节描述完整,包含系统架构图或关键流程图,对已有相关工作(sched_ext、RVV 推理优化等)有准确调研与引用 ✅ 已完成
c) 运行效果/测试结果 10 分 测试数据规范(含测试环境描述、统一基线配置说明、均值与标准差、各并发档位结果),实验可复现,提供演示视频(3–5 分钟);性能数据来自真实 RVV 1.0 硬件 ✅ 已完成
d) 特色创新 10 分 方案提出新的调度原语、用户态-内核协同机制,或对问题有更深层次的分析与拓展 ✅ 已完成

开发过程(20 分)

项目管理使用飞书,代码仓库托管在 GitLink。成员分工见 docs/成员分工及主要贡献说明.pdf。

子项 分值 评分标准 状态
e) 代码提交情况 15 分 Git 提交历史规范,工作量分布合理,提交信息清晰,体现迭代过程 ✅ 已完成
f) 团队协作情况 5 分 成员分工明确,协作有效 ✅ 已完成

⭐ 主要功能

📊 量化分析工具

通过 bpftrace 挂载 sched:sched_switch tracepoint,在内核上下文切换时从内核栈指定偏移读取 pt_regs.status 的 VS 域,判断被切换进程的 V 状态是否 dirty,从而量化统计 V 状态 save/restore 次数。

脚本 功能
vstate_trace.bt 基础版 — 全局统计 V 状态 save/restore 总次数,按进程名和 PID 分组
vstate_trace_cpu.bt per-CPU 增强版 — 每个 CPU 核上的 V 状态分布,用于识别绑核后 V 状态泄漏
vstate_trace_llama_server.bt llama-server 专用版 — 只统计 llama-server 的切换,并区分 V 状态与非 V 状态切换耗时

💡 不依赖 riscv_vstate_save 的具体内核符号,通过 tracepoint 接口采集,兼容性更好。

⚙️ 调度优化实现

已实现多种 V 状态感知的调度优化策略:

方案 原理 隔离方向
CPU affinity taskset -c X-Y 将推理线程绑定到指定核心 单向
cgroup cpuset cgroup 设置 cpuset.cpus + PID 移入 单向
partition-root cgroup + cpuset.cpus.partition=root,独占核心 双向
systemd-scope AllowedCPUs + systemd-run --scope 单向
taskset + SCHED_BATCH taskset + chrt -b 0 单向 + BATCH
taskset + SCHED_FIFO taskset + chrt -f 90 单向 + FIFO
llama-server -Cr 服务端 --cpu-range,只约束计算线程 单向
sched_ext vec_affine_sched — BPF 可编程调度器,异构核心硬隔离 双向

🧠 vec_affine_sched — sched_ext 自定义调度器

基于 Linux sched_ext 框架实现的 RISC-V 异构核心感知调度器。通过 eBPF + Uprobe 实现 LLM 推理线程的精准识别与硬隔离:

  • Uprobe 精准识别:挂载 ggml_compute_forward_mul_mat 函数,标记真正的矩阵乘法推理线程
  • 异构核心硬隔离:推理 worker 绑定 AI 计算核心(CPU 0至3),普通任务隔离到通用核心(CPU 4至7)
  • Prev-CPU 热 Cache 归巢:唤醒推理线程时优先检测原核是否空闲,保留 L1/L2 Cache 热度
  • 差异化时间片:推理线程 30ms 长时间片 vs 普通任务 2ms 短时间片

🧪 性能评测框架

完整的自动化测试工具链,支持多模型、多并发、多策略的对比测试:

工具 功能
benchmark_llama.py 基准测试主脚本,支持 QEMU/本机/远程板卡,含自动化实验矩阵
bench_runner.py 自动化测试运行器(单配置),SSH 连接板卡,自动启停 server + bpftrace
bench_runner_all.py 多配置批量测试,预定义 10 组测试配置自动遍历
bench_runner_final.py 终版场景运行器:构建版本、-Cr、sched_ext、stress-ng
cb_ab.py Continuous Batching 开关对照(单波 / 多请求闭环)
quantification.py V 状态量化统计脚本

📊 输出指标:

指标 单位 说明
TPS / agg_tps token/s 聚合吞吐量,越高越好
Avg TTFT ms 平均首 token 延迟,越低越好
P95 TTFT ms 95 分位首 token 延迟,越低越好
v_saves 次 V 状态保存总数
v_restores 次 V 状态恢复总数
target_saves / nontarget_saves 次 目标/非目标核上的 V 状态 save,用于检测绑核泄漏

🛠️ 系统环境

🔌 硬件要求

项目 说明
型号 Milk-V Jupiter(K1)
主控 SpacemiT K1(1.6GHz, 8 核)
RAM 8GB
RVV 1.0, VLEN=256

💻 软件环境

项目 说明
操作系统 Ubuntu / openEuler(RISC-V)
内核 Linux 6.12+(需开启 CONFIG_SCHED_CLASS_EXT、CONFIG_BPF)
编译器 SPACEMIT RISC-V GCC 交叉编译工具链
bpftrace 用于 V 状态追踪
Python 3 用于 benchmark 脚本(宿主机)
llama.cpp 支持 RVV 1.0 的 llama-server

实验板卡为 openEuler,内核 6.18.38。开启 sched_ext 的移植步骤见 OS移植方法。

🔬 QEMU 验证环境

qemu-system-riscv64 -cpu rv64,v=true,vlen=256,elen=64,vext_spec=v1.0

依赖要求

位置 依赖
板卡内核 CONFIG_BPF、CONFIG_BPF_EVENTS、CONFIG_DEBUG_INFO_BTF;使用 sched_ext 时再开启 CONFIG_SCHED_CLASS_EXT
板卡软件 bpftrace、clang、bpftool、gcc、libbpf、libelf、zlib;python3、python3-requests、curl;绑核批量测试另需 python3-numpy;分级负载测试另需 stress-ng
宿主机 Python 3;pip install paramiko requests numpy。重绘 CB 对照图另需 matplotlib
模型与服务 支持 RVV 1.0 的 llama-server,以及 Llama-3.2 Instruct Q4_K_M GGUF

bpftrace 脚本和 Python 评测脚本没有单独的安装包。llama-server 不在本仓库内编译。


构建方法

追踪脚本与评测脚本无需编译。需要在板卡上编译的是 src/scheduler/ 中的 vec_affine_sched。在该目录执行:

# 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 中,换环境时改这里。


📦 模型下载

本项目使用 Llama-3.2 Instruct Q4_K_M GGUF 量化模型:

模型 大小 下载链接
Llama-3.2-1B-Instruct Q4_K_M ~0.8 GB hugging-quants/Llama-3.2-1B-Instruct-Q4_K_M-GGUF
Llama-3.2-3B-Instruct Q4_K_M ~2.1 GB hugging-quants/Llama-3.2-3B-Instruct-Q4_K_M-GGUF
Meta-Llama-3.1-8B-Instruct Q4_K_M 规模实验 板上路径 /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 操作板卡。调度器需先按上一节编译。

⚡ 1. 性能 Governor 设置

测试前固定到 performance 模式:

sudo cpupower frequency-set -g performance

测试完成后恢复:

sudo cpupower frequency-set -g conservative

📡 2. V 状态追踪

# 基础版 — 全局统计
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

🦙 3. 推理服务启动

# 基础启动
./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

🧠 4. sched_ext 调度器部署

# 基本运行(无 Uprobe 精准标记)
./vec_affine_sched

# 挂载 Uprobe 到 libggml-cpu.so,精准识别推理线程
./vec_affine_sched -t /path/to/libggml-cpu.so

🧪 5. Benchmark 测试

# 宿主机安装依赖
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

💡 技术特色

🏆 创新点

  1. RISC-V V 状态量化方法:通过 bpftrace 挂载 sched_switch tracepoint 读取 pt_regs.status 的 VS 域,通用性优于 kprobe 挂载特定内核符号
  2. 异构核心硬隔离调度器:基于 sched_ext 框架实现推理线程与普通任务的物理核心隔离,结合 Uprobe 实现线程级精准识别
  3. 自研自动化评测框架:一套脚本覆盖 QEMU 验证、本机测试、远程板卡实验矩阵,自动管理 server 生命周期与V状态信息同步采集
  4. 多方案系统对比:taskset、cgroup、partition-root、systemd-scope、SCHED_BATCH、SCHED_FIFO、-Cr 与 sched_ext 放在同一评测框架里比较

🎯 技术优势

  • 完整工具链:从量化分析到调度优化到性能评测的全链路覆盖
  • 硬件无关设计:bpftrace 追踪方案基于 tracepoint 通用接口,兼容不同 RISC-V 内核
  • 自动化程度高:bench_runner 一键完成 server 启停、bpftrace 采集、请求发送、结果汇总
  • 可复现性强:所有实验参数、server 命令、模型等均记录在 CSV 中

测试方法

目的 命令 归档结果
绑核 / 调度策略,10 组参数 python src/benchmark/bench_runner_all.py tests/test/
单组参数轮换方法 python src/benchmark/bench_runner.py 脚本配置的结果目录
构建版本、-Cr、sched_ext、stress-ng python src/benchmark/bench_runner_final.py tests/final_test/
模型规模与并发矩阵 benchmark_llama.py --experiment-matrix full tests/rvv/,索引见 tests/README.md
Continuous Batching 开关 python src/benchmark/cb_ab.py tests/benchmark/cb-ab/,说明见 CB开关对照实验
sched_ext 与 CFS 先运行 vec_affine_sched,再用评测脚本 tests/sched_ext/

bench_runner*.py 的 CSV 写到脚本里的结果目录(实验时为宿主机上的 D:/比赛/results/)。仓库里的 tests/ 是归档副本。

CB 对照在宿主机设置 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 能完成加载、回调执行和卸载。

六种通用方法

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 的一组数据为例。

指标 含冷启动 排除冷启动 偏差
Avg TTFT 4354 ms 2127 ms +105%
P95 TTFT 2162 ms 2153 ms 基本不变

排除冷启动后,六种方法的稳态结果如下。

方法 TPS Avg TTFT (ms) P95 TTFT (ms) V-Saves V/ktok
taskset(基准) 0.90 3146 ± 335 4802 5663980 131111
cpuset 0.90 3135 ± 343 4787 5566101 128845 (-1.7%)
partition-root 0.90 3120 ± 333 4777 2288749 52980 (-59.6%)
systemd-scope 0.90 3125 ± 351 4723 9072549 210013 (+60.2%)
taskset-chrt-b 0.90 3128 ± 253 4786 5062738 117193 (-10.6%)
taskset-chrt-f 0.86 3279 ± 283 4967 503062 11645 (-91.1%)

sched_ext

无外部负载时,默认调度与 vec_affine_sched 在 --parallel 2 / 4 / 8 下各重复 3 次,其余参数相同。原始数据在 tests/final_test/。

par 2:

指标 默认 sched_ext
TPS (tok/s) 5.50 ± 0.01 5.44 ± 0.01
平均 TTFT (ms) 405 ± 1 409 ± 3
P95 TTFT (ms) 472 ± 1 492 ± 22
V_save (次) 90880 ± 4836 135451 ± 8977
V_save 耗时 (µs) 32.9 ± 1.0 29.2 ± 0.3
CPU 0–3 保存占比 (%) 79.0 ± 1.1 88.3 ± 0.5

par 4:

指标 默认 sched_ext
TPS (tok/s) 6.82 ± 0.02 6.86 ± 0.04
平均 TTFT (ms) 652 ± 1 624 ± 21
P95 TTFT (ms) 722 ± 5 712 ± 6
V_save (次) 63452 ± 3827 78225 ± 27926
V_save 耗时 (µs) 30.9 ± 1.1 32.1 ± 5.2
CPU 0–3 保存占比 (%) 71.6 ± 3.8 81.4 ± 5.3

par 8:

指标 默认 sched_ext
TPS (tok/s) 6.85 ± 0.03 6.89 ± 0.01
平均 TTFT (ms) 1110 ± 7 1101 ± 9
V_save (次) 83863 ± 18446 64787 ± 3157
V_save 耗时 (µs) 27.2 ± 1.8 32.8 ± 0.8
CPU 0–3 保存占比 (%) 79.1 ± 4.7 73.9 ± 3.5

三档并发的聚合吞吐差异都不足 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。
  • V 状态 save/restore 是次数。一次计数覆盖整轮请求,不能分到单条 HTTP 请求,次数本身也不能换成微秒。切换耗时由 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

关于
273.3 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号