Merged
feat: 补充部分算子缺失的 aclnn API 示例 #4575
feat: 补充部分算子缺失的 aclnn API 示例 #4575
Merged
zhangqijia1Add on Aug 11
Total: 25 files changed+1952-468
@@ -16,11 +16,11 @@
16## 功能说明16## 功能说明
17 17 
18- 算子功能:根据输入的二维张量,提取由diagonal指定的对角线元素。18- 算子功能:根据输入的二维张量,提取由diagonal指定的对角线元素。
19- 19+ 
20 如果diagonal = 0,选择主对角线;20 如果diagonal = 0,选择主对角线;
21- 21+ 
22 如果diagonal > 0,选择主对角线上方的第diagonal条对角线;22 如果diagonal > 0,选择主对角线上方的第diagonal条对角线;
23- 23+ 
24 如果diagonal < 0,选择主对角线下方的第-diagonal条对角线。24 如果diagonal < 0,选择主对角线下方的第-diagonal条对角线。
25 25 
26## 参数说明26## 参数说明
@@ -76,4 +76,5 @@
76 76 
77| 调用方式 | 调用样例 | 说明 |77| 调用方式 | 调用样例 | 说明 |
78|--------------|------------------------------------------------------------------------|--------------------------------------------------------------|78|--------------|------------------------------------------------------------------------|--------------------------------------------------------------|
79+| aclnn调用 | [test_aclnn_diag](./examples/test_aclnn_diag.cpp) | 通过[aclnnDiag](./docs/aclnnDiag.md)接口方式调用DiagV2算子。 |
79| 图模式调用 | [test_geir_diag_v2](./examples/test_geir_diag_v2.cpp) | 通过[算子IR](./op_graph/diag_v2_proto.h)构图方式调用DiagV2算子。 |80| 图模式调用 | [test_geir_diag_v2](./examples/test_geir_diag_v2.cpp) | 通过[算子IR](./op_graph/diag_v2_proto.h)构图方式调用DiagV2算子。 |
@@ -0,0 +1,145 @@
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+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_diag.h"
15+ 
16+#define CHECK_RET(cond, return_expr) \
17+ do { \
18+ if (!(cond)) { \
19+ return_expr; \
20+ } \
21+ } while (0)
22+ 
23+#define LOG_PRINT(message, ...) \
24+ do { \
25+ printf(message, ##__VA_ARGS__); \
26+ } while (0)
27+ 
28+int64_t GetShapeSize(const std::vector<int64_t>& shape)
29+{
30+ int64_t shapeSize = 1;
31+ for (auto i : shape) {
32+ shapeSize *= i;
33+ }
34+ return shapeSize;
35+}
36+ 
37+int Init(int32_t deviceId, aclrtStream* stream)
38+{
39+ // 固定写法,资源初始化
40+ auto ret = aclInit(nullptr);
41+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
42+ ret = aclrtSetDevice(deviceId);
43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
44+ ret = aclrtCreateStream(stream);
45+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
46+ return 0;
47+}
48+ 
49+template <typename T>
50+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
51+ aclDataType dataType, aclTensor** tensor)
52+{
53+ auto size = GetShapeSize(shape) * sizeof(T);
54+ // 调用aclrtMalloc申请device侧内存
55+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
56+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
57+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
58+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
59+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
60+ 
61+ // 计算连续tensor的strides
62+ std::vector<int64_t> strides(shape.size(), 1);
63+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
64+ strides[i] = shape[i + 1] * strides[i + 1];
65+ }
66+ 
67+ // 调用aclCreateTensor接口创建aclTensor
68+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
69+ shape.data(), shape.size(), *deviceAddr);
70+ return 0;
71+}
72+ 
73+int main()
74+{
75+ // 1.(固定写法)device/stream初始化,参考acl API手册
76+ // 根据自己的实际device填写deviceId
77+ int32_t deviceId = 0;
78+ aclrtStream stream;
79+ auto ret = Init(deviceId, &stream);
80+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
81+ 
82+ // 2.构造输入与输出,需要根据API的接口自定义构造
83+ std::vector<int64_t> selfShape = {2, 2};
84+ std::vector<int64_t> outShape = {2};
85+ void* selfDeviceAddr = nullptr;
86+ void* outDeviceAddr = nullptr;
87+ aclTensor* self = nullptr;
88+ aclTensor* out = nullptr;
89+ std::vector<float> selfHostData = {1, 2, 3, 4};
90+ std::vector<float> outHostData(2, 0);
91+ int64_t diagonalVal = 0;
92+ 
93+ // 创建self aclTensor
94+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
95+ CHECK_RET(ret == ACL_SUCCESS, return ret);
96+ // 创建out aclTensor
97+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
98+ CHECK_RET(ret == ACL_SUCCESS, return ret);
99+ 
100+ // 3.调用CANN算子库API,需要修改为具体的Api名称
101+ uint64_t workspaceSize = 0;
102+ aclOpExecutor* executor;
103+ // 调用aclnnDiag第一段接口
104+ ret = aclnnDiagGetWorkspaceSize(self, diagonalVal, out, &workspaceSize, &executor);
105+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnDiagGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
106+ // 根据第一段接口计算出的workspaceSize申请device内存
107+ void* workspaceAddr = nullptr;
108+ if (workspaceSize > 0) {
109+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
110+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
111+ }
112+ // 调用aclnnDiag第二段接口
113+ ret = aclnnDiag(workspaceAddr, workspaceSize, executor, stream);
114+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnDiag failed. ERROR: %d\n", ret); return ret);
115+ 
116+ // 4.(固定写法)同步等待任务执行结束
117+ ret = aclrtSynchronizeStream(stream);
118+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
119+ 
120+ // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
121+ auto size = GetShapeSize(outShape);
122+ std::vector<float> resultData(size, 0);
123+ ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
124+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
125+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
126+ for (int64_t i = 0; i < size; i++) {
127+ LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
128+ }
129+ 
130+ // 6.释放aclTensor,需要根据具体API的接口定义修改
131+ aclDestroyTensor(self);
132+ aclDestroyTensor(out);
133+ 
134+ // 7.释放Device资源,需要根据具体API的接口定义修改
135+ aclrtFree(selfDeviceAddr);
136+ aclrtFree(outDeviceAddr);
137+ if (workspaceSize > 0) {
138+ aclrtFree(workspaceAddr);
139+ }
140+ aclrtDestroyStream(stream);
141+ aclrtResetDevice(deviceId);
142+ aclFinalize();
143+ 
144+ return 0;
145+}
@@ -123,3 +123,9 @@
123## 约束说明123## 约束说明
124 124 
125无125无
126+ 
127+## 调用说明
128+ 
129+| 调用方式 | 调用样例 | 说明 |
130+|---------|---------|------|
131+| aclnn调用 | [test_aclnn_amp_update_scale](./examples/test_aclnn_amp_update_scale.cpp) | 通过[aclnnAmpUpdateScale](./docs/aclnnAmpUpdateScale.md)接口方式调用AmpUpdateScale算子。 |
@@ -0,0 +1,181 @@
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+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_amp_update_scale.h"
15+ 
16+#define CHECK_RET(cond, return_expr) \
17+ do { \
18+ if (!(cond)) { \
19+ return_expr; \
20+ } \
21+ } while (0)
22+ 
23+#define LOG_PRINT(message, ...) \
24+ do { \
25+ printf(message, ##__VA_ARGS__); \
26+ } while (0)
27+ 
28+int64_t GetShapeSize(const std::vector<int64_t>& shape)
29+{
30+ int64_t shapeSize = 1;
31+ for (auto i : shape) {
32+ shapeSize *= i;
33+ }
34+ return shapeSize;
35+}
36+ 
37+int Init(int32_t deviceId, aclrtStream* stream)
38+{
39+ // 固定写法,资源初始化
40+ auto ret = aclInit(nullptr);
41+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
42+ ret = aclrtSetDevice(deviceId);
43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
44+ ret = aclrtCreateStream(stream);
45+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
46+ return 0;
47+}
48+ 
49+template <typename T>
50+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
51+ aclDataType dataType, aclTensor** tensor)
52+{
53+ auto size = GetShapeSize(shape) * sizeof(T);
54+ // 调用aclrtMalloc申请device侧内存
55+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
56+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
57+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
58+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
59+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
60+ 
61+ // 计算连续tensor的strides
62+ std::vector<int64_t> strides(shape.size(), 1);
63+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
64+ strides[i] = shape[i + 1] * strides[i + 1];
65+ }
66+ 
67+ // 调用aclCreateTensor接口创建aclTensor
68+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
69+ shape.data(), shape.size(), *deviceAddr);
70+ return 0;
71+}
72+ 
73+int main()
74+{
75+ // 1.(固定写法)device/stream初始化,参考acl API手册
76+ // 根据自己的实际device填写deviceId
77+ int32_t deviceId = 0;
78+ aclrtStream stream;
79+ auto ret = Init(deviceId, &stream);
80+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
81+ 
82+ // 2. 构造输入与输出,需要根据API的接口自定义构造
83+ std::vector<int64_t> scalarShape = {1};
84+ void* currentScaleDeviceAddr = nullptr;
85+ void* growthTrackerDeviceAddr = nullptr;
86+ void* foundInfDeviceAddr = nullptr;
87+ void* updatedScaleDeviceAddr = nullptr;
88+ void* updatedGrowthTrackerDeviceAddr = nullptr;
89+ aclTensor* currentScale = nullptr;
90+ aclTensor* growthTracker = nullptr;
91+ aclTensor* foundInf = nullptr;
92+ aclTensor* updatedScale = nullptr;
93+ aclTensor* updatedGrowthTracker = nullptr;
94+ 
95+ // 创建currentScale
96+ std::vector<float> currentScaleHost = {65536.0f};
97+ ret = CreateAclTensor(currentScaleHost, scalarShape, &currentScaleDeviceAddr, ACL_FLOAT, &currentScale);
98+ CHECK_RET(ret == ACL_SUCCESS, return ret);
99+ 
100+ // 创建growthTracker
101+ std::vector<int32_t> growthTrackerHost = {900};
102+ ret = CreateAclTensor(growthTrackerHost, scalarShape, &growthTrackerDeviceAddr, ACL_INT32, &growthTracker);
103+ CHECK_RET(ret == ACL_SUCCESS, return ret);
104+ 
105+ // 创建foundInf
106+ std::vector<float> foundInfHost = {0.0f};
107+ ret = CreateAclTensor(foundInfHost, scalarShape, &foundInfDeviceAddr, ACL_FLOAT, &foundInf);
108+ CHECK_RET(ret == ACL_SUCCESS, return ret);
109+ 
110+ // 创建输出updatedScale
111+ std::vector<float> updatedScaleHost = {0.0f};
112+ ret = CreateAclTensor(updatedScaleHost, scalarShape, &updatedScaleDeviceAddr, ACL_FLOAT, &updatedScale);
113+ CHECK_RET(ret == ACL_SUCCESS, return ret);
114+ 
115+ // 创建输出updatedGrowthTracker
116+ std::vector<int32_t> updatedGrowthTrackerHost = {0};
117+ ret = CreateAclTensor(updatedGrowthTrackerHost, scalarShape, &updatedGrowthTrackerDeviceAddr, ACL_INT32,
118+ &updatedGrowthTracker);
119+ CHECK_RET(ret == ACL_SUCCESS, return ret);
120+ 
121+ // 3. 调用第一段接口,获取workspace大小和执行器
122+ float growthFactor = 2.0f;
123+ float backoffFactor = 0.5f;
124+ int64_t growthInterval = 1000;
125+ 
126+ uint64_t workspaceSize = 0;
127+ aclOpExecutor* executor = nullptr;
128+ ret = aclnnAmpUpdateScaleGetWorkspaceSize(currentScale, growthTracker, foundInf, growthFactor, backoffFactor,
129+ growthInterval, updatedScale, updatedGrowthTracker, &workspaceSize,
130+ &executor);
131+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAmpUpdateScaleGetWorkspaceSize failed. ERROR: %d\n", ret);
132+ return ret);
133+ 
134+ // 4. 根据workspaceSize申请workspace内存
135+ void* workspace = nullptr;
136+ if (workspaceSize > 0) {
137+ ret = aclrtMalloc(&workspace, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
138+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
139+ }
140+ 
141+ // 5. 调用第二段接口,执行计算
142+ ret = aclnnAmpUpdateScale(workspace, workspaceSize, executor, stream);
143+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAmpUpdateScale failed. ERROR: %d\n", ret); return ret);
144+ 
145+ // 6. 同步等待任务执行结束
146+ ret = aclrtSynchronizeStream(stream);
147+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
148+ 
149+ // 7. 将输出数据从device拷贝到host,并打印结果
150+ float updatedScaleVal = 0.0f;
151+ int32_t updatedGrowthTrackerVal = 0;
152+ ret = aclrtMemcpy(&updatedScaleVal, sizeof(float), updatedScaleDeviceAddr, sizeof(float),
153+ ACL_MEMCPY_DEVICE_TO_HOST);
154+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy updatedScale failed. ERROR: %d\n", ret); return ret);
155+ ret = aclrtMemcpy(&updatedGrowthTrackerVal, sizeof(int32_t), updatedGrowthTrackerDeviceAddr, sizeof(int32_t),
156+ ACL_MEMCPY_DEVICE_TO_HOST);
157+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy updatedGrowthTracker failed. ERROR: %d\n", ret); return ret);
158+ LOG_PRINT("aclnnAmpUpdateScale result: updatedScale = %f, updatedGrowthTracker = %d\n", updatedScaleVal,
159+ updatedGrowthTrackerVal);
160+ 
161+ // 8.(固定写法)释放资源
162+ aclDestroyTensor(currentScale);
163+ aclDestroyTensor(growthTracker);
164+ aclDestroyTensor(foundInf);
165+ aclDestroyTensor(updatedScale);
166+ aclDestroyTensor(updatedGrowthTracker);
167+ aclrtFree(currentScaleDeviceAddr);
168+ aclrtFree(growthTrackerDeviceAddr);
169+ aclrtFree(foundInfDeviceAddr);
170+ aclrtFree(updatedScaleDeviceAddr);
171+ aclrtFree(updatedGrowthTrackerDeviceAddr);
172+ if (workspaceSize > 0) {
173+ aclrtFree(workspace);
174+ }
175+ aclrtDestroyStream(stream);
176+ auto aclRet = aclrtResetDevice(deviceId);
177+ CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("reset device failed. ERROR: %d\n", aclRet); return aclRet);
178+ aclRet = aclFinalize();
179+ CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("finalize acl failed. ERROR: %d\n", aclRet); return aclRet);
180+ return 0;
181+}
@@ -67,4 +67,5 @@ $$
67 67 
68| 调用方式 | 调用样例 | 说明 |68| 调用方式 | 调用样例 | 说明 |
69|--------------|------------------------------------------------------------------------|--------------------------------------------------------------|69|--------------|------------------------------------------------------------------------|--------------------------------------------------------------|
70+| aclnn调用 | [test_aclnn_angle_v2](./examples/test_aclnn_angle_v2.cpp) | 通过[aclnnAngleV2](./docs/aclnnAngleV2.md)接口方式调用AngleV2算子。 |
70| 图模式调用 | [test_geir_angle_v2](./examples/test_geir_angle_v2.cpp) | 通过[算子IR](./op_graph/angle_v2_proto.h)构图方式调用AngleV2算子。 |71| 图模式调用 | [test_geir_angle_v2](./examples/test_geir_angle_v2.cpp) | 通过[算子IR](./op_graph/angle_v2_proto.h)构图方式调用AngleV2算子。 |
@@ -0,0 +1,152 @@
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+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_angle_v2.h"
15+ 
16+#define CHECK_RET(cond, return_expr) \
17+ do { \
18+ if (!(cond)) { \
19+ return_expr; \
20+ } \
21+ } while (0)
22+ 
23+#define LOG_PRINT(message, ...) \
24+ do { \
25+ printf(message, ##__VA_ARGS__); \
26+ } while (0)
27+ 
28+int64_t GetShapeSize(const std::vector<int64_t>& shape)
29+{
30+ int64_t shapeSize = 1;
31+ for (auto i : shape) {
32+ shapeSize *= i;
33+ }
34+ return shapeSize;
35+}
36+ 
37+void PrintOutResult(std::vector<int64_t>& shape, void** deviceAddr)
38+{
39+ auto size = GetShapeSize(shape);
40+ std::vector<float> resultData(size, 0);
41+ auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), *deviceAddr,
42+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return);
44+ for (int64_t i = 0; i < size; i++) {
45+ LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
46+ }
47+}
48+ 
49+int Init(int32_t deviceId, aclrtStream* stream)
50+{
51+ // 固定写法,初始化
52+ auto ret = aclInit(nullptr);
53+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
54+ ret = aclrtSetDevice(deviceId);
55+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
56+ ret = aclrtCreateStream(stream);
57+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
58+ return 0;
59+}
60+ 
61+template <typename T>
62+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
63+ aclDataType dataType, aclTensor** tensor)
64+{
65+ auto size = GetShapeSize(shape) * sizeof(T);
66+ // 调用aclrtMalloc申请device侧内存
67+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
68+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
69+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
70+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
71+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
72+ 
73+ // 计算连续tensor的strides
74+ std::vector<int64_t> strides(shape.size(), 1);
75+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
76+ strides[i] = shape[i + 1] * strides[i + 1];
77+ }
78+ 
79+ // 调用aclCreateTensor接口创建aclTensor
80+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
81+ shape.data(), shape.size(), *deviceAddr);
82+ return 0;
83+}
84+ 
85+int main()
86+{
87+ // 1.(固定写法)device/stream初始化,参考acl API文档
88+ int32_t deviceId = 0;
89+ aclrtStream stream;
90+ auto ret = Init(deviceId, &stream);
91+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
92+ 
93+ // 2. 构造输入与输出
94+ std::vector<int64_t> xShape = {2, 3};
95+ std::vector<int64_t> yShape = {2, 3};
96+ 
97+ void* xDeviceAddr = nullptr;
98+ void* yDeviceAddr = nullptr;
99+ 
100+ aclTensor* x = nullptr;
101+ aclTensor* y = nullptr;
102+ 
103+ std::vector<float> xHostData = {1.0, 0.0, 0.0, 1.0, -1.0, 0.0};
104+ std::vector<float> yHostData = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
105+ 
106+ ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_FLOAT, &x);
107+ CHECK_RET(ret == ACL_SUCCESS, return ret);
108+ ret = CreateAclTensor(yHostData, yShape, &yDeviceAddr, aclDataType::ACL_FLOAT, &y);
109+ CHECK_RET(ret == ACL_SUCCESS, return ret);
110+ 
111+ // 3. 调用CANN算子库API
112+ uint64_t workspaceSize = 0;
113+ aclOpExecutor* executor;
114+ 
115+ // 调用aclnnAngleV2第一段接口
116+ ret = aclnnAngleV2GetWorkspaceSize(x, y, &workspaceSize, &executor);
117+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAngleV2GetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
118+ 
119+ // 根据第一段接口计算出的workspaceSize申请device内存
120+ void* workspaceAddr = nullptr;
121+ if (workspaceSize > 0) {
122+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
123+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
124+ }
125+ 
126+ // 调用aclnnAngleV2第二段接口
127+ ret = aclnnAngleV2(workspaceAddr, workspaceSize, executor, stream);
128+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAngleV2 failed. ERROR: %d\n", ret); return ret);
129+ 
130+ // 4.(固定写法)同步等待任务执行结束
131+ ret = aclrtSynchronizeStream(stream);
132+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
133+ 
134+ // 5. 获取输出的值
135+ PrintOutResult(yShape, &yDeviceAddr);
136+ 
137+ // 6. 释放aclTensor
138+ aclDestroyTensor(x);
139+ aclDestroyTensor(y);
140+ 
141+ // 7. 释放device资源
142+ aclrtFree(xDeviceAddr);
143+ aclrtFree(yDeviceAddr);
144+ if (workspaceSize > 0) {
145+ aclrtFree(workspaceAddr);
146+ }
147+ aclrtDestroyStream(stream);
148+ aclrtResetDevice(deviceId);
149+ aclFinalize();
150+ 
151+ return 0;
152+}
@@ -1,3 +1,87 @@
1# Cdist1# Cdist
Y
Yyue-maAug 12

这里的信息不对,应补充算子kernel相关的定义和介绍

likedislike
2 2 
3-本目录仅包含Cdist算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。3+## 产品支持情况
4+ 
5+| 产品 | 是否支持 |
6+| :--- | :------: |
7+| <term>Ascend 950PR/Ascend 950DT</term> | √ |
8+| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ |
9+| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ |
10+| <term>Atlas 200I/500 A2 推理产品</term> | × |
11+| <term>Atlas 推理系列产品</term> | × |
12+| <term>Atlas 训练系列产品</term> | × |
13+ 
14+## 功能说明
15+ 
16+- 算子功能:计算两个向量集合中每对向量之间的p范数距离。
17+- 计算公式:对于输入张量x1和x2,设其shape分别为$[B, P, M]$和$[B, R, M]$,输出张量y的shape为$[B, P, R]$。
18+ 
19+ 当$p>0$时:
20+ 
21+ $$
22+ y_{b,i,j}=\left(\sum_{k=1}^{M}|x1_{b,i,k}-x2_{b,j,k}|^p\right)^{\frac{1}{p}}
23+ $$
24+ 
25+ 当$p=0$时,输出为对应向量中不相等元素的数量;当$p=+\infty$时,输出为对应向量元素差值绝对值的最大值。
26+ 
27+## 参数说明
28+ 
29+<table style="undefined;table-layout: fixed; width: 980px"><colgroup>
30+ <col style="width: 100px">
31+ <col style="width: 150px">
32+ <col style="width: 280px">
33+ <col style="width: 330px">
34+ <col style="width: 120px">
35+ </colgroup>
36+ <thead>
37+ <tr>
38+ <th>参数名</th>
39+ <th>输入/输出/属性</th>
40+ <th>描述</th>
41+ <th>数据类型</th>
42+ <th>数据格式</th>
43+ </tr></thead>
44+ <tbody>
45+ <tr>
46+ <td>x1</td>
47+ <td>输入</td>
48+ <td>第一个输入张量,shape为[B, P, M]。</td>
49+ <td>BFLOAT16、FLOAT16、FLOAT</td>
50+ <td>ND</td>
51+ </tr>
52+ <tr>
53+ <td>x2</td>
54+ <td>输入</td>
55+ <td>第二个输入张量,shape为[B, R, M]。</td>
56+ <td>BFLOAT16、FLOAT16、FLOAT</td>
57+ <td>ND</td>
58+ </tr>
59+ <tr>
60+ <td>y</td>
61+ <td>输出</td>
62+ <td>p范数距离计算结果,shape为[B, P, R]。</td>
63+ <td>BFLOAT16、FLOAT16、FLOAT</td>
64+ <td>ND</td>
65+ </tr>
66+ <tr>
67+ <td>p</td>
68+ <td>可选属性</td>
69+ <td>范数阶数,取值范围为[0, +∞],默认值为2.0。</td>
70+ <td>FLOAT</td>
71+ <td>-</td>
72+ </tr>
73+ </tbody></table>
74+ 
75+## 约束说明
76+ 
77+- x1、x2和y的数据类型必须一致。
78+- x1和x2的维度范围为2~8,最后一维长度必须相同。
79+- x1和x2除最后两维外的其他维度必须满足broadcast关系;输出对应维度为broadcast后的shape。
80+- 若x1的倒数第二维为P,x2的倒数第二维为R,则输出的最后两维为[P, R]。
81+- p必须大于或等于0,支持+∞,常用取值为0、1.0、2.0和+∞。
82+ 
83+## 调用说明
84+ 
85+| 调用方式 | 调用样例 | 说明 |
86+| :--- | :--- | :--- |
87+| aclnn调用 | [test_aclnn_cdist](./examples/test_aclnn_cdist.cpp) | 通过[aclnnCdist](./docs/aclnnCdist.md)接口方式调用Cdist算子。 |
吴
吴吴瑶Aug 18

补充op_list调用说明

likedislike
Rmath/cdist/examples/aclnn_cdist.cpp→math/cdist/examples/test_aclnn_cdist.cpp+0-0
File renamed without changes.
@@ -79,4 +79,5 @@
79 79 
80| 调用方式 | 调用样例 | 说明 |80| 调用方式 | 调用样例 | 说明 |
81|--------------|------------------------------------------------------------------------|----------------------------------------------------------------|81|--------------|------------------------------------------------------------------------|----------------------------------------------------------------|
82+| aclnn调用 | [test_aclnn_histc](./examples/test_aclnn_histc.cpp) | 通过[aclnnHistc](./docs/aclnnHistc.md)接口方式调用HistogramV2算子。 |
82| 图模式调用 | [test_geir_histogram_v2](./examples/test_geir_histogram_v2.cpp) | 通过[算子IR](./op_graph/histogram_v2_proto.h)构图方式调用HistogramV2算子。 |83| 图模式调用 | [test_geir_histogram_v2](./examples/test_geir_histogram_v2.cpp) | 通过[算子IR](./op_graph/histogram_v2_proto.h)构图方式调用HistogramV2算子。 |
@@ -0,0 +1,156 @@
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+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_histc.h"
15+ 
16+#define CHECK_RET(cond, return_expr) \
17+ do { \
18+ if (!(cond)) { \
19+ return_expr; \
20+ } \
21+ } while (0)
22+ 
23+#define LOG_PRINT(message, ...) \
24+ do { \
25+ printf(message, ##__VA_ARGS__); \
26+ } while (0)
27+ 
28+int64_t GetShapeSize(const std::vector<int64_t>& shape)
29+{
30+ int64_t shapeSize = 1;
31+ for (auto i : shape) {
32+ shapeSize *= i;
33+ }
34+ return shapeSize;
35+}
36+ 
37+int Init(int32_t deviceId, aclrtStream* stream)
38+{
39+ // 固定写法,资源初始化
40+ auto ret = aclInit(nullptr);
41+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
42+ ret = aclrtSetDevice(deviceId);
43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
44+ ret = aclrtCreateStream(stream);
45+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
46+ return 0;
47+}
48+ 
49+template <typename T>
50+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
51+ aclDataType dataType, aclTensor** tensor)
52+{
53+ auto size = GetShapeSize(shape) * sizeof(T);
54+ // 调用aclrtMalloc申请device侧内存
55+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
56+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
57+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
58+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
59+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
60+ 
61+ // 计算连续tensor的strides
62+ std::vector<int64_t> strides(shape.size(), 1);
63+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
64+ strides[i] = shape[i + 1] * strides[i + 1];
65+ }
66+ 
67+ // 调用aclCreateTensor接口创建aclTensor
68+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
69+ shape.data(), shape.size(), *deviceAddr);
70+ return 0;
71+}
72+ 
73+int main()
74+{
75+ // 1.(固定写法)device/stream初始化,参考acl API手册
76+ // 根据自己的实际device填写deviceId
77+ int32_t deviceId = 0;
78+ aclrtStream stream;
79+ auto ret = Init(deviceId, &stream);
80+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
81+ 
82+ // 2. 构造输入与输出,需要根据API的接口自定义构造
83+ std::vector<int64_t> selfShape = {3, 3};
84+ std::vector<int64_t> outShape = {3};
85+ void* selfDeviceAddr = nullptr;
86+ void* outDeviceAddr = nullptr;
87+ aclTensor* self = nullptr;
88+ aclScalar* min = nullptr;
89+ aclScalar* max = nullptr;
90+ aclTensor* out = nullptr;
91+ std::vector<float> selfHostData = {1, 2, 3, 4, 5, 6, 7, 8, 9};
92+ std::vector<float> outHostData = {0, 0, 0};
93+ int64_t bins = 3;
94+ float minValue = 1.0f;
95+ float maxValue = 9.0f;
96+ // 创建self aclTensor
97+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
98+ CHECK_RET(ret == ACL_SUCCESS, return ret);
99+ // 创建min aclScalar
100+ min = aclCreateScalar(&minValue, aclDataType::ACL_FLOAT);
101+ CHECK_RET(min != nullptr, return ret);
102+ // 创建max aclScalar
103+ max = aclCreateScalar(&maxValue, aclDataType::ACL_FLOAT);
104+ CHECK_RET(max != nullptr, return ret);
105+ // 创建out aclTensor
106+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
107+ CHECK_RET(ret == ACL_SUCCESS, return ret);
108+ 
109+ // 3. 调用CANN算子库API,需要修改为具体的API名称
110+ uint64_t workspaceSize = 0;
111+ aclOpExecutor* executor;
112+ // 调用aclnnHistc第一段接口
113+ ret = aclnnHistcGetWorkspaceSize(self, bins, min, max, out, &workspaceSize, &executor);
114+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnHistcGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
115+ // 根据第一段接口计算出的workspaceSize申请device内存
116+ void* workspaceAddr = nullptr;
117+ if (workspaceSize > 0) {
118+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
119+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
120+ }
121+ // 调用aclnnHistc第二段接口
122+ ret = aclnnHistc(workspaceAddr, workspaceSize, executor, stream);
123+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnHistc failed. ERROR: %d\n", ret); return ret);
124+ 
125+ // 4.(固定写法)同步等待任务执行结束
126+ ret = aclrtSynchronizeStream(stream);
127+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
128+ 
129+ // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
130+ auto size = GetShapeSize(outShape);
131+ std::vector<float> resultData(size, 0);
132+ ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
133+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
134+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
135+ for (int64_t i = 0; i < size; i++) {
136+ LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
137+ }
138+ 
139+ // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
140+ aclDestroyTensor(self);
141+ aclDestroyScalar(min);
142+ aclDestroyScalar(max);
143+ aclDestroyTensor(out);
144+ 
145+ // 7. 释放Device资源,需要根据具体API的接口定义修改
146+ aclrtFree(selfDeviceAddr);
147+ aclrtFree(outDeviceAddr);
148+ if (workspaceSize > 0) {
149+ aclrtFree(workspaceAddr);
150+ }
151+ aclrtDestroyStream(stream);
152+ aclrtResetDevice(deviceId);
153+ aclFinalize();
154+ 
155+ return 0;
156+}
@@ -1,3 +1,9 @@
1# ReduceNansum1# ReduceNansum
2 2 
3本目录仅包含ReduceNansum算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。3本目录仅包含ReduceNansum算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。
4+ 
5+## 调用说明
6+ 
7+| 调用方式 | 调用样例 | 说明 |
8+|---------|---------|------|
9+| aclnn调用 | [test_aclnn_reduce_nansum](./examples/test_aclnn_reduce_nansum.cpp) | 通过[aclnnReduceNansum](./docs/aclnnReduceNansum.md)接口方式调用ReduceNansum算子。 |
@@ -1,145 +0,0 @@
1-/**
2- * This program is free software, you can redistribute it and/or modify.
3- * Copyright (c) 2026 Huawei Technologies Co., Ltd.
4- * This file is a part of the CANN Open Software.
5- * Licensed under CANN Open Software License Agreement Version 2.0 (the "License").
6- * Please refer to the License for details. You may not use this file except in compliance with the License.
7- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, 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-#include <iostream>
12-#include <vector>
13-#include "acl/acl.h"
14-#include "aclnnop/aclnn_reduce_nansum.h"
15- 
16-#define CHECK_RET(cond, return_expr) \
17- do { \
18- if (!(cond)) { \
19- return_expr; \
20- } \
21- } while (0)
22- 
23-#define LOG_PRINT(message, ...) \
24- do { \
25- printf(message, ##__VA_ARGS__); \
26- } while (0)
27- 
28-int64_t GetShapeSize(const std::vector<int64_t>& shape) {
29- int64_t shapeSize = 1;
30- for (auto i : shape) {
31- shapeSize *= i;
32- }
33- return shapeSize;
34-}
35- 
36-int Init(int32_t deviceId, aclrtStream* stream) {
37- // 固定写法,资源初始化
38- auto ret = aclInit(nullptr);
39- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
40- ret = aclrtSetDevice(deviceId);
41- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
42- ret = aclrtCreateStream(stream);
43- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
44- return 0;
45-}
46- 
47-template <typename T>
48-int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
49- aclDataType dataType, aclTensor** tensor) {
50- auto size = GetShapeSize(shape) * sizeof(T);
51- // 调用aclrtMalloc申请device侧内存
52- auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
53- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
54- // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
55- ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
56- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
57- 
58- // 计算连续tensor的strides
59- std::vector<int64_t> strides(shape.size(), 1);
60- for (int64_t i = shape.size() - 2; i >= 0; i--) {
61- strides[i] = shape[i + 1] * strides[i + 1];
62- }
63- 
64- // 调用aclCreateTensor接口创建aclTensor
65- *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr);
66- return 0;
67-}
68- 
69-int main() {
70- // 1.(固定写法)device/stream初始化,参考acl API手册
71- // 根据自己的实际device填写deviceId
72- int32_t deviceId = 0;
73- aclrtStream stream;
74- auto ret = Init(deviceId, &stream);
75- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
76- 
77- // 2.构造输入与输出,需要根据API的接口自定义构造
78- std::vector<int64_t> selfShape = {4, 2};
79- std::vector<int64_t> outShape = {2};
80- void* selfDeviceAddr = nullptr;
81- void* outDeviceAddr = nullptr;
82- aclTensor* self = nullptr;
83- aclIntArray* dim = nullptr;
84- aclTensor* out = nullptr;
85- std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7};
86- std::vector<float> outHostData = {0, 0};
87- std::vector<int64_t> dimData = {0};
88- bool keepDim = false;
89- auto dtype = aclDataType::ACL_FLOAT;
90- // 创建self aclTensor
91- ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
92- CHECK_RET(ret == ACL_SUCCESS, return ret);
93- // 创建out aclTensor
94- ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
95- CHECK_RET(ret == ACL_SUCCESS, return ret);
96- // 创建dim aclIntArray
97- dim = aclCreateIntArray(dimData.data(), 1);
98- CHECK_RET(dim != nullptr, return ret);
99- 
100-// 3.调用CANN算子库API,需要修改为具体的Api名称
101- uint64_t workspaceSize = 0;
102- aclOpExecutor* executor;
103- // 调用aclnnReduceNansum第一段接口
104- ret = aclnnReduceNansumGetWorkspaceSize(self, dim, keepDim, dtype, out, &workspaceSize, &executor);
105- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnReduceNansumGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
106- // 根据第一段接口计算出的workspaceSize申请device内存
107- void* workspaceAddr = nullptr;
108- if (workspaceSize > 0) {
109- ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
110- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
111- }
112- // 调用aclnnReduceNansum第二段接口
113- ret = aclnnReduceNansum(workspaceAddr, workspaceSize, executor, stream);
114- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnReduceNansum failed. ERROR: %d\n", ret); return ret);
115- 
116- // 4.(固定写法)同步等待任务执行结束
117- ret = aclrtSynchronizeStream(stream);
118- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
119- 
120- // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
121- auto size = GetShapeSize(outShape);
122- std::vector<float> resultData(size, 0);
123- ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
124- size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
125- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
126- for (int64_t i = 0; i < size; i++) {
127- LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
128- }
129- 
130- // 6.释放aclTensor和aclIntArray,需要根据具体API的接口定义修改
131- aclDestroyTensor(self);
132- aclDestroyIntArray(dim);
133- aclDestroyTensor(out);
134- 
135- // 7.释放device资源,需要根据具体API的接口定义修改
136- aclrtFree(selfDeviceAddr);
137- aclrtFree(outDeviceAddr);
138- if (workspaceSize > 0) {
139- aclrtFree(workspaceAddr);
140- }
141- aclrtDestroyStream(stream);
142- aclrtResetDevice(deviceId);
143- aclFinalize();
144- return 0;
145-}
@@ -0,0 +1,150 @@
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+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_reduce_nansum.h"
15+ 
16+#define CHECK_RET(cond, return_expr) \
17+ do { \
18+ if (!(cond)) { \
19+ return_expr; \
20+ } \
21+ } while (0)
22+ 
23+#define LOG_PRINT(message, ...) \
24+ do { \
25+ printf(message, ##__VA_ARGS__); \
26+ } while (0)
27+ 
28+int64_t GetShapeSize(const std::vector<int64_t>& shape)
29+{
30+ int64_t shapeSize = 1;
31+ for (auto i : shape) {
32+ shapeSize *= i;
33+ }
34+ return shapeSize;
35+}
36+ 
37+int Init(int32_t deviceId, aclrtStream* stream)
38+{
39+ // 固定写法,资源初始化
40+ auto ret = aclInit(nullptr);
41+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
42+ ret = aclrtSetDevice(deviceId);
43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
44+ ret = aclrtCreateStream(stream);
45+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
46+ return 0;
47+}
48+ 
49+template <typename T>
50+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
51+ aclDataType dataType, aclTensor** tensor)
52+{
53+ auto size = GetShapeSize(shape) * sizeof(T);
54+ // 调用aclrtMalloc申请device侧内存
55+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
56+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
57+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
58+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
59+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
60+ 
61+ // 计算连续tensor的strides
62+ std::vector<int64_t> strides(shape.size(), 1);
63+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
64+ strides[i] = shape[i + 1] * strides[i + 1];
65+ }
66+ 
67+ // 调用aclCreateTensor接口创建aclTensor
68+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
69+ shape.data(), shape.size(), *deviceAddr);
70+ return 0;
71+}
72+ 
73+int main()
74+{
75+ // 1.(固定写法)device/stream初始化,参考acl API手册
76+ // 根据自己的实际device填写deviceId
77+ int32_t deviceId = 0;
78+ aclrtStream stream;
79+ auto ret = Init(deviceId, &stream);
80+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
81+ 
82+ // 2.构造输入与输出,需要根据API的接口自定义构造
83+ std::vector<int64_t> selfShape = {4, 2};
84+ std::vector<int64_t> outShape = {2};
85+ void* selfDeviceAddr = nullptr;
86+ void* outDeviceAddr = nullptr;
87+ aclTensor* self = nullptr;
88+ aclIntArray* dim = nullptr;
89+ aclTensor* out = nullptr;
90+ std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7};
91+ std::vector<float> outHostData = {0, 0};
92+ std::vector<int64_t> dimData = {0};
93+ bool keepDim = false;
94+ auto dtype = aclDataType::ACL_FLOAT;
95+ // 创建self aclTensor
96+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
97+ CHECK_RET(ret == ACL_SUCCESS, return ret);
98+ // 创建out aclTensor
99+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
100+ CHECK_RET(ret == ACL_SUCCESS, return ret);
101+ // 创建dim aclIntArray
102+ dim = aclCreateIntArray(dimData.data(), 1);
103+ CHECK_RET(dim != nullptr, return ret);
104+ 
105+ // 3.调用CANN算子库API,需要修改为具体的Api名称
106+ uint64_t workspaceSize = 0;
107+ aclOpExecutor* executor;
108+ // 调用aclnnReduceNansum第一段接口
109+ ret = aclnnReduceNansumGetWorkspaceSize(self, dim, keepDim, dtype, out, &workspaceSize, &executor);
110+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnReduceNansumGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
111+ // 根据第一段接口计算出的workspaceSize申请device内存
112+ void* workspaceAddr = nullptr;
113+ if (workspaceSize > 0) {
114+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
115+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
116+ }
117+ // 调用aclnnReduceNansum第二段接口
118+ ret = aclnnReduceNansum(workspaceAddr, workspaceSize, executor, stream);
119+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnReduceNansum failed. ERROR: %d\n", ret); return ret);
120+ 
121+ // 4.(固定写法)同步等待任务执行结束
122+ ret = aclrtSynchronizeStream(stream);
123+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
124+ 
125+ // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
126+ auto size = GetShapeSize(outShape);
127+ std::vector<float> resultData(size, 0);
128+ ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
129+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
130+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
131+ for (int64_t i = 0; i < size; i++) {
132+ LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
133+ }
134+ 
135+ // 6.释放aclTensor和aclIntArray,需要根据具体API的接口定义修改
136+ aclDestroyTensor(self);
137+ aclDestroyIntArray(dim);
138+ aclDestroyTensor(out);
139+ 
140+ // 7.释放device资源,需要根据具体API的接口定义修改
141+ aclrtFree(selfDeviceAddr);
142+ aclrtFree(outDeviceAddr);
143+ if (workspaceSize > 0) {
144+ aclrtFree(workspaceAddr);
145+ }
146+ aclrtDestroyStream(stream);
147+ aclrtResetDevice(deviceId);
148+ aclFinalize();
149+ return 0;
150+}
@@ -1,3 +1,10 @@
1# ReduceStdWithMean1# ReduceStdWithMean
2 2 
3本目录仅包含ReduceStdWithMean算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。3本目录仅包含ReduceStdWithMean算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。
4+ 
5+## 调用说明
6+ 
7+| 调用方式 | 调用样例 | 说明 |
8+|---------|---------|------|
9+| aclnn调用 | [test_aclnn_batch_norm_stats](./examples/test_aclnn_batch_norm_stats.cpp) | 通过[aclnnBatchNormStats](./docs/aclnnBatchNormStats.md)接口方式调用ReduceStdWithMean算子。 |
10+| aclnn调用 | [test_aclnn_std_mean_correction](./examples/test_aclnn_std_mean_correction.cpp) | 通过[aclnnStdMeanCorrection](./docs/aclnnStdMeanCorrection.md)接口方式调用ReduceStdWithMean算子。 |
@@ -1,158 +0,0 @@
1-/**
2- * This program is free software, you can redistribute it and/or modify.
3- * Copyright (c) 2026 Huawei Technologies Co., Ltd.
4- * This file is a part of the CANN Open Software.
5- * Licensed under CANN Open Software License Agreement Version 2.0 (the "License").
6- * Please refer to the License for details. You may not use this file except in compliance with the License.
7- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, 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-#include <iostream>
12-#include <vector>
13-#include "acl/acl.h"
14-#include "aclnnop/aclnn_batch_norm_stats.h"
15- 
16-#define CHECK_RET(cond, return_expr) \
17- do { \
18- if (!(cond)) { \
19- return_expr; \
20- } \
21- } while (0)
22- 
23-#define LOG_PRINT(message, ...) \
24- do { \
25- printf(message, ##__VA_ARGS__); \
26- } while (0)
27- 
28-int64_t GetShapeSize(const std::vector<int64_t>& shape) {
29- int64_t shapeSize = 1;
30- for (auto i : shape) {
31- shapeSize *= i;
32- }
33- return shapeSize;
34-}
35- 
36-int Init(int32_t deviceId, aclrtStream* stream) {
37- // 固定写法,资源初始化
38- auto ret = aclInit(nullptr);
39- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
40- ret = aclrtSetDevice(deviceId);
41- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
42- ret = aclrtCreateStream(stream);
43- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
44- return 0;
45-}
46- 
47-template <typename T>
48-int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
49- aclDataType dataType, aclTensor** tensor) {
50- auto size = GetShapeSize(shape) * sizeof(T);
51- // 调用aclrtMalloc申请Device侧内存
52- auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
53- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
54- 
55- // 调用aclrtMemcpy将Host侧数据拷贝到Device侧内存上
56- ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
57- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
58- 
59- // 计算连续tensor的strides
60- std::vector<int64_t> strides(shape.size(), 1);
61- for (int64_t i = shape.size() - 2; i >= 0; i--) {
62- strides[i] = shape[i + 1] * strides[i + 1];
63- }
64- 
65- // 调用aclCreateTensor接口创建aclTensor
66- *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
67- shape.data(), shape.size(), *deviceAddr);
68- return 0;
69-}
70- 
71-int main() {
72- // 1.(固定写法)device/stream初始化,参考acl API手册
73- // 根据自己的实际device填写deviceId
74- int32_t deviceId = 0;
75- aclrtStream stream;
76- auto ret = Init(deviceId, &stream);
77- // check根据自己的需要处理
78- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
79- 
80- // 2.构造输入与输出,需要根据API的接口自定义构造
81- std::vector<int64_t> inputShape = {2, 3};
82- std::vector<int64_t> outShape = {3,};
83- void* inputDeviceAddr = nullptr;
84- void* meanDeviceAddr = nullptr;
85- void* invstdDeviceAddr = nullptr;
86- aclTensor* input = nullptr;
87- aclTensor* mean = nullptr;
88- aclTensor* invstd = nullptr;
89- std::vector<float> inputHostData = {1, 2, 3, 4, 5, 6};
90- std::vector<float> meanHostData = {0, 0, 0};
91- std::vector<float> invstdHostData = {0, 0, 0};
92- double eps = 1e-5;
93- 
94- // 创建self aclTensor
95- ret = CreateAclTensor(inputHostData, inputShape, &inputDeviceAddr, aclDataType::ACL_FLOAT, &input);
96- CHECK_RET(ret == ACL_SUCCESS, return ret);
97- // 创建mean aclTensor
98- ret = CreateAclTensor(meanHostData, outShape, &meanDeviceAddr, aclDataType::ACL_FLOAT, &mean);
99- CHECK_RET(ret == ACL_SUCCESS, return ret);
100- // 创建invstd aclTensor
101- ret = CreateAclTensor(invstdHostData, outShape, &invstdDeviceAddr, aclDataType::ACL_FLOAT, &invstd);
102- CHECK_RET(ret == ACL_SUCCESS, return ret);
103- 
104- uint64_t workspaceSize = 0;
105- aclOpExecutor* executor;
106- // aclnnBatchNormStats接口调用示例
107- // 3.调用CANN算子库API,需要修改为具体的API名称
108- // 调用aclnnBatchNormStats第一段接口
109- ret = aclnnBatchNormStatsGetWorkspaceSize(input, eps, mean, invstd, &workspaceSize, &executor);
110- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBatchNormStatsGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
111- // 根据第一段接口计算出的workspaceSize申请device内存
112- void* workspaceAddr = nullptr;
113- if (workspaceSize > 0) {
114- ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
115- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
116- }
117- // 调用aclnnBatchNormStats第二段接口
118- ret = aclnnBatchNormStats(workspaceAddr, workspaceSize, executor, stream);
119- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBatchNormStats failed. ERROR: %d\n", ret); return ret);
120- 
121- // 4.(固定写法)同步等待任务执行结束
122- ret = aclrtSynchronizeStream(stream);
123- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
124- 
125- // 5.获取输出的值,将Device侧内存上的结果拷贝至Host侧,需要根据具体API的接口定义修改
126- auto size = GetShapeSize(outShape);
127- std::vector<float> meanData(size, 0);
128- ret = aclrtMemcpy(meanData.data(), meanData.size() * sizeof(meanData[0]), meanDeviceAddr,
129- size * sizeof(meanData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
130- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
131- for (int64_t i = 0; i < size; i++) {
132- LOG_PRINT("mean result[%ld] is: %f\n", i, meanData[i]);
133- }
134- std::vector<float> invstdData(size, 0);
135- ret = aclrtMemcpy(invstdData.data(), invstdData.size() * sizeof(invstdData[0]), invstdDeviceAddr,
136- size * sizeof(invstdData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
137- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
138- for (int64_t i = 0; i < size; i++) {
139- LOG_PRINT("mean result[%ld] is: %f\n", i, invstdData[i]);
140- }
141- 
142- // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改
143- aclDestroyTensor(input);
144- aclDestroyTensor(mean);
145- aclDestroyTensor(invstd);
146- 
147- // 7.释放device资源,需要根据具体API的接口定义修改
148- aclrtFree(inputDeviceAddr);
149- aclrtFree(meanDeviceAddr);
150- aclrtFree(invstdDeviceAddr);
151- if (workspaceSize > 0) {
152- aclrtFree(workspaceAddr);
153- }
154- aclrtDestroyStream(stream);
155- aclrtResetDevice(deviceId);
156- aclFinalize();
157- return 0;
158-}
@@ -1,161 +0,0 @@
1-/**
2- * This program is free software, you can redistribute it and/or modify.
3- * Copyright (c) 2026 Huawei Technologies Co., Ltd.
4- * This file is a part of the CANN Open Software.
5- * Licensed under CANN Open Software License Agreement Version 2.0 (the "License").
6- * Please refer to the License for details. You may not use this file except in compliance with the License.
7- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, 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-#include <iostream>
12-#include <vector>
13-#include "acl/acl.h"
14-#include "aclnnop/aclnn_std_mean_correction.h"
15- 
16-#define CHECK_RET(cond, return_expr) \
17- do { \
18- if (!(cond)) { \
19- return_expr; \
20- } \
21- } while (0)
22- 
23-#define LOG_PRINT(message, ...) \
24- do { \
25- printf(message, ##__VA_ARGS__); \
26- } while (0)
27- 
28-int64_t GetShapeSize(const std::vector<int64_t>& shape) {
29- int64_t shape_size = 1;
30- for (auto i : shape) {
31- shape_size *= i;
32- }
33- return shape_size;
34-}
35- 
36-int Init(int32_t deviceId, aclrtStream* stream) {
37- // 固定写法,资源初始化
38- auto ret = aclInit(nullptr);
39- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
40- ret = aclrtSetDevice(deviceId);
41- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
42- ret = aclrtCreateStream(stream);
43- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
44- return 0;
45-}
46- 
47-template <typename T>
48-int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
49- aclDataType dataType, aclTensor** tensor) {
50- auto size = GetShapeSize(shape) * sizeof(T);
51- // 调用aclrtMalloc申请device侧内存
52- auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
53- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
54- 
55- // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
56- ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
57- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
58- 
59- // 计算连续tensor的strides
60- std::vector<int64_t> strides(shape.size(), 1);
61- for (int64_t i = shape.size() - 2; i >= 0; i--) {
62- strides[i] = shape[i + 1] * strides[i + 1];
63- }
64- 
65- // 调用aclCreateTensor接口创建aclTensor
66- *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
67- shape.data(), shape.size(), *deviceAddr);
68- return 0;
69-}
70- 
71-int main() {
72- // 1.(固定写法)device/stream初始化,参考acl API手册
73- // 根据自己的实际device填写deviceId
74- int32_t deviceId = 0;
75- aclrtStream stream;
76- auto ret = Init(deviceId, &stream);
77- // check根据自己的需要处理
78- CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
79- // 2.构造输入与输出,需要根据API的接口自定义构造
80- std::vector<int64_t> selfShape = {2, 3, 4};
81- std::vector<int64_t> stdOutShape = {2, 4};
82- std::vector<int64_t> meanOutShape = {2, 4};
83- void* selfDeviceAddr = nullptr;
84- void* stdOutDeviceAddr = nullptr;
85- void* meanOutDeviceAddr = nullptr;
86- aclTensor* self = nullptr;
87- aclTensor* stdOut = nullptr;
88- aclTensor* meanOut = nullptr;
89- std::vector<float> selfHostData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
90- 19, 20, 21, 22, 23, 24};
91- std::vector<float> stdOutHostData = {1, 2, 3, 4, 5, 6, 7, 8.0};
92- std::vector<float> meanOutHostData = {1, 2, 3, 4, 5, 6, 7, 8.0};
93- std::vector<int64_t> dimData = {1};
94- int64_t correction = 1;
95- bool keepdim = false;
96- // 创建self aclTensor
97- ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
98- CHECK_RET(ret == ACL_SUCCESS, return ret);
99- // 创建stdOut aclTensor
100- ret = CreateAclTensor(stdOutHostData, stdOutShape, &stdOutDeviceAddr, aclDataType::ACL_FLOAT, &stdOut);
101- CHECK_RET(ret == ACL_SUCCESS, return ret);
102- // 创建meanOut aclTensor
103- ret = CreateAclTensor(meanOutHostData, meanOutShape, &meanOutDeviceAddr, aclDataType::ACL_FLOAT, &meanOut);
104- CHECK_RET(ret == ACL_SUCCESS, return ret);
105- 
106- const aclIntArray *dim = aclCreateIntArray(dimData.data(), dimData.size());
107- CHECK_RET(dim != nullptr, return ACL_ERROR_INTERNAL_ERROR);
108- 
109- // 3.调用CANN算子库API,需要修改为具体的API
110- uint64_t workspaceSize = 0;
111- aclOpExecutor* executor;
112- // 调用aclnnStdMeanCorrection第一段接口
113- ret = aclnnStdMeanCorrectionGetWorkspaceSize(self, dim, correction, keepdim, stdOut, meanOut, &workspaceSize, &executor);
114- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnStdMeanCorrectionGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
115- // 根据第一段接口计算出的workspaceSize申请device内存
116- void* workspaceAddr = nullptr;
117- if (workspaceSize > 0) {
118- ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
119- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;);
120- }
121- // 调用aclnnStdMeanCorrection第二段接口
122- ret = aclnnStdMeanCorrection(workspaceAddr, workspaceSize, executor, stream);
123- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnStdMeanCorrection failed. ERROR: %d\n", ret); return ret);
124- // 4.(固定写法)同步等待任务执行结束
125- ret = aclrtSynchronizeStream(stream);
126- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
127- // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
128- auto size = GetShapeSize(stdOutShape);
129- std::vector<float> stdResultData(size, 0);
130- ret = aclrtMemcpy(stdResultData.data(), stdResultData.size() * sizeof(stdResultData[0]), stdOutDeviceAddr, size * sizeof(float),
131- ACL_MEMCPY_DEVICE_TO_HOST);
132- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
133- for (int64_t i = 0; i < size; i++) {
134- LOG_PRINT("stdResultData[%ld] is: %f\n", i, stdResultData[i]);
135- }
136- 
137- std::vector<float> meanResultData(size, 0);
138- ret = aclrtMemcpy(meanResultData.data(), meanResultData.size() * sizeof(meanResultData[0]), meanOutDeviceAddr, size * sizeof(float),
139- ACL_MEMCPY_DEVICE_TO_HOST);
140- CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
141- for (int64_t i = 0; i < size; i++) {
142- LOG_PRINT("meanResultData[%ld] is: %f\n", i, meanResultData[i]);
143- }
144- 
145- // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改
146- aclDestroyTensor(self);
147- aclDestroyTensor(stdOut);
148- aclDestroyTensor(meanOut);
149- 
150- // 7.释放device资源,需要根据具体API的接口定义修改
151- aclrtFree(selfDeviceAddr);
152- aclrtFree(stdOutDeviceAddr);
153- aclrtFree(meanOutDeviceAddr);
154- if (workspaceSize > 0) {
155- aclrtFree(workspaceAddr);
156- }
157- aclrtDestroyStream(stream);
158- aclrtResetDevice(deviceId);
159- aclFinalize();
160- return 0;
161-}
@@ -0,0 +1,165 @@
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+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_batch_norm_stats.h"
15+ 
16+#define CHECK_RET(cond, return_expr) \
17+ do { \
18+ if (!(cond)) { \
19+ return_expr; \
20+ } \
21+ } while (0)
22+ 
23+#define LOG_PRINT(message, ...) \
24+ do { \
25+ printf(message, ##__VA_ARGS__); \
26+ } while (0)
27+ 
28+int64_t GetShapeSize(const std::vector<int64_t>& shape)
29+{
30+ int64_t shapeSize = 1;
31+ for (auto i : shape) {
32+ shapeSize *= i;
33+ }
34+ return shapeSize;
35+}
36+ 
37+int Init(int32_t deviceId, aclrtStream* stream)
38+{
39+ // 固定写法,资源初始化
40+ auto ret = aclInit(nullptr);
41+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
42+ ret = aclrtSetDevice(deviceId);
43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
44+ ret = aclrtCreateStream(stream);
45+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
46+ return 0;
47+}
48+ 
49+template <typename T>
50+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
51+ aclDataType dataType, aclTensor** tensor)
52+{
53+ auto size = GetShapeSize(shape) * sizeof(T);
54+ // 调用aclrtMalloc申请Device侧内存
55+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
56+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
57+ 
58+ // 调用aclrtMemcpy将Host侧数据拷贝到Device侧内存上
59+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
60+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
61+ 
62+ // 计算连续tensor的strides
63+ std::vector<int64_t> strides(shape.size(), 1);
64+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
65+ strides[i] = shape[i + 1] * strides[i + 1];
66+ }
67+ 
68+ // 调用aclCreateTensor接口创建aclTensor
69+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
70+ shape.data(), shape.size(), *deviceAddr);
71+ return 0;
72+}
73+ 
74+int main()
75+{
76+ // 1.(固定写法)device/stream初始化,参考acl API手册
77+ // 根据自己的实际device填写deviceId
78+ int32_t deviceId = 0;
79+ aclrtStream stream;
80+ auto ret = Init(deviceId, &stream);
81+ // check根据自己的需要处理
82+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
83+ 
84+ // 2.构造输入与输出,需要根据API的接口自定义构造
85+ std::vector<int64_t> inputShape = {2, 3};
86+ std::vector<int64_t> outShape = {
87+ 3,
88+ };
89+ void* inputDeviceAddr = nullptr;
90+ void* meanDeviceAddr = nullptr;
91+ void* invstdDeviceAddr = nullptr;
92+ aclTensor* input = nullptr;
93+ aclTensor* mean = nullptr;
94+ aclTensor* invstd = nullptr;
95+ std::vector<float> inputHostData = {1, 2, 3, 4, 5, 6};
96+ std::vector<float> meanHostData = {0, 0, 0};
97+ std::vector<float> invstdHostData = {0, 0, 0};
98+ double eps = 1e-5;
99+ 
100+ // 创建self aclTensor
101+ ret = CreateAclTensor(inputHostData, inputShape, &inputDeviceAddr, aclDataType::ACL_FLOAT, &input);
102+ CHECK_RET(ret == ACL_SUCCESS, return ret);
103+ // 创建mean aclTensor
104+ ret = CreateAclTensor(meanHostData, outShape, &meanDeviceAddr, aclDataType::ACL_FLOAT, &mean);
105+ CHECK_RET(ret == ACL_SUCCESS, return ret);
106+ // 创建invstd aclTensor
107+ ret = CreateAclTensor(invstdHostData, outShape, &invstdDeviceAddr, aclDataType::ACL_FLOAT, &invstd);
108+ CHECK_RET(ret == ACL_SUCCESS, return ret);
109+ 
110+ uint64_t workspaceSize = 0;
111+ aclOpExecutor* executor;
112+ // aclnnBatchNormStats接口调用示例
113+ // 3.调用CANN算子库API,需要修改为具体的API名称
114+ // 调用aclnnBatchNormStats第一段接口
115+ ret = aclnnBatchNormStatsGetWorkspaceSize(input, eps, mean, invstd, &workspaceSize, &executor);
116+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBatchNormStatsGetWorkspaceSize failed. ERROR: %d\n", ret);
117+ return ret);
118+ // 根据第一段接口计算出的workspaceSize申请device内存
119+ void* workspaceAddr = nullptr;
120+ if (workspaceSize > 0) {
121+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
122+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
123+ }
124+ // 调用aclnnBatchNormStats第二段接口
125+ ret = aclnnBatchNormStats(workspaceAddr, workspaceSize, executor, stream);
126+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBatchNormStats failed. ERROR: %d\n", ret); return ret);
127+ 
128+ // 4.(固定写法)同步等待任务执行结束
129+ ret = aclrtSynchronizeStream(stream);
130+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
131+ 
132+ // 5.获取输出的值,将Device侧内存上的结果拷贝至Host侧,需要根据具体API的接口定义修改
133+ auto size = GetShapeSize(outShape);
134+ std::vector<float> meanData(size, 0);
135+ ret = aclrtMemcpy(meanData.data(), meanData.size() * sizeof(meanData[0]), meanDeviceAddr,
136+ size * sizeof(meanData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
137+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
138+ for (int64_t i = 0; i < size; i++) {
139+ LOG_PRINT("mean result[%ld] is: %f\n", i, meanData[i]);
140+ }
141+ std::vector<float> invstdData(size, 0);
142+ ret = aclrtMemcpy(invstdData.data(), invstdData.size() * sizeof(invstdData[0]), invstdDeviceAddr,
143+ size * sizeof(invstdData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
144+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
145+ for (int64_t i = 0; i < size; i++) {
146+ LOG_PRINT("mean result[%ld] is: %f\n", i, invstdData[i]);
147+ }
148+ 
149+ // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改
150+ aclDestroyTensor(input);
151+ aclDestroyTensor(mean);
152+ aclDestroyTensor(invstd);
153+ 
154+ // 7.释放device资源,需要根据具体API的接口定义修改
155+ aclrtFree(inputDeviceAddr);
156+ aclrtFree(meanDeviceAddr);
157+ aclrtFree(invstdDeviceAddr);
158+ if (workspaceSize > 0) {
159+ aclrtFree(workspaceAddr);
160+ }
161+ aclrtDestroyStream(stream);
162+ aclrtResetDevice(deviceId);
163+ aclFinalize();
164+ return 0;
165+}
@@ -0,0 +1,167 @@
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+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_std_mean_correction.h"
15+ 
16+#define CHECK_RET(cond, return_expr) \
17+ do { \
18+ if (!(cond)) { \
19+ return_expr; \
20+ } \
21+ } while (0)
22+ 
23+#define LOG_PRINT(message, ...) \
24+ do { \
25+ printf(message, ##__VA_ARGS__); \
26+ } while (0)
27+ 
28+int64_t GetShapeSize(const std::vector<int64_t>& shape)
29+{
30+ int64_t shape_size = 1;
31+ for (auto i : shape) {
32+ shape_size *= i;
33+ }
34+ return shape_size;
35+}
36+ 
37+int Init(int32_t deviceId, aclrtStream* stream)
38+{
39+ // 固定写法,资源初始化
40+ auto ret = aclInit(nullptr);
41+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
42+ ret = aclrtSetDevice(deviceId);
43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
44+ ret = aclrtCreateStream(stream);
45+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
46+ return 0;
47+}
48+ 
49+template <typename T>
50+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
51+ aclDataType dataType, aclTensor** tensor)
52+{
53+ auto size = GetShapeSize(shape) * sizeof(T);
54+ // 调用aclrtMalloc申请device侧内存
55+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
56+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
57+ 
58+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
59+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
60+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
61+ 
62+ // 计算连续tensor的strides
63+ std::vector<int64_t> strides(shape.size(), 1);
64+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
65+ strides[i] = shape[i + 1] * strides[i + 1];
66+ }
67+ 
68+ // 调用aclCreateTensor接口创建aclTensor
69+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
70+ shape.data(), shape.size(), *deviceAddr);
71+ return 0;
72+}
73+ 
74+int main()
75+{
76+ // 1.(固定写法)device/stream初始化,参考acl API手册
77+ // 根据自己的实际device填写deviceId
78+ int32_t deviceId = 0;
79+ aclrtStream stream;
80+ auto ret = Init(deviceId, &stream);
81+ // check根据自己的需要处理
82+ CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
83+ // 2.构造输入与输出,需要根据API的接口自定义构造
84+ std::vector<int64_t> selfShape = {2, 3, 4};
85+ std::vector<int64_t> stdOutShape = {2, 4};
86+ std::vector<int64_t> meanOutShape = {2, 4};
87+ void* selfDeviceAddr = nullptr;
88+ void* stdOutDeviceAddr = nullptr;
89+ void* meanOutDeviceAddr = nullptr;
90+ aclTensor* self = nullptr;
91+ aclTensor* stdOut = nullptr;
92+ aclTensor* meanOut = nullptr;
93+ std::vector<float> selfHostData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
94+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
95+ std::vector<float> stdOutHostData = {1, 2, 3, 4, 5, 6, 7, 8.0};
96+ std::vector<float> meanOutHostData = {1, 2, 3, 4, 5, 6, 7, 8.0};
97+ std::vector<int64_t> dimData = {1};
98+ int64_t correction = 1;
99+ bool keepdim = false;
100+ // 创建self aclTensor
101+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
102+ CHECK_RET(ret == ACL_SUCCESS, return ret);
103+ // 创建stdOut aclTensor
104+ ret = CreateAclTensor(stdOutHostData, stdOutShape, &stdOutDeviceAddr, aclDataType::ACL_FLOAT, &stdOut);
105+ CHECK_RET(ret == ACL_SUCCESS, return ret);
106+ // 创建meanOut aclTensor
107+ ret = CreateAclTensor(meanOutHostData, meanOutShape, &meanOutDeviceAddr, aclDataType::ACL_FLOAT, &meanOut);
108+ CHECK_RET(ret == ACL_SUCCESS, return ret);
109+ 
110+ const aclIntArray* dim = aclCreateIntArray(dimData.data(), dimData.size());
111+ CHECK_RET(dim != nullptr, return ACL_ERROR_INTERNAL_ERROR);
112+ 
113+ // 3.调用CANN算子库API,需要修改为具体的API
114+ uint64_t workspaceSize = 0;
115+ aclOpExecutor* executor;
116+ // 调用aclnnStdMeanCorrection第一段接口
117+ ret = aclnnStdMeanCorrectionGetWorkspaceSize(self, dim, correction, keepdim, stdOut, meanOut, &workspaceSize,
118+ &executor);
119+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnStdMeanCorrectionGetWorkspaceSize failed. ERROR: %d\n", ret);
120+ return ret);
121+ // 根据第一段接口计算出的workspaceSize申请device内存
122+ void* workspaceAddr = nullptr;
123+ if (workspaceSize > 0) {
124+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
125+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;);
126+ }
127+ // 调用aclnnStdMeanCorrection第二段接口
128+ ret = aclnnStdMeanCorrection(workspaceAddr, workspaceSize, executor, stream);
129+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnStdMeanCorrection failed. ERROR: %d\n", ret); return ret);
130+ // 4.(固定写法)同步等待任务执行结束
131+ ret = aclrtSynchronizeStream(stream);
132+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
133+ // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
134+ auto size = GetShapeSize(stdOutShape);
135+ std::vector<float> stdResultData(size, 0);
136+ ret = aclrtMemcpy(stdResultData.data(), stdResultData.size() * sizeof(stdResultData[0]), stdOutDeviceAddr,
137+ size * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST);
138+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
139+ for (int64_t i = 0; i < size; i++) {
140+ LOG_PRINT("stdResultData[%ld] is: %f\n", i, stdResultData[i]);
141+ }
142+ 
143+ std::vector<float> meanResultData(size, 0);
144+ ret = aclrtMemcpy(meanResultData.data(), meanResultData.size() * sizeof(meanResultData[0]), meanOutDeviceAddr,
145+ size * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST);
146+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
147+ for (int64_t i = 0; i < size; i++) {
148+ LOG_PRINT("meanResultData[%ld] is: %f\n", i, meanResultData[i]);
149+ }
150+ 
151+ // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改
152+ aclDestroyTensor(self);
153+ aclDestroyTensor(stdOut);
154+ aclDestroyTensor(meanOut);
155+ 
156+ // 7.释放device资源,需要根据具体API的接口定义修改
157+ aclrtFree(selfDeviceAddr);
158+ aclrtFree(stdOutDeviceAddr);
159+ aclrtFree(meanOutDeviceAddr);
160+ if (workspaceSize > 0) {
161+ aclrtFree(workspaceAddr);
162+ }
163+ aclrtDestroyStream(stream);
164+ aclrtResetDevice(deviceId);
165+ aclFinalize();
166+ return 0;
167+}
@@ -92,4 +92,6 @@
92 92 
93| 调用方式 | 调用样例 | 说明 |93| 调用方式 | 调用样例 | 说明 |
94|--------|-------------------------------------------------------------------|------------------------------------------------------------------------|94|--------|-------------------------------------------------------------------|------------------------------------------------------------------------|
95+| aclnn调用 | [test_aclnn_search_sorted](./examples/test_aclnn_search_sorted.cpp) | 通过[aclnnSearchSorted](./docs/aclnnSearchSorted.md)接口方式调用SearchSorted算子。 |
96+| aclnn调用 | [test_aclnn_search_sorteds](./examples/test_aclnn_search_sorteds.cpp) | 通过[aclnnSearchSorteds](./docs/aclnnSearchSorteds.md)接口方式调用SearchSorted算子。 |
95| 图模式调用 | [test_geir_search_sorted](./examples/test_geir_search_sorted.cpp) | 通过[算子IR](./op_graph/search_sorted_proto.h)构图方式调用SearchSorted算子。 |97| 图模式调用 | [test_geir_search_sorted](./examples/test_geir_search_sorted.cpp) | 通过[算子IR](./op_graph/search_sorted_proto.h)构图方式调用SearchSorted算子。 |
@@ -0,0 +1,165 @@
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+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_searchsorted.h"
15+ 
16+#define CHECK_RET(cond, return_expr) \
17+ do { \
18+ if (!(cond)) { \
19+ return_expr; \
20+ } \
21+ } while (0)
22+ 
23+#define LOG_PRINT(message, ...) \
24+ do { \
25+ printf(message, ##__VA_ARGS__); \
26+ } while (0)
27+ 
28+int64_t GetShapeSize(const std::vector<int64_t>& shape)
29+{
30+ int64_t shape_size = 1;
31+ for (auto i : shape) {
32+ shape_size *= i;
33+ }
34+ return shape_size;
35+}
36+ 
37+int Init(int32_t deviceId, aclrtStream* stream)
38+{
39+ // 固定写法,资源初始化
40+ auto ret = aclInit(nullptr);
41+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
42+ ret = aclrtSetDevice(deviceId);
43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
44+ ret = aclrtCreateStream(stream);
45+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
46+ return 0;
47+}
48+ 
49+template <typename T>
50+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
51+ aclDataType dataType, aclTensor** tensor)
52+{
53+ auto size = GetShapeSize(shape) * sizeof(T);
54+ // 调用aclrtMalloc申请device侧内存
55+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
56+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
57+ 
58+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
59+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
60+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
61+ 
62+ // 计算连续tensor的strides
63+ std::vector<int64_t> strides(shape.size(), 1);
64+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
65+ strides[i] = shape[i + 1] * strides[i + 1];
66+ }
67+ 
68+ // 调用aclCreateTensor接口创建aclTensor
69+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
70+ shape.data(), shape.size(), *deviceAddr);
71+ return 0;
72+}
73+ 
74+int main()
75+{
76+ // 1.(固定写法)device/stream初始化,参考acl API手册
77+ // 根据自己的实际device填写deviceId
78+ int32_t deviceId = 0;
79+ aclrtStream stream;
80+ auto ret = Init(deviceId, &stream);
81+ // check根据自己的需要处理
82+ CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
83+ 
84+ // 2.构造输入与输出,需要根据API的接口自定义构造
85+ std::vector<int64_t> selfShape = {4, 2};
86+ std::vector<int64_t> sortedSequenceShape = {4, 4};
87+ std::vector<int64_t> sorterShape = {4, 4};
88+ std::vector<int64_t> outShape = {4, 2};
89+ void* selfDeviceAddr = nullptr;
90+ void* sortedSequenceDeviceAddr = nullptr;
91+ void* sorterDeviceAddr = nullptr;
92+ void* outDeviceAddr = nullptr;
93+ aclTensor* self = nullptr;
94+ aclTensor* sortedSequence = nullptr;
95+ aclTensor* sorter = nullptr;
96+ aclTensor* out = nullptr;
97+ std::vector<float> selfHostData = {1, 3, 6, 8, 10, 11, 14, 16};
98+ std::vector<float> sortedSequenceHostData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
99+ std::vector<int64_t> sorterHostData = {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3};
100+ std::vector<int64_t> outHostData = {0, 0, 0, 0, 0, 0, 0, 0};
101+ 
102+ // 创建self aclTensor
103+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
104+ CHECK_RET(ret == ACL_SUCCESS, return ret);
105+ // 创建sortedSequence aclTensor
106+ ret = CreateAclTensor(sortedSequenceHostData, sortedSequenceShape, &sortedSequenceDeviceAddr,
107+ aclDataType::ACL_FLOAT, &sortedSequence);
108+ CHECK_RET(ret == ACL_SUCCESS, return ret);
109+ // 创建sorter aclTensor
110+ ret = CreateAclTensor(sorterHostData, sorterShape, &sorterDeviceAddr, aclDataType::ACL_INT64, &sorter);
111+ CHECK_RET(ret == ACL_SUCCESS, return ret);
112+ // 创建out aclTensor
113+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_INT64, &out);
114+ CHECK_RET(ret == ACL_SUCCESS, return ret);
115+ bool outInt32 = false;
116+ bool right = false;
117+ // 3.调用CANN算子库API,需要修改为具体的API
118+ uint64_t workspaceSize = 0;
119+ aclOpExecutor* executor;
120+ // 调用aclnnSearchSorted第一段接口
121+ ret = aclnnSearchSortedGetWorkspaceSize(sortedSequence, self, outInt32, right, sorter, out, &workspaceSize,
122+ &executor);
123+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSearchSortedGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
124+ // 根据第一段接口计算出的workspaceSize申请device内存
125+ void* workspaceAddr = nullptr;
126+ if (workspaceSize > 0) {
127+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
128+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;);
129+ }
130+ // 调用aclnnSearchSorted第二段接口
131+ ret = aclnnSearchSorted(workspaceAddr, workspaceSize, executor, stream);
132+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSearchSorted failed. ERROR: %d\n", ret); return ret);
133+ // 4.(固定写法)同步等待任务执行结束
134+ ret = aclrtSynchronizeStream(stream);
135+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
136+ // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
137+ auto size = GetShapeSize(outShape);
138+ std::vector<int64_t> resultData(size, 0);
139+ ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
140+ size * sizeof(int64_t), ACL_MEMCPY_DEVICE_TO_HOST);
141+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
142+ for (int64_t i = 0; i < size; i++) {
143+ LOG_PRINT("result[%ld] is: %ld\n", i, resultData[i]);
144+ }
145+ 
146+ // 6.释放aclTensor,需要根据具体API的接口定义修改
147+ aclDestroyTensor(self);
148+ aclDestroyTensor(sortedSequence);
149+ aclDestroyTensor(sorter);
150+ aclDestroyTensor(out);
151+ 
152+ // 7.释放device资源,需要根据具体API的接口定义修改
153+ aclrtFree(selfDeviceAddr);
154+ aclrtFree(sortedSequenceDeviceAddr);
155+ aclrtFree(sorterDeviceAddr);
156+ aclrtFree(outDeviceAddr);
157+ if (workspaceSize > 0) {
158+ aclrtFree(workspaceAddr);
159+ }
160+ aclrtDestroyStream(stream);
161+ aclrtResetDevice(deviceId);
162+ aclFinalize();
163+ 
164+ return 0;
165+}
@@ -0,0 +1,159 @@
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+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_searchsorted.h"
15+ 
16+#define CHECK_RET(cond, return_expr) \
17+ do { \
18+ if (!(cond)) { \
19+ return_expr; \
20+ } \
21+ } while (0)
22+ 
23+#define LOG_PRINT(message, ...) \
24+ do { \
25+ printf(message, ##__VA_ARGS__); \
26+ } while (0)
27+ 
28+int64_t GetShapeSize(const std::vector<int64_t>& shape)
29+{
30+ int64_t shape_size = 1;
31+ for (auto i : shape) {
32+ shape_size *= i;
33+ }
34+ return shape_size;
35+}
36+ 
37+int Init(int32_t deviceId, aclrtStream* stream)
38+{
39+ // 固定写法,资源初始化
40+ auto ret = aclInit(nullptr);
41+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
42+ ret = aclrtSetDevice(deviceId);
43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
44+ ret = aclrtCreateStream(stream);
45+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
46+ return 0;
47+}
48+ 
49+template <typename T>
50+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
51+ aclDataType dataType, aclTensor** tensor)
52+{
53+ auto size = GetShapeSize(shape) * sizeof(T);
54+ // 调用aclrtMalloc申请device侧内存
55+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
56+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
57+ 
58+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
59+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
60+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
61+ 
62+ // 计算连续tensor的strides
63+ std::vector<int64_t> strides(shape.size(), 1);
64+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
65+ strides[i] = shape[i + 1] * strides[i + 1];
66+ }
67+ 
68+ // 调用aclCreateTensor接口创建aclTensor
69+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
70+ shape.data(), shape.size(), *deviceAddr);
71+ return 0;
72+}
73+ 
74+int main()
75+{
76+ // 1.(固定写法)device/stream初始化,参考acl API手册
77+ // 根据自己的实际device填写deviceId
78+ int32_t deviceId = 0;
79+ aclrtStream stream;
80+ auto ret = Init(deviceId, &stream);
81+ // check根据自己的需要处理
82+ CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
83+ 
84+ // 2.构造输入与输出,需要根据API的接口自定义构造
85+ std::vector<int64_t> sortedSequenceShape = {4};
86+ std::vector<int64_t> sorterShape = {4};
87+ std::vector<int64_t> outShape = {1};
88+ void* sortedSequenceDeviceAddr = nullptr;
89+ void* sorterDeviceAddr = nullptr;
90+ void* outDeviceAddr = nullptr;
91+ aclTensor* sortedSequence = nullptr;
92+ aclTensor* sorter = nullptr;
93+ aclTensor* out = nullptr;
94+ std::vector<float> sortedSequenceHostData = {1, 3, 6, 8};
95+ std::vector<int64_t> sorterHostData = {0, 1, 2, 3};
96+ std::vector<int64_t> outHostData = {0};
97+ 
98+ // 创建sortedSequence aclTensor
99+ ret = CreateAclTensor(sortedSequenceHostData, sortedSequenceShape, &sortedSequenceDeviceAddr,
100+ aclDataType::ACL_FLOAT, &sortedSequence);
101+ CHECK_RET(ret == ACL_SUCCESS, return ret);
102+ // 创建sorter aclTensor
103+ ret = CreateAclTensor(sorterHostData, sorterShape, &sorterDeviceAddr, aclDataType::ACL_INT64, &sorter);
104+ CHECK_RET(ret == ACL_SUCCESS, return ret);
105+ // 创建out aclTensor
106+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_INT64, &out);
107+ CHECK_RET(ret == ACL_SUCCESS, return ret);
108+ float value = 5;
109+ auto self = aclCreateScalar(&value, aclDataType::ACL_FLOAT);
110+ CHECK_RET(self != nullptr, LOG_PRINT("aclCreateScalar failed.\n"); return -1);
111+ bool outInt32 = false;
112+ bool right = false;
113+ // 3.调用CANN算子库API,需要修改为具体的API
114+ uint64_t workspaceSize = 0;
115+ aclOpExecutor* executor;
116+ // 调用aclnnSearchSorteds第一段接口
117+ ret = aclnnSearchSortedsGetWorkspaceSize(sortedSequence, self, outInt32, right, sorter, out, &workspaceSize,
118+ &executor);
119+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSearchSortedsGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
120+ // 根据第一段接口计算出的workspaceSize申请device内存
121+ void* workspaceAddr = nullptr;
122+ if (workspaceSize > 0) {
123+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
124+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;);
125+ }
126+ // 调用aclnnSearchSorteds第二段接口
127+ ret = aclnnSearchSorteds(workspaceAddr, workspaceSize, executor, stream);
128+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSearchSorteds failed. ERROR: %d\n", ret); return ret);
129+ // 4.(固定写法)同步等待任务执行结束
130+ ret = aclrtSynchronizeStream(stream);
131+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
132+ // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
133+ auto size = GetShapeSize(outShape);
134+ std::vector<int64_t> resultData(size, 0);
135+ ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
136+ size * sizeof(int64_t), ACL_MEMCPY_DEVICE_TO_HOST);
137+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
138+ for (int64_t i = 0; i < size; i++) {
139+ LOG_PRINT("result[%ld] is: %ld\n", i, resultData[i]);
140+ }
141+ 
142+ // 6.释放aclTensor,需要根据具体API的接口定义修改
143+ aclDestroyScalar(self);
144+ aclDestroyTensor(sortedSequence);
145+ aclDestroyTensor(sorter);
146+ aclDestroyTensor(out);
147+ 
148+ // 7.释放device资源,需要根据具体API的接口定义修改
149+ aclrtFree(sortedSequenceDeviceAddr);
150+ aclrtFree(sorterDeviceAddr);
151+ aclrtFree(outDeviceAddr);
152+ if (workspaceSize > 0) {
153+ aclrtFree(workspaceAddr);
154+ }
155+ aclrtDestroyStream(stream);
156+ aclrtResetDevice(deviceId);
157+ aclFinalize();
158+ return 0;
159+}
@@ -1,3 +1,9 @@
1# SilentCheck1# SilentCheck
2 2 
3本目录仅包含SilentCheck算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。3本目录仅包含SilentCheck算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。
4+ 
5+## 调用说明
6+ 
7+| 调用方式 | 调用样例 | 说明 |
8+|---------|---------|------|
9+| aclnn调用 | [test_aclnn_silent_check](./examples/test_aclnn_silent_check.cpp) | 通过[aclnnSilentCheck](./docs/aclnnSilentCheck.md)接口方式调用SilentCheck算子。 |
@@ -0,0 +1,185 @@
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+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_silent_check.h"
15+ 
16+#define CHECK_RET(cond, return_expr) \
17+ do { \
18+ if (!(cond)) { \
19+ return_expr; \
20+ } \
21+ } while (0)
22+ 
23+#define LOG_PRINT(message, ...) \
24+ do { \
25+ printf(message, ##__VA_ARGS__); \
26+ } while (0)
27+ 
28+int64_t GetShapeSize(const std::vector<int64_t>& shape)
29+{
30+ int64_t shapeSize = 1;
31+ for (auto i : shape) {
32+ shapeSize *= i;
33+ }
34+ return shapeSize;
35+}
36+ 
37+void PrintOutResult(std::vector<int64_t>& shape, void** deviceAddr)
38+{
39+ auto size = GetShapeSize(shape);
40+ std::vector<int32_t> resultData(size, 0);
41+ auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), *deviceAddr,
42+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return);
44+ for (int64_t i = 0; i < size; i++) {
45+ LOG_PRINT("result[%ld] is: %d\n", i, resultData[i]);
46+ }
47+}
48+ 
49+int Init(int32_t deviceId, aclrtStream* stream)
50+{
51+ // 固定写法,acl初始化
52+ auto ret = aclInit(nullptr);
53+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
54+ ret = aclrtSetDevice(deviceId);
55+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
56+ ret = aclrtCreateStream(stream);
57+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
58+ return 0;
59+}
60+ 
61+template <typename T>
62+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
63+ aclDataType dataType, aclTensor** tensor)
64+{
65+ auto size = GetShapeSize(shape) * sizeof(T);
66+ // 调用aclrtMalloc申请device侧内存
67+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
68+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
69+ 
70+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
71+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
72+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
73+ 
74+ // 计算连续tensor的strides
75+ std::vector<int64_t> strides(shape.size(), 1);
76+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
77+ strides[i] = shape[i + 1] * strides[i + 1];
78+ }
79+ 
80+ // 调用aclCreateTensor接口创建aclTensor
81+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
82+ shape.data(), shape.size(), *deviceAddr);
83+ return 0;
84+}
85+ 
86+int main()
87+{
88+ // 1.(固定写法)device/stream初始化,参考acl对外接口列表
89+ // 根据自己的实际device填写deviceId
90+ int32_t deviceId = 0;
91+ aclrtStream stream;
92+ auto ret = Init(deviceId, &stream);
93+ // check根据自己的需要处理
94+ CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
95+ // 2.构造输入与输出,需要根据API的接口自定义构造
96+ std::vector<int64_t> valShape = {};
97+ std::vector<int64_t> inputGradShape = {4, 2};
98+ std::vector<int64_t> sfdaShape = {3};
99+ std::vector<int64_t> stepShape = {1};
100+ std::vector<int64_t> resultShape = {1};
101+ void* valDeviceAddr = nullptr;
102+ void* inputGradDeviceAddr = nullptr;
103+ void* sfdaDeviceAddr = nullptr;
104+ void* stepDeviceAddr = nullptr;
105+ void* resultDeviceAddr = nullptr;
106+ aclTensor* val = nullptr;
107+ aclTensor* inputGrad = nullptr;
108+ aclTensor* sfda = nullptr;
109+ aclTensor* step = nullptr;
110+ aclTensor* result = nullptr;
111+ std::vector<float> valHostData = {160.0};
112+ std::vector<float> inputGradHostData = {0, 1, 2, 3, 4, 5, 6, 7};
113+ std::vector<float> sfdaHostData = {70.0, 200.0, 400.0};
114+ std::vector<int64_t> stepHostData = {7};
115+ std::vector<int32_t> resultHostData = {0};
116+ int32_t c_min_steps = 7;
117+ float c_thresh_l1 = 1000000;
118+ float c_coeff_l1 = 100000;
119+ float c_thresh_l2 = 10000;
120+ float c_coeff_l2 = 5000;
121+ int32_t npu_asd_detect = 3;
122+ 
123+ // 创建val aclTensor
124+ ret = CreateAclTensor(valHostData, valShape, &valDeviceAddr, aclDataType::ACL_FLOAT, &val);
125+ CHECK_RET(ret == ACL_SUCCESS, return ret);
126+ // 创建input_grad aclTensor
127+ ret = CreateAclTensor(inputGradHostData, inputGradShape, &inputGradDeviceAddr, aclDataType::ACL_FLOAT, &inputGrad);
128+ CHECK_RET(ret == ACL_SUCCESS, return ret);
129+ // 创建sfda aclTensor
130+ ret = CreateAclTensor(sfdaHostData, sfdaShape, &sfdaDeviceAddr, aclDataType::ACL_FLOAT, &sfda);
131+ CHECK_RET(ret == ACL_SUCCESS, return ret);
132+ // 创建step aclTensor
133+ ret = CreateAclTensor(stepHostData, stepShape, &stepDeviceAddr, aclDataType::ACL_INT64, &step);
134+ CHECK_RET(ret == ACL_SUCCESS, return ret);
135+ // 创建result aclTensor
136+ ret = CreateAclTensor(resultHostData, resultShape, &resultDeviceAddr, aclDataType::ACL_INT32, &result);
137+ if (result == nullptr) {
138+ std::cout << "result is nullptr!" << std::endl;
139+ return 0;
140+ }
141+ CHECK_RET(ret == ACL_SUCCESS, return ret);
142+ 
143+ // 3.调用CANN算子库API,需要修改为具体的HostApi
144+ uint64_t workspaceSize = 0;
145+ aclOpExecutor* executor;
146+ // 调用aclnnSilentCheck第一段接口
147+ ret = aclnnSilentCheckGetWorkspaceSize(val, inputGrad, sfda, step, c_min_steps, c_thresh_l1, c_coeff_l1,
148+ c_thresh_l2, c_coeff_l2, npu_asd_detect, result, &workspaceSize, &executor);
149+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSilentCheckGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
150+ // 根据第一段接口计算出的workspaceSize申请device内存
151+ void* workspaceAddr = nullptr;
152+ if (workspaceSize > 0) {
153+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
154+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
155+ }
156+ // 调用aclnnSilentCheck第二段接口
157+ ret = aclnnSilentCheck(workspaceAddr, workspaceSize, executor, stream);
158+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSilentCheck failed. ERROR: %d\n", ret); return ret);
159+ // 4.(固定写法)同步等待任务执行结束
160+ ret = aclrtSynchronizeStream(stream);
161+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
162+ // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
163+ PrintOutResult(resultShape, &resultDeviceAddr);
164+ 
165+ // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改
166+ aclDestroyTensor(val);
167+ aclDestroyTensor(inputGrad);
168+ aclDestroyTensor(sfda);
169+ aclDestroyTensor(step);
170+ aclDestroyTensor(result);
171+ 
172+ // 7.释放device资源,需要根据具体API的接口定义修改
173+ aclrtFree(valDeviceAddr);
174+ aclrtFree(inputGradDeviceAddr);
175+ aclrtFree(sfdaDeviceAddr);
176+ aclrtFree(stepDeviceAddr);
177+ aclrtFree(resultDeviceAddr);
178+ if (workspaceSize > 0) {
179+ aclrtFree(workspaceAddr);
180+ }
181+ aclrtDestroyStream(stream);
182+ aclrtResetDevice(deviceId);
183+ aclFinalize();
184+ return 0;
185+}
@@ -1,3 +1,9 @@
1# SilentCheckV21# SilentCheckV2
2 2 
3本目录仅包含SilentCheckV2算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。3本目录仅包含SilentCheckV2算子对应的aclnn接口;如您想要贡献该算子的AscendC实现,请参考[贡献流程](../../CONTRIBUTING.md)。
4+ 
5+## 调用说明
6+ 
7+| 调用方式 | 调用样例 | 说明 |
8+|---------|---------|------|
9+| aclnn调用 | [test_aclnn_silent_check_v2](./examples/test_aclnn_silent_check_v2.cpp) | 通过[aclnnSilentCheckV2](./docs/aclnnSilentCheckV2.md)接口方式调用SilentCheckV2算子。 |
@@ -0,0 +1,203 @@
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+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_silent_check_v2.h"
15+ 
16+#define CHECK_RET(cond, return_expr) \
17+ do { \
18+ if (!(cond)) { \
19+ return_expr; \
20+ } \
21+ } while (0)
22+ 
23+#define LOG_PRINT(message, ...) \
24+ do { \
25+ printf(message, ##__VA_ARGS__); \
26+ } while (0)
27+ 
28+int64_t GetShapeSize(const std::vector<int64_t>& shape)
29+{
30+ int64_t shapeSize = 1;
31+ for (auto i : shape) {
32+ shapeSize *= i;
33+ }
34+ return shapeSize;
35+}
36+ 
37+void PrintOutResult(std::vector<int64_t>& shape, void** deviceAddr)
38+{
39+ auto size = GetShapeSize(shape);
40+ std::vector<int32_t> resultData(size, 0);
41+ auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), *deviceAddr,
42+ size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return);
44+ for (int64_t i = 0; i < size; i++) {
45+ LOG_PRINT("result[%ld] is: %d\n", i, resultData[i]);
46+ }
47+}
48+ 
49+int Init(int32_t deviceId, aclrtStream* stream)
50+{
51+ // 固定写法,acl初始化
52+ auto ret = aclInit(nullptr);
53+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
54+ ret = aclrtSetDevice(deviceId);
55+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
56+ ret = aclrtCreateStream(stream);
57+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
58+ return 0;
59+}
60+ 
61+template <typename T>
62+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
63+ aclDataType dataType, aclTensor** tensor)
64+{
65+ auto size = GetShapeSize(shape) * sizeof(T);
66+ // 调用aclrtMalloc申请device侧内存
67+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
68+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
69+ 
70+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
71+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
72+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
73+ 
74+ // 计算连续tensor的strides
75+ std::vector<int64_t> strides(shape.size(), 1);
76+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
77+ strides[i] = shape[i + 1] * strides[i + 1];
78+ }
79+ 
80+ // 调用aclCreateTensor接口创建aclTensor
81+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
82+ shape.data(), shape.size(), *deviceAddr);
83+ return 0;
84+}
85+ 
86+int main()
87+{
88+ // 1.(固定写法)device/stream初始化,参考acl对外接口列表
89+ // 根据自己的实际device填写deviceId
90+ int32_t deviceId = 0;
91+ aclrtStream stream;
92+ auto ret = Init(deviceId, &stream);
93+ // check根据自己的需要处理
94+ CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
95+ // 2.构造输入与输出,需要根据API的接口自定义构造
96+ std::vector<int64_t> valShape = {1};
97+ std::vector<int64_t> maxShape = {1};
98+ std::vector<int64_t> avgRefShape = {1};
99+ std::vector<int64_t> inputGradRefShape = {2, 3};
100+ std::vector<int64_t> stepRefShape = {1};
101+ std::vector<int64_t> resultShape = {1};
102+ void* valDeviceAddr = nullptr;
103+ void* maxDeviceAddr = nullptr;
104+ void* avgRefDeviceAddr = nullptr;
105+ void* inputGradRefDeviceAddr = nullptr;
106+ void* stepRefDeviceAddr = nullptr;
107+ void* resultDeviceAddr = nullptr;
108+ aclTensor* val = nullptr;
109+ aclTensor* max = nullptr;
110+ aclTensor* avgRef = nullptr;
111+ aclTensor* inputGradRef = nullptr;
112+ aclTensor* stepRef = nullptr;
113+ aclTensor* result = nullptr;
114+ std::vector<float> valHostData = {160.0};
115+ std::vector<float> maxHostData = {400.0};
116+ std::vector<float> avgRefHostData = {200.0};
117+ std::vector<float> inputGradRefHostData = {0, 1, 2, 3, 4, 5};
118+ std::vector<int64_t> stepRefHostData = {0};
119+ std::vector<int64_t> dstSizeData = {2, 3};
120+ std::vector<int64_t> dstStrideData = {3, 1};
121+ std::vector<int64_t> dstOffsetData = {0};
122+ std::vector<int32_t> resultHostData = {0};
123+ aclIntArray* dstSize = aclCreateIntArray(dstSizeData.data(), 2);
124+ aclIntArray* dstStride = aclCreateIntArray(dstStrideData.data(), 2);
125+ aclIntArray* dstOffset = aclCreateIntArray(dstOffsetData.data(), 1);
126+ float cThreshL1 = 1000000;
127+ float cThreshL2 = 10000;
128+ float beta1 = 0.99;
129+ int32_t npuAsdDetect = 3;
130+ 
131+ // 创建val aclTensor
132+ ret = CreateAclTensor(valHostData, valShape, &valDeviceAddr, aclDataType::ACL_FLOAT, &val);
133+ CHECK_RET(ret == ACL_SUCCESS, return ret);
134+ // 创建max aclTensor
135+ ret = CreateAclTensor(maxHostData, maxShape, &maxDeviceAddr, aclDataType::ACL_FLOAT, &max);
136+ CHECK_RET(ret == ACL_SUCCESS, return ret);
137+ // 创建avgRef aclTensor
138+ ret = CreateAclTensor(avgRefHostData, avgRefShape, &avgRefDeviceAddr, aclDataType::ACL_FLOAT, &avgRef);
139+ CHECK_RET(ret == ACL_SUCCESS, return ret);
140+ // 创建inputGradRef aclTensor
141+ ret = CreateAclTensor(inputGradRefHostData, inputGradRefShape, &inputGradRefDeviceAddr, aclDataType::ACL_FLOAT,
142+ &inputGradRef);
143+ CHECK_RET(ret == ACL_SUCCESS, return ret);
144+ // 创建stepRef aclTensor
145+ ret = CreateAclTensor(stepRefHostData, stepRefShape, &stepRefDeviceAddr, aclDataType::ACL_INT64, &stepRef);
146+ CHECK_RET(ret == ACL_SUCCESS, return ret);
147+ // 创建result aclTensor
148+ ret = CreateAclTensor(resultHostData, resultShape, &resultDeviceAddr, aclDataType::ACL_INT32, &result);
149+ if (result == nullptr) {
150+ std::cout << "result is nullptr!" << std::endl;
151+ return 0;
152+ }
153+ CHECK_RET(ret == ACL_SUCCESS, return ret);
154+ 
155+ // 3.调用CANN算子库API,需要修改为具体的HostApi
156+ uint64_t workspaceSize = 0;
157+ aclOpExecutor* executor;
158+ // 调用aclnnSilentCheckV2第一段接口
159+ ret = aclnnSilentCheckV2GetWorkspaceSize(val, max, avgRef, inputGradRef, stepRef, dstSize, dstStride, dstOffset,
160+ cThreshL1, cThreshL2, beta1, npuAsdDetect, result, &workspaceSize,
161+ &executor);
162+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSilentCheckV2GetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
163+ // 根据第一段接口计算出的workspaceSize申请device内存
164+ void* workspaceAddr = nullptr;
165+ if (workspaceSize > 0) {
166+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
167+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
168+ }
169+ // 调用aclnnSilentCheckV2第二段接口
170+ ret = aclnnSilentCheckV2(workspaceAddr, workspaceSize, executor, stream);
171+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnSilentCheckV2 failed. ERROR: %d\n", ret); return ret);
172+ // 4.(固定写法)同步等待任务执行结束
173+ ret = aclrtSynchronizeStream(stream);
174+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
175+ // 5.获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
176+ PrintOutResult(resultShape, &resultDeviceAddr);
177+ 
178+ // 6.释放aclTensor和aclScalar,需要根据具体API的接口定义修改
179+ aclDestroyTensor(val);
180+ aclDestroyTensor(max);
181+ aclDestroyTensor(avgRef);
182+ aclDestroyTensor(inputGradRef);
183+ aclDestroyTensor(stepRef);
184+ aclDestroyIntArray(dstSize);
185+ aclDestroyIntArray(dstStride);
186+ aclDestroyIntArray(dstOffset);
187+ aclDestroyTensor(result);
188+ 
189+ // 7.释放device资源,需要根据具体API的接口定义修改
190+ aclrtFree(valDeviceAddr);
191+ aclrtFree(maxDeviceAddr);
192+ aclrtFree(avgRefDeviceAddr);
193+ aclrtFree(inputGradRefDeviceAddr);
194+ aclrtFree(stepRefDeviceAddr);
195+ aclrtFree(resultDeviceAddr);
196+ if (workspaceSize > 0) {
197+ aclrtFree(workspaceAddr);
198+ }
199+ aclrtDestroyStream(stream);
200+ aclrtResetDevice(deviceId);
201+ aclFinalize();
202+ return 0;
203+}