| @@ -0,0 +1,30 @@ | |||
| 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 | +#ifndef ATT_BASE_ARCH_PARAM_H_ | ||
| 12 | +#define ATT_BASE_ARCH_PARAM_H_ | ||
| 13 | + | ||
| 14 | +#include <cstdint> | ||
| 15 | + | ||
| 16 | +namespace att { | ||
| 17 | +namespace arch_param { | ||
| 18 | +struct ArchHardwareConfig { | ||
| 19 | + uint32_t cache_line_size; | ||
| 20 | + uint32_t vector_len_size; | ||
| 21 | +}; | ||
| 22 | + | ||
| 23 | +inline constexpr ArchHardwareConfig kV1ArchHardwareConfig{512U, 256U}; | ||
| 24 | +inline constexpr ArchHardwareConfig kV2ArchHardwareConfig{128U, 256U}; | ||
| 25 | +inline constexpr uint32_t kDefaultCacheLineSize = kV2ArchHardwareConfig.cache_line_size; | ||
| 26 | +inline constexpr uint32_t kDefaultVectorLenSize = kV2ArchHardwareConfig.vector_len_size; | ||
| 27 | +} // namespace arch_param | ||
| 28 | +} // namespace att | ||
| 29 | + | ||
| 30 | +#endif // ATT_BASE_ARCH_PARAM_H_ | ||
| @@ -12,6 +12,7 @@ | |||
| 12 | #define ATT_MODEL_INFO_H | 12 | #define ATT_MODEL_INFO_H |
| 13 | #include <memory> | 13 | #include <memory> |
| 14 | #include <map> | 14 | #include <map> |
| 15 | +#include "base/arch_param.h" | ||
| 15 | #include "base/base_types.h" | 16 | #include "base/base_types.h" |
| 16 | #include "base/perf_breakdown.h" | 17 | #include "base/perf_breakdown.h" |
| 17 | #include "schedule_result.h" | 18 | #include "schedule_result.h" |
| @@ -173,7 +174,10 @@ struct TilingScheduleConfig { | |||
| 173 | TradeOffConfig trade_off_config; | 174 | TradeOffConfig trade_off_config; |
| 174 | 175 | ||
| 175 | // CacheLine 大小(字节) | 176 | // CacheLine 大小(字节) |
| 176 | - uint32_t cache_line_size{128}; | 177 | + uint32_t cache_line_size{arch_param::kDefaultCacheLineSize}; |
| 178 | + | ||
| 179 | + // Vector length 大小(字节) | ||
| 180 | + uint32_t vector_len_size{arch_param::kDefaultVectorLenSize}; | ||
| 177 | 181 | ||
| 178 | // 是否启用惩罚配置(用于日志区分) | 182 | // 是否启用惩罚配置(用于日志区分) |
| 179 | bool is_penalty_config{false}; | 183 | bool is_penalty_config{false}; |
| @@ -181,6 +185,7 @@ struct TilingScheduleConfig { | |||
| 181 | [[nodiscard]] std::string DebugString() const { | 185 | [[nodiscard]] std::string DebugString() const { |
| 182 | return "trade_off_config: {" + trade_off_config.DebugString() + | 186 | return "trade_off_config: {" + trade_off_config.DebugString() + |
| 183 | "}, cache_line_size: " + std::to_string(cache_line_size) + | 187 | "}, cache_line_size: " + std::to_string(cache_line_size) + |
| 188 | + ", vector_len_size: " + std::to_string(vector_len_size) + | ||
| 184 | ", is_penalty_config: " + std::to_string(is_penalty_config); | 189 | ", is_penalty_config: " + std::to_string(is_penalty_config); |
| 185 | } | 190 | } |
| 186 | }; | 191 | }; |
| @@ -225,6 +230,15 @@ struct CacheLineConfig { | |||
| 225 | } | 230 | } |
| 226 | }; | 231 | }; |
| 227 | 232 | ||
| 233 | +struct RuntimeReorderRule { | ||
| 234 | + Expr preferred_axis; | ||
| 235 | + Expr fallback_axis; | ||
| 236 | + Expr condition_axis; | ||
| 237 | + Expr compare_axis; | ||
| 238 | + uint32_t condition_threshold{0U}; | ||
| 239 | + uint32_t compare_threshold{0U}; | ||
| 240 | +}; | ||
| 241 | + | ||
| 228 | class TilingScheduleConfigTable { | 242 | class TilingScheduleConfigTable { |
| 229 | public: | 243 | public: |
| 230 | virtual ~TilingScheduleConfigTable() = default; | 244 | virtual ~TilingScheduleConfigTable() = default; |
| @@ -248,6 +262,11 @@ class TilingScheduleConfigTable { | |||
| 248 | // 新增:获取 CacheLine 大小 | 262 | // 新增:获取 CacheLine 大小 |
| 249 | [[nodiscard]] virtual uint32_t GetCacheLineSize() const = 0; | 263 | [[nodiscard]] virtual uint32_t GetCacheLineSize() const = 0; |
| 250 | 264 | ||
| 265 | + // 新增:获取 Vector length 大小 | ||
| 266 | + [[nodiscard]] virtual uint32_t GetVectorLenSize() const { | ||
| 267 | + return arch_param::kDefaultVectorLenSize; | ||
| 268 | + } | ||
| 269 | + | ||
| 251 | // 新增:是否启用Reduce分核Store地址冲突惩罚功能 | 270 | // 新增:是否启用Reduce分核Store地址冲突惩罚功能 |
| 252 | [[nodiscard]] virtual bool IsCoreNumThresholdPenaltyEnable() const = 0; | 271 | [[nodiscard]] virtual bool IsCoreNumThresholdPenaltyEnable() const = 0; |
| 253 | }; | 272 | }; |
| @@ -292,6 +311,7 @@ struct ModelInfo { | |||
| 292 | const TilingScheduleConfigTable *tiling_schedule_config_table{nullptr}; | 311 | const TilingScheduleConfigTable *tiling_schedule_config_table{nullptr}; |
| 293 | TilingScheduleConfig tiling_schedule_config; // Model 级别的 Tiling 调度配置 | 312 | TilingScheduleConfig tiling_schedule_config; // Model 级别的 Tiling 调度配置 |
| 294 | bool is_enable_equal_order_tiling{false}; // 使能等order tiling算法 | 313 | bool is_enable_equal_order_tiling{false}; // 使能等order tiling算法 |
| 314 | + std::vector<RuntimeReorderRule> runtime_reorder_rules; // 运行时按shape调整单模板内轴优先级 | ||
| 295 | }; | 315 | }; |
| 296 | 316 | ||
| 297 | using TilingModelInfo = std::vector<ModelInfo>; | 317 | using TilingModelInfo = std::vector<ModelInfo>; |
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #include <string> | 14 | #include <string> |
| 15 | #include <map> | 15 | #include <map> |
| 16 | +#include "base/arch_param.h" | ||
| 16 | #include "base/base_types.h" | 17 | #include "base/base_types.h" |
| 17 | #include "gen_model_info/parser/tuning_space.h" | 18 | #include "gen_model_info/parser/tuning_space.h" |
| 18 | #include "util/ternary_op.h" | 19 | #include "util/ternary_op.h" |
| @@ -45,8 +46,7 @@ class PerfParamTable { | |||
| 45 | } | 46 | } |
| 46 | // 获取每条MicroApi指令能处理的字节数 | 47 | // 获取每条MicroApi指令能处理的字节数 |
| 47 | [[nodiscard]] virtual uint32_t GetMicroApiLen() const { | 48 | [[nodiscard]] virtual uint32_t GetMicroApiLen() const { |
| 48 | - constexpr uint32_t kDefaultVectorLen = 256; | 49 | + return arch_param::kDefaultVectorLenSize; |
| 49 | - return kDefaultVectorLen; | ||
| 50 | } | 50 | } |
| 51 | // 获取注册的关键字名 | 51 | // 获取注册的关键字名 |
| 52 | [[nodiscard]] virtual std::string GetApiRegisterVerName() const { | 52 | [[nodiscard]] virtual std::string GetApiRegisterVerName() const { |
| @@ -1,9 +1,9 @@ | |||
| 1 | /** | 1 | /** |
| 2 | * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | * Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 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 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, | 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. | 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 | */ |
| @@ -23,8 +23,10 @@ class PerfParamTableV1 : public PerfParamTable { | |||
| 23 | [[nodiscard]] const std::string *GetAscendCApiPerfTable() const override; | 23 | [[nodiscard]] const std::string *GetAscendCApiPerfTable() const override; |
| 24 | [[nodiscard]] PipeHeadPerfFunc GetPipeHeadPerfFunc(PipeType pipe_type) const override; | 24 | [[nodiscard]] PipeHeadPerfFunc GetPipeHeadPerfFunc(PipeType pipe_type) const override; |
| 25 | [[nodiscard]] Expr GetOpHeadCost() const override; | 25 | [[nodiscard]] Expr GetOpHeadCost() const override; |
| 26 | - [[nodiscard]] static Expr GetMTE2PipeHead(const std::vector<NodeInfo> &node_infos, | 26 | + [[nodiscard]] uint32_t GetMicroApiLen() const override { |
| 27 | - std::map<Expr, TernaryOp, ExprCmp> &ternary_ops); | 27 | + return arch_param::kV1ArchHardwareConfig.vector_len_size; |
| 28 | + } | ||
| 29 | + [[nodiscard]] static Expr GetMTE2PipeHead(const std::vector<NodeInfo> &node_infos, std::map<Expr, TernaryOp, ExprCmp> &ternary_ops); | ||
| 28 | 30 | ||
| 29 | private: | 31 | private: |
| 30 | std::map<PipeType, PipeHeadPerfFunc> pipes_head_perf; | 32 | std::map<PipeType, PipeHeadPerfFunc> pipes_head_perf; |
| @@ -48,11 +50,15 @@ class TilingScheduleConfigTableV1 : public TilingScheduleConfigTable { | |||
| 48 | [[nodiscard]] TilingScheduleConfig GetModelTilingScheduleConfig() const override { | 50 | [[nodiscard]] TilingScheduleConfig GetModelTilingScheduleConfig() const override { |
| 49 | TilingScheduleConfig config; | 51 | TilingScheduleConfig config; |
| 50 | config.trade_off_config = GetTradeOffConfig(); | 52 | config.trade_off_config = GetTradeOffConfig(); |
| 51 | - config.cache_line_size = 512; // V1 CacheLine 大小为 512 字节 | 53 | + config.cache_line_size = GetCacheLineSize(); |
| 54 | + config.vector_len_size = GetVectorLenSize(); | ||
| 52 | return config; | 55 | return config; |
| 53 | } | 56 | } |
| 54 | [[nodiscard]] uint32_t GetCacheLineSize() const override { | 57 | [[nodiscard]] uint32_t GetCacheLineSize() const override { |
| 55 | - return 512; // V1 CacheLine 大小为 512 字节 | 58 | + return arch_param::kV1ArchHardwareConfig.cache_line_size; |
| 59 | + } | ||
| 60 | + [[nodiscard]] uint32_t GetVectorLenSize() const override { | ||
| 61 | + return arch_param::kV1ArchHardwareConfig.vector_len_size; | ||
| 56 | } | 62 | } |
| 57 | // 新增:V1形态不使能Reduce分核惩罚 | 63 | // 新增:V1形态不使能Reduce分核惩罚 |
| 58 | [[nodiscard]] bool IsCoreNumThresholdPenaltyEnable() const override { | 64 | [[nodiscard]] bool IsCoreNumThresholdPenaltyEnable() const override { |
| @@ -62,7 +68,7 @@ class TilingScheduleConfigTableV1 : public TilingScheduleConfigTable { | |||
| 62 | 68 | ||
| 63 | class TilingScheduleConfigTableV1HeavyOp : public TilingScheduleConfigTableV1 { | 69 | class TilingScheduleConfigTableV1HeavyOp : public TilingScheduleConfigTableV1 { |
| 64 | public: | 70 | public: |
| 65 | - [[nodiscard]] bool IsEnableBlockLoopAutoTune() const override { | 71 | + [[nodiscard]] bool IsEnableBlockLoopAutoTune() const override{ |
| 66 | return false; | 72 | return false; |
| 67 | } | 73 | } |
| 68 | [[nodiscard]] TradeOffConfig GetTradeOffConfig() const override { | 74 | [[nodiscard]] TradeOffConfig GetTradeOffConfig() const override { |
| @@ -1,20 +1,120 @@ | |||
| 1 | /** | 1 | /** |
| 2 | * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | * Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 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 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, | 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. | 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 | #include "arg_list_reorder.h" | 11 | #include "arg_list_reorder.h" |
| 12 | 12 | ||
| 13 | +#include <algorithm> | ||
| 14 | +#include <limits> | ||
| 15 | + | ||
| 13 | namespace att { | 16 | namespace att { |
| 14 | namespace { | 17 | namespace { |
| 15 | constexpr size_t kOrderIdStart = 1; | 18 | constexpr size_t kOrderIdStart = 1; |
| 16 | -const std::vector<std::string> kDefaultNodeWhiteList = {"Data", "Output", "Constant", "Workspace", "TbufData"}; | 19 | +const std::vector<std::string> kDefaultNodeWhiteList = { |
| 17 | -} // namespace | 20 | + "Data", "Output", "Constant", "Workspace", "TbufData" |
| 21 | +}; | ||
| 22 | + | ||
| 23 | +bool GetExprBytes(const Expr &repeat_expr, uint32_t data_type_size, uint64_t &axis_bytes) { | ||
| 24 | + if (data_type_size == 0U) { | ||
| 25 | + return false; | ||
| 26 | + } | ||
| 27 | + uint64_t repeat = 0UL; | ||
| 28 | + if (!repeat_expr.GetConstValue(repeat)) { | ||
| 29 | + return false; | ||
| 30 | + } | ||
| 31 | + if (repeat > std::numeric_limits<uint64_t>::max() / data_type_size) { | ||
| 32 | + return false; | ||
| 33 | + } | ||
| 34 | + axis_bytes = repeat * data_type_size; | ||
| 35 | + return true; | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | +bool IsReduceOrigAxis(const SubAxis *axis, const std::set<std::string> &reduce_axis_ori_axes_set) { | ||
| 39 | + if (axis == nullptr) { | ||
| 40 | + return false; | ||
| 41 | + } | ||
| 42 | + if (reduce_axis_ori_axes_set.find(axis->name) != reduce_axis_ori_axes_set.end()) { | ||
| 43 | + return true; | ||
| 44 | + } | ||
| 45 | + for (const auto &orig_axis : axis->orig_axis_name) { | ||
| 46 | + if (reduce_axis_ori_axes_set.find(orig_axis) != reduce_axis_ori_axes_set.end()) { | ||
| 47 | + return true; | ||
| 48 | + } | ||
| 49 | + } | ||
| 50 | + for (const auto *orig_axis : axis->orig_axis) { | ||
| 51 | + if ((orig_axis != nullptr) && | ||
| 52 | + (reduce_axis_ori_axes_set.find(orig_axis->name) != reduce_axis_ori_axes_set.end())) { | ||
| 53 | + return true; | ||
| 54 | + } | ||
| 55 | + } | ||
| 56 | + return false; | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +bool IsSameOrRelatedAxis(const SubAxis *lhs, const SubAxis *rhs) { | ||
| 60 | + if ((lhs == nullptr) || (rhs == nullptr)) { | ||
| 61 | + return false; | ||
| 62 | + } | ||
| 63 | + if ((lhs == rhs) || (lhs->name == rhs->name)) { | ||
| 64 | + return true; | ||
| 65 | + } | ||
| 66 | + for (const auto &lhs_orig_axis : lhs->orig_axis_name) { | ||
| 67 | + if (std::find(rhs->orig_axis_name.begin(), rhs->orig_axis_name.end(), lhs_orig_axis) != | ||
| 68 | + rhs->orig_axis_name.end()) { | ||
| 69 | + return true; | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + return false; | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +bool TryGetTensorDataTypeSize(const TensorPtr &tensor, uint32_t &data_type_size) { | ||
| 76 | + if ((tensor == nullptr) || (tensor->data_type_size == 0U)) { | ||
| 77 | + return false; | ||
| 78 | + } | ||
| 79 | + data_type_size = tensor->data_type_size; | ||
| 80 | + return true; | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +bool IsDynamicExprBytes(const Expr &repeat_expr, uint32_t data_type_size) { | ||
| 84 | + if (data_type_size == 0U) { | ||
| 85 | + return false; | ||
| 86 | + } | ||
| 87 | + uint64_t axis_bytes = 0UL; | ||
| 88 | + return !GetExprBytes(repeat_expr, data_type_size, axis_bytes); | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +bool IsConstExpr(const Expr &expr) { | ||
| 92 | + uint64_t value = 0UL; | ||
| 93 | + return expr.GetConstValue(value); | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +uint32_t CeilDiv(uint32_t dividend, uint32_t divisor) { | ||
| 97 | + if (divisor == 0U) { | ||
| 98 | + return 0U; | ||
| 99 | + } | ||
| 100 | + return dividend / divisor + ((dividend % divisor) == 0U ? 0U : 1U); | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +Expr GetOriginalAxisRepeat(const SubAxis *axis) { | ||
| 104 | + if (axis == nullptr) { | ||
| 105 | + return Expr(); | ||
| 106 | + } | ||
| 107 | + Expr original_repeat; | ||
| 108 | + bool has_original_repeat = false; | ||
| 109 | + for (const auto *orig_axis : axis->orig_axis) { | ||
| 110 | + if ((orig_axis != nullptr) && orig_axis->repeat.IsValid()) { | ||
| 111 | + original_repeat = has_original_repeat ? af::sym::Mul(original_repeat, orig_axis->repeat) : orig_axis->repeat; | ||
| 112 | + has_original_repeat = true; | ||
| 113 | + } | ||
| 114 | + } | ||
| 115 | + return has_original_repeat ? original_repeat : axis->repeat; | ||
| 116 | +} | ||
| 117 | +} | ||
| 18 | 118 | ||
| 19 | // 初始化arglist的优先级连边图 | 119 | // 初始化arglist的优先级连边图 |
| 20 | // 初始化排序原则:父轴的优先级必须大于子轴,举例说明: | 120 | // 初始化排序原则:父轴的优先级必须大于子轴,举例说明: |
| @@ -89,16 +189,42 @@ bool ArgListReorder::CheckReduce(const SubAxis *dim, const Expr &repeat, const E | |||
| 89 | return CheckAxisProperty(dim, repeat, stride, output_tensors, AxisProperty::kReduce); | 189 | return CheckAxisProperty(dim, repeat, stride, output_tensors, AxisProperty::kReduce); |
| 90 | } | 190 | } |
| 91 | 191 | ||
| 92 | -bool ArgListReorder::IsReduceAxisBlockSplit(const std::vector<SubAxisPtr> &all_axes, | 192 | +uint32_t ArgListReorder::GetCacheLineSize() const { |
| 93 | - const std::set<std::string> &reduce_axis_ori_axes_set) const { | 193 | + if ((tuning_space_ != nullptr) && (tuning_space_->tiling_schedule_config_table != nullptr)) { |
| 94 | - for (const auto &axis : all_axes) { | 194 | + return tuning_space_->tiling_schedule_config_table->GetCacheLineSize(); |
| 95 | - if (!axis->is_bind_multi_core) { | 195 | + } |
| 196 | + return arch_param::kDefaultCacheLineSize; | ||
| 197 | +} | ||
| 198 | + | ||
| 199 | +uint32_t ArgListReorder::GetVectorLenSize() const { | ||
| 200 | + if ((tuning_space_ != nullptr) && (tuning_space_->tiling_schedule_config_table != nullptr)) { | ||
| 201 | + return tuning_space_->tiling_schedule_config_table->GetVectorLenSize(); | ||
| 202 | + } | ||
| 203 | + return arch_param::kDefaultVectorLenSize; | ||
| 204 | +} | ||
| 205 | + | ||
| 206 | +bool ArgListReorder::GetReduceAxisDataTypeSize(const NodeInfo &node, const SubAxis *axis, | ||
| 207 | + const std::set<std::string> &reduce_axis_ori_axes_set, | ||
| 208 | + uint32_t &data_type_size) const { | ||
| 209 | + std::vector<TensorPtr> tensors; | ||
| 210 | + tensors.insert(tensors.end(), node.inputs.begin(), node.inputs.end()); | ||
| 211 | + tensors.insert(tensors.end(), node.outputs.begin(), node.outputs.end()); | ||
| 212 | + for (const auto &tensor : tensors) { | ||
| 213 | + if (!TryGetTensorDataTypeSize(tensor, data_type_size)) { | ||
| 96 | continue; | 214 | continue; |
| 97 | } | 215 | } |
| 98 | - GELOGI("axis[%s] bind multi core", axis->name.c_str()); | 216 | + for (const auto *dim : tensor->dim_info) { |
| 99 | - for (auto &orig_axis : axis->orig_axis_name) { | 217 | + if (IsSameOrRelatedAxis(dim, axis)) { |
| 100 | - GELOGI("bind multi core axis[%s] has orig_axis: [%s]", axis->name.c_str(), orig_axis.c_str()); | 218 | + return true; |
| 101 | - if (reduce_axis_ori_axes_set.find(orig_axis) != reduce_axis_ori_axes_set.end()) { | 219 | + } |
| 220 | + } | ||
| 221 | + } | ||
| 222 | + for (const auto &tensor : tensors) { | ||
| 223 | + if (!TryGetTensorDataTypeSize(tensor, data_type_size)) { | ||
| 224 | + continue; | ||
| 225 | + } | ||
| 226 | + for (const auto *dim : tensor->dim_info) { | ||
| 227 | + if (IsReduceOrigAxis(dim, reduce_axis_ori_axes_set)) { | ||
| 102 | return true; | 228 | return true; |
| 103 | } | 229 | } |
| 104 | } | 230 | } |
| @@ -106,8 +232,122 @@ bool ArgListReorder::IsReduceAxisBlockSplit(const std::vector<SubAxisPtr> &all_a | |||
| 106 | return false; | 232 | return false; |
| 107 | } | 233 | } |
| 108 | 234 | ||
| 109 | -void ArgListReorder::SaveReduceAxisOrig(const SubAxis *reduce_axis, | 235 | +bool ArgListReorder::IsReduceAxisBlockSplit(const std::vector<SubAxisPtr> &all_axes, |
| 110 | - std::set<std::string> &reduce_axis_ori_axes_set) const { | 236 | + const std::set<std::string> &reduce_axis_ori_axes_set) const { |
| 237 | + for (const auto &axis : all_axes) { | ||
| 238 | + if (!axis->is_bind_multi_core || !IsReduceOrigAxis(axis.get(), reduce_axis_ori_axes_set)) { | ||
| 239 | + continue; | ||
| 240 | + } | ||
| 241 | + GELOGI("reduce axis[%s] bind multi core", axis->name.c_str()); | ||
| 242 | + return true; | ||
| 243 | + } | ||
| 244 | + return false; | ||
| 245 | +} | ||
| 246 | + | ||
| 247 | +bool ArgListReorder::IsReduceAxisTileSplit(const std::set<std::string> &reduce_axis_ori_axes_set) const { | ||
| 248 | + for (const auto &axis : tuning_space_->sub_axes) { | ||
| 249 | + if ((axis->axis_type != AxisPosition::INNER) || axis->is_bind_multi_core || | ||
| 250 | + !IsReduceOrigAxis(axis.get(), reduce_axis_ori_axes_set)) { | ||
| 251 | + continue; | ||
| 252 | + } | ||
| 253 | + return true; | ||
| 254 | + } | ||
| 255 | + return false; | ||
| 256 | +} | ||
| 257 | + | ||
| 258 | +bool ArgListReorder::TryBuildReduceTileRuntimeReorderRule(const NodeInfo &node, | ||
| 259 | + const std::set<std::string> &reduce_axis_ori_axes_set, | ||
| 260 | + RuntimeReorderRule &rule) const { | ||
| 261 | + for (const auto &axis : tuning_space_->sub_axes) { | ||
| 262 | + if ((axis->axis_type != AxisPosition::INNER) || axis->is_bind_multi_core || | ||
| 263 | + !IsReduceOrigAxis(axis.get(), reduce_axis_ori_axes_set)) { | ||
| 264 | + continue; | ||
| 265 | + } | ||
| 266 | + uint32_t data_type_size = 0U; | ||
| 267 | + if (!GetReduceAxisDataTypeSize(node, axis.get(), reduce_axis_ori_axes_set, data_type_size)) { | ||
| 268 | + continue; | ||
| 269 | + } | ||
| 270 | + rule.preferred_axis = axis->repeat; | ||
| 271 | + rule.fallback_axis = axis->repeat; | ||
| 272 | + rule.compare_axis = GetOriginalAxisRepeat(axis.get()); | ||
| 273 | + rule.compare_threshold = GetVectorLenSize() / data_type_size; | ||
| 274 | + return true; | ||
| 275 | + } | ||
| 276 | + return false; | ||
| 277 | +} | ||
| 278 | + | ||
| 279 | +bool ArgListReorder::HasSmallTailLargeReduceTile(const NodeInfo &node, | ||
| 280 | + const std::set<std::string> &reduce_axis_ori_axes_set, | ||
| 281 | + RuntimeReorderRule &rule) const { | ||
| 282 | + if (!TryBuildReduceTileRuntimeReorderRule(node, reduce_axis_ori_axes_set, rule)) { | ||
| 283 | + return false; | ||
| 284 | + } | ||
| 285 | + bool has_dynamic = false; | ||
| 286 | + for (const auto &tensor : node.inputs) { | ||
| 287 | + if (tensor == nullptr) { | ||
| 288 | + continue; | ||
| 289 | + } | ||
| 290 | + const size_t dim_size = std::min(tensor->dim_info.size(), tensor->repeat.size()); | ||
| 291 | + for (size_t i = 0U; i < dim_size; ++i) { | ||
| 292 | + const auto *dim = tensor->dim_info[i]; | ||
| 293 | + if ((dim == nullptr) || !dim->is_node_innerest_dim) { | ||
| 294 | + continue; | ||
| 295 | + } | ||
| 296 | + if (tensor->data_type_size == 0U) { | ||
| 297 | + continue; | ||
| 298 | + } | ||
| 299 | + rule.preferred_axis = tensor->repeat[i]; | ||
| 300 | + rule.condition_axis = GetOriginalAxisRepeat(dim); | ||
| 301 | + rule.condition_threshold = CeilDiv(GetCacheLineSize(), tensor->data_type_size); | ||
| 302 | + uint64_t tail_bytes = 0UL; | ||
| 303 | + uint64_t reduce_bytes = 0UL; | ||
| 304 | + const bool has_static_tail = GetExprBytes(rule.condition_axis, tensor->data_type_size, tail_bytes); | ||
| 305 | + const bool has_static_reduce = GetExprBytes(rule.compare_axis, tensor->data_type_size, reduce_bytes); | ||
| 306 | + const bool small_tail = has_static_tail && (tail_bytes < GetCacheLineSize()); | ||
| 307 | + const bool large_reduce = has_static_reduce && (reduce_bytes > GetVectorLenSize()); | ||
| 308 | + if ((has_static_tail && !small_tail) || (has_static_reduce && !large_reduce)) { | ||
| 309 | + continue; | ||
| 310 | + } | ||
| 311 | + has_dynamic = has_dynamic || IsDynamicExprBytes(rule.condition_axis, tensor->data_type_size) || | ||
| 312 | + IsDynamicExprBytes(rule.compare_axis, tensor->data_type_size); | ||
| 313 | + if (small_tail && large_reduce) { | ||
| 314 | + return true; | ||
| 315 | + } | ||
| 316 | + } | ||
| 317 | + } | ||
| 318 | + return has_dynamic; | ||
| 319 | +} | ||
| 320 | + | ||
| 321 | +void ArgListReorder::RecordReduceTileTemplateSelection(const NodeInfo &node, | ||
| 322 | + const std::set<std::string> &reduce_axis_ori_axes_set) { | ||
| 323 | + if (!IsReduceAxisTileSplit(reduce_axis_ori_axes_set)) { | ||
| 324 | + return; | ||
| 325 | + } | ||
| 326 | + RuntimeReorderRule runtime_rule; | ||
| 327 | + if (!HasSmallTailLargeReduceTile(node, reduce_axis_ori_axes_set, runtime_rule)) { | ||
| 328 | + GELOGI( | ||
| 329 | + "[ATT][ReduceTileReorder] Static reduce tile selects fallback single template: keep reduce axis before tail " | ||
| 330 | + "axis, prefer splitting tail axis."); | ||
| 331 | + return; | ||
| 332 | + } | ||
| 333 | + const bool is_static = IsConstExpr(runtime_rule.condition_axis) && IsConstExpr(runtime_rule.compare_axis); | ||
| 334 | + if (is_static) { | ||
| 335 | + GELOGI( | ||
| 336 | + "[ATT][ReduceTileReorder] Static reduce tile selects preferred single template: keep tail axis before reduce " | ||
| 337 | + "axis, prefer splitting reduce axis."); | ||
| 338 | + prefer_reduce_tile_ = true; | ||
| 339 | + return; | ||
| 340 | + } | ||
| 341 | + GELOGI( | ||
| 342 | + "[ATT][ReduceTileReorder] Dynamic reduce tile selects runtime single template: condition axis %s < %u and " | ||
| 343 | + "compare axis %s > %u chooses preferred order at runtime.", | ||
| 344 | + Str(runtime_rule.condition_axis).c_str(), runtime_rule.condition_threshold, | ||
| 345 | + Str(runtime_rule.compare_axis).c_str(), runtime_rule.compare_threshold); | ||
| 346 | + has_dynamic_reduce_tile_reorder_ = true; | ||
| 347 | + dynamic_reduce_tile_reorder_rule_ = runtime_rule; | ||
| 348 | +} | ||
| 349 | + | ||
| 350 | +void ArgListReorder::SaveReduceAxisOrig(const SubAxis *reduce_axis, std::set<std::string> &reduce_axis_ori_axes_set) const { | ||
| 111 | for (SubAxis *ori_axis : reduce_axis->orig_axis) { | 351 | for (SubAxis *ori_axis : reduce_axis->orig_axis) { |
| 112 | GELOGI("reduce axis ori set add: [%s]", ori_axis->name.c_str()); | 352 | GELOGI("reduce axis ori set add: [%s]", ori_axis->name.c_str()); |
| 113 | reduce_axis_ori_axes_set.insert(ori_axis->name); | 353 | reduce_axis_ori_axes_set.insert(ori_axis->name); |
| @@ -142,11 +382,11 @@ void ArgListReorder::FindSpecialArgs() { | |||
| 142 | kDefaultNodeWhiteList.end()) { | 382 | kDefaultNodeWhiteList.end()) { |
| 143 | continue; | 383 | continue; |
| 144 | } | 384 | } |
| 145 | - | 385 | + |
| 146 | const auto &input_tensors = node.inputs; | 386 | const auto &input_tensors = node.inputs; |
| 147 | const auto &output_tensors = node.outputs; | 387 | const auto &output_tensors = node.outputs; |
| 148 | std::set<std::string> reduce_axis_ori_axes_set; | 388 | std::set<std::string> reduce_axis_ori_axes_set; |
| 149 | - | 389 | + |
| 150 | for (const auto &tensor : input_tensors) { | 390 | for (const auto &tensor : input_tensors) { |
| 151 | for (size_t i = 0; i < tensor->dim_info.size(); i++) { | 391 | for (size_t i = 0; i < tensor->dim_info.size(); i++) { |
| 152 | RecordSpecialArgs(node, tensor, i, output_tensors, reduce_axis_ori_axes_set); | 392 | RecordSpecialArgs(node, tensor, i, output_tensors, reduce_axis_ori_axes_set); |
| @@ -154,13 +394,18 @@ void ArgListReorder::FindSpecialArgs() { | |||
| 154 | auto asc_node = node.node_ptr; | 394 | auto asc_node = node.node_ptr; |
| 155 | auto graph = tuning_space_->asc_graph; | 395 | auto graph = tuning_space_->asc_graph; |
| 156 | std::string last_dim_name; | 396 | std::string last_dim_name; |
| 157 | - if (AttUtils::IsLoadStoreNode(asc_node.get()) && (asc_node != nullptr) && (graph != nullptr) && | 397 | + if ((asc_node != nullptr) && (graph != nullptr) && AttUtils::IsLoadStoreNode(asc_node.get()) && |
| 158 | (AttUtils::GetLastTileSplitAxisName(*asc_node, *graph, last_dim_name))) { | 398 | (AttUtils::GetLastTileSplitAxisName(*asc_node, *graph, last_dim_name))) { |
| 159 | load_store_inner_most_dims_.insert(last_dim_name); | 399 | load_store_inner_most_dims_.insert(last_dim_name); |
| 160 | GELOGD("[DFX]Found Tile split axis %s in load/store node", last_dim_name.c_str()); | 400 | GELOGD("[DFX]Found Tile split axis %s in load/store node", last_dim_name.c_str()); |
| 161 | } | 401 | } |
| 162 | } | 402 | } |
| 163 | - tiling_R_ = tiling_R_ || IsReduceAxisBlockSplit(tuning_space_->sub_axes, reduce_axis_ori_axes_set); | 403 | + const bool is_reduce_block_split = IsReduceAxisBlockSplit(tuning_space_->sub_axes, reduce_axis_ori_axes_set); |
| 404 | + tiling_R_ = tiling_R_ || is_reduce_block_split; | ||
| 405 | + if (is_reduce_block_split) { | ||
| 406 | + continue; | ||
| 407 | + } | ||
| 408 | + RecordReduceTileTemplateSelection(node, reduce_axis_ori_axes_set); | ||
| 164 | } | 409 | } |
| 165 | } | 410 | } |
| 166 | 411 | ||
| @@ -172,7 +417,7 @@ ge::Status ArgListReorder::AddEdgeGroups(const std::vector<std::string> &from_ax | |||
| 172 | GE_ASSERT_TRUE(axis_name_2_id_map_.find(from_axis) != axis_name_2_id_map_.end(), | 417 | GE_ASSERT_TRUE(axis_name_2_id_map_.find(from_axis) != axis_name_2_id_map_.end(), |
| 173 | "from axis[%s] cannot be found in arg", from_axis.c_str()); | 418 | "from axis[%s] cannot be found in arg", from_axis.c_str()); |
| 174 | size_t from_axis_id = axis_name_2_id_map_[from_axis]; | 419 | size_t from_axis_id = axis_name_2_id_map_[from_axis]; |
| 175 | - | 420 | + |
| 176 | for (const auto &to_axis : to_axes_group) { | 421 | for (const auto &to_axis : to_axes_group) { |
| 177 | GE_ASSERT_TRUE(axis_name_2_id_map_.find(to_axis) != axis_name_2_id_map_.end(), | 422 | GE_ASSERT_TRUE(axis_name_2_id_map_.find(to_axis) != axis_name_2_id_map_.end(), |
| 178 | "to axis[%s] cannot be found in arg", to_axis.c_str()); | 423 | "to axis[%s] cannot be found in arg", to_axis.c_str()); |
| @@ -214,13 +459,13 @@ ArgListReorder::AxisCategories ArgListReorder::CategorizeAxesByProperty(const ve | |||
| 214 | } else { | 459 | } else { |
| 215 | categories.non_reduce_arg_names.push_back(arg->name); | 460 | categories.non_reduce_arg_names.push_back(arg->name); |
| 216 | } | 461 | } |
| 217 | - | 462 | + |
| 218 | if (broadcast_map_.find(arg->name) != broadcast_map_.end()) { | 463 | if (broadcast_map_.find(arg->name) != broadcast_map_.end()) { |
| 219 | categories.broadcast_arg_names.push_back(arg->name); | 464 | categories.broadcast_arg_names.push_back(arg->name); |
| 220 | } else { | 465 | } else { |
| 221 | categories.non_broadcast_arg_names.push_back(arg->name); | 466 | categories.non_broadcast_arg_names.push_back(arg->name); |
| 222 | } | 467 | } |
| 223 | - | 468 | + |
| 224 | if (innermost_dim_map_.find(arg->name) != innermost_dim_map_.end()) { | 469 | if (innermost_dim_map_.find(arg->name) != innermost_dim_map_.end()) { |
| 225 | categories.innermost_dim_arg_names.push_back(arg->name); | 470 | categories.innermost_dim_arg_names.push_back(arg->name); |
| 226 | } else { | 471 | } else { |
| @@ -272,7 +517,6 @@ ge::Status ArgListReorder::ApplyPriorityRules(bool tiling_R, const AxisCategorie | |||
| 272 | // 连边操作会判环,如果z0z1t->z2t, z2t->z0z1t会成环,因此不会连z2t->z0z1t,这样也是遵循reduce轴优先级高于最内轴这条原则 | 517 | // 连边操作会判环,如果z0z1t->z2t, z2t->z0z1t会成环,因此不会连z2t->z0z1t,这样也是遵循reduce轴优先级高于最内轴这条原则 |
| 273 | ge::Status ArgListReorder::BuildArgListPriorityGraph(const vector<AttAxisPtr> &arg_list, bool tiling_R) { | 518 | ge::Status ArgListReorder::BuildArgListPriorityGraph(const vector<AttAxisPtr> &arg_list, bool tiling_R) { |
| 274 | GE_ASSERT_SUCCESS(InitArgListPriorityGraph(arg_list), "init arg list graph failed"); | 519 | GE_ASSERT_SUCCESS(InitArgListPriorityGraph(arg_list), "init arg list graph failed"); |
| 275 | - FindSpecialArgs(); | ||
| 276 | return ApplyPriorityRules(tiling_R, CategorizeAxesByProperty(arg_list)); | 520 | return ApplyPriorityRules(tiling_R, CategorizeAxesByProperty(arg_list)); |
| 277 | } | 521 | } |
| 278 | 522 | ||
| @@ -321,9 +565,10 @@ std::vector<AttAxisPtr> ArgListReorder::GetNewArgList(const std::vector<size_t> | |||
| 321 | } | 565 | } |
| 322 | 566 | ||
| 323 | // 排序的入口函数 | 567 | // 排序的入口函数 |
| 324 | -ge::Status ArgListReorder::SortArgList(vector<AttAxisPtr> &arg_list, vector<AttAxisPtr> &tiling_R_arg_list) { | 568 | +ge::Status ArgListReorder::SortArgList(vector<AttAxisPtr> &arg_list, vector<AttAxisPtr> &tiling_R_arg_list, |
| 569 | + std::vector<RuntimeReorderRule> *runtime_reorder_rules) { | ||
| 325 | GE_ASSERT_TRUE(!arg_list.empty(), "arg list is empty"); | 570 | GE_ASSERT_TRUE(!arg_list.empty(), "arg list is empty"); |
| 326 | - | 571 | + |
| 327 | graph_ = af::MakeShared<ArgPriorityGraph>(arg_list.size()); | 572 | graph_ = af::MakeShared<ArgPriorityGraph>(arg_list.size()); |
| 328 | GE_ASSERT_NOTNULL(graph_, "Create graph failed"); | 573 | GE_ASSERT_NOTNULL(graph_, "Create graph failed"); |
| 329 | GELOGI("Before reorder ArgList:"); | 574 | GELOGI("Before reorder ArgList:"); |
| @@ -332,9 +577,13 @@ ge::Status ArgListReorder::SortArgList(vector<AttAxisPtr> &arg_list, vector<AttA | |||
| 332 | axis_name_2_id_map_[arg->name] = i; | 577 | axis_name_2_id_map_[arg->name] = i; |
| 333 | GELOGI("arg[%s], id is [%zu]", arg->name.c_str(), i); | 578 | GELOGI("arg[%s], id is [%zu]", arg->name.c_str(), i); |
| 334 | } | 579 | } |
| 580 | + FindSpecialArgs(); | ||
| 335 | // 构建最终优先级连边图 | 581 | // 构建最终优先级连边图 |
| 336 | - GE_ASSERT_SUCCESS(BuildArgListPriorityGraph(arg_list, false), "build arg list graph failed"); | 582 | + GE_ASSERT_SUCCESS(BuildArgListPriorityGraph(arg_list, prefer_reduce_tile_), "build arg list graph failed"); |
| 337 | std::vector<AttAxisPtr> new_arg_list = GetNewArgList(graph_->TopologicalSort(), arg_list); | 583 | std::vector<AttAxisPtr> new_arg_list = GetNewArgList(graph_->TopologicalSort(), arg_list); |
| 584 | + if ((runtime_reorder_rules != nullptr) && has_dynamic_reduce_tile_reorder_) { | ||
| 585 | + runtime_reorder_rules->emplace_back(dynamic_reduce_tile_reorder_rule_); | ||
| 586 | + } | ||
| 338 | 587 | ||
| 339 | if (tiling_R_) { | 588 | if (tiling_R_) { |
| 340 | GELOGI("ReduceAxis BlockSplit, another reorder ArgList:"); | 589 | GELOGI("ReduceAxis BlockSplit, another reorder ArgList:"); |
| @@ -344,7 +593,7 @@ ge::Status ArgListReorder::SortArgList(vector<AttAxisPtr> &arg_list, vector<AttA | |||
| 344 | std::vector<AttAxisPtr> tiling_R_new_arg_list = GetNewArgList(graph_->TopologicalSort(), arg_list); | 593 | std::vector<AttAxisPtr> tiling_R_new_arg_list = GetNewArgList(graph_->TopologicalSort(), arg_list); |
| 345 | tiling_R_arg_list = tiling_R_new_arg_list; | 594 | tiling_R_arg_list = tiling_R_new_arg_list; |
| 346 | } | 595 | } |
| 347 | - | 596 | + |
| 348 | arg_list = new_arg_list; | 597 | arg_list = new_arg_list; |
| 349 | return ge::SUCCESS; | 598 | return ge::SUCCESS; |
| 350 | } | 599 | } |
| @@ -1,9 +1,9 @@ | |||
| 1 | /** | 1 | /** |
| 2 | * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | * Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 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 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, | 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. | 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 | */ |
| @@ -172,7 +172,8 @@ class ArgListReorder { | |||
| 172 | explicit ArgListReorder(const TuningSpacePtr &tuning_space) : tuning_space_(tuning_space) {} | 172 | explicit ArgListReorder(const TuningSpacePtr &tuning_space) : tuning_space_(tuning_space) {} |
| 173 | ~ArgListReorder() = default; | 173 | ~ArgListReorder() = default; |
| 174 | // 排序ArgList入口函数 | 174 | // 排序ArgList入口函数 |
| 175 | - ge::Status SortArgList(vector<AttAxisPtr> &arg_list, vector<AttAxisPtr> &tiling_R_arg_list); | 175 | + ge::Status SortArgList(vector<AttAxisPtr> &arg_list, vector<AttAxisPtr> &tiling_R_arg_list, |
| 176 | + std::vector<RuntimeReorderRule> *runtime_reorder_rules = nullptr); | ||
| 176 | 177 | ||
| 177 | private: | 178 | private: |
| 178 | // 轴属性枚举 | 179 | // 轴属性枚举 |
| @@ -201,6 +202,9 @@ class ArgListReorder { | |||
| 201 | TuningSpacePtr tuning_space_; | 202 | TuningSpacePtr tuning_space_; |
| 202 | ArgPriorityGraphPtr graph_; | 203 | ArgPriorityGraphPtr graph_; |
| 203 | bool tiling_R_ = false; | 204 | bool tiling_R_ = false; |
| 205 | + bool prefer_reduce_tile_ = false; | ||
| 206 | + bool has_dynamic_reduce_tile_reorder_ = false; | ||
| 207 | + RuntimeReorderRule dynamic_reduce_tile_reorder_rule_; | ||
| 204 | 208 | ||
| 205 | // 成员函数保持原名 | 209 | // 成员函数保持原名 |
| 206 | bool CheckReduce(const SubAxis *dim, const Expr &repeat, const Expr &stride, | 210 | bool CheckReduce(const SubAxis *dim, const Expr &repeat, const Expr &stride, |
| @@ -210,10 +214,20 @@ class ArgListReorder { | |||
| 210 | bool CheckAxisProperty(const SubAxis *dim, const Expr &repeat, const Expr &stride, | 214 | bool CheckAxisProperty(const SubAxis *dim, const Expr &repeat, const Expr &stride, |
| 211 | const std::vector<TensorPtr> &output_tensors, AxisProperty property); | 215 | const std::vector<TensorPtr> &output_tensors, AxisProperty property); |
| 212 | void FindSpecialArgs(); | 216 | void FindSpecialArgs(); |
| 213 | - ge::Status AddEdgeGroups(const std::vector<std::string> &from_axes_group, | 217 | + ge::Status AddEdgeGroups(const std::vector<std::string> &from_axes_group, const std::vector<std::string> &to_axes_group); |
| 214 | - const std::vector<std::string> &to_axes_group); | ||
| 215 | bool IsReduceAxisBlockSplit(const std::vector<SubAxisPtr> &all_axes, | 218 | bool IsReduceAxisBlockSplit(const std::vector<SubAxisPtr> &all_axes, |
| 216 | const std::set<std::string> &reduce_axis_ori_axes_set) const; | 219 | const std::set<std::string> &reduce_axis_ori_axes_set) const; |
| 220 | + bool IsReduceAxisTileSplit(const std::set<std::string> &reduce_axis_ori_axes_set) const; | ||
| 221 | + uint32_t GetCacheLineSize() const; | ||
| 222 | + uint32_t GetVectorLenSize() const; | ||
| 223 | + bool GetReduceAxisDataTypeSize(const NodeInfo &node, const SubAxis *axis, | ||
| 224 | + const std::set<std::string> &reduce_axis_ori_axes_set, | ||
| 225 | + uint32_t &data_type_size) const; | ||
| 226 | + bool TryBuildReduceTileRuntimeReorderRule(const NodeInfo &node, const std::set<std::string> &reduce_axis_ori_axes_set, | ||
| 227 | + RuntimeReorderRule &rule) const; | ||
| 228 | + bool HasSmallTailLargeReduceTile(const NodeInfo &node, const std::set<std::string> &reduce_axis_ori_axes_set, | ||
| 229 | + RuntimeReorderRule &rule) const; | ||
| 230 | + void RecordReduceTileTemplateSelection(const NodeInfo &node, const std::set<std::string> &reduce_axis_ori_axes_set); | ||
| 217 | void SaveReduceAxisOrig(const SubAxis *reduce_axis, std::set<std::string> &reduce_axis_ori_axes_set) const; | 231 | void SaveReduceAxisOrig(const SubAxis *reduce_axis, std::set<std::string> &reduce_axis_ori_axes_set) const; |
| 218 | AxisCategories CategorizeAxesByProperty(const vector<AttAxisPtr> &arg_list); | 232 | AxisCategories CategorizeAxesByProperty(const vector<AttAxisPtr> &arg_list); |
| 219 | ge::Status ApplyPriorityRules(bool tiling_R, const AxisCategories &categories); | 233 | ge::Status ApplyPriorityRules(bool tiling_R, const AxisCategories &categories); |
| @@ -242,6 +242,7 @@ void ProcessTilingR(std::vector<ModelInfo> &model_info_list, const ModelInfo &mo | |||
| 242 | ModelInfo model_info_tiling_R = model_info; | 242 | ModelInfo model_info_tiling_R = model_info; |
| 243 | model_info_tiling_R.arg_list = tiling_R_arg_list; | 243 | model_info_tiling_R.arg_list = tiling_R_arg_list; |
| 244 | model_info_tiling_R.sub_case_tag = "R"; | 244 | model_info_tiling_R.sub_case_tag = "R"; |
| 245 | + model_info_tiling_R.runtime_reorder_rules.clear(); | ||
| 245 | model_info_list.emplace_back(model_info_tiling_R); | 246 | model_info_list.emplace_back(model_info_tiling_R); |
| 246 | } | 247 | } |
| 247 | 248 | ||
| @@ -284,7 +285,9 @@ ge::Status GenerateModelInfo(const std::vector<af::AscGraph> &graph_list, std::v | |||
| 284 | GE_ASSERT_SUCCESS(GenerateModelInfo(graph, model_info, tuning_space, tiling_key), "General model info failed."); | 285 | GE_ASSERT_SUCCESS(GenerateModelInfo(graph, model_info, tuning_space, tiling_key), "General model info failed."); |
| 285 | if (IsAxesReorderAlgorithm()) { | 286 | if (IsAxesReorderAlgorithm()) { |
| 286 | ArgListReorder arg_list_reorder(tuning_space); | 287 | ArgListReorder arg_list_reorder(tuning_space); |
| 287 | - GE_ASSERT_SUCCESS(arg_list_reorder.SortArgList(model_info.arg_list, tiling_R_arg_list), "Sort arg list failed."); | 288 | + GE_ASSERT_SUCCESS( |
| 289 | + arg_list_reorder.SortArgList(model_info.arg_list, tiling_R_arg_list, &model_info.runtime_reorder_rules), | ||
| 290 | + "Sort arg list failed."); | ||
| 288 | } | 291 | } |
| 289 | const auto iter = options.find(kTilingDataTypeName); | 292 | const auto iter = options.find(kTilingDataTypeName); |
| 290 | const std::string tiling_data_type = (iter != options.cend()) ? iter->second : ""; | 293 | const std::string tiling_data_type = (iter != options.cend()) ? iter->second : ""; |
| @@ -1053,6 +1053,89 @@ std::string AxesReorderSolverGen::SetTilingVars(VarsType var_type) { | |||
| 1053 | return strs; | 1053 | return strs; |
| 1054 | } | 1054 | } |
| 1055 | 1055 | ||
| 1056 | +int32_t AxesReorderSolverGen::GetLocalBufferVarIndex(const Expr &expr) const { | ||
| 1057 | + for (size_t i = 0U; i < local_buffer_tiling_vars_.size(); ++i) { | ||
| 1058 | + if (local_buffer_tiling_vars_[i] == expr) { | ||
| 1059 | + return static_cast<int32_t>(i); | ||
| 1060 | + } | ||
| 1061 | + } | ||
| 1062 | + return -1; | ||
| 1063 | +} | ||
| 1064 | + | ||
| 1065 | +std::string AxesReorderSolverGen::GenRuntimeExprValue(const Expr &expr) const { | ||
| 1066 | + if (expr.IsConstExpr()) { | ||
| 1067 | + return Str(expr); | ||
| 1068 | + } | ||
| 1069 | + const int32_t local_idx = GetLocalBufferVarIndex(expr); | ||
| 1070 | + if (local_idx >= 0) { | ||
| 1071 | + return Str(expr) + ".upper_bound(" + Str(expr) + ".upper_bound_vars)"; | ||
| 1072 | + } | ||
| 1073 | + if (expr.IsVariableExpr()) { | ||
| 1074 | + return Str(expr) + ".value"; | ||
| 1075 | + } | ||
| 1076 | + return GenRuntimeCompoundExprValue(expr); | ||
| 1077 | +} | ||
| 1078 | + | ||
| 1079 | +std::string AxesReorderSolverGen::GenRuntimeCompoundExprValue(const Expr &expr) const { | ||
| 1080 | + Expr runtime_expr = expr; | ||
| 1081 | + std::vector<std::pair<Expr, Expr>> subs_vars; | ||
| 1082 | + std::vector<std::pair<std::string, std::string>> runtime_values; | ||
| 1083 | + size_t runtime_idx = 0U; | ||
| 1084 | + for (const auto &arg : expr.FreeSymbols()) { | ||
| 1085 | + const std::string runtime_name = "__runtime_expr_" + std::to_string(runtime_idx++) + "__"; | ||
| 1086 | + subs_vars.emplace_back(arg, CreateExpr(runtime_name.c_str())); | ||
| 1087 | + runtime_values.emplace_back(runtime_name, GenRuntimeExprValue(arg)); | ||
| 1088 | + } | ||
| 1089 | + runtime_expr = runtime_expr.Subs(subs_vars); | ||
| 1090 | + std::string runtime_expr_str = Str(runtime_expr); | ||
| 1091 | + for (const auto &runtime_value : runtime_values) { | ||
| 1092 | + size_t pos = runtime_expr_str.find(runtime_value.first); | ||
| 1093 | + while (pos != std::string::npos) { | ||
| 1094 | + runtime_expr_str.replace(pos, runtime_value.first.size(), runtime_value.second); | ||
| 1095 | + pos = runtime_expr_str.find(runtime_value.first, pos + runtime_value.second.size()); | ||
| 1096 | + } | ||
| 1097 | + } | ||
| 1098 | + return runtime_expr_str; | ||
| 1099 | +} | ||
🔵 Low Priority
虽然当前占位名格式(带序号 + 双下划线)与正常 Expr 名称冲突概率极低,但随着系统演进,存在潜在风险。建议使用更安全的替换方式,例如按 token 边界替换,或在替换前对占位名做更唯一的编码(如加入随机后缀或使用不合法 C++ 标识符字符)。 建议:考虑在占位名中加入不会出现在正常 Expr 名中的字符(如 ![]() ![]() 不准确? | |||
| 1100 | + | ||
| 1101 | +std::string AxesReorderSolverGen::GenRuntimeReorderRule(const RuntimeReorderRule &rule) { | ||
| 1102 | + const int32_t preferred_idx = GetLocalBufferVarIndex(rule.preferred_axis); | ||
| 1103 | + const int32_t fallback_idx = GetLocalBufferVarIndex(rule.fallback_axis); | ||
| 1104 | + if ((preferred_idx < 0) || (fallback_idx < 0) || (preferred_idx == fallback_idx)) { | ||
| 1105 | + return ""; | ||
| 1106 | + } | ||
| 1107 | + std::string code; | ||
| 1108 | + code += " if ((" + GenRuntimeExprValue(rule.condition_axis) + " < " + std::to_string(rule.condition_threshold) + | ||
| 1109 | + ") && (" + GenRuntimeExprValue(rule.compare_axis) + " > " + std::to_string(rule.compare_threshold) + ")) {\n"; | ||
| 1110 | + code += " OP_LOGI(OP_NAME, \"[ATT][ReduceTileReorder] Runtime reduce tile reorder chooses preferred axis "; | ||
| 1111 | + code += Str(rule.preferred_axis); | ||
| 1112 | + code += " before fallback axis "; | ||
| 1113 | + code += Str(rule.fallback_axis); | ||
| 1114 | + code += ", prefer splitting reduce axis.\");\n"; | ||
| 1115 | + if (preferred_idx > fallback_idx) { | ||
| 1116 | + code += " auto *runtime_preferred_var = input.local_buffer_vars[" + std::to_string(preferred_idx) + "];\n"; | ||
| 1117 | + code += " input.local_buffer_vars[" + std::to_string(preferred_idx) + "] = input.local_buffer_vars[" + | ||
| 1118 | + std::to_string(fallback_idx) + "];\n"; | ||
| 1119 | + code += " input.local_buffer_vars[" + std::to_string(fallback_idx) + "] = runtime_preferred_var;\n"; | ||
| 1120 | + } | ||
| 1121 | + code += " } else {\n"; | ||
| 1122 | + code += " OP_LOGI(OP_NAME, \"[ATT][ReduceTileReorder] Runtime reduce tile reorder keeps fallback axis "; | ||
| 1123 | + code += Str(rule.fallback_axis); | ||
| 1124 | + code += " before preferred axis "; | ||
| 1125 | + code += Str(rule.preferred_axis); | ||
| 1126 | + code += ", prefer splitting tail axis.\");\n"; | ||
| 1127 | + code += " }\n"; | ||
| 1128 | + return code; | ||
| 1129 | +} | ||
| 1130 | + | ||
| 1131 | +std::string AxesReorderSolverGen::GenRuntimeReorderRules() { | ||
| 1132 | + std::string code; | ||
| 1133 | + for (const auto &rule : runtime_reorder_rules_) { | ||
| 1134 | + code += GenRuntimeReorderRule(rule); | ||
| 1135 | + } | ||
| 1136 | + return code; | ||
| 1137 | +} | ||
| 1138 | + | ||
| 1056 | std::string AxesReorderSolverGen::GenInput(const TradeOffConfig &trade_off_config, std::vector<Expr> &all_cons) { | 1139 | std::string AxesReorderSolverGen::GenInput(const TradeOffConfig &trade_off_config, std::vector<Expr> &all_cons) { |
| 1057 | std::string strs; | 1140 | std::string strs; |
| 1058 | strs += " AxesReorderSolverInput input;\n"; | 1141 | strs += " AxesReorderSolverInput input;\n"; |
| @@ -1339,6 +1422,34 @@ std::string AxesReorderSolverGen::IsEnableBlockLoopTradeOffByPerf() const { | |||
| 1339 | return res; | 1422 | return res; |
| 1340 | } | 1423 | } |
| 1341 | 1424 | ||
| 1425 | +std::string AxesReorderSolverGen::GenPendingSearchConfigOverride() { | ||
| 1426 | + std::string codes; | ||
| 1427 | + if (!(enable_autofuse_pgo_ || is_inductor_scene_)) { | ||
| 1428 | + return codes; | ||
| 1429 | + } | ||
| 1430 | + const ge::char_t *runtime_enable_multicore_ub_tradeoff = | ||
| 1431 | + (NeedUBMultiCoreBalance() && | ||
| 1432 | + (enable_multicore_ub_tradeoff_ || tiling_schedule_config_.trade_off_config.is_enable)) | ||
| 1433 | + ? "true" | ||
| 1434 | + : "false"; | ||
| 1435 | + codes += " bool runtime_enable_multicore_ub_tradeoff = "; | ||
| 1436 | + codes += runtime_enable_multicore_ub_tradeoff; | ||
| 1437 | + codes += ";\n"; | ||
| 1438 | + codes += " if (pending_search_cfg_ != nullptr) {\n"; | ||
| 1439 | + codes += " if (pending_search_cfg_->ub_threshold_enabled) {\n"; | ||
| 1440 | + codes += " input.ub_threshold = pending_search_cfg_->ub_threshold;\n"; | ||
| 1441 | + codes += " }\n"; | ||
| 1442 | + codes += " if (pending_search_cfg_->corenum_threshold_enabled) {\n"; | ||
| 1443 | + codes += " input.corenum_threshold = pending_search_cfg_->corenum_threshold;\n"; | ||
| 1444 | + codes += " }\n"; | ||
| 1445 | + codes += " runtime_enable_multicore_ub_tradeoff = pending_search_cfg_->enable_multicore_ub_tradeoff;\n"; | ||
| 1446 | + codes += " }\n"; | ||
| 1447 | + codes += " const bool runtime_enable_block_loop_trade_off_by_perf = "; | ||
| 1448 | + codes += IsEnableBlockLoopTradeOffByPerf(); | ||
| 1449 | + codes += " && !runtime_enable_multicore_ub_tradeoff;\n"; | ||
| 1450 | + return codes; | ||
| 1451 | +} | ||
| 1452 | + | ||
| 1342 | std::string AxesReorderSolverGen::GenSolverFuncImpl() { | 1453 | std::string AxesReorderSolverGen::GenSolverFuncImpl() { |
| 1343 | std::string codes; | 1454 | std::string codes; |
| 1344 | std::vector<Expr> all_cons; | 1455 | std::vector<Expr> all_cons; |
| @@ -1350,6 +1461,7 @@ std::string AxesReorderSolverGen::GenSolverFuncImpl() { | |||
| 1350 | codes += GenInputInfo(all_cons, local_buffer_cons, mc_mixed_cons); | 1461 | codes += GenInputInfo(all_cons, local_buffer_cons, mc_mixed_cons); |
| 1351 | // 直接使用 ModelInfo 中的 TilingScheduleConfig | 1462 | // 直接使用 ModelInfo 中的 TilingScheduleConfig |
| 1352 | codes += GenInput(tiling_schedule_config_.trade_off_config, all_cons); | 1463 | codes += GenInput(tiling_schedule_config_.trade_off_config, all_cons); |
| 1464 | + codes += GenRuntimeReorderRules(); | ||
| 1353 | // 支持二次Tiling:使用调整后的核数比例(需在创建solver之前设置) | 1465 | // 支持二次Tiling:使用调整后的核数比例(需在创建solver之前设置) |
| 1354 | // 注意:g_secondary_tiling_ratio 只在 enable_group_parallel_ 为 true 时才声明 | 1466 | // 注意:g_secondary_tiling_ratio 只在 enable_group_parallel_ 为 true 时才声明 |
| 1355 | if (enable_group_parallel_ && group_num_ > 1) { | 1467 | if (enable_group_parallel_ && group_num_ > 1) { |
| @@ -1361,29 +1473,7 @@ std::string AxesReorderSolverGen::GenSolverFuncImpl() { | |||
| 1361 | codes += " input.corenum_threshold = g_secondary_tiling_ratio;\n"; | 1473 | codes += " input.corenum_threshold = g_secondary_tiling_ratio;\n"; |
| 1362 | codes += " }\n"; | 1474 | codes += " }\n"; |
| 1363 | } | 1475 | } |
| 1364 | - // Override solver input thresholds from pending_search_cfg_ (set by ExecutePGOSolver) | 1476 | + codes += GenPendingSearchConfigOverride(); |
| 1365 | - if (enable_autofuse_pgo_ || is_inductor_scene_) { | ||
| 1366 | - const ge::char_t *runtime_enable_multicore_ub_tradeoff = | ||
| 1367 | - (NeedUBMultiCoreBalance() && | ||
| 1368 | - (enable_multicore_ub_tradeoff_ || tiling_schedule_config_.trade_off_config.is_enable)) | ||
| 1369 | - ? "true" | ||
| 1370 | - : "false"; | ||
| 1371 | - codes += " bool runtime_enable_multicore_ub_tradeoff = "; | ||
| 1372 | - codes += runtime_enable_multicore_ub_tradeoff; | ||
| 1373 | - codes += ";\n"; | ||
| 1374 | - codes += " if (pending_search_cfg_ != nullptr) {\n"; | ||
| 1375 | - codes += " if (pending_search_cfg_->ub_threshold_enabled) {\n"; | ||
| 1376 | - codes += " input.ub_threshold = pending_search_cfg_->ub_threshold;\n"; | ||
| 1377 | - codes += " }\n"; | ||
| 1378 | - codes += " if (pending_search_cfg_->corenum_threshold_enabled) {\n"; | ||
| 1379 | - codes += " input.corenum_threshold = pending_search_cfg_->corenum_threshold;\n"; | ||
| 1380 | - codes += " }\n"; | ||
| 1381 | - codes += " runtime_enable_multicore_ub_tradeoff = pending_search_cfg_->enable_multicore_ub_tradeoff;\n"; | ||
| 1382 | - codes += " }\n"; | ||
| 1383 | - codes += " const bool runtime_enable_block_loop_trade_off_by_perf = "; | ||
| 1384 | - codes += IsEnableBlockLoopTradeOffByPerf(); | ||
| 1385 | - codes += " && !runtime_enable_multicore_ub_tradeoff;\n"; | ||
| 1386 | - } | ||
| 1387 | codes += " " + class_name + " solver(input);\n"; | 1477 | codes += " " + class_name + " solver(input);\n"; |
| 1388 | codes += GenSolverRunInvoke(class_name); | 1478 | codes += GenSolverRunInvoke(class_name); |
| 1389 | codes += GenEmptyTensorCheckInSolver(); | 1479 | codes += GenEmptyTensorCheckInSolver(); |
| @@ -24,234 +24,227 @@ | |||
| 24 | #include "generator/solver_pass_gen/pgo_config_setters_mixin.h" | 24 | #include "generator/solver_pass_gen/pgo_config_setters_mixin.h" |
| 25 | 25 | ||
| 26 | namespace att { | 26 | namespace att { |
| 27 | -enum class ConsType { | 27 | + enum class ConsType { |
| 28 | - BUFFER = 0, | 28 | + BUFFER = 0, |
| 29 | - CUT = 1, | 29 | + CUT = 1, |
| 30 | - MCMIXED = 2, | 30 | + MCMIXED = 2, |
| 31 | - ALL = 3, | 31 | + ALL = 3, |
| 32 | -}; | ||
| 33 | - | ||
| 34 | -enum class InputType { | ||
| 35 | - INPUT = 0, | ||
| 36 | - TILING = 1, | ||
| 37 | -}; | ||
| 38 | - | ||
| 39 | -enum class VarsType { | ||
| 40 | - PUREMC = 0, | ||
| 41 | - LOCALBUFFER = 1, | ||
| 42 | -}; | ||
| 43 | - | ||
| 44 | -class AxesReorderSolverGen : public SolverGen, | ||
| 45 | - public InputOutputSettersMixin<AxesReorderSolverGen>, | ||
| 46 | - public PgoConfigSettersMixin<AxesReorderSolverGen> { | ||
| 47 | - public: | ||
| 48 | - explicit AxesReorderSolverGen(const std::string &tiling_case_id, const std::string &type_name) | ||
| 49 | - : SolverGen(tiling_case_id, type_name) {} | ||
| 50 | - ~AxesReorderSolverGen() override = default; | ||
| 51 | - std::string GenSolverClassImpl() override; | ||
| 52 | - std::string GenSolverFuncImpl() override; | ||
| 53 | - std::string GenPGOSolverFilter(); | ||
| 54 | - std::string GenSolverFuncInvoke() override; | ||
| 55 | - std::string GenPGOSolverClassImpl(); | ||
| 56 | - std::string GenPGOSolverFuncImpl(); | ||
| 57 | - | ||
| 58 | - void SetInputArgs(const std::vector<Expr> &input_args) { | ||
| 59 | - input_args_ = input_args; | ||
| 60 | - } | ||
| 61 | - void SetConstArgs(const ExprUintMap &const_vars) { | ||
| 62 | - std::vector<Expr> const_args; | ||
| 63 | - const_vars_map_ = const_vars; | ||
| 64 | - for (const auto &pair : const_vars_map_) { | ||
| 65 | - const_args.push_back(pair.first); | ||
| 66 | - } | ||
| 67 | - const_args_ = const_args; | ||
| 68 | - } | ||
| 69 | - void SetBufferUseAlg(const std::map<HardwareDef, Expr> &hardware_use_map) { | ||
| 70 | - hardware_use_map_ = hardware_use_map; | ||
| 71 | - } | ||
| 72 | - void SetArgAlignMap(const ExprExprMap &arg_align_map) { | ||
| 73 | - arg_align_map_ = arg_align_map; | ||
| 74 | - } | ||
| 75 | - void SetArgPromptAlignMap(const ExprUintMap &arg_prompt_align_map) { | ||
| 76 | - arg_prompt_align_map_ = arg_prompt_align_map; | ||
| 77 | - } | ||
| 78 | - void SetArgDataTypeSizeMap(const ExprUintMap &data_type_size_map) { | ||
| 79 | - data_type_size_map_ = data_type_size_map; | ||
| 80 | - } | ||
| 81 | - void SetInputAlign(const ExprExprMap &input_align); | ||
| 82 | - void SetTotalCutCons(const std::vector<Expr> &total_cut_cons) { | ||
| 83 | - total_cut_cons_ = total_cut_cons; | ||
| 84 | - } | ||
| 85 | - void SetFromAxesMap(const std::map<Expr, std::vector<Expr>, ExprCmp> &from_axes_map) { | ||
| 86 | - from_axes_map_ = from_axes_map; | ||
| 87 | - } | ||
| 88 | - void SetVarPriority(const ExprUintMap &priority) { | ||
| 89 | - priority_map_ = priority; | ||
| 90 | - } | ||
| 91 | - void SetContainerExpr(const ExprExprMap &container_expr) { | ||
| 92 | - container_expr_ = container_expr; | ||
| 93 | - } | ||
| 94 | - void SetContainerNames(const std::map<Expr, std::string, ExprCmp> &container_names) { | ||
| 95 | - container_names_ = container_names; | ||
| 96 | - } | ||
| 97 | - void SetReplaceVars(const std::vector<std::pair<Expr, Expr>> &replace_vars) { | ||
| 98 | - for (const auto &var : replace_vars) { | ||
| 99 | - replace_vars_.emplace_back(var); | ||
| 100 | - } | ||
| 101 | - } | ||
| 102 | - void SetTernaryOps(const std::map<Expr, TernaryOp, ExprCmp> &ternary_ops) { | ||
| 103 | - ternary_ops_ = ternary_ops; | ||
| 104 | - } | ||
| 105 | - | ||
| 106 | - void SetExeTimeMap(const std::map<Expr, std::vector<Expr>, ExprCmp> &exe_time_map) { | ||
| 107 | - for (const auto &pair : exe_time_map) { | ||
| 108 | - exe_time_map_[pair.first] = pair.second; | ||
| 109 | - } | ||
| 110 | - } | ||
| 111 | - void Arrange(); | ||
| 112 | - void SetObjFunc(const Expr &head_cost, const std::map<PipeType, Expr> pipe_2_obj_map) { | ||
| 113 | - head_cost_ = head_cost; | ||
| 114 | - pipe_2_obj_map_ = pipe_2_obj_map; | ||
| 115 | - } | ||
| 116 | - void SetIsConcatOuterMap(const ExprUintMap &is_concat_outer_map) { | ||
| 117 | - is_concat_outer_map_ = is_concat_outer_map; | ||
| 118 | - } | ||
| 119 | - void SetConcatInnerDims(const std::vector<Expr> &concat_inner_dims) { | ||
| 120 | - concat_inner_dims_ = concat_inner_dims; | ||
| 121 | - } | ||
| 122 | - void SetUBThreshold(const double &ub_threshold) { | ||
| 123 | - ub_threshold_ = ub_threshold; | ||
| 124 | - } | ||
| 125 | - void SetCoreNumThreshold(const double &corenum_threshold) { | ||
| 126 | - corenum_threshold_ = corenum_threshold; | ||
| 127 | }; | 32 | }; |
| 128 | - void SetReservedUbSize(const Expr &reserved_ub_size) { | ||
| 129 | - reserved_ub_size_ = reserved_ub_size; | ||
| 130 | - }; | ||
| 131 | - void SetHighPerfTiling(const bool enable_high_perf) { | ||
| 132 | - enable_high_perf_ = enable_high_perf; | ||
| 133 | - } | ||
| 134 | - void SetEnableEqualOrder(const bool enable_equal_order) { | ||
| 135 | - enable_equal_order_ = enable_equal_order; | ||
| 136 | - } | ||
| 137 | - void SetSearchArgs(const std::vector<Expr> &search_args) { | ||
| 138 | - search_args_ = search_args; | ||
| 139 | - } | ||
| 140 | - void SetArrangeCode(const std::string &arrange_code) { | ||
| 141 | - arrange_code_ = arrange_code; | ||
| 142 | - } | ||
| 143 | - void SetTilingScheduleConfigTable(const TilingScheduleConfigTable *tiling_schedule_config_table) { | ||
| 144 | - tiling_schedule_config_table_ = tiling_schedule_config_table; | ||
| 145 | - } | ||
| 146 | - void SetTilingScheduleConfig(const TilingScheduleConfig &tiling_schedule_config) { | ||
| 147 | - tiling_schedule_config_ = tiling_schedule_config; | ||
| 148 | - } | ||
| 149 | - void SetCacheLineConfig(const vector<CacheLineConfig> *cache_line_config) { | ||
| 150 | - cache_line_config_ = cache_line_config; | ||
| 151 | - } | ||
| 152 | - void SetEnableParallel(bool enable_parallel) { | ||
| 153 | - enable_group_parallel_ = enable_parallel; | ||
| 154 | - } | ||
| 155 | - void SetTilingCaseIdent(TilingCaseIdent tiling_case_ident) { | ||
| 156 | - tiling_case_ident_ = tiling_case_ident; | ||
| 157 | - } | ||
| 158 | - void SetGroupNum(size_t group_num) { | ||
| 159 | - group_num_ = group_num; | ||
| 160 | - } | ||
| 161 | 33 | ||
| 162 | - private: | 34 | + enum class InputType { |
| 163 | - static bool VarCmp(Expr &a, Expr &b); | 35 | + INPUT = 0, |
| 164 | - void ReorderVars(); | 36 | + TILING = 1, |
| 165 | - void GetMCArgs(); | 37 | + }; |
| 166 | - void GetLocalBufferTilingVars(); | 38 | + |
| 167 | - void GetRelatedArgs(const Expr &expr, std::vector<Expr> &related_args) const; | 39 | + enum class VarsType { |
| 168 | - bool NeedUBMultiCoreBalance(); | 40 | + PUREMC = 0, |
| 169 | - std::string GenGetStaticInputParam(const HardwareDef &hardware_type, bool no_type = false) const; | 41 | + LOCALBUFFER = 1, |
| 170 | - std::string GenGetObjStaticInputParam(bool no_type = false); | 42 | + }; |
| 171 | - std::string GenGetObjStaticFunc(); | 43 | + |
| 172 | - void CollectInitialWorkList(std::vector<Expr> &work_list) const; | 44 | + class AxesReorderSolverGen : public SolverGen, public InputOutputSettersMixin<AxesReorderSolverGen>, |
| 173 | - void CollectNeededTenaryVarsClosure(std::vector<Expr> &work_list, std::set<std::string> &needed_vars) const; | 45 | + public PgoConfigSettersMixin<AxesReorderSolverGen> { |
| 174 | - std::string GenTenaryVarDecls(const std::set<std::string> &needed_vars); | 46 | + public: |
| 175 | - std::string GenSingleTenaryVar(const TernaryOp &op, const std::string &var_name, std::set<std::string> &declared_vars, | 47 | + explicit AxesReorderSolverGen(const std::string &tiling_case_id, const std::string &type_name) |
| 176 | - std::map<std::string, std::string> &content_to_first_var); | 48 | + : SolverGen(tiling_case_id, type_name) {} |
| 177 | - std::string GenGetTilingDataObjStaticFunc(); | 49 | + ~AxesReorderSolverGen() override = default; |
| 178 | - std::string GenObjFunc(); | 50 | + std::string GenSolverClassImpl() override; |
| 179 | - std::string GenGetUbSizeStaticFunc(); | 51 | + std::string GenSolverFuncImpl() override; |
| 180 | - std::string GenGetTilingDataUbSizeStaticFunc(); | 52 | + std::string GenPGOSolverFilter(); |
| 181 | - std::string GenGetBlockDimStatic(Expr &corenum_cons); | 53 | + std::string GenSolverFuncInvoke() override; |
| 182 | - std::string GenGetTilingDataBlockDimStatic(Expr &corenum_cons); | 54 | + std::string GenPGOSolverClassImpl(); |
| 183 | - std::string GenUBThresholdFunc(); | 55 | + std::string GenPGOSolverFuncImpl(); |
| 184 | - std::string GenUBSizeCacheLineFunc(); | 56 | + |
| 185 | - std::string GenCoreNumFunc(); | 57 | + void SetInputArgs(const std::vector<Expr> &input_args) { input_args_ = input_args; } |
| 186 | - std::pair<std::vector<Expr>, std::vector<Expr>> SortConsArgs(const Expr &expr, bool &is_mc_mixed); | 58 | + void SetConstArgs(const ExprUintMap &const_vars) { |
| 187 | - std::string ObtainRelatedVars(Expr &expr); | 59 | + std::vector<Expr> const_args; |
| 188 | - std::string InitiateArgs(); | 60 | + const_vars_map_ = const_vars; |
| 189 | - std::string InitiateBufferConsArgs(uint32_t cons_idx, HardwareDef hardware, const Expr &cons); | 61 | + for (const auto &pair : const_vars_map_) { |
| 190 | - std::string InitiateCutConsArgs(uint32_t cons_idx, const Expr &cons, bool &is_mc_mixed); | 62 | + const_args.push_back(pair.first); |
| 191 | - std::string GenConsUbFunc(uint32_t cons_idx, const std::vector<Expr> &rel_tiling_vars, | 63 | + } |
| 192 | - const std::vector<Expr> &rel_cons_vars) const; | 64 | + const_args_ = const_args; |
| 193 | - std::string GenConsFunc(uint32_t cons_idx, ConsType cons_type, const Expr &cons, | 65 | + } |
| 194 | - const std::vector<Expr> &rel_tiling_vars, const std::vector<Expr> &rel_cons_vars) const; | 66 | + void SetBufferUseAlg(const std::map<HardwareDef, Expr> &hardware_use_map) { |
| 195 | - std::string SetVarCons(const Expr &arg, const std::vector<Expr> &all_cons) const; | 67 | + hardware_use_map_ = hardware_use_map; |
| 196 | - std::string GenUpperBoundFunc(const Expr &var); | 68 | + } |
| 197 | - std::string GenUpperBoundInfo(const Expr &var); | 69 | + void SetArgAlignMap(const ExprExprMap &arg_align_map) { |
| 198 | - std::string SetInputVars(InputType input_type); | 70 | + arg_align_map_ = arg_align_map; |
| 199 | - std::string SetInputCons(std::vector<Expr> cons) const; | 71 | + } |
| 200 | - std::string SetTilingVars(VarsType var_type); | 72 | + void SetArgPromptAlignMap(const ExprUintMap &arg_prompt_align_map) { |
| 201 | - void InitConcatPromptAlign(const Expr &local_var, const uint32_t prompt_align, std::string &strs); | 73 | + arg_prompt_align_map_ = arg_prompt_align_map; |
| 202 | - std::string GenInputInfo(std::vector<Expr> &all_cons, std::vector<Expr> &local_buffer_cons, | 74 | + } |
| 203 | - std::vector<Expr> &mc_mixed_cons); | 75 | + void SetArgDataTypeSizeMap(const ExprUintMap &data_type_size_map) { |
| 204 | - std::string GenInput(const TradeOffConfig &trade_off_config, std::vector<Expr> &all_cons); | 76 | + data_type_size_map_ = data_type_size_map; |
| 205 | - std::string GenSetTiling(); | 77 | + } |
| 206 | - std::string GenSolverRunInvoke(const std::string &class_name); | 78 | + void SetInputAlign(const ExprExprMap &input_align); |
| 207 | - std::string GenEmptyTensorCheckInSolver(); | 79 | + void SetTotalCutCons(const std::vector<Expr> &total_cut_cons) { total_cut_cons_ = total_cut_cons; } |
| 208 | - std::string GenOriginExpr(const std::vector<Expr> &exprs, const std::string &indent) const; | 80 | + void SetFromAxesMap(const std::map<Expr, std::vector<Expr>, ExprCmp> &from_axes_map) { from_axes_map_ = from_axes_map; } |
| 209 | - std::pair<std::string, std::string> GenOriginBufExpr(const Expr &expr, const std::string &indent) const; | 81 | + void SetVarPriority(const ExprUintMap &priority) { priority_map_ = priority; } |
| 210 | - std::pair<std::string, std::string> GenNamedOriginBufExpr(const Expr &expr, const std::string &indent) const; | 82 | + void SetContainerExpr(const ExprExprMap &container_expr) { container_expr_ = container_expr; } |
| 211 | - std::string GenPgoSetTiling(); | 83 | + void SetContainerNames(const std::map<Expr, std::string, ExprCmp> &container_names) { container_names_ = container_names; } |
| 212 | - std::string GenPgoSetMaxBlockDim() const; | 84 | + void SetReplaceVars(const std::vector<std::pair<Expr, Expr>> &replace_vars) { |
| 213 | - std::vector<uint32_t> GetArgRelateCons(const Expr &arg, const std::vector<Expr> &all_cons) const; | 85 | + for (const auto &var : replace_vars) { |
| 214 | - std::string IsEnableBlockLoopTradeOffByPerf() const; | 86 | + replace_vars_.emplace_back(var); |
| 215 | - std::vector<Expr> mc_args_; | 87 | + } |
| 216 | - std::vector<Expr> input_args_; | 88 | + } |
| 217 | - std::vector<Expr> const_args_; | 89 | + void SetTernaryOps(const std::map<Expr, TernaryOp, ExprCmp> &ternary_ops) { |
| 218 | - std::vector<Expr> total_cut_cons_; | 90 | + ternary_ops_ = ternary_ops; |
| 219 | - std::vector<Expr> local_buffer_tiling_vars_; | 91 | + } |
| 220 | - ExprExprMap input_align_; | 92 | + |
| 221 | - ExprUintMap const_vars_map_; | 93 | + void SetExeTimeMap(const std::map<Expr, std::vector<Expr>, ExprCmp> &exe_time_map) { |
| 222 | - ExprExprMap arg_align_map_; | 94 | + for (const auto &pair : exe_time_map) { |
| 223 | - ExprUintMap arg_prompt_align_map_; | 95 | + exe_time_map_[pair.first] = pair.second; |
| 224 | - ExprUintMap data_type_size_map_; | 96 | + } |
| 225 | - ExprExprMap container_expr_; | 97 | + } |
| 226 | - std::vector<std::pair<Expr, Expr>> replace_vars_; | 98 | + void Arrange(); |
| 227 | - std::map<Expr, TernaryOp, ExprCmp> ternary_ops_; | 99 | + void SetObjFunc(const Expr &head_cost, const std::map<PipeType, Expr> pipe_2_obj_map) { |
| 228 | - std::map<Expr, std::vector<Expr>, ExprCmp> exe_time_map_; | 100 | + head_cost_ = head_cost; |
| 229 | - std::map<Expr, std::string, ExprCmp> container_names_; | 101 | + pipe_2_obj_map_ = pipe_2_obj_map; |
| 230 | - std::map<HardwareDef, Expr> hardware_use_map_; | 102 | + } |
| 231 | - std::map<Expr, std::vector<Expr>, ExprCmp> from_axes_map_; | 103 | + void SetIsConcatOuterMap(const ExprUintMap &is_concat_outer_map) { is_concat_outer_map_ = is_concat_outer_map; } |
| 232 | - static ExprUintMap priority_map_; | 104 | + void SetConcatInnerDims(const std::vector<Expr> &concat_inner_dims) { concat_inner_dims_ = concat_inner_dims; } |
| 233 | - std::map<PipeType, Expr> pipe_2_obj_map_; | 105 | + void SetUBThreshold(const double &ub_threshold) { |
| 234 | - Expr head_cost_; | 106 | + ub_threshold_ = ub_threshold; |
| 235 | - ExprUintMap is_concat_outer_map_; | 107 | + } |
| 236 | - std::vector<Expr> concat_inner_dims_; | 108 | + void SetCoreNumThreshold(const double &corenum_threshold) { |
| 237 | - ExprUintMap mc_related_ub_args_map_; | 109 | + corenum_threshold_ = corenum_threshold; |
| 238 | - std::vector<Expr> search_args_; | 110 | + }; |
| 239 | - double ub_threshold_{0.2}; | 111 | + void SetReservedUbSize(const Expr &reserved_ub_size) { |
| 240 | - Expr reserved_ub_size_{CreateExpr(0)}; | 112 | + reserved_ub_size_ = reserved_ub_size; |
| 241 | - double corenum_threshold_{0.4}; | 113 | + }; |
| 242 | - bool enable_high_perf_{false}; | 114 | + void SetHighPerfTiling(const bool enable_high_perf) { |
| 243 | - bool enable_equal_order_{false}; | 115 | + enable_high_perf_ = enable_high_perf; |
| 244 | - std::string arrange_code_; | 116 | + } |
| 245 | - const TilingScheduleConfigTable *tiling_schedule_config_table_{nullptr}; | 117 | + void SetEnableEqualOrder(const bool enable_equal_order) { |
| 246 | - TilingScheduleConfig tiling_schedule_config_; // Model 级别的 Tiling 调度配置 | 118 | + enable_equal_order_ = enable_equal_order; |
| 247 | - const vector<CacheLineConfig> *cache_line_config_{nullptr}; | 119 | + } |
| 248 | - bool enable_group_parallel_{false}; | 120 | + void SetSearchArgs(const std::vector<Expr> &search_args) { |
| 249 | - size_t group_num_{1UL}; | 121 | + search_args_ = search_args; |
| 250 | - TilingCaseIdent tiling_case_ident_{ScheduleGroupIdent{}, 0U, ""}; | 122 | + } |
| 251 | -}; | 123 | + void SetArrangeCode(const std::string &arrange_code) { |
| 252 | -bool CheckExist(const std::vector<Expr> &args, const Expr &check_arg); | 124 | + arrange_code_ = arrange_code; |
| 253 | -std::string SetRelatedVars(const std::vector<Expr> &rel_tiling_vars, const std::vector<Expr> &rel_cons_vars); | 125 | + } |
| 254 | -std::string GenRelatedVars(uint32_t cons_idx, const std::vector<Expr> &rel_tiling_vars, | 126 | + void SetTilingScheduleConfigTable(const TilingScheduleConfigTable *tiling_schedule_config_table) { |
| 255 | - const std::vector<Expr> &rel_cons_vars); | 127 | + tiling_schedule_config_table_ = tiling_schedule_config_table; |
| 256 | -} // namespace att | 128 | + } |
| 129 | + void SetTilingScheduleConfig(const TilingScheduleConfig &tiling_schedule_config) { | ||
| 130 | + tiling_schedule_config_ = tiling_schedule_config; | ||
| 131 | + } | ||
| 132 | + void SetRuntimeReorderRules(const std::vector<RuntimeReorderRule> &runtime_reorder_rules) { | ||
| 133 | + runtime_reorder_rules_ = runtime_reorder_rules; | ||
| 134 | + } | ||
| 135 | + void SetCacheLineConfig(const vector<CacheLineConfig> *cache_line_config) { | ||
| 136 | + cache_line_config_ = cache_line_config; | ||
| 137 | + } | ||
| 138 | + void SetEnableParallel(bool enable_parallel) { | ||
| 139 | + enable_group_parallel_ = enable_parallel; | ||
| 140 | + } | ||
| 141 | + void SetTilingCaseIdent(TilingCaseIdent tiling_case_ident) { | ||
| 142 | + tiling_case_ident_ = tiling_case_ident; | ||
| 143 | + } | ||
| 144 | + void SetGroupNum(size_t group_num) { | ||
| 145 | + group_num_ = group_num; | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + private: | ||
| 149 | + static bool VarCmp(Expr &a, Expr &b); | ||
| 150 | + void ReorderVars(); | ||
| 151 | + void GetMCArgs(); | ||
| 152 | + void GetLocalBufferTilingVars(); | ||
| 153 | + void GetRelatedArgs(const Expr &expr, std::vector<Expr> &related_args) const; | ||
| 154 | + bool NeedUBMultiCoreBalance(); | ||
| 155 | + std::string GenGetStaticInputParam(const HardwareDef &hardware_type, bool no_type = false) const; | ||
| 156 | + std::string GenGetObjStaticInputParam(bool no_type = false); | ||
| 157 | + std::string GenGetObjStaticFunc(); | ||
| 158 | + void CollectInitialWorkList(std::vector<Expr> &work_list) const; | ||
| 159 | + void CollectNeededTenaryVarsClosure(std::vector<Expr> &work_list, std::set<std::string> &needed_vars) const; | ||
| 160 | + std::string GenTenaryVarDecls(const std::set<std::string> &needed_vars); | ||
| 161 | + std::string GenSingleTenaryVar(const TernaryOp &op, const std::string &var_name, | ||
| 162 | + std::set<std::string> &declared_vars, | ||
| 163 | + std::map<std::string, std::string> &content_to_first_var); | ||
| 164 | + std::string GenGetTilingDataObjStaticFunc(); | ||
| 165 | + std::string GenObjFunc(); | ||
| 166 | + std::string GenGetUbSizeStaticFunc(); | ||
| 167 | + std::string GenGetTilingDataUbSizeStaticFunc(); | ||
| 168 | + std::string GenGetBlockDimStatic(Expr &corenum_cons); | ||
| 169 | + std::string GenGetTilingDataBlockDimStatic(Expr &corenum_cons); | ||
| 170 | + std::string GenUBThresholdFunc(); | ||
| 171 | + std::string GenUBSizeCacheLineFunc(); | ||
| 172 | + std::string GenCoreNumFunc(); | ||
| 173 | + std::pair<std::vector<Expr>, std::vector<Expr>> SortConsArgs(const Expr &expr, bool &is_mc_mixed); | ||
| 174 | + std::string ObtainRelatedVars(Expr &expr); | ||
| 175 | + std::string InitiateArgs(); | ||
| 176 | + std::string InitiateBufferConsArgs(uint32_t cons_idx, HardwareDef hardware, const Expr &cons); | ||
| 177 | + std::string InitiateCutConsArgs(uint32_t cons_idx, const Expr &cons, bool &is_mc_mixed); | ||
| 178 | + std::string GenConsUbFunc(uint32_t cons_idx, const std::vector<Expr> &rel_tiling_vars, | ||
| 179 | + const std::vector<Expr> &rel_cons_vars) const; | ||
| 180 | + std::string GenConsFunc(uint32_t cons_idx, ConsType cons_type, const Expr &cons, | ||
| 181 | + const std::vector<Expr> &rel_tiling_vars, const std::vector<Expr> &rel_cons_vars) const; | ||
| 182 | + std::string SetVarCons(const Expr &arg, const std::vector<Expr> &all_cons) const; | ||
| 183 | + std::string GenUpperBoundFunc(const Expr &var); | ||
| 184 | + std::string GenUpperBoundInfo(const Expr &var); | ||
| 185 | + std::string SetInputVars(InputType input_type); | ||
| 186 | + std::string SetInputCons(std::vector<Expr> cons) const; | ||
| 187 | + std::string SetTilingVars(VarsType var_type); | ||
| 188 | + std::string GenRuntimeReorderRules(); | ||
| 189 | + std::string GenRuntimeReorderRule(const RuntimeReorderRule &rule); | ||
| 190 | + std::string GenRuntimeExprValue(const Expr &expr) const; | ||
| 191 | + std::string GenRuntimeCompoundExprValue(const Expr &expr) const; | ||
| 192 | + int32_t GetLocalBufferVarIndex(const Expr &expr) const; | ||
| 193 | + void InitConcatPromptAlign(const Expr &local_var, const uint32_t prompt_align, std::string &strs); | ||
| 194 | + std::string GenInputInfo(std::vector<Expr> &all_cons, std::vector<Expr> &local_buffer_cons, | ||
| 195 | + std::vector<Expr> &mc_mixed_cons); | ||
| 196 | + std::string GenInput(const TradeOffConfig &trade_off_config, std::vector<Expr> &all_cons); | ||
| 197 | + std::string GenSetTiling(); | ||
| 198 | + std::string GenSolverRunInvoke(const std::string &class_name); | ||
| 199 | + std::string GenEmptyTensorCheckInSolver(); | ||
| 200 | + std::string GenOriginExpr(const std::vector<Expr> &exprs, const std::string &indent) const; | ||
| 201 | + std::pair<std::string, std::string> GenOriginBufExpr(const Expr &expr, const std::string &indent) const; | ||
| 202 | + std::pair<std::string, std::string> GenNamedOriginBufExpr(const Expr &expr, const std::string &indent) const; | ||
| 203 | + std::string GenPgoSetTiling(); | ||
| 204 | + std::string GenPgoSetMaxBlockDim() const; | ||
| 205 | + std::vector<uint32_t> GetArgRelateCons(const Expr &arg, const std::vector<Expr> &all_cons) const; | ||
| 206 | + std::string IsEnableBlockLoopTradeOffByPerf() const; | ||
| 207 | + std::string GenPendingSearchConfigOverride(); | ||
| 208 | + std::vector<Expr> mc_args_; | ||
| 209 | + std::vector<Expr> input_args_; | ||
| 210 | + std::vector<Expr> const_args_; | ||
| 211 | + std::vector<Expr> total_cut_cons_; | ||
| 212 | + std::vector<Expr> local_buffer_tiling_vars_; | ||
| 213 | + ExprExprMap input_align_; | ||
| 214 | + ExprUintMap const_vars_map_; | ||
| 215 | + ExprExprMap arg_align_map_; | ||
| 216 | + ExprUintMap arg_prompt_align_map_; | ||
| 217 | + ExprUintMap data_type_size_map_; | ||
| 218 | + ExprExprMap container_expr_; | ||
| 219 | + std::vector<std::pair<Expr, Expr>> replace_vars_; | ||
| 220 | + std::map<Expr, TernaryOp, ExprCmp> ternary_ops_; | ||
| 221 | + std::map<Expr, std::vector<Expr>, ExprCmp> exe_time_map_; | ||
| 222 | + std::map<Expr, std::string, ExprCmp> container_names_; | ||
| 223 | + std::map<HardwareDef, Expr> hardware_use_map_; | ||
| 224 | + std::map<Expr, std::vector<Expr>, ExprCmp> from_axes_map_; | ||
| 225 | + static ExprUintMap priority_map_; | ||
| 226 | + std::map<PipeType, Expr> pipe_2_obj_map_; | ||
| 227 | + Expr head_cost_; | ||
| 228 | + ExprUintMap is_concat_outer_map_; | ||
| 229 | + std::vector<Expr> concat_inner_dims_; | ||
| 230 | + ExprUintMap mc_related_ub_args_map_; | ||
| 231 | + std::vector<Expr> search_args_; | ||
| 232 | + double ub_threshold_{0.2}; | ||
| 233 | + Expr reserved_ub_size_{CreateExpr(0)}; | ||
| 234 | + double corenum_threshold_{0.4}; | ||
| 235 | + bool enable_high_perf_{false}; | ||
| 236 | + bool enable_equal_order_{false}; | ||
| 237 | + std::string arrange_code_; | ||
| 238 | + const TilingScheduleConfigTable *tiling_schedule_config_table_{nullptr}; | ||
| 239 | + TilingScheduleConfig tiling_schedule_config_; // Model 级别的 Tiling 调度配置 | ||
| 240 | + std::vector<RuntimeReorderRule> runtime_reorder_rules_; | ||
| 241 | + const vector<CacheLineConfig> *cache_line_config_ {nullptr}; | ||
| 242 | + bool enable_group_parallel_{false}; | ||
| 243 | + size_t group_num_{1UL}; | ||
| 244 | + TilingCaseIdent tiling_case_ident_{ScheduleGroupIdent{}, 0U, ""}; | ||
| 245 | + }; | ||
| 246 | + bool CheckExist(const std::vector<Expr> &args, const Expr &check_arg); | ||
| 247 | + std::string SetRelatedVars(const std::vector<Expr> &rel_tiling_vars, const std::vector<Expr> &rel_cons_vars); | ||
| 248 | + std::string GenRelatedVars(uint32_t cons_idx, const std::vector<Expr> &rel_tiling_vars, const std::vector<Expr> &rel_cons_vars); | ||
| 249 | +} | ||
| 257 | #endif | 250 | #endif |
| @@ -487,6 +487,7 @@ void SolverPassManager::InitSolverGen(AxesReorderSolverGen &solver_gen) { | |||
| 487 | solver_gen.SetIsUniGroup(GetIsUniGroup()); | 487 | solver_gen.SetIsUniGroup(GetIsUniGroup()); |
| 488 | solver_gen.SetTilingScheduleConfigTable(args_manager_.GetModelInfo().tiling_schedule_config_table); | 488 | solver_gen.SetTilingScheduleConfigTable(args_manager_.GetModelInfo().tiling_schedule_config_table); |
| 489 | solver_gen.SetTilingScheduleConfig(args_manager_.GetModelInfo().tiling_schedule_config); | 489 | solver_gen.SetTilingScheduleConfig(args_manager_.GetModelInfo().tiling_schedule_config); |
| 490 | + solver_gen.SetRuntimeReorderRules(args_manager_.GetModelInfo().runtime_reorder_rules); | ||
| 490 | solver_gen.SetCacheLineConfig(&args_manager_.GetModelInfo().cache_line_config); | 491 | solver_gen.SetCacheLineConfig(&args_manager_.GetModelInfo().cache_line_config); |
| 491 | solver_gen.SetEnableParallel(args_manager_.GetModelInfo().enable_group_parallel); | 492 | solver_gen.SetEnableParallel(args_manager_.GetModelInfo().enable_group_parallel); |
| 492 | solver_gen.SetGroupNum(group_num_); | 493 | solver_gen.SetGroupNum(group_num_); |
| @@ -36,6 +36,7 @@ class TestTilingScheduleConfigTable : public TilingScheduleConfigTable { | |||
| 36 | [[nodiscard]] TilingScheduleConfig GetModelTilingScheduleConfig() const override { | 36 | [[nodiscard]] TilingScheduleConfig GetModelTilingScheduleConfig() const override { |
| 37 | TilingScheduleConfig config; | 37 | TilingScheduleConfig config; |
| 38 | config.cache_line_size = cache_line_size_; | 38 | config.cache_line_size = cache_line_size_; |
| 39 | + config.vector_len_size = GetVectorLenSize(); | ||
| 39 | return config; | 40 | return config; |
| 40 | } | 41 | } |
| 41 | [[nodiscard]] uint32_t GetCacheLineSize() const override { | 42 | [[nodiscard]] uint32_t GetCacheLineSize() const override { |
| @@ -1,47 +1,213 @@ | |||
| 1 | /** | 1 | /** |
| 2 | * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | * Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 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 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, | 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. | 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 | #include <iostream> | 11 | #include <iostream> |
| 12 | #include "gtest/gtest.h" | 12 | #include "gtest/gtest.h" |
| 13 | +#include "gen_model_info/api_perf_register/v1/perf_param_v1.h" | ||
| 14 | +#include "v35/att/api_perf_register/perf_param_v2.h" | ||
| 13 | #define private public | 15 | #define private public |
| 14 | #include "expr_gen/arg_list_reorder.h" | 16 | #include "expr_gen/arg_list_reorder.h" |
| 15 | 17 | ||
| 16 | -namespace att { | 18 | + |
| 19 | +namespace att{ | ||
| 17 | class TestArgListReorder : public ::testing::Test { | 20 | class TestArgListReorder : public ::testing::Test { |
| 18 | public: | 21 | public: |
| 19 | - static void TearDownTestCase() { | 22 | + static void TearDownTestCase() |
| 23 | + { | ||
| 20 | std::cout << "Test end." << std::endl; | 24 | std::cout << "Test end." << std::endl; |
| 21 | } | 25 | } |
| 22 | - static void SetUpTestCase() { | 26 | + static void SetUpTestCase() |
| 27 | + { | ||
| 23 | std::cout << "Test begin." << std::endl; | 28 | std::cout << "Test begin." << std::endl; |
| 24 | } | 29 | } |
| 25 | void SetUp() override { | 30 | void SetUp() override { |
| 26 | - // Code here will be called immediately after the constructor (right | 31 | + // Code here will be called immediately after the constructor (right |
| 27 | - // before each test). | 32 | + // before each test). |
| 28 | } | 33 | } |
| 29 | 34 | ||
| 30 | void TearDown() override { | 35 | void TearDown() override { |
| 31 | - // Code here will be called immediately after each test (right | 36 | + // Code here will be called immediately after each test (right |
| 32 | - // before the destructor). | 37 | + // before the destructor). |
| 33 | } | 38 | } |
| 34 | }; | 39 | }; |
| 35 | 40 | ||
| 36 | -TEST_F(TestArgListReorder, case0) { | 41 | +namespace { |
| 37 | - // Define TuningSpace | 42 | +constexpr uint32_t kTensorDataTypeSize = 2U; |
| 38 | - // Create node: MatMul | 43 | +constexpr uint32_t kAxisDataTypeSize = 4U; |
| 39 | - // input : [m, k][k, n] | 44 | + |
| 40 | - // repeat : [M, K][K, N] | 45 | +class TestTilingScheduleConfigTable : public TilingScheduleConfigTable { |
| 41 | - // stride : [MM, KK][KK, NN] | 46 | + public: |
| 42 | - // output : [m, n, k] | 47 | + TestTilingScheduleConfigTable(uint32_t cache_line_size, uint32_t vector_len_size) |
| 43 | - // repeat : [M, N, ONE] | 48 | + : cache_line_size_(cache_line_size), vector_len_size_(vector_len_size) {} |
| 44 | - // stride : [MM, NN, ZERO] | 49 | + |
| 50 | + [[nodiscard]] bool IsEnableBlockLoopAutoTune() const override { return false; } | ||
| 51 | + [[nodiscard]] bool IsEnableCacheLineCheck() const override { return true; } | ||
| 52 | + [[nodiscard]] TradeOffConfig GetTradeOffConfig() const override { return {}; } | ||
| 53 | + [[nodiscard]] double GetUbThresholdPerfValEffect() const override { return 0.0; } | ||
| 54 | + [[nodiscard]] TilingScheduleConfig GetModelTilingScheduleConfig() const override | ||
| 55 | + { | ||
| 56 | + TilingScheduleConfig config; | ||
| 57 | + config.cache_line_size = cache_line_size_; | ||
| 58 | + config.vector_len_size = vector_len_size_; | ||
| 59 | + return config; | ||
| 60 | + } | ||
| 61 | + [[nodiscard]] uint32_t GetCacheLineSize() const override { return cache_line_size_; } | ||
| 62 | + [[nodiscard]] uint32_t GetVectorLenSize() const override { return vector_len_size_; } | ||
| 63 | + [[nodiscard]] bool IsCoreNumThresholdPenaltyEnable() const override { return false; } | ||
| 64 | + | ||
| 65 | + private: | ||
| 66 | + uint32_t cache_line_size_; | ||
| 67 | + uint32_t vector_len_size_; | ||
| 68 | +}; | ||
| 69 | + | ||
| 70 | +struct ReduceTailSortCase { | ||
| 71 | + std::shared_ptr<TuningSpace> tuning_space; | ||
| 72 | + ModelInfo model_info; | ||
| 73 | + std::shared_ptr<TilingScheduleConfigTable> tiling_schedule_config_table; | ||
| 74 | +}; | ||
| 75 | + | ||
| 76 | +struct ReduceTailSubAxes { | ||
| 77 | + std::unique_ptr<SubAxis> origin_reduce; | ||
| 78 | + std::unique_ptr<SubAxis> reduce; | ||
| 79 | + std::unique_ptr<SubAxis> tail; | ||
| 80 | +}; | ||
| 81 | + | ||
| 82 | +std::shared_ptr<AttAxis> MakeAttAxis(const std::string &name) | ||
| 83 | +{ | ||
| 84 | + auto axis = std::make_shared<AttAxis>(); | ||
| 85 | + axis->name = name; | ||
| 86 | + return axis; | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +size_t GetArgIndex(const std::vector<AttAxisPtr> &arg_list, const std::string &name) | ||
| 90 | +{ | ||
| 91 | + for (size_t i = 0U; i < arg_list.size(); ++i) { | ||
| 92 | + if (arg_list[i]->name == name) { | ||
| 93 | + return i; | ||
| 94 | + } | ||
| 95 | + } | ||
| 96 | + return arg_list.size(); | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +SymInfoPtr MakeAxisSize(const Expr &expr) { | ||
| 100 | + if (expr.IsConstExpr()) { | ||
| @@ -158,7 +158,120 @@ TEST_F(TestAxesReorderSolverGen, TEST_GEN_SOLVER) { | |||
| 158 | EXPECT_NE(invoke_code, ""); | 158 | EXPECT_NE(invoke_code, ""); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | -TEST_F(TestAxesReorderSolverGen, TEST_GEN_SOLVER_case2) { | 161 | +TEST_F(TestAxesReorderSolverGen, GenRuntimeReorderRuleForDynamicReduceTile) { |
| 162 | + Expr reduce = CreateExpr("reduce"); | ||
| 163 | + Expr tail = CreateExpr("tail"); | ||
| 164 | + RuntimeReorderRule rule; | ||
| 165 | + rule.preferred_axis = tail; | ||
| 166 | + rule.fallback_axis = reduce; | ||
| 167 | + rule.condition_axis = tail; | ||
| 168 | + rule.compare_axis = reduce; | ||
| 169 | + rule.condition_threshold = 64U; | ||
| 170 | + rule.compare_threshold = 128U; | ||
| 171 | + | ||
| 172 | + AxesReorderSolverGen solver_gen("case_test", "TilingData"); | ||
| 173 | + solver_gen.local_buffer_tiling_vars_ = {reduce, tail}; | ||
| 174 | + solver_gen.from_axes_map_[tail] = {tail}; | ||
| 175 | + solver_gen.from_axes_map_[reduce] = {reduce}; | ||
| 176 | + solver_gen.SetRuntimeReorderRules({rule}); | ||
| 177 | + | ||
| 178 | + std::string code = solver_gen.GenRuntimeReorderRules(); | ||
| 179 | + EXPECT_TRUE(code.find("(tail.upper_bound(tail.upper_bound_vars) < 64)") != std::string::npos); | ||
| 180 | + EXPECT_TRUE(code.find("(reduce.upper_bound(reduce.upper_bound_vars) > 128)") != std::string::npos); | ||
| 181 | + EXPECT_TRUE(code.find("Runtime reduce tile reorder chooses preferred axis tail before fallback axis reduce") != | ||
| 182 | + std::string::npos); | ||
| 183 | + EXPECT_TRUE(code.find("Runtime reduce tile reorder keeps fallback axis reduce before preferred axis tail") != | ||
| 184 | + std::string::npos); | ||
| 185 | + EXPECT_TRUE(code.find("auto *runtime_preferred_var = input.local_buffer_vars[1]") != std::string::npos); | ||
| 186 | + EXPECT_TRUE(code.find("input.local_buffer_vars[1] = input.local_buffer_vars[0]") != std::string::npos); | ||
| 187 | + EXPECT_TRUE(code.find("input.local_buffer_vars[0] = runtime_preferred_var") != std::string::npos); | ||
| 188 | +} | ||
| 189 | + | ||
| 190 | +TEST_F(TestAxesReorderSolverGen, GenRuntimeReorderRuleUsesOriginalAxesForDynamicReduceTile) { | ||
| 191 | + Expr reduce = CreateExpr("reduce"); | ||
| 192 | + Expr tail = CreateExpr("tail"); | ||
| 193 | + Expr origin_reduce = CreateExpr("origin_reduce"); | ||
| 194 | + Expr origin_tail = CreateExpr("origin_tail"); | ||
| 195 | + RuntimeReorderRule rule; | ||
| 196 | + rule.preferred_axis = tail; | ||
| 197 | + rule.fallback_axis = reduce; | ||
| 198 | + rule.condition_axis = origin_tail; | ||
| 199 | + rule.compare_axis = origin_reduce; | ||
| 200 | + rule.condition_threshold = 64U; | ||
| 201 | + rule.compare_threshold = 128U; | ||
| 202 | + | ||
| 203 | + AxesReorderSolverGen solver_gen("case_test", "TilingData"); | ||
| 204 | + solver_gen.input_args_ = {origin_reduce, origin_tail}; | ||
| 205 | + solver_gen.local_buffer_tiling_vars_ = {reduce, tail}; | ||
| 206 | + solver_gen.from_axes_map_[tail] = {origin_tail}; | ||
| 207 | + solver_gen.from_axes_map_[reduce] = {origin_reduce}; | ||
| 208 | + solver_gen.SetRuntimeReorderRules({rule}); | ||
| 209 | + | ||
| 210 | + std::string code = solver_gen.GenRuntimeReorderRules(); | ||
| 211 | + EXPECT_TRUE(code.find("(origin_tail.value < 64)") != std::string::npos); | ||
| 212 | + EXPECT_TRUE(code.find("(origin_reduce.value > 128)") != std::string::npos); | ||
| 213 | + EXPECT_TRUE(code.find("auto *runtime_preferred_var = input.local_buffer_vars[1]") != std::string::npos); | ||
| 214 | + EXPECT_TRUE(code.find("input.local_buffer_vars[1] = input.local_buffer_vars[0]") != std::string::npos); | ||
| 215 | + EXPECT_TRUE(code.find("input.local_buffer_vars[0] = runtime_preferred_var") != std::string::npos); | ||
| 216 | +} | ||
| 217 | + | ||
| 218 | +TEST_F(TestAxesReorderSolverGen, GenRuntimeReorderRuleUsesOriginalAxisProductForDynamicReduceTile) { | ||
| 219 | + Expr reduce = CreateExpr("reduce"); | ||
| 220 | + Expr tail = CreateExpr("tail"); | ||
| 221 | + Expr origin_reduce0 = CreateExpr("origin_reduce0"); | ||
| 222 | + Expr origin_reduce1 = CreateExpr("origin_reduce1"); | ||
| 223 | + Expr origin_tail0 = CreateExpr("origin_tail0"); | ||
| 224 | + Expr origin_tail1 = CreateExpr("origin_tail1"); | ||
| 225 | + RuntimeReorderRule rule; | ||
| 226 | + rule.preferred_axis = tail; | ||
| 227 | + rule.fallback_axis = reduce; | ||
| 228 | + rule.condition_axis = origin_tail0 * origin_tail1; | ||
| 229 | + rule.compare_axis = origin_reduce0 * origin_reduce1; | ||
| 230 | + rule.condition_threshold = 64U; | ||
| 231 | + rule.compare_threshold = 128U; | ||
| 232 | + | ||
| 233 | + AxesReorderSolverGen solver_gen("case_test", "TilingData"); | ||
| 234 | + solver_gen.input_args_ = {origin_reduce0, origin_reduce1, origin_tail0, origin_tail1}; | ||
| 235 | + solver_gen.local_buffer_tiling_vars_ = {reduce, tail}; | ||
| 236 | + solver_gen.SetRuntimeReorderRules({rule}); | ||
| 237 | + | ||
| 238 | + std::string code = solver_gen.GenRuntimeReorderRules(); | ||
| 239 | + EXPECT_TRUE(code.find("origin_tail0.value") != std::string::npos); | ||
| 240 | + EXPECT_TRUE(code.find("origin_tail1.value") != std::string::npos); | ||
| 241 | + EXPECT_TRUE(code.find("origin_reduce0.value") != std::string::npos); | ||
| 242 | + EXPECT_TRUE(code.find("origin_reduce1.value") != std::string::npos); | ||
| 243 | + EXPECT_TRUE(code.find("origin_tail0*origin_tail1.value") == std::string::npos); | ||
| 244 | + EXPECT_TRUE(code.find("origin_reduce0*origin_reduce1.value") == std::string::npos); | ||
| 245 | +} | ||
| 246 | + | ||
| 247 | +TEST_F(TestAxesReorderSolverGen, GenSolverFuncImplAppliesRuntimeReorderOnceBeforeSolverRun) { | ||
| 248 | + Expr reduce = CreateExpr("reduce"); | ||
| 249 | + Expr tail = CreateExpr("tail"); | ||
| 250 | + RuntimeReorderRule rule; | ||
| 251 | + rule.preferred_axis = tail; | ||
| 252 | + rule.fallback_axis = reduce; | ||
| 253 | + rule.condition_axis = tail; | ||
| 254 | + rule.compare_axis = reduce; | ||
| 255 | + rule.condition_threshold = 64U; | ||
| 256 | + rule.compare_threshold = 128U; | ||
| 257 | + | ||
| 258 | + AxesReorderSolverGen solver_gen("case_test", "TilingData"); | ||
| 259 | + solver_gen.local_buffer_tiling_vars_ = {reduce, tail}; | ||
| 260 | + solver_gen.hardware_use_map_[HardwareDef::UB] = reduce + tail; | ||
| 261 | + solver_gen.SetRuntimeReorderRules({rule}); | ||
| 262 | + | ||
| 263 | + const std::string code = solver_gen.GenSolverFuncImpl(); | ||
| 264 | + const std::string swap_code = "auto *runtime_preferred_var = input.local_buffer_vars[1]"; | ||
| 265 | + const size_t swap_pos = code.find(swap_code); | ||
| 266 | + const size_t solver_pos = code.find("AxesReorderSolvercase_test solver(input);"); | ||
| 267 | + EXPECT_EQ(CountSubstr(code, swap_code), 1U); | ||
| 268 | + EXPECT_NE(swap_pos, std::string::npos); | ||
| 269 | + EXPECT_NE(solver_pos, std::string::npos); | ||
| 270 | + EXPECT_LT(swap_pos, solver_pos); | ||
| 271 | +} | ||
| 272 | + | ||
| 273 | +TEST_F(TestAxesReorderSolverGen, TEST_GEN_SOLVER_case2) | ||
| 274 | +{ | ||
| 162 | Expr x0 = CreateExpr("x0"); | 275 | Expr x0 = CreateExpr("x0"); |
| 163 | Expr x1 = CreateExpr("block_dim"); | 276 | Expr x1 = CreateExpr("block_dim"); |
| 164 | std::vector<Expr> cut_cons; | 277 | std::vector<Expr> cut_cons; |
| @@ -349,7 +349,61 @@ TEST_F(UTestReduceMinMaxApiPerfV2, AscendCApiReduceSumSupportsAscendC3510Dtypes) | |||
| 349 | } | 349 | } |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | -TEST_F(UTestReduceMinMaxApiPerfV2, ReduceSumB64UsesSpecializedAscendC3510Cost) { | 352 | +TEST_F(UTestReduceMinMaxApiPerfV2, ReduceSumRaUnalignedTailRDoesNotRepeatVfHead) |
| 353 | +{ | ||
| 354 | + auto context = MakeRaContext(kFloat32, {CreateExpr(1917), CreateExpr(10)}, true); | ||
| 355 | + PerfOutputInfo perf; | ||
| 356 | + ASSERT_EQ(ascendcapi_v2::ReduceSumPerf(context, perf), ge::SUCCESS); | ||
| 357 | + | ||
| 358 | + const std::string vec_perf = PipeString(perf, PipeType::AIV_VEC); | ||
| 359 | + EXPECT_EQ(vec_perf, "TernaryOp(IsEqual(8, 0), 1310, 11892)"); | ||
| 360 | +} | ||
| 361 | + | ||
| 362 | +TEST_F(UTestReduceMinMaxApiPerfV2, ReduceSumRaAlignedTailRDoesNotRepeatVfHead) | ||
| 363 | +{ | ||
| 364 | + auto context = MakeRaContext(kFloat32, {CreateExpr(1917), CreateExpr(80)}, true); | ||
| 365 | + PerfOutputInfo perf; | ||
| 366 | + ASSERT_EQ(ascendcapi_v2::ReduceSumPerf(context, perf), ge::SUCCESS); | ||
| 367 | + | ||
| 368 | + const std::string vec_perf = PipeString(perf, PipeType::AIV_VEC); | ||
| 369 | + EXPECT_EQ(vec_perf, "TernaryOp(IsEqual(0, 0), 13808, 15732)"); | ||
| 370 | +} | ||
| 371 | + | ||
| 372 | +TEST_F(UTestReduceMinMaxApiPerfV2, ReduceSumRaSymbolicAlignedTailDoesNotRepeatVfHead) | ||
| 373 | +{ | ||
| 374 | + const Expr a2t_size = CreateExpr("a2t_size"); | ||
| 375 | + auto context = MakeRaContext(kFloat32, {CreateExpr(1917), CreateExpr(8) * af::sym::Ceiling(a2t_size / CreateExpr(8))}, | ||
| 376 | + true); | ||
| 377 | + PerfOutputInfo perf; | ||
| 378 | + ASSERT_EQ(ascendcapi_v2::ReduceSumPerf(context, perf), ge::SUCCESS); | ||
| 379 | + | ||
| 380 | + const std::string aligned_formula = TernaryChoiceString(perf, true); | ||
| 381 | + EXPECT_NE(aligned_formula.find("+ 4) * 893"), std::string::npos) << aligned_formula; | ||
| 382 | + EXPECT_EQ(aligned_formula.find("+ 64) * 893"), std::string::npos) << aligned_formula; | ||
| 383 | +} | ||
| 384 | + | ||
| 385 | +TEST_F(UTestReduceMinMaxApiPerfV2, ReduceRaB64TailRDoesNotRepeatVfHead) | ||
| 386 | +{ | ||
| 387 | + auto context = MakeRaContext(kInt64, {CreateExpr(1224), CreateExpr(12)}, true); | ||
| 388 | + PerfOutputInfo perf; | ||
| 389 | + ASSERT_EQ(ascendcapi_v2::ReduceSumPerf(context, perf), ge::SUCCESS); | ||
| 390 | + | ||
| 391 | + const std::string vec_perf = PipeString(perf, PipeType::AIV_VEC); | ||
| 392 | + EXPECT_EQ(vec_perf, "TernaryOp(IsEqual(0, 0), 57326, 57526)"); | ||
| 393 | +} | ||
| 394 | + | ||
| 395 | +TEST_F(UTestReduceMinMaxApiPerfV2, ReduceArTailRDoesNotRepeatVfHead) | ||
| 396 | +{ | ||
| 397 | + auto context = MakeArContext(kFloat32, {CreateExpr(16), CreateExpr(1917)}, true); | ||
| 398 | + PerfOutputInfo perf; | ||
| 399 | + ASSERT_EQ(ascendcapi_v2::ReduceSumPerf(context, perf), ge::SUCCESS); | ||
| 400 | + | ||
| 401 | + const std::string vec_perf = PipeString(perf, PipeType::AIV_VEC); | ||
| 402 | + EXPECT_EQ(vec_perf, "TernaryOp(IsEqual(38320, 0), 944, 1168)"); | ||
| 403 | +} | ||
| 404 | + | ||
| 405 | +TEST_F(UTestReduceMinMaxApiPerfV2, ReduceSumB64UsesSpecializedAscendC3510Cost) | ||
| 406 | +{ | ||
| 353 | auto int64_context = MakeRaContext(kInt64, {CreateExpr(8), CreateExpr(64)}, true); | 407 | auto int64_context = MakeRaContext(kInt64, {CreateExpr(8), CreateExpr(64)}, true); |
| 354 | auto uint64_context = MakeArContext(kUInt64, {CreateExpr(8), CreateExpr(64)}, true); | 408 | auto uint64_context = MakeArContext(kUInt64, {CreateExpr(8), CreateExpr(64)}, true); |
| 355 | 409 | ||
| @@ -728,7 +782,7 @@ TEST_F(UTestReduceMinMaxApiPerfV2, RaB64ExpandsInt64BinaryFuncCost) { | |||
| 728 | PerfOutputInfo perf; | 782 | PerfOutputInfo perf; |
| 729 | EXPECT_EQ(ascendcapi_v2::ReduceMaxPerf(aligned_context, perf), ge::SUCCESS); | 783 | EXPECT_EQ(ascendcapi_v2::ReduceMaxPerf(aligned_context, perf), ge::SUCCESS); |
| 730 | 784 | ||
| 731 | - EXPECT_EQ(TernaryChoiceString(perf, true), "99911"); | 785 | + EXPECT_EQ(TernaryChoiceString(perf, true), "92295"); |
| 732 | } | 786 | } |
| 733 | 787 | ||
| 734 | TEST_F(UTestReduceMinMaxApiPerfV2, ArB64UnalignedSmallLastUsesOneVectorBlock) { | 788 | TEST_F(UTestReduceMinMaxApiPerfV2, ArB64UnalignedSmallLastUsesOneVectorBlock) { |
| @@ -24,6 +24,7 @@ namespace { | |||
| 24 | constexpr int64_t kOneStride = 32768; | 24 | constexpr int64_t kOneStride = 32768; |
| 25 | constexpr int64_t kVectorBlockBytes = 256; | 25 | constexpr int64_t kVectorBlockBytes = 256; |
| 26 | constexpr int64_t kB64RegTraitNumTwoElements = 64; | 26 | constexpr int64_t kB64RegTraitNumTwoElements = 64; |
| 27 | +constexpr int64_t kReduceVfHeadCost = 64; | ||
🟡 Medium Priority
具体影响:对于 tail repeats=N 的场景,旧模型为 触发条件:任何 Reduce tail 场景(AR tail inplace、RA tree reduce tail、RA B64 const tree cost、RA normal aligned/unaligned tail)。 建议:确认 ![]() ![]() 不准确? | |||
| 27 | constexpr uint32_t kReduceMaxMainRPower = 15U; | 28 | constexpr uint32_t kReduceMaxMainRPower = 15U; |
| 28 | 29 | ||
| 29 | // 调用关系: | 30 | // 调用关系: |
| @@ -253,6 +254,12 @@ Expr GetVfGroupCost(const VfCostAccumulator &acc) { | |||
| 253 | return cost; | 254 | return cost; |
| 254 | } | 255 | } |
| 255 | 256 | ||
| 257 | +Expr GetVfGroupBodyCost(const VfCostAccumulator &acc) { | ||
| 258 | + Expr cost = acc.max_latency + acc.throughput; | ||
| 259 | + cost.Simplify(); | ||
| 260 | + return cost; | ||
| 261 | +} | ||
| 262 | + | ||
| 256 | Expr GetB64RepeatEle(const std::string &dtype) { | 263 | Expr GetB64RepeatEle(const std::string &dtype) { |
| 257 | (void)dtype; | 264 | (void)dtype; |
| 258 | return CreateExpr(kB64RegTraitNumTwoElements); | 265 | return CreateExpr(kB64RegTraitNumTwoElements); |
| @@ -283,21 +290,42 @@ ge::Status BuildVfGroupCost(const ReduceOpCostModel &model, const std::string &d | |||
| 283 | return ge::SUCCESS; | 290 | return ge::SUCCESS; |
| 284 | } | 291 | } |
| 285 | 292 | ||
| 293 | +ge::Status BuildVfGroupBodyCost(const ReduceOpCostModel &model, const std::string &dtype, const Expr &count, | ||
| 294 | + const Expr &repeat_ele, uint32_t load_count, uint32_t binary_count, | ||
| 295 | + uint32_t store_count, Expr &cost) { | ||
| 296 | + Expr repeat_time = CreateExpr(0); | ||
| 297 | + GE_ASSERT_SUCCESS(CeilDivByPositiveConstExpr(count, repeat_ele, "repeat_ele", repeat_time)); | ||
| 298 | + VfCostAccumulator acc; | ||
| 299 | + GE_ASSERT_SUCCESS(AddVfInstructCost(kLoad, dtype, repeat_time, load_count, acc)); | ||
| 300 | + GE_ASSERT_SUCCESS(AddVfInstructCost(model.binary_op, dtype, repeat_time, binary_count, acc)); | ||
| 301 | + GE_ASSERT_SUCCESS(AddVfInstructCost(kStore, dtype, repeat_time, store_count, acc)); | ||
| 302 | + cost = acc.max_latency + acc.throughput; | ||
| 303 | + cost.Simplify(); | ||
| 304 | + return ge::SUCCESS; | ||
| 305 | +} | ||
| 306 | + | ||
| 307 | +ge::Status AddB64BinaryFuncInstructCost(const ReduceOpCostModel &model, const Expr &repeat_time, | ||
| 308 | + uint32_t binary_count, VfCostAccumulator &acc) { | ||
| 309 | + for (uint32_t i = 0; i < binary_count; ++i) { | ||
| 310 | + if (model.op_kind == ReduceOpKind::kSum) { | ||
| 311 | + GE_ASSERT_SUCCESS(AddVfInstructCost(kVcadd, kUInt32, repeat_time, 3U, acc)); | ||
| 312 | + GE_ASSERT_SUCCESS(AddVfInstructCost(kAdd, kUInt32, repeat_time, 2U, acc)); | ||
| 313 | + GE_ASSERT_SUCCESS(AddVfInstructCost(kAnd, kUInt32, repeat_time, 3U, acc)); | ||
| 314 | + GE_ASSERT_SUCCESS(AddVfInstructCost(kVshrs, kUInt32, repeat_time, 2U, acc)); | ||
| 315 | + continue; | ||
| 316 | + } | ||
| 317 | + const std::string compare_op = (model.binary_op == kMin) ? kLt : kGt; | ||
| 318 | + GE_ASSERT_SUCCESS(AddVfInstructCost(kEq, kUInt32, repeat_time, 1U, acc)); | ||
| 319 | + GE_ASSERT_SUCCESS(AddVfInstructCost(compare_op, kUInt32, repeat_time, 2U, acc)); | ||
| 320 | + GE_ASSERT_SUCCESS(AddVfInstructCost(kSelect, kUInt32, repeat_time, 5U, acc)); | ||
| 321 | + GE_ASSERT_SUCCESS(AddVfInstructCost(kDuplicate, kUInt32, repeat_time, 2U, acc)); | ||
| 322 | + } | ||
| 323 | + return ge::SUCCESS; | ||
| 324 | +} | ||
| 325 | + | ||
| 286 | ge::Status BuildB64BinaryFuncCost(const ReduceOpCostModel &model, const Expr &repeat_time, Expr &cost) { | 326 | ge::Status BuildB64BinaryFuncCost(const ReduceOpCostModel &model, const Expr &repeat_time, Expr &cost) { |
| 287 | VfCostAccumulator acc; | 327 | VfCostAccumulator acc; |
| 288 | - if (model.op_kind == ReduceOpKind::kSum) { | 328 | + GE_ASSERT_SUCCESS(AddB64BinaryFuncInstructCost(model, repeat_time, 1U, acc)); |
| 289 | - GE_ASSERT_SUCCESS(AddVfInstructCost(kVcadd, kUInt32, repeat_time, 3U, acc)); | ||
| 290 | - GE_ASSERT_SUCCESS(AddVfInstructCost(kAdd, kUInt32, repeat_time, 2U, acc)); | ||
| 291 | - GE_ASSERT_SUCCESS(AddVfInstructCost(kAnd, kUInt32, repeat_time, 3U, acc)); | ||
| 292 | - GE_ASSERT_SUCCESS(AddVfInstructCost(kVshrs, kUInt32, repeat_time, 2U, acc)); | ||
| 293 | - cost = GetVfGroupCost(acc); | ||
| 294 | - return ge::SUCCESS; | ||
| 295 | - } | ||
| 296 | - const std::string compare_op = (model.binary_op == kMin) ? kLt : kGt; | ||
| 297 | - GE_ASSERT_SUCCESS(AddVfInstructCost(kEq, kUInt32, repeat_time, 1U, acc)); | ||
| 298 | - GE_ASSERT_SUCCESS(AddVfInstructCost(compare_op, kUInt32, repeat_time, 2U, acc)); | ||
| 299 | - GE_ASSERT_SUCCESS(AddVfInstructCost(kSelect, kUInt32, repeat_time, 5U, acc)); | ||
| 300 | - GE_ASSERT_SUCCESS(AddVfInstructCost(kDuplicate, kUInt32, repeat_time, 2U, acc)); | ||
| 301 | cost = GetVfGroupCost(acc); | 329 | cost = GetVfGroupCost(acc); |
| 302 | return ge::SUCCESS; | 330 | return ge::SUCCESS; |
| 303 | } | 331 | } |
| @@ -343,6 +371,23 @@ ge::Status BuildB64VfGroupCost(const ReduceOpCostModel &model, const std::string | |||
| 343 | return ge::SUCCESS; | 371 | return ge::SUCCESS; |
| 344 | } | 372 | } |
| 345 | 373 | ||
| 374 | +ge::Status BuildB64VfGroupBodyCost(const ReduceOpCostModel &model, const std::string &dtype, const Expr &count, | ||
| 375 | + uint32_t load_count, uint32_t binary_count, uint32_t store_count, Expr &cost) { | ||
| 376 | + const Expr repeat_ele = GetB64RepeatEle(dtype); | ||
| 377 | + Expr repeat_time = CreateExpr(0); | ||
| 378 | + GE_ASSERT_SUCCESS(CeilDivByPositiveConstExpr(count, repeat_ele, "repeat_ele", repeat_time)); | ||
| 379 | + VfCostAccumulator acc; | ||
| 380 | + GE_ASSERT_SUCCESS(AddVfInstructCost(kLoad, dtype, repeat_time, load_count, acc)); | ||
| 381 | + if (!IsMinMaxReduce(model) && model.op_kind != ReduceOpKind::kSum) { | ||
| 382 | + GE_ASSERT_SUCCESS(AddVfInstructCost(model.binary_op, dtype, repeat_time, binary_count, acc)); | ||
| 383 | + } else { | ||
| 384 | + GE_ASSERT_SUCCESS(AddB64BinaryFuncInstructCost(model, repeat_time, binary_count, acc)); | ||
| 385 | + } | ||
| 386 | + GE_ASSERT_SUCCESS(AddVfInstructCost(kStore, dtype, repeat_time, store_count, acc)); | ||
| 387 | + cost = GetVfGroupBodyCost(acc); | ||
| 388 | + return ge::SUCCESS; | ||
| 389 | +} | ||
| 390 | + | ||
| 346 | ge::Status BuildReduceVfGroupCost(const ReduceOpCostModel &model, const std::string &dtype, const Expr &count, | 391 | ge::Status BuildReduceVfGroupCost(const ReduceOpCostModel &model, const std::string &dtype, const Expr &count, |
| 347 | const Expr &repeat_ele, const ReduceVfGroupCounts &counts, Expr &cost) { | 392 | const Expr &repeat_ele, const ReduceVfGroupCounts &counts, Expr &cost) { |
| 348 | Expr load_cost = CreateExpr(0); | 393 | Expr load_cost = CreateExpr(0); |
| @@ -368,6 +413,15 @@ ge::Status BuildCopyOutCost(const ReduceOpCostModel &model, const std::string &d | |||
| 368 | return BuildVfGroupCost(model, dtype, count, repeat_ele, 1U, 0U, 1U, cost); | 413 | return BuildVfGroupCost(model, dtype, count, repeat_ele, 1U, 0U, 1U, cost); |
| 369 | } | 414 | } |
| 370 | 415 | ||
| 416 | +ge::Status BuildRepeatedVfGroupCost(const Expr &repeats, const std::function<ge::Status(Expr &)> &body_builder, | ||
| 417 | + Expr &cost) { | ||
| 418 | + Expr body_cost = CreateExpr(0); | ||
| 419 | + GE_ASSERT_SUCCESS(body_builder(body_cost)); | ||
| 420 | + cost = af::sym::Min(repeats, CreateExpr(1)) * CreateExpr(kReduceVfHeadCost) + repeats * body_cost; | ||
| 421 | + cost.Simplify(); | ||
| 422 | + return ge::SUCCESS; | ||
| 423 | +} | ||
| 424 | + | ||
| 371 | bool IsPositiveConst(const Expr &value) { | 425 | bool IsPositiveConst(const Expr &value) { |
| 372 | if (!value.IsConstExpr()) { | 426 | if (!value.IsConstExpr()) { |
| 373 | return true; | 427 | return true; |
| @@ -417,6 +471,7 @@ struct RaNormalContext { | |||
| 417 | }; | 471 | }; |
| 418 | 472 | ||
| 419 | using TreeCostBuilder = std::function<ge::Status(uint32_t, const Expr &, Expr &)>; | 473 | using TreeCostBuilder = std::function<ge::Status(uint32_t, const Expr &, Expr &)>; |
| 474 | +using TailInplaceCostBuilder = std::function<ge::Status(const TreeReduceParams &, Expr &)>; | ||
| 420 | 475 | ||
| 421 | Expr MakeBoolExpr(bool value) { | 476 | Expr MakeBoolExpr(bool value) { |
| 422 | return CreateExpr(value ? 1 : 0); | 477 | return CreateExpr(value ? 1 : 0); |
| @@ -735,16 +790,17 @@ ge::Status BuildArTailInplaceCost(const ReduceApiPerfContext &context, const Red | |||
| 735 | Expr repeats = CreateExpr(0); | 790 | Expr repeats = CreateExpr(0); |
| 736 | GE_ASSERT_SUCCESS(CeilDivByPositiveConstExpr(params.tailR, repeat_ele, "repeat_ele", repeats)); | 791 | GE_ASSERT_SUCCESS(CeilDivByPositiveConstExpr(params.tailR, repeat_ele, "repeat_ele", repeats)); |
| 737 | const VfGroupCounts counts = unaligned ? VfGroupCounts{4U, 1U, 2U} : VfGroupCounts{2U, 1U, 1U}; | 792 | const VfGroupCounts counts = unaligned ? VfGroupCounts{4U, 1U, 2U} : VfGroupCounts{2U, 1U, 1U}; |
| 738 | - if (b64) { | 793 | + return BuildRepeatedVfGroupCost( |
| 739 | - GE_ASSERT_SUCCESS( | 794 | + repeats, |
| 740 | - BuildB64VfGroupCost(model, dtype, count, counts.load_count, counts.binary_count, counts.store_count, cost)); | 795 | + [&model, dtype, count, repeat_ele, counts, b64](Expr &body_cost) -> ge::Status { |
| 741 | - } else { | 796 | + if (b64) { |
| 742 | - GE_ASSERT_SUCCESS(BuildVfGroupCost(model, dtype, count, repeat_ele, counts.load_count, counts.binary_count, | 797 | + return BuildB64VfGroupBodyCost(model, dtype, count, counts.load_count, counts.binary_count, |
| 743 | - counts.store_count, cost)); | 798 | + counts.store_count, body_cost); |
| 744 | - } | 799 | + } |
| 745 | - cost = repeats * cost; | 800 | + return BuildVfGroupBodyCost(model, dtype, count, repeat_ele, counts.load_count, counts.binary_count, |
| 746 | - cost.Simplify(); | 801 | + counts.store_count, body_cost); |
| 747 | - return ge::SUCCESS; | 802 | + }, |
| 803 | + cost); | ||
| 748 | } | 804 | } |
| 749 | 805 | ||
| 750 | ge::Status CalculateArTreeReduceParams(const ReduceApiPerfContext &context, uint32_t avg_folds, | 806 | ge::Status CalculateArTreeReduceParams(const ReduceApiPerfContext &context, uint32_t avg_folds, |
| @@ -965,34 +1021,50 @@ ge::Status AddSymbolicTailFoldCost(const ReduceOpCostModel &model, const NormalS | |||
| 965 | return ge::SUCCESS; | 1021 | return ge::SUCCESS; |
| 966 | } | 1022 | } |
| 967 | 1023 | ||
| 968 | -ge::Status BuildTreeBodyCost(const ReduceOpCostModel &model, const NormalSymbolicTreeSpec &spec, uint32_t avg_folds, | 1024 | +ge::Status BuildTreeBodyCost(const ReduceOpCostModel &model, const NormalSymbolicTreeSpec &spec, |
| 969 | - bool b64, const TreeReduceParams ¶ms, Expr &cost) { | 1025 | + uint32_t avg_folds, bool b64, |
| 1026 | + const TreeReduceParams ¶ms, const TailInplaceCostBuilder &tail_builder, Expr &cost) { | ||
| 970 | Expr inplace_one = CreateExpr(0); | 1027 | Expr inplace_one = CreateExpr(0); |
| 971 | - const uint32_t inplace_store_count = GetInplaceStoreCount(spec); | 1028 | + if (tail_builder != nullptr) { |
| 972 | - if (b64) { | 1029 | + GE_ASSERT_SUCCESS(tail_builder(params, inplace_one)); |
| 973 | - GE_ASSERT_SUCCESS(BuildB64VfGroupCost(model, spec.dtype, spec.count, spec.inplace_load_count, 1U, | ||
| 974 | - inplace_store_count, inplace_one)); | ||
| 975 | } else { | 1030 | } else { |
| 976 | - GE_ASSERT_SUCCESS(BuildVfGroupCost(model, spec.dtype, spec.count, spec.repeat_ele, spec.inplace_load_count, 1U, | 1031 | + const uint32_t inplace_store_count = GetInplaceStoreCount(spec); |
| 977 | - inplace_store_count, inplace_one)); | 1032 | + if (b64) { |
| 1033 | + GE_ASSERT_SUCCESS(BuildRepeatedVfGroupCost( | ||
| 1034 | + params.tailR, | ||
| 1035 | + [&model, spec, inplace_store_count](Expr &body_cost) -> ge::Status { | ||
| 1036 | + return BuildB64VfGroupBodyCost(model, spec.dtype, spec.count, spec.inplace_load_count, 1U, | ||
| 1037 | + inplace_store_count, body_cost); | ||
| 1038 | + }, | ||
| 1039 | + inplace_one)); | ||
| 1040 | + } else { | ||
| 1041 | + GE_ASSERT_SUCCESS(BuildRepeatedVfGroupCost( | ||
| 1042 | + params.tailR, | ||
| 1043 | + [&model, spec, inplace_store_count](Expr &body_cost) -> ge::Status { | ||
| 1044 | + return BuildVfGroupBodyCost(model, spec.dtype, spec.count, spec.repeat_ele, spec.inplace_load_count, 1U, | ||
| 1045 | + inplace_store_count, body_cost); | ||
| 1046 | + }, | ||
| 1047 | + inplace_one)); | ||
| 1048 | + } | ||
| 978 | } | 1049 | } |
| 979 | 1050 | ||
| 980 | Expr main_fold = CreateExpr(0); | 1051 | Expr main_fold = CreateExpr(0); |
| 981 | GE_ASSERT_SUCCESS(AddSymbolicMainFoldCost(model, spec, params, avg_folds, b64, main_fold)); | 1052 | GE_ASSERT_SUCCESS(AddSymbolicMainFoldCost(model, spec, params, avg_folds, b64, main_fold)); |
| 982 | Expr tail_fold = CreateExpr(0); | 1053 | Expr tail_fold = CreateExpr(0); |
| 983 | GE_ASSERT_SUCCESS(AddSymbolicTailFoldCost(model, spec, params.flags, b64, tail_fold)); | 1054 | GE_ASSERT_SUCCESS(AddSymbolicTailFoldCost(model, spec, params.flags, b64, tail_fold)); |
| 984 | - cost = params.tailR * inplace_one + main_fold + tail_fold; | 1055 | + cost = inplace_one + main_fold + tail_fold; |
| 985 | cost.Simplify(); | 1056 | cost.Simplify(); |
| 986 | return ge::SUCCESS; | 1057 | return ge::SUCCESS; |
| 987 | } | 1058 | } |
| 988 | 1059 | ||
| 989 | TreeCostBuilder MakeTreeCostBuilder(const ReduceOpCostModel &model, const NormalSymbolicTreeSpec &spec, | 1060 | TreeCostBuilder MakeTreeCostBuilder(const ReduceOpCostModel &model, const NormalSymbolicTreeSpec &spec, |
| 990 | - uint32_t avg_folds, bool supports_fold_three, bool b64) { | 1061 | + uint32_t avg_folds, bool supports_fold_three, bool b64, |
| 991 | - return [&model, spec, avg_folds, supports_fold_three, b64](uint32_t main_r, const Expr &tail_r, | 1062 | + const TailInplaceCostBuilder &tail_builder = nullptr) { |
| 992 | - Expr &case_cost) -> ge::Status { | 1063 | + return [&model, spec, avg_folds, supports_fold_three, b64, tail_builder](uint32_t main_r, const Expr &tail_r, |
| 1064 | + Expr &case_cost) -> ge::Status { | ||
| 993 | TreeReduceParams params; | 1065 | TreeReduceParams params; |
| 994 | GE_ASSERT_SUCCESS(MakeTreeReduceParams(main_r, tail_r, avg_folds, supports_fold_three, params)); | 1066 | GE_ASSERT_SUCCESS(MakeTreeReduceParams(main_r, tail_r, avg_folds, supports_fold_three, params)); |
| 995 | - return BuildTreeBodyCost(model, spec, avg_folds, b64, params, case_cost); | 1067 | + return BuildTreeBodyCost(model, spec, avg_folds, b64, params, tail_builder, case_cost); |
| 996 | }; | 1068 | }; |
| 997 | } | 1069 | } |
| 998 | 1070 | ||
| @@ -1008,9 +1080,12 @@ ge::Status BuildRaB64ConstTreeCost(const ReduceOpCostModel &model, const std::st | |||
| 1008 | uint32_t inplace_store, Expr &cost) { | 1080 | uint32_t inplace_store, Expr &cost) { |
| 1009 | Expr inplace_add = CreateExpr(0); | 1081 | Expr inplace_add = CreateExpr(0); |
| 1010 | if (IsPositiveConst(params.tailR)) { | 1082 | if (IsPositiveConst(params.tailR)) { |
| 1011 | - Expr inplace_one = CreateExpr(0); | 1083 | + GE_ASSERT_SUCCESS(BuildRepeatedVfGroupCost( |
| 1012 | - GE_ASSERT_SUCCESS(BuildB64VfGroupCost(model, dtype, count, inplace_load, 1U, inplace_store, inplace_one)); | 1084 | + params.tailR, |
| 1013 | - inplace_add = params.tailR * inplace_one; | 1085 | + [&model, dtype, count, inplace_load, inplace_store](Expr &body_cost) -> ge::Status { |
| 1086 | + return BuildB64VfGroupBodyCost(model, dtype, count, inplace_load, 1U, inplace_store, body_cost); | ||
| 1087 | + }, | ||
| 1088 | + inplace_add)); | ||
| 1014 | } | 1089 | } |
| 1015 | Expr main_fold = CreateExpr(0); | 1090 | Expr main_fold = CreateExpr(0); |
| 1016 | GE_ASSERT_SUCCESS(AddMainFoldCost(model, dtype, count, repeat_ele, params, 3U, true, main_fold)); | 1091 | GE_ASSERT_SUCCESS(AddMainFoldCost(model, dtype, count, repeat_ele, params, 3U, true, main_fold)); |
| @@ -1256,9 +1331,12 @@ ge::Status BuildRaNormalOverVlAlignedCost(const ReduceApiPerfContext &context, c | |||
| 1256 | 1331 | ||
| 1257 | Expr inplace_add = CreateExpr(0); | 1332 | Expr inplace_add = CreateExpr(0); |
| 1258 | if (IsPositiveConst(params.tailR)) { | 1333 | if (IsPositiveConst(params.tailR)) { |
| 1259 | - Expr inplace_one = CreateExpr(0); | 1334 | + GE_ASSERT_SUCCESS(BuildRepeatedVfGroupCost( |
| 1260 | - GE_ASSERT_SUCCESS(BuildVfGroupCost(model, dtype, count, repeat_ele, 2U, 1U, 1U, inplace_one)); | 1335 | + params.tailR, |
| 1261 | - inplace_add = params.tailR * inplace_one; | 1336 | + [&model, dtype, count, repeat_ele](Expr &body_cost) -> ge::Status { |
| 1337 | + return BuildVfGroupBodyCost(model, dtype, count, repeat_ele, 2U, 1U, 1U, body_cost); | ||
| 1338 | + }, | ||
| 1339 | + inplace_add)); | ||
| 1262 | } | 1340 | } |
| 1263 | 1341 | ||
| 1264 | Expr main_fold = CreateExpr(0); | 1342 | Expr main_fold = CreateExpr(0); |
| @@ -1330,6 +1408,16 @@ ge::Status AddNormalUnalignedTailFoldCost(const ReduceOpCostModel &model, const | |||
| 1330 | return ge::SUCCESS; | 1408 | return ge::SUCCESS; |
| 1331 | } | 1409 | } |
| 1332 | 1410 | ||
| 1411 | +ge::Status BuildNormalUnalignedInplaceCost(const ReduceOpCostModel &model, const std::string &dtype, const Expr &dim_a, | ||
| 1412 | + const Expr &repeat_ele, const Expr &tail_r, Expr &cost) { | ||
| 1413 | + return BuildRepeatedVfGroupCost( | ||
| 1414 | + tail_r, | ||
| 1415 | + [&model, dtype, dim_a, repeat_ele](Expr &body_cost) -> ge::Status { | ||
| 1416 | + return BuildVfGroupBodyCost(model, dtype, dim_a, repeat_ele, 4U, 1U, 2U, body_cost); | ||
| 1417 | + }, | ||
| 1418 | + cost); | ||
| 1419 | +} | ||
| 1420 | + | ||
| 1333 | ge::Status BuildRaNormalUnalignedCost(const ReduceApiPerfContext &context, const ReduceOpCostModel &model, | 1421 | ge::Status BuildRaNormalUnalignedCost(const ReduceApiPerfContext &context, const ReduceOpCostModel &model, |
| 1334 | PerfOutputInfo &perf, Expr &cost) { | 1422 | PerfOutputInfo &perf, Expr &cost) { |
| 1335 | const auto &nd = context.node_detail; | 1423 | const auto &nd = context.node_detail; |
| @@ -1339,17 +1427,19 @@ ge::Status BuildRaNormalUnalignedCost(const ReduceApiPerfContext &context, const | |||
| 1339 | const Expr repeat_ele = GetNormalVlSize(dtype); | 1427 | const Expr repeat_ele = GetNormalVlSize(dtype); |
| 1340 | if (!dim_r.IsConstExpr()) { | 1428 | if (!dim_r.IsConstExpr()) { |
| 1341 | NormalSymbolicTreeSpec spec{dtype, dim_r, dim_a, repeat_ele, 4U, 32U, 4U, 2U}; | 1429 | NormalSymbolicTreeSpec spec{dtype, dim_r, dim_a, repeat_ele, 4U, 32U, 4U, 2U}; |
| 1430 | + TailInplaceCostBuilder tail_builder = [&model, dtype, dim_a, repeat_ele](const TreeReduceParams ¶ms, | ||
| 1431 | + Expr &tail_cost) -> ge::Status { | ||
| 1432 | + return BuildNormalUnalignedInplaceCost(model, dtype, dim_a, repeat_ele, params.tailR, tail_cost); | ||
| 1433 | + }; | ||
| 1342 | return SelectSymbolicTreeCost("reduce_ra_normal_unaligned_tree_cost", dim_r, | 1434 | return SelectSymbolicTreeCost("reduce_ra_normal_unaligned_tree_cost", dim_r, |
| 1343 | - MakeTreeCostBuilder(model, spec, 4U, true, false), perf, cost); | 1435 | + MakeTreeCostBuilder(model, spec, 4U, true, false, tail_builder), perf, cost); |
| 1344 | } | 1436 | } |
| 1345 | 1437 | ||
| 1346 | TreeReduceParams params; | 1438 | TreeReduceParams params; |
| 1347 | GE_ASSERT_SUCCESS(CalculateTreeReduceParams(dim_r, 4U, true, params)); | 1439 | GE_ASSERT_SUCCESS(CalculateTreeReduceParams(dim_r, 4U, true, params)); |
| 1348 | Expr inplace_add = CreateExpr(0); | 1440 | Expr inplace_add = CreateExpr(0); |
| 1349 | if (IsPositiveConst(params.tailR)) { | 1441 | if (IsPositiveConst(params.tailR)) { |
| 1350 | - Expr inplace_one = CreateExpr(0); | 1442 | + GE_ASSERT_SUCCESS(BuildNormalUnalignedInplaceCost(model, dtype, dim_a, repeat_ele, params.tailR, inplace_add)); |
| 1351 | - GE_ASSERT_SUCCESS(BuildVfGroupCost(model, dtype, dim_a, repeat_ele, 4U, 1U, 2U, inplace_one)); | ||
| 1352 | - inplace_add = params.tailR * inplace_one; | ||
| 1353 | } | 1443 | } |
| 1354 | 1444 | ||
| 1355 | Expr main_fold = CreateExpr(0); | 1445 | Expr main_fold = CreateExpr(0); |
| @@ -26,6 +26,9 @@ class PerfParamTableV2 : public PerfParamTable { | |||
| 26 | [[nodiscard]] Expr GetVectorFunctionHeadCost() const override; | 26 | [[nodiscard]] Expr GetVectorFunctionHeadCost() const override; |
| 27 | [[nodiscard]] std::string GetApiRegisterVerName() const override; | 27 | [[nodiscard]] std::string GetApiRegisterVerName() const override; |
| 28 | [[nodiscard]] Expr GetOpHeadCost() const override; | 28 | [[nodiscard]] Expr GetOpHeadCost() const override; |
| 29 | + [[nodiscard]] uint32_t GetMicroApiLen() const override { | ||
| 30 | + return arch_param::kV2ArchHardwareConfig.vector_len_size; | ||
| 31 | + } | ||
| 29 | [[nodiscard]] const std::string *GetAscendCApiPerfTable() const override; | 32 | [[nodiscard]] const std::string *GetAscendCApiPerfTable() const override; |
| 30 | [[nodiscard]] PipeHeadPerfFunc GetPipeHeadPerfFunc(PipeType pipe_type) const override; | 33 | [[nodiscard]] PipeHeadPerfFunc GetPipeHeadPerfFunc(PipeType pipe_type) const override; |
| 31 | [[nodiscard]] static Expr GetMTE2PipeHead(const std::vector<NodeInfo> &node_infos, | 34 | [[nodiscard]] static Expr GetMTE2PipeHead(const std::vector<NodeInfo> &node_infos, |
| @@ -58,11 +61,15 @@ class TilingScheduleConfigTableV2 : public TilingScheduleConfigTable { | |||
| 58 | [[nodiscard]] TilingScheduleConfig GetModelTilingScheduleConfig() const override { | 61 | [[nodiscard]] TilingScheduleConfig GetModelTilingScheduleConfig() const override { |
| 59 | TilingScheduleConfig config; | 62 | TilingScheduleConfig config; |
| 60 | config.trade_off_config = GetTradeOffConfig(); | 63 | config.trade_off_config = GetTradeOffConfig(); |
| 61 | - config.cache_line_size = 128; // V2 CacheLine 大小为 128 字节 | 64 | + config.cache_line_size = GetCacheLineSize(); |
| 65 | + config.vector_len_size = GetVectorLenSize(); | ||
| 62 | return config; | 66 | return config; |
| 63 | } | 67 | } |
| 64 | [[nodiscard]] uint32_t GetCacheLineSize() const override { | 68 | [[nodiscard]] uint32_t GetCacheLineSize() const override { |
| 65 | - return 128; // V2 CacheLine 大小为 128 字节 | 69 | + return arch_param::kV2ArchHardwareConfig.cache_line_size; |
| 70 | + } | ||
| 71 | + [[nodiscard]] uint32_t GetVectorLenSize() const override { | ||
| 72 | + return arch_param::kV2ArchHardwareConfig.vector_len_size; | ||
| 66 | } | 73 | } |
| 67 | // 新增:V2形态使能Reduce分核惩罚 | 74 | // 新增:V2形态使能Reduce分核惩罚 |
| 68 | [[nodiscard]] bool IsCoreNumThresholdPenaltyEnable() const override { | 75 | [[nodiscard]] bool IsCoreNumThresholdPenaltyEnable() const override { |


🔵 Low Priority
CeilDiv(arg_list_reorder.cpp第 96–101 行)在divisor == 0U时直接返回0U,不记录任何错误。这会在调用方意外传入 0 除数时静默产生0结果,可能掩盖数据问题。当前所有调用点在传入divisor前均已校验(例如HasSmallTailLargeReduceTile第 296 行检查tensor->data_type_size == 0U),但该函数作为工具函数,静默吞错的设计不够安全,未来新增调用点可能遗漏校验。建议:在 divisor==0 分支增加错误日志,并返回一个标示异常的上界值(例如 UINT32_MAX),或者使用 assert/GE_ASSERT_TRUE 确保调用方不会传入零除数。