已合并
修复qbmmV4perblock kernal流水同步错误和tilingkey拷贝错误 #3430
修复qbmmV4perblock kernal流水同步错误和tilingkey拷贝错误 #3430
已合并
HKFLYE创建于 4月1日
4 个文件变更+270-6
Amatmul/quant_batch_matmul_v4/examples/test_aclnn_quant_matmul_v5_perblock.cpp+264-0
@@ -0,0 +1,264 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+* \file test_aclnn_quant_matmul_v5_perblock.cpp
13+* \brief Test case for perblock quantization matmul
14+*/
15+ 
16+#include <iostream>
17+#include <memory>
18+#include <vector>
19+ 
20+#include "acl/acl.h"
21+#include "aclnnop/aclnn_quant_matmul_v5.h"
22+ 
23+#define CHECK_RET(cond, return_expr) \
24+ do { \
25+ if (!(cond)) { \
26+ return_expr; \
27+ } \
28+ } while (0)
29+ 
30+#define CHECK_FREE_RET(cond, return_expr) \
31+ do { \
32+ if (!(cond)) { \
33+ Finalize(deviceId, stream); \
34+ return_expr; \
35+ } \
36+ } while (0)
37+ 
38+#define LOG_PRINT(message, ...) \
39+ do { \
40+ printf(message, ##__VA_ARGS__); \
41+ } while (0)
42+ 
43+int64_t GetShapeSize(const std::vector<int64_t>& shape)
44+{
45+ int64_t shapeSize = 1;
46+ for (auto i : shape) {
47+ shapeSize *= i;
48+ }
49+ return shapeSize;
50+}
51+ 
52+int Init(int32_t deviceId, aclrtStream* stream)
53+{
54+ // 固定写法,资源初始化
55+ auto ret = aclInit(nullptr);
56+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
57+ ret = aclrtSetDevice(deviceId);
58+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
59+ ret = aclrtCreateStream(stream);
60+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
61+ return 0;
62+}
63+ 
64+template <typename T>
65+int CreateAclTensor(
66+ const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType,
67+ aclTensor** tensor)
68+{
69+ auto size = GetShapeSize(shape) * sizeof(T);
70+ // 调用aclrtMalloc申请device侧内存
71+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
72+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
73+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
74+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
75+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
76+ 
77+ // 计算连续tensor的strides
78+ std::vector<int64_t> strides(shape.size(), 1);
79+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
80+ strides[i] = shape[i + 1] * strides[i + 1];
81+ }
82+ 
83+ // 调用aclCreateTensor接口创建aclTensor
84+ *tensor = aclCreateTensor(
85+ shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(),
86+ *deviceAddr);
87+ return 0;
88+}
89+ 
90+void Finalize(int32_t deviceId, aclrtStream stream)
91+{
92+ aclrtDestroyStream(stream);
93+ aclrtResetDevice(deviceId);
94+ aclFinalize();
95+}
96+ 
97+/**
98+ * Test case for perblock quantization matmul
99+ *
100+ * Test configuration (satisfying all perblock tiling constraints):
101+ * - M = 128, K = 4096, N = 512
102+ * - groupSizeK = 128, groupSizeN = 128
103+ * - transposeX1 = false, transposeX2 = true
104+ * - x1: [M, K] = [128, 4096], dtype = INT8
105+ * - x2: [N, K] = [512, 4096] (transposed), dtype = INT8
106+ * - x1Scale: [M, CeilDiv(K, 128)] = [128, 32], dtype = FLOAT
107+ * - x2Scale: [CeilDiv(N, 128), CeilDiv(K, 128)] = [4, 32], dtype = FLOAT
108+ * - bias: [N] = [512], dtype = FLOAT
109+ * - output: [M, N] = [128, 512], dtype = BF16
110+ * - N % 256 == 0 (satisfied: 512 % 256 == 0)
111+ */
112+int AclnnQuantMatmulV5PerblockTest(int32_t deviceId, aclrtStream& stream)
113+{
114+ auto ret = Init(deviceId, &stream);
115+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
116+ 
117+ // Perblock tiling constraints:
118+ // - groupSizeK = 128, groupSizeN = 128
119+ // - transposeX1 = false, transposeX2 = true
120+ // - N % 256 == 0
121+ constexpr int64_t M = 128;
122+ constexpr int64_t K = 4096;
123+ constexpr int64_t N = 512; // N must be multiple of 256 (baseN)
124+ constexpr int64_t groupSizeM = 1;
125+ constexpr int64_t groupSizeK = 128;
126+ constexpr int64_t groupSizeN = 128;
127+ 
128+ // x1: [M, K], dtype = INT8
129+ std::vector<int64_t> x1Shape = {M, K};
130+ // x2: [N, K] (transposed, so shape is [N, K]), dtype = INT8
131+ std::vector<int64_t> x2Shape = {N, K};
132+ // x1Scale: [M, CeilDiv(K, groupSizeK)], dtype = FLOAT
133+ std::vector<int64_t> x1ScaleShape = {M, (K + groupSizeK - 1) / groupSizeK}; // [128, 32]
134+ // x2Scale: [CeilDiv(N, groupSizeN), CeilDiv(K, groupSizeK)] (transposed), dtype = FLOAT
135+ std::vector<int64_t> x2ScaleShape = {(N + groupSizeN - 1) / groupSizeN, (K + groupSizeK - 1) / groupSizeK}; // [4, 32]
136+ // bias: [N], dtype = FLOAT
137+ std::vector<int64_t> biasShape = {N};
138+ // output: [M, N], dtype = BF16
139+ std::vector<int64_t> outShape = {M, N};
140+ 
141+ void* x1DeviceAddr = nullptr;
142+ void* x2DeviceAddr = nullptr;
143+ void* x2ScaleDeviceAddr = nullptr;
144+ void* x1ScaleDeviceAddr = nullptr;
145+ void* biasDeviceAddr = nullptr;
146+ void* outDeviceAddr = nullptr;
147+ aclTensor* x1 = nullptr;
148+ aclTensor* x2 = nullptr;
149+ aclTensor* bias = nullptr;
150+ aclTensor* x2Scale = nullptr;
151+ aclTensor* x1Scale = nullptr;
152+ aclTensor* out = nullptr;
153+ 
154+ // Initialize input data
155+ std::vector<int8_t> x1HostData(GetShapeSize(x1Shape), 1);
156+ std::vector<int8_t> x2HostData(GetShapeSize(x2Shape), 1);
157+ std::vector<float> x1ScaleHostData(GetShapeSize(x1ScaleShape), 1.0f);
158+ std::vector<float> x2ScaleHostData(GetShapeSize(x2ScaleShape), 1.0f);
159+ std::vector<float> biasHostData(GetShapeSize(biasShape), 0.0f);
160+ std::vector<uint16_t> outHostData(GetShapeSize(outShape), 0);
161+ 
162+ // 创建x1 aclTensor (INT8)
163+ ret = CreateAclTensor(x1HostData, x1Shape, &x1DeviceAddr, aclDataType::ACL_INT8, &x1);
164+ std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> x1TensorPtr(x1, aclDestroyTensor);
165+ std::unique_ptr<void, aclError (*)(void*)> x1DeviceAddrPtr(x1DeviceAddr, aclrtFree);
166+ CHECK_RET(ret == ACL_SUCCESS, return ret);
167+ 
168+ // 创建x2 aclTensor (INT8)
169+ ret = CreateAclTensor(x2HostData, x2Shape, &x2DeviceAddr, aclDataType::ACL_INT8, &x2);
170+ std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> x2TensorPtr(x2, aclDestroyTensor);
171+ std::unique_ptr<void, aclError (*)(void*)> x2DeviceAddrPtr(x2DeviceAddr, aclrtFree);
172+ CHECK_RET(ret == ACL_SUCCESS, return ret);
173+ 
174+ // 创建x1Scale aclTensor (FLOAT)
175+ ret = CreateAclTensor(x1ScaleHostData, x1ScaleShape, &x1ScaleDeviceAddr, aclDataType::ACL_FLOAT, &x1Scale);
176+ std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> x1ScaleTensorPtr(x1Scale, aclDestroyTensor);
177+ std::unique_ptr<void, aclError (*)(void*)> x1ScaleDeviceAddrPtr(x1ScaleDeviceAddr, aclrtFree);
178+ CHECK_RET(ret == ACL_SUCCESS, return ret);
179+ 
180+ // 创建x2Scale aclTensor (FLOAT)
181+ ret = CreateAclTensor(x2ScaleHostData, x2ScaleShape, &x2ScaleDeviceAddr, aclDataType::ACL_FLOAT, &x2Scale);
182+ std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> x2ScaleTensorPtr(x2Scale, aclDestroyTensor);
183+ std::unique_ptr<void, aclError (*)(void*)> x2ScaleDeviceAddrPtr(x2ScaleDeviceAddr, aclrtFree);
184+ CHECK_RET(ret == ACL_SUCCESS, return ret);
185+ 
186+ // 创建bias aclTensor (FLOAT)
187+ ret = CreateAclTensor(biasHostData, biasShape, &biasDeviceAddr, aclDataType::ACL_FLOAT, &bias);
188+ std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> biasTensorPtr(bias, aclDestroyTensor);
189+ std::unique_ptr<void, aclError (*)(void*)> biasDeviceAddrPtr(biasDeviceAddr, aclrtFree);
190+ CHECK_RET(ret == ACL_SUCCESS, return ret);
191+ 
192+ // 创建out aclTensor (BF16)
193+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_BF16, &out);
194+ std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> outTensorPtr(out, aclDestroyTensor);
195+ std::unique_ptr<void, aclError (*)(void*)> outDeviceAddrPtr(outDeviceAddr, aclrtFree);
196+ CHECK_RET(ret == ACL_SUCCESS, return ret);
197+ 
198+ // Perblock requires: transposeX1 = false, transposeX2 = true
199+ bool transposeX1 = false;
200+ bool transposeX2 = true;
201+ // groupSize encoding: groupSizeM in high bits, groupSizeN in middle, groupSizeK in low
202+ int64_t groupSize = (groupSizeM << 32) | (groupSizeN << 16) | groupSizeK;
203+ 
204+ // 3. 调用CANN算子库API
205+ uint64_t workspaceSize = 0;
206+ aclOpExecutor* executor = nullptr;
207+ 
208+ LOG_PRINT("Testing perblock quantization matmul:\n");
209+ LOG_PRINT(" M=%ld, K=%ld, N=%ld\n", M, K, N);
210+ LOG_PRINT(" x1Shape=[%ld, %ld], x2Shape=[%ld, %ld]\n", x1Shape[0], x1Shape[1], x2Shape[0], x2Shape[1]);
211+ LOG_PRINT(" x1ScaleShape=[%ld, %ld], x2ScaleShape=[%ld, %ld]\n", x1ScaleShape[0], x1ScaleShape[1], x2ScaleShape[0], x2ScaleShape[1]);
212+ LOG_PRINT(" biasShape=[%ld], outShape=[%ld, %ld]\n", biasShape[0], outShape[0], outShape[1]);
213+ LOG_PRINT(" transposeX1=%d, transposeX2=%d, groupSize=0x%lx\n", transposeX1, transposeX2, groupSize);
214+ 
215+ ret = aclnnQuantMatmulV5GetWorkspaceSize(
216+ x1, x2, x1Scale, x2Scale, nullptr, nullptr, nullptr, nullptr, bias, transposeX1, transposeX2, groupSize, out,
217+ &workspaceSize, &executor);
218+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnQuantMatmulV5GetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
219+ 
220+ // 根据第一段接口计算出的workspaceSize申请device内存
221+ void* workspaceAddr = nullptr;
222+ std::unique_ptr<void, aclError (*)(void*)> workspaceAddrPtr(nullptr, aclrtFree);
223+ if (workspaceSize > 0) {
224+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
225+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
226+ workspaceAddrPtr.reset(workspaceAddr);
227+ }
228+ 
229+ // 调用aclnnQuantMatmulV5第二段接口
230+ ret = aclnnQuantMatmulV5(workspaceAddr, workspaceSize, executor, stream);
231+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnQuantMatmulV5 failed. ERROR: %d\n", ret); return ret);
232+ 
233+ // 4. 同步等待任务执行结束
234+ ret = aclrtSynchronizeStream(stream);
235+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
236+ 
237+ LOG_PRINT("Perblock test completed successfully! The sync event ID fix is working.\n");
238+ 
239+ // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧
240+ auto size = GetShapeSize(outShape);
241+ std::vector<uint16_t> resultData(size, 0);
242+ ret = aclrtMemcpy(
243+ resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(resultData[0]),
244+ ACL_MEMCPY_DEVICE_TO_HOST);
245+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
246+ 
247+ // Print first few results for verification
248+ int64_t printCount = (size < 10) ? size : 10;
249+ for (int64_t i = 0; i < printCount; i++) {
250+ LOG_PRINT("result[%ld] is: %u\n", i, resultData[i]);
251+ }
252+ return ACL_SUCCESS;
253+}
254+ 
255+int main()
256+{
257+ // 1. device/stream初始化
258+ int32_t deviceId = 0;
259+ aclrtStream stream;
260+ auto ret = AclnnQuantMatmulV5PerblockTest(deviceId, stream);
261+ CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("AclnnQuantMatmulV5PerblockTest failed. ERROR: %d\n", ret); return ret);
262+ Finalize(deviceId, stream);
263+ return 0;
264+}
Mmatmul/quant_batch_matmul_v4/op_host/op_tiling/quant_batch_matmul_v4_perblock_tiling.cpp+1-1
@@ -407,7 +407,7 @@ ge::graphStatus QuantBatchMatmulV4PerblockTiling::DoLibApiTiling()
407 size_t tilingDataSize = sizeof(QuantBatchMatmulV4PerblockTilingData);407 size_t tilingDataSize = sizeof(QuantBatchMatmulV4PerblockTilingData);
408 context_->SetBlockDim(compileInfo_.aicNum);408 context_->SetBlockDim(compileInfo_.aicNum);
409 context_->SetScheduleMode(1); // 独占全核,设置以后会让所有核空闲以后才启动,有多核同步指令需要做此设置避免影响整网其他算子409 context_->SetScheduleMode(1); // 独占全核,设置以后会让所有核空闲以后才启动,有多核同步指令需要做此设置避免影响整网其他算子
410- errno_t ret = memcpy_s(context_->GetRawTilingData()->GetData(), context_->GetRawTilingData()->GetCapacity(), reinterpret_cast<void *>(&tilingData_), tilingDataSize);410+ errno_t ret = memcpy_s(context_->GetRawTilingData()->GetData(), context_->GetRawTilingData()->GetCapacity(), reinterpret_cast<void *>(tilingData_), tilingDataSize);
411 if (ret != EOK){411 if (ret != EOK){
412 OP_LOGE(context_->GetNodeName(), "memcpy_s failed, ret=%d", ret);412 OP_LOGE(context_->GetNodeName(), "memcpy_s failed, ret=%d", ret);
413 return ge::GRAPH_FAILED;413 return ge::GRAPH_FAILED;
Mmatmul/quant_batch_matmul_v4/op_kernel/quant_batch_matmul_v4_common.h+4-4
@@ -88,10 +88,10 @@ protected:
88 GetTPipePtr()->ReleaseEventID<HardEvent::MTE1_MTE2>(eAL1Pong12_);88 GetTPipePtr()->ReleaseEventID<HardEvent::MTE1_MTE2>(eAL1Pong12_);
89 GetTPipePtr()->ReleaseEventID<HardEvent::MTE1_MTE2>(eBL1Ping12_);89 GetTPipePtr()->ReleaseEventID<HardEvent::MTE1_MTE2>(eBL1Ping12_);
90 GetTPipePtr()->ReleaseEventID<HardEvent::MTE1_MTE2>(eBL1Pong12_);90 GetTPipePtr()->ReleaseEventID<HardEvent::MTE1_MTE2>(eBL1Pong12_);
91- GetTPipePtr()->ReleaseEventID<HardEvent::MTE1_MTE2>(eAL1Ping21_);91+ GetTPipePtr()->ReleaseEventID<HardEvent::MTE2_MTE1>(eAL1Ping21_);
92- GetTPipePtr()->ReleaseEventID<HardEvent::MTE1_MTE2>(eAL1Pong21_);92+ GetTPipePtr()->ReleaseEventID<HardEvent::MTE2_MTE1>(eAL1Pong21_);
93- GetTPipePtr()->ReleaseEventID<HardEvent::MTE1_MTE2>(eBL1Ping21_);93+ GetTPipePtr()->ReleaseEventID<HardEvent::MTE2_MTE1>(eBL1Ping21_);
94- GetTPipePtr()->ReleaseEventID<HardEvent::MTE1_MTE2>(eBL1Ping21_);94+ GetTPipePtr()->ReleaseEventID<HardEvent::MTE2_MTE1>(eBL1Pong21_);
95 }95 }
96 96 
97 __aicore__ inline void initEventID()97 __aicore__ inline void initEventID()
Mmatmul/quant_batch_matmul_v4/op_kernel/quant_batch_matmul_v4_perblock.h+1-1
@@ -278,7 +278,7 @@ private:
278 aL1PingFlag = !aL1PingFlag;278 aL1PingFlag = !aL1PingFlag;
279 }279 }
280 if ((kidx + 1) % stepkb_ == 0) {280 if ((kidx + 1) % stepkb_ == 0) {
281- SetFlag<HardEvent::MTE1_MTE2>(bL1PingFlag ? eBL1Ping21_ : eBL1Pong21_);281+ SetFlag<HardEvent::MTE1_MTE2>(bL1PingFlag ? eBL1Ping12_ : eBL1Pong12_);
282 bL1PingFlag = !bL1PingFlag;282 bL1PingFlag = !bL1PingFlag;
283 }283 }
284 CrossCoreWaitFlag(wsPingFlag ? V2C_PING_FLAG : V2C_PONG_FLAG);284 CrossCoreWaitFlag(wsPingFlag ? V2C_PING_FLAG : V2C_PONG_FLAG);