已合并
【代码侦探Challenge05】完成weixin_48384182的MulCustom逐元素乘法算子 #2452
爱上纯净的蓝天创建于 9月2日
【代码侦探Challenge05】完成weixin_48384182的MulCustom逐元素乘法算子 #2452
已合并
共 6 个文件变更+464-0
A2026/CANN-Code-Detective/Challenge02-DivBf16Custom/weixin_48384182/DivBf16Custom/CMakeLists.txt+10-0
| @@ -0,0 +1,10 @@ | |||
| 1 | +cmake_minimum_required(VERSION 3.16) | ||
| 2 | +find_package(ASC REQUIRED) | ||
| 3 | +project(kernel_samples LANGUAGES ASC CXX) | ||
| 4 | + | ||
| 5 | +add_executable(div_bf16_test | ||
| 6 | + div_bf16_custom.asc | ||
| 7 | +) | ||
| 8 | +target_compile_options(div_bf16_test PRIVATE | ||
| 9 | + $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=dav-2201> | ||
| 10 | +) | ||
A2026/CANN-Code-Detective/Challenge02-DivBf16Custom/weixin_48384182/DivBf16Custom/div_bf16_custom.asc+238-0
| @@ -0,0 +1,238 @@ | |||
| 1 | +// div_bf16_custom.asc | ||
| 2 | + | ||
| 3 | +#include <cstdint> | ||
| 4 | +#include <iostream> | ||
| 5 | +#include <vector> | ||
| 6 | +#include <algorithm> | ||
| 7 | +#include <iterator> | ||
| 8 | +#include <cstring> | ||
| 9 | +#include "acl/acl.h" | ||
| 10 | +#include "kernel_operator.h" | ||
| 11 | + | ||
| 12 | +class KernelDivBf16 { | ||
| 13 | +public: | ||
| 14 | + __aicore__ inline KernelDivBf16() {} | ||
| 15 | + __aicore__ inline void Init(GM_ADDR x, GM_ADDR y, GM_ADDR z, uint32_t totalLength) | ||
| 16 | + { | ||
| 17 | + this->totalLength = totalLength; | ||
| 18 | + xGm.SetGlobalBuffer((__gm__ bfloat16_t *)x, totalLength); | ||
| 19 | + yGm.SetGlobalBuffer((__gm__ bfloat16_t *)y, totalLength); | ||
| 20 | + zGm.SetGlobalBuffer((__gm__ bfloat16_t *)z, totalLength); | ||
| 21 | + | ||
| 22 | + // 初始化输入输出队列 | ||
| 23 | + // 本题无需 Tiling,直接使用整个 totalLength 一次性计算 | ||
| 24 | + pipe.InitBuffer(inQueueX, 1, totalLength * sizeof(bfloat16_t)); | ||
| 25 | + pipe.InitBuffer(inQueueY, 1, totalLength * sizeof(bfloat16_t)); | ||
| 26 | + pipe.InitBuffer(outQueueZ, 1, totalLength * sizeof(bfloat16_t)); | ||
| 27 | + | ||
| 28 | + // 完成 TBuf 初始化 | ||
| 29 | + // 使用 InitBuffer 初始化两个 TBuf(tmpBuf0、tmpBuf1), | ||
| 30 | + // 大小为 totalLength * sizeof(float),位置为 VECCALC | ||
| 31 | + pipe.InitBuffer(tmpBuf0, totalLength * sizeof(float)); | ||
| 32 | + pipe.InitBuffer(tmpBuf1, totalLength * sizeof(float)); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + __aicore__ inline void Process() | ||
| 36 | + { | ||
| 37 | + CopyIn(); | ||
| 38 | + Compute(); | ||
| 39 | + CopyOut(); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | +private: | ||
| 43 | + __aicore__ inline void CopyIn() | ||
| 44 | + { | ||
| 45 | + // 完成 CopyIn 实现 | ||
| 46 | + // 提示:本题无需 Tiling,直接使用整个 totalLength 进行 DataCopy | ||
| 47 | + // 1. AllocTensor 获取 xLocal、yLocal | ||
| 48 | + auto xLocal = inQueueX.AllocTensor<bfloat16_t>(); | ||
| 49 | + auto yLocal = inQueueY.AllocTensor<bfloat16_t>(); | ||
| 50 | + // 2. DataCopy 从 GM 搬运到 UB | ||
| 51 | + AscendC::DataCopy(xLocal, xGm[0], totalLength); | ||
| 52 | + AscendC::DataCopy(yLocal, yGm[0], totalLength); | ||
| 53 | + // 3. EnQue 入队 | ||
| 54 | + inQueueX.EnQue(xLocal); | ||
| 55 | + inQueueY.EnQue(yLocal); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + __aicore__ inline void Compute() | ||
| 59 | + { | ||
| 60 | + // 完成 Compute 实现 | ||
| 61 | + // 1. 从 inQueueX、inQueueY 中 DeQue 获取 xLocal、yLocal(bfloat16_t) | ||
| 62 | + auto xLocal = inQueueX.DeQue<bfloat16_t>(); | ||
| 63 | + auto yLocal = inQueueY.DeQue<bfloat16_t>(); | ||
| 64 | + // 2. 从 outQueueZ 中 AllocTensor 获取 zLocal(bfloat16_t) | ||
| 65 | + auto zLocal = outQueueZ.AllocTensor<bfloat16_t>(); | ||
| 66 | + // 3. 从 tmpBuf0、tmpBuf1 中 Get<float> 获取临时 tensor | ||
| 67 | + auto tmpTensor0 = tmpBuf0.Get<float>(); | ||
| 68 | + auto tmpTensor1 = tmpBuf1.Get<float>(); | ||
| 69 | + // 4. 使用 Cast 将 xLocal、yLocal 从 bfloat16_t 转为 float,存入 tmpTensor | ||
| 70 | + // 提示:RoundMode 使用 CAST_NONE | ||
| 71 | + AscendC::Cast<float, bfloat16_t>(tmpTensor0, xLocal, AscendC::RoundMode::CAST_NONE, totalLength); | ||
| 72 | + AscendC::Cast<float, bfloat16_t>(tmpTensor1, yLocal, AscendC::RoundMode::CAST_NONE, totalLength); | ||
| 73 | + // 5. 使用 Div 执行 float 除法:tmpTensor0 = tmpTensor0 / tmpTensor1 | ||
| 74 | + AscendC::Div<float>(tmpTensor0, tmpTensor0, tmpTensor1, totalLength); | ||
| 75 | + // 6. 使用 Cast 将结果从 float 转回 bfloat16_t,存入 zLocal | ||
| 76 | + // 提示:RoundMode 使用 CAST_RINT | ||
| 77 | + AscendC::Cast<bfloat16_t, float>(zLocal, tmpTensor0, AscendC::RoundMode::CAST_RINT, totalLength); | ||
| 78 | + // 7. EnQue(zLocal),FreeTensor(xLocal)、FreeTensor(yLocal) | ||
| 79 | + outQueueZ.EnQue(zLocal); | ||
| 80 | + inQueueX.FreeTensor(xLocal); | ||
| 81 | + inQueueY.FreeTensor(yLocal); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + __aicore__ inline void CopyOut() | ||
| 85 | + { | ||
| 86 | + // 完成 CopyOut 实现 | ||
| 87 | + // 提示:本题无需 Tiling,直接使用整个 totalLength 进行 DataCopy | ||
| 88 | + // 1. DeQue 获取 zLocal | ||
| 89 | + auto zLocal = outQueueZ.DeQue<bfloat16_t>(); | ||
| 90 | + // 2. DataCopy 从 UB 搬运到 GM | ||
| 91 | + AscendC::DataCopy(zGm[0], zLocal, totalLength); | ||
| 92 | + // 3. FreeTensor | ||
| 93 | + outQueueZ.FreeTensor(zLocal); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | +private: | ||
| 97 | + uint32_t totalLength; | ||
| 98 | + AscendC::GlobalTensor<bfloat16_t> xGm; | ||
| 99 | + AscendC::GlobalTensor<bfloat16_t> yGm; | ||
| 100 | + AscendC::GlobalTensor<bfloat16_t> zGm; | ||
| 101 | + AscendC::TPipe pipe; | ||
| 102 | + AscendC::TQue<AscendC::TPosition::VECIN, 1> inQueueX; | ||
| 103 | + AscendC::TQue<AscendC::TPosition::VECIN, 1> inQueueY; | ||
| 104 | + AscendC::TQue<AscendC::TPosition::VECOUT, 1> outQueueZ; | ||
| 105 | + // 完成 TBuf 声明 | ||
| 106 | + // 声明两个 TBuf<AscendC::TPosition::VECCALC>:tmpBuf0、tmpBuf1 | ||
| 107 | + AscendC::TBuf<AscendC::TPosition::VECCALC> tmpBuf0; | ||
| 108 | + AscendC::TBuf<AscendC::TPosition::VECCALC> tmpBuf1; | ||
| 109 | +}; | ||
| 110 | + | ||
| 111 | +__global__ __aicore__ void div_bf16_custom(GM_ADDR x, GM_ADDR y, GM_ADDR z, uint32_t totalLength) | ||
| 112 | +{ | ||
| 113 | + KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY); | ||
| 114 | + KernelDivBf16 op; | ||
| 115 | + op.Init(x, y, z, totalLength); | ||
| 116 | + op.Process(); | ||
| 117 | +} | ||
| 118 | + | ||
| 119 | +// bfloat16 与 float 之间的转换辅助函数,实现为简化计算,不与kernel侧实现完全一致 | ||
| 120 | +inline uint16_t FloatToBfloat16Bits(float f) | ||
| 121 | +{ | ||
| 122 | + uint32_t bits; | ||
| 123 | + std::memcpy(&bits, &f, sizeof(float)); | ||
| 124 | + return static_cast<uint16_t>(bits >> 16); | ||
| 125 | +} | ||
| 126 | + | ||
| 127 | +inline float Bfloat16BitsToFloat(uint16_t bf16) | ||
| 128 | +{ | ||
| 129 | + uint32_t bits = static_cast<uint32_t>(bf16) << 16; | ||
| 130 | + float f; | ||
| 131 | + std::memcpy(&f, &bits, sizeof(float)); | ||
| 132 | + return f; | ||
| 133 | +} | ||
| 134 | + | ||
| 135 | +std::vector<float> kernel_div_bf16(std::vector<float> &x, std::vector<float> &y) | ||
| 136 | +{ | ||
| 137 | + uint32_t totalLength = static_cast<uint32_t>(x.size()); | ||
| 138 | + | ||
| 139 | + // 将 float 输入转为 bfloat16 (uint16_t) 比特表示 | ||
| 140 | + std::vector<uint16_t> xBf16(totalLength); | ||
| 141 | + std::vector<uint16_t> yBf16(totalLength); | ||
| 142 | + for (uint32_t i = 0; i < totalLength; i++) { | ||
| 143 | + xBf16[i] = FloatToBfloat16Bits(x[i]); | ||
| 144 | + yBf16[i] = FloatToBfloat16Bits(y[i]); | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + // 初始化 ACL | ||
| 148 | + aclrtStream stream = nullptr; | ||
| 149 | + uint8_t *xDevice = nullptr; | ||
| 150 | + uint8_t *yDevice = nullptr; | ||
| 151 | + uint8_t *zDevice = nullptr; | ||
| 152 | + std::vector<uint16_t> zHost(totalLength, 0); | ||
| 153 | + | ||
| 154 | + aclInit(nullptr); | ||
| 155 | + aclrtSetDevice(0); | ||
| 156 | + aclrtCreateStream(&stream); | ||
| 157 | + | ||
| 158 | + // 分配 device 内存并搬运数据 | ||
| 159 | + uint32_t bufferSize = totalLength * sizeof(uint16_t); | ||
| 160 | + aclrtMalloc((void **)&xDevice, bufferSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 161 | + aclrtMalloc((void **)&yDevice, bufferSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 162 | + aclrtMalloc((void **)&zDevice, bufferSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 163 | + aclrtMemcpy(xDevice, bufferSize, xBf16.data(), bufferSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 164 | + aclrtMemcpy(yDevice, bufferSize, yBf16.data(), bufferSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 165 | + | ||
| 166 | + // 启动 kernel:单核执行 | ||
| 167 | + constexpr uint32_t blockDim = 1; | ||
| 168 | + div_bf16_custom<<<blockDim, nullptr, stream>>>(xDevice, yDevice, zDevice, totalLength); | ||
| 169 | + aclrtSynchronizeStream(stream); | ||
| 170 | + | ||
| 171 | + // 回拷结果 | ||
| 172 | + aclrtMemcpy(zHost.data(), bufferSize, zDevice, bufferSize, ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 173 | + | ||
| 174 | + // 将 bfloat16 比特转回 float | ||
| 175 | + std::vector<float> output(totalLength); | ||
| 176 | + for (uint32_t i = 0; i < totalLength; i++) { | ||
| 177 | + output[i] = Bfloat16BitsToFloat(zHost[i]); | ||
| 178 | + } | ||
| 179 | + | ||
| 180 | + // 释放资源 | ||
| 181 | + aclrtFree(xDevice); | ||
| 182 | + aclrtFree(yDevice); | ||
| 183 | + aclrtFree(zDevice); | ||
| 184 | + aclrtDestroyStream(stream); | ||
| 185 | + aclrtResetDevice(0); | ||
| 186 | + aclFinalize(); | ||
| 187 | + | ||
| 188 | + return output; | ||
| 189 | +} | ||
| 190 | + | ||
| 191 | +uint32_t VerifyResult(std::vector<float> &output, std::vector<float> &golden) | ||
| 192 | +{ | ||
| 193 | + auto printTensor = [](std::vector<float> &tensor, const char *name) { | ||
| 194 | + constexpr size_t maxPrintSize = 20; | ||
| 195 | + std::cout << name << ": "; | ||
| 196 | + std::copy(tensor.begin(), tensor.begin() + std::min(tensor.size(), maxPrintSize), | ||
| 197 | + std::ostream_iterator<float>(std::cout, " ")); | ||
| 198 | + if (tensor.size() > maxPrintSize) { | ||
| 199 | + std::cout << "..."; | ||
| 200 | + } | ||
| 201 | + std::cout << std::endl; | ||
| 202 | + }; | ||
| 203 | + printTensor(output, "Output"); | ||
| 204 | + printTensor(golden, "Golden"); | ||
| 205 | + // bfloat16 精度较低,使用容差比较 | ||
| 206 | + bool success = true; | ||
| 207 | + for (size_t i = 0; i < output.size(); i++) { | ||
| 208 | + if (std::abs(output[i] - golden[i]) > 1e-3) { | ||
| 209 | + success = false; | ||
| 210 | + break; | ||
| 211 | + } | ||
| 212 | + } | ||
| 213 | + if (success) { | ||
| 214 | + std::cout << "[Success] Case accuracy is verification passed." << std::endl; | ||
| 215 | + return 0; | ||
| 216 | + } else { | ||
| 217 | + std::cout << "[Failed] Case accuracy is verification failed!" << std::endl; | ||
| 218 | + return 1; | ||
| 219 | + } | ||
| 220 | +} | ||
| 221 | + | ||
| 222 | +int32_t main(int32_t argc, char *argv[]) | ||
| 223 | +{ | ||
| 224 | + constexpr uint32_t totalLength = 2048; | ||
| 225 | + constexpr float valueX = 1.2f; | ||
| 226 | + constexpr float valueY = 2.3f; | ||
| 227 | + std::vector<float> x(totalLength, valueX); | ||
| 228 | + std::vector<float> y(totalLength, valueY); | ||
| 229 | + | ||
| 230 | + std::vector<float> output = kernel_div_bf16(x, y); | ||
| 231 | + | ||
| 232 | + // golden 值需模拟 bfloat16 精度:float → bfloat16 → float → 除法 → bfloat16 → float | ||
| 233 | + float xBf16 = Bfloat16BitsToFloat(FloatToBfloat16Bits(valueX)); | ||
| 234 | + float yBf16 = Bfloat16BitsToFloat(FloatToBfloat16Bits(valueY)); | ||
| 235 | + float goldenValue = Bfloat16BitsToFloat(FloatToBfloat16Bits(xBf16 / yBf16)); | ||
| 236 | + std::vector<float> golden(totalLength, goldenValue); | ||
| 237 | + return VerifyResult(output, golden); | ||
| 238 | +} | ||
| @@ -0,0 +1,9 @@ | |||
| 1 | +#!/bin/bash | ||
| 2 | +# 激活cann环境,可根据实际情况修改,在线环境一般不用修改, | ||
| 3 | +source "$ASCEND_TOOLKIT_HOME/set_env.sh" | ||
| 4 | +mkdir -p build | ||
| 5 | +export ASC_DIR="$ASCEND_HOME_PATH/aarch64-linux/tikcpp/ascendc_kernel_cmake/" | ||
| 6 | +cd build/ && \ | ||
| 7 | +cmake .. && \ | ||
| 8 | +make && \ | ||
| 9 | +./div_bf16_test | ||
| @@ -0,0 +1,13 @@ | |||
| 1 | +cmake_minimum_required(VERSION 3.16) | ||
| 2 | + | ||
| 3 | +find_package(ASC REQUIRED) | ||
| 4 | + | ||
| 5 | +project(kernel_samples LANGUAGES ASC CXX) | ||
| 6 | + | ||
| 7 | +add_executable(mul_test | ||
| 8 | + mul_custom.asc | ||
| 9 | +) | ||
| 10 | + | ||
| 11 | +target_compile_options(mul_test PRIVATE | ||
| 12 | + $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=dav-2201> | ||
| 13 | +) | ||
| @@ -0,0 +1,176 @@ | |||
| 1 | +#include <cstdint> | ||
| 2 | +#include <iostream> | ||
| 3 | +#include <vector> | ||
| 4 | +#include <algorithm> | ||
| 5 | +#include <iterator> | ||
| 6 | +#include "acl/acl.h" | ||
| 7 | +#include "kernel_operator.h" | ||
| 8 | + | ||
| 9 | +constexpr uint32_t BUFFER_NUM = 2; // tensor num for each queue | ||
| 10 | + | ||
| 11 | +struct MulCustomTilingData | ||
| 12 | +{ | ||
| 13 | + uint32_t totalLength; | ||
| 14 | + uint32_t tileNum; | ||
| 15 | +}; | ||
| 16 | + | ||
| 17 | +class KernelMul { | ||
| 18 | +public: | ||
| 19 | + __aicore__ inline KernelMul() {} | ||
| 20 | + __aicore__ inline void Init(GM_ADDR x, GM_ADDR y, GM_ADDR z, uint32_t totalLength, uint32_t tileNum) | ||
| 21 | + { | ||
| 22 | + // 请补充:多核数据切分,计算每个核处理的长度 blockLength | ||
| 23 | + this->blockLength = totalLength / AscendC::GetBlockNum(); | ||
| 24 | + this->tileNum = tileNum; | ||
| 25 | + // 请补充:Double Buffer 下每段搬运长度 tileLength | ||
| 26 | + this->tileLength = this->blockLength / tileNum / BUFFER_NUM; | ||
| 27 | + // 请补充:按核号偏移,设置每核的 GlobalBuffer 起始地址 | ||
| 28 | + xGm.SetGlobalBuffer((__gm__ float *)x + this->blockLength * AscendC::GetBlockIdx(), this->blockLength); | ||
| 29 | + yGm.SetGlobalBuffer((__gm__ float *)y + this->blockLength * AscendC::GetBlockIdx(), this->blockLength); | ||
| 30 | + zGm.SetGlobalBuffer((__gm__ float *)z + this->blockLength * AscendC::GetBlockIdx(), this->blockLength); | ||
| 31 | + // 请补充:为输入/输出队列分配 UB 内存(Double Buffer) | ||
| 32 | + pipe.InitBuffer(inQueueX, BUFFER_NUM, this->tileLength * sizeof(float)); | ||
| 33 | + pipe.InitBuffer(inQueueY, BUFFER_NUM, this->tileLength * sizeof(float)); | ||
| 34 | + pipe.InitBuffer(outQueueZ, BUFFER_NUM, this->tileLength * sizeof(float)); | ||
| 35 | + } | ||
| 36 | + __aicore__ inline void Process() | ||
| 37 | + { | ||
| 38 | + int32_t loopCount = this->tileNum * BUFFER_NUM; | ||
| 39 | + for (int32_t i = 0; i < loopCount; i++) { | ||
| 40 | + CopyIn(i); | ||
| 41 | + Compute(i); | ||
| 42 | + CopyOut(i); | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | +private: | ||
| 47 | + __aicore__ inline void CopyIn(int32_t progress) | ||
| 48 | + { | ||
| 49 | + // 请补充:申请局部张量,DataCopy 从 GM 搬入 UB,再 EnQue 入队 | ||
| 50 | + AscendC::LocalTensor<float> xLocal = inQueueX.AllocTensor<float>(); | ||
| 51 | + AscendC::LocalTensor<float> yLocal = inQueueY.AllocTensor<float>(); | ||
| 52 | + AscendC::DataCopy(xLocal, xGm[progress * this->tileLength], this->tileLength); | ||
| 53 | + AscendC::DataCopy(yLocal, yGm[progress * this->tileLength], this->tileLength); | ||
| 54 | + inQueueX.EnQue(xLocal); | ||
| 55 | + inQueueY.EnQue(yLocal); | ||
| 56 | + } | ||
| 57 | + __aicore__ inline void Compute(int32_t progress) | ||
| 58 | + { | ||
| 59 | + // 请补充:出队输入,调用 AscendC::Mul 完成 z = x * y,结果入队并释放输入 | ||
| 60 | + AscendC::LocalTensor<float> xLocal = inQueueX.DeQue<float>(); | ||
| 61 | + AscendC::LocalTensor<float> yLocal = inQueueY.DeQue<float>(); | ||
| 62 | + AscendC::LocalTensor<float> zLocal = outQueueZ.AllocTensor<float>(); | ||
| 63 | + AscendC::Mul(zLocal, xLocal, yLocal, this->tileLength); | ||
| 64 | + outQueueZ.EnQue<float>(zLocal); | ||
| 65 | + inQueueX.FreeTensor(xLocal); | ||
| 66 | + inQueueY.FreeTensor(yLocal); | ||
| 67 | + } | ||
| 68 | + __aicore__ inline void CopyOut(int32_t progress) | ||
| 69 | + { | ||
| 70 | + // 请补充:出队结果,DataCopy 从 UB 搬回 GM,释放输出张量 | ||
| 71 | + AscendC::LocalTensor<float> zLocal = outQueueZ.DeQue<float>(); | ||
| 72 | + AscendC::DataCopy(zGm[progress * this->tileLength], zLocal, this->tileLength); | ||
| 73 | + outQueueZ.FreeTensor(zLocal); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | +private: | ||
| 77 | + AscendC::TPipe pipe; | ||
| 78 | + AscendC::TQue<AscendC::TPosition::VECIN, BUFFER_NUM> inQueueX, inQueueY; | ||
| 79 | + AscendC::TQue<AscendC::TPosition::VECOUT, BUFFER_NUM> outQueueZ; | ||
| 80 | + AscendC::GlobalTensor<float> xGm; | ||
| 81 | + AscendC::GlobalTensor<float> yGm; | ||
| 82 | + AscendC::GlobalTensor<float> zGm; | ||
| 83 | + uint32_t blockLength; | ||
| 84 | + uint32_t tileNum; | ||
| 85 | + uint32_t tileLength; | ||
| 86 | +}; | ||
| 87 | + | ||
| 88 | +__global__ __vector__ void mul_custom(GM_ADDR x, GM_ADDR y, GM_ADDR z, MulCustomTilingData tiling) | ||
| 89 | +{ | ||
| 90 | + KernelMul op; | ||
| 91 | + op.Init(x, y, z, tiling.totalLength, tiling.tileNum); | ||
| 92 | + op.Process(); | ||
| 93 | +} | ||
| 94 | + | ||
| 95 | +std::vector<float> kernel_mul(std::vector<float> &x, std::vector<float> &y) | ||
| 96 | +{ | ||
| 97 | + constexpr uint32_t numBlocks = 8; | ||
| 98 | + uint32_t totalLength = x.size(); | ||
| 99 | + size_t totalByteSize = totalLength * sizeof(float); | ||
| 100 | + int32_t deviceId = 0; | ||
| 101 | + aclrtStream stream = nullptr; | ||
| 102 | + MulCustomTilingData tiling = {/*totalLength:*/totalLength, /*tileNum:*/8}; | ||
| 103 | + uint8_t *xHost = reinterpret_cast<uint8_t *>(x.data()); | ||
| 104 | + uint8_t *yHost = reinterpret_cast<uint8_t *>(y.data()); | ||
| 105 | + uint8_t *zHost = nullptr; | ||
| 106 | + uint8_t *xDevice = nullptr; | ||
| 107 | + uint8_t *yDevice = nullptr; | ||
| 108 | + uint8_t *zDevice = nullptr; | ||
| 109 | + | ||
| 110 | + aclInit(nullptr); | ||
| 111 | + aclrtSetDevice(deviceId); | ||
| 112 | + aclrtCreateStream(&stream); | ||
| 113 | + | ||
| 114 | + aclrtMallocHost((void **)(&zHost), totalByteSize); | ||
| 115 | + aclrtMalloc((void **)&xDevice, totalByteSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 116 | + aclrtMalloc((void **)&yDevice, totalByteSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 117 | + aclrtMalloc((void **)&zDevice, totalByteSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 118 | + | ||
| 119 | + aclrtMemcpy(xDevice, totalByteSize, xHost, totalByteSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 120 | + aclrtMemcpy(yDevice, totalByteSize, yHost, totalByteSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 121 | + | ||
| 122 | + mul_custom<<<numBlocks, nullptr, stream>>>(xDevice, yDevice, zDevice, tiling); | ||
| 123 | + aclrtSynchronizeStream(stream); | ||
| 124 | + | ||
| 125 | + aclrtMemcpy(zHost, totalByteSize, zDevice, totalByteSize, ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 126 | + std::vector<float> z((float *)zHost, (float *)(zHost + totalByteSize)); | ||
| 127 | + | ||
| 128 | + aclrtFree(xDevice); | ||
| 129 | + aclrtFree(yDevice); | ||
| 130 | + aclrtFree(zDevice); | ||
| 131 | + aclrtFreeHost(zHost); | ||
| 132 | + | ||
| 133 | + aclrtDestroyStream(stream); | ||
| 134 | + aclrtResetDevice(deviceId); | ||
| 135 | + aclFinalize(); | ||
| 136 | + | ||
| 137 | + return z; | ||
| 138 | +} | ||
| 139 | + | ||
| 140 | +uint32_t VerifyResult(std::vector<float> &output, std::vector<float> &golden) | ||
| 141 | +{ | ||
| 142 | + auto printTensor = [](std::vector<float> &tensor, const char *name) { | ||
| 143 | + constexpr size_t maxPrintSize = 20; | ||
| 144 | + std::cout << name << ": "; | ||
| 145 | + std::copy(tensor.begin(), tensor.begin() + std::min(tensor.size(), maxPrintSize), | ||
| 146 | + std::ostream_iterator<float>(std::cout, " ")); | ||
| 147 | + if (tensor.size() > maxPrintSize) { | ||
| 148 | + std::cout << "..."; | ||
| 149 | + } | ||
| 150 | + std::cout << std::endl; | ||
| 151 | + }; | ||
| 152 | + printTensor(output, "Output"); | ||
| 153 | + printTensor(golden, "Golden"); | ||
| 154 | + if (std::equal(golden.begin(), golden.end(), output.begin())) { | ||
| 155 | + std::cout << "[Success] Case accuracy is verification passed." << std::endl; | ||
| 156 | + return 0; | ||
| 157 | + } else { | ||
| 158 | + std::cout << "[Failed] Case accuracy is verification failed!" << std::endl; | ||
| 159 | + return 1; | ||
| 160 | + } | ||
| 161 | + return 0; | ||
| 162 | +} | ||
| 163 | + | ||
| 164 | +int32_t main(int32_t argc, char *argv[]) | ||
| 165 | +{ | ||
| 166 | + constexpr uint32_t totalLength = 8 * 2048; | ||
| 167 | + constexpr float valueX = 1.2f; | ||
| 168 | + constexpr float valueY = 2.3f; | ||
| 169 | + std::vector<float> x(totalLength, valueX); | ||
| 170 | + std::vector<float> y(totalLength, valueY); | ||
| 171 | + | ||
| 172 | + std::vector<float> output = kernel_mul(x, y); | ||
| 173 | + | ||
| 174 | + std::vector<float> golden(totalLength, valueX * valueY); | ||
| 175 | + return VerifyResult(output, golden); | ||
| 176 | +} | ||
| @@ -0,0 +1,18 @@ | |||
| 1 | +#!/bin/bash | ||
| 2 | +set -e | ||
| 3 | + | ||
| 4 | +# 激活 CANN 环境(CANNLab 中一般为 /home/developer/Ascend/cann-9.0.0 或 $ASCEND_TOOLKIT_HOME) | ||
| 5 | +if [ -z "$ASCEND_TOOLKIT_HOME" ]; then | ||
| 6 | + for d in /home/developer/Ascend/ascend-toolkit/latest /usr/local/Ascend/ascend-toolkit/latest; do | ||
| 7 | + if [ -d "$d" ]; then export ASCEND_TOOLKIT_HOME="$d"; break; fi | ||
| 8 | + done | ||
| 9 | +fi | ||
| 10 | +source "$ASCEND_TOOLKIT_HOME/set_env.sh" | ||
| 11 | + | ||
| 12 | +rm -rf build | ||
| 13 | +mkdir -p build && cd build | ||
| 14 | +cmake -DCMAKE_ASC_ARCHITECTURES=dav-2201 .. && make -j | ||
| 15 | +cd .. | ||
| 16 | + | ||
| 17 | +# 运行验证:输出 Output 与 Golden 均为 2.76 时打印 [Success] Case accuracy is verification passed. | ||
| 18 | +./build/mul_test | ||