已合并
fix: 优化 Reduce RA 未对齐尾部开销和 tile reorder 轴优先级 #1006
fix: 优化 Reduce RA 未对齐尾部开销和 tile reorder 轴优先级 #1006
已合并
zhang_shengjie创建于 6月23日
共 16 个文件变更+1356-396
@@ -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_H12#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+ 
228class TilingScheduleConfigTable {242class 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 
297using TilingModelInfo = std::vector<ModelInfo>;317using 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 of3+ * 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 
63class TilingScheduleConfigTableV1HeavyOp : public TilingScheduleConfigTableV1 {69class 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 of3+ * 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+ 
13namespace att {16namespace att {
14namespace {17namespace {
15constexpr size_t kOrderIdStart = 1;18constexpr size_t kOrderIdStart = 1;
16-const std::vector<std::string> kDefaultNodeWhiteList = {"Data", "Output", "Constant", "Workspace", "TbufData"};19+const std::vector<std::string> kDefaultNodeWhiteList = {
17-} // namespace20+ "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+}
atomgit-bot
atomgit-botatomgit-bot6月23日

🔵 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 确保调用方不会传入零除数。

likedislike
不准确?
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轴优先级高于最内轴这条原则
273ge::Status ArgListReorder::BuildArgListPriorityGraph(const vector<AttAxisPtr> &arg_list, bool tiling_R) {518ge::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 of3+ * 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+}
atomgit-bot
atomgit-botatomgit-bot6月23日

🔵 Low Priority

GenRuntimeCompoundExprValue(axes_reorder_solver_gen.cpp 第 1079–1099 行)使用字符串 find + replace 的方式将临时占位名(__runtime_expr_N__)替换为运行时求值表达式。该方案依赖占位名不会出现在任何替换值的字符串表示中。如果某个 GenRuntimeExprValue(arg) 的返回值恰好包含形如 __runtime_expr_M__ 的子串,则可能发生错误替换,导致生成的 C++ 代码不正确。

虽然当前占位名格式(带序号 + 双下划线)与正常 Expr 名称冲突概率极低,但随着系统演进,存在潜在风险。建议使用更安全的替换方式,例如按 token 边界替换,或在替换前对占位名做更唯一的编码(如加入随机后缀或使用不合法 C++ 标识符字符)。

建议:考虑在占位名中加入不会出现在正常 Expr 名中的字符(如 $),或用一次 regex_replace 整体替换,避免先后替换时的子串匹配问题。

likedislike
不准确?
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+ 
1056std::string AxesReorderSolverGen::GenInput(const TradeOffConfig &trade_off_config, std::vector<Expr> &all_cons) {1139std::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+ 
1342std::string AxesReorderSolverGen::GenSolverFuncImpl() {1453std::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 中的 TilingScheduleConfig1462 // 直接使用 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 
26namespace att {26namespace 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 att128+ }
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#endif250#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 of3+ * 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 public15#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{
17class TestArgListReorder : public ::testing::Test {20class 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 (right31+ // 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 (right36+ // 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 TuningSpace42+constexpr uint32_t kTensorDataTypeSize = 2U;
38- // Create node: MatMul43+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 
734TEST_F(UTestReduceMinMaxApiPerfV2, ArB64UnalignedSmallLastUsesOneVectorBlock) {788TEST_F(UTestReduceMinMaxApiPerfV2, ArB64UnalignedSmallLastUsesOneVectorBlock) {
@@ -24,6 +24,7 @@ namespace {
24constexpr int64_t kOneStride = 32768;24constexpr int64_t kOneStride = 32768;
25constexpr int64_t kVectorBlockBytes = 256;25constexpr int64_t kVectorBlockBytes = 256;
26constexpr int64_t kB64RegTraitNumTwoElements = 64;26constexpr int64_t kB64RegTraitNumTwoElements = 64;
27+constexpr int64_t kReduceVfHeadCost = 64;
atomgit-bot
atomgit-botatomgit-bot6月23日

🟡 Medium Priority

BuildRepeatedVfGroupCost(第 420 行)使用硬编码常量 kReduceVfHeadCost = 64(第 27 行)作为 VF 头开销。但系统中已有的 VF 头开销获取途径 VfPerfUtils::GetVFHeadCost() 返回 PerfParamTableV2::GetVectorFunctionHeadCost() 的值 20(perf_param_v2.cpp 第 418–420 行)。旧代码中,tail 路径通过 VfOpCost / GetVfGroupCost 间接使用了 20 这个值(每次调用加 20),新代码的 body builder(BuildVfGroupBodyCost、BuildB64VfGroupBodyCost)完全去掉了 per-group 的 20,改为在 BuildRepeatedVfGroupCost 中一次性加 64。

具体影响:对于 tail repeats=N 的场景,旧模型为 N * (20 * group_count + body_instructions),新模型为 1 * 64 + N * body_instructions。这意味着 per-instruction-group 的 20 cycles 头开销完全消失,取而代之的是一次性的 64 cycles。如果 20 和 64 对应的是不同层级的开销(per-instruct-group vs per-VF-invocation),需要确认 body cost 是否应当保留 per-group 的 20。目前 main-fold 路径仍使用 GetVfGroupCost(含 20),而所有 tail 路径均使用新模型(含 64),两者不一致。

触发条件:任何 Reduce tail 场景(AR tail inplace、RA tree reduce tail、RA B64 const tree cost、RA normal aligned/unaligned tail)。

建议:确认 kReduceVfHeadCost = 64 的语义:如果 64 是 Reduce VF 调用级头开销,应将其统一定义到 arch_param 或通过 PerfParamTable 查询,避免硬编码;同时确认 body builder 中是否需要恢复 per-instruct-group 的 GetVectorFunctionHeadCost()(20)。如果 20 本身就不该在 body 中出现,那 main-fold 路径也需同步调整,消除两者不一致。

likedislike
不准确?
27constexpr uint32_t kReduceMaxMainRPower = 15U;28constexpr 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+ 
256Expr GetB64RepeatEle(const std::string &dtype) {263Expr 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+ 
286ge::Status BuildB64BinaryFuncCost(const ReduceOpCostModel &model, const Expr &repeat_time, Expr &cost) {326ge::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+ 
346ge::Status BuildReduceVfGroupCost(const ReduceOpCostModel &model, const std::string &dtype, const Expr &count,391ge::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+ 
371bool IsPositiveConst(const Expr &value) {425bool 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 
419using TreeCostBuilder = std::function<ge::Status(uint32_t, const Expr &, Expr &)>;473using TreeCostBuilder = std::function<ge::Status(uint32_t, const Expr &, Expr &)>;
474+using TailInplaceCostBuilder = std::function<ge::Status(const TreeReduceParams &, Expr &)>;
420 475 
421Expr MakeBoolExpr(bool value) {476Expr 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 
750ge::Status CalculateArTreeReduceParams(const ReduceApiPerfContext &context, uint32_t avg_folds,806ge::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 &params, Expr &cost) {1025+ uint32_t avg_folds, bool b64,
1026+ const TreeReduceParams &params, 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 
989TreeCostBuilder MakeTreeCostBuilder(const ReduceOpCostModel &model, const NormalSymbolicTreeSpec &spec,1060TreeCostBuilder 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+ 
1333ge::Status BuildRaNormalUnalignedCost(const ReduceApiPerfContext &context, const ReduceOpCostModel &model,1421ge::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 &params,
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 {