本案例对分组Matmul即GroupedMatmul算子的per-token量化场景进行性能分析和优化,GroupedMatmul算子计算过程(通过python代码表达)为:
验证平台为Atlas A2 训练系列产品/Atlas A2 推理系列产品。
优化分析以如下算子规格为例:
表 1 算子规格
[object Object][object Object]
[object Object]主要介绍以下优化方法:
- 对于Vector计算占比较高(Vector Bound)的场景,将AI Core中的AIC核和AIV核启动比例设置为1:2;
- 优化CV并行流水,减少Cube和Vector计算间的空闲等待时间;
- 优化Vector计算流水,提高Vector并行计算速度。
固定8核测试,即当前性能和后续优化tiling中numBlocks固定设置为8。
通过msProf算子调优工具获取算子性能数据:
- 获取真实环境执行的性能数据(指令的cycle占比数据ArithmeticUtilization.csv),包含各个流水的占比情况;
- 获取仿真性能数据(指令流水图),包含各个流水的占用区间,可观察流水间依赖情况,从而优化并行效率。
固定8核进行测试的情况下,通过msprof op命令获取指令的cycle占比数据如下:
图 1 指令的cycle占比数据ArithmeticUtilization.csv(性能总耗时为218.1us)[object Object][object Object]
通过msprof op simulator获取到的指令流水图如下图所示:
图 2 指令流水图[object Object][object Object]
结合上述两种数据(真实数据和仿真数据)进行性能分析:
Vector计算bound,当前为减少核启动开销设置为1:1;
实际优化过程中,对上述问题进行优化、Vector计算占比下降后,Cube和Vector计算各自都有间隙,相互之间都有等待耗时;
Vector计算没有开启double buffer,计算和数据搬运部分没有并行。
将AI Core中的AIC核和AIV核启动比例设置为1:2。每次AIC输出的数据,由两个AIV并行计算对应的反量化和激活函数;在Vector侧代码的循环里,AIV0和AIV1交替进行计算(前提条件,循环次数不为1)。代码示例如下:
[object Object]AIC和AIV启动比例设置为1:2后,出现Cube和Vector计算各自都有间隙、相互之间都有等待耗时的情况。分析原因是因为Vector和Cube计算存在使用一份workspace进行数据传递的场景,通过4份workspace的方案进行优化:host按4倍baseM * baseN申请workspace,Cube侧代码在计算前可以跳过前4轮的等待。
[object Object]Vector计算开启double buffer,InitBuffer指定分配内存块个数为2。
[object Object]
将AI Core中的AIC和AIV启动比例设置为1:2后,执行总耗时从218.1us下降为154.2us。指令流水图显示Cube计算间等待变小。
如上图所示,Vector计算已经不处于bound状态,但Cube和Vector计算都有间隙,未被充分利用(上述两个箭头的位置)。分析原因如下:
Vector计算在等Cube计算输出的数据,Cube侧需要等Vector计算完释放workspace以存放下一轮的计算结果,当前为了让Cube、Vector计算流水并行,workspace使用了两份空间:
因为Vector和Cube计算存在使用一份workspace进行数据传递的场景,存在数据依赖,所以会有等待的间隔。
可以采用4份workspace进行优化:
优化后,总耗时由154.2us下降为131.8us。指令流水图显示Vector、Cube计算各自间隙明显减小。
Vector计算开启double buffer,优化后执行总耗时从131.8us下降为128.1us。
- 在Vector计算为主要瓶颈点时,将AI Core中的AIC核和AIV核启动比例设置为1:2;
- Cube、Vector计算时间接近,且两者都有因相互等待导致的间隙时,采用4份workspace优化;
- 观察数据搬运是否与计算相互掩盖,多轮计算没有数据依赖,且buffer够大时,开启double buffer,增加并行效率。