已合并
feat(autofuse): support effective-view NDDMA models #1792
zhang_shengjie创建于 17 天前
feat(autofuse): support effective-view NDDMA models #1792
已合并
共 12 个文件变更+339-174
| @@ -19,8 +19,9 @@ | |||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | namespace att { | 21 | namespace att { |
| 22 | -// legacy 连续轴合并前的原始 DataCopyNddma 描述。所有向量均按 vectorized_axis 排列,dim 和 stride 的单位 | 22 | +// Codegen DataCopyNddma 的 effective view。向量已按 vectorized_axis 排列,并应与 |
| 23 | -// 分别为元素个数和元素;input_strides 对应 GM stride,output_strides 对应 UB vectorized stride。 | 23 | +// CalculateDmaParams 合轴、忽略双零 stride 轴及 tail actual size 后的参数一致;dim 和 stride 的单位 |
| 24 | +// 分别为元素个数和元素,input_strides 对应 GM stride,output_strides 对应 UB vectorized stride。 | ||
| 24 | struct NddmaDescriptorInfo { | 25 | struct NddmaDescriptorInfo { |
| 25 | std::vector<Expr> output_dims; | 26 | std::vector<Expr> output_dims; |
| 26 | std::vector<Expr> input_strides; | 27 | std::vector<Expr> input_strides; |
| @@ -120,7 +120,6 @@ bool CalculateDmaParams(const TPipe &tpipe, const Tensor &gm_tensor, const Tenso | |||
| 120 | } | 120 | } |
| 121 | AxisInfo axis_info; | 121 | AxisInfo axis_info; |
| 122 | MergeInfo merge_info; | 122 | MergeInfo merge_info; |
| 123 | - | ||
| 124 | size_t vec_axis_pos = ub_tensor.vectorized_axis.size() - 1; | 123 | size_t vec_axis_pos = ub_tensor.vectorized_axis.size() - 1; |
| 125 | bool has_non_zero_axis = false; | 124 | bool has_non_zero_axis = false; |
| 126 | for (vec_axis_pos = ub_tensor.vectorized_axis.size(); vec_axis_pos-- > 0UL;) { | 125 | for (vec_axis_pos = ub_tensor.vectorized_axis.size(); vec_axis_pos-- > 0UL;) { |
| @@ -128,11 +127,8 @@ bool CalculateDmaParams(const TPipe &tpipe, const Tensor &gm_tensor, const Tenso | |||
| 128 | GE_ASSERT_TRUE((pos != gm_tensor.axis.end()), "Codegen vectorized axis[%zu] not found", vec_axis_pos); | 127 | GE_ASSERT_TRUE((pos != gm_tensor.axis.end()), "Codegen vectorized axis[%zu] not found", vec_axis_pos); |
| 129 | const auto axis_pos = std::distance(gm_tensor.axis.begin(), pos); | 128 | const auto axis_pos = std::distance(gm_tensor.axis.begin(), pos); |
| 130 | // 如果当前轴gm和ub上对应的stride均为0,如果前序轴的stride不为1,则保留当前轴 | 129 | // 如果当前轴gm和ub上对应的stride均为0,如果前序轴的stride不为1,则保留当前轴 |
| 131 | - const bool ignore_zero_axis = has_non_zero_axis || vec_axis_pos == 0UL || | 130 | + const bool ignore_zero_axis = |
| 132 | - af::SymbolicUtils::StaticCheckEq(ub_tensor.vectorized_strides[vec_axis_pos - 1], | 131 | + ascgen_utils::ShouldIgnoreDataCopyZeroAxis(has_non_zero_axis, vec_axis_pos, ub_tensor.vectorized_strides); |
| 133 | - af::ops::One) == af::TriBool::kTrue || | ||
| 134 | - af::SymbolicUtils::StaticCheckEq(ub_tensor.vectorized_strides[vec_axis_pos - 1], | ||
| 135 | - af::ops::Zero) == af::TriBool::kTrue; | ||
| 136 | if (af::SymbolicUtils::StaticCheckEq(gm_tensor.axis_strides[axis_pos], af::ops::Zero) == af::TriBool::kTrue && | 132 | if (af::SymbolicUtils::StaticCheckEq(gm_tensor.axis_strides[axis_pos], af::ops::Zero) == af::TriBool::kTrue && |
| 137 | af::SymbolicUtils::StaticCheckEq(ub_tensor.vectorized_strides[vec_axis_pos], af::ops::Zero) == | 133 | af::SymbolicUtils::StaticCheckEq(ub_tensor.vectorized_strides[vec_axis_pos], af::ops::Zero) == |
| 138 | af::TriBool::kTrue && | 134 | af::TriBool::kTrue && |
| @@ -142,9 +138,9 @@ bool CalculateDmaParams(const TPipe &tpipe, const Tensor &gm_tensor, const Tenso | |||
| 142 | has_non_zero_axis = true; | 138 | has_non_zero_axis = true; |
| 143 | ascir::SizeExpr cur_axis_stride = axis_info.prev_axis_stride * axis_info.prev_repeat; | 139 | ascir::SizeExpr cur_axis_stride = axis_info.prev_axis_stride * axis_info.prev_repeat; |
| 144 | ascir::SizeExpr cur_vectorized_axis_stride = axis_info.prev_vectorized_axis_stride * axis_info.prev_repeat; | 140 | ascir::SizeExpr cur_vectorized_axis_stride = axis_info.prev_vectorized_axis_stride * axis_info.prev_repeat; |
| 145 | - if (af::SymbolicUtils::StaticCheckEq(cur_axis_stride, gm_tensor.axis_strides[axis_pos]) != af::TriBool::kTrue || | 141 | + if (!ascgen_utils::IsDataCopyAxisContinuous(cur_axis_stride, cur_vectorized_axis_stride, |
| 146 | - af::SymbolicUtils::StaticCheckEq(cur_vectorized_axis_stride, ub_tensor.vectorized_strides[vec_axis_pos]) != | 142 | + gm_tensor.axis_strides[axis_pos], |
| 147 | - af::TriBool::kTrue || | 143 | + ub_tensor.vectorized_strides[vec_axis_pos]) || |
| 148 | merge_info.merge_repeats.empty() || | 144 | merge_info.merge_repeats.empty() || |
| 149 | (vec_axis_pos < (ub_tensor.vectorized_axis.size() - 1) && | 145 | (vec_axis_pos < (ub_tensor.vectorized_axis.size() - 1) && |
| 150 | tpipe.tiler.GetAxis(ub_tensor.vectorized_axis[vec_axis_pos + 1]).type == | 146 | tpipe.tiler.GetAxis(ub_tensor.vectorized_axis[vec_axis_pos + 1]).type == |
| @@ -161,6 +157,14 @@ bool CalculateDmaParams(const TPipe &tpipe, const Tensor &gm_tensor, const Tenso | |||
| 161 | std::reverse(merge_info.merge_repeats.begin(), merge_info.merge_repeats.end()); | 157 | std::reverse(merge_info.merge_repeats.begin(), merge_info.merge_repeats.end()); |
| 162 | std::reverse(merge_info.merge_gm_strides.begin(), merge_info.merge_gm_strides.end()); | 158 | std::reverse(merge_info.merge_gm_strides.begin(), merge_info.merge_gm_strides.end()); |
| 163 | std::reverse(merge_info.merge_ub_strides.begin(), merge_info.merge_ub_strides.end()); | 159 | std::reverse(merge_info.merge_ub_strides.begin(), merge_info.merge_ub_strides.end()); |
| 160 | + GELOGD( | ||
| 161 | + "[Codegen NDDMA] effective view: raw_rank=%zu, effective_rank=%zu, repeats=[%s], gm_strides=[%s], " | ||
| 162 | + "ub_strides=[%s], vectorized_axis=[%s]", | ||
| 163 | + ub_tensor.vectorized_axis.size(), merge_info.merge_repeats.size(), | ||
| 164 | + ascgen_utils::VectorToStr(merge_info.merge_repeats).c_str(), | ||
| 165 | + ascgen_utils::VectorToStr(merge_info.merge_gm_strides).c_str(), | ||
| 166 | + ascgen_utils::VectorToStr(merge_info.merge_ub_strides).c_str(), | ||
| 167 | + ascgen_utils::VectorToStr(ub_tensor.vectorized_axis).c_str()); | ||
| 164 | SetDataCopyParams(merge_info, param, multi_axis_copy); | 168 | SetDataCopyParams(merge_info, param, multi_axis_copy); |
| 165 | return true; | 169 | return true; |
| 166 | } | 170 | } |
| @@ -65,12 +65,6 @@ struct DmaParamsExpr { | |||
| 65 | } | 65 | } |
| 66 | }; | 66 | }; |
| 67 | 67 | ||
| 68 | -struct AxisInfo { | ||
| 69 | - ascir::SizeExpr prev_repeat = af::ops::One; | ||
| 70 | - ascir::SizeExpr prev_axis_stride = af::ops::One; | ||
| 71 | - ascir::SizeExpr prev_vectorized_axis_stride = af::ops::One; | ||
| 72 | -}; | ||
| 73 | - | ||
| 74 | struct ApiLoopParams { | 68 | struct ApiLoopParams { |
| 75 | std::vector<std::string> outer_repeats; | 69 | std::vector<std::string> outer_repeats; |
| 76 | std::vector<std::vector<ascir::SizeExpr>> inputs_strides; | 70 | std::vector<std::vector<ascir::SizeExpr>> inputs_strides; |
| @@ -86,6 +80,12 @@ struct MergeInfo { | |||
| 86 | std::vector<ascir::SizeExpr> merge_ub_strides; | 80 | std::vector<ascir::SizeExpr> merge_ub_strides; |
| 87 | }; | 81 | }; |
| 88 | 82 | ||
| 83 | +struct AxisInfo { | ||
| 84 | + ascir::SizeExpr prev_repeat = af::ops::One; | ||
| 85 | + ascir::SizeExpr prev_axis_stride = af::ops::One; | ||
| 86 | + ascir::SizeExpr prev_vectorized_axis_stride = af::ops::One; | ||
| 87 | +}; | ||
| 88 | + | ||
| 89 | struct VectorizedAixsLoopStatus { | 89 | struct VectorizedAixsLoopStatus { |
| 90 | ascir::SizeExpr prev_repeat = af::ops::One; | 90 | ascir::SizeExpr prev_repeat = af::ops::One; |
| 91 | std::vector<ascir::SizeExpr> prev_input_axis_stride; | 91 | std::vector<ascir::SizeExpr> prev_input_axis_stride; |
| @@ -233,6 +233,19 @@ bool IsStaticSchedResult(const ascir::FusedScheduledResult &fused_schedule_resul | |||
| 233 | return true; | 233 | return true; |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | +bool ShouldIgnoreDataCopyZeroAxis(bool has_non_zero_axis, size_t axis_pos, | ||
| 237 | + const std::vector<af::Expression> &ub_strides) { | ||
| 238 | + return has_non_zero_axis || axis_pos == 0U || | ||
| 239 | + af::SymbolicUtils::StaticCheckEq(ub_strides[axis_pos - 1U], af::ops::One) == af::TriBool::kTrue || | ||
| 240 | + af::SymbolicUtils::StaticCheckEq(ub_strides[axis_pos - 1U], af::ops::Zero) == af::TriBool::kTrue; | ||
| 241 | +} | ||
| 242 | + | ||
| 243 | +bool IsDataCopyAxisContinuous(const af::Expression &cur_gm_stride, const af::Expression &cur_ub_stride, | ||
| 244 | + const af::Expression &gm_stride, const af::Expression &ub_stride) { | ||
| 245 | + return af::SymbolicUtils::StaticCheckEq(cur_gm_stride, gm_stride) == af::TriBool::kTrue && | ||
| 246 | + af::SymbolicUtils::StaticCheckEq(cur_ub_stride, ub_stride) == af::TriBool::kTrue; | ||
| 247 | +} | ||
| 248 | + | ||
| 236 | const std::vector<af::Expression> &GetFrontendShapeVars(const ascir::FusedScheduledResult &fused_schedule_result) { | 249 | const std::vector<af::Expression> &GetFrontendShapeVars(const ascir::FusedScheduledResult &fused_schedule_result) { |
| 237 | if (fused_schedule_result.frontend_shape_vars_collected || !fused_schedule_result.frontend_shape_vars.empty()) { | 250 | if (fused_schedule_result.frontend_shape_vars_collected || !fused_schedule_result.frontend_shape_vars.empty()) { |
| 238 | return fused_schedule_result.frontend_shape_vars; | 251 | return fused_schedule_result.frontend_shape_vars; |
| @@ -167,6 +167,13 @@ bool IsScalarNextNodeSupportBlkTensor(const af::AscNodePtr &node); | |||
| 167 | bool IsUbScalarLoad(const af::AscNodePtr &node); | 167 | bool IsUbScalarLoad(const af::AscNodePtr &node); |
| 168 | bool IsStaticSchedResult(const ascir::FusedScheduledResult &fused_schedule_result); | 168 | bool IsStaticSchedResult(const ascir::FusedScheduledResult &fused_schedule_result); |
| 169 | 169 | ||
| 170 | +// Shared DataCopy axis rules. The caller owns the original loop state so the | ||
| 171 | +// codegen state machine remains unchanged while ATT can reuse the same rules. | ||
| 172 | +bool ShouldIgnoreDataCopyZeroAxis(bool has_non_zero_axis, size_t axis_pos, | ||
| 173 | + const std::vector<af::Expression> &ub_strides); | ||
| 174 | +bool IsDataCopyAxisContinuous(const af::Expression &cur_gm_stride, const af::Expression &cur_ub_stride, | ||
| 175 | + const af::Expression &gm_stride, const af::Expression &ub_stride); | ||
| 176 | + | ||
| 170 | // Return the frontend ABI symbol list. Results produced before the new field | 177 | // Return the frontend ABI symbol list. Results produced before the new field |
| 171 | // was introduced may only have origin_vars; keep that as a compatibility | 178 | // was introduced may only have origin_vars; keep that as a compatibility |
| 172 | // fallback for legacy callers and unit fixtures. | 179 | // fallback for legacy callers and unit fixtures. |
| @@ -1269,7 +1269,6 @@ af::Status AnalyzeRewrittenGraph(af::AscGraph &graph, const af::AscNodePtr &indi | |||
| 1269 | if (!is_candidate_legal) { | 1269 | if (!is_candidate_legal) { |
| 1270 | return af::SUCCESS; | 1270 | return af::SUCCESS; |
| 1271 | } | 1271 | } |
| 1272 | - | ||
| 1273 | if (template_id != ascir::TemplateId::kIndirectLoadSK) { | 1272 | if (template_id != ascir::TemplateId::kIndirectLoadSK) { |
| 1274 | // 收集阶段:一次遍历收集全部状态(改写定稿后无需重收) | 1273 | // 收集阶段:一次遍历收集全部状态(改写定稿后无需重收) |
| 1275 | GE_ASSERT_SUCCESS(CollectRewrittenBoundaries(indirect_load, analysis)); | 1274 | GE_ASSERT_SUCCESS(CollectRewrittenBoundaries(indirect_load, analysis)); |
| @@ -410,7 +410,6 @@ TEST_F(STestAscirPerfV2, TestNddma1DModelHandlesStaticAndDynamicShapes) { | |||
| 410 | EXPECT_NE(cycles.find("TernaryOp"), std::string::npos); | 410 | EXPECT_NE(cycles.find("TernaryOp"), std::string::npos); |
| 411 | EXPECT_NE(cycles.find("input_stride"), std::string::npos); | 411 | EXPECT_NE(cycles.find("input_stride"), std::string::npos); |
| 412 | EXPECT_NE(cycles.find("output_stride"), std::string::npos); | 412 | EXPECT_NE(cycles.find("output_stride"), std::string::npos); |
| 413 | - EXPECT_NE(cycles.find("Max"), std::string::npos); | ||
| 414 | EXPECT_NE(cycles.find("Min"), std::string::npos); | 413 | EXPECT_NE(cycles.find("Min"), std::string::npos); |
| 415 | EXPECT_NE(cycles.find("n"), std::string::npos); | 414 | EXPECT_NE(cycles.find("n"), std::string::npos); |
| 416 | } | 415 | } |
| @@ -639,7 +639,7 @@ TEST_F(UTestAscirPerfV2, TestNddma1DModelSupportsFourDtypeSizes) { | |||
| 639 | } | 639 | } |
| 640 | } | 640 | } |
| 641 | 641 | ||
| 642 | -TEST_F(UTestAscirPerfV2, TestNddmaRaw2DTo5DKeepLegacyOutputAfterMerge) { | 642 | +TEST_F(UTestAscirPerfV2, TestNddmaEffectiveRank2To5UsesNewModel) { |
| 643 | auto nddma = ApiPerfFactory::Instance().Create("NddmaV2"); | 643 | auto nddma = ApiPerfFactory::Instance().Create("NddmaV2"); |
| 644 | ASSERT_NE(nddma, nullptr); | 644 | ASSERT_NE(nddma, nullptr); |
| 645 | NodeInfo node; | 645 | NodeInfo node; |
| @@ -663,11 +663,22 @@ TEST_F(UTestAscirPerfV2, TestNddmaRaw2DTo5DKeepLegacyOutputAfterMerge) { | |||
| 663 | 663 | ||
| 664 | ASSERT_EQ(nddma->GetPerfFunc()(shapes, shapes, node, perf_res), af::SUCCESS); | 664 | ASSERT_EQ(nddma->GetPerfFunc()(shapes, shapes, node, perf_res), af::SUCCESS); |
| 665 | const auto cycles = Str(perf_res.pipe_res[PipeType::AIV_MTE2]); | 665 | const auto cycles = Str(perf_res.pipe_res[PipeType::AIV_MTE2]); |
| 666 | - EXPECT_EQ(cycles.find("nddma_1d_multicore"), std::string::npos); | 666 | + EXPECT_NE(cycles.find("nddma_1d_multicore"), std::string::npos); |
| 667 | - EXPECT_EQ(cycles, "((2048 / (((6.3899998664856 / (block_dim)) + 7.6100001335144))) + 418.978912353516)"); | ||
| 668 | } | 667 | } |
| 669 | } | 668 | } |
| 670 | 669 | ||
| 670 | +TEST_F(UTestAscirPerfV2, TestNddmaFallsBackOnDtypeSizeMismatch) { | ||
| 671 | + const auto shape = Make1DNddmaShape("float16", 4, CreateExpr(256), CreateExpr(1), CreateExpr(1)); | ||
| 672 | + const std::vector<TensorShapeInfo> shapes = {shape}; | ||
| 673 | + NodeInfo node; | ||
| 674 | + node.node_ptr = GraphConstructUtils::ConstructSingleOp("Nddma", 1, 1); | ||
| 675 | + PerfOutputInfo perf_res; | ||
| 676 | + auto nddma = ApiPerfFactory::Instance().Create("NddmaV2"); | ||
| 677 | + ASSERT_NE(nddma, nullptr); | ||
| 678 | + ASSERT_EQ(nddma->GetPerfFunc()(shapes, shapes, node, perf_res), af::SUCCESS); | ||
| 679 | + EXPECT_EQ(Str(perf_res.pipe_res[PipeType::AIV_MTE2]).find("nddma_1d_multicore"), std::string::npos); | ||
| 680 | +} | ||
| 681 | + | ||
| 671 | TEST_F(UTestAscirPerfV2, TestNddma1DModelFallsBackForCvUbFusion) { | 682 | TEST_F(UTestAscirPerfV2, TestNddma1DModelFallsBackForCvUbFusion) { |
| 672 | const auto shape = Make1DNddmaShape("int8", 1, CreateExpr(256), CreateExpr(1), CreateExpr(1)); | 683 | const auto shape = Make1DNddmaShape("int8", 1, CreateExpr(256), CreateExpr(1), CreateExpr(1)); |
| 673 | const std::vector<TensorShapeInfo> shapes = {shape}; | 684 | const std::vector<TensorShapeInfo> shapes = {shape}; |
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | + | ||
| 16 | 17 | ||
| 17 | 18 | ||
| 18 | namespace att { | 19 | namespace att { |
| @@ -40,7 +41,7 @@ TEST(NddmaModelV2, EvaluatesStaticB8LowCoreFormula) { | |||
| 40 | 41 | ||
| 41 | ASSERT_EQ(EvaluateNddmaModel(descriptor, "uint8", CreateExpr(2), result), af::SUCCESS); | 42 | ASSERT_EQ(EvaluateNddmaModel(descriptor, "uint8", CreateExpr(2), result), af::SUCCESS); |
| 42 | ASSERT_TRUE(result.selected); | 43 | ASSERT_TRUE(result.selected); |
| 43 | - EXPECT_EQ(result.model_name, "NDDMA_1D_MULTICORE_V1"); | 44 | + EXPECT_EQ(result.model_name, "NDDMA_1D_MULTICORE_V2"); |
| 44 | EXPECT_EQ(result.fallback_reason, NddmaFallbackReason::kNone); | 45 | EXPECT_EQ(result.fallback_reason, NddmaFallbackReason::kNone); |
| 45 | EXPECT_TRUE(result.ternary_ops.empty()); | 46 | EXPECT_TRUE(result.ternary_ops.empty()); |
| 46 | EXPECT_NEAR(GetConstCycles(result.cycles), 219.37435914613698, 1e-6); | 47 | EXPECT_NEAR(GetConstCycles(result.cycles), 219.37435914613698, 1e-6); |
| @@ -52,8 +53,7 @@ TEST(NddmaModelV2, UsesMergedLowCoreCoefficientsForStridedOutput) { | |||
| 52 | 53 | ||
| 53 | ASSERT_EQ(EvaluateNddmaModel(descriptor, "uint8", CreateExpr(2), result), af::SUCCESS); | 54 | ASSERT_EQ(EvaluateNddmaModel(descriptor, "uint8", CreateExpr(2), result), af::SUCCESS); |
| 54 | ASSERT_TRUE(result.selected); | 55 | ASSERT_TRUE(result.selected); |
| 55 | - result.cycles.Simplify(); | 56 | + EXPECT_TRUE(result.cycles.IsValid()); |
| 56 | - EXPECT_NE(Str(result.cycles).find("6.998497418"), std::string::npos); | ||
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | TEST(NddmaModelV2, AllowsZeroInputStride) { | 59 | TEST(NddmaModelV2, AllowsZeroInputStride) { |
| @@ -71,7 +71,7 @@ TEST(NddmaModelV2, EvaluatesStaticB16HighCoreFormula) { | |||
| 71 | 71 | ||
| 72 | ASSERT_EQ(EvaluateNddmaModel(descriptor, "float16", CreateExpr(8), result), af::SUCCESS); | 72 | ASSERT_EQ(EvaluateNddmaModel(descriptor, "float16", CreateExpr(8), result), af::SUCCESS); |
| 73 | ASSERT_TRUE(result.selected); | 73 | ASSERT_TRUE(result.selected); |
| 74 | - EXPECT_NEAR(GetConstCycles(result.cycles), 3670.0883956043676, 1e-6); | 74 | + EXPECT_NEAR(GetConstCycles(result.cycles), 3667.5976503571769, 1e-6); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | TEST(NddmaModelV2, EvaluatesStaticB32LowCoreFormula) { | 77 | TEST(NddmaModelV2, EvaluatesStaticB32LowCoreFormula) { |
| @@ -80,7 +80,7 @@ TEST(NddmaModelV2, EvaluatesStaticB32LowCoreFormula) { | |||
| 80 | 80 | ||
| 81 | ASSERT_EQ(EvaluateNddmaModel(descriptor, "float32", CreateExpr(2), result), af::SUCCESS); | 81 | ASSERT_EQ(EvaluateNddmaModel(descriptor, "float32", CreateExpr(2), result), af::SUCCESS); |
| 82 | ASSERT_TRUE(result.selected); | 82 | ASSERT_TRUE(result.selected); |
| 83 | - EXPECT_NEAR(GetConstCycles(result.cycles), 418.8332396657097, 1e-6); | 83 | + EXPECT_NEAR(GetConstCycles(result.cycles), 415.93874765450965, 1e-6); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | TEST(NddmaModelV2, EvaluatesStaticB64HighCoreWithSaturatedInputStride) { | 86 | TEST(NddmaModelV2, EvaluatesStaticB64HighCoreWithSaturatedInputStride) { |
| @@ -89,7 +89,7 @@ TEST(NddmaModelV2, EvaluatesStaticB64HighCoreWithSaturatedInputStride) { | |||
| 89 | 89 | ||
| 90 | ASSERT_EQ(EvaluateNddmaModel(descriptor, "int64", CreateExpr(8), result), af::SUCCESS); | 90 | ASSERT_EQ(EvaluateNddmaModel(descriptor, "int64", CreateExpr(8), result), af::SUCCESS); |
| 91 | ASSERT_TRUE(result.selected); | 91 | ASSERT_TRUE(result.selected); |
| 92 | - EXPECT_NEAR(GetConstCycles(result.cycles), 1191.9782139196707, 1e-6); | 92 | + EXPECT_NEAR(GetConstCycles(result.cycles), 1490.6546508742531, 1e-6); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | TEST(NddmaModelV2, ReplaysAllCoefficientGroupsForFourDtypeSizes) { | 95 | TEST(NddmaModelV2, ReplaysAllCoefficientGroupsForFourDtypeSizes) { |
| @@ -98,10 +98,10 @@ TEST(NddmaModelV2, ReplaysAllCoefficientGroupsForFourDtypeSizes) { | |||
| 98 | double low_core; | 98 | double low_core; |
| 99 | double high_core; | 99 | double high_core; |
| 100 | }; | 100 | }; |
| 101 | - const DtypeCase cases[] = {{"int8", 1846.461366862137, 3651.7081836980888}, | 101 | + const DtypeCase cases[] = {{"int8", 1846.461366862137, 3651.7082163688292}, |
| 102 | - {"float16", 1853.918764807075, 3670.0883956043676}, | 102 | + {"float16", 1852.9241082038752, 3667.5976503571769}, |
| 103 | - {"float32", 418.8332396657097, 787.4986605915115}, | 103 | + {"float32", 415.93874765450965, 801.7379345551185}, |
| 104 | - {"int64", 457.66637430298624, 889.5759615048607}}; | 104 | + {"int64", 436.1371738143462, 834.9812022377600}}; |
| 105 | const auto descriptor = MakeDescriptor(CreateExpr(256), CreateExpr(4), CreateExpr(2)); | 105 | const auto descriptor = MakeDescriptor(CreateExpr(256), CreateExpr(4), CreateExpr(2)); |
| 106 | for (const auto &test_case : cases) { | 106 | for (const auto &test_case : cases) { |
| 107 | SCOPED_TRACE(test_case.dtype); | 107 | SCOPED_TRACE(test_case.dtype); |
| @@ -136,7 +136,7 @@ TEST(NddmaModelV2, RejectsMismatchedDescriptorSchema) { | |||
| 136 | EXPECT_STREQ(NddmaFallbackReasonToString(result.fallback_reason), "schema_mismatch"); | 136 | EXPECT_STREQ(NddmaFallbackReasonToString(result.fallback_reason), "schema_mismatch"); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | -TEST(NddmaModelV2, FallsBackForUnregisteredRanks2To5) { | 139 | +TEST(NddmaModelV2, EvaluatesRegisteredRanks2To5) { |
| 140 | for (size_t rank = 2U; rank <= 5U; ++rank) { | 140 | for (size_t rank = 2U; rank <= 5U; ++rank) { |
| 141 | SCOPED_TRACE(rank); | 141 | SCOPED_TRACE(rank); |
| 142 | NddmaDescriptorInfo descriptor; | 142 | NddmaDescriptorInfo descriptor; |
| @@ -149,13 +149,29 @@ TEST(NddmaModelV2, FallsBackForUnregisteredRanks2To5) { | |||
| 149 | NddmaModelResult result; | 149 | NddmaModelResult result; |
| 150 | 150 | ||
| 151 | ASSERT_EQ(EvaluateNddmaModel(descriptor, "int64", CreateExpr(1), result), af::SUCCESS); | 151 | ASSERT_EQ(EvaluateNddmaModel(descriptor, "int64", CreateExpr(1), result), af::SUCCESS); |
| 152 | - EXPECT_FALSE(result.selected); | 152 | + EXPECT_TRUE(result.selected); |
| 153 | - EXPECT_EQ(result.raw_rank, rank); | 153 | + EXPECT_EQ(result.raw_rank, 0U); |
| 154 | EXPECT_EQ(result.effective_rank, rank); | 154 | EXPECT_EQ(result.effective_rank, rank); |
| 155 | - EXPECT_EQ(result.fallback_reason, NddmaFallbackReason::kNoRegisteredModel); | 155 | + EXPECT_EQ(result.fallback_reason, NddmaFallbackReason::kNone); |
| 156 | + EXPECT_EQ(result.model_name, "NDDMA_ND_MULTICORE_V1"); | ||
| 156 | } | 157 | } |
| 157 | } | 158 | } |
| 158 | 159 | ||
| 160 | +TEST(NddmaModelV2, UsesInnerToOuterFormulaOrderForTwoDimensions) { | ||
| 161 | + NddmaDescriptorInfo descriptor; | ||
| 162 | + // Descriptor is effective outer -> inner; the formula must consume [inner, outer]. | ||
| 163 | + descriptor.output_dims = {CreateExpr(3), CreateExpr(8)}; | ||
| 164 | + descriptor.input_strides = {CreateExpr(8), CreateExpr(1)}; | ||
| 165 | + descriptor.output_strides = {CreateExpr(8), CreateExpr(1)}; | ||
| 166 | + descriptor.vectorized_axis = {1, 0}; | ||
| 167 | + NddmaModelResult result; | ||
| 168 | + ASSERT_EQ(EvaluateNddmaModel(descriptor, "float32", CreateExpr(2), result), af::SUCCESS); | ||
| 169 | + ASSERT_TRUE(result.selected); | ||
| 170 | + EXPECT_EQ(result.effective_rank, 2U); | ||
| 171 | + EXPECT_EQ(result.model_name, "NDDMA_ND_MULTICORE_V1"); | ||
| 172 | + EXPECT_TRUE(result.cycles.IsValid()); | ||
| 173 | +} | ||
| 174 | + | ||
| 159 | TEST(NddmaModelV2, RejectsNonPositiveStaticOutputStride) { | 175 | TEST(NddmaModelV2, RejectsNonPositiveStaticOutputStride) { |
| 160 | const auto descriptor = MakeDescriptor(CreateExpr(16), CreateExpr(1), CreateExpr(0)); | 176 | const auto descriptor = MakeDescriptor(CreateExpr(16), CreateExpr(1), CreateExpr(0)); |
| 161 | NddmaModelResult result; | 177 | NddmaModelResult result; |
| @@ -166,7 +182,7 @@ TEST(NddmaModelV2, RejectsNonPositiveStaticOutputStride) { | |||
| 166 | } | 182 | } |
| 167 | 183 | ||
| 168 | TEST(NddmaModelV2, RejectsRankOutsideSupportedRange) { | 184 | TEST(NddmaModelV2, RejectsRankOutsideSupportedRange) { |
| 169 | - for (const size_t rank : {0U, 6U}) { | 185 | + for (const size_t rank : {0U, 6U, 7U}) { |
| 170 | SCOPED_TRACE(rank); | 186 | SCOPED_TRACE(rank); |
| 171 | NddmaDescriptorInfo descriptor; | 187 | NddmaDescriptorInfo descriptor; |
| 172 | descriptor.output_dims.assign(rank, CreateExpr(8)); | 188 | descriptor.output_dims.assign(rank, CreateExpr(8)); |
| @@ -182,6 +198,16 @@ TEST(NddmaModelV2, RejectsRankOutsideSupportedRange) { | |||
| 182 | } | 198 | } |
| 183 | } | 199 | } |
| 184 | 200 | ||
| 201 | +TEST(NddmaModelV2, SharedDataCopyAxisRulesMatchCodegenConditions) { | ||
| 202 | + const std::vector<Expr> ub_strides = {CreateExpr(15), CreateExpr(5), CreateExpr(1)}; | ||
| 203 | + EXPECT_TRUE(ascgen_utils::ShouldIgnoreDataCopyZeroAxis(false, 0U, ub_strides)); | ||
| 204 | + EXPECT_TRUE(ascgen_utils::ShouldIgnoreDataCopyZeroAxis(true, 2U, ub_strides)); | ||
| 205 | + EXPECT_FALSE(ascgen_utils::ShouldIgnoreDataCopyZeroAxis(false, 2U, {CreateExpr(15), CreateExpr(5), CreateExpr(3)})); | ||
| 206 | + | ||
| 207 | + EXPECT_TRUE(ascgen_utils::IsDataCopyAxisContinuous(CreateExpr(5), CreateExpr(1), CreateExpr(5), CreateExpr(1))); | ||
| 208 | + EXPECT_FALSE(ascgen_utils::IsDataCopyAxisContinuous(CreateExpr(4), CreateExpr(1), CreateExpr(5), CreateExpr(1))); | ||
| 209 | +} | ||
| 210 | + | ||
| 185 | TEST(NddmaModelV2, RejectsUnsupportedDtype) { | 211 | TEST(NddmaModelV2, RejectsUnsupportedDtype) { |
| 186 | const auto descriptor = MakeDescriptor(CreateExpr(16), CreateExpr(1), CreateExpr(1)); | 212 | const auto descriptor = MakeDescriptor(CreateExpr(16), CreateExpr(1), CreateExpr(1)); |
| 187 | NddmaModelResult result; | 213 | NddmaModelResult result; |
| @@ -257,10 +283,10 @@ TEST(NddmaModelV2, BuildsDescriptorFromRawTensorShape) { | |||
| 257 | NddmaDescriptorInfo descriptor; | 283 | NddmaDescriptorInfo descriptor; |
| 258 | 284 | ||
| 259 | EXPECT_EQ(BuildNddmaDescriptor(shape_info, {3, 1}, descriptor), NddmaFallbackReason::kNone); | 285 | EXPECT_EQ(BuildNddmaDescriptor(shape_info, {3, 1}, descriptor), NddmaFallbackReason::kNone); |
| 260 | - EXPECT_EQ(descriptor.output_dims, shape_info.repeats); | 286 | + EXPECT_EQ(descriptor.output_dims, (std::vector<Expr>{CreateExpr(256)})); |
| 261 | - EXPECT_EQ(descriptor.input_strides, shape_info.gm_strides); | 287 | + EXPECT_EQ(descriptor.input_strides, (std::vector<Expr>{CreateExpr(2)})); |
| 262 | - EXPECT_EQ(descriptor.output_strides, shape_info.strides); | 288 | + EXPECT_EQ(descriptor.output_strides, (std::vector<Expr>{CreateExpr(1)})); |
| 263 | - EXPECT_EQ(descriptor.vectorized_axis, (std::vector<int64_t>{3, 1})); | 289 | + EXPECT_EQ(descriptor.vectorized_axis, (std::vector<int64_t>{1})); |
| 264 | } | 290 | } |
| 265 | 291 | ||
| 266 | TEST(NddmaModelV2, RejectsMissingVectorizedAxisForCodegenParity) { | 292 | TEST(NddmaModelV2, RejectsMissingVectorizedAxisForCodegenParity) { |
| @@ -40,7 +40,25 @@ af::Status TryNewNddmaModel(const TensorShapeInfo &shape_info, const NodeInfo &n | |||
| 40 | LogNddmaFallback(node_detail.name, shape_info.data_type, nullptr, result); | 40 | LogNddmaFallback(node_detail.name, shape_info.data_type, nullptr, result); |
| 41 | return af::SUCCESS; | 41 | return af::SUCCESS; |
| 42 | } | 42 | } |
| 43 | - const auto build_reason = BuildNddmaDescriptor(shape_info, GetNddmaVectorizedAxis(node.node_ptr), descriptor); | 43 | + uint64_t expected_dtype_size = 0U; |
| 44 | + const auto dtype_iter = kDataTypeSizeMap.find(shape_info.data_type); | ||
| 45 | + if (dtype_iter == kDataTypeSizeMap.end() || !dtype_iter->second.GetConstValue(expected_dtype_size) || | ||
| 46 | + expected_dtype_size == 0U || expected_dtype_size != shape_info.data_type_size) { | ||
| 47 | + result.raw_rank = shape_info.repeats.size(); | ||
| 48 | + result.fallback_reason = NddmaFallbackReason::kDtypeUnsupported; | ||
| 49 | + LogNddmaFallback(node_detail.name, shape_info.data_type, nullptr, result); | ||
| 50 | + return af::SUCCESS; | ||
| 51 | + } | ||
| 52 | + std::vector<bool> tile_inner; | ||
| 53 | + if (!node.outputs.empty() && node.outputs[0] != nullptr && | ||
| 54 | + node.outputs[0]->dim_info.size() == shape_info.repeats.size()) { | ||
| 55 | + tile_inner.reserve(node.outputs[0]->dim_info.size()); | ||
| 56 | + for (const auto *axis : node.outputs[0]->dim_info) { | ||
| 57 | + tile_inner.push_back(axis != nullptr && axis->axis_type == AxisPosition::INNER && !axis->is_bind_multi_core); | ||
| 58 | + } | ||
| 59 | + } | ||
| 60 | + const auto build_reason = | ||
| 61 | + BuildNddmaDescriptor(shape_info, GetNddmaVectorizedAxis(node.node_ptr), descriptor, tile_inner); | ||
| 44 | if (build_reason != NddmaFallbackReason::kNone) { | 62 | if (build_reason != NddmaFallbackReason::kNone) { |
| 45 | result.raw_rank = shape_info.repeats.size(); | 63 | result.raw_rank = shape_info.repeats.size(); |
| 46 | result.fallback_reason = build_reason; | 64 | result.fallback_reason = build_reason; |
| @@ -49,6 +67,7 @@ af::Status TryNewNddmaModel(const TensorShapeInfo &shape_info, const NodeInfo &n | |||
| 49 | } | 67 | } |
| 50 | node_detail.nddma_descriptor = descriptor; | 68 | node_detail.nddma_descriptor = descriptor; |
| 51 | GE_ASSERT_SUCCESS(EvaluateNddmaModel(descriptor, shape_info.data_type, CreateExpr("block_dim"), result)); | 69 | GE_ASSERT_SUCCESS(EvaluateNddmaModel(descriptor, shape_info.data_type, CreateExpr("block_dim"), result)); |
| 70 | + result.raw_rank = shape_info.repeats.size(); | ||
| 52 | if (!result.selected) { | 71 | if (!result.selected) { |
| 53 | LogNddmaFallback(node_detail.name, shape_info.data_type, &descriptor, result); | 72 | LogNddmaFallback(node_detail.name, shape_info.data_type, &descriptor, result); |
| 54 | return af::SUCCESS; | 73 | return af::SUCCESS; |
| @@ -23,51 +23,27 @@ constexpr size_t kMaxNddmaRank = 5U; | |||
| 23 | constexpr uint64_t kLowCoreUpperBound = 2U; | 23 | constexpr uint64_t kLowCoreUpperBound = 2U; |
| 24 | constexpr uint64_t kInputStrideUpperBound = 128U; | 24 | constexpr uint64_t kInputStrideUpperBound = 128U; |
| 25 | 25 | ||
| 26 | -// 合并模型直接表示最终多项式,避免运行时重新组合 NG、NGM 和 rho。 | ||
| 27 | -struct NddmaLowCoreParams { | ||
| 28 | - double constant; | ||
| 29 | - double bytes; | ||
| 30 | - double stride; | ||
| 31 | - double bytes_stride; | ||
| 32 | -}; | ||
| 33 | - | ||
| 34 | -struct NddmaHighCoreParams { | ||
| 35 | - double constant; | ||
| 36 | - double stride; | ||
| 37 | - double stride_square; | ||
| 38 | - double bytes; | ||
| 39 | - double bytes_stride; | ||
| 40 | - double bytes_stride_square; | ||
| 41 | -}; | ||
| 42 | - | ||
| 43 | struct Nddma1DParams { | 26 | struct Nddma1DParams { |
| 44 | - NddmaLowCoreParams low_os_one; | 27 | + double t1; |
| 45 | - NddmaLowCoreParams low_os_ge_two; | 28 | + double h1; |
| 46 | - NddmaHighCoreParams high_os_one; | 29 | + double t2; |
| 47 | - NddmaHighCoreParams high_os_ge_two; | 30 | + double h2; |
| 31 | + double a1, a2, b1, b2, b3, b4, c1, c2, c3, c4; | ||
| 48 | }; | 32 | }; |
| 49 | 33 | ||
| 50 | const Nddma1DParams *GetNddma1DParams(uint64_t dtype_size) { | 34 | const Nddma1DParams *GetNddma1DParams(uint64_t dtype_size) { |
| 51 | - static constexpr Nddma1DParams kB8 = { | 35 | + static constexpr Nddma1DParams kB8 = {11.7626, 194.421, 6.05735, 373.274, 1.1117457, |
| 52 | - {194.421, 0.08501521772, 1.1117457, 0.0081160848}, | 36 | + 0.0081160848, -140.60967, -0.85102455, 6.9134822, -0.0081240796, |
| 53 | - {53.81133, 6.998497418, 0.26072115, -0.0000079948}, | 37 | + 1.5052979, 0.007823918, 0.47972982, -0.0078196972}; |
| 54 | - {373.274, 1.673508468, 0.008698207194, 0.1650886939, 0.01221712541, 0.00006349958196}, | 38 | + static constexpr Nddma1DParams kB16 = {25.7579, 204.604, 13.259, 399.909, 0.93077499, |
| 55 | - {94.1599102, 0.5169452208, 0.000001100449223, 13.88854236, 0.00001331045708, -0.00000000003374437189}}; | 39 | + 0.0041300563, -144.93927, -0.65222426, 3.4593577, -0.0041392279, |
| 56 | - static constexpr Nddma1DParams kB16 = { | 40 | + 1.1389125, 0.015061621, 0.84385983, -0.015043028}; |
| 57 | - {204.604, 0.0388230407, 0.96094416, 0.0091341897}, | 41 | + static constexpr Nddma1DParams kB32 = {57.2624, 235.137, 29.4096, 453.859, 0.29118972, |
| 58 | - {61.53027, 3.498120341, 0.34357215, -0.0000114298}, | 42 | + 0.0021022688, -75.847618, -0.098291434, 0.23017978, -0.0021037148, |
| 59 | - {399.909, 2.009597249, -0.007116959052, 0.07542046912, 0.01910209069, -0.00006764977277}, | 43 | + 1.5982043, 0.0048954057, 0.21802244, 0.0016884734}; |
| 60 | - {116.1609008, 0.6810487439, 0.0000008016156689, 6.936002307, -0.00001459675784, -0.00000000002666778076}}; | 44 | + static constexpr Nddma1DParams kB64 = {57.2346, 243.205, 29.3906, 468.971, 0.32660604, |
| 61 | - static constexpr Nddma1DParams kB32 = { | 45 | + 0.00087486841, -62.346718, -0.089369196, 0.10364992, -0.00088051835, |
| 62 | - {235.137, 0.01746346643, 0.3675047, 0.0058486918}, | 46 | + 0.75774914, 0.021509891, 1.1274142, -0.021494907}; |
| 63 | - {158.723147, 0.2427621164, 1.4596785, 0.0013874442}, | ||
| 64 | - {453.859, 1.420515439, -0.008545279188, 0.03400250258, 0.02260694081, -0.0001359947351}, | ||
| 65 | - {323.0812754, 0.7652737348, 0.03310192195, 0.4195876242, 0.007483747325, 0.00003146382551}}; | ||
| 66 | - static constexpr Nddma1DParams kB64 = { | ||
| 67 | - {243.205, 0.01747194879, 0.90051511, 0.0030237371}, | ||
| 68 | - {189.027128, 0.1244607288, 1.98330501, 0.0007092839}, | ||
| 69 | - {468.971, 3.366949543, -0.02124182228, 0.03402448402, 0.0113054963, -0.00007132549515}, | ||
| 70 | - {361.5012267, 4.200466405, -0.009748131943, 0.2462524565, 0.0008811088948, -0.000003486197538}}; | ||
| 71 | switch (dtype_size) { | 47 | switch (dtype_size) { |
| 72 | case 1U: | 48 | case 1U: |
| 73 | return &kB8; | 49 | return &kB8; |
| @@ -143,43 +119,97 @@ bool HasStaticByteCountOverflow(const Expr &dim, uint64_t dtype_size) { | |||
| 143 | return static_cast<uint64_t>(dim_value) > std::numeric_limits<uint64_t>::max() / dtype_size; | 119 | return static_cast<uint64_t>(dim_value) > std::numeric_limits<uint64_t>::max() / dtype_size; |
| 144 | } | 120 | } |
| 145 | 121 | ||
| 146 | -Expr BuildLowCore(const NddmaLowCoreParams ¶ms, const Expr &bytes, const Expr &stride) { | 122 | +NddmaFallbackReason ValidateNddmaDescriptorInput(const TensorShapeInfo &shape_info, |
| 147 | - return CreateExpr(params.constant) + CreateExpr(params.bytes) * bytes + CreateExpr(params.stride) * stride + | 123 | + const std::vector<int64_t> &vectorized_axis, |
| 148 | - CreateExpr(params.bytes_stride) * bytes * stride; | 124 | + const std::vector<bool> &tile_inner) { |
| 149 | -} | 125 | + if (shape_info.repeats.empty()) { |
| 150 | - | 126 | + return NddmaFallbackReason::kNoDescriptor; |
| 151 | -Expr BuildHighCore(const NddmaHighCoreParams ¶ms, const Expr &bytes, const Expr &stride) { | ||
| 152 | - const Expr stride_square = stride * stride; | ||
| 153 | - return CreateExpr(params.constant) + CreateExpr(params.stride) * stride + | ||
| 154 | - CreateExpr(params.stride_square) * stride_square + | ||
| 155 | - bytes * (CreateExpr(params.bytes) + CreateExpr(params.bytes_stride) * stride + | ||
| 156 | - CreateExpr(params.bytes_stride_square) * stride_square); | ||
| 157 | -} | ||
| 158 | - | ||
| 159 | -Expr SelectOutputStrideModel(const Expr &output_stride, const Expr &os_one, const Expr &os_ge_two) { | ||
| 160 | - if (output_stride.IsConstExpr()) { | ||
| 161 | - if (af::SymbolicUtils::StaticCheckEq(output_stride, af::sym::kSymbolOne) == af::TriBool::kTrue) { | ||
| 162 | - return os_one; | ||
| 163 | - } | ||
| 164 | - if (af::SymbolicUtils::StaticCheckGt(output_stride, af::sym::kSymbolOne) == af::TriBool::kTrue) { | ||
| 165 | - return os_ge_two; | ||
| 166 | - } | ||
| 167 | } | 127 | } |
| 168 | - const Expr output_stride_gate = | 128 | + if (shape_info.repeats.size() != shape_info.gm_strides.size() || |
| 169 | - af::sym::Max(af::sym::kSymbolZero, af::sym::Min(af::sym::kSymbolOne, output_stride - af::sym::kSymbolOne)); | 129 | + shape_info.repeats.size() != shape_info.strides.size()) { |
| 170 | - return os_one + output_stride_gate * (os_ge_two - os_one); | 130 | + return NddmaFallbackReason::kSchemaMismatch; |
| 131 | + } | ||
| 132 | + if (vectorized_axis.empty() || vectorized_axis.size() != shape_info.repeats.size()) { | ||
| 133 | + return NddmaFallbackReason::kCodegenMismatch; | ||
| 134 | + } | ||
| 135 | + if (!tile_inner.empty() && tile_inner.size() != shape_info.repeats.size()) { | ||
| 136 | + return NddmaFallbackReason::kSchemaMismatch; | ||
| 137 | + } | ||
| 138 | + return NddmaFallbackReason::kNone; | ||
| 171 | } | 139 | } |
| 172 | 140 | ||
| 173 | -void BuildNddma1DBranches(const NddmaNormalizedDesc &descriptor, uint64_t dtype_size, const Nddma1DParams ¶ms, | 141 | +void BuildNddmaEffectiveView(const TensorShapeInfo &shape_info, const std::vector<bool> &tile_inner, |
| 174 | - Expr &low_core, Expr &high_core) { | 142 | + std::vector<Expr> &effective_repeats, std::vector<Expr> &effective_gm_strides, |
| 175 | - const Expr bytes = descriptor.output_dims[0] * CreateExpr(dtype_size); | 143 | + std::vector<Expr> &effective_ub_strides, std::vector<int64_t> &effective_axes) { |
| 176 | - const Expr input_stride = af::sym::Min(CreateExpr(kInputStrideUpperBound), descriptor.input_strides[0]); | 144 | + const auto &origin_repeats = |
| 177 | - const Expr low_os_one = BuildLowCore(params.low_os_one, bytes, input_stride); | 145 | + shape_info.origin_repeats.size() == shape_info.repeats.size() ? shape_info.origin_repeats : shape_info.repeats; |
| 178 | - const Expr low_os_ge_two = BuildLowCore(params.low_os_ge_two, bytes, input_stride); | 146 | + const size_t rank = origin_repeats.size(); |
| 179 | - const Expr high_os_one = BuildHighCore(params.high_os_one, bytes, input_stride); | 147 | + Expr prev_repeat = CreateExpr(1); |
| 180 | - const Expr high_os_ge_two = BuildHighCore(params.high_os_ge_two, bytes, input_stride); | 148 | + Expr prev_actual_repeat = CreateExpr(1); |
| 181 | - low_core = SelectOutputStrideModel(descriptor.output_strides[0], low_os_one, low_os_ge_two); | 149 | + Expr prev_gm_stride = CreateExpr(1); |
| 182 | - high_core = SelectOutputStrideModel(descriptor.output_strides[0], high_os_one, high_os_ge_two); | 150 | + Expr prev_ub_stride = CreateExpr(1); |
| 151 | + bool has_non_zero_axis = false; | ||
| 152 | + for (size_t pos = rank; pos-- > 0U;) { | ||
| 153 | + const bool ignore_zero_axis = | ||
| 154 | + ascgen_utils::ShouldIgnoreDataCopyZeroAxis(has_non_zero_axis, pos, shape_info.strides); | ||
| 155 | + const bool zero_axis = | ||
| 156 | + af::SymbolicUtils::StaticCheckEq(shape_info.gm_strides[pos], CreateExpr(0)) == af::TriBool::kTrue && | ||
| 157 | + af::SymbolicUtils::StaticCheckEq(shape_info.strides[pos], CreateExpr(0)) == af::TriBool::kTrue && | ||
| 158 | + ignore_zero_axis; | ||
| 159 | + if (zero_axis) { | ||
| 160 | + continue; | ||
| 161 | + } | ||
| 162 | + has_non_zero_axis = true; | ||
| 163 | + const Expr cur_gm_stride = prev_gm_stride * prev_repeat; | ||
| 164 | + const Expr cur_ub_stride = prev_ub_stride * prev_repeat; | ||
| 165 | + const bool tile_boundary = !tile_inner.empty() && pos + 1U < rank && tile_inner[pos + 1U]; | ||
| 166 | + if (!ascgen_utils::IsDataCopyAxisContinuous(cur_gm_stride, cur_ub_stride, shape_info.gm_strides[pos], | ||
| 167 | + shape_info.strides[pos]) || | ||
| 168 | + effective_repeats.empty() || tile_boundary) { | ||
| 169 | + effective_repeats.emplace_back(shape_info.repeats[pos]); | ||
| 170 | + effective_gm_strides.emplace_back(shape_info.gm_strides[pos]); | ||
| 171 | + effective_ub_strides.emplace_back(shape_info.strides[pos]); | ||
| 172 | + effective_axes.emplace_back(static_cast<int64_t>(pos)); | ||
| 173 | + prev_gm_stride = shape_info.gm_strides[pos]; | ||
| 174 | + prev_ub_stride = shape_info.strides[pos]; | ||
| 175 | + prev_repeat = origin_repeats[pos]; | ||
| 176 | + prev_actual_repeat = shape_info.repeats[pos]; | ||
| 177 | + continue; | ||
| 178 | + } | ||
| 179 | + const Expr product = origin_repeats[pos] * prev_repeat; | ||
| 180 | + effective_repeats.back() = shape_info.repeats[pos] * prev_actual_repeat; | ||
| 181 | + prev_repeat = product; | ||
| 182 | + prev_actual_repeat = shape_info.repeats[pos] * prev_actual_repeat; | ||
| 183 | + } | ||
| 184 | + std::reverse(effective_repeats.begin(), effective_repeats.end()); | ||
| 185 | + std::reverse(effective_gm_strides.begin(), effective_gm_strides.end()); | ||
| 186 | + std::reverse(effective_ub_strides.begin(), effective_ub_strides.end()); | ||
| 187 | + std::reverse(effective_axes.begin(), effective_axes.end()); | ||
| 188 | +} | ||
| 189 | + | ||
| 190 | +NddmaFallbackReason MapNddmaEffectiveAxes(std::vector<int64_t> &effective_axes, | ||
| 191 | + const std::vector<int64_t> &vectorized_axis) { | ||
| 192 | + for (auto &axis : effective_axes) { | ||
| 193 | + if (axis < 0 || static_cast<size_t>(axis) >= vectorized_axis.size()) { | ||
| 194 | + return NddmaFallbackReason::kCodegenMismatch; | ||
| 195 | + } | ||
| 196 | + axis = vectorized_axis[static_cast<size_t>(axis)]; | ||
| 197 | + } | ||
| 198 | + return NddmaFallbackReason::kNone; | ||
| 199 | +} | ||
| 200 | + | ||
| 201 | +Expr AbsExpr(const Expr &value) { | ||
| 202 | + return af::sym::Max(value, af::sym::kSymbolZero - value); | ||
| 203 | +} | ||
| 204 | + | ||
| 205 | +Expr BuildNddma1DResidual(const Nddma1DParams &p, const Expr &bytes, const Expr &input_stride, | ||
| 206 | + const Expr &output_stride, uint64_t dtype_size, bool high_core) { | ||
| 207 | + const Expr s = af::sym::Min(CreateExpr(kInputStrideUpperBound), input_stride * CreateExpr(dtype_size)); | ||
| 208 | + const Expr g = af::sym::Min(af::sym::kSymbolOne, output_stride - af::sym::kSymbolOne); | ||
| 209 | + const Expr ng = (CreateExpr(p.a1) + CreateExpr(p.a2) * bytes) * s; | ||
| 210 | + const Expr ngu = (CreateExpr(p.b1) + CreateExpr(p.b2) * s + (CreateExpr(p.b3) + CreateExpr(p.b4) * s) * bytes) * g; | ||
| 211 | + const Expr rho = CreateExpr(p.c1) + CreateExpr(p.c2) * s + g * (CreateExpr(p.c3) + CreateExpr(p.c4) * s); | ||
| 212 | + return (ng + ngu) * (high_core ? rho : CreateExpr(1)); | ||
| 183 | } | 213 | } |
| 184 | 214 | ||
| 185 | af::Status SelectCoreBranch(const Expr &block_dim, const Expr &low_core, const Expr &high_core, | 215 | af::Status SelectCoreBranch(const Expr &block_dim, const Expr &low_core, const Expr &high_core, |
| @@ -203,6 +233,42 @@ af::Status SelectCoreBranch(const Expr &block_dim, const Expr &low_core, const E | |||
| 203 | result.ternary_ops[result.cycles] = std::move(ternary); | 233 | result.ternary_ops[result.cycles] = std::move(ternary); |
| 204 | return af::SUCCESS; | 234 | return af::SUCCESS; |
| 205 | } | 235 | } |
| 236 | + | ||
| 237 | +NddmaFallbackReason BuildNddmaCoreCycles(const NddmaNormalizedDesc &normalized, const Nddma1DParams ¶ms, | ||
| 238 | + uint64_t dtype_size, Expr &low_core, Expr &high_core) { | ||
| 239 | + Expr total_elements = CreateExpr(1); | ||
| 240 | + for (const auto &dim : normalized.output_dims) { | ||
| 241 | + total_elements = total_elements * dim; | ||
| 242 | + } | ||
| 243 | + if (HasStaticByteCountOverflow(total_elements, dtype_size)) { | ||
| 244 | + return NddmaFallbackReason::kSchemaMismatch; | ||
| 245 | + } | ||
| 246 | + const Expr total_bytes = total_elements * CreateExpr(dtype_size); | ||
| 247 | + low_core = total_bytes / CreateExpr(params.t1) + CreateExpr(params.h1); | ||
| 248 | + high_core = total_bytes / CreateExpr(params.t2) + CreateExpr(params.h2); | ||
| 249 | + Expr input_prefix = CreateExpr(0); | ||
| 250 | + Expr output_prefix = CreateExpr(0); | ||
| 251 | + for (size_t i = 0; i < normalized.effective_rank; ++i) { | ||
| 252 | + if (i > 0U) { | ||
| 253 | + input_prefix = input_prefix + normalized.output_dims[i - 1U] * normalized.input_strides[i - 1U]; | ||
| 254 | + output_prefix = output_prefix + normalized.output_dims[i - 1U] * normalized.output_strides[i - 1U]; | ||
| 255 | + } | ||
| 256 | + Expr input_stride = normalized.input_strides[i]; | ||
| 257 | + Expr output_stride = normalized.output_strides[i]; | ||
| 258 | + if (i > 0U) { | ||
| 259 | + input_stride = AbsExpr(input_stride - input_prefix) + CreateExpr(1); | ||
| 260 | + output_stride = AbsExpr(output_stride - output_prefix) + CreateExpr(1); | ||
| 261 | + } | ||
| 262 | + Expr suffix_elements = CreateExpr(1); | ||
| 263 | + for (size_t suffix = i; suffix < normalized.effective_rank; ++suffix) { | ||
| 264 | + suffix_elements = suffix_elements * normalized.output_dims[suffix]; | ||
| 265 | + } | ||
| 266 | + const Expr bytes = suffix_elements * CreateExpr(dtype_size); | ||
| 267 | + low_core = low_core + BuildNddma1DResidual(params, bytes, input_stride, output_stride, dtype_size, false); | ||
| 268 | + high_core = high_core + BuildNddma1DResidual(params, bytes, input_stride, output_stride, dtype_size, true); | ||
| 269 | + } | ||
| 270 | + return NddmaFallbackReason::kNone; | ||
| 271 | +} | ||
| 206 | } // namespace | 272 | } // namespace |
| 207 | 273 | ||
| 208 | const char *NddmaFallbackReasonToString(NddmaFallbackReason reason) { | 274 | const char *NddmaFallbackReasonToString(NddmaFallbackReason reason) { |
| @@ -214,30 +280,39 @@ const char *NddmaFallbackReasonToString(NddmaFallbackReason reason) { | |||
| 214 | } | 280 | } |
| 215 | 281 | ||
| 216 | NddmaFallbackReason BuildNddmaDescriptor(const TensorShapeInfo &shape_info, const std::vector<int64_t> &vectorized_axis, | 282 | NddmaFallbackReason BuildNddmaDescriptor(const TensorShapeInfo &shape_info, const std::vector<int64_t> &vectorized_axis, |
| 217 | - NddmaDescriptorInfo &descriptor) { | 283 | + NddmaDescriptorInfo &descriptor, const std::vector<bool> &tile_inner) { |
| 218 | descriptor = NddmaDescriptorInfo{}; | 284 | descriptor = NddmaDescriptorInfo{}; |
| 219 | - if (shape_info.repeats.empty()) { | 285 | + const auto input_reason = ValidateNddmaDescriptorInput(shape_info, vectorized_axis, tile_inner); |
| 220 | - return NddmaFallbackReason::kNoDescriptor; | 286 | + if (input_reason != NddmaFallbackReason::kNone) { |
| 287 | + return input_reason; | ||
| 221 | } | 288 | } |
| 222 | - if (shape_info.repeats.size() != shape_info.gm_strides.size() || | 289 | + std::vector<Expr> effective_repeats; |
| 223 | - shape_info.repeats.size() != shape_info.strides.size()) { | 290 | + std::vector<Expr> effective_gm_strides; |
| 224 | - return NddmaFallbackReason::kSchemaMismatch; | 291 | + std::vector<Expr> effective_ub_strides; |
| 292 | + std::vector<int64_t> effective_axes; | ||
| 293 | + BuildNddmaEffectiveView(shape_info, tile_inner, effective_repeats, effective_gm_strides, effective_ub_strides, | ||
| 294 | + effective_axes); | ||
| 295 | + const auto axis_reason = MapNddmaEffectiveAxes(effective_axes, vectorized_axis); | ||
| 296 | + if (axis_reason != NddmaFallbackReason::kNone) { | ||
| 297 | + return axis_reason; | ||
| 225 | } | 298 | } |
| 226 | - descriptor.output_dims = shape_info.repeats; | 299 | + descriptor.output_dims = std::move(effective_repeats); |
| 227 | - descriptor.input_strides = shape_info.gm_strides; | 300 | + descriptor.input_strides = std::move(effective_gm_strides); |
| 228 | - descriptor.output_strides = shape_info.strides; | 301 | + descriptor.output_strides = std::move(effective_ub_strides); |
| 229 | - if (vectorized_axis.empty()) { | 302 | + descriptor.vectorized_axis = std::move(effective_axes); |
| 230 | - return NddmaFallbackReason::kCodegenMismatch; | 303 | + GELOGD( |
| 231 | - } | 304 | + "[ATT NDDMA] effective view: raw_rank=%zu, effective_rank=%zu, repeats=[%s], gm_strides=[%s], ub_strides=[%s], " |
| 232 | - descriptor.vectorized_axis = vectorized_axis; | 305 | + "axes=[%s]", |
| 306 | + shape_info.repeats.size(), descriptor.output_dims.size(), GetVecString(descriptor.output_dims).c_str(), | ||
| 307 | + GetVecString(descriptor.input_strides).c_str(), GetVecString(descriptor.output_strides).c_str(), | ||
| 308 | + ascgen_utils::VectorToStr(descriptor.vectorized_axis).c_str()); | ||
| 233 | return NddmaFallbackReason::kNone; | 309 | return NddmaFallbackReason::kNone; |
| 234 | } | 310 | } |
| 235 | 311 | ||
| 236 | NddmaFallbackReason NormalizeNddmaDescriptor(const NddmaDescriptorInfo &descriptor, NddmaNormalizedDesc &normalized) { | 312 | NddmaFallbackReason NormalizeNddmaDescriptor(const NddmaDescriptorInfo &descriptor, NddmaNormalizedDesc &normalized) { |
| 237 | normalized = NddmaNormalizedDesc{}; | 313 | normalized = NddmaNormalizedDesc{}; |
| 238 | - normalized.raw_rank = descriptor.output_dims.size(); | 314 | + normalized.effective_rank = descriptor.output_dims.size(); |
| 239 | - normalized.effective_rank = normalized.raw_rank; | 315 | + if (normalized.effective_rank < kMinNddmaRank || normalized.effective_rank > kMaxNddmaRank) { |
| 240 | - if (normalized.raw_rank < kMinNddmaRank || normalized.raw_rank > kMaxNddmaRank) { | ||
| 241 | return NddmaFallbackReason::kRankUnsupported; | 316 | return NddmaFallbackReason::kRankUnsupported; |
| 242 | } | 317 | } |
| 243 | if (!HasValidVectorLengths(descriptor)) { | 318 | if (!HasValidVectorLengths(descriptor)) { |
| @@ -246,10 +321,10 @@ NddmaFallbackReason NormalizeNddmaDescriptor(const NddmaDescriptorInfo &descript | |||
| 246 | if (!HasValidAxisOrder(descriptor)) { | 321 | if (!HasValidAxisOrder(descriptor)) { |
| 247 | return NddmaFallbackReason::kCodegenMismatch; | 322 | return NddmaFallbackReason::kCodegenMismatch; |
| 248 | } | 323 | } |
| 249 | - normalized.output_dims = descriptor.output_dims; | 324 | + normalized.output_dims.assign(descriptor.output_dims.rbegin(), descriptor.output_dims.rend()); |
| 250 | - normalized.input_strides = descriptor.input_strides; | 325 | + normalized.input_strides.assign(descriptor.input_strides.rbegin(), descriptor.input_strides.rend()); |
| 251 | - normalized.output_strides = descriptor.output_strides; | 326 | + normalized.output_strides.assign(descriptor.output_strides.rbegin(), descriptor.output_strides.rend()); |
| 252 | - normalized.vectorized_axis = descriptor.vectorized_axis; | 327 | + normalized.vectorized_axis.assign(descriptor.vectorized_axis.rbegin(), descriptor.vectorized_axis.rend()); |
| 253 | return HasInvalidStaticValue(normalized) ? NddmaFallbackReason::kStrideInvalid : NddmaFallbackReason::kNone; | 328 | return HasInvalidStaticValue(normalized) ? NddmaFallbackReason::kStrideInvalid : NddmaFallbackReason::kNone; |
| 254 | } | 329 | } |
| 255 | 330 | ||
| @@ -258,12 +333,11 @@ af::Status EvaluateNddmaModel(const NddmaDescriptorInfo &descriptor, const std:: | |||
| 258 | result = NddmaModelResult{}; | 333 | result = NddmaModelResult{}; |
| 259 | NddmaNormalizedDesc normalized; | 334 | NddmaNormalizedDesc normalized; |
| 260 | result.fallback_reason = NormalizeNddmaDescriptor(descriptor, normalized); | 335 | result.fallback_reason = NormalizeNddmaDescriptor(descriptor, normalized); |
| 261 | - result.raw_rank = normalized.raw_rank; | ||
| 262 | result.effective_rank = normalized.effective_rank; | 336 | result.effective_rank = normalized.effective_rank; |
| 263 | if (result.fallback_reason != NddmaFallbackReason::kNone) { | 337 | if (result.fallback_reason != NddmaFallbackReason::kNone) { |
| 264 | return af::SUCCESS; | 338 | return af::SUCCESS; |
| 265 | } | 339 | } |
| 266 | - if (normalized.raw_rank != 1U || normalized.effective_rank != 1U) { | 340 | + if (normalized.effective_rank < kMinNddmaRank || normalized.effective_rank > kMaxNddmaRank) { |
| 267 | result.fallback_reason = NddmaFallbackReason::kNoRegisteredModel; | 341 | result.fallback_reason = NddmaFallbackReason::kNoRegisteredModel; |
| 268 | return af::SUCCESS; | 342 | return af::SUCCESS; |
| 269 | } | 343 | } |
| @@ -278,15 +352,23 @@ af::Status EvaluateNddmaModel(const NddmaDescriptorInfo &descriptor, const std:: | |||
| 278 | params == nullptr ? NddmaFallbackReason::kDtypeUnsupported : NddmaFallbackReason::kSchemaMismatch; | 352 | params == nullptr ? NddmaFallbackReason::kDtypeUnsupported : NddmaFallbackReason::kSchemaMismatch; |
| 279 | return af::SUCCESS; | 353 | return af::SUCCESS; |
| 280 | } | 354 | } |
| 281 | - if (HasStaticByteCountOverflow(normalized.output_dims[0], dtype_size)) { | 355 | + Expr low_core; |
| 356 | + Expr high_core; | ||
| 357 | + result.fallback_reason = BuildNddmaCoreCycles(normalized, *params, dtype_size, low_core, high_core); | ||
| 358 | + if (result.fallback_reason != NddmaFallbackReason::kNone) { | ||
| 359 | + return af::SUCCESS; | ||
| 360 | + } | ||
| 361 | + GE_ASSERT_SUCCESS(SelectCoreBranch(block_dim, low_core, high_core, result)); | ||
| 362 | + // Fitted residual terms can become non-positive outside their measured | ||
| 363 | + // domain (for example, tiny B with a large effective stride). Do not emit | ||
| 364 | + // an invalid performance expression; use the existing legacy path instead. | ||
| 365 | + if (IsStaticNonPositive(result.cycles)) { | ||
| 366 | + result.selected = false; | ||
| 282 | result.fallback_reason = NddmaFallbackReason::kSchemaMismatch; | 367 | result.fallback_reason = NddmaFallbackReason::kSchemaMismatch; |
| 283 | return af::SUCCESS; | 368 | return af::SUCCESS; |
| 284 | } | 369 | } |
| 285 | - Expr low_core; | ||
| 286 | - Expr high_core; | ||
| 287 | - BuildNddma1DBranches(normalized, dtype_size, *params, low_core, high_core); | ||
| 288 | - GE_ASSERT_SUCCESS(SelectCoreBranch(block_dim, low_core, high_core, result)); | ||
| 289 | result.selected = true; | 370 | result.selected = true; |
| 371 | + result.model_name = normalized.effective_rank == 1U ? "NDDMA_1D_MULTICORE_V2" : "NDDMA_ND_MULTICORE_V1"; | ||
| 290 | result.fallback_reason = NddmaFallbackReason::kNone; | 372 | result.fallback_reason = NddmaFallbackReason::kNone; |
| 291 | return af::SUCCESS; | 373 | return af::SUCCESS; |
| 292 | } | 374 | } |
| @@ -18,8 +18,7 @@ namespace att { | |||
| 18 | * @brief NDDMA 精确性能模型的组成和计算原理。 | 18 | * @brief NDDMA 精确性能模型的组成和计算原理。 |
| 19 | * | 19 | * |
| 20 | * 当前范围: | 20 | * 当前范围: |
| 21 | - * - 只注册 NDDMA_1D_MULTICORE_V1,覆盖默认 Codegen 路径下 raw rank=1、effective rank=1 的搬运。 | 21 | + * - 注册 NDDMA_1D_MULTICORE_V2(effective rank=1)和 NDDMA_ND_MULTICORE_V1(effective rank=2~5)。 |
| 22 | - * - raw rank=2~5 暂无正式模型,保留完整 descriptor 后回退 legacy NDDMA 模型;不会因连续轴合并而伪装成 1D。 | ||
| 23 | * - kUBFuse Codegen 使用 {curAivM, curAlignN} 和固定 2D stride,与 raw descriptor 不等价,因此通过 | 22 | * - kUBFuse Codegen 使用 {curAivM, curAlignN} 和固定 2D stride,与 raw descriptor 不等价,因此通过 |
| 24 | * NodeInfo::is_cv_ub_fusion 门禁回退 legacy 模型。 | 23 | * NodeInfo::is_cv_ub_fusion 门禁回退 legacy 模型。 |
| 25 | * | 24 | * |
| @@ -30,44 +29,50 @@ namespace att { | |||
| 30 | * - AscTensorAttr::vectorized_axis -> descriptor 轴序; | 29 | * - AscTensorAttr::vectorized_axis -> descriptor 轴序; |
| 31 | * - dtype -> dtype_size,并选择 B8/B16/B32/B64 参数; | 30 | * - dtype -> dtype_size,并选择 B8/B16/B32/B64 参数; |
| 32 | * - block_dim -> 参与搬运的核数。 | 31 | * - block_dim -> 参与搬运的核数。 |
| 33 | - * 三组向量均为 legacy 连续轴合并前的原始值,顺序与 vectorized_axis 一致,stride 单位均为元素。 | 32 | + * 三组向量表示 codegen 合轴后的 effective view,顺序与 vectorized_axis 一致,stride 单位均为元素。 |
| 34 | * 默认 Codegen 使用同源的 DataCopyParams,经 SetNddmaParams 左侧补 1 后生成 5 元素 API 数组;补 1 不改变 | 33 | * 默认 Codegen 使用同源的 DataCopyParams,经 SetNddmaParams 左侧补 1 后生成 5 元素 API 数组;补 1 不改变 |
| 35 | * effective rank 和搬运语义。 | 34 | * effective rank 和搬运语义。 |
| 36 | * | 35 | * |
| 37 | - * 1D 特征: | 36 | + * 统一公式(effective rank D=1~5): |
| 38 | - * B = output_dims[0] * dtype_size // 每核每次搬运字节数 | 37 | + * 设归一化后的维度和 stride 按内轴到外轴排列为 |
| 39 | - * is = input_strides[0], s = min(is, 128) // GM 非连续程度,is 允许为 0 | 38 | + * d_j、is_j、os_j(j=0...D-1),dtype_size 为每个元素的字节数。 |
| 40 | - * os = output_strides[0] | 39 | + * B = dtype_size * Π(d_j) // 单次搬运字节数 |
| 41 | - * g = max(0, min(1, os - 1)) // os=1 连续,os>=2 时修正饱和 | 40 | + * P_is_0 = 0,P_os_0 = 0 |
| 41 | + * P_is_j = Σ(d_m * is_m),P_os_j = Σ(d_m * os_m),m=0...j-1 | ||
| 42 | + * hat_is_j = 1 (j=0) | ||
| 43 | + * |is_j - P_is_j| + 1 (j>0) | ||
| 44 | + * hat_os_j = 1 (j=0) | ||
| 45 | + * |os_j - P_os_j| + 1 (j>0) | ||
| 46 | + * B_j = dtype_size * Π(d_m),m=j...D-1 // 第 j 层剩余数据量 | ||
| 47 | + * s_j = min(hat_is_j * dtype_size, 128) | ||
| 48 | + * g_j = min(1, hat_os_j - 1) | ||
| 49 | + * NG_j = (a1 + a2 * B_j) * s_j | ||
| 50 | + * NGU_j = (b1 + b2 * s_j + (b3 + b4 * s_j) * B_j) * g_j | ||
| 51 | + * rho_j = c1 + c2 * s_j + g_j * (c3 + c4 * s_j) | ||
| 52 | + * N_j = NG_j + NGU_j (block_dim<=2) | ||
| 53 | + * (NG_j + NGU_j) * rho_j (block_dim>2) | ||
| 54 | + * N_base = B/T1 + H1 (block_dim<=2) | ||
| 55 | + * B/T2 + H2 (block_dim>2) | ||
| 56 | + * cycles = N_base + Σ(N_j),j=0...D-1 | ||
| 42 | * | 57 | * |
| 43 | - * 参数组成(每种 dtype_size 各有一组): | 58 | + * D=1 时上述求和只有一个层级,即为 1D 模型;D=2~5 时逐层累加同一组 |
| 44 | - * - low_os_one / low_os_ge_two:k<=2 且 os=1/os>=2 时的 L0、LB、Ls、LBs; | 59 | + * 参数,不复制或展开另一套多维系数。参数表保存 T1/H1/T2/H2、a1...c4。 |
| 45 | - * - high_os_one / high_os_ge_two:k>2 且 os=1/os>=2 时的 C0、C1、C2、E0、E1、E2。 | ||
| 46 | - * 合并后的参数是原始 t/h/a/b/c 参数在合法 os 分支上的代数展开结果,参数表直接对应最终 cycles。 | ||
| 47 | - * | ||
| 48 | - * 1D 公式: | ||
| 49 | - * low(os=1) = L0 + LB*B + Ls*s + LBs*B*s | ||
| 50 | - * high(os=1) = C0 + C1*s + C2*s² + B*(E0 + E1*s + E2*s²) | ||
| 51 | - * low(os>=2) = L0 + LB*B + Ls*s + LBs*B*s | ||
| 52 | - * high(os>=2) = C0 + C1*s + C2*s² + B*(E0 + E1*s + E2*s²) | ||
| 53 | - * cycles = low(block_dim <= 2) or high(block_dim > 2) | ||
| 54 | - * 合法 stride 为整数,因此动态 os 使用 g=max(0,min(1,os-1)) 在两个 os 多项式之间选择;g=0 对应 os=1, | ||
| 55 | - * g=1 对应 os>=2。对于非法分数 stride,不承诺与原始连续 g 公式等价。 | ||
| 56 | * | 60 | * |
| 57 | * 静态和动态 shape: | 61 | * 静态和动态 shape: |
| 58 | * - 两者使用同一组参数和同一公式;静态表达式直接折叠,动态 block_dim 生成一个 TernaryOp; | 62 | * - 两者使用同一组参数和同一公式;静态表达式直接折叠,动态 block_dim 生成一个 TernaryOp; |
| 59 | - * - 动态 is/os 保留符号 Min/Max,g 的非负保护避免动态 os 产生负修正; | 63 | + * - 动态 is/os 保留符号 Min,输出 stride 修正项按统一公式保留符号表达式; |
| 60 | * - 静态非正 dim、负 input_stride、非正 output_stride、非法 dtype/schema 均记录原因并回退 legacy。 | 64 | * - 静态非正 dim、负 input_stride、非正 output_stride、非法 dtype/schema 均记录原因并回退 legacy。 |
| 61 | * | 65 | * |
| 62 | * 处理阶段: | 66 | * 处理阶段: |
| 63 | - * 1. BuildNddmaDescriptor:从 TensorShapeInfo 构造原始 descriptor,不从 legacy 标量 stride 反推; | 67 | + * 1. BuildNddmaDescriptor:从 TensorShapeInfo 构造并合并 effective descriptor,不从 legacy 标量 stride 反推; |
| 64 | - * 2. NormalizeNddmaDescriptor:校验 rank、向量长度、轴序、静态值及默认 Codegen 一致性; | 68 | + * 2. NormalizeNddmaDescriptor:校验 rank、向量长度、轴序和静态值; |
| 65 | * 3. EvaluateNddmaModel:选择 dtype 参数、构造静态/动态 cycles,并返回 ternary_ops; | 69 | * 3. EvaluateNddmaModel:选择 dtype 参数、构造静态/动态 cycles,并返回 ternary_ops; |
| 66 | - * 4. LogNddmaFallback:未选择新模型时记录一次稳定 reason,调用方继续执行原有 GetDmaPerf。 | 70 | + * 4. EvaluateNddmaModel 只返回 fallback reason;TryNewNddmaModel 在 CV-Fusion、dtype/schema、descriptor 构造和 |
| 71 | + * 模型归一化/求值失败路径统一调用 LogNddmaFallback,记录 node、raw/effective rank、candidate model 和 reason, | ||
| 72 | + * 然后继续执行原有 GetDmaPerf。 | ||
| 67 | * 模型只输出单次调用的 AIV_MTE2 cycles;全局 pipe head 仍由 PipePerfExpr 统一添加。 | 73 | * 模型只输出单次调用的 AIV_MTE2 cycles;全局 pipe head 仍由 PipePerfExpr 统一添加。 |
| 68 | * | 74 | * |
| 69 | - * 扩展约束:原始 NddmaDescriptorInfo 与物理 NddmaNormalizedDesc 分离。后续 2D~5D 可在归一化阶段构造 | 75 | + * raw rank 仅用于诊断日志;模型选择和公式计算只使用 effective rank。 |
| 70 | - * effective view,并独立选择 raw 或 normalized 统计特征,不改变现有 descriptor 字段及 legacy 数据结构。 | ||
| 71 | */ | 76 | */ |
| 72 | enum class NddmaFallbackReason : int32_t { | 77 | enum class NddmaFallbackReason : int32_t { |
| 73 | kNone = 0, | 78 | kNone = 0, |
| @@ -87,7 +92,6 @@ struct NddmaNormalizedDesc { | |||
| 87 | std::vector<Expr> input_strides; | 92 | std::vector<Expr> input_strides; |
| 88 | std::vector<Expr> output_strides; | 93 | std::vector<Expr> output_strides; |
| 89 | std::vector<int64_t> vectorized_axis; | 94 | std::vector<int64_t> vectorized_axis; |
| 90 | - size_t raw_rank{0U}; | ||
| 91 | size_t effective_rank{0U}; | 95 | size_t effective_rank{0U}; |
| 92 | }; | 96 | }; |
| 93 | 97 | ||
| @@ -95,7 +99,7 @@ struct NddmaNormalizedDesc { | |||
| 95 | struct NddmaModelResult { | 99 | struct NddmaModelResult { |
| 96 | bool selected{false}; | 100 | bool selected{false}; |
| 97 | Expr cycles; | 101 | Expr cycles; |
| 98 | - std::string model_name{"NDDMA_1D_MULTICORE_V1"}; | 102 | + std::string model_name{"NDDMA_1D_MULTICORE_V2"}; |
| 99 | NddmaFallbackReason fallback_reason{NddmaFallbackReason::kNone}; | 103 | NddmaFallbackReason fallback_reason{NddmaFallbackReason::kNone}; |
| 100 | size_t raw_rank{0U}; | 104 | size_t raw_rank{0U}; |
| 101 | size_t effective_rank{0U}; | 105 | size_t effective_rank{0U}; |
| @@ -105,7 +109,7 @@ struct NddmaModelResult { | |||
| 105 | const char *NddmaFallbackReasonToString(NddmaFallbackReason reason); | 109 | const char *NddmaFallbackReasonToString(NddmaFallbackReason reason); |
| 106 | 110 | ||
| 107 | NddmaFallbackReason BuildNddmaDescriptor(const TensorShapeInfo &shape_info, const std::vector<int64_t> &vectorized_axis, | 111 | NddmaFallbackReason BuildNddmaDescriptor(const TensorShapeInfo &shape_info, const std::vector<int64_t> &vectorized_axis, |
| 108 | - NddmaDescriptorInfo &descriptor); | 112 | + NddmaDescriptorInfo &descriptor, const std::vector<bool> &tile_inner = {}); |
| 109 | 113 | ||
| 110 | NddmaFallbackReason NormalizeNddmaDescriptor(const NddmaDescriptorInfo &descriptor, NddmaNormalizedDesc &normalized); | 114 | NddmaFallbackReason NormalizeNddmaDescriptor(const NddmaDescriptorInfo &descriptor, NddmaNormalizedDesc &normalized); |
| 111 | 115 | ||