5.4 KiB
5.4 KiB
CANN Backend Multi-Stream Parallel Implementation
思考过程记录
1. 分析Vulkan后端的多流并行实现
通过分析PR #15489 和 #15850,我了解到Vulkan后端的多流并行实现包含以下两个关键部分:
1.1 PR #15489: 重写同步机制,允许节点之间的重叠执行
核心思想:
- 追踪需要同步的节点列表
- 只有当新节点依赖于未完成的节点时才进行同步
- 这允许一些重叠执行,从而提高性能
关键实现:
- 使用内存范围(地址)来判断依赖关系,而不是直接查看图结构
- 每个预分配的临时缓冲区(如dequantization或split_k)都有一个bool标记,指示它们是否被使用过并需要同步
- 性能提升:在RTX 5090上,部分模型性能提升约5-8%
1.2 PR #15850: 图排序优化,允许更多的并行执行
核心思想:
- 添加backend proc(
graph_optimize)允许后端修改计算图 - Vulkan实现会分析哪些节点相互依赖,并贪婪地重排序它们
- 将不相互依赖的节点分组在一起
关键实现:
ggml_vk_graph_optimize函数实现图优化- 保留特定的fusion pattern不被重排序(如RMS_NORM + MUL)
- 使用两遍扫描:第一遍抓取"real"节点,第二遍抓取view节点
- 最多检查接下来的20个节点是否可以提前执行
2. CANN后端当前状态分析
现有基础设施:
- 已有stream管理(
cann_ctx->stream()) - 支持ACL Graph模式
- 已有同步机制(
aclrtSynchronizeStream) - 后端接口中
graph_optimize目前为NULL
需要添加的功能:
- 实现
ggml_backend_cann_graph_optimize函数 - 可能需要添加多流支持
- 添加环境变量控制开关
3. 设计方案
3.1 实现 graph_optimize 函数
参考Vulkan的实现,我们需要:
static void ggml_backend_cann_graph_optimize(ggml_backend_t backend, struct ggml_cgraph * graph);
核心逻辑:
- 判断是否禁用优化(环境变量控制)
- 定义辅助函数判断节点是否为"空"(VIEW, RESHAPE等)
- 定义辅助函数判断节点依赖关系
- 重排序算法:
- 遍历所有未使用的节点
- 找到可以与当前节点并行执行的节点(不相互依赖)
- 保留fusion pattern
- 更新节点顺序
3.2 环境变量
GGML_CANN_DISABLE_GRAPH_OPTIMIZE: 禁用图优化
4. 实现计划
- 在
ggml-cann.cpp中实现ggml_backend_cann_graph_optimize - 在
ggml_backend_cann_interface中注册该函数 - 编译验证
- 使用Qwen 0.5B模型验证功能正确性
5. 预期收益
根据Vulkan后端的测试结果,图优化可以带来:
- 小模型(1B参数):约5-8%的性能提升
- 中等模型(8B参数):约3-4%的性能提升
- MoE模型:约6-7%的性能提升
这些收益来自于减少同步次数,允许更多操作并行执行。
实现代码
修改文件
ggml/src/ggml-cann/ggml-cann.cpp
主要更改
-
添加头文件:
<algorithm>- 用于std::find<set>- 用于std::set<vector>- 用于std::vector
-
实现
ggml_backend_cann_graph_optimize函数:- 位于
ggml_backend_cann_event_wait函数之后 - 约250行代码
- 参考Vulkan后端的实现
- 位于
-
注册到backend interface:
- 修改
ggml_backend_cann_interface结构体 - 将
graph_optimize从NULL改为ggml_backend_cann_graph_optimize
- 修改
关键算法
// 核心优化算法伪代码
while (还有未处理的节点) {
current_set = [下一个未处理的节点]
// 保留fusion pattern
if (match_pattern(ADD + RMS_NORM)) {
keep_pattern_together()
continue
}
// 第一遍:抓取可并行执行的"real"节点
for (接下来的20个节点) {
if (节点不依赖于未处理的节点) {
if (支持fusion pattern) {
add_to_current_set()
}
}
}
// 第二遍:抓取view节点
for (接下来的20个节点) {
if (is_empty(节点) && 依赖已满足) {
add_to_current_set()
}
}
// 更新节点顺序
new_order.append(current_set)
}
支持的Fusion Pattern
- RMS_NORM + MUL
- MUL_MAT + ADD
- MUL_MAT_ID + ADD
- ADD + ADD
- ADD + RMS_NORM(CANN特有)
- ROPE + VIEW + SET_ROWS
测试结果
测试环境
- 模型:Qwen 2.5 0.5B Instruct FP16
- 设备:4x Ascend 910B4
- 测试命令:
llama-cli -m qwen2.5:0.5b-instruct-fp16 -n 50 -ngl 99
测试输出
> Hello, how are you?
Hello! I'm Qwen, an AI developed by Alibaba Cloud. I'm here to answer any questions you may have and help with anything else you need help with. How can I assist you today?
[ Prompt: 1346.4 t/s | Generation: 142.8 t/s ]
结论
- ✅ 编译通过
- ✅ 模型加载成功
- ✅ 推理输出正确
- ✅ 正常退出
使用方法
启用图优化(默认)
./llama-cli -m model.gguf -ngl 99
禁用图优化
GGML_CANN_DISABLE_GRAPH_OPTIMIZE=1 ./llama-cli -m model.gguf -ngl 99
后续优化建议
- 添加性能测试:使用llama-bench进行before/after性能对比
- 多流支持:进一步实现真正的多流并行,利用CANN的多stream能力
- 更多fusion pattern:根据CANN的特性添加更多融合优化
- 环境变量调优:添加更细粒度的控制参数