So simple and Innocent
·
今天是古法编程()
写完AddCustom、SubCustom再补一点DivCustom
Hi Ascend
#include "acl/acl.h"
#include "kernel_operator.h"
using namespace AscendC;
__global__ __aicore__ void hi_ascend(){
printf("Block[%lu/%lu]: Hi Ascend\n",GetBlockIdx(),GetBlockNum());//long unsigned
}
int32_t main(int argc ,char const *argv[]){
aclInit(nullptr);
int32_t device=0;
aclrtSetDevice(deviceId);
aclrtStream stream=nullptr;
aclrtCreateStream(&stream);
constexpr uint32_t blockDim=4;
hi_ascend<<<blockDim,nullptr,stream>>>();
aclrtSynchronizeStream(stream);
aclrtDestoryStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}
教程 - 逐元素加法
- 数据类型:输入与输出均为 float 类型。
- 数据形状(Shape): 输入Shape为 (8, 2048),输出Shape与输入相同。
首先是函数库
#include <cstdint>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include "acl/acl.h" //host侧调用
#include "kernel_operator.h" //kernel侧调用
using namespace AscendC;
using namespace std;
BufferNum
constexpr uint32_t BUFFER_NUM=2;
constexpr uint32_t QUEUE_DEPTH=2;
tiling结构体
struct AddCustomTilingData{
uint32_t totalLength;
uint32_t tileNum;
};
KernelAdd类
class KernelAdd{
public:
__aicore__ inline KernelAdd(){}
__aicore__ inline void Init(GM_ADDR x,GM_ADDR y,GM_ADDR z,uint32_t totalLength,uint32_t tileNum);
__aicore__ inline void Process();
private:
private:
Tpipe pipe;//TPipe内存管理对象
TQue<TPosition::VECIN,QUEUE_DEPTH> inQueueX,inQueueY;
TQue<TPosition::VECOUT,QUEUE_DEPTH> outQueueZ;
AscendC::GlobalTensor<float> xGm;
AscendC::GlobalTensor<float> yGm;
AscendC::GlobalTensor<float> zGm;
uint32_t blockLength;//单个AICore需要处理数据的总长度
uint32_t tileNum; //核内分块的数量
uint32_t tileLength;//核内分块的数据长度
}
初始化Init函数
__aicore__ inline void KernelAdd::Init(GM_ADDR x,GM_ADDR y,GM_ADDR z,uint32_t totalLength,uint32_t tileNum){
this->blockLength=totalLength/AscendC::GetBlockNum();
this->tileNum=tileNum;
this->tileLength=this->blockLength/tileNum/BUFFER_NUM;
xGm.SetGlobalBuffer((__gm__ float *)x + this->blockLength*GetBlockIdx(),this->blockLength);
yGm.SetGlobalBuffer((__gm__ float *)y +this->blockLength*GetBlockIdx(),this->blockLength);
zGm.SetGlobalBuffer((__gm__ float *)z+this->blockLength*GetBlockIdx(),this->blockLength);
pipe.InitBuffer(inQueueX,BUFFER_NUM,this->tileLength*sizeof(float));
pipe.InitBuffer(inQueueY,BUFFER_NUM,this->tileLength*sizeof(float));
pipe.InitBuffer(outQueueZ,BUFFER_NUM,this->tileLength*sizeof(float));
}
核函数入口
__global__ __aicore__ void add_custom(GM_ADDR x,GM_ADDR y,GM_ADDR z,AddCustomTilingData tiling){
KERNEL_TASK_TYPE_DEFAULT(KERNLE_TYPE_AIV_ONLY);
KernelAdd op;
op.Init(x,y,z,tiling.totalLength,total.tileNum);//初始GlobalMemory数据地址,数据总长度,分块数量
op.Process();
}
Process逻辑
__aicore__ inline void KernelAdd::Process(){
int32_t loopCount=this->tileNum*BUFFER_NUM;
for(int32_t i=0;i<loopCount;i++){
CopyIn(i);
Compute(i);
CopyOut(i);
}
}
CopyIn任务
__aicore__ inline void KernelAdd::CopyIn(int32_t progress){
LocalTensor<float> xLocal=inQueueX.AllocTensor<float>();
LocalTensor<float> yLocal=inQueueY.AllocTensor<float>();
DataCopy(xLocal,xGm[progress*this->tileLength],this->tileLength);
DataCopy(yLocal,yGm[progress*this->tileLength],this->tileLength);
inQueueX.EnQue(xLocal);
inQueueY.EnQue(yLocal);
}
Compute任务
__aicore__ inline void KernelAdd::Compute(int32_t progress){
LocalTensor<float> xLocal=inQueueX.DeQue<float>();
LocalTensor<float> yLocal=inQueueY.DeQue<float>();
LocalTensor<float> zLocal=outQueueZ.AllocTensor<float>();
Add(zLocal,xLocal,yLocal,this->tileLength);
outQueuZ.EnQue<float>(zLocal);
inQueueX.FreeTensor(xLocal);
inQueueY.FreeTensor(yLocal);
}
CopyOut任务
__aicore__ inline void KernelAdd::CopyOut(int32_t progress){
LocalTensor<float> zLocal=outQueueZ.DeQue<float>();
DataCopy(zGm[progress*tileLength],zLocal,tileLength);
outQueueZ.FreeTensor(zlocal);
}
Host侧调用
vector<float> kernel_add(vector<float> &x,vector<float> &y){
constexpr uint32_t blockDim=8;//启动核数
uint32_t totalLength=x.size();
size_t totalByteSize=totalLength*sizeof(float);
int32_t deviceId=0;
aclrtStream stream=nullptr;
AddCustomTilingData tiling={totalLength,8};
uint8_t *xHost=reinterpret_cast<uint8_t *>(x.data());
uint8_t *yHost=reinterpret_cast<uint8_t *>(y.data());
uint8_t *zHost=nullptr;
uint8_t xDevice=nullptr;
uint8_t yDevice=nullptr;
uint8_t zDevice=nullptr;
aclInit(nullptr);
aclrtSetDevice(deviceId);
aclrtCreatStream(&stream);
aclrtMallocHost((void**)(&zHost),totalByteSize);
aclrtMalloc((void **)&xDevice, totalByteSize, ACL_MEM_MALLOC_HUGE_FIRST);
aclrtMalloc((void **)&yDevice, totalByteSize, ACL_MEM_MALLOC_HUGE_FIRST);
aclrtMalloc((void **)&zDevice, totalByteSize, ACL_MEM_MALLOC_HUGE_FIRST);
aclrtMemcpy(xDevice, totalByteSize, xHost, totalByteSize, ACL_MEMCPY_HOST_TO_DEVICE);
aclrtMemcpy(yDevice, totalByteSize, yHost, totalByteSize, ACL_MEMCPY_HOST_TO_DEVICE);
add_custom<<<blockDim, nullptr, stream>>>(xDevice, yDevice, zDevice, tiling);//<<<blockDim, l2ctrl, stream>>> l2ctrl,保留参数,暂时设置为固定值nullptr。
aclrtSynchronizeStream(stream);
aclrtMemcpy(zHost, totalByteSize, zDevice, totalByteSize, ACL_MEMCPY_DEVICE_TO_HOST);
std::vector<float> z((float *)zHost, (float *)(zHost + totalByteSize));
aclrtFree(xDevice);
aclrtFree(yDevice);
aclrtFree(zDevice);
aclrtFreeHost(zHost);
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return z;
}
验证函数VerrifyResult
uint32_t VerifyResult(std::vector<float> &output, std::vector<float> &golden)
{
auto printTensor = [](std::vector<float> &tensor, const char *name) {
constexpr size_t maxPrintSize = 20;
std::cout << name << ": ";
std::copy(tensor.begin(), tensor.begin() + std::min(tensor.size(), maxPrintSize),
std::ostream_iterator<float>(std::cout, " "));
if (tensor.size() > maxPrintSize) {
std::cout << "...";
}
std::cout << std::endl;
};
printTensor(output, "Output");
printTensor(golden, "Golden");
if (std::equal(golden.begin(), golden.end(), output.begin())) {
std::cout << "[Success] Case accuracy is verification passed." << std::endl;
return 0;
} else {
std::cout << "[Failed] Case accuracy is verification failed!" << std::endl;
return 1;
}
return 0;
}
Host侧验证主程序main
int32_t main(int32_t argc, char *argv[])
{
constexpr uint32_t totalLength = 8 * 2048;
constexpr float valueX = 1.2f;
constexpr float valueY = 2.3f;
std::vector<float> x(totalLength, valueX);
std::vector<float> y(totalLength, valueY);
std::vector<float> output = kernel_add(x, y);
std::vector<float> golden(totalLength, valueX + valueY);
return VerifyResult(output, golden);
}
课后实践
请根据本节教程内容,在下面的代码框中补充实现sub_custom.asc,使用Ascend C编程实现矢量减法算子sub_custom。
- 数据类型:输入与输出均为 float 类型。
- 数据形状(Shape): 输入Shape为 (8, 2048),输出Shape与输入相同。
- 数据布局(Format):ND。
#include <cstdint>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include "acl/acl.h"
#include "kernel_operator.h"
using namespace AscendC;
constexpr uint32_t BUFFER_NUM = 2; // tensor num for each queue
constexpr uint32_t QUEUE_DEPTH = 2;
constexpr uint32_t TILE_NUM=8;
constexpr uint32_t BLOCK_NUM=8;
struct SubCustomTilingData
{
uint32_t totalLength;
uint32_t tileNum;
};
class KernelSub {
public:
__aicore__ inline KernelSub(){}
__aicore__ inline void Init(GM_ADDR x, GM_ADDR y, GM_ADDR z, uint32_t totalLength, uint32_t tileNum)
{
// 请补充……
blockLength=totalLegnth/GetBlockNum();
tileNum=tileNum;
tileLength=blockLength/tileNum/BUFFER_NUM;
//从哪传来的 要分配什么
//分配内存,每个核的GlobalMemory访问地址和队列的初始buffer
xGm.SetGlobalBuffer((__gm__ float *)x+this->blockLength*GetBlockId(),tileLength);
yGm.SetGlobalBuffer((__gm__ float *)y+GetBlockNum()*tileLength,tileLength);//这个__gm__ float *是什么写法
zGm.SetGlobalBuffer((__gm__ float *)z+tileLength*GetBloackNum(),tileLength);
//然后下面是用pipe分配内存的
pipe.InitBuffer(inQueueX,BUFFER_NUM,this->tileLength*sizeof(float));
pipe.InitBuffer(inQueueY,BUFFER_NUM,tileLength*sizeof(float));//后面这一项填充的是字节数
pipe.InitBuffer(inQueueY,BUFFER_NUM,tileLength*sizeof(float));
pipe.InitBuffer(outQueue,BUFFER_NUM,tileLength*sizeof(float));
}
__aicore__ inline void Process()
{
// 请补充……
int32_t loopNum=tileNum*BUFFER_NUM;
for(int32_t i=0;i<loopNum;i++){
CopyIn(i);
Compute(i);
CopyOut(i);
}
}
private:
__aicore__ inline void CopyIn(int32_t progress)
{
// 请补充……
LocalTensor<float>xLocal=inQueueX.AllocTensor<float>();
LocalTensor<float>yLocal=inQueueY.AllocTensor<float>();
DataCopy(xLocal,xGm[process*tileLength],tileLength);
DataCopy(xLocal,yGm[process*tileLength].tileLength);
inQueueX.EnQue(xLocal);
inQueueY.EnQue(yLocal);
}
__aicore__ inline void Compute(int32_t progress)
{
// 请补充……
LocalTensor<float>xLocal=inQueueX.Deque<float>();
LocalTensor<float>yLocal=inQueueY.Deque<float>();
LocalTensor<float>zLocal=outQueueZ.AllocTensor<float>();
Sub(zLocal,xLocal,yLocal,tileLength);
outQueueZ.EnQue<float>(zLocal);
inQueueX.FreeTensor(xLocal);
inQueueY.FreeTensor(yLocal);
}
__aicore__ inline void CopyOut(int32_t progress)
{
// 请补充……
LocalTensor<float> zLocal=outQueuZ.DeQue<float>();
DataCopy(zGm[progress*tileLength],zLocal,tileLength);
outQueueZ.FreeTensor(zLocal);
}
private:
// 请补充……
Tpipe pipe;
TQue<AscendC::TPosition::VECIN,QUEUE_DEPTH> inQueueX,inQueueY;
TQue<TPosition::VECOUT,QUEUE_DEPTH> outQueueZ;
GlobalTensor<float> xGm,yGm,zGm;
uint32_t blockLength,tileNum,tileLength;//tiling结构体 totalLength,tileNum
};
__global__ __aicore__ void sub_custom(GM_ADDR x, GM_ADDR y, GM_ADDR z, SubCustomTilingData tiling)
{
// 请补充……
KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY);
KernelSub op;
op.Init(x,y,z,tiling.totalLength,tiling.tileNum);
op.process();
}
std::vector<float> kernel_sub(std::vector<float> &x, std::vector<float> &y)
{
// 请补充……
constexpr uint32_t blockDim=BLOCK_NUM;
uint32_t totalLength=x.size();
size_t totalByteSize=totalLength*sizeof(float);
int32_t deviceId=0;
aclrtStream stream=nullptr;
AddCustomTilingData tiling={totalLength,TILE_NUM}
uint8_t *xHost=reinterpret_cast<uint8_t*>(x.data());//按字节粒度操作内存,二进制层面直接重解释指针类型,强制重解释为1字节无符号字节指针uint8_t *,用这个指针可以逐字节访问 Host 内存
uint8_t *yHost=reinterpret_cast<uint8_t*>(y.data());
uint8_t *zHost =nullptr;
uint8_t *xDevice=nullptr;
uint8_t *yDevice=nullptr;
uint8_t *zDevice=nullptr;
aclInit(nullptr);
aclrtSetDevice(deviceId);
aclrtCreatStream(&stream);
aclrtMallocHost((void**)(&zHost),totalByteSize);
aclrtMalloc((void**)&xDevice,totalByteSize,ACL_MEM_MALLOC_HUGE_FIRST);
aclrtMemcpy(xDevice,totalByteSize,xHost,totalByteSize,ACL_MEMCPY_HOST_TO_DEVICE);
sub_custom<<<BlockDim,nullptr,stream>>>(xDevice,yDevice,zDevice,tiling);//device作资源管理指针
aclrtSynchronizeStream(stream);
aclrtMemcpy(zHost, totalByteSize, zDevice, totalByteSize, ACL_MEMCPY_DEVICE_TO_HOST);
std::vector<float> z((float *)zHost, (float *)(zHost + totalByteSize));
aclrtFree(xDevice);
aclrtFree(yDevice);
aclrtFree(zDevice);
aclrtFreeHost(zHost);
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return z;
}
uint32_t VerifyResult(std::vector<float> &output, std::vector<float> &golden)
{
auto printTensor = [](std::vector<float> &tensor, const char *name) {
constexpr size_t maxPrintSize = 20;
std::cout << name << ": ";
std::copy(tensor.begin(), tensor.begin() + std::min(tensor.size(), maxPrintSize),
std::ostream_iterator<float>(std::cout, " "));
if (tensor.size() > maxPrintSize) {
std::cout << "...";
}
std::cout << std::endl;
};
printTensor(output, "Output");
printTensor(golden, "Golden");
if (std::equal(golden.begin(), golden.end(), output.begin())) {
std::cout << "[Success] Case accuracy is verification passed." << std::endl;
return 0;
} else {
std::cout << "[Failed] Case accuracy is verification failed!" << std::endl;
return 1;
}
return 0;
}
int32_t main(int32_t argc, char *argv[])
{
constexpr uint32_t totalLength = 8 * 2048;
constexpr float valueX = 1.2f;
constexpr float valueY = 2.3f;
std::vector<float> x(totalLength, valueX);
std::vector<float> y(totalLength, valueY);
// 请补充……
std::vector<float> output=kernel_sub(x,y);
std::vector<float> golden(totalLength, valueX - valueY);
return VerifyResult(output, golden);
}
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐

所有评论(0)