尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

CANN Runtime IPC Event 跨进程任务同步实战:从单 Device 双进程到多 Device 多进程

CANN Runtime IPC Event 跨进程任务同步实战:从单 Device 双进程到多 Device 多进程 CANN Runtime IPC Event 跨进程任务同步实战从单 Device 双进程到多 Device 多进程【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtimeIPC EventInter-Process Communication Event是 CANN Runtime 提供的一种可跨进程共享的 Event 机制用于在多进程、多 Device 场景下实现任务级同步。本文以开源仓库 CANN/runtime 中example/2_advanced_features/ipcevent目录下的两个官方样例为核心完整讲解 IPC Event 的创建、导出、导入、等待、记录、查询与销毁全流程并深入到源码与运行脚本层面帮助你掌握在真实工程中编写跨进程同步代码的能力。目录结构速览ipcevent样例目录聚焦 IPCEvent 的同步能力包含两个递进式的样例0_ipcevent演示单 Device 多进程 IPC Event 同步1_ipcevent_multi_device演示多 Device 间 IPC Event 同步。两个样例的目录结构如下example/2_advanced_features/ipcevent/ ├── README.md # 目录总览 ├── 0_ipcevent/ │ ├── README.md │ ├── CMakeLists.txt # 编译配置链接 ascendcl │ ├── proc_a.cpp # 生产者进程 │ ├── proc_b.cpp # 消费者进程 │ └── run.sh # 编译并并行启动双进程 └── 1_ipcevent_multi_device/ ├── README.md ├── CMakeLists.txt ├── precheck.cpp # 设备数量预检查 ├── proc_a.cpp # 生产者Device 0 ├── proc_b.cpp # 消费者指定 Device └── run.sh # 编译、预检、多进程编排什么是 IPC Event解决的问题与适用场景在 CANN 编程模型中普通 Event 属于创建它的进程私有无法被其他进程直接引用。但在真实的分布式推理、训练流水线或多进程控制面架构中常常需要一个进程完成任务后通知另一个进程继续例如数据生产进程与消费进程之间的乒乓同步多 Device 上并行计算的消费者进程等待统一的启动信号进程 A 通知进程 B某个算子流已执行到指定位置。IPC Event 正是为此设计通过aclrtIpcGetEventHandle将本进程的 Event 导出为句柄另一个进程通过aclrtIpcOpenEventHandle导入该句柄即可获得对同一事件对象的操作能力。根据 07_event_management.md 的说明该机制支持同一个 Device 内的多个进程以及跨 Device 的多个进程。核心 API 全景两个样例涉及的关键功能点与接口完全一致只是编排方式不同。下表汇总了完整调用链功能点接口作用初始化aclInit初始化 ACL 运行环境参数传nullptr使用默认配置去初始化aclFinalize释放 ACL 资源Device 管理aclrtSetDevice指定当前进程使用的 DeviceDevice 管理aclrtResetDevice复位 Device释放当前进程占用的 Device 资源Device 管理aclrtGetDeviceCount查询可用 Device 数量多 Device 样例预检用Stream 管理aclrtCreateStream创建 StreamStream 管理aclrtSynchronizeStream阻塞等待 Stream 上任务完成Stream 管理aclrtDestroyStream销毁 StreamEvent 管理aclrtCreateEventExWithFlag创建带 flag 的 EventIPC 场景需传ACL_EVENT_IPCEvent 管理aclrtRecordEvent在 Stream 中记录 EventEvent 管理aclrtSynchronizeEvent阻塞等待 Event 完成Event 管理aclrtQueryEventStatus查询 Event 记录状态Event 管理aclrtIpcGetEventHandle获取 Event 的 IPC 句柄导出Event 管理aclrtIpcOpenEventHandle导入 IPC 句柄打开本进程可用的 EventEvent 管理aclrtStreamWaitEvent阻塞 Stream等待 Event 完成Event 管理aclrtDestroyEvent销毁 Event其中 IPC 句柄相关的两个接口在 acl_rt.h 中的声明为ACL_FUNC_VISIBILITY aclError aclrtIpcGetEventHandle(aclrtEvent event, aclrtIpcEventHandle* handle); ACL_FUNC_VISIBILITY aclError aclrtIpcOpenEventHandle(aclrtIpcEventHandle handle, aclrtEvent* event);注意aclrtIpcGetEventHandle的入参要求event必须是通过aclrtCreateEventExWithFlag创建、flag 为ACL_EVENT_IPC的 Event普通 Event 无法导出为 IPC 句柄。样例一单 Device 多进程同步0_ipcevent运行架构该样例启动两个进程通过临时文件交换 IPC Event 句柄进程 A生产者创建 IPC 事件、记录事件并导出句柄然后等待消费者完成进程 B消费者导入 IPC 事件句柄、等待事件、完成工作后记录事件通知生产者。进程间除 Event 本身外还使用了两个临时文件作为带外协调手段event_handle.bin生产者将 IPC 句柄以二进制形式写入消费者读取consumer_done.flag消费者完成后创建的标志文件生产者轮询其存在性以确认完成。生产者源码解析proc_a.cpp生产者主流程见 0_ipcevent/proc_a.cpp#define EVENT_HANDLE_FILE ./event_handle.bin #define DONE_FILE ./consumer_done.flag CHECK_ERROR(aclInit(nullptr)); int32_t deviceId 0; CHECK_ERROR(aclrtSetDevice(deviceId)); aclrtStream stream nullptr; CHECK_ERROR(aclrtCreateStream(stream)); // 1. 创建支持 IPC 的事件 aclrtEvent ipcEvent nullptr; CHECK_ERROR(aclrtCreateEventExWithFlag(ipcEvent, ACL_EVENT_IPC)); // 2. 记录事件模拟生产者自身任务完成 CHECK_ERROR(aclrtRecordEvent(ipcEvent, stream)); CHECK_ERROR(aclrtSynchronizeEvent(ipcEvent)); // 3. 查询事件状态应为已完成 aclrtEventRecordedStatus status; CHECK_ERROR(aclrtQueryEventStatus(ipcEvent, status)); // 4. 导出 IPC 事件句柄二进制写入文件 aclrtIpcEventHandle handle; CHECK_ERROR(aclrtIpcGetEventHandle(ipcEvent, handle)); FILE* fp fopen(EVENT_HANDLE_FILE, wb); fwrite(handle, sizeof(handle), 1, fp); fclose(fp);关键点创建aclrtCreateEventExWithFlag(ipcEvent, ACL_EVENT_IPC)中的ACL_EVENT_IPC定义在 acl_rt.h 中值为0x00000040U。该 flag 是位图宏但 API 文档明确说明它不支持与其他 flag 进行位或操作也不支持在aclrtResetEvent、aclrtQueryEventWaitStatus、aclrtEventElapsedTime、aclrtEventGetTimestamp、aclrtGetEventId以及模型捕获场景中使用。记录与等待aclrtRecordEvent把事件插入 StreamaclrtSynchronizeEvent阻塞等待其完成这是生产者侧自身任务完成的信号。导出aclrtIpcGetEventHandle拿到句柄后用fwrite(handle, sizeof(handle), 1, fp)以二进制写入文件保证句柄结构逐字节原样传递。生产者随后进入等待阶段以 30 秒为超时上限、每秒轮询一次consumer_done.flag是否出现超时则报错退出。收到消费者完成信号后依次aclrtDestroyEvent、aclrtDestroyStream、aclrtResetDevice、aclFinalize清理资源并删除两个临时文件。消费者源码解析proc_b.cpp消费者主流程见 0_ipcevent/proc_b.cpp// 1. 等待生产者创建事件句柄文件30 秒超时轮询 while (access(EVENT_HANDLE_FILE, F_OK) ! 0 timeout-- 0) { sleep(1); } // 2. 二进制读取事件句柄 aclrtIpcEventHandle handle; FILE* fp fopen(EVENT_HANDLE_FILE, rb); fread(handle, sizeof(handle), 1, fp); fclose(fp); // 3. 打开 IPC 事件 aclrtEvent ipcEvent nullptr; CHECK_ERROR(aclrtIpcOpenEventHandle(handle, ipcEvent)); // 4. 在流中等待该事件等待生产者记录的事件 CHECK_ERROR(aclrtStreamWaitEvent(stream, ipcEvent)); CHECK_ERROR(aclrtSynchronizeStream(stream)); // 5. 模拟消费者自身的工作 usleep(2000000); // 2秒 // 6. 记录事件通知生产者 CHECK_ERROR(aclrtRecordEvent(ipcEvent, stream)); CHECK_ERROR(aclrtSynchronizeEvent(ipcEvent)); // 7. 查询事件状态应为已完成 aclrtEventRecordedStatus status; CHECK_ERROR(aclrtQueryEventStatus(ipcEvent, status)); // 8. 创建完成标志文件通知生产者 fp fopen(DONE_FILE, w); fprintf(fp, done); fclose(fp);消费者的核心动作是aclrtStreamWaitEvent(stream, ipcEvent)让本地 Stream 等待导入的事件完成从而在 Stream 上实现跨进程的任务依赖。完成自身工作后再通过aclrtRecordEvent记录该 IPC 事件并aclrtSynchronizeEvent即可通知生产者我已完成。编译与运行按 example/README.md 中的通用环境安装步骤准备环境后执行# ${install_root} 替换为 CANN 安装根目录默认安装在 /usr/local/Ascend 目录 source ${install_root}/cann/set_env.sh # 自动识别 SOC_VERSION 和 ASCENDC_CMAKE_DIR source ${git_clone_path}/example/set_sample_env.sh # 编译运行 bash run.shrun.sh见 0_ipcevent/run.sh做的事情包括依次 source${ASCEND_INSTALL_PATH}/bin/setenv.bash与set_sample_env.sh自动识别SOC_VERSION执行cmake -B build -DASCEND_CANN_PACKAGE_PATH${_ASCEND_INSTALL_PATH}并cmake --build build -j编译、cmake --install build安装后台并行启动proc_a与proc_b日志分别输出到proc_a.log、proc_b.logwait两个进程结束后检查proc_a.log中是否出现cleanup completed字样出现则输出[SUCCESS] IPC event synchronization works correctly.并以退出码 0 结束否则输出[FAILURE]并以退出码 1 结束供自动化框架判定。编译配置见 0_ipcevent/CMakeLists.txt两个可执行文件均链接ascendcl库add_executable(proc_a proc_a.cpp) add_executable(proc_b proc_b.cpp) target_link_libraries(proc_a PRIVATE ascendcl) target_link_libraries(proc_b PRIVATE ascendcl)代码中的CHECK_ERROR与INFO_LOG宏来自样例公共头文件 example/utils.h任何 ACL 调用返回非ACL_SUCCESS都会打印含调用名与错误码的日志并立即返回-1这是样例统一采用的错误处理模式。示例输出正常运行时的完整输出如下[INFO] Process A: IPC event created [INFO] Process A: event recorded and synchronized [INFO] Process A: event status 1 (1completed) [INFO] Process A: IPC event handle written to ./event_handle.bin [INFO] Process A: consumer finished [INFO] Process A: cleanup completed [INFO] Process B: IPC event opened [INFO] Process B: event received, stream synchronized [INFO] Process B: event status 1 (1completed) [INFO] Process B: cleanup completed [SUCCESS] IPC event synchronization works correctly.其中event status 1对应枚举ACL_EVENT_RECORDED_STATUS_COMPLETE。该枚举在 acl_rt.h 中定义typedef enum aclrtEventRecordedStatus { ACL_EVENT_RECORDED_STATUS_NOT_READY 0, // 尚未记录完成 ACL_EVENT_RECORDED_STATUS_COMPLETE 1, // 已记录完成 } aclrtEventRecordedStatus;样例二多 Device 跨进程同步1_ipcevent_multi_device与样例一的差异当消费者分布在多个 Device 上时同步模型从1 对 1变为1 对 N生产者进程proc_a运行在 Device 0 上创建一个 IPC Event记录事件并导出句柄到文件然后等待所有消费者进程完成消费者进程proc_b运行在其他 Device如 Device 1、Device 2...上每个消费者读取事件句柄、打开事件、在 Stream 中等待该事件然后记录事件并通知生产者。通过这种方式一个生产者可以同步多个运行在不同 Device 上的消费者实现分布式任务协调。设备数预检机制precheck.cpp多 Device 场景下可用设备数量是环境相关的run.sh在启动进程前会先运行 precheck.cppCHECK_ERROR(aclInit(nullptr)); uint32_t deviceCount 0; aclError ret aclrtGetDeviceCount(deviceCount); aclFinalize(); // ... if (deviceCount static_castuint32_t(requiredDeviceCount)) { INFO_LOG([SKIP] Need at least %d devices, but only %u device(s) are available., requiredDeviceCount, deviceCount); return 2; // 环境不满足返回 2 表示 SKIP }run.sh对预检返回码的处理规则返回码2说明设备数不足输出[SKIP]提示并以退出码 0 结束便于自动化框架识别为环境不满足而非用例失败返回码非 0输出[ERROR] Device count precheck failed.并以该返回码结束。运行编排run.sh见 1_ipcevent_multi_device/run.sh# 设置消费者数量根据实际可用设备数量调整生产者使用 device 0 # 例如如果有3个设备0,1,2消费者数量为2 CONSUMER_NUM1 REQUIRED_DEVICE_COUNT$((CONSUMER_NUM 1)) ./out/precheck ${REQUIRED_DEVICE_COUNT} # ... 依据返回码决定继续或跳过 # 启动生产者后台 ./out/proc_a $CONSUMER_NUM 21 | tee producer.log PROC_A_PID$! # 启动消费者每个消费者运行在不同的设备上 for ((i1; i$CONSUMER_NUM; i)); do DEVICE_ID$i ./out/proc_b $DEVICE_ID $i 21 | tee consumer_${i}.log CONSUMER_PIDS[$i]$! done # 等待所有进程结束 wait $PROC_A_PID for ((i1; i$CONSUMER_NUM; i)); do wait ${CONSUMER_PIDS[$i]} done # 检查生产者日志是否成功 if grep -q finished successfully producer.log; then echo [SUCCESS] IPC event multi-device synchronization works correctly. exit 0 else echo [FAILURE] IPC event multi-device synchronization test failed. exit 1 fi关键参数CONSUMER_NUM消费者数量默认配置为 1表示生产者使用 Device 0、消费者使用 Device 1需根据实际可用 Device 数量调整例如 3 个设备0、1、2时设为 2所需设备数 CONSUMER_NUM 1生产者独占 Device 0第 i 个消费者使用 Device i。生产者与消费者源码要点生产者 proc_a.cpp 接收命令行参数number_of_consumers校验其取值范围为 1~8MAX_CONSUMER_NUM核心流程与单 Device 样例一致但等待逻辑改为轮询多个完成标志文件./consumer_%d.donei 从 1 到消费者总数全部出现且总数匹配才算完成同样带 30 秒超时int WaitForConsumers(int expectedCount) { while (completed expectedCount elapsed timeoutSec) { completed 0; for (int i 1; i expectedCount; i) { snprintf(flagFile, sizeof(flagFile), ./consumer_%d.done, i); if (access(flagFile, F_OK) 0) completed; } sleep(1); elapsed; } // completed expectedCount 时返回 0否则超时报错 }消费者 proc_b.cpp 接收device_id consumer_id两个参数在自己的 Device 上调用aclrtSetDevice(deviceId)其余 IPC 交互等待句柄文件、导入句柄、aclrtStreamWaitEvent等待、工作后aclrtRecordEvent回写、创建consumer_%d.done标志与单 Device 样例一一对应充分说明同一套 IPC Event API 可无缝覆盖单 Device 与跨 Device 两种拓扑。示例输出[INFO] Starting producer on device 0, waiting for 1 consumer(s)... [INFO] Starting consumer 1 on device 1 [INFO] Consumer 1: IPC event opened on device 1 [INFO] Consumer 1: event received, stream synchronized [INFO] Consumer 1: event status 1 (1completed) [INFO] Consumer 1 (device 1) finished successfully. [INFO] Producer: IPC event created on device 0 [INFO] Producer: event status 1 (1completed) [INFO] All 1 consumers have finished. [INFO] Producer: finished successfully. [SUCCESS] IPC event multi-device synchronization works correctly.深入理解IPC Event 的跨进程语义结合 07_event_management.md 中aclrtIpcGetEventHandle的功能说明标准的两进程协作流程为进程 AaclrtCreateEventExWithFlag创建ACL_EVENT_IPC事件 →aclrtIpcGetEventHandle获取句柄 → 在 Stream 中aclrtRecordEvent记录该事件进程 BaclrtIpcOpenEventHandle打开句柄获得本进程可用的 Event →aclrtStreamWaitEvent等待该事件完成进程 B 完成工作后可再次aclrtRecordEvent从而把完成信号回传给进程 A如样例所示实现双向握手。值得注意的实现细节句柄是带外传递的aclrtIpcEventHandle是固定大小结构体样例采用二进制文件传递在真实工程中也可以使用共享内存、Unix Domain Socket、消息队列等任意 IPC 手段传递本样例选择文件是为了最小化依赖、便于演示。完成标志文件的意义Event 信号本身是非持久的事件被等待并消费后记录状态查询到的只是最近一次记录的结果样例额外引入.flag文件来传递某进程整体已退出/已完成全部清理这一更强的生命周期信息避免对 Event 状态作过度假设。进程退出顺序两个样例中生产者与消费者都使用aclrtResetDevice而非aclrtResetDeviceForce释放当前进程的 Device 资源。README 中特别说明本样例为单机多进程 IPC 场景避免强制复位影响同机其他进程——强制复位会打断同机上其他进程对该 Device 的使用在多进程协作场景中是必须规避的操作。产品支持情况与适用前提两个样例 README 声明的产品支持情况一致产品是否支持Ascend 950PR/Ascend 950DT√Atlas A3 训练系列产品/Atlas A3 推理系列产品√Atlas A2 训练系列产品/Atlas A2 推理系列产品√使用前提与限制提醒多 Device 样例至少需要 2 个可用 Device运行前通过aclrtGetDeviceCount自动预检ACL_EVENT_IPCflag 不支持与其他 flag 位或组合使用范围受限于上文列出的接口集合详见 07_event_management.md 中aclrtCreateEventExWithFlag的参数说明具体限制请以实际安装版本的配套 API 文档为准样例中的超时轮询30 秒与文件路径./event_handle.bin等为演示性设计生产代码建议按需配置更健壮的通信与超时策略。小结通过两个样例你可以掌握 CANN Runtime IPC Event 的完整能力边界ACL_EVENT_IPC标志的 Event 创建、句柄导出与导入、跨进程的 Stream 等待与事件记录、状态查询与资源清理。从单 Device 双进程的握手到多 Device 下1 生产者对 N 消费者的分布式协调同一套 API 即可覆盖且配合aclrtGetDeviceCount预检与标志文件协调可以构建出适合自动化测试与生产部署的跨进程同步骨架。更多 Event 管理接口计时、查询、等待状态等可继续阅读 Event 管理 API 参考 与 Event 管理开发指南。【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表