算法分析器工具用户指南
【免费下载链接】hcommHCOMM(Huawei Communication)是HCCL的通信基础库,提供通信域以及通信资源的管理能力。项目地址: https://gitcode.com/cann/hcomm
工具简介
HCCL算法分析器用于在离线环境中模拟HCCL算法的运行,验证算法逻辑及内存操作等功能。HCCL算法分析器提供了高效、快捷的批量执行测试任务,满足开发者的运行诉求。
原理介绍
几个关键点:
- 算法分析器通过对平台和框架层进行打桩,在算法执行的过程可以获取到所有rank的Task序列。
- 将所有Rank的Task信息组成一张有向无环图。
- 基于图算法做一些校验,比如内存读写冲突校验,语义校验。1)内存冲突校验会基于图中的同步情况分析是否存在可能的读写冲突。2)语义校验通过模拟执行Task图,记录数据的搬运信息,模拟执行完成后检查UserOutput内存中数据搬运信息是否符合算子的要求。
环境准备
参照源码构建中的环境准备,源码下载,进行算法分析器编译前的准备工作。
用例编写
LLT用例一览
一个算法checker用例分为5个步骤,分别如下图5个框框所示,接下来依次介绍下每个步骤的写法,以适应不同的算子需求。并介绍下出现问题之后,如何借助checker工具进行问题定位。
LLT用例各步骤详解
拓扑生成
TopoMeta结构体介绍
checker:使用TopoMeta来表示一个拓扑结构,TopoMeta是一个三层vector结构。
PhyDeviceId:表示一个NPU的物理Id。
ServerMeta:由PhyDeviceId组成,表示一个服务器的卡数及对应的PhyDeviceId。
SuperPodMeta:由ServerMeta组成,表示组成超节点的服务器情况。
TopoMeta:表示集群的整体拓扑情况。
TopoMeta生成方式
TopoMeta生成有两种方式:
指定超节点个数、服务器个数、每个服务器的卡数,然后利用RankTable_For_LLT类提供的GenTopoMeta函数来生成,适用于对称拓扑场景。
对超节点、服务器、卡数等完全定制,适用非对称拓扑场景。如下图,TopoMeta中有一个超节点,超节点内有两个server,一个server有2张卡,一个server有3张卡
rank table生成
有了TopoMeta之后,利用RankTable_For_LLT类提供的GenRankTable函数即可生成rank table。
环境变量设置
设置环境变量
环境变量会影响代码中的判断逻辑,通过setenv函数可以在用例执行前设置好用例需要的条件。
清理环境变量
因为环境变量是进程级别的,一个LLT任务在同一个进程中执行,环境变量的使用可能会影响其他的用例执行。为了清理环境变量,目前在测试套中的TearDown函数中调用了清理环境变量的函数。
目前清理环境变量的函数会清理如下的环境变量,如果后续有新增的环境变量,需要在这个函数中进行补充。
日志级别设置
checker日志级别(默认ERROR级别)
调用接口
setCheckerLogWarn()设置日志级别将checker日志级别设置为WARNING:
通过环境变量设置日志级别
打开WARNING级别日志:
export CHECK_LOG_LEVEL=2打开ERROR级别日志:
export CHECK_LOG_LEVEL=3
HCCL日志级别(默认ERROR级别)
当前设置环境变量的方式失效,用下面这种方法设置日志级别并打印。
打开DEBUG级别日志:
export ASCEND_LOG_LEVEL=0打开INFO级别日志:
export ASCEND_LOG_LEVEL=1打开WARNING级别日志:
export ASCEND_LOG_LEVEL=2打开ERROR级别日志:
export ASCEND_LOG_LEVEL=3
算子参数设置
TestOpParam用来设置测试参数,下表介绍其主要使用的一些参数。
| 参数名称 | 必选 or 可选 | 作用 | 备注 |
|---|---|---|---|
| opType | 必选 | 指定被测试算子类型 | 当前batchsendrecv还在开发中 |
| tag | 必选 | 及算子执行入口的tag | 随意设置即可 |
| algName | 可选 | 指定执行的算法名称 | 若指定则跳过算法选择流程,若不指定,则自动选择算法 |
| opMode | 必选 | 指定单算子模式或图模式 | |
| reduceType | 可选 | 涉及reduce类型时需指定 | |
| devtype | 必选 | 执行运行的硬件类型 | 支持310P3 V卡/310P3 Duo卡/910A/910B/910C |
| is310P3V | 可选 | 运行环境为310P3 V卡时需设置为true | |
| count | 必选 | 数据个数 | |
| dataType | 必选 | 数据类型 |
运行checker
将前述步骤生成的TestOpParam、rankTable、TopoMeta等参数送给Checker对象的Check函数执行即可。
校验检查结果
检查Check返回值为HcclResult::HCCL_SUCCESS即可。
LLT用例过滤
用例较多,仅需执行某个用例时,修改main.cc中用例名称即可。
用例执行
在源码仓根目录下,按如下命令,编译并执行算法分析器用例:
# 编译所有测试套用例,并自动执行 bash build.sh --st # 编译单个测试套用例,并自动执行 bash build.sh --open_hccl_test bash build.sh --executor_hccl_test bash build.sh --executor_reduce_hccl_test bash build.sh --executor_pipeline_hccl_test # 手动执行测试用例 ./build/test/st/algorithm/testcase/testcase/open_hccl_test ./build/test/st/algorithm/testcase/testcase/executor_hccl_test ./build/test/st/algorithm/testcase/testcase/executor_reduce_hccl_test ./build/test/st/algorithm/testcase/testcase/executor_pipeline_hccl_test结果示例
结果解析
用例执行结果如下所示:
各字段含义如下:
[run]:表示执行验证的用例
[OK]:表示执行成功,验证通过
[FAIL]:表示执行失败,具体原因根据打屏日志进行分析。
问题定位
内存冲突校验定位方法
问题现象
当两个同步信号之间的某片内存被多个task并发写入,或者在被读取的同时被写入,就会发生内存冲突。这种情况下,在实际运行环境中通常会表现为随机出现的精度问题。
当前Mesh结构下,若存在Reduce算子,可能存在误报的情况。原因是Mesh结构下,可能会出现某块内存在一个同步之间被其他卡同时写入的情况。此时硬件可以确保Reduce操作的原子性,在实际运行中不会出现精度问题,但从checker的角度来看,确实是两个同步之间对同一内存进行了多次读写操作,因为会被认为错误。
除上述场景以外,出现如下报错则认为task编排中有内存冲突的风险:
[1]there is memory use confilict in two SliceMemoryStatus [2]one is startAddr is 0, size is 3200, status is WRITE. [3]another is startAddr is 0, size is 3200, status is WRITE. [4]failed to check memory BufferType::OUTPUT_CCL [5]memory conflict between node [rankId:1, queueId:0, index:1] and node [rankId:2, queueId:0, index:1] [6]check rank memory conflict failed for rank 0第2、3句表示冲突的两个内存块的起始地址(startAddr)、大小(size)以及读写状态(status)。
status有READ和WRITE两个状态,READ表示该内存块正在被读,WRITE表示该内存块正在被写。被读和被写是抽象的内存操作语义,不仅仅是write task和read task。
可能是READ状态的内存块包括localcopy任务的src,read任务的src,write任务的src;可能是WRITE状态的内存块包括localcopy任务的dst,read任务的dst,write任务的dst。
第4句表示冲突内存块的类型。
第5句说明了是哪两个task造成的内存冲突。
第6句说明了产生内存冲突的rank号。
上述错误日志说明同时有两个task在往OUTPUT_CCL类型的0~3200的范围内执行写入操作。
定位方法
在调用Check函数前打开task打印开关。
checker.EnableTaskPrint();根据报错日志找到造成内存冲突的两个task,排查这两个task前后同步的编排。
问题现象中的错误日志说明同时有两个task在往OUTPUT_CCL类型的0~3200的范围内执行写入操作。
语义校验失败定位方法
语义校验基础概念
算法分析器中内存使用相对地址进行表示,由三个字段组成:内存类型、偏移地址offset、大小size,用结构体DataSlice表示:
class DataSlice { public: // 一些方法函数 private: BufferType type; u64 offset; u64 size; }内存支持Input、Output、CCL_Input、CCL_Output、Scratch等类型。
集合通信算法在运行过程中会涉及复杂的数据搬运、规约操作,算法分析器用BufferSemantic(语义)记录数据搬运关系,其中有目的内存表达和多个源内存表达。目的内存通过成员变量startAddr和Size表示;源内存用结构体SrcBufDes表示,结构体定义如下:
struct BufferSemantic { u64 startAddr; mutable u64 size; // 大小,源内存和目的内存共享相同的大小 mutable bool isReduce; // 是否做了reduce操作,srcBufs有多个的时候必定是reduce场景 mutable HcclReduce0p reduceType; // reduce操作的类型 mutable std::set<SrcBufDes> srcBufs; //这块数据来自哪个或哪些rank }; struct SrcBufDes { RankId rankId; // 数据源的rankId BufferType bufType; // 数据源的内存类型 mutable u64 srcAddr; // 相对于数据源内存类型的偏移地址 };语义计算举例
下面已具体例子介绍什么是语义计算。
初始状态,有Rank0与Rank1两个Rank,有Input,Output两种内存类型。
状态一动作:将rank0的Input,偏移地址20,大小为30的数据块搬运到rank0的Output,偏移地址为35结果:在rank0的Output上产生了一个语义块,记录了本次搬运的信息。
状态二动作:将rank1的Input,偏移地址70,大小为15的数据块搬运到rank0的Output,偏移地址为50结果:目的内存与现有的语义块有重叠,需要对现有的语义块进行拆分,产生两条语义块。
结果校验
语义分析执行的过程中产生很多语义块(即记录了很多数据搬运关系)。执行完成后,校验Output内存中的语义块是否符合预期。
接下来以2 rank做AllGather举例,说明Rank0的Output内存中语义块的正常场景和异常场景。假设输入数据大小是100字节。
正确场景:
错误场景:
定位思路
语义校验阶段可以发现两种类型的错误:
- 数据缺失。
- 数据来源错误。
扩展到规约场景,也有类似的问题,比如参与规约的rank数量缺失、参与规约的数据偏移地址不一样等。通常情况下,语义报错的时候会给出一定的提示信息。需要借助提示信息,并结合算法分析器打印的task序列进行具体分析。
【免费下载链接】hcommHCOMM(Huawei Communication)是HCCL的通信基础库,提供通信域以及通信资源的管理能力。项目地址: https://gitcode.com/cann/hcomm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考