| name | shmem-ops-code-gen |
| description | 根据 design.md 生成基于 SHMEM 的算子代码、CMake、README 和目录结构。关键词:基于SHMEM代码生成、算子实现、code-gen、kernel、CMake。 |
SHMEM 算子代码生成
Skill类型:代码生成型(读取设计文档,输出可编译代码)
中文写作要求:README.md 等交付文档必须使用中文撰写。仅 API 名称、代码片段、命令行示例等技术术语保留英文原文。
消费通过质量门禁的 design.md,生成 SHMEM 通信算子或通算融合算子的完整代码。不做需求设计(回 shmem-ops-design),不做正确性验证(交给 shmem-ops-correctness-eval),不做性能优化(交给 shmem-ops-performance-optim)。
必读资料
读 ${SHMEM_REPO}/docs/ 只读;MUST 先定位 SHMEM_REPO(shmem-repo-resolution),NEVER 向 docs/ 追加或修改内容。
模板(分文件承载,按生成步骤按需读取,NEVER 一次读完全部模板):
必要时先定位 SHMEM_REPO,再查阅仓内文档与头文件(见 shmem-repo-docs-index、shmem-repo-resolution):${SHMEM_REPO}/docs/、${SHMEM_REPO}/install/shmem/include/、${SHMEM_REPO}/examples/。真实代码与文档优先于记忆。
输入门禁
开始生成前必须验证 design.md:
门禁失败时停止,要求先用 shmem-ops-design 修订。
门禁执行规则
门禁检查是阻断条件,不是建议。执行方式:
- 逐项检查上述 checklist,结果必须显式输出给用户(列表形式)
- 任一项 FAIL → 立即停止,向用户报告缺失项,要求回
shmem-ops-design 补齐
- 不得以"先跑通再补"、"设计基本够用"、"benchmark 不需要完整设计"等理由跳过 FAIL 项
- 如果 design.md 缺少 Canonical DSL 的
schedule / correctness / performance section,直接判定 FAIL
- 如果 Design Review Before Handoff(section 5)不存在或有 FAIL 项,直接判定 FAIL
工作流
步骤 1 提取设计契约
步骤 2 选择模板和参考 example
步骤 3 制定实现计划
步骤 4 渐进式代码生成
步骤 5 调用 shmem-ops-compile-debug 编译验证
步骤 1:提取设计契约
从 design.md 提取:
| 内容 | DSL 字段 |
|---|
| 算子身份 | meta.op_name、op_kind、target SoC、scope |
| 接口 | inputs/outputs、dtype、shape、visibility |
| 语义 | local_compute、communication、finalize |
| 拓扑 | team、peer_model、addressing |
| 内存 | buffers、symmetric_layout、signal/state |
| 调度 | phases、tile/chunk/tail、core_partition、overlap |
| 正确性 | oracle、tolerance、invariants、case_matrix |
| 性能 | metric、baseline、target_cases |
步骤 2:选择模板和参考 example
op_kind 或语义 | 模板目录 |
|---|
transport / collective / compute / 纯 put/get/exchange | templates/communication |
fused_compute_comm(Matmul/GEMM + 跨 PE 通信,AIC/AIV CoC) | templates/fused-compute |
compute:单 PE 或 Device 内本地计算、无跨 PE 通信语义时仍用 templates/communication(通常仅 Host + 空/轻量 kernel);禁止因存在 local_compute 字段就路由到 fused-compute。
fused_compute_comm:必须同时含 Cube matmul(CATLASS BlockMmad)与 SHMEM 跨 PE 通信(CommBlockEpilogue),见 core-allocation.md §4。
选定模板后,仅读取当前生成步骤对应的模板文件(见上表)。纯通信按 templates/communication/GUIDE.md 分步读取子模板;通算融合从 templates/fused-compute/GUIDE.md 按章节标题提取 fenced code block,写入目标路径,替换 <op_name>/<OpName>/<OP_NAME> 占位符。
参考 example 选择:
- allgather / put-get / SDMA / RDMA →
${SHMEM_REPO}/examples/allgather、sdma、rdma_demo(先定位 SHMEM_REPO)
- matmul allreduce / reduce-scatter →
${SHMEM_REPO}/examples/matmul_allreduce、matmul_reduce_scatter
- KV / dispatch combine →
${SHMEM_REPO}/examples/kv_shuffle、dispatch_gmm_combine
选定后记录路径和复用理由。
步骤 3:制定实现计划
编码前写出:
- 目标目录和文件列表(默认
custom-ops/<op_name>/,非 examples/)
- 复用的 API、example、template
main.cpp 与 Host helper 模块的职责边界
- 构建模式(
independent_project 默认)与编译命令(custom-ops-entrypoints.md §1 编译)
- README.md 覆盖范围
步骤 4:渐进式代码生成
模板分支(MUST):
meta.op_kind == fused_compute_comm → 只读 templates/fused-compute/GUIDE.md,按章节标题提取代码块;NEVER 读 templates/communication/templates-*.md
transport / collective / compute → 只读 communication 子模板(下表)
按"最小正确路径 → 完整正确性 → 性能路径"顺序。每子步骤只读当前分支对应模板文件:
- CMake + Host(communication:
templates-cmake-main.md;fusion:fused-compute GUIDE 对应章节)
- Kernel 声明(communication:
templates-kernel.md;fusion:fused-compute GUIDE):src/<op_name>_kernel.h
- lifecycle + memory(同上):初始化、symmetric allocation、释放
- transport + sync + compute(communication 分支;fusion 在 fused-compute kernel 章节实现):
- 通算融合:AIC 必须使用 CATLASS BlockMmad 实现 matmul,AIV 负责 CommBlockEpilogue;禁止在 AIV 上用标量/向量运算替代 Cube 计算
- 纯通信:按 design.md 实现 local compute(如有)
- GM 累加方式选择:当 kernel 需要将远端数据累加到 output 时,按 references/atomic-add-pattern.md §12 决策优先级表选择
- 测试脚本(communication:
templates-scripts.md;fusion:fused-compute GUIDE;若 Phase 2 已生成则跳过)
- scheduler(communication:kernel.cpp;fusion:fused-compute kernel 章节):phase、tile/chunk/tail、core partition、overlap
- README.md(按 references/readme-spec.md)
性能打点代码(Phase 3 跳过):模板中的 --perf 模式(templates-cmake-main.md perf 代码段)、SHMEMI_PROF_START/END 宏(templates-kernel.md perf 代码段)、scripts/perf.sh MUST 在 Phase 3 跳过。这些代码段仅当 Phase 6 dev 显式调用 code-gen 添加性能打点时写入。Phase 3 生成的是纯 correctness 代码(perf_times 默认 0,无 SHMEMI_PROF)。
关键约束
- 算子必须在 Device 执行,禁止 Host RMA 作为主通信路径
- main.cpp 只做单 PE Host 编排:参数解析、lifecycle、I/O、launch、cleanup
- 复杂 Host 逻辑拆到独立
.cpp/.h(如 op_host_plan.cpp)
- 跨 PE 传输必须使用
aclshmem_* 或 aclshmemx_* 接口
- symmetric allocation 顺序和大小在所有 PE 一致
- 通算融合算子必须使用 AIC + CATLASS 高性能计算:AIC 侧 BlockMmad(或同等实现),AIV 侧 CommBlockEpilogue;禁止在 AIV 上用标量/向量点乘替代 AIC 计算
block_dim=1 仅临时调试用;首版 correctness 必须落地 design 的并发
- 新增核心能力必须对应 gap analysis
性能输出要求
main.cpp 的 --perf 模式必须输出双指标延迟和带宽(严格按照 shmem-ops-performance-eval/references/timing-and-metrics-standard.md 执行):
| 指标 | 说明 | 公式 |
|---|
e2e_us | 端到端延迟:做法 A 下 ≈kernel_us(搬运在 kernel 内);做法 B 下含 aclrtMemcpy + barrier + kernel | 做法 A:kernel launch 前到 stream sync 后;做法 B:aclrtMemcpy 前到 stream sync 后 |
kernel_us | kernel 执行时间 | kernel launch 前到 stream sync 后 |
algo_bandwidth_GBps | 算法带宽(基于 e2e_us,参考) | logical_payload_bytes / (e2e_us * 1e-6) / 1e9 |
e2e_bus_bandwidth_GBps | 总线带宽(e2e 参考) | algo_bandwidth * bus_factor(bus_factor 见 timing-and-metrics-standard.md §4.3) |
kernel_bus_bandwidth_GBps | 达标主指标(kernel 口径) | logical_payload_bytes / (kernel_us * 1e-6) / 1e9 * bus_factor |
bandwidth_utilization_pct | 带宽利用率(基于 kernel_bus_bandwidth_GBps) | kernel_bus_bandwidth_GBps / peak_bandwidth * 100(peak_bandwidth 按通信模式确定,见下文) |
bus_factor 按算子语义确定(不区分拓扑,NCCL 惯例的通信量标准化系数):AllReduce: 2*(n-1)/n,ReduceScatter/AllGather: (n-1)/n,AllToAll/Shuffle: (n-1)/n,Broadcast/P2P: 1。
peak_bandwidth 按通信模式确定(参考 hardware-architecture.md §2.6):
- P2P 点对点:28 GB/s(单条 HCCS 链路单向)
- 集合通信(AllReduce/AllGather 等):聚合带宽,如 910B3 8 卡 full-mesh 为 7 × 28 = 196 GB/s
perf 循环结构要求:
- e2e 循环:每轮覆盖从用户 input(GM) 到结果 output(GM) 的全部数据搬运。做法 A(MTE/SDMA/UDMA kernel 内放置)下 e2e 循环 = kernel launch 循环,搬运在 kernel 内自然完成;做法 B(RDMA)下需包含 aclrtMemcpy + barrier + kernel launch。数据放置方式详见 timing-and-metrics-standard.md §1.2
- kernel-only 循环:起点始终为 kernel launch,禁止在 kernel-only 循环前预做数据放置
- e2e 计时口径:做法 A 下 e2e_us≈kernel_us 是正常的(搬运在 kernel 内),代码中 MUST 有注释说明引擎选择(如
// MTE put_nbi src=local GM, no Host-side memcpy needed);做法 B 下 e2e_us MUST > kernel_us,差值等于 kernel 外搬运时间。禁止为制造 e2e > kernel 假象而在做法 A 路径上加无意义的 kernel 外搬运;禁止在性能循环前预做搬运使 e2e 口径缩水
注意:algo_bandwidth 不乘 2,统一按 input size 计算(NCCL algBw 惯例)。logical_payload_bytes 必须在输出中注明口径(单 PE 还是全局)。Phase 6 达标与 Round 对比 MUST 用 [PERF] 行的 kernel_bus_bandwidth_GBps,不得用 e2e 带宽。
如果算子包含 SHMEMI_PROF_START/END 打点,--perf 模式还应调用 aclshmemx_get_prof(nullptr, true) 输出 Device 帧数据。
步骤 5:编译验证
- 调用
shmem-ops-compile-debug,传入 compile contract,由 compile-debug 执行构建并诊断失败
- compile-debug 返回诊断结果后:
- compile / link / launch 失败 → 本 skill 修复代码(compile-debug 只诊断不改代码),修复后重新调用 compile-debug
- correctness 失败 → 先判断是代码问题还是 Phase 2 测试脚本不匹配(如 gen_data 布局、check_result 容差);代码问题由本 skill 修复,脚本问题委托
shmem-ops-testcase-gen 修正
- runtime / environment 失败 → compile-debug 自行修复环境后重试
- 该循环持续直到编译通过且 smoke case 运行通过,或确认为环境阻塞 / 设计缺陷
最终目标目录结构
默认根路径:custom-ops/<op_name>/(独立工程)。in-tree 时为 examples/<op_name>/。
最终交付目录结构 MUST 严格遵循以下布局(以下以 <op_root>/ 表示算子根目录):
op_name/
├── CMakeLists.txt
├── README.md
├── docs/
│ ├── design.md # shmem-ops-design
│ ├── review-report.md # shmem-ops-code-review
│ ├── correctness_report.md # shmem-ops-correctness-eval
│ ├── performance_report.md # shmem-ops-performance-eval / shmem-ops-performance-optim
│ └── case_matrix_report.md # shmem-ops-testcase-gen
├── src/
│ ├── main.cpp
│ ├── op_name_kernel.cpp
│ ├── op_name_kernel.h
│ ├── op_host_plan.cpp (可选)
│ └── op_host_plan.h (可选)
├── scripts/
│ ├── gen_data.py
│ ├── check_result.py
│ ├── run.sh
│ ├── run_case_matrix.py
│ ├── perf.sh # Phase 6;实现见 perf-workflow.md
│ └── perf_compare.sh # 有 baseline 时;或统一用 perf-workflow §1 阶段 C
└── baseline/ # 有 baseline 时 MUST 存在
├── CMakeLists.txt # 独立的 baseline 编译 target(add_subdirectory)
├── src/
│ └── op_name_baseline.cpp # HCCL/aclnn baseline 源码
└── scripts/
└── run_baseline.sh # baseline 运行脚本,输出 [BASELINE_PERF]
MUST检查(全部通过方可通过本阶段,禁止以"先跑通再补"跳过任一项)
P0(阻断级——任一 FAIL 则禁止进入 Phase 4)
P1(严重级——任一 FAIL 必须先修复再进入 Phase 4)
P2(建议级——MUST在交付前修复)
P0 全部 PASS 且 P1 全部 PASS → 进入 Phase 4;否则 MUST 修复后重新检查。
条件性需求:性能打点代码(Phase 6 按需生成)
以下需求 仅当 meta.performance_required: true 且 dev 在 Phase 6 显式调用 code-gen 添加性能打点时才生效。Phase 3 不检查、不生成。
反模式(NEVER DO THESE)
- ❌ Host RMA 作为 correctness 实现
- ❌ main.cpp 包含 route/payload/tiling/golden 逻辑
- ❌ main.cpp fork/spawn 多 PE
- ❌ DataCopy 直接写远端地址
- ❌ 跳过 Device kernel 实现
- ❌ 不读 design.md 就生成代码
- ❌ 一次性读取全部 communication 模板文件(必须按步骤只读当前子文件)
- ❌ design.md 门禁有 FAIL 项仍继续生成代码("先跑通再补设计"是最常见的违规路径)
- ❌ GM 标量循环累加作为性能路径交付(按 atomic-add-pattern.md §12 决策表选择正确方式)
- ❌ reduce-scatter/allreduce RS 阶段使用串行 UB 累加(get→UB→Add)替代
SetAtomicAdd<T>() + mte_get_nbi 批量并行模式(见 atomic-add-pattern.md §5.1 / §12 优先级1)
- ❌ bus_factor 取值错误(MUST 从
timing-and-metrics-standard.md §4.3 唯一参照表取值,如 AllReduce 为 2*(n-1)/n,禁止用 n-1)
- ❌ License 头缺失即作为交付
- ❌ 错误处理裸写
if (status != ACL_ERROR_NONE) 而不使用 ACL_CHECK / CHECK_SHMEM 宏
- ❌ README.md 非中文或不遵循 readme-spec.md 结构
- ❌ 脚本/文档硬编码用户机器路径
- ❌
algo_bandwidth_GBps 基于 kernel_us 计算(应基于 e2e_us)
- ❌ Phase 3 生成 SHMEMI_PROF / --perf 打点代码(性能打点由 Phase 6 按需添加,code-gen 模板中 perf 代码段仅当 dev 显式调用时才写入)
- ❌ SHMEMI_PROF 只用单个 frame_id 包裹整个 kernel
- ❌ Host 侧不调用
aclshmemx_get_prof(nullptr, true)
- ❌ 无理由使用
aclshmemx_barrier_all_vec() 替代 aclshmem_barrier_all()
- ❌
(void)cast 替代 UNUSED_PARAM(x)
- ❌ UB buffer 偏移量散落裸 magic value
- ❌
aclshmem_barrier_all() / aclshmem_finalize() 不对称调用(某 PE 跳过 barrier/finalize,导致死锁或资源泄漏)
- ❌ 算子代码中无正当理由调用
aclshmemi_* 内部接口(除非无公开等价 API 且已在 gap analysis 中登记)
- ❌ 修改 SHMEM 核心库却无 gap analysis 授权
- ❌ 将数据搬运排除在 e2e 性能循环外(性能循环前预搬运使 e2e 口径缩水);或在做法 A 上加无意义搬运制造 e2e>kernel 假象
- ❌
.md 文档散放在算子根目录(必须归入 docs/)
- ❌
.cpp/.h 源文件散放在算子根目录(必须归入 src/)
- ❌ baseline 源码放在
src/ 下或算子根目录(必须归入 baseline/src/,编译 target 必须在 baseline/CMakeLists.txt)
- ❌ Phase 3 自行生成 baseline 代码(baseline 在 Phase 6 确定后才由 dev 调用 code-gen 按需生成)
- ❌ 用户未要求 in-tree 时将算子生成到
examples/(默认 custom-ops/<op_name>/)
- ❌ 通算融合算子在 AIV 上用标量/向量点乘替代 AIC + CATLASS 高性能计算(即使以"正确性验证"为由也不允许——须使用 CATLASS BlockMmad + CommBlockEpilogue 的 AIC/AIV 分工模式)