已开启
【代码侦探Challenge05】实现 MulCustom 逐元素乘法算子 #3563
【代码侦探Challenge05】实现 MulCustom 逐元素乘法算子 #3563
已开启
FineL1创建于 9月9日
共 5 个文件变更+862-0
@@ -0,0 +1,417 @@
1+// mul_custom.asc
2+// 逐元素乘法算子:z[i] = x[i] * y[i]
3+ 
4+#include <cstdint>
5+#include <iostream>
6+#include <vector>
7+#include <algorithm>
8+#include <iterator>
9+#include "acl/acl.h"
10+#include "kernel_operator.h"
11+ 
12+constexpr uint32_t BUFFER_NUM = 2; // Double Buffer 队列深度
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(
25+ GM_ADDR x,
26+ GM_ADDR y,
27+ GM_ADDR z,
28+ uint32_t totalLength,
29+ uint32_t tileNum)
30+ {
31+ // 每个 Core 负责的数据量
32+ this->blockLength =
33+ totalLength / AscendC::GetBlockNum();
34+ 
35+ this->tileNum = tileNum;
36+ 
37+ // 双缓冲下,每个 Tile 实际处理的数据量
38+ this->tileLength =
39+ this->blockLength / tileNum / BUFFER_NUM;
40+ 
41+ // 当前 Core 在 GM 中的数据偏移
42+ uint32_t blockOffset =
43+ this->blockLength * AscendC::GetBlockIdx();
44+ 
45+ // 设置当前 Core 对应的 GM 地址
46+ xGm.SetGlobalBuffer(
47+ (__gm__ float *)x + blockOffset,
48+ this->blockLength);
49+ 
50+ yGm.SetGlobalBuffer(
51+ (__gm__ float *)y + blockOffset,
52+ this->blockLength);
53+ 
54+ zGm.SetGlobalBuffer(
55+ (__gm__ float *)z + blockOffset,
56+ this->blockLength);
57+ 
58+ // 为输入输出队列分配 UB
59+ pipe.InitBuffer(
60+ inQueueX,
61+ BUFFER_NUM,
62+ this->tileLength * sizeof(float));
63+ 
64+ pipe.InitBuffer(
65+ inQueueY,
66+ BUFFER_NUM,
67+ this->tileLength * sizeof(float));
68+ 
69+ pipe.InitBuffer(
70+ outQueueZ,
71+ BUFFER_NUM,
72+ this->tileLength * sizeof(float));
73+ }
74+ 
75+ __aicore__ inline void Process()
76+ {
77+ // tileNum=8,BUFFER_NUM=2
78+ // 所以每个 Core 一共循环 16 次
79+ int32_t loopCount =
80+ this->tileNum * BUFFER_NUM;
81+ 
82+ for (int32_t i = 0; i < loopCount; ++i) {
83+ CopyIn(i);
84+ Compute(i);
85+ CopyOut(i);
86+ }
87+ }
88+ 
89+private:
90+ __aicore__ inline void CopyIn(int32_t progress)
91+ {
92+ AscendC::LocalTensor<float> xLocal =
93+ inQueueX.AllocTensor<float>();
94+ 
95+ AscendC::LocalTensor<float> yLocal =
96+ inQueueY.AllocTensor<float>();
97+ 
98+ // GM -> UB
99+ AscendC::DataCopy(
100+ xLocal,
101+ xGm[progress * this->tileLength],
102+ this->tileLength);
103+ 
104+ AscendC::DataCopy(
105+ yLocal,
106+ yGm[progress * this->tileLength],
107+ this->tileLength);
108+ 
109+ inQueueX.EnQue(xLocal);
110+ inQueueY.EnQue(yLocal);
111+ }
112+ 
113+ __aicore__ inline void Compute(int32_t progress)
114+ {
115+ AscendC::LocalTensor<float> xLocal =
116+ inQueueX.DeQue<float>();
117+ 
118+ AscendC::LocalTensor<float> yLocal =
119+ inQueueY.DeQue<float>();
120+ 
121+ AscendC::LocalTensor<float> zLocal =
122+ outQueueZ.AllocTensor<float>();
123+ 
124+ // 核心计算:z[i] = x[i] * y[i]
125+ AscendC::Mul(
126+ zLocal,
127+ xLocal,
128+ yLocal,
129+ this->tileLength);
130+ 
131+ outQueueZ.EnQue(zLocal);
132+ 
133+ inQueueX.FreeTensor(xLocal);
134+ inQueueY.FreeTensor(yLocal);
135+ }
136+ 
137+ __aicore__ inline void CopyOut(int32_t progress)
138+ {
139+ AscendC::LocalTensor<float> zLocal =
140+ outQueueZ.DeQue<float>();
141+ 
142+ // UB -> GM
143+ AscendC::DataCopy(
144+ zGm[progress * this->tileLength],
145+ zLocal,
146+ this->tileLength);
147+ 
148+ outQueueZ.FreeTensor(zLocal);
149+ }
150+ 
151+private:
152+ AscendC::TPipe pipe;
153+ 
154+ AscendC::TQue<
155+ AscendC::TPosition::VECIN,
156+ BUFFER_NUM> inQueueX;
157+ 
158+ AscendC::TQue<
159+ AscendC::TPosition::VECIN,
160+ BUFFER_NUM> inQueueY;
161+ 
162+ AscendC::TQue<
163+ AscendC::TPosition::VECOUT,
164+ BUFFER_NUM> outQueueZ;
165+ 
166+ AscendC::GlobalTensor<float> xGm;
167+ AscendC::GlobalTensor<float> yGm;
168+ AscendC::GlobalTensor<float> zGm;
169+ 
170+ uint32_t blockLength;
171+ uint32_t tileNum;
172+ uint32_t tileLength;
173+};
174+ 
175+ 
176+// Kernel 入口函数
177+__global__ __aicore__ void mul_custom(
178+ GM_ADDR x,
179+ GM_ADDR y,
180+ GM_ADDR z,
181+ MulCustomTilingData tiling)
182+{
183+ // 本算子只使用 AI Vector Core
184+ KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY);
185+ 
186+ KernelMul op;
187+ 
188+ op.Init(
189+ x,
190+ y,
191+ z,
192+ tiling.totalLength,
193+ tiling.tileNum);
194+ 
195+ op.Process();
196+}
197+ 
198+ 
199+// ----- Host 侧:kernel 直调封装 -----
200+ 
201+std::vector<float> kernel_mul(
202+ std::vector<float> &x,
203+ std::vector<float> &y)
204+{
205+ constexpr uint32_t blockDim = 8;
206+ constexpr uint32_t tileNum = 8;
207+ constexpr int32_t deviceId = 0;
208+ 
209+ uint32_t totalLength =
210+ static_cast<uint32_t>(x.size());
211+ 
212+ size_t totalByteSize =
213+ static_cast<size_t>(totalLength) * sizeof(float);
214+ 
215+ MulCustomTilingData tiling {
216+ totalLength,
217+ tileNum
218+ };
219+ 
220+ aclrtStream stream = nullptr;
221+ 
222+ float *xHost = nullptr;
223+ float *yHost = nullptr;
224+ float *zHost = nullptr;
225+ 
226+ uint8_t *xDevice = nullptr;
227+ uint8_t *yDevice = nullptr;
228+ uint8_t *zDevice = nullptr;
229+ 
230+ // 1. ACL 初始化
231+ aclInit(nullptr);
232+ 
233+ // 2. 设置 Device
234+ aclrtSetDevice(deviceId);
235+ 
236+ // 3. 创建 Stream
237+ aclrtCreateStream(&stream);
238+ 
239+ // 4. Host 内存申请
240+ aclrtMallocHost(
241+ reinterpret_cast<void **>(&xHost),
242+ totalByteSize);
243+ 
244+ aclrtMallocHost(
245+ reinterpret_cast<void **>(&yHost),
246+ totalByteSize);
247+ 
248+ aclrtMallocHost(
249+ reinterpret_cast<void **>(&zHost),
250+ totalByteSize);
251+ 
252+ // 把 vector 数据写入 Host 内存
253+ std::copy(
254+ x.begin(),
255+ x.end(),
256+ xHost);
257+ 
258+ std::copy(
259+ y.begin(),
260+ y.end(),
261+ yHost);
262+ 
263+ // 5. Device 内存申请
264+ aclrtMalloc(
265+ reinterpret_cast<void **>(&xDevice),
266+ totalByteSize,
267+ ACL_MEM_MALLOC_HUGE_FIRST);
268+ 
269+ aclrtMalloc(
270+ reinterpret_cast<void **>(&yDevice),
271+ totalByteSize,
272+ ACL_MEM_MALLOC_HUGE_FIRST);
273+ 
274+ aclrtMalloc(
275+ reinterpret_cast<void **>(&zDevice),
276+ totalByteSize,
277+ ACL_MEM_MALLOC_HUGE_FIRST);
278+ 
279+ // 6. Host -> Device
280+ aclrtMemcpy(
281+ xDevice,
282+ totalByteSize,
283+ xHost,
284+ totalByteSize,
285+ ACL_MEMCPY_HOST_TO_DEVICE);
286+ 
287+ aclrtMemcpy(
288+ yDevice,
289+ totalByteSize,
290+ yHost,
291+ totalByteSize,
292+ ACL_MEMCPY_HOST_TO_DEVICE);
293+ 
294+ // 7. Kernel 直调
295+ mul_custom<<<blockDim, nullptr, stream>>>(
296+ xDevice,
297+ yDevice,
298+ zDevice,
299+ tiling);
300+ 
301+ // 8. 等待 Kernel 执行完成
302+ aclrtSynchronizeStream(stream);
303+ 
304+ // 9. Device -> Host
305+ aclrtMemcpy(
306+ zHost,
307+ totalByteSize,
308+ zDevice,
309+ totalByteSize,
310+ ACL_MEMCPY_DEVICE_TO_HOST);
311+ 
312+ // 10. 构造返回结果
313+ std::vector<float> output(
314+ zHost,
315+ zHost + totalLength);
316+ 
317+ // 11. 释放 Device 内存
318+ aclrtFree(xDevice);
319+ aclrtFree(yDevice);
320+ aclrtFree(zDevice);
321+ 
322+ // 12. 释放 Host 内存
323+ aclrtFreeHost(xHost);
324+ aclrtFreeHost(yHost);
325+ aclrtFreeHost(zHost);
326+ 
327+ // 13. 清理运行时资源
328+ aclrtDestroyStream(stream);
329+ aclrtResetDevice(deviceId);
330+ aclFinalize();
331+ 
332+ return output;
333+}
334+ 
335+ 
336+// ----- 验证与主函数 -----
337+ 
338+uint32_t VerifyResult(
339+ std::vector<float> &output,
340+ std::vector<float> &golden)
341+{
342+ auto printTensor = [](
343+ std::vector<float> &tensor,
344+ const char *name)
345+ {
346+ constexpr size_t maxPrintSize = 20;
347+ 
348+ std::cout << name << ": ";
349+ 
350+ std::copy(
351+ tensor.begin(),
352+ tensor.begin() +
353+ std::min(tensor.size(), maxPrintSize),
354+ std::ostream_iterator<float>(
355+ std::cout,
356+ " "));
357+ 
358+ if (tensor.size() > maxPrintSize) {
359+ std::cout << "...";
360+ }
361+ 
362+ std::cout << std::endl;
363+ };
364+ 
365+ printTensor(output, "Output");
366+ printTensor(golden, "Golden");
367+ 
368+ if (std::equal(
369+ golden.begin(),
370+ golden.end(),
371+ output.begin()))
372+ {
373+ std::cout
374+ << "[Success] Case accuracy is verification passed."
375+ << std::endl;
376+ 
377+ return 0;
378+ }
379+ else
380+ {
381+ std::cout
382+ << "[Failed] Case accuracy is verification failed!"
383+ << std::endl;
384+ 
385+ return 1;
386+ }
387+}
388+ 
389+ 
390+int32_t main(int32_t argc, char *argv[])
391+{
392+ constexpr uint32_t totalLength =
393+ 8 * 2048;
394+ 
395+ constexpr float valueX = 1.2f;
396+ constexpr float valueY = 2.3f;
397+ 
398+ std::vector<float> x(
399+ totalLength,
400+ valueX);
401+ 
402+ std::vector<float> y(
403+ totalLength,
404+ valueY);
405+ 
406+ // 调用 Ascend C Kernel
407+ std::vector<float> output =
408+ kernel_mul(x, y);
409+ 
410+ std::vector<float> golden(
411+ totalLength,
412+ valueX * valueY);
413+ 
414+ return VerifyResult(
415+ output,
416+ golden);
417+}
@@ -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
@@ -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,417 @@
1+// mul_custom.asc
2+// 逐元素乘法算子:z[i] = x[i] * y[i]
3+ 
4+#include <cstdint>
5+#include <iostream>
6+#include <vector>
7+#include <algorithm>
8+#include <iterator>
9+#include "acl/acl.h"
10+#include "kernel_operator.h"
11+ 
12+constexpr uint32_t BUFFER_NUM = 2; // Double Buffer 队列深度
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(
25+ GM_ADDR x,
26+ GM_ADDR y,
27+ GM_ADDR z,
28+ uint32_t totalLength,
29+ uint32_t tileNum)
30+ {
31+ // 每个 Core 负责的数据量
32+ this->blockLength =
33+ totalLength / AscendC::GetBlockNum();
34+ 
35+ this->tileNum = tileNum;
36+ 
37+ // 双缓冲下,每个 Tile 实际处理的数据量
38+ this->tileLength =
39+ this->blockLength / tileNum / BUFFER_NUM;
40+ 
41+ // 当前 Core 在 GM 中的数据偏移
42+ uint32_t blockOffset =
43+ this->blockLength * AscendC::GetBlockIdx();
44+ 
45+ // 设置当前 Core 对应的 GM 地址
46+ xGm.SetGlobalBuffer(
47+ (__gm__ float *)x + blockOffset,
48+ this->blockLength);
49+ 
50+ yGm.SetGlobalBuffer(
51+ (__gm__ float *)y + blockOffset,
52+ this->blockLength);
53+ 
54+ zGm.SetGlobalBuffer(
55+ (__gm__ float *)z + blockOffset,
56+ this->blockLength);
57+ 
58+ // 为输入输出队列分配 UB
59+ pipe.InitBuffer(
60+ inQueueX,
61+ BUFFER_NUM,
62+ this->tileLength * sizeof(float));
63+ 
64+ pipe.InitBuffer(
65+ inQueueY,
66+ BUFFER_NUM,
67+ this->tileLength * sizeof(float));
68+ 
69+ pipe.InitBuffer(
70+ outQueueZ,
71+ BUFFER_NUM,
72+ this->tileLength * sizeof(float));
73+ }
74+ 
75+ __aicore__ inline void Process()
76+ {
77+ // tileNum=8,BUFFER_NUM=2
78+ // 所以每个 Core 一共循环 16 次
79+ int32_t loopCount =
80+ this->tileNum * BUFFER_NUM;
81+ 
82+ for (int32_t i = 0; i < loopCount; ++i) {
83+ CopyIn(i);
84+ Compute(i);
85+ CopyOut(i);
86+ }
87+ }
88+ 
89+private:
90+ __aicore__ inline void CopyIn(int32_t progress)
91+ {
92+ AscendC::LocalTensor<float> xLocal =
93+ inQueueX.AllocTensor<float>();
94+ 
95+ AscendC::LocalTensor<float> yLocal =
96+ inQueueY.AllocTensor<float>();
97+ 
98+ // GM -> UB
99+ AscendC::DataCopy(
100+ xLocal,
101+ xGm[progress * this->tileLength],
102+ this->tileLength);
103+ 
104+ AscendC::DataCopy(
105+ yLocal,
106+ yGm[progress * this->tileLength],
107+ this->tileLength);
108+ 
109+ inQueueX.EnQue(xLocal);
110+ inQueueY.EnQue(yLocal);
111+ }
112+ 
113+ __aicore__ inline void Compute(int32_t progress)
114+ {
115+ AscendC::LocalTensor<float> xLocal =
116+ inQueueX.DeQue<float>();
117+ 
118+ AscendC::LocalTensor<float> yLocal =
119+ inQueueY.DeQue<float>();
120+ 
121+ AscendC::LocalTensor<float> zLocal =
122+ outQueueZ.AllocTensor<float>();
123+ 
124+ // 核心计算:z[i] = x[i] * y[i]
125+ AscendC::Mul(
126+ zLocal,
127+ xLocal,
128+ yLocal,
129+ this->tileLength);
130+ 
131+ outQueueZ.EnQue(zLocal);
132+ 
133+ inQueueX.FreeTensor(xLocal);
134+ inQueueY.FreeTensor(yLocal);
135+ }
136+ 
137+ __aicore__ inline void CopyOut(int32_t progress)
138+ {
139+ AscendC::LocalTensor<float> zLocal =
140+ outQueueZ.DeQue<float>();
141+ 
142+ // UB -> GM
143+ AscendC::DataCopy(
144+ zGm[progress * this->tileLength],
145+ zLocal,
146+ this->tileLength);
147+ 
148+ outQueueZ.FreeTensor(zLocal);
149+ }
150+ 
151+private:
152+ AscendC::TPipe pipe;
153+ 
154+ AscendC::TQue<
155+ AscendC::TPosition::VECIN,
156+ BUFFER_NUM> inQueueX;
157+ 
158+ AscendC::TQue<
159+ AscendC::TPosition::VECIN,
160+ BUFFER_NUM> inQueueY;
161+ 
162+ AscendC::TQue<
163+ AscendC::TPosition::VECOUT,
164+ BUFFER_NUM> outQueueZ;
165+ 
166+ AscendC::GlobalTensor<float> xGm;
167+ AscendC::GlobalTensor<float> yGm;
168+ AscendC::GlobalTensor<float> zGm;
169+ 
170+ uint32_t blockLength;
171+ uint32_t tileNum;
172+ uint32_t tileLength;
173+};
174+ 
175+ 
176+// Kernel 入口函数
177+__global__ __aicore__ void mul_custom(
178+ GM_ADDR x,
179+ GM_ADDR y,
180+ GM_ADDR z,
181+ MulCustomTilingData tiling)
182+{
183+ // 本算子只使用 AI Vector Core
184+ KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_AIV_ONLY);
185+ 
186+ KernelMul op;
187+ 
188+ op.Init(
189+ x,
190+ y,
191+ z,
192+ tiling.totalLength,
193+ tiling.tileNum);
194+ 
195+ op.Process();
196+}
197+ 
198+ 
199+// ----- Host 侧:kernel 直调封装 -----
200+ 
201+std::vector<float> kernel_mul(
202+ std::vector<float> &x,
203+ std::vector<float> &y)
204+{
205+ constexpr uint32_t blockDim = 8;
206+ constexpr uint32_t tileNum = 8;
207+ constexpr int32_t deviceId = 0;
208+ 
209+ uint32_t totalLength =
210+ static_cast<uint32_t>(x.size());
211+ 
212+ size_t totalByteSize =
213+ static_cast<size_t>(totalLength) * sizeof(float);
214+ 
215+ MulCustomTilingData tiling {
216+ totalLength,
217+ tileNum
218+ };
219+ 
220+ aclrtStream stream = nullptr;
221+ 
222+ float *xHost = nullptr;
223+ float *yHost = nullptr;
224+ float *zHost = nullptr;
225+ 
226+ uint8_t *xDevice = nullptr;
227+ uint8_t *yDevice = nullptr;
228+ uint8_t *zDevice = nullptr;
229+ 
230+ // 1. ACL 初始化
231+ aclInit(nullptr);
232+ 
233+ // 2. 设置 Device
234+ aclrtSetDevice(deviceId);
235+ 
236+ // 3. 创建 Stream
237+ aclrtCreateStream(&stream);
238+ 
239+ // 4. Host 内存申请
240+ aclrtMallocHost(
241+ reinterpret_cast<void **>(&xHost),
242+ totalByteSize);
243+ 
244+ aclrtMallocHost(
245+ reinterpret_cast<void **>(&yHost),
246+ totalByteSize);
247+ 
248+ aclrtMallocHost(
249+ reinterpret_cast<void **>(&zHost),
250+ totalByteSize);
251+ 
252+ // 把 vector 数据写入 Host 内存
253+ std::copy(
254+ x.begin(),
255+ x.end(),
256+ xHost);
257+ 
258+ std::copy(
259+ y.begin(),
260+ y.end(),
261+ yHost);
262+ 
263+ // 5. Device 内存申请
264+ aclrtMalloc(
265+ reinterpret_cast<void **>(&xDevice),
266+ totalByteSize,
267+ ACL_MEM_MALLOC_HUGE_FIRST);
268+ 
269+ aclrtMalloc(
270+ reinterpret_cast<void **>(&yDevice),
271+ totalByteSize,
272+ ACL_MEM_MALLOC_HUGE_FIRST);
273+ 
274+ aclrtMalloc(
275+ reinterpret_cast<void **>(&zDevice),
276+ totalByteSize,
277+ ACL_MEM_MALLOC_HUGE_FIRST);
278+ 
279+ // 6. Host -> Device
280+ aclrtMemcpy(
281+ xDevice,
282+ totalByteSize,
283+ xHost,
284+ totalByteSize,
285+ ACL_MEMCPY_HOST_TO_DEVICE);
286+ 
287+ aclrtMemcpy(
288+ yDevice,
289+ totalByteSize,
290+ yHost,
291+ totalByteSize,
292+ ACL_MEMCPY_HOST_TO_DEVICE);
293+ 
294+ // 7. Kernel 直调
295+ mul_custom<<<blockDim, nullptr, stream>>>(
296+ xDevice,
297+ yDevice,
298+ zDevice,
299+ tiling);
300+ 
301+ // 8. 等待 Kernel 执行完成
302+ aclrtSynchronizeStream(stream);
303+ 
304+ // 9. Device -> Host
305+ aclrtMemcpy(
306+ zHost,
307+ totalByteSize,
308+ zDevice,
309+ totalByteSize,
310+ ACL_MEMCPY_DEVICE_TO_HOST);
311+ 
312+ // 10. 构造返回结果
313+ std::vector<float> output(
314+ zHost,
315+ zHost + totalLength);
316+ 
317+ // 11. 释放 Device 内存
318+ aclrtFree(xDevice);
319+ aclrtFree(yDevice);
320+ aclrtFree(zDevice);
321+ 
322+ // 12. 释放 Host 内存
323+ aclrtFreeHost(xHost);
324+ aclrtFreeHost(yHost);
325+ aclrtFreeHost(zHost);
326+ 
327+ // 13. 清理运行时资源
328+ aclrtDestroyStream(stream);
329+ aclrtResetDevice(deviceId);
330+ aclFinalize();
331+ 
332+ return output;
333+}
334+ 
335+ 
336+// ----- 验证与主函数 -----
337+ 
338+uint32_t VerifyResult(
339+ std::vector<float> &output,
340+ std::vector<float> &golden)
341+{
342+ auto printTensor = [](
343+ std::vector<float> &tensor,
344+ const char *name)
345+ {
346+ constexpr size_t maxPrintSize = 20;
347+ 
348+ std::cout << name << ": ";
349+ 
350+ std::copy(
351+ tensor.begin(),
352+ tensor.begin() +
353+ std::min(tensor.size(), maxPrintSize),
354+ std::ostream_iterator<float>(
355+ std::cout,
356+ " "));
357+ 
358+ if (tensor.size() > maxPrintSize) {
359+ std::cout << "...";
360+ }
361+ 
362+ std::cout << std::endl;
363+ };
364+ 
365+ printTensor(output, "Output");
366+ printTensor(golden, "Golden");
367+ 
368+ if (std::equal(
369+ golden.begin(),
370+ golden.end(),
371+ output.begin()))
372+ {
373+ std::cout
374+ << "[Success] Case accuracy is verification passed."
375+ << std::endl;
376+ 
377+ return 0;
378+ }
379+ else
380+ {
381+ std::cout
382+ << "[Failed] Case accuracy is verification failed!"
383+ << std::endl;
384+ 
385+ return 1;
386+ }
387+}
388+ 
389+ 
390+int32_t main(int32_t argc, char *argv[])
391+{
392+ constexpr uint32_t totalLength =
393+ 8 * 2048;
394+ 
395+ constexpr float valueX = 1.2f;
396+ constexpr float valueY = 2.3f;
397+ 
398+ std::vector<float> x(
399+ totalLength,
400+ valueX);
401+ 
402+ std::vector<float> y(
403+ totalLength,
404+ valueY);
405+ 
406+ // 调用 Ascend C Kernel
407+ std::vector<float> output =
408+ kernel_mul(x, y);
409+ 
410+ std::vector<float> golden(
411+ totalLength,
412+ valueX * valueY);
413+ 
414+ return VerifyResult(
415+ output,
416+ golden);
417+}
@@ -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