已合并
feat(cdgmm): 迁移 ColwiseMul 为行主序 Cdgmm;新增 extensions/ 目录迁移 ComplexMatDot #314
2301_82146483创建于 7月28日
feat(cdgmm): 迁移 ColwiseMul 为行主序 Cdgmm;新增 extensions/ 目录迁移 ComplexMatDot #314
已合并
共 30 个文件变更+1669-812
| @@ -158,6 +158,7 @@ set(ALL_BLAS_SRC_FILES "") | |||
| 158 | set(OPS_BLAS ops_blas) | 158 | set(OPS_BLAS ops_blas) |
| 159 | 159 | ||
| 160 | add_subdirectory(blas) | 160 | add_subdirectory(blas) |
| 161 | +add_subdirectory(extensions) | ||
| 161 | 162 | ||
| 162 | project(${OPS_BLAS} LANGUAGES ASC CXX) | 163 | project(${OPS_BLAS} LANGUAGES ASC CXX) |
| 163 | 164 | ||
| @@ -175,6 +176,8 @@ target_include_directories(${OPS_BLAS} PRIVATE | |||
| 175 | ${ASCEND_CANN_PACKAGE_PATH}/include/op_common/ | 176 | ${ASCEND_CANN_PACKAGE_PATH}/include/op_common/ |
| 176 | ./include | 177 | ./include |
| 177 | ${CMAKE_CURRENT_LIST_DIR}/blas | 178 | ${CMAKE_CURRENT_LIST_DIR}/blas |
| 179 | + ${CMAKE_CURRENT_LIST_DIR}/extensions | ||
| 180 | + ${CMAKE_CURRENT_LIST_DIR}/extensions/complexmatdot/arch22 | ||
| 178 | "${_OPS_BLAS_ASC_ROOT}" | 181 | "${_OPS_BLAS_ASC_ROOT}" |
| 179 | "${_OPS_BLAS_ASC_ROOT}/include" | 182 | "${_OPS_BLAS_ASC_ROOT}/include" |
| 180 | "${_OPS_BLAS_ASC_ROOT}/include/utils" | 183 | "${_OPS_BLAS_ASC_ROOT}/include/utils" |
| @@ -68,12 +68,14 @@ if(NOT ENABLE_BLAS_TRMM) | |||
| 68 | STATUS | 68 | STATUS |
| 69 | "Skipping blas trmm/strmm (requires asc-devkit >= 9.1, current ${ASC_DEVKIT_MAJOR}.${ASC_DEVKIT_MINOR})") | 69 | "Skipping blas trmm/strmm (requires asc-devkit >= 9.1, current ${ASC_DEVKIT_MAJOR}.${ASC_DEVKIT_MINOR})") |
| 70 | endif() | 70 | endif() |
| 71 | -if(NOT ENABLE_BLAS_DGMM) | 71 | +# Only arch35 sdgmm uses tensor_api; arch22 cdgmm does not depend on it. |
| 72 | - list(FILTER OP_SRC_FILES EXCLUDE REGEX "/dgmm/") | 72 | +# Filter only sdgmm sources so cdgmm (arch22) is not excluded. |
| 73 | - list(FILTER ARCH_SRC_FILES EXCLUDE REGEX "/dgmm/") | 73 | +if(NOT ENABLE_BLAS_SDGMM) |
| 74 | + list(FILTER OP_SRC_FILES EXCLUDE REGEX "/dgmm/arch35/sdgmm") | ||
| 75 | + list(FILTER ARCH_SRC_FILES EXCLUDE REGEX "/dgmm/arch35/sdgmm") | ||
| 74 | message( | 76 | message( |
| 75 | STATUS | 77 | STATUS |
| 76 | - "Skipping blas dgmm/sdgmm (requires asc-devkit >= 9.1, current ${ASC_DEVKIT_MAJOR}.${ASC_DEVKIT_MINOR})") | 78 | + "Skipping blas dgmm/sdgmm arch35 (requires asc-devkit >= 9.1, current ${ASC_DEVKIT_MAJOR}.${ASC_DEVKIT_MINOR})") |
| 77 | endif() | 79 | endif() |
| 78 | if(NOT ENABLE_BLAS_GEMM_BATCHED) | 80 | if(NOT ENABLE_BLAS_GEMM_BATCHED) |
| 79 | list(FILTER OP_SRC_FILES EXCLUDE REGEX "/gemm_batched/") | 81 | list(FILTER OP_SRC_FILES EXCLUDE REGEX "/gemm_batched/") |
Dblas/colwise_mul/README.md+0-48
| @@ -1,48 +0,0 @@ | |||
| 1 | -# ColwiseMul算子 | ||
| 2 | - | ||
| 3 | -## 算子概述 | ||
| 4 | - | ||
| 5 | -ColwiseMul(列方向复数乘法)算子实现了复数向量与矩阵每行的逐元素乘法运算,是 BLAS 基础线性代数库中的扩展算子之一。该算子针对复数运算特性进行了优化,高效完成向量与矩阵的列方向乘法操作。 | ||
| 6 | - | ||
| 7 | -数学表达式: | ||
| 8 | - | ||
| 9 | -``` | ||
| 10 | -result[i, j] = vec[i] * mat[i, j] | ||
| 11 | -``` | ||
| 12 | - | ||
| 13 | -包含以下接口: | ||
| 14 | - | ||
| 15 | -| 接口名 | 功能简述 | | ||
| 16 | -|--------|---------| | ||
| 17 | -| aclblasColwiseMul | 复数向量与矩阵每行逐元素乘法 | | ||
| 18 | - | ||
| 19 | -## 算子执行接口 | ||
| 20 | - | ||
| 21 | -### aclblasColwiseMul | ||
| 22 | - | ||
| 23 | -#### 产品支持情况 | ||
| 24 | - | ||
| 25 | -- Ascend 950PR / Ascend 950DT:不支持 | ||
| 26 | -- Atlas A3 训练系列产品 / Atlas A3 推理系列产品:支持 | ||
| 27 | -- Atlas A2 训练系列产品 / Atlas A2 推理系列产品:支持 | ||
| 28 | - | ||
| 29 | -#### 函数原型 | ||
| 30 | - | ||
| 31 | -```cpp | ||
| 32 | -int aclblasColwiseMul(const float *mat, const float *vec, float *result, const int64_t m, const int64_t n, void *stream) | ||
| 33 | -``` | ||
| 34 | - | ||
| 35 | -#### 参数说明 | ||
| 36 | - | ||
| 37 | -| 参数名 | 输入/输出 | 参数类型 | 说明 | | ||
| 38 | -|--------|----------|---------|------| | ||
| 39 | -| mat | 输入 | const float*(FP32) | 复数矩阵,维度为 m x n,存储为 2*m*n 个 float,Device 内存 | | ||
| 40 | -| vec | 输入 | const float*(FP32) | 复数向量,包含 m 个元素,存储为 2*m 个 float,Device 内存 | | ||
| 41 | -| result | 输出 | float*(FP32) | 复数矩阵,维度为 m x n,存储为 2*m*n 个 float,Device 内存 | | ||
| 42 | -| m | 输入 | int64_t | 矩阵的行数,Host 内存 | | ||
| 43 | -| n | 输入 | int64_t | 矩阵的列数,Host 内存 | | ||
| 44 | -| stream | 输入 | void* | 执行流,Host 内存 | | ||
| 45 | - | ||
| 46 | -#### 约束说明 | ||
| 47 | - | ||
| 48 | -无 | ||
Dblas/colwise_mul/arch22/colwise_mul_host.cpp+0-158
| @@ -1,158 +0,0 @@ | |||
| 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 the License for 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 colwise_mul_host.cpp | ||
| 13 | - * \brief Host side implementation for colwise_mul operator | ||
| 14 | - */ | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | - | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | - | ||
| 23 | - | ||
| 24 | - | ||
| 25 | - | ||
| 26 | -void colwise_mul_kernel_do(uint8_t* mat, uint8_t* vec, uint8_t* aug, uint8_t* result, | ||
| 27 | - uint8_t* workSpace, uint8_t* tilingGm, | ||
| 28 | - uint32_t numBlocks, void *stream); | ||
| 29 | - | ||
| 30 | -constexpr uint32_t DEFAULT_VECTOR_NUM = 40; | ||
| 31 | -constexpr uint32_t DEFAULT_CUBE_NUM = 20; | ||
| 32 | - | ||
| 33 | -constexpr uint32_t COMPLEX_NUM = 2; | ||
| 34 | -constexpr uint32_t FP32_BYTE_SIZE = 4; | ||
| 35 | -constexpr uint32_t MAX_DATA_COUNT = 32 * 1024 / sizeof(float); | ||
| 36 | - | ||
| 37 | -// Tiling data structure | ||
| 38 | -struct ColwiseMulTilingData { | ||
| 39 | - uint32_t m; | ||
| 40 | - uint32_t n; | ||
| 41 | - | ||
| 42 | - uint32_t startOffset[40]; | ||
| 43 | - uint32_t calRowNum[40]; | ||
| 44 | -}; | ||
| 45 | - | ||
| 46 | -// Tiling calculation | ||
| 47 | -ColwiseMulTilingData CalColwiseMulTilingData(uint32_t m, uint32_t n, uint32_t vecCoreNum) | ||
| 48 | -{ | ||
| 49 | - ColwiseMulTilingData tilingData; | ||
| 50 | - memset(&tilingData, 0, sizeof(ColwiseMulTilingData)); | ||
| 51 | - | ||
| 52 | - if (vecCoreNum == 0) { | ||
| 53 | - vecCoreNum = 1; | ||
| 54 | - } | ||
| 55 | - vecCoreNum = vecCoreNum > DEFAULT_VECTOR_NUM ? DEFAULT_VECTOR_NUM : vecCoreNum; | ||
| 56 | - | ||
| 57 | - // n is already in float elements (for complex, it's 2 * num_complex) | ||
| 58 | - uint32_t rowNumEachCore = m / vecCoreNum; | ||
| 59 | - uint32_t remainRowNum = m % vecCoreNum; | ||
| 60 | - | ||
| 61 | - if (rowNumEachCore == 0) { | ||
| 62 | - for (uint32_t i = 0; i < remainRowNum; i++) { | ||
| 63 | - tilingData.calRowNum[i] = 1; | ||
| 64 | - tilingData.startOffset[i] = n * i; // each row has n FP32 elements | ||
| 65 | - } | ||
| 66 | - } else { | ||
| 67 | - uint32_t currOffset = 0; | ||
| 68 | - uint32_t currRowNum; | ||
| 69 | - for (uint32_t i = 0; i < vecCoreNum; i++) { | ||
| 70 | - if (i < remainRowNum) { | ||
| 71 | - currRowNum = rowNumEachCore + 1; | ||
| 72 | - } else { | ||
| 73 | - currRowNum = rowNumEachCore; | ||
| 74 | - } | ||
| 75 | - tilingData.calRowNum[i] = currRowNum; | ||
| 76 | - tilingData.startOffset[i] = currOffset; | ||
| 77 | - currOffset += currRowNum * n; | ||
| 78 | - } | ||
| 79 | - } | ||
| 80 | - | ||
| 81 | - tilingData.m = m; // num of rows | ||
| 82 | - tilingData.n = n; // num of FP32 elements each row | ||
| 83 | - | ||
| 84 | - return tilingData; | ||
| 85 | -} | ||
| 86 | - | ||
| 87 | -uint32_t* CreateAugColwiseMul() | ||
| 88 | -{ | ||
| 89 | - uint32_t complexCount = MAX_DATA_COUNT / COMPLEX_NUM; | ||
| 90 | - | ||
| 91 | - uint32_t* augData = nullptr; | ||
| 92 | - | ||
| 93 | - augData = new uint32_t[MAX_DATA_COUNT]; | ||
| 94 | - | ||
| 95 | - for (uint32_t i = 0; i < complexCount; i++) { | ||
| 96 | - augData[COMPLEX_NUM * i] = FP32_BYTE_SIZE * i; | ||
| 97 | - augData[COMPLEX_NUM * i + 1] = FP32_BYTE_SIZE * (i + complexCount); | ||
| 98 | - } | ||
| 99 | - return augData; | ||
| 100 | -} | ||
| 101 | - | ||
| 102 | -aclblasStatus_t aclblasColwiseMul( | ||
| 103 | - aclblasHandle_t handle, const int64_t m, const int64_t n, uint8_t* mat, uint8_t* vec, uint8_t* result) | ||
| 104 | -{ | ||
| 105 | - auto* h = handle; | ||
| 106 | - aclrtStream useStream = h->stream; | ||
| 107 | - | ||
| 108 | - uint32_t nFloats = n * 2; | ||
| 109 | - uint32_t numBlocks = 8; | ||
| 110 | - | ||
| 111 | - ColwiseMulTilingData tiling = CalColwiseMulTilingData(m, nFloats, numBlocks); | ||
| 112 | - | ||
| 113 | - uint32_t* aug = CreateAugColwiseMul(); | ||
| 114 | - size_t augByteSize = MAX_DATA_COUNT * sizeof(uint32_t); | ||
| 115 | - size_t workspaceSize = 1024; | ||
| 116 | - | ||
| 117 | - uint8_t* augDevice = nullptr; | ||
| 118 | - uint8_t* workspaceDevice = nullptr; | ||
| 119 | - uint8_t* tilingDevice = nullptr; | ||
| 120 | - | ||
| 121 | - aclError aclRet = aclrtMalloc((void**)&augDevice, augByteSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 122 | - CHECK_RET( | ||
| 123 | - aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", aclRet); | ||
| 124 | - return ACLBLAS_STATUS_ALLOC_FAILED); | ||
| 125 | - | ||
| 126 | - aclRet = aclrtMalloc((void**)&workspaceDevice, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 127 | - CHECK_RET( | ||
| 128 | - aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", aclRet); aclrtFree(augDevice); | ||
| 129 | - return ACLBLAS_STATUS_ALLOC_FAILED); | ||
| 130 | - | ||
| 131 | - aclRet = aclrtMalloc((void**)&tilingDevice, sizeof(ColwiseMulTilingData), ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 132 | - CHECK_RET( | ||
| 133 | - aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", aclRet); aclrtFree(workspaceDevice); | ||
| 134 | - aclrtFree(augDevice); return ACLBLAS_STATUS_ALLOC_FAILED); | ||
| 135 | - | ||
| 136 | - aclRet = aclrtMemcpy(augDevice, augByteSize, aug, augByteSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 137 | - CHECK_RET( | ||
| 138 | - aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", aclRet); aclrtFree(tilingDevice); | ||
| 139 | - aclrtFree(workspaceDevice); aclrtFree(augDevice); return ACLBLAS_STATUS_INTERNAL_ERROR); | ||
| 140 | - | ||
| 141 | - aclRet = aclrtMemcpy( | ||
| 142 | - tilingDevice, sizeof(ColwiseMulTilingData), &tiling, sizeof(ColwiseMulTilingData), ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 143 | - CHECK_RET( | ||
| 144 | - aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", aclRet); aclrtFree(tilingDevice); | ||
| 145 | - aclrtFree(workspaceDevice); aclrtFree(augDevice); return ACLBLAS_STATUS_INTERNAL_ERROR); | ||
| 146 | - | ||
| 147 | - colwise_mul_kernel_do(mat, vec, augDevice, result, workspaceDevice, tilingDevice, numBlocks, useStream); | ||
| 148 | - aclRet = aclrtSynchronizeStream(useStream); | ||
| 149 | - CHECK_RET( | ||
| 150 | - aclRet == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", aclRet); aclrtFree(tilingDevice); | ||
| 151 | - aclrtFree(workspaceDevice); aclrtFree(augDevice); return ACLBLAS_STATUS_INTERNAL_ERROR); | ||
| 152 | - | ||
| 153 | - aclrtFree(augDevice); | ||
| 154 | - aclrtFree(workspaceDevice); | ||
| 155 | - aclrtFree(tilingDevice); | ||
| 156 | - | ||
| 157 | - return ACLBLAS_STATUS_SUCCESS; | ||
| 158 | -} | ||
Dblas/colwise_mul/arch22/colwise_mul_kernel.cpp+0-263
| @@ -1,263 +0,0 @@ | |||
| 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 the License for 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 | -__aicore__ __inline__ __attribute__((always_inline)) void copy_vec_gm2ub_uint32( | ||
| 17 | - AscendC::LocalTensor<uint32_t> dst, | ||
| 18 | - AscendC::GlobalTensor<uint32_t> src, | ||
| 19 | - uint32_t len) | ||
| 20 | -{ | ||
| 21 | - uint16_t nBurst = 1; | ||
| 22 | - uint32_t lenBurst = len * sizeof(uint32_t); | ||
| 23 | - uint8_t leftPaddingNum = 0; | ||
| 24 | - uint8_t rightPaddingNum = 0; | ||
| 25 | - uint32_t srcGap = 0; | ||
| 26 | - uint32_t dstGap = 0; | ||
| 27 | - gm_to_ub_align<ArchType::ASCEND_V220, uint32_t>(dst, src, | ||
| 28 | - 0, // sid | ||
| 29 | - nBurst, lenBurst, leftPaddingNum, rightPaddingNum, srcGap, dstGap); | ||
| 30 | -} | ||
| 31 | - | ||
| 32 | -__aicore__ __inline__ __attribute__((always_inline)) void copy_vec_gm2ub( | ||
| 33 | - AscendC::LocalTensor<float> dst, | ||
| 34 | - AscendC::GlobalTensor<float> src, | ||
| 35 | - uint32_t len) | ||
| 36 | -{ | ||
| 37 | - uint16_t nBurst = 1; | ||
| 38 | - uint32_t lenBurst = len * sizeof(float); | ||
| 39 | - uint8_t leftPaddingNum = 0; | ||
| 40 | - uint8_t rightPaddingNum = 0; | ||
| 41 | - uint32_t srcGap = 0; | ||
| 42 | - uint32_t dstGap = 0; | ||
| 43 | - gm_to_ub_align<ArchType::ASCEND_V220, float>(dst, src, | ||
| 44 | - 0, // sid | ||
| 45 | - nBurst, lenBurst, leftPaddingNum, rightPaddingNum, srcGap, dstGap); | ||
| 46 | -} | ||
| 47 | - | ||
| 48 | -__aicore__ __inline__ __attribute__((always_inline)) void copy_vec_ub2gm( | ||
| 49 | - AscendC::GlobalTensor<float> dst, | ||
| 50 | - AscendC::LocalTensor<float> src, | ||
| 51 | - uint32_t len) | ||
| 52 | -{ | ||
| 53 | - uint16_t nBurst = 1; | ||
| 54 | - uint32_t lenBurst = len * sizeof(float); | ||
| 55 | - uint8_t leftPaddingNum = 0; | ||
| 56 | - uint8_t rightPaddingNum = 0; | ||
| 57 | - uint32_t srcGap = 0; | ||
| 58 | - uint32_t dstGap = 0; | ||
| 59 | - ub_to_gm_align<ArchType::ASCEND_V220, float>(dst, src, | ||
| 60 | - 0, // sid | ||
| 61 | - nBurst, lenBurst, leftPaddingNum, rightPaddingNum, srcGap, dstGap); | ||
| 62 | -} | ||
| 63 | - | ||
| 64 | -__aicore__ __inline__ __attribute__((always_inline)) void colwise_mul_compute_aiv( | ||
| 65 | - AscendC::GlobalTensor<float> gm_in, | ||
| 66 | - AscendC::GlobalTensor<float> gm_out, | ||
| 67 | - AscendC::LocalTensor<float> ub_in, | ||
| 68 | - AscendC::LocalTensor<float> ub_out, | ||
| 69 | - AscendC::LocalTensor<uint32_t> ub_offset, | ||
| 70 | - float s_real, float s_imag, uint32_t copy_len, uint32_t len, uint32_t event_id) | ||
| 71 | -{ | ||
| 72 | - uint32_t repeatTime = (len + 63) / 64; // 3 | ||
| 73 | - uint32_t computeRepeat = (len / 2 + 63) / 64; // 2 | ||
| 74 | - | ||
| 75 | - uint32_t real_offset = 0; | ||
| 76 | - uint32_t imag_offset = 32 * 1024 / sizeof(float) / 2; | ||
| 77 | - | ||
| 78 | - AscendC::LocalTensor<float> ub_out_real = ub_out; | ||
| 79 | - AscendC::LocalTensor<float> ub_out_imag = ub_out[imag_offset]; | ||
| 80 | - | ||
| 81 | - copy_vec_gm2ub(ub_in, gm_in, copy_len); | ||
| 82 | - | ||
| 83 | - SET_FLAG(MTE2, V, event_id); | ||
| 84 | - WAIT_FLAG(MTE2, V, event_id); | ||
| 85 | - | ||
| 86 | - uint32_t mask = 0; | ||
| 87 | - uint64_t rsvdCnt = 0; | ||
| 88 | - | ||
| 89 | - AscendC::GatherMask<float>(ub_out_real, ub_in, 1, false, mask, | ||
| 90 | - {1, static_cast<uint16_t>(repeatTime), 8, 8}, rsvdCnt); | ||
| 91 | - | ||
| 92 | - AscendC::GatherMask<float>(ub_out_imag, ub_in, 2, false, mask, | ||
| 93 | - {1, static_cast<uint16_t>(repeatTime), 8, 8}, rsvdCnt); | ||
| 94 | - | ||
| 95 | - PIPE_BARRIER(V); | ||
| 96 | - | ||
| 97 | - // R * R | ||
| 98 | - muls_v<ArchType::ASCEND_V220, float>(ub_in, ub_out_real, s_real, computeRepeat, 1, 1, 8, 8); | ||
| 99 | - | ||
| 100 | - // R * I | ||
| 101 | - muls_v<ArchType::ASCEND_V220, float>(ub_in[imag_offset], ub_out_real, s_imag, computeRepeat, 1, 1, 8, 8); | ||
| 102 | - | ||
| 103 | - // I * I | ||
| 104 | - muls_v<ArchType::ASCEND_V220, float>(ub_out_real, ub_out_imag, s_imag, computeRepeat, 1, 1, 8, 8); | ||
| 105 | - | ||
| 106 | - PIPE_BARRIER(V); | ||
| 107 | - // R * R - I * I | ||
| 108 | - sub_v<ArchType::ASCEND_V220, float>(ub_in, ub_in, ub_out_real, computeRepeat, 1, 1, 1, 8, 8, 8); | ||
| 109 | - | ||
| 110 | - // I * R | ||
| 111 | - muls_v<ArchType::ASCEND_V220, float>(ub_out_imag, ub_out_imag, s_real, computeRepeat, 1, 1, 8, 8); | ||
| 112 | - | ||
| 113 | - PIPE_BARRIER(V); | ||
| 114 | - // R * I + I * R | ||
| 115 | - add_v<ArchType::ASCEND_V220, float>( | ||
| 116 | - ub_in[imag_offset], ub_out_imag, ub_in[imag_offset], computeRepeat, 1, 1, 1, 8, 8, 8); | ||
| 117 | - | ||
| 118 | - PIPE_BARRIER(V); | ||
| 119 | - | ||
| 120 | - AscendC::Gather(ub_out, ub_in, ub_offset, (uint32_t)0, repeatTime * 64); | ||
| 121 | - PIPE_BARRIER(ALL); | ||
| 122 | - | ||
| 123 | - SET_FLAG(V, MTE3, event_id); | ||
| 124 | - WAIT_FLAG(V, MTE3, event_id); | ||
| 125 | - | ||
| 126 | - copy_vec_ub2gm(gm_out, ub_out, copy_len); | ||
| 127 | -} | ||
| 128 | - | ||
| 129 | -__aicore__ __inline__ __attribute__((always_inline)) void colwise_mul_aiv( | ||
| 130 | - AscendC::GlobalTensor<float> gm_in, | ||
| 131 | - AscendC::GlobalTensor<float> gm_vec, | ||
| 132 | - AscendC::GlobalTensor<uint32_t> gm_aug, | ||
| 133 | - AscendC::GlobalTensor<float> gm_out, | ||
| 134 | - uint32_t m, uint32_t cal_num, uint32_t offset, uint32_t row_num) | ||
| 135 | -{ | ||
| 136 | - // ub 192kb | ||
| 137 | - AsdopsBuffer<ArchType::ASCEND_V220> buf; | ||
| 138 | - AscendC::LocalTensor<float> ub_out_ping = buf.GetBuffer<BufferType::ASCEND_UB, float>(0 * 1024); | ||
| 139 | - AscendC::LocalTensor<float> ub_out_pong = buf.GetBuffer<BufferType::ASCEND_UB, float>(32 * 1024); | ||
| 140 | - AscendC::LocalTensor<float> ub_in_ping = buf.GetBuffer<BufferType::ASCEND_UB, float>(64 * 1024); | ||
| 141 | - AscendC::LocalTensor<float> ub_in_pong = buf.GetBuffer<BufferType::ASCEND_UB, float>(96 * 1024); | ||
| 142 | - AscendC::LocalTensor<uint32_t> ub_offset = buf.GetBuffer<BufferType::ASCEND_UB, uint32_t>(128 * 1024); | ||
| 143 | - | ||
| 144 | - uint32_t ping_flag = 1; | ||
| 145 | - | ||
| 146 | - uint32_t maxDataCount = 32 * 1024 / sizeof(float); | ||
| 147 | - | ||
| 148 | - uint32_t repeatTime = cal_num / maxDataCount; | ||
| 149 | - uint32_t remainNum = cal_num % maxDataCount; | ||
| 150 | - | ||
| 151 | - float s_real; | ||
| 152 | - float s_imag; | ||
| 153 | - | ||
| 154 | - // prepare offset | ||
| 155 | - copy_vec_gm2ub_uint32(ub_offset, gm_aug, maxDataCount); | ||
| 156 | - | ||
| 157 | - SET_FLAG(MTE2, V, EVENT_ID0); | ||
| 158 | - WAIT_FLAG(MTE2, V, EVENT_ID0); | ||
| 159 | - SET_FLAG(MTE2, V, EVENT_ID1); | ||
| 160 | - WAIT_FLAG(MTE2, V, EVENT_ID1); | ||
| 161 | - | ||
| 162 | - uint32_t curr_offset = offset; | ||
| 163 | - if (cal_num == 0) { | ||
| 164 | - return; | ||
| 165 | - } | ||
| 166 | - uint32_t curr_row = curr_offset / cal_num; | ||
| 167 | - | ||
| 168 | - for (uint32_t row_idx = 0; row_idx < row_num; row_idx++) { | ||
| 169 | - curr_offset = offset + cal_num * row_idx; | ||
| 170 | - | ||
| 171 | - s_real = gm_vec.GetValue((curr_row + row_idx) * 2); | ||
| 172 | - s_imag = gm_vec.GetValue((curr_row + row_idx) * 2 + 1); | ||
| 173 | - | ||
| 174 | - SET_FLAG(S, V, EVENT_ID0); | ||
| 175 | - WAIT_FLAG(S, V, EVENT_ID0); | ||
| 176 | - SET_FLAG(S, V, EVENT_ID1); | ||
| 177 | - WAIT_FLAG(S, V, EVENT_ID1); | ||
| 178 | - | ||
| 179 | - if (repeatTime > 0) { | ||
| 180 | - SET_FLAG(MTE3, MTE2, EVENT_ID0); | ||
| 181 | - SET_FLAG(MTE3, MTE2, EVENT_ID1); | ||
| 182 | - for (uint32_t i = 0; i < repeatTime; i++) { | ||
| 183 | - auto ub_in = ping_flag ? ub_in_ping : ub_in_pong; | ||
| 184 | - auto ub_out = ping_flag ? ub_out_ping : ub_out_pong; | ||
| 185 | - | ||
| 186 | - auto event_id = ping_flag ? EVENT_ID0 : EVENT_ID1; | ||
| 187 | - | ||
| 188 | - WAIT_FLAG(MTE3, MTE2, event_id); | ||
| 189 | - | ||
| 190 | - colwise_mul_compute_aiv(gm_in[curr_offset], gm_out[curr_offset], ub_in, ub_out, ub_offset, s_real, | ||
| 191 | - s_imag, maxDataCount, maxDataCount, event_id); | ||
| 192 | - | ||
| 193 | - SET_FLAG(MTE3, MTE2, event_id); | ||
| 194 | - | ||
| 195 | - curr_offset += maxDataCount; | ||
| 196 | - ping_flag = 1 - ping_flag; | ||
| 197 | - } | ||
| 198 | - WAIT_FLAG(MTE3, MTE2, EVENT_ID0); | ||
| 199 | - WAIT_FLAG(MTE3, MTE2, EVENT_ID1); | ||
| 200 | - } | ||
| 201 | - | ||
| 202 | - if (remainNum > 0) { | ||
| 203 | - SET_FLAG(MTE3, MTE2, EVENT_ID0); | ||
| 204 | - SET_FLAG(MTE3, MTE2, EVENT_ID1); | ||
| 205 | - auto ub_in = ping_flag ? ub_in_ping : ub_in_pong; | ||
| 206 | - auto ub_out = ping_flag ? ub_out_ping : ub_out_pong; | ||
| 207 | - auto event_id = ping_flag ? EVENT_ID0 : EVENT_ID1; | ||
| 208 | - WAIT_FLAG(MTE3, MTE2, event_id); | ||
| 209 | - | ||
| 210 | - colwise_mul_compute_aiv(gm_in[curr_offset], gm_out[curr_offset], ub_in, ub_out, ub_offset, s_real, s_imag, | ||
| 211 | - remainNum, remainNum, event_id); | ||
| 212 | - | ||
| 213 | - SET_FLAG(MTE3, MTE2, event_id); | ||
| 214 | - ping_flag = 1 - ping_flag; | ||
| 215 | - curr_offset += remainNum; | ||
| 216 | - WAIT_FLAG(MTE3, MTE2, EVENT_ID0); | ||
| 217 | - WAIT_FLAG(MTE3, MTE2, EVENT_ID1); | ||
| 218 | - } | ||
| 219 | - } | ||
| 220 | - PIPE_BARRIER(ALL); | ||
| 221 | -} | ||
| 222 | - | ||
| 223 | -__global__ __aicore__ __vector__ void colwise_mul(GM_ADDR mat, GM_ADDR vec, | ||
| 224 | - GM_ADDR aug, GM_ADDR result, | ||
| 225 | - GM_ADDR workSpace, GM_ADDR tilingGm) | ||
| 226 | -{ | ||
| 227 | - AscendC::SetAtomicNone(); | ||
| 228 | - AscendC::SetMaskNorm(); | ||
| 229 | - // AscendC::SetVectorMask<float>((uint64_t)-1, (uint64_t)-1); | ||
| 230 | - | ||
| 231 | - auto core_idx = AscendC::GetBlockIdx(); | ||
| 232 | - | ||
| 233 | - auto tiling_buf = reinterpret_cast<__gm__ uint8_t *>(tilingGm); | ||
| 234 | - | ||
| 235 | - uint32_t m = (*(__gm__ uint32_t *)((__gm__ uint8_t *)tiling_buf)); // num of float elements | ||
| 236 | - uint32_t n = (*(__gm__ uint32_t *)((__gm__ uint8_t *)tiling_buf + 4)); // num of float elements | ||
| 237 | - | ||
| 238 | - uint32_t offset = (*(__gm__ uint32_t *)((__gm__ uint8_t *)tiling_buf + 8 + 4 * core_idx)); | ||
| 239 | - uint32_t row_num = (*(__gm__ uint32_t *)((__gm__ uint8_t *)tiling_buf + 8 + 40 * 4 + 4 * core_idx)); | ||
| 240 | - | ||
| 241 | - if (row_num <= 0) | ||
| 242 | - return; | ||
| 243 | - | ||
| 244 | - AscendC::GlobalTensor<float> mat_tensor; | ||
| 245 | - AscendC::GlobalTensor<float> vec_tensor; | ||
| 246 | - AscendC::GlobalTensor<uint32_t> aug_tensor; | ||
| 247 | - AscendC::GlobalTensor<float> result_tensor; | ||
| 248 | - | ||
| 249 | - mat_tensor.SetGlobalBuffer(reinterpret_cast<__gm__ float *>(mat)); | ||
| 250 | - vec_tensor.SetGlobalBuffer(reinterpret_cast<__gm__ float *>(vec)); | ||
| 251 | - aug_tensor.SetGlobalBuffer(reinterpret_cast<__gm__ uint32_t *>(aug)); | ||
| 252 | - result_tensor.SetGlobalBuffer(reinterpret_cast<__gm__ float *>(result)); | ||
| 253 | - colwise_mul_aiv(mat_tensor, vec_tensor, aug_tensor, result_tensor, m, n, offset, row_num); | ||
| 254 | -} | ||
| 255 | - | ||
| 256 | -// Wrapper function for host to call | ||
| 257 | -void colwise_mul_kernel_do(GM_ADDR mat, GM_ADDR vec, GM_ADDR aug, GM_ADDR result, | ||
| 258 | - GM_ADDR workSpace, GM_ADDR tilingGm, | ||
| 259 | - uint32_t numBlocks, void *stream) | ||
| 260 | -{ | ||
| 261 | - colwise_mul<<<numBlocks, nullptr, stream>>>(mat, vec, aug, result, workSpace, tilingGm); | ||
| 262 | -} | ||
| 263 | - | ||
| @@ -2,7 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | ## 算子概述 | 3 | ## 算子概述 |
| 4 | 4 | ||
| 5 | -Dgmm(Diagonal Matrix-Matrix Multiplication)算子实现了对角矩阵与普通矩阵的乘法运算,使用一个向量构造对角矩阵,按行(LEFT)或按列(RIGHT)对输入矩阵进行缩放,核心运算为逐元素乘法。矩阵按列主序(BLAS 约定)存储。 | 5 | +Dgmm(Diagonal Matrix-Matrix Multiplication)算子实现了对角矩阵与普通矩阵的乘法运算,使用一个向量构造对角矩阵,按行(LEFT)或按列(RIGHT)对输入矩阵进行缩放,核心运算为逐元素乘法。 |
| 6 | 6 | ||
| 7 | 数学表达式: | 7 | 数学表达式: |
| 8 | 8 | ||
| @@ -15,7 +15,8 @@ RIGHT 模式: C = A * diag(x), C[i,j] = A[i,j] * x[j] (x 长度为 n | |||
| 15 | 15 | ||
| 16 | | 接口名 | 功能简述 | | 16 | | 接口名 | 功能简述 | |
| 17 | |--------|---------| | 17 | |--------|---------| |
| 18 | -| aclblasSdgmm | 单精度浮点对角矩阵乘法 | | 18 | +| aclblasSdgmm | 单精度实数对角矩阵乘法 | |
| 19 | +| aclblasCdgmm | 单精度复数对角矩阵乘法,当前仅支持 LEFT 模式,RIGHT 模式暂未实现 | | ||
| 19 | 20 | ||
| 20 | ## 算子执行接口 | 21 | ## 算子执行接口 |
| 21 | 22 | ||
| @@ -237,3 +238,52 @@ C[0,2] = 14.000000 | |||
| 237 | C[1,2] = 24.000000 | 238 | C[1,2] = 24.000000 |
| 238 | C[2,2] = 36.000000 | 239 | C[2,2] = 36.000000 |
| 239 | ``` | 240 | ``` |
| 241 | + | ||
| 242 | +### aclblasCdgmm | ||
| 243 | + | ||
| 244 | +#### 产品支持情况 | ||
| 245 | + | ||
| 246 | +- Ascend 950PR / Ascend 950DT:不支持 | ||
| 247 | +- Atlas A3 训练系列产品 / Atlas A3 推理系列产品:支持 | ||
| 248 | +- Atlas A2 训练系列产品 / Atlas A2 推理系列产品:支持 | ||
| 249 | + | ||
| 250 | +#### 函数原型 | ||
| 251 | + | ||
| 252 | +```cpp | ||
| 253 | +aclblasStatus_t aclblasCdgmm(aclblasHandle_t handle, aclblasSideMode_t mode, int m, int n, const aclblasComplex *A, int lda, const aclblasComplex *x, int incx, aclblasComplex *C, int ldc) | ||
| 254 | +``` | ||
| 255 | + | ||
| 256 | +#### 参数说明 | ||
| 257 | + | ||
| 258 | +| 参数名 | 输入/输出 | 参数类型 | 说明 | | ||
| 259 | +|--------|----------|---------|------| | ||
| 260 | +| handle | 输入 | aclblasHandle_t | ops-blas 库上下文句柄,携带 stream,Host 内存 | | ||
| 261 | +| mode | 输入 | aclblasSideMode_t | 缩放模式:当前仅支持 ACLBLAS_SIDE_LEFT(C = diag(x) * A,x 长度为 m);ACLBLAS_SIDE_RIGHT 返回 ACLBLAS_STATUS_NOT_SUPPORTED,Host 内存 | | ||
| 262 | +| m | 输入 | int | 矩阵 A/C 的行数,m >= 0,Host 内存 | | ||
| 263 | +| n | 输入 | int | 矩阵 A/C 的列数,n >= 0,Host 内存 | | ||
| 264 | +| A | 输入 | const aclblasComplex* | 输入矩阵,行主序存储,维度 m×n,Device 内存 | | ||
| 265 | +| lda | 输入 | int | 矩阵 A 的行跨度(row-major),lda >= max(1, n),Host 内存 | | ||
| 266 | +| x | 输入 | const aclblasComplex* | 对角向量,LEFT 模式下长度为 m,Device 内存 | | ||
| 267 | +| incx | 输入 | int | x 中相邻元素的步长,incx != 0,可为负数,Host 内存 | | ||
| 268 | +| C | 输出 | aclblasComplex* | 输出矩阵,行主序存储,维度 m×n,Device 内存 | | ||
| 269 | +| ldc | 输入 | int | 矩阵 C 的行跨度(row-major),ldc >= max(1, n),Host 内存 | | ||
| 270 | + | ||
| 271 | +#### 约束说明 | ||
| 272 | + | ||
| 273 | +- 当前仅支持 `ACLBLAS_SIDE_LEFT` 模式(C = diag(x) * A,C[i,j] = x[i] * A[i,j]) | ||
| 274 | +- `ACLBLAS_SIDE_RIGHT` 是合法枚举,但当前返回 `ACLBLAS_STATUS_NOT_SUPPORTED` | ||
| 275 | +- A 和 C 使用行主序(row-major)存储,与 cuBLAS `cublasCdgmm` 的列主序语义存在差异,不能把 cuBLAS 的列主序输入未经转换直接传入 | ||
| 276 | +- `lda` 和 `ldc` 表示行主序的行跨度(相邻两行起始位置之间的复数元素数),约束为不小于 n | ||
| 277 | +- handle 不能为 nullptr,否则返回 `ACLBLAS_STATUS_HANDLE_IS_NULLPTR` | ||
| 278 | +- mode 必须为 `ACLBLAS_SIDE_LEFT` 或 `ACLBLAS_SIDE_RIGHT`,否则返回 `ACLBLAS_STATUS_INVALID_ENUM` | ||
| 279 | +- m >= 0, n >= 0,否则返回 `ACLBLAS_STATUS_INVALID_VALUE` | ||
| 280 | +- incx != 0(可为负数,表示反向访问 x),否则返回 `ACLBLAS_STATUS_INVALID_VALUE` | ||
| 281 | +- lda >= max(1, n),否则返回 `ACLBLAS_STATUS_INVALID_VALUE` | ||
| 282 | +- ldc >= max(1, n),否则返回 `ACLBLAS_STATUS_INVALID_VALUE` | ||
| 283 | +- 当 m > 0 且 n > 0 时,A、x、C 不能为 nullptr,否则返回 `ACLBLAS_STATUS_INVALID_VALUE` | ||
| 284 | +- m == 0 或 n == 0 时为 no-op,直接返回 `ACLBLAS_STATUS_SUCCESS` | ||
| 285 | +- 支持正负 `incx` | ||
| 286 | +- 支持独立 `lda`、`ldc`(lda != ldc) | ||
| 287 | +- C 的 padding 区域(C[i*ldc+n ... i*ldc+ldc-1])不被修改 | ||
| 288 | +- 支持 `A == C && lda == ldc` 的原地执行;`A == C && lda != ldc` 返回 `ACLBLAS_STATUS_INVALID_VALUE` | ||
| 289 | +- arch22 支持;arch35 暂不支持 Cdgmm | ||
| @@ -0,0 +1,292 @@ | |||
| 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 the License for the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, 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 cdgmm_host.cpp | ||
| 13 | + * \brief Host-side implementation of aclblasCdgmm (arch22). | ||
| 14 | + * Complex diagonal matrix-matrix multiplication: C = diag(x) * A | ||
| 15 | + * (mode=LEFT). Row-major storage. RIGHT mode returns | ||
| 16 | + * ACLBLAS_STATUS_NOT_SUPPORTED. | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +constexpr uint32_t CDGMM_DEFAULT_VECTOR_NUM = 40; | ||
| 30 | +constexpr uint32_t CDGMM_COMPLEX_NUM = 2; | ||
| 31 | +constexpr uint32_t CDGMM_FP32_BYTE_SIZE = 4; | ||
| 32 | +constexpr uint32_t CDGMM_MAX_DATA_COUNT = 32 * 1024 / sizeof(float); | ||
| 33 | +constexpr size_t CDGMM_WORKSPACE_SIZE = 1024; | ||
| 34 | + | ||
| 35 | +// ========================================================================== | ||
| 36 | +// RAII wrapper for device buffers — guarantees aclrtFree on all paths. | ||
| 37 | +// ========================================================================== | ||
| 38 | +class AclDeviceBuffer { | ||
| 39 | +public: | ||
| 40 | + AclDeviceBuffer() = default; | ||
| 41 | + ~AclDeviceBuffer() | ||
| 42 | + { | ||
| 43 | + if (data_ != nullptr) { | ||
| 44 | + aclrtFree(data_); | ||
| 45 | + } | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + aclError Allocate(size_t size) | ||
| 49 | + { | ||
| 50 | + data_ = nullptr; | ||
| 51 | + return aclrtMalloc(reinterpret_cast<void**>(&data_), size, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + uint8_t* Get() const { return data_; } | ||
| 55 | + | ||
| 56 | + AclDeviceBuffer(const AclDeviceBuffer&) = delete; | ||
| 57 | + AclDeviceBuffer& operator=(const AclDeviceBuffer&) = delete; | ||
| 58 | + | ||
| 59 | +private: | ||
| 60 | + uint8_t* data_ = nullptr; | ||
| 61 | +}; | ||
| 62 | + | ||
| 63 | +// ========================================================================== | ||
| 64 | +// Parameter validation | ||
| 65 | +// ========================================================================== | ||
| 66 | +static aclblasStatus_t ValidateCdgmmParams( | ||
| 67 | + aclblasSideMode_t mode, int m, int n, | ||
| 68 | + const aclblasComplex* A, int lda, const aclblasComplex* x, int incx, | ||
| 69 | + aclblasComplex* C, int ldc) | ||
| 70 | +{ | ||
| 71 | + if (mode != ACLBLAS_SIDE_LEFT && mode != ACLBLAS_SIDE_RIGHT) { | ||
| 72 | + OP_LOGE("aclblasCdgmm", "mode must be SIDE_LEFT(141) or SIDE_RIGHT(142), got %d", | ||
| 73 | + static_cast<int>(mode)); | ||
| 74 | + return ACLBLAS_STATUS_INVALID_ENUM; | ||
| 75 | + } | ||
| 76 | + if (mode == ACLBLAS_SIDE_RIGHT) { | ||
| 77 | + OP_LOGE("aclblasCdgmm", | ||
| 78 | + "ACLBLAS_SIDE_RIGHT is not supported in the current row-major implementation"); | ||
| 79 | + return ACLBLAS_STATUS_NOT_SUPPORTED; | ||
| 80 | + } | ||
| 81 | + if (m < 0) { | ||
| 82 | + OP_LOGE("aclblasCdgmm", "m must be >= 0, got %d", m); | ||
| 83 | + return ACLBLAS_STATUS_INVALID_VALUE; | ||
| 84 | + } | ||
| 85 | + if (n < 0) { | ||
| 86 | + OP_LOGE("aclblasCdgmm", "n must be >= 0, got %d", n); | ||
| 87 | + return ACLBLAS_STATUS_INVALID_VALUE; | ||
| 88 | + } | ||
| 89 | + if (incx == 0) { | ||
| 90 | + OP_LOGE("aclblasCdgmm", "incx must not be zero"); | ||
| 91 | + return ACLBLAS_STATUS_INVALID_VALUE; | ||
| 92 | + } | ||
| 93 | + if (lda < std::max(1, n)) { | ||
| 94 | + OP_LOGE("aclblasCdgmm", "lda must be >= max(1, n), got lda=%d, n=%d", lda, n); | ||
| 95 | + return ACLBLAS_STATUS_INVALID_VALUE; | ||
| 96 | + } | ||
| 97 | + if (ldc < std::max(1, n)) { | ||
| 98 | + OP_LOGE("aclblasCdgmm", "ldc must be >= max(1, n), got ldc=%d, n=%d", ldc, n); | ||
| 99 | + return ACLBLAS_STATUS_INVALID_VALUE; | ||
| 100 | + } | ||
| 101 | + if (m > 0 && n > 0 && (A == nullptr || x == nullptr || C == nullptr)) { | ||
| 102 | + OP_LOGE("aclblasCdgmm", "A/x/C must not be nullptr when m>0 and n>0"); | ||
| 103 | + return ACLBLAS_STATUS_INVALID_VALUE; | ||
| 104 | + } | ||
| 105 | + if (A == C && lda != ldc) { | ||
| 106 | + OP_LOGE("aclblasCdgmm", "in-place execution (A==C) requires lda==ldc, got lda=%d, ldc=%d", lda, ldc); | ||
| 107 | + return ACLBLAS_STATUS_INVALID_VALUE; | ||
| 108 | + } | ||
| 109 | + return ACLBLAS_STATUS_SUCCESS; | ||
| 110 | +} | ||
| 111 | + | ||
| 112 | +// ========================================================================== | ||
| 113 | +// Unified numBlocks calculation — shared by tiling and host launch. | ||
| 114 | +// ========================================================================== | ||
| 115 | +static uint32_t CalcCdgmmNumBlocks(uint32_t m, uint32_t aivCoreNum) | ||
| 116 | +{ | ||
| 117 | + uint32_t clamped = std::max(1U, std::min(aivCoreNum, CDGMM_DEFAULT_VECTOR_NUM)); | ||
| 118 | + return std::min(clamped, m); | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +// ========================================================================== | ||
| 122 | +// Tiling: row-split decomposition (Task 1 + Task 2) | ||
| 123 | +// ========================================================================== | ||
| 124 | +static CdgmmTilingData CalCdgmmTilingData( | ||
| 125 | + uint32_t mode, uint32_t m, uint32_t n, int32_t incx, | ||
| 126 | + uint32_t lda, uint32_t ldc, uint32_t aivCoreNum) | ||
| 127 | +{ | ||
| 128 | + CdgmmTilingData tiling{}; | ||
| 129 | + | ||
| 130 | + tiling.mode = mode; | ||
| 131 | + tiling.m = m; | ||
| 132 | + tiling.n = n; | ||
| 133 | + tiling.incx = incx; | ||
| 134 | + tiling.lda = lda; | ||
| 135 | + tiling.ldc = ldc; | ||
| 136 | + | ||
| 137 | + // Guard: empty matrix — return zero-initialized tiling without division. | ||
| 138 | + if (m == 0) { | ||
| 139 | + return tiling; | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + const uint32_t numBlocks = CalcCdgmmNumBlocks(m, aivCoreNum); | ||
| 143 | + if (numBlocks == 0) { | ||
| 144 | + return tiling; | ||
| 145 | + } | ||
| 146 | + const uint32_t rowsPerCore = m / numBlocks; | ||
| 147 | + const uint32_t remainder = m % numBlocks; | ||
| 148 | + | ||
| 149 | + uint32_t currRow = 0; | ||
| 150 | + for (uint32_t i = 0; i < numBlocks; i++) { | ||
| 151 | + uint32_t currCount = (i < remainder) ? rowsPerCore + 1 : rowsPerCore; | ||
| 152 | + tiling.startRow[i] = currRow; | ||
| 153 | + tiling.rowCount[i] = currCount; | ||
| 154 | + currRow += currCount; | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + return tiling; | ||
| 158 | +} | ||
| 159 | + | ||
| 160 | +// ========================================================================== | ||
| 161 | +// Aug offset table builder | ||
| 162 | +// ========================================================================== | ||
| 163 | +static std::vector<uint32_t> CreateAugCdgmm() | ||
| 164 | +{ | ||
| 165 | + uint32_t complexCount = CDGMM_MAX_DATA_COUNT / CDGMM_COMPLEX_NUM; | ||
| 166 | + std::vector<uint32_t> aug(CDGMM_MAX_DATA_COUNT); | ||
| 167 | + | ||
| 168 | + for (uint32_t i = 0; i < complexCount; i++) { | ||
| 169 | + aug[CDGMM_COMPLEX_NUM * i] = CDGMM_FP32_BYTE_SIZE * i; | ||
| 170 | + aug[CDGMM_COMPLEX_NUM * i + 1] = CDGMM_FP32_BYTE_SIZE * (i + complexCount); | ||
| 171 | + } | ||
| 172 | + return aug; | ||
| 173 | +} | ||
| 174 | + | ||
| 175 | +// ========================================================================== | ||
| 176 | +// Build launch configuration (tiling, numBlocks, aug) | ||
| 177 | +// ========================================================================== | ||
| 178 | +struct CdgmmLaunchConfig { | ||
| 179 | + CdgmmTilingData tiling{}; | ||
| 180 | + uint32_t numBlocks = 0; | ||
| 181 | + std::vector<uint32_t> aug; | ||
| 182 | +}; | ||
| 183 | + | ||
| 184 | +static aclblasStatus_t BuildCdgmmLaunchConfig( | ||
| 185 | + aclblasSideMode_t mode, int m, int n, int lda, int incx, int ldc, | ||
| 186 | + uint32_t aivCoreNum, CdgmmLaunchConfig& config) | ||
| 187 | +{ | ||
| 188 | + uint32_t modeNorm = (mode == ACLBLAS_SIDE_LEFT) ? CDGMM_MODE_LEFT : CDGMM_MODE_RIGHT; | ||
| 189 | + | ||
| 190 | + config.tiling = CalCdgmmTilingData( | ||
| 191 | + modeNorm, static_cast<uint32_t>(m), static_cast<uint32_t>(n), incx, | ||
| 192 | + static_cast<uint32_t>(lda), static_cast<uint32_t>(ldc), aivCoreNum); | ||
| 193 | + | ||
| 194 | + config.numBlocks = CalcCdgmmNumBlocks(static_cast<uint32_t>(m), aivCoreNum); | ||
| 195 | + config.aug = CreateAugCdgmm(); | ||
| 196 | + | ||
| 197 | + return ACLBLAS_STATUS_SUCCESS; | ||
| 198 | +} | ||
| 199 | + | ||
| 200 | +// ========================================================================== | ||
| 201 | +// Launch: allocate device buffers, copy, kernel, sync (Task 3) | ||
| 202 | +// ========================================================================== | ||
| 203 | +static aclblasStatus_t LaunchCdgmm( | ||
| 204 | + aclrtStream stream, | ||
| 205 | + const aclblasComplex* A, const aclblasComplex* x, aclblasComplex* C, | ||
| 206 | + const CdgmmLaunchConfig& config) | ||
| 207 | +{ | ||
| 208 | + AclDeviceBuffer augDevice; | ||
| 209 | + AclDeviceBuffer workspaceDevice; | ||
| 210 | + AclDeviceBuffer tilingDevice; | ||
| 211 | + | ||
| 212 | + size_t augByteSize = config.aug.size() * sizeof(uint32_t); | ||
| 213 | + | ||
| 214 | + aclError aclRet = augDevice.Allocate(augByteSize); | ||
| 215 | + if (aclRet != ACL_SUCCESS) { | ||
| 216 | + OP_LOGE("aclblasCdgmm", "aclrtMalloc aug failed. ERROR: %d", aclRet); | ||
| 217 | + return ACLBLAS_STATUS_ALLOC_FAILED; | ||
| 218 | + } | ||
| 219 | + | ||
| 220 | + aclRet = workspaceDevice.Allocate(CDGMM_WORKSPACE_SIZE); | ||
| 221 | + if (aclRet != ACL_SUCCESS) { | ||
| 222 | + OP_LOGE("aclblasCdgmm", "aclrtMalloc workspace failed. ERROR: %d", aclRet); | ||
| 223 | + return ACLBLAS_STATUS_ALLOC_FAILED; | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + aclRet = tilingDevice.Allocate(sizeof(CdgmmTilingData)); | ||
| 227 | + if (aclRet != ACL_SUCCESS) { | ||
| 228 | + OP_LOGE("aclblasCdgmm", "aclrtMalloc tiling failed. ERROR: %d", aclRet); | ||
| 229 | + return ACLBLAS_STATUS_ALLOC_FAILED; | ||
| 230 | + } | ||
| 231 | + | ||
| 232 | + aclRet = aclrtMemcpy(augDevice.Get(), augByteSize, config.aug.data(), | ||
| 233 | + augByteSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 234 | + if (aclRet != ACL_SUCCESS) { | ||
| 235 | + OP_LOGE("aclblasCdgmm", "aclrtMemcpy aug failed. ERROR: %d", aclRet); | ||
| 236 | + return ACLBLAS_STATUS_INTERNAL_ERROR; | ||
| 237 | + } | ||
| 238 | + | ||
| 239 | + aclRet = aclrtMemcpy(tilingDevice.Get(), sizeof(CdgmmTilingData), &config.tiling, | ||
| 240 | + sizeof(CdgmmTilingData), ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 241 | + if (aclRet != ACL_SUCCESS) { | ||
| 242 | + OP_LOGE("aclblasCdgmm", "aclrtMemcpy tiling failed. ERROR: %d", aclRet); | ||
| 243 | + return ACLBLAS_STATUS_INTERNAL_ERROR; | ||
| 244 | + } | ||
| 245 | + | ||
| 246 | + cdgmm_kernel_do(reinterpret_cast<GM_ADDR>(const_cast<aclblasComplex*>(A)), | ||
| 247 | + reinterpret_cast<GM_ADDR>(const_cast<aclblasComplex*>(x)), | ||
| 248 | + reinterpret_cast<GM_ADDR>(C), | ||
| 249 | + augDevice.Get(), workspaceDevice.Get(), tilingDevice.Get(), | ||
| 250 | + config.numBlocks, stream); | ||
| 251 | + | ||
| 252 | + aclRet = aclrtSynchronizeStream(stream); | ||
| 253 | + if (aclRet != ACL_SUCCESS) { | ||
| 254 | + OP_LOGE("aclblasCdgmm", "aclrtSynchronizeStream failed. ERROR: %d", aclRet); | ||
| 255 | + return ACLBLAS_STATUS_INTERNAL_ERROR; | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + return ACLBLAS_STATUS_SUCCESS; | ||
| 259 | +} | ||
| 260 | + | ||
| 261 | +// ========================================================================== | ||
| 262 | +// Public API — orchestrates validate → build config → launch | ||
| 263 | +// ========================================================================== | ||
| 264 | +extern "C" aclblasStatus_t aclblasCdgmm( | ||
| 265 | + aclblasHandle_t handle, aclblasSideMode_t mode, | ||
| 266 | + int m, int n, const aclblasComplex* A, int lda, | ||
| 267 | + const aclblasComplex* x, int incx, aclblasComplex* C, int ldc) | ||
| 268 | +{ | ||
| 269 | + if (handle == nullptr) { | ||
| 270 | + OP_LOGE("aclblasCdgmm", "handle is nullptr"); | ||
| 271 | + return ACLBLAS_STATUS_HANDLE_IS_NULLPTR; | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + aclblasStatus_t st = ValidateCdgmmParams(mode, m, n, A, lda, x, incx, C, ldc); | ||
| 275 | + if (st != ACLBLAS_STATUS_SUCCESS) { | ||
| 276 | + return st; | ||
| 277 | + } | ||
| 278 | + if (m == 0 || n == 0) { | ||
| 279 | + return ACLBLAS_STATUS_SUCCESS; | ||
| 280 | + } | ||
| 281 | + | ||
| 282 | + uint32_t aivCoreNum = GetAivCoreCount(); | ||
| 283 | + if (aivCoreNum == 0) { | ||
| 284 | + OP_LOGE("aclblasCdgmm", "GetAivCoreCount failed"); | ||
| 285 | + return ACLBLAS_STATUS_INTERNAL_ERROR; | ||
| 286 | + } | ||
| 287 | + | ||
| 288 | + CdgmmLaunchConfig config; | ||
| 289 | + BuildCdgmmLaunchConfig(mode, m, n, lda, incx, ldc, aivCoreNum, config); | ||
| 290 | + | ||
| 291 | + return LaunchCdgmm(handle->stream, A, x, C, config); | ||
| 292 | +} | ||
| @@ -0,0 +1,374 @@ | |||
| 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 the License for the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, 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 cdgmm_kernel.cpp | ||
| 13 | + * \brief Device-side kernel for aclblasCdgmm (arch22). | ||
| 14 | + * Row-major storage. Complex elements are stored as interleaved | ||
| 15 | + * float pairs (real, imag). | ||
| 16 | + * | ||
| 17 | + * mode=LEFT: C[i,j] = x[i] * A[i,j] | ||
| 18 | + * Each row is contiguous and multiplied by a single complex | ||
| 19 | + * scalar x[i]. Reuses the original scalar-vector complex | ||
| 20 | + * multiply path (GatherMask deinterleave, muls_v, Gather | ||
| 21 | + * re-interleave) with ping-pong UB buffers. | ||
| 22 | + */ | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +// ========================================================================== | ||
| 31 | +// UB copy helpers (kept from original colwise_mul, renamed) | ||
| 32 | +// ========================================================================== | ||
| 33 | + | ||
| 34 | +__aicore__ __inline__ __attribute__((always_inline)) void copy_vec_gm2ub_uint32( | ||
| 35 | + AscendC::LocalTensor<uint32_t> dst, | ||
| 36 | + AscendC::GlobalTensor<uint32_t> src, | ||
| 37 | + uint32_t len) | ||
| 38 | +{ | ||
| 39 | + uint16_t nBurst = 1; | ||
| 40 | + uint32_t lenBurst = len * sizeof(uint32_t); | ||
| 41 | + uint8_t leftPaddingNum = 0; | ||
| 42 | + uint8_t rightPaddingNum = 0; | ||
| 43 | + uint32_t srcGap = 0; | ||
| 44 | + uint32_t dstGap = 0; | ||
| 45 | + gm_to_ub_align<ArchType::ASCEND_V220, uint32_t>(dst, src, | ||
| 46 | + 0, nBurst, lenBurst, leftPaddingNum, rightPaddingNum, srcGap, dstGap); | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +__aicore__ __inline__ __attribute__((always_inline)) void copy_vec_gm2ub( | ||
| 50 | + AscendC::LocalTensor<float> dst, | ||
| 51 | + AscendC::GlobalTensor<float> src, | ||
| 52 | + uint32_t len) | ||
| 53 | +{ | ||
| 54 | + uint16_t nBurst = 1; | ||
| 55 | + uint32_t lenBurst = len * sizeof(float); | ||
| 56 | + uint8_t leftPaddingNum = 0; | ||
| 57 | + uint8_t rightPaddingNum = 0; | ||
| 58 | + uint32_t srcGap = 0; | ||
| 59 | + uint32_t dstGap = 0; | ||
| 60 | + gm_to_ub_align<ArchType::ASCEND_V220, float>(dst, src, | ||
| 61 | + 0, nBurst, lenBurst, leftPaddingNum, rightPaddingNum, srcGap, dstGap); | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +__aicore__ __inline__ __attribute__((always_inline)) void copy_vec_ub2gm( | ||
| 65 | + AscendC::GlobalTensor<float> dst, | ||
| 66 | + AscendC::LocalTensor<float> src, | ||
| 67 | + uint32_t len) | ||
| 68 | +{ | ||
| 69 | + uint16_t nBurst = 1; | ||
| 70 | + uint32_t lenBurst = len * sizeof(float); | ||
| 71 | + uint8_t leftPaddingNum = 0; | ||
| 72 | + uint8_t rightPaddingNum = 0; | ||
| 73 | + uint32_t srcGap = 0; | ||
| 74 | + uint32_t dstGap = 0; | ||
| 75 | + ub_to_gm_align<ArchType::ASCEND_V220, float>(dst, src, | ||
| 76 | + 0, nBurst, lenBurst, leftPaddingNum, rightPaddingNum, srcGap, dstGap); | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +// ========================================================================== | ||
| 80 | +// Core compute: scalar complex multiply on a contiguous block. | ||
| 81 | +// (Renamed from colwise_mul_compute_aiv, logic preserved.) | ||
| 82 | +// | ||
| 83 | +// Multiplies a contiguous block of interleaved complex floats by a complex | ||
| 84 | +// scalar (s_real, s_imag): | ||
| 85 | +// out = a * (s_real + s_imag*i) | ||
| 86 | +// ========================================================================== | ||
| 87 | +__aicore__ __inline__ __attribute__((always_inline)) void cdgmm_compute_aiv( | ||
| 88 | + AscendC::GlobalTensor<float> gm_in, | ||
| 89 | + AscendC::GlobalTensor<float> gm_out, | ||
| 90 | + AscendC::LocalTensor<float> ub_in, | ||
| 91 | + AscendC::LocalTensor<float> ub_out, | ||
| 92 | + AscendC::LocalTensor<uint32_t> ub_offset, | ||
| 93 | + float s_real, float s_imag, uint32_t copy_len, uint32_t event_id) | ||
| 94 | +{ | ||
| 95 | + uint32_t len = copy_len; | ||
| 96 | + uint32_t repeatTime = (len + 63) / 64; | ||
| 97 | + uint32_t computeRepeat = (len / 2 + 63) / 64; | ||
| 98 | + | ||
| 99 | + uint32_t real_offset = 0; | ||
| 100 | + uint32_t imag_offset = 32 * 1024 / sizeof(float) / 2; | ||
| 101 | + | ||
| 102 | + AscendC::LocalTensor<float> ub_out_real = ub_out; | ||
| 103 | + AscendC::LocalTensor<float> ub_out_imag = ub_out[imag_offset]; | ||
| 104 | + | ||
| 105 | + copy_vec_gm2ub(ub_in, gm_in, copy_len); | ||
| 106 | + | ||
| 107 | + SET_FLAG(MTE2, V, event_id); | ||
| 108 | + WAIT_FLAG(MTE2, V, event_id); | ||
| 109 | + | ||
| 110 | + uint32_t mask = 0; | ||
| 111 | + uint64_t rsvdCnt = 0; | ||
| 112 | + | ||
| 113 | + AscendC::GatherMask<float>(ub_out_real, ub_in, 1, false, mask, | ||
| 114 | + {1, static_cast<uint16_t>(repeatTime), 8, 8}, rsvdCnt); | ||
| 115 | + | ||
| 116 | + AscendC::GatherMask<float>(ub_out_imag, ub_in, 2, false, mask, | ||
| 117 | + {1, static_cast<uint16_t>(repeatTime), 8, 8}, rsvdCnt); | ||
| 118 | + | ||
| 119 | + PIPE_BARRIER(V); | ||
| 120 | + | ||
| 121 | + // R * R | ||
| 122 | + muls_v<ArchType::ASCEND_V220, float>(ub_in, ub_out_real, s_real, computeRepeat, 1, 1, 8, 8); | ||
| 123 | + | ||
| 124 | + // R * I | ||
| 125 | + muls_v<ArchType::ASCEND_V220, float>(ub_in[imag_offset], ub_out_real, s_imag, computeRepeat, 1, 1, 8, 8); | ||
| 126 | + | ||
| 127 | + // I * I | ||
| 128 | + muls_v<ArchType::ASCEND_V220, float>(ub_out_real, ub_out_imag, s_imag, computeRepeat, 1, 1, 8, 8); | ||
| 129 | + | ||
| 130 | + PIPE_BARRIER(V); | ||
| 131 | + // R * R - I * I | ||
| 132 | + sub_v<ArchType::ASCEND_V220, float>(ub_in, ub_in, ub_out_real, computeRepeat, 1, 1, 1, 8, 8, 8); | ||
| 133 | + | ||
| 134 | + // I * R | ||
| 135 | + muls_v<ArchType::ASCEND_V220, float>(ub_out_imag, ub_out_imag, s_real, computeRepeat, 1, 1, 8, 8); | ||
| 136 | + | ||
| 137 | + PIPE_BARRIER(V); | ||
| 138 | + // R * I + I * R | ||
| 139 | + add_v<ArchType::ASCEND_V220, float>( | ||
| 140 | + ub_in[imag_offset], ub_out_imag, ub_in[imag_offset], computeRepeat, 1, 1, 1, 8, 8, 8); | ||
| 141 | + | ||
| 142 | + PIPE_BARRIER(V); | ||
| 143 | + | ||
| 144 | + AscendC::Gather(ub_out, ub_in, ub_offset, (uint32_t)0, repeatTime * 64); | ||
| 145 | + PIPE_BARRIER(ALL); | ||
| 146 | + | ||
| 147 | + SET_FLAG(V, MTE3, event_id); | ||
| 148 | + WAIT_FLAG(V, MTE3, event_id); | ||
| 149 | + | ||
| 150 | + copy_vec_ub2gm(gm_out, ub_out, copy_len); | ||
| 151 | +} | ||
| 152 | + | ||
| 153 | +// ========================================================================== | ||
| 154 | +// Pure computation: x index for given row with signed incx (Task 4) | ||
| 155 | +// ========================================================================== | ||
| 156 | +__aicore__ __inline__ __attribute__((always_inline)) int64_t CalcCdgmmXIndex( | ||
| 157 | + uint32_t row, uint32_t m, int32_t incx) | ||
| 158 | +{ | ||
| 159 | + if (incx >= 0) { | ||
| 160 | + return static_cast<int64_t>(row) * static_cast<int64_t>(incx); | ||
| 161 | + } | ||
| 162 | + int64_t absIncx = -static_cast<int64_t>(incx); | ||
| 163 | + return (static_cast<int64_t>(m) - 1 - static_cast<int64_t>(row)) * absIncx; | ||
| 164 | +} | ||
| 165 | + | ||
| 166 | +// ========================================================================== | ||
| 167 | +// UB buffer context for LEFT-mode ping-pong processing | ||
| 168 | +// ========================================================================== | ||
| 169 | +struct CdgmmLeftUbCtx { | ||
| 170 | + AscendC::LocalTensor<float> ubOutPing; | ||
| 171 | + AscendC::LocalTensor<float> ubOutPong; | ||
| 172 | + AscendC::LocalTensor<float> ubInPing; | ||
| 173 | + AscendC::LocalTensor<float> ubInPong; | ||
| 174 | + AscendC::LocalTensor<uint32_t> ubOffset; | ||
| 175 | + uint32_t pingFlag; | ||
| 176 | + uint32_t maxDataCount; | ||
| 177 | + uint32_t repeatTime; | ||
| 178 | + uint32_t remainNum; | ||
| 179 | +}; | ||
| 180 | + | ||
| 181 | +// ========================================================================== | ||
| 182 | +// Process full chunks for a single row (Task 4) | ||
| 183 | +// ========================================================================== | ||
| 184 | +__aicore__ __inline__ __attribute__((always_inline)) void ProcessCdgmmFullChunks( | ||
| 185 | + AscendC::GlobalTensor<float> gm_a, | ||
| 186 | + AscendC::GlobalTensor<float> gm_c, | ||
| 187 | + AscendC::GlobalTensor<uint32_t> gm_aug, | ||
| 188 | + float s_real, float s_imag, | ||
| 189 | + uint64_t aBase, uint64_t cBase, | ||
| 190 | + CdgmmLeftUbCtx& ctx) | ||
| 191 | +{ | ||
| 192 | + if (ctx.repeatTime == 0) { | ||
| 193 | + return; | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + uint64_t currOffset = 0; | ||
| 197 | + SET_FLAG(MTE3, MTE2, EVENT_ID0); | ||
| 198 | + SET_FLAG(MTE3, MTE2, EVENT_ID1); | ||
| 199 | + | ||
| 200 | + for (uint32_t i = 0; i < ctx.repeatTime; i++) { | ||
| 201 | + auto ubIn = ctx.pingFlag ? ctx.ubInPing : ctx.ubInPong; | ||
| 202 | + auto ubOut = ctx.pingFlag ? ctx.ubOutPing : ctx.ubOutPong; | ||
| 203 | + auto eventId = ctx.pingFlag ? EVENT_ID0 : EVENT_ID1; | ||
| 204 | + | ||
| 205 | + WAIT_FLAG(MTE3, MTE2, eventId); | ||
| 206 | + | ||
| 207 | + cdgmm_compute_aiv(gm_a[aBase + currOffset], gm_c[cBase + currOffset], | ||
| 208 | + ubIn, ubOut, ctx.ubOffset, s_real, s_imag, | ||
| 209 | + ctx.maxDataCount, eventId); | ||
| 210 | + | ||
| 211 | + SET_FLAG(MTE3, MTE2, eventId); | ||
| 212 | + currOffset += ctx.maxDataCount; | ||
| 213 | + ctx.pingFlag = 1 - ctx.pingFlag; | ||
| 214 | + } | ||
| 215 | + WAIT_FLAG(MTE3, MTE2, EVENT_ID0); | ||
| 216 | + WAIT_FLAG(MTE3, MTE2, EVENT_ID1); | ||
| 217 | +} | ||
| 218 | + | ||
| 219 | +// ========================================================================== | ||
| 220 | +// Process tail chunk for a single row (Task 4) | ||
| 221 | +// ========================================================================== | ||
| 222 | +__aicore__ __inline__ __attribute__((always_inline)) void ProcessCdgmmTailChunk( | ||
| 223 | + AscendC::GlobalTensor<float> gm_a, | ||
| 224 | + AscendC::GlobalTensor<float> gm_c, | ||
| 225 | + AscendC::GlobalTensor<uint32_t> gm_aug, | ||
| 226 | + float s_real, float s_imag, | ||
| 227 | + uint64_t aBase, uint64_t cBase, uint64_t prevOffset, | ||
| 228 | + CdgmmLeftUbCtx& ctx) | ||
| 229 | +{ | ||
| 230 | + if (ctx.remainNum == 0) { | ||
| 231 | + return; | ||
| 232 | + } | ||
| 233 | + | ||
| 234 | + uint64_t currOffset = prevOffset; | ||
| 235 | + SET_FLAG(MTE3, MTE2, EVENT_ID0); | ||
| 236 | + SET_FLAG(MTE3, MTE2, EVENT_ID1); | ||
| 237 | + | ||
| 238 | + auto ubIn = ctx.pingFlag ? ctx.ubInPing : ctx.ubInPong; | ||
| 239 | + auto ubOut = ctx.pingFlag ? ctx.ubOutPing : ctx.ubOutPong; | ||
| 240 | + auto eventId = ctx.pingFlag ? EVENT_ID0 : EVENT_ID1; | ||
| 241 | + WAIT_FLAG(MTE3, MTE2, eventId); | ||
| 242 | + | ||
| 243 | + cdgmm_compute_aiv(gm_a[aBase + currOffset], gm_c[cBase + currOffset], | ||
| 244 | + ubIn, ubOut, ctx.ubOffset, s_real, s_imag, | ||
| 245 | + ctx.remainNum, eventId); | ||
| 246 | + | ||
| 247 | + SET_FLAG(MTE3, MTE2, eventId); | ||
| 248 | + ctx.pingFlag = 1 - ctx.pingFlag; | ||
| 249 | + WAIT_FLAG(MTE3, MTE2, EVENT_ID0); | ||
| 250 | + WAIT_FLAG(MTE3, MTE2, EVENT_ID1); | ||
| 251 | +} | ||
| 252 | + | ||
| 253 | +// ========================================================================== | ||
| 254 | +// LEFT mode row processing (ping-pong, migrated from colwise_mul_aiv) | ||
| 255 | +// | ||
| 256 | +// Row-major: row i starts at A_float[2*i*lda] and C_float[2*i*ldc]. | ||
| 257 | +// Each row has n complex elements = 2*n float elements. | ||
| 258 | +// x[i] is read using incx stride: xIndex = (incx>0) ? i*incx : (m-1-i)*|incx| | ||
| 259 | +// ========================================================================== | ||
| 260 | +__aicore__ __inline__ __attribute__((always_inline)) void cdgmm_left_aiv( | ||
| 261 | + AscendC::GlobalTensor<float> gm_a, | ||
| 262 | + AscendC::GlobalTensor<float> gm_x, | ||
| 263 | + AscendC::GlobalTensor<uint32_t> gm_aug, | ||
| 264 | + AscendC::GlobalTensor<float> gm_c, | ||
| 265 | + uint32_t m, uint32_t n, int32_t incx, | ||
| 266 | + uint32_t lda, uint32_t ldc, | ||
| 267 | + uint32_t startRow, uint32_t rowCount) | ||
| 268 | +{ | ||
| 269 | + // ub 192kb | ||
| 270 | + AsdopsBuffer<ArchType::ASCEND_V220> buf; | ||
| 271 | + | ||
| 272 | + CdgmmLeftUbCtx ctx; | ||
| 273 | + ctx.ubOutPing = buf.GetBuffer<BufferType::ASCEND_UB, float>(0 * 1024); | ||
| 274 | + ctx.ubOutPong = buf.GetBuffer<BufferType::ASCEND_UB, float>(32 * 1024); | ||
| 275 | + ctx.ubInPing = buf.GetBuffer<BufferType::ASCEND_UB, float>(64 * 1024); | ||
| 276 | + ctx.ubInPong = buf.GetBuffer<BufferType::ASCEND_UB, float>(96 * 1024); | ||
| 277 | + ctx.ubOffset = buf.GetBuffer<BufferType::ASCEND_UB, uint32_t>(128 * 1024); | ||
| 278 | + ctx.pingFlag = 1; | ||
| 279 | + ctx.maxDataCount = 32 * 1024 / sizeof(float); | ||
| 280 | + | ||
| 281 | + uint32_t rowFloats = 2 * n; | ||
| 282 | + ctx.repeatTime = rowFloats / ctx.maxDataCount; | ||
| 283 | + ctx.remainNum = rowFloats % ctx.maxDataCount; | ||
| 284 | + | ||
| 285 | + // prepare offset | ||
| 286 | + copy_vec_gm2ub_uint32(ctx.ubOffset, gm_aug, ctx.maxDataCount); | ||
| 287 | + | ||
| 288 | + SET_FLAG(MTE2, V, EVENT_ID0); | ||
| 289 | + WAIT_FLAG(MTE2, V, EVENT_ID0); | ||
| 290 | + SET_FLAG(MTE2, V, EVENT_ID1); | ||
| 291 | + WAIT_FLAG(MTE2, V, EVENT_ID1); | ||
| 292 | + | ||
| 293 | + if (rowCount == 0) { | ||
| 294 | + return; | ||
| 295 | + } | ||
| 296 | + | ||
| 297 | + for (uint32_t localRow = 0; localRow < rowCount; localRow++) { | ||
| 298 | + uint32_t row = startRow + localRow; | ||
| 299 | + | ||
| 300 | + uint64_t aFloatOffset = 2ULL * static_cast<uint64_t>(row) * lda; | ||
| 301 | + uint64_t cFloatOffset = 2ULL * static_cast<uint64_t>(row) * ldc; | ||
| 302 | + | ||
| 303 | + int64_t xIndex = CalcCdgmmXIndex(row, m, incx); | ||
| 304 | + | ||
| 305 | + float s_real = gm_x.GetValue(2ULL * static_cast<uint64_t>(xIndex)); | ||
| 306 | + float s_imag = gm_x.GetValue(2ULL * static_cast<uint64_t>(xIndex) + 1); | ||
| 307 | + | ||
| 308 | + SET_FLAG(S, V, EVENT_ID0); | ||
| 309 | + WAIT_FLAG(S, V, EVENT_ID0); | ||
| 310 | + SET_FLAG(S, V, EVENT_ID1); | ||
| 311 | + WAIT_FLAG(S, V, EVENT_ID1); | ||
| 312 | + | ||
| 313 | + ProcessCdgmmFullChunks(gm_a, gm_c, gm_aug, s_real, s_imag, | ||
| 314 | + aFloatOffset, cFloatOffset, ctx); | ||
| 315 | + | ||
| 316 | + uint64_t prevOffset = static_cast<uint64_t>(ctx.repeatTime) * ctx.maxDataCount; | ||
| 317 | + ProcessCdgmmTailChunk(gm_a, gm_c, gm_aug, s_real, s_imag, | ||
| 318 | + aFloatOffset, cFloatOffset, prevOffset, ctx); | ||
| 319 | + } | ||
| 320 | + PIPE_BARRIER(ALL); | ||
| 321 | +} | ||
| 322 | + | ||
| 323 | +// ========================================================================== | ||
| 324 | +// Kernel entry point | ||
| 325 | +// ========================================================================== | ||
| 326 | +__global__ __aicore__ __vector__ void cdgmm(GM_ADDR A, GM_ADDR x, | ||
| 327 | + GM_ADDR C, GM_ADDR aug, | ||
| 328 | + GM_ADDR workSpace, GM_ADDR tilingGm) | ||
| 329 | +{ | ||
| 330 | + AscendC::SetAtomicNone(); | ||
| 331 | + AscendC::SetMaskNorm(); | ||
| 332 | + | ||
| 333 | + auto core_idx = AscendC::GetBlockIdx(); | ||
| 334 | + | ||
| 335 | + auto* tiling = reinterpret_cast<__gm__ CdgmmTilingData*>(tilingGm); | ||
| 336 | + | ||
| 337 | + uint32_t mode = tiling->mode; | ||
| 338 | + uint32_t m = tiling->m; | ||
| 339 | + uint32_t n = tiling->n; | ||
| 340 | + int32_t incx = tiling->incx; | ||
| 341 | + uint32_t lda = tiling->lda; | ||
| 342 | + uint32_t ldc = tiling->ldc; | ||
| 343 | + | ||
| 344 | + uint32_t startRow = tiling->startRow[core_idx]; | ||
| 345 | + uint32_t rowCount = tiling->rowCount[core_idx]; | ||
| 346 | + | ||
| 347 | + if (rowCount == 0) { | ||
| 348 | + return; | ||
| 349 | + } | ||
| 350 | + | ||
| 351 | + AscendC::GlobalTensor<float> a_tensor; | ||
| 352 | + AscendC::GlobalTensor<float> x_tensor; | ||
| 353 | + AscendC::GlobalTensor<uint32_t> aug_tensor; | ||
| 354 | + AscendC::GlobalTensor<float> c_tensor; | ||
| 355 | + | ||
| 356 | + a_tensor.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(A)); | ||
| 357 | + x_tensor.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(x)); | ||
| 358 | + aug_tensor.SetGlobalBuffer(reinterpret_cast<__gm__ uint32_t*>(aug)); | ||
| 359 | + c_tensor.SetGlobalBuffer(reinterpret_cast<__gm__ float*>(C)); | ||
| 360 | + | ||
| 361 | + // Only LEFT is supported; RIGHT is rejected by Host before kernel launch. | ||
| 362 | + if (mode == CDGMM_MODE_LEFT) { | ||
| 363 | + cdgmm_left_aiv(a_tensor, x_tensor, aug_tensor, c_tensor, | ||
| 364 | + m, n, incx, lda, ldc, startRow, rowCount); | ||
| 365 | + } | ||
| 366 | +} | ||
| 367 | + | ||
| 368 | +// Wrapper function for host to call | ||
| 369 | +void cdgmm_kernel_do(GM_ADDR A, GM_ADDR x, GM_ADDR C, | ||
| 370 | + GM_ADDR aug, GM_ADDR workSpace, GM_ADDR tilingGm, | ||
| 371 | + uint32_t numBlocks, void* stream) | ||
| 372 | +{ | ||
| 373 | + cdgmm<<<numBlocks, nullptr, stream>>>(A, x, C, aug, workSpace, tilingGm); | ||
| 374 | +} | ||
| @@ -0,0 +1,42 @@ | |||
| 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 the License for the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, 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 cdgmm_kernel.h | ||
| 13 | + * \brief Declaration of the kernel launcher for aclblasCdgmm (arch22). | ||
| 14 | + * Shared by host.cpp and kernel.cpp. | ||
| 15 | + * | ||
| 16 | + * Row-major storage. Only LEFT mode is implemented (C[i,j] = x[i] * A[i,j]). | ||
| 17 | + */ | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | +/*! | ||
| 29 | + * \brief Kernel launcher: synchronously launches the Cdgmm kernel. | ||
| 30 | + * | ||
| 31 | + * \param A GM address of matrix A (row-major complex, m x n, stride lda) | ||
| 32 | + * \param x GM address of vector x (interleaved complex) | ||
| 33 | + * \param C GM address of output matrix C (row-major complex, m x n, stride ldc) | ||
| 34 | + * \param aug GM address of gather offset table (pre-computed by Host) | ||
| 35 | + * \param workSpace GM address of workspace (currently unused, reserved) | ||
| 36 | + * \param tilingGm GM address of tiling data | ||
| 37 | + * \param numBlocks block count for the <<<>>> launch | ||
| 38 | + * \param stream aclrtStream handle | ||
| 39 | + */ | ||
| 40 | +void cdgmm_kernel_do(GM_ADDR A, GM_ADDR x, GM_ADDR C, | ||
| 41 | + GM_ADDR aug, GM_ADDR workSpace, GM_ADDR tilingGm, | ||
| 42 | + uint32_t numBlocks, void* stream); | ||
| @@ -0,0 +1,51 @@ | |||
| 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 the License for the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, 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 cdgmm_tiling_data.h | ||
| 13 | + * \brief Tiling data structure for aclblasCdgmm (arch22). | ||
| 14 | + * Shared by host side and kernel side to avoid layout mismatch. | ||
| 15 | + * | ||
| 16 | + * Row-major storage: A and C are m x n row-major complex matrices. | ||
| 17 | + * Complex elements are stored as interleaved float pairs (real, imag). | ||
| 18 | + * Only LEFT mode is implemented; RIGHT is rejected by the Host. | ||
| 19 | + */ | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +static constexpr uint32_t CDGMM_MODE_LEFT = 0; | ||
| 26 | +static constexpr uint32_t CDGMM_MODE_RIGHT = 1; | ||
| 27 | + | ||
| 28 | +static constexpr uint32_t CDGMM_MAX_CORES = 40; | ||
| 29 | + | ||
| 30 | +/*! | ||
| 31 | + * \brief Tiling data for Cdgmm. | ||
| 32 | + * | ||
| 33 | + * Row-split decomposition: each core handles a contiguous range of | ||
| 34 | + * rows [startRow[i], startRow[i] + rowCount[i]). The Host balances | ||
| 35 | + * rows across at most CDGMM_MAX_CORES cores (capped by aivCoreNum and m). | ||
| 36 | + * | ||
| 37 | + * Matrices A and C are row-major. lda/ldc are row strides (number of | ||
| 38 | + * complex elements between consecutive rows). Complex elements are | ||
| 39 | + * stored as interleaved float pairs (real, imag). | ||
| 40 | + */ | ||
| 41 | +struct CdgmmTilingData { | ||
| 42 | + uint32_t mode; // normalized: CDGMM_MODE_LEFT or CDGMM_MODE_RIGHT | ||
| 43 | + uint32_t m; // number of rows of matrix A/C | ||
| 44 | + uint32_t n; // number of columns of matrix A/C | ||
| 45 | + int32_t incx; // stride of vector x (may be negative) | ||
| 46 | + uint32_t lda; // row stride of A (row-major, in complex elements) | ||
| 47 | + uint32_t ldc; // row stride of C (row-major, in complex elements) | ||
| 48 | + | ||
| 49 | + uint32_t startRow[CDGMM_MAX_CORES]; // start row per core | ||
| 50 | + uint32_t rowCount[CDGMM_MAX_CORES]; // row count per core | ||
| 51 | +}; | ||
| @@ -12,7 +12,8 @@ | |||
| 12 | # - MXFP8/MXFP4:blasLt 矩阵乘法,需 asc-devkit >= 9.1 | 12 | # - MXFP8/MXFP4:blasLt 矩阵乘法,需 asc-devkit >= 9.1 |
| 13 | # - TRMM/STRMM:仅 arch35(ascend950) 的 strmm 使用 tensor_api,需 asc-devkit >= 9.1; | 13 | # - TRMM/STRMM:仅 arch35(ascend950) 的 strmm 使用 tensor_api,需 asc-devkit >= 9.1; |
| 14 | # 其他架构的 strmm 不依赖 tensor_api,不受此版本限制 | 14 | # 其他架构的 strmm 不依赖 tensor_api,不受此版本限制 |
| 15 | -# - DGMM/SDGMM:仅 arch35(ascend950) 的 sdgmm 使用 tensor_api,需 asc-devkit >= 9.1 | 15 | +# - SDGMM:仅 arch35(ascend950) 的 sdgmm 使用 tensor_api,需 asc-devkit >= 9.1; |
| 16 | +# arch22 的 cdgmm 不依赖 tensor_api,不受此版本限制 | ||
| 16 | # - GEMM_BATCHED:仅 arch35(ascend950) 的 gemm_batched 使用 tensor_api,需 asc-devkit >= 9.1 | 17 | # - GEMM_BATCHED:仅 arch35(ascend950) 的 gemm_batched 使用 tensor_api,需 asc-devkit >= 9.1 |
| 17 | # - GEMM3M/SGEMM3M:仅 arch35(ascend950) 的 sgemm3m 使用 tensor_api,需 asc-devkit >= 9.1 | 18 | # - GEMM3M/SGEMM3M:仅 arch35(ascend950) 的 sgemm3m 使用 tensor_api,需 asc-devkit >= 9.1 |
| 18 | # - SYRK/SSYRK:仅 arch35(ascend950) 的 ssyrk 使用 tensor_api,需 asc-devkit >= 9.1 | 19 | # - SYRK/SSYRK:仅 arch35(ascend950) 的 ssyrk 使用 tensor_api,需 asc-devkit >= 9.1 |
| @@ -23,7 +24,7 @@ function(ops_blas_detect_asc_devkit_version) | |||
| 23 | set(ASC_DEVKIT_MINOR 0) | 24 | set(ASC_DEVKIT_MINOR 0) |
| 24 | set(ENABLE_BLASLT_MXFP8 FALSE) | 25 | set(ENABLE_BLASLT_MXFP8 FALSE) |
| 25 | set(ENABLE_BLAS_TRMM TRUE) | 26 | set(ENABLE_BLAS_TRMM TRUE) |
| 26 | - set(ENABLE_BLAS_DGMM TRUE) | 27 | + set(ENABLE_BLAS_SDGMM TRUE) |
| 27 | set(ENABLE_BLAS_GEMM_BATCHED TRUE) | 28 | set(ENABLE_BLAS_GEMM_BATCHED TRUE) |
| 28 | set(ENABLE_BLAS_GEMM3M TRUE) | 29 | set(ENABLE_BLAS_GEMM3M TRUE) |
| 29 | set(ENABLE_BLAS_SYRK TRUE) | 30 | set(ENABLE_BLAS_SYRK TRUE) |
| @@ -42,30 +43,29 @@ function(ops_blas_detect_asc_devkit_version) | |||
| 42 | # arch35 的 strmm/sdgmm/gemm_batched/sgemm3m/ssyrk 使用 tensor_api,需 devkit >= 9.1;其他架构不受限 | 43 | # arch35 的 strmm/sdgmm/gemm_batched/sgemm3m/ssyrk 使用 tensor_api,需 devkit >= 9.1;其他架构不受限 |
| 43 | if("arch35" IN_LIST SOC_ARCH_DIRS AND NOT (ASC_DEVKIT_MAJOR GREATER_EQUAL 9 AND ASC_DEVKIT_MINOR GREATER 0)) | 44 | if("arch35" IN_LIST SOC_ARCH_DIRS AND NOT (ASC_DEVKIT_MAJOR GREATER_EQUAL 9 AND ASC_DEVKIT_MINOR GREATER 0)) |
| 44 | set(ENABLE_BLAS_TRMM FALSE) | 45 | set(ENABLE_BLAS_TRMM FALSE) |
| 45 | - set(ENABLE_BLAS_DGMM FALSE) | 46 | + set(ENABLE_BLAS_SDGMM FALSE) |
| 46 | set(ENABLE_BLAS_GEMM_BATCHED FALSE) | 47 | set(ENABLE_BLAS_GEMM_BATCHED FALSE) |
| 47 | set(ENABLE_BLAS_GEMM3M FALSE) | 48 | set(ENABLE_BLAS_GEMM3M FALSE) |
| 48 | set(ENABLE_BLAS_SYRK FALSE) | 49 | set(ENABLE_BLAS_SYRK FALSE) |
| 49 | endif() | 50 | endif() |
| 50 | else() | 51 | else() |
| 51 | set(ENABLE_BLAS_TRMM FALSE) | 52 | set(ENABLE_BLAS_TRMM FALSE) |
| 52 | - set(ENABLE_BLAS_DGMM FALSE) | 53 | + set(ENABLE_BLAS_SDGMM FALSE) |
| 53 | set(ENABLE_BLAS_GEMM_BATCHED FALSE) | 54 | set(ENABLE_BLAS_GEMM_BATCHED FALSE) |
| 54 | set(ENABLE_BLAS_GEMM3M FALSE) | 55 | set(ENABLE_BLAS_GEMM3M FALSE) |
| 55 | - set(ENABLE_BLAS_SYRK FALSE) | 56 | + message(WARNING "asc_devkit_version.h not found: ${_header}, MXFP8/TRMM/SDGMM/GEMM_BATCHED/GEMM3M will be skipped") |
| 56 | - message(WARNING "asc_devkit_version.h not found: ${_header}, MXFP8/TRMM/DGMM/GEMM_BATCHED/GEMM3M/SYRK will be skipped") | ||
| 57 | endif() | 57 | endif() |
| 58 | 58 | ||
| 59 | set(ASC_DEVKIT_MAJOR ${ASC_DEVKIT_MAJOR} PARENT_SCOPE) | 59 | set(ASC_DEVKIT_MAJOR ${ASC_DEVKIT_MAJOR} PARENT_SCOPE) |
| 60 | set(ASC_DEVKIT_MINOR ${ASC_DEVKIT_MINOR} PARENT_SCOPE) | 60 | set(ASC_DEVKIT_MINOR ${ASC_DEVKIT_MINOR} PARENT_SCOPE) |
| 61 | set(ENABLE_BLASLT_MXFP8 ${ENABLE_BLASLT_MXFP8} PARENT_SCOPE) | 61 | set(ENABLE_BLASLT_MXFP8 ${ENABLE_BLASLT_MXFP8} PARENT_SCOPE) |
| 62 | set(ENABLE_BLAS_TRMM ${ENABLE_BLAS_TRMM} PARENT_SCOPE) | 62 | set(ENABLE_BLAS_TRMM ${ENABLE_BLAS_TRMM} PARENT_SCOPE) |
| 63 | - set(ENABLE_BLAS_DGMM ${ENABLE_BLAS_DGMM} PARENT_SCOPE) | 63 | + set(ENABLE_BLAS_SDGMM ${ENABLE_BLAS_SDGMM} PARENT_SCOPE) |
| 64 | set(ENABLE_BLAS_GEMM_BATCHED ${ENABLE_BLAS_GEMM_BATCHED} PARENT_SCOPE) | 64 | set(ENABLE_BLAS_GEMM_BATCHED ${ENABLE_BLAS_GEMM_BATCHED} PARENT_SCOPE) |
| 65 | set(ENABLE_BLAS_GEMM3M ${ENABLE_BLAS_GEMM3M} PARENT_SCOPE) | 65 | set(ENABLE_BLAS_GEMM3M ${ENABLE_BLAS_GEMM3M} PARENT_SCOPE) |
| 66 | set(ENABLE_BLAS_SYRK ${ENABLE_BLAS_SYRK} PARENT_SCOPE) | 66 | set(ENABLE_BLAS_SYRK ${ENABLE_BLAS_SYRK} PARENT_SCOPE) |
| 67 | message( | 67 | message( |
| 68 | STATUS | 68 | STATUS |
| 69 | - "ASC_DEVKIT_MAJOR=${ASC_DEVKIT_MAJOR}, ASC_DEVKIT_MINOR=${ASC_DEVKIT_MINOR}, ENABLE_BLASLT_MXFP8=${ENABLE_BLASLT_MXFP8}, ENABLE_BLAS_TRMM=${ENABLE_BLAS_TRMM}, ENABLE_BLAS_DGMM=${ENABLE_BLAS_DGMM}, ENABLE_BLAS_GEMM_BATCHED=${ENABLE_BLAS_GEMM_BATCHED}, ENABLE_BLAS_GEMM3M=${ENABLE_BLAS_GEMM3M}, ENABLE_BLAS_SYRK=${ENABLE_BLAS_SYRK}" | 69 | + "ASC_DEVKIT_MAJOR=${ASC_DEVKIT_MAJOR}, ASC_DEVKIT_MINOR=${ASC_DEVKIT_MINOR}, ENABLE_BLASLT_MXFP8=${ENABLE_BLASLT_MXFP8}, ENABLE_BLAS_TRMM=${ENABLE_BLAS_TRMM}, ENABLE_BLAS_SDGMM=${ENABLE_BLAS_SDGMM}, ENABLE_BLAS_GEMM_BATCHED=${ENABLE_BLAS_GEMM_BATCHED}, ENABLE_BLAS_GEMM3M=${ENABLE_BLAS_GEMM3M}" |
| 70 | ) | 70 | ) |
| 71 | endfunction() | 71 | endfunction() |
| @@ -17,7 +17,7 @@ function(_ops_blas_has_blas_op_sources op_name out_var) | |||
| 17 | set(${out_var} FALSE PARENT_SCOPE) | 17 | set(${out_var} FALSE PARENT_SCOPE) |
| 18 | return() | 18 | return() |
| 19 | endif() | 19 | endif() |
| 20 | - if(NOT ENABLE_BLAS_DGMM AND (op_name STREQUAL "sdgmm" OR op_name STREQUAL "dgmm")) | 20 | + if(NOT ENABLE_BLAS_SDGMM AND (op_name STREQUAL "sdgmm")) |
| 21 | set(${out_var} FALSE PARENT_SCOPE) | 21 | set(${out_var} FALSE PARENT_SCOPE) |
| 22 | return() | 22 | return() |
| 23 | endif() | 23 | endif() |
| @@ -37,7 +37,9 @@ function(_ops_blas_has_blas_op_sources op_name out_var) | |||
| 37 | foreach(arch_dir ${SOC_ARCH_DIRS}) | 37 | foreach(arch_dir ${SOC_ARCH_DIRS}) |
| 38 | file(GLOB arch_dir_srcs ${CMAKE_SOURCE_DIR}/blas/${op_name}/${arch_dir}/*.cpp | 38 | file(GLOB arch_dir_srcs ${CMAKE_SOURCE_DIR}/blas/${op_name}/${arch_dir}/*.cpp |
| 39 | ${CMAKE_SOURCE_DIR}/blas/*/${op_name}/${arch_dir}/*.cpp | 39 | ${CMAKE_SOURCE_DIR}/blas/*/${op_name}/${arch_dir}/*.cpp |
| 40 | - ${CMAKE_SOURCE_DIR}/blas/*/${arch_dir}/${op_name}_*.cpp) | 40 | + ${CMAKE_SOURCE_DIR}/blas/*/${arch_dir}/${op_name}_*.cpp |
| 41 | + ${CMAKE_SOURCE_DIR}/extensions/*/${op_name}/${arch_dir}/*.cpp | ||
| 42 | + ${CMAKE_SOURCE_DIR}/extensions/${op_name}/${arch_dir}/*.cpp) | ||
| 41 | if(arch_dir_srcs) | 43 | if(arch_dir_srcs) |
| 42 | set(has_sources TRUE) | 44 | set(has_sources TRUE) |
| 43 | break() | 45 | break() |
| @@ -47,7 +49,8 @@ function(_ops_blas_has_blas_op_sources op_name out_var) | |||
| 47 | if(NOT has_sources AND op_name MATCHES "^[a-zA-Z]") | 49 | if(NOT has_sources AND op_name MATCHES "^[a-zA-Z]") |
| 48 | string(SUBSTRING "${op_name}" 1 -1 _stripped) | 50 | string(SUBSTRING "${op_name}" 1 -1 _stripped) |
| 49 | foreach(arch_dir ${SOC_ARCH_DIRS}) | 51 | foreach(arch_dir ${SOC_ARCH_DIRS}) |
| 50 | - file(GLOB arch_dir_srcs ${CMAKE_SOURCE_DIR}/blas/${_stripped}/${arch_dir}/*.cpp) | 52 | + file(GLOB arch_dir_srcs ${CMAKE_SOURCE_DIR}/blas/${_stripped}/${arch_dir}/*.cpp |
| 53 | + ${CMAKE_SOURCE_DIR}/extensions/${_stripped}/${arch_dir}/*.cpp) | ||
| 51 | if(arch_dir_srcs) | 54 | if(arch_dir_srcs) |
| 52 | set(has_sources TRUE) | 55 | set(has_sources TRUE) |
| 53 | break() | 56 | break() |
| @@ -56,7 +59,9 @@ function(_ops_blas_has_blas_op_sources op_name out_var) | |||
| 56 | endif() | 59 | endif() |
| 57 | if(NOT has_sources) | 60 | if(NOT has_sources) |
| 58 | file(GLOB base_srcs ${CMAKE_SOURCE_DIR}/blas/${op_name}/*.cpp | 61 | file(GLOB base_srcs ${CMAKE_SOURCE_DIR}/blas/${op_name}/*.cpp |
| 59 | - ${CMAKE_SOURCE_DIR}/blas/*/${op_name}/*.cpp) | 62 | + ${CMAKE_SOURCE_DIR}/blas/*/${op_name}/*.cpp |
| 63 | + ${CMAKE_SOURCE_DIR}/extensions/${op_name}/*.cpp | ||
| 64 | + ${CMAKE_SOURCE_DIR}/extensions/*/${op_name}/*.cpp) | ||
| 60 | if(base_srcs) | 65 | if(base_srcs) |
| 61 | set(has_sources TRUE) | 66 | set(has_sources TRUE) |
| 62 | endif() | 67 | endif() |
| @@ -812,8 +812,8 @@ Level 1 接口在向量之间进行运算,典型操作包括向量缩放(sca | |||
| 812 | | [aclblasSasum](../../blas/asum/README.md) | 实数向量绝对值之和 | | 812 | | [aclblasSasum](../../blas/asum/README.md) | 实数向量绝对值之和 | |
| 813 | | [aclblasSaxpy](../../blas/axpy/README.md) | 单精度浮点 AXPY(y = αx + y) | | 813 | | [aclblasSaxpy](../../blas/axpy/README.md) | 单精度浮点 AXPY(y = αx + y) | |
| 814 | | [aclblasCaxpy](../../blas/axpy/README.md) | 复数 AXPY | | 814 | | [aclblasCaxpy](../../blas/axpy/README.md) | 复数 AXPY | |
| 815 | -| [aclblasColwiseMul](../../blas/colwise_mul/README.md) | 复数向量与矩阵每行逐元素乘法 | | 815 | +| [aclblasCdgmm](../../blas/dgmm/README.md) | 行主序单精度复数对角矩阵左乘 | |
| 816 | -| [aclblasComplexMatDot](../../blas/complex_mat_dot/README.md) | 复数矩阵逐元素点乘 | | 816 | +| [aclblasComplexMatDot](../../extensions/complexmatdot/README.md) | 复数矩阵逐元素点乘 | |
| 817 | | [aclblasScopy](../../blas/copy/README.md) | 单精度浮点向量拷贝 | | 817 | | [aclblasScopy](../../blas/copy/README.md) | 单精度浮点向量拷贝 | |
| 818 | | [aclblasCcopy](../../blas/copy/README.md) | 复数向量拷贝 | | 818 | | [aclblasCcopy](../../blas/copy/README.md) | 复数向量拷贝 | |
| 819 | | [aclblasSdot](../../blas/dot/README.md) | 实数向量点积 | | 819 | | [aclblasSdot](../../blas/dot/README.md) | 实数向量点积 | |
| @@ -0,0 +1,64 @@ | |||
| 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 the License for the License. | ||
| 6 | +# THIS FILE IS PROVIDED ON AN "AS IS" BASIS, 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 | +cmake_minimum_required(VERSION 3.16) | ||
| 12 | + | ||
| 13 | +# Collect base source files (non-arch-specific) | ||
| 14 | +file(GLOB BASE_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) | ||
| 15 | + | ||
| 16 | +# Auto-collect operator source files from subdirectories | ||
| 17 | +set(OP_SRC_FILES "") | ||
| 18 | +file(GLOB children RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*) | ||
| 19 | +foreach(child ${children}) | ||
| 20 | + if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${child}) | ||
| 21 | + # Recursively collect non-arch-specific source files | ||
| 22 | + file(GLOB_RECURSE dir_srcs ${CMAKE_CURRENT_SOURCE_DIR}/${child}/*.cpp) | ||
| 23 | + foreach(src_file ${dir_srcs}) | ||
| 24 | + set(is_arch_specific FALSE) | ||
| 25 | + foreach(arch_dir ${ARCH_SPECIFIC_DIRS}) | ||
| 26 | + if(src_file MATCHES "/${arch_dir}/") | ||
| 27 | + set(is_arch_specific TRUE) | ||
| 28 | + break() | ||
| 29 | + endif() | ||
| 30 | + endforeach() | ||
| 31 | + if(NOT is_arch_specific) | ||
| 32 | + get_filename_component(_src_fname ${src_file} NAME) | ||
| 33 | + get_filename_component(_src_dir ${src_file} DIRECTORY) | ||
| 34 | + set(_has_arch_counterpart FALSE) | ||
| 35 | + foreach(_arch_dir ${SOC_ARCH_DIRS}) | ||
| 36 | + if(EXISTS ${_src_dir}/${_arch_dir}/${_src_fname}) | ||
| 37 | + set(_has_arch_counterpart TRUE) | ||
| 38 | + break() | ||
| 39 | + endif() | ||
| 40 | + endforeach() | ||
| 41 | + if(NOT _has_arch_counterpart) | ||
| 42 | + list(APPEND OP_SRC_FILES ${src_file}) | ||
| 43 | + endif() | ||
| 44 | + endif() | ||
| 45 | + endforeach() | ||
| 46 | + endif() | ||
| 47 | +endforeach() | ||
| 48 | + | ||
| 49 | +# Collect arch-specific source files for the target SOC | ||
| 50 | +set(ARCH_SRC_FILES "") | ||
| 51 | +foreach(arch_dir ${SOC_ARCH_DIRS}) | ||
| 52 | + file(GLOB_RECURSE arch_dir_srcs | ||
| 53 | + ${CMAKE_CURRENT_SOURCE_DIR}/*/${arch_dir}/*.cpp | ||
| 54 | + ) | ||
| 55 | + list(APPEND ARCH_SRC_FILES ${arch_dir_srcs}) | ||
| 56 | +endforeach() | ||
| 57 | + | ||
| 58 | +set(ALL_BLAS_SRC_FILES | ||
| 59 | + ${ALL_BLAS_SRC_FILES} | ||
| 60 | + ${BASE_SRC_FILES} | ||
| 61 | + ${OP_SRC_FILES} | ||
| 62 | + ${ARCH_SRC_FILES} | ||
| 63 | + PARENT_SCOPE | ||
| 64 | +) | ||
| @@ -45,4 +45,4 @@ int aclblasComplexMatDot(const float *matx, const float *maty, float *result, co | |||
| 45 | 45 | ||
| 46 | #### 约束说明 | 46 | #### 约束说明 |
| 47 | 47 | ||
| 48 | -无 | 48 | +无 |
Rblas/complex_mat_dot/arch22/complex_mat_dot_host.cpp→extensions/complexmatdot/arch22/complexmatdot_host.cpp+9-13
| @@ -2,15 +2,15 @@ | |||
| 2 | * Copyright (c) 2026 Huawei Technologies Co., Ltd. | 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 | 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"). | 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. | 5 | + * Please refer to the License for details. You may not use the License for the License. |
| 6 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 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. | 8 | * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | /* ! | 11 | /* ! |
| 12 | - * \file complex_mat_dot_host.cpp | 12 | + * \file complexmatdot_host.cpp |
| 13 | - * \brief Complex matrix dot product host implementation | 13 | + * \brief Complex matrix dot product host implementation (extensions) |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | 16 | ||
| @@ -20,12 +20,10 @@ | |||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | 22 | ||
| 23 | + | ||
| 23 | 24 | ||
| 24 | 25 | ||
| 25 | 26 | ||
| 26 | -void complex_mat_dot_kernel_do(uint8_t* matx, uint8_t* maty, uint8_t* aug, uint8_t* result, | ||
| 27 | - uint8_t* tilingGm, uint32_t numBlocks, void *stream); | ||
| 28 | - | ||
| 29 | constexpr uint32_t COMPLEX_NUM = 2; | 27 | constexpr uint32_t COMPLEX_NUM = 2; |
| 30 | 28 | ||
| 31 | constexpr uint32_t MAX_DATA_COUNT = 27 * 1024 / sizeof(float); | 29 | constexpr uint32_t MAX_DATA_COUNT = 27 * 1024 / sizeof(float); |
| @@ -79,13 +77,11 @@ static void CalTilingData(ComplexMatDotTilingData& tilingData, uint32_t m, uint3 | |||
| 79 | } | 77 | } |
| 80 | } | 78 | } |
| 81 | 79 | ||
| 82 | -uint32_t* CreateAugComplexMatDot() | 80 | +static std::vector<uint32_t> CreateAugComplexMatDot() |
| 83 | { | 81 | { |
| 84 | uint32_t complexCount = MAX_DATA_COUNT / 2; | 82 | uint32_t complexCount = MAX_DATA_COUNT / 2; |
| 85 | 83 | ||
| 86 | - uint32_t* augData = nullptr; | 84 | + std::vector<uint32_t> augData(MAX_DATA_COUNT); |
| 87 | - | ||
| 88 | - augData = new uint32_t[MAX_DATA_COUNT]; | ||
| 89 | 85 | ||
| 90 | for (uint32_t i = 0; i < complexCount; i++) { | 86 | for (uint32_t i = 0; i < complexCount; i++) { |
| 91 | augData[MUL_NUM * i] = FOUR_NUM * i; | 87 | augData[MUL_NUM * i] = FOUR_NUM * i; |
| @@ -105,7 +101,7 @@ aclblasStatus_t aclblasComplexMatDot( | |||
| 105 | 101 | ||
| 106 | ComplexMatDotTilingData tiling; | 102 | ComplexMatDotTilingData tiling; |
| 107 | CalTilingData(tiling, m, n, numBlocks); | 103 | CalTilingData(tiling, m, n, numBlocks); |
| 108 | - uint32_t* aug = CreateAugComplexMatDot(); | 104 | + std::vector<uint32_t> aug = CreateAugComplexMatDot(); |
| 109 | 105 | ||
| 110 | size_t augByteSize = MAX_DATA_COUNT * sizeof(uint32_t); | 106 | size_t augByteSize = MAX_DATA_COUNT * sizeof(uint32_t); |
| 111 | 107 | ||
| @@ -122,7 +118,7 @@ aclblasStatus_t aclblasComplexMatDot( | |||
| 122 | aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", aclRet); aclrtFree(augDevice); | 118 | aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", aclRet); aclrtFree(augDevice); |
| 123 | return ACLBLAS_STATUS_ALLOC_FAILED); | 119 | return ACLBLAS_STATUS_ALLOC_FAILED); |
| 124 | 120 | ||
| 125 | - aclRet = aclrtMemcpy(augDevice, augByteSize, aug, augByteSize, ACL_MEMCPY_HOST_TO_DEVICE); | 121 | + aclRet = aclrtMemcpy(augDevice, augByteSize, aug.data(), augByteSize, ACL_MEMCPY_HOST_TO_DEVICE); |
| 126 | CHECK_RET( | 122 | CHECK_RET( |
| 127 | aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", aclRet); aclrtFree(tilingDevice); | 123 | aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", aclRet); aclrtFree(tilingDevice); |
| 128 | aclrtFree(augDevice); return ACLBLAS_STATUS_INTERNAL_ERROR); | 124 | aclrtFree(augDevice); return ACLBLAS_STATUS_INTERNAL_ERROR); |
Rblas/complex_mat_dot/arch22/complex_mat_dot_kernel.cpp→extensions/complexmatdot/arch22/complexmatdot_kernel.cpp+3-7
| @@ -2,19 +2,17 @@ | |||
| 2 | * Copyright (c) 2026 Huawei Technologies Co., Ltd. | 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 | 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"). | 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. | 5 | +* Please refer to the License for details. You may not use the License for the License. |
| 6 | -* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 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. | 8 | * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | - | ||
| 12 | - | ||
| 13 | - | ||
| 14 | 11 | ||
| 15 | 12 | ||
| 16 | 13 | ||
| 17 | 14 | ||
| 15 | + | ||
| 18 | 16 | ||
| 19 | using namespace AscendC; | 17 | using namespace AscendC; |
| 20 | using namespace matmul; | 18 | using namespace matmul; |
| @@ -257,5 +255,3 @@ void complex_mat_dot_kernel_do(GM_ADDR matx, GM_ADDR maty, GM_ADDR aug, GM_ADDR | |||
| 257 | { | 255 | { |
| 258 | complex_mat_dot_kernel<<<numBlocks, nullptr, stream>>>(matx, maty, aug, result, tilingGm); | 256 | complex_mat_dot_kernel<<<numBlocks, nullptr, stream>>>(matx, maty, aug, result, tilingGm); |
| 259 | } | 257 | } |
| 260 | - | ||
| 261 | - | ||
| @@ -0,0 +1,26 @@ | |||
| 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 the License for the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, 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 complexmatdot_kernel.h | ||
| 13 | + * \brief Declaration of the kernel launcher for aclblasComplexMatDot (arch22). | ||
| 14 | + * Shared by host.cpp and kernel.cpp. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +void complex_mat_dot_kernel_do(GM_ADDR matx, GM_ADDR maty, GM_ADDR aug, GM_ADDR result, | ||
| 26 | + GM_ADDR tilingGm, uint32_t numBlocks, void *stream); | ||
| @@ -198,9 +198,6 @@ aclblasStatus_t aclblasCsrot( | |||
| 198 | aclblasHandle_t handle, const int64_t n, aclblasComplex* x, const int64_t incx, aclblasComplex* y, | 198 | aclblasHandle_t handle, const int64_t n, aclblasComplex* x, const int64_t incx, aclblasComplex* y, |
| 199 | const int64_t incy, const float c, const float s); | 199 | const int64_t incy, const float c, const float s); |
| 200 | 200 | ||
| 201 | -aclblasStatus_t aclblasColwiseMul( | ||
| 202 | - aclblasHandle_t handle, const int64_t m, const int64_t n, uint8_t* mat, uint8_t* vec, uint8_t* result); | ||
| 203 | - | ||
| 204 | aclblasStatus_t aclblasComplexMatDot( | 201 | aclblasStatus_t aclblasComplexMatDot( |
| 205 | aclblasHandle_t handle, const int64_t m, const int64_t n, aclblasComplex* matx, aclblasComplex* maty, | 202 | aclblasHandle_t handle, const int64_t m, const int64_t n, aclblasComplex* matx, aclblasComplex* maty, |
| 206 | aclblasComplex* result); | 203 | aclblasComplex* result); |
| @@ -466,6 +463,11 @@ aclblasStatus_t aclblasSdgmm( | |||
| 466 | const float* A, int lda, const float* x, int incx, | 463 | const float* A, int lda, const float* x, int incx, |
| 467 | float* C, int ldc); | 464 | float* C, int ldc); |
| 468 | 465 | ||
| 466 | +aclblasStatus_t aclblasCdgmm( | ||
| 467 | + aclblasHandle_t handle, aclblasSideMode_t mode, int m, int n, | ||
| 468 | + const aclblasComplex* A, int lda, const aclblasComplex* x, int incx, | ||
| 469 | + aclblasComplex* C, int ldc); | ||
| 470 | + | ||
| 469 | aclblasStatus_t aclblasSgemm3m( | 471 | aclblasStatus_t aclblasSgemm3m( |
| 470 | aclblasHandle handle, aclblasOperation_t transA, aclblasOperation_t transB, int m, int n, int k, | 472 | aclblasHandle handle, aclblasOperation_t transA, aclblasOperation_t transB, int m, int n, int k, |
| 471 | const float* alpha, const float* A, int lda, | 473 | const float* alpha, const float* A, int lda, |
| @@ -66,7 +66,7 @@ if(BUILD_TEST) | |||
| 66 | if(NOT ENABLE_BLAS_TRMM AND (TEST_NAME STREQUAL "strmm" OR TEST_NAME STREQUAL "trmm")) | 66 | if(NOT ENABLE_BLAS_TRMM AND (TEST_NAME STREQUAL "strmm" OR TEST_NAME STREQUAL "trmm")) |
| 67 | list(APPEND SKIP_REASONS | 67 | list(APPEND SKIP_REASONS |
| 68 | "requires asc-devkit >= 9.1, current ${ASC_DEVKIT_MAJOR}.${ASC_DEVKIT_MINOR}") | 68 | "requires asc-devkit >= 9.1, current ${ASC_DEVKIT_MAJOR}.${ASC_DEVKIT_MINOR}") |
| 69 | - elseif(NOT ENABLE_BLAS_DGMM AND (TEST_NAME STREQUAL "sdgmm" OR TEST_NAME STREQUAL "dgmm")) | 69 | + elseif(NOT ENABLE_BLAS_SDGMM AND TEST_NAME STREQUAL "sdgmm") |
| 70 | list(APPEND SKIP_REASONS | 70 | list(APPEND SKIP_REASONS |
| 71 | "requires asc-devkit >= 9.1, current ${ASC_DEVKIT_MAJOR}.${ASC_DEVKIT_MINOR}") | 71 | "requires asc-devkit >= 9.1, current ${ASC_DEVKIT_MAJOR}.${ASC_DEVKIT_MINOR}") |
| 72 | elseif(NOT ENABLE_BLAS_GEMM_BATCHED AND (TEST_NAME STREQUAL "sgemm_batched" OR TEST_NAME STREQUAL "gemm_batched")) | 72 | elseif(NOT ENABLE_BLAS_GEMM_BATCHED AND (TEST_NAME STREQUAL "sgemm_batched" OR TEST_NAME STREQUAL "gemm_batched")) |
Dtest/colwise_mul/colwise_mul/arch22/colwise_mul_test.cpp+0-149
| @@ -1,149 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | - * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | - * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | - */ | ||
| 10 | - | ||
| 11 | -/* ! | ||
| 12 | - * \file colwise_mul_test.cpp | ||
| 13 | - * \brief Test for colwise_mul operator | ||
| 14 | - */ | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | - | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | - | ||
| 23 | - | ||
| 24 | - do { \ | ||
| 25 | - if (!(cond)) { \ | ||
| 26 | - return_expr; \ | ||
| 27 | - } \ | ||
| 28 | - } while (0) | ||
| 29 | - | ||
| 30 | - | ||
| 31 | - do { \ | ||
| 32 | - printf(message, ##__VA_ARGS__); \ | ||
| 33 | - } while (0) | ||
| 34 | - | ||
| 35 | -uint32_t VerifyResult(const float* output, const float* golden, size_t size, const char* test_name) | ||
| 36 | -{ | ||
| 37 | - std::cout << "\n========== " << test_name << " ==========" << std::endl; | ||
| 38 | - | ||
| 39 | - const float epsilon = 1e-4; | ||
| 40 | - uint32_t errors = 0; | ||
| 41 | - | ||
| 42 | - for (size_t i = 0; i < size; i++) { | ||
| 43 | - if (std::abs(output[i] - golden[i]) > epsilon) { | ||
| 44 | - if (errors < 5) { | ||
| 45 | - std::cout << "Mismatch at index " << i << ": output=" << output[i] << ", golden=" << golden[i] | ||
| 46 | - << std::endl; | ||
| 47 | - } | ||
| 48 | - errors++; | ||
| 49 | - } | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - if (errors == 0) { | ||
| 53 | - std::cout << "[Success] " << test_name << " verification passed." << std::endl; | ||
| 54 | - return 0; | ||
| 55 | - } else { | ||
| 56 | - std::cout << "[Failed] " << test_name << " verification failed with " << errors << " errors!" << std::endl; | ||
| 57 | - return 1; | ||
| 58 | - } | ||
| 59 | -} | ||
| 60 | - | ||
| 61 | -int32_t main(int32_t argc, char* argv[]) | ||
| 62 | -{ | ||
| 63 | - int32_t deviceId = 0; | ||
| 64 | - | ||
| 65 | - aclInit(nullptr); | ||
| 66 | - aclrtSetDevice(deviceId); | ||
| 67 | - | ||
| 68 | - aclblasHandle_t handle = nullptr; | ||
| 69 | - auto ret = aclblasCreate(&handle); | ||
| 70 | - CHECK_RET(ret == ACLBLAS_STATUS_SUCCESS, LOG_PRINT("aclblasCreate failed. ERROR: %d\n", ret); return ret); | ||
| 71 | - | ||
| 72 | - aclrtStream stream = nullptr; | ||
| 73 | - aclrtCreateStream(&stream); | ||
| 74 | - ret = aclblasSetStream(handle, stream); | ||
| 75 | - CHECK_RET(ret == ACLBLAS_STATUS_SUCCESS, LOG_PRINT("aclblasSetStream failed. ERROR: %d\n", ret); return ret); | ||
| 76 | - | ||
| 77 | - // Test: 2x3 complex matrix multiplied by 2-element complex vector | ||
| 78 | - // Matrix (complex): | ||
| 79 | - // Row 0: (1+2i, 3+4i, 5+6i) | ||
| 80 | - // Row 1: (7+8i, 9+10i, 11+12i) | ||
| 81 | - // Vector (complex): | ||
| 82 | - // vec[0] = 2+3i | ||
| 83 | - // vec[1] = 4+5i | ||
| 84 | - // Result: | ||
| 85 | - // Row 0: (2+3i) * (1+2i, 3+4i, 5+6i) = (-4+7i, -6+17i, -8+27i) | ||
| 86 | - // Row 1: (4+5i) * (7+8i, 9+10i, 11+12i) = (-12+67i, -14+85i, -16+103i) | ||
| 87 | - | ||
| 88 | - constexpr int64_t m = 2; | ||
| 89 | - constexpr int64_t n = 3; | ||
| 90 | - | ||
| 91 | - std::vector<float> mat = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f}; | ||
| 92 | - | ||
| 93 | - std::vector<float> vec = {2.0f, 3.0f, 4.0f, 5.0f}; | ||
| 94 | - | ||
| 95 | - std::vector<float> result(m * n * 2); | ||
| 96 | - | ||
| 97 | - std::vector<float> golden = {-4.0f, 7.0f, -6.0f, 17.0f, -8.0f, 27.0f, -12.0f, 67.0f, -14.0f, 85.0f, -16.0f, 103.0f}; | ||
| 98 | - | ||
| 99 | - uint8_t* matDevice = nullptr; | ||
| 100 | - uint8_t* vecDevice = nullptr; | ||
| 101 | - uint8_t* resultDevice = nullptr; | ||
| 102 | - size_t matByteSize = mat.size() * sizeof(float); | ||
| 103 | - size_t vecByteSize = vec.size() * sizeof(float); | ||
| 104 | - size_t resultByteSize = result.size() * sizeof(float); | ||
| 105 | - | ||
| 106 | - aclError aclRet = aclrtMalloc((void**)&matDevice, matByteSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 107 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc matDevice failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 108 | - aclRet = aclrtMalloc((void**)&vecDevice, vecByteSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 109 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc vecDevice failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 110 | - aclRet = aclrtMalloc((void**)&resultDevice, resultByteSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 111 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc resultDevice failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 112 | - aclRet = aclrtMemcpy(matDevice, matByteSize, mat.data(), matByteSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 113 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy matDevice failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 114 | - aclRet = aclrtMemcpy(vecDevice, vecByteSize, vec.data(), vecByteSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 115 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy vecDevice failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 116 | - | ||
| 117 | - aclblasStatus_t statusRet = aclblasColwiseMul(handle, m, n, matDevice, vecDevice, resultDevice); | ||
| 118 | - CHECK_RET( | ||
| 119 | - statusRet == ACLBLAS_STATUS_SUCCESS, LOG_PRINT("aclblasColwiseMul failed. ERROR: %d\n", statusRet); | ||
| 120 | - return statusRet); | ||
| 121 | - | ||
| 122 | - aclRet = aclrtSynchronizeStream(stream); | ||
| 123 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 124 | - aclRet = aclrtMemcpy(result.data(), resultByteSize, resultDevice, resultByteSize, ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 125 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy result failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 126 | - | ||
| 127 | - int32_t testRet = VerifyResult(result.data(), golden.data(), m * n * 2, "ColwiseMul Complex Test"); | ||
| 128 | - | ||
| 129 | - aclrtFree(matDevice); | ||
| 130 | - aclrtFree(vecDevice); | ||
| 131 | - aclrtFree(resultDevice); | ||
| 132 | - | ||
| 133 | - aclrtDestroyStream(stream); | ||
| 134 | - aclblasDestroy(handle); | ||
| 135 | - aclrtResetDevice(deviceId); | ||
| 136 | - aclFinalize(); | ||
| 137 | - | ||
| 138 | - if (testRet == 0) { | ||
| 139 | - std::cout << "\n========================================" << std::endl; | ||
| 140 | - std::cout << "Test passed successfully!" << std::endl; | ||
| 141 | - std::cout << "========================================" << std::endl; | ||
| 142 | - } else { | ||
| 143 | - std::cout << "\n========================================" << std::endl; | ||
| 144 | - std::cout << "Test failed!" << std::endl; | ||
| 145 | - std::cout << "========================================" << std::endl; | ||
| 146 | - } | ||
| 147 | - | ||
| 148 | - return testRet; | ||
| 149 | -} | ||
Dtest/complex_mat_dot/complex_mat_dot/arch22/complex_mat_dot_test.cpp+0-144
| @@ -1,144 +0,0 @@ | |||
| 1 | -/** | ||
| 2 | - * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | - * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | - * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | - */ | ||
| 10 | - | ||
| 11 | -/* ! | ||
| 12 | - * \file complex_mat_dot_test.cpp | ||
| 13 | - * \brief Test for complex matrix dot product | ||
| 14 | - */ | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | - | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | - | ||
| 23 | - | ||
| 24 | - | ||
| 25 | - | ||
| 26 | - do { \ | ||
| 27 | - if (!(cond)) { \ | ||
| 28 | - return_expr; \ | ||
| 29 | - } \ | ||
| 30 | - } while (0) | ||
| 31 | - | ||
| 32 | - | ||
| 33 | - do { \ | ||
| 34 | - printf(message, ##__VA_ARGS__); \ | ||
| 35 | - } while (0) | ||
| 36 | - | ||
| 37 | -uint32_t VerifyResult(std::vector<float>& output, std::vector<float>& golden) | ||
| 38 | -{ | ||
| 39 | - auto printTensor = [](std::vector<float>& tensor, const char* name) { | ||
| 40 | - constexpr size_t maxPrintSize = 20; | ||
| 41 | - std::cout << name << ": "; | ||
| 42 | - std::copy( | ||
| 43 | - tensor.begin(), tensor.begin() + std::min(tensor.size(), maxPrintSize), | ||
| 44 | - std::ostream_iterator<float>(std::cout, " ")); | ||
| 45 | - if (tensor.size() > maxPrintSize) { | ||
| 46 | - std::cout << "..."; | ||
| 47 | - } | ||
| 48 | - std::cout << std::endl; | ||
| 49 | - }; | ||
| 50 | - printTensor(output, "Output"); | ||
| 51 | - printTensor(golden, "Golden"); | ||
| 52 | - | ||
| 53 | - // Use relative error for floating point comparison | ||
| 54 | - constexpr float epsilon = 1e-5f; | ||
| 55 | - size_t errorCount = 0; | ||
| 56 | - for (size_t i = 0; i < output.size(); i++) { | ||
| 57 | - float relError = std::abs(output[i] - golden[i]) / (std::abs(golden[i]) + 1e-10f); | ||
| 58 | - if (relError > epsilon) { | ||
| 59 | - errorCount++; | ||
| 60 | - } | ||
| 61 | - } | ||
| 62 | - | ||
| 63 | - if (errorCount == 0) { | ||
| 64 | - std::cout << "[Success] Case accuracy is verification passed." << std::endl; | ||
| 65 | - return 0; | ||
| 66 | - } else { | ||
| 67 | - std::cout << "[Failed] Case accuracy is verification failed! Error count: " << errorCount << std::endl; | ||
| 68 | - return 1; | ||
| 69 | - } | ||
| 70 | -} | ||
| 71 | - | ||
| 72 | -int32_t main(int32_t argc, char* argv[]) | ||
| 73 | -{ | ||
| 74 | - int32_t deviceId = 0; | ||
| 75 | - aclrtStream stream = nullptr; | ||
| 76 | - aclblasHandle handle = nullptr; | ||
| 77 | - | ||
| 78 | - constexpr uint32_t m = 4; | ||
| 79 | - constexpr uint32_t n = 4; | ||
| 80 | - constexpr uint32_t complexSize = m * n * 2; | ||
| 81 | - | ||
| 82 | - std::vector<float> matx(complexSize); | ||
| 83 | - std::vector<float> maty(complexSize); | ||
| 84 | - std::vector<float> result(complexSize, 0.0f); | ||
| 85 | - | ||
| 86 | - for (uint32_t i = 0; i < m * n; i++) { | ||
| 87 | - matx[i * 2] = 1.0f; | ||
| 88 | - matx[i * 2 + 1] = 2.0f; | ||
| 89 | - maty[i * 2] = 3.0f; | ||
| 90 | - maty[i * 2 + 1] = 4.0f; | ||
| 91 | - } | ||
| 92 | - | ||
| 93 | - aclInit(nullptr); | ||
| 94 | - aclrtSetDevice(deviceId); | ||
| 95 | - aclrtCreateStream(&stream); | ||
| 96 | - aclblasCreate(&handle); | ||
| 97 | - aclblasSetStream(handle, stream); | ||
| 98 | - | ||
| 99 | - size_t dataSize = complexSize * sizeof(float); | ||
| 100 | - | ||
| 101 | - aclblasComplex* matxDevice = nullptr; | ||
| 102 | - aclblasComplex* matyDevice = nullptr; | ||
| 103 | - aclblasComplex* resultDevice = nullptr; | ||
| 104 | - | ||
| 105 | - aclError aclRet = aclrtMalloc((void**)&matxDevice, dataSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 106 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc matxDevice failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 107 | - aclRet = aclrtMalloc((void**)&matyDevice, dataSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 108 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc matyDevice failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 109 | - aclRet = aclrtMalloc((void**)&resultDevice, dataSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 110 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc resultDevice failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 111 | - | ||
| 112 | - aclRet = aclrtMemcpy(matxDevice, dataSize, matx.data(), dataSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 113 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy matxDevice failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 114 | - aclRet = aclrtMemcpy(matyDevice, dataSize, maty.data(), dataSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 115 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy matyDevice failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 116 | - aclRet = aclrtMemcpy(resultDevice, dataSize, result.data(), dataSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 117 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy resultDevice failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 118 | - | ||
| 119 | - auto ret = aclblasComplexMatDot(handle, m, n, matxDevice, matyDevice, resultDevice); | ||
| 120 | - CHECK_RET(ret == ACLBLAS_STATUS_SUCCESS, LOG_PRINT("aclblasComplexMatDot failed. ERROR: %d\n", ret); return ret); | ||
| 121 | - | ||
| 122 | - aclRet = aclrtSynchronizeStream(stream); | ||
| 123 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 124 | - | ||
| 125 | - aclRet = aclrtMemcpy(result.data(), dataSize, resultDevice, dataSize, ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 126 | - CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy result failed. ERROR: %d\n", aclRet); return aclRet); | ||
| 127 | - | ||
| 128 | - aclrtFree(matxDevice); | ||
| 129 | - aclrtFree(matyDevice); | ||
| 130 | - aclrtFree(resultDevice); | ||
| 131 | - | ||
| 132 | - aclblasDestroy(handle); | ||
| 133 | - aclrtDestroyStream(stream); | ||
| 134 | - aclrtResetDevice(deviceId); | ||
| 135 | - aclFinalize(); | ||
| 136 | - | ||
| 137 | - std::vector<float> golden(complexSize); | ||
| 138 | - for (uint32_t i = 0; i < m * n; i++) { | ||
| 139 | - golden[i * 2] = matx[i * 2] * maty[i * 2] - matx[i * 2 + 1] * maty[i * 2 + 1]; | ||
| 140 | - golden[i * 2 + 1] = matx[i * 2] * maty[i * 2 + 1] + matx[i * 2 + 1] * maty[i * 2]; | ||
| 141 | - } | ||
| 142 | - | ||
| 143 | - return VerifyResult(result, golden); | ||
| 144 | -} | ||
| @@ -2,10 +2,10 @@ | |||
| 2 | # Copyright (c) 2026 Huawei Technologies Co., Ltd. | 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 | 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"). | 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. | 5 | +# Please refer to the License for details. You may not use the License for the License. |
| 6 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | +# THIS FILE IS PROVIDED ON AN "AS IS" BASIS, WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 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. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 9 | # ---------------------------------------------------------------------------------------------------------- | 9 | # ---------------------------------------------------------------------------------------------------------- |
| 10 | 10 | ||
| 11 | -ops_blas_add_tests(${OPS_BLAS}) | 11 | +ops_blas_add_gtest_tests(${OPS_BLAS} cdgmm_test) |
| @@ -0,0 +1,122 @@ | |||
| 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 the License for the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, 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 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +static inline bool CdgmmNeedPassThrough( | ||
| 21 | + aclblasHandle_t handle, aclblasSideMode_t mode, int m, int n) | ||
| 22 | +{ | ||
| 23 | + return handle == nullptr || | ||
| 24 | + m <= 0 || n <= 0 || | ||
| 25 | + (mode != ACLBLAS_SIDE_LEFT && mode != ACLBLAS_SIDE_RIGHT); | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +static inline aclError CdgmmAllocCopyH2D(void*& dPtr, const void* hPtr, size_t bytes) | ||
| 29 | +{ | ||
| 30 | + dPtr = nullptr; | ||
| 31 | + if (hPtr == nullptr) return ACL_SUCCESS; | ||
| 32 | + aclError ret = aclrtMalloc(&dPtr, bytes, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 33 | + if (ret != ACL_SUCCESS) return ret; | ||
| 34 | + ret = aclrtMemcpy(dPtr, bytes, hPtr, bytes, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 35 | + if (ret != ACL_SUCCESS) { | ||
| 36 | + aclrtFree(dPtr); | ||
| 37 | + dPtr = nullptr; | ||
| 38 | + } | ||
| 39 | + return ret; | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +static inline void CdgmmFreeAll(void* dX, void* dA, void* dC) | ||
| 43 | +{ | ||
| 44 | + if (dX) aclrtFree(dX); | ||
| 45 | + if (dA) aclrtFree(dA); | ||
| 46 | + if (dC) aclrtFree(dC); | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +static inline aclError CdgmmAllocAndFillC(void*& dC, aclblasComplex* C, size_t cBytes) | ||
| 50 | +{ | ||
| 51 | + dC = nullptr; | ||
| 52 | + if (C == nullptr) return ACL_SUCCESS; | ||
| 53 | + aclError ret = aclrtMalloc(&dC, cBytes, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 54 | + if (ret != ACL_SUCCESS) return ret; | ||
| 55 | + // Fill with sentinel so unmodified padding matches the golden's untouched region. | ||
| 56 | + std::vector<float> sentinelBuf(cBytes / sizeof(float), kBlasSentinel); | ||
| 57 | + ret = aclrtMemcpy(dC, cBytes, sentinelBuf.data(), cBytes, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 58 | + if (ret != ACL_SUCCESS) { | ||
| 59 | + aclrtFree(dC); | ||
| 60 | + dC = nullptr; | ||
| 61 | + } | ||
| 62 | + return ret; | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | +inline aclblasStatus_t aclblasCdgmm_npu( | ||
| 66 | + aclblasHandle_t handle, | ||
| 67 | + aclblasSideMode_t mode, | ||
| 68 | + int m, int n, | ||
| 69 | + const aclblasComplex* A, int lda, | ||
| 70 | + const aclblasComplex* x, int incx, | ||
| 71 | + aclblasComplex* C, int ldc) | ||
| 72 | +{ | ||
| 73 | + if (CdgmmNeedPassThrough(handle, mode, m, n)) { | ||
| 74 | + return aclblasCdgmm(handle, mode, m, n, A, lda, x, incx, C, ldc); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + // Row-major: x length is m (LEFT only). Storage = lda * m complex elements. | ||
| 78 | + const int xLen = m; | ||
| 79 | + const int64_t absIncx = (incx >= 0) ? static_cast<int64_t>(incx) | ||
| 80 | + : -static_cast<int64_t>(incx); | ||
| 81 | + const size_t xTotalEl = static_cast<size_t>(xLen - 1) * static_cast<size_t>(absIncx) + 1; | ||
| 82 | + const size_t xBytes = xTotalEl * sizeof(aclblasComplex); | ||
| 83 | + const size_t aBytes = static_cast<size_t>(lda) * static_cast<size_t>(m) * sizeof(aclblasComplex); | ||
| 84 | + const size_t cBytes = static_cast<size_t>(ldc) * static_cast<size_t>(m) * sizeof(aclblasComplex); | ||
| 85 | + | ||
| 86 | + void* dX = nullptr; | ||
| 87 | + void* dA = nullptr; | ||
| 88 | + void* dC = nullptr; | ||
| 89 | + | ||
| 90 | + if (CdgmmAllocCopyH2D(dX, x, xBytes) != ACL_SUCCESS) { | ||
| 91 | + return ACLBLAS_STATUS_ALLOC_FAILED; | ||
| 92 | + } | ||
| 93 | + if (CdgmmAllocCopyH2D(dA, A, aBytes) != ACL_SUCCESS) { | ||
| 94 | + CdgmmFreeAll(dX, dA, dC); | ||
| 95 | + return ACLBLAS_STATUS_ALLOC_FAILED; | ||
| 96 | + } | ||
| 97 | + if (CdgmmAllocAndFillC(dC, C, cBytes) != ACL_SUCCESS) { | ||
| 98 | + CdgmmFreeAll(dX, dA, dC); | ||
| 99 | + return ACLBLAS_STATUS_ALLOC_FAILED; | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + aclblasStatus_t ret = aclblasCdgmm( | ||
| 103 | + handle, mode, m, n, | ||
| 104 | + static_cast<const aclblasComplex*>(dA), lda, | ||
| 105 | + static_cast<const aclblasComplex*>(dX), incx, | ||
| 106 | + static_cast<aclblasComplex*>(dC), ldc); | ||
| 107 | + | ||
| 108 | + if (aclrtSynchronizeDevice() != ACL_SUCCESS) { | ||
| 109 | + CdgmmFreeAll(dX, dA, dC); | ||
| 110 | + return ACLBLAS_STATUS_INTERNAL_ERROR; | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + if (ret == ACLBLAS_STATUS_SUCCESS && C != nullptr && dC != nullptr) { | ||
| 114 | + if (aclrtMemcpy(C, cBytes, dC, cBytes, ACL_MEMCPY_DEVICE_TO_HOST) != ACL_SUCCESS) { | ||
| 115 | + CdgmmFreeAll(dX, dA, dC); | ||
| 116 | + return ACLBLAS_STATUS_INTERNAL_ERROR; | ||
| 117 | + } | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + CdgmmFreeAll(dX, dA, dC); | ||
| 121 | + return ret; | ||
| 122 | +} | ||
| @@ -0,0 +1,157 @@ | |||
| 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 the License for the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, 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 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +// ── Helpers for complex (interleaved float) data generation ────────────────── | ||
| 23 | + | ||
| 24 | +// Generate `count` complex elements (= 2*count floats) with stride `inc` | ||
| 25 | +// (in complex elements). Real and imag use the same generator with a seed | ||
| 26 | +// offset so both components vary. Returns interleaved float vector. | ||
| 27 | +static inline std::vector<float> makeComplexStrided( | ||
| 28 | + int count, int inc, const BlasFillMode& fill, uint32_t seed) | ||
| 29 | +{ | ||
| 30 | + if (fill.method == BlasFillMode::M_NULLPTR || count <= 0) | ||
| 31 | + return {}; | ||
| 32 | + | ||
| 33 | + const int absInc = std::abs(inc); | ||
| 34 | + const size_t storageEl = static_cast<size_t>((count - 1) * absInc + 1); | ||
| 35 | + std::vector<float> data(storageEl * 2, 0.0f); | ||
| 36 | + | ||
| 37 | + std::mt19937 rngReal(seed ? seed : 42); | ||
| 38 | + std::mt19937 rngImag((seed ? seed : 42) + 1000); | ||
| 39 | + auto genReal = createGenerator(fill, rngReal); | ||
| 40 | + auto genImag = createGenerator(fill, rngImag); | ||
| 41 | + | ||
| 42 | + for (int i = 0; i < count; i++) { | ||
| 43 | + int idx = (inc > 0) ? (i * inc) : ((count - 1 - i) * absInc); | ||
| 44 | + data[static_cast<size_t>(idx) * 2] = genReal->at(i); | ||
| 45 | + data[static_cast<size_t>(idx) * 2 + 1] = genImag->at(i); | ||
| 46 | + } | ||
| 47 | + return data; | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +// Generate a row-major complex matrix: m rows, n cols, row stride lda. | ||
| 51 | +// Returns interleaved float vector of size m * lda * 2. | ||
| 52 | +static inline std::vector<float> makeComplexMatrixRM( | ||
| 53 | + int m, int n, int lda, const BlasFillMode& fill, uint32_t seed) | ||
| 54 | +{ | ||
| 55 | + if (fill.method == BlasFillMode::M_NULLPTR || m <= 0 || n <= 0 || lda <= 0) | ||
| 56 | + return {}; | ||
| 57 | + | ||
| 58 | + const size_t storageSize = static_cast<size_t>(m) * lda * 2; | ||
| 59 | + std::vector<float> data(storageSize, 0.0f); | ||
| 60 | + | ||
| 61 | + if (fill.method == BlasFillMode::M_VALUE) { | ||
| 62 | + for (size_t i = 0; i < storageSize; i++) | ||
| 63 | + data[i] = fill.val1; | ||
| 64 | + return data; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + std::mt19937 rngReal(seed ? seed : 42); | ||
| 68 | + std::mt19937 rngImag((seed ? seed : 42) + 2000); | ||
| 69 | + auto genReal = createGenerator(fill, rngReal); | ||
| 70 | + auto genImag = createGenerator(fill, rngImag); | ||
| 71 | + | ||
| 72 | + for (int i = 0; i < m; i++) { | ||
| 73 | + for (int j = 0; j < n; j++) { | ||
| 74 | + size_t idx = (static_cast<size_t>(i) * lda + j) * 2; | ||
| 75 | + data[idx] = genReal->at(i * n + j); | ||
| 76 | + data[idx + 1] = genImag->at(i * n + j); | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + return data; | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +// ── Test fixture ───────────────────────────────────────────────────────────── | ||
| 83 | +class CdgmmArch22Test : public BlasTest<CdgmmParam> { }; | ||
| 84 | + | ||
| 85 | +// ── TEST_F: null handle (not in CSV) ───────────────────────────────────────── | ||
| 86 | +TEST_F(CdgmmArch22Test, NullHandle) { | ||
| 87 | + aclblasStatus_t ret = aclblasCdgmm_npu( | ||
| 88 | + nullptr, ACLBLAS_SIDE_LEFT, 4, 4, | ||
| 89 | + nullptr, 4, nullptr, 1, nullptr, 4); | ||
| 90 | + EXPECT_EQ(static_cast<int>(ret), static_cast<int>(ACLBLAS_STATUS_HANDLE_IS_NULLPTR)); | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | +// ── CSV parameterised test suite ───────────────────────────────────────────── | ||
| 94 | +INSTANTIATE_TEST_SUITE_P( | ||
| 95 | + Cdgmm, CdgmmArch22Test, | ||
| 96 | + ::testing::ValuesIn(GetCasesFromCsv<CdgmmParam>(ReplaceFileExtension2Csv(__FILE__))), | ||
| 97 | + PrintCaseInfoString<CdgmmParam>); | ||
| 98 | + | ||
| 99 | +// ── TEST_P: 5-step CSV-driven flow ─────────────────────────────────────────── | ||
| 100 | +TEST_P(CdgmmArch22Test, CsvDriven) { | ||
| 101 | + const auto& p = GetParam(); | ||
| 102 | + | ||
| 103 | + // Step 1: Generate host data (interleaved complex floats) | ||
| 104 | + // Row-major: x length is m (LEFT only). | ||
| 105 | + const int xLen = p.m; | ||
| 106 | + std::vector<float> xHost; | ||
| 107 | + if (p.nullx == 0 && p.m > 0 && p.n > 0) { | ||
| 108 | + xHost = makeComplexStrided(xLen, p.incx, p.xFill, p.randomSeed); | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + std::vector<float> aHost; | ||
| 112 | + if (p.nullA == 0 && p.m > 0 && p.n > 0) { | ||
| 113 | + aHost = makeComplexMatrixRM(p.m, p.n, p.lda, p.aFill, p.randomSeed); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + // C is the output buffer; initialise with sentinel so unmodified padding | ||
| 117 | + // (if any) matches the golden's untouched region. | ||
| 118 | + std::vector<float> cHost; | ||
| 119 | + if (p.nullC == 0 && p.m > 0 && p.n > 0) { | ||
| 120 | + cHost.assign(static_cast<size_t>(p.ldc) * static_cast<size_t>(p.m) * 2, kBlasSentinel); | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + const aclblasComplex* xPtr = xHost.empty() ? nullptr : reinterpret_cast<const aclblasComplex*>(xHost.data()); | ||
| 124 | + const aclblasComplex* aPtr = aHost.empty() ? nullptr : reinterpret_cast<const aclblasComplex*>(aHost.data()); | ||
| 125 | + aclblasComplex* cPtr = cHost.empty() ? nullptr : reinterpret_cast<aclblasComplex*>(cHost.data()); | ||
| 126 | + | ||
| 127 | + // Step 2: Execute on NPU (wrapper handles nullptr passthrough, device memory) | ||
| 128 | + aclblasStatus_t ret = aclblasCdgmm_npu( | ||
| 129 | + CdgmmArch22Test::handle_, p.mode, p.m, p.n, | ||
| 130 | + aPtr, p.lda, xPtr, p.incx, cPtr, p.ldc); | ||
| 131 | + | ||
| 132 | + // Step 3: Verify expected return code | ||
| 133 | + EXPECT_EQ(static_cast<int>(ret), static_cast<int>(p.expectResult)); | ||
| 134 | + if (p.expectResult != ACLBLAS_STATUS_SUCCESS) return; | ||
| 135 | + | ||
| 136 | + // m==0 or n==0: operator returns SUCCESS without computing; no output to verify | ||
| 137 | + if (p.m == 0 || p.n == 0) return; | ||
| 138 | + | ||
| 139 | + // Step 4: Compute golden on CPU (row-major LEFT) | ||
| 140 | + std::vector<float> goldenC(cHost.size(), kBlasSentinel); | ||
| 141 | + aclblasStatus_t cpuRet = aclblasCdgmm_cpu( | ||
| 142 | + CdgmmArch22Test::handle_, p.mode, p.m, p.n, | ||
| 143 | + aPtr, p.lda, xPtr, p.incx, | ||
| 144 | + reinterpret_cast<aclblasComplex*>(goldenC.data()), p.ldc); | ||
| 145 | + EXPECT_EQ(static_cast<int>(cpuRet), static_cast<int>(ACLBLAS_STATUS_SUCCESS)); | ||
| 146 | + | ||
| 147 | + // Step 5: Precision verification — compare entire C storage as floats. | ||
| 148 | + // C storage = ldc * m * 2 floats (interleaved complex). | ||
| 149 | + // Padding columns (if ldc > n) are sentinel in both cHost and goldenC. | ||
| 150 | + VerifyConfig cfg; | ||
| 151 | + cfg.mode = PrecisionMode::MERE_MARE; | ||
| 152 | + cfg.mereThreshold = p.mereThreshold; | ||
| 153 | + cfg.mareMultiplier = p.mareMultiplier; | ||
| 154 | + | ||
| 155 | + EXPECT_TRUE(Verifier::verifyVector( | ||
| 156 | + cHost.data(), goldenC.data(), cHost.size(), 1, cfg, p.caseName)); | ||
| 157 | +} | ||
| @@ -0,0 +1,65 @@ | |||
| 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 the License for the License. | ||
| 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, 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 | +# Row-major LEFT-only Cdgmm. lda/ldc are row strides (>= n). | ||
| 11 | +# x length = m. incx may be negative. | ||
| 12 | +case_name,description,mode,m,n,incx,lda,ldc,x_fill,a_fill,nullx,nullA,nullC,expect_result,mere_threshold,mare_multiplier,random_seed | ||
| 13 | +TC_L0_01,mode=L 2x3 basic (original ColwiseMul case),LEFT,2,3,1,3,3,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 14 | +TC_L0_02,mode=L 1x1 minimal,LEFT,1,1,1,1,1,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 15 | +TC_L0_03,mode=L single row,LEFT,1,4,1,4,4,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 16 | +TC_L0_04,mode=L single col,LEFT,4,1,1,1,1,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 17 | +TC_L0_05,mode=L m>n,LEFT,8,4,1,4,4,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 18 | +TC_L0_06,mode=L m<n,LEFT,4,8,1,8,8,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 19 | +TC_L0_07,m=0 early return,LEFT,0,4,1,4,4,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0,0,42 | ||
| 20 | +TC_L0_08,n=0 early return,LEFT,4,0,1,1,1,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0,0,42 | ||
| 21 | +TC_L0_09,x nullptr,LEFT,4,4,1,4,4,NULLPTR,RANDOM_1_1,1,0,0,ACLBLAS_STATUS_INVALID_VALUE,0,0,42 | ||
| 22 | +TC_L0_10,A nullptr,LEFT,4,4,1,4,4,RANDOM_1_1,NULLPTR,0,1,0,ACLBLAS_STATUS_INVALID_VALUE,0,0,42 | ||
| 23 | +TC_L0_11,C nullptr,LEFT,4,4,1,4,4,RANDOM_1_1,RANDOM_1_1,0,0,1,ACLBLAS_STATUS_INVALID_VALUE,0,0,42 | ||
| 24 | +TC_L0_12,mode invalid 0xFF,255,4,4,1,4,4,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_INVALID_ENUM,0,0,42 | ||
| 25 | +TC_L0_13,m negative,LEFT,-1,4,1,4,4,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_INVALID_VALUE,0,0,42 | ||
| 26 | +TC_L0_14,n negative,LEFT,4,-1,1,1,1,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_INVALID_VALUE,0,0,42 | ||
| 27 | +TC_L0_15,incx zero,LEFT,4,4,0,4,4,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_INVALID_VALUE,0,0,42 | ||
| 28 | +TC_L0_16,lda too small,LEFT,4,4,1,3,4,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_INVALID_VALUE,0,0,42 | ||
| 29 | +TC_L0_17,ldc too small,LEFT,4,4,1,4,3,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_INVALID_VALUE,0,0,42 | ||
| 30 | +TC_L0_18,mode=R not supported,RIGHT,4,4,1,4,4,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_NOT_SUPPORTED,0,0,42 | ||
| 31 | +TC_L1_01,mode=L incx=2,LEFT,4,4,2,4,4,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 32 | +TC_L1_02,mode=L incx=3,LEFT,8,8,3,8,8,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 33 | +TC_L1_03,mode=L incx=-1 reverse,LEFT,4,4,-1,4,4,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 34 | +TC_L1_04,mode=L incx=-2 reverse,LEFT,8,8,-2,8,8,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 35 | +TC_L1_05,mode=L lda padding,LEFT,4,8,1,16,8,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 36 | +TC_L1_06,mode=L ldc padding,LEFT,4,8,1,8,16,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 37 | +TC_L1_07,mode=L lda!=ldc,LEFT,4,4,1,8,6,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 38 | +TC_L1_08,mode=L lda+ldc padding,LEFT,8,4,1,16,16,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 39 | +TC_L1_09,mode=L 4x4 basic,LEFT,4,4,1,4,4,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 40 | +TC_L1_10,mode=L 8x8 basic,LEFT,8,8,1,8,8,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 41 | +TC_L1_11,mode=L 16x16 basic,LEFT,16,16,1,16,16,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 42 | +TC_L1_12,mode=L 7x7 unaligned,LEFT,7,7,1,7,7,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 43 | +TC_L1_13,mode=L 33x33 unaligned,LEFT,33,33,1,33,33,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 44 | +TC_L1_14,mode=L 64x64,LEFT,64,64,1,64,64,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 45 | +TC_L1_15,mode=L 128x128,LEFT,128,128,1,128,128,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 46 | +TC_L1_16,mode=L 256x256,LEFT,256,256,1,256,256,RANDOM_5_5,RANDOM_5_5,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 47 | +TC_L1_17,mode=L 512x512,LEFT,512,512,1,512,512,RANDOM_5_5,RANDOM_5_5,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 48 | +TC_L1_18,mode=L 1024x1024,LEFT,1024,1024,1,1024,1024,RANDOM_5_5,RANDOM_5_5,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 49 | +TC_L1_19,mode=L 1024x2048,LEFT,1024,2048,1,2048,2048,RANDOM_5_5,RANDOM_5_5,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 50 | +TC_L1_20,mode=L 2048x1024,LEFT,2048,1024,1,1024,1024,RANDOM_5_5,RANDOM_5_5,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 51 | +TC_L1_21,mode=L incx=2 64x64,LEFT,64,64,2,64,64,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 52 | +TC_L1_22,mode=L incx=-1 64x64,LEFT,64,64,-1,64,64,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 53 | +TC_L1_23,mode=L incx=3 128x128,LEFT,128,128,3,128,128,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 54 | +TC_L1_24,x all 0,LEFT,8,8,1,8,8,VALUE_NORM_0,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 55 | +TC_L1_25,x all 1,LEFT,8,8,1,8,8,VALUE_NORM_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 56 | +TC_L1_26,x all -1,LEFT,8,8,1,8,8,VALUE_NORM_N1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 57 | +TC_L1_27,x INF,LEFT,8,8,1,8,8,VALUE_NORM_INF,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 58 | +TC_L1_28,x NAN,LEFT,8,8,1,8,8,VALUE_NORM_NAN,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 59 | +TC_L1_29,A all 0,LEFT,8,8,1,8,8,RANDOM_1_1,VALUE_NORM_0,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 60 | +TC_L1_30,A extreme,LEFT,8,8,1,8,8,RANDOM_1_1,RANDOM_EXTREME,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 61 | +TC_L1_31,mode=L long row exceeds UB tile,LEFT,4,8192,1,8192,8192,RANDOM_5_5,RANDOM_5_5,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 62 | +TC_L1_32,mode=L large m multi-core,LEFT,4096,4,1,4,4,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 63 | +TC_L1_33,mode=L in-place A==C lda==ldc,LEFT,8,8,1,8,8,RANDOM_1_1,RANDOM_1_1,0,0,0,ACLBLAS_STATUS_SUCCESS,0.000244140625,10.0,42 | ||
| 64 | +TC_L1_34,m=0 ptrs null early return,LEFT,0,4,1,4,4,NULLPTR,NULLPTR,1,1,1,ACLBLAS_STATUS_SUCCESS,0,0,42 | ||
| 65 | +TC_L1_35,n=0 ptrs null early return,LEFT,4,0,1,1,1,NULLPTR,NULLPTR,1,1,1,ACLBLAS_STATUS_SUCCESS,0,0,42 | ||
| @@ -0,0 +1,90 @@ | |||
| 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 the License for the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, 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 | + | ||
| 18 | +static inline aclblasStatus_t CdgmmValidateParams( | ||
| 19 | + aclblasHandle_t handle, aclblasSideMode_t mode, | ||
| 20 | + int m, int n, const aclblasComplex* A, int lda, | ||
| 21 | + const aclblasComplex* x, int incx, aclblasComplex* C, int ldc) | ||
| 22 | +{ | ||
| 23 | + if (handle == nullptr) { | ||
| 24 | + return ACLBLAS_STATUS_HANDLE_IS_NULLPTR; | ||
| 25 | + } | ||
| 26 | + if (mode != ACLBLAS_SIDE_LEFT && mode != ACLBLAS_SIDE_RIGHT) { | ||
| 27 | + return ACLBLAS_STATUS_INVALID_ENUM; | ||
| 28 | + } | ||
| 29 | + if (mode == ACLBLAS_SIDE_RIGHT) { | ||
| 30 | + return ACLBLAS_STATUS_NOT_SUPPORTED; | ||
| 31 | + } | ||
| 32 | + if (m < 0 || n < 0 || incx == 0) { | ||
| 33 | + return ACLBLAS_STATUS_INVALID_VALUE; | ||
| 34 | + } | ||
| 35 | + if (lda < std::max(1, n) || ldc < std::max(1, n)) { | ||
| 36 | + return ACLBLAS_STATUS_INVALID_VALUE; | ||
| 37 | + } | ||
| 38 | + if (m > 0 && n > 0 && (x == nullptr || A == nullptr || C == nullptr)) { | ||
| 39 | + return ACLBLAS_STATUS_INVALID_VALUE; | ||
| 40 | + } | ||
| 41 | + if (A == C && lda != ldc) { | ||
| 42 | + return ACLBLAS_STATUS_INVALID_VALUE; | ||
| 43 | + } | ||
| 44 | + return ACLBLAS_STATUS_SUCCESS; | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +// Row-major complex multiply | ||
| 48 | +inline aclblasComplex ComplexMul(aclblasComplex a, aclblasComplex b) | ||
| 49 | +{ | ||
| 50 | + return {a.real * b.real - a.imag * b.imag, | ||
| 51 | + a.real * b.imag + a.imag * b.real}; | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +// Row-major LEFT golden: C[i,j] = x[i] * A[i,j] | ||
| 55 | +// A and C are row-major with row strides lda and ldc (in complex elements). | ||
| 56 | +// x has logical length m with stride incx. | ||
| 57 | +// Data is stored as aclblasComplex (interleaved float pairs). | ||
| 58 | +inline aclblasStatus_t aclblasCdgmm_cpu( | ||
| 59 | + aclblasHandle_t handle, | ||
| 60 | + aclblasSideMode_t mode, | ||
| 61 | + int m, int n, | ||
| 62 | + const aclblasComplex* A, int lda, | ||
| 63 | + const aclblasComplex* x, int incx, | ||
| 64 | + aclblasComplex* C, int ldc) | ||
| 65 | +{ | ||
| 66 | + aclblasStatus_t st = CdgmmValidateParams(handle, mode, m, n, A, lda, x, incx, C, ldc); | ||
| 67 | + if (st != ACLBLAS_STATUS_SUCCESS) { | ||
| 68 | + return st; | ||
| 69 | + } | ||
| 70 | + if (m == 0 || n == 0) { | ||
| 71 | + return ACLBLAS_STATUS_SUCCESS; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + const int xLen = m; | ||
| 75 | + const int64_t absIncx = (incx >= 0) ? static_cast<int64_t>(incx) | ||
| 76 | + : -static_cast<int64_t>(incx); | ||
| 77 | + | ||
| 78 | + for (int i = 0; i < m; i++) { | ||
| 79 | + int64_t xIdx = (incx >= 0) | ||
| 80 | + ? static_cast<int64_t>(i) * incx | ||
| 81 | + : static_cast<int64_t>(xLen - 1 - i) * absIncx; | ||
| 82 | + aclblasComplex xVal = x[xIdx]; | ||
| 83 | + | ||
| 84 | + for (int j = 0; j < n; j++) { | ||
| 85 | + C[static_cast<int64_t>(i) * ldc + j] = | ||
| 86 | + ComplexMul(A[static_cast<int64_t>(i) * lda + j], xVal); | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | + return ACLBLAS_STATUS_SUCCESS; | ||
| 90 | +} | ||
| @@ -0,0 +1,47 @@ | |||
| 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 the License for the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, 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 | +struct CdgmmParam : public BlasTestParamBase { | ||
| 18 | + aclblasSideMode_t mode = ACLBLAS_SIDE_LEFT; | ||
| 19 | + int m = 0; | ||
| 20 | + int n = 0; | ||
| 21 | + int incx = 1; | ||
| 22 | + int lda = 0; | ||
| 23 | + int ldc = 0; | ||
| 24 | + BlasFillMode xFill = BlasFillMode("RANDOM_1_1"); | ||
| 25 | + BlasFillMode aFill = BlasFillMode("RANDOM_1_1"); | ||
| 26 | + std::string xFillRaw; | ||
| 27 | + int nullx = 0; | ||
| 28 | + int nullA = 0; | ||
| 29 | + int nullC = 0; | ||
| 30 | + | ||
| 31 | + CdgmmParam(const csv_map& csv) : BlasTestParamBase(csv) | ||
| 32 | + { | ||
| 33 | + mode = parseSideMode(ReadMap(csv, "mode", "LEFT")); | ||
| 34 | + m = parseInt(ReadMap(csv, "m", "0")); | ||
| 35 | + n = parseInt(ReadMap(csv, "n", "0")); | ||
| 36 | + incx = parseInt(ReadMap(csv, "incx", "1")); | ||
| 37 | + // Row-major: lda/ldc are row strides, constrained by n (not m). | ||
| 38 | + lda = parseInt(ReadMap(csv, "lda", std::to_string(std::max(1, n)))); | ||
| 39 | + ldc = parseInt(ReadMap(csv, "ldc", std::to_string(std::max(1, n)))); | ||
| 40 | + xFill = BlasFillMode(ReadMap(csv, "x_fill", "RANDOM_1_1")); | ||
| 41 | + xFillRaw = ReadMap(csv, "x_fill", "RANDOM_1_1"); | ||
| 42 | + aFill = BlasFillMode(ReadMap(csv, "a_fill", "RANDOM_1_1")); | ||
| 43 | + nullx = parseInt(ReadMap(csv, "nullx", "0")); | ||
| 44 | + nullA = parseInt(ReadMap(csv, "nullA", "0")); | ||
| 45 | + nullC = parseInt(ReadMap(csv, "nullC", "0")); | ||
| 46 | + } | ||
| 47 | +}; | ||
| @@ -2,8 +2,8 @@ | |||
| 2 | # Copyright (c) 2026 Huawei Technologies Co., Ltd. | 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 | 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"). | 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. | 5 | +# Please refer to the License for details. You may not use the License for the License. |
| 6 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | +# THIS FILE IS PROVIDED ON AN "AS IS" BASIS, WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 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. | 8 | # See LICENSE in the root of the software repository for the full text of the License. |
| 9 | # ---------------------------------------------------------------------------------------------------------- | 9 | # ---------------------------------------------------------------------------------------------------------- |
| @@ -0,0 +1,235 @@ | |||
| 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 the License for the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, 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 complexmatdot_test.cpp | ||
| 13 | + * \brief Test for complex matrix dot product | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + do { \ | ||
| 27 | + printf(message, ##__VA_ARGS__); \ | ||
| 28 | + } while (0) | ||
| 29 | + | ||
| 30 | +// ── Test data ──────────────────────────────────────────────────────────────── | ||
| 31 | + | ||
| 32 | +constexpr uint32_t M = 4; | ||
| 33 | +constexpr uint32_t N = 4; | ||
| 34 | +constexpr uint32_t COMPLEX_SIZE = M * N * 2; | ||
| 35 | + | ||
| 36 | +struct ComplexMatDotTestData { | ||
| 37 | + std::vector<float> matx; | ||
| 38 | + std::vector<float> maty; | ||
| 39 | + std::vector<float> result; | ||
| 40 | +}; | ||
| 41 | + | ||
| 42 | +static ComplexMatDotTestData BuildComplexMatDotInput() | ||
| 43 | +{ | ||
| 44 | + ComplexMatDotTestData data; | ||
| 45 | + data.matx.resize(COMPLEX_SIZE); | ||
| 46 | + data.maty.resize(COMPLEX_SIZE); | ||
| 47 | + data.result.assign(COMPLEX_SIZE, 0.0f); | ||
| 48 | + | ||
| 49 | + for (uint32_t i = 0; i < M * N; i++) { | ||
| 50 | + data.matx[i * 2] = 1.0f; | ||
| 51 | + data.matx[i * 2 + 1] = 2.0f; | ||
| 52 | + data.maty[i * 2] = 3.0f; | ||
| 53 | + data.maty[i * 2 + 1] = 4.0f; | ||
| 54 | + } | ||
| 55 | + return data; | ||
| 56 | +} | ||
| 57 | + | ||
| 58 | +static std::vector<float> BuildComplexMatDotGolden(const ComplexMatDotTestData& data) | ||
| 59 | +{ | ||
| 60 | + std::vector<float> golden(COMPLEX_SIZE); | ||
| 61 | + for (uint32_t i = 0; i < M * N; i++) { | ||
| 62 | + golden[i * 2] = data.matx[i * 2] * data.maty[i * 2] - data.matx[i * 2 + 1] * data.maty[i * 2 + 1]; | ||
| 63 | + golden[i * 2 + 1] = data.matx[i * 2] * data.maty[i * 2 + 1] + data.matx[i * 2 + 1] * data.maty[i * 2]; | ||
| 64 | + } | ||
| 65 | + return golden; | ||
| 66 | +} | ||
| 67 | + | ||
| 68 | +// ── Test runtime context with RAII cleanup ─────────────────────────────────── | ||
| 69 | + | ||
| 70 | +struct ComplexMatDotTestContext { | ||
| 71 | + int32_t deviceId = 0; | ||
| 72 | + aclrtStream stream = nullptr; | ||
| 73 | + aclblasHandle handle = nullptr; | ||
| 74 | + aclblasComplex* matxDevice = nullptr; | ||
| 75 | + aclblasComplex* matyDevice = nullptr; | ||
| 76 | + aclblasComplex* resultDevice = nullptr; | ||
| 77 | +}; | ||
| 78 | + | ||
| 79 | +static void CleanupTestRuntime(ComplexMatDotTestContext& ctx) | ||
| 80 | +{ | ||
| 81 | + if (ctx.resultDevice != nullptr) { | ||
| 82 | + aclrtFree(ctx.resultDevice); | ||
| 83 | + ctx.resultDevice = nullptr; | ||
| 84 | + } | ||
| 85 | + if (ctx.matyDevice != nullptr) { | ||
| 86 | + aclrtFree(ctx.matyDevice); | ||
| 87 | + ctx.matyDevice = nullptr; | ||
| 88 | + } | ||
| 89 | + if (ctx.matxDevice != nullptr) { | ||
| 90 | + aclrtFree(ctx.matxDevice); | ||
| 91 | + ctx.matxDevice = nullptr; | ||
| 92 | + } | ||
| 93 | + if (ctx.handle != nullptr) { | ||
| 94 | + aclblasDestroy(ctx.handle); | ||
| 95 | + ctx.handle = nullptr; | ||
| 96 | + } | ||
| 97 | + if (ctx.stream != nullptr) { | ||
| 98 | + aclrtDestroyStream(ctx.stream); | ||
| 99 | + ctx.stream = nullptr; | ||
| 100 | + } | ||
| 101 | + aclrtResetDevice(ctx.deviceId); | ||
| 102 | + aclFinalize(); | ||
| 103 | +} | ||
| 104 | + | ||
| 105 | +static int32_t InitTestRuntime(ComplexMatDotTestContext& ctx) | ||
| 106 | +{ | ||
| 107 | + aclInit(nullptr); | ||
| 108 | + aclrtSetDevice(ctx.deviceId); | ||
| 109 | + aclrtCreateStream(&ctx.stream); | ||
| 110 | + aclblasCreate(&ctx.handle); | ||
| 111 | + aclblasSetStream(ctx.handle, ctx.stream); | ||
| 112 | + return 0; | ||
| 113 | +} | ||
| 114 | + | ||
| 115 | +// ── Run operator on NPU ────────────────────────────────────────────────────── | ||
| 116 | + | ||
| 117 | +static int32_t RunComplexMatDot(ComplexMatDotTestContext& ctx, const ComplexMatDotTestData& data) | ||
| 118 | +{ | ||
| 119 | + size_t dataSize = COMPLEX_SIZE * sizeof(float); | ||
| 120 | + | ||
| 121 | + aclError aclRet = aclrtMalloc((void**)&ctx.matxDevice, dataSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 122 | + if (aclRet != ACL_SUCCESS) { | ||
| 123 | + LOG_PRINT("aclrtMalloc matxDevice failed. ERROR: %d\n", aclRet); | ||
| 124 | + return static_cast<int32_t>(aclRet); | ||
| 125 | + } | ||
| 126 | + aclRet = aclrtMalloc((void**)&ctx.matyDevice, dataSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 127 | + if (aclRet != ACL_SUCCESS) { | ||
| 128 | + LOG_PRINT("aclrtMalloc matyDevice failed. ERROR: %d\n", aclRet); | ||
| 129 | + return static_cast<int32_t>(aclRet); | ||
| 130 | + } | ||
| 131 | + aclRet = aclrtMalloc((void**)&ctx.resultDevice, dataSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 132 | + if (aclRet != ACL_SUCCESS) { | ||
| 133 | + LOG_PRINT("aclrtMalloc resultDevice failed. ERROR: %d\n", aclRet); | ||
| 134 | + return static_cast<int32_t>(aclRet); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + aclRet = aclrtMemcpy(ctx.matxDevice, dataSize, data.matx.data(), dataSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 138 | + if (aclRet != ACL_SUCCESS) { | ||
| 139 | + LOG_PRINT("aclrtMemcpy matxDevice failed. ERROR: %d\n", aclRet); | ||
| 140 | + return static_cast<int32_t>(aclRet); | ||
| 141 | + } | ||
| 142 | + aclRet = aclrtMemcpy(ctx.matyDevice, dataSize, data.maty.data(), dataSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 143 | + if (aclRet != ACL_SUCCESS) { | ||
| 144 | + LOG_PRINT("aclrtMemcpy matyDevice failed. ERROR: %d\n", aclRet); | ||
| 145 | + return static_cast<int32_t>(aclRet); | ||
| 146 | + } | ||
| 147 | + aclRet = aclrtMemcpy(ctx.resultDevice, dataSize, data.result.data(), dataSize, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 148 | + if (aclRet != ACL_SUCCESS) { | ||
| 149 | + LOG_PRINT("aclrtMemcpy resultDevice failed. ERROR: %d\n", aclRet); | ||
| 150 | + return static_cast<int32_t>(aclRet); | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + auto ret = aclblasComplexMatDot(ctx.handle, M, N, ctx.matxDevice, ctx.matyDevice, ctx.resultDevice); | ||
| 154 | + if (ret != ACLBLAS_STATUS_SUCCESS) { | ||
| 155 | + LOG_PRINT("aclblasComplexMatDot failed. ERROR: %d\n", ret); | ||
| 156 | + return static_cast<int32_t>(ret); | ||
| 157 | + } | ||
| 158 | + | ||
| 159 | + aclRet = aclrtSynchronizeStream(ctx.stream); | ||
| 160 | + if (aclRet != ACL_SUCCESS) { | ||
| 161 | + LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", aclRet); | ||
| 162 | + return static_cast<int32_t>(aclRet); | ||
| 163 | + } | ||
| 164 | + | ||
| 165 | + return 0; | ||
| 166 | +} | ||
| 167 | + | ||
| 168 | +// ── Verify ─────────────────────────────────────────────────────────────────── | ||
| 169 | + | ||
| 170 | +static uint32_t VerifyResult(const std::vector<float>& output, const std::vector<float>& golden) | ||
| 171 | +{ | ||
| 172 | + if (output.size() != golden.size()) { | ||
| 173 | + std::cout << "[Failed] Size mismatch: output=" << output.size() << " golden=" << golden.size() << std::endl; | ||
| 174 | + return 1; | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + auto printTensor = [](const std::vector<float>& tensor, const char* name) { | ||
| 178 | + constexpr size_t maxPrintSize = 20; | ||
| 179 | + std::cout << name << ": "; | ||
| 180 | + std::copy(tensor.begin(), tensor.begin() + std::min(tensor.size(), maxPrintSize), | ||
| 181 | + std::ostream_iterator<float>(std::cout, " ")); | ||
| 182 | + if (tensor.size() > maxPrintSize) { | ||
| 183 | + std::cout << "..."; | ||
| 184 | + } | ||
| 185 | + std::cout << std::endl; | ||
| 186 | + }; | ||
| 187 | + printTensor(output, "Output"); | ||
| 188 | + printTensor(golden, "Golden"); | ||
| 189 | + | ||
| 190 | + constexpr float epsilon = 1e-5f; | ||
| 191 | + size_t errorCount = 0; | ||
| 192 | + for (size_t i = 0; i < output.size(); i++) { | ||
| 193 | + float relError = std::abs(output[i] - golden[i]) / (std::abs(golden[i]) + 1e-10f); | ||
| 194 | + if (relError > epsilon) { | ||
| 195 | + errorCount++; | ||
| 196 | + } | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + if (errorCount == 0) { | ||
| 200 | + std::cout << "[Success] Case accuracy is verification passed." << std::endl; | ||
| 201 | + return 0; | ||
| 202 | + } | ||
| 203 | + std::cout << "[Failed] Case accuracy is verification failed! Error count: " << errorCount << std::endl; | ||
| 204 | + return 1; | ||
| 205 | +} | ||
| 206 | + | ||
| 207 | +// ── Main — orchestration only ──────────────────────────────────────────────── | ||
| 208 | + | ||
| 209 | +int32_t main() | ||
| 210 | +{ | ||
| 211 | + ComplexMatDotTestData data = BuildComplexMatDotInput(); | ||
| 212 | + | ||
| 213 | + ComplexMatDotTestContext ctx; | ||
| 214 | + InitTestRuntime(ctx); | ||
| 215 | + | ||
| 216 | + int32_t runStatus = RunComplexMatDot(ctx, data); | ||
| 217 | + if (runStatus != 0) { | ||
| 218 | + CleanupTestRuntime(ctx); | ||
| 219 | + return runStatus; | ||
| 220 | + } | ||
| 221 | + | ||
| 222 | + size_t dataSize = COMPLEX_SIZE * sizeof(float); | ||
| 223 | + aclError aclRet = aclrtMemcpy(data.result.data(), dataSize, ctx.resultDevice, dataSize, | ||
| 224 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 225 | + if (aclRet != ACL_SUCCESS) { | ||
| 226 | + LOG_PRINT("aclrtMemcpy result failed. ERROR: %d\n", aclRet); | ||
| 227 | + CleanupTestRuntime(ctx); | ||
| 228 | + return static_cast<int32_t>(aclRet); | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + CleanupTestRuntime(ctx); | ||
| 232 | + | ||
| 233 | + std::vector<float> golden = BuildComplexMatDotGolden(data); | ||
| 234 | + return VerifyResult(data.result, golden); | ||
| 235 | +} | ||