已合并
贡献Ascend C实现的Equal算子 #2890
fulltower创建于 5月21日
贡献Ascend C实现的Equal算子 #2890
已合并
共 25 个文件变更+4711-16
| @@ -1,18 +1,18 @@ | |||
| 1 | repos: | 1 | repos: |
| 2 | - - repo: https://github.com/pre-commit/mirrors-clang-format | 2 | + - repo: https://github.com/pre-commit/mirrors-clang-format |
| 3 | - rev: v16.0.0 | 3 | + rev: v16.0.0 |
| 4 | - hooks: | 4 | + hooks: |
| 5 | - - id: clang-format | 5 | + - id: clang-format |
| 6 | - types_or: [c++, c] | 6 | + types_or: [c++, c] |
| 7 | 7 | ||
| 8 | - # OAT compliance check (Open Source Audit Tool) | 8 | + # OAT compliance check (Open Source Audit Tool) |
| 9 | - - repo: local | 9 | + - repo: local |
| 10 | - hooks: | 10 | + hooks: |
| 11 | - - id: oat-check | 11 | + - id: oat-check |
| 12 | - name: OAT Compliance Check | 12 | + name: OAT Compliance Check |
| 13 | - entry: bash scripts/oat_check.sh | 13 | + entry: bash scripts/oat_check.sh |
| 14 | - language: system | 14 | + language: system |
| 15 | - pass_filenames: true | 15 | + pass_filenames: true |
| 16 | - types: [file] | 16 | + types: [file] |
| 17 | - stages: [commit] | 17 | + stages: [commit] |
| 18 | - verbose: true | 18 | + verbose: true |
| @@ -0,0 +1,11 @@ | |||
| 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 | +add_all_modules_sources(OPTYPE equal ACLNNTYPE aclnn_exclude) | ||
| @@ -0,0 +1,43 @@ | |||
| 1 | +# Equal | ||
| 2 | + | ||
| 3 | +## 贡献说明 | ||
| 4 | + | ||
| 5 | +| 贡献者 | 贡献方 | 贡献算子 | 贡献时间 | 贡献内容 | | ||
| 6 | +|-------|------------------|-------|-----------|-----------| | ||
| 7 | +| skywang2 | 个人开发者 | Equal | 2026/6/21 | 新增Equal算子 | | ||
| 8 | + | ||
| 9 | +## 支持的产品型号 | ||
| 10 | +- Atlas A2训练系列产品 | ||
| 11 | + | ||
| 12 | +产品形态详细说明请参见[昇腾产品形态说明](http://www.hiascend.com/document/redirect/CannCommunityProductForm) | ||
| 13 | + | ||
| 14 | +## 算子描述 | ||
| 15 | + | ||
| 16 | +- 功能描述 | ||
| 17 | + | ||
| 18 | + `Equal`算子将输入的两个向量数据进行各对应位置的判等运算,返回结果向量。 | ||
| 19 | + | ||
| 20 | +- 原型信息 | ||
| 21 | + | ||
| 22 | + <table> | ||
| 23 | + <tr><th align="center">算子类型(OpType)</th><th colspan="4" align="center">Equal</th></tr> | ||
| 24 | + <tr><td align="center"> </td><td align="center">name</td><td align="center">Type</td><td align="center">data type</td><td align="center">format</td></tr> | ||
| 25 | + <tr><td rowspan="2" align="center">算子输入</td><td align="center">x1</td><td align="center">tensor</td><td align="center">float32,float16,bfloat16,uint8,int8,uint32,int32</td><td align="center">ND</td></tr> | ||
| 26 | + <tr><td align="center">x2</td><td align="center">tensor</td><td align="center">float32,float16,bfloat16,uint8,int8,uint32,int32</td><td align="center">ND</td></tr> | ||
| 27 | + <tr><td align="center">算子输出</td><td align="center">y</td><td align="center">tensor</td><td align="center">bool</td><td align="center">ND</td></tr> | ||
| 28 | + <tr><td align="center">核函数名</td><td colspan="4" align="center">equal</td></tr> | ||
| 29 | + </table> | ||
| 30 | + | ||
| 31 | +## 约束与限制 | ||
| 32 | + | ||
| 33 | +- x,y,out的数据类型仅支持float32,float16,bfloat16,uint8,int8,uint32,int32,数据格式仅支持ND | ||
| 34 | + | ||
| 35 | +### 运行验证 | ||
| 36 | + | ||
| 37 | +测试命令调用方式:[build.sh](../../../docs/zh/invocation/quick_op_invocation.md) | ||
| 38 | +<table> | ||
| 39 | + <tr><th>目录</th><th>描述</th></tr> | ||
| 40 | + <tr> | ||
| 41 | + <td><a href="./examples/test_aclnn_equal.cpp">test_aclnn_equal.cpp</a></td><td>通过aclnn调用的方式调用Equal算子。</td> | ||
| 42 | + </tr> | ||
| 43 | +</table> | ||
| @@ -0,0 +1,758 @@ | |||
| 1 | +# aclnnEqScalar&aclnnInplaceEqScalar | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +## 产品支持情况 | ||
| 5 | + | ||
| 6 | +| 产品 | 是否支持 | | ||
| 7 | +| :----------------------------------------------------------- | :------: | | ||
| 8 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | ||
| 9 | + | ||
| 10 | +## 功能说明 | ||
| 11 | + | ||
| 12 | +- 接口功能:计算self中的元素的值与other的值是否相等,将self每个元素与other的值的比较结果写入out中。 | ||
| 13 | +- 计算公式: | ||
| 14 | + | ||
| 15 | + $$ | ||
| 16 | + out_i = (self_i == \mathit{other} ) ? [True] : [False] | ||
| 17 | + $$ | ||
| 18 | + | ||
| 19 | +## 函数原型 | ||
| 20 | + | ||
| 21 | +- aclnnEqScalar和aclnnInplaceEqScalar实现相同的功能,使用区别如下,请根据自身实际场景选择合适的算子。 | ||
| 22 | + | ||
| 23 | + - aclnnEqScalar:需新建一个输出张量对象存储计算结果。 | ||
| 24 | + - aclnnInplaceEqScalar:无需新建输出张量对象,直接在输入张量的内存中存储计算结果。 | ||
| 25 | + | ||
| 26 | +- 每个算子分为[两段式接口](../../../../docs/zh/context/两段式接口.md),必须先调用“aclnnEqScalarGetWorkspaceSize”或者“aclnnInplaceEqScalarGetWorkspaceSize”接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用“aclnnEqScalar”或者“aclnnInplaceEqScalar”接口执行计算。 | ||
| 27 | + | ||
| 28 | +```Cpp | ||
| 29 | +aclnnStatus aclnnEqScalarGetWorkspaceSize( | ||
| 30 | + const aclTensor *self, | ||
| 31 | + const aclScalar *other, | ||
| 32 | + aclTensor *out, | ||
| 33 | + uint64_t *workspaceSize, | ||
| 34 | + aclOpExecutor **executor) | ||
| 35 | +``` | ||
| 36 | + | ||
| 37 | +```Cpp | ||
| 38 | +aclnnStatus aclnnEqScalar( | ||
| 39 | + void* workspace, | ||
| 40 | + uint64_t workspaceSize, | ||
| 41 | + aclOpExecutor* executor, | ||
| 42 | + const aclrtStream stream) | ||
| 43 | +``` | ||
| 44 | + | ||
| 45 | +```Cpp | ||
| 46 | +aclnnStatus aclnnInplaceEqScalarGetWorkspaceSize( | ||
| 47 | + const aclTensor *selfRef, | ||
| 48 | + const aclScalar *other, | ||
| 49 | + uint64_t *workspaceSize, | ||
| 50 | + aclOpExecutor **executor) | ||
| 51 | +``` | ||
| 52 | + | ||
| 53 | +```Cpp | ||
| 54 | +aclnnStatus aclnnInplaceEqScalar( | ||
| 55 | + void *workspace, | ||
| 56 | + uint64_t workspaceSize, | ||
| 57 | + aclOpExecutor *executor, | ||
| 58 | + aclrtStream stream) | ||
| 59 | +``` | ||
| 60 | + | ||
| 61 | +## aclnnEqScalarGetWorkspaceSize | ||
| 62 | + | ||
| 63 | +- **参数说明:** | ||
| 64 | + | ||
| 65 | + <table style="undefined;table-layout: fixed; width: 1494px"><colgroup> | ||
| 66 | + <col style="width: 168px"> | ||
| 67 | + <col style="width: 136px"> | ||
| 68 | + <col style="width: 213px"> | ||
| 69 | + <col style="width: 200px"> | ||
| 70 | + <col style="width: 373px"> | ||
| 71 | + <col style="width: 115px"> | ||
| 72 | + <col style="width: 142px"> | ||
| 73 | + <col style="width: 147px"> | ||
| 74 | + </colgroup> | ||
| 75 | + <thead> | ||
| 76 | + <tr> | ||
| 77 | + <th>参数名</th> | ||
| 78 | + <th>输入/输出</th> | ||
| 79 | + <th>描述</th> | ||
| 80 | + <th>使用说明</th> | ||
| 81 | + <th>数据类型</th> | ||
| 82 | + <th>数据格式</th> | ||
| 83 | + <th>维度(shape)</th> | ||
| 84 | + <th>非连续Tensor</th> | ||
| 85 | + </tr></thead> | ||
| 86 | + <tbody> | ||
| 87 | + <tr> | ||
| 88 | + <td>self</td> | ||
| 89 | + <td>输入</td> | ||
| 90 | + <td>公式中的self。</td> | ||
| 91 | + <td>-</td> | ||
| 92 | + <td>DOUBLE、FLOAT16、FLOAT、BFLOAT16、INT64、INT32、INT8、UINT8、BOOL、INT16、COMPLEX64、COMPLEX128、UINT32、UINT64</td> | ||
| 93 | + <td>ND</td> | ||
| 94 | + <td>不高于8维</td> | ||
| 95 | + <td>√</td> | ||
| 96 | + </tr> | ||
| 97 | + <tr> | ||
| 98 | + <td>other</td> | ||
| 99 | + <td>输入</td> | ||
| 100 | + <td>公式中的other。</td> | ||
| 101 | + <td>-</td> | ||
| 102 | + <td>DOUBLE、FLOAT16、FLOAT、BFLOAT16、INT64、INT32、INT8、UINT8、BOOL、INT16、COMPLEX64、COMPLEX128、UINT32、UINT64</td> | ||
| 103 | + <td>-</td> | ||
| 104 | + <td>-</td> | ||
| 105 | + <td>-</td> | ||
| 106 | + </tr> | ||
| 107 | + <tr> | ||
| 108 | + <td>out</td> | ||
| 109 | + <td>输出</td> | ||
| 110 | + <td>公式中的out。</td> | ||
| 111 | + <td>数据类型BOOL可转换的数据类型(参见<a href="../../../../docs/zh/context/互转换关系.md" target="_blank">互转换关系</a>)。</td> | ||
| 112 | + <td>DOUBLE、FLOAT16、FLOAT、BFLOAT16、INT64、INT32、INT8、UINT8、BOOL、INT16、COMPLEX64、COMPLEX128、UINT64、UINT32、UINT16</td> | ||
| 113 | + <td>ND</td> | ||
| 114 | + <td>与self的shape一致</td> | ||
| 115 | + <td>√</td> | ||
| 116 | + </tr> | ||
| 117 | + <tr> | ||
| 118 | + <td>workspaceSize</td> | ||
| 119 | + <td>输出</td> | ||
| 120 | + <td>返回需要在Device侧申请的workspace大小。</td> | ||
| 121 | + <td>-</td> | ||
| 122 | + <td>-</td> | ||
| 123 | + <td>-</td> | ||
| 124 | + <td>-</td> | ||
| 125 | + <td>-</td> | ||
| 126 | + </tr> | ||
| 127 | + <tr> | ||
| 128 | + <td>executor</td> | ||
| 129 | + <td>输出</td> | ||
| 130 | + <td>返回op执行器,包含了算子计算流程。</td> | ||
| 131 | + <td>-</td> | ||
| 132 | + <td>-</td> | ||
| 133 | + <td>-</td> | ||
| 134 | + <td>-</td> | ||
| 135 | + <td>-</td> | ||
| 136 | + </tr> | ||
| 137 | + </tbody> | ||
| 138 | + </table> | ||
| 139 | + | ||
| 140 | + - <term>Ascend 950PR/Ascend 950DT</term>: | ||
| 141 | + - self与other满足[TensorScalar互推导关系](../../../../docs/zh/context/TensorScalar互推导关系.md)。 | ||
| 142 | + - self、other不支持UINT32数据类型。 | ||
| 143 | + - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>: | ||
| 144 | + - self与other满足[互推导关系](../../../../docs/zh/context/互推导关系.md)。 | ||
| 145 | + - self、other不支持UINT32、UINT64数据类型 | ||
| 146 | + - out不支持UINT64、UINT32、UINT16数据类型。 | ||
| 147 | + - <term>Atlas 训练系列产品</term>: | ||
| 148 | + - self与other满足[互推导关系](../../../../docs/zh/context/互推导关系.md)。 | ||
| 149 | + - 不支持BFLOAT16数据类型。 | ||
| 150 | + - out不支持UINT64、UINT32、UINT16、BFLOAT16数据类型。 | ||
| 151 | + | ||
| 152 | +- **返回值:** | ||
| 153 | + | ||
| 154 | + aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 155 | + | ||
| 156 | + 第一段接口完成入参校验,出现以下场景时报错: | ||
| 157 | + | ||
| 158 | + <table style="undefined;table-layout: fixed; width: 1150px"><colgroup> | ||
| 159 | + <col style="width: 272px"> | ||
| 160 | + <col style="width: 114px"> | ||
| 161 | + <col style="width: 764px"> | ||
| 162 | + </colgroup> | ||
| 163 | + <thead> | ||
| 164 | + <tr> | ||
| 165 | + <th>返回码</th> | ||
| 166 | + <th>错误码</th> | ||
| 167 | + <th>描述</th> | ||
| 168 | + </tr></thead> | ||
| 169 | + <tbody> | ||
| 170 | + <tr> | ||
| 171 | + <td>ACLNN_ERR_PARAM_NULLPTR</td> | ||
| 172 | + <td>161001</td> | ||
| 173 | + <td>传入的self、other、out是空指针时。</td> | ||
| 174 | + </tr> | ||
| 175 | + <tr> | ||
| 176 | + <td rowspan="4">ACLNN_ERR_PARAM_INVALID</td> | ||
| 177 | + <td rowspan="4">161002</td> | ||
| 178 | + <td>self,other或out的数据类型不在支持的范围之内。</td> | ||
| 179 | + </tr> | ||
| 180 | + <tr> | ||
| 181 | + <td>self和other数据类型不满足数据类型推导规则。</td> | ||
| 182 | + </tr> | ||
| 183 | + <tr> | ||
| 184 | + <td>self和out的shape不同。</td> | ||
| 185 | + </tr> | ||
| 186 | + <tr> | ||
| 187 | + <td>self和out的维度大于8。</td> | ||
| 188 | + </tr> | ||
| 189 | + </tbody> | ||
| 190 | + </table> | ||
| 191 | + | ||
| 192 | +## aclnnEqScalar | ||
| 193 | + | ||
| 194 | +- **参数说明:** | ||
| 195 | + | ||
| 196 | + <table style="undefined;table-layout: fixed; width: 1150px"><colgroup> | ||
| 197 | + <col style="width: 153px"> | ||
| 198 | + <col style="width: 124px"> | ||
| 199 | + <col style="width: 873px"> | ||
| 200 | + </colgroup> | ||
| 201 | + <thead> | ||
| 202 | + <tr> | ||
| 203 | + <th>参数名</th> | ||
| 204 | + <th>输入/输出</th> | ||
| 205 | + <th>描述</th> | ||
| 206 | + </tr></thead> | ||
| 207 | + <tbody> | ||
| 208 | + <tr> | ||
| 209 | + <td>workspace</td> | ||
| 210 | + <td>输入</td> | ||
| 211 | + <td>在Device侧申请的workspace内存地址。</td> | ||
| 212 | + </tr> | ||
| 213 | + <tr> | ||
| 214 | + <td>workspaceSize</td> | ||
| 215 | + <td>输入</td> | ||
| 216 | + <td>在Device侧申请的workspace大小,由第一段接口aclnnEqScalarGetWorkspaceSize获取。</td> | ||
| 217 | + </tr> | ||
| 218 | + <tr> | ||
| 219 | + <td>executor</td> | ||
| 220 | + <td>输入</td> | ||
| 221 | + <td>op执行器,包含了算子计算流程。</td> | ||
| 222 | + </tr> | ||
| 223 | + <tr> | ||
| 224 | + <td>stream</td> | ||
| 225 | + <td>输入</td> | ||
| 226 | + <td>指定执行任务的Stream。</td> | ||
| 227 | + </tr> | ||
| 228 | + </tbody> | ||
| 229 | + </table> | ||
| 230 | + | ||
| 231 | +- **返回值:** | ||
| 232 | + | ||
| 233 | + aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 234 | + | ||
| 235 | +## aclnnInplaceEqScalarGetWorkspaceSize | ||
| 236 | + | ||
| 237 | +- **参数说明:** | ||
| 238 | + | ||
| 239 | + <table style="undefined;table-layout: fixed; width: 1502px"><colgroup> | ||
| 240 | + <col style="width: 167px"> | ||
| 241 | + <col style="width: 135px"> | ||
| 242 | + <col style="width: 267px"> | ||
| 243 | + <col style="width: 159px"> | ||
| 244 | + <col style="width: 372px"> | ||
| 245 | + <col style="width: 115px"> | ||
| 246 | + <col style="width: 141px"> | ||
| 247 | + <col style="width: 146px"> | ||
| 248 | + </colgroup> | ||
| 249 | + <thead> | ||
| 250 | + <tr> | ||
| 251 | + <th>参数名</th> | ||
| 252 | + <th>输入/输出</th> | ||
| 253 | + <th>描述</th> | ||
| 254 | + <th>使用说明</th> | ||
| 255 | + <th>数据类型</th> | ||
| 256 | + <th>数据格式</th> | ||
| 257 | + <th>维度(shape)</th> | ||
| 258 | + <th>非连续Tensor</th> | ||
| 259 | + </tr></thead> | ||
| 260 | + <tbody> | ||
| 261 | + <tr> | ||
| 262 | + <td>selfRef</td> | ||
| 263 | + <td>输入/输出</td> | ||
| 264 | + <td>公式中的selfRef。</td> | ||
| 265 | + <td>-</td> | ||
| 266 | + <td>DOUBLE、FLOAT16、FLOAT、BFLOAT16、INT64、INT32、INT8、UINT8、BOOL、INT16、COMPLEX64、COMPLEX128、UINT32、UINT64</td> | ||
| 267 | + <td>ND</td> | ||
| 268 | + <td>不高于8维</td> | ||
| 269 | + <td>√</td> | ||
| 270 | + </tr> | ||
| 271 | + <tr> | ||
| 272 | + <td>other</td> | ||
| 273 | + <td>输入</td> | ||
| 274 | + <td>公式中的other。</td> | ||
| 275 | + <td>-</td> | ||
| 276 | + <td>DOUBLE、FLOAT16、FLOAT、BFLOAT16、INT64、INT32、INT8、UINT8、BOOL、INT16、COMPLEX64、COMPLEX128、UINT32、UINT64</td> | ||
| 277 | + <td>-</td> | ||
| 278 | + <td>-</td> | ||
| 279 | + <td>-</td> | ||
| 280 | + </tr> | ||
| 281 | + <tr> | ||
| 282 | + <td>workspaceSize</td> | ||
| 283 | + <td>输出</td> | ||
| 284 | + <td>返回需要在Device侧申请的workspace大小。</td> | ||
| 285 | + <td>-</td> | ||
| 286 | + <td>-</td> | ||
| 287 | + <td>-</td> | ||
| 288 | + <td>-</td> | ||
| 289 | + <td>-</td> | ||
| 290 | + </tr> | ||
| 291 | + <tr> | ||
| 292 | + <td>executor</td> | ||
| 293 | + <td>输出</td> | ||
| 294 | + <td>返回op执行器,包含了算子计算流程。</td> | ||
| 295 | + <td>-</td> | ||
| 296 | + <td>-</td> | ||
| 297 | + <td>-</td> | ||
| 298 | + <td>-</td> | ||
| 299 | + <td>-</td> | ||
| 300 | + </tr> | ||
| 301 | + </tbody> | ||
| 302 | + </table> | ||
| 303 | + | ||
| 304 | + - <term>Ascend 950PR/Ascend 950DT</term>: | ||
| 305 | + - selfRef与other满足[TensorScalar互推导关系](../../../../docs/zh/context/TensorScalar互推导关系.md)。 | ||
| 306 | + - selfRef、other不支持UINT32数据类型。 | ||
| 307 | + - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>: | ||
| 308 | + - selfRef与other满足[互推导关系](../../../../docs/zh/context/互推导关系.md)。 | ||
| 309 | + - selfRef、other不支持UINT32、UINT64数据类型。 | ||
| 310 | + - <term>Atlas 训练系列产品</term>: | ||
| 311 | + - selfRef与other满足[互推导关系](../../../../docs/zh/context/互推导关系.md)。 | ||
| 312 | + - 不支持BFLOAT16数据类型。 | ||
| 313 | + | ||
| 314 | +- **返回值:** | ||
| 315 | + | ||
| 316 | + aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 317 | + | ||
| 318 | + 第一段接口完成入参校验,出现以下场景时报错: | ||
| 319 | + | ||
| 320 | + <table style="undefined;table-layout: fixed; width: 1150px"><colgroup> | ||
| 321 | + <col style="width: 272px"> | ||
| 322 | + <col style="width: 114px"> | ||
| 323 | + <col style="width: 764px"> | ||
| 324 | + </colgroup> | ||
| 325 | + <thead> | ||
| 326 | + <tr> | ||
| 327 | + <th>返回码</th> | ||
| 328 | + <th>错误码</th> | ||
| 329 | + <th>描述</th> | ||
| 330 | + </tr></thead> | ||
| 331 | + <tbody> | ||
| 332 | + <tr> | ||
| 333 | + <td>ACLNN_ERR_PARAM_NULLPTR</td> | ||
| 334 | + <td>161001</td> | ||
| 335 | + <td>传入的selfRef和other是空指针时。</td> | ||
| 336 | + </tr> | ||
| 337 | + <tr> | ||
| 338 | + <td rowspan="3">ACLNN_ERR_PARAM_INVALID</td> | ||
| 339 | + <td rowspan="3">161002</td> | ||
| 340 | + <td>selfRef和other的数据类型不在支持的范围之内。</td> | ||
| 341 | + </tr> | ||
| 342 | + <tr> | ||
| 343 | + <td>selfRef和other的数据类型不满足数据类型推导规则。</td> | ||
| 344 | + </tr> | ||
| 345 | + <tr> | ||
| 346 | + <td>selfRef的维度大于8。</td> | ||
| 347 | + </tr> | ||
| 348 | + </tbody> | ||
| 349 | + </table> | ||
| 350 | + | ||
| 351 | +## aclnnInplaceEqScalar | ||
| 352 | + | ||
| 353 | +- **参数说明:** | ||
| 354 | + | ||
| 355 | + <table style="undefined;table-layout: fixed; width: 1150px"><colgroup> | ||
| 356 | + <col style="width: 153px"> | ||
| 357 | + <col style="width: 124px"> | ||
| 358 | + <col style="width: 873px"> | ||
| 359 | + </colgroup> | ||
| 360 | + <thead> | ||
| 361 | + <tr> | ||
| 362 | + <th>参数名</th> | ||
| 363 | + <th>输入/输出</th> | ||
| 364 | + <th>描述</th> | ||
| 365 | + </tr></thead> | ||
| 366 | + <tbody> | ||
| 367 | + <tr> | ||
| 368 | + <td>workspace</td> | ||
| 369 | + <td>输入</td> | ||
| 370 | + <td>在Device侧申请的workspace内存地址。</td> | ||
| 371 | + </tr> | ||
| 372 | + <tr> | ||
| 373 | + <td>workspaceSize</td> | ||
| 374 | + <td>输入</td> | ||
| 375 | + <td>在Device侧申请的workspace大小,由第一段接口aclnnInplaceEqScalarGetWorkspaceSize获取。</td> | ||
| 376 | + </tr> | ||
| 377 | + <tr> | ||
| 378 | + <td>executor</td> | ||
| 379 | + <td>输入</td> | ||
| 380 | + <td>op执行器,包含了算子计算流程。</td> | ||
| 381 | + </tr> | ||
| 382 | + <tr> | ||
| 383 | + <td>stream</td> | ||
| 384 | + <td>输入</td> | ||
| 385 | + <td>指定执行任务的Stream。</td> | ||
| 386 | + </tr> | ||
| 387 | + </tbody> | ||
| 388 | + </table> | ||
| 389 | + | ||
| 390 | +- **返回值:** | ||
| 391 | + | ||
| 392 | + aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 393 | + | ||
| 394 | +## 约束说明 | ||
| 395 | + | ||
| 396 | +- 确定性计算: | ||
| 397 | + - aclnnEqScalar&aclnnInplaceEqScalar默认确定性实现。 | ||
| 398 | + | ||
| 399 | +## 调用示例 | ||
| 400 | + | ||
| 401 | +示例代码如下,仅供参考,具体编译和执行过程请参考[编译与运行样例](../../../../docs/zh/context/编译与运行样例.md)。 | ||
| 402 | + | ||
| 403 | +**aclnnEqScalar示例代码:** | ||
| 404 | + | ||
| 405 | +```Cpp | ||
| 406 | +#include <iostream> | ||
| 407 | +#include <vector> | ||
| 408 | +#include "acl/acl.h" | ||
| 409 | +#include "aclnnop/aclnn_eq_scalar.h" | ||
| 410 | + | ||
| 411 | +#define CHECK_RET(cond, return_expr) \ | ||
| 412 | + do { \ | ||
| 413 | + if (!(cond)) { \ | ||
| 414 | + return_expr; \ | ||
| 415 | + } \ | ||
| 416 | + } while (0) | ||
| 417 | + | ||
| 418 | +#define LOG_PRINT(message, ...) \ | ||
| 419 | + do { \ | ||
| 420 | + printf(message, ##__VA_ARGS__); \ | ||
| 421 | + } while (0) | ||
| 422 | + | ||
| 423 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 424 | +{ | ||
| 425 | + int64_t shape_size = 1; | ||
| 426 | + for (auto i : shape) { | ||
| 427 | + shape_size *= i; | ||
| 428 | + } | ||
| 429 | + return shape_size; | ||
| 430 | +} | ||
| 431 | + | ||
| 432 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 433 | +{ | ||
| 434 | + // 固定写法,资源初始化 | ||
| 435 | + auto ret = aclInit(nullptr); | ||
| 436 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 437 | + ret = aclrtSetDevice(deviceId); | ||
| 438 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 439 | + ret = aclrtCreateStream(stream); | ||
| 440 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 441 | + return 0; | ||
| 442 | +} | ||
| 443 | + | ||
| 444 | +template <typename T> | ||
| 445 | +int CreateAclTensor( | ||
| 446 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, | ||
| 447 | + aclTensor** tensor) | ||
| 448 | +{ | ||
| 449 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 450 | + // 调用aclrtMalloc申请device侧内存 | ||
| 451 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 452 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 453 | + | ||
| 454 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 455 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 456 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 457 | + | ||
| 458 | + // 计算连续tensor的strides | ||
| 459 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 460 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 461 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 462 | + } | ||
| 463 | + | ||
| 464 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 465 | + *tensor = aclCreateTensor( | ||
| 466 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), | ||
| 467 | + *deviceAddr); | ||
| 468 | + return 0; | ||
| 469 | +} | ||
| 470 | + | ||
| 471 | +aclError InitAcl(int32_t deviceId, aclrtStream* stream) | ||
| 472 | +{ | ||
| 473 | + auto ret = Init(deviceId, stream); | ||
| 474 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 475 | + return ACL_SUCCESS; | ||
| 476 | +} | ||
| 477 | + | ||
| 478 | +aclError CreateInputs( | ||
| 479 | + std::vector<int64_t>& selfShape, std::vector<int64_t>& outShape, void** selfDeviceAddr, void** outDeviceAddr, | ||
| 480 | + aclTensor** self, aclScalar** other, aclTensor** out) | ||
| 481 | +{ | ||
| 482 | + std::vector<double> selfHostData = {0, 1, 1.2, 0.3, 4.1, 5, 1.6, 7}; | ||
| 483 | + std::vector<char> outHostData = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 484 | + double otherValue = 1.2; | ||
| 485 | + | ||
| 486 | + // 创建 self tensor | ||
| 487 | + auto ret = CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_DOUBLE, self); | ||
| 488 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 489 | + | ||
| 490 | + // 创建 other scalar | ||
| 491 | + *other = aclCreateScalar(&otherValue, aclDataType::ACL_DOUBLE); | ||
| 492 | + CHECK_RET(*other != nullptr, return ret); | ||
| 493 | + | ||
| 494 | + // 创建 out tensor | ||
| 495 | + ret = CreateAclTensor(outHostData, outShape, &(*outDeviceAddr), aclDataType::ACL_BOOL, out); | ||
| 496 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 497 | + | ||
| 498 | + return ACL_SUCCESS; | ||
| 499 | +} | ||
| 500 | + | ||
| 501 | +aclError ExecOpApi( | ||
| 502 | + aclTensor* self, aclScalar* other, aclTensor* out, void** workspaceAddrOut, uint64_t& workspaceSize, | ||
| 503 | + void* outDeviceAddr, std::vector<int64_t>& outShape, aclrtStream stream) | ||
| 504 | +{ | ||
| 505 | + aclOpExecutor* executor; | ||
| 506 | + | ||
| 507 | + // 获取 workspace 大小 | ||
| 508 | + auto ret = aclnnEqScalarGetWorkspaceSize(self, other, out, &workspaceSize, &executor); | ||
| 509 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEqScalarGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 510 | + | ||
| 511 | + // 申请 workspace(释放放在 main 里) | ||
| 512 | + void* workspaceAddr = nullptr; | ||
| 513 | + if (workspaceSize > 0) { | ||
| 514 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 515 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 516 | + } | ||
| 517 | + *workspaceAddrOut = workspaceAddr; | ||
| 518 | + | ||
| 519 | + // 调用算子 | ||
| 520 | + ret = aclnnEqScalar(workspaceAddr, workspaceSize, executor, stream); | ||
| 521 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEqScalar failed. ERROR: %d\n", ret); return ret); | ||
| 522 | + | ||
| 523 | + // 同步 | ||
| 524 | + ret = aclrtSynchronizeStream(stream); | ||
| 525 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 526 | + | ||
| 527 | + // 拷贝输出 | ||
| 528 | + auto size = GetShapeSize(outShape); | ||
| 529 | + std::vector<char> resultData(size, 0); | ||
| 530 | + | ||
| 531 | + ret = aclrtMemcpy( | ||
| 532 | + resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(char), | ||
| 533 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 534 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 535 | + | ||
| 536 | + for (int64_t i = 0; i < size; i++) { | ||
| 537 | + LOG_PRINT("result[%ld] is: %d\n", i, resultData[i]); | ||
| 538 | + } | ||
| 539 | + | ||
| 540 | + return ACL_SUCCESS; | ||
| 541 | +} | ||
| 542 | + | ||
| 543 | +int main() | ||
| 544 | +{ | ||
| 545 | + int32_t deviceId = 0; | ||
| 546 | + aclrtStream stream; | ||
| 547 | + auto ret = InitAcl(deviceId, &stream); | ||
| 548 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("InitAcl failed. ERROR: %d\n", ret); return ret); | ||
| 549 | + | ||
| 550 | + std::vector<int64_t> selfShape = {4, 2}; | ||
| 551 | + std::vector<int64_t> outShape = {4, 2}; | ||
| 552 | + | ||
| 553 | + void* selfDeviceAddr = nullptr; | ||
| 554 | + void* outDeviceAddr = nullptr; | ||
| 555 | + aclTensor* self = nullptr; | ||
| 556 | + aclScalar* other = nullptr; | ||
| 557 | + aclTensor* out = nullptr; | ||
| 558 | + | ||
| 559 | + ret = CreateInputs(selfShape, outShape, &selfDeviceAddr, &outDeviceAddr, &self, &other, &out); | ||
| 560 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 561 | + | ||
| 562 | + uint64_t workspaceSize = 0; | ||
| 563 | + void* workspaceAddr = nullptr; | ||
| 564 | + | ||
| 565 | + ret = ExecOpApi(self, other, out, &workspaceAddr, workspaceSize, outDeviceAddr, outShape, stream); | ||
| 566 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 567 | + | ||
| 568 | + // 释放 Tensor / Scalar | ||
| 569 | + aclDestroyTensor(self); | ||
| 570 | + aclDestroyScalar(other); | ||
| 571 | + aclDestroyTensor(out); | ||
| 572 | + | ||
| 573 | + // 释放 device 内存 | ||
| 574 | + aclrtFree(selfDeviceAddr); | ||
| 575 | + aclrtFree(outDeviceAddr); | ||
| 576 | + if (workspaceSize > 0) { | ||
| 577 | + aclrtFree(workspaceAddr); | ||
| 578 | + } | ||
| 579 | + | ||
| 580 | + aclrtDestroyStream(stream); | ||
| 581 | + aclrtResetDevice(deviceId); | ||
| 582 | + aclFinalize(); | ||
| 583 | + | ||
| 584 | + return 0; | ||
| 585 | +} | ||
| 586 | +``` | ||
| 587 | + | ||
| 588 | +**aclnnInplaceEqScalar示例代码:** | ||
| 589 | + | ||
| 590 | +```Cpp | ||
| 591 | +#include <iostream> | ||
| 592 | +#include <vector> | ||
| 593 | +#include "acl/acl.h" | ||
| 594 | +#include "aclnnop/aclnn_eq_scalar.h" | ||
| 595 | + | ||
| 596 | +#define CHECK_RET(cond, return_expr) \ | ||
| 597 | + do { \ | ||
| 598 | + if (!(cond)) { \ | ||
| 599 | + return_expr; \ | ||
| 600 | + } \ | ||
| 601 | + } while (0) | ||
| 602 | + | ||
| 603 | +#define LOG_PRINT(message, ...) \ | ||
| 604 | + do { \ | ||
| 605 | + printf(message, ##__VA_ARGS__); \ | ||
| 606 | + } while (0) | ||
| 607 | + | ||
| 608 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 609 | +{ | ||
| 610 | + int64_t shapeSize = 1; | ||
| 611 | + for (auto i : shape) { | ||
| 612 | + shapeSize *= i; | ||
| 613 | + } | ||
| 614 | + return shapeSize; | ||
| 615 | +} | ||
| 616 | + | ||
| 617 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 618 | +{ | ||
| 619 | + // 固定写法,资源初始化 | ||
| 620 | + auto ret = aclInit(nullptr); | ||
| 621 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 622 | + ret = aclrtSetDevice(deviceId); | ||
| 623 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 624 | + ret = aclrtCreateStream(stream); | ||
| 625 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 626 | + return 0; | ||
| 627 | +} | ||
| 628 | + | ||
| 629 | +template <typename T> | ||
| 630 | +int CreateAclTensor( | ||
| 631 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, | ||
| 632 | + aclTensor** tensor) | ||
| 633 | +{ | ||
| 634 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 635 | + // 调用aclrtMalloc申请device侧内存 | ||
| 636 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 637 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 638 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 639 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 640 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 641 | + | ||
| 642 | + // 计算连续tensor的strides | ||
| 643 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 644 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 645 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 646 | + } | ||
| 647 | + | ||
| 648 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 649 | + *tensor = aclCreateTensor( | ||
| 650 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), | ||
| 651 | + *deviceAddr); | ||
| 652 | + return 0; | ||
| 653 | +} | ||
| 654 | + | ||
| 655 | +aclError InitAcl(int32_t deviceId, aclrtStream* stream) | ||
| 656 | +{ | ||
| 657 | + auto ret = Init(deviceId, stream); | ||
| 658 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 659 | + return ACL_SUCCESS; | ||
| 660 | +} | ||
| 661 | + | ||
| 662 | +aclError CreateInputs(std::vector<int64_t>& selfShape, void** selfDeviceAddr, aclTensor** self, aclScalar** other) | ||
| 663 | +{ | ||
| 664 | + std::vector<double> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
| 665 | + double otherValue = 2.0; | ||
| 666 | + | ||
| 667 | + // 创建self aclTensor | ||
| 668 | + auto ret = CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_DOUBLE, self); | ||
| 669 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 670 | + | ||
| 671 | + // 创建other aclScalar | ||
| 672 | + *other = aclCreateScalar(&otherValue, aclDataType::ACL_DOUBLE); | ||
| 673 | + CHECK_RET(*other != nullptr, return ACL_ERROR_INVALID_PARAM); | ||
| 674 | + | ||
| 675 | + return ACL_SUCCESS; | ||
| 676 | +} | ||
| 677 | + | ||
| 678 | +aclError ExecOpApi( | ||
| 679 | + aclTensor* self, aclScalar* other, void* selfDeviceAddr, std::vector<int64_t>& selfShape, aclrtStream stream, | ||
| 680 | + void** workspaceAddrOut) | ||
| 681 | +{ | ||
| 682 | + uint64_t workspaceSize = 0; | ||
| 683 | + aclOpExecutor* executor; | ||
| 684 | + | ||
| 685 | + auto ret = aclnnInplaceEqScalarGetWorkspaceSize(self, other, &workspaceSize, &executor); | ||
| 686 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceEqScalarGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 687 | + | ||
| 688 | + // workspace 分配 | ||
| 689 | + void* workspaceAddr = nullptr; | ||
| 690 | + if (workspaceSize > 0) { | ||
| 691 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 692 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 693 | + } | ||
| 694 | + | ||
| 695 | + *workspaceAddrOut = workspaceAddr; | ||
| 696 | + | ||
| 697 | + // 执行 | ||
| 698 | + ret = aclnnInplaceEqScalar(workspaceAddr, workspaceSize, executor, stream); | ||
| 699 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceEqScalar failed. ERROR: %d\n", ret); return ret); | ||
| 700 | + | ||
| 701 | + // 同步 | ||
| 702 | + ret = aclrtSynchronizeStream(stream); | ||
| 703 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 704 | + | ||
| 705 | + // 拷贝输出 | ||
| 706 | + auto size = GetShapeSize(selfShape); | ||
| 707 | + std::vector<double> resultData(size); | ||
| 708 | + | ||
| 709 | + ret = aclrtMemcpy( | ||
| 710 | + resultData.data(), resultData.size() * sizeof(resultData[0]), selfDeviceAddr, size * sizeof(resultData[0]), | ||
| 711 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 712 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 713 | + | ||
| 714 | + for (int64_t i = 0; i < size; i++) { | ||
| 715 | + LOG_PRINT("result[%ld] is: %lf\n", i, resultData[i]); | ||
| 716 | + } | ||
| 717 | + | ||
| 718 | + return ACL_SUCCESS; | ||
| 719 | +} | ||
| 720 | + | ||
| 721 | +int main() | ||
| 722 | +{ | ||
| 723 | + int32_t deviceId = 0; | ||
| 724 | + aclrtStream stream; | ||
| 725 | + | ||
| 726 | + auto ret = InitAcl(deviceId, &stream); | ||
| 727 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 728 | + | ||
| 729 | + std::vector<int64_t> selfShape = {4, 2}; | ||
| 730 | + void* selfDeviceAddr = nullptr; | ||
| 731 | + | ||
| 732 | + aclTensor* self = nullptr; | ||
| 733 | + aclScalar* other = nullptr; | ||
| 734 | + | ||
| 735 | + ret = CreateInputs(selfShape, &selfDeviceAddr, &self, &other); | ||
| 736 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 737 | + | ||
| 738 | + void* workspaceAddr = nullptr; | ||
| 739 | + ret = ExecOpApi(self, other, selfDeviceAddr, selfShape, stream, &workspaceAddr); | ||
| 740 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 741 | + | ||
| 742 | + // 销毁 | ||
| 743 | + aclDestroyTensor(self); | ||
| 744 | + aclDestroyScalar(other); | ||
| 745 | + | ||
| 746 | + aclrtFree(selfDeviceAddr); | ||
| 747 | + if (workspaceAddr != nullptr) { | ||
| 748 | + aclrtFree(workspaceAddr); | ||
| 749 | + } | ||
| 750 | + // 释放 | ||
| 751 | + aclrtDestroyStream(stream); | ||
| 752 | + aclrtResetDevice(deviceId); | ||
| 753 | + aclFinalize(); | ||
| 754 | + | ||
| 755 | + return 0; | ||
| 756 | +} | ||
| 757 | + | ||
| 758 | +``` | ||
| @@ -0,0 +1,766 @@ | |||
| 1 | +# aclnnEqTensor&aclnnInplaceEqTensor | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +## 产品支持情况 | ||
| 5 | + | ||
| 6 | +| 产品 | 是否支持 | | ||
| 7 | +| :----------------------------------------------------------- | :------: | | ||
| 8 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | ||
| 9 | + | ||
| 10 | +## 功能说明 | ||
| 11 | + | ||
| 12 | +- 接口功能:计算两个Tensor中的元素是否相等,返回一个Tensor,self=other的为True(1.),否则为False(0.)。 | ||
| 13 | +- 计算表达式: | ||
| 14 | + | ||
| 15 | + $$ | ||
| 16 | + out = (self_i == other_i) ? [True] : [False] | ||
| 17 | + $$ | ||
| 18 | + | ||
| 19 | +## 函数原型 | ||
| 20 | + | ||
| 21 | +- aclnnEqTensor和aclnnInplaceEqTensor实现相同的功能,使用区别如下,请根据自身实际场景选择合适的算子。 | ||
| 22 | + | ||
| 23 | + - aclnnEqTensor:需新建一个输出张量对象存储计算结果。 | ||
| 24 | + - aclnnInplaceEqTensor:无需新建输出张量对象,直接在输入张量的内存中存储计算结果。 | ||
| 25 | + | ||
| 26 | +- 每个算子分为[两段式接口](../../../../docs/zh/context/两段式接口.md),必须先调用“aclnnEqTensorGetWorkspaceSize”或者“aclnnInplaceEqTensorGetWorkspaceSize”接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用“aclnnEqTensor”或者“aclnnInplaceEqTensor”接口执行计算aclnnEqTensor。 | ||
| 27 | + | ||
| 28 | +```Cpp | ||
| 29 | +aclnnStatus aclnnEqTensorGetWorkspaceSize( | ||
| 30 | + const aclTensor *self, | ||
| 31 | + const aclTensor *other, | ||
| 32 | + aclTensor *out, | ||
| 33 | + uint64_t *workspaceSize, | ||
| 34 | + aclOpExecutor **executor) | ||
| 35 | +``` | ||
| 36 | + | ||
| 37 | +```Cpp | ||
| 38 | +aclnnStatus aclnnEqTensor( | ||
| 39 | + void *workspace, | ||
| 40 | + uint64_t workspaceSize, | ||
| 41 | + aclOpExecutor *executor, | ||
| 42 | + aclrtStream stream) | ||
| 43 | +``` | ||
| 44 | + | ||
| 45 | +```Cpp | ||
| 46 | +aclnnStatus aclnnInplaceEqTensorGetWorkspaceSize( | ||
| 47 | + const aclTensor *selfRef, | ||
| 48 | + const aclTensor *other, | ||
| 49 | + uint64_t *workspaceSize, | ||
| 50 | + aclOpExecutor **executor) | ||
| 51 | +``` | ||
| 52 | + | ||
| 53 | +```Cpp | ||
| 54 | +aclnnStatus aclnnInplaceEqTensor( | ||
| 55 | + void *workspace, | ||
| 56 | + uint64_t workspaceSize, | ||
| 57 | + aclOpExecutor *executor, | ||
| 58 | + aclrtStream stream) | ||
| 59 | +``` | ||
| 60 | + | ||
| 61 | +## aclnnEqTensorGetWorkspaceSize | ||
| 62 | + | ||
| 63 | +- **参数说明:** | ||
| 64 | + | ||
| 65 | + <table style="undefined;table-layout: fixed; width: 1550px"><colgroup> | ||
| 66 | + <col style="width: 168px"> | ||
| 67 | + <col style="width: 136px"> | ||
| 68 | + <col style="width: 215px"> | ||
| 69 | + <col style="width: 286px"> | ||
| 70 | + <col style="width: 340px"> | ||
| 71 | + <col style="width: 116px"> | ||
| 72 | + <col style="width: 142px"> | ||
| 73 | + <col style="width: 147px"> | ||
| 74 | + </colgroup> | ||
| 75 | + <thead> | ||
| 76 | + <tr> | ||
| 77 | + <th>参数名</th> | ||
| 78 | + <th>输入/输出</th> | ||
| 79 | + <th>描述</th> | ||
| 80 | + <th>使用说明</th> | ||
| 81 | + <th>数据类型</th> | ||
| 82 | + <th>数据格式</th> | ||
| 83 | + <th>维度(shape)</th> | ||
| 84 | + <th>非连续Tensor</th> | ||
| 85 | + </tr></thead> | ||
| 86 | + <tbody> | ||
| 87 | + <tr> | ||
| 88 | + <td>self(aclTensor*)</td> | ||
| 89 | + <td>输入</td> | ||
| 90 | + <td>输入tensor。</td> | ||
| 91 | + <td><ul><li>数据类型需要与other满足数据类型推导规则(参见<a href="../../../../docs/zh/context/互推导关系.md" target="_blank">互推导关系</a>)。</li><li>shape需要与other满足<a href="../../../../docs/zh/context/broadcast关系.md" target="_blank">broadcast关系</a>。</li></ul></td> | ||
| 92 | + <td>DOUBLE、FLOAT16、FLOAT、BFLOAT16、INT64、INT32、INT8、UINT8、BOOL、INT16、COMPLEX64、COMPLEX128、UINT32、UINT64</td> | ||
| 93 | + <td>ND</td> | ||
| 94 | + <td>不高于8维</td> | ||
| 95 | + <td>√</td> | ||
| 96 | + </tr> | ||
| 97 | + <tr> | ||
| 98 | + <td>other(aclTensor*)</td> | ||
| 99 | + <td>输入</td> | ||
| 100 | + <td>输入tensor。</td> | ||
| 101 | + <td><ul><li>数据类型需要与self满足数据类型推导规则(参见<a href="../../../../docs/zh/context/互推导关系.md" target="_blank">互推导关系</a>)。</li><li>shape需要与self的shape满足<a href="../../../../docs/zh/context/broadcast关系.md" target="_blank">broadcast关系</a>。</li></ul></td> | ||
| 102 | + <td>DOUBLE、FLOAT16、FLOAT、BFLOAT16、INT64、INT32、INT8、UINT8、BOOL、INT16、COMPLEX64、COMPLEX128、UINT32、UINT64</td> | ||
| 103 | + <td>ND</td> | ||
| 104 | + <td>不高于8维</td> | ||
| 105 | + <td>√</td> | ||
| 106 | + </tr> | ||
| 107 | + <tr> | ||
| 108 | + <td>out(aclTensor*)</td> | ||
| 109 | + <td>输出</td> | ||
| 110 | + <td>输出tensor。</td> | ||
| 111 | + <td><ul><li>数据类型需要是BOOL可转换的数据类型<a href="../../../../docs/zh/context/互转换关系.md" target="_blank">互转换关系</a>。</li><li>shape与self、other广播之后的shape(参见<a href="../../../../docs/zh/context/broadcast关系.md" target="_blank">broadcast关系</a>)一致。</li></ul></td> | ||
| 112 | + <td>DOUBLE、FLOAT16、FLOAT、BFLOAT16、INT64、INT32、INT8、UINT8、BOOL、INT16、COMPLEX64、COMPLEX128、UINT64、UINT32、UINT16</td> | ||
| 113 | + <td>ND</td> | ||
| 114 | + <td>不高于8维</td> | ||
| 115 | + <td>√</td> | ||
| 116 | + </tr> | ||
| 117 | + <tr> | ||
| 118 | + <td>workspaceSize(uint64_t*)</td> | ||
| 119 | + <td>输出</td> | ||
| 120 | + <td>返回需要在Device侧申请的workspace大小。</td> | ||
| 121 | + <td>-</td> | ||
| 122 | + <td>-</td> | ||
| 123 | + <td>-</td> | ||
| 124 | + <td>-</td> | ||
| 125 | + <td>-</td> | ||
| 126 | + </tr> | ||
| 127 | + <tr> | ||
| 128 | + <td>executor(aclOpExecutor**)</td> | ||
| 129 | + <td>输出</td> | ||
| 130 | + <td>返回op执行器,包含了算子计算流程。</td> | ||
| 131 | + <td>-</td> | ||
| 132 | + <td>-</td> | ||
| 133 | + <td>-</td> | ||
| 134 | + <td>-</td> | ||
| 135 | + <td>-</td> | ||
| 136 | + </tr> | ||
| 137 | + </tbody> | ||
| 138 | + </table> | ||
| 139 | + | ||
| 140 | + - <term>Ascend 950PR/Ascend 950DT</term>: | ||
| 141 | + - self、other不支持UINT32数据类型。 | ||
| 142 | + - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>: | ||
| 143 | + - self、other不支持UINT32、UINT64数据类型。 | ||
| 144 | + - out不支持UINT64、UINT32、UINT16数据类型。 | ||
| 145 | + - <term>Atlas 训练系列产品</term>: | ||
| 146 | + - 不支持BFLOAT16数据类型。 | ||
| 147 | + - out不支持BFLOAT16、UINT64、UINT32、UINT16数据类型。 | ||
| 148 | + | ||
| 149 | +- **返回值:** | ||
| 150 | + | ||
| 151 | + aclnnStatus: 返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 152 | + | ||
| 153 | + 第一段接口完成入参校验,出现以下场景时报错: | ||
| 154 | + | ||
| 155 | + <table style="undefined;table-layout: fixed; width: 1150px"><colgroup> | ||
| 156 | + <col style="width: 281px"> | ||
| 157 | + <col style="width: 119px"> | ||
| 158 | + <col style="width: 750px"> | ||
| 159 | + </colgroup> | ||
| 160 | + <thead> | ||
| 161 | + <tr> | ||
| 162 | + <th>返回码</th> | ||
| 163 | + <th>错误码</th> | ||
| 164 | + <th>描述</th> | ||
| 165 | + </tr></thead> | ||
| 166 | + <tbody> | ||
| 167 | + <tr> | ||
| 168 | + <td>ACLNN_ERR_PARAM_NULLPTR</td> | ||
| 169 | + <td>161001</td> | ||
| 170 | + <td>传入的self、other、out是空指针时。</td> | ||
| 171 | + </tr> | ||
| 172 | + <tr> | ||
| 173 | + <td rowspan="5">ACLNN_ERR_PARAM_INVALID</td> | ||
| 174 | + <td rowspan="5">161002</td> | ||
| 175 | + <td>传入的self、other、out是空指针时。</td> | ||
| 176 | + </tr> | ||
| 177 | + <tr> | ||
| 178 | + <td>self、other或out的维度大于8。</td> | ||
| 179 | + </tr> | ||
| 180 | + <tr> | ||
| 181 | + <td>self和other的数据类型无法进行推导。</td> | ||
| 182 | + </tr> | ||
| 183 | + <tr> | ||
| 184 | + <td>self和other的shape无法进行broadcast。</td> | ||
| 185 | + </tr> | ||
| 186 | + <tr> | ||
| 187 | + <td>out的shape与broadcast后的shape不一致。</td> | ||
| 188 | + </tr> | ||
| 189 | + </tbody> | ||
| 190 | + </table> | ||
| 191 | + | ||
| 192 | +## aclnnEqTensor | ||
| 193 | + | ||
| 194 | +- **参数说明:** | ||
| 195 | + | ||
| 196 | + <table style="undefined;table-layout: fixed; width: 1150px"><colgroup> | ||
| 197 | + <col style="width: 168px"> | ||
| 198 | + <col style="width: 128px"> | ||
| 199 | + <col style="width: 854px"> | ||
| 200 | + </colgroup> | ||
| 201 | + <thead> | ||
| 202 | + <tr> | ||
| 203 | + <th>参数名</th> | ||
| 204 | + <th>输入/输出</th> | ||
| 205 | + <th>描述</th> | ||
| 206 | + </tr></thead> | ||
| 207 | + <tbody> | ||
| 208 | + <tr> | ||
| 209 | + <td>workspace</td> | ||
| 210 | + <td>输入</td> | ||
| 211 | + <td>在Device侧申请的workspace内存地址。</td> | ||
| 212 | + </tr> | ||
| 213 | + <tr> | ||
| 214 | + <td>workspaceSize</td> | ||
| 215 | + <td>输入</td> | ||
| 216 | + <td>在Device侧申请的workspace大小,由第一段接口aclnnEqTensorGetWorkspaceSize获取。</td> | ||
| 217 | + </tr> | ||
| 218 | + <tr> | ||
| 219 | + <td>executor</td> | ||
| 220 | + <td>输入</td> | ||
| 221 | + <td>op执行器,包含了算子计算流程。</td> | ||
| 222 | + </tr> | ||
| 223 | + <tr> | ||
| 224 | + <td>stream</td> | ||
| 225 | + <td>输入</td> | ||
| 226 | + <td>指定执行任务的Stream。</td> | ||
| 227 | + </tr> | ||
| 228 | + </tbody> | ||
| 229 | + </table> | ||
| 230 | + | ||
| 231 | +- **返回值:** | ||
| 232 | + | ||
| 233 | + aclnnStatus: 返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 234 | + | ||
| 235 | +## aclnnInplaceEqTensorGetWorkspaceSize | ||
| 236 | + | ||
| 237 | +- **参数说明:** | ||
| 238 | + | ||
| 239 | + <table style="undefined;table-layout: fixed; width: 1542px"><colgroup> | ||
| 240 | + <col style="width: 166px"> | ||
| 241 | + <col style="width: 134px"> | ||
| 242 | + <col style="width: 212px"> | ||
| 243 | + <col style="width: 283px"> | ||
| 244 | + <col style="width: 348px"> | ||
| 245 | + <col style="width: 114px"> | ||
| 246 | + <col style="width: 140px"> | ||
| 247 | + <col style="width: 145px"> | ||
| 248 | + </colgroup> | ||
| 249 | + <thead> | ||
| 250 | + <tr> | ||
| 251 | + <th>参数名</th> | ||
| 252 | + <th>输入/输出</th> | ||
| 253 | + <th>描述</th> | ||
| 254 | + <th>使用说明</th> | ||
| 255 | + <th>数据类型</th> | ||
| 256 | + <th>数据格式</th> | ||
| 257 | + <th>维度(shape)</th> | ||
| 258 | + <th>非连续Tensor</th> | ||
| 259 | + </tr></thead> | ||
| 260 | + <tbody> | ||
| 261 | + <tr> | ||
| 262 | + <td>selfRef</td> | ||
| 263 | + <td>输入/输出</td> | ||
| 264 | + <td>输入输出tensor,即公式中的self与out。</td> | ||
| 265 | + <td><ul><li>数据类型与other的数据类型需满足数据类型推导规则(参见<a href="../../../../docs/zh/context/互推导关系.md" target="_blank">互推导关系</a>)。</li><li>shape需要与other满足<a href="../../../../docs/zh/context/broadcast关系.md" target="_blank">broadcast关系</a>。</li></ul></td> | ||
| 266 | + <td>DOUBLE、FLOAT16、FLOAT、BFLOAT16、INT64、INT32、INT8、UINT8、BOOL、INT16、COMPLEX64、COMPLEX128、UINT32、UINT64</td> | ||
| 267 | + <td>ND</td> | ||
| 268 | + <td>-</td> | ||
| 269 | + <td>√</td> | ||
| 270 | + </tr> | ||
| 271 | + <tr> | ||
| 272 | + <td>other</td> | ||
| 273 | + <td>输入</td> | ||
| 274 | + <td>公式中的other。</td> | ||
| 275 | + <td><ul><li>数据类型与selfRef的数据类型需满足数据类型推导规则(参见<a href="../../../../docs/zh/context/互推导关系.md" target="_blank">互推导关系</a>)。</li><li>shape需要与selfRef满足<a href="../../../../docs/zh/context/broadcast关系.md" target="_blank">broadcast关系</a>。</li></ul></td> | ||
| 276 | + <td>DOUBLE、FLOAT16、FLOAT、BFLOAT16、INT64、INT32、INT8、UINT8、BOOL、INT16、COMPLEX64、COMPLEX128、UINT32、UINT64</td> | ||
| 277 | + <td>ND</td> | ||
| 278 | + <td>-</td> | ||
| 279 | + <td>√</td> | ||
| 280 | + </tr> | ||
| 281 | + <tr> | ||
| 282 | + <td>workspaceSize</td> | ||
| 283 | + <td>输出</td> | ||
| 284 | + <td>返回需要在Device侧申请的workspace大小。</td> | ||
| 285 | + <td>-</td> | ||
| 286 | + <td>-</td> | ||
| 287 | + <td>-</td> | ||
| 288 | + <td>-</td> | ||
| 289 | + <td>-</td> | ||
| 290 | + </tr> | ||
| 291 | + <tr> | ||
| 292 | + <td>executor</td> | ||
| 293 | + <td>输出</td> | ||
| 294 | + <td>返回op执行器,包含了算子计算流程。</td> | ||
| 295 | + <td>-</td> | ||
| 296 | + <td>-</td> | ||
| 297 | + <td>-</td> | ||
| 298 | + <td>-</td> | ||
| 299 | + <td>-</td> | ||
| 300 | + </tr> | ||
| 301 | + </tbody> | ||
| 302 | + </table> | ||
| 303 | + | ||
| 304 | + - <term>Ascend 950PR/Ascend 950DT</term>: | ||
| 305 | + - selfRef、other不支持UINT32数据类型。 | ||
| 306 | + - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>: | ||
| 307 | + - selfRef、other不支持UINT32、UINT64数据类型。 | ||
| 308 | + - <term>Atlas 训练系列产品</term>: | ||
| 309 | + - 不支持BFLOAT16数据类型。 | ||
| 310 | + | ||
| 311 | +- **返回值:** | ||
| 312 | + | ||
| 313 | + aclnnStatus: 返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 314 | + | ||
| 315 | + 第一段接口完成入参校验,出现以下场景时报错: | ||
| 316 | + | ||
| 317 | + <table style="undefined;table-layout: fixed; width: 1150px"><colgroup> | ||
| 318 | + <col style="width: 281px"> | ||
| 319 | + <col style="width: 119px"> | ||
| 320 | + <col style="width: 750px"> | ||
| 321 | + </colgroup> | ||
| 322 | + <thead> | ||
| 323 | + <tr> | ||
| 324 | + <th>返回码</th> | ||
| 325 | + <th>错误码</th> | ||
| 326 | + <th>描述</th> | ||
| 327 | + </tr></thead> | ||
| 328 | + <tbody> | ||
| 329 | + <tr> | ||
| 330 | + <td>ACLNN_ERR_PARAM_NULLPTR</td> | ||
| 331 | + <td>161001</td> | ||
| 332 | + <td>传入的selfRef和other是空指针时。</td> | ||
| 333 | + </tr> | ||
| 334 | + <tr> | ||
| 335 | + <td rowspan="6">ACLNN_ERR_PARAM_INVALID</td> | ||
| 336 | + <td rowspan="6">161002</td> | ||
| 337 | + <td>selfRef和other的数据类型不在支持的范围之内。</td> | ||
| 338 | + </tr> | ||
| 339 | + <tr> | ||
| 340 | + <td>selfRef和other的数据类型无法进行推导。</td> | ||
| 341 | + </tr> | ||
| 342 | + <tr> | ||
| 343 | + <td>selfRef和other的shape无法做broadcast。</td> | ||
| 344 | + </tr> | ||
| 345 | + <tr> | ||
| 346 | + <td>selfRef和other做broadcast后的shape不等于selfRef的shape。</td> | ||
| 347 | + </tr> | ||
| 348 | + <tr> | ||
| 349 | + <td>selfRef、other的维度大于8。</td> | ||
| 350 | + </tr> | ||
| 351 | + <tr> | ||
| 352 | + <td>selfRef和other有且仅有一个为空Tensor。</td> | ||
| 353 | + </tr> | ||
| 354 | + </tbody> | ||
| 355 | + </table> | ||
| 356 | + | ||
| 357 | +## aclnnInplaceEqTensor | ||
| 358 | + | ||
| 359 | +- **参数说明:** | ||
| 360 | + | ||
| 361 | + <table style="undefined;table-layout: fixed; width: 1150px"><colgroup> | ||
| 362 | + <col style="width: 168px"> | ||
| 363 | + <col style="width: 128px"> | ||
| 364 | + <col style="width: 854px"> | ||
| 365 | + </colgroup> | ||
| 366 | + <thead> | ||
| 367 | + <tr> | ||
| 368 | + <th>参数名</th> | ||
| 369 | + <th>输入/输出</th> | ||
| 370 | + <th>描述</th> | ||
| 371 | + </tr></thead> | ||
| 372 | + <tbody> | ||
| 373 | + <tr> | ||
| 374 | + <td>workspace</td> | ||
| 375 | + <td>输入</td> | ||
| 376 | + <td>在Device侧申请的workspace内存地址。</td> | ||
| 377 | + </tr> | ||
| 378 | + <tr> | ||
| 379 | + <td>workspaceSize</td> | ||
| 380 | + <td>输入</td> | ||
| 381 | + <td>在Device侧申请的workspace大小,由第一段接口aclnnInplaceEqTensorGetWorkspaceSize获取。</td> | ||
| 382 | + </tr> | ||
| 383 | + <tr> | ||
| 384 | + <td>executor</td> | ||
| 385 | + <td>输入</td> | ||
| 386 | + <td>op执行器,包含了算子计算流程。</td> | ||
| 387 | + </tr> | ||
| 388 | + <tr> | ||
| 389 | + <td>stream</td> | ||
| 390 | + <td>输入</td> | ||
| 391 | + <td>指定执行任务的Stream。</td> | ||
| 392 | + </tr> | ||
| 393 | + </tbody> | ||
| 394 | + </table> | ||
| 395 | + | ||
| 396 | +- **返回值:** | ||
| 397 | + | ||
| 398 | + aclnnStatus: 返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 399 | + | ||
| 400 | +## 约束说明 | ||
| 401 | + | ||
| 402 | +- 确定性计算: | ||
| 403 | + - aclnnEqTensor&aclnnInplaceEqTensor默认确定性实现。 | ||
| 404 | + | ||
| 405 | +## 调用示例 | ||
| 406 | + | ||
| 407 | +示例代码如下,仅供参考,具体编译和执行过程请参考[编译与运行样例](../../../../docs/zh/context/编译与运行样例.md)。 | ||
| 408 | + | ||
| 409 | +**aclnnEqTensor示例代码:** | ||
| 410 | + | ||
| 411 | +```Cpp | ||
| 412 | +#include <iostream> | ||
| 413 | +#include <vector> | ||
| 414 | +#include "acl/acl.h" | ||
| 415 | +#include "aclnnop/aclnn_eq_tensor.h" | ||
| 416 | + | ||
| 417 | +#define CHECK_RET(cond, return_expr) \ | ||
| 418 | + do { \ | ||
| 419 | + if (!(cond)) { \ | ||
| 420 | + return_expr; \ | ||
| 421 | + } \ | ||
| 422 | + } while (0) | ||
| 423 | + | ||
| 424 | +#define LOG_PRINT(message, ...) \ | ||
| 425 | + do { \ | ||
| 426 | + printf(message, ##__VA_ARGS__); \ | ||
| 427 | + } while (0) | ||
| 428 | + | ||
| 429 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 430 | +{ | ||
| 431 | + int64_t shape_size = 1; | ||
| 432 | + for (auto i : shape) { | ||
| 433 | + shape_size *= i; | ||
| 434 | + } | ||
| 435 | + return shape_size; | ||
| 436 | +} | ||
| 437 | + | ||
| 438 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 439 | +{ | ||
| 440 | + // 固定写法,资源初始化 | ||
| 441 | + auto ret = aclInit(nullptr); | ||
| 442 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 443 | + ret = aclrtSetDevice(deviceId); | ||
| 444 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 445 | + ret = aclrtCreateStream(stream); | ||
| 446 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 447 | + return 0; | ||
| 448 | +} | ||
| 449 | + | ||
| 450 | +template <typename T> | ||
| 451 | +int CreateAclTensor( | ||
| 452 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, | ||
| 453 | + aclTensor** tensor) | ||
| 454 | +{ | ||
| 455 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 456 | + // 调用aclrtMalloc申请device侧内存 | ||
| 457 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 458 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 459 | + | ||
| 460 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 461 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 462 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 463 | + | ||
| 464 | + // 计算连续tensor的strides | ||
| 465 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 466 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 467 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 468 | + } | ||
| 469 | + | ||
| 470 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 471 | + *tensor = aclCreateTensor( | ||
| 472 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), | ||
| 473 | + *deviceAddr); | ||
| 474 | + return 0; | ||
| 475 | +} | ||
| 476 | + | ||
| 477 | +aclError InitAcl(int32_t deviceId, aclrtStream* stream) | ||
| 478 | +{ | ||
| 479 | + auto ret = Init(deviceId, stream); | ||
| 480 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 481 | + return ACL_SUCCESS; | ||
| 482 | +} | ||
| 483 | + | ||
| 484 | +aclError CreateInputs( | ||
| 485 | + std::vector<int64_t>& selfShape, std::vector<int64_t>& otherShape, std::vector<int64_t>& outShape, | ||
| 486 | + void** selfDeviceAddr, void** otherDeviceAddr, void** outDeviceAddr, aclTensor** self, aclTensor** other, | ||
| 487 | + aclTensor** out) | ||
| 488 | +{ | ||
| 489 | + std::vector<double> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
| 490 | + std::vector<double> otherHostData = {0, 1, 9, 9, 9, 9, 9, 9}; | ||
| 491 | + std::vector<char> outHostData = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 492 | + | ||
| 493 | + auto ret = CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_DOUBLE, self); | ||
| 494 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 495 | + | ||
| 496 | + ret = CreateAclTensor(otherHostData, otherShape, otherDeviceAddr, aclDataType::ACL_DOUBLE, other); | ||
| 497 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 498 | + | ||
| 499 | + ret = CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_BOOL, out); | ||
| 500 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 501 | + | ||
| 502 | + return ACL_SUCCESS; | ||
| 503 | +} | ||
| 504 | + | ||
| 505 | +aclError ExecOpApi( | ||
| 506 | + aclTensor* self, aclTensor* other, aclTensor* out, void** workspaceAddrOut, uint64_t& workspaceSize, | ||
| 507 | + void* outDeviceAddr, std::vector<int64_t>& outShape, aclrtStream stream) | ||
| 508 | +{ | ||
| 509 | + aclOpExecutor* executor; | ||
| 510 | + | ||
| 511 | + auto ret = aclnnEqTensorGetWorkspaceSize(self, other, out, &workspaceSize, &executor); | ||
| 512 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEqTensorGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 513 | + | ||
| 514 | + void* workspaceAddr = nullptr; | ||
| 515 | + if (workspaceSize > 0) { | ||
| 516 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 517 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 518 | + } | ||
| 519 | + *workspaceAddrOut = workspaceAddr; | ||
| 520 | + | ||
| 521 | + ret = aclnnEqTensor(workspaceAddr, workspaceSize, executor, stream); | ||
| 522 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEqTensor failed. ERROR: %d\n", ret); return ret); | ||
| 523 | + | ||
| 524 | + ret = aclrtSynchronizeStream(stream); | ||
| 525 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 526 | + | ||
| 527 | + auto size = GetShapeSize(outShape); | ||
| 528 | + std::vector<char> resultData(size, 0); | ||
| 529 | + | ||
| 530 | + ret = aclrtMemcpy( | ||
| 531 | + resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(char), | ||
| 532 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 533 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 534 | + | ||
| 535 | + for (int64_t i = 0; i < size; i++) { | ||
| 536 | + LOG_PRINT("result[%ld] is: %d\n", i, resultData[i]); | ||
| 537 | + } | ||
| 538 | + | ||
| 539 | + return ACL_SUCCESS; | ||
| 540 | +} | ||
| 541 | + | ||
| 542 | +int main() | ||
| 543 | +{ | ||
| 544 | + int32_t deviceId = 0; | ||
| 545 | + aclrtStream stream; | ||
| 546 | + | ||
| 547 | + auto ret = InitAcl(deviceId, &stream); | ||
| 548 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 549 | + | ||
| 550 | + std::vector<int64_t> selfShape = {4, 2}; | ||
| 551 | + std::vector<int64_t> otherShape = {4, 2}; | ||
| 552 | + std::vector<int64_t> outShape = {4, 2}; | ||
| 553 | + | ||
| 554 | + void* selfDeviceAddr = nullptr; | ||
| 555 | + void* otherDeviceAddr = nullptr; | ||
| 556 | + void* outDeviceAddr = nullptr; | ||
| 557 | + | ||
| 558 | + aclTensor* self = nullptr; | ||
| 559 | + aclTensor* other = nullptr; | ||
| 560 | + aclTensor* out = nullptr; | ||
| 561 | + | ||
| 562 | + ret = CreateInputs( | ||
| 563 | + selfShape, otherShape, outShape, &selfDeviceAddr, &otherDeviceAddr, &outDeviceAddr, &self, &other, &out); | ||
| 564 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 565 | + | ||
| 566 | + uint64_t workspaceSize = 0; | ||
| 567 | + void* workspaceAddr = nullptr; | ||
| 568 | + | ||
| 569 | + ret = ExecOpApi(self, other, out, &workspaceAddr, workspaceSize, outDeviceAddr, outShape, stream); | ||
| 570 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 571 | + | ||
| 572 | + // 释放资源 | ||
| 573 | + aclDestroyTensor(self); | ||
| 574 | + aclDestroyTensor(other); | ||
| 575 | + aclDestroyTensor(out); | ||
| 576 | + | ||
| 577 | + aclrtFree(selfDeviceAddr); | ||
| 578 | + aclrtFree(otherDeviceAddr); | ||
| 579 | + aclrtFree(outDeviceAddr); | ||
| 580 | + | ||
| 581 | + if (workspaceSize > 0) { | ||
| 582 | + aclrtFree(workspaceAddr); | ||
| 583 | + } | ||
| 584 | + | ||
| 585 | + aclrtDestroyStream(stream); | ||
| 586 | + aclrtResetDevice(deviceId); | ||
| 587 | + aclFinalize(); | ||
| 588 | + return 0; | ||
| 589 | +} | ||
| 590 | +``` | ||
| 591 | + | ||
| 592 | +**aclnnInplaceEqTensor示例代码:** | ||
| 593 | + | ||
| 594 | +```Cpp | ||
| 595 | +#include <iostream> | ||
| 596 | +#include <vector> | ||
| 597 | +#include "acl/acl.h" | ||
| 598 | +#include "aclnnop/aclnn_eq_tensor.h" | ||
| 599 | + | ||
| 600 | +#define CHECK_RET(cond, return_expr) \ | ||
| 601 | + do { \ | ||
| 602 | + if (!(cond)) { \ | ||
| 603 | + return_expr; \ | ||
| 604 | + } \ | ||
| 605 | + } while (0) | ||
| 606 | + | ||
| 607 | +#define LOG_PRINT(message, ...) \ | ||
| 608 | + do { \ | ||
| 609 | + printf(message, ##__VA_ARGS__); \ | ||
| 610 | + } while (0) | ||
| 611 | + | ||
| 612 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 613 | +{ | ||
| 614 | + int64_t shapeSize = 1; | ||
| 615 | + for (auto i : shape) { | ||
| 616 | + shapeSize *= i; | ||
| 617 | + } | ||
| 618 | + return shapeSize; | ||
| 619 | +} | ||
| 620 | + | ||
| 621 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 622 | +{ | ||
| 623 | + // 固定写法,资源初始化 | ||
| 624 | + auto ret = aclInit(nullptr); | ||
| 625 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 626 | + ret = aclrtSetDevice(deviceId); | ||
| 627 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 628 | + ret = aclrtCreateStream(stream); | ||
| 629 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 630 | + return 0; | ||
| 631 | +} | ||
| 632 | + | ||
| 633 | +template <typename T> | ||
| 634 | +int CreateAclTensor( | ||
| 635 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, | ||
| 636 | + aclTensor** tensor) | ||
| 637 | +{ | ||
| 638 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 639 | + // 调用aclrtMalloc申请device侧内存 | ||
| 640 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 641 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 642 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 643 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 644 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 645 | + | ||
| 646 | + // 计算连续tensor的strides | ||
| 647 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 648 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 649 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 650 | + } | ||
| 651 | + | ||
| 652 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 653 | + *tensor = aclCreateTensor( | ||
| 654 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), | ||
| 655 | + *deviceAddr); | ||
| 656 | + return 0; | ||
| 657 | +} | ||
| 658 | + | ||
| 659 | +aclError InitAcl(int32_t deviceId, aclrtStream* stream) | ||
| 660 | +{ | ||
| 661 | + auto ret = Init(deviceId, stream); | ||
| 662 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 663 | + return ACL_SUCCESS; | ||
| 664 | +} | ||
| 665 | + | ||
| 666 | +aclError CreateInputs( | ||
| 667 | + std::vector<int64_t>& selfShape, std::vector<int64_t>& otherShape, void** selfDeviceAddr, void** otherDeviceAddr, | ||
| 668 | + aclTensor** self, aclTensor** other) | ||
| 669 | +{ | ||
| 670 | + std::vector<double> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
| 671 | + std::vector<double> otherHostData = {1, 1, 3, 3, 5, 5, 7, 7}; | ||
| 672 | + | ||
| 673 | + // 创建 self | ||
| 674 | + auto ret = CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_DOUBLE, self); | ||
| 675 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 676 | + | ||
| 677 | + // 创建 other | ||
| 678 | + ret = CreateAclTensor(otherHostData, otherShape, otherDeviceAddr, aclDataType::ACL_DOUBLE, other); | ||
| 679 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 680 | + | ||
| 681 | + return ACL_SUCCESS; | ||
| 682 | +} | ||
| 683 | + | ||
| 684 | +aclError ExecOpApi( | ||
| 685 | + aclTensor* self, aclTensor* other, void** workspaceAddrOut, uint64_t& workspaceSize, void* selfDeviceAddr, | ||
| 686 | + std::vector<int64_t>& selfShape, aclrtStream stream) | ||
| 687 | +{ | ||
| 688 | + aclOpExecutor* executor; | ||
| 689 | + | ||
| 690 | + // 获取 workspace 大小 | ||
| 691 | + auto ret = aclnnInplaceEqTensorGetWorkspaceSize(self, other, &workspaceSize, &executor); | ||
| 692 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceEqTensorGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 693 | + | ||
| 694 | + // 分配 workspace | ||
| 695 | + void* workspaceAddr = nullptr; | ||
| 696 | + if (workspaceSize > 0) { | ||
| 697 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 698 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 699 | + } | ||
| 700 | + *workspaceAddrOut = workspaceAddr; | ||
| 701 | + | ||
| 702 | + // 执行算子 | ||
| 703 | + ret = aclnnInplaceEqTensor(workspaceAddr, workspaceSize, executor, stream); | ||
| 704 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceEqTensor failed. ERROR: %d\n", ret); return ret); | ||
| 705 | + | ||
| 706 | + // 同步 | ||
| 707 | + ret = aclrtSynchronizeStream(stream); | ||
| 708 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 709 | + | ||
| 710 | + // 拷贝输出 | ||
| 711 | + auto size = GetShapeSize(selfShape); | ||
| 712 | + std::vector<double> resultData(size); | ||
| 713 | + | ||
| 714 | + ret = aclrtMemcpy( | ||
| 715 | + resultData.data(), resultData.size() * sizeof(resultData[0]), selfDeviceAddr, size * sizeof(double), | ||
| 716 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 717 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 718 | + | ||
| 719 | + for (int64_t i = 0; i < size; i++) { | ||
| 720 | + LOG_PRINT("result[%ld] is: %lf\n", i, resultData[i]); | ||
| 721 | + } | ||
| 722 | + | ||
| 723 | + return ACL_SUCCESS; | ||
| 724 | +} | ||
| 725 | + | ||
| 726 | +int main() | ||
| 727 | +{ | ||
| 728 | + int32_t deviceId = 0; | ||
| 729 | + aclrtStream stream; | ||
| 730 | + | ||
| 731 | + auto ret = InitAcl(deviceId, &stream); | ||
| 732 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 733 | + | ||
| 734 | + std::vector<int64_t> selfShape = {4, 2}; | ||
| 735 | + std::vector<int64_t> otherShape = {4, 2}; | ||
| 736 | + void* selfDeviceAddr = nullptr; | ||
| 737 | + void* otherDeviceAddr = nullptr; | ||
| 738 | + aclTensor* self = nullptr; | ||
| 739 | + aclTensor* other = nullptr; | ||
| 740 | + | ||
| 741 | + ret = CreateInputs(selfShape, otherShape, &selfDeviceAddr, &otherDeviceAddr, &self, &other); | ||
| 742 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 743 | + | ||
| 744 | + uint64_t workspaceSize = 0; | ||
| 745 | + void* workspaceAddr = nullptr; | ||
| 746 | + | ||
| 747 | + ret = ExecOpApi(self, other, &workspaceAddr, workspaceSize, selfDeviceAddr, selfShape, stream); | ||
| 748 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 749 | + | ||
| 750 | + // 销毁 | ||
| 751 | + aclDestroyTensor(self); | ||
| 752 | + aclDestroyTensor(other); | ||
| 753 | + | ||
| 754 | + // 释放 | ||
| 755 | + aclrtFree(selfDeviceAddr); | ||
| 756 | + aclrtFree(otherDeviceAddr); | ||
| 757 | + if (workspaceSize > 0) { | ||
| 758 | + aclrtFree(workspaceAddr); | ||
| 759 | + } | ||
| 760 | + | ||
| 761 | + aclrtDestroyStream(stream); | ||
| 762 | + aclrtResetDevice(deviceId); | ||
| 763 | + aclFinalize(); | ||
| 764 | + return 0; | ||
| 765 | +} | ||
| 766 | +``` | ||
| @@ -0,0 +1,408 @@ | |||
| 1 | +# aclnnIsInScalarTensor | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +## 产品支持情况 | ||
| 5 | + | ||
| 6 | +| 产品 | 是否支持 | | ||
| 7 | +| :----------------------------------------------------------- | :------: | | ||
| 8 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | ||
| 9 | + | ||
| 10 | +## 功能说明 | ||
| 11 | + | ||
| 12 | +检查element中的元素是否等于testElement。 | ||
| 13 | + | ||
| 14 | +## 函数原型 | ||
| 15 | + | ||
| 16 | +每个算子分为[两段式接口](../../../../docs/zh/context/两段式接口.md),必须先调用“aclnnIsInScalarTensorGetWorkspaceSize”接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用“aclnnIsInScalarTensor”接口执行计算。 | ||
| 17 | + | ||
| 18 | +```Cpp | ||
| 19 | +aclnnStatus aclnnIsInScalarTensorGetWorkspaceSize( | ||
| 20 | + const aclTensor* self, | ||
| 21 | + const aclScalar* element, | ||
| 22 | + bool assumeUnique, | ||
| 23 | + bool invert, | ||
| 24 | + aclTensor* out, | ||
| 25 | + uint64_t* workspaceSize, | ||
| 26 | + aclOpExecutor** executor) | ||
| 27 | +``` | ||
| 28 | + | ||
| 29 | +```Cpp | ||
| 30 | +aclnnStatus aclnnIsInScalarTensor( | ||
| 31 | + void* workspace, | ||
| 32 | + uint64_t workspaceSize, | ||
| 33 | + aclOpExecutor* executor, | ||
| 34 | + aclrtStream stream) | ||
| 35 | +``` | ||
| 36 | + | ||
| 37 | +## aclnnIsInScalarTensorGetWorkspaceSize | ||
| 38 | + | ||
| 39 | +- **参数说明:** | ||
| 40 | + | ||
| 41 | + <table style="undefined;table-layout: fixed; width: 1555px"><colgroup> | ||
| 42 | + <col style="width: 217px"> | ||
| 43 | + <col style="width: 125px"> | ||
| 44 | + <col style="width: 247px"> | ||
| 45 | + <col style="width: 317px"> | ||
| 46 | + <col style="width: 233px"> | ||
| 47 | + <col style="width: 126px"> | ||
| 48 | + <col style="width: 144px"> | ||
| 49 | + <col style="width: 146px"> | ||
| 50 | + </colgroup> | ||
| 51 | + <thead> | ||
| 52 | + <tr> | ||
| 53 | + <th>参数名</th> | ||
| 54 | + <th>输入/输出</th> | ||
| 55 | + <th>描述</th> | ||
| 56 | + <th>使用说明</th> | ||
| 57 | + <th>数据类型</th> | ||
| 58 | + <th>数据格式</th> | ||
| 59 | + <th>维度(shape)</th> | ||
| 60 | + <th>非连续Tensor</th> | ||
| 61 | + </tr></thead> | ||
| 62 | + <tbody> | ||
| 63 | + <tr> | ||
| 64 | + <td>self(aclTensor*)</td> | ||
| 65 | + <td>输入</td> | ||
| 66 | + <td>输入张量,公式中的self。</td> | ||
| 67 | + <td>-</td> | ||
| 68 | + <td>FLOAT、FLOAT16、DOUBLE、BFLOAT16、INT8、INT16、INT32、INT64、UINT8、UINT16、BOOL、COMPLEX64、COMPLEX128</td> | ||
| 69 | + <td>ND</td> | ||
| 70 | + <td>0-8</td> | ||
| 71 | + <td>√</td> | ||
| 72 | + </tr> | ||
| 73 | + <tr> | ||
| 74 | + <td>element(aclScalar*)</td> | ||
| 75 | + <td>输入</td> | ||
| 76 | + <td>输入标量,公式中的element。</td> | ||
| 77 | + <td>数据类型需要与self的数据类型满足<a href="../../../../docs/zh/context/互推导关系.md" target="_blank">数据类型推导规则</a>。</td> | ||
| 78 | + <td>FLOAT、FLOAT16、DOUBLE、BFLOAT16、INT8、INT16、INT32、INT64、UINT8、UINT16、BOOL、COMPLEX64、COMPLEX128</td> | ||
| 79 | + <td>-</td> | ||
| 80 | + <td>-</td> | ||
| 81 | + <td>-</td> | ||
| 82 | + </tr> | ||
| 83 | + <tr> | ||
| 84 | + <td>assumeUnique(bool)</td> | ||
| 85 | + <td>输入</td> | ||
| 86 | + <td>是否假设element唯一,公式中的assumeUnique。</td> | ||
| 87 | + <td>-</td> | ||
| 88 | + <td>-</td> | ||
| 89 | + <td>-</td> | ||
| 90 | + <td>-</td> | ||
| 91 | + <td>-</td> | ||
| 92 | + </tr> | ||
| 93 | + <tr> | ||
| 94 | + <td>invert(bool)</td> | ||
| 95 | + <td>输入</td> | ||
| 96 | + <td>是否取反,公式中的invert。</td> | ||
| 97 | + <td>-</td> | ||
| 98 | + <td>-</td> | ||
| 99 | + <td>-</td> | ||
| 100 | + <td>-</td> | ||
| 101 | + <td>-</td> | ||
| 102 | + </tr> | ||
| 103 | + <tr> | ||
| 104 | + <td>out(aclTensor*)</td> | ||
| 105 | + <td>输出</td> | ||
| 106 | + <td>输出张量,公式中的out。</td> | ||
| 107 | + <td>数据类型为BOOL。shape与self相同。</td> | ||
| 108 | + <td>BOOL</td> | ||
| 109 | + <td>ND</td> | ||
| 110 | + <td>0-8</td> | ||
| 111 | + <td>√</td> | ||
| 112 | + </tr> | ||
| 113 | + <tr> | ||
| 114 | + <td>workspaceSize(uint64_t*)</td> | ||
| 115 | + <td>输出</td> | ||
| 116 | + <td>返回需要在Device侧申请的workspace大小。</td> | ||
| 117 | + <td>-</td> | ||
| 118 | + <td>-</td> | ||
| 119 | + <td>-</td> | ||
| 120 | + <td>-</td> | ||
| 121 | + <td>-</td> | ||
| 122 | + </tr> | ||
| 123 | + <tr> | ||
| 124 | + <td>executor(aclOpExecutor**)</td> | ||
| 125 | + <td>输出</td> | ||
| 126 | + <td>返回op执行器,包含了算子计算流程。</td> | ||
| 127 | + <td>-</td> | ||
| 128 | + <td>-</td> | ||
| 129 | + <td>-</td> | ||
| 130 | + <td>-</td> | ||
| 131 | + <td>-</td> | ||
| 132 | + </tr> | ||
| 133 | + </tbody></table> | ||
| 134 | + | ||
| 135 | + - <term>Atlas 训练系列产品</term>、<term>Atlas 推理系列产品</term>:不支持BFLOAT16、COMPLEX64、COMPLEX128。 | ||
| 136 | + | ||
| 137 | +- **返回值:** | ||
| 138 | + | ||
| 139 | + aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 140 | + | ||
| 141 | + 第一段接口完成入参校验,出现以下场景时报错: | ||
| 142 | + | ||
| 143 | + <table style="undefined;table-layout: fixed; width: 1150px"><colgroup> | ||
| 144 | + <col style="width: 300px"> | ||
| 145 | + <col style="width: 134px"> | ||
| 146 | + <col style="width: 716px"> | ||
| 147 | + </colgroup> | ||
| 148 | + <thead> | ||
| 149 | + <tr> | ||
| 150 | + <th>返回码</th> | ||
| 151 | + <th>错误码</th> | ||
| 152 | + <th>描述</th> | ||
| 153 | + </tr></thead> | ||
| 154 | + <tbody> | ||
| 155 | + <tr> | ||
| 156 | + <td>ACLNN_ERR_PARAM_NULLPTR</td> | ||
| 157 | + <td>161001</td> | ||
| 158 | + <td>传入的self、element或out是空指针。</td> | ||
| 159 | + </tr> | ||
| 160 | + <tr> | ||
| 161 | + <td rowspan="3">ACLNN_ERR_PARAM_INVALID</td> | ||
| 162 | + <td rowspan="3">161002</td> | ||
| 163 | + <td>self或out的数据类型不在支持范围之内。</td> | ||
| 164 | + </tr> | ||
| 165 | + <tr> | ||
| 166 | + <td>self和out的维度超过8维。</td> | ||
| 167 | + </tr> | ||
| 168 | + <tr> | ||
| 169 | + <td>self和out的shape不一致。</td> | ||
| 170 | + </tr> | ||
| 171 | + </tbody></table> | ||
| 172 | + | ||
| 173 | +## aclnnIsInScalarTensor | ||
| 174 | + | ||
| 175 | +- **参数说明:** | ||
| 176 | + | ||
| 177 | + <table style="undefined;table-layout: fixed; width: 1151px"><colgroup> | ||
| 178 | + <col style="width: 184px"> | ||
| 179 | + <col style="width: 134px"> | ||
| 180 | + <col style="width: 833px"> | ||
| 181 | + </colgroup> | ||
| 182 | + <thead> | ||
| 183 | + <tr> | ||
| 184 | + <th>参数名</th> | ||
| 185 | + <th>输入/输出</th> | ||
| 186 | + <th>描述</th> | ||
| 187 | + </tr></thead> | ||
| 188 | + <tbody> | ||
| 189 | + <tr> | ||
| 190 | + <td>workspace</td> | ||
| 191 | + <td>输入</td> | ||
| 192 | + <td>在Device侧申请的workspace内存地址。</td> | ||
| 193 | + </tr> | ||
| 194 | + <tr> | ||
| 195 | + <td>workspaceSize</td> | ||
| 196 | + <td>输入</td> | ||
| 197 | + <td>在Device侧申请的workspace大小,由第一段接口aclnnIsInScalarTensorGetWorkspaceSize获取。</td> | ||
| 198 | + </tr> | ||
| 199 | + <tr> | ||
| 200 | + <td>executor</td> | ||
| 201 | + <td>输入</td> | ||
| 202 | + <td>op执行器,包含了算子计算流程。</td> | ||
| 203 | + </tr> | ||
| 204 | + <tr> | ||
| 205 | + <td>stream</td> | ||
| 206 | + <td>输入</td> | ||
| 207 | + <td>指定执行任务的Stream。</td> | ||
| 208 | + </tr> | ||
| 209 | + </tbody></table> | ||
| 210 | + | ||
| 211 | +- **返回值:** | ||
| 212 | + | ||
| 213 | + aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 214 | + | ||
| 215 | +## 约束说明 | ||
| 216 | + | ||
| 217 | +- 确定性计算: | ||
| 218 | + - aclnnIsInScalarTensor默认确定性实现。 | ||
| 219 | + | ||
| 220 | +## 调用示例 | ||
| 221 | + | ||
| 222 | +示例代码如下,仅供参考,具体编译和执行过程请参考[编译与运行样例](../../../../docs/zh/context/编译与运行样例.md)。 | ||
| 223 | + | ||
| 224 | +```Cpp | ||
| 225 | +#include <iostream> | ||
| 226 | +#include <vector> | ||
| 227 | +#include "acl/acl.h" | ||
| 228 | +#include "aclnnop/aclnn_isin.h" | ||
| 229 | + | ||
| 230 | +#define CHECK_RET(cond, return_expr) \ | ||
| 231 | + do { \ | ||
| 232 | + if (!(cond)) { \ | ||
| 233 | + return_expr; \ | ||
| 234 | + } \ | ||
| 235 | + } while (0) | ||
| 236 | + | ||
| 237 | +#define LOG_PRINT(message, ...) \ | ||
| 238 | + do { \ | ||
| 239 | + printf(message, ##__VA_ARGS__); \ | ||
| 240 | + } while (0) | ||
| 241 | + | ||
| 242 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 243 | +{ | ||
| 244 | + int64_t shape_size = 1; | ||
| 245 | + for (auto i : shape) { | ||
| 246 | + shape_size *= i; | ||
| 247 | + } | ||
| 248 | + return shape_size; | ||
| 249 | +} | ||
| 250 | + | ||
| 251 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 252 | +{ | ||
| 253 | + // 固定写法,资源初始化 | ||
| 254 | + auto ret = aclInit(nullptr); | ||
| 255 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 256 | + ret = aclrtSetDevice(deviceId); | ||
| 257 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 258 | + ret = aclrtCreateStream(stream); | ||
| 259 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 260 | + return 0; | ||
| 261 | +} | ||
| 262 | + | ||
| 263 | +template <typename T> | ||
| 264 | +int CreateAclTensor( | ||
| 265 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, | ||
| 266 | + aclTensor** tensor) | ||
| 267 | +{ | ||
| 268 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 269 | + // 调用aclrtMalloc申请device侧内存 | ||
| 270 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 271 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 272 | + | ||
| 273 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 274 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 275 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 276 | + | ||
| 277 | + // 计算连续tensor的strides | ||
| 278 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 279 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 280 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 284 | + *tensor = aclCreateTensor( | ||
| 285 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), | ||
| 286 | + *deviceAddr); | ||
| 287 | + return 0; | ||
| 288 | +} | ||
| 289 | + | ||
| 290 | +aclError InitAcl(int32_t deviceId, aclrtStream* stream) | ||
| 291 | +{ | ||
| 292 | + auto ret = Init(deviceId, stream); | ||
| 293 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 294 | + return ACL_SUCCESS; | ||
| 295 | +} | ||
| 296 | + | ||
| 297 | +aclError CreateInputs( | ||
| 298 | + std::vector<int64_t>& testElementsShape, std::vector<int64_t>& outShape, void** testElementsDeviceAddr, | ||
| 299 | + void** outDeviceAddr, aclTensor** testElements, aclTensor** out, aclScalar** element, bool& assumeUnique, | ||
| 300 | + bool& invert) | ||
| 301 | +{ | ||
| 302 | + std::vector<double> testElementsHostData = {1.0, 2.0, 3.0}; | ||
| 303 | + std::vector<char> outHostData = {0}; | ||
| 304 | + double elementValue = 4.0; | ||
| 305 | + | ||
| 306 | + // 创建 testElements Tensor | ||
| 307 | + auto ret = CreateAclTensor( | ||
| 308 | + testElementsHostData, testElementsShape, testElementsDeviceAddr, aclDataType::ACL_DOUBLE, testElements); | ||
| 309 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 310 | + | ||
| 311 | + // 创建 element Scalar | ||
| 312 | + *element = aclCreateScalar(&elementValue, aclDataType::ACL_DOUBLE); | ||
| 313 | + CHECK_RET(*element != nullptr, return ACL_ERROR_INVALID_PARAM); | ||
| 314 | + | ||
| 315 | + // 创建 out Tensor | ||
| 316 | + ret = CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_BOOL, out); | ||
| 317 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 318 | + | ||
| 319 | + return ACL_SUCCESS; | ||
| 320 | +} | ||
| 321 | + | ||
| 322 | +aclError ExecOpApi( | ||
| 323 | + aclScalar* element, aclTensor* testElements, bool assumeUnique, bool invert, aclTensor* out, | ||
| 324 | + void** workspaceAddrOut, uint64_t& workspaceSize, void* outDeviceAddr, aclrtStream stream) | ||
| 325 | +{ | ||
| 326 | + aclOpExecutor* executor; | ||
| 327 | + | ||
| 328 | + // 第一段接口 | ||
| 329 | + auto ret = aclnnIsInScalarTensorGetWorkspaceSize( | ||
| 330 | + element, testElements, assumeUnique, invert, out, &workspaceSize, &executor); | ||
| 331 | + CHECK_RET( | ||
| 332 | + ret == ACL_SUCCESS, LOG_PRINT("aclnnIsInScalarTensorGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 333 | + | ||
| 334 | + // 分配 workspace | ||
| 335 | + void* workspaceAddr = nullptr; | ||
| 336 | + if (workspaceSize > 0) { | ||
| 337 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 338 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 339 | + } | ||
| 340 | + *workspaceAddrOut = workspaceAddr; | ||
| 341 | + | ||
| 342 | + // 第二段接口 | ||
| 343 | + ret = aclnnIsInScalarTensor(workspaceAddr, workspaceSize, executor, stream); | ||
| 344 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnIsInScalarTensor failed. ERROR: %d\n", ret); return ret); | ||
| 345 | + | ||
| 346 | + // 同步 | ||
| 347 | + ret = aclrtSynchronizeStream(stream); | ||
| 348 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 349 | + | ||
| 350 | + // 输出拷贝 | ||
| 351 | + char resultData = 0; | ||
| 352 | + ret = aclrtMemcpy(&resultData, sizeof(char), outDeviceAddr, sizeof(char), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 353 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 354 | + | ||
| 355 | + LOG_PRINT("result is: %d\n", static_cast<bool>(resultData)); | ||
| 356 | + | ||
| 357 | + return ACL_SUCCESS; | ||
| 358 | +} | ||
| 359 | + | ||
| 360 | +int main() | ||
| 361 | +{ | ||
| 362 | + int32_t deviceId = 0; | ||
| 363 | + aclrtStream stream; | ||
| 364 | + | ||
| 365 | + auto ret = InitAcl(deviceId, &stream); | ||
| 366 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 367 | + | ||
| 368 | + std::vector<int64_t> testElementsShape = {3}; | ||
| 369 | + std::vector<int64_t> outShape = {}; | ||
| 370 | + void* testElementsDeviceAddr = nullptr; | ||
| 371 | + void* outDeviceAddr = nullptr; | ||
| 372 | + aclTensor* testElements = nullptr; | ||
| 373 | + aclTensor* out = nullptr; | ||
| 374 | + aclScalar* element = nullptr; | ||
| 375 | + | ||
| 376 | + bool assumeUnique = false; | ||
| 377 | + bool invert = true; | ||
| 378 | + | ||
| 379 | + ret = CreateInputs( | ||
| 380 | + testElementsShape, outShape, &testElementsDeviceAddr, &outDeviceAddr, &testElements, &out, &element, assumeUnique, | ||
| 381 | + invert); | ||
| 382 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 383 | + | ||
| 384 | + uint64_t workspaceSize = 0; | ||
| 385 | + void* workspaceAddr = nullptr; | ||
| 386 | + | ||
| 387 | + ret = | ||
| 388 | + ExecOpApi(element, testElements, assumeUnique, invert, out, &workspaceAddr, workspaceSize, outDeviceAddr, stream); | ||
| 389 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 390 | + | ||
| 391 | + // 释放 | ||
| 392 | + aclDestroyScalar(element); | ||
| 393 | + aclDestroyTensor(testElements); | ||
| 394 | + aclDestroyTensor(out); | ||
| 395 | + | ||
| 396 | + aclrtFree(testElementsDeviceAddr); | ||
| 397 | + aclrtFree(outDeviceAddr); | ||
| 398 | + | ||
| 399 | + if (workspaceSize > 0) { | ||
| 400 | + aclrtFree(workspaceAddr); | ||
| 401 | + } | ||
| 402 | + | ||
| 403 | + aclrtDestroyStream(stream); | ||
| 404 | + aclrtResetDevice(deviceId); | ||
| 405 | + aclFinalize(); | ||
| 406 | + return 0; | ||
| 407 | +} | ||
| 408 | +``` | ||
| @@ -0,0 +1,407 @@ | |||
| 1 | +# aclnnIsInTensorScalar | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +## 产品支持情况 | ||
| 5 | + | ||
| 6 | +| 产品 | 是否支持 | | ||
| 7 | +| :----------------------------------------------------------- | :------: | | ||
| 8 | +| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | ||
| 9 | + | ||
| 10 | +## 功能说明 | ||
| 11 | + | ||
| 12 | +检查element中的元素是否等于testElement。 | ||
| 13 | + | ||
| 14 | +## 函数原型 | ||
| 15 | + | ||
| 16 | +每个算子分为[两段式接口](../../../../docs/zh/context/两段式接口.md),必须先调用“aclnnIsInTensorScalarGetWorkspaceSize”接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用“aclnnIsInTensorScalar”接口执行计算。 | ||
| 17 | + | ||
| 18 | +```Cpp | ||
| 19 | +aclnnStatus aclnnIsInTensorScalarGetWorkspaceSize( | ||
| 20 | + const aclTensor* self, | ||
| 21 | + const aclScalar* element, | ||
| 22 | + bool assumeUnique, | ||
| 23 | + bool invert, | ||
| 24 | + aclScalar* out, | ||
| 25 | + uint64_t* workspaceSize, | ||
| 26 | + aclOpExecutor** executor) | ||
| 27 | +``` | ||
| 28 | + | ||
| 29 | +```Cpp | ||
| 30 | +aclnnStatus aclnnIsInTensorScalar( | ||
| 31 | + void* workspace, | ||
| 32 | + uint64_t workspaceSize, | ||
| 33 | + aclOpExecutor* executor, | ||
| 34 | + aclrtStream stream) | ||
| 35 | +``` | ||
| 36 | + | ||
| 37 | +## aclnnIsInTensorScalarGetWorkspaceSize | ||
| 38 | + | ||
| 39 | +- **参数说明:** | ||
| 40 | + | ||
| 41 | + <table style="undefined;table-layout: fixed; width: 1555px"><colgroup> | ||
| 42 | + <col style="width: 217px"> | ||
| 43 | + <col style="width: 125px"> | ||
| 44 | + <col style="width: 247px"> | ||
| 45 | + <col style="width: 317px"> | ||
| 46 | + <col style="width: 233px"> | ||
| 47 | + <col style="width: 126px"> | ||
| 48 | + <col style="width: 144px"> | ||
| 49 | + <col style="width: 146px"> | ||
| 50 | + </colgroup> | ||
| 51 | + <thead> | ||
| 52 | + <tr> | ||
| 53 | + <th>参数名</th> | ||
| 54 | + <th>输入/输出</th> | ||
| 55 | + <th>描述</th> | ||
| 56 | + <th>使用说明</th> | ||
| 57 | + <th>数据类型</th> | ||
| 58 | + <th>数据格式</th> | ||
| 59 | + <th>维度(shape)</th> | ||
| 60 | + <th>非连续Tensor</th> | ||
| 61 | + </tr></thead> | ||
| 62 | + <tbody> | ||
| 63 | + <tr> | ||
| 64 | + <td>self(aclTensor*)</td> | ||
| 65 | + <td>输入</td> | ||
| 66 | + <td>输入张量,公式中的self。</td> | ||
| 67 | + <td>-</td> | ||
| 68 | + <td>FLOAT、FLOAT16、DOUBLE、BFLOAT16、INT8、INT16、INT32、INT64、UINT8、UINT16、BOOL、COMPLEX64、COMPLEX128</td> | ||
| 69 | + <td>ND</td> | ||
| 70 | + <td>0-8</td> | ||
| 71 | + <td>√</td> | ||
| 72 | + </tr> | ||
| 73 | + <tr> | ||
| 74 | + <td>element(aclScalar*)</td> | ||
| 75 | + <td>输入</td> | ||
| 76 | + <td>输入标量,公式中的element。</td> | ||
| 77 | + <td>数据类型需要与self的数据类型满足<a href="../../../../docs/zh/context/互推导关系.md" target="_blank">数据类型推导规则</a>。</td> | ||
| 78 | + <td>FLOAT、FLOAT16、DOUBLE、BFLOAT16、INT8、INT16、INT32、INT64、UINT8、UINT16、BOOL、COMPLEX64、COMPLEX128</td> | ||
| 79 | + <td>-</td> | ||
| 80 | + <td>-</td> | ||
| 81 | + <td>-</td> | ||
| 82 | + </tr> | ||
| 83 | + <tr> | ||
| 84 | + <td>assumeUnique(bool)</td> | ||
| 85 | + <td>输入</td> | ||
| 86 | + <td>是否假设element唯一,公式中的assumeUnique。</td> | ||
| 87 | + <td>-</td> | ||
| 88 | + <td>-</td> | ||
| 89 | + <td>-</td> | ||
| 90 | + <td>-</td> | ||
| 91 | + <td>-</td> | ||
| 92 | + </tr> | ||
| 93 | + <tr> | ||
| 94 | + <td>invert(bool)</td> | ||
| 95 | + <td>输入</td> | ||
| 96 | + <td>是否取反,公式中的invert。</td> | ||
| 97 | + <td>-</td> | ||
| 98 | + <td>-</td> | ||
| 99 | + <td>-</td> | ||
| 100 | + <td>-</td> | ||
| 101 | + <td>-</td> | ||
| 102 | + </tr> | ||
| 103 | + <tr> | ||
| 104 | + <td>out(aclScalar*)</td> | ||
| 105 | + <td>输出</td> | ||
| 106 | + <td>输出标量,公式中的out。</td> | ||
| 107 | + <td>数据类型为BOOL。</td> | ||
| 108 | + <td>BOOL</td> | ||
| 109 | + <td>-</td> | ||
| 110 | + <td>-</td> | ||
| 111 | + <td>-</td> | ||
| 112 | + </tr> | ||
| 113 | + <tr> | ||
| 114 | + <td>workspaceSize(uint64_t*)</td> | ||
| 115 | + <td>输出</td> | ||
| 116 | + <td>返回需要在Device侧申请的workspace大小。</td> | ||
| 117 | + <td>-</td> | ||
| 118 | + <td>-</td> | ||
| 119 | + <td>-</td> | ||
| 120 | + <td>-</td> | ||
| 121 | + <td>-</td> | ||
| 122 | + </tr> | ||
| 123 | + <tr> | ||
| 124 | + <td>executor(aclOpExecutor**)</td> | ||
| 125 | + <td>输出</td> | ||
| 126 | + <td>返回op执行器,包含了算子计算流程。</td> | ||
| 127 | + <td>-</td> | ||
| 128 | + <td>-</td> | ||
| 129 | + <td>-</td> | ||
| 130 | + <td>-</td> | ||
| 131 | + <td>-</td> | ||
| 132 | + </tr> | ||
| 133 | + </tbody></table> | ||
| 134 | + | ||
| 135 | + - <term>Atlas 训练系列产品</term>、<term>Atlas 推理系列产品</term>:不支持BFLOAT16、COMPLEX64、COMPLEX128。 | ||
| 136 | + | ||
| 137 | +- **返回值:** | ||
| 138 | + | ||
| 139 | + aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 140 | + | ||
| 141 | + 第一段接口完成入参校验,出现以下场景时报错: | ||
| 142 | + | ||
| 143 | + <table style="undefined;table-layout: fixed; width: 1150px"><colgroup> | ||
| 144 | + <col style="width: 300px"> | ||
| 145 | + <col style="width: 134px"> | ||
| 146 | + <col style="width: 716px"> | ||
| 147 | + </colgroup> | ||
| 148 | + <thead> | ||
| 149 | + <tr> | ||
| 150 | + <th>返回码</th> | ||
| 151 | + <th>错误码</th> | ||
| 152 | + <th>描述</th> | ||
| 153 | + </tr></thead> | ||
| 154 | + <tbody> | ||
| 155 | + <tr> | ||
| 156 | + <td>ACLNN_ERR_PARAM_NULLPTR</td> | ||
| 157 | + <td>161001</td> | ||
| 158 | + <td>传入的self、element或out是空指针。</td> | ||
| 159 | + </tr> | ||
| 160 | + <tr> | ||
| 161 | + <td rowspan="2">ACLNN_ERR_PARAM_INVALID</td> | ||
| 162 | + <td rowspan="2">161002</td> | ||
| 163 | + <td>self的数据类型不在支持范围之内。</td> | ||
| 164 | + </tr> | ||
| 165 | + <tr> | ||
| 166 | + <td>self的维度超过8维。</td> | ||
| 167 | + </tr> | ||
| 168 | + </tbody></table> | ||
| 169 | + | ||
| 170 | +## aclnnIsInTensorScalar | ||
| 171 | + | ||
| 172 | +- **参数说明:** | ||
| 173 | + | ||
| 174 | + <table style="undefined;table-layout: fixed; width: 1151px"><colgroup> | ||
| 175 | + <col style="width: 184px"> | ||
| 176 | + <col style="width: 134px"> | ||
| 177 | + <col style="width: 833px"> | ||
| 178 | + </colgroup> | ||
| 179 | + <thead> | ||
| 180 | + <tr> | ||
| 181 | + <th>参数名</th> | ||
| 182 | + <th>输入/输出</th> | ||
| 183 | + <th>描述</th> | ||
| 184 | + </tr></thead> | ||
| 185 | + <tbody> | ||
| 186 | + <tr> | ||
| 187 | + <td>workspace</td> | ||
| 188 | + <td>输入</td> | ||
| 189 | + <td>在Device侧申请的workspace内存地址。</td> | ||
| 190 | + </tr> | ||
| 191 | + <tr> | ||
| 192 | + <td>workspaceSize</td> | ||
| 193 | + <td>输入</td> | ||
| 194 | + <td>在Device侧申请的workspace大小,由第一段接口aclnnIsInTensorScalarGetWorkspaceSize获取。</td> | ||
| 195 | + </tr> | ||
| 196 | + <tr> | ||
| 197 | + <td>executor</td> | ||
| 198 | + <td>输入</td> | ||
| 199 | + <td>op执行器,包含了算子计算流程。</td> | ||
| 200 | + </tr> | ||
| 201 | + <tr> | ||
| 202 | + <td>stream</td> | ||
| 203 | + <td>输入</td> | ||
| 204 | + <td>指定执行任务的Stream。</td> | ||
| 205 | + </tr> | ||
| 206 | + </tbody></table> | ||
| 207 | + | ||
| 208 | +- **返回值:** | ||
| 209 | + | ||
| 210 | + aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../../docs/zh/context/aclnn返回码.md)。 | ||
| 211 | + | ||
| 212 | +## 约束说明 | ||
| 213 | + | ||
| 214 | +- 确定性计算: | ||
| 215 | + - aclnnIsInTensorScalar默认确定性实现。 | ||
| 216 | + | ||
| 217 | +## 调用示例 | ||
| 218 | + | ||
| 219 | +示例代码如下,仅供参考,具体编译和执行过程请参考[编译与运行样例](../../../../docs/zh/context/编译与运行样例.md)。 | ||
| 220 | + | ||
| 221 | +```Cpp | ||
| 222 | +#include <iostream> | ||
| 223 | +#include <vector> | ||
| 224 | +#include "acl/acl.h" | ||
| 225 | +#include "aclnnop/aclnn_isin_tensor_scalar.h" | ||
| 226 | + | ||
| 227 | +#define CHECK_RET(cond, return_expr) \ | ||
| 228 | + do { \ | ||
| 229 | + if (!(cond)) { \ | ||
| 230 | + return_expr; \ | ||
| 231 | + } \ | ||
| 232 | + } while (0) | ||
| 233 | + | ||
| 234 | +#define LOG_PRINT(message, ...) \ | ||
| 235 | + do { \ | ||
| 236 | + printf(message, ##__VA_ARGS__); \ | ||
| 237 | + } while (0) | ||
| 238 | + | ||
| 239 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 240 | +{ | ||
| 241 | + int64_t shape_size = 1; | ||
| 242 | + for (auto i : shape) { | ||
| 243 | + shape_size *= i; | ||
| 244 | + } | ||
| 245 | + return shape_size; | ||
| 246 | +} | ||
| 247 | + | ||
| 248 | +int Init(int32_t deviceId, aclrtStream* stream) | ||
| 249 | +{ | ||
| 250 | + // 固定写法,资源初始化 | ||
| 251 | + auto ret = aclInit(nullptr); | ||
| 252 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 253 | + ret = aclrtSetDevice(deviceId); | ||
| 254 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 255 | + ret = aclrtCreateStream(stream); | ||
| 256 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 257 | + return 0; | ||
| 258 | +} | ||
| 259 | + | ||
| 260 | +template <typename T> | ||
| 261 | +int CreateAclTensor( | ||
| 262 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, | ||
| 263 | + aclTensor** tensor) | ||
| 264 | +{ | ||
| 265 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 266 | + // 调用aclrtMalloc申请device侧内存 | ||
| 267 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 268 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 269 | + | ||
| 270 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 271 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 272 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 273 | + | ||
| 274 | + // 计算连续tensor的strides | ||
| 275 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 276 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 277 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 278 | + } | ||
| 279 | + | ||
| 280 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 281 | + *tensor = aclCreateTensor( | ||
| 282 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), | ||
| 283 | + *deviceAddr); | ||
| 284 | + return 0; | ||
| 285 | +} | ||
| 286 | + | ||
| 287 | +aclError InitAcl(int32_t deviceId, aclrtStream* stream) | ||
| 288 | +{ | ||
| 289 | + auto ret = Init(deviceId, stream); | ||
| 290 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 291 | + return ACL_SUCCESS; | ||
| 292 | +} | ||
| 293 | + | ||
| 294 | +aclError CreateInputs( | ||
| 295 | + std::vector<int64_t>& elementShape, std::vector<int64_t>& outShape, void** elementDeviceAddr, void** outDeviceAddr, | ||
| 296 | + aclTensor** element, aclTensor** out, aclScalar** testElement, bool& assumeUnique, bool& invert) | ||
| 297 | +{ | ||
| 298 | + std::vector<double> elementHostData = {0, 1, 2, 3, 2}; | ||
| 299 | + std::vector<char> outHostData = {5, 0}; | ||
| 300 | + double testElementValue = 2; | ||
| 301 | + | ||
| 302 | + // 创建 testElement scalar | ||
| 303 | + *testElement = aclCreateScalar(&testElementValue, aclDataType::ACL_DOUBLE); | ||
| 304 | + CHECK_RET(*testElement != nullptr, return ACL_ERROR_INVALID_PARAM); | ||
| 305 | + | ||
| 306 | + // 创建 element tensor | ||
| 307 | + auto ret = CreateAclTensor(elementHostData, elementShape, elementDeviceAddr, aclDataType::ACL_DOUBLE, element); | ||
| 308 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 309 | + | ||
| 310 | + // 创建 out tensor | ||
| 311 | + ret = CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_BOOL, out); | ||
| 312 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 313 | + | ||
| 314 | + return ACL_SUCCESS; | ||
| 315 | +} | ||
| 316 | + | ||
| 317 | +aclError ExecOpApi( | ||
| 318 | + aclTensor* element, aclScalar* testElement, bool assumeUnique, bool invert, aclTensor* out, void** workspaceAddrOut, | ||
| 319 | + uint64_t& workspaceSize, void* outDeviceAddr, std::vector<int64_t>& outShape, aclrtStream stream) | ||
| 320 | +{ | ||
| 321 | + aclOpExecutor* executor; | ||
| 322 | + | ||
| 323 | + // 第一段接口 | ||
| 324 | + auto ret = | ||
| 325 | + aclnnIsInTensorScalarGetWorkspaceSize(element, testElement, assumeUnique, invert, out, &workspaceSize, &executor); | ||
| 326 | + CHECK_RET( | ||
| 327 | + ret == ACL_SUCCESS, LOG_PRINT("aclnnIsInTensorScalarGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 328 | + | ||
| 329 | + // 分配 workspace | ||
| 330 | + void* workspaceAddr = nullptr; | ||
| 331 | + if (workspaceSize > 0) { | ||
| 332 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 333 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 334 | + } | ||
| 335 | + *workspaceAddrOut = workspaceAddr; | ||
| 336 | + | ||
| 337 | + // 第二段接口 | ||
| 338 | + ret = aclnnIsInTensorScalar(workspaceAddr, workspaceSize, executor, stream); | ||
| 339 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnIsInTensorScalar failed. ERROR: %d\n", ret); return ret); | ||
| 340 | + | ||
| 341 | + // 同步 | ||
| 342 | + ret = aclrtSynchronizeStream(stream); | ||
| 343 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 344 | + | ||
| 345 | + // 拷贝输出 | ||
| 346 | + auto size = GetShapeSize(outShape); | ||
| 347 | + std::vector<char> resultData(size, 0); | ||
| 348 | + | ||
| 349 | + ret = aclrtMemcpy( | ||
| 350 | + resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(resultData[0]), | ||
| 351 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 352 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 353 | + | ||
| 354 | + for (int64_t i = 0; i < size; i++) { | ||
| 355 | + LOG_PRINT("result[%ld] is: %d\n", i, resultData[i]); | ||
| 356 | + } | ||
| 357 | + | ||
| 358 | + return ACL_SUCCESS; | ||
| 359 | +} | ||
| 360 | + | ||
| 361 | +int main() | ||
| 362 | +{ | ||
| 363 | + int32_t deviceId = 0; | ||
| 364 | + aclrtStream stream; | ||
| 365 | + | ||
| 366 | + auto ret = InitAcl(deviceId, &stream); | ||
| 367 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 368 | + | ||
| 369 | + std::vector<int64_t> elementShape = {5}; | ||
| 370 | + std::vector<int64_t> outShape = {5}; | ||
| 371 | + void* elementDeviceAddr = nullptr; | ||
| 372 | + void* outDeviceAddr = nullptr; | ||
| 373 | + aclTensor* element = nullptr; | ||
| 374 | + aclScalar* testElement = nullptr; | ||
| 375 | + aclTensor* out = nullptr; | ||
| 376 | + | ||
| 377 | + bool assumeUnique = false; | ||
| 378 | + bool invert = false; | ||
| 379 | + | ||
| 380 | + ret = CreateInputs( | ||
| 381 | + elementShape, outShape, &elementDeviceAddr, &outDeviceAddr, &element, &out, &testElement, assumeUnique, invert); | ||
| 382 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 383 | + | ||
| 384 | + uint64_t workspaceSize = 0; | ||
| 385 | + void* workspaceAddr = nullptr; | ||
| 386 | + | ||
| 387 | + ret = ExecOpApi( | ||
| 388 | + element, testElement, assumeUnique, invert, out, &workspaceAddr, workspaceSize, outDeviceAddr, outShape, stream); | ||
| 389 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 390 | + | ||
| 391 | + // 释放 | ||
| 392 | + aclDestroyScalar(testElement); | ||
| 393 | + aclDestroyTensor(element); | ||
| 394 | + aclDestroyTensor(out); | ||
| 395 | + | ||
| 396 | + aclrtFree(elementDeviceAddr); | ||
| 397 | + aclrtFree(outDeviceAddr); | ||
| 398 | + if (workspaceSize > 0) { | ||
| 399 | + aclrtFree(workspaceAddr); | ||
| 400 | + } | ||
| 401 | + | ||
| 402 | + aclrtDestroyStream(stream); | ||
| 403 | + aclrtResetDevice(deviceId); | ||
| 404 | + aclFinalize(); | ||
| 405 | + return 0; | ||
| 406 | +} | ||
| 407 | +``` | ||
| @@ -0,0 +1,189 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + do { \ | ||
| 17 | + if (!(cond)) { \ | ||
| 18 | + return_expr; \ | ||
| 19 | + } \ | ||
| 20 | + } while (0) | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + do { \ | ||
| 24 | + printf(message, ##__VA_ARGS__); \ | ||
| 25 | + } while (0) | ||
| 26 | + | ||
| 27 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) | ||
| 28 | +{ | ||
| 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 | + // 固定写法,资源初始化 | ||
| 39 | + auto ret = aclInit(nullptr); | ||
| 40 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | ||
| 41 | + ret = aclrtSetDevice(deviceId); | ||
| 42 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | ||
| 43 | + ret = aclrtCreateStream(stream); | ||
| 44 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | ||
| 45 | + return 0; | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +template <typename T> | ||
| 49 | +int CreateAclTensor( | ||
| 50 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, | ||
| 51 | + 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( | ||
| 70 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), | ||
| 71 | + *deviceAddr); | ||
| 72 | + return 0; | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +aclError InitAcl(int32_t deviceId, aclrtStream* stream) | ||
| 76 | +{ | ||
| 77 | + auto ret = Init(deviceId, stream); | ||
| 78 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 79 | + return ACL_SUCCESS; | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +aclError CreateInputs( | ||
| 83 | + std::vector<int64_t>& selfShape, std::vector<int64_t>& outShape, void** selfDeviceAddr, void** outDeviceAddr, | ||
| 84 | + aclTensor** self, aclScalar** other, aclTensor** out) | ||
| 85 | +{ | ||
| 86 | + std::vector<double> selfHostData = {0, 1, 1.2, 0.3, 4.1, 5, 1.6, 7}; | ||
| 87 | + std::vector<char> outHostData = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 88 | + double otherValue = 1.2; | ||
| 89 | + | ||
| 90 | + // 创建 self tensor | ||
| 91 | + auto ret = CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_DOUBLE, self); | ||
| 92 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 93 | + | ||
| 94 | + // 创建 other scalar | ||
| 95 | + *other = aclCreateScalar(&otherValue, aclDataType::ACL_DOUBLE); | ||
| 96 | + CHECK_RET(*other != nullptr, return ret); | ||
| 97 | + | ||
| 98 | + // 创建 out tensor | ||
| 99 | + ret = CreateAclTensor(outHostData, outShape, &(*outDeviceAddr), aclDataType::ACL_BOOL, out); | ||
| 100 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 101 | + | ||
| 102 | + return ACL_SUCCESS; | ||
| 103 | +} | ||
| 104 | + | ||
| 105 | +aclError ExecOpApi( | ||
| 106 | + aclTensor* self, aclScalar* other, aclTensor* out, void** workspaceAddrOut, uint64_t& workspaceSize, | ||
| 107 | + void* outDeviceAddr, std::vector<int64_t>& outShape, aclrtStream stream) | ||
| 108 | +{ | ||
| 109 | + aclOpExecutor* executor; | ||
| 110 | + | ||
| 111 | + // 获取 workspace 大小 | ||
| 112 | + auto ret = aclnnEqScalarGetWorkspaceSize(self, other, out, &workspaceSize, &executor); | ||
| 113 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEqScalarGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 114 | + | ||
| 115 | + // 申请 workspace(释放放在 main 里) | ||
| 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 | + *workspaceAddrOut = workspaceAddr; | ||
| 122 | + | ||
| 123 | + // 调用算子 | ||
| 124 | + ret = aclnnEqScalar(workspaceAddr, workspaceSize, executor, stream); | ||
| 125 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEqScalar failed. ERROR: %d\n", ret); return ret); | ||
| 126 | + | ||
| 127 | + // 同步 | ||
| 128 | + ret = aclrtSynchronizeStream(stream); | ||
| 129 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 130 | + | ||
| 131 | + // 拷贝输出 | ||
| 132 | + auto size = GetShapeSize(outShape); | ||
| 133 | + std::vector<char> resultData(size, 0); | ||
| 134 | + | ||
| 135 | + ret = aclrtMemcpy( | ||
| 136 | + resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(char), | ||
| 137 | + 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 | + | ||
| 140 | + for (int64_t i = 0; i < size; i++) { | ||
| 141 | + LOG_PRINT("result[%ld] is: %d\n", i, resultData[i]); | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | + return ACL_SUCCESS; | ||
| 145 | +} | ||
| 146 | + | ||
| 147 | +int main() | ||
| 148 | +{ | ||
| 149 | + int32_t deviceId = 0; | ||
| 150 | + aclrtStream stream; | ||
| 151 | + auto ret = InitAcl(deviceId, &stream); | ||
| 152 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("InitAcl failed. ERROR: %d\n", ret); return ret); | ||
| 153 | + | ||
| 154 | + std::vector<int64_t> selfShape = {4, 2}; | ||
| 155 | + std::vector<int64_t> outShape = {4, 2}; | ||
| 156 | + | ||
| 157 | + void* selfDeviceAddr = nullptr; | ||
| 158 | + void* outDeviceAddr = nullptr; | ||
| 159 | + aclTensor* self = nullptr; | ||
| 160 | + aclScalar* other = nullptr; | ||
| 161 | + aclTensor* out = nullptr; | ||
| 162 | + | ||
| 163 | + ret = CreateInputs(selfShape, outShape, &selfDeviceAddr, &outDeviceAddr, &self, &other, &out); | ||
| 164 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 165 | + | ||
| 166 | + uint64_t workspaceSize = 0; | ||
| 167 | + void* workspaceAddr = nullptr; | ||
| 168 | + | ||
| 169 | + ret = ExecOpApi(self, other, out, &workspaceAddr, workspaceSize, outDeviceAddr, outShape, stream); | ||
| 170 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 171 | + | ||
| 172 | + // 释放 Tensor / Scalar | ||
| 173 | + aclDestroyTensor(self); | ||
| 174 | + aclDestroyScalar(other); | ||
| 175 | + aclDestroyTensor(out); | ||
| 176 | + | ||
| 177 | + // 释放 device 内存 | ||
| 178 | + aclrtFree(selfDeviceAddr); | ||
| 179 | + aclrtFree(outDeviceAddr); | ||
| 180 | + if (workspaceSize > 0) { | ||
| 181 | + aclrtFree(workspaceAddr); | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | + aclrtDestroyStream(stream); | ||
| 185 | + aclrtResetDevice(deviceId); | ||
| 186 | + aclFinalize(); | ||
| 187 | + | ||
| 188 | + return 0; | ||
| 189 | +} | ||
| @@ -0,0 +1,188 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | + | ||
| 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( | ||
| 51 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, | ||
| 52 | + aclTensor** tensor) | ||
| 53 | +{ | ||
| 54 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 55 | + // 调用aclrtMalloc申请device侧内存 | ||
| 56 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 57 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 58 | + | ||
| 59 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 60 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 61 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 62 | + | ||
| 63 | + // 计算连续tensor的strides | ||
| 64 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 65 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 66 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 70 | + *tensor = aclCreateTensor( | ||
| 71 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), | ||
| 72 | + *deviceAddr); | ||
| 73 | + return 0; | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +aclError InitAcl(int32_t deviceId, aclrtStream* stream) | ||
| 77 | +{ | ||
| 78 | + auto ret = Init(deviceId, stream); | ||
| 79 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 80 | + return ACL_SUCCESS; | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +aclError CreateInputs( | ||
| 84 | + std::vector<int64_t>& selfShape, std::vector<int64_t>& otherShape, std::vector<int64_t>& outShape, | ||
| 85 | + void** selfDeviceAddr, void** otherDeviceAddr, void** outDeviceAddr, aclTensor** self, aclTensor** other, | ||
| 86 | + aclTensor** out) | ||
| 87 | +{ | ||
| 88 | + std::vector<double> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
| 89 | + std::vector<double> otherHostData = {0, 1, 9, 9, 9, 9, 9, 9}; | ||
| 90 | + std::vector<char> outHostData = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 91 | + | ||
| 92 | + auto ret = CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_DOUBLE, self); | ||
| 93 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 94 | + | ||
| 95 | + ret = CreateAclTensor(otherHostData, otherShape, otherDeviceAddr, aclDataType::ACL_DOUBLE, other); | ||
| 96 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 97 | + | ||
| 98 | + ret = CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_BOOL, out); | ||
| 99 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 100 | + | ||
| 101 | + return ACL_SUCCESS; | ||
| 102 | +} | ||
| 103 | + | ||
| 104 | +aclError ExecOpApi( | ||
| 105 | + aclTensor* self, aclTensor* other, aclTensor* out, void** workspaceAddrOut, uint64_t& workspaceSize, | ||
| 106 | + void* outDeviceAddr, std::vector<int64_t>& outShape, aclrtStream stream) | ||
| 107 | +{ | ||
| 108 | + aclOpExecutor* executor; | ||
| 109 | + | ||
| 110 | + auto ret = aclnnEqTensorGetWorkspaceSize(self, other, out, &workspaceSize, &executor); | ||
| 111 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEqTensorGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 112 | + | ||
| 113 | + void* workspaceAddr = nullptr; | ||
| 114 | + if (workspaceSize > 0) { | ||
| 115 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 116 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 117 | + } | ||
| 118 | + *workspaceAddrOut = workspaceAddr; | ||
| 119 | + | ||
| 120 | + ret = aclnnEqTensor(workspaceAddr, workspaceSize, executor, stream); | ||
| 121 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEqTensor failed. ERROR: %d\n", ret); return ret); | ||
| 122 | + | ||
| 123 | + ret = aclrtSynchronizeStream(stream); | ||
| 124 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 125 | + | ||
| 126 | + auto size = GetShapeSize(outShape); | ||
| 127 | + std::vector<char> resultData(size, 0); | ||
| 128 | + | ||
| 129 | + ret = aclrtMemcpy( | ||
| 130 | + resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(char), | ||
| 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 | + | ||
| 134 | + for (int64_t i = 0; i < size; i++) { | ||
| 135 | + LOG_PRINT("result[%ld] is: %d\n", i, resultData[i]); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + return ACL_SUCCESS; | ||
| 139 | +} | ||
| 140 | + | ||
| 141 | +int main() | ||
| 142 | +{ | ||
| 143 | + int32_t deviceId = 0; | ||
| 144 | + aclrtStream stream; | ||
| 145 | + | ||
| 146 | + auto ret = InitAcl(deviceId, &stream); | ||
| 147 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 148 | + | ||
| 149 | + std::vector<int64_t> selfShape = {4, 2}; | ||
| 150 | + std::vector<int64_t> otherShape = {4, 2}; | ||
| 151 | + std::vector<int64_t> outShape = {4, 2}; | ||
| 152 | + | ||
| 153 | + void* selfDeviceAddr = nullptr; | ||
| 154 | + void* otherDeviceAddr = nullptr; | ||
| 155 | + void* outDeviceAddr = nullptr; | ||
| 156 | + | ||
| 157 | + aclTensor* self = nullptr; | ||
| 158 | + aclTensor* other = nullptr; | ||
| 159 | + aclTensor* out = nullptr; | ||
| 160 | + | ||
| 161 | + ret = CreateInputs( | ||
| 162 | + selfShape, otherShape, outShape, &selfDeviceAddr, &otherDeviceAddr, &outDeviceAddr, &self, &other, &out); | ||
| 163 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 164 | + | ||
| 165 | + uint64_t workspaceSize = 0; | ||
| 166 | + void* workspaceAddr = nullptr; | ||
| 167 | + | ||
| 168 | + ret = ExecOpApi(self, other, out, &workspaceAddr, workspaceSize, outDeviceAddr, outShape, stream); | ||
| 169 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 170 | + | ||
| 171 | + // 释放资源 | ||
| 172 | + aclDestroyTensor(self); | ||
| 173 | + aclDestroyTensor(other); | ||
| 174 | + aclDestroyTensor(out); | ||
| 175 | + | ||
| 176 | + aclrtFree(selfDeviceAddr); | ||
| 177 | + aclrtFree(otherDeviceAddr); | ||
| 178 | + aclrtFree(outDeviceAddr); | ||
| 179 | + | ||
| 180 | + if (workspaceSize > 0) { | ||
| 181 | + aclrtFree(workspaceAddr); | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | + aclrtDestroyStream(stream); | ||
| 185 | + aclrtResetDevice(deviceId); | ||
| 186 | + aclFinalize(); | ||
| 187 | + return 0; | ||
| 188 | +} | ||
| @@ -0,0 +1,188 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2025 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + do { \ | ||
| 18 | + if (!(cond)) { \ | ||
| 19 | + return_expr; \ | ||
| 20 | + } \ | ||
| 21 | + } while (0) | ||
| 22 | + | ||
| 23 | + | ||
| 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( | ||
| 51 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, | ||
| 52 | + aclTensor** tensor) | ||
| 53 | +{ | ||
| 54 | + auto size = GetShapeSize(shape) * sizeof(T); | ||
| 55 | + // 调用aclrtMalloc申请device侧内存 | ||
| 56 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 57 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | ||
| 58 | + | ||
| 59 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | ||
| 60 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 61 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 62 | + | ||
| 63 | + // 计算连续tensor的strides | ||
| 64 | + std::vector<int64_t> strides(shape.size(), 1); | ||
| 65 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { | ||
| 66 | + strides[i] = shape[i + 1] * strides[i + 1]; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + // 调用aclCreateTensor接口创建aclTensor | ||
| 70 | + *tensor = aclCreateTensor( | ||
| 71 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), | ||
| 72 | + *deviceAddr); | ||
| 73 | + return 0; | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +aclError InitAcl(int32_t deviceId, aclrtStream* stream) | ||
| 77 | +{ | ||
| 78 | + auto ret = Init(deviceId, stream); | ||
| 79 | + CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 80 | + return ACL_SUCCESS; | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +aclError CreateInputs( | ||
| 84 | + std::vector<int64_t>& selfShape, std::vector<int64_t>& otherShape, std::vector<int64_t>& outShape, | ||
| 85 | + void** selfDeviceAddr, void** otherDeviceAddr, void** outDeviceAddr, aclTensor** self, aclTensor** other, | ||
| 86 | + aclTensor** out) | ||
| 87 | +{ | ||
| 88 | + std::vector<double> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
| 89 | + std::vector<double> otherHostData = {0, 1, 9, 9, 9, 9, 9, 9}; | ||
| 90 | + std::vector<char> outHostData = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 91 | + | ||
| 92 | + auto ret = CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_DOUBLE, self); | ||
| 93 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 94 | + | ||
| 95 | + ret = CreateAclTensor(otherHostData, otherShape, otherDeviceAddr, aclDataType::ACL_DOUBLE, other); | ||
| 96 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 97 | + | ||
| 98 | + ret = CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_BOOL, out); | ||
| 99 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 100 | + | ||
| 101 | + return ACL_SUCCESS; | ||
| 102 | +} | ||
| 103 | + | ||
| 104 | +aclError ExecOpApi( | ||
| 105 | + aclTensor* self, aclTensor* other, aclTensor* out, void** workspaceAddrOut, uint64_t& workspaceSize, | ||
| 106 | + void* outDeviceAddr, std::vector<int64_t>& outShape, aclrtStream stream) | ||
| 107 | +{ | ||
| 108 | + aclOpExecutor* executor; | ||
| 109 | + | ||
| 110 | + auto ret = aclnnEqTensorGetWorkspaceSize(self, other, out, &workspaceSize, &executor); | ||
| 111 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEqTensorGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 112 | + | ||
| 113 | + void* workspaceAddr = nullptr; | ||
| 114 | + if (workspaceSize > 0) { | ||
| 115 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 116 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 117 | + } | ||
| 118 | + *workspaceAddrOut = workspaceAddr; | ||
| 119 | + | ||
| 120 | + ret = aclnnEqTensor(workspaceAddr, workspaceSize, executor, stream); | ||
| 121 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEqTensor failed. ERROR: %d\n", ret); return ret); | ||
| 122 | + | ||
| 123 | + ret = aclrtSynchronizeStream(stream); | ||
| 124 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 125 | + | ||
| 126 | + auto size = GetShapeSize(outShape); | ||
| 127 | + std::vector<char> resultData(size, 0); | ||
| 128 | + | ||
| 129 | + ret = aclrtMemcpy( | ||
| 130 | + resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(char), | ||
| 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 | + | ||
| 134 | + for (int64_t i = 0; i < size; i++) { | ||
| 135 | + LOG_PRINT("result[%ld] is: %d\n", i, resultData[i]); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + return ACL_SUCCESS; | ||
| 139 | +} | ||
| 140 | + | ||
| 141 | +int main() | ||
| 142 | +{ | ||
| 143 | + int32_t deviceId = 0; | ||
| 144 | + aclrtStream stream; | ||
| 145 | + | ||
| 146 | + auto ret = InitAcl(deviceId, &stream); | ||
| 147 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 148 | + | ||
| 149 | + std::vector<int64_t> selfShape = {4, 2}; | ||
| 150 | + std::vector<int64_t> otherShape = {4, 2}; | ||
| 151 | + std::vector<int64_t> outShape = {4, 2}; | ||
| 152 | + | ||
| 153 | + void* selfDeviceAddr = nullptr; | ||
| 154 | + void* otherDeviceAddr = nullptr; | ||
| 155 | + void* outDeviceAddr = nullptr; | ||
| 156 | + | ||
| 157 | + aclTensor* self = nullptr; | ||
| 158 | + aclTensor* other = nullptr; | ||
| 159 | + aclTensor* out = nullptr; | ||
| 160 | + | ||
| 161 | + ret = CreateInputs( | ||
| 162 | + selfShape, otherShape, outShape, &selfDeviceAddr, &otherDeviceAddr, &outDeviceAddr, &self, &other, &out); | ||
| 163 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 164 | + | ||
| 165 | + uint64_t workspaceSize = 0; | ||
| 166 | + void* workspaceAddr = nullptr; | ||
| 167 | + | ||
| 168 | + ret = ExecOpApi(self, other, out, &workspaceAddr, workspaceSize, outDeviceAddr, outShape, stream); | ||
| 169 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 170 | + | ||
| 171 | + // 释放资源 | ||
| 172 | + aclDestroyTensor(self); | ||
| 173 | + aclDestroyTensor(other); | ||
| 174 | + aclDestroyTensor(out); | ||
| 175 | + | ||
| 176 | + aclrtFree(selfDeviceAddr); | ||
| 177 | + aclrtFree(otherDeviceAddr); | ||
| 178 | + aclrtFree(outDeviceAddr); | ||
| 179 | + | ||
| 180 | + if (workspaceSize > 0) { | ||
| 181 | + aclrtFree(workspaceAddr); | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | + aclrtDestroyStream(stream); | ||
| 185 | + aclrtResetDevice(deviceId); | ||
| 186 | + aclFinalize(); | ||
| 187 | + return 0; | ||
| 188 | +} | ||