
人工智能编译器模型编译高性能计算深度学习CANN【免费下载链接】pyptoPyPTO发音: pai p-t-oParallel Tensor/Tile Operation编程范式。项目地址https://gitcode.com/cann/pypto点击查看免费下载pypto_pro.language.system.wait_cross_core是 CANN PyPTOParallel Tensor/Tile Operation 编程范式中用于核间跨 AI Core / AIV同步消费的底层控制接口与 set_cross_core 配对使用实现不同核、不同流水之间的信号握手。本文以该接口为主线完整讲解其函数原型、参数语义、四种CrossCoreSyncMode同步模式、事件 ID 配对规则与死锁约束并结合仓库源码与测试用例说明其底层实现原理帮助读者在自研 Kernel 中正确编排多核并行计算。一、接口定位核间同步的等待-消费半边在多核多 AI Core并行编程中一个 Kernel 的计算可能被拆分到多个核AIC / AIV上执行核之间往往存在数据依赖例如 AIV 计算出的中间结果需要交给同一 AI Core 的 AIC 做矩阵乘。PyPTO 通过set_cross_core/wait_cross_core这一对接口实现核间同步set_cross_core发送同步信号SET。每个事件 ID 对应一个初始值为 0 的计数器指定流水中的前序指令完成后执行 SET使对应计数器加 1wait_cross_core等待并消费同步信号WAIT。执行时若计数器为 0则阻塞指定流水中的后续指令若计数器大于 0则计数器减 1 并放行后续指令。从计数语义可以清晰看出wait_cross_core是带消费的同步每一条 WAIT 恰好抵消一条 SET二者必须成对出现这与sync_all全核栅栏等一次性屏障不同因而天然支持多轮、多事件的细粒度流水同步。其同步机制细节以 set_cross_core 为准。在 Python 侧该接口由 python/pypto_pro/ir/op/system_ops.py 中的wait_cross_core构造 IR 算子调用实现pipe、event_id、sync_mode均为仅限关键字参数keyword-only。二、产品支持情况产品支持情况Ascend 950PR / Ascend 950DT支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品不支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品不支持即该接口目前仅在 Ascend 950 系列产品上可用使用前需确认目标硬件平台。三、函数原型pypto_pro.language.system.wait_cross_core( *, pipe: PipeType, event_id: Union[int, Scalar], sync_mode: CrossCoreSyncMode pypto_pro.language.CrossCoreSyncMode.INTRA_BLOCK, ) - None三个参数均为仅限关键字参数调用时必须写成pipe...形式。函数无返回值。四、参数说明参数输入/输出说明pipe输入pypto_pro.language.PipeType 枚举值表示等待期间被阻塞的硬件流水。接口只阻塞该流水中尚未下发的后续指令已经下发的指令仍可继续执行等待完成后该流水才能继续执行后续指令。对于 INTER_BLOCK、INTER_SUBBLOCK、INTRA_BLOCK 和 UNICAST_BLOCKpipe 均支持 M、V、MTE1、MTE2、MTE3、FIX 和 S不支持 ALL。wait_cross_core 的 pipe 用于指定等待期间被阻塞的流水无需与配对的 set_cross_core 的 pipe 相同。event_id输入核间同步事件 ID。支持Python 整型常量或运行时整数 Scalar 表达式。Python 整型常量当前只能取 015动态表达式须由调用方保证运行时取值合法INTER_BLOCK、INTER_SUBBLOCK、INTRA_BLOCK 取 015UNICAST_BLOCK 在 AIV 侧取 015在 AIC 侧取 031。UNICAST_BLOCK 中AIV0 发送的 015 与 AIC 等待的 015 配对AIV1 发送的 015 与 AIC 等待的 1631 配对AIC 发送的 015 与 AIV0 等待的 015 配对AIC 发送的 1631 与 AIV1 等待的 015 配对。事件 ID 的计数器、复用、SET 顺序、SyncAll 占用冲突及自动流水编排冲突等约束参见 set_cross_core 参数说明。sync_mode输入核间同步模式用于指定参与同步的核以及 SET/WAIT 信号的配对方式。须与配对的 set_cross_core 使用相同模式取值参见 pypto_pro.language.CrossCoreSyncMode。4.1 pipe 的语义细节pipe决定的是哪条硬件流水被卡住因此它既可以是产生数据的流水如 MTE3 搬出完成后再等待也可以是消费数据的流水如 MTE1 等待搬入前提。由于 WAIT 只阻塞指定流水尚未下发的后续指令已下发的指令不受影响这为流水级并行留出了空间——例如可以在 MTE3 等待期间让 V 流水继续执行不依赖同步数据的指令。同时需要注意WAIT 的 pipe 与 SET 的 pipe 不必相同。典型场景是MTE3 上发送信号、V 流水上等待允许跨流水组合出更灵活的同步拓扑。4.2 event_id 的静态与动态形式源码 system_ops.py 展示了两种形式的底层分流if isinstance(event_id, Expr): return _ir_core.create_op_call( system.wait_cross_core_dyn, [event_id], {pipe: pipe, sync_mode: sync_mode}, actual_span ) _check_id_range(event_id, MAX_EVENT_ID, event_id) kwargs {pipe: pipe, event_id: event_id, sync_mode: sync_mode} return _ir_core.create_op_call(system.wait_cross_core, [], kwargs, actual_span)传入 Python 整型常量时会经过_check_id_range校验MAX_EVENT_ID 15见 system_ops.py越界直接报错传入运行时 Scalar 表达式Expr时生成动态事件 ID 算子system.wait_cross_core_dyn取值合法性015UNICAST_BLOCK 的 AIC 侧为 031由调用方保证。4.3 对 ALL 的拒绝_validate_concrete_pipe明确拒绝PipeType.ALLif pipe PipeType.ALL: raise InvalidArgument(f{name} must identify one concrete pipe, got PipeType.ALL, spanspan)见 system_ops.py。也就是说wait_cross_core必须指定一条具体的硬件流水这与sync_all、bar_all等全局屏障语义有本质区别。五、同步模式详解CrossCoreSyncMode 四种取值sync_mode的类型为 pypto_pro.language.CrossCoreSyncMode枚举定义PYPTO_DECLARE_ENUM(CrossCoreSyncMode, INTER_BLOCK, INTER_SUBBLOCK, INTRA_BLOCK, UNICAST_BLOCK )四种模式参与同步的核与信号配对方式如下模式值名称参与同步的核SET/WAIT 配对方式0INTER_BLOCK多个 AI Core 之间的同类核全核同步AIC 场景同步本次 Kernel 启动的所有 AICAIV 场景同步本次 Kernel 启动的所有 AIVAIC 与 AIV 不会在该模式下互相同步1INTER_SUBBLOCK同一 AI Core 内的 AIV0 与 AIV1仅两个子核之间同步不同 AI Core 之间互不影响2INTRA_BLOCK同一 AI Core 内的 AIC 与全部 AIVAIV→AIC 方向AIV0 和 AIV1分别发送信号AIC 等待两路信号AIC→AIV 方向AIC 发送信号AIV0 和 AIV1 分别等待。该值为set_cross_core和wait_cross_core的默认同步模式3UNICAST_BLOCK同一 AI Core 内的 AIC 与单个AIVAIC 侧事件 ID 015 对应 AIV01631 对应 AIV1AIV 侧事件 ID 取 0155.1 UNICAST_BLOCK 的事件 ID 配对细节UNICAST_BLOCK 是四者中唯一存在事件 ID 映射偏移的模式也是最容易用错的点AIV0 发送 015 ↔ AIC 等待 015AIV1 发送 015 ↔ AIC 等待 1631AIC 发送 015 ↔ AIV0 等待 015AIC 发送 1631 ↔ AIV1 等待 015。即谁在等待决定了 AIC 侧事件 ID 是否要加 16 的偏移而 AIV 侧永远只使用 015。编写 UNICAST_BLOCK 同步时务必根据收发双方核对 ID避免错配导致死锁或误放行。六、约束说明必须存在匹配的 SET调用wait_cross_core前必须存在与之配对的 set_cross_core 调用并保证所有参与同步的核均能到达同步点否则可能发生死锁某个核一直等待永远不来的信号。INTER_BLOCK 的并发死锁风险使用 INTER_BLOCK 时还需满足 set_cross_core 的约束当多流或多个算子并发执行且并发算子申请的核数总和超过物理核数时如果至少两个并发算子使用核间同步部分核可能因未被调度而无法到达同步点造成死锁。必须保证每个同步算子所需的核能够同时执行。同一事件 ID 的复用前提对于 INTER_BLOCK、INTER_SUBBLOCK 和 INTRA_BLOCK同一核复用事件 ID 或将同一事件 ID 用于不同同步模式前必须完成该事件 ID 在前一同步过程中的所有 SET 和 WAIT。计数器溢出每个事件 ID 对应的计数器取值范围为 015同一事件的信号未被 WAIT 消费时连续发送超过 15 次 SET 会触发异常并中断执行。与 sync_all 及自动流水编排的冲突与 sync_all 同时使用时须避开 HARD 模式占用的事件 ID使用自动流水编排时还应避免与其分配的事件 ID 冲突。SET 顺序不确定性同一核连续发送多个 SET 时不保证不同事件 ID 之间的生效顺序存在先后依赖时应先完成前一组 SET/WAIT。七、调用示例7.1 INTER_BLOCK全核屏障式等待with pl.section_vector(): pl.system.wait_cross_core( pipepl.PipeType.MTE3, event_id0, sync_modepl.CrossCoreSyncMode.INTER_BLOCK, ) # 所有AIV均到达同步点后执行的操作。对应配对的 SET 侧所有 AIV 各自执行完前置操作后发送信号with pl.section_vector(): # 本AIV上的前置操作。 pl.system.set_cross_core( pipepl.PipeType.MTE3, event_id0, sync_modepl.CrossCoreSyncMode.INTER_BLOCK, )7.2 INTER_SUBBLOCK同核内 AIV0/AIV1 握手with pl.section_vector(): pl.system.wait_cross_core( pipepl.PipeType.V, event_id1, sync_modepl.CrossCoreSyncMode.INTER_SUBBLOCK, ) # 同一AI Core内的AIV0和AIV1均到达后继续。配对 SET 侧由 AIV0 和 AIV1 各自执行前置操作后发送with pl.section_vector(): # AIV0和AIV1各自执行前置操作。 pl.system.set_cross_core( pipepl.PipeType.V, event_id1, sync_modepl.CrossCoreSyncMode.INTER_SUBBLOCK, )7.3 INTRA_BLOCKAIC 与全部 AIV 同步默认模式with pl.section_cube(): # 等待AIV0和AIV1的信号。 pl.system.wait_cross_core( pipepl.PipeType.MTE1, event_id2, sync_modepl.CrossCoreSyncMode.INTRA_BLOCK, )AIC 侧需要等待两路信号AIV0 与 AIV1 分别发送因此配对的 SET 侧是with pl.section_vector(): # AIV0和AIV1完成前置操作后分别发送信号。 pl.system.set_cross_core( pipepl.PipeType.MTE3, event_id2, sync_modepl.CrossCoreSyncMode.INTRA_BLOCK, )7.4 UNICAST_BLOCKAIC 与单个 AIV 同步with pl.section_cube(): # 仅等待AIV0的信号。 pl.system.wait_cross_core( pipepl.PipeType.S, event_id15, sync_modepl.CrossCoreSyncMode.UNICAST_BLOCK, )配对 SET 侧需要显式限定只有 AIV0 发送信号with pl.section_vector(): if pl.get_subblock_idx() 0: # 仅AIV0发送信号。 pl.system.set_cross_core( pipepl.PipeType.S, event_id15, sync_modepl.CrossCoreSyncMode.UNICAST_BLOCK, )7.5 完整 Kernel 示例AIV 计算 AIC 矩阵乘的 INTRA_BLOCK 同步下面的完整示例体现了核间同步的真实用法AIV 子核分别加载x、y并按子核索引切片做加法将结果写入共享的v1_matMat 空间AIC 侧加载rhs后在 MTE1 上等待 AIV 的信号再读取v1_mat做矩阵乘。注意其中pl.system.set_cross_core在section_vector中发送pl.system.wait_cross_core在section_cube中等待二者同为INTRA_BLOCK、event_id2import pypto_pro.language as pl pl.jit() def cross_core_kernel( x: pl.Tensor[[64, 64], pl.DT_FP32], y: pl.Tensor[[64, 64], pl.DT_FP32], rhs: pl.Tensor[[64, 64], pl.DT_FP32], out: pl.Tensor[[64, 64], pl.DT_FP32], ): v1_mat pl.make_tile( pl.TileType(shape[64, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Mat, layoutpl.NZ), addr0x10000) with pl.section_vector(): sub_index pl.get_subblock_idx() off sub_index * 32 tile_x pl.make_tile( pl.TileType(shape[32, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Vec), addr0x0000) tile_y pl.make_tile( pl.TileType(shape[32, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Vec), addr0x2000) tile_sum pl.make_tile( pl.TileType(shape[32, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Vec), addr0x4000) tile_nz pl.make_tile( pl.TileType(shape[32, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Vec, layoutpl.NZ), addr0x6000) pl.load(tile_x, x, [off, 0]) pl.load(tile_y, y, [off, 0]) pl.system.sync_src(set_pipepl.PipeType.MTE2, wait_pipepl.PipeType.V, event_id0) pl.system.sync_dst(set_pipepl.PipeType.MTE2, wait_pipepl.PipeType.V, event_id0) pl.add(tile_sum, tile_x, tile_y) pl.move(tile_nz, tile_sum) pl.system.sync_src(set_pipepl.PipeType.V, wait_pipepl.PipeType.MTE3, event_id2) pl.system.sync_dst(set_pipepl.PipeType.V, wait_pipepl.PipeType.MTE3, event_id2) pl.insert(v1_mat, tile_nz, [off, 0]) pl.system.set_cross_core( pipepl.PipeType.MTE3, event_id2, sync_modepl.CrossCoreSyncMode.INTRA_BLOCK, ) with pl.section_cube(): rhs_mat pl.make_tile( pl.TileType(shape[64, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Mat, layoutpl.NZ), addr0x0000) v1_left pl.make_tile( pl.TileType(shape[64, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Left, layoutpl.NZ), addr0x0000) rhs_right pl.make_tile( pl.TileType(shape[64, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Right, layoutpl.ZN), addr0x0000) c_l0c pl.make_tile( pl.TileType(shape[64, 64], dtypepl.DT_FP32, target_memorypl.MemorySpace.Acc, layoutpl.NZ, fractal1024), addr0x0000) pl.load(rhs_mat, rhs, [0, 0]) pl.system.sync_src(set_pipepl.PipeType.MTE2, wait_pipepl.PipeType.MTE1, event_id0) pl.system.sync_dst(set_pipepl.PipeType.MTE2, wait_pipepl.PipeType.MTE1, event_id0) pl.move(rhs_right, rhs_mat) pl.system.wait_cross_core( pipepl.PipeType.MTE1, event_id2, sync_modepl.CrossCoreSyncMode.INTRA_BLOCK, ) pl.move(v1_left, v1_mat) pl.system.sync_src(set_pipepl.PipeType.MTE1, wait_pipepl.PipeType.M, event_id0) pl.system.sync_dst(set_pipepl.PipeType.MTE1, wait_pipepl.PipeType.M, event_id0) pl.matmul(c_l0c, v1_left, rhs_right) pl.system.sync_src(set_pipepl.PipeType.M, wait_pipepl.PipeType.FIX, event_id0) pl.system.sync_dst(set_pipepl.PipeType.M, wait_pipepl.PipeType.FIX, event_id0) pl.store(out, c_l0c, [0, 0])示例中的要点流水内同步先行在核间 SET 之前先用sync_src/sync_dst保证insert到 Mat 空间的写已完成V→MTE3 事件 ID 2SET 与 WAIT 分属不同 sectionAIV 侧在section_vector中发送AIC 侧在section_cube中等待符合 INTRA_BLOCK 的 AIV→AIC 方向语义WAIT 之后才消费共享数据wait_cross_core(pipeMTE1, event_id2)阻塞 MTE1确保pl.move(v1_left, v1_mat)发生在 AIV 的insert完成之后事件 ID 可复用不同同步域事件 ID 0 被用于流水内sync_src/sync_dst事件 ID 2 被用于核间同步二者同步域不同、互不冲突。八、源码级实现解析8.1 IR 层的算子构造wait_cross_core在 python/pypto_pro/ir/op/system_ops.py 中实现核心逻辑是校验pipe必须是具体的PipeType拒绝ALL对静态event_id做015的范围校验_check_id_range配合MAX_EVENT_ID 15动态event_idExpr走system.wait_cross_core_dyn算子静态event_id生成system.wait_cross_core算子调用。set_cross_core的实现与之对称system_ops.py二者共享同一套 pipe 校验与 ID 范围校验逻辑这也解释了文档中配对使用、参数须一致的要求为何会在编译期被强制。8.2 与自动流水编排的关系在 PyPTO 的自动流水编排pipeline scheduling框架中存在专门的跨核同步扫描逻辑 python/pypto_pro/runtime/pipeline/_cross_core_scanner.py其文档注释表明扫描结果会驱动在流水阶段边界自动插入 wait/set_cross_core。也就是说wait_cross_core既是开发者可以手动调用的底层原语也是自动流水编排内部用于生成跨核依赖同步的构件之一。这解释了文档中使用自动流水编排时应避免与其分配的事件 ID 冲突这一约束的由来。8.3 枚举的 Python 导出CrossCoreSyncMode由 python/pypto_pro/language/init.py 导出源码中同时出现在CrossCoreSyncMode的__all__列表与 import 列表中并在 C 绑定层 python/src/bindings/ir/ir.cpp 中注册因此可以在 Kernel 中以pl.CrossCoreSyncMode.INTRA_BLOCK形式直接使用。九、测试用例验证仓库测试 python/tests/st/pypto_pro/frontend/system/test_manual_sync_dynamic.py 中给出了核间同步与核内手动同步共存的验证场景with pl.section_vector(): pl.system.set_cross_core( pipepl.PipeType.V, event_id14, sync_modepl.CrossCoreSyncMode.INTER_SUBBLOCK ) pl.system.wait_cross_core( pipepl.PipeType.V, event_id14, sync_modepl.CrossCoreSyncMode.INTER_SUBBLOCK )该用例的注释说明跨子核同步可以与核内所有手动同步形式共存测试仍以端到端精度结果校验核内流水行为。此外 python/tests/st/pypto_pro/frontend/system/test_cube_vector_sync.py、python/tests/ut/pypto_pro/codegen/test_manual_sync_dynamic_shape.py 等测试也覆盖了核间/核内同步的多种组合可作为编写自身用例时的参考范式。十、使用要点小结成对使用每个wait_cross_core必须匹配一个同event_id、同sync_mode的set_cross_core并保证所有参与核都能到达同步点pipe 各管各的SET 与 WAIT 的 pipe 可以不同WAIT 的 pipe 只决定哪条流水被阻塞模式决定核集合INTER_BLOCK跨核同类核、INTER_SUBBLOCK同核 AIV0/AIV1、INTRA_BLOCK同核 AIC↔全部 AIV默认、UNICAST_BLOCK同核 AIC↔单个 AIV注意 AIC 侧 1631 的 ID 偏移事件 ID 是有限资源静态 ID 015计数器上限 15复用前须确认前一轮 SET/WAIT 全部完成同时避开sync_allHARD 模式与自动流水编排占用的 ID警惕死锁INTER_BLOCK 模式下并发算子核数总和超过物理核数时可能因部分核未被调度而死锁需保证同步算子所需核能同时执行平台限制当前仅 Ascend 950PR / Ascend 950DT 支持。核间同步是编写高效多核 Kernel 的关键一环建议读者结合 set_cross_core 与 CrossCoreSyncMode 两份文档通读并以上述完整 Kernel 示例为起点在目标硬件上实测验证同步语义。赞分享人工智能编译器模型编译高性能计算深度学习CANN【免费下载链接】pyptoPyPTO发音: pai p-t-oParallel Tensor/Tile Operation编程范式。项目地址https://gitcode.com/cann/pypto点击查看免费下载相关推荐PyPTO-Pro 跨核同步设计指南set_cross_core/wait_cross_core 的同步点、pipe 与 event_id 规划PyPTO Pro 跨核同步设计指南set_cross_core/wait_cross_core 的同步点、pipe 与 event_id 规划 本篇技术指南人工智能大模型算子库AI 技能/插件CANN PyPTO 核间同步接口 set_cross_core 完全指南事件计数器、四种同步模式与死锁规避CANN PyPTO 核间同步接口 set_cross_core 完全指南事件计数器、四种同步模式与死锁规避 导读 pypto_pro.language.sy人工智能编译器模型编译高性能计算深度学习CANNPyPTO 核间同步模式 CrossCoreSyncMode 详解SET/WAIT 信号配对与 AI Core 同步编程PyPTO 核间同步模式 CrossCoreSyncMode 详解SET/WAIT 信号配对与 AI Core 同步编程 本文围绕 CANN PyPTOPa人工智能编译器模型编译高性能计算深度学习CANN创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考