已合并
feat: 支持vectorfunc动态stride性能公式 #1208
gaoxin创建于 7月6日
feat: 支持vectorfunc动态stride性能公式 #1208
已合并
共 18 个文件变更+599-114
| @@ -22,30 +22,6 @@ Expr GetDataTypeSize(const std::string &data_type) { | |||
| 22 | } | 22 | } |
| 23 | return iter->second; | 23 | return iter->second; |
| 24 | } | 24 | } |
| 25 | -bool IsLoadStoreVfApi(const std::string µ_api_type) { | ||
| 26 | - const std::set<std::string> kLoadStoreVfType{kMoveGmToUb, kMoveUbToGm}; | ||
| 27 | - return kLoadStoreVfType.find(micro_api_type) != kLoadStoreVfType.end(); | ||
| 28 | -} | ||
| 29 | - | ||
| 30 | -// 获取vf api的基础latency和throughput | ||
| 31 | -af::Status GetVFNodePerf(const NodePerfInfo &node_info, const uint32_t micro_api_len, Expr &latency, Expr &throughput) { | ||
| 32 | - GE_ASSERT_SUCCESS(VfPerfUtils::GetVfInstructPerf(node_info.optype, node_info.input_dtype, latency, throughput)); | ||
| 33 | - Expr dim_product = std::accumulate(node_info.dims.begin(), node_info.dims.end(), CreateExpr(1), | ||
| 34 | - [](const Expr &a, const Expr &b) { return a * b; }); | ||
| 35 | - // 简化计算,后续进一步考虑每个op的latency和throughput的掩盖 | ||
| 36 | - Expr shape_size = dim_product * GetDataTypeSize(node_info.input_dtype); | ||
| 37 | - Expr api_count = af::sym::Ceiling(shape_size / CreateExpr(micro_api_len)); | ||
| 38 | - api_count = api_count.Simplify(); | ||
| 39 | - throughput = throughput * api_count; | ||
| 40 | - throughput = throughput.Simplify(); | ||
| 41 | - GELOGD( | ||
| 42 | - "[VF_PERF_DFX] node[%s], input_dtype[%s], dims[%s], dim_product[%s], shape_size[%s], micro_api_len[%u], " | ||
| 43 | - "api_count[%s], latency[%s], throughput[%s]", | ||
| 44 | - node_info.optype.c_str(), node_info.input_dtype.c_str(), GetVecString(node_info.dims).c_str(), | ||
| 45 | - dim_product.Serialize().get(), shape_size.Serialize().get(), micro_api_len, api_count.Serialize().get(), | ||
| 46 | - latency.Serialize().get(), throughput.Serialize().get()); | ||
| 47 | - return af::SUCCESS; | ||
| 48 | -} | ||
| 49 | 25 | ||
| 50 | const PerfParamTable *GetParamPerfTable() { | 26 | const PerfParamTable *GetParamPerfTable() { |
| 51 | const auto default_impl = ascgen_utils::GetAscIrAttImpl(kDefaultApi); | 27 | const auto default_impl = ascgen_utils::GetAscIrAttImpl(kDefaultApi); |
| @@ -56,6 +32,65 @@ const PerfParamTable *GetParamPerfTable() { | |||
| 56 | GE_ASSERT_NOTNULL(api_perf); | 32 | GE_ASSERT_NOTNULL(api_perf); |
| 57 | return api_perf->GetPerfParam(); | 33 | return api_perf->GetPerfParam(); |
| 58 | } | 34 | } |
| 35 | + | ||
| 36 | +Expr GetVFApiCount(const NodePerfInfo &node_info, const uint32_t micro_api_len, bool strides_equal, | ||
| 37 | + const ascir_param::VectorFuncNodeParams &vector_func_params) { | ||
| 38 | + const Expr data_type_size = GetDataTypeSize(node_info.input_dtype); | ||
| 39 | + if (vector_func_params.is_double_loop && strides_equal) { | ||
| 40 | + const Expr element_count = vector_func_params.all_strides[0] * vector_func_params.output_dims[0]; | ||
| 41 | + return af::sym::Ceiling(element_count * data_type_size / CreateExpr(micro_api_len)); | ||
| 42 | + } | ||
| 43 | + if (vector_func_params.is_double_loop && !strides_equal) { | ||
| 44 | + GE_ASSERT_TRUE(vector_func_params.output_dims.size() >= 2U, | ||
| 45 | + "VectorFunc double loop with unequal strides requires output_dims size >= 2, but got %zu.", | ||
| 46 | + vector_func_params.output_dims.size()); | ||
| 47 | + return vector_func_params.output_dims[0] * | ||
Z | |||
| 48 | + af::sym::Ceiling(vector_func_params.output_dims[1] * data_type_size / CreateExpr(micro_api_len)); | ||
| 49 | + } | ||
| 50 | + Expr dim_product = std::accumulate(node_info.dims.begin(), node_info.dims.end(), CreateExpr(1), | ||
| 51 | + [](const Expr &a, const Expr &b) { return a * b; }); | ||
| 52 | + return af::sym::Ceiling(dim_product * data_type_size / CreateExpr(micro_api_len)); | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +// 获取vf api的基础latency和throughput | ||
| 56 | +af::Status GetVFNodePerf(const NodePerfInfo &node_info, const uint32_t micro_api_len, bool strides_equal, | ||
| 57 | + const ascir_param::VectorFuncNodeParams &vector_func_params, Expr &latency, Expr &throughput) { | ||
| 58 | + GE_ASSERT_SUCCESS(VfPerfUtils::GetVfInstructPerf(node_info.optype, node_info.input_dtype, latency, throughput)); | ||
| 59 | + // 简化计算,后续进一步考虑每个op的latency和throughput的掩盖 | ||
| 60 | + Expr api_count = GetVFApiCount(node_info, micro_api_len, strides_equal, vector_func_params); | ||
| 61 | + api_count = api_count.Simplify(); | ||
| 62 | + throughput = throughput * api_count; | ||
| 63 | + throughput = throughput.Simplify(); | ||
| 64 | + GELOGD("Got node %s input %s reg base latency %s, throughput %s, api_count %s", node_info.optype.c_str(), | ||
| 65 | + node_info.input_dtype.c_str(), latency.Serialize().get(), throughput.Serialize().get(), | ||
| 66 | + api_count.Serialize().get()); | ||
| 67 | + return af::SUCCESS; | ||
| 68 | +} | ||
| 69 | + | ||
| 70 | +af::Status GetVectorFunctionPerfByStrideStatus(const std::vector<NodePerfInfo> &node_perf_infos, | ||
| 71 | + const uint32_t micro_api_len, bool strides_equal, | ||
| 72 | + const ascir_param::VectorFuncNodeParams &vector_func_params, Expr &res) { | ||
| 73 | + Expr all_micro_api_cost = CreateExpr(0); | ||
| 74 | + Expr max_latency = CreateExpr(0); | ||
| 75 | + for (const auto &node_info : node_perf_infos) { | ||
| 76 | + Expr latency = CreateExpr(0); | ||
| 77 | + Expr throughput = CreateExpr(0); | ||
| 78 | + GE_ASSERT_SUCCESS(GetVFNodePerf(node_info, micro_api_len, strides_equal, vector_func_params, latency, throughput)); | ||
| 79 | + all_micro_api_cost = af::sym::Add(all_micro_api_cost, throughput); | ||
| 80 | + max_latency = af::sym::Max(max_latency, latency); | ||
| 81 | + } | ||
| 82 | + max_latency = max_latency.Simplify(); | ||
| 83 | + all_micro_api_cost = all_micro_api_cost.Simplify(); | ||
| 84 | + res = af::sym::Add(all_micro_api_cost, max_latency); | ||
| 85 | + const auto vector_function_head_cost = GetParamPerfTable()->GetVectorFunctionHeadCost(); | ||
| 86 | + res = af::sym::Add(res, vector_function_head_cost); | ||
| 87 | + res = res.Simplify(); | ||
| 88 | + GELOGD("Got vector function perf %s, vector_function_head_cost %s, max_latency %s, all_micro_api_cost %s", | ||
| 89 | + res.Serialize().get(), vector_function_head_cost.Serialize().get(), max_latency.Serialize().get(), | ||
| 90 | + all_micro_api_cost.Serialize().get()); | ||
| 91 | + return af::SUCCESS; | ||
| 92 | +} | ||
| 93 | + | ||
| 59 | } // namespace | 94 | } // namespace |
| 60 | 95 | ||
| 61 | af::Status VfPerfUtils::GetVfInstructPerf(const std::string µ_api_type, const std::string &data_type, | 96 | af::Status VfPerfUtils::GetVfInstructPerf(const std::string µ_api_type, const std::string &data_type, |
| @@ -106,35 +141,40 @@ Expr VfPerfUtils::GetVFHeadCost() { | |||
| 106 | // 5.Micro Api的并发度 | 141 | // 5.Micro Api的并发度 |
| 107 | // 第一版建模简化模型,仅考虑1,2,3,每个op的latency求最大值,throughput求和 | 142 | // 第一版建模简化模型,仅考虑1,2,3,每个op的latency求最大值,throughput求和 |
| 108 | // 后续建模考虑4,5 | 143 | // 后续建模考虑4,5 |
| 109 | -af::Status VfPerfUtils::GetVectorFunctionPerf(const std::vector<NodePerfInfo> &node_perf_infos, Expr &res) { | 144 | +af::Status VfPerfUtils::GetVectorFunctionPerf(const std::vector<NodePerfInfo> &node_perf_infos, |
| 145 | + const ascir_param::VectorFuncNodeParams &vector_func_params, | ||
| 146 | + std::map<Expr, TernaryOp, ExprCmp> &ternary_ops, Expr &res) { | ||
| 110 | const auto param_table = GetParamPerfTable(); | 147 | const auto param_table = GetParamPerfTable(); |
| 111 | GE_ASSERT_NOTNULL(param_table); | 148 | GE_ASSERT_NOTNULL(param_table); |
| 112 | const uint32_t micro_api_len = param_table->GetMicroApiLen(); | 149 | const uint32_t micro_api_len = param_table->GetMicroApiLen(); |
| 113 | - Expr all_micro_api_cost = CreateExpr(0); | 150 | + const auto &all_strides = vector_func_params.all_strides; |
| 114 | - Expr max_latency = CreateExpr(0); | 151 | + if (!vector_func_params.is_double_loop) { |
| 115 | - for (const auto &node_info : node_perf_infos) { | 152 | + return GetVectorFunctionPerfByStrideStatus(node_perf_infos, micro_api_len, false, vector_func_params, res); |
| 116 | - Expr latency = CreateExpr(0); | ||
| 117 | - Expr throughput = CreateExpr(0); | ||
| 118 | - if (IsLoadStoreVfApi(node_info.optype)) { | ||
| 119 | - // Load Store VF API暂认为非主导因素,待后续支持搬运类算子或Brc算子时再进行建模 | ||
| 120 | - continue; | ||
| 121 | - } | ||
| 122 | - // 在vf function内的必须支持vector, 待校验 | ||
| 123 | - GE_ASSERT_SUCCESS(GetVFNodePerf(node_info, micro_api_len, latency, throughput)); | ||
| 124 | - // 每个op的latency相加, throughput求最大值 | ||
| 125 | - all_micro_api_cost = af::sym::Add(all_micro_api_cost, throughput); | ||
| 126 | - max_latency = af::sym::Max(max_latency, latency); | ||
| 127 | } | 153 | } |
| 128 | - max_latency = max_latency.Simplify(); | 154 | + if (all_strides.empty()) { |
| 129 | - all_micro_api_cost = all_micro_api_cost.Simplify(); | 155 | + return GetVectorFunctionPerfByStrideStatus(node_perf_infos, micro_api_len, false, vector_func_params, res); |
| 130 | - // 加上最大的latency | 156 | + } |
| 131 | - res = af::sym::Add(all_micro_api_cost, max_latency); | 157 | + if (all_strides.size() == 1U) { |
| 132 | - const auto vector_function_head_cost = param_table->GetVectorFunctionHeadCost(); | 158 | + return GetVectorFunctionPerfByStrideStatus(node_perf_infos, micro_api_len, true, vector_func_params, res); |
| 133 | - res = af::sym::Add(res, vector_function_head_cost); | 159 | + } |
| 134 | - res = res.Simplify(); | 160 | + Expr strides_equal_perf; |
| 135 | - GELOGD("Got vector function perf %s, vector_function_head_cost %s, max_latency %s, all_micro_api_cost %s", | 161 | + Expr strides_unequal_perf; |
| 136 | - res.Serialize().get(), vector_function_head_cost.Serialize().get(), max_latency.Serialize().get(), | 162 | + GE_ASSERT_SUCCESS(GetVectorFunctionPerfByStrideStatus(node_perf_infos, micro_api_len, true, vector_func_params, |
| 137 | - all_micro_api_cost.Serialize().get()); | 163 | + strides_equal_perf)); |
| 164 | + GE_ASSERT_SUCCESS(GetVectorFunctionPerfByStrideStatus(node_perf_infos, micro_api_len, false, vector_func_params, | ||
| 165 | + strides_unequal_perf)); | ||
| 166 | + res = CreateExpr("vf_dynamic_perf"); | ||
| 167 | + GetPerfVar("vf_dynamic_perf", res, ternary_ops); | ||
| 168 | + std::shared_ptr<IfCase> equal_case = std::make_shared<IfCase>(strides_equal_perf); | ||
| 169 | + for (size_t i = all_strides.size() - 1U; i > 0U; --i) { | ||
| 170 | + equal_case = std::make_shared<IfCase>(CondType::K_EQ, all_strides[0], all_strides[i], std::move(equal_case), | ||
| 171 | + std::make_shared<IfCase>(strides_unequal_perf)); | ||
| 172 | + } | ||
| 173 | + std::vector<Expr> related_vars; | ||
| 174 | + equal_case->GetUsedArgs(related_vars); | ||
| 175 | + ternary_ops[res] = TernaryOp(res, std::move(equal_case), related_vars); | ||
| 176 | + ternary_ops[res].SetVariable(res); | ||
| 177 | + ternary_ops[res].SetDescription("vf_dynamic_perf"); | ||
| 138 | return af::SUCCESS; | 178 | return af::SUCCESS; |
| 139 | } | 179 | } |
| 140 | } // namespace att | 180 | } // namespace att |
| @@ -12,7 +12,9 @@ | |||
| 12 | #define AUTOFUSE_VF_PERF_UTILS_H | 12 | #define AUTOFUSE_VF_PERF_UTILS_H |
| 13 | 13 | ||
| 14 | #include "base/att_const_values.h" | 14 | #include "base/att_const_values.h" |
| 15 | +#include "ascir_node_param/ascir_node_param.h" | ||
| 15 | #include "gen_model_info/api_perf_register/perf_param.h" | 16 | #include "gen_model_info/api_perf_register/perf_param.h" |
| 17 | +#include "util/ternary_op.h" | ||
| 16 | namespace att { | 18 | namespace att { |
| 17 | class VfPerfUtils { | 19 | class VfPerfUtils { |
| 18 | public: | 20 | public: |
| @@ -26,7 +28,9 @@ class VfPerfUtils { | |||
| 26 | // 获取vf头开销 | 28 | // 获取vf头开销 |
| 27 | static Expr GetVFHeadCost(); | 29 | static Expr GetVFHeadCost(); |
| 28 | // 根据vf function子图解析的结果获取vf function的性能 | 30 | // 根据vf function子图解析的结果获取vf function的性能 |
| 29 | - static af::Status GetVectorFunctionPerf(const std::vector<NodePerfInfo> &node_perf_infos, Expr &res); | 31 | + static af::Status GetVectorFunctionPerf(const std::vector<NodePerfInfo> &node_perf_infos, |
| 32 | + const ascir_param::VectorFuncNodeParams &vector_func_params, | ||
| 33 | + std::map<Expr, TernaryOp, ExprCmp> &ternary_ops, Expr &res); | ||
| 30 | }; | 34 | }; |
| 31 | } // namespace att | 35 | } // namespace att |
| 32 | 36 | ||
| @@ -587,7 +587,7 @@ af::Status PipePerfExpr::GetPerfExpr(std::map<PipeType, Expr> &pipe_costs, | |||
| 587 | // 获取节点性能(内部方法,包含VectorFunc特殊处理) | 587 | // 获取节点性能(内部方法,包含VectorFunc特殊处理) |
| 588 | af::Status PipePerfExpr::GetNodePerfInternal(const NodeInfo &node, std::map<PipeType, Expr> &node_perf, | 588 | af::Status PipePerfExpr::GetNodePerfInternal(const NodeInfo &node, std::map<PipeType, Expr> &node_perf, |
| 589 | std::map<Expr, TernaryOp, ExprCmp> &ternary_ops, | 589 | std::map<Expr, TernaryOp, ExprCmp> &ternary_ops, |
| 590 | - std::vector<PerfBreakdownGroup> &perf_breakdowns) const { | 590 | + std::vector<PerfBreakdownGroup> &perf_breakdowns, bool tail_shape) const { |
| 591 | if (node.node_type == kVectorFunc) { | 591 | if (node.node_type == kVectorFunc) { |
| 592 | // VectorFunc节点特殊处理 | 592 | // VectorFunc节点特殊处理 |
| 593 | std::vector<NodePerfInfo> node_perf_infos; | 593 | std::vector<NodePerfInfo> node_perf_infos; |
| @@ -597,7 +597,7 @@ af::Status PipePerfExpr::GetNodePerfInternal(const NodeInfo &node, std::map<Pipe | |||
| 597 | GE_ASSERT_SUCCESS(ConvertToPerfInfo(node.sub_nodes_infos, node_perf_infos, vector_func_dims), | 597 | GE_ASSERT_SUCCESS(ConvertToPerfInfo(node.sub_nodes_infos, node_perf_infos, vector_func_dims), |
| 598 | "Convert to perf info failed, node = %s %s", node.name.c_str(), node.node_type.c_str()); | 598 | "Convert to perf info failed, node = %s %s", node.name.c_str(), node.node_type.c_str()); |
| 599 | Expr res; | 599 | Expr res; |
| 600 | - GE_ASSERT_SUCCESS(VfPerfUtils::GetVectorFunctionPerf(node_perf_infos, res), | 600 | + GE_ASSERT_SUCCESS(VfPerfUtils::GetVectorFunctionPerf(node_perf_infos, node.vector_func_params, ternary_ops, res), |
| 601 | "Get vector function perf failed, node = %s %s.", node.name.c_str(), node.node_type.c_str()); | 601 | "Get vector function perf failed, node = %s %s.", node.name.c_str(), node.node_type.c_str()); |
| 602 | 602 | ||
| 603 | // 为VectorFunc节点创建ternary_ops条目 | 603 | // 为VectorFunc节点创建ternary_ops条目 |
| @@ -620,8 +620,8 @@ af::Status PipePerfExpr::GetNodePerfInternal(const NodeInfo &node, std::map<Pipe | |||
| 620 | } | 620 | } |
| 621 | } else { | 621 | } else { |
| 622 | // 普通节点 | 622 | // 普通节点 |
| 623 | - GE_ASSERT_SUCCESS(GetNodePerf(node, node_perf, ternary_ops, perf_breakdowns), "Get node [%s][%s] perf failed.", | 623 | + GE_ASSERT_SUCCESS(GetNodePerf(node, node_perf, ternary_ops, perf_breakdowns, tail_shape), |
| 624 | - node.name.c_str(), node.node_type.c_str()); | 624 | + "Get node [%s][%s] perf failed.", node.name.c_str(), node.node_type.c_str()); |
| 625 | } | 625 | } |
| 626 | return af::SUCCESS; | 626 | return af::SUCCESS; |
| 627 | } | 627 | } |
| @@ -639,7 +639,7 @@ af::Status PipePerfExpr::AddNodePerfToPipeCost(const NodeInfo &node, const Expr | |||
| 639 | GELOGD("Node with single cut, add tail perf."); | 639 | GELOGD("Node with single cut, add tail perf."); |
| 640 | Expr tail_exe_time; | 640 | Expr tail_exe_time; |
| 641 | std::map<PipeType, Expr> node_tail_perf; | 641 | std::map<PipeType, Expr> node_tail_perf; |
| 642 | - GE_ASSERT_SUCCESS(GetNodePerf(node, node_tail_perf, ternary_ops, perf_breakdowns, true), | 642 | + GE_ASSERT_SUCCESS(GetNodePerfInternal(node, node_tail_perf, ternary_ops, perf_breakdowns, true), |
| 643 | "Get node [%s] tail perf failed.", node.name.c_str()); | 643 | "Get node [%s] tail perf failed.", node.name.c_str()); |
| 644 | GE_ASSERT_SUCCESS(GetTailExeTime(node, exe_var, tail_exe_time)); | 644 | GE_ASSERT_SUCCESS(GetTailExeTime(node, exe_var, tail_exe_time)); |
| 645 | GE_ASSERT_SUCCESS(AddTailPerf(tail_exe_time, exe_var, node_tail_perf, ctx)); | 645 | GE_ASSERT_SUCCESS(AddTailPerf(tail_exe_time, exe_var, node_tail_perf, ctx)); |
| @@ -74,7 +74,7 @@ class PipePerfExpr { | |||
| 74 | // 获取节点性能(内部方法,包含VectorFunc特殊处理) | 74 | // 获取节点性能(内部方法,包含VectorFunc特殊处理) |
| 75 | af::Status GetNodePerfInternal(const NodeInfo &node, std::map<PipeType, Expr> &node_perf, | 75 | af::Status GetNodePerfInternal(const NodeInfo &node, std::map<PipeType, Expr> &node_perf, |
| 76 | std::map<Expr, TernaryOp, ExprCmp> &ternary_ops, | 76 | std::map<Expr, TernaryOp, ExprCmp> &ternary_ops, |
| 77 | - std::vector<PerfBreakdownGroup> &perf_breakdowns) const; | 77 | + std::vector<PerfBreakdownGroup> &perf_breakdowns, bool tail_shape = false) const; |
| 78 | // 添加节点性能到pipe_costs | 78 | // 添加节点性能到pipe_costs |
| 79 | af::Status AddNodePerfToPipeCost(const NodeInfo &node, const Expr &exe_var, const std::map<PipeType, Expr> &node_perf, | 79 | af::Status AddNodePerfToPipeCost(const NodeInfo &node, const Expr &exe_var, const std::map<PipeType, Expr> &node_perf, |
| 80 | std::map<PipeType, Expr> &pipe_costs, | 80 | std::map<PipeType, Expr> &pipe_costs, |
| @@ -21,9 +21,10 @@ | |||
| 21 | #include "util/thread_local_context.h" | 21 | #include "util/thread_local_context.h" |
| 22 | #include "att_utils.h" | 22 | #include "att_utils.h" |
| 23 | #include "ascendc_ir/ascendc_ir_core/ascendc_ir.h" | 23 | #include "ascendc_ir/ascendc_ir_core/ascendc_ir.h" |
| 24 | +#include "ascir_node_param/ascir_node_param.h" | ||
| 24 | #include "base_types_printer.h" | 25 | #include "base_types_printer.h" |
| 25 | #include "common_utils.h" | 26 | #include "common_utils.h" |
| 26 | -#include "reduce_specific_params_builder.h" | 27 | +#include "specific_params_builder.h" |
| 27 | #include "vector_function_graph_parser.h" | 28 | #include "vector_function_graph_parser.h" |
| 28 | 29 | ||
| 29 | namespace att { | 30 | namespace att { |
| @@ -770,7 +771,7 @@ af::Status AscendGraphParser::ConvertNodeInfos(const af::AscNodePtr &ge_node, co | |||
| 770 | } | 771 | } |
| 771 | } | 772 | } |
| 772 | node_info.node_ptr = ge_node; | 773 | node_info.node_ptr = ge_node; |
| 773 | - GE_ASSERT_SUCCESS(FillReduceSpecificParams(ge_node, node_info)); | 774 | + GE_ASSERT_SUCCESS(FillSpecificParams(ge_node, node_info)); |
| 774 | auto vectorized_axis_ids = GetNodeVectorizedAxis(ge_node, loop_axis); | 775 | auto vectorized_axis_ids = GetNodeVectorizedAxis(ge_node, loop_axis); |
| 775 | for (const auto &axis_info : vectorized_axis_ids) { | 776 | for (const auto &axis_info : vectorized_axis_ids) { |
| 776 | auto sub_axis_iter = sub_axes_info_.find(axis_info); | 777 | auto sub_axis_iter = sub_axes_info_.find(axis_info); |
Rautofuse/att/gen_model_info/parser/reduce_specific_params_builder.cpp→autofuse/att/gen_model_info/parser/specific_params_builder.cpp+26-5
| @@ -8,13 +8,31 @@ | |||
| 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 "reduce_specific_params_builder.h" | 11 | +#include "specific_params_builder.h" |
| 12 | 12 | ||
| 13 | #include "ascir_node_param/ascir_node_param.h" | 13 | #include "ascir_node_param/ascir_node_param.h" |
| 14 | +#include "ascir_node_param/ascir_param_builder.h" | ||
| 15 | +#include "base/att_const_values.h" | ||
| 14 | #include "common/checker.h" | 16 | #include "common/checker.h" |
| 15 | 17 | ||
| 16 | namespace att { | 18 | namespace att { |
| 17 | -af::Status FillReduceSpecificParams(const af::AscNodePtr &ge_node, NodeInfo &node_info) { | 19 | +namespace { |
| 20 | +af::Status FillReduceParams(const ascir_param::AscirNodeParams ¶ms, NodeInfo &node_info) { | ||
| 21 | + const auto *reduce = ascir_param::GetSpecificParams<ascir_param::ReduceNodeParams>(params); | ||
| 22 | + GE_ASSERT_NOTNULL(reduce, "Reduce specific params is null, node[%s].", node_info.name.c_str()); | ||
| 23 | + node_info.reduce_specific_params = *reduce; | ||
| 24 | + return af::SUCCESS; | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +af::Status FillVectorFuncParams(const ascir_param::AscirNodeParams ¶ms, NodeInfo &node_info) { | ||
| 28 | + const auto *vector_func_params = ascir_param::GetSpecificParams<ascir_param::VectorFuncNodeParams>(params); | ||
| 29 | + GE_ASSERT_NOTNULL(vector_func_params, "VectorFunc specific params is null, node[%s].", node_info.name.c_str()); | ||
| 30 | + node_info.vector_func_params = *vector_func_params; | ||
| 31 | + return af::SUCCESS; | ||
| 32 | +} | ||
| 33 | +} // namespace | ||
| 34 | + | ||
| 35 | +af::Status FillSpecificParams(const af::AscNodePtr &ge_node, NodeInfo &node_info) { | ||
| 18 | const auto params = ascir_param::GetAscirNodeParams(ge_node); | 36 | const auto params = ascir_param::GetAscirNodeParams(ge_node); |
| 19 | if (params == nullptr) { | 37 | if (params == nullptr) { |
| 20 | return af::SUCCESS; | 38 | return af::SUCCESS; |
| @@ -24,9 +42,12 @@ af::Status FillReduceSpecificParams(const af::AscNodePtr &ge_node, NodeInfo &nod | |||
| 24 | } | 42 | } |
| 25 | GE_ASSERT_TRUE(params->status == ascir_param::ParamBuildStatus::kBuilt, "Build ascir node params failed, node[%s].", | 43 | GE_ASSERT_TRUE(params->status == ascir_param::ParamBuildStatus::kBuilt, "Build ascir node params failed, node[%s].", |
| 26 | node_info.name.c_str()); | 44 | node_info.name.c_str()); |
| 27 | - const auto *reduce = ascir_param::GetSpecificParams<ascir_param::ReduceNodeParams>(*params); | 45 | + if (ascir_param::IsReduceParamSupported(node_info.node_type)) { |
| 28 | - GE_ASSERT_NOTNULL(reduce, "Reduce specific params is null, node[%s].", node_info.name.c_str()); | 46 | + return FillReduceParams(*params, node_info); |
| 29 | - node_info.reduce_specific_params = *reduce; | 47 | + } |
| 48 | + if (node_info.node_type == kVectorFunc) { | ||
| 49 | + return FillVectorFuncParams(*params, node_info); | ||
| 50 | + } | ||
| 30 | return af::SUCCESS; | 51 | return af::SUCCESS; |
| 31 | } | 52 | } |
| 32 | } // namespace att | 53 | } // namespace att |
Rautofuse/att/gen_model_info/parser/reduce_specific_params_builder.h→autofuse/att/gen_model_info/parser/specific_params_builder.h+4-4
| @@ -8,13 +8,13 @@ | |||
| 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 | -#ifndef PARSER_REDUCE_SPECIFIC_PARAMS_BUILDER_H_ | 11 | +#ifndef PARSER_SPECIFIC_PARAMS_BUILDER_H_ |
| 12 | -#define PARSER_REDUCE_SPECIFIC_PARAMS_BUILDER_H_ | 12 | +#define PARSER_SPECIFIC_PARAMS_BUILDER_H_ |
| 13 | 13 | ||
| 14 | #include "tuning_space.h" | 14 | #include "tuning_space.h" |
| 15 | 15 | ||
| 16 | namespace att { | 16 | namespace att { |
| 17 | -af::Status FillReduceSpecificParams(const af::AscNodePtr &ge_node, NodeInfo &node_info); | 17 | +af::Status FillSpecificParams(const af::AscNodePtr &ge_node, NodeInfo &node_info); |
| 18 | } // namespace att | 18 | } // namespace att |
| 19 | 19 | ||
| 20 | -#endif // PARSER_REDUCE_SPECIFIC_PARAMS_BUILDER_H_ | 20 | +#endif // PARSER_SPECIFIC_PARAMS_BUILDER_H_ |
| @@ -181,6 +181,7 @@ struct NodeInfo { | |||
| 181 | af::AscNodePtr node_ptr; | 181 | af::AscNodePtr node_ptr; |
| 182 | std::set<std::string> from_data; // 隶属的Data节点名称 | 182 | std::set<std::string> from_data; // 隶属的Data节点名称 |
| 183 | std::vector<NodeInfo> sub_nodes_infos; | 183 | std::vector<NodeInfo> sub_nodes_infos; |
| 184 | + ascir_param::VectorFuncNodeParams vector_func_params; | ||
| 184 | ascir_param::ReduceNodeParams reduce_specific_params; | 185 | ascir_param::ReduceNodeParams reduce_specific_params; |
| 185 | af::ExecuteCondition exec_condition{af::ExecuteCondition::kNoCache}; | 186 | af::ExecuteCondition exec_condition{af::ExecuteCondition::kNoCache}; |
| 186 | std::string DebugString() const { | 187 | std::string DebugString() const { |
| @@ -68,7 +68,13 @@ struct ReduceNodeParams { | |||
| 68 | ReduceParamExprs exprs; | 68 | ReduceParamExprs exprs; |
| 69 | }; | 69 | }; |
| 70 | 70 | ||
| 71 | -using AnySpecificParams = std::variant<std::monostate, ReduceNodeParams>; | 71 | +struct VectorFuncNodeParams { |
| 72 | + bool is_double_loop{false}; | ||
| 73 | + std::vector<ge::Expression> all_strides; | ||
| 74 | + std::vector<ge::Expression> output_dims; | ||
| 75 | +}; | ||
| 76 | + | ||
| 77 | +using AnySpecificParams = std::variant<std::monostate, ReduceNodeParams, VectorFuncNodeParams>; | ||
| 72 | 78 | ||
| 73 | struct AscirNodeParams { | 79 | struct AscirNodeParams { |
| 74 | // 扩展属性载荷版本,用于后续兼容。 | 80 | // 扩展属性载荷版本,用于后续兼容。 |
| @@ -23,6 +23,7 @@ | |||
| 23 | namespace ascir_param { | 23 | namespace ascir_param { |
| 24 | namespace { | 24 | namespace { |
| 25 | constexpr const char *kAscirNodeParams = "AscirNodeParams"; | 25 | constexpr const char *kAscirNodeParams = "AscirNodeParams"; |
| 26 | +constexpr const char *kVectorFunc = "VectorFunc"; | ||
| 26 | 27 | ||
| 27 | struct AscirParamSourceContext { | 28 | struct AscirParamSourceContext { |
| 28 | af::AscNodePtr node; | 29 | af::AscNodePtr node; |
| @@ -84,8 +85,9 @@ af::Status RegisterAscirNodeParams(const af::AscNodePtr &node, const AscirNodePa | |||
| 84 | graph_name.c_str(), static_cast<void *>(node.get()), static_cast<void *>(op_desc.get()), | 85 | graph_name.c_str(), static_cast<void *>(node.get()), static_cast<void *>(op_desc.get()), |
| 85 | static_cast<void *>(owner_graph.get())); | 86 | static_cast<void *>(owner_graph.get())); |
| 86 | } | 87 | } |
| 88 | + const std::string graph_name = owner_graph == nullptr ? std::string("<null>") : owner_graph->GetName(); | ||
| 87 | GE_ASSERT_TRUE(op_desc->SetExtAttr(kAscirNodeParams, params), "Graph:%s, Node:%s SetExtAttr failed", | 89 | GE_ASSERT_TRUE(op_desc->SetExtAttr(kAscirNodeParams, params), "Graph:%s, Node:%s SetExtAttr failed", |
| 88 | - node->GetOwnerComputeGraph()->GetName().c_str(), node->GetNamePtr()); | 90 | + graph_name.c_str(), node->GetNamePtr()); |
| 89 | return af::SUCCESS; | 91 | return af::SUCCESS; |
| 90 | } | 92 | } |
| 91 | 93 | ||
| @@ -97,6 +99,15 @@ af::Status RegisterSkippedAscirNodeParams(const af::AscNodePtr &node) { | |||
| 97 | return RegisterAscirNodeParams(node, params); | 99 | return RegisterAscirNodeParams(node, params); |
| 98 | } | 100 | } |
| 99 | 101 | ||
| 102 | +af::Status RegisterVectorFuncAscirNodeParams(const af::AscNodePtr &node) { | ||
| 103 | + GE_ASSERT_NOTNULL(node); | ||
| 104 | + auto params = std::make_shared<AscirNodeParams>(); | ||
| 105 | + params->api_name = node->GetType(); | ||
| 106 | + params->status = ParamBuildStatus::kBuilt; | ||
| 107 | + params->specific_params = VectorFuncNodeParams{}; | ||
| 108 | + return RegisterAscirNodeParams(node, params); | ||
| 109 | +} | ||
| 110 | + | ||
| 100 | std::map<int64_t, af::AxisPtr> BuildAxisMap(const af::AscGraph &graph) { | 111 | std::map<int64_t, af::AxisPtr> BuildAxisMap(const af::AscGraph &graph) { |
| 101 | std::map<int64_t, af::AxisPtr> axis_map; | 112 | std::map<int64_t, af::AxisPtr> axis_map; |
| 102 | for (const auto &axis : graph.GetAllAxis()) { | 113 | for (const auto &axis : graph.GetAllAxis()) { |
| @@ -414,13 +425,6 @@ af::Status FillReduceReuseSource(const af::AscNodePtr &node, codegen::ReduceReus | |||
| 414 | return af::SUCCESS; | 425 | return af::SUCCESS; |
| 415 | } | 426 | } |
| 416 | 427 | ||
| 417 | -bool IsReduceParamSupported(const std::string &api_name) { | ||
| 418 | - static const std::set<std::string> kReduceTypes = {"Max", "Min", "Mean", "Prod", "Sum", | ||
| 419 | - "Any", "All", "ReduceMax", "ReduceMean", "ReduceMin", | ||
| 420 | - "ReduceProd", "ReduceSum", "ReduceAny", "ReduceAll"}; | ||
| 421 | - return kReduceTypes.count(api_name) != 0U; | ||
| 422 | -} | ||
| 423 | - | ||
| 424 | af::Status BuildReduceInput(const AscirParamBuildContext &ctx, codegen::ReduceSpecificParamBuildInput &input) { | 428 | af::Status BuildReduceInput(const AscirParamBuildContext &ctx, codegen::ReduceSpecificParamBuildInput &input) { |
| 425 | GE_ASSERT_TRUE(!ctx.inputs.empty(), "Reduce input tensor is empty, node[%s].", ctx.api_name.c_str()); | 429 | GE_ASSERT_TRUE(!ctx.inputs.empty(), "Reduce input tensor is empty, node[%s].", ctx.api_name.c_str()); |
| 426 | GE_ASSERT_TRUE(!ctx.outputs.empty(), "Reduce output tensor is empty, node[%s].", ctx.api_name.c_str()); | 430 | GE_ASSERT_TRUE(!ctx.outputs.empty(), "Reduce output tensor is empty, node[%s].", ctx.api_name.c_str()); |
| @@ -497,6 +501,9 @@ af::Status BuildAndRegisterAscirNodeParams(const AscirParamBuildContext &ctx) { | |||
| 497 | 501 | ||
| 498 | af::Status EnrichAscirNodeParams(const AscirParamSourceContext &source) { | 502 | af::Status EnrichAscirNodeParams(const AscirParamSourceContext &source) { |
| 499 | GE_ASSERT_NOTNULL(source.node); | 503 | GE_ASSERT_NOTNULL(source.node); |
| 504 | + if (source.node->GetType() == kVectorFunc) { | ||
| 505 | + return RegisterVectorFuncAscirNodeParams(source.node); | ||
| 506 | + } | ||
| 500 | if (!IsReduceParamSupported(source.node->GetType())) { | 507 | if (!IsReduceParamSupported(source.node->GetType())) { |
| 501 | return RegisterSkippedAscirNodeParams(source.node); | 508 | return RegisterSkippedAscirNodeParams(source.node); |
| 502 | } | 509 | } |
| @@ -506,6 +513,13 @@ af::Status EnrichAscirNodeParams(const AscirParamSourceContext &source) { | |||
| 506 | } | 513 | } |
| 507 | } // namespace | 514 | } // namespace |
| 508 | 515 | ||
| 516 | +bool IsReduceParamSupported(const std::string &api_name) { | ||
| 517 | + static const std::set<std::string> kReduceTypes = {"Max", "Min", "Mean", "Prod", "Sum", | ||
| 518 | + "Any", "All", "ReduceMax", "ReduceMean", "ReduceMin", | ||
| 519 | + "ReduceProd", "ReduceSum", "ReduceAny", "ReduceAll"}; | ||
| 520 | + return kReduceTypes.count(api_name) != 0U; | ||
| 521 | +} | ||
| 522 | + | ||
| 509 | af::Status EnrichAscirGraphNodeParams(const af::AscGraph &graph) { | 523 | af::Status EnrichAscirGraphNodeParams(const af::AscGraph &graph) { |
| 510 | for (const auto &node : graph.GetAllNodes()) { | 524 | for (const auto &node : graph.GetAllNodes()) { |
| 511 | GE_ASSERT_SUCCESS(EnrichAscirNodeParams({node, &graph})); | 525 | GE_ASSERT_SUCCESS(EnrichAscirNodeParams({node, &graph})); |
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "ascir_node_param/ascir_node_param.h" | 14 | #include "ascir_node_param/ascir_node_param.h" |
| 15 | 15 | ||
| 16 | namespace ascir_param { | 16 | namespace ascir_param { |
| 17 | +bool IsReduceParamSupported(const std::string &api_name); | ||
| 17 | af::Status EnrichAscirGraphNodeParams(const af::AscGraph &graph); | 18 | af::Status EnrichAscirGraphNodeParams(const af::AscGraph &graph); |
| 18 | } // namespace ascir_param | 19 | } // namespace ascir_param |
| 19 | 20 | ||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <iostream> | 12 | #include <iostream> |
| 13 | #include "gtest/gtest.h" | 13 | #include "gtest/gtest.h" |
| 14 | #include "base/att_const_values.h" | 14 | #include "base/att_const_values.h" |
| 15 | +#include "gen_model_info/api_perf_register/utils/vf_perf_utils.h" | ||
| 15 | #include "gen_model_info.h" | 16 | #include "gen_model_info.h" |
| 16 | #include "test_fa_ascir_graph.h" | 17 | #include "test_fa_ascir_graph.h" |
| 17 | #include "parser/ascend_graph_parser.h" | 18 | #include "parser/ascend_graph_parser.h" |
| @@ -19,6 +20,7 @@ | |||
| 19 | #include "expr_gen/pipe_perf_expr.h" | 20 | #include "expr_gen/pipe_perf_expr.h" |
| 20 | #undef private | 21 | #undef private |
| 21 | #include "ascir_ops.h" | 22 | #include "ascir_ops.h" |
| 23 | +#include "ascir_node_param/ascir_param_builder.h" | ||
| 22 | #include "expr_gen/arg_list_manager.h" | 24 | #include "expr_gen/arg_list_manager.h" |
| 23 | #include "ascendc_ir/ascendc_ir_core/ascendc_ir.h" | 25 | #include "ascendc_ir/ascendc_ir_core/ascendc_ir.h" |
| 24 | #include "graph_construct_utils.h" | 26 | #include "graph_construct_utils.h" |
| @@ -176,6 +178,34 @@ NodeInfo CreateSubNodeInfo(const std::string &name, const std::string &type, con | |||
| 176 | return node_info; | 178 | return node_info; |
| 177 | } | 179 | } |
| 178 | 180 | ||
| 181 | +void SetAscirNodeParamsForTest(const af::AscNodePtr &node, const ascir_param::AscirNodeParamsPtr ¶ms) { | ||
| 182 | + ASSERT_NE(node, nullptr); | ||
| 183 | + ASSERT_NE(params, nullptr); | ||
| 184 | + auto op_desc = node->GetOpDesc(); | ||
| 185 | + ASSERT_NE(op_desc, nullptr); | ||
| 186 | + ASSERT_TRUE(op_desc->SetExtAttr("AscirNodeParams", params)); | ||
| 187 | +} | ||
| 188 | + | ||
| 189 | +NodePerfInfo CreateVectorFuncNodePerfInfo() { | ||
| 190 | + NodePerfInfo node_perf_info; | ||
| 191 | + node_perf_info.optype = kAbs; | ||
| 192 | + node_perf_info.input_dtype = kFloat32; | ||
| 193 | + node_perf_info.output_dtype = kFloat32; | ||
| 194 | + node_perf_info.dims = {CreateExpr("vf_dim")}; | ||
| 195 | + return node_perf_info; | ||
| 196 | +} | ||
| 197 | + | ||
| 198 | +void ExpectValidPerfWithoutDynamicTernary(const ascir_param::VectorFuncNodeParams &vector_func_params) { | ||
| 199 | + std::vector<NodePerfInfo> node_perf_infos = {CreateVectorFuncNodePerfInfo()}; | ||
| 200 | + std::map<Expr, TernaryOp, ExprCmp> ternary_ops; | ||
| 201 | + Expr perf; | ||
| 202 | + | ||
| 203 | + ASSERT_EQ(VfPerfUtils::GetVectorFunctionPerf(node_perf_infos, vector_func_params, ternary_ops, perf), af::SUCCESS); | ||
| 204 | + | ||
| 205 | + EXPECT_TRUE(perf.IsValid()); | ||
| 206 | + EXPECT_TRUE(ternary_ops.empty()); | ||
| 207 | +} | ||
| 208 | + | ||
| 179 | // 辅助函数:验证 contrib 变量 | 209 | // 辅助函数:验证 contrib 变量 |
| 180 | void VerifyContribVar(const std::map<Expr, TernaryOp, ExprCmp> &exe_times) { | 210 | void VerifyContribVar(const std::map<Expr, TernaryOp, ExprCmp> &exe_times) { |
| 181 | bool found_aiv_vec_contrib = false; | 211 | bool found_aiv_vec_contrib = false; |
| @@ -293,6 +323,136 @@ TEST_F(TestPipePerfExpr, ConvertToPerfInfoUsesParentGraphDims) { | |||
| 293 | EXPECT_EQ(Str(node_perf_infos[0].dims[0]), "z0bt_size"); | 323 | EXPECT_EQ(Str(node_perf_infos[0].dims[0]), "z0bt_size"); |
| 294 | } | 324 | } |
| 295 | 325 | ||
| 326 | +TEST_F(TestPipePerfExpr, VectorFuncPerfUsesDefaultParamsWhenNoCodegenParams) { | ||
| 327 | + ascir_param::VectorFuncNodeParams vector_func_params; | ||
| 328 | + | ||
| 329 | + ExpectValidPerfWithoutDynamicTernary(vector_func_params); | ||
| 330 | +} | ||
| 331 | + | ||
| 332 | +TEST_F(TestPipePerfExpr, VectorFuncPerfUsesUnequalFormulaWhenDoubleLoopHasNoStride) { | ||
| 333 | + ascir_param::VectorFuncNodeParams vector_func_params; | ||
| 334 | + vector_func_params.is_double_loop = true; | ||
| 335 | + vector_func_params.output_dims = {CreateExpr("outer_dim"), CreateExpr("inner_dim")}; | ||
| 336 | + | ||
| 337 | + ExpectValidPerfWithoutDynamicTernary(vector_func_params); | ||
| 338 | +} | ||
| 339 | + | ||
| 340 | +TEST_F(TestPipePerfExpr, VectorFuncPerfUsesEqualFormulaWhenDoubleLoopHasSingleStride) { | ||
| 341 | + ascir_param::VectorFuncNodeParams vector_func_params; | ||
| 342 | + vector_func_params.is_double_loop = true; | ||
| 343 | + vector_func_params.all_strides = {CreateExpr("only_stride")}; | ||
| 344 | + vector_func_params.output_dims = {CreateExpr("outer_dim"), CreateExpr("inner_dim")}; | ||
| 345 | + | ||
| 346 | + ExpectValidPerfWithoutDynamicTernary(vector_func_params); | ||
| 347 | +} | ||
| 348 | + | ||
| 349 | +TEST_F(TestPipePerfExpr, VectorFuncPerfCreatesDynamicStrideTernaryOp) { | ||
| 350 | + std::vector<NodePerfInfo> node_perf_infos = {CreateVectorFuncNodePerfInfo()}; | ||
| 351 | + ascir_param::VectorFuncNodeParams vector_func_params; | ||
| 352 | + vector_func_params.is_double_loop = true; | ||
| 353 | + vector_func_params.all_strides = {CreateExpr("input_stride"), CreateExpr("output_stride")}; | ||
| 354 | + vector_func_params.output_dims = {CreateExpr("outer_dim"), CreateExpr("inner_dim")}; | ||
| 355 | + std::map<Expr, TernaryOp, ExprCmp> ternary_ops; | ||
| 356 | + Expr perf; | ||
| 357 | + | ||
| 358 | + ASSERT_EQ(VfPerfUtils::GetVectorFunctionPerf(node_perf_infos, vector_func_params, ternary_ops, perf), af::SUCCESS); | ||
| 359 | + | ||
| 360 | + EXPECT_EQ(Str(perf), "vf_dynamic_perf"); | ||
| 361 | + auto iter = ternary_ops.find(perf); | ||
| 362 | + ASSERT_NE(iter, ternary_ops.end()); | ||
| 363 | + EXPECT_EQ(iter->second.GetDescription(), "vf_dynamic_perf"); | ||
| 364 | + const std::string ternary_expr = iter->second.GetTernaryOpStr(); | ||
| 365 | + EXPECT_NE(ternary_expr.find("input_stride"), std::string::npos); | ||
| 366 | + EXPECT_NE(ternary_expr.find("output_stride"), std::string::npos); | ||
| 367 | +} | ||
| 368 | + | ||
| 369 | +TEST_F(TestPipePerfExpr, ParserCopiesVectorFuncNodeParamsFromAscirNodeParams) { | ||
| 370 | + af::AscGraph graph("vf_graph"); | ||
| 371 | + ASSERT_EQ(af::ascir::cg::BuildVectorFuncTestGraph(graph), af::SUCCESS); | ||
| 372 | + auto vf_node = graph.FindNode("vector_func"); | ||
| 373 | + ASSERT_NE(vf_node, nullptr); | ||
| 374 | + auto params = std::make_shared<ascir_param::AscirNodeParams>(); | ||
| 375 | + ascir_param::VectorFuncNodeParams expected_params; | ||
| 376 | + expected_params.is_double_loop = true; | ||
| 377 | + expected_params.all_strides = {CreateExpr("input_stride"), CreateExpr("output_stride")}; | ||
| 378 | + expected_params.output_dims = {CreateExpr("outer_dim"), CreateExpr("inner_dim")}; | ||
| 379 | + params->api_name = kVectorFunc; | ||
| 380 | + params->status = ascir_param::ParamBuildStatus::kBuilt; | ||
| 381 | + params->specific_params = expected_params; | ||
| 382 | + SetAscirNodeParamsForTest(vf_node, params); | ||
| 383 | + | ||
| 384 | + TuningSpacePtr ts = std::make_shared<TuningSpace>(); | ||
| 385 | + ASSERT_NE(ts, nullptr); | ||
| 386 | + att::AscendGraphParser ascend_graph_parser(ts); | ||
| 387 | + ASSERT_EQ(ascend_graph_parser.GraphParser(graph), af::SUCCESS); | ||
| 388 | + | ||
| 389 | + const auto vector_func_iter = std::find_if(ts->node_infos.begin(), ts->node_infos.end(), | ||
| 390 | + [](const NodeInfo &node) { return node.node_type == kVectorFunc; }); | ||
| 391 | + ASSERT_NE(vector_func_iter, ts->node_infos.end()); | ||
| 392 | + EXPECT_TRUE(vector_func_iter->vector_func_params.is_double_loop); | ||
| 393 | + ASSERT_EQ(vector_func_iter->vector_func_params.all_strides.size(), 2U); | ||
| 394 | + EXPECT_EQ(Str(vector_func_iter->vector_func_params.all_strides[0]), "input_stride"); | ||
| 395 | + ASSERT_EQ(vector_func_iter->vector_func_params.output_dims.size(), 2U); | ||
| 396 | + EXPECT_EQ(Str(vector_func_iter->vector_func_params.output_dims[1]), "inner_dim"); | ||
| 397 | +} | ||
| 398 | + | ||
| 399 | +TEST_F(TestPipePerfExpr, ParserKeepsDefaultVectorFuncNodeParamsWhenAscirNodeParamsMissing) { | ||
| 400 | + af::AscGraph graph("vf_graph"); | ||
| 401 | + ASSERT_EQ(af::ascir::cg::BuildVectorFuncTestGraph(graph), af::SUCCESS); | ||
| 402 | + | ||
| 403 | + TuningSpacePtr ts = std::make_shared<TuningSpace>(); | ||
| 404 | + ASSERT_NE(ts, nullptr); | ||
| 405 | + att::AscendGraphParser ascend_graph_parser(ts); | ||
| 406 | + ASSERT_EQ(ascend_graph_parser.GraphParser(graph), af::SUCCESS); | ||
| 407 | + | ||
| 408 | + const auto vector_func_iter = std::find_if(ts->node_infos.begin(), ts->node_infos.end(), | ||
| 409 | + [](const NodeInfo &node) { return node.node_type == kVectorFunc; }); | ||
| 410 | + ASSERT_NE(vector_func_iter, ts->node_infos.end()); | ||
| 411 | + EXPECT_FALSE(vector_func_iter->vector_func_params.is_double_loop); | ||
| 412 | + EXPECT_TRUE(vector_func_iter->vector_func_params.all_strides.empty()); | ||
| 413 | + EXPECT_TRUE(vector_func_iter->vector_func_params.output_dims.empty()); | ||
| 414 | +} | ||
| 415 | + | ||
| 416 | +TEST_F(TestPipePerfExpr, VectorFuncTailPerfUsesVectorFuncInternalPath) { | ||
| 417 | + af::AscGraph graph("vf_graph"); | ||
| 418 | + ASSERT_EQ(af::ascir::cg::BuildVectorFuncTestGraph(graph), af::SUCCESS); | ||
| 419 | + auto vf_node = graph.FindNode("vector_func"); | ||
| 420 | + ASSERT_NE(vf_node, nullptr); | ||
| 421 | + auto params = std::make_shared<ascir_param::AscirNodeParams>(); | ||
| 422 | + ascir_param::VectorFuncNodeParams vector_func_params; | ||
| 423 | + vector_func_params.is_double_loop = true; | ||
| 424 | + vector_func_params.all_strides = {CreateExpr(1)}; | ||
| 425 | + vector_func_params.output_dims = {CreateExpr(1), CreateExpr(64)}; | ||
| 426 | + params->api_name = kVectorFunc; | ||
| 427 | + params->status = ascir_param::ParamBuildStatus::kBuilt; | ||
| 428 | + params->specific_params = vector_func_params; | ||
| 429 | + SetAscirNodeParamsForTest(vf_node, params); | ||
| 430 | + | ||
| 431 | + TuningSpacePtr ts = std::make_shared<TuningSpace>(); | ||
| 432 | + ASSERT_NE(ts, nullptr); | ||
| 433 | + att::AscendGraphParser ascend_graph_parser(ts); | ||
| 434 | + ASSERT_EQ(ascend_graph_parser.GraphParser(graph), af::SUCCESS); | ||
| 435 | + const auto vector_func_iter = std::find_if(ts->node_infos.begin(), ts->node_infos.end(), | ||
| 436 | + [](const NodeInfo &node) { return node.node_type == kVectorFunc; }); | ||
| 437 | + ASSERT_NE(vector_func_iter, ts->node_infos.end()); | ||
| 438 | + | ||
| 439 | + PipePerfExpr pipe_perf(ts); | ||
| 440 | + std::map<PipeType, Expr> node_perf; | ||
| 441 | + std::map<Expr, TernaryOp, ExprCmp> ternary_ops; | ||
| 442 | + std::vector<PerfBreakdownGroup> perf_breakdowns; | ||
| 443 | + | ||
| 444 | + ASSERT_EQ(pipe_perf.GetNodePerfInternal(*vector_func_iter, node_perf, ternary_ops, perf_breakdowns, true), | ||
| 445 | + af::SUCCESS); | ||
| 446 | + | ||
| 447 | + const auto iter = node_perf.find(PipeType::AIV_VEC); | ||
| 448 | + ASSERT_NE(iter, node_perf.end()); | ||
| 449 | + const auto ternary_iter = ternary_ops.find(iter->second); | ||
| 450 | + ASSERT_NE(ternary_iter, ternary_ops.end()); | ||
| 451 | + const std::string desc = ternary_iter->second.GetDescription(); | ||
| 452 | + EXPECT_NE(desc.find("VectorFunc"), std::string::npos) << desc; | ||
| 453 | + EXPECT_NE(desc.find("AIV_VEC_perf"), std::string::npos) << desc; | ||
| 454 | +} | ||
| 455 | + | ||
| 296 | TEST_F(TestPipePerfExpr, case_get_perf_for_loop) { | 456 | TEST_F(TestPipePerfExpr, case_get_perf_for_loop) { |
| 297 | af::AscGraph graph("graph"); | 457 | af::AscGraph graph("graph"); |
| 298 | ASSERT_EQ(af::ascir::cg::BuildEqAscendGraphND(graph), af::SUCCESS); | 458 | ASSERT_EQ(af::ascir::cg::BuildEqAscendGraphND(graph), af::SUCCESS); |
| @@ -18,7 +18,7 @@ | |||
| 18 | #include "ascir_ops.h" | 18 | #include "ascir_ops.h" |
| 19 | #include "ascir_node_param/ascir_node_param.h" | 19 | #include "ascir_node_param/ascir_node_param.h" |
| 20 | #include "ascir_node_param/ascir_param_builder.h" | 20 | #include "ascir_node_param/ascir_param_builder.h" |
| 21 | -#include "gen_model_info/parser/reduce_specific_params_builder.h" | 21 | +#include "gen_model_info/parser/specific_params_builder.h" |
| 22 | #include "gen_model_info/parser/tuning_space.h" | 22 | #include "gen_model_info/parser/tuning_space.h" |
| 23 | 23 | ||
| 24 | namespace ascir_reduce_test_helpers { | 24 | namespace ascir_reduce_test_helpers { |
| @@ -96,7 +96,7 @@ inline att::NodeInfo BuildReduceNodeInfo(ReduceTestEnv &env, const std::string & | |||
| 96 | BuildParserTensor("y", {&env.axis0, &env.axis1}, {ge::Symbol(8), ge::Symbol(1)}, {ge::Symbol(1), ge::Symbol(0)})}; | 96 | BuildParserTensor("y", {&env.axis0, &env.axis1}, {ge::Symbol(8), ge::Symbol(1)}, {ge::Symbol(1), ge::Symbol(0)})}; |
| 97 | node_info.loop_axes = {&env.axis1}; | 97 | node_info.loop_axes = {&env.axis1}; |
| 98 | (void)ascir_param::EnrichAscirGraphNodeParams(env.graph); | 98 | (void)ascir_param::EnrichAscirGraphNodeParams(env.graph); |
| 99 | - (void)att::FillReduceSpecificParams(env.node, node_info); | 99 | + (void)att::FillSpecificParams(env.node, node_info); |
| 100 | return node_info; | 100 | return node_info; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| @@ -64,6 +64,43 @@ TEST(AscirNodeParamsTest, EnrichGraphRegistersSkippedForUnsupportedApi) { | |||
| 64 | EXPECT_TRUE(std::holds_alternative<std::monostate>(params->specific_params)); | 64 | EXPECT_TRUE(std::holds_alternative<std::monostate>(params->specific_params)); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | +TEST(AscirNodeParamsTest, VectorFuncParamsCanBeStoredInAscirNodeParams) { | ||
| 68 | + ascir_param::AscirNodeParams params; | ||
| 69 | + ascir_param::VectorFuncNodeParams vf_params; | ||
| 70 | + vf_params.is_double_loop = true; | ||
| 71 | + vf_params.all_strides = {Expr(4), Expr(8)}; | ||
| 72 | + vf_params.output_dims = {Expr(2), Expr(16)}; | ||
| 73 | + | ||
| 74 | + params.specific_params = vf_params; | ||
| 75 | + | ||
| 76 | + const auto *stored = ascir_param::GetSpecificParams<ascir_param::VectorFuncNodeParams>(params); | ||
| 77 | + ASSERT_NE(stored, nullptr); | ||
| 78 | + EXPECT_TRUE(stored->is_double_loop); | ||
| 79 | + ASSERT_EQ(stored->all_strides.size(), 2U); | ||
| 80 | + EXPECT_EQ(stored->all_strides[0], Expr(4)); | ||
| 81 | + ASSERT_EQ(stored->output_dims.size(), 2U); | ||
| 82 | + EXPECT_EQ(stored->output_dims[1], Expr(16)); | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +TEST(AscirNodeParamsTest, EnrichGraphRegistersVectorFuncParams) { | ||
| 86 | + af::AscGraph graph("test_graph"); | ||
| 87 | + af::ascir_op::VectorFunc vf_op("vf"); | ||
| 88 | + graph.AddNode(vf_op); | ||
| 89 | + auto node = graph.FindNode("vf"); | ||
| 90 | + ASSERT_NE(node, nullptr); | ||
| 91 | + | ||
| 92 | + ExpectEnrichSuccess(graph); | ||
| 93 | + auto params = ascir_param::GetAscirNodeParams(node); | ||
| 94 | + ASSERT_NE(params, nullptr); | ||
| 95 | + EXPECT_EQ(params->api_name, "VectorFunc"); | ||
| 96 | + EXPECT_EQ(params->status, ascir_param::ParamBuildStatus::kBuilt); | ||
| 97 | + const auto *stored = ascir_param::GetSpecificParams<ascir_param::VectorFuncNodeParams>(*params); | ||
| 98 | + ASSERT_NE(stored, nullptr); | ||
| 99 | + EXPECT_FALSE(stored->is_double_loop); | ||
| 100 | + EXPECT_TRUE(stored->all_strides.empty()); | ||
| 101 | + EXPECT_TRUE(stored->output_dims.empty()); | ||
| 102 | +} | ||
| 103 | + | ||
| 67 | TEST(AscirNodeParamsTest, EnrichReduceParamsForArSingleReduce) { | 104 | TEST(AscirNodeParamsTest, EnrichReduceParamsForArSingleReduce) { |
| 68 | auto env = MakeArReduceEnv("max"); | 105 | auto env = MakeArReduceEnv("max"); |
| 69 | 106 | ||
| @@ -22,7 +22,7 @@ | |||
| 22 | #include "common/platform_context.h" | 22 | #include "common/platform_context.h" |
| 23 | #include "api_perf_register/utils/api_perf_utils.h" | 23 | #include "api_perf_register/utils/api_perf_utils.h" |
| 24 | #include "graph_construct_utils.h" | 24 | #include "graph_construct_utils.h" |
| 25 | -#include "parser/reduce_specific_params_builder.h" | 25 | +#include "parser/specific_params_builder.h" |
| 26 | #include "tests/ut/common/ascir_reduce_test_helpers.h" | 26 | #include "tests/ut/common/ascir_reduce_test_helpers.h" |
| 27 | 27 | ||
| 28 | using namespace att; | 28 | using namespace att; |
| @@ -62,7 +62,7 @@ void SetSingleReduceSpecificParams(NodeInfo &node) { | |||
| 62 | params.exprs.merge_times = {true, {{CreateExpr(1), ascir_param::ParamExprRole::kSemantic}}}; | 62 | params.exprs.merge_times = {true, {{CreateExpr(1), ascir_param::ParamExprRole::kSemantic}}}; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | -TEST_F(UTestAscirPerfV2, FillReduceSpecificParamsStoresSharedParamsOnAscNode) { | 65 | +TEST_F(UTestAscirPerfV2, FillSpecificParamsStoresSharedReduceParamsOnAscNode) { |
| 66 | using ascir_reduce_test_helpers::BuildReduceNodeInfo; | 66 | using ascir_reduce_test_helpers::BuildReduceNodeInfo; |
| 67 | using ascir_reduce_test_helpers::ReduceTestEnv; | 67 | using ascir_reduce_test_helpers::ReduceTestEnv; |
| 68 | ReduceTestEnv env("reduce"); | 68 | ReduceTestEnv env("reduce"); |
| @@ -19,7 +19,7 @@ | |||
| 19 | #include "ascir_node_param/ascir_node_param.h" | 19 | #include "ascir_node_param/ascir_node_param.h" |
| 20 | #include "ascir_node_param/ascir_param_builder.h" | 20 | #include "ascir_node_param/ascir_param_builder.h" |
| 21 | #include "ascir_ops.h" | 21 | #include "ascir_ops.h" |
| 22 | -#include "parser/reduce_specific_params_builder.h" | 22 | +#include "parser/specific_params_builder.h" |
| 23 | #include "common/platform_context.h" | 23 | #include "common/platform_context.h" |
| 24 | #include "codegen_api_param/codegen_api_param.h" | 24 | #include "codegen_api_param/codegen_api_param.h" |
| 25 | #include "v35/att/api_perf_register/ascendc_api_perf/reduce_api_perf_v2.h" | 25 | #include "v35/att/api_perf_register/ascendc_api_perf/reduce_api_perf_v2.h" |
| @@ -167,7 +167,7 @@ void SetReduceSpecificParams(NodeInfo &node, codegen::ReducePattern pattern, cod | |||
| 167 | 167 | ||
| 168 | // --- Parser integration tests --- | 168 | // --- Parser integration tests --- |
| 169 | 169 | ||
| 170 | -TEST_F(UTestReduceMinMaxApiPerfV2, FillReduceSpecificParamsRegistersSharedNodeParams) { | 170 | +TEST_F(UTestReduceMinMaxApiPerfV2, FillSpecificParamsRegistersSharedReduceNodeParams) { |
| 171 | using ascir_reduce_test_helpers::BuildReduceNodeInfo; | 171 | using ascir_reduce_test_helpers::BuildReduceNodeInfo; |
| 172 | using ascir_reduce_test_helpers::ReduceTestEnv; | 172 | using ascir_reduce_test_helpers::ReduceTestEnv; |
| 173 | ReduceTestEnv env("max"); | 173 | ReduceTestEnv env("max"); |
| @@ -183,7 +183,7 @@ TEST_F(UTestReduceMinMaxApiPerfV2, FillReduceSpecificParamsRegistersSharedNodePa | |||
| 183 | EXPECT_EQ(node_info.reduce_specific_params.canonical_params.merge_size, reduce->canonical_params.merge_size); | 183 | EXPECT_EQ(node_info.reduce_specific_params.canonical_params.merge_size, reduce->canonical_params.merge_size); |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | -TEST_F(UTestReduceMinMaxApiPerfV2, FillReduceSpecificParamsRegistersSkippedForUnsupportedApi) { | 186 | +TEST_F(UTestReduceMinMaxApiPerfV2, FillSpecificParamsRegistersSkippedForUnsupportedApi) { |
| 187 | af::AscGraph graph("skip_param_graph"); | 187 | af::AscGraph graph("skip_param_graph"); |
| 188 | af::ascir_op::Add add("add"); | 188 | af::ascir_op::Add add("add"); |
| 189 | graph.AddNode(add); | 189 | graph.AddNode(add); |
| @@ -195,14 +195,14 @@ TEST_F(UTestReduceMinMaxApiPerfV2, FillReduceSpecificParamsRegistersSkippedForUn | |||
| 195 | node_info.node_type = "Add"; | 195 | node_info.node_type = "Add"; |
| 196 | node_info.node_ptr = node; | 196 | node_info.node_ptr = node; |
| 197 | EXPECT_EQ(ascir_param::EnrichAscirGraphNodeParams(graph), af::SUCCESS); | 197 | EXPECT_EQ(ascir_param::EnrichAscirGraphNodeParams(graph), af::SUCCESS); |
| 198 | - EXPECT_EQ(FillReduceSpecificParams(node, node_info), af::SUCCESS); | 198 | + EXPECT_EQ(FillSpecificParams(node, node_info), af::SUCCESS); |
| 199 | const auto params = ascir_param::GetAscirNodeParams(node); | 199 | const auto params = ascir_param::GetAscirNodeParams(node); |
| 200 | ASSERT_NE(params, nullptr); | 200 | ASSERT_NE(params, nullptr); |
| 201 | EXPECT_EQ(params->status, ascir_param::ParamBuildStatus::kSkipped); | 201 | EXPECT_EQ(params->status, ascir_param::ParamBuildStatus::kSkipped); |
| 202 | EXPECT_FALSE(node_info.reduce_specific_params.canonical_params.valid); | 202 | EXPECT_FALSE(node_info.reduce_specific_params.canonical_params.valid); |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | -TEST_F(UTestReduceMinMaxApiPerfV2, FillReduceSpecificParamsKeepsInvalidWhenParamsMissing) { | 205 | +TEST_F(UTestReduceMinMaxApiPerfV2, FillSpecificParamsKeepsInvalidWhenParamsMissing) { |
| 206 | using ascir_reduce_test_helpers::ReduceTestEnv; | 206 | using ascir_reduce_test_helpers::ReduceTestEnv; |
| 207 | ReduceTestEnv env("max"); | 207 | ReduceTestEnv env("max"); |
| 208 | NodeInfo node_info; | 208 | NodeInfo node_info; |
| @@ -210,7 +210,7 @@ TEST_F(UTestReduceMinMaxApiPerfV2, FillReduceSpecificParamsKeepsInvalidWhenParam | |||
| 210 | node_info.node_type = "Max"; | 210 | node_info.node_type = "Max"; |
| 211 | node_info.node_ptr = env.node; | 211 | node_info.node_ptr = env.node; |
| 212 | 212 | ||
| 213 | - EXPECT_EQ(FillReduceSpecificParams(env.node, node_info), af::SUCCESS); | 213 | + EXPECT_EQ(FillSpecificParams(env.node, node_info), af::SUCCESS); |
| 214 | EXPECT_EQ(ascir_param::GetAscirNodeParams(env.node), nullptr); | 214 | EXPECT_EQ(ascir_param::GetAscirNodeParams(env.node), nullptr); |
| 215 | EXPECT_FALSE(node_info.reduce_specific_params.canonical_params.valid); | 215 | EXPECT_FALSE(node_info.reduce_specific_params.canonical_params.valid); |
| 216 | } | 216 | } |
| @@ -11,6 +11,8 @@ | |||
| 11 | #include "gtest/gtest.h" | 11 | #include "gtest/gtest.h" |
| 12 | #include "node_utils_ex.h" | 12 | #include "node_utils_ex.h" |
| 13 | #include "ascir_utils.h" | 13 | #include "ascir_utils.h" |
| 14 | +#include "ascir_node_param/ascir_node_param.h" | ||
| 15 | +#include "ascir_node_param/ascir_param_builder.h" | ||
| 14 | #include "graph_utils.h" | 16 | #include "graph_utils.h" |
| 15 | #include "ascendc_ir.h" | 17 | #include "ascendc_ir.h" |
| 16 | #include "ascir_ops.h" | 18 | #include "ascir_ops.h" |
| @@ -137,6 +139,129 @@ std::string GenerateScalarDataVfCall(AscGraph &graph, const af::Axis &z0, const | |||
| 137 | EXPECT_EQ(call.Generate(tpipe, vector<af::AxisId>{}, result), 0); | 139 | EXPECT_EQ(call.Generate(tpipe, vector<af::AxisId>{}, result), 0); |
| 138 | return result; | 140 | return result; |
| 139 | } | 141 | } |
| 142 | + | ||
| 143 | +template <typename TensorLike> | ||
| 144 | +void SetFiveDimSchedule(TensorLike &tensor, const std::vector<af::Axis> &axes, | ||
| 145 | + const std::vector<af::Expression> &repeats, const std::vector<af::Expression> &strides) { | ||
| 146 | + *tensor.axis = {axes[0].id, axes[1].id, axes[2].id, axes[3].id, axes[4].id}; | ||
| 147 | + *tensor.repeats = repeats; | ||
| 148 | + *tensor.strides = strides; | ||
| 149 | +} | ||
| 150 | + | ||
| 151 | +void SetFiveDimVecInAttr(AscTensor &tensor, const std::vector<af::Axis> &axes, | ||
| 152 | + const std::vector<af::Expression> &strides, int64_t tensor_id) { | ||
| 153 | + tensor.attr.vectorized_axis = {axes[0].id, axes[1].id, axes[2].id, axes[3].id, axes[4].id}; | ||
| 154 | + tensor.attr.vectorized_strides = strides; | ||
| 155 | + tensor.attr.dtype = af::DT_FLOAT; | ||
| 156 | + tensor.attr.mem.position = af::Position::kPositionVecIn; | ||
| 157 | + tensor.attr.mem.tensor_id = tensor_id; | ||
| 158 | +} | ||
| 159 | + | ||
| 160 | +void InitDoubleLoopVfGraph(VectorFunc &vf_op, Store &store_op, Load &sub_load_op, Abs &abs_op, Store &sub_store_op, | ||
| 161 | + Output &sub_output_op, const Load &load_op, const Data &sub_x_op, | ||
| 162 | + const std::vector<af::Axis> &axes, const std::vector<af::Expression> &repeats, | ||
| 163 | + const std::vector<af::Expression> &strides) { | ||
| 164 | + vf_op.InstanceOutputy(1); | ||
| 165 | + vf_op.x = {load_op.y}; | ||
| 166 | + vf_op.attr.sched.axis = {axes[0].id, axes[1].id, axes[2].id, axes[3].id, axes[4].id}; | ||
| 167 | + SetFiveDimSchedule(vf_op.y[0], axes, repeats, strides); | ||
| 168 | + | ||
| 169 | + store_op.x = vf_op.y[0]; | ||
| 170 | + store_op.ir_attr.SetOffset(af::Symbol(0)); | ||
| 171 | + SetFiveDimSchedule(store_op.y, axes, repeats, strides); | ||
| 172 | + | ||
| 173 | + sub_load_op.x = sub_x_op.y; | ||
| 174 | + sub_load_op.attr.sched.axis = {axes[3].id, axes[4].id}; | ||
| 175 | + sub_load_op.attr.sched.loop_axis = axes[4].id; | ||
| 176 | + SetFiveDimSchedule(sub_load_op.y, axes, repeats, strides); | ||
| 177 | + | ||
| 178 | + abs_op.x = sub_load_op.y; | ||
| 179 | + abs_op.attr.sched.axis = {axes[3].id, axes[4].id}; | ||
| 180 | + abs_op.attr.sched.loop_axis = axes[4].id; | ||
| 181 | + SetFiveDimSchedule(abs_op.y, axes, repeats, strides); | ||
| 182 | + | ||
| 183 | + sub_store_op.x = abs_op.y; | ||
| 184 | + sub_store_op.attr.sched.axis = {axes[3].id, axes[4].id}; | ||
| 185 | + sub_store_op.attr.sched.loop_axis = axes[4].id; | ||
| 186 | + SetFiveDimSchedule(sub_store_op.y, axes, repeats, strides); | ||
| 187 | + sub_output_op.x = sub_store_op.y; | ||
| 188 | +} | ||
| 189 | + | ||
| 190 | +void InitDoubleLoopTensorAttrs(AscGraph &graph, AscGraph &vf_sub_graph, const std::vector<af::Axis> &axes, | ||
| 191 | + const std::vector<af::Expression> &base_strides, | ||
| 192 | + const std::vector<af::Expression> &output_strides) { | ||
| 193 | + auto load = graph.FindNode("load"); | ||
| 194 | + SetFiveDimVecInAttr(load->outputs[0], axes, base_strides, 0); | ||
| 195 | + load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 196 | + load->outputs[0].attr.que.id = 1; | ||
| 197 | + load->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 198 | + | ||
| 199 | + SetFiveDimVecInAttr(vf_sub_graph.FindNode("sub_load")->outputs[0], axes, base_strides, 0); | ||
| 200 | + SetFiveDimVecInAttr(vf_sub_graph.FindNode("abs")->outputs[0], axes, base_strides, 1); | ||
| 201 | + SetFiveDimVecInAttr(vf_sub_graph.FindNode("sub_store")->outputs[0], axes, output_strides, 2); | ||
| 202 | + | ||
| 203 | + auto vf = graph.FindNode("vf"); | ||
| 204 | + SetFiveDimVecInAttr(vf->outputs[0], axes, output_strides, 1); | ||
| 205 | + vf->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 206 | + vf->outputs[0].attr.que.id = 1; | ||
| 207 | + vf->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 208 | + | ||
| 209 | + auto store = graph.FindNode("store"); | ||
| 210 | + store->outputs[0].attr.vectorized_axis = {axes[0].id, axes[1].id, axes[2].id, axes[3].id, axes[4].id}; | ||
| 211 | + store->outputs[0].attr.vectorized_strides = output_strides; | ||
| 212 | + store->outputs[0].attr.dtype = af::DT_FLOAT; | ||
| 213 | + store->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 214 | + store->outputs[0].attr.mem.tensor_id = 2; | ||
| 215 | + store->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 216 | + store->outputs[0].attr.que.id = 2; | ||
| 217 | + store->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 218 | +} | ||
| 219 | + | ||
| 220 | +void PrepareDoubleLoopCodegen(AscGraph &graph, const std::vector<af::Axis> &axes, | ||
| 221 | + const std::vector<af::Expression> &repeats, codegen::Tiler &tiler, codegen::TPipe &tpipe, | ||
| 222 | + codegen::VfCall &call, std::stringstream &func_def) { | ||
| 223 | + auto load = graph.FindNode("load"); | ||
| 224 | + auto vf = graph.FindNode("vf"); | ||
| 225 | + tpipe.AddTensor(load->outputs[0]); | ||
| 226 | + tpipe.AddTensor(vf->outputs[0]); | ||
| 227 | + for (const auto &axis : axes) { | ||
| 228 | + tiler.AddAxis(axis); | ||
| 229 | + } | ||
| 230 | + for (const auto &repeat : repeats) { | ||
| 231 | + tiler.AddSizeVar(af::SizeVar(repeat)); | ||
| 232 | + } | ||
| 233 | + | ||
| 234 | + codegen::ApiTensor x1; | ||
| 235 | + x1.id = load->outputs[0].attr.mem.tensor_id; | ||
| 236 | + ASSERT_EQ(call.Init(vf), 0); | ||
| 237 | + call.inputs.push_back(&x1); | ||
| 238 | + ASSERT_EQ(ascir_param::EnrichAscirGraphNodeParams(graph), af::SUCCESS); | ||
| 239 | + ASSERT_EQ(call.GenerateFuncDefinition(tpipe, tiler, func_def), 0); | ||
| 240 | +} | ||
| 241 | + | ||
| 242 | +void RegisterDoubleLoopNodes(AscGraph &graph, AscGraph &vf_sub_graph, VectorFunc &vf_op, Data &sub_x_op, | ||
| 243 | + Output &sub_output_op, Load &load_op, Store &store_op, const std::string &sub_graph_name) { | ||
| 244 | + vf_op.SetAttr("sub_graph_name", sub_graph_name); | ||
| 245 | + sub_x_op.ir_attr.SetIndex(0); | ||
| 246 | + sub_output_op.ir_attr.SetIndex(0); | ||
| 247 | + graph.AddNode(load_op); | ||
| 248 | + graph.AddSubGraph(vf_sub_graph); | ||
| 249 | + graph.AddNode(store_op); | ||
| 250 | +} | ||
| 251 | + | ||
| 252 | +void CheckDoubleLoopVectorFuncParams(const af::AscNodePtr &vf) { | ||
| 253 | + auto params = ascir_param::GetAscirNodeParams(vf); | ||
| 254 | + ASSERT_NE(params, nullptr); | ||
| 255 | + const auto *vector_func_params = std::get_if<ascir_param::VectorFuncNodeParams>(¶ms->specific_params); | ||
| 256 | + ASSERT_NE(vector_func_params, nullptr); | ||
| 257 | + EXPECT_TRUE(vector_func_params->is_double_loop); | ||
| 258 | + ASSERT_EQ(vector_func_params->all_strides.size(), 6U); | ||
| 259 | + EXPECT_STREQ(vector_func_params->all_strides[0].Serialize().get(), "(s2 * s3 * s4)"); | ||
| 260 | + EXPECT_STREQ(vector_func_params->all_strides[5].Serialize().get(), "(2 * s4)"); | ||
| 261 | + ASSERT_EQ(vector_func_params->output_dims.size(), 4U); | ||
| 262 | + EXPECT_STREQ(vector_func_params->output_dims[0].Serialize().get(), "s1"); | ||
| 263 | + EXPECT_STREQ(vector_func_params->output_dims[3].Serialize().get(), "s4"); | ||
| 264 | +} | ||
| 140 | } // namespace | 265 | } // namespace |
| 141 | 266 | ||
| 142 | TEST(CodegenKernel, VfCall_TwoDimLoad) { | 267 | TEST(CodegenKernel, VfCall_TwoDimLoad) { |
| @@ -1040,6 +1165,61 @@ TEST(CodegenKernel, VfCall_FiveDimLoad) { | |||
| 1040 | "#endif\n"}); | 1165 | "#endif\n"}); |
| 1041 | } | 1166 | } |
| 1042 | 1167 | ||
| 1168 | +TEST(CodegenKernel, VfCall_DoubleLoopWritesVectorFuncParams) { | ||
| 1169 | + ge::SetupRuntimeStub(); | ||
| 1170 | + af::AscGraph graph("test_graph"); | ||
| 1171 | + | ||
| 1172 | + af::Expression Two = af::Symbol(2); | ||
| 1173 | + af::Expression Three = af::Symbol(3); | ||
| 1174 | + af::Expression Four = af::Symbol(4); | ||
| 1175 | + af::Expression Five = af::Symbol(5); | ||
| 1176 | + | ||
| 1177 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 1178 | + auto s1 = graph.CreateSizeVar("s1"); | ||
| 1179 | + auto s2 = graph.CreateSizeVar("s2"); | ||
| 1180 | + auto s3 = graph.CreateSizeVar("s3"); | ||
| 1181 | + auto s4 = graph.CreateSizeVar("s4"); | ||
| 1182 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 1183 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 1184 | + auto z2 = graph.CreateAxis("z2", s2); | ||
| 1185 | + auto z3 = graph.CreateAxis("z3", s3); | ||
| 1186 | + auto z4 = graph.CreateAxis("z4", s4); | ||
| 1187 | + const std::vector<af::Axis> axes = {z0, z1, z2, z3, z4}; | ||
| 1188 | + const std::vector<af::Expression> repeats = {s0, s1, s2, s3, s4}; | ||
| 1189 | + const std::vector<af::Expression> base_strides = {s1 * s2 * s3 * s4, s2 * s3 * s4, s3 * s4, s4, One}; | ||
| 1190 | + const std::vector<af::Expression> output_strides = {s1 * s2 * s3 * s4 * Five, s2 * s3 * s4 * Four, s3 * s4 * Three, | ||
| 1191 | + s4 * Two, One}; | ||
| 1192 | + | ||
| 1193 | + Data x_op("x", graph); | ||
| 1194 | + Load load_op("load"); | ||
| 1195 | + std::string sub_graph_name = "vf_sub_graph_double_loop"; | ||
| 1196 | + af::AscGraph vf_sub_graph(sub_graph_name.c_str()); | ||
| 1197 | + VectorFunc vf_op("vf"); | ||
| 1198 | + Data sub_x_op("sub_x", vf_sub_graph); | ||
| 1199 | + Load sub_load_op("sub_load"); | ||
| 1200 | + Abs abs_op("abs"); | ||
| 1201 | + Store sub_store_op("sub_store"); | ||
| 1202 | + Output sub_output_op("sub_output"); | ||
| 1203 | + Store store_op("store"); | ||
| 1204 | + RegisterDoubleLoopNodes(graph, vf_sub_graph, vf_op, sub_x_op, sub_output_op, load_op, store_op, sub_graph_name); | ||
| 1205 | + | ||
| 1206 | + load_op.x = x_op.y; | ||
| 1207 | + load_op.attr.sched.axis = {z0.id, z1.id, z2.id, z3.id, z4.id}; | ||
| 1208 | + SetFiveDimSchedule(load_op.y, axes, repeats, base_strides); | ||
| 1209 | + InitDoubleLoopVfGraph(vf_op, store_op, sub_load_op, abs_op, sub_store_op, sub_output_op, load_op, sub_x_op, axes, | ||
| 1210 | + repeats, base_strides); | ||
| 1211 | + InitDoubleLoopTensorAttrs(graph, vf_sub_graph, axes, base_strides, output_strides); | ||
| 1212 | + | ||
| 1213 | + codegen::Tiler tiler; | ||
| 1214 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 1215 | + codegen::VfCall call; | ||
| 1216 | + std::stringstream func_def; | ||
| 1217 | + PrepareDoubleLoopCodegen(graph, axes, repeats, tiler, tpipe, call, func_def); | ||
| 1218 | + | ||
| 1219 | + auto vf = graph.FindNode("vf"); | ||
| 1220 | + CheckDoubleLoopVectorFuncParams(vf); | ||
| 1221 | +} | ||
| 1222 | + | ||
| 1043 | // 测试单维场景不触发优化逻辑 | 1223 | // 测试单维场景不触发优化逻辑 |
| 1044 | TEST(CodegenKernel, VfCall_OneDim_NoOptimization) { | 1224 | TEST(CodegenKernel, VfCall_OneDim_NoOptimization) { |
| 1045 | ge::SetupRuntimeStub(); | 1225 | ge::SetupRuntimeStub(); |
| @@ -10,7 +10,7 @@ | |||
| 10 | #include "vec_func_call.h" | 10 | #include "vec_func_call.h" |
| 11 | 11 | ||
| 12 | #include <sstream> | 12 | #include <sstream> |
| 13 | -#include "attr_utils.h" | 13 | +#include "ascir_node_param/ascir_node_param.h" |
| 14 | #include "ascir_ops.h" | 14 | #include "ascir_ops.h" |
| 15 | #include "common/ge_common/debug/log.h" | 15 | #include "common/ge_common/debug/log.h" |
| 16 | #include "graph/ascendc_ir/utils/asc_tensor_utils.h" | 16 | #include "graph/ascendc_ir/utils/asc_tensor_utils.h" |
| @@ -31,6 +31,16 @@ using namespace af::ascir_op; | |||
| 31 | using namespace ascgen_utils; | 31 | using namespace ascgen_utils; |
| 32 | 32 | ||
| 33 | namespace { | 33 | namespace { |
| 34 | +std::vector<ge::Expression> GetVfOutputDims(const VectorizedAxisLoopMergeStatus &merge_info) { | ||
| 35 | + std::vector<ge::Expression> output_dims; | ||
| 36 | + const size_t dim_size = merge_info.merge_repeats.size(); | ||
| 37 | + size_t start_idx = dim_size <= kVFMaxLoop ? 0 : dim_size - kVFMaxLoop; | ||
| 38 | + for (; start_idx < dim_size; ++start_idx) { | ||
| 39 | + output_dims.emplace_back(merge_info.merge_repeats[start_idx]); | ||
| 40 | + } | ||
| 41 | + return output_dims; | ||
| 42 | +} | ||
| 43 | + | ||
| 34 | void ParamPostProcess(std::stringstream &ss) { | 44 | void ParamPostProcess(std::stringstream &ss) { |
| 35 | if (ss.str().length() < kCommaSpaceLength) { | 45 | if (ss.str().length() < kCommaSpaceLength) { |
| 36 | return; | 46 | return; |
| @@ -329,36 +339,30 @@ Status VfCall::ParseInputOutputInfo(const TPipe &tpipe) const { | |||
| 329 | return af::SUCCESS; | 339 | return af::SUCCESS; |
| 330 | } | 340 | } |
| 331 | 341 | ||
| 332 | -void GenerateStridesEqualCheck(const std::vector<Tensor> &inputs, const std::vector<Tensor> &outputs, | 342 | +void CollectStrideNames(const std::vector<Tensor> &tensors, const std::vector<std::vector<ge::Expression>> &strides, |
| 333 | - const VectorizedAxisLoopMergeStatus &merge_info, std::stringstream &ss) { | 343 | + std::vector<std::string> &all_stride_names, std::vector<ge::Expression> &all_strides) { |
| 334 | - std::vector<std::string> all_stride_names; | 344 | + for (size_t j = 0; j < strides.size(); j++) { |
| 335 | - for (size_t j = 0; j < merge_info.inputs_strides.size(); j++) { | 345 | + size_t stride_size = strides[j].size(); |
| 336 | - size_t stride_size = merge_info.inputs_strides[j].size(); | ||
| 337 | size_t start_idx = stride_size <= kVFMaxLoop ? 0 : stride_size - kVFMaxLoop; | 346 | size_t start_idx = stride_size <= kVFMaxLoop ? 0 : stride_size - kVFMaxLoop; |
| 338 | for (; start_idx < stride_size; start_idx++) { | 347 | for (; start_idx < stride_size; start_idx++) { |
| 339 | - if (merge_info.inputs_strides[j][start_idx].Simplify() == af::ops::One || | 348 | + if (strides[j][start_idx].Simplify() == af::ops::One || strides[j][start_idx].Simplify() == af::ops::Zero) { |
| 340 | - merge_info.inputs_strides[j][start_idx].Simplify() == af::ops::Zero) { | ||
| 341 | continue; | 349 | continue; |
| 342 | } | 350 | } |
| 343 | std::stringstream tensor_name; | 351 | std::stringstream tensor_name; |
| 344 | - tensor_name << inputs[j]; | 352 | + tensor_name << tensors[j]; |
| 345 | - all_stride_names.push_back(tensor_name.str() + "_stride_" + std::to_string(start_idx)); | 353 | + const std::string stride_name = tensor_name.str() + "_stride_" + std::to_string(start_idx); |
| 354 | + all_stride_names.push_back(stride_name); | ||
| 355 | + all_strides.emplace_back(strides[j][start_idx]); | ||
| 346 | } | 356 | } |
| 347 | } | 357 | } |
| 358 | +} | ||
| 348 | 359 | ||
| 349 | - for (size_t j = 0; j < merge_info.outputs_strides.size(); j++) { | 360 | +void GenerateStridesEqualCheck(const std::vector<Tensor> &inputs, const std::vector<Tensor> &outputs, |
| 350 | - size_t stride_size = merge_info.outputs_strides[j].size(); | 361 | + const VectorizedAxisLoopMergeStatus &merge_info, |
| 351 | - size_t start_idx = stride_size <= kVFMaxLoop ? 0 : stride_size - kVFMaxLoop; | 362 | + std::vector<ge::Expression> &all_strides, std::stringstream &ss) { |
| 352 | - for (; start_idx < stride_size; start_idx++) { | 363 | + std::vector<std::string> all_stride_names; |
| 353 | - if (merge_info.outputs_strides[j][start_idx].Simplify() == af::ops::One || | 364 | + CollectStrideNames(inputs, merge_info.inputs_strides, all_stride_names, all_strides); |
| 354 | - merge_info.outputs_strides[j][start_idx].Simplify() == af::ops::Zero) { | 365 | + CollectStrideNames(outputs, merge_info.outputs_strides, all_stride_names, all_strides); |
| 355 | - continue; | ||
| 356 | - } | ||
| 357 | - std::stringstream tensor_name; | ||
| 358 | - tensor_name << outputs[j]; | ||
| 359 | - all_stride_names.push_back(tensor_name.str() + "_stride_" + std::to_string(start_idx)); | ||
| 360 | - } | ||
| 361 | - } | ||
| 362 | 366 | ||
| 363 | if (all_stride_names.empty()) { | 367 | if (all_stride_names.empty()) { |
| 364 | ss << " uint32_t strides_align = 0;\n bool strides_equal = false;\n"; | 368 | ss << " uint32_t strides_align = 0;\n bool strides_equal = false;\n"; |
| @@ -430,6 +434,21 @@ void GenerateTensorDefs(const TPipe &tpipe, const TensorManager &tensor_mgr, con | |||
| 430 | } | 434 | } |
| 431 | } | 435 | } |
| 432 | 436 | ||
| 437 | +af::Status UpdateVectorFuncNodeParams(const af::AscNodePtr &node, const VectorizedAxisLoopMergeStatus &merge_info, | ||
| 438 | + const std::vector<ge::Expression> &all_strides) { | ||
| 439 | + GE_ASSERT_NOTNULL(node); | ||
| 440 | + auto params = ascir_param::GetAscirNodeParams(node); | ||
| 441 | + GE_ASSERT_NOTNULL(params); | ||
| 442 | + ascir_param::VectorFuncNodeParams vector_func_params; | ||
| 443 | + vector_func_params.is_double_loop = true; | ||
| 444 | + vector_func_params.all_strides = all_strides; | ||
| 445 | + vector_func_params.output_dims = GetVfOutputDims(merge_info); | ||
| 446 | + params->api_name = node->GetType(); | ||
| 447 | + params->status = ascir_param::ParamBuildStatus::kBuilt; | ||
| 448 | + params->specific_params = vector_func_params; | ||
| 449 | + return af::SUCCESS; | ||
| 450 | +} | ||
| 451 | + | ||
| 433 | Status VfCall::GenerateFuncDefinition(const TPipe &tpipe, const Tiler &tiler, std::stringstream &ss) const { | 452 | Status VfCall::GenerateFuncDefinition(const TPipe &tpipe, const Tiler &tiler, std::stringstream &ss) const { |
| 434 | // 收集输入输出信息,由于GenInnerLoopSizeAndActualSize函数中会刷新tiler对象中的actual_sizes字段, | 453 | // 收集输入输出信息,由于GenInnerLoopSizeAndActualSize函数中会刷新tiler对象中的actual_sizes字段, |
| 435 | // 导致生成函数签名和函数调用时,获取到的size信息不一致,因此生成函数签名和函数调用时均需要调用合轴函数 | 454 | // 导致生成函数签名和函数调用时,获取到的size信息不一致,因此生成函数签名和函数调用时均需要调用合轴函数 |
| @@ -485,13 +504,14 @@ Status VfCall::GenerateFuncDefinition(const TPipe &tpipe, const Tiler &tiler, st | |||
| 485 | int32_t only_loop_max_depth = -1; | 504 | int32_t only_loop_max_depth = -1; |
| 486 | std::vector<std::string> loop_size_vec; | 505 | std::vector<std::string> loop_size_vec; |
| 487 | root_loop_.Generate(tpipe, tensor_mgr_, stride_depth, loop_body, loop_size, only_loop_max_depth, loop_size_vec); | 506 | root_loop_.Generate(tpipe, tensor_mgr_, stride_depth, loop_body, loop_size, only_loop_max_depth, loop_size_vec); |
| 507 | + const bool is_double_loop = | ||
| 508 | + stride_depth == MAX_VF_AXIS_MERGE_SIZE - 1 && only_loop_max_depth == MAX_VF_AXIS_MERGE_SIZE - 1; | ||
| 509 | + std::vector<ge::Expression> all_strides; | ||
| 488 | params << std::endl << loop_size << std::endl; | 510 | params << std::endl << loop_size << std::endl; |
| 489 | - if (stride_depth == MAX_VF_AXIS_MERGE_SIZE - 1 && | 511 | + if (is_double_loop) { // 假如stride_depth为1即两层循环,那实际上loop里递归了三次,分别是0、1、2,在2里单独处理call |
| 490 | - only_loop_max_depth == | 512 | + GenerateStridesEqualCheck(this->ub_inputs_, this->ub_outputs_, merge_info, all_strides, params); |
| 491 | - MAX_VF_AXIS_MERGE_SIZE - | ||
| 492 | - 1) { // 假如stride_depth为1即两层循环,那实际上loop里递归了三次,分别是0、1、2,在2里单独处理call | ||
| 493 | - GenerateStridesEqualCheck(this->ub_inputs_, this->ub_outputs_, merge_info, params); | ||
| 494 | OptimizeMergeParamsAndLoopSize(loop_size_vec, params); | 513 | OptimizeMergeParamsAndLoopSize(loop_size_vec, params); |
| 514 | + GE_ASSERT_SUCCESS(UpdateVectorFuncNodeParams(node, merge_info, all_strides)); | ||
| 495 | } | 515 | } |
| 496 | vf_body << std::endl << loop_body << std::endl; | 516 | vf_body << std::endl << loop_body << std::endl; |
| 497 | GetVFCallFuncBody(params.str(), vf_body.str(), ss); | 517 | GetVFCallFuncBody(params.str(), vf_body.str(), ss); |
直接访问 all_strides[0]、output_dims[0/1],建议在进入 double-loop 分支前显式校验 output_dims.size() >= 2,equal 分支校验 !all_strides.empty()