4月技术报告-周雨
目标与问题
主要目标
- rknpu 任务调度器的正式落地:可以基于优先级调度处理多个线程提交的 submit。
- 驱动的工程化重构:将 RKNPU 驱动抽象为一个独立且通用的 Rust crates 库,外部 OS 通过实现驱动所需的 trait 来使用驱动,实现内核与驱动逻辑的解耦。
- 调度器性能验证:对完成的调度器进行全面的 Benchmark 验证,重点对比多核(3-core)与单核(1-core)在不同尺度 workload 下的提交时间与并行效率,产出完整的性能数据。
具体方案
1. 搭建后台 Worker 推进模型,解耦用户提交与调度器
为了避免用户线程长时间阻塞并承担硬件推进逻辑,我重新设计了提交流程:
- 后台 Worker 线程:设计了专门用于任务调度的 worker 线程。该线程在后台循环推进和调度任务。当没有任务时,worker 线程会进入两阶段睡眠(基于 listen 和 wait),挂起在监听新任务的信号量上;当有新任务入队时,通过全局的 notify_one (kick) 机制去唤醒调度线程。
- 用户态阻塞与唤醒:用户线程只需要调用 ioctl 接口将 NPU 任务入队即可睡眠等待。为此,我为每次 submit 维护了独立的 waiter(基于 RknpuSubmitWaiter trait)。用户线程在提交任务后直接挂起 (wait),直到任务在多核上真正结束并触发 terminal,再由底层调用 complete 唤醒用户线程,安全返回用户态。
2. 将 RKNPU 驱动抽象为通用 Crate
为了让 RKNPU 驱动不依赖于特定的 OS 环境(如 StarryOS),我在 crate 层设计了一套平台相关的 Trait 接口,外部 OS 只需要实现 RknpuPlatform 即可接入驱动。具体拆分如下:
- RknpuDeviceAccess:负责底层设备的临时可变借用(with_device),由 OS 决定低层级 RKNPU 实例的存储和锁机制。
- RknpuUserMemory:抽象了内核与用户态之间的内存拷贝操作(copy_from_user 和 copy_to_user),处理不同 OS 内存管理模型的差异。
- RknpuSchedulerRuntime:抽象了调度器所需的 OS 运行时能力,包括创建等待原语(new_waiter)、创建 Worker 唤醒信号(new_worker_signal)、生成后台 Worker 线程(spawn_worker)以及在硬件执行或调度停滞时的出让机制(yield_now)。
3. 多尺度 workload 的 Benchmark 测试
设计并执行覆盖多种场景的基准测试,包括:
- tiny_dispatch(极小任务调度)
- mid_balanced(中等规模平衡负载)
- throughput_heavy(重吞吐负载)
- llama_decode_like(模拟大模型解码负载)
实现结果
1. 调度模型与并发机制成功运行
成功实现了基于 Worker 线程和任务信号量的调度模型。底层通过 RknpuWorkerSignal 和 RknpuSubmitWaiter 实现了可靠的两阶段休眠与唤醒机制,彻底解决了用户态提交与底层硬件执行的深度耦合,多进程争抢 NPU 时的调度变得更加平滑。
2. 驱动 crate 化解耦完成
完成 rknpu crate 的重构,成功将平台强相关的内存拷贝、设备锁等待以及线程调度抽离到 RknpuPlatform trait 中。这证明了驱动的主体逻辑能够以纯库(Library)的形式独立演进,大幅提升了后续移植和维护的工程效率。
3. Benchmark 测试与多核性能验证
完成了全量 Benchmark 测试。结合日志数据,得出了明确的结论:在中大型任务场景下,多核并行已经能够稳定地带来明显的正向收益。 具体的几组明确结果如下:
- mid_balanced 场景:1-core 的平均提交时间从 56.158 ms 降到了 3-core 的 39.204 ms,加速比达到了 1.432x,并行效率为 47.75%。
- throughput_heavy 场景:1-core 的平均提交时间从 76.605 ms 降到了 40.824 ms,加速比提升至 1.876x,并行效率达到了 62.55%。
- llama_decode_like 场景:1-core 平均提交时间从 423.358 ms 降到了 231.858 ms,加速比达到 1.826x,并行效率为 60.86%。 结论:数据有力地证明了,在重负载(如吞吐密集型和模拟大模型推理场景)下,当前的 crate 化调度机制和多核分发路径是稳定且具备实战价值的。但在极小任务(如 tiny_dispatch)下,由于调度本身的软件开销,多核加速比不明显甚至可能出现负收益,这也为下阶段(如探索 fast-path 或 batching 提交)指明了优化方向。