3天上手Ascend C编程丨带你认识Ascend C基本概念及常用接口
本文分享自《【2023 · CANN训练营第一季】——Ascend C算子开发入门——第一次课(核函数的定义及实现)》,作者:dayao。
Ascend C是CANN针对算子开发场景推出的编程语言,原生支持C和C++标准规范,最大化匹配用户开发习惯;通过多层接口抽象、自动并行计算、孪生调试等关键技术,极大提高算子开发效率,助力AI开发者低成本完成算子开发和模型调优部署。
时间充足的小伙伴推荐去看官方教程:Ascend C官方教程
想省时省力快速入门可以看这篇文章,为你系统化梳理AscendC编程最重要的知识点,3天快速上手不迷路!
第1天学习要点:

一、使用Ascend C有哪些优势
C/C++原语编程
编程模型屏蔽硬件差异,编程范式提高开发效率
多层级API封装,从简单到灵活,兼顾易用与高效
孪生调试,CPU侧模拟NPU侧的行为,可先在CPU侧调试
二、核函数
核函数(Kernel Function)是Ascend C算子kernel侧实现的入口。Ascend C允许用户使用核函数这种C/C++函数的语法扩展来管理设备端的运行代码,用户在核函数中进行算子类对象的创建和其成员函数的调用,由此实现该算子的所有功能。核函数是主机端和设备端连接的桥梁。
1、核函数定义
核函数是直接在设备端执行的代码。在核函数中,需要为在一个核上执行的代码规定要进行的数据访问和计算操作,当核函数被调用时,多个核将并行执行同一个计算任务。核函数需要按照如下规则进行编写。

1、函数类型限定符

2、必须具有void返回类型
3、变量类型限定符

为了方便:指针入参变量统一的类型定义为__gm__ uint8_t*。用户统一使用uint8_t类型的指针,并在使用时转换为实际的指针类型;亦可直接传入实际的指针类型。
2、核函数调用
核函数的调用语句是C/C++函数调用语句的一种扩展。不同于常见的function_name(argument list)函数调用方式,核函数使用内核调用符<<<...>>>这种语法形式,来规定核函数的执行配置:

1、内核调用符这种调用方式,仅可在NPU侧编译时调用,CPU侧编译无法识别该符号。
2、核函数的调用是异步的,核函数的调用结束后,控制权立刻返回给主机端,可以调用aclrtSynchronizeStream函数来强制主机端程序等待所有核函数执行完毕。
3、算子运行验证
Ascend C算子可用CPU模式或NPU模式执行
CPU模式:算子功能调试用,可以模拟在NPU上的计算行为,不需要依赖昇腾设备
NPU模式:算子功能/性能调试,可以使用NPU的强大算力进行运算加速

4、代码里使用内置宏 __CCE_KT_TEST__标识被宏包括的代码在CPU或NPU模式下编译。
#ifdef __CCE_KT_TEST__
//表示在CPU模式下会编译该段代码 #ifndef __CCE_KT_TEST__
//表示在NPU模式下会编译该段代码
三、helloworld样例演示
1、代码


2、编译与运行


四、常用数据定义
1、GlobalTensor
GlobalTensor用来存放Global Memory(外部存储)的全局数据。
template <typename T> class GlobalTensor {
void SetGlobalBuffer(__gm__ T* buffer, uint32_t bufferSize); // 传入全局数据的指针,并手动设置一个buffer size,初始化GlobalTensor
}
buffer:主机侧传入的全局数据指针
bufferSize:所包含的类型为T的数据个数,单位为 element,需自行保证不会超出实际数据的长度
类型T支持所有数据类型,但需要遵循使用此GlobalTensor的指令的数据类型支持情况。
SetGlobalBuffer用于设置GlobalTensor的存储位置:buffer指向外部存储的起始地址,bufferSize为Tensor所占外部存储的大小,如指向的外部存储有连续256个int32_t,则其dataSize为256。代码示例:
void Init(__gm__ uint8_t *__restrict__ src_gm, __gm__ uint8_t *__restrict__ dst_gm)
{
uint32_t dataSize = 256; //设置input_global的大小为256 GlobalTensor<int32_t> inputGlobal; // 类型为int32_t
inputGlobal.SetGlobalBuffer(reinterpret_cast<__gm__ int32_t *>(src_gm), dataSize); // 设置源操作数在Global Memmory上的起始地址为src_gm,所占外部存储的大小为256个int32_t LocalTensor<int32_t> inputLocal = inQueueX.AllocTensor<int32_t>();
DataCopy(inoutLocal, inputGlobal, dataSize); // 将Global Memmory上的inputGlobal拷贝到Local Memmory的inputLocal上
...
}
2、LocalTensor
用于存放AI Core中Local Memory(内部存储)的数据,支持QuePosition为VECIN、VECOUT、A1、A2、B1、B2、CO1、CO2。
template <typename T> class LocalTensor {
T GetValue(const uint32_t offset) const;
template <typename T1> void SetValue(const uint32_t offset, const T1 value) const;
LocalTensor operator[](const uint32_t offset) const;
uint32_t GetSize() const;
}
函数说明:类型T支持所有数据类型,但需要遵循使用此LocalTensor的指令的数据类型支持情况。

代码示例:
// srcLen = 256, num = 100, M=50
// 示例1
for (int32_t i = 0; i < srcLen; ++i) {
input_local.SetValue(i, num); // 对input_local中第i个位置进行赋值为num
}
// 示例1结果如下:
// 数据(input_local): [100 100 100 ... 100] // 示例2
for (int32_t i = 0; i < srcLen; ++i) {
auto element = input_local.GetValue(i); // 获取input_local中第i个位置的数值
}
// 示例2结果如下:
// element 为100 // 示例3
auto size = input_local.GetSize(); // 获取input_local的长度,size大小为input_local有多少个element
// 示例3结果如下:
// size大小为srcLen,256。 // 示例4
Add(output_local[M], input_local[M], input_local2[M], M); // operator[]使用方法,output_local[M]为从起始地址开始偏移量为M的新tensor
// 示例4结果如下:
// 输入数据(input_local): [100 100 100 ... 100]
// 输入数据(input_local2): [1 2 3 ... 50]
// 输出数据(output_local): [101 102 103 ... 150]
五、多层级API接口
Ascend C提供了多层级的0-3级API,随着级别增高,API使用的自由度降低,易用性增强。开发者可以根据需要选择合适的API,使用最通俗易懂的高级接口快速搭建算子逻辑,使用自由灵活的低级接口进行复杂的逻辑实现和性能调优。这样做的主要作用是:
降低复杂指令的使用难度
跨代兼容性保障
保留最大灵活度的可能



1、3级接口
运算符重载,支持+, -, *, /, |, &, <, >, <=, >=, ==, !=,实现1级指令的简化表达。允许用户使用形如:dst = src0 * src1,针对整个Tensor进行计算,以下指令API拥有3级接口:

2、2级接口
针对源操作数srcLocal的连续COUNT个数据进行计算,并连续写入目的操作数dstLocal,解决一维tensor的连续计算问题。


3、0级接口
0级功能灵活计算接口,是最底层的开发接口,可以完整发回硬件优势的计算API,可以进行非连续计算,该功能可以充分发回CANN系列芯片的强大功能指令,支持对每个操作数的Block stride,Repeat stride,MASK的操作,允许用户使用诸多的通用参数来定制化所需要的操作:

1、重复迭代次数-Repeat times
矢量计算单元,每次读取连续的8个block(每个block32 Bytes,共256 Bytes)数据进行计算,为完成对输入数据的处理,必须通过多次迭代(repeat)才能完成所有数据的读取与计算。Repeat times表示迭代的次数。
如下图所示,待处理数据大小为16个block(512Bytes),每次迭代处理8个block(256Bytes),需要两次迭代完成计算,Repeat times应设置为2。

2、相邻迭代间相同block的地址步长
当Repeat times大于1,需要多次迭代完成矢量计算时,您可以根据不同的使用场景合理设置相邻迭代间相同block的地址步长Repeat stride的值。
连续计算场景:假设定义一个Tensor供目的操作数和源操作数同时使用(即地址重叠),Repeat stride取值为8。此时,矢量计算单元第一次迭代读取连续8个block,第二轮迭代读取下一个连续的8个block,通过多次迭代即可完成所有输入数据的计算。

非连续计算场景:Repeat stride取值大于8(如取10)时,则相邻迭代间矢量计算单元读取的数据在地址上不连续,出现2个block的间隔。

反复计算场景:Repeat stride取值为0时,矢量计算单元会对首个连续的8个block进行反复读取和计算。

部分重复计算:Repeat stride取值大于0且小于8时,相邻迭代间部分数据会被矢量计算单元重复读取和计算,此种情形一般场景不涉及。

3、同一迭代内不同block的地址步长
如果需要控制单次迭代内,数据处理的步长,可以通过设置同一迭代内不同block的地址步长Block stride来实现。
连续计算,Block stride 设置为1,对同一迭代内的8个block数据连续进行处理。
非连续计算,Block stride值大于1(如取2),同一迭代内不同block之间在读取数据时出现一个block的间隔,如下图所示。
4、Mask参数
mask用于控制每次迭代内参与计算的元素。可通过连续模式和逐比特模式两种方式进行设置。
连续模式:表示前面连续的多少个元素参与计算。数据类型为uint64_t。取值范围和操作数的数据类型有关,数据类型不同,每次迭代内能够处理的元素个数最大值不同(当前数据类型单次迭代时能处理的元素个数最大值为:256 / sizeof(数据类型))。当操作数的数据类型占比特位16位时(如half,uint16_t),mask∈[1, 128];当操作数为32位时(如float, int32_t),mask∈[1, 64]。

逐bit模式:可以按位控制哪些元素参与计算,bit位的值为1表示参与计算,0表示不参与。参数类型为长度为2的uint64_t类型数组。参数取值范围和操作数的数据类型有关,数据类型不同,每次迭代内能够处理的元素个数最大值不同。当操作数为16位时,mask[0]、mask[1]∈[0, 264-1];当dst/src为32位时,mask[1]为0,mask[0]∈[0, 264-1]。

512个int16相加分别用0,2,3级接口实现对比,大家可以根据自己的实际需要选择对应的接口。

六、更多学习资源
好啦,本次分享结束啦,Ascend C的学习资源还有很多,想深入学习的可以参考官网教程:Ascend C官方教程。
号外!

华为将于2023年9月20-22日,在上海世博展览馆和上海世博中心举办第八届华为全联接大会(HUAWEICONNECT 2023)。本次大会以“加速行业智能化”为主题,邀请思想领袖、商业精英、技术专家、合作伙伴、开发者等业界同仁,从商业、产业、生态等方面探讨如何加速行业智能化。
我们诚邀您莅临现场,分享智能化的机遇和挑战,共商智能化的关键举措,体验智能化技术的创新和应用。您可以:
在100+场主题演讲、峰会、论坛中,碰撞加速行业智能化的观点
参观17000平米展区,近距离感受智能化技术在行业中的创新和应用
与技术专家面对面交流,了解最新的解决方案、开发工具并动手实践
与客户和伙伴共寻商机
感谢您一如既往的支持和信赖,我们热忱期待与您在上海见面。
大会官网:https://www.huawei.com/cn/events/huaweiconnect
欢迎关注“华为云开发者联盟”公众号,获取大会议程、精彩活动和前沿干货。
3天上手Ascend C编程丨带你认识Ascend C基本概念及常用接口的更多相关文章
- spring框架应用系列三:切面编程(带参数)
本文系作者原创,转载请注明出处:http://www.cnblogs.com/further-further-further/p/7786715.html 解决问题 1.分离业务监控与业务处理.简单点 ...
- JDBC 学习笔记(三)—— JDBC 常用接口和类,JDBC 编程步骤
1. JDBC 常用接口和类 DriverManager 负责管理 JDBC 驱动的服务类,程序中主要的功能是获取连接数据库的 Connection 对象. Connection 代表一个数据库连接对 ...
- 一文带你看清HTTP所有概念(转)
一文带你看清HTTP所有概念 上一篇文章我们大致讲解了一下 HTTP 的基本特征和使用,大家反响很不错,那么本篇文章我们就来深究一下 HTTP 的特性.我们接着上篇文章没有说完的 HTTP 标头继 ...
- YApi——手摸手,带你在Win10环境下安装YApi可视化接口管理平台
手摸手,带你在Win10环境下安装YApi可视化接口管理平台 YApi YApi 是高效.易用.功能强大的 api 管理平台,旨在为开发.产品.测试人员提供更优雅的接口管理服务.可以帮助开发者轻松创建 ...
- 7款易上手C语言编程软件推荐
C语言是一门历史很长的编程语言,其编译器和开发工具也多种多样,其开发工具包括编译器,现举几个开发工具供大家选择,当然也要根据自己的操作系统来选择适合自己的开发工具. 好多刚开始接触c语言的朋友都想知道 ...
- 超级码力编程赛带着6万奖金和1200件T恤向你跑来了~
炎炎夏日,总是感觉很疲劳,提不起一点精神怎么办?是时候参加一场比赛来唤醒你的激情了!阿里云超级码力在线编程大赛震撼携手全国数百所高校震撼来袭. 它来了,它来了,它带着60000现金和1200件T恤向你 ...
- UNIX网络编程——TCP带外数据小结
带外数据概念实际上时向接收端传送三个不同的信息:(1)发送端进入紧急模式这个事实.接收进程得以通知这个事实的手段不外乎SIGURG信号或select调用.本通知在发送进程发送带外字节后由发送端TCP立 ...
- javascript面向对象编程,带你认识封装、继承和多态
原文链接:点我 周末的时候深入的了解了下javascript的面向对象编程思想,收获颇丰,感觉对面向对象编程有了那么一丢丢的了解了~很开森 什么是面向对象编程 先上一张图,可以对面向对象有一个大致的了 ...
- 初学编程丨从零开始学习编程的基本路线,BAT程序员亲手总结!
编程并不是说代码怎么写,框架怎么用,业务怎么转换为代码逻辑,这些都不是编程的要素(但却是工作的刚需......).我认为按照下面这个路线来学习编程,会使自己在学习的路途上少去很多问题(比如为啥会有多线 ...
- C语言编程丨循环链表实现约瑟夫环!真可谓无所不能的C!
循环链表 把链表的两头连接,使其成为了一个环状链表,通常称为循环链表. 和它名字的表意一样,只需要将表中最后一个结点的指针指向头结点,链表就能成环儿,下图所示. 需要注意的是,虽然循环链表成环 ...
随机推荐
- CF1401C
题目简化和分析: 交换数组使其变为升序,满足交互的两数 \(a_i\) 与 \(a_j\),$ \min{a_i(1\le i\le n)}|\gcd(a_i,a_j)$ . 简单思维题,Div.2 ...
- Java并发编程和多线程的区别
并发编程: 并发编程是一种编程范式,它关注的是编写能够正确和高效处理多个并发任务的程序.并发编程不仅包括多线程,还包括了处理多个独立任务的各种技术和模式,如进程.协程.分布式编程等.并发编程的目标是实 ...
- 18.1 Socket 原生套接字抓包
原生套接字抓包的实现原理依赖于Windows系统中提供的ioctlsocket函数,该函数可将指定的网卡设置为混杂模式,网卡混杂模式(Promiscuous Mode)是常用于计算机网络抓包的一种模式 ...
- nginx学习(基本概念、配置和命令、反向代理、负载均衡、动静分离)
之前都只会照着网上的nginx配置和代码什么的直接拿过来用,但是没系统学习过,所以来系统学习一下nginx内容. 建议服务器不要关闭防火墙,按需开启端口就好,然后云服务器也要设置SSH密钥,安全性高一 ...
- 拒绝恶意IP登录服务器
拒绝恶意IP登录服务器,并加入防火墙黑名单 #!/bin/bash #2020-03-20 16:39 #auto refuse ip dlu #By Precious ############### ...
- js前端操作,c#后端下发xml文件
前端: var xmlLanguageDoc; $.ajax({ url: "/GiveMeXML",//此处可随意定义,不一定是路径.在c# ,请求被捕获后,由c ...
- Mach-O Inside: 命令行工具集 otool objdump od 与 dwarfdump
1 otool otool 命令行工具用来查看 Mach-O 文件的结构. 1.1 查看文件头 otool -h -v 文件路径 -h选项表明查看 Mach-O 文件头. -v 选项表明将展示的内容进 ...
- Python 潮流周刊#24:no-GIL 提案正式被采纳了!
你好,我是猫哥.这里每周分享优质的 Python.AI 及通用技术内容,大部分为英文.标题取自其中两则分享,不代表全部内容都是该主题,特此声明. 微信 | 博客 | 邮件 | Github | Tel ...
- js 加密、解密算法类库
有些功能需要前端进行加密解密,就会用到这些库 crypto-js 是一个纯 javascript 写的加密算法类库 ,可以非常方便地在 javascript 进行 MD5.SHA1.SHA2.SHA3 ...
- 一文概览NLP句法分析:从理论到PyTorch实战解读
关注TechLead,分享AI全维度知识.作者拥有10+年互联网服务架构.AI产品研发经验.团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师,项目管理专业人士,上亿营收AI ...