已合并
[PR1/3] migrate transdata aicpu kernel: kernel impl + format_transfer base + basic UT #4113
pantong创建于 7月16日
[PR1/3] migrate transdata aicpu kernel: kernel impl + format_transfer base + basic UT #4113
已合并
共 10 个文件变更+1495-16
| @@ -86,7 +86,7 @@ function(merge_graph_headers) | |||
| 86 | endfunction() | 86 | endfunction() |
| 87 | 87 | ||
| 88 | function(gen_es_math_lib_ready) | 88 | function(gen_es_math_lib_ready) |
| 89 | - # 合并proto.h生成ops_proto_math.h和ops_proto_math.cpp | 89 | + # 合并proto.h生成ops_proto_math.h和ops_proto_math.cpp |
| 90 | merge_graph_headers(TARGET merge_ops_proto_${PKG_NAME} OUT_DIR ${ASCEND_GRAPH_CONF_DST}) | 90 | merge_graph_headers(TARGET merge_ops_proto_${PKG_NAME} OUT_DIR ${ASCEND_GRAPH_CONF_DST}) |
| 91 | add_library( | 91 | add_library( |
| 92 | proto_${PKG_NAME} SHARED | 92 | proto_${PKG_NAME} SHARED |
| @@ -103,7 +103,7 @@ function(gen_es_math_lib_ready) | |||
| 103 | ) | 103 | ) |
| 104 | target_link_directories(proto_${PKG_NAME} PRIVATE ${ASCEND_DIR}/${SYSTEM_PREFIX}/lib64) | 104 | target_link_directories(proto_${PKG_NAME} PRIVATE ${ASCEND_DIR}/${SYSTEM_PREFIX}/lib64) |
| 105 | 105 | ||
| 106 | - # 生成 es_math | 106 | + # 生成 es_math |
| 107 | add_es_library_and_whl( | 107 | add_es_library_and_whl( |
| 108 | ES_LINKABLE_AND_ALL_TARGET es_${PKG_NAME} | 108 | ES_LINKABLE_AND_ALL_TARGET es_${PKG_NAME} |
| 109 | OPP_PROTO_TARGET proto_${PKG_NAME} | 109 | OPP_PROTO_TARGET proto_${PKG_NAME} |
| @@ -146,7 +146,7 @@ function(gen_es_math_lib_ready_cust) | |||
| 146 | ) | 146 | ) |
| 147 | target_link_directories(proto_${PKG_NAME}_cust PRIVATE ${ASCEND_DIR}/${SYSTEM_PREFIX}/lib64) | 147 | target_link_directories(proto_${PKG_NAME}_cust PRIVATE ${ASCEND_DIR}/${SYSTEM_PREFIX}/lib64) |
| 148 | 148 | ||
| 149 | - # 生成 es_math | 149 | + # 生成 es_math |
| 150 | add_es_library( | 150 | add_es_library( |
| 151 | ES_LINKABLE_AND_ALL_TARGET es_${PKG_NAME} | 151 | ES_LINKABLE_AND_ALL_TARGET es_${PKG_NAME} |
| 152 | OPP_PROTO_TARGET proto_${PKG_NAME}_cust | 152 | OPP_PROTO_TARGET proto_${PKG_NAME}_cust |
| @@ -180,17 +180,17 @@ function(gen_opgraph_symbol) | |||
| 180 | add_library( | 180 | add_library( |
| 181 | ${OPGRAPH_NAME} SHARED | 181 | ${OPGRAPH_NAME} SHARED |
| 182 | $<$<TARGET_EXISTS:${GRAPH_PLUGIN_NAME}_obj>:$<TARGET_OBJECTS:${GRAPH_PLUGIN_NAME}_obj>> | 182 | $<$<TARGET_EXISTS:${GRAPH_PLUGIN_NAME}_obj>:$<TARGET_OBJECTS:${GRAPH_PLUGIN_NAME}_obj>> |
| 183 | - $<$<TARGET_EXISTS:opbase_util_objs>:$<TARGET_OBJECTS:opbase_util_objs>> | 183 | + $<$<TARGET_EXISTS:opbase_util_objs>:$<TARGET_OBJECTS:opbase_util_objs>> |
| 184 | $<$<TARGET_EXISTS:opbase_infer_objs>:$<TARGET_OBJECTS:opbase_infer_objs>> | 184 | $<$<TARGET_EXISTS:opbase_infer_objs>:$<TARGET_OBJECTS:opbase_infer_objs>> |
| 185 | ) | 185 | ) |
| 186 | add_dependencies(${OPGRAPH_NAME} merge_ops_proto_${PKG_NAME}) | 186 | add_dependencies(${OPGRAPH_NAME} merge_ops_proto_${PKG_NAME}) |
| 187 | 187 | ||
| 188 | - target_sources( | 188 | + target_sources( |
| 189 | - ${OPGRAPH_NAME} | 189 | + ${OPGRAPH_NAME} |
| 190 | - PRIVATE | 190 | + PRIVATE |
| 191 | - ${ASCEND_GRAPH_CONF_DST}/ops_proto_math.cpp | 191 | + ${ASCEND_GRAPH_CONF_DST}/ops_proto_math.cpp |
| 192 | ) | 192 | ) |
| 193 | - | 193 | + |
| 194 | target_link_libraries( | 194 | target_link_libraries( |
| 195 | ${OPGRAPH_NAME} | 195 | ${OPGRAPH_NAME} |
| 196 | PRIVATE $<BUILD_INTERFACE:intf_pub_cxx17> | 196 | PRIVATE $<BUILD_INTERFACE:intf_pub_cxx17> |
| @@ -205,12 +205,12 @@ function(gen_opgraph_symbol) | |||
| 205 | -Wl,-Bsymbolic | 205 | -Wl,-Bsymbolic |
| 206 | ge_compiler | 206 | ge_compiler |
| 207 | ) | 207 | ) |
| 208 | - | 208 | + |
| 209 | - target_link_directories(${OPGRAPH_NAME} PRIVATE | 209 | + target_link_directories(${OPGRAPH_NAME} PRIVATE |
| 210 | ${ASCEND_DIR}/${SYSTEM_PREFIX}/lib64 | 210 | ${ASCEND_DIR}/${SYSTEM_PREFIX}/lib64 |
| 211 | ${CMAKE_BINARY_DIR}/es_packages/lib64 | 211 | ${CMAKE_BINARY_DIR}/es_packages/lib64 |
| 212 | ) | 212 | ) |
| 213 | - set_target_properties(${OPGRAPH_NAME} PROPERTIES | 213 | + set_target_properties(${OPGRAPH_NAME} PROPERTIES |
| 214 | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/opp/built-in/op_proto | 214 | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/opp/built-in/op_proto |
| 215 | ) | 215 | ) |
| 216 | 216 | ||
| @@ -332,7 +332,7 @@ function(gen_cust_proto_symbol) | |||
| 332 | $<$<TARGET_EXISTS:opbase_util_objs>:$<TARGET_OBJECTS:opbase_util_objs>> | 332 | $<$<TARGET_EXISTS:opbase_util_objs>:$<TARGET_OBJECTS:opbase_util_objs>> |
| 333 | $<$<TARGET_EXISTS:opbase_infer_objs>:$<TARGET_OBJECTS:opbase_infer_objs>> | 333 | $<$<TARGET_EXISTS:opbase_infer_objs>:$<TARGET_OBJECTS:opbase_infer_objs>> |
| 334 | ) | 334 | ) |
| 335 | - | 335 | + |
| 336 | target_link_libraries( | 336 | target_link_libraries( |
| 337 | cust_proto | 337 | cust_proto |
| 338 | PUBLIC $<BUILD_INTERFACE:intf_pub_cxx17> | 338 | PUBLIC $<BUILD_INTERFACE:intf_pub_cxx17> |
| @@ -460,6 +460,7 @@ function(gen_aicpu_kernel_symbol enable_built_in) | |||
| 460 | -o ${ARM_SO_OUTPUT} | 460 | -o ${ARM_SO_OUTPUT} |
| 461 | DEPENDS ${AICPU_CUST_OBJ_TARGETS} | 461 | DEPENDS ${AICPU_CUST_OBJ_TARGETS} |
| 462 | COMMENT "Linking aicpu_kernels.so using ARM toolchain" | 462 | COMMENT "Linking aicpu_kernels.so using ARM toolchain" |
| 463 | + COMMAND_EXPAND_LISTS | ||
| 463 | ) | 464 | ) |
| 464 | 465 | ||
| 465 | add_custom_target(aicpu_kernels ALL DEPENDS ${ARM_SO_OUTPUT}) | 466 | add_custom_target(aicpu_kernels ALL DEPENDS ${ARM_SO_OUTPUT}) |
| @@ -619,7 +620,7 @@ function(gen_norm_symbol) | |||
| 619 | gen_opapi_symbol() | 620 | gen_opapi_symbol() |
| 620 | 621 | ||
| 621 | gen_onnx_plugin_symbol() | 622 | gen_onnx_plugin_symbol() |
| 622 | - | 623 | + |
| 623 | gen_tf_plugin_symbol() | 624 | gen_tf_plugin_symbol() |
| 624 | 625 | ||
| 625 | gen_aicpu_const_symbol() | 626 | gen_aicpu_const_symbol() |
| @@ -637,4 +638,4 @@ function(gen_cust_symbol) | |||
| 637 | gen_aicpu_json_symbol(FALSE) | 638 | gen_aicpu_json_symbol(FALSE) |
| 638 | 639 | ||
| 639 | gen_aicpu_kernel_symbol(FALSE) | 640 | gen_aicpu_kernel_symbol(FALSE) |
| 640 | -endfunction() | 641 | +endfunction() |
| @@ -13,4 +13,18 @@ | |||
| 13 | set(SUPPORT_COMPUTE_UNIT "ascend950") | 13 | set(SUPPORT_COMPUTE_UNIT "ascend950") |
| 14 | # 设置每种芯片类型对应的tiling文件目录,即采用op_host目录下哪个文件夹下的tiling文件编译 | 14 | # 设置每种芯片类型对应的tiling文件目录,即采用op_host目录下哪个文件夹下的tiling文件编译 |
| 15 | set(SUPPORT_TILING_DIR "arch35") | 15 | set(SUPPORT_TILING_DIR "arch35") |
| 16 | -add_all_modules_sources(OPTYPE trans_data ACLNNTYPE aclnn_exclude COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} TILING_DIR ${SUPPORT_TILING_DIR} DISABLE_IN_OPP TRUE) | 16 | +add_all_modules_sources(OPTYPE trans_data ACLNNTYPE aclnn_exclude COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} TILING_DIR ${SUPPORT_TILING_DIR} DISABLE_IN_OPP TRUE) |
| 17 | + | ||
| 18 | +# format_transfer 辅助源文件不匹配 *_aicpu.cpp glob,需显式追加到已创建的 OBJECT 目标 | ||
| 19 | +file(GLOB TRANS_DATA_FT_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/op_kernel_aicpu/format_transfer/*.cpp) | ||
| 20 | +if(TRANS_DATA_FT_SRCS) | ||
| 21 | + if(TARGET ${OPHOST_NAME}_aicpu_obj) | ||
| 22 | + target_sources(${OPHOST_NAME}_aicpu_obj PRIVATE ${TRANS_DATA_FT_SRCS}) | ||
| 23 | + endif() | ||
| 24 | + if(TARGET trans_data_obj) | ||
| 25 | + target_sources(trans_data_obj PRIVATE ${TRANS_DATA_FT_SRCS}) | ||
| 26 | + endif() | ||
| 27 | + if(TARGET trans_data_cases_obj) | ||
| 28 | + target_sources(trans_data_cases_obj PRIVATE ${TRANS_DATA_FT_SRCS}) | ||
| 29 | + endif() | ||
| 30 | +endif() | ||
| @@ -0,0 +1,318 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +using namespace std; | ||
| 20 | +using namespace ge; | ||
| 21 | + | ||
| 22 | +namespace aicpu { | ||
| 23 | +namespace formats { | ||
| 24 | +bool IsShapeValid(const vector<int64_t>& shape) | ||
| 25 | +{ | ||
| 26 | + if (shape.empty()) { | ||
| 27 | + return false; | ||
| 28 | + } | ||
| 29 | + int64_t num = 1; | ||
| 30 | + for (auto dim : shape) { | ||
| 31 | + if (dim < 0) { | ||
| 32 | + string error = "Invalid negative dims in the shape " + FmtToStr(VectorToString(shape)); | ||
| 33 | + KERNEL_LOG_ERROR("%s", error.c_str()); | ||
| 34 | + return false; | ||
| 35 | + } | ||
| 36 | + if (dim != 0 && kShapeItemNumMAX / dim < num) { | ||
| 37 | + string error = "Shape overflow, the total count should be less than " + FmtToStr(kShapeItemNumMAX); | ||
| 38 | + KERNEL_LOG_ERROR("%s", error.c_str()); | ||
| 39 | + return false; | ||
| 40 | + } | ||
| 41 | + num *= dim; | ||
| 42 | + } | ||
| 43 | + return true; | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +bool CheckShapeValid(const vector<int64_t>& shape, const int64_t expect_dims) | ||
| 47 | +{ | ||
| 48 | + if (expect_dims <= 0 || shape.size() != static_cast<size_t>(expect_dims)) { | ||
| 49 | + string error = "Invalid shape, dims num " + FmtToStr(shape.size()) + ", expect " + FmtToStr(expect_dims); | ||
| 50 | + KERNEL_LOG_ERROR("%s", error.c_str()); | ||
| 51 | + return false; | ||
| 52 | + } | ||
| 53 | + return IsShapeValid(shape); | ||
| 54 | +} | ||
| 55 | + | ||
| 56 | +int64_t GetCubeSizeByDataType(DataType data_type) | ||
| 57 | +{ | ||
| 58 | + // Current cube does not support 4 bytes and longer data | ||
| 59 | + auto size = GetSizeByDataType(data_type); | ||
| 60 | + if (size <= 0) { | ||
| 61 | + std::string error = "Failed to get cube size, the data type " + FmtToStr(DTypeStr(data_type)) + " is invalid"; | ||
| 62 | + KERNEL_LOG_ERROR("%s", error.c_str()); | ||
| 63 | + return -1; | ||
| 64 | + } else if (size == 1) { | ||
| 65 | + return kCubeSize * 2; // 32 bytes cube size | ||
| 66 | + } else { | ||
| 67 | + return kCubeSize; | ||
| 68 | + } | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +int64_t GetC0ValueForTransShape(DataType data_type, const int32_t format) | ||
| 72 | +{ | ||
| 73 | + if (ge::HasC0Format(format)) { | ||
| 74 | + return ge::GetC0Value(format); | ||
| 75 | + } else { | ||
| 76 | + return GetCubeSizeByDataType(data_type); | ||
| 77 | + } | ||
| 78 | +} | ||
| 79 | + | ||
| 80 | +int64_t GetC0ValueForTransFormat(DataType data_type, const int32_t input_format, const int32_t output_format) | ||
| 81 | +{ | ||
| 82 | + if (ge::HasC0Format(input_format)) { | ||
| 83 | + return ge::GetC0Value(input_format); | ||
| 84 | + } else if (ge::HasC0Format(output_format)) { | ||
| 85 | + return ge::GetC0Value(output_format); | ||
| 86 | + } else { | ||
| 87 | + return GetCubeSizeByDataType(data_type); | ||
| 88 | + } | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +bool IsTransShapeSrcCorrect(const TransArgs& args, std::vector<int64_t>& expect_shape) | ||
| 92 | +{ | ||
| 93 | + if (args.src_shape != expect_shape) { | ||
| 94 | + string error = "Failed to trans format from" + FmtToStr(FormatToSerialString(args.src_format)) + " to " + | ||
| 95 | + FmtToStr(FormatToSerialString(args.dst_format)) + ", invalid relationship between src shape " + | ||
| 96 | + FmtToStr(VectorToString(args.src_shape)) + " and dst " + | ||
| 97 | + FmtToStr(VectorToString(args.dst_shape)); | ||
| 98 | + KERNEL_LOG_ERROR("%s", error.c_str()); | ||
| 99 | + return false; | ||
| 100 | + } | ||
| 101 | + return true; | ||
| 102 | +} | ||
| 103 | + | ||
| 104 | +bool IsTransShapeDstCorrect(const TransArgs& args, vector<int64_t>& expect_shape) | ||
| 105 | +{ | ||
| 106 | + if (!args.dst_shape.empty() && args.dst_shape != expect_shape) { | ||
| 107 | + string error = "Failed to trans format from " + FmtToStr(FormatToSerialString(args.src_format)) + " to " + | ||
| 108 | + FmtToStr(FormatToSerialString(args.dst_format)) + ", the dst shape" + | ||
| 109 | + FmtToStr(VectorToString(args.dst_shape)) + " is invalid, expect" + | ||
| 110 | + FmtToStr(VectorToString(expect_shape)); | ||
| 111 | + KERNEL_LOG_ERROR("%s", error.c_str()); | ||
| 112 | + return false; | ||
| 113 | + } | ||
| 114 | + return true; | ||
| 115 | +} | ||
| 116 | + | ||
| 117 | +int64_t GetItemNumByShape(const vector<int64_t>& shape) | ||
| 118 | +{ | ||
| 119 | + // shape will not be greater than INT_MAX | ||
| 120 | + int64_t num = 1; | ||
| 121 | + for (auto dim : shape) { | ||
| 122 | + num *= dim; | ||
| 123 | + } | ||
| 124 | + return num; | ||
| 125 | +} | ||
| 126 | + | ||
| 127 | +uint32_t TransFormat(const TransArgs& args) | ||
| 128 | +{ | ||
| 129 | + auto transfer = BuildFormatTransfer(args); | ||
| 130 | + if (transfer == nullptr) { | ||
| 131 | + string error = "Failed to trans data from format " + FmtToStr(FormatToSerialString(args.src_format)) + " to " + | ||
| 132 | + FmtToStr(FormatToSerialString(args.dst_format)); | ||
| 133 | + KERNEL_LOG_WARN("%s", error.c_str()); | ||
| 134 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + auto src_shape_size = GetItemNumByShape(args.src_shape); | ||
| 138 | + if (args.data == nullptr && src_shape_size != 0) { | ||
| 139 | + KERNEL_LOG_WARN("Invalid input null data"); | ||
| 140 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + return transfer->TransFormat(args); | ||
| 144 | +} | ||
| 145 | + | ||
| 146 | +int64_t Measure(int64_t x, int64_t y) | ||
| 147 | +{ | ||
| 148 | + if (y == 0) { | ||
| 149 | + return 1; | ||
| 150 | + } | ||
| 151 | + int64_t z = y; | ||
| 152 | + while (x % y != 0) { | ||
| 153 | + z = x % y; | ||
| 154 | + x = y; | ||
| 155 | + y = z; | ||
| 156 | + } | ||
| 157 | + return z; | ||
| 158 | +} | ||
| 159 | +// least common multiple | ||
| 160 | +int64_t Lcm(int64_t a, int64_t b) | ||
| 161 | +{ | ||
| 162 | + if (b == 0) { | ||
| 163 | + return -1; | ||
| 164 | + } | ||
| 165 | + int64_t temp = (a * b) / (Measure(a, b)); | ||
| 166 | + return temp; | ||
| 167 | +} | ||
| 168 | + | ||
| 169 | +void copy_data(const uint8_t* input_data, uint8_t* dst, int64_t src_index, int64_t dst_index, int64_t data_size) | ||
| 170 | +{ | ||
| 171 | + auto ret = memcpy_s(dst + dst_index * data_size, static_cast<size_t>(data_size), input_data + src_index * data_size, | ||
| 172 | + static_cast<size_t>(data_size)); | ||
| 173 | + if (ret != EOK) { | ||
| 174 | + KERNEL_LOG_ERROR("memcpy_s failed, ret [%d].", ret); | ||
| 175 | + } | ||
| 176 | +} | ||
| 177 | + | ||
| 178 | +KernelStatus CheckDimOri(int64_t cin_ori, int64_t cout_ori) | ||
| 179 | +{ | ||
| 180 | + if (cin_ori == 0 || cout_ori == 0) { | ||
| 181 | + KERNEL_LOG_ERROR("Cin_ori, cout_ori must not be equal 0, and current cin_ori is [%ld], " | ||
| 182 | + "cout_ori is [%ld]", | ||
| 183 | + cin_ori, cout_ori); | ||
| 184 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 185 | + } | ||
| 186 | + return KERNEL_STATUS_OK; | ||
| 187 | +} | ||
| 188 | + | ||
| 189 | +uint32_t Prepare4dFormatBasics(const Format& format_4d, const std::vector<int64_t>& shape_4d, const TransArgs& args, | ||
| 190 | + Format4dBasics& out) | ||
| 191 | +{ | ||
| 192 | + out.d_dim = 1; | ||
| 193 | + out.h_dim = 0; | ||
| 194 | + out.w_dim = 0; | ||
| 195 | + out.c_dim = 0; | ||
| 196 | + out.n_dim = 0; | ||
| 197 | + if (GetFormatDim(out.d_dim, out.h_dim, out.w_dim, out.c_dim, out.n_dim, format_4d, shape_4d) != KERNEL_STATUS_OK) { | ||
| 198 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 199 | + } | ||
| 200 | + out.data_type = args.src_data_type; | ||
| 201 | + out.c0 = GetC0ValueForTransFormat(out.data_type, args.input_format, args.output_format); | ||
| 202 | + out.data_size = GetSizeByDataType(out.data_type); | ||
| 203 | + out.dst_size = GetItemNumByShape(args.dst_shape) * out.data_size; | ||
| 204 | + return KERNEL_STATUS_OK; | ||
| 205 | +} | ||
| 206 | + | ||
| 207 | +uint32_t ComputeCinCoutOri(int64_t n, int64_t c, int64_t groups, int64_t cube_k, int64_t& cin_ori, int64_t& cout_ori) | ||
| 208 | +{ | ||
| 209 | + if (groups == 0 || cube_k == 0) { | ||
| 210 | + KERNEL_LOG_ERROR("Groups and cube_k must not be equal to 0, now [%ld] [%ld]", groups, cube_k); | ||
| 211 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 212 | + } | ||
| 213 | + cin_ori = c; | ||
| 214 | + // groups is not equal to 0, which had been checked above. | ||
| 215 | + cout_ori = n / groups; | ||
| 216 | + if (cin_ori == 0 || cout_ori == 0) { | ||
| 217 | + KERNEL_LOG_ERROR("Cin_ori, cout_ori must not be equal 0, " | ||
| 218 | + "and current cin_ori, cout_ori, groups are [%ld] [%ld] [%ld]", | ||
| 219 | + cin_ori, cout_ori, groups); | ||
| 220 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 221 | + } | ||
| 222 | + return KERNEL_STATUS_OK; | ||
| 223 | +} | ||
| 224 | + | ||
| 225 | +uint32_t BuildFzWithGroupsShape(int64_t n, int64_t c, int64_t spatial_dim, int64_t cube_k, int64_t groups, | ||
| 226 | + std::vector<int64_t>& dst_shape) | ||
| 227 | +{ | ||
| 228 | + int64_t cin_ori = 0; | ||
| 229 | + int64_t cout_ori = 0; | ||
| 230 | + if (ComputeCinCoutOri(n, c, groups, cube_k, cin_ori, cout_ori) != KERNEL_STATUS_OK) { | ||
| 231 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 232 | + } | ||
| 233 | + // ComputeCinCoutOri guarantees cube_k > 0 and cin_ori/cout_ori > 0 on success; | ||
| 234 | + // reassert locally to satisfy static analyzers on the divisions below. | ||
| 235 | + if (cube_k == 0 || cin_ori == 0 || cout_ori == 0) { | ||
| 236 | + KERNEL_LOG_ERROR("Invalid cube_k/cin_ori/cout_ori [%ld] [%ld] [%ld].", cube_k, cin_ori, cout_ori); | ||
| 237 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 238 | + } | ||
| 239 | + if (cube_k == 0) { | ||
| 240 | + KERNEL_LOG_ERROR("cube_k must not be 0."); | ||
| 241 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 242 | + } | ||
| 243 | + if (cin_ori == 0 || cout_ori == 0) { | ||
| 244 | + KERNEL_LOG_ERROR("cin_ori/cout_ori must not be 0."); | ||
| 245 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 246 | + } | ||
| 247 | + const int64_t e_mult = std::min( | ||
| 248 | + Lcm(Lcm(cin_ori, cube_k) / cin_ori, Lcm(cout_ori, static_cast<int64_t>(kCubeSize)) / cout_ori), groups); | ||
| 249 | + if (e_mult == 0) { | ||
| 250 | + KERNEL_LOG_ERROR("e_mult must not be 0."); | ||
| 251 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 252 | + } | ||
| 253 | + const int64_t cin_opt = Ceil(e_mult * cin_ori, cube_k) * cube_k; | ||
| 254 | + const int64_t c1_dim = cin_opt / cube_k; | ||
| 255 | + const int64_t g_dim = Ceil(groups, e_mult); | ||
| 256 | + const int64_t n1 = Ceil(cout_ori * e_mult, static_cast<int64_t>(kCubeSize)); | ||
| 257 | + dst_shape.clear(); | ||
| 258 | + dst_shape.push_back(g_dim * c1_dim * spatial_dim); | ||
| 259 | + dst_shape.push_back(n1); | ||
| 260 | + dst_shape.push_back(kNiSize); | ||
| 261 | + dst_shape.push_back(cube_k); | ||
| 262 | + if (!IsShapeValid(dst_shape)) { | ||
| 263 | + KERNEL_LOG_ERROR("Check shape failed, dst shape [%s]", VectorToString(dst_shape).c_str()); | ||
| 264 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 265 | + } | ||
| 266 | + return KERNEL_STATUS_OK; | ||
| 267 | +} | ||
| 268 | + | ||
| 269 | +KernelStatus GetFormatDim(int64_t& d_dim, int64_t& h_dim, int64_t& w_dim, int64_t& c_dim, int64_t& n_dim, | ||
| 270 | + const Format& input_format, const std::vector<int64_t>& dims) | ||
| 271 | +{ | ||
| 272 | + if (input_format == FORMAT_NCDHW) { | ||
| 273 | + n_dim = dims[kNcdhwN]; | ||
| 274 | + c_dim = dims[kNcdhwC]; | ||
| 275 | + d_dim = dims[kNcdhwD]; | ||
| 276 | + h_dim = dims[kNcdhwH]; | ||
| 277 | + w_dim = dims[kNcdhwW]; | ||
| 278 | + } else if (input_format == FORMAT_DHWCN) { | ||
| 279 | + d_dim = dims[kDhwcnD]; | ||
| 280 | + h_dim = dims[kDhwcnH]; | ||
| 281 | + w_dim = dims[kDhwcnW]; | ||
| 282 | + c_dim = dims[kDhwcnC]; | ||
| 283 | + n_dim = dims[kDhwcnN]; | ||
| 284 | + } else if (input_format == FORMAT_NDHWC) { | ||
| 285 | + n_dim = dims[kNdhwcN]; | ||
| 286 | + d_dim = dims[kNdhwcD]; | ||
| 287 | + h_dim = dims[kNdhwcH]; | ||
| 288 | + w_dim = dims[kNdhwcW]; | ||
| 289 | + c_dim = dims[kNdhwcC]; | ||
| 290 | + } else if (input_format == FORMAT_NHWC) { | ||
| 291 | + n_dim = dims[kNhwcN]; | ||
| 292 | + h_dim = dims[kNhwcH]; | ||
| 293 | + d_dim = 1; | ||
| 294 | + w_dim = dims[kNhwcW]; | ||
| 295 | + c_dim = dims[kNhwcC]; | ||
| 296 | + } else if (input_format == FORMAT_NCHW) { | ||
| 297 | + n_dim = dims[kNchwN]; | ||
| 298 | + c_dim = dims[kNchwC]; | ||
| 299 | + h_dim = dims[kNchwH]; | ||
| 300 | + w_dim = dims[kNchwW]; | ||
| 301 | + d_dim = 1; | ||
| 302 | + } else if (input_format == FORMAT_HWCN) { | ||
| 303 | + h_dim = dims[kHwcnH]; | ||
| 304 | + w_dim = dims[kHwcnW]; | ||
| 305 | + c_dim = dims[kHwcnC]; | ||
| 306 | + n_dim = dims[kHwcnN]; | ||
| 307 | + d_dim = 1; | ||
| 308 | + } else { | ||
| 309 | + KERNEL_LOG_WARN("Format is not FORMAT_DHWCN or FORMAT_NDHWC or FORMAT_NCDHW or " | ||
| 310 | + "FORMAT_NHWC or FORMAT_NCHW or FORMAT_HWCN, current input " | ||
| 311 | + "format is [%d]", | ||
| 312 | + static_cast<int32_t>(input_format)); | ||
| 313 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 314 | + } | ||
| 315 | + return KERNEL_STATUS_OK; | ||
| 316 | +} | ||
| 317 | +} // namespace formats | ||
| 318 | +} // namespace aicpu | ||
| @@ -0,0 +1,113 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace aicpu { | ||
| 21 | +namespace formats { | ||
| 22 | +static const int kCubeSize = 16; | ||
| 23 | +static const int kNiSize = 16; | ||
| 24 | +static const int kC0 = 4; | ||
| 25 | +static const int64_t kShapeItemNumMAX = 1024UL * 1024UL * 1024UL * 1024UL; | ||
| 26 | +int64_t Measure(int64_t x, int64_t y); | ||
| 27 | +int64_t Lcm(int64_t a, int64_t b); | ||
| 28 | +bool IsShapeValid(const std::vector<int64_t>& shape); | ||
| 29 | + | ||
| 30 | +bool CheckShapeValid(const std::vector<int64_t>& shape, const int64_t expect_dims); | ||
| 31 | + | ||
| 32 | +int64_t GetC0ValueForTransShape(DataType data_type, const int32_t format); | ||
| 33 | + | ||
| 34 | +int64_t GetC0ValueForTransFormat(DataType data_type, const int32_t input_format, const int32_t output_format); | ||
| 35 | + | ||
| 36 | +int64_t GetCubeSizeByDataType(DataType data_type); | ||
| 37 | + | ||
| 38 | +bool IsTransShapeSrcCorrect(const TransArgs& args, std::vector<int64_t>& expect_shape); | ||
| 39 | + | ||
| 40 | +bool IsTransShapeDstCorrect(const TransArgs& args, std::vector<int64_t>& expect_shape); | ||
| 41 | + | ||
| 42 | +int64_t GetItemNumByShape(const std::vector<int64_t>& shape); | ||
| 43 | + | ||
| 44 | +void copy_data(const uint8_t* input_data, uint8_t* dst, int64_t src_index, int64_t dst_index, int64_t data_size); | ||
| 45 | + | ||
| 46 | +KernelStatus GetFormatDim(int64_t& d_dim, int64_t& h_dim, int64_t& w_dim, int64_t& c_dim, int64_t& n_dim, | ||
| 47 | + const Format& input_format, const std::vector<int64_t>& dims); | ||
| 48 | +KernelStatus CheckDimOri(int64_t cin_ori, int64_t cout_ori); | ||
| 49 | + | ||
| 50 | +// Shared 4D-format preamble used by TransFormatToC1hwc0 / TransFormatToWINO. | ||
| 51 | +struct Format4dBasics { | ||
| 52 | + int64_t d_dim; | ||
| 53 | + int64_t h_dim; | ||
| 54 | + int64_t w_dim; | ||
| 55 | + int64_t c_dim; | ||
| 56 | + int64_t n_dim; | ||
| 57 | + DataType data_type; | ||
| 58 | + int64_t c0; | ||
| 59 | + int64_t data_size; | ||
| 60 | + int64_t dst_size; | ||
| 61 | +}; | ||
| 62 | +uint32_t Prepare4dFormatBasics(const Format& format_4d, const std::vector<int64_t>& shape_4d, const TransArgs& args, | ||
| 63 | + Format4dBasics& out); | ||
| 64 | + | ||
| 65 | +// Shared groups/cube_k/cin/cout validation used by TransShapeToFz*WithGroups. | ||
| 66 | +uint32_t ComputeCinCoutOri(int64_t n, int64_t c, int64_t groups, int64_t cube_k, int64_t& cin_ori, int64_t& cout_ori); | ||
| 67 | + | ||
| 68 | +// Shared shape builder for both TransShapeToFzWithGroups (fractal_z, spatial_dim = h*w) | ||
| 69 | +// and TransShapeToFz3DWithGroups (fractalz_3d, spatial_dim = d*h*w). | ||
| 70 | +uint32_t BuildFzWithGroupsShape(int64_t n, int64_t c, int64_t spatial_dim, int64_t cube_k, int64_t groups, | ||
| 71 | + std::vector<int64_t>& dst_shape); | ||
| 72 | + | ||
| 73 | +// Shared grouped-format loop skeleton used by TransFormatWithGroups in fractal_z / fractalz_3d. | ||
| 74 | +template <typename Ctx, typename CopyHwSliceFn> | ||
| 75 | +uint32_t RunGroupedFormatTransfer(const TransArgs& args, const Ctx& ctx, CopyHwSliceFn copy_hw_slice) | ||
| 76 | +{ | ||
| 77 | + if (ctx.dst_size == 0) { | ||
| 78 | + return KERNEL_STATUS_OK; | ||
| 79 | + } | ||
| 80 | + if (!BiggerMemSet(args.output, static_cast<size_t>(ctx.dst_size), 0, static_cast<size_t>(ctx.dst_size))) { | ||
| 81 | + KERNEL_LOG_ERROR("BiggerMemSet failed, size [%ld].", ctx.dst_size); | ||
| 82 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 83 | + } | ||
| 84 | + for (int64_t g = 0; g < args.groups; g++) { | ||
| 85 | + for (int64_t d = 0; d < ctx.d_dim; d++) { | ||
| 86 | + for (int64_t c = 0; c < ctx.c_dim; c++) { | ||
| 87 | + copy_hw_slice(g, d, c); | ||
| 88 | + } | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + return KERNEL_STATUS_OK; | ||
| 92 | +} | ||
| 93 | + | ||
| 94 | +template <typename T> | ||
| 95 | +T Ceil(T n1, T n2) | ||
| 96 | +{ | ||
| 97 | + if (n1 == 0) { | ||
| 98 | + return 0; | ||
| 99 | + } | ||
| 100 | + return (n2 != 0) ? (n1 - 1) / n2 + 1 : 0; | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +/** | ||
| 104 | + * Convert the data format, and put the converted format and length in the | ||
| 105 | + * result | ||
| 106 | + * @param args | ||
| 107 | + * @param result | ||
| 108 | + * @return | ||
| 109 | + */ | ||
| 110 | +uint32_t TransFormat(const TransArgs& args); | ||
| 111 | +} // namespace formats | ||
| 112 | +} // namespace aicpu | ||
| 113 | + | ||
| @@ -0,0 +1,55 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +namespace aicpu { | ||
| 15 | +namespace formats { | ||
| 16 | +enum NchwDimIndex { kNchwN, kNchwC, kNchwH, kNchwW, kNchwDimsNum }; | ||
| 17 | + | ||
| 18 | +enum NhwcDimIndex { kNhwcN, kNhwcH, kNhwcW, kNhwcC, kNhwcDimsNum }; | ||
| 19 | + | ||
| 20 | +enum HwcnDimIndex { kHwcnH, kHwcnW, kHwcnC, kHwcnN, kHwcnDimsNum }; | ||
| 21 | + | ||
| 22 | +enum ChwnDimIndex { kChwnC, kChwnH, kChwnW, kChwnN, kChwnDimsNum }; | ||
| 23 | + | ||
| 24 | +enum Nc1hwc0DimIndex { kNc1hwc0N, kNc1hwc0C1, kNc1hwc0H, kNc1hwc0W, kNc1hwc0C0, kNc1hwc0DimsNum }; | ||
| 25 | + | ||
| 26 | +enum C1hwncoc0DimIndex { | ||
| 27 | + kC1hwncoc0C1, | ||
| 28 | + kC1hwncoc0H, | ||
| 29 | + kC1hwncoc0W, | ||
| 30 | + kC1hwncoc0N, | ||
| 31 | + kC1hwncoc0Co, | ||
| 32 | + kC1hwncoc0C0, | ||
| 33 | + kC1hwncoc0DimsNum | ||
| 34 | +}; | ||
| 35 | + | ||
| 36 | +enum FracZDimIndex { kFracZHWC1, kFracZN0, kFracZNi, kFracZC0, kFracZDimsNum }; | ||
| 37 | + | ||
| 38 | +enum DhwcnDimIndex { kDhwcnD, kDhwcnH, kDhwcnW, kDhwcnC, kDhwcnN, kDhwcnDimsNum }; | ||
| 39 | + | ||
| 40 | +enum NcdhwDimIndex { kNcdhwN, kNcdhwC, kNcdhwD, kNcdhwH, kNcdhwW, kNcdhwDimsNum }; | ||
| 41 | + | ||
| 42 | +enum NdhwcDimIndex { kNdhwcN, kNdhwcD, kNdhwcH, kNdhwcW, kNdhwcC, kNdhwcDimsNum }; | ||
| 43 | + | ||
| 44 | +enum FracZWinoDimIndex { | ||
| 45 | + kFracZWinoC1, | ||
| 46 | + kFracZWinoN1, | ||
| 47 | + kFracZWinoN0_2, | ||
| 48 | + kFracZWinoHW, | ||
| 49 | + kFracZWinoN0_8, | ||
| 50 | + kFracZWinoC0, | ||
| 51 | + kFracZWinoDimsNum | ||
| 52 | +}; | ||
| 53 | +} // namespace formats | ||
| 54 | +} // namespace aicpu | ||
| 55 | + | ||
| @@ -0,0 +1,63 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +using namespace std; | ||
| 15 | + | ||
| 16 | +namespace aicpu { | ||
| 17 | +namespace formats { | ||
| 18 | +namespace { | ||
| 19 | +struct FormatTransferRegistry { | ||
| 20 | + void RegisterBuilder(Format src, Format dst, FormatTransferBuilder builder) | ||
| 21 | + { | ||
| 22 | + src_dst_builder[src][dst] = std::move(builder); | ||
| 23 | + } | ||
| 24 | + map<Format, map<Format, FormatTransferBuilder>> src_dst_builder; | ||
| 25 | +}; | ||
| 26 | + | ||
| 27 | +FormatTransferRegistry& GetFormatTransferRegistry() | ||
| 28 | +{ | ||
| 29 | + static FormatTransferRegistry registry; | ||
| 30 | + return registry; | ||
| 31 | +} | ||
| 32 | +} // namespace | ||
| 33 | + | ||
| 34 | +FormatTransferRegister::FormatTransferRegister(FormatTransferBuilder builder, Format src, Format dst) | ||
| 35 | +{ | ||
| 36 | + GetFormatTransferRegistry().RegisterBuilder(src, dst, std::move(builder)); | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +shared_ptr<FormatTransfer> BuildFormatTransfer(const TransArgs& args) | ||
| 40 | +{ | ||
| 41 | + auto& registry = GetFormatTransferRegistry(); | ||
| 42 | + auto dst_builder = registry.src_dst_builder.find(args.src_format); | ||
| 43 | + if (dst_builder == registry.src_dst_builder.end()) { | ||
| 44 | + return nullptr; | ||
| 45 | + } | ||
| 46 | + auto builder_iter = dst_builder->second.find(args.dst_format); | ||
| 47 | + if (builder_iter == dst_builder->second.end()) { | ||
| 48 | + return nullptr; | ||
| 49 | + } | ||
| 50 | + return builder_iter->second(); | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +bool FormatTransferExists(const TransArgs& args) | ||
| 54 | +{ | ||
| 55 | + auto& registry = GetFormatTransferRegistry(); | ||
| 56 | + auto dst_builder = registry.src_dst_builder.find(args.src_format); | ||
| 57 | + if (dst_builder == registry.src_dst_builder.end()) { | ||
| 58 | + return false; | ||
| 59 | + } | ||
| 60 | + return dst_builder->second.count(args.dst_format) > 0; | ||
| 61 | +} | ||
| 62 | +} // namespace formats | ||
| 63 | +} // namespace aicpu | ||
| @@ -0,0 +1,74 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +namespace aicpu { | ||
| 21 | +namespace formats { | ||
| 22 | +struct TransArgs { | ||
| 23 | + const uint8_t* data; | ||
| 24 | + uint8_t* output; | ||
| 25 | + // format from GetFormat | ||
| 26 | + const int32_t input_format; | ||
| 27 | + const int32_t output_format; | ||
| 28 | + // primary format | ||
| 29 | + Format src_format; | ||
| 30 | + Format dst_format; | ||
| 31 | + // For scenes that need to supplement the shape, for example, 5D to 4D | ||
| 32 | + // It is not possible to convert the format normally if you only get the | ||
| 33 | + // src_shape, and must get the shape before you mend the shape. So the | ||
| 34 | + // parameters here need to be passed in both src_shape and dst_shape | ||
| 35 | + std::vector<int64_t> src_shape; | ||
| 36 | + std::vector<int64_t> dst_shape; | ||
| 37 | + DataType src_data_type; | ||
| 38 | + int64_t groups; | ||
| 39 | + const CpuKernelContext* ctx; | ||
| 40 | +}; | ||
| 41 | + | ||
| 42 | +class FormatTransfer { | ||
| 43 | +public: | ||
| 44 | + virtual ~FormatTransfer() = default; | ||
| 45 | + virtual uint32_t TransFormat(const TransArgs& args) = 0; | ||
| 46 | + virtual uint32_t TransShape(const TransArgs& args, std::vector<int64_t>& dst_shape, bool reverse) = 0; | ||
| 47 | +}; | ||
| 48 | + | ||
| 49 | +using FormatTransferBuilder = std::function<std::shared_ptr<FormatTransfer>()>; | ||
| 50 | + | ||
| 51 | +class FormatTransferRegister { | ||
| 52 | +public: | ||
| 53 | + FormatTransferRegister(FormatTransferBuilder builder, Format src, Format dst); | ||
| 54 | + ~FormatTransferRegister() = default; | ||
| 55 | +}; | ||
| 56 | + | ||
| 57 | + | ||
| 58 | + namespace { \ | ||
| 59 | + FormatTransferRegister format_transfer_register_##TransferClass##format1##format2( \ | ||
| 60 | + []() { return std::make_shared<TransferClass>(); }, format1, format2); \ | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | +/** | ||
| 64 | + * Build a FormatTransfer according to 'args' | ||
| 65 | + * @param args | ||
| 66 | + * @param result | ||
| 67 | + * @return | ||
| 68 | + */ | ||
| 69 | +std::shared_ptr<FormatTransfer> BuildFormatTransfer(const TransArgs& args); | ||
| 70 | + | ||
| 71 | +bool FormatTransferExists(const TransArgs& args); | ||
| 72 | +} // namespace formats | ||
| 73 | +} // namespace aicpu | ||
| 74 | + | ||
| @@ -0,0 +1,717 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +using namespace std; | ||
| 25 | + | ||
| 26 | +namespace { | ||
| 27 | +const char* const kTransData = "TransData"; | ||
| 28 | +constexpr int64_t kDimN0 = 16; | ||
| 29 | +constexpr int64_t kCubeN = 16; | ||
| 30 | +constexpr int64_t kGroupNum = 1; | ||
| 31 | +constexpr int64_t kMaxDimsNumC = 4; | ||
| 32 | +constexpr size_t kMinInputDimsNum = 4; | ||
| 33 | +constexpr int32_t kCubeSize = 16; | ||
| 34 | +constexpr int32_t kShapeOffset = 2; | ||
| 35 | + | ||
| 36 | +using aicpu::DTypeStr; | ||
| 37 | +using aicpu::FormatToSerialString; | ||
| 38 | +using aicpu::GetPrimaryFormat; | ||
| 39 | +using aicpu::GetSizeByDataType; | ||
| 40 | +using aicpu::KERNEL_STATUS_INNER_ERROR; | ||
| 41 | +using aicpu::KERNEL_STATUS_OK; | ||
| 42 | +using aicpu::KERNEL_STATUS_PARAM_INVALID; | ||
| 43 | +using aicpu::formats::Lcm; | ||
| 44 | + | ||
| 45 | +template <typename T> | ||
| 46 | +std::string VectorToString(const std::vector<T>& vec) | ||
| 47 | +{ | ||
| 48 | + std::stringstream ss; | ||
| 49 | + bool first = true; | ||
| 50 | + for (auto& ele : vec) { | ||
| 51 | + if (first) { | ||
| 52 | + first = false; | ||
| 53 | + } else { | ||
| 54 | + ss << ","; | ||
| 55 | + } | ||
| 56 | + ss << ele; | ||
| 57 | + } | ||
| 58 | + return ss.str(); | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +int64_t VectorToNum(const std::vector<int64_t>& vec) | ||
| 62 | +{ | ||
| 63 | + int64_t result = 1; | ||
| 64 | + for (auto& ele : vec) { | ||
| 65 | + result *= ele; | ||
| 66 | + } | ||
| 67 | + return result; | ||
| 68 | +} | ||
| 69 | + | ||
| 70 | +void TransShapeByPerm(const std::vector<int64_t>& src_shape, const std::vector<int64_t>& perm_arg, | ||
| 71 | + std::vector<int64_t>& dst_shape) | ||
| 72 | +{ | ||
| 73 | + dst_shape.resize(src_shape.size()); | ||
| 74 | + for (size_t i = 0; i < perm_arg.size(); ++i) { | ||
| 75 | + dst_shape[i] = src_shape[perm_arg[i]]; | ||
| 76 | + } | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +void GetIndexMap(const std::vector<int64_t>& perm_arg, std::map<int32_t, int32_t>& index_map) | ||
| 80 | +{ | ||
| 81 | + for (size_t i = 0; i < perm_arg.size(); i++) { | ||
| 82 | + index_map[perm_arg[i]] = static_cast<int32_t>(i); | ||
| 83 | + } | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +void GetShapeHead(const std::vector<int64_t>& shape, std::vector<int64_t>& shape_head) | ||
| 87 | +{ | ||
| 88 | + shape_head.resize(shape.size()); | ||
| 89 | + shape_head[shape.size() - 1] = 1; | ||
| 90 | + for (int i = static_cast<int>(shape.size() - kShapeOffset); i >= 0; i--) { | ||
| 91 | + shape_head[i] = shape_head[i + 1] * shape[i + 1]; | ||
| 92 | + } | ||
| 93 | +} | ||
| 94 | + | ||
| 95 | +int32_t GetSrcIndex(int64_t dst_index, const std::vector<int64_t>& src_shape, const std::vector<int64_t>& dst_shape, | ||
| 96 | + const std::vector<int64_t>& src_shape_head, const std::vector<int64_t>& dst_shape_head, | ||
| 97 | + std::map<int32_t, int32_t> index_map) | ||
| 98 | +{ | ||
| 99 | + std::vector<int32_t> src_vec(dst_shape.size()); | ||
| 100 | + for (size_t i = 0; i < dst_shape.size(); i++) { | ||
| 101 | + src_vec[i] = dst_index / dst_shape_head[i]; | ||
| 102 | + dst_index = dst_index % dst_shape_head[i]; | ||
| 103 | + } | ||
| 104 | + int32_t src_index = 0; | ||
| 105 | + for (size_t i = 0; i < src_shape.size(); i++) { | ||
| 106 | + src_index += static_cast<int32_t>(src_shape_head[i] * src_vec[index_map[i]]); | ||
| 107 | + } | ||
| 108 | + return src_index; | ||
| 109 | +} | ||
| 110 | + | ||
| 111 | +// get the result of two number divisor and let result round up | ||
| 112 | +static int64_t Ceil(int64_t a, int64_t b) | ||
| 113 | +{ | ||
| 114 | + if (b == 0) { | ||
| 115 | + return -1; | ||
| 116 | + } else { | ||
| 117 | + int64_t ret = a / b; | ||
| 118 | + if ((a % b) != 0) { | ||
| 119 | + ret++; | ||
| 120 | + } | ||
| 121 | + return ret; | ||
| 122 | + } | ||
| 123 | +} | ||
| 124 | + | ||
| 125 | +struct TransDataTensorInfo { | ||
| 126 | + uint8_t* data; | ||
| 127 | + aicpu::DataType data_type; | ||
| 128 | + std::vector<int64_t> dims; | ||
| 129 | + aicpu::Format format; | ||
| 130 | +}; | ||
| 131 | + | ||
| 132 | +uint32_t ExtractTensorInfo(aicpu::Tensor* tensor, TransDataTensorInfo& info, const char* who) | ||
| 133 | +{ | ||
| 134 | + KERNEL_CHECK_NULLPTR(tensor, KERNEL_STATUS_PARAM_INVALID, "%s get tensor failed, tensor is nullptr.", who); | ||
| 135 | + info.data = reinterpret_cast<uint8_t*>(tensor->GetData()); | ||
| 136 | + info.data_type = tensor->GetDataType(); | ||
| 137 | + auto shape = tensor->GetTensorShape(); | ||
| 138 | + KERNEL_CHECK_NULLPTR(shape, KERNEL_STATUS_PARAM_INVALID, "%s get shape failed, shape is nullptr.", who); | ||
| 139 | + info.dims = shape->GetDimSizes(); | ||
| 140 | + info.format = shape->GetFormat(); | ||
| 141 | + return KERNEL_STATUS_OK; | ||
| 142 | +} | ||
| 143 | + | ||
| 144 | +struct DealDataCtx { | ||
| 145 | + aicpu::Format input_format; | ||
| 146 | + int64_t d_dim; | ||
| 147 | + int64_t h_dim; | ||
| 148 | + int64_t w_dim; | ||
| 149 | + int64_t c_dim; | ||
| 150 | + int64_t n_dim; | ||
| 151 | + int64_t cin_ori; | ||
| 152 | + int64_t cout_ori; | ||
| 153 | + int64_t cube_k; | ||
| 154 | + int64_t e_mult; | ||
| 155 | + int64_t cout_opt; | ||
| 156 | + int64_t c1_dim; | ||
| 157 | + int64_t size_output_data; | ||
| 158 | +}; | ||
| 159 | + | ||
| 160 | +uint32_t BuildDealDataCtx(const aicpu::Tensor* input_tensor, int64_t group, int64_t cube_k, DealDataCtx& c) | ||
| 161 | +{ | ||
| 162 | + if (group == 0) { | ||
| 163 | + KERNEL_LOG_ERROR("Group must not be equal to 0"); | ||
| 164 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 165 | + } | ||
| 166 | + if (cube_k == 0) { | ||
| 167 | + KERNEL_LOG_ERROR("Cube_k must not be equal to 0, data type [%s]", | ||
| 168 | + DTypeStr(static_cast<aicpu::DataType>(input_tensor->GetDataType())).c_str()); | ||
| 169 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 170 | + } | ||
| 171 | + auto input_shape = input_tensor->GetTensorShape(); | ||
| 172 | + const aicpu::Format ge_input_format = input_shape->GetFormat(); | ||
| 173 | + c.input_format = static_cast<aicpu::Format>(GetPrimaryFormat(static_cast<int32_t>(ge_input_format))); | ||
| 174 | + std::vector<int64_t> dims = input_shape->GetDimSizes(); | ||
| 175 | + c.d_dim = 0; | ||
| 176 | + c.h_dim = 0; | ||
| 177 | + c.w_dim = 0; | ||
| 178 | + c.c_dim = 0; | ||
| 179 | + c.n_dim = 0; | ||
| 180 | + if (aicpu::formats::GetFormatDim(c.d_dim, c.h_dim, c.w_dim, c.c_dim, c.n_dim, c.input_format, dims) != | ||
| 181 | + KERNEL_STATUS_OK) { | ||
| 182 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 183 | + } | ||
| 184 | + c.cin_ori = c.c_dim; | ||
| 185 | + c.cout_ori = c.n_dim / group; | ||
| 186 | + if (aicpu::formats::CheckDimOri(c.cin_ori, c.cout_ori) != KERNEL_STATUS_OK) { | ||
| 187 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 188 | + } | ||
| 189 | + c.cube_k = cube_k; | ||
| 190 | + c.e_mult = std::min(Lcm(Lcm(c.cin_ori, cube_k) / (c.cin_ori), Lcm(c.cout_ori, kCubeN) / (c.cout_ori)), group); | ||
| 191 | + if (c.e_mult == 0) { | ||
| 192 | + KERNEL_LOG_ERROR("E_mult must not be equal to 0"); | ||
| 193 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 194 | + } | ||
| 195 | + const int64_t cin_opt = Ceil(c.e_mult * c.cin_ori, cube_k) * cube_k; | ||
| 196 | + c.cout_opt = Ceil(c.e_mult * c.cout_ori, kCubeN) * kCubeN; | ||
| 197 | + c.c1_dim = cin_opt / cube_k; | ||
| 198 | + const int64_t g_dim = Ceil(group, c.e_mult); | ||
| 199 | + c.size_output_data = g_dim * c.d_dim * c.c1_dim * c.h_dim * c.w_dim * c.cout_opt * cube_k; | ||
| 200 | + return KERNEL_STATUS_OK; | ||
| 201 | +} | ||
| 202 | + | ||
| 203 | +inline int64_t ComputeSrcIndexForDealData(const DealDataCtx& c, int64_t d, int64_t h, int64_t w, int64_t co, | ||
| 204 | + int64_t src_co) | ||
| 205 | +{ | ||
| 206 | + if ((c.input_format == aicpu::FORMAT_DHWCN) || (c.input_format == aicpu::FORMAT_HWCN)) { | ||
| 207 | + return d * c.h_dim * c.w_dim * c.c_dim * c.n_dim + h * c.w_dim * c.c_dim * c.n_dim + w * c.c_dim * c.n_dim + | ||
| 208 | + co * c.n_dim + src_co; | ||
| 209 | + } | ||
| 210 | + if ((c.input_format == aicpu::FORMAT_NCDHW) || (c.input_format == aicpu::FORMAT_NCHW)) { | ||
| 211 | + return src_co * c.c_dim * c.d_dim * c.h_dim * c.w_dim + co * c.d_dim * c.h_dim * c.w_dim + | ||
| 212 | + d * c.h_dim * c.w_dim + h * c.w_dim + w; | ||
| 213 | + } | ||
| 214 | + if ((c.input_format == aicpu::FORMAT_NDHWC) || (c.input_format == aicpu::FORMAT_NHWC)) { | ||
| 215 | + return src_co * c.d_dim * c.h_dim * c.w_dim * c.c_dim + d * c.h_dim * c.w_dim * c.c_dim + | ||
| 216 | + h * c.w_dim * c.c_dim + w * c.c_dim + co; | ||
| 217 | + } | ||
| 218 | + return 0; | ||
| 219 | +} | ||
| 220 | + | ||
| 221 | +template <typename T> | ||
| 222 | +void DealDataInner(const T* input_data, T* output_data, const DealDataCtx& c, int64_t g, int64_t d, int64_t co, | ||
| 223 | + int64_t h, int64_t w) | ||
| 224 | +{ | ||
| 225 | + for (int64_t n = 0; n < c.cout_ori; n++) { | ||
| 226 | + const int64_t e_val = g % c.e_mult; | ||
| 227 | + const int64_t dst_ci = e_val * c.cin_ori + co; | ||
| 228 | + const int64_t dst_co = e_val * c.cout_ori + n; | ||
| 229 | + const int64_t src_co = g * c.cout_ori + n; | ||
| 230 | + const int64_t tempory = dst_ci % c.cube_k; | ||
| 231 | + const int64_t dst_inx = (g / c.e_mult) * c.d_dim * c.c1_dim * c.h_dim * c.w_dim * c.cout_opt * c.cube_k + | ||
| 232 | + d * c.c1_dim * c.h_dim * c.w_dim * c.cout_opt * c.cube_k + | ||
| 233 | + (dst_ci / c.cube_k) * c.h_dim * c.w_dim * c.cout_opt * c.cube_k + | ||
| 234 | + h * c.w_dim * c.cout_opt * c.cube_k + w * c.cout_opt * c.cube_k + dst_co * c.cube_k + | ||
| 235 | + tempory; | ||
| 236 | + const int64_t srx_inx = ComputeSrcIndexForDealData(c, d, h, w, co, src_co); | ||
| 237 | + output_data[dst_inx] = input_data[srx_inx]; | ||
| 238 | + } | ||
| 239 | +} | ||
| 240 | + | ||
| 241 | +template <typename T> | ||
| 242 | +void DealDataForHW(const T* input_data, T* output_data, const DealDataCtx& c, int64_t g, int64_t d, int64_t co) | ||
| 243 | +{ | ||
| 244 | + for (int64_t h = 0; h < c.h_dim; h++) { | ||
| 245 | + for (int64_t w = 0; w < c.w_dim; w++) { | ||
| 246 | + DealDataInner<T>(input_data, output_data, c, g, d, co, h, w); | ||
| 247 | + } | ||
| 248 | + } | ||
| 249 | +} | ||
| 250 | + | ||
| 251 | +constexpr int64_t kMaxPaddingBufferBytes = 1LL << 32; // 4 GiB upper bound for padding buffer | ||
| 252 | + | ||
| 253 | +uint32_t AllocatePaddingBuffer(int64_t dst_byte_size, std::shared_ptr<uint8_t>& dst) | ||
| 254 | +{ | ||
| 255 | + if (dst_byte_size <= 0 || dst_byte_size > kMaxPaddingBufferBytes) { | ||
| 256 | + KERNEL_LOG_ERROR("Invalid padding buffer size [%ld], expect (0, %ld]", dst_byte_size, kMaxPaddingBufferBytes); | ||
| 257 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 258 | + } | ||
| 259 | + dst.reset(new (std::nothrow) uint8_t[dst_byte_size], std::default_delete<uint8_t[]>()); | ||
| 260 | + if (dst == nullptr) { | ||
| 261 | + KERNEL_LOG_ERROR("New Memory failed!"); | ||
| 262 | + return KERNEL_STATUS_INNER_ERROR; | ||
| 263 | + } | ||
| 264 | + const errno_t ret_mem = memset_s(dst.get(), dst_byte_size, 0, dst_byte_size); | ||
| 265 | + if (ret_mem != 0) { | ||
| 266 | + KERNEL_LOG_ERROR("Memset failed, ret is [%d]", ret_mem); | ||
| 267 | + return KERNEL_STATUS_INNER_ERROR; | ||
| 268 | + } | ||
| 269 | + return KERNEL_STATUS_OK; | ||
| 270 | +} | ||
| 271 | +void LogTransBegin(const TransDataTensorInfo& in, const TransDataTensorInfo& out, int64_t group) | ||
| 272 | +{ | ||
| 273 | + KERNEL_LOG_DEBUG("Begin trans formats from [%s] to [%s], shape [%s] to [%s], data type " | ||
| 274 | + "[%s] to [%s], group is [%ld]", | ||
| 275 | + FormatToSerialString(in.format).c_str(), FormatToSerialString(out.format).c_str(), | ||
| 276 | + VectorToString(in.dims).c_str(), VectorToString(out.dims).c_str(), DTypeStr(in.data_type).c_str(), | ||
| 277 | + DTypeStr(out.data_type).c_str(), group); | ||
| 278 | +} | ||
| 279 | + | ||
| 280 | +void LogTransEnd(const TransDataTensorInfo& in, const TransDataTensorInfo& out) | ||
| 281 | +{ | ||
| 282 | + KERNEL_LOG_DEBUG("End trans formats from [%s] to [%s], shape [%s] to [%s], data type " | ||
| 283 | + "[%s] to [%s]", | ||
| 284 | + FormatToSerialString(in.format).c_str(), FormatToSerialString(out.format).c_str(), | ||
| 285 | + VectorToString(in.dims).c_str(), VectorToString(out.dims).c_str(), DTypeStr(in.data_type).c_str(), | ||
| 286 | + DTypeStr(out.data_type).c_str()); | ||
| 287 | +} | ||
| 288 | + | ||
| 289 | +void LogTransUnsupported(const TransDataTensorInfo& in, const TransDataTensorInfo& out) | ||
| 290 | +{ | ||
| 291 | + KERNEL_LOG_WARN("Transfer from format[%s] to [%s], shape [%s] to [%s], data type [%s] " | ||
| 292 | + "to [%s] is not supported", | ||
| 293 | + FormatToSerialString(in.format).c_str(), FormatToSerialString(out.format).c_str(), | ||
| 294 | + VectorToString(in.dims).c_str(), VectorToString(out.dims).c_str(), DTypeStr(in.data_type).c_str(), | ||
| 295 | + DTypeStr(out.data_type).c_str()); | ||
| 296 | +} | ||
| 297 | + | ||
| 298 | +void LogTransFailed(const TransDataTensorInfo& in, const TransDataTensorInfo& out) | ||
| 299 | +{ | ||
| 300 | + KERNEL_LOG_WARN("Failed to trans formats from[%s] to [%s], shape [%s] to [%s], data " | ||
| 301 | + "type [%s]", | ||
| 302 | + FormatToSerialString(in.format).c_str(), FormatToSerialString(out.format).c_str(), | ||
| 303 | + VectorToString(in.dims).c_str(), VectorToString(out.dims).c_str(), DTypeStr(in.data_type).c_str()); | ||
| 304 | +} | ||
| 305 | + | ||
| 306 | +aicpu::formats::TransArgs BuildTransArgs(const TransDataTensorInfo& in, const TransDataTensorInfo& out, int64_t group, | ||
| 307 | + const aicpu::CpuKernelContext* ctx) | ||
| 308 | +{ | ||
| 309 | + return aicpu::formats::TransArgs{in.data, | ||
| 310 | + out.data, | ||
| 311 | + static_cast<int32_t>(in.format), | ||
| 312 | + static_cast<int32_t>(out.format), | ||
| 313 | + static_cast<aicpu::Format>(GetPrimaryFormat(static_cast<int32_t>(in.format))), | ||
| 314 | + static_cast<aicpu::Format>(GetPrimaryFormat(static_cast<int32_t>(out.format))), | ||
| 315 | + in.dims, | ||
| 316 | + out.dims, | ||
| 317 | + in.data_type, | ||
| 318 | + group, | ||
| 319 | + ctx}; | ||
| 320 | +} | ||
| 321 | + | ||
| 322 | +uint32_t RunFormatTransfer(const TransDataTensorInfo& in, const TransDataTensorInfo& out, int64_t group, | ||
| 323 | + const aicpu::CpuKernelContext* ctx) | ||
| 324 | +{ | ||
| 325 | + LogTransBegin(in, out, group); | ||
| 326 | + const aicpu::formats::TransArgs trans_args = BuildTransArgs(in, out, group, ctx); | ||
| 327 | + if (in.data_type != out.data_type || in.dims.empty() || !aicpu::formats::FormatTransferExists(trans_args)) { | ||
| 328 | + LogTransUnsupported(in, out); | ||
| 329 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 330 | + } | ||
| 331 | + const uint32_t ret = aicpu::formats::TransFormat(trans_args); | ||
| 332 | + if (ret != KERNEL_STATUS_OK) { | ||
| 333 | + LogTransFailed(in, out); | ||
| 334 | + return ret; | ||
| 335 | + } | ||
| 336 | + LogTransEnd(in, out); | ||
| 337 | + return KERNEL_STATUS_OK; | ||
| 338 | +} | ||
| 339 | +} // namespace | ||
| 340 | + | ||
| 341 | +namespace aicpu { | ||
| 342 | +bool TransDataCpuKernel::IsOriginSupportFormatTransfer(Format src_format, Format dst_format) | ||
| 343 | +{ | ||
| 344 | + static const map<Format, map<Format, int32_t>> kOriginSupportFormatTransfer = { | ||
| 345 | + {FORMAT_HWCN, {{FORMAT_FRACTAL_Z_C04, 1}}}}; | ||
| 346 | + auto dst = kOriginSupportFormatTransfer.find(src_format); | ||
| 347 | + if (dst == kOriginSupportFormatTransfer.end()) { | ||
| 348 | + return false; | ||
| 349 | + } | ||
| 350 | + return dst->second.count(dst_format) > 0; | ||
| 351 | +} | ||
| 352 | + | ||
| 353 | +uint32_t TransDataCpuKernel::NewCompute(const CpuKernelContext& ctx) | ||
| 354 | +{ | ||
| 355 | + TransDataTensorInfo input_info; | ||
| 356 | + TransDataTensorInfo output_info; | ||
| 357 | + if (ExtractTensorInfo(ctx.Input(0), input_info, kTransData) != KERNEL_STATUS_OK) { | ||
| 358 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 359 | + } | ||
| 360 | + if (ExtractTensorInfo(ctx.Output(0), output_info, kTransData) != KERNEL_STATUS_OK) { | ||
| 361 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 362 | + } | ||
| 363 | + KERNEL_CHECK_NULLPTR(output_info.data, KERNEL_STATUS_PARAM_INVALID, | ||
| 364 | + "%s get output_data failed, output_data is nullptr.", kTransData); | ||
| 365 | + int64_t group = kGroupNum; | ||
| 366 | + AttrValue* groups = ctx.GetAttr("groups"); | ||
| 367 | + if (groups != nullptr) { | ||
| 368 | + group = groups->GetInt(); | ||
| 369 | + } | ||
| 370 | + return RunFormatTransfer(input_info, output_info, group, &ctx); | ||
| 371 | +} | ||
| 372 | + | ||
| 373 | +template <typename T> | ||
| 374 | +uint32_t TransDataCpuKernel::DealData(const T* input_data, T* output_data, const Tensor* input_tensor, | ||
| 375 | + Tensor* output_tensor, int64_t group) | ||
| 376 | +{ | ||
| 377 | + (void)output_tensor; | ||
| 378 | + DealDataCtx c{}; | ||
| 379 | + if (BuildDealDataCtx(input_tensor, group, GetCubeSizeByDataType(static_cast<DataType>(input_tensor->GetDataType())), | ||
| 380 | + c) != KERNEL_STATUS_OK) { | ||
| 381 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 382 | + } | ||
| 383 | + const errno_t ret_mem = memset_s(output_data, static_cast<int64_t>(sizeof(T)) * c.size_output_data, 0, | ||
| 384 | + static_cast<int64_t>(sizeof(T)) * c.size_output_data); | ||
| 385 | + if (ret_mem != EOK) { | ||
| 386 | + KERNEL_LOG_ERROR("memset_s failed, ret [%d].", ret_mem); | ||
| 387 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 388 | + } | ||
| 389 | + for (int64_t g = 0; g < group; g++) { | ||
| 390 | + for (int64_t d = 0; d < c.d_dim; d++) { | ||
| 391 | + for (int64_t co = 0; co < c.c_dim; co++) { | ||
| 392 | + DealDataForHW<T>(input_data, output_data, c, g, d, co); | ||
| 393 | + } | ||
| 394 | + } | ||
| 395 | + } | ||
| 396 | + return KERNEL_STATUS_OK; | ||
| 397 | +} | ||
| 398 | + | ||
| 399 | +// TransData supports input formats (NCDHW, DHWCN, NDHWC) convert to | ||
| 400 | +// FORMAT_FRACTAL_Z_3D (GDC1HWN1N0C0), and also supports NHWC, NCHW, HWCN | ||
| 401 | +// converte to FORMAT_FRACTAL_Z (GC1HWN1N0C0), HWCN to FZC04. The final effect | ||
| 402 | +// achieved is for the data to be distributed diagonally. For example: When the | ||
| 403 | +// input filter format is NCDHW, calculated the Correspondence of index between | ||
| 404 | +// NCDHW and FORMAT_FRACTAL_Z_3D , then Convert the old filter to the new | ||
| 405 | +// filter, and finally added 0 to the position where there is no data. | ||
| 406 | +uint32_t TransDataCpuKernel::HandleHwcnToFzC04(const Tensor* input_tensor, Tensor* output_tensor) | ||
| 407 | +{ | ||
| 408 | + KERNEL_LOG_DEBUG("Begin trans formats from FORMAT_HWCN to FORMAT_FRACTAL_Z_C04"); | ||
| 409 | + const DataType data_type = static_cast<DataType>(input_tensor->GetDataType()); | ||
| 410 | + const int64_t cube = GetCubeSizeByDataType(data_type); | ||
| 411 | + if (cube < 0) { | ||
| 412 | + KERNEL_LOG_WARN("Don't support dtype[%s]", DTypeStr(data_type).c_str()); | ||
| 413 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 414 | + } | ||
| 415 | + const uint64_t data_type_size = output_tensor->GetDataSize(); | ||
| 416 | + const uint64_t data_byte_size = GetSizeByDataType(data_type) * data_type_size; | ||
| 417 | + TransArgs args = {reinterpret_cast<uint8_t*>(input_tensor->GetData()), | ||
| 418 | + input_tensor->GetTensorShape()->GetDimSizes(), output_tensor->GetTensorShape()->GetDimSizes(), | ||
| 419 | + data_type}; | ||
| 420 | + auto output_addr = reinterpret_cast<uint8_t*>(output_tensor->GetData()); | ||
| 421 | + const int64_t c0_cube = formats::GetC0ValueForTransShape( | ||
| 422 | + args.src_data_type, static_cast<int32_t>(output_tensor->GetTensorShape()->GetFormat())); | ||
| 423 | + KERNEL_CHECK_FALSE((c0_cube > 0), KERNEL_STATUS_PARAM_INVALID, "c0_cube must greater than 0, now is [%ld].", | ||
| 424 | + c0_cube); | ||
| 425 | + const uint32_t ret = FormatTransferHwcnToFZC04(args, output_addr, data_byte_size, c0_cube); | ||
| 426 | + if (ret != KERNEL_STATUS_OK) { | ||
| 427 | + KERNEL_LOG_ERROR("FormatTransferHwcnToFZC04 function failed"); | ||
| 428 | + return ret; | ||
| 429 | + } | ||
| 430 | + KERNEL_LOG_DEBUG("Finish trans formats from FORMAT_HWCN to FORMAT_FRACTAL_Z_C04"); | ||
| 431 | + return KERNEL_STATUS_OK; | ||
| 432 | +} | ||
| 433 | + | ||
| 434 | +uint32_t TransDataCpuKernel::DispatchDealData(DataType dt, void* input_data_temp, void* output_data_temp, | ||
| 435 | + const Tensor* input_tensor, Tensor* output_tensor, int64_t group) | ||
| 436 | +{ | ||
| 437 | + switch (dt) { | ||
| 438 | + case DT_INT8: | ||
| 439 | + return DealData(reinterpret_cast<int8_t*>(input_data_temp), reinterpret_cast<int8_t*>(output_data_temp), | ||
| 440 | + input_tensor, output_tensor, group); | ||
| 441 | + case DT_FLOAT: | ||
| 442 | + return DealData(reinterpret_cast<float*>(input_data_temp), reinterpret_cast<float*>(output_data_temp), | ||
| 443 | + input_tensor, output_tensor, group); | ||
| 444 | + case DT_FLOAT16: | ||
| 445 | + return DealData(reinterpret_cast<Eigen::half*>(input_data_temp), | ||
| 446 | + reinterpret_cast<Eigen::half*>(output_data_temp), input_tensor, output_tensor, group); | ||
| 447 | + default: | ||
| 448 | + KERNEL_LOG_WARN("DateType is not DT_INT8 or DT_FLOAT or DT_FLOAT16, and current " | ||
| 449 | + "DataType is [%d]", | ||
| 450 | + static_cast<int32_t>(dt)); | ||
| 451 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 452 | + } | ||
| 453 | +} | ||
| 454 | + | ||
| 455 | +uint32_t TransDataCpuKernel::Compute(CpuKernelContext& ctx) | ||
| 456 | +{ | ||
| 457 | + Tensor* input_tensor = ctx.Input(0); | ||
| 458 | + KERNEL_CHECK_NULLPTR(input_tensor, KERNEL_STATUS_PARAM_INVALID, "%s get input_tensor failed", kTransData); | ||
| 459 | + const auto input_format = GetPrimaryFormat(static_cast<int32_t>(input_tensor->GetTensorShape()->GetFormat())); | ||
| 460 | + Tensor* output_tensor = ctx.Output(0); | ||
| 461 | + KERNEL_CHECK_NULLPTR(output_tensor, KERNEL_STATUS_PARAM_INVALID, "%s get output_tensor failed", kTransData); | ||
| 462 | + const auto output_format = GetPrimaryFormat(static_cast<int32_t>(output_tensor->GetTensorShape()->GetFormat())); | ||
| 463 | + if (!IsOriginSupportFormatTransfer(static_cast<Format>(input_format), static_cast<Format>(output_format))) { | ||
| 464 | + return NewCompute(ctx); | ||
| 465 | + } | ||
| 466 | + if ((input_format == FORMAT_HWCN) && (output_format == FORMAT_FRACTAL_Z_C04)) { | ||
| 467 | + return HandleHwcnToFzC04(input_tensor, output_tensor); | ||
| 468 | + } | ||
| 469 | + const int32_t primary_out_put_format = GetPrimaryFormat(static_cast<int32_t>(output_format)); | ||
| 470 | + if ((primary_out_put_format != static_cast<int32_t>(FORMAT_FRACTAL_Z)) && | ||
| 471 | + (primary_out_put_format != static_cast<int32_t>(FORMAT_FRACTAL_Z_3D))) { | ||
| 472 | + KERNEL_LOG_EVENT("%s unsupport output_format [%d]", kTransData, primary_out_put_format); | ||
| 473 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 474 | + } | ||
| 475 | + auto input_shape = input_tensor->GetTensorShape(); | ||
| 476 | + KERNEL_CHECK_NULLPTR(input_shape, KERNEL_STATUS_PARAM_INVALID, "%s get input_shape failed", kTransData); | ||
| 477 | + const std::vector<int64_t> dims = input_shape->GetDimSizes(); | ||
| 478 | + if ((dims.size()) < kMinInputDimsNum) { | ||
| 479 | + KERNEL_LOG_WARN("%s dims size [%zu] must >= 4", kTransData, dims.size()); | ||
| 480 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 481 | + } | ||
| 482 | + AttrValue* groups = ctx.GetAttr("groups"); | ||
| 483 | + int64_t group = kGroupNum; | ||
| 484 | + if (groups != nullptr) { | ||
| 485 | + group = groups->GetInt(); | ||
| 486 | + KERNEL_CHECK_FALSE((group != 0L), KERNEL_STATUS_PARAM_INVALID, "groups can't be 0."); | ||
| 487 | + } | ||
| 488 | + const DataType dt = static_cast<DataType>(input_tensor->GetDataType()); | ||
| 489 | + auto input_data_temp = input_tensor->GetData(); | ||
| 490 | + KERNEL_CHECK_NULLPTR(input_data_temp, KERNEL_STATUS_PARAM_INVALID, "%s get input_data failed", kTransData); | ||
| 491 | + auto output_data_temp = output_tensor->GetData(); | ||
| 492 | + KERNEL_CHECK_NULLPTR(output_data_temp, KERNEL_STATUS_PARAM_INVALID, "%s get output_data failed", kTransData); | ||
| 493 | + return DispatchDealData(dt, input_data_temp, output_data_temp, input_tensor, output_tensor, group); | ||
| 494 | +} | ||
| 495 | + | ||
| 496 | +uint32_t TransDataCpuKernel::FormatTransferHwcnToFZC04(TransArgs& args, uint8_t* output_addr, uint64_t length, | ||
| 497 | + int64_t c0_cube) | ||
| 498 | +{ | ||
| 499 | + KERNEL_LOG_DEBUG("Begin to trans format from HWCN to FZC04, src shape [%s], data type " | ||
| 500 | + "[%s], dst shape [%s], c0_cube [%ld]", | ||
| 501 | + VectorToString(args.src_shape).c_str(), DTypeStr(args.src_data_type).c_str(), | ||
| 502 | + VectorToString(args.dst_shape).c_str(), c0_cube); | ||
| 503 | + std::shared_ptr<uint8_t> dst_padding_one(nullptr); | ||
| 504 | + uint32_t ret = PaddingOne(args, dst_padding_one); | ||
| 505 | + if (ret != KERNEL_STATUS_OK) { | ||
| 506 | + return ret; | ||
| 507 | + } | ||
| 508 | + std::vector<int64_t> perm_arg_tmp_one = {3, 0, 1, 2}; | ||
| 509 | + std::shared_ptr<uint8_t> dst_transpose_one(nullptr); | ||
| 510 | + ret = Transpose(args, perm_arg_tmp_one, dst_transpose_one); | ||
| 511 | + if (ret != KERNEL_STATUS_OK) { | ||
| 512 | + return ret; | ||
| 513 | + } | ||
| 514 | + std::vector<int64_t>& src_shape = args.src_shape; | ||
| 515 | + std::vector<int64_t> src_shape_tmp = src_shape; | ||
| 516 | + constexpr size_t new_dims = 2; | ||
| 517 | + src_shape.resize(new_dims); | ||
| 518 | + src_shape[0] = src_shape_tmp[formats::kHwcnH]; | ||
| 519 | + src_shape[1] = src_shape_tmp[formats::kHwcnW] * src_shape_tmp[formats::kHwcnC] * src_shape_tmp[formats::kHwcnN]; | ||
| 520 | + std::shared_ptr<uint8_t> dst_padding_two(nullptr); | ||
| 521 | + ret = PaddingTwo(args, dst_padding_two, c0_cube); | ||
| 522 | + if (ret != KERNEL_STATUS_OK) { | ||
| 523 | + return ret; | ||
| 524 | + } | ||
| 525 | + | ||
| 526 | + KERNEL_CHECK_FALSE((c0_cube > 0), KERNEL_STATUS_PARAM_INVALID, "c0_cube must greater than 0, now is [%ld].", | ||
| 527 | + c0_cube); // for avoid warning for div 0 | ||
| 528 | + src_shape_tmp = src_shape; | ||
| 529 | + src_shape.resize(formats::kHwcnDimsNum); | ||
| 530 | + src_shape[formats::kHwcnH] = src_shape_tmp[0] / kDimN0; | ||
| 531 | + src_shape[formats::kHwcnW] = kDimN0; | ||
| 532 | + src_shape[formats::kHwcnC] = src_shape_tmp[1] / c0_cube; | ||
| 533 | + src_shape[formats::kHwcnN] = c0_cube; | ||
| 534 | + std::vector<int64_t> perm_arg_tmp_two = {2, 0, 1, 3}; | ||
| 535 | + std::shared_ptr<uint8_t> dst_transpose_two(nullptr); | ||
| 536 | + ret = Transpose(args, perm_arg_tmp_two, dst_transpose_two); | ||
| 537 | + if (ret != KERNEL_STATUS_OK) { | ||
| 538 | + return ret; | ||
| 539 | + } | ||
| 540 | + auto ret_mem = BiggerMemCpy(output_addr, length, args.data, | ||
| 541 | + VectorToNum(args.src_shape) * GetSizeByDataType(args.src_data_type)); | ||
| 542 | + if (!ret_mem) { | ||
| 543 | + KERNEL_LOG_ERROR("BiggerMemCpy failed"); | ||
| 544 | + return KERNEL_STATUS_INNER_ERROR; | ||
| 545 | + } | ||
| 546 | + return KERNEL_STATUS_OK; | ||
| 547 | +} | ||
| 548 | + | ||
| 549 | +uint32_t TransDataCpuKernel::PaddingOne(TransArgs& args, std::shared_ptr<uint8_t>& dst) | ||
| 550 | +{ | ||
| 551 | + DataType data_type = args.src_data_type; | ||
| 552 | + std::vector<int64_t> dst_shape; | ||
| 553 | + uint32_t ret = GetPaddingOneShape(args, dst_shape); | ||
| 554 | + if (ret != KERNEL_STATUS_OK) { | ||
| 555 | + return ret; | ||
| 556 | + } | ||
| 557 | + int32_t type_size = GetSizeByDataType(data_type); | ||
| 558 | + int64_t dst_byte_size = VectorToNum(dst_shape) * type_size; | ||
| 559 | + if (AllocatePaddingBuffer(dst_byte_size, dst) != KERNEL_STATUS_OK) { | ||
| 560 | + return KERNEL_STATUS_INNER_ERROR; | ||
| 561 | + } | ||
| 562 | + std::vector<int64_t>& src_shape = args.src_shape; | ||
| 563 | + auto h = src_shape.at(0); | ||
| 564 | + auto w = src_shape.at(1); | ||
| 565 | + auto c = src_shape.at(2); | ||
| 566 | + auto n = src_shape.at(3); | ||
| 567 | + auto h_padding = dst_shape[0]; | ||
| 568 | + auto w_padding = dst_shape[1]; | ||
| 569 | + auto c_padding = dst_shape[2]; | ||
| 570 | + auto n_padding = dst_shape[3]; | ||
| 571 | + auto src_add = args.data; | ||
| 572 | + auto dst_add = dst.get(); | ||
| 573 | + auto protect_size = h_padding * w_padding * c_padding * n_padding * type_size; | ||
| 574 | + for (int i = 0; i < h; i++) { | ||
| 575 | + for (int j = 0; j < w; j++) { | ||
| 576 | + for (int k = 0; k < c; k++) { | ||
| 577 | + auto dst_stride = ((i * w_padding + j) * c_padding + k) * n_padding * type_size; | ||
| 578 | + auto ret_cpy = memcpy_s(dst_add + dst_stride, protect_size - dst_stride, | ||
| 579 | + src_add + ((i * w + j) * c + k) * n * type_size, n * type_size); | ||
| 580 | + if (ret_cpy != 0) { | ||
| 581 | + KERNEL_LOG_ERROR("Memcpy failed, ret is [%d]", ret_cpy); | ||
| 582 | + return KERNEL_STATUS_INNER_ERROR; | ||
| 583 | + } | ||
| 584 | + } | ||
| 585 | + } | ||
| 586 | + } | ||
| 587 | + args.data = dst.get(); | ||
| 588 | + src_shape = dst_shape; | ||
| 589 | + return KERNEL_STATUS_OK; | ||
| 590 | +} | ||
| 591 | + | ||
| 592 | +uint32_t TransDataCpuKernel::PaddingTwo(TransArgs& args, std::shared_ptr<uint8_t>& dst, int64_t c0_cube) | ||
| 593 | +{ | ||
| 594 | + DataType data_type = args.src_data_type; | ||
| 595 | + std::vector<int64_t> dst_shape; | ||
| 596 | + uint32_t ret = GetPaddingTwoShape(args, dst_shape, c0_cube); | ||
| 597 | + if (ret != KERNEL_STATUS_OK) { | ||
| 598 | + return ret; | ||
| 599 | + } | ||
| 600 | + int32_t type_size = GetSizeByDataType(data_type); | ||
| 601 | + int64_t dst_byte_size = VectorToNum(dst_shape) * type_size; | ||
| 602 | + if (AllocatePaddingBuffer(dst_byte_size, dst) != KERNEL_STATUS_OK) { | ||
| 603 | + return KERNEL_STATUS_INNER_ERROR; | ||
| 604 | + } | ||
| 605 | + std::vector<int64_t>& src_shape = args.src_shape; | ||
| 606 | + auto n = src_shape.at(0); | ||
| 607 | + auto z = src_shape.at(1); | ||
| 608 | + auto n_padding = dst_shape[0]; | ||
| 609 | + auto z_padding = dst_shape[1]; | ||
| 610 | + auto src_add = args.data; | ||
| 611 | + auto dst_add = dst.get(); | ||
| 612 | + auto protect_size = n_padding * z_padding * type_size; | ||
| 613 | + for (int i = 0; i < n; i++) { | ||
| 614 | + auto dst_stride = i * z_padding * type_size; | ||
| 615 | + auto ret_cpy = memcpy_s(dst_add + dst_stride, protect_size - dst_stride, src_add + i * z * type_size, | ||
| 616 | + z * type_size); | ||
| 617 | + if (ret_cpy != 0) { | ||
| 618 | + KERNEL_LOG_ERROR("Memcpy failed, ret is [%d]", ret_cpy); | ||
| 619 | + return KERNEL_STATUS_INNER_ERROR; | ||
| 620 | + } | ||
| 621 | + } | ||
| 622 | + args.data = dst.get(); | ||
| 623 | + src_shape = dst_shape; | ||
| 624 | + return KERNEL_STATUS_OK; | ||
| 625 | +} | ||
| 626 | + | ||
| 627 | +uint32_t TransDataCpuKernel::GetPaddingOneShape(const TransArgs& args, std::vector<int64_t>& dst_shape) | ||
| 628 | +{ | ||
| 629 | + int64_t cube = kDimN0; | ||
| 630 | + auto h = args.src_shape.at(formats::kHwcnH); | ||
| 631 | + auto w = args.src_shape.at(formats::kHwcnW); | ||
| 632 | + auto c = args.src_shape.at(formats::kHwcnC); | ||
| 633 | + auto n = args.src_shape.at(formats::kHwcnN); | ||
| 634 | + if (c > kMaxDimsNumC) { | ||
| 635 | + KERNEL_LOG_ERROR("Invalid dim c num[%lu].It should be in (0, %ld]", c, kMaxDimsNumC); | ||
| 636 | + return KERNEL_STATUS_PARAM_INVALID; | ||
| 637 | + } | ||
| 638 | + dst_shape.resize(formats::kHwcnDimsNum); | ||
| 639 | + dst_shape[formats::kHwcnH] = h; | ||
| 640 | + dst_shape[formats::kHwcnW] = w; | ||
| 641 | + dst_shape[formats::kHwcnC] = kMaxDimsNumC; | ||
| 642 | + int64_t tmp = Ceil(n, cube); | ||
| 643 | + dst_shape[formats::kHwcnN] = tmp * cube; | ||
| 644 | + return KERNEL_STATUS_OK; | ||
| 645 | +} | ||
| 646 | + | ||
| 647 | +uint32_t TransDataCpuKernel::GetPaddingTwoShape(const TransArgs& args, std::vector<int64_t>& dst_shape, int64_t cube) | ||
| 648 | +{ | ||
| 649 | + auto n = args.src_shape.at(0); | ||
| 650 | + auto z = args.src_shape.at(1); | ||
| 651 | + constexpr size_t new_size = 2; | ||
| 652 | + dst_shape.resize(new_size); | ||
| 653 | + dst_shape[0] = n; | ||
| 654 | + int64_t tmp = Ceil(z, cube); | ||
| 655 | + dst_shape[1] = tmp * cube; | ||
| 656 | + return KERNEL_STATUS_OK; | ||
| 657 | +} | ||
| 658 | + | ||
| 659 | +uint32_t TransDataCpuKernel::Transpose(TransArgs& args, const std::vector<int64_t>& perm_arg, | ||
| 660 | + std::shared_ptr<uint8_t>& dst) | ||
| 661 | +{ | ||
| 662 | + std::vector<int64_t>& src_shape = args.src_shape; | ||
| 663 | + std::vector<int64_t> dst_shape; | ||
| 664 | + TransShapeByPerm(src_shape, perm_arg, dst_shape); | ||
| 665 | + DataType src_data_type = args.src_data_type; | ||
| 666 | + KERNEL_LOG_DEBUG("Begin to transpose, src shape [%s], perm arg [%s], dst shape [%s], data " | ||
| 667 | + "type [%s]", | ||
| 668 | + VectorToString(src_shape).c_str(), VectorToString(perm_arg).c_str(), | ||
| 669 | + VectorToString(dst_shape).c_str(), DTypeStr(src_data_type).c_str()); | ||
| 670 | + int64_t dst_ele_num = VectorToNum(dst_shape); | ||
| 671 | + int64_t data_size = GetSizeByDataType(src_data_type); | ||
| 672 | + int64_t dst_size = data_size * dst_ele_num; | ||
| 673 | + dst.reset(new (std::nothrow) uint8_t[dst_size], std::default_delete<uint8_t[]>()); | ||
| 674 | + if (dst == nullptr) { | ||
| 675 | + KERNEL_LOG_ERROR("New Memory failed!"); | ||
| 676 | + return KERNEL_STATUS_INNER_ERROR; | ||
| 677 | + } | ||
| 678 | + int64_t dst_index = 0; | ||
| 679 | + std::vector<int64_t> src_shape_head; | ||
| 680 | + GetShapeHead(src_shape, src_shape_head); | ||
| 681 | + std::vector<int64_t> dst_shape_head; | ||
| 682 | + GetShapeHead(dst_shape, dst_shape_head); | ||
| 683 | + std::map<int32_t, int32_t> index_map; | ||
| 684 | + GetIndexMap(perm_arg, index_map); | ||
| 685 | + while (dst_index < dst_ele_num) { | ||
| 686 | + auto src_index = GetSrcIndex(dst_index, src_shape, dst_shape, src_shape_head, dst_shape_head, index_map); | ||
| 687 | + const int64_t remain = dst_size - dst_index * data_size; | ||
| 688 | + const size_t protect_size = (remain < static_cast<int64_t>(SECUREC_MEM_MAX_LEN)) ? static_cast<size_t>(remain) : | ||
| 689 | + SECUREC_MEM_MAX_LEN; | ||
| 690 | + auto ret = memcpy_s(dst.get() + dst_index * data_size, protect_size, args.data + src_index * data_size, | ||
| 691 | + static_cast<size_t>(data_size)); | ||
| 692 | + if (ret != 0) { | ||
| 693 | + KERNEL_LOG_ERROR("Memcpy failed, ret is [%d]", ret); | ||
| 694 | + return KERNEL_STATUS_INNER_ERROR; | ||
| 695 | + } | ||
| 696 | + dst_index += 1; | ||
| 697 | + } | ||
| 698 | + src_shape = dst_shape; | ||
| 699 | + args.data = dst.get(); | ||
| 700 | + return KERNEL_STATUS_OK; | ||
| 701 | +} | ||
| 702 | + | ||
| 703 | +int64_t TransDataCpuKernel::GetCubeSizeByDataType(DataType data_type) | ||
| 704 | +{ | ||
| 705 | + // Current cube does not support 4 bytes and longer data | ||
| 706 | + auto size = GetSizeByDataType(data_type); | ||
| 707 | + if (size <= 0) { | ||
| 708 | + KERNEL_LOG_ERROR("Failed to get cube size, the data type [%s] is invalid", DTypeStr(data_type).c_str()); | ||
| 709 | + return -1; | ||
| 710 | + } else if (size == 1) { | ||
| 711 | + return kCubeSize * 2; // 32 bytes cube size | ||
| 712 | + } else { | ||
| 713 | + return kCubeSize; | ||
| 714 | + } | ||
| 715 | +} | ||
| 716 | +REGISTER_CPU_KERNEL(kTransData, TransDataCpuKernel); | ||
| 717 | +} // namespace aicpu | ||
| @@ -0,0 +1,48 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | +namespace aicpu { | ||
| 16 | +struct TransArgs { | ||
| 17 | + const uint8_t* data; | ||
| 18 | + std::vector<int64_t> src_shape; | ||
| 19 | + std::vector<int64_t> dst_shape; | ||
| 20 | + DataType src_data_type; | ||
| 21 | +}; | ||
| 22 | + | ||
| 23 | +class TransDataCpuKernel : public CpuKernel { | ||
| 24 | +public: | ||
| 25 | + ~TransDataCpuKernel() = default; | ||
| 26 | + uint32_t Compute(CpuKernelContext& ctx) override; | ||
| 27 | + | ||
| 28 | +private: | ||
| 29 | + template <typename T> | ||
| 30 | + uint32_t DealData(const T* input_Data, T* output_data, const Tensor* input_tensor, Tensor* out_put_tensor, | ||
| 31 | + int64_t group); | ||
| 32 | + uint32_t FormatTransferHwcnToFZC04(TransArgs& args, uint8_t* output_addr, uint64_t length, int64_t c0_cube); | ||
| 33 | + uint32_t PaddingOne(TransArgs& args, std::shared_ptr<uint8_t>& dst); | ||
| 34 | + uint32_t PaddingTwo(TransArgs& args, std::shared_ptr<uint8_t>& dst, int64_t c0_cube); | ||
| 35 | + uint32_t GetPaddingOneShape(const TransArgs& args, std::vector<int64_t>& dst_shape); | ||
| 36 | + uint32_t GetPaddingTwoShape(const TransArgs& args, std::vector<int64_t>& dst_shape, int64_t cube); | ||
| 37 | + uint32_t Transpose(TransArgs& args, const std::vector<int64_t>& perm_arg, std::shared_ptr<uint8_t>& dst); | ||
| 38 | + int64_t GetCubeSizeByDataType(DataType data_type); | ||
| 39 | + | ||
| 40 | + bool IsOriginSupportFormatTransfer(Format src_fromat, Format dst_format); | ||
| 41 | + | ||
| 42 | + uint32_t NewCompute(const CpuKernelContext& ctx); | ||
| 43 | + uint32_t HandleHwcnToFzC04(const Tensor* input_tensor, Tensor* output_tensor); | ||
| 44 | + uint32_t DispatchDealData(DataType dt, void* input_data_temp, void* output_data_temp, const Tensor* input_tensor, | ||
| 45 | + Tensor* output_tensor, int64_t group); | ||
| 46 | +}; | ||
| 47 | +} // namespace aicpu | ||
| 48 | + | ||
| @@ -0,0 +1,76 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +using namespace aicpu; | ||
| 24 | + | ||
| 25 | +class TEST_TRANS_DATA_UT : public testing::Test {}; | ||
| 26 | + | ||
| 27 | +namespace { | ||
| 28 | +std::shared_ptr<NodeDef> BuildTransDataNode(DataType dtype, Format src_fmt, Format dst_fmt, | ||
| 29 | + const std::vector<int64_t>& src_shape, | ||
| 30 | + const std::vector<int64_t>& dst_shape, void* src_data, void* dst_data, | ||
| 31 | + const std::string& src_format_str, const std::string& dst_format_str, | ||
| 32 | + int64_t groups = 1) | ||
| 33 | +{ | ||
| 34 | + auto node_def = CpuKernelUtils::CreateNodeDef(); | ||
| 35 | + NodeDefBuilder(node_def.get(), "TransData", "TransData") | ||
| 36 | + .Input({"src", dtype, src_shape, src_data, src_fmt}) | ||
| 37 | + .Output({"dst", dtype, dst_shape, dst_data, dst_fmt}) | ||
| 38 | + .Attr("src_format", src_format_str) | ||
| 39 | + .Attr("dst_format", dst_format_str) | ||
| 40 | + .Attr("groups", groups); | ||
| 41 | + return node_def; | ||
| 42 | +} | ||
| 43 | +} // namespace | ||
| 44 | + | ||
| 45 | +TEST_F(TEST_TRANS_DATA_UT, unsupported_output_format_returns_param_invalid) | ||
| 46 | +{ | ||
| 47 | + std::vector<int64_t> src_shape = {1, 2, 2, 4}; | ||
| 48 | + std::vector<int64_t> dst_shape = {1, 2, 2, 4}; | ||
| 49 | + std::vector<float> src(16, 1.0f); | ||
| 50 | + std::vector<float> dst(16, 0.0f); | ||
| 51 | + auto node_def = BuildTransDataNode(DT_FLOAT, FORMAT_NHWC, FORMAT_NHWC, src_shape, dst_shape, src.data(), dst.data(), | ||
| 52 | + "NHWC", "NHWC"); | ||
| 53 | + RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID); | ||
| 54 | +} | ||
| 55 | + | ||
| 56 | +TEST_F(TEST_TRANS_DATA_UT, insufficient_dims_returns_param_invalid) | ||
| 57 | +{ | ||
| 58 | + std::vector<int64_t> src_shape = {2, 4}; | ||
| 59 | + std::vector<int64_t> dst_shape = {1, 1, 16, 16}; | ||
| 60 | + std::vector<float> src(8, 1.0f); | ||
| 61 | + std::vector<float> dst(256, 0.0f); | ||
| 62 | + auto node_def = BuildTransDataNode(DT_FLOAT, FORMAT_HWCN, FORMAT_FRACTAL_Z, src_shape, dst_shape, src.data(), | ||
| 63 | + dst.data(), "HWCN", "FRACTAL_Z"); | ||
| 64 | + RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID); | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +TEST_F(TEST_TRANS_DATA_UT, groups_zero_returns_param_invalid) | ||
| 68 | +{ | ||
| 69 | + std::vector<int64_t> src_shape = {1, 1, 1, 16}; | ||
| 70 | + std::vector<int64_t> dst_shape = {1, 1, 16, 16}; | ||
| 71 | + std::vector<float> src(16, 1.0f); | ||
| 72 | + std::vector<float> dst(256, 0.0f); | ||
| 73 | + auto node_def = BuildTransDataNode(DT_FLOAT, FORMAT_HWCN, FORMAT_FRACTAL_Z, src_shape, dst_shape, src.data(), | ||
| 74 | + dst.data(), "HWCN", "FRACTAL_Z", 0); | ||
| 75 | + RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID); | ||
| 76 | +} | ||
🟡 Medium Priority
test_trans_data.cpp中的两个测试用例当前都能通过并返回KERNEL_STATUS_PARAM_INVALID,但并非因为触发了 kernel 内部的校验逻辑,而是因为所测格式组合(HWCN→FRACTAL_Z)在 PR1 中尚未注册格式转换实现。证据链:
后果: 这两个测试名称暗示它们验证 kernel 侧的 groups/dims 校验,但实际路径绕开了这些校验。当 PR2/PR3 注册 HWCN→FRACTAL_Z 格式转换后,测试将进入真正的转换逻辑,届时
NewCompute缺失的 groups/dims 校验会导致测试失败或触发 UB(参见前述两个 kernel 侧 findings)。当前测试状态掩盖了NewCompute的校验缺失问题。建议:建议:1) 修复 kernel 侧
NewCompute缺失的 groups 和 dims 校验(参见前述 findings);2) 修复后这两个测试将正确覆盖新代码路径的校验逻辑。在 PR1 中也可以考虑增加一个不会注册格式转换但能触发 Compute 旧路径校验的测试(如使用 FORMAT_FRACTAL_Z 作为输出格式且 dims < 4),以独立验证 dims 校验。