已合并
【代码侦探Challenge05】完成 zhaojianing2025 的 MulCustom 逐元素乘法算子 #3500
【代码侦探Challenge05】完成 zhaojianing2025 的 MulCustom 逐元素乘法算子 #3500
已合并
zhaojianing2025创建于 9月7日
共 3 个文件变更+205-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(mul_test
6+ mul_custom.asc
7+)
8+target_compile_options(mul_test PRIVATE
9+ $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=dav-2201>
10+)
@@ -0,0 +1,186 @@
1+// mul_custom.asc
2+// Ascend C 逐元素乘法算子:z[i] = x[i] * y[i]
3+ 
4+#include <algorithm>
5+#include <cstdint>
6+#include <iostream>
7+#include <iterator>
8+#include <vector>
9+#include "acl/acl.h"
10+#include "kernel_operator.h"
11+ 
12+constexpr uint32_t BUFFER_NUM = 2;
13+ 
14+struct MulCustomTilingData
15+{
16+ uint32_t totalLength;
17+ uint32_t tileNum;
18+};
19+ 
20+class KernelMul {
21+public:
22+ __aicore__ inline KernelMul() {}
23+ 
24+ __aicore__ inline void Init(GM_ADDR x, GM_ADDR y, GM_ADDR z,
25+ uint32_t totalLength, uint32_t tileNum)
26+ {
27+ blockLength = totalLength / AscendC::GetBlockNum();
28+ this->tileNum = tileNum;
29+ tileLength = blockLength / tileNum / BUFFER_NUM;
30+ 
31+ const uint32_t blockOffset = blockLength * AscendC::GetBlockIdx();
32+ xGm.SetGlobalBuffer((__gm__ float *)x + blockOffset, blockLength);
33+ yGm.SetGlobalBuffer((__gm__ float *)y + blockOffset, blockLength);
34+ zGm.SetGlobalBuffer((__gm__ float *)z + blockOffset, blockLength);
35+ 
36+ pipe.InitBuffer(inQueueX, BUFFER_NUM, tileLength * sizeof(float));
37+ pipe.InitBuffer(inQueueY, BUFFER_NUM, tileLength * sizeof(float));
38+ pipe.InitBuffer(outQueueZ, BUFFER_NUM, tileLength * sizeof(float));
39+ }
40+ 
41+ __aicore__ inline void Process()
42+ {
43+ const int32_t loopCount = tileNum * BUFFER_NUM;
44+ for (int32_t i = 0; i < loopCount; ++i) {
45+ CopyIn(i);
46+ Compute();
47+ CopyOut(i);
48+ }
49+ }
50+ 
51+private:
52+ __aicore__ inline void CopyIn(int32_t progress)
53+ {
54+ AscendC::LocalTensor<float> xLocal = inQueueX.AllocTensor<float>();
55+ AscendC::LocalTensor<float> yLocal = inQueueY.AllocTensor<float>();
56+ const uint32_t offset = progress * tileLength;
57+ AscendC::DataCopy(xLocal, xGm[offset], tileLength);
58+ AscendC::DataCopy(yLocal, yGm[offset], tileLength);
59+ inQueueX.EnQue(xLocal);
60+ inQueueY.EnQue(yLocal);
61+ }
62+ 
63+ __aicore__ inline void Compute()
64+ {
65+ AscendC::LocalTensor<float> xLocal = inQueueX.DeQue<float>();
66+ AscendC::LocalTensor<float> yLocal = inQueueY.DeQue<float>();
67+ AscendC::LocalTensor<float> zLocal = outQueueZ.AllocTensor<float>();
68+ 
69+ AscendC::Mul(zLocal, xLocal, yLocal, tileLength);
70+ 
71+ outQueueZ.EnQue(zLocal);
72+ inQueueX.FreeTensor(xLocal);
73+ inQueueY.FreeTensor(yLocal);
74+ }
75+ 
76+ __aicore__ inline void CopyOut(int32_t progress)
77+ {
78+ AscendC::LocalTensor<float> zLocal = outQueueZ.DeQue<float>();
79+ AscendC::DataCopy(zGm[progress * tileLength], zLocal, tileLength);
80+ outQueueZ.FreeTensor(zLocal);
81+ }
82+ 
83+private:
84+ AscendC::TPipe pipe;
85+ AscendC::TQue<AscendC::TPosition::VECIN, BUFFER_NUM> inQueueX;
86+ AscendC::TQue<AscendC::TPosition::VECIN, BUFFER_NUM> inQueueY;
87+ AscendC::TQue<AscendC::TPosition::VECOUT, BUFFER_NUM> outQueueZ;
88+ AscendC::GlobalTensor<float> xGm;
89+ AscendC::GlobalTensor<float> yGm;
90+ AscendC::GlobalTensor<float> zGm;
91+ uint32_t blockLength;
92+ uint32_t tileNum;
93+ uint32_t tileLength;
94+};
95+ 
96+__global__ __aicore__ void mul_custom(GM_ADDR x, GM_ADDR y, GM_ADDR z,
97+ MulCustomTilingData tiling)
98+{
99+ KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY);
100+ KernelMul op;
101+ op.Init(x, y, z, tiling.totalLength, tiling.tileNum);
102+ op.Process();
103+}
104+ 
105+std::vector<float> kernel_mul(std::vector<float> &x, std::vector<float> &y)
106+{
107+ constexpr uint32_t blockDim = 8;
108+ constexpr uint32_t tileNum = 8;
109+ constexpr int32_t deviceId = 0;
110+ const uint32_t totalLength = x.size();
111+ const size_t totalByteSize = totalLength * sizeof(float);
112+ const MulCustomTilingData tiling = {totalLength, tileNum};
113+ 
114+ aclrtStream stream = nullptr;
115+ float *zHost = nullptr;
116+ uint8_t *xDevice = nullptr;
117+ uint8_t *yDevice = nullptr;
118+ uint8_t *zDevice = nullptr;
119+ 
120+ aclInit(nullptr);
121+ aclrtSetDevice(deviceId);
122+ aclrtCreateStream(&stream);
123+ 
124+ aclrtMallocHost(reinterpret_cast<void **>(&zHost), totalByteSize);
125+ aclrtMalloc(reinterpret_cast<void **>(&xDevice), totalByteSize, ACL_MEM_MALLOC_HUGE_FIRST);
126+ aclrtMalloc(reinterpret_cast<void **>(&yDevice), totalByteSize, ACL_MEM_MALLOC_HUGE_FIRST);
127+ aclrtMalloc(reinterpret_cast<void **>(&zDevice), totalByteSize, ACL_MEM_MALLOC_HUGE_FIRST);
128+ 
129+ aclrtMemcpy(xDevice, totalByteSize, x.data(), totalByteSize,
130+ ACL_MEMCPY_HOST_TO_DEVICE);
131+ aclrtMemcpy(yDevice, totalByteSize, y.data(), totalByteSize,
132+ ACL_MEMCPY_HOST_TO_DEVICE);
133+ 
134+ mul_custom<<<blockDim, nullptr, stream>>>((__gm__ uint8_t *)xDevice,
135+ (__gm__ uint8_t *)yDevice, (__gm__ uint8_t *)zDevice, tiling);
136+ aclrtSynchronizeStream(stream);
137+ aclrtMemcpy(zHost, totalByteSize, zDevice, totalByteSize,
138+ ACL_MEMCPY_DEVICE_TO_HOST);
139+ 
140+ std::vector<float> output(zHost, zHost + totalLength);
141+ 
142+ aclrtFree(xDevice);
143+ aclrtFree(yDevice);
144+ aclrtFree(zDevice);
145+ aclrtFreeHost(zHost);
146+ aclrtDestroyStream(stream);
147+ aclrtResetDevice(deviceId);
148+ aclFinalize();
149+ 
150+ return output;
151+}
152+ 
153+uint32_t VerifyResult(std::vector<float> &output, std::vector<float> &golden)
154+{
155+ auto printTensor = [](std::vector<float> &tensor, const char *name) {
156+ constexpr size_t maxPrintSize = 20;
157+ std::cout << name << ": ";
158+ std::copy(tensor.begin(), tensor.begin() + std::min(tensor.size(), maxPrintSize),
159+ std::ostream_iterator<float>(std::cout, " "));
160+ if (tensor.size() > maxPrintSize) {
161+ std::cout << "...";
162+ }
163+ std::cout << std::endl;
164+ };
165+ printTensor(output, "Output");
166+ printTensor(golden, "Golden");
167+ if (std::equal(golden.begin(), golden.end(), output.begin())) {
168+ std::cout << "[Success] Case accuracy is verification passed." << std::endl;
169+ return 0;
170+ }
171+ std::cout << "[Failed] Case accuracy is verification failed!" << std::endl;
172+ return 1;
173+}
174+ 
175+int32_t main(int32_t argc, char *argv[])
176+{
177+ constexpr uint32_t totalLength = 8 * 2048;
178+ constexpr float valueX = 1.2f;
179+ constexpr float valueY = 2.3f;
180+ std::vector<float> x(totalLength, valueX);
181+ std::vector<float> y(totalLength, valueY);
182+ 
183+ std::vector<float> output = kernel_mul(x, y);
184+ std::vector<float> golden(totalLength, valueX * valueY);
185+ return VerifyResult(output, golden);
186+}
@@ -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+./mul_test