LCOV - code coverage report
Current view: top level - ut/foreach/foreach_sub_list/op_host/op_api - aclnn_foreach_sub_list_v2.cpp Coverage Total Hit
Test: CHG Lines: 50.0 % 12 6
Test Date: 2026-08-29 15:24:08
Legend: Lines: hit not hit

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2025-2026 Huawei Technologies Co., Ltd.
       3              :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4              :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5              :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6              :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7              :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8              :  * See LICENSE in the root of the software repository for the full text of the License.
       9              :  */
      10              : 
      11              : /*!
      12              :  * \file aclnn_foreach_sub_list_v2.cpp
      13              :  * \brief
      14              :  */
      15              : 
      16              : #include "aclnn_foreach_sub_list_v2.h"
      17              : #include "foreach_sub_list_v2.h"
      18              : #include "aclnn_kernels/contiguous.h"
      19              : #include "op_api/op_api_def_nn.h"
      20              : #include "op_api/aclnn_util.h"
      21              : #include "aclnn_kernels/common/op_error_check.h"
      22              : #include "opdev/op_dfx.h"
      23              : #include "opdev/make_op_executor.h"
      24              : #include "opdev/platform.h"
      25              : 
      26              : using namespace op;
      27              : 
      28              : #ifdef __cplusplus
      29              : extern "C" {
      30              : #endif
      31              : 
      32              : static const std::initializer_list<ge::DataType> ASCEND910BC_TENSOR_DTYPE_DTYPE_SUPPORT_LIST = {
      33              :     ge::DT_FLOAT, ge::DT_FLOAT16, ge::DT_BF16, ge::DT_INT32, ge::DT_INT16, ge::DT_INT8, ge::DT_UINT8};
      34              : 
      35              : static const std::initializer_list<ge::DataType> FOREACH_SCALAR_FLOAT_SUPPORT_LIST = {ge::DT_FLOAT, ge::DT_DOUBLE};
      36              : 
      37              : static const std::initializer_list<ge::DataType> FOREACH_SCALAR_FLOAT16_SUPPORT_LIST = {ge::DT_FLOAT16, ge::DT_DOUBLE};
      38              : 
      39              : static const std::initializer_list<ge::DataType> FOREACH_SCALAR_INT_SUPPORT_LIST = {ge::DT_INT32, ge::DT_INT64};
      40              : 
      41              : static const std::initializer_list<ge::DataType> EMPTY_LIST = {};
      42              : 
      43              : static inline ge::DataType GetAlphaTensorDtype(ge::DataType selfDtype)
      44              : {
      45              :     if (selfDtype == ge::DT_BF16) {
      46              :         return ge::DT_FLOAT;
      47              :     }
      48              :     if (selfDtype == ge::DT_INT16 || selfDtype == ge::DT_INT8 || selfDtype == ge::DT_UINT8) {
      49              :         return ge::DT_INT32;
      50              :     }
      51              :     return selfDtype;
      52              : }
      53              : 
      54              : static inline bool CheckNotNull(const aclTensorList* self, const aclTensorList* x2, const aclScalar* scalar,
      55              :                                 const aclTensorList* out)
      56              : {
      57              :     OP_CHECK_NULL(self, return false);
      58              :     OP_CHECK_NULL(x2, return false);
      59              :     OP_CHECK_NULL(scalar, return false);
      60              :     OP_CHECK_NULL(out, return false);
      61              :     return true;
      62              : }
      63              : 
      64              : static inline bool CheckFormat(const aclTensorList* self, const aclTensorList* x2, const aclTensorList* out)
      65              : {
      66              :     for (uint64_t i = 0; i < self->Size(); i++) {
      67              :         // self格式不能是私有格式
      68              :         if (IsPrivateFormat((*self)[i]->GetStorageFormat()) || IsPrivateFormat((*x2)[i]->GetStorageFormat()) ||
      69              :             IsPrivateFormat((*out)[i]->GetStorageFormat())) {
      70              :             OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Format only support ND, NCHW, NHWC, HWCN, NDHWC, NCDHW.");
      71              :             return false;
      72              :         }
      73              :     }
      74              :     return true;
      75              : }
      76              : 
      77              : static const std::initializer_list<ge::DataType>& GetDtypeSupportList()
      78              : {
      79              :     auto curArch = GetCurrentPlatformInfo().GetCurNpuArch();
      80              :     if (curArch == NpuArch::DAV_2201 || Ops::NN::AclnnUtil::IsRegbase(curArch)) {
      81              :         return ASCEND910BC_TENSOR_DTYPE_DTYPE_SUPPORT_LIST;
      82              :     } else {
      83              :         OP_LOGE(ACLNN_ERR_RUNTIME_ERROR, "support for %s is not implemented",
      84              :                 op::ToString(GetCurrentPlatformInfo().GetSocVersion()).GetString());
      85              :         return EMPTY_LIST;
      86              :     }
      87              : }
      88              : 
      89              : static inline bool CheckDtypeValid(const aclTensorList* self, const aclTensorList* x2, const aclScalar* scalar,
      90              :                                    const aclTensorList* out)
      91              : {
      92              :     const auto& dtypeSupportList = GetDtypeSupportList();
      93              :     if (dtypeSupportList.size() == 0) {
      94              :         OP_LOGE(ACLNN_ERR_PARAM_INVALID, "support for %s is not implemented",
      95              :                 op::ToString(GetCurrentPlatformInfo().GetSocVersion()).GetString());
      96              :         return false;
      97              :     }
      98              :     if (self->Size() == 0) {
      99              :         return true;
     100              :     }
     101              : 
     102              :     // checkself input dtype, and check the releation of input and out
     103              :     auto selfDtyte = (*self)[0]->GetDataType();
     104              :     OP_CHECK_DTYPE_NOT_SUPPORT((*self)[0], dtypeSupportList, return false);
     105              : 
     106              :     // check the releation of self and scalar
     107              :     if (selfDtyte == ge::DT_BF16 || selfDtyte == ge::DT_FLOAT) {
     108              :         OP_CHECK_DTYPE_NOT_SUPPORT(scalar, FOREACH_SCALAR_FLOAT_SUPPORT_LIST, return false);
     109              :     } else if (selfDtyte == ge::DT_FLOAT16) {
     110              :         OP_CHECK_DTYPE_NOT_SUPPORT(scalar, FOREACH_SCALAR_FLOAT16_SUPPORT_LIST, return false);
     111              :     } else if (selfDtyte == ge::DT_INT32 || selfDtyte == ge::DT_INT16 || selfDtyte == ge::DT_INT8 ||
     112              :                selfDtyte == ge::DT_UINT8) {
     113              :         OP_CHECK_DTYPE_NOT_SUPPORT(scalar, FOREACH_SCALAR_INT_SUPPORT_LIST, return false);
     114              :     }
     115              : 
     116              :     for (uint64_t i = 0; i < self->Size(); i++) {
     117              :         OP_CHECK_DTYPE_NOT_MATCH((*self)[i], selfDtyte, return false);
     118              :     }
     119              : 
     120              :     for (uint64_t i = 0; i < x2->Size(); i++) {
     121              :         OP_CHECK_DTYPE_NOT_MATCH((*x2)[i], selfDtyte, return false);
     122              :     }
     123              : 
     124              :     for (uint64_t i = 0; i < out->Size(); i++) {
     125              :         OP_CHECK_DTYPE_NOT_MATCH((*out)[i], selfDtyte, return false);
     126              :     }
     127              :     return true;
     128              : }
     129              : 
     130              : static inline bool CheckShape(const aclTensorList* self, const aclTensorList* x2, const aclTensorList* out)
     131              : {
     132              :     // tensorlist size检查
     133              :     if (self->Size() != x2->Size()) {
     134              :         OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Tensor lists must have the same number of tensors, got %lu and %lu",
     135              :                 self->Size(), x2->Size());
     136              :         return false;
     137              :     }
     138              : 
     139              :     // tensorlist中tensor shape一致性检查
     140              :     for (uint64_t i = 0; i < self->Size(); i++) {
     141              :         OP_CHECK_SHAPE_NOT_EQUAL((*self)[i], (*x2)[i], return false);
     142              :     }
     143              : 
     144              :     // tensor 维度检查
     145              :     for (uint64_t i = 0; i < self->Size(); i++) {
     146              :         OP_CHECK_MAX_DIM((*self)[i], MAX_SUPPORT_DIMS_NUMS, return false);
     147              :     }
     148              : 
     149              :     // self和out的shape必须一致
     150              :     for (uint64_t i = 0; i < self->Size(); i++) {
     151              :         OP_CHECK_SHAPE_NOT_EQUAL((*self)[i], (*out)[i], return false);
     152              :     }
     153              :     return true;
     154              : }
     155              : 
     156              : static inline aclnnStatus CheckParams(const aclTensorList* self, const aclTensorList* x2, const aclScalar* scalar,
     157              :                                       const aclTensorList* out)
     158              : {
     159              :     // 1. 检查参数是否为空指针
     160              :     CHECK_RET(CheckNotNull(self, x2, scalar, out), ACLNN_ERR_PARAM_NULLPTR);
     161              : 
     162              :     // Check every entry in tensor lists is not null, to avoid null pointer
     163              :     // dereference in CheckDtypeValid/CheckShape/CheckFormat.
     164           22 :     for (uint64_t i = 0; i < self->Size(); i++) {
     165           11 :         if ((*self)[i] == nullptr) {
     166            0 :             OP_LOGE(ACLNN_ERR_PARAM_INVALID, "self[%lu] is null.", i);
     167            0 :             return ACLNN_ERR_PARAM_INVALID;
     168              :         }
     169              :     }
     170           22 :     for (uint64_t i = 0; i < x2->Size(); i++) {
     171           11 :         if ((*x2)[i] == nullptr) {
     172            0 :             OP_LOGE(ACLNN_ERR_PARAM_INVALID, "x2[%lu] is null.", i);
     173            0 :             return ACLNN_ERR_PARAM_INVALID;
     174              :         }
     175              :     }
     176           22 :     for (uint64_t i = 0; i < out->Size(); i++) {
     177           11 :         if ((*out)[i] == nullptr) {
     178            0 :             OP_LOGE(ACLNN_ERR_PARAM_INVALID, "out[%lu] is null.", i);
     179            0 :             return ACLNN_ERR_PARAM_INVALID;
     180              :         }
     181              :     }
     182              : 
     183              :     // 2. 检查输入的数据类型是否在API支持的数据类型范围之内,需要根据api定义校验
     184              :     CHECK_RET(CheckDtypeValid(self, x2, scalar, out), ACLNN_ERR_PARAM_INVALID);
     185              :     // 3. 检查shape是否满足约束
     186              :     CHECK_RET(CheckShape(self, x2, out), ACLNN_ERR_PARAM_INVALID);
     187              :     // 4. 检查Format是否满足约束
     188              :     CHECK_RET(CheckFormat(self, x2, out), ACLNN_ERR_PARAM_INVALID);
     189              :     return ACLNN_SUCCESS;
     190              : }
     191              : 
     192              : static aclnnStatus ExecForeachSubListV2GetWorkspaceSize(const aclTensorList* x1, const aclTensorList* x2,
     193              :                                                         const aclScalar* scalar, const aclTensorList* out,
     194              :                                                         uint64_t* workspaceSize, aclOpExecutor** executor)
     195              : {
     196              :     // 固定写法,创建OpExecutor
     197              :     auto uniqueExecutor = CREATE_EXECUTOR();
     198              :     CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
     199              : 
     200              :     // 固定写法,参数检查
     201              :     auto ret = CheckParams(x1, x2, scalar, out);
     202              :     CHECK_RET(ret == ACLNN_SUCCESS, ret);
     203              : 
     204              :     // 空Tensorlist处理
     205              :     if (x1->Size() == 0 || x2->Size() == 0) {
     206              :         *workspaceSize = 0;
     207              :         uniqueExecutor.ReleaseTo(executor);
     208              :         return ACLNN_SUCCESS;
     209              :     }
     210              : 
     211              :     // self如果非连续,需要转连续
     212              :     std::vector<const aclTensor*> tensorsVecX1;
     213              :     for (size_t i = 0; i < x1->Size(); ++i) {
     214              :         auto secondContiguous = l0op::Contiguous((*x1)[i], uniqueExecutor.get());
     215              :         CHECK_RET(secondContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
     216              :         tensorsVecX1.push_back(secondContiguous);
     217              :     }
     218              :     auto contiguousTensorsX1 = uniqueExecutor.get()->AllocTensorList(tensorsVecX1.data(), tensorsVecX1.size());
     219              :     CHECK_RET(contiguousTensorsX1 != nullptr, ACLNN_ERR_INNER_NULLPTR);
     220              : 
     221              :     std::vector<const aclTensor*> tensorsVecX2;
     222              :     for (size_t i = 0; i < x2->Size(); ++i) {
     223              :         auto secondContiguous = l0op::Contiguous((*x2)[i], uniqueExecutor.get());
     224              :         CHECK_RET(secondContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
     225              :         tensorsVecX2.push_back(secondContiguous);
     226              :     }
     227              :     auto contiguousTensorsX2 = uniqueExecutor.get()->AllocTensorList(tensorsVecX2.data(), tensorsVecX2.size());
     228              :     CHECK_RET(contiguousTensorsX2 != nullptr, ACLNN_ERR_INNER_NULLPTR);
     229              : 
     230              :     // sclar to tensor
     231              :     const aclTensor* otherTensor = uniqueExecutor.get()->ConvertToTensor(scalar,
     232              :                                                                          GetAlphaTensorDtype((*x1)[0]->GetDataType()));
     233              : 
     234              :     // 调用l0算子ForeachSubListV2进行计算
     235              :     auto result = l0op::ForeachSubListV2(contiguousTensorsX1, contiguousTensorsX2, otherTensor, out,
     236              :                                          uniqueExecutor.get());
     237              :     CHECK_RET(result != nullptr, ACLNN_ERR_INNER_NULLPTR);
     238              : 
     239              :     // 固定写法,获取计算过程中需要使用的workspace大小
     240              :     *workspaceSize = uniqueExecutor->GetWorkspaceSize();
     241              :     uniqueExecutor.ReleaseTo(executor);
     242              :     return ACLNN_SUCCESS;
     243              : }
     244              : 
     245              : aclnnStatus aclnnForeachSubListV2GetWorkspaceSize(const aclTensorList* x1, const aclTensorList* x2,
     246              :                                                   const aclScalar* alpha, aclTensorList* out, uint64_t* workspaceSize,
     247              :                                                   aclOpExecutor** executor)
     248              : {
     249              :     L2_DFX_PHASE_1(aclnnForeachSubListV2, DFX_IN(x1, x2, alpha), DFX_OUT(out));
     250              :     return ExecForeachSubListV2GetWorkspaceSize(x1, x2, alpha, out, workspaceSize, executor);
     251              : }
     252              : 
     253              : aclnnStatus aclnnForeachSubListV2(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor,
     254              :                                   const aclrtStream stream)
     255              : {
     256              :     L2_DFX_PHASE_2(aclnnForeachSubListV2);
     257              :     return CommonOpExecutorRun(workspace, workspaceSize, executor, stream);
     258              : }
     259              : 
     260              : #ifdef __cplusplus
     261              : }
     262              : #endif
        

Generated by: LCOV version 2.0-1