基于Ascend C的Matmul算子性能优化最佳实践

news2024/9/21 2:36:42

矩阵乘法是深度学习计算中的基础操作,对于提升模型训练和推理速度至关重要。昇腾AI处理器是一款专门面向AI领域的AI加速器,其AI Core采用达芬奇架构,以高性能Cube计算引擎为基础,针对矩阵运算进行加速,可大幅提高单位面积下的AI算力。Matmul算子实现的功能是矩阵乘法,通过Ascend C算子编程语言优化该算子的实现逻辑,可以使其在昇腾AI处理器上获得更优的执行性能。希望通过本案例的讲解,可以为开发者优化昇腾Cube类算子性能带来启发。


本案例以矩阵维度M = 4096,N = 5120,K = 4096,输入数据类型half,输出数据类型float,输出格式是ND为例,性能验证平台为Atlas A2训练系列产品/Atlas 800I A2推理产品,介绍针对Matmul算子的主要优化手段,包括优化分核逻辑、优化基本块、开启大包搬运。

  • 优化分核逻辑:开启尽量多的Cube核使能并行计算。
  • 优化基本块,选择最优的baseM、baseN、baseK参数。
  • 开启大包搬运:从Global Memory搬运数据到L1时,对于A矩阵,一次搬入depthA1个基本块,基本块大小为baseM * baseK,对于B矩阵,一次搬入depthB1个基本块,基本块大小为baseN * baseK。使能大包搬运后,一次搬入的数据量变大,提升MTE2搬运效率。

分析主要瓶颈点

借助昇腾Profiling性能数据可较方便地分析主要瓶颈点,这里我们重点分析MTE2,Cube,Scalar pipeline的流水情况,其中MTE2(Memory Transfer Engine)pipeline反映了数据的搬入情况,Cube和Scalar pipeline则反映了AI Core中的数据计算及标量的使用情况。

优化前Profiling数据

从上图Profiling数据来看,aic_mte2_ratio数值是0.973,这表明MTE2类型指令的cycle数在total cycle数中的占比过大,这意味着当前性能瓶颈点可能在于MTE2流水。此外,从图中的Block Dim数值4也可以看到,参与计算的AI处理器核并没有用满,这里假设当前案例使用的AI处理器上共有20个核。整体优化思路如下:

  • 优化分核逻辑,假设CurrentCore是未优化前分核的Cube核数,MaxCore为最大Cube核数,当开启全部核并行做当前shape数据量的计算时,预估性能收益约为MaxCore / CurrentCore的倍数。
  • 优化基本块切分将影响搬运数据的效率,算子搬运的总数据量为搬运的左矩阵和右矩阵数据量之和。根据矩阵乘法的算法,搬运左矩阵的次数为N / baseN,搬运右矩阵的次数为M / baseM,即搬运总数据量totalCnt = (N / baseN) * M * K + (M / baseM) * K * N。预估性能收益为搬运数据量的比值,优化前搬运数据量totalCnt0/优化后搬运数据量totalCnt1,化简后结果为(1 / baseM0 + 1 / baseN0) / (1 / baseM1 + 1 / baseN1),其中,baseM0, baseN0为优化前基本块参数,baseM1, baseN1为优化后基本块参数。
  • 开启大包搬运后,指令条数变化、地址对齐等因素会影响性能,按照经验预估,对于MTE2为性能瓶颈的场景,会有20%以上的MTE2性能收益。

优化分核逻辑

由Profiling数据看出分核数为4,启动更多的核同时计算,可以提高计算并行度。在当前案例使用的AI处理器上共20个核,每个核中包含1个Cube Core和2个Vector Core。程序中设置blockDim为实际使用的核数20。

// 代码片段 
uint32_t blockDim = 20; // 优化前blockDim为4 
CHECK_ACL(aclInit(nullptr)); 
aclrtContext context; 
int32_t deviceId = 0; 
CHECK_ACL(aclrtSetDevice(deviceId)); 
CHECK_ACL(aclrtCreateContext(&context, deviceId)); 
aclrtStream stream = nullptr; 
CHECK_ACL(aclrtCreateStream(&stream)); 
 
uint8_t *aHost; 
uint8_t *aDevice; 
CHECK_ACL(aclrtMallocHost((void **)(&aHost), aFileSize)); 
CHECK_ACL( 
  aclrtMalloc((void **)&aDevice, aFileSize, ACL_MEM_MALLOC_HUGE_FIRST)); 
ReadFile("./input/x1_gm.bin", aFileSize, aHost, aFileSize); 
// PrintData(aHost, 16, printDataType::HALF); 
CHECK_ACL(aclrtMemcpy(aDevice, aFileSize, aHost, aFileSize, 
                    ACL_MEMCPY_HOST_TO_DEVICE)); 
 
uint8_t *bHost; 
uint8_t *bDevice; 
CHECK_ACL(aclrtMallocHost((void **)(&bHost), bFileSize)); 
CHECK_ACL( 
  aclrtMalloc((void **)&bDevice, bFileSize, ACL_MEM_MALLOC_HUGE_FIRST)); 
ReadFile("./input/x2_gm.bin", bFileSize, bHost, bFileSize); 
// PrintData(bHost, 16, printDataType::HALF); 
CHECK_ACL(aclrtMemcpy(bDevice, bFileSize, bHost, bFileSize, 
                    ACL_MEMCPY_HOST_TO_DEVICE)); 
 
uint8_t *workspaceHost; 
uint8_t *workspaceDevice; 
CHECK_ACL(aclrtMallocHost((void **)(&workspaceHost), workspaceSize)); 
CHECK_ACL(aclrtMalloc((void **)&workspaceDevice, workspaceSize, 
                    ACL_MEM_MALLOC_HUGE_FIRST)); 
 
uint8_t *tilingHost; 
uint8_t *tilingDevice; 
CHECK_ACL(aclrtMallocHost((void **)(&tilingHost), tilingFileSize)); 
CHECK_ACL(aclrtMalloc((void **)&tilingDevice, tilingFileSize, 
                    ACL_MEM_MALLOC_HUGE_FIRST)); 
CHECK_ACL(aclrtMemcpy(tilingHost, tilingFileSize, GenerateTiling(), 
                    tilingFileSize, ACL_MEMCPY_HOST_TO_HOST)); 
// PrintData(tilingHost, 16, printDataType::UINT32_T); 
CHECK_ACL(aclrtMemcpy(tilingDevice, tilingFileSize, tilingHost, 
                    tilingFileSize, ACL_MEMCPY_HOST_TO_DEVICE)); 
 
uint8_t *cHost; 
uint8_t *cDevice; 
CHECK_ACL(aclrtMallocHost((void **)(&cHost), cFileSize)); 
CHECK_ACL( 
  aclrtMalloc((void **)&cDevice, cFileSize, ACL_MEM_MALLOC_HUGE_FIRST)); 
 
matmul_custom_do(blockDim, stream, aDevice, bDevice, cDevice, workspaceDevice, tilingDevice);

由于Matmul API都是从Vector侧发起的,按照Cube Core和Vector Core的配比1:2,在Matmul tiling计算中需要按照2倍的blockDim数切分,因此Tiling代码中,设置Tiling API按照40个核进行数据切分,如下代码所示。

int usedCoreNum = 40; // 优化前usedCoreNum是8 
int runMode = 1; 
int32_t baseM = 64; // 64 
int32_t baseN = 64; // 64 
optiling::TCubeTiling tilingData; 
auto ascendcPlatform = platform_ascendc::PlatformAscendCManager::GetInstance(socVersion);     
MultiCoreMatmulTiling tilingApi(*ascendcPlatform); 
tilingApi.SetDim(usedCoreNum);

修改代码后,算子执行时间(对应aicore_time)从12045us下降到2532us,约等于(20核 / 4核) = 5倍的性能提升。

优化分核逻辑后Profilling数据

优化基本块

当前Tiling中设置的base块为 [baseM, baseN, baseK] = [64, 64, 256],这种基本块Cube计算cycle少,计算访存比(即计算量与需要数据量的比值)低;搬出一次Matmul结果到Global Memory的base块是64 * 64,由于输出格式是ND,数据类型是float,搬出下一次Matmul结果的起始地址需要偏移一个baseN的大小,即64 * 4 = 256字节,导致fixpipe搬出时Global Memory地址非512byte对齐,那么需要设置更优的基本块。


针对当前shape较大的场景,基本块的选择原则为计算访存比最大,即在Cube计算量最大的情况下,访存的数据量最小。在输入为fp16类型的情况下,Cube执行单元1 cycle能算16 * 16 * 16个数。根据经验,[baseM, baseN, baseK] = [128, 256, 64]和[128, 128, 128]两种切分方案均满足搬出时Global Memory地址512Byte对齐(每搬出一次Matmul结果时,地址分别偏移256 * 4byte和128 * 4byte),Cube计算cycle数一致,为(128 * 64 * 256) / (16 * 16 * 16) = (128 * 128 * 128) / (16 * 16 * 16) = 512cycle。


针对[baseM, baseN, baseK] = [128, 256, 64],计算访存比为512cycle / (128 * 64 * 2 + 256 * 64 * 2) = 512cycle / 48KB;针对[baseM, baseN, baseK] = [128, 128, 128],计算访存比为512cycle / (128 * 128 * 2 + 128 * 128 * 2) = 512cycle / 64KB。可见,[128, 256, 64]基本块方案的计算访存比更高,计算密度更大,同样的计算量,需要的数据量最小,可最大限度地提高Cube单元计算量。


修改Tiling代码,通过SetFixSplit()接口设置baseM和baseN,tiling函数会自动计算出最优baseK,这里得到64。

int32_t baseM = 128; // 优化前baseM是64 
int32_t baseN = 256; // 优化前baseN是64 
 
optiling::TCubeTiling tilingData; 
auto ascendcPlatform = platform_ascendc::PlatformAscendCManager::GetInstance(socVersion);     
MultiCoreMatmulTiling tilingApi(*ascendcPlatform); 
tilingApi.SetDim(usedCoreNum); 
tilingApi.SetAType(leftPos, leftFormat, leftDtype, bool(transposeA)); 
tilingApi.SetBType(rightPos, rightFormat, rightDtype, bool(transposeB)); 
tilingApi.SetCType(resPos, resFormat, resDtype); 
tilingApi.SetBiasType(biasPos, biasFormat, biasDtype); 
 
tilingApi.SetOrgShape(M, N, K); 
tilingApi.SetShape(M, N, K); 
tilingApi.SetFixSplit(baseM, baseN, -1);

从下图可以看到,使能这组基本块后,MTE2耗时(对应aic_mte2_time)从2452us降低到808us,MTE2性能提升3倍。

优化基本块后Profilling数据

使能大包搬运

当前带宽利用率为:totalSize / mte2Time = totalCnt * dtype / mte2Time,代入数据计算为 2491GB/s。未使能大包搬运的情况下,矩阵从Global Memory搬运到L1一次只搬运1个基本块。通过模板参数使能大包搬运,一次搬运多个基本块,提高MTE2带宽利用率。

 // 原始matmul对象定义: 
  Matmul<MatmulType<TPosition::GM, CubeFormat::ND, A_T>, 
         MatmulType<TPosition::GM, CubeFormat::ND, B_T>, 
         MatmulType<TPosition::GM, CubeFormat::ND, C_T>, 
         MatmulType<TPosition::GM, CubeFormat::ND, BiasT>>> 
      mm; 
 // 通过在定义matmul对象的模板参数里加上CFG_MDL参数使能大包搬运功能: 
  Matmul<MatmulType<TPosition::GM, CubeFormat::ND, A_T>, 
         MatmulType<TPosition::GM, CubeFormat::ND, B_T>, 
         MatmulType<TPosition::GM, CubeFormat::ND, C_T>, 
         MatmulType<TPosition::GM, CubeFormat::ND, BiasT>, CFG_MDL>> 
      mm;

从下图可以看到,使能大包搬运后,MTE2耗时从808us下降到591us,带宽利用率代入数据计算为3406GB/s,利用率提升36%+,Cube利用率(对应aic_mac_ratio)达到80%+。

使能大包搬运后Profilling数据

验证优化方案性能收益

  • 优化分核逻辑,实际收益4.75倍,约等于(20核 / 4核) = 5倍收益,并且考虑到核的启动开销,可以认为两者基本一致。
  • 优化基本块,实际收益约3倍,理论评估带入上述分析公式,收益为(1 / 64 + 1 / 64) / (1 / 128 + 1 / 256),约等于2.7倍,考虑到cache缓存的影响,可以认为两者基本一致。
  • 大包搬运,大包搬运实际收益25%+,与经验值基本一致。

但需要注意的是,优化分核逻辑和基本块一般在输入数据shape足够大、数据量足够多时,才能分满核和使能最优的基本块。因此,大shape场景下MTE2 Bound算子可参考此案例的优化手段。

更多学习资源

了解更多Ascend C算子性能优化手段和实践案例,请访问昇腾社区Ascend C信息专区:昇腾Ascend C-入门课程-学习资源-算子文档-昇腾社区 

 

 相关推荐阅读:
《基于Ascend C的FlashAttention算子性能优化最佳实践》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2034893.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript 逆向爬取实战

准备介绍&#xff1a; 当我们学习完整个 JS 逆向技巧后&#xff0c;这里是一次完整的分析爬取实战 案例介绍 本节案例网站不仅在 API 参数有加密&#xff0c; 而且前端 JS 也带有压缩混淆&#xff0c;其前端压缩打包工具使用 webpack , 混淆工具使用 javascript-obfuscator 。…

Spring @Transactional事务传播行为详解

目录 一、无事务情况 二、有事务情况 REQUIRED SUPPORTS MANDATORY REQUIRES_NEW NOT_SUPPORTED NEVER NESTED Spring的事务传播机制用于控制在多个事务方法相互调用时事务的行为。 在复杂的业务场景中&#xff0c;多个事务方法之间的调用可能会导致事务的一致性&…

谷粒商城【renren-fast-vue】:npm install 报错

谷粒商城【renren-fast-vue】&#xff1a;npm install 报错 报错信息报错原因解决办法 报错信息 谷粒商城【renren-fast-vue】&#xff1a;npm install 报错 npm install 下载依赖的时候报错sass 版本与 node 版本不对应 报错原因 直接使用 npm 下载依赖&#xff0c;可能会…

RCE技巧

RCE技巧 Linux命令长度限制突破方法8个字符限制绕过过滤英文字母和数字php版本7php版本5 Linux命令长度限制突破方法 8个字符限制绕过 <?php <?php $param $_REQUEST[param]; if (strlen($param) < 8) {echo shell_exec($param); }shell_exec — 通过 shell 执行…

【大模型从入门到精通14】openAI API 构建和评估大型语言模型(LLM)应用2

这里写目录标题 评估大型语言模型&#xff08;LLM&#xff09;输出的方法构建评估标准实施评估协议利用专家比较案例研究评估客户服务聊天机器人学术文本摘要高级评估技术 评估大型语言模型&#xff08;LLM&#xff09;输出的方法 评估大型语言模型&#xff08;LLM&#xff09…

甄选范文“论软件设计方法及其应”软考高级论文系统架构设计师论文

论文真题 软件设计(Software Design,SD)根据软件需求规格说明书设计软件系统的整体结构、划分功能模块、确定每个模块的实现算法以及程序流程等,形成软件的具体设计方案。软件设计把许多事物和问题按不同的层次和角度进行抽象,将问题或事物进行模块化分解,以便更容易解决…

无人机之电机篇

一、无人机使用什么类型的电动机 无人机主要使用直流无刷电机和伺服电机。 直流无刷电机通常用于无人机的推进系统&#xff0c;因为它具有强大的驱动力和高功率输出&#xff0c;能够为无人机提供足够的推力。 此外&#xff0c;直流无刷电机具有电动机启动转矩大、无刷向触点…

MTF-SFR总结/探讨

空间频率响应&#xff08;SFR&#xff09;定义 在iso12233:2000中&#xff0c;空间频率响应&#xff08;SFR&#xff09;测量被定义为通过分析倾斜黑白边缘附近的相机数据而测量的值。 图像清晰度测试方法 通过ISO12233测试图像清晰度的方法&#xff0c;一般有 TVline测试和S…

去中心化技术的崛起:探索Web3的新时代

引言&#xff1a; Web3是互联网发展的新阶段&#xff0c;它通过去中心化技术重新定义了数字世界的运作方式。这一新时代不仅带来了技术上的突破&#xff0c;也为社会互动和数据管理开辟了新的前景。本文将深入探讨Web3的核心技术、应用领域、全球影响以及面临的挑战&#xff0…

nvm的下载和使用(Windows)

NVM&#xff08;Node Version Manager&#xff09;是一个用于管理多个Node.js版本的工具&#xff0c;它允许用户在同一台机器上安装和使用多个Node.js版本。 一、NVM的基本功能 多版本支持&#xff1a;NVM允许用户在同一台机器上安装多个Node.js版本&#xff0c;方便处理不同…

极光流星大爆发

卑微仔广东持续200%含云量&#xff0c;线上观望大家分享的极光与流星共舞的神奇场景。 极光与流星相伴的瞬间&#xff0c;永远震撼于绝美的星空 开始放毒&#xff08;放图放图&#xff09;&#xff08;以下均拍摄于12日晚至13日晨这一时间段&#xff09;&#xff1a; 先驱猎光…

Qt之2048项目的介绍

文章目录 前言项目介绍项目截图技术介绍1. Qt 框架2. 界面绘制3. 用户输入4. 游戏逻辑5. 音效处理总结前言 2048 是一款流行的益智游戏,通过滑动屏幕上的数字方块,使相同的数字合并并生成更大的数字,最终目标是生成2048这个数字。本文介绍了基于 Qt 框架开发的一个 2048 游…

超声波清洗机哪个品牌好用?品质上等的超声波眼镜清洗机评选

随着科技的发展&#xff0c;超声波清洗机已经成为了人们生活中的清洁神器&#xff0c;它只需要清水便可以清洗假牙、刮胡刀、牙刷、眼镜、化妆工具等小物件&#xff0c;而且能够清洗到物件中的角落缝隙&#xff0c;在专业设备上还同时具备消毒除菌的功能&#xff0c;既能保证清…

软件检测报告的客观性与权威性如何确定

确保软件检测报告的客观性与权威性乃是软件测试进程中的关键要素&#xff0c;以下乃是若干确保报告质量与信誉的举措&#xff1a; 其一&#xff0c;拣选获认证的测试机构&#xff1a;选取具备 CMA&#xff08;中国计量认证&#xff09;以及 CNAS&#xff08;中国合格评定国家认…

AxMath保姆级安装教程(word联用)及使用TIPS

一、软件介绍 AxMath是一款数学公式编辑器软件。它提供了一个直观的界面&#xff0c;使用户可以轻松创建和编辑数学公式。AxMath支持多种数学符号、方程式、函数、矩阵等的输入和编辑&#xff0c;并提供了丰富的数学符号库和模板&#xff0c;方便用户快速创建复杂的数学公式。…

33_对bluecms v1.6进行代码审计、用代码审计三种方法分别进行实施、bluecms v1.6下载与安装、定向功能分析法

部署bluecms v1.6 靶场下载地址&#xff1a; https://wwtt.lanzn.com/b00uyckd9a 密码:2x71 访问 http://127.0.0.1/bluecms/install/ 数据库名称建议跟网站名一样 进入mysql-front查看&#xff0c;出现bluecms数据库&#xff0c;并且库中有很多表 然后访问前台&#xff1a;h…

DW_ahb_databook学习及部分AHB知识回顾

一、DW_ahb框图 Arbiter: 一次只允许一个master发起数据传输&#xff0c;同时可以选择slave Optional Internal Decoder: 通过解码系统地址总线为AHB上的从机生成外设选择。每个slave都可以指定一个起始和结束地址&#xff0c;该地址必须与1kb边界对齐。 Optional External D…

【云原生】高可用集群KEEPALIVED(理论篇)

一、高可用集群 1.1 集群类型 LB:Load Balance 负载均衡 LVS/HAProxy/nginx(http/upstream, stream/upstream)HA:High Availability 高可用集群数据库、RedisSPoF: Single Point of Failure&#xff0c;解决单点故障HPC: High Performance computing 高性能集群 1.2 系统可用…

第二十五天培训笔记

2 、在 python 中连接数据库并结合游标对数据库进行操作 前提&#xff1a;要有 python3 环境 pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple // 设置 pip3 的全 局配置&#xff0c;将默认的 Python 包索引源&#xff08; index-url &am…

Raspberry Pi Pico 2 上实现:实时机器学习(ML)音频噪音抑制功能

Arm 公司的首席软件工程师 Sandeep Mistry 为我们展示了一种全新的巧妙方法&#xff1a; 在 Raspberry Pi Pico 2 上如何将音频噪音抑制应用于麦克风输入。 机器学习&#xff08;ML&#xff09;技术彻底改变了许多软件应用程序的开发方式。应用程序开发人员现在可以为所需系统整…