Skip to content

Latest commit

 

History

History
388 lines (296 loc) · 12.2 KB

File metadata and controls

388 lines (296 loc) · 12.2 KB

BangC 教程编写工作流程

本文档总结了从拿到一个完整的参考算子实现开始,如何编写初学者教程的完整工作流程。

工作流程概览

参考实现 → 分析理解 → 创建最小实现 → 统一验证方式 → 创建工具函数 → 创建运行脚本 → 编写教程 → 整理代码 → 生成 README

详细步骤

步骤 1: 分析参考实现

目标:理解参考实现的结构、关键特性和设计思路

任务清单

  • 阅读参考实现的代码,理解整体结构
  • 识别核心算法逻辑
  • 识别性能优化技术(tiling、多任务并行、内存优化等)
  • 识别关键配置参数(tile 大小、任务数量、任务类型等)
  • 理解数据流动(GDRAM ↔ NRAM ↔ 计算单元)
  • 记录关键 API 的使用方式

输出

  • 对参考实现的理解文档(可选)
  • 关键特性列表

步骤 2: 创建最小实现版本

目标:创建一个简化的、易于理解的版本,去掉复杂的优化技术

任务清单

  • 创建 {operator}_minimal.mlu 文件
  • 移除 tiling 逻辑(如果参考实现有)
  • 移除多任务并行(使用单个任务)
  • 简化数据规模(使用较小的测试数据)
  • 保留核心算法逻辑
  • 保留基本的 BangC API 使用(__memcpy、核心计算 API 等)
  • 统一验证方式:使用 vecadd 的验证模式
    • 实现 CPU 参考函数(如 cpu_{operator}
    • 使用 verify_rm_rm 函数进行结果验证
    • 移除其他验证方式(如自定义验证函数、文件保存等)
  • 保留完整的 Host 端流程(设备初始化、内存分配、数据拷贝、Kernel 启动、结果验证)
  • 确保代码可以编译和运行

设计原则

  • 简单优先:优先保证代码简单易懂,而不是性能
  • 完整性:虽然简化,但要保证功能完整(能运行、能验证)
  • 渐进式:最小实现应该能够自然地演进到完整实现

输出

  • {operator}_minimal.mlu 文件

步骤 3: 统一验证方式

目标:将所有算子的验证方式统一为 vecadd 的标准形式

标准验证模式(参考 vecadd.mlu):

// 1. CPU 参考实现(生成参考结果)
cpu_{operator}(host_input, host_ref, ...);

// 2. 使用统一的验证函数
(void)verify_rm_rm(host_output, host_ref, total_elements, "{operator_name}", 1e-6f, 1e-6f);

任务清单

  • 分析参考实现的验证方式
    • 检查是否有 CPU 参考实现
    • 检查使用的验证函数(可能是自定义的 verify_{operator}
    • 检查是否有其他验证方式(如文件保存、自定义比较等)
  • 实现 CPU 参考函数
    • .mlu 文件中添加 cpu_{operator} 函数
    • 使用简单的 C 代码实现,便于理解
    • 确保与 MLU Kernel 的逻辑一致
  • 统一验证函数
    • 移除自定义的验证函数(如 verify_reluverify_softmax 等)
    • 统一使用 verify_rm_rm 函数(已在 utils.h 中提供)
    • 移除文件保存等额外操作
  • 更新 main 函数
    • 确保验证流程与 vecadd 一致
    • 保留性能测量(Notifier)
    • 保留错误检查(CNRT_CHECK)

常见需要替换的验证方式

  • verify_{operator}(...) → ✅ verify_rm_rm(...)
  • save_output_to_file(...) → ✅ 移除(验证已足够)
  • ❌ 自定义比较逻辑 → ✅ 使用 verify_rm_rm
  • ❌ 缺少 CPU 参考 → ✅ 添加 cpu_{operator} 函数

验证模板示例

// =============================================================================
// CPU 参考实现:用于验证 MLU 计算结果
// =============================================================================
static inline void cpu_{operator}(const float* input, float* output, int n) {
  // 使用简单的 C 代码实现算子逻辑
  for (int i = 0; i < n; ++i) {
    // 实现算子的核心逻辑
    output[i] = /* 算子计算逻辑 */;
  }
}

// 在 main 函数中的验证部分:
// CPU 参考计算和结果验证
cpu_{operator}(host_input, host_ref, total_elements);
(void)verify_rm_rm(host_output, host_ref, total_elements, "{operator_name}", 1e-6f, 1e-6f);

常见算子验证示例

  • VecAdd: cpu_vector_add(a, b, c, n)verify_rm_rm(c, ref, n, "vector_add", ...)
  • ReLU: cpu_relu(src, dst, n)verify_rm_rm(dst, ref, n, "relu", ...)
  • Softmax: cpu_softmax(x, out, batch, dim)verify_rm_rm(out, ref, total, "softmax", ...)

输出

  • 更新后的 .mlu 文件,使用统一的验证方式

步骤 4: 创建工具函数(如需要)

目标:提取公共工具函数,保持项目独立性

任务清单

  • 检查是否有未实现的工具函数(如 generate_random_matrix_row_majorverify_rm_rm 等)
  • Experiments/utils.h 中实现这些函数
  • 确保实现简单、独立,不依赖外部库
  • 更新所有 .mlu 文件中的 include 路径

注意verify_rm_rm 函数已在 utils.h 中提供,所有算子都应使用它进行验证。

输出

  • Experiments/utils.h(如果不存在则创建,存在则更新)

步骤 5: 创建运行脚本

目标:提供一键编译和运行的脚本

任务清单

  • 创建 build_eval.sh 脚本(统一命名)
  • 设置必要的环境变量(NEUWARE_HOME、LD_LIBRARY_PATH、PATH 等)
  • 实现参数解析(接受 .mlu 文件名)
  • 实现编译命令(使用 cncc
  • 实现执行命令
  • 确保脚本简洁明了,易于理解

脚本模板

#!/bin/bash
# 环境变量设置
export NEUWARE_HOME=/usr/local/neuware
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$NEUWARE_HOME/lib64
export PATH=$PATH:$NEUWARE_HOME/bin
export MLU_VISIBLE_DEVICES=0
export TORCH_DEVICE_BACKEND_AUTOLOAD=0

set -euo pipefail

# 参数检查
if [ $# -ne 1 ]; then
  echo "Usage: $0 <mlucode 文件名,*.mlu>"
  exit 1
fi

MLU_SOURCE=$1
if [[ "$MLU_SOURCE" == *.mlu ]]; then
  TARGET="${MLU_SOURCE%.mlu}"
else
  TARGET="$MLU_SOURCE"
fi

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# 激活环境
source /torch/venv3/pytorch/bin/activate

# 编译和运行
pushd "$SCRIPT_DIR" >/dev/null
cncc "${MLU_SOURCE}" -o "${TARGET}" --bang-mlu-arch=mtp_592 -O3 -lm
./"${TARGET}"
popd >/dev/null

输出

  • build_eval.sh 脚本(统一命名)

步骤 6: 编写教程文档

目标:创建完整的初学者教程

任务清单

  • 创建 tutorial.md 文件
  • 编写教程概述
  • 编写最小实现部分说明
  • 编写完整实现(tiling/优化版本)部分说明
  • 编写运行脚本部分说明(包括环境变量、使用方法、编译参数),脚本统一命名为 build_eval.sh
  • 编写探索任务:
    • 最小实现的探索任务(上限/下限探索,参考硬件实现文档)
    • 完整实现的参数调优任务(参考任务映射文档)
  • 编写学习流程建议

教程结构模板

# {Operator} 初学者教程

本目录围绕 `{operator}.mlu` 展示了两个学习阶段的程序、一个运行脚本(`build_eval.sh`)和如何快速上手的说明。

## 1. 最小实现(`{operator}_minimal.mlu`

- 核心特性说明
- 设计思路说明
- 关键代码说明

**探索任务**- 上限探索(NRAM 容量限制)
- 下限探索(对齐要求)
- 存储层次理解
- 计算能力差异

## 2. {优化特性}实现(`{operator}.mlu`

- 优化技术说明(tiling、多任务并行等)
- 关键参数说明
- 性能考虑

**探索任务 - 参数调优**- Tiling 大小调优
- 任务类型(ktype)调优
- 任务数量(dim)调优
- 任务映射理解
- 综合调优

## 3. 运行脚本(`build_eval.sh`

### 3.1 环境变量配置
### 3.2 使用方法
### 3.3 编译参数说明

## 4. 建议的学习流程

1. 先用最小实现确认基本流程
2. 理解完整实现的优化技术
3. 进行探索任务
4. 进行参数调优

参考文档链接

输出

  • tutorial.md 文件

步骤 7: 整理代码注释

目标:统一代码风格,提高可读性

任务清单

  • 统一注释语言(中文)
  • 为关键代码段添加注释
  • 为配置参数添加说明
  • 为函数添加功能说明
  • 移除过时的注释(如 "FIXED:" 标记)
  • 确保注释准确反映代码功能

注释规范

  • 使用中文注释
  • 关键配置参数要有说明
  • 复杂逻辑要有注释
  • 数据流动要有说明
  • 设计决策要有解释

输出

  • 更新后的 .mlu 文件

步骤 8: 生成带 TODO 的 README

目标:创建项目级别的 README,包含待办事项

任务清单

  • 创建或更新 Experiments/README.md
  • 列出所有算子教程
  • 为每个算子添加状态标记(✅ 完成 / 🚧 进行中 / ⏳ 待开始)
  • 添加待办事项列表
  • 添加贡献指南(可选)

README 模板

# BangC 算子教程集合

本目录包含一系列 BangC 算子实现的初学者教程,每个教程都包含最小实现、优化实现、运行脚本和详细说明。

## 教程列表

| 算子 | 状态 | 说明 | 教程链接 |
|------|------|------|----------|
| VecAdd || 向量加法 | [tutorial.md](01_vecadd/tutorial.md) |
| ReLU || ReLU 激活函数 | - |
| Softmax || Softmax 归一化 | - |
| ... | ... | ... | ... |

## 待办事项

### 高优先级
- [ ] 完成 ReLU 教程
- [ ] 完成 Softmax 教程
- [ ] 添加更多探索任务示例

### 中优先级
- [ ] 统一代码风格
- [ ] 添加性能基准测试
- [ ] 添加常见问题解答

### 低优先级
- [ ] 添加视频教程链接
- [ ] 添加更多算子实现
- [ ] 国际化支持

## 贡献指南

欢迎贡献新的算子教程!请参考 [TUTORIAL_WORKFLOW.md](TUTORIAL_WORKFLOW.md) 了解编写流程。

输出

  • Experiments/README.md 文件

检查清单

在完成所有步骤后,使用以下检查清单验证工作质量:

代码质量

  • 最小实现可以编译和运行
  • 完整实现可以编译和运行
  • 验证方式统一:使用 verify_rm_rm 函数
  • CPU 参考实现完整:所有算子都有对应的 CPU 参考函数
  • 代码注释清晰、准确
  • 代码风格统一

文档质量

  • 教程文档完整、清晰
  • 探索任务有明确的指导
  • 参考文档链接正确
  • 学习流程合理

工具质量

  • 运行脚本可以正常使用
  • 工具函数实现正确
  • 环境变量配置正确

整体质量

  • 项目结构清晰
  • 文件命名规范
  • README 更新完整

经验总结

关键原则

  1. 渐进式学习:从简单到复杂,最小实现 → 优化实现
  2. 实践导向:提供探索任务,让学习者自己发现规律
  3. 文档完善:提供硬件背景和理论支撑
  4. 工具支持:提供便捷的运行脚本

常见问题

  1. 最小实现太复杂:应该进一步简化,只保留核心逻辑
  2. 验证方式不统一:应该统一使用 verify_rm_rm 函数,移除自定义验证函数
  3. 缺少 CPU 参考实现:应该为每个算子添加简单的 CPU 参考函数
  4. 探索任务不明确:应该提供具体的操作步骤和思考问题
  5. 文档缺少背景:应该链接官方文档,提供硬件背景
  6. 代码注释不足:应该为关键代码添加详细注释

最佳实践

  1. 先理解参考实现,再创建最小实现
  2. 最小实现要能独立运行和验证
  3. 教程要包含探索任务,引导主动学习
  4. 代码注释要统一风格,提高可读性
  5. 定期更新 README,跟踪项目进度

下一步

完成教程编写后,可以考虑:

  • 添加性能基准测试
  • 添加常见问题解答(FAQ)
  • 添加视频教程
  • 收集学习者反馈,持续改进