已合并
feat: reuse cv tiling wrapper compilation & support dtype-aware cv fusion #1700
xuyafei创建于 15 天前
feat: reuse cv tiling wrapper compilation & support dtype-aware cv fusion #1700
已合并
共 62 个文件变更+4289-2082
| @@ -10,21 +10,12 @@ | |||
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | - | ||
| 14 | - | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | 13 | ||
| 19 | 14 | ||
| 20 | 15 | ||
| 21 | - | ||
| 22 | 16 | ||
| 23 | namespace codegen { | 17 | namespace codegen { |
| 24 | using namespace std; | 18 | using namespace std; |
| 25 | -using namespace af::ops; | ||
| 26 | -using namespace af::ascir_op; | ||
| 27 | -using namespace ascgen_utils; | ||
| 28 | 19 | ||
| 29 | static void CreateComputeNodeOuterForIfRequired(size_t outer_repeats_size, ApiLoopParams param, | 20 | static void CreateComputeNodeOuterForIfRequired(size_t outer_repeats_size, ApiLoopParams param, |
| 30 | const std::stringstream &ss1, std::stringstream &ss) { | 21 | const std::stringstream &ss1, std::stringstream &ss) { |
| @@ -69,19 +60,20 @@ Status CompareApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::Axi | |||
| 69 | } | 60 | } |
| 70 | 61 | ||
| 71 | if (x2.IsAnyScalar()) { | 62 | if (x2.IsAnyScalar()) { |
| 63 | + const std::string actual_size = | ||
| 64 | + IsCVFusionStage(this->api_call_context) ? GenBlockAlignNExpr(x1, x1.actual_size.Str()) : x1.actual_size.Str(); | ||
| 72 | ub_inputs.push_back(x1); | 65 | ub_inputs.push_back(x1); |
| 73 | ub_outputs.push_back(y); | 66 | ub_outputs.push_back(y); |
| 74 | bool status = GenerateVectorizedAxisMergeStatus(ub_inputs, ub_outputs, merge_info, tpipe); | 67 | bool status = GenerateVectorizedAxisMergeStatus(ub_inputs, ub_outputs, merge_info, tpipe); |
| 75 | GE_ASSERT_TRUE(status, "GenerateVectorizedAxisMergeStatus failed"); | 68 | GE_ASSERT_TRUE(status, "GenerateVectorizedAxisMergeStatus failed"); |
| 76 | SaveApiLoopAxisParams(merge_info, param); | 69 | SaveApiLoopAxisParams(merge_info, param); |
| 77 | std::string scalar_local_blk_tensor_name_x2 = x2.IsConstScalar() ? "local_blk_tensor_of_" + x2.name : x2.name; | 70 | std::string scalar_local_blk_tensor_name_x2 = x2.IsConstScalar() ? "local_blk_tensor_of_" + x2.name : x2.name; |
| 78 | - scalar_local_blk_tensor_name_x2 = scalar_local_blk_tensor_name_x2; | ||
| 79 | size_t outer_repeats_size = param.outer_repeats.size(); | 71 | size_t outer_repeats_size = param.outer_repeats.size(); |
| 80 | if (outer_repeats_size == 0U) { | 72 | if (outer_repeats_size == 0U) { |
| 81 | ss << "CompareScalarExtend" << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " | 73 | ss << "CompareScalarExtend" << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " |
| 82 | << x1 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2_scalar << ", " | 74 | << x1 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2_scalar << ", " |
| 83 | - << "CMPMODE::" << this->api_name_ << ", " << x1.actual_size << ", " << tpipe.tmp_buf << "_" | 75 | + << "CMPMODE::" << this->api_name_ << ", " << actual_size << ", " << tpipe.tmp_buf << "_" << std::to_string(id) |
| 84 | - << std::to_string(id) << ");" << std::endl; | 76 | + << ");" << std::endl; |
| 85 | } else { | 77 | } else { |
| 86 | std::stringstream ss1; | 78 | std::stringstream ss1; |
| 87 | size_t input0_strides_size = param.inputs_strides[0].size(); | 79 | size_t input0_strides_size = param.inputs_strides[0].size(); |
| @@ -98,12 +90,16 @@ Status CompareApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::Axi | |||
| 98 | ss1 << "CompareExtend<" << dtype_name << ", CMPMODE::" << this->api_name_ << ">(" << y << "[" | 90 | ss1 << "CompareExtend<" << dtype_name << ", CMPMODE::" << this->api_name_ << ">(" << y << "[" |
| 99 | << output_inner_offset << "], " << x1 << "[" << input0_inner_offset << "], " | 91 | << output_inner_offset << "], " << x1 << "[" << input0_inner_offset << "], " |
| 100 | << scalar_local_blk_tensor_name_x2 << "[0], " << param.outer_repeats[outer_repeats_size - 1] << ", " | 92 | << scalar_local_blk_tensor_name_x2 << "[0], " << param.outer_repeats[outer_repeats_size - 1] << ", " |
| 101 | - << tpipe.tiler.ActualSize(param.cal_count) << ", " << tpipe.tiler.Size(param.input_second_to_last_stride) | 93 | + << (IsCVFusionStage(this->api_call_context) ? GenBlockAlignNExpr(x1, tpipe.tiler.ActualSize(param.cal_count)) |
| 102 | - << ", " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " << tpipe.tmp_buf << "_" | 94 | + : tpipe.tiler.ActualSize(param.cal_count)) |
| 103 | - << std::to_string(id) << ");" << std::endl; | 95 | + << ", " << tpipe.tiler.Size(param.input_second_to_last_stride) << ", " |
| 96 | + << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " << tpipe.tmp_buf << "_" << std::to_string(id) | ||
| 97 | + << ");" << std::endl; | ||
| 104 | CreateComputeNodeOuterForIfRequired(outer_repeats_size, param, ss1, ss); | 98 | CreateComputeNodeOuterForIfRequired(outer_repeats_size, param, ss1, ss); |
| 105 | } | 99 | } |
| 106 | } else { | 100 | } else { |
| 101 | + const std::string actual_size = | ||
| 102 | + IsCVFusionStage(this->api_call_context) ? GenBlockAlignNExpr(x1, x1.actual_size.Str()) : x1.actual_size.Str(); | ||
| 107 | ub_inputs.push_back(x1); | 103 | ub_inputs.push_back(x1); |
| 108 | ub_inputs.push_back(x2); | 104 | ub_inputs.push_back(x2); |
| 109 | ub_outputs.push_back(y); | 105 | ub_outputs.push_back(y); |
| @@ -115,8 +111,8 @@ Status CompareApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::Axi | |||
| 115 | ss << "CompareExtend" << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 | 111 | ss << "CompareExtend" << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 |
| 116 | << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "[" | 112 | << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "[" |
| 117 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], " | 113 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], " |
| 118 | - << "CMPMODE::" << this->api_name_ << ", " << x1.actual_size << ", " << tpipe.tmp_buf << "_" | 114 | + << "CMPMODE::" << this->api_name_ << ", " << actual_size << ", " << tpipe.tmp_buf << "_" << std::to_string(id) |
| 119 | - << std::to_string(id) << ");" << std::endl; | 115 | + << ");" << std::endl; |
| 120 | } else { | 116 | } else { |
| 121 | size_t input0_strides_size = param.inputs_strides[0].size(); | 117 | size_t input0_strides_size = param.inputs_strides[0].size(); |
| 122 | std::vector<ascir::SizeExpr> inner0_input_strides(param.inputs_strides[0].begin(), | 118 | std::vector<ascir::SizeExpr> inner0_input_strides(param.inputs_strides[0].begin(), |
| @@ -138,9 +134,11 @@ Status CompareApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::Axi | |||
| 138 | ss1 << "CompareExtend<" << dtype_name << ", CMPMODE::" << this->api_name_ << ">(" << y << "[" | 134 | ss1 << "CompareExtend<" << dtype_name << ", CMPMODE::" << this->api_name_ << ">(" << y << "[" |
| 139 | << output_inner_offset << "], " << x1 << "[" << input0_inner_offset << "], " << x2 << "[" | 135 | << output_inner_offset << "], " << x1 << "[" << input0_inner_offset << "], " << x2 << "[" |
| 140 | << input1_inner_offset << "], " << param.outer_repeats[outer_repeats_size - 1] << ", " | 136 | << input1_inner_offset << "], " << param.outer_repeats[outer_repeats_size - 1] << ", " |
| 141 | - << tpipe.tiler.ActualSize(param.cal_count) << ", " << tpipe.tiler.Size(param.input_second_to_last_stride) | 137 | + << (IsCVFusionStage(this->api_call_context) ? GenBlockAlignNExpr(x1, tpipe.tiler.ActualSize(param.cal_count)) |
| 142 | - << ", " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " << tpipe.tmp_buf << "_" | 138 | + : tpipe.tiler.ActualSize(param.cal_count)) |
| 143 | - << std::to_string(id) << ");" << std::endl; | 139 | + << ", " << tpipe.tiler.Size(param.input_second_to_last_stride) << ", " |
| 140 | + << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " << tpipe.tmp_buf << "_" << std::to_string(id) | ||
| 141 | + << ");" << std::endl; | ||
| 144 | CreateComputeNodeOuterForIfRequired(outer_repeats_size, param, ss1, ss); | 142 | CreateComputeNodeOuterForIfRequired(outer_repeats_size, param, ss1, ss); |
| 145 | } | 143 | } |
| 146 | } | 144 | } |
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | + | ||
| 20 | 21 | ||
| 21 | 22 | ||
| 22 | namespace codegen { | 23 | namespace codegen { |
| @@ -44,7 +45,8 @@ Status LogicalNotApiCall::Generate(const TPipe &tpipe, const std::vector<ascir:: | |||
| 44 | stringstream ss; | 45 | stringstream ss; |
| 45 | ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "[" | 46 | ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "[" |
| 46 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], local_blk_tensor_of_half_1, " << tpipe.tmp_buf << "_" | 47 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], local_blk_tensor_of_half_1, " << tpipe.tmp_buf << "_" |
| 47 | - << std::to_string(id) << ", " << x.actual_size << ");" << std::endl; | 48 | + << std::to_string(id) << ", " << GetCVAlignedSize(this->api_call_context, y, x.actual_size.Str()) << ");" |
| 49 | + << std::endl; | ||
| 48 | result = ss.str(); | 50 | result = ss.str(); |
| 49 | return af::SUCCESS; | 51 | return af::SUCCESS; |
| 50 | } | 52 | } |
| @@ -10,20 +10,13 @@ | |||
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | - | ||
| 14 | - | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | 13 | ||
| 19 | 14 | ||
| 15 | + | ||
| 20 | 16 | ||
| 21 | 17 | ||
| 22 | namespace codegen { | 18 | namespace codegen { |
| 23 | using namespace std; | 19 | using namespace std; |
| 24 | -using namespace af::ops; | ||
| 25 | -using namespace af::ascir_op; | ||
| 26 | -using namespace ascgen_utils; | ||
| 27 | 20 | ||
| 28 | Status UnaryApiTmpCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisId> ¤t_axis, | 21 | Status UnaryApiTmpCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisId> ¤t_axis, |
| 29 | const std::vector<std::reference_wrapper<const Tensor>> &inputs, | 22 | const std::vector<std::reference_wrapper<const Tensor>> &inputs, |
| @@ -45,7 +38,7 @@ Status UnaryApiTmpCall::Generate(const TPipe &tpipe, const std::vector<ascir::Ax | |||
| 45 | stringstream ss; | 38 | stringstream ss; |
| 46 | ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "[" | 39 | ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "[" |
| 47 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " << tpipe.tmp_buf << "_" << std::to_string(id) | 40 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " << tpipe.tmp_buf << "_" << std::to_string(id) |
| 48 | - << ", " << x.actual_size << ");" << std::endl; | 41 | + << ", " << GetCVAlignedSize(this->api_call_context, y, x.actual_size.Str()) << ");" << std::endl; |
| 49 | result = ss.str(); | 42 | result = ss.str(); |
| 50 | return af::SUCCESS; | 43 | return af::SUCCESS; |
| 51 | } | 44 | } |
| @@ -10,11 +10,6 @@ | |||
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | - | ||
| 14 | - | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | 13 | ||
| 19 | 14 | ||
| 20 | 15 | ||
| @@ -22,9 +17,6 @@ | |||
| 22 | 17 | ||
| 23 | namespace codegen { | 18 | namespace codegen { |
| 24 | using namespace std; | 19 | using namespace std; |
| 25 | -using namespace af::ops; | ||
| 26 | -using namespace af::ascir_op; | ||
| 27 | -using namespace ascgen_utils; | ||
| 28 | 20 | ||
| 29 | Status UnaryBitWidthChangeApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisId> ¤t_axis, | 21 | Status UnaryBitWidthChangeApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisId> ¤t_axis, |
| 30 | const std::vector<std::reference_wrapper<const Tensor>> &inputs, | 22 | const std::vector<std::reference_wrapper<const Tensor>> &inputs, |
| @@ -57,7 +49,7 @@ Status UnaryBitWidthChangeApiCall::Generate(const TPipe &tpipe, const std::vecto | |||
| 57 | tpipe.tmp_buf.name + "_" + std::to_string(id)); | 49 | tpipe.tmp_buf.name + "_" + std::to_string(id)); |
| 58 | ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "[" | 50 | ss << this->api_name_ << "(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "[" |
| 59 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " << tpipe.tmp_buf << "_" << std::to_string(id) | 51 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " << tpipe.tmp_buf << "_" << std::to_string(id) |
| 60 | - << ", " << x.actual_size << ");" << std::endl; | 52 | + << ", " << GetCVAlignedSize(this->api_call_context, x, x.actual_size.Str()) << ");" << std::endl; |
| 61 | } else { | 53 | } else { |
| 62 | (void)RegisterBasicDumpParam(this->api_name_, inputs, outputs, | 54 | (void)RegisterBasicDumpParam(this->api_name_, inputs, outputs, |
| 63 | CombinedExprFactory::SymbolVar(tpipe.tiler.ActualSize(param.cal_count)), | 55 | CombinedExprFactory::SymbolVar(tpipe.tiler.ActualSize(param.cal_count)), |
| @@ -66,8 +58,8 @@ Status UnaryBitWidthChangeApiCall::Generate(const TPipe &tpipe, const std::vecto | |||
| 66 | std::string output_inner_offset = CalcInnerOffset(tpipe, param.outputs_strides[0]); | 58 | std::string output_inner_offset = CalcInnerOffset(tpipe, param.outputs_strides[0]); |
| 67 | std::stringstream ss1; | 59 | std::stringstream ss1; |
| 68 | ss1 << this->api_name_ << "(" << y << "[" << output_inner_offset << "], " << x << "[" << input_inner_offset << "], " | 60 | ss1 << this->api_name_ << "(" << y << "[" << output_inner_offset << "], " << x << "[" << input_inner_offset << "], " |
| 69 | - << tpipe.tmp_buf << "_" << std::to_string(id) << ", " << tpipe.tiler.ActualSize(param.cal_count) << ");" | 61 | + << tpipe.tmp_buf << "_" << std::to_string(id) << ", " |
| 70 | - << std::endl; | 62 | + << GetCVAlignedSize(this->api_call_context, x, tpipe.tiler.ActualSize(param.cal_count)) << ");" << std::endl; |
| 71 | CreateComputeNodeOuterFor(param.outer_repeats, ss1, ss, 0); | 63 | CreateComputeNodeOuterFor(param.outer_repeats, ss1, ss, 0); |
| 72 | } | 64 | } |
| 73 | 65 | ||
| @@ -10,20 +10,14 @@ | |||
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | - | ||
| 14 | - | ||
| 15 | 13 | ||
| 16 | 14 | ||
| 17 | - | ||
| 18 | 15 | ||
| 19 | 16 | ||
| 20 | 17 | ||
| 21 | - | ||
| 22 | 18 | ||
| 23 | namespace codegen { | 19 | namespace codegen { |
| 24 | using namespace std; | 20 | using namespace std; |
| 25 | -using namespace af::ops; | ||
| 26 | -using namespace af::ascir_op; | ||
| 27 | using namespace ascgen_utils; | 21 | using namespace ascgen_utils; |
| 28 | 22 | ||
| 29 | Status WhereApiCall::PrepareInputsAndOutputs(const std::vector<std::reference_wrapper<const Tensor>> &inputs, | 23 | Status WhereApiCall::PrepareInputsAndOutputs(const std::vector<std::reference_wrapper<const Tensor>> &inputs, |
| @@ -97,7 +91,8 @@ Status WhereApiCall::GenerateNoLoopCase(const TPipe &tpipe, const std::vector<as | |||
| 97 | ss << x3 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x3) << "], "; | 91 | ss << x3 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x3) << "], "; |
| 98 | } | 92 | } |
| 99 | 93 | ||
| 100 | - ss << x1.actual_size << ", " << tpipe.tmp_buf << "_" << std::to_string(id) << ");" << std::endl; | 94 | + ss << GetCVAlignedSize(this->api_call_context, y, x1.actual_size.Str()) << ", " << tpipe.tmp_buf << "_" |
| 95 | + << std::to_string(id) << ");" << std::endl; | ||
| 101 | 96 | ||
| 102 | return af::SUCCESS; | 97 | return af::SUCCESS; |
| 103 | } | 98 | } |
| @@ -107,6 +102,9 @@ Status WhereApiCall::GenerateBothScalarCase(const TPipe &tpipe, const ApiLoopPar | |||
| 107 | const std::string &scalar_local_blk_tensor_name_x3, const int64_t id, | 102 | const std::string &scalar_local_blk_tensor_name_x3, const int64_t id, |
| 108 | std::stringstream &ss) const { | 103 | std::stringstream &ss) const { |
| 109 | stringstream ss1; | 104 | stringstream ss1; |
| 105 | + std::string dtype_name; | ||
| 106 | + GE_CHK_STATUS_RET(Tensor::DtypeName(y.dtype, dtype_name), "Codegen get data type:%d failed", | ||
| 107 | + static_cast<int32_t>(y.dtype)); | ||
| 110 | 108 | ||
| 111 | size_t output_strides_size = param.outputs_strides[0].size(); | 109 | size_t output_strides_size = param.outputs_strides[0].size(); |
| 112 | std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(), | 110 | std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(), |
| @@ -122,11 +120,12 @@ Status WhereApiCall::GenerateBothScalarCase(const TPipe &tpipe, const ApiLoopPar | |||
| 122 | ss1 << this->api_name_ << "<true, true>(" << y << "[" << output_inner_offset << "], " << x1 << "[" | 120 | ss1 << this->api_name_ << "<true, true>(" << y << "[" << output_inner_offset << "], " << x1 << "[" |
| 123 | << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << scalar_local_blk_tensor_name_x3 | 121 | << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << scalar_local_blk_tensor_name_x3 |
| 124 | << "[0], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", " | 122 | << "[0], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", " |
| 125 | - << tpipe.tiler.ActualSize(param.cal_count) << ", " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " | 123 | + << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ", " |
| 124 | + << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " | ||
| 126 | << tpipe.tiler.Size(param.input_second_to_last_stride) << ", " | 125 | << tpipe.tiler.Size(param.input_second_to_last_stride) << ", " |
| 127 | - << "ONE_BLK_SIZE / sizeof(float), " | 126 | + << "ONE_BLK_SIZE / sizeof(" << dtype_name << "), " |
| 128 | - << "ONE_BLK_SIZE / sizeof(float), " << tpipe.tmp_buf << "_" << std::to_string(id) << ", ONE_BLK_SIZE * 2);" | 127 | + << "ONE_BLK_SIZE / sizeof(" << dtype_name << "), " << tpipe.tmp_buf << "_" << std::to_string(id) |
| 129 | - << std::endl; | 128 | + << ", ONE_BLK_SIZE * 2);" << std::endl; |
| 130 | 129 | ||
| 131 | if (param.outer_repeats.size() == 1) { | 130 | if (param.outer_repeats.size() == 1) { |
| 132 | ss << ss1.str(); | 131 | ss << ss1.str(); |
| @@ -142,6 +141,9 @@ Status WhereApiCall::GenerateX2ScalarCase(const TPipe &tpipe, const ApiLoopParam | |||
| 142 | const std::string &scalar_local_blk_tensor_name_x2, const int64_t id, | 141 | const std::string &scalar_local_blk_tensor_name_x2, const int64_t id, |
| 143 | std::stringstream &ss) const { | 142 | std::stringstream &ss) const { |
| 144 | stringstream ss1; | 143 | stringstream ss1; |
| 144 | + std::string dtype_name; | ||
| 145 | + GE_CHK_STATUS_RET(Tensor::DtypeName(y.dtype, dtype_name), "Codegen get data type:%d failed", | ||
| 146 | + static_cast<int32_t>(y.dtype)); | ||
| 145 | 147 | ||
| 146 | size_t output_strides_size = param.outputs_strides[0].size(); | 148 | size_t output_strides_size = param.outputs_strides[0].size(); |
| 147 | std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(), | 149 | std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(), |
| @@ -162,10 +164,11 @@ Status WhereApiCall::GenerateX2ScalarCase(const TPipe &tpipe, const ApiLoopParam | |||
| 162 | 164 | ||
| 163 | ss1 << this->api_name_ << "<true, false>(" << y << "[" << output_inner_offset << "], " << x1 << "[" | 165 | ss1 << this->api_name_ << "<true, false>(" << y << "[" << output_inner_offset << "], " << x1 << "[" |
| 164 | << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << x3 << "[" << input2_inner_offset | 166 | << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << x3 << "[" << input2_inner_offset |
| 165 | - << "], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", " << tpipe.tiler.ActualSize(param.cal_count) | 167 | + << "], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", " |
| 166 | - << ", " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " | 168 | + << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ", " |
| 169 | + << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " | ||
| 167 | << tpipe.tiler.Size(param.input_second_to_last_stride) << ", " | 170 | << tpipe.tiler.Size(param.input_second_to_last_stride) << ", " |
| 168 | - << "ONE_BLK_SIZE / sizeof(float), " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " | 171 | + << "ONE_BLK_SIZE / sizeof(" << dtype_name << "), " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " |
| 169 | << tpipe.tmp_buf << "_" << std::to_string(id) << ", ONE_BLK_SIZE);" << std::endl; | 172 | << tpipe.tmp_buf << "_" << std::to_string(id) << ", ONE_BLK_SIZE);" << std::endl; |
| 170 | 173 | ||
| 171 | if (param.outer_repeats.size() == 1) { | 174 | if (param.outer_repeats.size() == 1) { |
| @@ -182,6 +185,9 @@ Status WhereApiCall::GenerateX3ScalarCase(const TPipe &tpipe, const ApiLoopParam | |||
| 182 | const std::string &scalar_local_blk_tensor_name_x3, const int64_t id, | 185 | const std::string &scalar_local_blk_tensor_name_x3, const int64_t id, |
| 183 | std::stringstream &ss) const { | 186 | std::stringstream &ss) const { |
| 184 | stringstream ss1; | 187 | stringstream ss1; |
| 188 | + std::string dtype_name; | ||
| 189 | + GE_CHK_STATUS_RET(Tensor::DtypeName(y.dtype, dtype_name), "Codegen get data type:%d failed", | ||
| 190 | + static_cast<int32_t>(y.dtype)); | ||
| 185 | 191 | ||
| 186 | size_t output_strides_size = param.outputs_strides[0].size(); | 192 | size_t output_strides_size = param.outputs_strides[0].size(); |
| 187 | std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(), | 193 | std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(), |
| @@ -203,11 +209,12 @@ Status WhereApiCall::GenerateX3ScalarCase(const TPipe &tpipe, const ApiLoopParam | |||
| 203 | ss1 << this->api_name_ << "<false, true>(" << y << "[" << output_inner_offset << "], " << x1 << "[" | 209 | ss1 << this->api_name_ << "<false, true>(" << y << "[" << output_inner_offset << "], " << x1 << "[" |
| 204 | << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << scalar_local_blk_tensor_name_x3 | 210 | << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << scalar_local_blk_tensor_name_x3 |
| 205 | << "[0], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", " | 211 | << "[0], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", " |
| 206 | - << tpipe.tiler.ActualSize(param.cal_count) << ", " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " | 212 | + << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ", " |
| 213 | + << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " | ||
| 207 | << tpipe.tiler.Size(param.input_second_to_last_stride) << ", " | 214 | << tpipe.tiler.Size(param.input_second_to_last_stride) << ", " |
| 208 | << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " | 215 | << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " |
| 209 | - << "ONE_BLK_SIZE / sizeof(float), " << tpipe.tmp_buf << "_" << std::to_string(id) << ", ONE_BLK_SIZE);" | 216 | + << "ONE_BLK_SIZE / sizeof(" << dtype_name << "), " << tpipe.tmp_buf << "_" << std::to_string(id) |
| 210 | - << std::endl; | 217 | + << ", ONE_BLK_SIZE);" << std::endl; |
| 211 | 218 | ||
| 212 | if (param.outer_repeats.size() == 1) { | 219 | if (param.outer_repeats.size() == 1) { |
| 213 | ss << ss1.str(); | 220 | ss << ss1.str(); |
| @@ -222,6 +229,9 @@ Status WhereApiCall::GenerateNormalCase(const TPipe &tpipe, const ApiLoopParams | |||
| 222 | const Tensor &x2, const Tensor &x3, const Tensor &y, const int64_t id, | 229 | const Tensor &x2, const Tensor &x3, const Tensor &y, const int64_t id, |
| 223 | std::stringstream &ss) const { | 230 | std::stringstream &ss) const { |
| 224 | stringstream ss1; | 231 | stringstream ss1; |
| 232 | + std::string dtype_name; | ||
| 233 | + GE_CHK_STATUS_RET(Tensor::DtypeName(y.dtype, dtype_name), "Codegen get data type:%d failed", | ||
| 234 | + static_cast<int32_t>(y.dtype)); | ||
| 225 | 235 | ||
| 226 | size_t output_strides_size = param.outputs_strides[0].size(); | 236 | size_t output_strides_size = param.outputs_strides[0].size(); |
| 227 | std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(), | 237 | std::vector<ascir::SizeExpr> inner_output_strides(param.outputs_strides[0].begin(), |
| @@ -248,8 +258,9 @@ Status WhereApiCall::GenerateNormalCase(const TPipe &tpipe, const ApiLoopParams | |||
| 248 | 258 | ||
| 249 | ss1 << this->api_name_ << "<false, false>(" << y << "[" << output_inner_offset << "], " << x1 << "[" | 259 | ss1 << this->api_name_ << "<false, false>(" << y << "[" << output_inner_offset << "], " << x1 << "[" |
| 250 | << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << x3 << "[" << input2_inner_offset | 260 | << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << x3 << "[" << input2_inner_offset |
| 251 | - << "], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", " << tpipe.tiler.ActualSize(param.cal_count) | 261 | + << "], " << param.outer_repeats[param.outer_repeats.size() - 1] << ", " |
| 252 | - << ", " << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " | 262 | + << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ", " |
| 263 | + << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " | ||
| 253 | << tpipe.tiler.Size(param.input_second_to_last_stride) << ", " | 264 | << tpipe.tiler.Size(param.input_second_to_last_stride) << ", " |
| 254 | << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " | 265 | << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " |
| 255 | << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " << tpipe.tmp_buf << "_" << std::to_string(id) | 266 | << tpipe.tiler.Size(param.output_second_to_last_stride) << ", " << tpipe.tmp_buf << "_" << std::to_string(id) |
| @@ -574,6 +574,33 @@ bool GetMaxDtypeSize(const ge::DataType input_data_type, const ge::DataType out_ | |||
| 574 | return true; | 574 | return true; |
| 575 | } | 575 | } |
| 576 | 576 | ||
| 577 | +bool IsCVFusionStage(const ApiCallContext &context) { | ||
| 578 | + return context.stage != ComputeStage::kDefault; | ||
| 579 | +} | ||
| 580 | + | ||
| 581 | +Status GetTensorDtypeSize(const Tensor &tensor, int64_t &dtype_size) { | ||
| 582 | + const int32_t tensor_dtype_size = GetSizeByDataType(tensor.dtype); | ||
| 583 | + GE_CHK_BOOL_RET_STATUS(tensor_dtype_size > 0 && tensor_dtype_size < ge::kDataTypeSizeBitOffset, af::FAILED, | ||
| 584 | + "get dtype size failed, tensor:%s, dtype:%d", tensor.name.c_str(), | ||
| 585 | + static_cast<int32_t>(tensor.dtype)); | ||
| 586 | + dtype_size = tensor_dtype_size; | ||
| 587 | + return af::SUCCESS; | ||
| 588 | +} | ||
| 589 | + | ||
| 590 | +std::string GenBlockAlignNExpr(const Tensor &tensor, const std::string &n_expr) { | ||
| 591 | + int64_t dtype_size = 0; | ||
| 592 | + if (GetTensorDtypeSize(tensor, dtype_size) != af::SUCCESS || dtype_size <= 0) { | ||
| 593 | + return n_expr; | ||
| 594 | + } | ||
| 595 | + const int64_t align_value = 32 / dtype_size; | ||
| 596 | + return "((" + n_expr + " + " + std::to_string(align_value) + " - 1) / " + std::to_string(align_value) + " * " + | ||
| 597 | + std::to_string(align_value) + ")"; | ||
| 598 | +} | ||
| 599 | + | ||
| 600 | +std::string GetCVAlignedSize(const ApiCallContext &context, const Tensor &tensor, const std::string &size_expr) { | ||
| 601 | + return IsCVFusionStage(context) ? GenBlockAlignNExpr(tensor, size_expr) : size_expr; | ||
| 602 | +} | ||
| 603 | + | ||
| 577 | void GenerateLinkStoreEventCode(const Tensor &ub, const std::string &offset_str, std::stringstream &ss) { | 604 | void GenerateLinkStoreEventCode(const Tensor &ub, const std::string &offset_str, std::stringstream &ss) { |
| 578 | std::hash<std::string> hasher; | 605 | std::hash<std::string> hasher; |
| 579 | [[maybe_unused]] size_t hasher_value = hasher(offset_str); | 606 | [[maybe_unused]] size_t hasher_value = hasher(offset_str); |
| @@ -122,6 +122,10 @@ bool CheckAxisContinuous(const std::vector<Tensor> &inputs, const std::vector<Te | |||
| 122 | VectorizedAixsLoopStatus &axis_info, int64_t index); | 122 | VectorizedAixsLoopStatus &axis_info, int64_t index); |
| 123 | void SaveApiLoopAxisParams(VectorizedAxisLoopMergeStatus &merge_info, ApiLoopParams ¶m); | 123 | void SaveApiLoopAxisParams(VectorizedAxisLoopMergeStatus &merge_info, ApiLoopParams ¶m); |
| 124 | bool GetMaxDtypeSize(const ge::DataType input_data_type, const ge::DataType out_put_data_type, std::string &dtype_size); | 124 | bool GetMaxDtypeSize(const ge::DataType input_data_type, const ge::DataType out_put_data_type, std::string &dtype_size); |
| 125 | +bool IsCVFusionStage(const ApiCallContext &context); | ||
| 126 | +Status GetTensorDtypeSize(const Tensor &tensor, int64_t &dtype_size); | ||
| 127 | +std::string GenBlockAlignNExpr(const Tensor &tensor, const std::string &n_expr); | ||
| 128 | +std::string GetCVAlignedSize(const ApiCallContext &context, const Tensor &tensor, const std::string &size_expr); | ||
| 125 | bool ShouldIgnoreZeroAxis(const std::vector<Tensor> &inputs, const std::vector<Tensor> &outputs, int64_t cur_index); | 129 | bool ShouldIgnoreZeroAxis(const std::vector<Tensor> &inputs, const std::vector<Tensor> &outputs, int64_t cur_index); |
| 126 | bool IsInputOutputStrideAllZero(const std::vector<Tensor> &inputs, const std::vector<Tensor> &outputs, | 130 | bool IsInputOutputStrideAllZero(const std::vector<Tensor> &inputs, const std::vector<Tensor> &outputs, |
| 127 | int64_t cur_index); | 131 | int64_t cur_index); |
| @@ -1656,7 +1656,11 @@ Status TPipe::LocalTQueAlloc(std::string &result) const { | |||
| 1656 | std::string dtype_name; | 1656 | std::string dtype_name; |
| 1657 | GE_CHK_STATUS_RET(Tensor::DtypeName(tensor->second.dtype, dtype_name), "Codegen get data type:%d failed", | 1657 | GE_CHK_STATUS_RET(Tensor::DtypeName(tensor->second.dtype, dtype_name), "Codegen get data type:%d failed", |
| 1658 | static_cast<int32_t>(tensor->second.dtype)); | 1658 | static_cast<int32_t>(tensor->second.dtype)); |
| 1659 | - tensor_size_max << tensor->second.size << " * sizeof(" << dtype_name << ")"; | 1659 | + std::string tensor_byte_size = tensor->second.size.Str() + " * sizeof(" + dtype_name + ")"; |
| 1660 | + if (this->cv_fusion_type == ascir::CubeTemplateType::kUBFuse) { | ||
| 1661 | + tensor_byte_size = "KernelUtils::BlkAlign<uint8_t>(" + tensor_byte_size + ")"; | ||
| 1662 | + } | ||
| 1663 | + tensor_size_max << tensor_byte_size; | ||
| 1660 | } | 1664 | } |
| 1661 | } | 1665 | } |
| 1662 | 1666 | ||
| @@ -115,6 +115,14 @@ Status AddSkippedApiEmitProcessCall(const ascir::NodeView &node, Loop *current_l | |||
| 115 | } | 115 | } |
| 116 | return af::SUCCESS; | 116 | return af::SUCCESS; |
| 117 | } | 117 | } |
| 118 | +std::string GetQueueSliceByteSize(const TPipe &tpipe, const Tensor &tensor) { | ||
| 119 | + auto size = af::GetSizeByDataType(tensor.dtype); | ||
| 120 | + std::string byte_size = tensor.size.name + " * " + std::to_string(size); | ||
| 121 | + if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) { | ||
| 122 | + byte_size = "KernelUtils::BlkAlign<uint8_t>(" + byte_size + ")"; | ||
| 123 | + } | ||
| 124 | + return byte_size; | ||
| 125 | +} | ||
| 118 | 126 | ||
| 119 | Status MoveToNodeLoop(const ascir::NodeView &node, std::vector<ascir::AxisId> ¤t_axis, Loop *¤t_loop) { | 127 | Status MoveToNodeLoop(const ascir::NodeView &node, std::vector<ascir::AxisId> ¤t_axis, Loop *¤t_loop) { |
| 120 | if (node->attr.api.unit == af::ComputeUnit::kUnitNone) { | 128 | if (node->attr.api.unit == af::ComputeUnit::kUnitNone) { |
| @@ -613,7 +621,7 @@ Status Loop::GenerateBody(const Tiler &tiler, const TPipe &tpipe, std::vector<as | |||
| 613 | std::string call; | 621 | std::string call; |
| 614 | std::string cache_guard; | 622 | std::string cache_guard; |
| 615 | 623 | ||
| 616 | - if (this->axis_id != af::kIdNone) { | 624 | + if (this->axis_id != af::kIdNone && this->compute_stage == ComputeStage::kDefault) { |
| 617 | auto axis = tiler.GetAxis(this->axis_id); | 625 | auto axis = tiler.GetAxis(this->axis_id); |
| 618 | const bool is_enable_cache = axis.is_split_b && body.call->enable_cache; | 626 | const bool is_enable_cache = axis.is_split_b && body.call->enable_cache; |
| 619 | const bool is_double_tile = IsReduceDoubleTile(tiler, tpipe, this->is_graph_has_reduce_node) && | 627 | const bool is_double_tile = IsReduceDoubleTile(tiler, tpipe, this->is_graph_has_reduce_node) && |
| @@ -779,7 +787,9 @@ Status Loop::GenerateLoop(const Tiler &tiler, const TPipe &tpipe, std::vector<as | |||
| 779 | if (tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse) { | 787 | if (tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse) { |
| 780 | ss << tiler.CalcFromAxis(axis.id); | 788 | ss << tiler.CalcFromAxis(axis.id); |
| 781 | } | 789 | } |
| 782 | - GenerateEnCacheCondition(tiler, tpipe, axis, ss); | 790 | + if (this->compute_stage == ComputeStage::kDefault) { |
| 791 | + GenerateEnCacheCondition(tiler, tpipe, axis, ss); | ||
| 792 | + } | ||
| 783 | if (tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse) { | 793 | if (tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse) { |
| 784 | std::set<ascir::AxisId> vectorized_axis; | 794 | std::set<ascir::AxisId> vectorized_axis; |
| 785 | for (const auto &tensor : tpipe.tensors) { | 795 | for (const auto &tensor : tpipe.tensors) { |
| @@ -1242,8 +1252,7 @@ af::Status DefineShareOffsets(const TPipe &tpipe, const ApiTensor &out, const Te | |||
| 1242 | } | 1252 | } |
| 1243 | auto prev_tensor = tpipe.GetTensor(order_to_tensor[i - 1]->id); | 1253 | auto prev_tensor = tpipe.GetTensor(order_to_tensor[i - 1]->id); |
| 1244 | GE_ASSERT_NOTNULL(prev_tensor, "Check[Param] tensor_ptr is nullptr"); | 1254 | GE_ASSERT_NOTNULL(prev_tensor, "Check[Param] tensor_ptr is nullptr"); |
| 1245 | - auto size = af::GetSizeByDataType(prev_tensor->dtype); | 1255 | + auto var_size = prev_var_name + " + " + GetQueueSliceByteSize(tpipe, *prev_tensor); |
| 1246 | - auto var_size = prev_var_name + " + " + prev_tensor->size.name + " * " + std::to_string(size); | ||
| 1247 | const auto &cur_var_name = t.que_share_offset.name + "_part_" + std::to_string(i); | 1256 | const auto &cur_var_name = t.que_share_offset.name + "_part_" + std::to_string(i); |
| 1248 | decltype(t.que_share_offset) offset_var(cur_var_name); | 1257 | decltype(t.que_share_offset) offset_var(cur_var_name); |
| 1249 | ss << offset_var.DefineConst(std::move(var_size)) << std::endl; | 1258 | ss << offset_var.DefineConst(std::move(var_size)) << std::endl; |
| @@ -1276,8 +1285,7 @@ BoolType ApiCall::AllocShareOutputs(const TPipe &tpipe, const ApiTensor &out, co | |||
| 1276 | auto tensor_ptr = tpipe.GetTensor(out.share_prev->id); | 1285 | auto tensor_ptr = tpipe.GetTensor(out.share_prev->id); |
| 1277 | GE_CHK_BOOL_RET_SPECIAL_STATUS(tensor_ptr == nullptr, BoolType::FAILED, "Check[Param] tensor_ptr is nullptr"); | 1286 | GE_CHK_BOOL_RET_SPECIAL_STATUS(tensor_ptr == nullptr, BoolType::FAILED, "Check[Param] tensor_ptr is nullptr"); |
| 1278 | auto prev_tensor = *tensor_ptr; | 1287 | auto prev_tensor = *tensor_ptr; |
| 1279 | - auto size = af::GetSizeByDataType(prev_tensor.dtype); | 1288 | + relative_offset = t.que_share_offset.name + " + " + GetQueueSliceByteSize(tpipe, prev_tensor); |
| 1280 | - relative_offset = t.que_share_offset.name + " + " + prev_tensor.size.name + " * " + std::to_string(size); | ||
| 1281 | ss << t.que_share_offset.Assign(relative_offset); | 1289 | ss << t.que_share_offset.Assign(relative_offset); |
| 1282 | ss << std::endl; | 1290 | ss << std::endl; |
| 1283 | } | 1291 | } |
| @@ -100,7 +100,7 @@ void RequireEntrySystemHeaders(autofuse::SourceDependencies &dependencies, bool | |||
| 100 | bool is_multi_group) { | 100 | bool is_multi_group) { |
| 101 | if (is_inductor && is_cv) { | 101 | if (is_inductor && is_cv) { |
| 102 | RequireSystemHeaders(dependencies, {"algorithm", "cfloat", "cstddef", "cstdint", "cstring", "ostream", "sstream", | 102 | RequireSystemHeaders(dependencies, {"algorithm", "cfloat", "cstddef", "cstdint", "cstring", "ostream", "sstream", |
| 103 | - "string", "vector"}); | 103 | + "iomanip", "string", "vector"}); |
| 104 | } else if (is_inductor) { | 104 | } else if (is_inductor) { |
| 105 | RequireSystemHeaders(dependencies, {"algorithm", "cfloat", "cmath", "cstddef", "cstdint", "map", "ostream", | 105 | RequireSystemHeaders(dependencies, {"algorithm", "cfloat", "cmath", "cstddef", "cstdint", "map", "ostream", |
| 106 | "sstream", "string", "unordered_map", "vector"}); | 106 | "sstream", "string", "unordered_map", "vector"}); |
| @@ -1127,6 +1127,114 @@ std::string TilingLib::GenCubeFusionTilingBodyInductor(const ascir::FusedSchedul | |||
| 1127 | return ss.str(); | 1127 | return ss.str(); |
| 1128 | } | 1128 | } |
| 1129 | 1129 | ||
| 1130 | +void TilingLib::GenInductorShapeDim(const ascir::FusedScheduledResult &elemwise_schedule_result, | ||
| 1131 | + codegen::PgoShapeStringStream &pgo_shape_dim, | ||
| 1132 | + std::vector<std::string> &dynamic_shape_vars, const std::string &tiling_var) const { | ||
| 1133 | + for (auto vars : elemwise_schedule_result.origin_vars) { | ||
| 1134 | + if (!(vars.IsConstExpr())) { | ||
| 1135 | + std::string var_define = std::string(vars.Str().get()); | ||
| 1136 | + dynamic_shape_vars.push_back(var_define); | ||
| 1137 | + pgo_shape_dim.shape_dim_def << "uint32_t " << var_define << ", "; | ||
| 1138 | + pgo_shape_dim.shape_dim_use << var_define << ", "; | ||
| 1139 | + TilingSetShapeDim(pgo_shape_dim.tiling_set_shape_dim, var_define, elemwise_schedule_result, tiling_var); | ||
| 1140 | + } | ||
| 1141 | + } | ||
| 1142 | +} | ||
| 1143 | + | ||
| 1144 | +std::string TilingLib::GenCallCubeTilingForInductor(const ascir::FusedScheduledResult &fused_schedule_result, | ||
| 1145 | + const std::vector<std::string> &dynamic_shape_vars, | ||
| 1146 | + const codegen::PgoShapeStringStream &pgo_shape_dim) const { | ||
| 1147 | + std::stringstream ss; | ||
| 1148 | + MatMulCubeInfo cube_info; | ||
| 1149 | + GE_ASSERT_SUCCESS(ExtractMatMulCubeInfoFromFusedResult(fused_schedule_result, cube_info), | ||
| 1150 | + "[Extract][MatMulCubeInfo]Failed to extract MatMul cube info from FusedScheduledResult"); | ||
| 1151 | + ss << "using namespace ge::autofuse;" << std::endl; | ||
| 1152 | + AppendCvBaseAlignHelperDefs(ss); | ||
| 1153 | + AppendCvSafetyMixModeHelperDefs(ss, cube_info.is_batch); | ||
| 1154 | + | ||
| 1155 | + // 在CallCubeTiling函数之前定义全局变量(用于静态shape常量生成) | ||
| 1156 | + ss << "// Global variable to store tiling bytes for const generation in static shape\n"; | ||
| 1157 | + ss << "std::vector<uint8_t> g_matmul_tiling_bytes;\n\n"; | ||
| 1158 | + ss << "extern \"C\" void CallCubeTiling(" << pgo_shape_dim.shape_dim_def.str() | ||
| 1159 | + << "int64_t &ws_size, uint32_t &cube_block_dim, int64_t &tiling_key, uint32_t &basem, uint32_t " | ||
| 1160 | + "&basen, CVAutofuseTilingData *tiling_data) {" | ||
| 1161 | + << std::endl; | ||
| 1162 | + GenCallCubeTilingCacheRead(ss, dynamic_shape_vars); | ||
| 1163 | + ss << ProcessCubeKernelTilingFromFusedResult(fused_schedule_result) << std::endl; | ||
| 1164 | + GenCallCubeTilingCacheWrite(ss, dynamic_shape_vars); | ||
| 1165 | + ss << "}" << std::endl; | ||
| 1166 | + return ss.str(); | ||
| 1167 | +} | ||
| 1168 | + | ||
| 1169 | +void TilingLib::GenCallCubeTilingCacheRead(std::stringstream &ss, | ||
| 1170 | + const std::vector<std::string> &dynamic_shape_vars) const { | ||
| 1171 | + ss << "static bool g_cube_tiling_cache_valid = false;\n"; | ||
| 1172 | + for (const auto &var_name : dynamic_shape_vars) { | ||
| 1173 | + ss << "static uint32_t g_cube_tiling_cache_" << var_name << " = 0;\n"; | ||
| 1174 | + } | ||
| 1175 | + ss << "static int64_t g_cube_tiling_cache_ws_size = 0;\n"; | ||
| 1176 | + ss << "static uint32_t g_cube_tiling_cache_block_dim = 0;\n"; | ||
| 1177 | + ss << "static int64_t g_cube_tiling_cache_tiling_key = 0;\n"; | ||
| 1178 | + ss << "static uint32_t g_cube_tiling_cache_basem = 0;\n"; | ||
| 1179 | + ss << "static uint32_t g_cube_tiling_cache_basen = 0;\n"; | ||
| 1180 | + ss << "static uint8_t g_cube_tiling_cache_bytes[sizeof(tiling_data->matmul_tiling_data)] = {};\n"; | ||
| 1181 | + ss << "static size_t g_cube_tiling_cache_bytes_size = 0;\n"; | ||
| 1182 | + ss << "if (g_cube_tiling_cache_valid"; | ||
| 1183 | + for (const auto &var_name : dynamic_shape_vars) { | ||
| 1184 | + ss << " && g_cube_tiling_cache_" << var_name << " == " << var_name; | ||
| 1185 | + } | ||
| 1186 | + ss << ") {\n"; | ||
| 1187 | + ss << " ws_size = g_cube_tiling_cache_ws_size;\n"; | ||
| 1188 | + ss << " cube_block_dim = g_cube_tiling_cache_block_dim;\n"; | ||
| 1189 | + ss << " tiling_key = g_cube_tiling_cache_tiling_key;\n"; | ||
| 1190 | + ss << " basem = g_cube_tiling_cache_basem;\n"; | ||
| 1191 | + ss << " basen = g_cube_tiling_cache_basen;\n"; | ||
| 1192 | + ss << " std::memcpy(tiling_data->matmul_tiling_data, g_cube_tiling_cache_bytes, " | ||
| 1193 | + "g_cube_tiling_cache_bytes_size);\n"; | ||
| 1194 | + ss << " return;\n"; | ||
| 1195 | + ss << "}\n"; | ||
| 1196 | +} | ||
| 1197 | + | ||
| 1198 | +void TilingLib::GenCallCubeTilingCacheWrite(std::stringstream &ss, | ||
| 1199 | + const std::vector<std::string> &dynamic_shape_vars) const { | ||
| 1200 | + ss << "g_cube_tiling_cache_valid = true;\n"; | ||
| 1201 | + for (const auto &var_name : dynamic_shape_vars) { | ||
| 1202 | + ss << "g_cube_tiling_cache_" << var_name << " = " << var_name << ";\n"; | ||
| 1203 | + } | ||
| 1204 | + ss << "g_cube_tiling_cache_ws_size = ws_size;\n"; | ||
| 1205 | + ss << "g_cube_tiling_cache_block_dim = cube_block_dim;\n"; | ||
| 1206 | + ss << "g_cube_tiling_cache_tiling_key = tiling_key;\n"; | ||
| 1207 | + ss << "g_cube_tiling_cache_basem = basem;\n"; | ||
| 1208 | + ss << "g_cube_tiling_cache_basen = basen;\n"; | ||
| 1209 | + ss << "std::memcpy(g_cube_tiling_cache_bytes, tiling_data->matmul_tiling_data, copy_size);\n"; | ||
| 1210 | + ss << "g_cube_tiling_cache_bytes_size = copy_size;\n"; | ||
| 1211 | +} | ||
| 1212 | + | ||
| 1213 | +std::string TilingLib::GenPlainInductorTilingTail(const ascir::FusedScheduledResult &elemwise_schedule_result, | ||
| 1214 | + codegen::PgoShapeStringStream &pgo_shape_dim, | ||
| 1215 | + const std::string &tiling) const { | ||
| 1216 | + std::stringstream ss; | ||
| 1217 | + ss << " tiling->set_block_dim(limit->aiv_num);" << std::endl; | ||
| 1218 | + ss << " tiling->set_ub_size(limit->ub_size - 256);" << std::endl; | ||
| 1219 | + ss << " if (!optiling::GetTiling(*tiling, -1, nullptr)) {return -1;}" << std::endl; | ||
| 1220 | + ss << " *blockDim = tiling->get_block_dim();" << std::endl; // Only consider 48 for now | ||
| 1221 | + ss << " using namespace optiling;" << std::endl; | ||
| 1222 | + ss << " *workspaceSize = GetWorkspaceSize(*tiling);" << std::endl; | ||
| 1223 | + ss << std::endl; | ||
| 1224 | + ss << " return 0;" << std::endl; | ||
| 1225 | + ss << "}" << std::endl; | ||
| 1226 | + if (enable_autofuse_pgo_) { | ||
| 1227 | + // PGOGetTilingKey | ||
| 1228 | + ss << GenPGOGetTilingKey(tiling); | ||
| 1229 | + // AutofuseTilingWithConfig | ||
| 1230 | + ss << GenPgoTilingFunc(elemwise_schedule_result, tiling, pgo_shape_dim, true); | ||
| 1231 | + } else { | ||
| 1232 | + // 生成 AutofuseTilingWithConfig 函数 | ||
| 1233 | + ss << GenPgoAutofuseTiling(elemwise_schedule_result, pgo_shape_dim, tiling, true); | ||
| 1234 | + } | ||
| 1235 | + return ss.str(); | ||
| 1236 | +} | ||
| 1237 | + | ||
| 1130 | std::string TilingLib::GenTilingFuncForInductor(const ascir::FusedScheduledResult &fused_schedule_result, | 1238 | std::string TilingLib::GenTilingFuncForInductor(const ascir::FusedScheduledResult &fused_schedule_result, |
| 1131 | const ::ascir::FusedScheduledResult &elemwise_schedule_result, | 1239 | const ::ascir::FusedScheduledResult &elemwise_schedule_result, |
| 1132 | const std::string func, const std::string tiling) const { | 1240 | const std::string func, const std::string tiling) const { |
| @@ -1137,72 +1245,11 @@ std::string TilingLib::GenTilingFuncForInductor(const ascir::FusedScheduledResul | |||
| 1137 | if (ascgen_utils::IsCubeFusedScheduled(fused_schedule_result)) { | 1245 | if (ascgen_utils::IsCubeFusedScheduled(fused_schedule_result)) { |
| 1138 | tiling_var = "tiling->tiling_data."; | 1246 | tiling_var = "tiling->tiling_data."; |
| 1139 | } | 1247 | } |
| 1140 | - for (auto vars : elemwise_schedule_result.origin_vars) { | 1248 | + GenInductorShapeDim(elemwise_schedule_result, pgo_shape_dim, dynamic_shape_vars, tiling_var); |
| 1141 | - if (!(vars.IsConstExpr())) { | ||
| 1142 | - std::string var_define = std::string(vars.Str().get()); | ||
| 1143 | - dynamic_shape_vars.push_back(var_define); | ||
| 1144 | - pgo_shape_dim.shape_dim_def << "uint32_t " << var_define << ", "; | ||
| 1145 | - pgo_shape_dim.shape_dim_use << var_define << ", "; | ||
| 1146 | - TilingSetShapeDim(pgo_shape_dim.tiling_set_shape_dim, var_define, elemwise_schedule_result, tiling_var); | ||
| 1147 | - } | ||
| 1148 | - } | ||
| 1149 | 1249 | ||
| 1150 | ss << GenGetResLimitStru(); | 1250 | ss << GenGetResLimitStru(); |
| 1151 | if (ascgen_utils::IsCubeFusedScheduled(fused_schedule_result)) { | 1251 | if (ascgen_utils::IsCubeFusedScheduled(fused_schedule_result)) { |
| 1152 | - MatMulCubeInfo cube_info; | 1252 | + ss << GenCallCubeTilingForInductor(fused_schedule_result, dynamic_shape_vars, pgo_shape_dim); |
| 1153 | - GE_ASSERT_SUCCESS(ExtractMatMulCubeInfoFromFusedResult(fused_schedule_result, cube_info), | ||
| 1154 | - "[Extract][MatMulCubeInfo]Failed to extract MatMul cube info from FusedScheduledResult"); | ||
| 1155 | - std::stringstream call_cube_tiling; | ||
| 1156 | - call_cube_tiling << "using namespace ge::autofuse;" << std::endl; | ||
| 1157 | - AppendCvBaseAlignHelperDefs(call_cube_tiling); | ||
| 1158 | - AppendCvSafetyMixModeHelperDefs(call_cube_tiling, cube_info.is_batch); | ||
| 1159 | - | ||
| 1160 | - // 在CallCubeTiling函数之前定义全局变量(用于静态shape常量生成) | ||
| 1161 | - call_cube_tiling << "// Global variable to store tiling bytes for const generation in static shape\n"; | ||
| 1162 | - call_cube_tiling << "std::vector<uint8_t> g_matmul_tiling_bytes;\n\n"; | ||
| 1163 | - | ||
| 1164 | - call_cube_tiling << "extern \"C\" void CallCubeTiling(" << pgo_shape_dim.shape_dim_def.str() | ||
| 1165 | - << "int64_t &ws_size, uint32_t &cube_block_dim, int64_t &tiling_key, uint32_t &basem, uint32_t " | ||
| 1166 | - "&basen, CVAutofuseTilingData *tiling_data) {" | ||
| 1167 | - << std::endl; | ||
| 1168 | - call_cube_tiling << "static bool g_cube_tiling_cache_valid = false;\n"; | ||
| 1169 | - for (const auto &var_name : dynamic_shape_vars) { | ||
| 1170 | - call_cube_tiling << "static uint32_t g_cube_tiling_cache_" << var_name << " = 0;\n"; | ||
| 1171 | - } | ||
| 1172 | - call_cube_tiling << "static int64_t g_cube_tiling_cache_ws_size = 0;\n"; | ||
| 1173 | - call_cube_tiling << "static uint32_t g_cube_tiling_cache_block_dim = 0;\n"; | ||
| 1174 | - call_cube_tiling << "static int64_t g_cube_tiling_cache_tiling_key = 0;\n"; | ||
| 1175 | - call_cube_tiling << "static uint32_t g_cube_tiling_cache_basem = 0;\n"; | ||
| 1176 | - call_cube_tiling << "static uint32_t g_cube_tiling_cache_basen = 0;\n"; | ||
| 1177 | - call_cube_tiling << "static uint8_t g_cube_tiling_cache_bytes[sizeof(tiling_data->matmul_tiling_data)] = {};\n"; | ||
| 1178 | - call_cube_tiling << "if (g_cube_tiling_cache_valid"; | ||
| 1179 | - for (const auto &var_name : dynamic_shape_vars) { | ||
| 1180 | - call_cube_tiling << " && g_cube_tiling_cache_" << var_name << " == " << var_name; | ||
| 1181 | - } | ||
| 1182 | - call_cube_tiling << ") {\n"; | ||
| 1183 | - call_cube_tiling << " ws_size = g_cube_tiling_cache_ws_size;\n"; | ||
| 1184 | - call_cube_tiling << " cube_block_dim = g_cube_tiling_cache_block_dim;\n"; | ||
| 1185 | - call_cube_tiling << " tiling_key = g_cube_tiling_cache_tiling_key;\n"; | ||
| 1186 | - call_cube_tiling << " basem = g_cube_tiling_cache_basem;\n"; | ||
| 1187 | - call_cube_tiling << " basen = g_cube_tiling_cache_basen;\n"; | ||
| 1188 | - call_cube_tiling << " std::memcpy(tiling_data->matmul_tiling_data, g_cube_tiling_cache_bytes, " | ||
| 1189 | - "sizeof(tiling_data->matmul_tiling_data));\n"; | ||
| 1190 | - call_cube_tiling << " return;\n"; | ||
| 1191 | - call_cube_tiling << "}\n"; | ||
| 1192 | - call_cube_tiling << ProcessCubeKernelTilingFromFusedResult(fused_schedule_result) << std::endl; | ||
| 1193 | - call_cube_tiling << "g_cube_tiling_cache_valid = true;\n"; | ||
| 1194 | - for (const auto &var_name : dynamic_shape_vars) { | ||
| 1195 | - call_cube_tiling << "g_cube_tiling_cache_" << var_name << " = " << var_name << ";\n"; | ||
| 1196 | - } | ||
| 1197 | - call_cube_tiling << "g_cube_tiling_cache_ws_size = ws_size;\n"; | ||
| 1198 | - call_cube_tiling << "g_cube_tiling_cache_block_dim = cube_block_dim;\n"; | ||
| 1199 | - call_cube_tiling << "g_cube_tiling_cache_tiling_key = tiling_key;\n"; | ||
| 1200 | - call_cube_tiling << "g_cube_tiling_cache_basem = basem;\n"; | ||
| 1201 | - call_cube_tiling << "g_cube_tiling_cache_basen = basen;\n"; | ||
| 1202 | - call_cube_tiling << "std::memcpy(g_cube_tiling_cache_bytes, tiling_data->matmul_tiling_data, " | ||
| 1203 | - "sizeof(tiling_data->matmul_tiling_data));\n"; | ||
| 1204 | - call_cube_tiling << "}" << std::endl; | ||
| 1205 | - ss << call_cube_tiling.str(); | ||
| 1206 | } | 1253 | } |
| 1207 | 1254 | ||
| 1208 | // AutofuseTiling | 1255 | // AutofuseTiling |
| @@ -1226,25 +1273,7 @@ std::string TilingLib::GenTilingFuncForInductor(const ascir::FusedScheduledResul | |||
| 1226 | return ss.str() + GenCubeFusionTilingBodyInductor(fused_schedule_result, elemwise_schedule_result, | 1273 | return ss.str() + GenCubeFusionTilingBodyInductor(fused_schedule_result, elemwise_schedule_result, |
| 1227 | pgo_shape_dim.shape_dim_use.str()); | 1274 | pgo_shape_dim.shape_dim_use.str()); |
| 1228 | } | 1275 | } |
| 1229 | - ss << " tiling->set_block_dim(limit->aiv_num);" << std::endl; | 1276 | + ss << GenPlainInductorTilingTail(elemwise_schedule_result, pgo_shape_dim, tiling); |
| 1230 | - ss << " tiling->set_ub_size(limit->ub_size - 256);" << std::endl; | ||
| 1231 | - ss << " if (!optiling::GetTiling(*tiling, -1, nullptr)) {return -1;}" << std::endl; | ||
| 1232 | - ss << " *blockDim = tiling->get_block_dim();" << std::endl; // Only consider 48 for now | ||
| 1233 | - ss << " using namespace optiling;" << std::endl; | ||
| 1234 | - ss << " *workspaceSize = GetWorkspaceSize(*tiling);" << std::endl; | ||
| 1235 | - ss << std::endl; | ||
| 1236 | - | ||
| 1237 | - ss << " return 0;" << std::endl; | ||
| 1238 | - ss << "}" << std::endl; | ||
| 1239 | - if (enable_autofuse_pgo_) { | ||
| 1240 | - // PGOGetTilingKey | ||
| 1241 | - ss << GenPGOGetTilingKey(tiling); | ||
| 1242 | - // AutofuseTilingWithConfig | ||
| 1243 | - ss << GenPgoTilingFunc(elemwise_schedule_result, tiling, pgo_shape_dim, true); | ||
| 1244 | - } else { | ||
| 1245 | - // 生成 AutofuseTilingWithConfig 函数 | ||
| 1246 | - ss << GenPgoAutofuseTiling(elemwise_schedule_result, pgo_shape_dim, tiling, true); | ||
| 1247 | - } | ||
| 1248 | return ss.str(); | 1277 | return ss.str(); |
| 1249 | } | 1278 | } |
| 1250 | 1279 | ||
| @@ -1645,6 +1674,7 @@ namespace gert { | |||
| 1645 | int vector_core_num = std::atoi(core_num.c_str()); | 1674 | int vector_core_num = std::atoi(core_num.c_str()); |
| 1646 | GetTilingParse(tiling_parse_def, vector_core_num); | 1675 | GetTilingParse(tiling_parse_def, vector_core_num); |
| 1647 | ss << tiling_parse_def << std::endl; | 1676 | ss << tiling_parse_def << std::endl; |
| 1677 | + const std::string graph_name = CamelToLowerSneak(fused_schedule_result.fused_graph_name.GetString()); | ||
| 1648 | if (ascgen_utils::IsCubeFusedScheduled(fused_schedule_result) && IsStaticSchedResult(fused_schedule_result)) { | 1678 | if (ascgen_utils::IsCubeFusedScheduled(fused_schedule_result) && IsStaticSchedResult(fused_schedule_result)) { |
| 1649 | ss << extern_c << " ge::graphStatus TilingFunc(gert::TilingSymbolEvalContext *context)" << std::endl; | 1679 | ss << extern_c << " ge::graphStatus TilingFunc(gert::TilingSymbolEvalContext *context)" << std::endl; |
| 1650 | ss << "{" << std::endl; | 1680 | ss << "{" << std::endl; |
| @@ -51,6 +51,8 @@ struct MatMulCubeInfo { | |||
| 51 | int32_t offset_x = 0; | 51 | int32_t offset_x = 0; |
| 52 | int64_t enable_hf32 = false; | 52 | int64_t enable_hf32 = false; |
| 53 | bool is_batch = false; | 53 | bool is_batch = false; |
| 54 | + bool has_bias = false; | ||
| 55 | + bool has_offset_w = false; | ||
| 54 | bool has_relu = false; | 56 | bool has_relu = false; |
| 55 | uint32_t input_num = 0U; | 57 | uint32_t input_num = 0U; |
| 56 | uint32_t type_size = 4U; | 58 | uint32_t type_size = 4U; |
| @@ -196,6 +198,16 @@ class TilingLib { | |||
| 196 | std::string GenTilingFuncForInductor(const ::ascir::FusedScheduledResult &fused_schedule_result, | 198 | std::string GenTilingFuncForInductor(const ::ascir::FusedScheduledResult &fused_schedule_result, |
| 197 | const ::ascir::FusedScheduledResult &elemwise_schedule_result, | 199 | const ::ascir::FusedScheduledResult &elemwise_schedule_result, |
| 198 | const std::string func, const std::string tiling) const; | 200 | const std::string func, const std::string tiling) const; |
| 201 | + void GenInductorShapeDim(const ::ascir::FusedScheduledResult &elemwise_schedule_result, | ||
| 202 | + codegen::PgoShapeStringStream &pgo_shape_dim, std::vector<std::string> &dynamic_shape_vars, | ||
| 203 | + const std::string &tiling_var) const; | ||
| 204 | + std::string GenCallCubeTilingForInductor(const ::ascir::FusedScheduledResult &fused_schedule_result, | ||
| 205 | + const std::vector<std::string> &dynamic_shape_vars, | ||
| 206 | + const codegen::PgoShapeStringStream &pgo_shape_dim) const; | ||
| 207 | + void GenCallCubeTilingCacheRead(std::stringstream &ss, const std::vector<std::string> &dynamic_shape_vars) const; | ||
| 208 | + void GenCallCubeTilingCacheWrite(std::stringstream &ss, const std::vector<std::string> &dynamic_shape_vars) const; | ||
| 209 | + std::string GenPlainInductorTilingTail(const ::ascir::FusedScheduledResult &elemwise_schedule_result, | ||
| 210 | + codegen::PgoShapeStringStream &pgo_shape_dim, const std::string &tiling) const; | ||
| 199 | // codegen_tiling_inductor_topn.cpp: candidate protocol, selection and multi-group performance aggregation. | 211 | // codegen_tiling_inductor_topn.cpp: candidate protocol, selection and multi-group performance aggregation. |
| 200 | std::string GenGetTopnSolutionsFuncForInductor(const ::ascir::FusedScheduledResult &fused_schedule_result, | 212 | std::string GenGetTopnSolutionsFuncForInductor(const ::ascir::FusedScheduledResult &fused_schedule_result, |
| 201 | const std::string &tiling, bool use_measured_perf = false, | 213 | const std::string &tiling, bool use_measured_perf = false, |
| @@ -158,6 +158,8 @@ Status TilingLib::ExtractMatMulCubeInfoFromImplGraph(const af::AscGraph &impl_gr | |||
| 158 | cube_info.transpose_x2 = (mm_attr_data.transpose_x2 != 0) || (mm_attr_data.adj_x2 != 0); | 158 | cube_info.transpose_x2 = (mm_attr_data.transpose_x2 != 0) || (mm_attr_data.adj_x2 != 0); |
| 159 | cube_info.offset_x = mm_attr_data.offset_x; | 159 | cube_info.offset_x = mm_attr_data.offset_x; |
| 160 | cube_info.is_batch = mm_attr_data.is_batch; | 160 | cube_info.is_batch = mm_attr_data.is_batch; |
| 161 | + cube_info.has_bias = mm_attr_data.is_bias; | ||
| 162 | + cube_info.has_offset_w = mm_attr_data.is_offset_w; | ||
| 161 | cube_info.has_relu = (mm_attr_data.has_relu != 0); | 163 | cube_info.has_relu = (mm_attr_data.has_relu != 0); |
| 162 | cube_info.enable_hf32 = mm_attr_data.enable_hf32; | 164 | cube_info.enable_hf32 = mm_attr_data.enable_hf32; |
| 163 | cube_info.matmul_node = node; | 165 | cube_info.matmul_node = node; |
| @@ -346,6 +348,18 @@ void TilingLib::PrepareMatMulAttrs(const MatMulCubeInfo &cube_info, std::vector< | |||
| 346 | attr5.dtype = "int"; | 348 | attr5.dtype = "int"; |
| 347 | attr5.value_int = kAscendcOpParaSize; | 349 | attr5.value_int = kAscendcOpParaSize; |
| 348 | attrs.push_back(attr5); | 350 | attrs.push_back(attr5); |
| 351 | + | ||
| 352 | + AttrInfo attr6; | ||
| 353 | + attr6.name = "autofuse_has_bias"; | ||
| 354 | + attr6.dtype = "bool"; | ||
| 355 | + attr6.value_bool = cube_info.has_bias; | ||
| 356 | + attrs.push_back(attr6); | ||
| 357 | + | ||
| 358 | + AttrInfo attr7; | ||
| 359 | + attr7.name = "autofuse_has_offset_w"; | ||
| 360 | + attr7.dtype = "bool"; | ||
| 361 | + attr7.value_bool = cube_info.has_offset_w; | ||
| 362 | + attrs.push_back(attr7); | ||
| 349 | } | 363 | } |
| 350 | 364 | ||
| 351 | void TilingLib::GenerateTensorListCode(std::stringstream &code_ss, const std::vector<TensorInfo> &inputs, | 365 | void TilingLib::GenerateTensorListCode(std::stringstream &code_ss, const std::vector<TensorInfo> &inputs, |
| @@ -14,803 +14,20 @@ inline const std::string kCubeKernelTilingWrapperHppValue = R"( | |||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | - | ||
| 18 | - | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | - | ||
| 23 | - | ||
| 24 | - | ||
| 25 | 17 | ||
| 26 | -#include <cstring> | 18 | +#include <cstdint> |
| 27 | -#include <cmath> | 19 | +#include <map> |
| 28 | -#include <iomanip> | 20 | +#include <memory> |
| 29 | -#include <algorithm> | 21 | +#include <string> |
| 30 | -#include <limits> | 22 | +#include <utility> |
| 31 | -#include "acl/acl.h" | 23 | +#include <vector> |
| 24 | + | ||
| 25 | + | ||
| 32 | 26 | ||
| 33 | - | ||
| 34 | 27 | ||
| 35 | namespace ge { | 28 | namespace ge { |
| 36 | namespace autofuse { | 29 | namespace autofuse { |
| 37 | 30 | ||
| 38 | -namespace json_internal { | ||
| 39 | - | ||
| 40 | -enum class Type { | ||
| 41 | - null, | ||
| 42 | - boolean, | ||
| 43 | - number_integer, | ||
| 44 | - number_float, | ||
| 45 | - string, | ||
| 46 | - array, | ||
| 47 | - object | ||
| 48 | -}; | ||
| 49 | - | ||
| 50 | -class Json { | ||
| 51 | -public: | ||
| 52 | - Json() : type_(Type::null) {} | ||
| 53 | - Json(bool value) : type_(Type::boolean), bool_value_(value) {} | ||
| 54 | - Json(int value) : type_(Type::number_integer), int_value_(value) {} | ||
| 55 | - Json(int64_t value) : type_(Type::number_integer), int_value_(value) {} | ||
| 56 | - Json(double value) : type_(Type::number_float), float_value_(value) {} | ||
| 57 | - Json(const char* value) : type_(Type::string), string_value_(new std::string(value)) {} | ||
| 58 | - Json(const std::string& value) : type_(Type::string), string_value_(new std::string(value)) {} | ||
| 59 | - Json(const std::vector<int64_t>& value) : type_(Type::array), array_value_(new std::vector<Json>()) { | ||
| 60 | - for (const auto& v : value) { | ||
| 61 | - array_value_->push_back(Json(v)); | ||
| 62 | - } | ||
| 63 | - } | ||
| 64 | - Json(const std::vector<double>& value) : type_(Type::array), array_value_(new std::vector<Json>()) { | ||
| 65 | - for (const auto& v : value) { | ||
| 66 | - array_value_->push_back(Json(v)); | ||
| 67 | - } | ||
| 68 | - } | ||
| 69 | - Json(const std::vector<std::string>& value) : type_(Type::array), array_value_(new std::vector<Json>()) { | ||
| 70 | - for (const auto& v : value) { | ||
| 71 | - array_value_->push_back(Json(v)); | ||
| 72 | - } | ||
| 73 | - } | ||
| 74 | - | ||
| 75 | - Json(const Json& other) : type_(other.type_) { | ||
| 76 | - CopyValue(other); | ||
| 77 | - } | ||
| 78 | - | ||
| 79 | - Json(Json&& other) noexcept : type_(other.type_) { | ||
| 80 | - MoveValue(std::move(other)); | ||
| 81 | - other.type_ = Type::null; | ||
| 82 | - } | ||
| 83 | - | ||
| 84 | - Json& operator=(const Json& other) { | ||
| 85 | - if (this != &other) { | ||
| 86 | - Clear(); | ||
| 87 | - type_ = other.type_; | ||
| 88 | - CopyValue(other); | ||
| 89 | - } | ||
| 90 | - return *this; | ||
| 91 | - } | ||
| 92 | - | ||
| 93 | - Json& operator=(Json&& other) noexcept { | ||
| 94 | - if (this != &other) { | ||
| 95 | - Clear(); | ||
| 96 | - type_ = other.type_; | ||
| 97 | - MoveValue(std::move(other)); | ||
| 98 | - other.type_ = Type::null; | ||
| 99 | - } | ||
| 100 | - return *this; | ||
| 101 | - } | ||
| 102 | - | ||
| 103 | - ~Json() { | ||
| 104 | - Clear(); | ||
| 105 | - } | ||
| 106 | - | ||
| 107 | - Type type() const { return type_; } | ||
| 108 | - bool is_null() const { return type_ == Type::null; } | ||
| 109 | - bool is_boolean() const { return type_ == Type::boolean; } | ||
| 110 | - bool is_number() const { return type_ == Type::number_integer || type_ == Type::number_float; } | ||
| 111 | - bool is_string() const { return type_ == Type::string; } | ||
| 112 | - bool is_array() const { return type_ == Type::array; } | ||
| 113 | - bool is_object() const { return type_ == Type::object; } | ||
| 114 | - | ||
| 115 | - bool get_bool() const { | ||
| 116 | - if (type_ != Type::boolean) throw std::runtime_error("Json is not a boolean"); | ||
| 117 | - return bool_value_; | ||
| 118 | - } | ||
| 119 | - | ||
| 120 | - int64_t get_int64() const { | ||
| 121 | - if (type_ == Type::number_integer) return int_value_; | ||
| 122 | - if (type_ == Type::number_float) return static_cast<int64_t>(float_value_); | ||
| 123 | - throw std::runtime_error("Json is not a number"); | ||
| 124 | - } | ||
| 125 | - | ||
| 126 | - int get_int() const { | ||
| 127 | - return static_cast<int>(get_int64()); | ||
| 128 | - } | ||
| 129 | - | ||
| 130 | - double get_double() const { | ||
| 131 | - if (type_ == Type::number_float) return float_value_; | ||
| 132 | - if (type_ == Type::number_integer) return static_cast<double>(int_value_); | ||
| 133 | - throw std::runtime_error("Json is not a number"); | ||
| 134 | - } | ||
| 135 | - | ||
| 136 | - std::string get_string() const { | ||
| 137 | - if (type_ != Type::string) throw std::runtime_error("Json is not a string"); | ||
| 138 | - return *string_value_; | ||
| 139 | - } | ||
| 140 | - | ||
| 141 | - std::vector<int64_t> get_int64_array() const { | ||
| 142 | - if (type_ != Type::array) throw std::runtime_error("Json is not an array"); | ||
| 143 | - std::vector<int64_t> result; | ||
| 144 | - for (const auto& item : *array_value_) { | ||
| 145 | - result.push_back(item.get_int64()); | ||
| 146 | - } | ||
| 147 | - return result; | ||
| 148 | - } | ||
| 149 | - | ||
| 150 | - std::vector<double> get_double_array() const { | ||
| 151 | - if (type_ != Type::array) throw std::runtime_error("Json is not an array"); | ||
| 152 | - std::vector<double> result; | ||
| 153 | - for (const auto& item : *array_value_) { | ||
| 154 | - result.push_back(item.get_double()); | ||
| 155 | - } | ||
| 156 | - return result; | ||
| 157 | - } | ||
| 158 | - | ||
| 159 | - std::vector<std::string> get_string_array() const { | ||
| 160 | - if (type_ != Type::array) throw std::runtime_error("Json is not an array"); | ||
| 161 | - std::vector<std::string> result; | ||
| 162 | - for (const auto& item : *array_value_) { | ||
| 163 | - result.push_back(item.get_string()); | ||
| 164 | - } | ||
| 165 | - return result; | ||
| 166 | - } | ||
| 167 | - | ||
| 168 | - Json& operator[](const std::string& key) { | ||
| 169 | - if (type_ == Type::null) { | ||
| 170 | - type_ = Type::object; | ||
| 171 | - object_value_ = new std::map<std::string, Json>(); | ||
| 172 | - } | ||
| 173 | - if (type_ != Type::object) throw std::runtime_error("Json is not an object"); | ||
| 174 | - return (*object_value_)[key]; | ||
| 175 | - } | ||
| 176 | - | ||
| 177 | - const Json& operator[](const std::string& key) const { | ||
| 178 | - if (type_ != Type::object) throw std::runtime_error("Json is not an object"); | ||
| 179 | - static const Json null_json; | ||
| 180 | - auto it = object_value_->find(key); | ||
| 181 | - if (it == object_value_->end()) return null_json; | ||
| 182 | - return it->second; | ||
| 183 | - } | ||
| 184 | - | ||
| 185 | - Json& operator[](size_t index) { | ||
| 186 | - if (type_ != Type::array) throw std::runtime_error("Json is not an array"); | ||
| 187 | - if (index >= array_value_->size()) throw std::runtime_error("Array index out of bounds"); | ||
| 188 | - return (*array_value_)[index]; | ||
| 189 | - } | ||
| 190 | - | ||
| 191 | - const Json& operator[](size_t index) const { | ||
| 192 | - if (type_ != Type::array) throw std::runtime_error("Json is not an array"); | ||
| 193 | - if (index >= array_value_->size()) throw std::runtime_error("Array index out of bounds"); | ||
| 194 | - return (*array_value_)[index]; | ||
| 195 | - } | ||
| 196 | - | ||
| 197 | - bool contains(const std::string& key) const { | ||
| 198 | - if (type_ != Type::object) return false; | ||
| 199 | - return object_value_->find(key) != object_value_->end(); | ||
| 200 | - } | ||
| 201 | - | ||
| 202 | - void push_back(const Json& value) { | ||
| 203 | - if (type_ == Type::null) { | ||
| 204 | - type_ = Type::array; | ||
| 205 | - array_value_ = new std::vector<Json>(); | ||
| 206 | - } | ||
| 207 | - if (type_ != Type::array) throw std::runtime_error("Json is not an array"); | ||
| 208 | - array_value_->push_back(value); | ||
| 209 | - } | ||
| 210 | - | ||
| 211 | - void push_back(Json&& value) { | ||
| 212 | - if (type_ == Type::null) { | ||
| 213 | - type_ = Type::array; | ||
| 214 | - array_value_ = new std::vector<Json>(); | ||
| 215 | - } | ||
| 216 | - if (type_ != Type::array) throw std::runtime_error("Json is not an array"); | ||
| 217 | - array_value_->push_back(std::move(value)); | ||
| 218 | - } | ||
| 219 | - | ||
| 220 | - size_t size() const { | ||
| 221 | - if (type_ == Type::array) return array_value_->size(); | ||
| 222 | - if (type_ == Type::object) return object_value_->size(); | ||
| 223 | - return 0; | ||
| 224 | - } | ||
| 225 | - | ||
| 226 | - std::string dump(int indent = -1) const { | ||
| 227 | - std::ostringstream oss; | ||
| 228 | - Dump(oss, indent, 0); | ||
| 229 | - return oss.str(); | ||
| 230 | - } | ||
| 231 | - | ||
| 232 | - static Json parse(const std::string& str) { | ||
| 233 | - Parser parser(str); | ||
| 234 | - return parser.Parse(); | ||
| 235 | - } | ||
| 236 | - | ||
| 237 | - static Json array() { | ||
| 238 | - Json j; | ||
| 239 | - j.type_ = Type::array; | ||
| 240 | - j.array_value_ = new std::vector<Json>(); | ||
| 241 | - return j; | ||
| 242 | - } | ||
| 243 | - | ||
| 244 | - static Json object() { | ||
| 245 | - Json j; | ||
| 246 | - j.type_ = Type::object; | ||
| 247 | - j.object_value_ = new std::map<std::string, Json>(); | ||
| 248 | - return j; | ||
| 249 | - } | ||
| 250 | - | ||
| 251 | -private: | ||
| 252 | - Type type_; | ||
| 253 | - | ||
| 254 | - union { | ||
| 255 | - bool bool_value_; | ||
| 256 | - int64_t int_value_; | ||
| 257 | - double float_value_; | ||
| 258 | - std::string* string_value_; | ||
| 259 | - std::vector<Json>* array_value_; | ||
| 260 | - std::map<std::string, Json>* object_value_; | ||
| 261 | - }; | ||
| 262 | - | ||
| 263 | - void Clear() { | ||
| 264 | - switch (type_) { | ||
| 265 | - case Type::string: | ||
| 266 | - delete string_value_; | ||
| 267 | - break; | ||
| 268 | - case Type::array: | ||
| 269 | - delete array_value_; | ||
| 270 | - break; | ||
| 271 | - case Type::object: | ||
| 272 | - delete object_value_; | ||
| 273 | - break; | ||
| 274 | - default: | ||
| 275 | - break; | ||
| 276 | - } | ||
| 277 | - } | ||
| 278 | - | ||
| 279 | - void CopyValue(const Json& other) { | ||
| 280 | - switch (other.type_) { | ||
| 281 | - case Type::null: | ||
| 282 | - break; | ||
| 283 | - case Type::boolean: | ||
| 284 | - bool_value_ = other.bool_value_; | ||
| 285 | - break; | ||
| 286 | - case Type::number_integer: | ||
| 287 | - int_value_ = other.int_value_; | ||
| 288 | - break; | ||
| 289 | - case Type::number_float: | ||
| 290 | - float_value_ = other.float_value_; | ||
| 291 | - break; | ||
| 292 | - case Type::string: | ||
| 293 | - string_value_ = new std::string(*other.string_value_); | ||
| 294 | - break; | ||
| 295 | - case Type::array: | ||
| 296 | - array_value_ = new std::vector<Json>(*other.array_value_); | ||
| 297 | - break; | ||
| 298 | - case Type::object: | ||
| 299 | - object_value_ = new std::map<std::string, Json>(*other.object_value_); | ||
| 300 | - break; | ||
| 301 | - } | ||
| 302 | - } | ||
| 303 | - | ||
| 304 | - void MoveValue(Json&& other) { | ||
| 305 | - switch (other.type_) { | ||
| 306 | - case Type::null: | ||
| 307 | - break; | ||
| 308 | - case Type::boolean: | ||
| 309 | - bool_value_ = other.bool_value_; | ||
| 310 | - break; | ||
| 311 | - case Type::number_integer: | ||
| 312 | - int_value_ = other.int_value_; | ||
| 313 | - break; | ||
| 314 | - case Type::number_float: | ||
| 315 | - float_value_ = other.float_value_; | ||
| 316 | - break; | ||
| 317 | - case Type::string: | ||
| 318 | - string_value_ = other.string_value_; | ||
| 319 | - other.string_value_ = nullptr; | ||
| 320 | - break; | ||
| 321 | - case Type::array: | ||
| 322 | - array_value_ = other.array_value_; | ||
| 323 | - other.array_value_ = nullptr; | ||
| 324 | - break; | ||
| 325 | - case Type::object: | ||
| 326 | - object_value_ = other.object_value_; | ||
| 327 | - other.object_value_ = nullptr; | ||
| 328 | - break; | ||
| 329 | - } | ||
| 330 | - } | ||
| 331 | - | ||
| 332 | - void Dump(std::ostringstream& oss, int indent, int level) const { | ||
| 333 | - std::string indent_str; | ||
| 334 | - if (indent > 0) { | ||
| 335 | - indent_str = std::string(level * indent, ' '); | ||
| 336 | - } | ||
| 337 | - | ||
| 338 | - switch (type_) { | ||
| 339 | - case Type::null: | ||
| 340 | - oss << "null"; | ||
| 341 | - break; | ||
| 342 | - case Type::boolean: | ||
| 343 | - oss << (bool_value_ ? "true" : "false"); | ||
| 344 | - break; | ||
| 345 | - case Type::number_integer: | ||
| 346 | - oss << int_value_; | ||
| 347 | - break; | ||
| 348 | - case Type::number_float: | ||
| 349 | - oss << float_value_; | ||
| 350 | - break; | ||
| 351 | - case Type::string: | ||
| 352 | - oss << "\"" << EscapeString(*string_value_) << "\""; | ||
| 353 | - break; | ||
| 354 | - case Type::array: | ||
| 355 | - oss << "["; | ||
| 356 | - if (indent > 0 && !array_value_->empty()) { | ||
| 357 | - oss << "\n"; | ||
| 358 | - } | ||
| 359 | - for (size_t i = 0; i < array_value_->size(); ++i) { | ||
| 360 | - if (indent > 0) { | ||
| 361 | - oss << indent_str << std::string(indent, ' '); | ||
| 362 | - } | ||
| 363 | - (*array_value_)[i].Dump(oss, indent, level + 1); | ||
| 364 | - if (i < array_value_->size() - 1) { | ||
| 365 | - oss << ","; | ||
| 366 | - } | ||
| 367 | - if (indent > 0) { | ||
| 368 | - oss << "\n"; | ||
| 369 | - } | ||
| 370 | - } | ||
| 371 | - if (indent > 0 && !array_value_->empty()) { | ||
| 372 | - oss << indent_str; | ||
| 373 | - } | ||
| 374 | - oss << "]"; | ||
| 375 | - break; | ||
| 376 | - case Type::object: | ||
| 377 | - oss << "{"; | ||
| 378 | - if (indent > 0 && !object_value_->empty()) { | ||
| 379 | - oss << "\n"; | ||
| 380 | - } | ||
| 381 | - auto it = object_value_->begin(); | ||
| 382 | - for (size_t i = 0; i < object_value_->size(); ++i, ++it) { | ||
| 383 | - if (indent > 0) { | ||
| 384 | - oss << indent_str << std::string(indent, ' '); | ||
| 385 | - } | ||
| 386 | - oss << "\"" << it->first << "\":"; | ||
| 387 | - if (indent > 0) { | ||
| 388 | - oss << " "; | ||
| 389 | - } | ||
| 390 | - it->second.Dump(oss, indent, level + 1); | ||
| 391 | - if (i < object_value_->size() - 1) { | ||
| 392 | - oss << ","; | ||
| 393 | - } | ||
| 394 | - if (indent > 0) { | ||
| 395 | - oss << "\n"; | ||
| 396 | - } | ||
| 397 | - } | ||
| 398 | - if (indent > 0 && !object_value_->empty()) { | ||
| 399 | - oss << indent_str; | ||
| 400 | - } | ||
| 401 | - oss << "}"; | ||
| 402 | - break; | ||
| 403 | - } | ||
| 404 | - } | ||
| 405 | - | ||
| 406 | - static std::string EscapeString(const std::string& str) { | ||
| 407 | - std::string result; | ||
| 408 | - for (char c : str) { | ||
| 409 | - switch (c) { | ||
| 410 | - case '"': result += "\\\""; break; | ||
| 411 | - case '\\': result += "\\\\"; break; | ||
| 412 | - case '\b': result += "\\b"; break; | ||
| 413 | - case '\f': result += "\\f"; break; | ||
| 414 | - case '\n': result += "\\n"; break; | ||
| 415 | - case '\r': result += "\\r"; break; | ||
| 416 | - case '\t': result += "\\t"; break; | ||
| 417 | - default: | ||
| 418 | - if (static_cast<unsigned char>(c) < 0x20) { | ||
| 419 | - char buf[7]; | ||
| 420 | - snprintf(buf, sizeof(buf), "\\u%04x", static_cast<unsigned char>(c)); | ||
| 421 | - result += buf; | ||
| 422 | - } else { | ||
| 423 | - result += c; | ||
| 424 | - } | ||
| 425 | - break; | ||
| 426 | - } | ||
| 427 | - } | ||
| 428 | - return result; | ||
| 429 | - } | ||
| 430 | - | ||
| 431 | - class Parser { | ||
| 432 | - public: | ||
| 433 | - Parser(const std::string& str) : str_(str), pos_(0) { | ||
| 434 | - SkipWhitespace(); | ||
| 435 | - } | ||
| 436 | - | ||
| 437 | - Json Parse() { | ||
| 438 | - if (pos_ >= str_.size()) { | ||
| 439 | - throw std::runtime_error("Empty JSON string"); | ||
| 440 | - } | ||
| 441 | - return ParseValue(); | ||
| 442 | - } | ||
| 443 | - | ||
| 444 | - private: | ||
| 445 | - const std::string& str_; | ||
| 446 | - size_t pos_; | ||
| 447 | - | ||
| 448 | - void SkipWhitespace() { | ||
| 449 | - while (pos_ < str_.size() && (str_[pos_] == ' ' || str_[pos_] == '\t' || | ||
| 450 | - str_[pos_] == '\n' || str_[pos_] == '\r')) { | ||
| 451 | - ++pos_; | ||
| 452 | - } | ||
| 453 | - } | ||
| 454 | - | ||
| 455 | - char Peek() const { | ||
| 456 | - if (pos_ >= str_.size()) return '\0'; | ||
| 457 | - return str_[pos_]; | ||
| 458 | - } | ||
| 459 | - | ||
| 460 | - char Consume() { | ||
| 461 | - if (pos_ >= str_.size()) return '\0'; | ||
| 462 | - return str_[pos_++]; | ||
| 463 | - } | ||
| 464 | - | ||
| 465 | - Json ParseValue() { | ||
| 466 | - SkipWhitespace(); | ||
| 467 | - char c = Peek(); | ||
| 468 | - | ||
| 469 | - if (c == 'n') return ParseNull(); | ||
| 470 | - if (c == 't' || c == 'f') return ParseBoolean(); | ||
| 471 | - if (c == '"') return ParseString(); | ||
| 472 | - if (c == '[') return ParseArray(); | ||
| 473 | - if (c == '{') return ParseObject(); | ||
| 474 | - if (c == '-' || (c >= '0' && c <= '9')) return ParseNumber(); | ||
| 475 | - | ||
| 476 | - throw std::runtime_error(std::string("Unexpected character: ") + c); | ||
| 477 | - } | ||
| 478 | - | ||
| 479 | - Json ParseNull() { | ||
| 480 | - if (str_.substr(pos_, 4) == "null") { | ||
| 481 | - pos_ += 4; | ||
| 482 | - return Json(); | ||
| 483 | - } | ||
| 484 | - throw std::runtime_error("Expected 'null'"); | ||
| 485 | - } | ||
| 486 | - | ||
| 487 | - Json ParseBoolean() { | ||
| 488 | - if (str_.substr(pos_, 4) == "true") { | ||
| 489 | - pos_ += 4; | ||
| 490 | - return Json(true); | ||
| 491 | - } | ||
| 492 | - if (str_.substr(pos_, 5) == "false") { | ||
| 493 | - pos_ += 5; | ||
| 494 | - return Json(false); | ||
| 495 | - } | ||
| 496 | - throw std::runtime_error("Expected 'true' or 'false'"); | ||
| 497 | - } | ||
| 498 | - | ||
| 499 | - Json ParseNumber() { | ||
| 500 | - size_t start = pos_; | ||
| 501 | - if (Peek() == '-') Consume(); | ||
| 502 | - | ||
| 503 | - while (pos_ < str_.size() && (str_[pos_] >= '0' && str_[pos_] <= '9')) { | ||
| 504 | - ++pos_; | ||
| 505 | - } | ||
| 506 | - | ||
| 507 | - bool is_float = false; | ||
| 508 | - if (pos_ < str_.size() && str_[pos_] == '.') { | ||
| 509 | - is_float = true; | ||
| 510 | - ++pos_; | ||
| 511 | - while (pos_ < str_.size() && (str_[pos_] >= '0' && str_[pos_] <= '9')) { | ||
| 512 | - ++pos_; | ||
| 513 | - } | ||
| 514 | - } | ||
| 515 | - | ||
| 516 | - if (pos_ < str_.size() && (str_[pos_] == 'e' || str_[pos_] == 'E')) { | ||
| 517 | - is_float = true; | ||
| 518 | - ++pos_; | ||
| 519 | - if (pos_ < str_.size() && (str_[pos_] == '+' || str_[pos_] == '-')) { | ||
| 520 | - ++pos_; | ||
| 521 | - } | ||
| 522 | - while (pos_ < str_.size() && (str_[pos_] >= '0' && str_[pos_] <= '9')) { | ||
| 523 | - ++pos_; | ||
| 524 | - } | ||
| 525 | - } | ||
| 526 | - | ||
| 527 | - std::string num_str = str_.substr(start, pos_ - start); | ||
| 528 | - if (is_float) { | ||
| 529 | - return Json(std::stod(num_str)); | ||
| 530 | - } else { | ||
| 531 | - return Json(static_cast<int64_t>(std::stoll(num_str))); | ||
| 532 | - } | ||
| 533 | - } | ||
| 534 | - | ||
| 535 | - Json ParseString() { | ||
| 536 | - if (Consume() != '"') { | ||
| 537 | - throw std::runtime_error("Expected '\"'"); | ||
| 538 | - } | ||
| 539 | - | ||
| 540 | - std::string result; | ||
| 541 | - while (pos_ < str_.size() && str_[pos_] != '"') { | ||
| 542 | - if (str_[pos_] == '\\') { | ||
| 543 | - ++pos_; | ||
| 544 | - if (pos_ >= str_.size()) { | ||
| 545 | - throw std::runtime_error("Unexpected end of string"); | ||
| 546 | - } | ||
| 547 | - switch (str_[pos_]) { | ||
| 548 | - case '"': result += '"'; break; | ||
| 549 | - case '\\': result += '\\'; break; | ||
| 550 | - case '/': result += '/'; break; | ||
| 551 | - case 'b': result += '\b'; break; | ||
| 552 | - case 'f': result += '\f'; break; | ||
| 553 | - case 'n': result += '\n'; break; | ||
| 554 | - case 'r': result += '\r'; break; | ||
| 555 | - case 't': result += '\t'; break; | ||
| 556 | - case 'u': { | ||
| 557 | - if (pos_ + 4 >= str_.size()) { | ||
| 558 | - throw std::runtime_error("Invalid unicode escape"); | ||
| 559 | - } | ||
| 560 | - std::string hex_str = str_.substr(pos_ + 1, 4); | ||
| 561 | - unsigned int codepoint = std::stoul(hex_str, nullptr, 16); | ||
| 562 | - if (codepoint < 0x80) { | ||
| 563 | - result += static_cast<char>(codepoint); | ||
| 564 | - } else if (codepoint < 0x800) { | ||
| 565 | - result += static_cast<char>(0xC0 | (codepoint >> 6)); | ||
| 566 | - result += static_cast<char>(0x80 | (codepoint & 0x3F)); | ||
| 567 | - } else { | ||
| 568 | - result += static_cast<char>(0xE0 | (codepoint >> 12)); | ||
| 569 | - result += static_cast<char>(0x80 | ((codepoint >> 6) & 0x3F)); | ||
| 570 | - result += static_cast<char>(0x80 | (codepoint & 0x3F)); | ||
| 571 | - } | ||
| 572 | - pos_ += 4; | ||
| 573 | - break; | ||
| 574 | - } | ||
| 575 | - default: | ||
| 576 | - throw std::runtime_error("Invalid escape sequence"); | ||
| 577 | - } | ||
| 578 | - } else { | ||
| 579 | - result += str_[pos_]; | ||
| 580 | - } | ||
| 581 | - ++pos_; | ||
| 582 | - } | ||
| 583 | - | ||
| 584 | - if (pos_ >= str_.size() || Consume() != '"') { | ||
| 585 | - throw std::runtime_error("Unterminated string"); | ||
| 586 | - } | ||
| 587 | - | ||
| 588 | - return Json(result); | ||
| 589 | - } | ||
| 590 | - | ||
| 591 | - Json ParseArray() { | ||
| 592 | - if (Consume() != '[') { | ||
| 593 | - throw std::runtime_error("Expected '['"); | ||
| 594 | - } | ||
| 595 | - | ||
| 596 | - Json result = Json::array(); | ||
| 597 | - SkipWhitespace(); | ||
| 598 | - | ||
| 599 | - if (Peek() == ']') { | ||
| 600 | - Consume(); | ||
| 601 | - return result; | ||
| 602 | - } | ||
| 603 | - | ||
| 604 | - while (true) { | ||
| 605 | - result.push_back(ParseValue()); | ||
| 606 | - SkipWhitespace(); | ||
| 607 | - | ||
| 608 | - if (Peek() == ']') { | ||
| 609 | - Consume(); | ||
| 610 | - return result; | ||
| 611 | - } | ||
| 612 | - | ||
| 613 | - if (Peek() == ',') { | ||
| 614 | - Consume(); | ||
| 615 | - } else { | ||
| 616 | - throw std::runtime_error("Expected ',' or ']' in array"); | ||
| 617 | - } | ||
| 618 | - } | ||
| 619 | - } | ||
| 620 | - | ||
| 621 | - Json ParseObject() { | ||
| 622 | - if (Consume() != '{') { | ||
| 623 | - throw std::runtime_error("Expected '{'"); | ||
| 624 | - } | ||
| 625 | - | ||
| 626 | - Json result = Json::object(); | ||
| 627 | - SkipWhitespace(); | ||
| 628 | - | ||
| 629 | - if (Peek() == '}') { | ||
| 630 | - Consume(); | ||
| 631 | - return result; | ||
| 632 | - } | ||
| 633 | - | ||
| 634 | - while (true) { | ||
| 635 | - SkipWhitespace(); | ||
| 636 | - Json key = ParseString(); | ||
| 637 | - SkipWhitespace(); | ||
| 638 | - | ||
| 639 | - if (Consume() != ':') { | ||
| 640 | - throw std::runtime_error("Expected ':' after key"); | ||
| 641 | - } | ||
| 642 | - | ||
| 643 | - Json value = ParseValue(); | ||
| 644 | - result[key.get_string()] = std::move(value); | ||
| 645 | - SkipWhitespace(); | ||
| 646 | - | ||
| 647 | - if (Peek() == '}') { | ||
| 648 | - Consume(); | ||
| 649 | - return result; | ||
| 650 | - } | ||
| 651 | - | ||
| 652 | - if (Peek() == ',') { | ||
| 653 | - Consume(); | ||
| 654 | - } else { | ||
| 655 | - throw std::runtime_error("Expected ',' or '}' in object"); | ||
| 656 | - } | ||
| 657 | - } | ||
| 658 | - } | ||
| 659 | - }; | ||
| 660 | -}; | ||
| 661 | - | ||
| 662 | -} // namespace json_internal | ||
| 663 | - | ||
| 664 | -namespace crypto { | ||
| 665 | - | ||
| 666 | -class SHA1 { | ||
| 667 | -public: | ||
| 668 | - static constexpr size_t DIGEST_LENGTH = 20; | ||
| 669 | - | ||
| 670 | - static std::string Hash(const std::string& input) { | ||
| 671 | - SHA1 sha1; | ||
| 672 | - sha1.Update(reinterpret_cast<const uint8_t*>(input.c_str()), input.length()); | ||
| 673 | - uint8_t digest[DIGEST_LENGTH]; | ||
| 674 | - sha1.Final(digest); | ||
| 675 | - return DigestToHex(digest); | ||
| 676 | - } | ||
| 677 | - | ||
| 678 | -private: | ||
| 679 | - SHA1() { | ||
| 680 | - Reset(); | ||
| 681 | - } | ||
| 682 | - | ||
| 683 | - void Reset() { | ||
| 684 | - m_digest[0] = 0x67452301; | ||
| 685 | - m_digest[1] = 0xEFCDAB89; | ||
| 686 | - m_digest[2] = 0x98BADCFE; | ||
| 687 | - m_digest[3] = 0x10325476; | ||
| 688 | - m_digest[4] = 0xC3D2E1F0; | ||
| 689 | - m_block_len = 0; | ||
| 690 | - m_total_len = 0; | ||
| 691 | - } | ||
| 692 | - | ||
| 693 | - void Update(const uint8_t* data, size_t len) { | ||
| 694 | - while (len) { | ||
| 695 | - size_t copy_len = std::min(len, 64 - m_block_len); | ||
| 696 | - std::memcpy(m_block + m_block_len, data, copy_len); | ||
| 697 | - | ||
| 698 | - m_block_len += copy_len; | ||
| 699 | - m_total_len += copy_len; | ||
| 700 | - data += copy_len; | ||
| 701 | - len -= copy_len; | ||
| 702 | - | ||
| 703 | - if (m_block_len == 64) { | ||
| 704 | - ProcessBlock(m_block); | ||
| 705 | - m_block_len = 0; | ||
| 706 | - } | ||
| 707 | - } | ||
| 708 | - } | ||
| 709 | - | ||
| 710 | - void Final(uint8_t* digest) { | ||
| 711 | - uint64_t total_bits = m_total_len * 8; | ||
| 712 | - | ||
| 713 | - m_block[m_block_len++] = 0x80; | ||
| 714 | - if (m_block_len > 56) { | ||
| 715 | - while (m_block_len < 64) { | ||
| 716 | - m_block[m_block_len++] = 0; | ||
| 717 | - } | ||
| 718 | - ProcessBlock(m_block); | ||
| 719 | - m_block_len = 0; | ||
| 720 | - } | ||
| 721 | - | ||
| 722 | - while (m_block_len < 56) { | ||
| 723 | - m_block[m_block_len++] = 0; | ||
| 724 | - } | ||
| 725 | - | ||
| 726 | - for (int i = 7; i >= 0; --i) { | ||
| 727 | - m_block[m_block_len++] = static_cast<uint8_t>((total_bits >> (i * 8)) & 0xFF); | ||
| 728 | - } | ||
| 729 | - | ||
| 730 | - ProcessBlock(m_block); | ||
| 731 | - | ||
| 732 | - for (int i = 0; i < 5; ++i) { | ||
| 733 | - digest[i * 4 + 0] = static_cast<uint8_t>((m_digest[i] >> 24) & 0xFF); | ||
| 734 | - digest[i * 4 + 1] = static_cast<uint8_t>((m_digest[i] >> 16) & 0xFF); | ||
| 735 | - digest[i * 4 + 2] = static_cast<uint8_t>((m_digest[i] >> 8) & 0xFF); | ||
| 736 | - digest[i * 4 + 3] = static_cast<uint8_t>(m_digest[i] & 0xFF); | ||
| 737 | - } | ||
| 738 | - } | ||
| 739 | - | ||
| 740 | - void ProcessBlock(const uint8_t* block) { | ||
| 741 | - uint32_t w[80]; | ||
| 742 | - | ||
| 743 | - for (int i = 0; i < 16; ++i) { | ||
| 744 | - w[i] = (block[i * 4 + 0] << 24) | (block[i * 4 + 1] << 16) | | ||
| 745 | - (block[i * 4 + 2] << 8) | block[i * 4 + 3]; | ||
| 746 | - } | ||
| 747 | - | ||
| 748 | - for (int i = 16; i < 80; ++i) { | ||
| 749 | - uint32_t temp = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]; | ||
| 750 | - w[i] = ROTL(temp, 1); | ||
| 751 | - } | ||
| 752 | - | ||
| 753 | - uint32_t a = m_digest[0]; | ||
| 754 | - uint32_t b = m_digest[1]; | ||
| 755 | - uint32_t c = m_digest[2]; | ||
| 756 | - uint32_t d = m_digest[3]; | ||
| 757 | - uint32_t e = m_digest[4]; | ||
| 758 | - | ||
| 759 | - for (int i = 0; i < 80; ++i) { | ||
| 760 | - uint32_t f, k; | ||
| 761 | - | ||
| 762 | - if (i < 20) { | ||
| 763 | - f = (b & c) | ((~b) & d); | ||
| 764 | - k = 0x5A827999; | ||
| 765 | - } else if (i < 40) { | ||
| 766 | - f = b ^ c ^ d; | ||
| 767 | - k = 0x6ED9EBA1; | ||
| 768 | - } else if (i < 60) { | ||
| 769 | - f = (b & c) | (b & d) | (c & d); | ||
| 770 | - k = 0x8F1BBCDC; | ||
| 771 | - } else { | ||
| 772 | - f = b ^ c ^ d; | ||
| 773 | - k = 0xCA62C1D6; | ||
| 774 | - } | ||
| 775 | - | ||
| 776 | - uint32_t temp = ROTL(a, 5) + f + e + k + w[i]; | ||
| 777 | - e = d; | ||
| 778 | - d = c; | ||
| 779 | - c = ROTL(b, 30); | ||
| 780 | - b = a; | ||
| 781 | - a = temp; | ||
| 782 | - } | ||
| 783 | - | ||
| 784 | - m_digest[0] += a; | ||
| 785 | - m_digest[1] += b; | ||
| 786 | - m_digest[2] += c; | ||
| 787 | - m_digest[3] += d; | ||
| 788 | - m_digest[4] += e; | ||
| 789 | - } | ||
| 790 | - | ||
| 791 | - static uint32_t ROTL(uint32_t x, uint32_t n) { | ||
| 792 | - return (x << n) | (x >> (32 - n)); | ||
| 793 | - } | ||
| 794 | - | ||
| 795 | - static std::string DigestToHex(const uint8_t* digest) { | ||
| 796 | - std::ostringstream oss; | ||
| 797 | - oss << std::hex << std::setfill('0'); | ||
| 798 | - for (size_t i = 0; i < DIGEST_LENGTH; ++i) { | ||
| 799 | - oss << std::setw(2) << static_cast<int>(digest[i]); | ||
| 800 | - } | ||
| 801 | - return oss.str(); | ||
| 802 | - } | ||
| 803 | - | ||
| 804 | - uint32_t m_digest[5]; | ||
| 805 | - uint8_t m_block[64]; | ||
| 806 | - size_t m_block_len; | ||
| 807 | - uint64_t m_total_len; | ||
| 808 | -}; | ||
| 809 | - | ||
| 810 | -} // namespace crypto | ||
| 811 | - | ||
| 812 | -using Json = json_internal::Json; | ||
| 813 | - | ||
| 814 | struct TensorInfo { | 31 | struct TensorInfo { |
| 815 | std::string param_name; | 32 | std::string param_name; |
| 816 | std::vector<int64_t> shape; | 33 | std::vector<int64_t> shape; |
| @@ -862,6 +79,13 @@ struct TilingResult { | |||
| 862 | MatMulV3BasicTilingData matmul_basic_tiling_data; | 79 | MatMulV3BasicTilingData matmul_basic_tiling_data; |
| 863 | }; | 80 | }; |
| 864 | 81 | ||
| 82 | +extern "C" bool AutofuseDoCubeMatMulTiling(const CompileInfo* compile_info, | ||
| 83 | + const std::vector<TensorInfo>* inputs, | ||
| 84 | + const std::vector<TensorInfo>* outputs, | ||
| 85 | + const std::vector<AttrInfo>* attrs, | ||
| 86 | + bool is_batch, | ||
| 87 | + TilingResult* result); | ||
| 88 | + | ||
| 865 | class CubeKernelTilingWrapper { | 89 | class CubeKernelTilingWrapper { |
| 866 | public: | 90 | public: |
| 867 | CubeKernelTilingWrapper(); | 91 | CubeKernelTilingWrapper(); |
| @@ -874,38 +98,12 @@ public: | |||
| 874 | bool is_batch = false); | 98 | bool is_batch = false); |
| 875 | 99 | ||
| 876 | static void BuildMatMulArgs(const std::vector<TensorInfo>& args_list, | 100 | static void BuildMatMulArgs(const std::vector<TensorInfo>& args_list, |
| 877 | - int input_num, | 101 | + int input_num, |
| 878 | - bool transpose_a, | 102 | + bool transpose_a, |
| 879 | - bool transpose_b, | 103 | + bool transpose_b, |
| 880 | - std::vector<TensorInfo>& origin_inputs, | 104 | + std::vector<TensorInfo>& origin_inputs, |
| 881 | - std::vector<TensorInfo>& origin_outputs, | 105 | + std::vector<TensorInfo>& origin_outputs, |
| 882 | - std::vector<TensorInfo>& inputs); | 106 | + std::vector<TensorInfo>& inputs); |
| 883 | - | ||
| 884 | - static std::string GenerateCompileInfoHash(const std::string& compile_info_info); | ||
| 885 | - | ||
| 886 | - static void ChangeParamNameToName(std::vector<TensorInfo>& inputs); | ||
| 887 | - static void InputsPreProcess(std::vector<TensorInfo>& inputs); | ||
| 888 | - static void AttrsPreProcess(std::vector<AttrInfo>& attrs); | ||
| 889 | - static std::vector<uint8_t> AlignTilingDataTo8Bytes(const std::vector<uint8_t>& tiling_data, const std::string& soc_version); | ||
| 890 | - | ||
| 891 | -private: | ||
| 892 | - static std::string SerializeToJson(const CompileInfo& compile_info); | ||
| 893 | - static std::string SerializeToJson(const std::vector<TensorInfo>& tensors); | ||
| 894 | - static std::string SerializeToJson(const std::vector<AttrInfo>& attrs); | ||
| 895 | - static std::string SerializeToJson(const std::map<std::string, std::string>& extra_params); | ||
| 896 | - | ||
| 897 | - static bool ParseTilingResult(const std::string& json_str, TilingResult& result); | ||
| 898 | - | ||
| 899 | - char* CallDoOpTilingForCompile(const char* op_type, | ||
| 900 | - const char* compile_info, | ||
| 901 | - const char* compile_info_hash, | ||
| 902 | - const char* inputs, | ||
| 903 | - const char* outputs, | ||
| 904 | - const char* attrs, | ||
| 905 | - char* buf, | ||
| 906 | - size_t buf_size, | ||
| 907 | - uint64_t* timer, | ||
| 908 | - const char* extra_params); | ||
| 909 | }; | 107 | }; |
| 910 | 108 | ||
| 911 | } // namespace autofuse | 109 | } // namespace autofuse |
| @@ -916,413 +114,1052 @@ private: | |||
| 916 | 114 | ||
| 917 | inline const std::string kCubeKernelTilingWrapperCppValue = R"( | 115 | inline const std::string kCubeKernelTilingWrapperCppValue = R"( |
| 918 | 116 | ||
| 919 | -#include <sstream> | 117 | +#include "registry/op_impl_space_registry_v2.h" |
| 920 | -#include <iomanip> | 118 | + |
| 921 | -#include <dlfcn.h> | 119 | +#include "context_builder/op_tiling_context_builder.h" |
| 922 | -#include <iostream> | 120 | +#include "context_builder/op_tiling_parse_context_builder.h" |
| 121 | + | ||
| 122 | + | ||
| 123 | + | ||
| 124 | + | ||
| 125 | + | ||
| 126 | + | ||
| 127 | + | ||
| 128 | + | ||
| 129 | + | ||
| 130 | + | ||
| 923 | 131 | ||
| 924 | - | ||
| 925 | 132 | ||
| 926 | - | ||
| 927 | 133 | ||
| 928 | - | 134 | +#include <map> |
| 929 | -using json = ge::autofuse::Json; | 135 | +#include <memory> |
| 930 | -using SHA1 = ge::autofuse::crypto::SHA1; | 136 | +#include <mutex> |
| 931 | - | 137 | +#include <sstream> |
| 932 | -#ifndef DEFAULT_ASCEND_OPP_PATH | 138 | +#include <tuple> |
| 933 | -#define DEFAULT_ASCEND_OPP_PATH "/usr/local/Ascend/cann/opp" | 139 | +#include <type_traits> |
| 934 | -#endif | 140 | +#include <utility> |
| 935 | - | ||
| 936 | -extern "C" const char *DoOpTilingForCompile(const char *optype, | ||
| 937 | - const char *compile_info, | ||
| 938 | - const char *compile_info_hash, | ||
| 939 | - const char *inputs, | ||
| 940 | - const char *outputs, | ||
| 941 | - const char *attrs, | ||
| 942 | - char *run_info_json, | ||
| 943 | - size_t run_info_len, | ||
| 944 | - uint64_t *elapse, | ||
| 945 | - const char *extra_info); | ||
| 946 | 141 | ||
| 947 | namespace ge { | 142 | namespace ge { |
| 948 | namespace autofuse { | 143 | namespace autofuse { |
| 949 | 144 | ||
| 145 | +namespace { | ||
| 146 | +constexpr size_t kMaxTilingDataSize = 64 * 1024; | ||
| 147 | +constexpr size_t kWorkspaceCapacity = 4096; | ||
| 148 | +const std::vector<uint32_t> kSingleOutputInstanceNum = {1U}; | ||
| 149 | + | ||
| 150 | +struct OpHostFuncs { | ||
| 151 | + gert::OpImplRegisterV2::TilingKernelFunc tiling = nullptr; | ||
| 152 | + gert::OpImplRegisterV2::KernelFunc tiling_parse = nullptr; | ||
| 153 | + gert::OpImplRegisterV2::CompileInfoCreatorFunc compile_info_creator = nullptr; | ||
| 154 | + size_t max_tiling_data_size = 0UL; | ||
| 155 | +}; | ||
| 156 | + | ||
| 157 | +struct CachedOpHostFuncs { | ||
| 158 | + OpHostFuncs funcs; | ||
| 159 | + bool loaded = false; | ||
| 160 | + std::once_flag once; | ||
| 161 | +}; | ||
| 162 | + | ||
| 163 | +struct OpHostSchema { | ||
| 164 | + const char *op_type; | ||
| 165 | +}; | ||
| 166 | + | ||
| 167 | +struct MatMulAttrs { | ||
| 168 | + bool transpose_x1 = false; | ||
| 169 | + bool transpose_x2 = false; | ||
| 170 | + int64_t offset_x = 0; | ||
| 171 | + int64_t op_impl_mode = 0; | ||
| 172 | + bool enable_hf32 = false; | ||
| 173 | + bool has_bias = false; | ||
| 174 | + bool has_offset_w = false; | ||
| 175 | + bool has_optional_input_markers = false; | ||
| 176 | +}; | ||
| 177 | + | ||
| 178 | +struct RuntimeTilingKey { | ||
| 179 | + std::string soc_version; | ||
| 180 | + std::string device_id; | ||
| 181 | + std::string op_type; | ||
| 182 | + std::string dtype; | ||
| 183 | + std::string format; | ||
| 184 | + std::vector<int64_t> input0_shape; | ||
| 185 | + std::vector<int64_t> input1_shape; | ||
| 186 | + std::vector<int64_t> input2_shape; | ||
| 187 | + std::vector<int64_t> input3_shape; | ||
| 188 | + std::string input2_dtype; | ||
| 189 | + std::string input3_dtype; | ||
| 190 | + std::string input2_format; | ||
| 191 | + std::string input3_format; | ||
| 192 | + std::vector<int64_t> output_shape; | ||
| 193 | + bool is_batch = false; | ||
| 194 | + size_t input_num = 0U; | ||
| 195 | + bool has_bias = false; | ||
| 196 | + bool has_offset_w = false; | ||
| 197 | + bool transpose_x1 = false; | ||
| 198 | + bool transpose_x2 = false; | ||
| 199 | + int64_t offset_x = 0; | ||
| 200 | + int64_t op_impl_mode = 0; | ||
| 201 | + bool enable_hf32 = false; | ||
| 202 | + int64_t aicore_num = 0; | ||
| 203 | + int64_t aiv_num = 0; | ||
| 204 | + | ||
| 205 | + bool operator<(const RuntimeTilingKey &other) const { | ||
| 206 | + return std::tie(soc_version, device_id, op_type, dtype, format, input0_shape, input1_shape, input2_shape, | ||
| 207 | + input3_shape, input2_dtype, input3_dtype, input2_format, input3_format, output_shape, is_batch, | ||
| 208 | + input_num, has_bias, has_offset_w, transpose_x1, transpose_x2, offset_x, op_impl_mode, enable_hf32, | ||
| 209 | + aicore_num, aiv_num) < | ||
| 210 | + std::tie(other.soc_version, other.device_id, other.op_type, other.dtype, other.format, other.input0_shape, | ||
| 211 | + other.input1_shape, other.input2_shape, other.input3_shape, other.input2_dtype, other.input3_dtype, | ||
| 212 | + other.input2_format, other.input3_format, other.output_shape, other.is_batch, other.input_num, | ||
| 213 | + other.has_bias, other.has_offset_w, other.transpose_x1, other.transpose_x2, other.offset_x, | ||
| 214 | + other.op_impl_mode, other.enable_hf32, other.aicore_num, other.aiv_num); | ||
| 215 | + } | ||
| 216 | +}; | ||
| 217 | + | ||
| 218 | +struct CompileState; | ||
| 219 | + | ||
| 220 | +struct CompileStateKey { | ||
| 221 | + std::string soc_version; | ||
| 222 | + std::string device_id; | ||
| 223 | + std::string dtype; | ||
| 224 | + std::string format; | ||
| 225 | + std::string input2_dtype; | ||
| 226 | + std::string input3_dtype; | ||
| 227 | + std::string input2_format; | ||
| 228 | + std::string input3_format; | ||
| 229 | + bool is_batch = false; | ||
| 230 | + size_t input_num = 0U; | ||
| 231 | + bool has_bias = false; | ||
| 232 | + bool has_offset_w = false; | ||
| 233 | + bool transpose_x1 = false; | ||
| 234 | + bool transpose_x2 = false; | ||
| 235 | + int64_t offset_x = 0; | ||
| 236 | + int64_t op_impl_mode = 0; | ||
| 237 | + bool enable_hf32 = false; | ||
| 238 | + int64_t aicore_num = 0; | ||
| 239 | + int64_t aiv_num = 0; | ||
| 240 | + | ||
| 241 | + bool operator<(const CompileStateKey &other) const { | ||
| 242 | + return std::tie(soc_version, device_id, dtype, format, input2_dtype, input3_dtype, input2_format, input3_format, | ||
| 243 | + is_batch, input_num, transpose_x1, transpose_x2, offset_x, op_impl_mode, enable_hf32, aicore_num, | ||
| 244 | + aiv_num, has_bias, has_offset_w) < | ||
| 245 | + std::tie(other.soc_version, other.device_id, other.dtype, other.format, other.input2_dtype, | ||
| 246 | + other.input3_dtype, other.input2_format, other.input3_format, other.is_batch, other.input_num, | ||
| 247 | + other.transpose_x1, other.transpose_x2, other.offset_x, other.op_impl_mode, other.enable_hf32, | ||
| 248 | + other.aicore_num, other.aiv_num, other.has_bias, other.has_offset_w); | ||
| 249 | + } | ||
| 250 | +}; | ||
| 251 | + | ||
| 252 | +struct CompileState { | ||
| 253 | + std::string compile_json; | ||
| 254 | + fe::PlatFormInfos platform_info; | ||
| 255 | + void *compile_info_ptr = nullptr; | ||
| 256 | +}; | ||
| 257 | + | ||
| 258 | +struct TilingRequest { | ||
| 259 | + const CompileInfo &compile_info; | ||
| 260 | + const std::vector<TensorInfo> &inputs; | ||
| 261 | + const std::vector<TensorInfo> &outputs; | ||
| 262 | + bool is_batch = false; | ||
| 263 | + const OpHostSchema &schema; | ||
| 264 | + MatMulAttrs matmul_attrs; | ||
| 265 | + ge::DataType data_type = ge::DT_UNDEFINED; | ||
| 266 | + ge::Format format = ge::FORMAT_RESERVED; | ||
| 267 | +}; | ||
| 268 | + | ||
| 269 | +struct TilingScratch { | ||
| 270 | + std::unique_ptr<uint8_t[]> tiling_data_holder; | ||
| 271 | + std::unique_ptr<uint8_t[]> workspace_holder; | ||
| 272 | + size_t tiling_data_capacity = 0UL; | ||
| 273 | + std::vector<gert::Tensor *> input_tensors; | ||
| 274 | + std::vector<gert::Tensor *> output_tensors; | ||
| 275 | + | ||
| 276 | + bool EnsureCapacity(size_t required_tiling_data_capacity, std::string &error_msg, const char *op_type) { | ||
| 277 | + if (tiling_data_holder == nullptr || required_tiling_data_capacity > tiling_data_capacity) { | ||
| 278 | + auto new_tiling_data_holder = gert::TilingData::CreateCap(required_tiling_data_capacity); | ||
| 279 | + if (new_tiling_data_holder == nullptr) { | ||
| 280 | + error_msg = std::string(op_type) + " tiling data allocation failed"; | ||
| 281 | + return false; | ||
| 282 | + } | ||
| 283 | + tiling_data_holder = std::move(new_tiling_data_holder); | ||
| 284 | + tiling_data_capacity = required_tiling_data_capacity; | ||
| 285 | + } | ||
| 286 | + if (workspace_holder == nullptr) { | ||
| 287 | + workspace_holder = gert::ContinuousVector::Create<size_t>(kWorkspaceCapacity); | ||
| 288 | + if (workspace_holder == nullptr) { | ||
| 289 | + error_msg = std::string(op_type) + " workspace allocation failed"; | ||
| 290 | + return false; | ||
| 291 | + } | ||
| 292 | + } | ||
| 293 | + input_tensors.reserve(4U); | ||
| 294 | + output_tensors.reserve(1U); | ||
| 295 | + return true; | ||
| 296 | + } | ||
| 297 | + | ||
| 298 | + gert::TilingData *MutableTilingData() const { | ||
| 299 | + return reinterpret_cast<gert::TilingData *>(tiling_data_holder.get()); | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + gert::ContinuousVector *MutableWorkspace() const { | ||
| 303 | + return reinterpret_cast<gert::ContinuousVector *>(workspace_holder.get()); | ||
| 304 | + } | ||
| 305 | +}; | ||
| 306 | + | ||
| 307 | +TilingScratch &GetTilingScratch() { | ||
| 308 | + thread_local TilingScratch scratch; | ||
| 309 | + return scratch; | ||
| 310 | +} | ||
| 311 | + | ||
| 312 | +CachedOpHostFuncs &GetMatMulFuncsCache() { | ||
| 313 | + static auto *cache = new CachedOpHostFuncs(); | ||
| 314 | + return *cache; | ||
| 315 | +} | ||
| 316 | + | ||
| 317 | +CachedOpHostFuncs &GetBatchMatMulFuncsCache() { | ||
| 318 | + static auto *cache = new CachedOpHostFuncs(); | ||
| 319 | + return *cache; | ||
| 320 | +} | ||
| 321 | + | ||
| 322 | +std::mutex &GetCompileStateMutex() { | ||
| 323 | + static auto *mutex = new std::mutex(); | ||
| 324 | + return *mutex; | ||
| 325 | +} | ||
| 326 | + | ||
| 327 | +std::map<CompileStateKey, std::shared_ptr<const CompileState>> &GetCompileStateCache() { | ||
| 328 | + static auto cache = std::make_shared<std::map<CompileStateKey, std::shared_ptr<const CompileState>>>(); | ||
| 329 | + return *cache; | ||
| 330 | +} | ||
| 331 | + | ||
| 332 | +std::mutex &GetTilingResultCacheMutex() { | ||
| 333 | + static auto *mutex = new std::mutex(); | ||
| 334 | + return *mutex; | ||
| 335 | +} | ||
| 336 | + | ||
| 337 | +std::map<RuntimeTilingKey, TilingResult> &GetTilingResultCache() { | ||
| 338 | + static auto *cache = new std::map<RuntimeTilingKey, TilingResult>(); | ||
| 339 | + return *cache; | ||
| 340 | +} | ||
| 341 | + | ||
| 342 | +const OpHostSchema &GetOpHostSchema(bool is_batch) { | ||
| 343 | + static const OpHostSchema kMatMulV3Schema{"MatMulV3"}; | ||
| 344 | + static const OpHostSchema kBatchMatMulV3Schema{"BatchMatMulV3"}; | ||
| 345 | + return is_batch ? kBatchMatMulV3Schema : kMatMulV3Schema; | ||
| 346 | +} | ||
| 347 | + | ||
| 348 | +ge::DataType DtypeToGeDataType(const std::string &dtype) { | ||
| 349 | + if (dtype == "float" || dtype == "float32" || dtype == "DT_FLOAT" || dtype == "torch.float32") { | ||
| 350 | + return ge::DT_FLOAT; | ||
| 351 | + } | ||
| 352 | + if (dtype == "float16" || dtype == "half" || dtype == "DT_FLOAT16" || dtype == "torch.float16") { | ||
| 353 | + return ge::DT_FLOAT16; | ||
| 354 | + } | ||
| 355 | + if (dtype == "bfloat16" || dtype == "bf16" || dtype == "DT_BF16" || dtype == "torch.bfloat16") { | ||
| 356 | + return ge::DT_BF16; | ||
| 357 | + } | ||
| 358 | + return ge::DT_UNDEFINED; | ||
| 359 | +} | ||
| 360 | + | ||
| 361 | +ge::Format FormatToGeFormat(const std::string &format) { | ||
| 362 | + if (format.empty() || format == "ND" || format == "FORMAT_ND" || format == "ACL_FORMAT_ND") { | ||
| 363 | + return ge::FORMAT_ND; | ||
| 364 | + } | ||
| 365 | + return ge::FORMAT_RESERVED; | ||
| 366 | +} | ||
| 367 | + | ||
| 368 | +bool AttrAsBool(const AttrInfo &attr) { | ||
| 369 | + if (attr.dtype == "bool") { | ||
| 370 | + return attr.value_bool; | ||
| 371 | + } | ||
| 372 | + if (attr.dtype == "int" || attr.dtype == "int32" || attr.dtype == "int64") { | ||
| 373 | + return attr.value_int != 0; | ||
| 374 | + } | ||
| 375 | + return false; | ||
| 376 | +} | ||
| 377 | + | ||
| 378 | +int64_t AttrAsInt(const AttrInfo &attr) { | ||
| 379 | + if (attr.dtype == "bool") { | ||
| 380 | + return attr.value_bool ? 1 : 0; | ||
| 381 | + } | ||
| 382 | + if (attr.dtype == "int" || attr.dtype == "int32" || attr.dtype == "int64") { | ||
| 383 | + return attr.value_int; | ||
| 384 | + } | ||
| 385 | + return 0; | ||
| 386 | +} | ||
| 387 | + | ||
| 388 | +MatMulAttrs ReadMatMulAttrs(const std::vector<AttrInfo> &attrs, bool is_batch) { | ||
| 389 | + MatMulAttrs result; | ||
| 390 | + const char *transpose_x1_name = is_batch ? "adj_x1" : "transpose_x1"; | ||
| 391 | + const char *transpose_x2_name = is_batch ? "adj_x2" : "transpose_x2"; | ||
| 392 | + for (const auto &attr : attrs) { | ||
| 393 | + if (attr.name == transpose_x1_name) { | ||
| 394 | + result.transpose_x1 = AttrAsBool(attr); | ||
| 395 | + } else if (attr.name == transpose_x2_name) { | ||
| 396 | + result.transpose_x2 = AttrAsBool(attr); | ||
| 397 | + } else if (attr.name == "offset_x") { | ||
| 398 | + result.offset_x = AttrAsInt(attr); | ||
| 399 | + } else if (attr.name == "opImplMode") { | ||
| 400 | + result.op_impl_mode = AttrAsInt(attr); | ||
| 401 | + } else if (attr.name == "enable_hf32") { | ||
| 402 | + result.enable_hf32 = AttrAsBool(attr); | ||
| 403 | + } else if (attr.name == "autofuse_has_bias") { | ||
| 404 | + result.has_bias = AttrAsBool(attr); | ||
| 405 | + result.has_optional_input_markers = true; | ||
| 406 | + } else if (attr.name == "autofuse_has_offset_w") { | ||
| 407 | + result.has_offset_w = AttrAsBool(attr); | ||
| 408 | + result.has_optional_input_markers = true; | ||
| 409 | + } | ||
| 410 | + } | ||
| 411 | + result.enable_hf32 = result.enable_hf32 || result.op_impl_mode != 0; | ||
| 412 | + return result; | ||
| 413 | +} | ||
| 414 | + | ||
| 415 | +bool LoadOpHostFuncs(const char *op_type, OpHostFuncs &funcs) { | ||
| 416 | + auto registry = gert::DefaultOpImplSpaceRegistryV2::GetInstance().GetSpaceRegistry(); | ||
| 417 | + if (registry == nullptr) { | ||
| 418 | + return false; | ||
| 419 | + } | ||
| 420 | + const auto *op_impl = registry->GetOpImpl(op_type); | ||
| 421 | + if (op_impl == nullptr) { | ||
| 422 | + return false; | ||
| 423 | + } | ||
| 424 | + funcs.tiling = op_impl->tiling; | ||
| 425 | + funcs.tiling_parse = op_impl->tiling_parse; | ||
| 426 | + funcs.compile_info_creator = op_impl->compile_info_creator; | ||
| 427 | + funcs.max_tiling_data_size = op_impl->max_tiling_data_size; | ||
| 428 | + return funcs.tiling != nullptr && funcs.tiling_parse != nullptr && funcs.compile_info_creator != nullptr; | ||
| 429 | +} | ||
| 430 | + | ||
| 431 | +const CachedOpHostFuncs &GetOpHostFuncs(bool is_batch, const char *op_type) { | ||
| 432 | + CachedOpHostFuncs &cache = is_batch ? GetBatchMatMulFuncsCache() : GetMatMulFuncsCache(); | ||
| 433 | + std::call_once(cache.once, [&cache, op_type]() { cache.loaded = LoadOpHostFuncs(op_type, cache.funcs); }); | ||
| 434 | + return cache; | ||
| 435 | +} | ||
| 436 | + | ||
| 437 | +bool ParseUint32(const std::string &value, uint32_t &result) { | ||
| 438 | + if (value.empty()) { | ||
| 439 | + return false; | ||
| 440 | + } | ||
| 441 | + char *end = nullptr; | ||
| 442 | + const unsigned long parsed = std::strtoul(value.c_str(), &end, 10); | ||
| 443 | + if (end == value.c_str() || *end != '\0' || parsed > std::numeric_limits<uint32_t>::max()) { | ||
| 444 | + return false; | ||
| 445 | + } | ||
| 446 | + result = static_cast<uint32_t>(parsed); | ||
| 447 | + return true; | ||
| 448 | +} | ||
| 449 | + | ||
| 450 | +bool ParseUint64(const std::string &value, uint64_t &result) { | ||
| 451 | + if (value.empty()) { | ||
| 452 | + return false; | ||
| 453 | + } | ||
| 454 | + char *end = nullptr; | ||
| 455 | + const unsigned long long parsed = std::strtoull(value.c_str(), &end, 10); | ||
| 456 | + if (end == value.c_str() || *end != '\0') { | ||
| 457 | + return false; | ||
| 458 | + } | ||
| 459 | + result = static_cast<uint64_t>(parsed); | ||
| 460 | + return true; | ||
| 461 | +} | ||
| 462 | + | ||
| 463 | +uint32_t GetCompileDeviceId(const CompileInfo &compile_info) { | ||
| 464 | + uint32_t device_id = 0; | ||
| 465 | + (void)ParseUint32(compile_info.device_id, device_id); | ||
| 466 | + return device_id; | ||
| 467 | +} | ||
| 468 | + | ||
| 469 | +std::string GetPlatformString(fe::PlatFormInfos &platform_info, const std::string &label, const std::string &key, | ||
| 470 | + const std::string &fallback = "") { | ||
| 471 | + std::string value; | ||
| 472 | + if (platform_info.GetPlatformResWithLock(label, key, value) && !value.empty()) { | ||
| 473 | + return value; | ||
| 474 | + } | ||
| 475 | + return fallback; | ||
| 476 | +} | ||
| 477 | + | ||
| 478 | +uint64_t GetPlatformUint64(fe::PlatFormInfos &platform_info, const std::string &label, const std::string &key, | ||
| 479 | + uint64_t fallback = 0U) { | ||
| 480 | + uint64_t value = 0U; | ||
| 481 | + if (ParseUint64(GetPlatformString(platform_info, label, key), value)) { | ||
| 482 | + return value; | ||
| 483 | + } | ||
| 484 | + return fallback; | ||
| 485 | +} | ||
| 486 | + | ||
| 487 | +uint64_t GetLocalMemSize(fe::PlatFormInfos &platform_info, fe::LocalMemType mem_type, const std::string &label, | ||
| 488 | + const std::string &key) { | ||
| 489 | + uint64_t size = 0U; | ||
| 490 | + platform_info.GetLocalMemSize(mem_type, size); | ||
| 491 | + if (size != 0U) { | ||
| 492 | + return size; | ||
| 493 | + } | ||
| 494 | + return GetPlatformUint64(platform_info, label, key); | ||
| 495 | +} | ||
| 496 | + | ||
| 497 | +uint32_t GetPlatformCoreNum(fe::PlatFormInfos &platform_info, const std::string &core_type, | ||
| 498 | + const std::string &soc_info_key) { | ||
| 499 | + uint32_t core_num = platform_info.GetCoreNumByType(core_type); | ||
| 500 | + if (core_num != 0U) { | ||
| 501 | + return core_num; | ||
| 502 | + } | ||
| 503 | + return static_cast<uint32_t>(GetPlatformUint64(platform_info, "SoCInfo", soc_info_key)); | ||
| 504 | +} | ||
| 505 | + | ||
| 506 | +void UpdatePlatformCoreNum(const CompileInfo &compile_info, fe::PlatFormInfos &platform_info) { | ||
| 507 | + uint32_t aic_num = compile_info.aicore_num > 0 ? static_cast<uint32_t>(compile_info.aicore_num) | ||
| 508 | + : GetPlatformCoreNum(platform_info, "AiCore", "cube_core_cnt"); | ||
| 509 | + uint32_t aiv_num = compile_info.aiv_num > 0 ? static_cast<uint32_t>(compile_info.aiv_num) | ||
| 510 | + : GetPlatformCoreNum(platform_info, "VectorCore", "vector_core_cnt"); | ||
| 511 | + std::map<std::string, std::string> soc_info; | ||
| 512 | + if (platform_info.GetPlatformResWithLock("SoCInfo", soc_info)) { | ||
| 513 | + if (aic_num != 0U) { | ||
| 514 | + soc_info["cube_core_cnt"] = std::to_string(aic_num); | ||
| 515 | + soc_info["ai_core_cnt"] = std::to_string(aic_num); | ||
| 516 | + } | ||
| 517 | + if (aiv_num != 0U) { | ||
| 518 | + soc_info["vector_core_cnt"] = std::to_string(aiv_num); | ||
| 519 | + } | ||
| 520 | + platform_info.SetPlatformResWithLock("SoCInfo", soc_info); | ||
| 521 | + } | ||
| 522 | + platform_info.SetCoreNumByCoreType("AiCore"); | ||
| 523 | +} | ||
| 524 | + | ||
| 525 | +bool FillRuntimePlatformInfo(const CompileInfo &compile_info, fe::PlatFormInfos &platform_info) { | ||
| 526 | + if (fe::PlatformInfoManager::GeInstance().GetRuntimePlatformInfosByDevice(GetCompileDeviceId(compile_info), | ||
| 527 | + platform_info, true) != 0U) { | ||
| 528 | + return false; | ||
| 529 | + } | ||
| 530 | + UpdatePlatformCoreNum(compile_info, platform_info); | ||
| 531 | + return true; | ||
| 532 | +} | ||
| 533 | + | ||
| 534 | +std::string JsonEscape(const std::string &value) { | ||
| 535 | + std::string escaped; | ||
| 536 | + escaped.reserve(value.size()); | ||
| 537 | + for (const char ch : value) { | ||
| 538 | + if (ch == '\\' || ch == '"') { | ||
| 539 | + escaped.push_back('\\'); | ||
| 540 | + } | ||
| 541 | + escaped.push_back(ch); | ||
| 542 | + } | ||
| 543 | + return escaped; | ||
| 544 | +} | ||
| 545 | + | ||
| 546 | +const char *BoolLiteral(bool value) { | ||
| 547 | + return value ? "true" : "false"; | ||
| 548 | +} | ||
| 549 | + | ||
| 550 | +bool HasIntrinsic(fe::PlatFormInfos &platform_info, const std::string &intrinsic_name) { | ||
| 551 | + std::map<std::string, std::string> intrinsic_res; | ||
| 552 | + if (platform_info.GetPlatformResWithLock("AICoreintrinsicDtypeMap", intrinsic_res) && | ||
| 553 | + intrinsic_res.find(intrinsic_name) != intrinsic_res.end()) { | ||
| 554 | + return true; | ||
| 555 | + } | ||
| 556 | + auto intrinsic_map = platform_info.GetAICoreIntrinsicDtype(); | ||
| 557 | + return intrinsic_map.find(intrinsic_name) != intrinsic_map.end(); | ||
| 558 | +} | ||
| 559 | + | ||
| 560 | +std::string MakeCubeCompileJson(const CompileInfo &compile_info, fe::PlatFormInfos &platform_info, bool is_batch, | ||
| 561 | + bool transpose_x1, bool transpose_x2, int64_t offset_x, int64_t op_impl_mode, | ||
| 562 | + bool enable_hf32) { | ||
| 563 | + const std::string soc_version = | ||
| 564 | + GetPlatformString(platform_info, "version", "Short_SoC_version", compile_info.soc_version); | ||
| 565 | + const uint32_t core_num = GetPlatformCoreNum(platform_info, "AiCore", "cube_core_cnt"); | ||
| 566 | + const uint32_t vector_core_num = GetPlatformCoreNum(platform_info, "VectorCore", "vector_core_cnt"); | ||
| 567 | + const uint64_t bt_size = GetPlatformUint64(platform_info, "AICoreSpec", "bt_size"); | ||
| 568 | + const uint64_t ub_size = GetLocalMemSize(platform_info, fe::LocalMemType::UB, "AICoreSpec", "ub_size"); | ||
| 569 | + const uint64_t l2_size = GetLocalMemSize(platform_info, fe::LocalMemType::L2, "SoCInfo", "l2_size"); | ||
| 570 | + const uint64_t l1_size = GetLocalMemSize(platform_info, fe::LocalMemType::L1, "AICoreSpec", "l1_size"); | ||
| 571 | + const uint64_t l0a_size = GetLocalMemSize(platform_info, fe::LocalMemType::L0_A, "AICoreSpec", "l0_a_size"); | ||
| 572 | + const uint64_t l0b_size = GetLocalMemSize(platform_info, fe::LocalMemType::L0_B, "AICoreSpec", "l0_b_size"); | ||
| 573 | + const uint64_t l0c_size = GetLocalMemSize(platform_info, fe::LocalMemType::L0_C, "AICoreSpec", "l0_c_size"); | ||
| 574 | + const std::string load3d_constraints = | ||
| 575 | + GetPlatformString(platform_info, "AICoreSpec", "load3d_constraints", "unknown"); | ||
| 576 | + std::ostringstream ss; | ||
| 577 | + ss << "{\"_pattern\":\"MatMul\",\"attrs\":{"; | ||
| 578 | + ss << "\"transpose_a\":" << BoolLiteral(transpose_x1) << ","; | ||
| 579 | + ss << "\"transpose_b\":" << BoolLiteral(transpose_x2) << ","; | ||
| 580 | + ss << "\"offset_x\":" << offset_x << ","; | ||
| 581 | + ss << (is_batch ? "\"enable_hf32\":" : "\"opImplMode\":") << (is_batch ? (enable_hf32 ? 1 : 0) : op_impl_mode); | ||
| 582 | + ss << "},\"binary_attrs\":{\"bias_flag\":false,\"nd_flag\":true,\"split_k_flag\":false,"; | ||
| 583 | + ss << "\"zero_flag\":false,\"weight_nz\":false,\"l2_size\":" << l2_size << "},\"binary_mode_flag\":true,"; | ||
| 584 | + ss << "\"block_dim\":{\"CORE_NUM\":" << core_num << ",\"vector_core_cnt\":" << vector_core_num << "},"; | ||
| 585 | + ss << "\"corerect_range_flag\":null,\"dynamic_mode\":\"dynamic_mkn\",\"fused_double_operand_num\":0,"; | ||
| 586 | + ss << "\"hardware_info\":{\"BT_SIZE\":" << bt_size << ",\"load3d_constraints\":\"" << JsonEscape(load3d_constraints) | ||
| 587 | + << "\","; | ||
| 588 | + ss << "\"Intrinsic_fix_pipe_l0c2out\":" << BoolLiteral(HasIntrinsic(platform_info, "Intrinsic_fix_pipe_l0c2out")) | ||
| 589 | + << ","; | ||
| 590 | + ss << "\"Intrinsic_data_move_l12ub\":" << BoolLiteral(HasIntrinsic(platform_info, "Intrinsic_data_move_l12ub")) | ||
| 591 | + << ","; | ||
| 592 | + ss << "\"Intrinsic_data_move_l0c2ub\":" << BoolLiteral(HasIntrinsic(platform_info, "Intrinsic_data_move_l0c2ub")) | ||
| 593 | + << ","; | ||
| 594 | + ss << "\"Intrinsic_data_move_out2l1_nd2nz\":" | ||
| 595 | + << BoolLiteral(HasIntrinsic(platform_info, "Intrinsic_data_move_out2l1_nd2nz")) << ","; | ||
| 596 | + ss << "\"Intrinsic_data_move_l12bt\":" << BoolLiteral(HasIntrinsic(platform_info, "Intrinsic_data_move_l12bt")) | ||
| 597 | + << ","; | ||
| 598 | + ss << "\"UB_SIZE\":" << ub_size << ",\"L2_SIZE\":" << l2_size << ",\"L1_SIZE\":" << l1_size << ","; | ||
| 599 | + ss << "\"L0A_SIZE\":" << l0a_size << ",\"L0B_SIZE\":" << l0b_size << ",\"L0C_SIZE\":" << l0c_size << ","; | ||
| 600 | + ss << "\"CORE_NUM\":" << core_num << ",\"vector_core_cnt\":" << vector_core_num << ","; | ||
| 601 | + ss << "\"socVersion\":\"" << JsonEscape(soc_version) << "\"},\"format_a\":\"ND\",\"format_b\":\"ND\","; | ||
| 602 | + ss << "\"repo_range\":{},\"repo_seeds\":{}}"; | ||
| 603 | + return ss.str(); | ||
| 604 | +} | ||
| 605 | + | ||
| 606 | +std::vector<uint32_t> MakeMatMulInputInstanceNum(bool has_bias, bool has_offset_w) { | ||
| 607 | + return {1U, 1U, has_bias ? 1U : 0U, has_offset_w ? 1U : 0U}; | ||
| 608 | +} | ||
| 609 | + | ||
| 610 | +std::vector<const TensorInfo *> BuildMatMulInputSlots(const std::vector<TensorInfo> &inputs, const MatMulAttrs &attrs) { | ||
| 611 | + std::vector<const TensorInfo *> slots = {&inputs[0], &inputs[1], nullptr, nullptr}; | ||
| 612 | + size_t input_index = 2U; | ||
| 613 | + if (attrs.has_bias && input_index < inputs.size()) { | ||
| 614 | + slots[2U] = &inputs[input_index++]; | ||
| 615 | + } | ||
| 616 | + if (attrs.has_offset_w && input_index < inputs.size()) { | ||
| 617 | + slots[3U] = &inputs[input_index++]; | ||
| 618 | + } | ||
| 619 | + return slots; | ||
| 620 | +} | ||
| 621 | + | ||
| 622 | +std::unique_ptr<CompileState> BuildCompileState(const CompileInfo &compile_info, const OpHostSchema &schema, | ||
| 623 | + const OpHostFuncs &funcs, bool is_batch, ge::DataType data_type, | ||
| 624 | + ge::Format format, const MatMulAttrs &attrs, | ||
| 625 | + const std::vector<TensorInfo> &inputs, std::string &error_msg) { | ||
| 626 | + auto state = std::make_unique<CompileState>(); | ||
| 627 | + if (!FillRuntimePlatformInfo(compile_info, state->platform_info)) { | ||
| 628 | + error_msg = std::string(schema.op_type) + " platform info setup failed"; | ||
| 629 | + return nullptr; | ||
| 630 | + } | ||
| 631 | + state->compile_info_ptr = funcs.compile_info_creator(); | ||
| 632 | + if (state->compile_info_ptr == nullptr) { | ||
| 633 | + error_msg = std::string(schema.op_type) + " compile info creation failed"; | ||
| 634 | + return nullptr; | ||
| 635 | + } | ||
| 636 | + state->compile_json = MakeCubeCompileJson(compile_info, state->platform_info, is_batch, attrs.transpose_x1, | ||
| 637 | + attrs.transpose_x2, attrs.offset_x, attrs.op_impl_mode, attrs.enable_hf32); | ||
| 638 | + gert::OpTilingParseContextBuilder parse_builder; | ||
| 639 | + const auto input_slots = BuildMatMulInputSlots(inputs, attrs); | ||
| 640 | + auto parse_holder = parse_builder.OpType(schema.op_type) | ||
| 641 | + .OpName(schema.op_type) | ||
| 642 | + .IOInstanceNum(MakeMatMulInputInstanceNum(attrs.has_bias, attrs.has_offset_w), | ||
| 643 | + kSingleOutputInstanceNum) | ||
| 644 | + .InputTensorDesc(0, data_type, format, format) | ||
| 645 | + .InputTensorDesc(1, data_type, format, format) | ||
| 646 | + .InputTensorDesc(2, input_slots[2U] == nullptr ? data_type : DtypeToGeDataType(input_slots[2U]->dtype), | ||
| 647 | + input_slots[2U] == nullptr ? format : FormatToGeFormat(input_slots[2U]->format), | ||
| 648 | + input_slots[2U] == nullptr ? format : FormatToGeFormat(input_slots[2U]->format)) | ||
| 649 | + .InputTensorDesc(3, | ||
| 650 | + input_slots[3U] == nullptr ? ge::DT_INT8 : DtypeToGeDataType(input_slots[3U]->dtype), | ||
| 651 | + input_slots[3U] == nullptr ? format : FormatToGeFormat(input_slots[3U]->format), | ||
| 652 | + input_slots[3U] == nullptr ? format : FormatToGeFormat(input_slots[3U]->format)) | ||
| 653 | + .OutputTensorDesc(0, data_type, format, format) | ||
| 654 | + .CompiledJson(state->compile_json.c_str()) | ||
| 655 | + .CompiledInfo(state->compile_info_ptr) | ||
| 656 | + .PlatformInfo(const_cast<fe::PlatFormInfos *>(&state->platform_info)) | ||
| 657 | + .Build(); | ||
| 658 | + auto *parse_ctx = reinterpret_cast<gert::KernelContext *>(parse_holder.GetContext()); | ||
| 659 | + const auto parse_ret = parse_ctx == nullptr ? ge::GRAPH_FAILED : funcs.tiling_parse(parse_ctx); | ||
| 660 | + if (parse_ctx == nullptr || parse_ret != ge::GRAPH_SUCCESS) { | ||
| 661 | + error_msg = std::string(schema.op_type) + " tiling parse failed"; | ||
| 662 | + return nullptr; | ||
| 663 | + } | ||
| 664 | + return state; | ||
| 665 | +} | ||
| 666 | + | ||
| 667 | +CompileStateKey MakeCompileStateKey(const CompileInfo &compile_info, bool is_batch, size_t input_num, | ||
| 668 | + const std::vector<TensorInfo> &inputs, const std::string &dtype, | ||
| 669 | + const std::string &format, const MatMulAttrs &attrs) { | ||
| 670 | + std::string input2_dtype; | ||
| 671 | + std::string input3_dtype; | ||
| 672 | + std::string input2_format; | ||
| 673 | + std::string input3_format; | ||
| 674 | + if (inputs.size() > 2U) { | ||
| 675 | + input2_dtype = inputs[2U].dtype; | ||
| 676 | + input2_format = inputs[2U].format; | ||
| 677 | + } | ||
| 678 | + if (inputs.size() > 3U) { | ||
| 679 | + input3_dtype = inputs[3U].dtype; | ||
| 680 | + input3_format = inputs[3U].format; | ||
| 681 | + } | ||
| 682 | + return CompileStateKey{compile_info.soc_version, | ||
| 683 | + compile_info.device_id, | ||
| 684 | + dtype, | ||
| 685 | + format, | ||
| 686 | + input2_dtype, | ||
| 687 | + input3_dtype, | ||
| 688 | + input2_format, | ||
| 689 | + input3_format, | ||
| 690 | + is_batch, | ||
| 691 | + input_num, | ||
| 692 | + attrs.has_bias, | ||
| 693 | + attrs.has_offset_w, | ||
| 694 | + attrs.transpose_x1, | ||
| 695 | + attrs.transpose_x2, | ||
| 696 | + attrs.offset_x, | ||
| 697 | + attrs.op_impl_mode, | ||
| 698 | + attrs.enable_hf32, | ||
| 699 | + compile_info.aicore_num, | ||
| 700 | + compile_info.aiv_num}; | ||
| 701 | +} | ||
| 702 | + | ||
| 703 | +std::shared_ptr<const CompileState> GetCompileState(const CompileInfo &compile_info, const OpHostSchema &schema, | ||
| 704 | + const OpHostFuncs &funcs, bool is_batch, ge::DataType data_type, | ||
| 705 | + ge::Format format, const MatMulAttrs &attrs, | ||
| 706 | + const std::string &dtype, const std::string &format_name, | ||
| 707 | + const std::vector<TensorInfo> &inputs, | ||
| 708 | + std::string &error_msg) { | ||
| 709 | + const CompileStateKey key = MakeCompileStateKey(compile_info, is_batch, inputs.size(), inputs, dtype, format_name, | ||
| 710 | + attrs); | ||
| 711 | + { | ||
| 712 | + std::lock_guard<std::mutex> lock(GetCompileStateMutex()); | ||
| 713 | + auto &cache = GetCompileStateCache(); | ||
| 714 | + const auto it = cache.find(key); | ||
| 715 | + if (it != cache.end() && it->second != nullptr) { | ||
| 716 | + return it->second; | ||
| 717 | + } | ||
| 718 | + } | ||
| 719 | + | ||
| 720 | + auto state = BuildCompileState(compile_info, schema, funcs, is_batch, data_type, format, attrs, inputs, error_msg); | ||
| 721 | + if (state == nullptr) { | ||
| 722 | + return nullptr; | ||
| 723 | + } | ||
| 724 | + | ||
| 725 | + auto cached_state = std::shared_ptr<const CompileState>(std::move(state)); | ||
| 726 | + std::lock_guard<std::mutex> lock(GetCompileStateMutex()); | ||
| 727 | + auto &cache_state = GetCompileStateCache()[key]; | ||
| 728 | + if (cache_state == nullptr) { | ||
| 729 | + cache_state = std::move(cached_state); | ||
| 730 | + } | ||
| 731 | + return cache_state; | ||
| 732 | +} | ||
| 733 | + | ||
| 734 | +void FillShape(gert::Shape &shape, const std::vector<int64_t> &dims) { | ||
| 735 | + shape.SetScalar(); | ||
| 736 | + for (const auto dim : dims) { | ||
| 737 | + shape.AppendDim(dim); | ||
| 738 | + } | ||
| 739 | +} | ||
| 740 | + | ||
| 741 | +std::vector<int64_t> GetRuntimeShape(const TensorInfo &tensor) { | ||
| 742 | + return tensor.shape.empty() ? tensor.ori_shape : tensor.shape; | ||
| 743 | +} | ||
| 744 | + | ||
| 745 | +TilingRequest MakeTilingRequest(const CompileInfo &compile_info, const std::vector<TensorInfo> &inputs, | ||
| 746 | + const std::vector<TensorInfo> &outputs, const std::vector<AttrInfo> &attrs, | ||
| 747 | + bool is_batch) { | ||
| 748 | + const auto &schema = GetOpHostSchema(is_batch); | ||
| 749 | + MatMulAttrs matmul_attrs = ReadMatMulAttrs(attrs, is_batch); | ||
| 750 | + return TilingRequest{compile_info, inputs, outputs, is_batch, schema, matmul_attrs, | ||
| 751 | + DtypeToGeDataType(inputs[0].dtype), FormatToGeFormat(inputs[0].format)}; | ||
| 752 | +} | ||
| 753 | + | ||
| 754 | +RuntimeTilingKey MakeRuntimeTilingKey(const TilingRequest &request) { | ||
| 755 | + RuntimeTilingKey key; | ||
| 756 | + key.soc_version = request.compile_info.soc_version; | ||
| 757 | + key.device_id = request.compile_info.device_id; | ||
| 758 | + key.op_type = request.schema.op_type == nullptr ? std::string() : request.schema.op_type; | ||
| 759 | + key.input_num = request.inputs.size(); | ||
| 760 | + key.has_bias = request.matmul_attrs.has_bias; | ||
| 761 | + key.has_offset_w = request.matmul_attrs.has_offset_w; | ||
| 762 | + if (!request.inputs.empty()) { | ||
| 763 | + key.dtype = request.inputs[0].dtype; | ||
| 764 | + key.format = request.inputs[0].format; | ||
| 765 | + key.input0_shape = GetRuntimeShape(request.inputs[0]); | ||
| 766 | + } | ||
| 767 | + if (request.inputs.size() > 1) { | ||
| 768 | + key.input1_shape = GetRuntimeShape(request.inputs[1]); | ||
| 769 | + } | ||
| 770 | + if (request.inputs.size() > 2) { | ||
| 771 | + key.input2_shape = GetRuntimeShape(request.inputs[2]); | ||
| 772 | + key.input2_dtype = request.inputs[2].dtype; | ||
| 773 | + key.input2_format = request.inputs[2].format; | ||
| 774 | + } | ||
| 775 | + if (request.inputs.size() > 3) { | ||
| 776 | + key.input3_shape = GetRuntimeShape(request.inputs[3]); | ||
| 777 | + key.input3_dtype = request.inputs[3].dtype; | ||
| 778 | + key.input3_format = request.inputs[3].format; | ||
| 779 | + } | ||
| 780 | + if (!request.outputs.empty()) { | ||
| 781 | + key.output_shape = GetRuntimeShape(request.outputs[0]); | ||
| 782 | + } | ||
| 783 | + key.is_batch = request.is_batch; | ||
| 784 | + key.transpose_x1 = request.matmul_attrs.transpose_x1; | ||
| 785 | + key.transpose_x2 = request.matmul_attrs.transpose_x2; | ||
| 786 | + key.offset_x = request.matmul_attrs.offset_x; | ||
| 787 | + key.op_impl_mode = request.matmul_attrs.op_impl_mode; | ||
| 788 | + key.enable_hf32 = request.matmul_attrs.enable_hf32; | ||
| 789 | + key.aicore_num = request.compile_info.aicore_num; | ||
| 790 | + key.aiv_num = request.compile_info.aiv_num; | ||
| 791 | + return key; | ||
| 792 | +} | ||
| 793 | + | ||
| 794 | +bool TryGetCachedTilingResult(const RuntimeTilingKey &key, TilingResult *result) { | ||
| 795 | + if (result == nullptr) { | ||
| 796 | + return false; | ||
| 797 | + } | ||
| 798 | + std::lock_guard<std::mutex> lock(GetTilingResultCacheMutex()); | ||
| 799 | + const auto &cache = GetTilingResultCache(); | ||
| 800 | + const auto it = cache.find(key); | ||
| 801 | + if (it == cache.end() || !it->second.success) { | ||
| 802 | + return false; | ||
| 803 | + } | ||
| 804 | + *result = it->second; | ||
| 805 | + return true; | ||
| 806 | +} | ||
| 807 | + | ||
| 808 | +void CacheTilingResult(const RuntimeTilingKey &key, const TilingResult &result) { | ||
| 809 | + if (!result.success) { | ||
| 810 | + return; | ||
| 811 | + } | ||
| 812 | + std::lock_guard<std::mutex> lock(GetTilingResultCacheMutex()); | ||
| 813 | + GetTilingResultCache()[key] = result; | ||
| 814 | +} | ||
| 815 | + | ||
| 816 | +gert::StorageShape MakeStorageShape(const TensorInfo &tensor) { | ||
| 817 | + gert::StorageShape storage_shape; | ||
| 818 | + const auto runtime_shape = GetRuntimeShape(tensor); | ||
| 819 | + FillShape(storage_shape.MutableOriginShape(), tensor.ori_shape.empty() ? runtime_shape : tensor.ori_shape); | ||
| 820 | + FillShape(storage_shape.MutableStorageShape(), runtime_shape); | ||
| 821 | + return storage_shape; | ||
| 822 | +} | ||
| 823 | + | ||
| 824 | +bool ValidateTilingRequest(const CompileInfo *compile_info, const std::vector<TensorInfo> *inputs, | ||
| 825 | + const std::vector<TensorInfo> *outputs, const std::vector<AttrInfo> *attrs, | ||
| 826 | + TilingResult *result) { | ||
| 827 | + return compile_info != nullptr && inputs != nullptr && outputs != nullptr && attrs != nullptr && result != nullptr && | ||
| 828 | + inputs->size() >= 2 && inputs->size() <= 4 && !outputs->empty(); | ||
| 829 | +} | ||
| 830 | + | ||
| 831 | +bool IsSupportedTilingTensorDesc(const std::vector<TensorInfo> &inputs, const std::vector<TensorInfo> &outputs, | ||
| 832 | + ge::DataType data_type, ge::Format format) { | ||
| 833 | + if (data_type == ge::DT_UNDEFINED || format == ge::FORMAT_RESERVED || DtypeToGeDataType(outputs[0].dtype) != data_type || | ||
| 834 | + FormatToGeFormat(outputs[0].format) != format) { | ||
| 835 | + return false; | ||
| 836 | + } | ||
| 837 | + for (const auto &input : inputs) { | ||
| 838 | + if (DtypeToGeDataType(input.dtype) == ge::DT_UNDEFINED || FormatToGeFormat(input.format) == ge::FORMAT_RESERVED) { | ||
| 839 | + return false; | ||
| 840 | + } | ||
| 841 | + } | ||
| 842 | + return DtypeToGeDataType(inputs[1].dtype) == data_type && FormatToGeFormat(inputs[1].format) == format; | ||
| 843 | +} | ||
| 844 | + | ||
| 845 | +bool IsOptionalInputSlotsValid(const TilingRequest &request) { | ||
| 846 | + const size_t expected_input_num = 2U + (request.matmul_attrs.has_bias ? 1U : 0U) + | ||
| 847 | + (request.matmul_attrs.has_offset_w ? 1U : 0U); | ||
| 848 | + return request.inputs.size() == expected_input_num; | ||
| 849 | +} | ||
| 850 | + | ||
| 851 | +template <typename TilingContext> | ||
| 852 | +void FillTilingResultFromContext(TilingContext *tiling_ctx, TilingResult &result) { | ||
| 853 | + auto *raw_tiling_data = tiling_ctx->GetRawTilingData(); | ||
| 854 | + const size_t tiling_data_len = raw_tiling_data->GetDataSize(); | ||
| 855 | + result.tiling_data.assign(reinterpret_cast<const uint8_t *>(raw_tiling_data->GetData()), | ||
| 856 | + reinterpret_cast<const uint8_t *>(raw_tiling_data->GetData()) + tiling_data_len); | ||
| 857 | + result.tiling_key = static_cast<int64_t>(tiling_ctx->GetTilingKey()); | ||
| 858 | + result.block_dim = static_cast<int64_t>(tiling_ctx->GetBlockDim()); | ||
| 859 | + const size_t workspace_num = tiling_ctx->GetWorkspaceNum(); | ||
| 860 | + auto *workspace_sizes = workspace_num > 0 ? tiling_ctx->GetWorkspaceSizes(workspace_num) : nullptr; | ||
| 861 | + result.workspace_size = workspace_sizes == nullptr ? 0 : static_cast<int64_t>(workspace_sizes[0]); | ||
| 862 | + result.success = true; | ||
| 863 | +} | ||
| 864 | + | ||
| 865 | +uint32_t PositiveOrDefault(int64_t value, uint32_t default_value) { | ||
| 866 | + return value > 0 ? static_cast<uint32_t>(value) : default_value; | ||
| 867 | +} | ||
| 868 | + | ||
| 869 | +template <typename T> | ||
| 870 | +bool CopyExactTilingData(const TilingResult &result, const size_t tiling_data_len, T &tiling_data) { | ||
| 871 | + if (tiling_data_len != sizeof(T)) { | ||
| 872 | + return false; | ||
| 873 | + } | ||
| 874 | + std::memcpy(&tiling_data, result.tiling_data.data(), sizeof(T)); | ||
| 875 | + return true; | ||
| 876 | +} | ||
| 877 | + | ||
| 878 | +void FillMetaFromBasicTiling(TilingResult &result, const MatMulV3BasicTilingData &tiling_data) { | ||
| 879 | + result.matmul_basic_tiling_data = tiling_data; | ||
| 880 | + result.cube_used_core_num = std::max(tiling_data.usedCoreNum, 1U); | ||
| 881 | + result.cube_base_m = std::max(tiling_data.baseM, 1U); | ||
| 882 | + result.cube_base_n = std::max(tiling_data.baseN, 1U); | ||
| 883 | +} | ||
| 884 | + | ||
| 885 | +void FillMetaFromBatchBasicTiling(TilingResult &result, const BatchMatMulV3BasicTilingData &tiling_data) { | ||
| 886 | + result.batch_matmul_tiling_data = tiling_data; | ||
| 887 | + FillMetaFromBasicTiling(result, tiling_data.matMulTilingData); | ||
| 888 | +} | ||
| 889 | + | ||
| 890 | +void FillMetaFromTCubeTiling(TilingResult &result, const TCubeTiling &tiling_data) { | ||
| 891 | + result.cube_used_core_num = PositiveOrDefault(tiling_data.usedCoreNum, 1U); | ||
| 892 | + result.cube_base_m = PositiveOrDefault(tiling_data.baseM, 1U); | ||
| 893 | + result.cube_base_n = PositiveOrDefault(tiling_data.baseN, 1U); | ||
| 894 | +} | ||
| 895 | + | ||
| 896 | +void FillBatchTilingMeta(TilingResult &result, const size_t tiling_data_len) { | ||
| 897 | + BatchMatMulV3BasicTilingData batch_basic_tiling_data = {}; | ||
| 898 | + if (CopyExactTilingData(result, tiling_data_len, batch_basic_tiling_data)) { | ||
| 899 | + FillMetaFromBatchBasicTiling(result, batch_basic_tiling_data); | ||
| 900 | + return; | ||
| 901 | + } | ||
| 902 | + BatchMatMulV3TilingData batch_tiling_data = {}; | ||
| 903 | + if (CopyExactTilingData(result, tiling_data_len, batch_tiling_data)) { | ||
| 904 | + FillMetaFromTCubeTiling(result, batch_tiling_data.matMulTilingData.tCubeTiling); | ||
| 905 | + return; | ||
| 906 | + } | ||
| 907 | + BatchMatMulV3IterBatchBasicTilingData iter_batch_tiling_data = {}; | ||
| 908 | + if (CopyExactTilingData(result, tiling_data_len, iter_batch_tiling_data)) { | ||
| 909 | + result.cube_base_m = std::max(iter_batch_tiling_data.baseM, 1U); | ||
| 910 | + result.cube_base_n = std::max(iter_batch_tiling_data.baseN, 1U); | ||
| 911 | + return; | ||
| 912 | + } | ||
| 913 | + BatchMatMulToMulBasicTilingData batch_to_mul_tiling_data = {}; | ||
| 914 | + if (CopyExactTilingData(result, tiling_data_len, batch_to_mul_tiling_data)) { | ||
| 915 | + result.cube_used_core_num = std::max(batch_to_mul_tiling_data.usedCoreNum, 1U); | ||
| 916 | + return; | ||
| 917 | + } | ||
| 918 | + BatchMatMulV3MergeBatchBasicTilingData merge_batch_tiling_data = {}; | ||
| 919 | + (void)CopyExactTilingData(result, tiling_data_len, merge_batch_tiling_data); | ||
| 920 | +} | ||
| 921 | + | ||
| 922 | +void FillMatMulTilingMeta(TilingResult &result, const size_t tiling_data_len) { | ||
| 923 | + MatMulV3BasicTilingData basic_tiling_data = {}; | ||
| 924 | + if (CopyExactTilingData(result, tiling_data_len, basic_tiling_data)) { | ||
| 925 | + FillMetaFromBasicTiling(result, basic_tiling_data); | ||
| 926 | + return; | ||
| 927 | + } | ||
| 928 | + MatMulV3TilingDataCopy tiling_data_copy = {}; | ||
| 929 | + if (CopyExactTilingData(result, tiling_data_len, tiling_data_copy)) { | ||
| 930 | + FillMetaFromTCubeTiling(result, tiling_data_copy.matMulTilingData.tCubeTiling); | ||
| 931 | + return; | ||
| 932 | + } | ||
| 933 | + MatMulV3TilingData tiling_data = {}; | ||
| 934 | + if (CopyExactTilingData(result, tiling_data_len, tiling_data)) { | ||
| 935 | + FillMetaFromTCubeTiling(result, tiling_data.tCubeTiling); | ||
| 936 | + return; | ||
| 937 | + } | ||
| 938 | + MatMulToMulBasicTilingData to_mul_tiling_data = {}; | ||
| 939 | + if (CopyExactTilingData(result, tiling_data_len, to_mul_tiling_data)) { | ||
| 940 | + result.cube_used_core_num = std::max(to_mul_tiling_data.usedCoreNum, 1U); | ||
| 941 | + if (to_mul_tiling_data.baseMN > 0) { | ||
| 942 | + result.cube_base_m = 1U; | ||
| 943 | + result.cube_base_n = to_mul_tiling_data.baseMN; | ||
| 944 | + } | ||
| 945 | + return; | ||
| 946 | + } | ||
| 947 | + MatMulV3KEqZeroBasicTilingData k_eq_zero_tiling_data = {}; | ||
| 948 | + (void)CopyExactTilingData(result, tiling_data_len, k_eq_zero_tiling_data); | ||
| 949 | +} | ||
| 950 | + | ||
| 951 | +void FillTilingMeta(TilingResult &result, bool is_batch) { | ||
| 952 | + const size_t tiling_data_len = result.tiling_data.size(); | ||
| 953 | + if (is_batch) { | ||
| 954 | + FillBatchTilingMeta(result, tiling_data_len); | ||
| 955 | + return; | ||
| 956 | + } | ||
| 957 | + FillMatMulTilingMeta(result, tiling_data_len); | ||
| 958 | +} | ||
| 959 | + | ||
| 960 | +template <typename RunTiling> | ||
| 961 | +bool BuildTilingContext(const TilingRequest &request, const CompileState &compile_state, gert::TilingData *tiling_data, | ||
| 962 | + gert::ContinuousVector *workspace, const std::vector<gert::Tensor *> &input_tensors, | ||
| 963 | + const std::vector<gert::Tensor *> &output_tensors, RunTiling run_tiling) { | ||
| 964 | + gert::OpTilingContextBuilder tiling_builder; | ||
| 965 | + auto tiling_holder = | ||
| 966 | + request.is_batch ? tiling_builder.OpType(request.schema.op_type) | ||
| 967 | + .OpName(request.schema.op_type) | ||
| 968 | + .IOInstanceNum(MakeMatMulInputInstanceNum(request.matmul_attrs.has_bias, | ||
| 969 | + request.matmul_attrs.has_offset_w), | ||
| 970 | + kSingleOutputInstanceNum) | ||
| 971 | + .AppendAttr(request.matmul_attrs.transpose_x1) | ||
| 972 | + .AppendAttr(request.matmul_attrs.transpose_x2) | ||
| 973 | + .AppendAttr(request.matmul_attrs.offset_x) | ||
| 974 | + .AppendAttr(request.matmul_attrs.enable_hf32) | ||
| 975 | + .CompileInfo(compile_state.compile_info_ptr) | ||
| 976 | + .PlatformInfo(const_cast<fe::PlatFormInfos *>(&compile_state.platform_info)) | ||
| 977 | + .TilingData(tiling_data) | ||
| 978 | + .Workspace(workspace) | ||
| 979 | + .InputTensors(input_tensors) | ||
| 980 | + .OutputTensors(output_tensors) | ||
| 981 | + .Build() | ||
| 982 | + : tiling_builder.OpType(request.schema.op_type) | ||
| 983 | + .OpName(request.schema.op_type) | ||
| 984 | + .IOInstanceNum(MakeMatMulInputInstanceNum(request.matmul_attrs.has_bias, | ||
| 985 | + request.matmul_attrs.has_offset_w), | ||
| 986 | + kSingleOutputInstanceNum) | ||
| 987 | + .AppendAttr(request.matmul_attrs.transpose_x1) | ||
| 988 | + .AppendAttr(request.matmul_attrs.transpose_x2) | ||
| 989 | + .AppendAttr(request.matmul_attrs.offset_x) | ||
| 990 | + .AppendAttr(request.matmul_attrs.op_impl_mode) | ||
| 991 | + .CompileInfo(compile_state.compile_info_ptr) | ||
| 992 | + .PlatformInfo(const_cast<fe::PlatFormInfos *>(&compile_state.platform_info)) | ||
| 993 | + .TilingData(tiling_data) | ||
| 994 | + .Workspace(workspace) | ||
| 995 | + .InputTensors(input_tensors) | ||
| 996 | + .OutputTensors(output_tensors) | ||
| 997 | + .Build(); | ||
| 998 | + return run_tiling(tiling_holder.GetContext()); | ||
| 999 | +} | ||
| 1000 | + | ||
| 1001 | +bool RunSharedCubeTiling(const TilingRequest &request, TilingResult &result) { | ||
| 1002 | + const RuntimeTilingKey runtime_key = MakeRuntimeTilingKey(request); | ||
| 1003 | + if (TryGetCachedTilingResult(runtime_key, &result)) { | ||
| 1004 | + return true; | ||
| 1005 | + } | ||
| 1006 | + | ||
| 1007 | + const char *op_type = request.schema.op_type; | ||
| 1008 | + const auto &cached_funcs = GetOpHostFuncs(request.is_batch, op_type); | ||
| 1009 | + if (!cached_funcs.loaded) { | ||
| 1010 | + result.error_msg = std::string(op_type) + " shared op_host registry lookup failed"; | ||
| 1011 | + return false; | ||
| 1012 | + } | ||
| 1013 | + | ||
| 1014 | + const auto &funcs = cached_funcs.funcs; | ||
| 1015 | + auto compile_state = GetCompileState(request.compile_info, request.schema, funcs, request.is_batch, request.data_type, | ||
| 1016 | + request.format, request.matmul_attrs, request.inputs[0].dtype, | ||
| 1017 | + request.inputs[0].format, request.inputs, result.error_msg); | ||
| 1018 | + if (compile_state == nullptr) { | ||
| 1019 | + return false; | ||
| 1020 | + } | ||
| 1021 | + | ||
| 1022 | + const size_t tiling_data_capacity = std::max(funcs.max_tiling_data_size, kMaxTilingDataSize); | ||
| 1023 | + auto &scratch = GetTilingScratch(); | ||
| 1024 | + if (!scratch.EnsureCapacity(tiling_data_capacity, result.error_msg, op_type)) { | ||
| 1025 | + return false; | ||
| 1026 | + } | ||
| 1027 | + auto *tiling_data = scratch.MutableTilingData(); | ||
| 1028 | + auto *workspace = scratch.MutableWorkspace(); | ||
| 1029 | + tiling_data->SetDataSize(0UL); | ||
| 1030 | + (void)workspace->SetSize(0UL); | ||
| 1031 | + | ||
| 1032 | + gert::StorageFormat storage_format(request.format, request.format, {}); | ||
| 1033 | + std::vector<gert::Tensor> input_tensors_storage; | ||
| 1034 | + const auto input_slots = BuildMatMulInputSlots(request.inputs, request.matmul_attrs); | ||
| 1035 | + input_tensors_storage.reserve(input_slots.size()); | ||
| 1036 | + scratch.input_tensors.clear(); | ||
| 1037 | + for (const auto *input : input_slots) { | ||
| 1038 | + if (input == nullptr) { | ||
| 1039 | + continue; | ||
| 1040 | + } | ||
| 1041 | + ge::Format input_format = FormatToGeFormat(input->format); | ||
| 1042 | + gert::StorageFormat input_storage_format(input_format, input_format, {}); | ||
| 1043 | + input_tensors_storage.emplace_back(MakeStorageShape(*input), input_storage_format, DtypeToGeDataType(input->dtype)); | ||
| 1044 | + scratch.input_tensors.push_back(&input_tensors_storage.back()); | ||
| 1045 | + } | ||
| 1046 | + std::array<gert::Tensor, 1> output_tensors_storage = { | ||
| 1047 | + gert::Tensor(MakeStorageShape(request.outputs[0]), storage_format, request.data_type)}; | ||
| 1048 | + scratch.output_tensors.clear(); | ||
| 1049 | + scratch.output_tensors.push_back(&output_tensors_storage[0]); | ||
| 1050 | + | ||
| 1051 | + const bool tiling_ok = BuildTilingContext( | ||
| 1052 | + request, *compile_state, tiling_data, workspace, scratch.input_tensors, scratch.output_tensors, | ||
| 1053 | + [&](auto *tiling_ctx) { | ||
| 1054 | + if (tiling_ctx == nullptr) { | ||
| 1055 | + result.error_msg = std::string(op_type) + " shared tiling context build failed"; | ||
| 1056 | + return false; | ||
| 1057 | + } | ||
| 1058 | + if (funcs.tiling(tiling_ctx) != ge::GRAPH_SUCCESS) { | ||
| 1059 | + result.error_msg = std::string(op_type) + " shared tiling call failed"; | ||
| 1060 | + return false; | ||
| 1061 | + } | ||
| 1062 | + if (tiling_ctx->GetRawTilingData() == nullptr || tiling_ctx->GetRawTilingData()->GetDataSize() == 0) { | ||
| 1063 | + result.error_msg = std::string(op_type) + " shared tiling returned empty data"; | ||
| 1064 | + return false; | ||
| 1065 | + } | ||
| 1066 | + FillTilingResultFromContext(tiling_ctx, result); | ||
| 1067 | + return true; | ||
| 1068 | + }); | ||
| 1069 | + if (!tiling_ok) { | ||
| 1070 | + return false; | ||
| 1071 | + } | ||
| 1072 | + CacheTilingResult(runtime_key, result); | ||
| 1073 | + return true; | ||
| 1074 | +} | ||
| 1075 | + | ||
| 1076 | +} // namespace | ||
| 1077 | + | ||
| 1078 | +extern "C" bool AutofuseDoCubeMatMulTiling(const ge::autofuse::CompileInfo *compile_info, | ||
| 1079 | + const std::vector<ge::autofuse::TensorInfo> *inputs, | ||
| 1080 | + const std::vector<ge::autofuse::TensorInfo> *outputs, | ||
| 1081 | + const std::vector<ge::autofuse::AttrInfo> *attrs, bool is_batch, | ||
| 1082 | + ge::autofuse::TilingResult *result) { | ||
| 1083 | + using namespace ge::autofuse; | ||
| 1084 | + if (!ValidateTilingRequest(compile_info, inputs, outputs, attrs, result)) { | ||
| 1085 | + return false; | ||
| 1086 | + } | ||
| 1087 | + const TilingRequest request = MakeTilingRequest(*compile_info, *inputs, *outputs, *attrs, is_batch); | ||
| 1088 | + if (!IsOptionalInputSlotsValid(request)) { | ||
| 1089 | + return false; | ||
| 1090 | + } | ||
| 1091 | + if (!IsSupportedTilingTensorDesc(*inputs, *outputs, request.data_type, request.format)) { | ||
| 1092 | + return false; | ||
| 1093 | + } | ||
| 1094 | + return RunSharedCubeTiling(request, *result); | ||
| 1095 | +} | ||
| 1096 | + | ||
| 950 | CubeKernelTilingWrapper::CubeKernelTilingWrapper() {} | 1097 | CubeKernelTilingWrapper::CubeKernelTilingWrapper() {} |
| 951 | 1098 | ||
| 952 | CubeKernelTilingWrapper::~CubeKernelTilingWrapper() {} | 1099 | CubeKernelTilingWrapper::~CubeKernelTilingWrapper() {} |
| 953 | 1100 | ||
| 954 | -void CubeKernelTilingWrapper::BuildMatMulArgs(const std::vector<TensorInfo>& args_list, | 1101 | +void CubeKernelTilingWrapper::BuildMatMulArgs(const std::vector<TensorInfo> &args_list, int input_num, |
| 955 | - int input_num, | 1102 | + bool transpose_a, bool transpose_b, |
| 956 | - bool transpose_a, | 1103 | + std::vector<TensorInfo> &origin_inputs, |
| 957 | - bool transpose_b, | 1104 | + std::vector<TensorInfo> &origin_outputs, |
| 958 | - std::vector<TensorInfo>& origin_inputs, | 1105 | + std::vector<TensorInfo> &inputs) { |
| 959 | - std::vector<TensorInfo>& origin_outputs, | 1106 | + origin_inputs.clear(); |
| 960 | - std::vector<TensorInfo>& inputs) { | 1107 | + origin_outputs.clear(); |
| 961 | - origin_inputs.clear(); | 1108 | + inputs.clear(); |
| 962 | - origin_outputs.clear(); | ||
| 963 | - inputs.clear(); | ||
| 964 | 1109 | ||
| 965 | - int64_t m = 0; | 1110 | + int64_t m = 0; |
| 966 | - int64_t n = 0; | 1111 | + int64_t n = 0; |
| 967 | - std::vector<int64_t> write_shape; | 1112 | + std::vector<int64_t> write_shape; |
| 968 | 1113 | ||
| 969 | - for (int i = 0; i < input_num && i < static_cast<int>(args_list.size()); ++i) { | 1114 | + for (int i = 0; i < input_num && i < static_cast<int>(args_list.size()); ++i) { |
| 970 | - TensorInfo input = args_list[i]; | 1115 | + TensorInfo input = args_list[i]; |
| 971 | - input.param_name = "input" + std::to_string(i); | 1116 | + input.param_name = "input" + std::to_string(i); |
| 972 | - input.ori_shape = input.shape; | 1117 | + input.ori_shape = input.shape; |
| 973 | 1118 | ||
| 974 | - origin_inputs.push_back(input); | 1119 | + origin_inputs.push_back(input); |
| 975 | - inputs.push_back(input); | 1120 | + inputs.push_back(input); |
| 976 | 1121 | ||
| 977 | - if (i == 0) { | 1122 | + if (i == 0) { |
| 978 | - write_shape = input.shape; | 1123 | + write_shape = input.shape; |
| 979 | - if (transpose_a) { | 1124 | + m = transpose_a ? input.shape[input.shape.size() - 1] : input.shape[input.shape.size() - 2]; |
| 980 | - m = input.shape[input.shape.size() - 1]; | 1125 | + } else if (i == 1) { |
| 981 | - } else { | 1126 | + n = transpose_b ? input.shape[input.shape.size() - 2] : input.shape[input.shape.size() - 1]; |
| 982 | - m = input.shape[input.shape.size() - 2]; | ||
| 983 | - } | ||
| 984 | - } else if (i == 1) { | ||
| 985 | - if (transpose_b) { | ||
| 986 | - n = input.shape[input.shape.size() - 2]; | ||
| 987 | - } else { | ||
| 988 | - n = input.shape[input.shape.size() - 1]; | ||
| 989 | - } | ||
| 990 | - } | ||
| 991 | } | 1127 | } |
| 1128 | + } | ||
| 992 | 1129 | ||
| 993 | - if (args_list.size() >= 2) { | 1130 | + if (args_list.size() >= 2) { |
| 994 | - TensorInfo output = args_list[args_list.size() - 2]; | 1131 | + TensorInfo output = args_list[args_list.size() - 2]; |
| 995 | - output.param_name = "output0"; | 1132 | + output.param_name = "output0"; |
| 996 | - if (!write_shape.empty()) { | 1133 | + if (!write_shape.empty()) { |
| 997 | - write_shape[write_shape.size() - 1] = n; | 1134 | + write_shape[write_shape.size() - 1] = n; |
| 998 | - write_shape[write_shape.size() - 2] = m; | 1135 | + write_shape[write_shape.size() - 2] = m; |
| 999 | - output.shape = write_shape; | 1136 | + output.shape = write_shape; |
| 1000 | - output.ori_shape = write_shape; | 1137 | + output.ori_shape = write_shape; |
| 1001 | - } | ||
| 1002 | - if (!inputs.empty()) { | ||
| 1003 | - output.dtype = inputs.back().dtype; | ||
| 1004 | - } | ||
| 1005 | - origin_outputs.push_back(output); | ||
| 1006 | } | 1138 | } |
| 1139 | + if (!inputs.empty()) { | ||
| 1140 | + output.dtype = inputs.back().dtype; | ||
| 1141 | + } | ||
| 1142 | + origin_outputs.push_back(output); | ||
| 1143 | + } | ||
| 1007 | } | 1144 | } |
| 1008 | 1145 | ||
| 1009 | -std::string CubeKernelTilingWrapper::SerializeToJson(const CompileInfo& compile_info) { | 1146 | +TilingResult CubeKernelTilingWrapper::DoMatMulTiling(const CompileInfo &compile_info, |
| 1010 | - json j; | 1147 | + const std::vector<TensorInfo> &inputs, |
| 1011 | - j["soc_version"] = compile_info.soc_version; | 1148 | + const std::vector<TensorInfo> &outputs, |
| 1012 | - j["core_type"] = compile_info.core_type; | 1149 | + const std::vector<AttrInfo> &attrs, bool is_batch) { |
| 1013 | - j["device_id"] = compile_info.device_id; | 1150 | + TilingResult result; |
| 1014 | - j["op_kernel_lib"] = compile_info.op_kernel_lib; | 1151 | + if (AutofuseDoCubeMatMulTiling(&compile_info, &inputs, &outputs, &attrs, is_batch, &result)) { |
| 1015 | - j["op_impl_mode"] = compile_info.op_impl_mode; | 1152 | + FillTilingMeta(result, is_batch); |
| 1016 | - j["aicore_num"] = compile_info.aicore_num; | 1153 | + } else { |
| 1017 | - j["aiv_num"] = compile_info.aiv_num; | 1154 | + result.success = false; |
| 1018 | - | 1155 | + if (result.error_msg.empty()) { |
| 1019 | - if (!compile_info.extra_info.empty()) { | 1156 | + result.error_msg = "codegen shared MatMulV3 tiling failed"; |
| 1020 | - json extra; | ||
| 1021 | - for (const auto& pair : compile_info.extra_info) { | ||
| 1022 | - extra[pair.first] = pair.second; | ||
| 1023 | - } | ||
| 1024 | - j["extra_info"] = extra; | ||
| 1025 | } | 1157 | } |
| 1026 | - | 1158 | + } |
| 1027 | - return j.dump(); | 1159 | + return result; |
| 1028 | } | 1160 | } |
| 1029 | 1161 | ||
| 1030 | -std::string CubeKernelTilingWrapper::SerializeToJson(const std::vector<TensorInfo>& tensors) { | 1162 | +} // namespace autofuse |
| 1031 | - json j = json::array(); | 1163 | +} // namespace ge |
| 1032 | - for (const auto& tensor : tensors) { | ||
| 1033 | - json t; | ||
| 1034 | - t["param_name"] = tensor.param_name; | ||
| 1035 | - t["shape"] = tensor.shape; | ||
| 1036 | - t["ori_shape"] = tensor.ori_shape; | ||
| 1037 | - t["dtype"] = tensor.dtype; | ||
| 1038 | - t["format"] = tensor.format; | ||
| 1039 | - t["name"] = tensor.name; | ||
| 1040 | - t["range_start"] = tensor.range_start; | ||
| 1041 | - t["range_end"] = tensor.range_end; | ||
| 1042 | - j.push_back(t); | ||
| 1043 | - } | ||
| 1044 | - return j.dump(); | ||
| 1045 | -} | ||
| 1046 | - | ||
| 1047 | -std::string CubeKernelTilingWrapper::SerializeToJson(const std::vector<AttrInfo>& attrs) { | ||
| 1048 | - json j = json::array(); | ||
| 1049 | - for (const auto& attr : attrs) { | ||
| 1050 | - json a; | ||
| 1051 | - a["name"] = attr.name; | ||
| 1052 | - a["dtype"] = attr.dtype; | ||
| 1053 | - | ||
| 1054 | - if (attr.is_list) { | ||
| 1055 | - if (attr.dtype == "list_int" || attr.dtype == "list_int32") { | ||
| 1056 | - a["value"] = attr.value_list_int; | ||
| 1057 | - } else if (attr.dtype == "list_float" || attr.dtype == "list_float32") { | ||
| 1058 | - a["value"] = attr.value_list_float; | ||
| 1059 | - } else if (attr.dtype == "list_str") { | ||
| 1060 | - a["value"] = attr.value_list_str; | ||
| 1061 | - } | ||
| 1062 | - } else { | ||
| 1063 | - if (attr.dtype == "bool") { | ||
| 1064 | - a["value"] = attr.value_bool; | ||
| 1065 | - } else if (attr.dtype == "int" || attr.dtype == "int32" || attr.dtype == "int64") { | ||
| 1066 | - a["value"] = attr.value_int; | ||
| 1067 | - } else if (attr.dtype == "float" || attr.dtype == "float32" || attr.dtype == "float64") { | ||
| 1068 | - a["value"] = attr.value_float; | ||
| 1069 | - } else { | ||
| 1070 | - a["value"] = attr.value_str; | ||
| 1071 | - } | ||
| 1072 | - } | ||
| 1073 | - j.push_back(a); | ||
| 1074 | - } | ||
| 1075 | - return j.dump(); | ||
| 1076 | -} | ||
| 1077 | - | ||
| 1078 | -std::string CubeKernelTilingWrapper::SerializeToJson(const std::map<std::string, std::string>& extra_params) { | ||
| 1079 | - json j; | ||
| 1080 | - for (const auto& pair : extra_params) { | ||
| 1081 | - j[pair.first] = pair.second; | ||
| 1082 | - } | ||
| 1083 | - return j.dump(); | ||
| 1084 | -} | ||
| 1085 | - | ||
| 1086 | -std::string CubeKernelTilingWrapper::GenerateCompileInfoHash(const std::string& compile_info_json) { | ||
| 1087 | - return SHA1::Hash(compile_info_json); | ||
| 1088 | -} | ||
| 1089 | - | ||
| 1090 | -void CubeKernelTilingWrapper::ChangeParamNameToName(std::vector<TensorInfo>& inputs) { | ||
| 1091 | - for (auto& input : inputs) { | ||
| 1092 | - if (input.name.empty() && !input.param_name.empty()) { | ||
| 1093 | - input.name = input.param_name; | ||
| 1094 | - } | ||
| 1095 | - } | ||
| 1096 | -} | ||
| 1097 | - | ||
| 1098 | -void CubeKernelTilingWrapper::InputsPreProcess(std::vector<TensorInfo>& inputs) { | ||
| 1099 | - for (auto& input : inputs) { | ||
| 1100 | - if (input.range_start != 0 || input.range_end != 0) { | ||
| 1101 | - if (input.range_start == std::numeric_limits<int64_t>::min() || | ||
| 1102 | - input.range_start == std::numeric_limits<int64_t>::max()) { | ||
| 1103 | - input.range_start = 0; | ||
| 1104 | - } | ||
| 1105 | - if (input.range_end == std::numeric_limits<int64_t>::min() || | ||
| 1106 | - input.range_end == std::numeric_limits<int64_t>::max()) { | ||
| 1107 | - input.range_end = 0; | ||
| 1108 | - } | ||
| 1109 | - } | ||
| 1110 | - } | ||
| 1111 | -} | ||
| 1112 | - | ||
| 1113 | -void CubeKernelTilingWrapper::AttrsPreProcess(std::vector<AttrInfo>& attrs) { | ||
| 1114 | - for (auto& attr : attrs) { | ||
| 1115 | - if (attr.dtype == "float" || attr.dtype == "float32" || attr.dtype == "float64") { | ||
| 1116 | - if (!attr.is_list) { | ||
| 1117 | - if (std::isinf(attr.value_float)) { | ||
| 1118 | - if (attr.value_float > 0) { | ||
| 1119 | - attr.value_str = "float(1.0 / 0.0) "; | ||
| 1120 | - } else { | ||
| 1121 | - attr.value_str = "float(-1.0 / 0.0) "; | ||
| 1122 | - } | ||
| 1123 | - } else if (std::isnan(attr.value_float)) { | ||
| 1124 | - attr.value_str = "float(0.0 / 0.0) "; | ||
| 1125 | - } | ||
| 1126 | - } else { | ||
| 1127 | - for (auto& val : attr.value_list_float) { | ||
| 1128 | - if (std::isinf(val)) { | ||
| 1129 | - if (val > 0) { | ||
| 1130 | - val = std::numeric_limits<double>::max(); | ||
| 1131 | - } else { | ||
| 1132 | - val = std::numeric_limits<double>::min(); | ||
| 1133 | - } | ||
| 1134 | - } else if (std::isnan(val)) { | ||
| 1135 | - val = 0.0; | ||
| 1136 | - } | ||
| 1137 | - } | ||
| 1138 | - } | ||
| 1139 | - } else if (attr.dtype == "list_float" || attr.dtype == "list_float32") { | ||
| 1140 | - for (auto& val : attr.value_list_float) { | ||
| 1141 | - if (std::isinf(val)) { | ||
| 1142 | - if (val > 0) { | ||
| 1143 | - val = std::numeric_limits<double>::max(); | ||
| 1144 | - } else { | ||
| 1145 | - val = std::numeric_limits<double>::min(); | ||
| 1146 | - } | ||
| 1147 | - } else if (std::isnan(val)) { | ||
| 1148 | - val = 0.0; | ||
| 1149 | - } | ||
| 1150 | - } | ||
| 1151 | - } | ||
| 1152 | - } | ||
| 1153 | -} | ||
| 1154 | - | ||
| 1155 | -std::vector<uint8_t> CubeKernelTilingWrapper::AlignTilingDataTo8Bytes(const std::vector<uint8_t>& tiling_data, const std::string& soc_version) { | ||
| 1156 | - size_t original_size = tiling_data.size(); | ||
| 1157 | - std::vector<uint8_t> aligned_data = tiling_data; | ||
| 1158 | - | ||
| 1159 | - if (soc_version == "Ascend310P") { | ||
| 1160 | - return aligned_data; | ||
| 1161 | - } | ||
| 1162 | - | ||
| 1163 | - size_t aligned_size = ((original_size + 7) / 8) * 8; | ||
| 1164 | - size_t padding_size = aligned_size - original_size; | ||
| 1165 | - | ||
| 1166 | - aligned_data.resize(aligned_size, 0); | ||
| 1167 | - | ||
| 1168 | - return aligned_data; | ||
| 1169 | -} | ||
| 1170 | - | ||
| 1171 | -bool CubeKernelTilingWrapper::ParseTilingResult(const std::string& json_str, TilingResult& result) { | ||
| 1172 | - try { | ||
| 1173 | - json j = json::parse(json_str); | ||
| 1174 | - | ||
| 1175 | - if (j.contains("ret_code") && j["ret_code"].get_int64() != 0) { | ||
| 1176 | - result.success = false; | ||
| 1177 | - if (j.contains("error_messages") && j["error_messages"].is_array()) { | ||
| 1178 | - for (size_t i = 0; i < j["error_messages"].size(); ++i) { | ||
| 1179 | - const auto& err = j["error_messages"][i]; | ||
| 1180 | - if (err.contains("errormsg")) { | ||
| 1181 | - result.error_msg += err["errormsg"].get_string() + "; "; | ||
| 1182 | - } | ||
| 1183 | - } | ||
| 1184 | - } | ||
| 1185 | - return false; | ||
| 1186 | - } | ||
| 1187 | - result.success = true; | ||
| 1188 | - return true; | ||
| 1189 | - } catch (const std::exception& e) { | ||
| 1190 | - result.success = false; | ||
| 1191 | - result.error_msg = std::string("Parse JSON failed: ") + e.what(); | ||
| 1192 | - return false; | ||
| 1193 | - } | ||
| 1194 | -} | ||
| 1195 | - | ||
| 1196 | -char* CubeKernelTilingWrapper::CallDoOpTilingForCompile(const char* op_type, | ||
| 1197 | - const char* compile_info, | ||
| 1198 | - const char* compile_info_hash, | ||
| 1199 | - const char* inputs, | ||
| 1200 | - const char* outputs, | ||
| 1201 | - const char* attrs, | ||
| 1202 | - char* buf, | ||
| 1203 | - size_t buf_size, | ||
| 1204 | - uint64_t* timer, | ||
| 1205 | - const char* extra_params) { | ||
| 1206 | - fe::PlatFormInfos platform_infos; | ||
| 1207 | - fe::OptionalInfos q; | ||
| 1208 | - const char* soc_name = aclrtGetSocName(); | ||
| 1209 | - std::string soc_ver = soc_name ? soc_name : ""; | ||
| 1210 | - q.Init(); | ||
| 1211 | - q.SetSocVersion(soc_ver); | ||
| 1212 | - fe::PlatformInfoManager::Instance().SetOptionalCompilationInfo(q); // 这两个SetOptionalCompilationInfo都得有 | ||
| 1213 | - fe::PlatformInfoManager::GeInstance().SetOptionalCompilationInfo(q); // 否则获取soc version失败tiling计算出错 | ||
| 1214 | - fe::PlatformInfoManager::GeInstance().InitRuntimePlatformInfos(soc_ver); | ||
| 1215 | - int32_t device_id = 0; | ||
| 1216 | - aclrtGetDevice(&device_id); | ||
| 1217 | - if (fe::PlatformInfoManager::GeInstance().GetRuntimePlatformInfosByDevice(device_id, platform_infos) != 0) { | ||
| 1218 | - OP_LOGE(OP_NAME, "GetRuntimePlatformInfosByDevice failed"); | ||
| 1219 | - return nullptr; | ||
| 1220 | - } | ||
| 1221 | - OP_LOGI(OP_NAME, "Calling DoOpTilingForCompile..."); | ||
| 1222 | - const char* result = DoOpTilingForCompile(op_type, compile_info, compile_info_hash, | ||
| 1223 | - inputs, outputs, attrs, buf, buf_size, timer, extra_params); | ||
| 1224 | - OP_LOGI(OP_NAME, "DoOpTilingForCompile returned"); | ||
| 1225 | - | ||
| 1226 | - return const_cast<char*>(result); | ||
| 1227 | -} | ||
| 1228 | - | ||
| 1229 | -TilingResult CubeKernelTilingWrapper::DoMatMulTiling(const CompileInfo& compile_info, | ||
| 1230 | - const std::vector<TensorInfo>& inputs, | ||
| 1231 | - const std::vector<TensorInfo>& outputs, | ||
| 1232 | - const std::vector<AttrInfo>& attrs, | ||
| 1233 | - bool is_batch) { | ||
| 1234 | - TilingResult result; | ||
| 1235 | - | ||
| 1236 | - std::vector<TensorInfo> processed_inputs = inputs; | ||
| 1237 | - std::vector<AttrInfo> processed_attrs = attrs; | ||
| 1238 | - | ||
| 1239 | - ChangeParamNameToName(processed_inputs); | ||
| 1240 | - InputsPreProcess(processed_inputs); | ||
| 1241 | - AttrsPreProcess(processed_attrs); | ||
| 1242 | - | ||
| 1243 | - std::string compile_info_json = SerializeToJson(compile_info); | ||
| 1244 | - std::string inputs_json = SerializeToJson(processed_inputs); | ||
| 1245 | - std::string outputs_json = SerializeToJson(outputs); | ||
| 1246 | - std::string attrs_json = SerializeToJson(processed_attrs); | ||
| 1247 | - | ||
| 1248 | - std::string compile_info_hash = GenerateCompileInfoHash(compile_info_json); | ||
| 1249 | - | ||
| 1250 | - json extra_params; | ||
| 1251 | - extra_params["op_name"] = is_batch ? "BatchMatMulV3" : "MatMulV3"; | ||
| 1252 | - extra_params["deterministic"] = false; | ||
| 1253 | - std::string extra_params_json = extra_params.dump(); | ||
| 1254 | - | ||
| 1255 | - std::string op_type = is_batch ? "BatchMatMulV3" : "MatMulV3"; | ||
| 1256 | - | ||
| 1257 | - const size_t buf_size = 1024 * 64; | ||
| 1258 | - std::vector<char> buf(buf_size, 0); | ||
| 1259 | - | ||
| 1260 | - char* ret = CallDoOpTilingForCompile(op_type.c_str(), | ||
| 1261 | - compile_info_json.c_str(), | ||
| 1262 | - compile_info_hash.c_str(), | ||
| 1263 | - inputs_json.c_str(), | ||
| 1264 | - outputs_json.c_str(), | ||
| 1265 | - attrs_json.c_str(), | ||
| 1266 | - buf.data(), | ||
| 1267 | - buf_size, | ||
| 1268 | - nullptr, | ||
| 1269 | - extra_params_json.c_str()); | ||
| 1270 | - | ||
| 1271 | - if (ret == nullptr) { | ||
| 1272 | - result.success = false; | ||
| 1273 | - result.error_msg = "DoOpTilingForCompile returned nullptr"; | ||
| 1274 | - return (result); | ||
| 1275 | - } | ||
| 1276 | - | ||
| 1277 | - std::string ret_json(ret); | ||
| 1278 | - ParseTilingResult(ret_json, result); | ||
| 1279 | - | ||
| 1280 | - if (result.success) { | ||
| 1281 | - std::string buf_json(buf.data()); | ||
| 1282 | - json j = json::parse(buf_json); | ||
| 1283 | - if (j.contains("tiling_data")) { | ||
| 1284 | - std::string hex_str = j["tiling_data"].get_string(); | ||
| 1285 | - result.tiling_data.clear(); | ||
| 1286 | - for (size_t i = 0; i < hex_str.length(); i += 2) { | ||
| 1287 | - std::string byte_str = hex_str.substr(i, 2); | ||
| 1288 | - result.tiling_data.push_back(static_cast<uint8_t>(std::stoul(byte_str, nullptr, 16))); | ||
| 1289 | - } | ||
| 1290 | - | ||
| 1291 | - result.tiling_data = AlignTilingDataTo8Bytes(result.tiling_data, compile_info.soc_version); | ||
| 1292 | - | ||
| 1293 | - if (result.tiling_data.size() >= sizeof(MatMulV3BasicTilingData)) { | ||
| 1294 | - memcpy(&result.matmul_basic_tiling_data, result.tiling_data.data(), sizeof(MatMulV3BasicTilingData)); | ||
| 1295 | - result.cube_used_core_num = std::max(result.matmul_basic_tiling_data.usedCoreNum, 1U); | ||
| 1296 | - result.cube_base_m = std::max(result.matmul_basic_tiling_data.baseM, 1U); | ||
| 1297 | - result.cube_base_n = std::max(result.matmul_basic_tiling_data.baseN, 1U); | ||
| 1298 | - } | ||
| 1299 | - if (result.tiling_data.size() >= sizeof(BatchMatMulV3BasicTilingData)) { | ||
| 1300 | - memcpy(&result.batch_matmul_tiling_data, result.tiling_data.data(), sizeof(BatchMatMulV3BasicTilingData)); | ||
| 1301 | - if (is_batch) { | ||
| 1302 | - result.cube_used_core_num = std::max(result.batch_matmul_tiling_data.matMulTilingData.usedCoreNum, 1U); | ||
| 1303 | - result.cube_base_m = std::max(result.batch_matmul_tiling_data.matMulTilingData.baseM, 1U); | ||
| 1304 | - result.cube_base_n = std::max(result.batch_matmul_tiling_data.matMulTilingData.baseN, 1U); | ||
| 1305 | - } | ||
| 1306 | - } | ||
| 1307 | - } | ||
| 1308 | - if (j.contains("tiling_key")) { | ||
| 1309 | - result.tiling_key = j["tiling_key"].get_int64(); | ||
| 1310 | - } | ||
| 1311 | - if (j.contains("block_dim")) { | ||
| 1312 | - result.block_dim = j["block_dim"].get_int64(); | ||
| 1313 | - } | ||
| 1314 | - if (j.contains("workspaces")) { | ||
| 1315 | - result.workspace_size = j["workspaces"][0].get_int64(); | ||
| 1316 | - } | ||
| 1317 | - if (j.contains("clear_atomic")) { | ||
| 1318 | - result.atomic_flag = j["clear_atomic"].get_bool(); | ||
| 1319 | - } | ||
| 1320 | - } | ||
| 1321 | - | ||
| 1322 | - return result; | ||
| 1323 | -} | ||
| 1324 | - | ||
| 1325 | -} // namespace autofuse | ||
| 1326 | -} // namespace ge | ||
| 1327 | 1164 | ||
| 1328 | )"; | 1165 | )"; |
| @@ -39,6 +39,11 @@ CV_HOST_LINK_LIBRARIES = HOST_LINK_LIBRARIES + ["nnopbase"] | |||
| 39 | INDUCTOR_COMPILE_TRACE_LABEL = "InductorCompile" | 39 | INDUCTOR_COMPILE_TRACE_LABEL = "InductorCompile" |
| 40 | HOST_COMPILE_MAX_WORKERS = 32 | 40 | HOST_COMPILE_MAX_WORKERS = 32 |
| 41 | HOST_CPP_STANDARD = "-std=c++17" | 41 | HOST_CPP_STANDARD = "-std=c++17" |
| 42 | +CV_WRAPPER_SOURCE_NAME = "cube_kernel_tiling_wrapper.cpp" | ||
| 43 | +CV_WRAPPER_SPLIT_KEY = "BCubeKernelTilingWrapperCpp" | ||
| 44 | +CV_WRAPPER_CACHE_DIR_NAME = "cv_tiling_wrapper_cache" | ||
| 45 | +CV_WRAPPER_SO_BASENAME = "libautofuse_cv_tiling_wrapper" | ||
| 46 | +CV_WRAPPER_RPATH_OPTION = f"-Wl,-rpath,$ORIGIN/{CV_WRAPPER_CACHE_DIR_NAME}" | ||
| 42 | PGO_BUNDLE_SCHEMA_VERSION = 1 | 47 | PGO_BUNDLE_SCHEMA_VERSION = 1 |
| 43 | PGO_RESULT_PROTOCOL_VERSION = 1 | 48 | PGO_RESULT_PROTOCOL_VERSION = 1 |
| 44 | PGO_KERNEL_FORMAT = "aicore_binary_elf_v1" | 49 | PGO_KERNEL_FORMAT = "aicore_binary_elf_v1" |
| @@ -185,10 +190,12 @@ def run_compile_command(cmd: List[str], stage_name): | |||
| 185 | print(f"[{stage_name}] {result.stdout}") | 190 | print(f"[{stage_name}] {result.stdout}") |
| 186 | 191 | ||
| 187 | 192 | ||
| 188 | -def link_shared(target_file, obj_files, link_libraries=None): | 193 | +def link_shared(target_file, obj_files, link_libraries=None, extra_link_options=None): |
| 189 | link_command = [f"{ASCEND_PATH}/tools/bisheng_compiler/bin/bisheng"] | 194 | link_command = [f"{ASCEND_PATH}/tools/bisheng_compiler/bin/bisheng"] |
| 190 | link_command.extend(obj_files) | 195 | link_command.extend(obj_files) |
| 191 | link_command.extend(["-fPIC", "--shared", "-o", target_file]) | 196 | link_command.extend(["-fPIC", "--shared", "-o", target_file]) |
| 197 | + if extra_link_options: | ||
| 198 | + link_command.extend(extra_link_options) | ||
| 192 | if link_libraries: | 199 | if link_libraries: |
| 193 | link_command.extend(["-L", f"{ASCEND_PATH}/lib64"]) | 200 | link_command.extend(["-L", f"{ASCEND_PATH}/lib64"]) |
| 194 | link_command.extend(["-L", f"{ASCEND_PATH}/{machine}-linux/lib64"]) | 201 | link_command.extend(["-L", f"{ASCEND_PATH}/{machine}-linux/lib64"]) |
| @@ -197,6 +204,115 @@ def link_shared(target_file, obj_files, link_libraries=None): | |||
| 197 | return target_file | 204 | return target_file |
| 198 | 205 | ||
| 199 | 206 | ||
| 207 | +def is_cv_wrapper_source(source_file): | ||
| 208 | + base_name = os.path.basename(source_file) | ||
| 209 | + return base_name == CV_WRAPPER_SOURCE_NAME or base_name.endswith( | ||
| 210 | + f"_tiling_func_{CV_WRAPPER_SPLIT_KEY}.cpp" | ||
| 211 | + ) | ||
| 212 | + | ||
| 213 | + | ||
| 214 | +def get_shared_cv_wrapper_cache_dir(args: argparse.Namespace, temp_dir): | ||
| 215 | + output_file = getattr(args, "output_file", None) | ||
| 216 | + output_file_dir = ( | ||
| 217 | + os.path.dirname(os.path.realpath(output_file)) if output_file else None | ||
| 218 | + ) | ||
| 219 | + cache_root = ( | ||
| 220 | + temp_dir | ||
| 221 | + or output_file_dir | ||
| 222 | + or os.getenv("RUN_DIR") | ||
| 223 | + or os.getenv("TORCHINDUCTOR_NPU_EXT_CACHE_DIR") | ||
| 224 | + ) | ||
| 225 | + return os.path.join(os.path.realpath(cache_root), CV_WRAPPER_CACHE_DIR_NAME) | ||
| 226 | + | ||
| 227 | + | ||
| 228 | +def read_file_bytes(file_path): | ||
| 229 | + with open(file_path, "rb") as f: | ||
| 230 | + return f.read() | ||
| 231 | + | ||
| 232 | + | ||
| 233 | +def get_shared_cv_wrapper_so_path(args: argparse.Namespace, temp_dir, source_file): | ||
| 234 | + digest = hashlib.sha256() | ||
| 235 | + digest.update(read_file_bytes(source_file)) | ||
| 236 | + digest.update(str(ASCEND_PATH).encode("utf-8")) | ||
| 237 | + digest.update(str(machine).encode("utf-8")) | ||
| 238 | + digest.update(str(getattr(args, "soc_version", "")).encode("utf-8")) | ||
| 239 | + digest.update(str(getattr(args, "compile_options", "")).encode("utf-8")) | ||
| 240 | + digest.update(str(getattr(args, "stage", "")).encode("utf-8")) | ||
| 241 | + so_name = f"{CV_WRAPPER_SO_BASENAME}_{digest.hexdigest()[:16]}.so" | ||
| 242 | + return os.path.join(get_shared_cv_wrapper_cache_dir(args, temp_dir), so_name) | ||
| 243 | + | ||
| 244 | + | ||
| 245 | +def get_shared_cv_wrapper_soname_options(so_path): | ||
| 246 | + return [f"-Wl,-soname,{os.path.basename(so_path)}"] | ||
| 247 | + | ||
| 248 | + | ||
| 249 | +def get_shared_cv_wrapper_rpath_options(args: argparse.Namespace): | ||
| 250 | + return ( | ||
| 251 | + [CV_WRAPPER_RPATH_OPTION] | ||
| 252 | + if getattr(args, "shared_cv_wrapper_so", None) | ||
| 253 | + else None | ||
| 254 | + ) | ||
| 255 | + | ||
| 256 | + | ||
| 257 | +def build_shared_cv_wrapper_so( | ||
| 258 | + args: argparse.Namespace, temp_dir, source_file, so_path | ||
| 259 | +): | ||
| 260 | + tmp_so_path = f"{so_path}.{os.getpid()}.{time.time_ns()}.tmp" | ||
| 261 | + try: | ||
| 262 | + wrapper_obj = compile_host_obj_file(args, temp_dir, source_file) | ||
| 263 | + link_shared( | ||
| 264 | + tmp_so_path, | ||
| 265 | + [wrapper_obj], | ||
| 266 | + link_libraries=CV_HOST_LINK_LIBRARIES, | ||
| 267 | + extra_link_options=get_shared_cv_wrapper_soname_options(so_path), | ||
| 268 | + ) | ||
| 269 | + os.replace(tmp_so_path, so_path) | ||
| 270 | + finally: | ||
| 271 | + if os.path.exists(tmp_so_path): | ||
| 272 | + os.remove(tmp_so_path) | ||
| 273 | + | ||
| 274 | + | ||
| 275 | +def ensure_shared_cv_wrapper_so(args: argparse.Namespace, temp_dir, source_file): | ||
| 276 | + so_path = get_shared_cv_wrapper_so_path(args, temp_dir, source_file) | ||
| 277 | + if os.path.exists(so_path): | ||
| 278 | + return so_path | ||
| 279 | + os.makedirs(os.path.dirname(so_path), exist_ok=True) | ||
| 280 | + lock_path = f"{so_path}.lock" | ||
| 281 | + with open(lock_path, "w") as lock_file: | ||
| 282 | + fcntl.flock(lock_file, fcntl.LOCK_EX) | ||
| 283 | + try: | ||
| 284 | + if os.path.exists(so_path): | ||
| 285 | + return so_path | ||
| 286 | + build_shared_cv_wrapper_so(args, temp_dir, source_file, so_path) | ||
| 287 | + finally: | ||
| 288 | + fcntl.flock(lock_file, fcntl.LOCK_UN) | ||
| 289 | + return so_path | ||
| 290 | + | ||
| 291 | + | ||
| 292 | +def append_shared_cv_wrapper_so(args: argparse.Namespace, obj_files): | ||
| 293 | + shared_cv_wrapper_so = getattr(args, "shared_cv_wrapper_so", None) | ||
| 294 | + if shared_cv_wrapper_so and is_cv_fusion_compile(args): | ||
| 295 | + return obj_files + [shared_cv_wrapper_so] | ||
| 296 | + return obj_files | ||
| 297 | + | ||
| 298 | + | ||
| 299 | +def prepare_shared_cv_wrapper(args: argparse.Namespace, temp_dir, host_files): | ||
| 300 | + if not is_cv_fusion_compile(args): | ||
| 301 | + return host_files | ||
| 302 | + regular_host_files = [] | ||
| 303 | + wrapper_sources = [] | ||
| 304 | + for source_file in host_files: | ||
| 305 | + if is_cv_wrapper_source(source_file): | ||
| 306 | + wrapper_sources.append(source_file) | ||
| 307 | + else: | ||
| 308 | + regular_host_files.append(source_file) | ||
| 309 | + if wrapper_sources: | ||
| 310 | + args.shared_cv_wrapper_so = ensure_shared_cv_wrapper_so( | ||
| 311 | + args, temp_dir, wrapper_sources[0] | ||
| 312 | + ) | ||
| 313 | + return regular_host_files | ||
| 314 | + | ||
| 315 | + | ||
| 200 | def link_pgo_executable(target_file, obj_files, mspti_link_flags): | 316 | def link_pgo_executable(target_file, obj_files, mspti_link_flags): |
| 201 | link_command = [f"{ASCEND_PATH}/tools/bisheng_compiler/bin/bisheng", *obj_files] | 317 | link_command = [f"{ASCEND_PATH}/tools/bisheng_compiler/bin/bisheng", *obj_files] |
| 202 | link_command.extend(["-fPIC", "-o", target_file]) | 318 | link_command.extend(["-fPIC", "-o", target_file]) |
| @@ -413,14 +529,18 @@ def build_host_include_options(temp_dir): | |||
| 413 | "-I", | 529 | "-I", |
| 414 | f"{ASCEND_PATH}/include", | 530 | f"{ASCEND_PATH}/include", |
| 415 | "-I", | 531 | "-I", |
| 532 | + f"{ASCEND_PATH}/{machine}-linux/pkg_inc", | ||
| 533 | + "-I", | ||
| 534 | + f"{ASCEND_PATH}/{machine}-linux/pkg_inc/base", | ||
| 535 | + "-I", | ||
| 536 | + f"{ASCEND_PATH}/pkg_inc", | ||
| 537 | + "-I", | ||
| 416 | f"{ASCEND_PATH}/pkg_inc/base", | 538 | f"{ASCEND_PATH}/pkg_inc/base", |
| 417 | "-I", | 539 | "-I", |
| 418 | f"{ASCEND_PATH}/include/base", | 540 | f"{ASCEND_PATH}/include/base", |
| 419 | "-I", | 541 | "-I", |
| 420 | f"{ASCEND_PATH}/include/experiment", | 542 | f"{ASCEND_PATH}/include/experiment", |
| 421 | "-I", | 543 | "-I", |
| 422 | - f"{ASCEND_PATH}/{machine}-linux/pkg_inc/base", | ||
| 423 | - "-I", | ||
| 424 | f"{ASCEND_PATH}/{machine}-linux/include", | 544 | f"{ASCEND_PATH}/{machine}-linux/include", |
| 425 | "-I", | 545 | "-I", |
| 426 | f"{ASCEND_PATH}/{machine}-linux/include/aclnn", | 546 | f"{ASCEND_PATH}/{machine}-linux/include/aclnn", |
| @@ -705,7 +825,11 @@ def normalize_to_list(value): | |||
| 705 | 825 | ||
| 706 | 826 | ||
| 707 | def compile_host_objs(args: argparse.Namespace, temp_dir, pch_path=None): | 827 | def compile_host_objs(args: argparse.Namespace, temp_dir, pch_path=None): |
| 708 | - host_files = normalize_to_list(args.host_files) | 828 | + host_files = prepare_shared_cv_wrapper( |
| 829 | + args, temp_dir, normalize_to_list(args.host_files) | ||
| 830 | + ) | ||
| 831 | + if not host_files: | ||
| 832 | + return [] | ||
| 709 | pch_state = {"path": pch_path, "lock": Lock()} | 833 | pch_state = {"path": pch_path, "lock": Lock()} |
| 710 | if len(host_files) == 1: | 834 | if len(host_files) == 1: |
| 711 | return [compile_host_obj_file(args, temp_dir, host_files[0], pch_state)] | 835 | return [compile_host_obj_file(args, temp_dir, host_files[0], pch_state)] |
| @@ -793,18 +917,24 @@ def build_device_so(args: argparse.Namespace, host_obj_path, temp_dir): | |||
| 793 | host_obj_paths = normalize_to_list(host_obj_path) | 917 | host_obj_paths = normalize_to_list(host_obj_path) |
| 794 | if host_obj_paths: | 918 | if host_obj_paths: |
| 795 | obj_files = host_obj_paths + obj_files | 919 | obj_files = host_obj_paths + obj_files |
| 920 | + obj_files = append_shared_cv_wrapper_so(args, obj_files) | ||
| 796 | link_libraries = ( | 921 | link_libraries = ( |
| 797 | CV_HOST_LINK_LIBRARIES | 922 | CV_HOST_LINK_LIBRARIES |
| 798 | if host_obj_paths and is_cv_fusion_compile(args) | 923 | if host_obj_paths and is_cv_fusion_compile(args) |
| 799 | else (HOST_LINK_LIBRARIES if host_obj_paths else None) | 924 | else (HOST_LINK_LIBRARIES if host_obj_paths else None) |
| 800 | ) | 925 | ) |
| 801 | with InductorCompileDuration(args, "LinkDeviceSo"): | 926 | with InductorCompileDuration(args, "LinkDeviceSo"): |
| 802 | - return link_shared(target_file, obj_files, link_libraries=link_libraries) | 927 | + return link_shared( |
| 928 | + target_file, | ||
| 929 | + obj_files, | ||
| 930 | + link_libraries=link_libraries, | ||
| 931 | + extra_link_options=get_shared_cv_wrapper_rpath_options(args), | ||
| 932 | + ) | ||
| 803 | 933 | ||
| 804 | 934 | ||
| 805 | def clean_before_modify(temp_dir): | 935 | def clean_before_modify(temp_dir): |
| 806 | src_directory = os.getcwd() | 936 | src_directory = os.getcwd() |
| 807 | - keep_dirs = {"host", "device"} | 937 | + keep_dirs = {"host", "device", CV_WRAPPER_CACHE_DIR_NAME} |
| 808 | for entry in os.listdir(temp_dir): | 938 | for entry in os.listdir(temp_dir): |
| 809 | entry_path = os.path.join(temp_dir, entry) | 939 | entry_path = os.path.join(temp_dir, entry) |
| 810 | if os.path.isfile(entry_path): | 940 | if os.path.isfile(entry_path): |
| @@ -1056,9 +1186,13 @@ def try_static_shape_compile(args: argparse.Namespace, temp_dir, so_path): | |||
| 1056 | def link_host_target(args, temp_dir, pch_path=None): | 1186 | def link_host_target(args, temp_dir, pch_path=None): |
| 1057 | # 处理 host 编译阶段 | 1187 | # 处理 host 编译阶段 |
| 1058 | if pch_path is None: | 1188 | if pch_path is None: |
| 1059 | - host_obj_paths = compile_host_objs(args, temp_dir) | 1189 | + host_obj_paths = append_shared_cv_wrapper_so( |
| 1190 | + args, compile_host_objs(args, temp_dir) | ||
| 1191 | + ) | ||
| 1060 | else: | 1192 | else: |
| 1061 | - host_obj_paths = compile_host_objs(args, temp_dir, pch_path) | 1193 | + host_obj_paths = append_shared_cv_wrapper_so( |
| 1194 | + args, compile_host_objs(args, temp_dir, pch_path) | ||
| 1195 | + ) | ||
| 1062 | so_file = os.path.join(temp_dir, os.path.basename(args.output_file)) | 1196 | so_file = os.path.join(temp_dir, os.path.basename(args.output_file)) |
| 1063 | link_libraries = ( | 1197 | link_libraries = ( |
| 1064 | CV_HOST_LINK_LIBRARIES if is_cv_fusion_compile(args) else HOST_LINK_LIBRARIES | 1198 | CV_HOST_LINK_LIBRARIES if is_cv_fusion_compile(args) else HOST_LINK_LIBRARIES |
| @@ -1066,7 +1200,12 @@ def link_host_target(args, temp_dir, pch_path=None): | |||
| 1066 | if getattr(args, "pgo_runner_file", None) is not None: | 1200 | if getattr(args, "pgo_runner_file", None) is not None: |
| 1067 | link_libraries = link_libraries + ["ascendcl", "runtime"] | 1201 | link_libraries = link_libraries + ["ascendcl", "runtime"] |
| 1068 | with InductorCompileDuration(args, "LinkHostSo"): | 1202 | with InductorCompileDuration(args, "LinkHostSo"): |
| 1069 | - link_shared(so_file, host_obj_paths, link_libraries=link_libraries) | 1203 | + link_shared( |
| 1204 | + so_file, | ||
| 1205 | + host_obj_paths, | ||
| 1206 | + link_libraries=link_libraries, | ||
| 1207 | + extra_link_options=get_shared_cv_wrapper_rpath_options(args), | ||
| 1208 | + ) | ||
| 1070 | return so_file | 1209 | return so_file |
| 1071 | 1210 | ||
| 1072 | 1211 | ||
| @@ -1104,6 +1243,15 @@ def copy_so_to_output(so_file, args, src_directory): | |||
| 1104 | os.makedirs(dst_dir_path) | 1243 | os.makedirs(dst_dir_path) |
| 1105 | 1244 | ||
| 1106 | shutil.copy(so_file, dst_file) | 1245 | shutil.copy(so_file, dst_file) |
| 1246 | + shared_cv_wrapper_so = getattr(args, "shared_cv_wrapper_so", None) | ||
| 1247 | + if shared_cv_wrapper_so: | ||
| 1248 | + wrapper_dst_dir = os.path.join(dst_dir_path, CV_WRAPPER_CACHE_DIR_NAME) | ||
| 1249 | + os.makedirs(wrapper_dst_dir, exist_ok=True) | ||
| 1250 | + wrapper_dst_file = os.path.join( | ||
| 1251 | + wrapper_dst_dir, os.path.basename(shared_cv_wrapper_so) | ||
| 1252 | + ) | ||
| 1253 | + if os.path.realpath(shared_cv_wrapper_so) != os.path.realpath(wrapper_dst_file): | ||
| 1254 | + shutil.copy(shared_cv_wrapper_so, wrapper_dst_file) | ||
| 1107 | print(f"copy file {so_file} to {dst_file}") | 1255 | print(f"copy file {so_file} to {dst_file}") |
| 1108 | os.chdir(src_directory) | 1256 | os.chdir(src_directory) |
| 1109 | 1257 | ||
| @@ -14,6 +14,8 @@ | |||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | + | ||
| 18 | + | ||
| 17 | 19 | ||
| 18 | std::vector<std::string> splitString(const std::string &input, char delimiter) { | 20 | std::vector<std::string> splitString(const std::string &input, char delimiter) { |
| 19 | std::vector<std::string> result; | 21 | std::vector<std::string> result; |
| @@ -29,6 +31,101 @@ std::vector<std::string> splitString(const std::string &input, char delimiter) { | |||
| 29 | 31 | ||
| 30 | class LoadIsFiniteStoreTest : public testing::Test {}; | 32 | class LoadIsFiniteStoreTest : public testing::Test {}; |
| 31 | 33 | ||
| 34 | +namespace { | ||
| 35 | +void ConnectUnaryBitWidthChangeGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, | ||
| 36 | + const af::Axis &z0, const af::Axis &z1) { | ||
| 37 | + af::ascir_op::Data x_op("x", graph); | ||
| 38 | + af::ascir_op::Load load_op("load"); | ||
| 39 | + af::ascir_op::Isnan isnan_op("isnan"); | ||
| 40 | + graph.AddNode(load_op); | ||
| 41 | + graph.AddNode(isnan_op); | ||
| 42 | + | ||
| 43 | + load_op.x = x_op.y; | ||
| 44 | + load_op.attr.sched.axis = {z0.id, z1.id}; | ||
| 45 | + *load_op.y.axis = {z0.id, z1.id}; | ||
| 46 | + *load_op.y.repeats = {s0, s1}; | ||
| 47 | + *load_op.y.strides = {s1, af::ops::One}; | ||
| 48 | + | ||
| 49 | + isnan_op.x = load_op.y; | ||
| 50 | + *isnan_op.y.axis = {z0.id, z1.id}; | ||
| 51 | + *isnan_op.y.repeats = {s0, s1}; | ||
| 52 | + *isnan_op.y.strides = {s1, af::ops::One}; | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +void InitUnaryLoadAttrs(const af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1) { | ||
| 56 | + auto load = graph.FindNode("load"); | ||
| 57 | + load->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 58 | + load->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 59 | + load->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 60 | + load->attr.sched.loop_axis = z0.id; | ||
| 61 | + load->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 62 | + load->outputs[0].attr.vectorized_strides = {af::ops::One}; | ||
| 63 | + load->outputs[0].attr.dtype = ge::DT_FLOAT; | ||
| 64 | + load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 65 | + load->outputs[0].attr.mem.tensor_id = 0; | ||
| 66 | + load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 67 | + load->outputs[0].attr.que.id = 1; | ||
| 68 | + load->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +void InitUnaryIsnanAttrs(const af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1) { | ||
| 72 | + auto isnan = graph.FindNode("isnan"); | ||
| 73 | + isnan->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 74 | + isnan->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 75 | + isnan->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 76 | + isnan->attr.sched.loop_axis = z0.id; | ||
| 77 | + isnan->attr.tmp_buffers = {{{af::Symbol(8192), -1}, af::MemAttr(), 0}}; | ||
| 78 | + isnan->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 79 | + isnan->outputs[0].attr.vectorized_strides = {af::ops::One}; | ||
| 80 | + isnan->outputs[0].attr.dtype = ge::DT_INT16; | ||
| 81 | + isnan->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 82 | + isnan->outputs[0].attr.mem.tensor_id = 3; | ||
| 83 | + isnan->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 84 | + isnan->outputs[0].attr.que.id = 2; | ||
| 85 | + isnan->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 86 | +} | ||
| 87 | + | ||
| 88 | +std::string GenerateUnaryBitWidthChangeNoLoopCall() { | ||
| 89 | + af::AscGraph graph("test_graph"); | ||
| 90 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 91 | + auto s1 = graph.CreateSizeVar("s1"); | ||
| 92 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 93 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 94 | + ConnectUnaryBitWidthChangeGraph(graph, s0, s1, z0, z1); | ||
| 95 | + InitUnaryLoadAttrs(graph, z0, z1); | ||
| 96 | + InitUnaryIsnanAttrs(graph, z0, z1); | ||
| 97 | + | ||
| 98 | + auto load = graph.FindNode("load"); | ||
| 99 | + auto isnan = graph.FindNode("isnan"); | ||
| 100 | + | ||
| 101 | + codegen::Tiler tiler; | ||
| 102 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 103 | + EXPECT_EQ(tpipe.CollectQues(graph), 0); | ||
| 104 | + EXPECT_EQ(tpipe.AddTensor(load->outputs[0]), 0); | ||
| 105 | + EXPECT_EQ(tpipe.AddTensor(isnan->outputs[0]), 0); | ||
| 106 | + | ||
| 107 | + tiler.AddAxis(z0); | ||
| 108 | + tiler.AddAxis(z1); | ||
| 109 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 110 | + tiler.AddSizeVar(af::SizeVar(s1)); | ||
| 111 | + | ||
| 112 | + codegen::ApiTensor x1; | ||
| 113 | + x1.id = load->outputs[0].attr.mem.tensor_id; | ||
| 114 | + codegen::UnaryBitWidthChangeApiCall call("IsnanExtend"); | ||
| 115 | + EXPECT_EQ(call.Init(isnan), 0); | ||
| 116 | + call.inputs.push_back(&x1); | ||
| 117 | + | ||
| 118 | + std::string result; | ||
| 119 | + EXPECT_EQ(call.Generate(tpipe, {z0.id}, result), 0); | ||
| 120 | + return result; | ||
| 121 | +} | ||
| 122 | +} // namespace | ||
| 123 | + | ||
| 124 | +TEST_F(LoadIsFiniteStoreTest, UnaryBitWidthChangeNoLoopUsesAlignedSize) { | ||
| 125 | + const std::string result = GenerateUnaryBitWidthChangeNoLoopCall(); | ||
| 126 | + EXPECT_EQ(result, "IsnanExtend(local_3[0], local_0[0], tmp_buf_0, local_0_actual_size);\n"); | ||
| 127 | +} | ||
| 128 | + | ||
| 32 | TEST_F(LoadIsFiniteStoreTest, LoadIsFiniteStoreCodegen) { | 129 | TEST_F(LoadIsFiniteStoreTest, LoadIsFiniteStoreCodegen) { |
| 33 | bool gen_success = true; | 130 | bool gen_success = true; |
| 34 | af::AscGraph test_graph("load_isfinite_store"); | 131 | af::AscGraph test_graph("load_isfinite_store"); |
| @@ -68,7 +68,11 @@ TEST_F(LoadLogicalNotStoreTest, LoadLogicalNotStoreCodegen) { | |||
| 68 | InitScheduleResultsByImplGraphs(test_impl_graphs, fused_schedule_result); | 68 | InitScheduleResultsByImplGraphs(test_impl_graphs, fused_schedule_result); |
| 69 | codegen::CodegenResult result; | 69 | codegen::CodegenResult result; |
| 70 | EXPECT_EQ(codegen.Generate(fused_schedule_result, result), 0); | 70 | EXPECT_EQ(codegen.Generate(fused_schedule_result, result), 0); |
| 71 | - kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel); | 71 | + const std::string kernel = RemoveSubDirInclude(result.kernel); |
| 72 | + EXPECT_NE(kernel.find("LogicalNot(local_4[0], local_2[0], local_blk_tensor_of_half_1, tmp_buf_0, " | ||
| 73 | + "local_2_actual_size);"), | ||
| 74 | + std::string::npos); | ||
| 75 | + kernel_file << tilig_stub << kernel; | ||
| 72 | tiling_file << result.tiling; | 76 | tiling_file << result.tiling; |
| 73 | tiling_data_file << result.tiling_data; | 77 | tiling_data_file << result.tiling_data; |
| 74 | } catch (...) { | 78 | } catch (...) { |
| @@ -68,7 +68,12 @@ TEST_F(LoadWhereStoreTest, LoadWhereStoreCodegen) { | |||
| 68 | InitScheduleResultsByImplGraphs(test_impl_graphs, fused_schedule_result); | 68 | InitScheduleResultsByImplGraphs(test_impl_graphs, fused_schedule_result); |
| 69 | codegen::CodegenResult result; | 69 | codegen::CodegenResult result; |
| 70 | EXPECT_EQ(codegen.Generate(fused_schedule_result, result), 0); | 70 | EXPECT_EQ(codegen.Generate(fused_schedule_result, result), 0); |
| 71 | - kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel); | 71 | + const std::string kernel = RemoveSubDirInclude(result.kernel); |
| 72 | + EXPECT_NE(kernel.find("Where<false, false>(local_6[0], local_3[0], local_4[0], local_5[0], z1t_actual_size, " | ||
| 73 | + "t->s2"), | ||
| 74 | + std::string::npos); | ||
| 75 | + EXPECT_NE(kernel.find("((8 * Ceiling((Rational(1 , 8) * t->s2))))/(1)"), std::string::npos); | ||
| 76 | + kernel_file << tilig_stub << kernel; | ||
| 72 | tiling_file << result.tiling; | 77 | tiling_file << result.tiling; |
| 73 | tiling_data_file << result.tiling_data; | 78 | tiling_data_file << result.tiling_data; |
| 74 | } catch (...) { | 79 | } catch (...) { |
| @@ -176,7 +176,9 @@ def test_inductor_host_link_includes_acl_runtime(ascendc_compile_module, tmp_pat | |||
| 176 | ascendc_compile_module.module.compile_host_objs = fake_compile_host_objs | 176 | ascendc_compile_module.module.compile_host_objs = fake_compile_host_objs |
| 177 | ascendc_compile_module.module.is_cv_fusion_compile = fake_is_cv_fusion_compile | 177 | ascendc_compile_module.module.is_cv_fusion_compile = fake_is_cv_fusion_compile |
| 178 | 178 | ||
| 179 | - def fake_link_shared(target_file, obj_files, link_libraries=None): | 179 | + def fake_link_shared( |
| 180 | + target_file, obj_files, link_libraries=None, extra_link_options=None | ||
| 181 | + ): | ||
| 180 | captured["link_libraries"] = link_libraries | 182 | captured["link_libraries"] = link_libraries |
| 181 | return target_file | 183 | return target_file |
| 182 | 184 | ||
| @@ -921,7 +921,7 @@ TEST(WhereApiCallTest, WhereApiCall_Scaler_x2x3_throwfor) { | |||
| 921 | std::cout << result << std::endl; | 921 | std::cout << result << std::endl; |
| 922 | EXPECT_EQ(result, std::string{"Where<true, true>(local_3[0], local_0[0], local_blk_tensor_of_local_1[0], " | 922 | EXPECT_EQ(result, std::string{"Where<true, true>(local_3[0], local_0[0], local_blk_tensor_of_local_1[0], " |
| 923 | "local_blk_tensor_of_local_2[0], t->s1, t->s2, t->s2, (2 * t->s2), ONE_BLK_SIZE / " | 923 | "local_blk_tensor_of_local_2[0], t->s1, t->s2, t->s2, (2 * t->s2), ONE_BLK_SIZE / " |
| 924 | - "sizeof(float), ONE_BLK_SIZE / sizeof(float), tmp_buf_0, ONE_BLK_SIZE * 2);\n"}); | 924 | + "sizeof(int16_t), ONE_BLK_SIZE / sizeof(int16_t), tmp_buf_0, ONE_BLK_SIZE * 2);\n"}); |
| 925 | } | 925 | } |
| 926 | 926 | ||
| 927 | TEST(WhereApiCallTest, WhereApiCall_Scaler_x2_throwfor) { | 927 | TEST(WhereApiCallTest, WhereApiCall_Scaler_x2_throwfor) { |
| @@ -1064,7 +1064,7 @@ TEST(WhereApiCallTest, WhereApiCall_Scaler_x2_throwfor) { | |||
| 1064 | std::cout << result << std::endl; | 1064 | std::cout << result << std::endl; |
| 1065 | EXPECT_EQ(result, | 1065 | EXPECT_EQ(result, |
| 1066 | std::string{"Where<true, false>(local_3[0], local_0[0], local_blk_tensor_of_local_1[0], local_2[0], t->s1, " | 1066 | std::string{"Where<true, false>(local_3[0], local_0[0], local_blk_tensor_of_local_1[0], local_2[0], t->s1, " |
| 1067 | - "t->s2, t->s2, t->s2, ONE_BLK_SIZE / sizeof(float), t->s2, tmp_buf_0, ONE_BLK_SIZE);\n"}); | 1067 | + "t->s2, t->s2, t->s2, ONE_BLK_SIZE / sizeof(int16_t), t->s2, tmp_buf_0, ONE_BLK_SIZE);\n"}); |
| 1068 | } | 1068 | } |
| 1069 | 1069 | ||
| 1070 | TEST(WhereApiCallTest, WhereApiCall_Scaler_x3_throwfor) { | 1070 | TEST(WhereApiCallTest, WhereApiCall_Scaler_x3_throwfor) { |
| @@ -1207,7 +1207,7 @@ TEST(WhereApiCallTest, WhereApiCall_Scaler_x3_throwfor) { | |||
| 1207 | std::cout << result << std::endl; | 1207 | std::cout << result << std::endl; |
| 1208 | EXPECT_EQ(result, | 1208 | EXPECT_EQ(result, |
| 1209 | std::string{"Where<false, true>(local_3[0], local_0[0], local_1[0], local_blk_tensor_of_local_2[0], t->s1, " | 1209 | std::string{"Where<false, true>(local_3[0], local_0[0], local_1[0], local_blk_tensor_of_local_2[0], t->s1, " |
| 1210 | - "t->s2, t->s2, t->s2, t->s2, ONE_BLK_SIZE / sizeof(float), tmp_buf_0, ONE_BLK_SIZE);\n"}); | 1210 | + "t->s2, t->s2, t->s2, t->s2, ONE_BLK_SIZE / sizeof(int16_t), tmp_buf_0, ONE_BLK_SIZE);\n"}); |
| 1211 | } | 1211 | } |
| 1212 | 1212 | ||
| 1213 | TEST(WhereApiCallTest, WhereApiCall_throwfor) { | 1213 | TEST(WhereApiCallTest, WhereApiCall_throwfor) { |
| @@ -1151,6 +1151,42 @@ TEST(CodegenKernel, TPipe_TensorSizeCalc_AllocFromQue) { | |||
| 1151 | "const uint32_t local_1_que_buf_num = 4;\n"}); | 1151 | "const uint32_t local_1_que_buf_num = 4;\n"}); |
| 1152 | } | 1152 | } |
| 1153 | 1153 | ||
| 1154 | +TEST(CodegenKernel, TPipe_TensorSizeAssignForCvUbFuseShouldUseCubeOutputElementCount) { | ||
| 1155 | + af::AscGraph graph("test"); | ||
| 1156 | + af::ascir_op::Data x("x", graph); | ||
| 1157 | + af::ascir_op::Data y("y", graph); | ||
| 1158 | + | ||
| 1159 | + auto int8_node = graph.FindNode("x"); | ||
| 1160 | + af::AscTensor int8_tensor = int8_node->outputs[0]; | ||
| 1161 | + int8_tensor.attr.dtype = ge::DT_INT8; | ||
| 1162 | + int8_tensor.attr.mem.tensor_id = 1; | ||
| 1163 | + int8_tensor.attr.mem.alloc_type = af::AllocType::kAllocTypeBuffer; | ||
| 1164 | + int8_tensor.attr.mem.position = af::Position::kPositionVecCalc; | ||
| 1165 | + int8_tensor.attr.opt.merge_scope = af::kIdNone; | ||
| 1166 | + int8_tensor.attr.buf.id = 1; | ||
| 1167 | + | ||
| 1168 | + auto int64_node = graph.FindNode("y"); | ||
| 1169 | + af::AscTensor int64_tensor = int64_node->outputs[0]; | ||
| 1170 | + int64_tensor.attr.dtype = ge::DT_INT64; | ||
| 1171 | + int64_tensor.attr.mem.tensor_id = 2; | ||
| 1172 | + int64_tensor.attr.mem.alloc_type = af::AllocType::kAllocTypeBuffer; | ||
| 1173 | + int64_tensor.attr.mem.position = af::Position::kPositionVecCalc; | ||
| 1174 | + int64_tensor.attr.opt.merge_scope = af::kIdNone; | ||
| 1175 | + int64_tensor.attr.buf.id = 2; | ||
| 1176 | + | ||
| 1177 | + codegen::Tiler tiler; | ||
| 1178 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 1179 | + tpipe.cv_fusion_type = ::ascir::CubeTemplateType::kUBFuse; | ||
| 1180 | + ASSERT_EQ(tpipe.AddTensor(int8_tensor), af::SUCCESS); | ||
| 1181 | + ASSERT_EQ(tpipe.AddTensor(int64_tensor), af::SUCCESS); | ||
| 1182 | + | ||
| 1183 | + std::string result; | ||
| 1184 | + ASSERT_EQ(tpipe.TensorSizeAssign("float", result), af::SUCCESS); | ||
| 1185 | + EXPECT_EQ(result, std::string{"local_1_size = stage_size / sizeof(float);\n" | ||
| 1186 | + "local_2_size = stage_size / sizeof(float);\n" | ||
| 1187 | + "\n"}); | ||
| 1188 | +} | ||
| 1189 | + | ||
| 1154 | TEST(CodegenKernel, TPipe_MergeScopeSizeCalc) { | 1190 | TEST(CodegenKernel, TPipe_MergeScopeSizeCalc) { |
| 1155 | af::SizeVar s0(af::Symbol("s0")); | 1191 | af::SizeVar s0(af::Symbol("s0")); |
| 1156 | af::SizeVar s1(af::Symbol("s1")); | 1192 | af::SizeVar s1(af::Symbol("s1")); |
| @@ -1490,6 +1526,50 @@ TEST(CodegenKernel, TPipe_LocalTQueAlloc) { | |||
| 1490 | "tpipe.InitBuffer(q1, q1_buf_num, t->q1_size);\n"}); | 1526 | "tpipe.InitBuffer(q1, q1_buf_num, t->q1_size);\n"}); |
| 1491 | } | 1527 | } |
| 1492 | 1528 | ||
| 1529 | +TEST(CodegenKernel, TPipe_LocalTQueAllocForCvUbFuseShouldAlignSharedTensorSlices) { | ||
| 1530 | + af::AscGraph graph("test"); | ||
| 1531 | + af::ascir_op::Data x("x", graph); | ||
| 1532 | + af::ascir_op::Data y("y", graph); | ||
| 1533 | + | ||
| 1534 | + auto int8_node = graph.FindNode("x"); | ||
| 1535 | + af::AscTensor int8_tensor = int8_node->outputs[0]; | ||
| 1536 | + int8_tensor.attr.dtype = ge::DT_INT8; | ||
| 1537 | + int8_tensor.attr.mem.tensor_id = 1; | ||
| 1538 | + int8_tensor.attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 1539 | + int8_tensor.attr.mem.position = af::Position::kPositionVecIn; | ||
| 1540 | + int8_tensor.attr.mem.reuse_id = 1; | ||
| 1541 | + int8_tensor.attr.opt.merge_scope = af::kIdNone; | ||
| 1542 | + int8_tensor.attr.que.id = 1; | ||
| 1543 | + int8_tensor.attr.que.buf_num = 1; | ||
| 1544 | + | ||
| 1545 | + auto int64_node = graph.FindNode("y"); | ||
| 1546 | + af::AscTensor int64_tensor = int64_node->outputs[0]; | ||
| 1547 | + int64_tensor.attr.dtype = ge::DT_INT64; | ||
| 1548 | + int64_tensor.attr.mem.tensor_id = 2; | ||
| 1549 | + int64_tensor.attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 1550 | + int64_tensor.attr.mem.position = af::Position::kPositionVecIn; | ||
| 1551 | + int64_tensor.attr.mem.reuse_id = 1; | ||
| 1552 | + int64_tensor.attr.opt.merge_scope = af::kIdNone; | ||
| 1553 | + int64_tensor.attr.que.id = 1; | ||
| 1554 | + int64_tensor.attr.que.buf_num = 1; | ||
| 1555 | + | ||
| 1556 | + codegen::Tiler tiler; | ||
| 1557 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 1558 | + tpipe.cv_fusion_type = ::ascir::CubeTemplateType::kUBFuse; | ||
| 1559 | + tpipe.CollectQues(graph); | ||
| 1560 | + ASSERT_EQ(tpipe.AddTensor(int8_tensor), af::SUCCESS); | ||
| 1561 | + ASSERT_EQ(tpipe.AddTensor(int64_tensor), af::SUCCESS); | ||
| 1562 | + | ||
| 1563 | + std::string result; | ||
| 1564 | + ASSERT_EQ(tpipe.LocalTQueAlloc(result), af::SUCCESS); | ||
| 1565 | + EXPECT_EQ(result, std::string{"const uint32_t q1_size = KernelUtils::Max(local_1_size * sizeof(int8_t), " | ||
| 1566 | + "local_2_size * sizeof(int64_t), " | ||
| 1567 | + "KernelUtils::BlkAlign<uint8_t>(local_1_size * sizeof(int8_t)) + " | ||
| 1568 | + "KernelUtils::BlkAlign<uint8_t>(local_2_size * sizeof(int64_t)));\n" | ||
| 1569 | + "const uint32_t q1_buf_num = KernelUtils::Max(1);\n" | ||
| 1570 | + "tpipe.InitBuffer(q1, q1_buf_num, KernelUtils::BlkAlign<uint8_t>(q1_size));\n"}); | ||
| 1571 | +} | ||
| 1572 | + | ||
| 1493 | TEST(CodegenKernel, ApiCall_Generate) { | 1573 | TEST(CodegenKernel, ApiCall_Generate) { |
| 1494 | af::AscGraph graph("test"); | 1574 | af::AscGraph graph("test"); |
| 1495 | af::ascir_op::Data x("x", graph); | 1575 | af::ascir_op::Data x("x", graph); |
| @@ -1534,6 +1614,7 @@ class CodegenKernel_CallSync : public ::testing::Test { | |||
| 1534 | af::AscGraph graph; | 1614 | af::AscGraph graph; |
| 1535 | af::AscNodePtr x; | 1615 | af::AscNodePtr x; |
| 1536 | int tensor_id = 0; | 1616 | int tensor_id = 0; |
| 1617 | + bool cv_ub_fuse_mode = false; | ||
| 1537 | 1618 | ||
| 1538 | CodegenKernel_CallSync() : graph("test_graph"), x(nullptr) { | 1619 | CodegenKernel_CallSync() : graph("test_graph"), x(nullptr) { |
| 1539 | Data x_op("x", graph); | 1620 | Data x_op("x", graph); |
| @@ -1707,6 +1788,9 @@ class CodegenKernel_CallSync : public ::testing::Test { | |||
| 1707 | std::string Generate() { | 1788 | std::string Generate() { |
| 1708 | codegen::Tiler tiler; | 1789 | codegen::Tiler tiler; |
| 1709 | codegen::TPipe tpipe("tpipe", tiler); | 1790 | codegen::TPipe tpipe("tpipe", tiler); |
| 1791 | + if (cv_ub_fuse_mode) { | ||
| 1792 | + tpipe.cv_fusion_type = ::ascir::CubeTemplateType::kUBFuse; | ||
| 1793 | + } | ||
| 1710 | tpipe.CollectQues(graph); | 1794 | tpipe.CollectQues(graph); |
| 1711 | 1795 | ||
| 1712 | codegen::Loop loop(af::kIdNone); | 1796 | codegen::Loop loop(af::kIdNone); |
| @@ -2285,6 +2369,30 @@ TEST_F(CodegenKernel_CallSync, AllocLoad1_ShareLoad2Enq_DeqVec) { | |||
| 2285 | "q1.FreeTensor(q1_buf);\n\n"}); | 2369 | "q1.FreeTensor(q1_buf);\n\n"}); |
| 2286 | } | 2370 | } |
| 2287 | 2371 | ||
| 2372 | +TEST_F(CodegenKernel_CallSync, CvUbFuseSharedQueueOffsetShouldUseBlockAlignedSliceSize) { | ||
| 2373 | + cv_ub_fuse_mode = true; | ||
| 2374 | + auto load1 = Load("load1", x); | ||
| 2375 | + load1->outputs[0].attr.dtype = ge::DT_INT8; | ||
| 2376 | + auto load2 = LoadForShare("load2", x, load1); | ||
| 2377 | + load2->outputs[0].attr.dtype = ge::DT_INT64; | ||
| 2378 | + auto vec = Vec("vec", {load1, load2}, false); | ||
| 2379 | + | ||
| 2380 | + EXPECT_EQ(Generate(), std::string{"uint32_t q1_reuse1_offset = 0;\n" | ||
| 2381 | + "q1_buf = q1.AllocTensor<uint8_t>();\n" | ||
| 2382 | + "local_1_actual_size = 1;\n" | ||
| 2383 | + "local_1 = q1_buf[q1_reuse1_offset].template ReinterpretCast<int8_t>();\n" | ||
| 2384 | + "load1();\n\n" | ||
| 2385 | + "q1_reuse1_offset = q1_reuse1_offset + " | ||
| 2386 | + "KernelUtils::BlkAlign<uint8_t>(local_1_size * 1);\n" | ||
| 2387 | + "local_2_actual_size = 1;\n" | ||
| 2388 | + "local_2 = q1_buf[q1_reuse1_offset].template ReinterpretCast<int64_t>();\n" | ||
| 2389 | + "load2();\n" | ||
| 2390 | + "q1.EnQue(q1_buf);\n\n" | ||
| 2391 | + "q1_buf = q1.DeQue<uint8_t>();\n" | ||
| 2392 | + "vec();\n" | ||
| 2393 | + "q1.FreeTensor(q1_buf);\n\n"}); | ||
| 2394 | +} | ||
| 2395 | + | ||
| 2288 | /* | 2396 | /* |
| 2289 | * load1 load2 | 2397 | * load1 load2 |
| 2290 | * \ / | 2398 | * \ / |
| @@ -2452,6 +2560,12 @@ TEST(CodegenKernel, StageGenerate_WillNotDuplicatAllocTensorInSameStage) { | |||
| 2452 | GTEST_SKIP(); | 2560 | GTEST_SKIP(); |
| 2453 | } | 2561 | } |
| 2454 | 2562 | ||
| 2563 | +namespace { | ||
| 2564 | +void BuildCompareApiCallCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, | ||
| 2565 | + const af::Axis &z0, const af::Axis &z1); | ||
| 2566 | +void InitCompareApiCallCvStageAttrs(af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1); | ||
| 2567 | +} // namespace | ||
| 2568 | + | ||
| 2455 | // 测试compare api不外抛for循环的场景 | 2569 | // 测试compare api不外抛for循环的场景 |
| 2456 | TEST(CodegenKernel, CompareApiCallNotThrowingFor) { | 2570 | TEST(CodegenKernel, CompareApiCallNotThrowingFor) { |
| 2457 | af::AscGraph graph("test_graph"); | 2571 | af::AscGraph graph("test_graph"); |
| @@ -2460,81 +2574,12 @@ TEST(CodegenKernel, CompareApiCallNotThrowingFor) { | |||
| 2460 | auto s1 = graph.CreateSizeVar("s1"); | 2574 | auto s1 = graph.CreateSizeVar("s1"); |
| 2461 | auto z0 = graph.CreateAxis("z0", s0); | 2575 | auto z0 = graph.CreateAxis("z0", s0); |
| 2462 | auto z1 = graph.CreateAxis("z1", s1); | 2576 | auto z1 = graph.CreateAxis("z1", s1); |
| 2463 | - | 2577 | + BuildCompareApiCallCvStageGraph(graph, s0, s1, z0, z1); |
| 2464 | - Data x_op("x", graph); | 2578 | + InitCompareApiCallCvStageAttrs(graph, z0, z1); |
| 2465 | - Data x_op2("x2", graph); | ||
| 2466 | - Load load_op("load"); | ||
| 2467 | - Load load_op2("load2"); | ||
| 2468 | - af::ascir_op::Gt gt_op("gt"); | ||
| 2469 | - graph.AddNode(load_op); | ||
| 2470 | - graph.AddNode(load_op2); | ||
| 2471 | - graph.AddNode(gt_op); | ||
| 2472 | - | ||
| 2473 | - load_op.x = x_op.y; | ||
| 2474 | - load_op.attr.sched.axis = {z0.id, z1.id}; | ||
| 2475 | - *load_op.y.axis = {z0.id, z1.id}; | ||
| 2476 | - *load_op.y.repeats = {s0, s1}; | ||
| 2477 | - *load_op.y.strides = {s1, One}; | ||
| 2478 | - | ||
| 2479 | - load_op2.x = x_op2.y; | ||
| 2480 | - load_op2.attr.sched.axis = {z0.id, z1.id}; | ||
| 2481 | - *load_op2.y.axis = {z0.id, z1.id}; | ||
| 2482 | - *load_op2.y.repeats = {s0, s1}; | ||
| 2483 | - *load_op2.y.strides = {s1, One}; | ||
| 2484 | - | ||
| 2485 | - gt_op.x1 = load_op.y; | ||
| 2486 | - gt_op.x2 = load_op2.y; | ||
| 2487 | - *gt_op.y.axis = {z0.id, z1.id}; | ||
| 2488 | - *gt_op.y.repeats = {s0, s1}; | ||
| 2489 | - *gt_op.y.strides = {s1, One}; | ||
| 2490 | 2579 | ||
| 2491 | auto load = graph.FindNode("load"); | 2580 | auto load = graph.FindNode("load"); |
| 2492 | - load->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 2493 | - load->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 2494 | - load->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 2495 | - load->attr.sched.loop_axis = z0.id; | ||
| 2496 | - | ||
| 2497 | auto load2 = graph.FindNode("load2"); | 2581 | auto load2 = graph.FindNode("load2"); |
| 2498 | - load2->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 2499 | - load2->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 2500 | - load2->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 2501 | - load2->attr.sched.loop_axis = z0.id; | ||
| 2502 | - | ||
| 2503 | - auto size = ge::GetSizeByDataType(ge::DT_FLOAT16); | ||
| 2504 | - load->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 2505 | - load->outputs[0].attr.vectorized_strides = {One}; | ||
| 2506 | - load->outputs[0].attr.dtype = ge::DT_FLOAT; | ||
| 2507 | - load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 2508 | - load->outputs[0].attr.mem.tensor_id = 0; | ||
| 2509 | - load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 2510 | - load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 2511 | - load->outputs[0].attr.que.id = 1; | ||
| 2512 | - load->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 2513 | - | ||
| 2514 | - load2->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 2515 | - load2->outputs[0].attr.vectorized_strides = {One}; | ||
| 2516 | - load2->outputs[0].attr.dtype = ge::DT_FLOAT; | ||
| 2517 | - load2->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 2518 | - load2->outputs[0].attr.mem.tensor_id = 1; | ||
| 2519 | - load2->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 2520 | - load2->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 2521 | - load2->outputs[0].attr.que.id = 1; | ||
| 2522 | - load2->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 2523 | - | ||
| 2524 | auto gt = graph.FindNode("gt"); | 2582 | auto gt = graph.FindNode("gt"); |
| 2525 | - gt->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 2526 | - gt->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 2527 | - gt->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 2528 | - gt->attr.sched.loop_axis = z0.id; | ||
| 2529 | - gt->attr.tmp_buffers = {{{af::Symbol(8192), -1}, af::MemAttr(), 0}}; | ||
| 2530 | - gt->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 2531 | - gt->outputs[0].attr.vectorized_strides = {One}; | ||
| 2532 | - gt->outputs[0].attr.dtype = ge::DT_INT16; | ||
| 2533 | - gt->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 2534 | - gt->outputs[0].attr.mem.tensor_id = 3; | ||
| 2535 | - gt->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 2536 | - gt->outputs[0].attr.que.id = 2; | ||
| 2537 | - gt->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 2538 | 2583 | ||
| 2539 | codegen::Tiler tiler; | 2584 | codegen::Tiler tiler; |
| 2540 | codegen::TPipe tpipe("tpipe", tiler); | 2585 | codegen::TPipe tpipe("tpipe", tiler); |
| @@ -2567,6 +2612,129 @@ TEST(CodegenKernel, CompareApiCallNotThrowingFor) { | |||
| 2567 | std::string{"CompareExtend(local_3[0], local_0[0], local_1[0], CMPMODE::GT, local_0_actual_size, tmp_buf_0);\n"}); | 2612 | std::string{"CompareExtend(local_3[0], local_0[0], local_1[0], CMPMODE::GT, local_0_actual_size, tmp_buf_0);\n"}); |
| 2568 | } | 2613 | } |
| 2569 | 2614 | ||
| 2615 | +namespace { | ||
| 2616 | +void BuildCompareApiCallCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, | ||
| 2617 | + const af::Axis &z0, const af::Axis &z1) { | ||
| 2618 | + Data x_op("x", graph); | ||
| 2619 | + Data x_op2("x2", graph); | ||
| 2620 | + Load load_op("load"); | ||
| 2621 | + Load load_op2("load2"); | ||
| 2622 | + af::ascir_op::Gt gt_op("gt"); | ||
| 2623 | + graph.AddNode(load_op); | ||
| 2624 | + graph.AddNode(load_op2); | ||
| 2625 | + graph.AddNode(gt_op); | ||
| 2626 | + | ||
| 2627 | + load_op.x = x_op.y; | ||
| 2628 | + load_op.attr.sched.axis = {z0.id, z1.id}; | ||
| 2629 | + *load_op.y.axis = {z0.id, z1.id}; | ||
| 2630 | + *load_op.y.repeats = {s0, s1}; | ||
| 2631 | + *load_op.y.strides = {s1, One}; | ||
| 2632 | + | ||
| 2633 | + load_op2.x = x_op2.y; | ||
| 2634 | + load_op2.attr.sched.axis = {z0.id, z1.id}; | ||
| 2635 | + *load_op2.y.axis = {z0.id, z1.id}; | ||
| 2636 | + *load_op2.y.repeats = {s0, s1}; | ||
| 2637 | + *load_op2.y.strides = {s1, One}; | ||
| 2638 | + | ||
| 2639 | + gt_op.x1 = load_op.y; | ||
| 2640 | + gt_op.x2 = load_op2.y; | ||
| 2641 | + *gt_op.y.axis = {z0.id, z1.id}; | ||
| 2642 | + *gt_op.y.repeats = {s0, s1}; | ||
| 2643 | + *gt_op.y.strides = {s1, One}; | ||
| 2644 | +} | ||
| 2645 | + | ||
| 2646 | +void InitCompareApiCallCvStageAttrs(af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1) { | ||
| 2647 | + auto load = graph.FindNode("load"); | ||
| 2648 | + load->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 2649 | + load->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 2650 | + load->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 2651 | + load->attr.sched.loop_axis = z0.id; | ||
| 2652 | + | ||
| 2653 | + auto load2 = graph.FindNode("load2"); | ||
| 2654 | + load2->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 2655 | + load2->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 2656 | + load2->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 2657 | + load2->attr.sched.loop_axis = z0.id; | ||
| 2658 | + | ||
| 2659 | + load->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 2660 | + load->outputs[0].attr.vectorized_strides = {One}; | ||
| 2661 | + load->outputs[0].attr.dtype = ge::DT_FLOAT; | ||
| 2662 | + load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 2663 | + load->outputs[0].attr.mem.tensor_id = 0; | ||
| 2664 | + load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 2665 | + load->outputs[0].attr.que.id = 1; | ||
| 2666 | + load->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 2667 | + | ||
| 2668 | + load2->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 2669 | + load2->outputs[0].attr.vectorized_strides = {One}; | ||
| 2670 | + load2->outputs[0].attr.dtype = ge::DT_FLOAT; | ||
| 2671 | + load2->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 2672 | + load2->outputs[0].attr.mem.tensor_id = 1; | ||
| 2673 | + load2->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 2674 | + load2->outputs[0].attr.que.id = 1; | ||
| 2675 | + load2->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 2676 | + | ||
| 2677 | + auto gt = graph.FindNode("gt"); | ||
| 2678 | + gt->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 2679 | + gt->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 2680 | + gt->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 2681 | + gt->attr.sched.loop_axis = z0.id; | ||
| 2682 | + gt->attr.tmp_buffers = {{{af::Symbol(8192), -1}, af::MemAttr(), 0}}; | ||
| 2683 | + gt->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 2684 | + gt->outputs[0].attr.vectorized_strides = {One}; | ||
| 2685 | + gt->outputs[0].attr.dtype = ge::DT_INT16; | ||
| 2686 | + gt->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 2687 | + gt->outputs[0].attr.mem.tensor_id = 3; | ||
| 2688 | + gt->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 2689 | + gt->outputs[0].attr.que.id = 2; | ||
| 2690 | + gt->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 2691 | +} | ||
| 2692 | +} // namespace | ||
| 2693 | + | ||
| 2694 | +TEST(CodegenKernel, CompareApiCallCvStageAlignsActualSize) { | ||
| 2695 | + af::AscGraph graph("test_graph"); | ||
| 2696 | + | ||
| 2697 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 2698 | + auto s1 = graph.CreateSizeVar("s1"); | ||
| 2699 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 2700 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 2701 | + BuildCompareApiCallCvStageGraph(graph, s0, s1, z0, z1); | ||
| 2702 | + InitCompareApiCallCvStageAttrs(graph, z0, z1); | ||
| 2703 | + | ||
| 2704 | + auto load = graph.FindNode("load"); | ||
| 2705 | + auto load2 = graph.FindNode("load2"); | ||
| 2706 | + auto gt = graph.FindNode("gt"); | ||
| 2707 | + | ||
| 2708 | + codegen::Tiler tiler; | ||
| 2709 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 2710 | + tpipe.CollectQues(graph); | ||
| 2711 | + tpipe.AddTensor(load->outputs[0]); | ||
| 2712 | + tpipe.AddTensor(load2->outputs[0]); | ||
| 2713 | + tpipe.AddTensor(gt->outputs[0]); | ||
| 2714 | + | ||
| 2715 | + tiler.AddAxis(z0); | ||
| 2716 | + tiler.AddAxis(z1); | ||
| 2717 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 2718 | + tiler.AddSizeVar(af::SizeVar(s1)); | ||
| 2719 | + std::vector<af::AxisId> current_axis; | ||
| 2720 | + current_axis.push_back(z0.id); | ||
| 2721 | + | ||
| 2722 | + codegen::ApiTensor x1; | ||
| 2723 | + codegen::ApiTensor x2; | ||
| 2724 | + x1.id = load->outputs[0].attr.mem.tensor_id; | ||
| 2725 | + x2.id = load2->outputs[0].attr.mem.tensor_id; | ||
| 2726 | + codegen::CompareApiCall call("GT"); | ||
| 2727 | + EXPECT_EQ(call.Init(gt), 0); | ||
| 2728 | + call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1; | ||
| 2729 | + call.inputs.push_back(&x1); | ||
| 2730 | + call.inputs.push_back(&x2); | ||
| 2731 | + | ||
| 2732 | + std::string result; | ||
| 2733 | + call.Generate(tpipe, current_axis, result); | ||
| 2734 | + EXPECT_EQ(result, std::string{"CompareExtend(local_3[0], local_0[0], local_1[0], CMPMODE::GT, ((local_0_actual_size " | ||
| 2735 | + "+ 8 - 1) / 8 * 8), tmp_buf_0);\n"}); | ||
| 2736 | +} | ||
| 2737 | + | ||
| 2570 | // 测试compare api需要外抛for循环的场景 | 2738 | // 测试compare api需要外抛for循环的场景 |
| 2571 | TEST(CodegenKernel, CompareApiCallThrowingFor) { | 2739 | TEST(CodegenKernel, CompareApiCallThrowingFor) { |
| 2572 | af::AscGraph graph("test_graph"); | 2740 | af::AscGraph graph("test_graph"); |
| @@ -6023,6 +6191,47 @@ TEST(CodegenKernel, ReduceDoubleTileUsesReduceSpecificCacheCondition) { | |||
| 6023 | delete cached_call; | 6191 | delete cached_call; |
| 6024 | } | 6192 | } |
| 6025 | 6193 | ||
| 6194 | +TEST(CodegenKernel, BroadcastInlineInCvStage_NoBlockDimCacheCondition) { | ||
| 6195 | + af::SizeVar s0(af::Symbol("s0")); | ||
| 6196 | + af::SizeVar s1(af::Symbol("s1")); | ||
| 6197 | + | ||
| 6198 | + af::Axis z0{.id = 0, .name = "z0", .size = s0.expr}; | ||
| 6199 | + af::Axis z1{.id = 1, .name = "z1", .size = s1.expr}; | ||
| 6200 | + | ||
| 6201 | + codegen::Tiler tiler; | ||
| 6202 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 6203 | + tiler.AddSizeVar(af::SizeVar(s1)); | ||
| 6204 | + tiler.AddAxis(z0); | ||
| 6205 | + tiler.AddAxis(z1); | ||
| 6206 | + | ||
| 6207 | + for (auto &[id, cur_axis] : tiler.axis_map) { | ||
| 6208 | + (void)id; | ||
| 6209 | + cur_axis.is_split_b = true; | ||
| 6210 | + } | ||
| 6211 | + | ||
| 6212 | + codegen::Loop loop1(z0.id); | ||
| 6213 | + codegen::Loop loop2(z1.id); | ||
| 6214 | + loop1.AddLoop(&loop2); | ||
| 6215 | + | ||
| 6216 | + auto call1 = new MockApiCall("call1"); | ||
| 6217 | + auto call2 = new MockApiCall("call2"); | ||
| 6218 | + call1->enable_cache = true; | ||
| 6219 | + call1->exec_condition = af::ExecuteCondition::kCacheBlockSplitFusedBroadcastAxis; | ||
| 6220 | + call1->unit = af::ComputeUnit::kUnitVector; | ||
| 6221 | + call1->api_call_context.stage = codegen::ComputeStage::kCVFuseStage1; | ||
| 6222 | + call2->enable_cache = true; | ||
| 6223 | + call2->exec_condition = af::ExecuteCondition::kCacheBlockSplitOriginBroadcastAxis; | ||
| 6224 | + call2->unit = af::ComputeUnit::kUnitVector; | ||
| 6225 | + call2->api_call_context.stage = codegen::ComputeStage::kCVFuseStage1; | ||
| 6226 | + | ||
| 6227 | + loop2.AddCall(call1); | ||
| 6228 | + loop2.AddCall(call2); | ||
| 6229 | + codegen::TPipe tpipe("t", tiler); | ||
| 6230 | + std::string result; | ||
| 6231 | + EXPECT_EQ(loop1.Generate(tiler, tpipe, result, codegen::ComputeStage::kCVFuseStage1), af::SUCCESS); | ||
| 6232 | + EXPECT_EQ(result.find("block_dim"), std::string::npos); | ||
| 6233 | +} | ||
| 6234 | + | ||
| 6026 | TEST(CodegenKernel, CalculateVectorizedAixsMergeStatus) { | 6235 | TEST(CodegenKernel, CalculateVectorizedAixsMergeStatus) { |
| 6027 | af::SizeVar s0(af::Symbol("s0")); | 6236 | af::SizeVar s0(af::Symbol("s0")); |
| 6028 | af::SizeVar s1(af::Symbol("s1")); | 6237 | af::SizeVar s1(af::Symbol("s1")); |
| @@ -1174,6 +1174,20 @@ TEST_F(TestCodegenTiling, NoWorkspaceTest) { | |||
| 1174 | "}\n"}); | 1174 | "}\n"}); |
| 1175 | } | 1175 | } |
| 1176 | 1176 | ||
| 1177 | +TEST_F(TestCodegenTiling, PrepareMatMulAttrsShouldUseDefaultOpImplModeForMatMulV3) { | ||
| 1178 | + codegen::MatMulCubeInfo cube_info; | ||
| 1179 | + cube_info.is_batch = false; | ||
| 1180 | + cube_info.enable_hf32 = 0; | ||
| 1181 | + | ||
| 1182 | + std::vector<codegen::AttrInfo> attrs; | ||
| 1183 | + PrepareMatMulAttrs(cube_info, attrs); | ||
| 1184 | + | ||
| 1185 | + ASSERT_GT(attrs.size(), 3U); | ||
| 1186 | + EXPECT_EQ(attrs[3].name, "opImplMode"); | ||
| 1187 | + EXPECT_EQ(attrs[3].dtype, "int"); | ||
| 1188 | + EXPECT_EQ(attrs[3].value_int, 0); | ||
| 1189 | +} | ||
| 1190 | + | ||
| 1177 | TEST_F(TestCodegenTiling, SingleGroupWorkspaceSymbolTest) { | 1191 | TEST_F(TestCodegenTiling, SingleGroupWorkspaceSymbolTest) { |
| 1178 | ascir::ImplGraph graph0("test_graph0"); | 1192 | ascir::ImplGraph graph0("test_graph0"); |
| 1179 | auto s0 = graph0.CreateSizeVar("s0"); | 1193 | auto s0 = graph0.CreateSizeVar("s0"); |
| @@ -3160,11 +3174,10 @@ TEST_F(TestCodegenTiling, GenerateForInductorCvFusionShouldEmitCvTilingAndCubeWr | |||
| 3160 | auto tiling_files = this->GenerateForInductor(fused_schedule_result); | 3174 | auto tiling_files = this->GenerateForInductor(fused_schedule_result); |
| 3161 | ASSERT_TRUE(tiling_files.find(codegen::kTilingDefAndConstIdentify) != tiling_files.end()); | 3175 | ASSERT_TRUE(tiling_files.find(codegen::kTilingDefAndConstIdentify) != tiling_files.end()); |
| 3162 | ASSERT_TRUE(tiling_files.find(codegen::kTilingApiHeaderIdentify) != tiling_files.end()); | 3176 | ASSERT_TRUE(tiling_files.find(codegen::kTilingApiHeaderIdentify) != tiling_files.end()); |
| 3177 | + ASSERT_TRUE(tiling_files.find(codegen::kTilingHeadIdentify) != tiling_files.end()); | ||
| 3163 | ASSERT_TRUE(tiling_files.find(codegen::kCubeKernelTilingWrapperHpp) != tiling_files.end()); | 3178 | ASSERT_TRUE(tiling_files.find(codegen::kCubeKernelTilingWrapperHpp) != tiling_files.end()); |
| 3164 | ASSERT_TRUE(tiling_files.find(codegen::kCubeKernelTilingWrapperCpp) != tiling_files.end()); | 3179 | ASSERT_TRUE(tiling_files.find(codegen::kCubeKernelTilingWrapperCpp) != tiling_files.end()); |
| 3165 | EXPECT_TRUE(tiling_files.find("TilingDataLog") == tiling_files.end()); | 3180 | EXPECT_TRUE(tiling_files.find("TilingDataLog") == tiling_files.end()); |
| 3166 | - EXPECT_NE(tiling_files.at(codegen::kCubeKernelTilingWrapperCpp).find("#include \"autofuse_tiling_func_log.h\""), | ||
| 3167 | - std::string::npos); | ||
| 3168 | 3181 | ||
| 3169 | const auto &tiling_impl = tiling_files.at(codegen::kTilingDefAndConstIdentify); | 3182 | const auto &tiling_impl = tiling_files.at(codegen::kTilingDefAndConstIdentify); |
| 3170 | const auto &api_header = tiling_files.at(codegen::kTilingApiHeaderIdentify); | 3183 | const auto &api_header = tiling_files.at(codegen::kTilingApiHeaderIdentify); |
| @@ -3189,6 +3202,8 @@ void set_g_basen_basem_align(int32_t value) { | |||
| 3189 | EXPECT_NE(tiling_impl.find("CallCubeTiling"), std::string::npos); | 3202 | EXPECT_NE(tiling_impl.find("CallCubeTiling"), std::string::npos); |
| 3190 | EXPECT_NE(tiling_impl.find("AutofuseTiling("), std::string::npos); | 3203 | EXPECT_NE(tiling_impl.find("AutofuseTiling("), std::string::npos); |
| 3191 | EXPECT_NE(tiling_impl.find("GenConstTilingData"), std::string::npos); | 3204 | EXPECT_NE(tiling_impl.find("GenConstTilingData"), std::string::npos); |
| 3205 | + EXPECT_NE(tiling_impl.find("autofuse_has_bias"), std::string::npos); | ||
| 3206 | + EXPECT_NE(tiling_impl.find("autofuse_has_offset_w"), std::string::npos); | ||
| 3192 | EXPECT_EQ(tiling_impl.find("GenerateTopnSolutions"), std::string::npos); | 3207 | EXPECT_EQ(tiling_impl.find("GenerateTopnSolutions"), std::string::npos); |
| 3193 | EXPECT_EQ(tiling_impl.find("GetModeledPerfForTesting"), std::string::npos); | 3208 | EXPECT_EQ(tiling_impl.find("GetModeledPerfForTesting"), std::string::npos); |
| 3194 | EXPECT_EQ(tiling_impl.find("AscirCompileAndLaunch"), std::string::npos); | 3209 | EXPECT_EQ(tiling_impl.find("AscirCompileAndLaunch"), std::string::npos); |
| @@ -3197,7 +3212,8 @@ void set_g_basen_basem_align(int32_t value) { | |||
| 3197 | EXPECT_EQ(tiling_impl.find("#include \"autofuse_cube_tiling_data.h\""), std::string::npos); | 3212 | EXPECT_EQ(tiling_impl.find("#include \"autofuse_cube_tiling_data.h\""), std::string::npos); |
| 3198 | EXPECT_NE(tiling_impl.find("#include \"cube_kernel_tiling_wrapper.h\""), std::string::npos); | 3213 | EXPECT_NE(tiling_impl.find("#include \"cube_kernel_tiling_wrapper.h\""), std::string::npos); |
| 3199 | ExpectSystemHeaders( | 3214 | ExpectSystemHeaders( |
| 3200 | - tiling_impl, {"algorithm", "cfloat", "cstddef", "cstdint", "cstring", "ostream", "sstream", "string", "vector"}, | 3215 | + tiling_impl, |
| 3216 | + {"algorithm", "cfloat", "cstddef", "cstdint", "cstring", "iomanip", "ostream", "sstream", "string", "vector"}, | ||
| 3201 | {"array", "cmath", "cstdlib", "functional", "map", "memory", "unordered_map", "utility"}); | 3217 | {"array", "cmath", "cstdlib", "functional", "map", "memory", "unordered_map", "utility"}); |
| 3202 | } | 3218 | } |
| 3203 | 3219 | ||
| @@ -3207,15 +3223,31 @@ TEST_F(TestCodegenTiling, CubeWrapperShouldPreserveTilingDataBytes) { | |||
| 3207 | const auto matmul_tiling_header_pos = wrapper_hpp.find("#include \"arch35/mat_mul_tiling_data.h\""); | 3223 | const auto matmul_tiling_header_pos = wrapper_hpp.find("#include \"arch35/mat_mul_tiling_data.h\""); |
| 3208 | const auto autofuse_namespace_pos = wrapper_hpp.find("namespace autofuse {"); | 3224 | const auto autofuse_namespace_pos = wrapper_hpp.find("namespace autofuse {"); |
| 3209 | EXPECT_NE(wrapper_hpp.find("std::vector<uint8_t> tiling_data;"), std::string::npos); | 3225 | EXPECT_NE(wrapper_hpp.find("std::vector<uint8_t> tiling_data;"), std::string::npos); |
| 3210 | - EXPECT_NE(wrapper_hpp.find("#include <cmath>"), std::string::npos); | ||
| 3211 | - EXPECT_NE(wrapper_hpp.find("#include <limits>"), std::string::npos); | ||
| 3212 | ASSERT_NE(matmul_tiling_header_pos, std::string::npos); | 3226 | ASSERT_NE(matmul_tiling_header_pos, std::string::npos); |
| 3213 | ASSERT_NE(autofuse_namespace_pos, std::string::npos); | 3227 | ASSERT_NE(autofuse_namespace_pos, std::string::npos); |
| 3214 | EXPECT_LT(matmul_tiling_header_pos, autofuse_namespace_pos); | 3228 | EXPECT_LT(matmul_tiling_header_pos, autofuse_namespace_pos); |
| 3215 | - EXPECT_NE(wrapper_cpp.find("result.tiling_data.push_back"), std::string::npos); | 3229 | + EXPECT_NE(wrapper_cpp.find("result.tiling_data.assign"), std::string::npos); |
| 3216 | - EXPECT_NE(wrapper_cpp.find("result.tiling_data = AlignTilingDataTo8Bytes"), std::string::npos); | 3230 | + EXPECT_NE(wrapper_cpp.find("raw_tiling_data->GetDataSize()"), std::string::npos); |
| 3217 | - EXPECT_NE(wrapper_cpp.find("#include \"autofuse_tiling_func_log.h\""), std::string::npos); | 3231 | +} |
| 3218 | - EXPECT_EQ(wrapper_cpp.find("autofuse_tiling_data_log.h"), std::string::npos); | 3232 | + |
| 3233 | +TEST_F(TestCodegenTiling, CubeWrapperShouldSupportBiasAndOffsetInputs) { | ||
| 3234 | + const auto &wrapper_cpp = kCubeKernelTilingWrapperCppValue; | ||
| 3235 | + EXPECT_NE(wrapper_cpp.find("MakeMatMulInputInstanceNum(request.matmul_attrs.has_bias"), std::string::npos); | ||
| 3236 | + EXPECT_NE(wrapper_cpp.find("key.input2_shape = GetRuntimeShape(request.inputs[2]);"), std::string::npos); | ||
| 3237 | + EXPECT_NE(wrapper_cpp.find("key.input3_shape = GetRuntimeShape(request.inputs[3]);"), std::string::npos); | ||
| 3238 | + EXPECT_NE(wrapper_cpp.find("key.input_num = request.inputs.size();"), std::string::npos); | ||
| 3239 | + EXPECT_NE(wrapper_cpp.find("inputs->size() >= 2 && inputs->size() <= 4"), std::string::npos); | ||
| 3240 | + EXPECT_NE(wrapper_cpp.find("has_bias = AttrAsBool(attr);"), std::string::npos); | ||
| 3241 | + EXPECT_NE(wrapper_cpp.find("has_offset_w = AttrAsBool(attr);"), std::string::npos); | ||
| 3242 | + EXPECT_NE(wrapper_cpp.find("if (attrs.has_offset_w && input_index < inputs.size())"), std::string::npos); | ||
| 3243 | + EXPECT_NE(wrapper_cpp.find("BuildMatMulInputSlots(request.inputs, request.matmul_attrs)"), std::string::npos); | ||
| 3244 | + EXPECT_NE(wrapper_cpp.find("if (input == nullptr)"), std::string::npos); | ||
| 3245 | + EXPECT_NE(wrapper_cpp.find("input2_dtype = inputs[2U].dtype;"), std::string::npos); | ||
| 3246 | + EXPECT_NE(wrapper_cpp.find("input3_format = inputs[3U].format;"), std::string::npos); | ||
| 3247 | + EXPECT_NE(wrapper_cpp.find("input_tensors_storage.reserve(input_slots.size());"), std::string::npos); | ||
| 3248 | + EXPECT_NE(wrapper_cpp.find("for (const auto *input : input_slots)"), std::string::npos); | ||
| 3249 | + EXPECT_NE(wrapper_cpp.find("DtypeToGeDataType(input.dtype) == ge::DT_UNDEFINED"), std::string::npos); | ||
| 3250 | + EXPECT_NE(wrapper_cpp.find("ge::Format input_format = FormatToGeFormat(input->format);"), std::string::npos); | ||
| 3219 | } | 3251 | } |
| 3220 | 3252 | ||
| 3221 | TEST_F(TestCodegenTiling, MultiGroupInductorShouldContainTopnMainOutputAbi) { | 3253 | TEST_F(TestCodegenTiling, MultiGroupInductorShouldContainTopnMainOutputAbi) { |
| @@ -12,7 +12,10 @@ | |||
| 12 | import hashlib | 12 | import hashlib |
| 13 | import json | 13 | import json |
| 14 | import os | 14 | import os |
| 15 | +import time | ||
| 15 | import types | 16 | import types |
| 17 | +from dataclasses import dataclass | ||
| 18 | +from concurrent.futures import ThreadPoolExecutor | ||
| 16 | 19 | ||
| 17 | import pytest | 20 | import pytest |
| 18 | 21 | ||
| @@ -82,6 +85,43 @@ def _make_pgo_bundle(module, artifacts, output_file, generation, ld_preload=""): | |||
| 82 | return module.PgoBundle(*artifacts, output_file, generation, ld_preload=ld_preload) | 85 | return module.PgoBundle(*artifacts, output_file, generation, ld_preload=ld_preload) |
| 83 | 86 | ||
| 84 | 87 | ||
| 88 | + | ||
| 89 | +class CopySoToOutputCase: | ||
| 90 | + src_file: object | ||
| 91 | + dst_file: object | ||
| 92 | + output_dir: object | ||
| 93 | + wrapper_file: object | ||
| 94 | + src_directory: str | ||
| 95 | + args: object | ||
| 96 | + | ||
| 97 | + | ||
| 98 | +def _make_copy_so_to_output_case(tmpdir, wrapper_in_output_dir=False): | ||
| 99 | + src_file = tmpdir.join("source.so") | ||
| 100 | + src_file.write("kernel") | ||
| 101 | + output_dir = tmpdir.mkdir("kernel_meta") | ||
| 102 | + if wrapper_in_output_dir: | ||
| 103 | + wrapper_dir = output_dir.mkdir("cv_tiling_wrapper_cache") | ||
| 104 | + else: | ||
| 105 | + wrapper_dir = tmpdir.mkdir("cache") | ||
| 106 | + wrapper_file = wrapper_dir.join("libautofuse_cv_tiling_wrapper_abc.so") | ||
| 107 | + wrapper_file.write("wrapper") | ||
| 108 | + dst_file = output_dir.join("target.so") | ||
| 109 | + src_directory = os.getcwd() | ||
| 110 | + args = type( | ||
| 111 | + "Args", | ||
| 112 | + (), | ||
| 113 | + { | ||
| 114 | + "output_file": str(dst_file), | ||
| 115 | + "shared_cv_wrapper_so": str(wrapper_file), | ||
| 116 | + "stage": "host", | ||
| 117 | + "graph_name": "graph", | ||
| 118 | + }, | ||
| 119 | + )() | ||
| 120 | + return CopySoToOutputCase( | ||
| 121 | + src_file, dst_file, output_dir, wrapper_file, src_directory, args | ||
| 122 | + ) | ||
| 123 | + | ||
| 124 | + | ||
| 85 | def test_link_shared_adds_requested_libraries(ascendc_compile_module): | 125 | def test_link_shared_adds_requested_libraries(ascendc_compile_module): |
| 86 | captured = {} | 126 | captured = {} |
| 87 | 127 | ||
| @@ -119,6 +159,23 @@ def test_link_shared_skips_libraries_by_default(ascendc_compile_module): | |||
| 119 | assert "-lgraph_base" not in captured["cmd"] | 159 | assert "-lgraph_base" not in captured["cmd"] |
| 120 | 160 | ||
| 121 | 161 | ||
| 162 | +def test_link_shared_appends_extra_link_options(ascendc_compile_module): | ||
| 163 | + captured = {} | ||
| 164 | + | ||
| 165 | + def fake_run_compile_command(cmd, stage_name): | ||
| 166 | + captured["cmd"] = cmd | ||
| 167 | + | ||
| 168 | + ascendc_compile_module.module.run_compile_command = fake_run_compile_command | ||
| 169 | + | ||
| 170 | + ascendc_compile_module.link_shared( | ||
| 171 | + "kernel.so", | ||
| 172 | + ["host.o"], | ||
| 173 | + extra_link_options=["-Wl,-rpath,$ORIGIN/cv_tiling_wrapper_cache"], | ||
| 174 | + ) | ||
| 175 | + | ||
| 176 | + assert "-Wl,-rpath,$ORIGIN/cv_tiling_wrapper_cache" in captured["cmd"] | ||
| 177 | + | ||
| 178 | + | ||
| 122 | def test_link_pgo_executable_uses_host_runtime_and_mspti_libraries( | 179 | def test_link_pgo_executable_uses_host_runtime_and_mspti_libraries( |
| 123 | ascendc_compile_module, | 180 | ascendc_compile_module, |
| 124 | ): | 181 | ): |
| @@ -709,6 +766,33 @@ def test_copy_so_to_output_records_stage(ascendc_compile_module, tmpdir): | |||
| 709 | assert dst_file.read() == "binary" | 766 | assert dst_file.read() == "binary" |
| 710 | 767 | ||
| 711 | 768 | ||
| 769 | +def test_copy_so_to_output_copies_shared_cv_wrapper_next_to_output( | ||
| 770 | + ascendc_compile_module, tmpdir | ||
| 771 | +): | ||
| 772 | + case = _make_copy_so_to_output_case(tmpdir) | ||
| 773 | + ascendc_compile_module.copy_so_to_output( | ||
| 774 | + str(case.src_file), case.args, case.src_directory | ||
| 775 | + ) | ||
| 776 | + | ||
| 777 | + copied_wrapper = case.output_dir.join( | ||
| 778 | + "cv_tiling_wrapper_cache", "libautofuse_cv_tiling_wrapper_abc.so" | ||
| 779 | + ) | ||
| 780 | + assert case.dst_file.read() == "kernel" | ||
| 781 | + assert copied_wrapper.read() == "wrapper" | ||
| 782 | + | ||
| 783 | + | ||
| 784 | +def test_copy_so_to_output_keeps_existing_shared_cv_wrapper_in_output_dir( | ||
| 785 | + ascendc_compile_module, tmpdir | ||
| 786 | +): | ||
| 787 | + case = _make_copy_so_to_output_case(tmpdir, wrapper_in_output_dir=True) | ||
| 788 | + ascendc_compile_module.copy_so_to_output( | ||
| 789 | + str(case.src_file), case.args, case.src_directory | ||
| 790 | + ) | ||
| 791 | + | ||
| 792 | + assert case.dst_file.read() == "kernel" | ||
| 793 | + assert case.wrapper_file.read() == "wrapper" | ||
| 794 | + | ||
| 795 | + | ||
| 712 | def test_static_shape_kernel_proc_removes_tiling_data_from_launch( | 796 | def test_static_shape_kernel_proc_removes_tiling_data_from_launch( |
| 713 | ascendc_compile_module, tmpdir | 797 | ascendc_compile_module, tmpdir |
| 714 | ): | 798 | ): |
| @@ -1182,6 +1266,67 @@ def test_compile_host_obj_removes_rejected_cached_pch(ascendc_compile_module, tm | |||
| 1182 | assert not os.path.exists(pch_path) | 1266 | assert not os.path.exists(pch_path) |
| 1183 | 1267 | ||
| 1184 | 1268 | ||
| 1269 | +def test_build_host_compile_cmd_includes_pkg_inc_roots(ascendc_compile_module): | ||
| 1270 | + ascendc_compile_module.module.ASCEND_PATH = "/usr/local/Ascend/cann" | ||
| 1271 | + ascendc_compile_module.module.machine = "x86_64" | ||
| 1272 | + | ||
| 1273 | + include_options = ascendc_compile_module.build_host_include_options("/tmp/build") | ||
| 1274 | + | ||
| 1275 | + assert "/usr/local/Ascend/cann/pkg_inc" in include_options | ||
| 1276 | + assert "/usr/local/Ascend/cann/x86_64-linux/pkg_inc" in include_options | ||
| 1277 | + | ||
| 1278 | + | ||
| 1279 | +def test_build_host_include_options_prefers_machine_pkg_inc_base( | ||
| 1280 | + ascendc_compile_module, | ||
| 1281 | +): | ||
| 1282 | + ascendc_compile_module.module.ASCEND_PATH = "/usr/local/Ascend/cann" | ||
| 1283 | + ascendc_compile_module.module.machine = "x86_64" | ||
| 1284 | + | ||
| 1285 | + include_options = ascendc_compile_module.build_host_include_options("/tmp/build") | ||
| 1286 | + | ||
| 1287 | + machine_base = include_options.index( | ||
| 1288 | + "/usr/local/Ascend/cann/x86_64-linux/pkg_inc/base" | ||
| 1289 | + ) | ||
| 1290 | + generic_base = include_options.index("/usr/local/Ascend/cann/pkg_inc/base") | ||
| 1291 | + assert machine_base < generic_base | ||
| 1292 | + | ||
| 1293 | + | ||
| 1294 | +def _assert_compile_host_objs_skips_shared_cv_wrapper_source( | ||
| 1295 | + ascendc_compile_module, tmpdir, monkeypatch, source_case | ||
| 1296 | +): | ||
| 1297 | + graph_file_name, wrapper_file_name, wrapper_content = source_case | ||
| 1298 | + host_dir = tmpdir.mkdir("host") | ||
| 1299 | + graph_file = host_dir.join(graph_file_name) | ||
| 1300 | + wrapper_file = host_dir.join(wrapper_file_name) | ||
| 1301 | + graph_file.write("CVAutofuseTilingData graph tiling") | ||
| 1302 | + wrapper_file.write(wrapper_content) | ||
| 1303 | + args = _make_compile_args([str(graph_file), str(wrapper_file)]) | ||
| 1304 | + compiled_sources = [] | ||
| 1305 | + | ||
| 1306 | + def fake_compile_host_obj_file(compile_args, temp_dir, source_file, pch_state=None): | ||
| 1307 | + compiled_sources.append(source_file) | ||
| 1308 | + return source_file + ".o" | ||
| 1309 | + | ||
| 1310 | + def fake_ensure_shared_cv_wrapper_so(compile_args, temp_dir, source_file): | ||
| 1311 | + assert source_file == str(wrapper_file) | ||
| 1312 | + return "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so" | ||
| 1313 | + | ||
| 1314 | + ascendc_compile_module.module.compile_host_obj_file = fake_compile_host_obj_file | ||
| 1315 | + ascendc_compile_module.module.ensure_shared_cv_wrapper_so = ( | ||
| 1316 | + fake_ensure_shared_cv_wrapper_so | ||
| 1317 | + ) | ||
| 1318 | + monkeypatch.setattr(ascendc_compile_module.os, "cpu_count", lambda: 2) | ||
| 1319 | + | ||
| 1320 | + result = ascendc_compile_module.compile_host_objs(args, str(tmpdir)) | ||
| 1321 | + | ||
| 1322 | + assert result == [str(graph_file) + ".o"] | ||
| 1323 | + assert compiled_sources == [str(graph_file)] | ||
| 1324 | + assert ( | ||
| 1325 | + args.shared_cv_wrapper_so | ||
| 1326 | + == "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so" | ||
| 1327 | + ) | ||
| 1328 | + | ||
| 1329 | + | ||
| 1185 | def test_build_host_compile_cmd_adds_pgo_mspti_include(ascendc_compile_module): | 1330 | def test_build_host_compile_cmd_adds_pgo_mspti_include(ascendc_compile_module): |
| 1186 | args = _make_compile_args("/tmp/build/host/graph_tiling_func_PgoRunner.cpp") | 1331 | args = _make_compile_args("/tmp/build/host/graph_tiling_func_PgoRunner.cpp") |
| 1187 | args.pgo_mspti_dir = "/usr/local/Ascend/cann/tools/mspti" | 1332 | args.pgo_mspti_dir = "/usr/local/Ascend/cann/tools/mspti" |
| @@ -1244,6 +1389,224 @@ def test_compile_host_objs_compiles_multiple_files(ascendc_compile_module, monke | |||
| 1244 | assert all("cmake" not in cmd and "make" not in cmd for cmd in compile_cmds) | 1389 | assert all("cmake" not in cmd and "make" not in cmd for cmd in compile_cmds) |
| 1245 | 1390 | ||
| 1246 | 1391 | ||
| 1392 | +def test_get_shared_cv_wrapper_cache_dir_prefers_run_dir_env( | ||
| 1393 | + ascendc_compile_module, tmpdir, monkeypatch | ||
| 1394 | +): | ||
| 1395 | + run_dir = tmpdir.mkdir("run") | ||
| 1396 | + monkeypatch.setenv("RUN_DIR", str(run_dir)) | ||
| 1397 | + args = _make_compile_args() | ||
| 1398 | + args.output_file = None | ||
| 1399 | + | ||
| 1400 | + result = ascendc_compile_module.get_shared_cv_wrapper_cache_dir(args, "") | ||
| 1401 | + | ||
| 1402 | + assert result == os.path.join(str(run_dir), "cv_tiling_wrapper_cache") | ||
| 1403 | + | ||
| 1404 | + | ||
| 1405 | +def test_get_shared_cv_wrapper_cache_dir_uses_inductor_cache_without_run_dir( | ||
| 1406 | + ascendc_compile_module, tmpdir, monkeypatch | ||
| 1407 | +): | ||
| 1408 | + cache_dir = tmpdir.mkdir("inductor_cache") | ||
| 1409 | + monkeypatch.delenv("RUN_DIR", raising=False) | ||
| 1410 | + monkeypatch.setenv("TORCHINDUCTOR_NPU_EXT_CACHE_DIR", str(cache_dir)) | ||
| 1411 | + args = _make_compile_args() | ||
| 1412 | + args.output_file = None | ||
| 1413 | + | ||
| 1414 | + result = ascendc_compile_module.get_shared_cv_wrapper_cache_dir(args, "") | ||
| 1415 | + | ||
| 1416 | + assert result == os.path.join(str(cache_dir), "cv_tiling_wrapper_cache") | ||
| 1417 | + | ||
| 1418 | + | ||
| 1419 | +def test_get_shared_cv_wrapper_cache_dir_prefers_output_file_dir( | ||
| 1420 | + ascendc_compile_module, tmpdir, monkeypatch | ||
| 1421 | +): | ||
| 1422 | + output_dir = tmpdir.mkdir("kernel_meta") | ||
| 1423 | + output_file = output_dir.join("kernel.so") | ||
| 1424 | + run_dir = tmpdir.mkdir("run") | ||
| 1425 | + cache_dir = tmpdir.mkdir("inductor_cache") | ||
| 1426 | + monkeypatch.setenv("RUN_DIR", str(run_dir)) | ||
| 1427 | + monkeypatch.setenv("TORCHINDUCTOR_NPU_EXT_CACHE_DIR", str(cache_dir)) | ||
| 1428 | + args = _make_compile_args() | ||
| 1429 | + args.output_file = str(output_file) | ||
| 1430 | + | ||
| 1431 | + result = ascendc_compile_module.get_shared_cv_wrapper_cache_dir(args, "") | ||
| 1432 | + | ||
| 1433 | + assert result == os.path.join(str(output_dir), "cv_tiling_wrapper_cache") | ||
| 1434 | + | ||
| 1435 | + | ||
| 1436 | +def test_get_shared_cv_wrapper_cache_dir_prefers_temp_dir( | ||
| 1437 | + ascendc_compile_module, tmpdir, monkeypatch | ||
| 1438 | +): | ||
| 1439 | + temp_dir = tmpdir.mkdir("temp") | ||
| 1440 | + output_dir = tmpdir.mkdir("kernel_meta") | ||
| 1441 | + output_file = output_dir.join("kernel.so") | ||
| 1442 | + run_dir = tmpdir.mkdir("run") | ||
| 1443 | + cache_dir = tmpdir.mkdir("inductor_cache") | ||
| 1444 | + monkeypatch.setenv("RUN_DIR", str(run_dir)) | ||
| 1445 | + monkeypatch.setenv("TORCHINDUCTOR_NPU_EXT_CACHE_DIR", str(cache_dir)) | ||
| 1446 | + args = _make_compile_args() | ||
| 1447 | + args.output_file = str(output_file) | ||
| 1448 | + | ||
| 1449 | + result = ascendc_compile_module.get_shared_cv_wrapper_cache_dir(args, str(temp_dir)) | ||
| 1450 | + | ||
| 1451 | + assert result == os.path.join(str(temp_dir), "cv_tiling_wrapper_cache") | ||
| 1452 | + | ||
| 1453 | + | ||
| 1454 | +def test_compile_host_objs_skips_shared_cv_wrapper_source( | ||
| 1455 | + ascendc_compile_module, tmpdir, monkeypatch | ||
| 1456 | +): | ||
| 1457 | + _assert_compile_host_objs_skips_shared_cv_wrapper_source( | ||
| 1458 | + ascendc_compile_module, | ||
| 1459 | + tmpdir, | ||
| 1460 | + monkeypatch, | ||
| 1461 | + ( | ||
| 1462 | + "graph_tiling_func.cpp", | ||
| 1463 | + "cube_kernel_tiling_wrapper.cpp", | ||
| 1464 | + "CVAutofuseTilingData wrapper tiling", | ||
| 1465 | + ), | ||
| 1466 | + ) | ||
| 1467 | + | ||
| 1468 | + | ||
| 1469 | +def test_compile_host_objs_skips_split_shared_cv_wrapper_source( | ||
| 1470 | + ascendc_compile_module, tmpdir, monkeypatch | ||
| 1471 | +): | ||
| 1472 | + _assert_compile_host_objs_skips_shared_cv_wrapper_source( | ||
| 1473 | + ascendc_compile_module, | ||
| 1474 | + tmpdir, | ||
| 1475 | + monkeypatch, | ||
| 1476 | + ( | ||
| 1477 | + "autofused_tiling_func_tiling_def_and_tiling_const.cpp", | ||
| 1478 | + "autofused_tiling_func_BCubeKernelTilingWrapperCpp.cpp", | ||
| 1479 | + "AutofuseDoCubeMatMulTiling wrapper tiling", | ||
| 1480 | + ), | ||
| 1481 | + ) | ||
| 1482 | + | ||
| 1483 | + | ||
| 1484 | +def test_ensure_shared_cv_wrapper_so_reuses_existing_so( | ||
| 1485 | + ascendc_compile_module, tmpdir, monkeypatch | ||
| 1486 | +): | ||
| 1487 | + run_dir = tmpdir.mkdir("run") | ||
| 1488 | + host_dir = tmpdir.mkdir("host") | ||
| 1489 | + wrapper_file = host_dir.join("cube_kernel_tiling_wrapper.cpp") | ||
| 1490 | + wrapper_file.write("CVAutofuseTilingData wrapper tiling") | ||
| 1491 | + args = _make_compile_args([str(wrapper_file)]) | ||
| 1492 | + monkeypatch.setenv("RUN_DIR", str(run_dir)) | ||
| 1493 | + so_path = ascendc_compile_module.get_shared_cv_wrapper_so_path( | ||
| 1494 | + args, str(tmpdir), str(wrapper_file) | ||
| 1495 | + ) | ||
| 1496 | + os.makedirs(os.path.dirname(so_path), exist_ok=True) | ||
| 1497 | + with open(so_path, "w") as f: | ||
| 1498 | + f.write("cached") | ||
| 1499 | + | ||
| 1500 | + def fail_compile(*_args, **_kwargs): | ||
| 1501 | + pytest.fail("cached wrapper so should not be recompiled") | ||
| 1502 | + | ||
| 1503 | + ascendc_compile_module.module.compile_host_obj_file = fail_compile | ||
| 1504 | + ascendc_compile_module.module.link_shared = fail_compile | ||
| 1505 | + | ||
| 1506 | + result = ascendc_compile_module.ensure_shared_cv_wrapper_so( | ||
| 1507 | + args, str(tmpdir), str(wrapper_file) | ||
| 1508 | + ) | ||
| 1509 | + | ||
| 1510 | + assert result == so_path | ||
| 1511 | + | ||
| 1512 | + | ||
| 1513 | +def test_ensure_shared_cv_wrapper_so_serializes_concurrent_first_compile( | ||
| 1514 | + ascendc_compile_module, tmpdir, monkeypatch | ||
| 1515 | +): | ||
| 1516 | + run_dir = tmpdir.mkdir("run") | ||
| 1517 | + host_dir = tmpdir.mkdir("host") | ||
| 1518 | + wrapper_file = host_dir.join("cube_kernel_tiling_wrapper.cpp") | ||
| 1519 | + wrapper_file.write("CVAutofuseTilingData wrapper tiling") | ||
| 1520 | + args = _make_compile_args([str(wrapper_file)]) | ||
| 1521 | + args.output_file = str(tmpdir.mkdir("kernel_meta").join("kernel.so")) | ||
| 1522 | + monkeypatch.setenv("RUN_DIR", str(run_dir)) | ||
| 1523 | + compile_calls = [] | ||
| 1524 | + | ||
| 1525 | + def fake_compile_host_obj_file(compile_args, temp_dir, source_file): | ||
| 1526 | + compile_calls.append(source_file) | ||
| 1527 | + time.sleep(0.05) | ||
| 1528 | + return source_file + ".o" | ||
| 1529 | + | ||
| 1530 | + def fake_link_shared( | ||
| 1531 | + target_file, obj_files, link_libraries=None, extra_link_options=None | ||
| 1532 | + ): | ||
| 1533 | + with open(target_file, "w") as f: | ||
| 1534 | + f.write("linked") | ||
| 1535 | + return target_file | ||
| 1536 | + | ||
| 1537 | + ascendc_compile_module.module.compile_host_obj_file = fake_compile_host_obj_file | ||
| 1538 | + ascendc_compile_module.module.link_shared = fake_link_shared | ||
| 1539 | + | ||
| 1540 | + with ThreadPoolExecutor(max_workers=2) as executor: | ||
| 1541 | + futures = [ | ||
| 1542 | + executor.submit( | ||
| 1543 | + ascendc_compile_module.ensure_shared_cv_wrapper_so, | ||
| 1544 | + args, | ||
| 1545 | + str(tmpdir), | ||
| 1546 | + str(wrapper_file), | ||
| 1547 | + ) | ||
| 1548 | + for _ in range(2) | ||
| 1549 | + ] | ||
| 1550 | + results = [future.result() for future in futures] | ||
| 1551 | + | ||
| 1552 | + assert results[0] == results[1] | ||
| 1553 | + assert os.path.exists(results[0]) | ||
| 1554 | + assert compile_calls == [str(wrapper_file)] | ||
| 1555 | + | ||
| 1556 | + | ||
| 1557 | +def test_ensure_shared_cv_wrapper_so_sets_soname( | ||
| 1558 | + ascendc_compile_module, tmpdir, monkeypatch | ||
| 1559 | +): | ||
| 1560 | + output_dir = tmpdir.mkdir("kernel_meta") | ||
| 1561 | + host_dir = tmpdir.mkdir("host") | ||
| 1562 | + wrapper_file = host_dir.join("cube_kernel_tiling_wrapper.cpp") | ||
| 1563 | + wrapper_file.write("CVAutofuseTilingData wrapper tiling") | ||
| 1564 | + args = _make_compile_args([str(wrapper_file)]) | ||
| 1565 | + args.output_file = str(output_dir.join("kernel.so")) | ||
| 1566 | + monkeypatch.delenv("RUN_DIR", raising=False) | ||
| 1567 | + monkeypatch.delenv("TORCHINDUCTOR_NPU_EXT_CACHE_DIR", raising=False) | ||
| 1568 | + captured = {} | ||
| 1569 | + | ||
| 1570 | + def fake_compile_host_obj_file(compile_args, temp_dir, source_file): | ||
| 1571 | + return source_file + ".o" | ||
| 1572 | + | ||
| 1573 | + def fake_link_shared( | ||
| 1574 | + target_file, obj_files, link_libraries=None, extra_link_options=None | ||
| 1575 | + ): | ||
| 1576 | + captured["target_file"] = target_file | ||
| 1577 | + captured["extra_link_options"] = extra_link_options | ||
| 1578 | + with open(target_file, "w") as f: | ||
| 1579 | + f.write("linked") | ||
| 1580 | + return target_file | ||
| 1581 | + | ||
| 1582 | + ascendc_compile_module.module.compile_host_obj_file = fake_compile_host_obj_file | ||
| 1583 | + ascendc_compile_module.module.link_shared = fake_link_shared | ||
| 1584 | + | ||
| 1585 | + so_path = ascendc_compile_module.ensure_shared_cv_wrapper_so( | ||
| 1586 | + args, str(tmpdir), str(wrapper_file) | ||
| 1587 | + ) | ||
| 1588 | + | ||
| 1589 | + assert captured["extra_link_options"] == [ | ||
| 1590 | + f"-Wl,-soname,{os.path.basename(so_path)}" | ||
| 1591 | + ] | ||
| 1592 | + | ||
| 1593 | + | ||
| 1594 | +def test_clean_before_modify_keeps_shared_cv_wrapper_cache( | ||
| 1595 | + ascendc_compile_module, tmpdir | ||
| 1596 | +): | ||
| 1597 | + tmpdir.mkdir("host") | ||
| 1598 | + tmpdir.mkdir("device") | ||
| 1599 | + cache_dir = tmpdir.mkdir("cv_tiling_wrapper_cache") | ||
| 1600 | + cache_file = cache_dir.join("libautofuse_cv_tiling_wrapper.so") | ||
| 1601 | + cache_file.write("cached") | ||
| 1602 | + tmpdir.mkdir("stale") | ||
| 1603 | + | ||
| 1604 | + ascendc_compile_module.clean_before_modify(str(tmpdir)) | ||
| 1605 | + | ||
| 1606 | + assert os.path.exists(str(cache_file)) | ||
| 1607 | + assert not os.path.exists(os.path.join(str(tmpdir), "stale")) | ||
| 1608 | + | ||
| 1609 | + | ||
| 1247 | def test_get_host_compile_worker_count_uses_32_worker_limit( | 1610 | def test_get_host_compile_worker_count_uses_32_worker_limit( |
| 1248 | ascendc_compile_module, monkeypatch | 1611 | ascendc_compile_module, monkeypatch |
| 1249 | ): | 1612 | ): |
| @@ -1299,6 +1662,29 @@ def test_compile_host_obj_rejects_multiple_sources_without_compile( | |||
| 1299 | assert "expects exactly one host source" in str(exc_info.value) | 1662 | assert "expects exactly one host source" in str(exc_info.value) |
| 1300 | 1663 | ||
| 1301 | 1664 | ||
| 1665 | +def _capture_build_device_so_link( | ||
| 1666 | + ascendc_compile_module, args, host_obj_path, temp_dir | ||
| 1667 | +): | ||
| 1668 | + captured = {} | ||
| 1669 | + | ||
| 1670 | + def fake_compile_device_obj(compile_args, temp_dir): | ||
| 1671 | + return "/tmp/build/device/kernel.cpp.o" | ||
| 1672 | + | ||
| 1673 | + ascendc_compile_module.module.compile_device_obj = fake_compile_device_obj | ||
| 1674 | + | ||
| 1675 | + def fake_link_shared( | ||
| 1676 | + target_file, obj_files, link_libraries=None, extra_link_options=None | ||
| 1677 | + ): | ||
| 1678 | + captured["obj_files"] = obj_files | ||
| 1679 | + captured["link_libraries"] = link_libraries | ||
| 1680 | + captured["extra_link_options"] = extra_link_options | ||
| 1681 | + return target_file | ||
| 1682 | + | ||
| 1683 | + ascendc_compile_module.module.link_shared = fake_link_shared | ||
| 1684 | + ascendc_compile_module.build_device_so(args, host_obj_path, temp_dir) | ||
| 1685 | + return captured | ||
| 1686 | + | ||
| 1687 | + | ||
| 1302 | def test_build_device_so_links_all_host_objects(ascendc_compile_module): | 1688 | def test_build_device_so_links_all_host_objects(ascendc_compile_module): |
| 1303 | captured = {} | 1689 | captured = {} |
| 1304 | args = _make_compile_args() | 1690 | args = _make_compile_args() |
| @@ -1308,10 +1694,13 @@ def test_build_device_so_links_all_host_objects(ascendc_compile_module): | |||
| 1308 | 1694 | ||
| 1309 | ascendc_compile_module.module.compile_device_obj = fake_compile_device_obj | 1695 | ascendc_compile_module.module.compile_device_obj = fake_compile_device_obj |
| 1310 | 1696 | ||
| 1311 | - def fake_link_shared(target_file, obj_files, link_libraries=None): | 1697 | + def fake_link_shared( |
| 1698 | + target_file, obj_files, link_libraries=None, extra_link_options=None | ||
| 1699 | + ): | ||
| 1312 | captured["target_file"] = target_file | 1700 | captured["target_file"] = target_file |
| 1313 | captured["obj_files"] = obj_files | 1701 | captured["obj_files"] = obj_files |
| 1314 | captured["link_libraries"] = link_libraries | 1702 | captured["link_libraries"] = link_libraries |
| 1703 | + captured["extra_link_options"] = extra_link_options | ||
| 1315 | return target_file | 1704 | return target_file |
| 1316 | 1705 | ||
| 1317 | ascendc_compile_module.module.link_shared = fake_link_shared | 1706 | ascendc_compile_module.module.link_shared = fake_link_shared |
| @@ -1323,6 +1712,51 @@ def test_build_device_so_links_all_host_objects(ascendc_compile_module): | |||
| 1323 | assert captured["link_libraries"] == ascendc_compile_module.HOST_LINK_LIBRARIES | 1712 | assert captured["link_libraries"] == ascendc_compile_module.HOST_LINK_LIBRARIES |
| 1324 | 1713 | ||
| 1325 | 1714 | ||
| 1715 | +def test_build_device_so_links_shared_cv_wrapper_so_for_cv_compile( | ||
| 1716 | + ascendc_compile_module, tmpdir | ||
| 1717 | +): | ||
| 1718 | + device_dir = tmpdir.mkdir("device") | ||
| 1719 | + device_file = device_dir.join("kernel.cpp") | ||
| 1720 | + device_file.write("CVAutofuseTilingData device tiling") | ||
| 1721 | + args = _make_compile_args() | ||
| 1722 | + args.device_files = str(device_file) | ||
| 1723 | + args.shared_cv_wrapper_so = ( | ||
| 1724 | + "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so" | ||
| 1725 | + ) | ||
| 1726 | + captured = _capture_build_device_so_link( | ||
| 1727 | + ascendc_compile_module, args, ["graph.o"], "/tmp/build" | ||
| 1728 | + ) | ||
| 1729 | + | ||
| 1730 | + assert captured["obj_files"] == [ | ||
| 1731 | + "graph.o", | ||
| 1732 | + "/tmp/build/device/kernel.cpp.o", | ||
| 1733 | + "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so", | ||
| 1734 | + ] | ||
| 1735 | + assert captured["link_libraries"] == ascendc_compile_module.CV_HOST_LINK_LIBRARIES | ||
| 1736 | + assert captured["extra_link_options"] == [ | ||
| 1737 | + ascendc_compile_module.CV_WRAPPER_RPATH_OPTION | ||
| 1738 | + ] | ||
| 1739 | + | ||
| 1740 | + | ||
| 1741 | +def test_build_device_so_ignores_shared_cv_wrapper_so_for_non_cv_compile( | ||
| 1742 | + ascendc_compile_module, tmpdir | ||
| 1743 | +): | ||
| 1744 | + device_dir = tmpdir.mkdir("device") | ||
| 1745 | + device_file = device_dir.join("kernel.cpp") | ||
| 1746 | + device_file.write("regular device tiling") | ||
| 1747 | + args = _make_compile_args() | ||
| 1748 | + args.device_files = str(device_file) | ||
| 1749 | + args.shared_cv_wrapper_so = ( | ||
| 1750 | + "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so" | ||
| 1751 | + ) | ||
| 1752 | + captured = _capture_build_device_so_link( | ||
| 1753 | + ascendc_compile_module, args, ["graph.o"], str(tmpdir) | ||
| 1754 | + ) | ||
| 1755 | + | ||
| 1756 | + assert captured["obj_files"] == ["graph.o", "/tmp/build/device/kernel.cpp.o"] | ||
| 1757 | + assert captured["link_libraries"] == ascendc_compile_module.HOST_LINK_LIBRARIES | ||
| 1758 | + | ||
| 1759 | + | ||
| 1326 | def test_link_host_target_links_multiple_host_objects(ascendc_compile_module): | 1760 | def test_link_host_target_links_multiple_host_objects(ascendc_compile_module): |
| 1327 | captured = {} | 1761 | captured = {} |
| 1328 | args = _make_compile_args( | 1762 | args = _make_compile_args( |
| @@ -1337,10 +1771,13 @@ def test_link_host_target_links_multiple_host_objects(ascendc_compile_module): | |||
| 1337 | 1771 | ||
| 1338 | ascendc_compile_module.module.compile_host_objs = fake_compile_host_objs | 1772 | ascendc_compile_module.module.compile_host_objs = fake_compile_host_objs |
| 1339 | 1773 | ||
| 1340 | - def fake_link_shared(target_file, obj_files, link_libraries=None): | 1774 | + def fake_link_shared( |
| 1775 | + target_file, obj_files, link_libraries=None, extra_link_options=None | ||
| 1776 | + ): | ||
| 1341 | captured["target_file"] = target_file | 1777 | captured["target_file"] = target_file |
| 1342 | captured["obj_files"] = obj_files | 1778 | captured["obj_files"] = obj_files |
| 1343 | captured["link_libraries"] = link_libraries | 1779 | captured["link_libraries"] = link_libraries |
| 1780 | + captured["extra_link_options"] = extra_link_options | ||
| 1344 | return target_file | 1781 | return target_file |
| 1345 | 1782 | ||
| 1346 | ascendc_compile_module.module.link_shared = fake_link_shared | 1783 | ascendc_compile_module.module.link_shared = fake_link_shared |
| @@ -1354,23 +1791,73 @@ def test_link_host_target_links_multiple_host_objects(ascendc_compile_module): | |||
| 1354 | assert "acl_rt" in captured["link_libraries"] | 1791 | assert "acl_rt" in captured["link_libraries"] |
| 1355 | 1792 | ||
| 1356 | 1793 | ||
| 1357 | -def test_link_host_target_adds_acl_runtime_for_pgo_proxy(ascendc_compile_module): | 1794 | +def _capture_link_host_target_link(ascendc_compile_module, args, temp_dir): |
| 1358 | captured = {} | 1795 | captured = {} |
| 1359 | - args = _make_compile_args(["/tmp/build/host/graph_tiling_func.cpp"]) | ||
| 1360 | - args.pgo_runner_file = "/tmp/build/host/graph_tiling_func_PgoRunner.cpp" | ||
| 1361 | 1796 | ||
| 1362 | - def fake_compile_host_objs(*_): | 1797 | + def fake_compile_host_objs(compile_args, temp_dir): |
| 1363 | - return ["host.o"] | 1798 | + return ["graph.o"] |
| 1364 | 1799 | ||
| 1365 | ascendc_compile_module.module.compile_host_objs = fake_compile_host_objs | 1800 | ascendc_compile_module.module.compile_host_objs = fake_compile_host_objs |
| 1366 | 1801 | ||
| 1367 | - def fake_link_shared(target_file, obj_files, link_libraries=None): | 1802 | + def fake_link_shared( |
| 1803 | + target_file, obj_files, link_libraries=None, extra_link_options=None | ||
| 1804 | + ): | ||
| 1805 | + captured["obj_files"] = obj_files | ||
| 1368 | captured["link_libraries"] = link_libraries | 1806 | captured["link_libraries"] = link_libraries |
| 1807 | + captured["extra_link_options"] = extra_link_options | ||
| 1369 | return target_file | 1808 | return target_file |
| 1370 | 1809 | ||
| 1371 | ascendc_compile_module.module.link_shared = fake_link_shared | 1810 | ascendc_compile_module.module.link_shared = fake_link_shared |
| 1811 | + ascendc_compile_module.link_host_target(args, temp_dir) | ||
| 1812 | + return captured | ||
| 1372 | 1813 | ||
| 1373 | - ascendc_compile_module.link_host_target(args, "/tmp/build") | 1814 | + |
| 1815 | +def test_link_host_target_links_shared_cv_wrapper_so_for_cv_compile( | ||
| 1816 | + ascendc_compile_module, tmpdir | ||
| 1817 | +): | ||
| 1818 | + host_dir = tmpdir.mkdir("host") | ||
| 1819 | + host_file = host_dir.join("graph_tiling_func.cpp") | ||
| 1820 | + host_file.write("CVAutofuseTilingData graph tiling") | ||
| 1821 | + args = _make_compile_args([str(host_file)]) | ||
| 1822 | + args.shared_cv_wrapper_so = ( | ||
| 1823 | + "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so" | ||
| 1824 | + ) | ||
| 1825 | + captured = _capture_link_host_target_link( | ||
| 1826 | + ascendc_compile_module, args, "/tmp/build" | ||
| 1827 | + ) | ||
| 1828 | + | ||
| 1829 | + assert captured["obj_files"] == [ | ||
| 1830 | + "graph.o", | ||
| 1831 | + "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so", | ||
| 1832 | + ] | ||
| 1833 | + assert captured["link_libraries"] == ascendc_compile_module.CV_HOST_LINK_LIBRARIES | ||
| 1834 | + assert captured["extra_link_options"] == [ | ||
| 1835 | + ascendc_compile_module.CV_WRAPPER_RPATH_OPTION | ||
| 1836 | + ] | ||
| 1837 | + | ||
| 1838 | + | ||
| 1839 | +def test_link_host_target_ignores_shared_cv_wrapper_so_for_non_cv_compile( | ||
| 1840 | + ascendc_compile_module, tmpdir | ||
| 1841 | +): | ||
| 1842 | + host_dir = tmpdir.mkdir("host") | ||
| 1843 | + host_file = host_dir.join("graph_tiling_func.cpp") | ||
| 1844 | + host_file.write("regular graph tiling") | ||
| 1845 | + args = _make_compile_args([str(host_file)]) | ||
| 1846 | + args.shared_cv_wrapper_so = ( | ||
| 1847 | + "/tmp/run/cv_tiling_wrapper_cache/libautofuse_cv_tiling_wrapper.so" | ||
| 1848 | + ) | ||
| 1849 | + captured = _capture_link_host_target_link(ascendc_compile_module, args, str(tmpdir)) | ||
| 1850 | + | ||
| 1851 | + assert captured["obj_files"] == ["graph.o"] | ||
| 1852 | + assert captured["link_libraries"] == ascendc_compile_module.HOST_LINK_LIBRARIES | ||
| 1853 | + | ||
| 1854 | + | ||
| 1855 | +def test_link_host_target_adds_acl_runtime_for_pgo_proxy(ascendc_compile_module): | ||
| 1856 | + args = _make_compile_args(["/tmp/build/host/graph_tiling_func.cpp"]) | ||
| 1857 | + args.pgo_runner_file = "/tmp/build/host/graph_tiling_func_PgoRunner.cpp" | ||
| 1858 | + captured = _capture_link_host_target_link( | ||
| 1859 | + ascendc_compile_module, args, "/tmp/build" | ||
| 1860 | + ) | ||
| 1374 | 1861 | ||
| 1375 | assert captured["link_libraries"] == ascendc_compile_module.HOST_LINK_LIBRARIES + [ | 1862 | assert captured["link_libraries"] == ascendc_compile_module.HOST_LINK_LIBRARIES + [ |
| 1376 | "ascendcl", | 1863 | "ascendcl", |
| @@ -200,6 +200,6 @@ add_subdirectory(expm_test) | |||
| 200 | # add_subdirectory(truncdiv_bf16_test) | 200 | # add_subdirectory(truncdiv_bf16_test) |
| 201 | # add_subdirectory(sinh_bf16_test) | 201 | # add_subdirectory(sinh_bf16_test) |
| 202 | # add_subdirectory(tan_bf16_test) | 202 | # add_subdirectory(tan_bf16_test) |
| 203 | -# add_subdirectory(round_to_int_float_to_int32_test) | 203 | +add_subdirectory(round_to_int_float_to_int32_test) |
| 204 | -# add_subdirectory(trunc_to_int_bf16_to_int32_test) | 204 | +add_subdirectory(trunc_to_int_bf16_to_int32_test) |
| 205 | # add_subdirectory(remainder_bf16_test) | 205 | # add_subdirectory(remainder_bf16_test) |
| @@ -0,0 +1,93 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +template <typename PrepareSchedule, typename CheckKernel> | ||
| 28 | +inline void GenerateBackendKernelWithScheduleCheck( | ||
| 29 | + const af::ComputeGraphPtr &graph, const std::map<std::string, std::string> &shape_info, | ||
| 30 | + const std::string &tiling_stub, const std::string &kernel_src_file_name, const std::string &tiling_src_file_name, | ||
| 31 | + const std::string &tiling_data_src_file_name, PrepareSchedule prepare_schedule, CheckKernel check_kernel) { | ||
| 32 | + bool gen_success = true; | ||
| 33 | + try { | ||
| 34 | + optimize::Optimizer optimizer(optimize::OptimizerOptions{}); | ||
| 35 | + codegen::Codegen codegen(codegen::CodegenOptions{}); | ||
| 36 | + | ||
| 37 | + std::fstream kernel_file(kernel_src_file_name, std::ios::out); | ||
| 38 | + std::fstream tiling_file(tiling_src_file_name, std::ios::out); | ||
| 39 | + std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out); | ||
| 40 | + | ||
| 41 | + std::vector<::ascir::ScheduledResult> schedule_results; | ||
| 42 | + ascir::FusedScheduledResult fused_schedule_result; | ||
| 43 | + fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results); | ||
| 44 | + EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0); | ||
| 45 | + if (prepare_schedule(fused_schedule_result)) { | ||
| 46 | + codegen::CodegenResult result; | ||
| 47 | + EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0); | ||
| 48 | + const std::string kernel = RemoveSubDirInclude(result.kernel); | ||
| 49 | + check_kernel(kernel); | ||
| 50 | + kernel_file << tiling_stub << kernel; | ||
| 51 | + tiling_file << result.tiling; | ||
| 52 | + tiling_data_file << result.tiling_data; | ||
| 53 | + } else { | ||
| 54 | + gen_success = false; | ||
| 55 | + } | ||
| 56 | + } catch (...) { | ||
| 57 | + gen_success = false; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + EXPECT_EQ(gen_success, true); | ||
| 61 | +} | ||
| 62 | + | ||
| 63 | +template <typename CheckKernel> | ||
| 64 | +inline void GenerateBackendKernelWithCheck(const af::ComputeGraphPtr &graph, | ||
| 65 | + const std::map<std::string, std::string> &shape_info, | ||
| 66 | + const std::string &tiling_stub, CheckKernel check_kernel) { | ||
| 67 | + std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl; | ||
| 68 | + std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':'); | ||
| 69 | + GenerateBackendKernelWithScheduleCheck( | ||
| 70 | + graph, shape_info, tiling_stub, parts[0], parts[1], parts[2], [](ascir::FusedScheduledResult &) { return true; }, | ||
| 71 | + check_kernel); | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +template <typename CheckKernel> | ||
| 75 | +inline void GenerateCvBackendUbKernelWithCheck(const af::ComputeGraphPtr &graph, | ||
| 76 | + const std::string &kernel_src_file_name, | ||
| 77 | + const std::string &tiling_src_file_name, | ||
| 78 | + const std::string &tiling_data_src_file_name, CheckKernel check_kernel) { | ||
| 79 | + GenerateBackendKernelWithScheduleCheck( | ||
| 80 | + graph, {}, "", kernel_src_file_name, tiling_src_file_name, tiling_data_src_file_name, | ||
| 81 | + [](ascir::FusedScheduledResult &fused_schedule_result) { | ||
| 82 | + const bool is_cube_fused = ascgen_utils::IsCubeFusedScheduled(fused_schedule_result); | ||
| 83 | + EXPECT_TRUE(is_cube_fused); | ||
| 84 | + if (!is_cube_fused) { | ||
| 85 | + return false; | ||
| 86 | + } | ||
| 87 | + ascgen_utils::FilterCVFusionUBResult(fused_schedule_result); | ||
| 88 | + return true; | ||
| 89 | + }, | ||
| 90 | + check_kernel); | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | + | ||
| @@ -19,7 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | -#include "backend_common.h" | 22 | +#include "backend_codegen_common.h" |
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | 25 | ||
| @@ -42,41 +42,13 @@ class BoolBackendCodegenE2e : public testing::Test { | |||
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | inline void GenerateBoolBackendKernel(const af::ComputeGraphPtr &graph) { | 44 | inline void GenerateBoolBackendKernel(const af::ComputeGraphPtr &graph) { |
| 45 | - bool gen_success = true; | ||
| 46 | std::string tiling_stub = R"( | 45 | std::string tiling_stub = R"( |
| 47 | 46 | ||
| 48 | 47 | ||
| 49 | )"; | 48 | )"; |
| 50 | 49 | ||
| 51 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}}); | 50 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}}); |
| 52 | - std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl; | 51 | + GenerateBackendKernelWithCheck(graph, shape_info, tiling_stub, [](const std::string &) {}); |
| 53 | - std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':'); | ||
| 54 | - const std::string &kernel_src_file_name = parts[0]; | ||
| 55 | - const std::string &tiling_src_file_name = parts[1]; | ||
| 56 | - const std::string &tiling_data_src_file_name = parts[2]; | ||
| 57 | - | ||
| 58 | - try { | ||
| 59 | - optimize::Optimizer optimizer(optimize::OptimizerOptions{}); | ||
| 60 | - codegen::Codegen codegen(codegen::CodegenOptions{}); | ||
| 61 | - | ||
| 62 | - std::fstream kernel_file(kernel_src_file_name, std::ios::out); | ||
| 63 | - std::fstream tiling_file(tiling_src_file_name, std::ios::out); | ||
| 64 | - std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out); | ||
| 65 | - | ||
| 66 | - std::vector<::ascir::ScheduledResult> schedule_results; | ||
| 67 | - ascir::FusedScheduledResult fused_schedule_result; | ||
| 68 | - fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results); | ||
| 69 | - EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0); | ||
| 70 | - codegen::CodegenResult result; | ||
| 71 | - EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0); | ||
| 72 | - kernel_file << tiling_stub << RemoveSubDirInclude(result.kernel); | ||
| 73 | - tiling_file << result.tiling; | ||
| 74 | - tiling_data_file << result.tiling_data; | ||
| 75 | - } catch (...) { | ||
| 76 | - gen_success = false; | ||
| 77 | - } | ||
| 78 | - | ||
| 79 | - EXPECT_EQ(gen_success, true); | ||
| 80 | } | 52 | } |
| 81 | 53 | ||
| 82 | 54 | ||
Mautofuse/tests/v35/st/backend_e2e_v2/floortoint_float_test/floortoint_float_backend_generate.cpp+7-30
| @@ -15,7 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | -#include "backend_common.h" | 18 | +#include "../backend_codegen_common.h" |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| @@ -38,7 +38,6 @@ class TestBackendFloortointFloatE2e : public testing::Test { | |||
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | TEST_F(TestBackendFloortointFloatE2e, FloortointFloatE2eCodegen) { | 40 | TEST_F(TestBackendFloortointFloatE2e, FloortointFloatE2eCodegen) { |
| 41 | - bool gen_success = true; | ||
| 42 | std::string tilig_stub = R"( | 41 | std::string tilig_stub = R"( |
| 43 | 42 | ||
| 44 | 43 | ||
| @@ -46,32 +45,10 @@ TEST_F(TestBackendFloortointFloatE2e, FloortointFloatE2eCodegen) { | |||
| 46 | 45 | ||
| 47 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}}); | 46 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}}); |
| 48 | auto graph = ascir::ShareGraph::FloorToIntFloatFusedGraph(2); | 47 | auto graph = ascir::ShareGraph::FloorToIntFloatFusedGraph(2); |
| 49 | - std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl; | 48 | + GenerateBackendKernelWithCheck(graph, shape_info, tilig_stub, [](const std::string &kernel) { |
| 50 | - std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':'); | 49 | + EXPECT_NE(kernel.find("AscendC::Cast(local_3[0], local_2[0], AscendC::RoundMode::CAST_FLOOR, " |
| 51 | - std::string kernel_src_file_name = parts[0]; | 50 | + "local_2_actual_size);"), |
| 52 | - std::string tiling_src_file_name = parts[1]; | 51 | + std::string::npos); |
| 53 | - std::string tiling_data_src = parts[2]; | 52 | + EXPECT_NE(kernel.find("DataCopyPadExtend<int32_t, AscendC::PaddingMode::Normal>"), std::string::npos); |
| 54 | - | 53 | + }); |
| 55 | - try { | ||
| 56 | - optimize::Optimizer optimizer(optimize::OptimizerOptions{}); | ||
| 57 | - codegen::Codegen codegen(codegen::CodegenOptions{}); | ||
| 58 | - | ||
| 59 | - std::fstream kernel_file(kernel_src_file_name, std::ios::out); | ||
| 60 | - std::fstream tiling_file(tiling_src_file_name, std::ios::out); | ||
| 61 | - std::fstream tiling_data_file(tiling_data_src, std::ios::out); | ||
| 62 | - | ||
| 63 | - std::vector<::ascir::ScheduledResult> schedule_results; | ||
| 64 | - ascir::FusedScheduledResult fused_schedule_result; | ||
| 65 | - fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results); | ||
| 66 | - EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0); | ||
| 67 | - codegen::CodegenResult result; | ||
| 68 | - EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0); | ||
| 69 | - kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel); | ||
| 70 | - tiling_file << result.tiling; | ||
| 71 | - tiling_data_file << result.tiling_data; | ||
| 72 | - } catch (...) { | ||
| 73 | - gen_success = false; | ||
| 74 | - } | ||
| 75 | - | ||
| 76 | - EXPECT_EQ(gen_success, true); | ||
| 77 | } | 54 | } |
Mautofuse/tests/v35/st/backend_e2e_v2/int16_logical_not_test/int16_logical_not_backend_generate.cpp+7-30
| @@ -15,7 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | -#include "backend_common.h" | 18 | +#include "../backend_codegen_common.h" |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| @@ -39,7 +39,6 @@ class TestBackendInt16LogicalNotE2e : public testing::Test { | |||
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | TEST_F(TestBackendInt16LogicalNotE2e, LoadLogicalNotStoreE2eCodegen) { | 41 | TEST_F(TestBackendInt16LogicalNotE2e, LoadLogicalNotStoreE2eCodegen) { |
| 42 | - bool gen_success = true; | ||
| 43 | std::string tiling_stub = R"( | 42 | std::string tiling_stub = R"( |
| 44 | 43 | ||
| 45 | 44 | ||
| @@ -48,32 +47,10 @@ TEST_F(TestBackendInt16LogicalNotE2e, LoadLogicalNotStoreE2eCodegen) { | |||
| 48 | // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) | 47 | // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) |
| 49 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}}); | 48 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}}); |
| 50 | auto graph = ascir::ShareGraph::LoadLogicalNotStoreFusedGraph(2, af::DT_INT16, af::DT_UINT8); | 49 | auto graph = ascir::ShareGraph::LoadLogicalNotStoreFusedGraph(2, af::DT_INT16, af::DT_UINT8); |
| 51 | - std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl; | 50 | + GenerateBackendKernelWithCheck(graph, shape_info, tiling_stub, [](const std::string &kernel) { |
| 52 | - std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':'); | 51 | + EXPECT_NE(kernel.find("LocalTensor<half> local_blk_tensor_of_half_1"), std::string::npos); |
| 53 | - const std::string &kernel_src_file_name = parts[0]; | 52 | + EXPECT_NE(kernel.find("Duplicate(local_blk_tensor_of_half_1[0], (half)1.0, ONE_BLK_SIZE / sizeof(half));"), |
| 54 | - const std::string &tiling_src_file_name = parts[1]; | 53 | + std::string::npos); |
| 55 | - const std::string &tiling_data_src_file_name = parts[2]; | 54 | + EXPECT_NE(kernel.find("AscendC::LogicalNot(dst, src, count);"), std::string::npos); |
| 56 | - | 55 | + }); |
| 57 | - try { | ||
| 58 | - optimize::Optimizer optimizer(optimize::OptimizerOptions{}); | ||
| 59 | - codegen::Codegen codegen(codegen::CodegenOptions{}); | ||
| 60 | - | ||
| 61 | - std::fstream kernel_file(kernel_src_file_name, std::ios::out); | ||
| 62 | - std::fstream tiling_file(tiling_src_file_name, std::ios::out); | ||
| 63 | - std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out); | ||
| 64 | - | ||
| 65 | - std::vector<::ascir::ScheduledResult> schedule_results; | ||
| 66 | - ascir::FusedScheduledResult fused_schedule_result; | ||
| 67 | - fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results); | ||
| 68 | - EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0); | ||
| 69 | - codegen::CodegenResult result; | ||
| 70 | - EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0); | ||
| 71 | - kernel_file << tiling_stub << RemoveSubDirInclude(result.kernel); | ||
| 72 | - tiling_file << result.tiling; | ||
| 73 | - tiling_data_file << result.tiling_data; | ||
| 74 | - } catch (...) { | ||
| 75 | - gen_success = false; | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - EXPECT_EQ(gen_success, true); | ||
| 79 | } | 56 | } |
Mautofuse/tests/v35/st/backend_e2e_v2/load_compare_cast_sum_store_test/load_compare_cast_sum_store_backend_generator.cpp+10-30
| @@ -15,7 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | -#include "backend_common.h" | 18 | +#include "../backend_codegen_common.h" |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| @@ -39,7 +39,6 @@ class TestBackendLoadCompareCastSumStoreE2e : public testing::Test { | |||
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | TEST_F(TestBackendLoadCompareCastSumStoreE2e, LoadCompareCastSumStoreE2eCodegen) { | 41 | TEST_F(TestBackendLoadCompareCastSumStoreE2e, LoadCompareCastSumStoreE2eCodegen) { |
| 42 | - bool gen_success = true; | ||
| 43 | std::string tiling_stub = R"( | 42 | std::string tiling_stub = R"( |
| 44 | 43 | ||
| 45 | 44 | ||
| @@ -48,32 +47,13 @@ TEST_F(TestBackendLoadCompareCastSumStoreE2e, LoadCompareCastSumStoreE2eCodegen) | |||
| 48 | // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) | 47 | // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) |
| 49 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}}); | 48 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}}); |
| 50 | auto graph = ascir::ShareGraph::LoadCompareCastSumStoreFusedGraph(3); | 49 | auto graph = ascir::ShareGraph::LoadCompareCastSumStoreFusedGraph(3); |
| 51 | - std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl; | 50 | + GenerateBackendKernelWithCheck(graph, shape_info, tiling_stub, [](const std::string &kernel) { |
| 52 | - std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':'); | 51 | + EXPECT_NE(kernel.find("CompareExtend<float, 2, CMPMODE::GE>"), std::string::npos); |
| 53 | - const std::string &kernel_src_file_name = parts[0]; | 52 | + EXPECT_NE(kernel.find("{static_cast<uint16_t>(z1t_actual_size), static_cast<uint16_t>(z2t_actual_size)}"), |
| 54 | - const std::string &tiling_src_file_name = parts[1]; | 53 | + std::string::npos); |
| 55 | - const std::string &tiling_data_src_file_name = parts[2]; | 54 | + EXPECT_NE(kernel.find("{static_cast<uint16_t>(((32 * Ceiling((Rational(1 , 32) * t->z2t_size))))/(1)), " |
| 56 | - | 55 | + "static_cast<uint16_t>(1)}"), |
| 57 | - try { | 56 | + std::string::npos); |
| 58 | - optimize::Optimizer optimizer(optimize::OptimizerOptions{}); | 57 | + EXPECT_NE(kernel.find("ReduceSum<float, AscendC::Pattern::Reduce::RA, true>"), std::string::npos); |
| 59 | - codegen::Codegen codegen(codegen::CodegenOptions{}); | 58 | + }); |
| 60 | - | ||
| 61 | - std::fstream kernel_file(kernel_src_file_name, std::ios::out); | ||
| 62 | - std::fstream tiling_file(tiling_src_file_name, std::ios::out); | ||
| 63 | - std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out); | ||
| 64 | - | ||
| 65 | - std::vector<::ascir::ScheduledResult> schedule_results; | ||
| 66 | - ascir::FusedScheduledResult fused_schedule_result; | ||
| 67 | - fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results); | ||
| 68 | - EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0); | ||
| 69 | - codegen::CodegenResult result; | ||
| 70 | - EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0); | ||
| 71 | - kernel_file << tiling_stub << RemoveSubDirInclude(result.kernel); | ||
| 72 | - tiling_file << result.tiling; | ||
| 73 | - tiling_data_file << result.tiling_data; | ||
| 74 | - } catch (...) { | ||
| 75 | - gen_success = false; | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - EXPECT_EQ(gen_success, true); | ||
| 79 | } | 59 | } |
Mautofuse/tests/v35/st/backend_e2e_v2/load_where_store_test/load_where_store_backend_generate.cpp+9-30
| @@ -15,7 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | -#include "backend_common.h" | 18 | +#include "../backend_codegen_common.h" |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| @@ -39,7 +39,6 @@ class TestBackendLoadWhereStoreE2e : public testing::Test { | |||
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | TEST_F(TestBackendLoadWhereStoreE2e, LoadWhereStoreE2eCodegen) { | 41 | TEST_F(TestBackendLoadWhereStoreE2e, LoadWhereStoreE2eCodegen) { |
| 42 | - bool gen_success = true; | ||
| 43 | std::string tilig_stub = R"( | 42 | std::string tilig_stub = R"( |
| 44 | 43 | ||
| 45 | 44 | ||
| @@ -47,32 +46,12 @@ TEST_F(TestBackendLoadWhereStoreE2e, LoadWhereStoreE2eCodegen) { | |||
| 47 | // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) | 46 | // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) |
| 48 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}}); | 47 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}}); |
| 49 | auto graph = ascir::ShareGraph::LoadWhereReduceStoreFusedGraph(3, false, false); | 48 | auto graph = ascir::ShareGraph::LoadWhereReduceStoreFusedGraph(3, false, false); |
| 50 | - std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl; | 49 | + GenerateBackendKernelWithCheck(graph, shape_info, tilig_stub, [](const std::string &kernel) { |
| 51 | - std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':'); | 50 | + EXPECT_NE(kernel.find("WhereExtend<false, false>(local_8[0], local_7[0], local_6[0], local_5[0], " |
| 52 | - std::string kernel_src_file_name = parts[0]; // load_where_store_test_tiling.cpp | 51 | + "{static_cast<uint16_t>(z0z1t_actual_size)"), |
| 53 | - std::string tiling_src_file_name = parts[1]; // load_where_store_test_kernel.cpp | 52 | + std::string::npos); |
| 54 | - std::string tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h | 53 | + EXPECT_NE(kernel.find("{static_cast<uint16_t>(((8 * Ceiling((Rational(1 , 8) * t->z2t_size))))/(1)), " |
| 55 | - | 54 | + "static_cast<uint16_t>(1)}"), |
| 56 | - try { | 55 | + std::string::npos); |
| 57 | - optimize::Optimizer optimizer(optimize::OptimizerOptions{}); | 56 | + }); |
| 58 | - codegen::Codegen codegen(codegen::CodegenOptions{}); | ||
| 59 | - | ||
| 60 | - std::fstream kernel_file(kernel_src_file_name, std::ios::out); | ||
| 61 | - std::fstream tiling_file(tiling_src_file_name, std::ios::out); | ||
| 62 | - std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out); | ||
| 63 | - | ||
| 64 | - std::vector<::ascir::ScheduledResult> schedule_results; | ||
| 65 | - ascir::FusedScheduledResult fused_schedule_result; | ||
| 66 | - fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results); | ||
| 67 | - EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0); | ||
| 68 | - codegen::CodegenResult result; | ||
| 69 | - EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0); | ||
| 70 | - kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel); | ||
| 71 | - tiling_file << result.tiling; | ||
| 72 | - tiling_data_file << result.tiling_data; | ||
| 73 | - } catch (...) { | ||
| 74 | - gen_success = false; | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | - EXPECT_EQ(gen_success, true); | ||
| 78 | } | 57 | } |
Mautofuse/tests/v35/st/backend_e2e_v2/load_where_x2_x3_is_ubscalar_store_test/load_where_x2_x3_is_ubscalar_store_backend_generate.cpp+9-30
| @@ -15,9 +15,9 @@ | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | - | ||
| 19 | 18 | ||
| 20 | 19 | ||
| 20 | + | ||
| 21 | 21 | ||
| 22 | 22 | ||
| 23 | 23 | ||
| @@ -39,7 +39,6 @@ class TestBackendLoadWhereX2X3IsUbscalarStoreE2e : public testing::Test { | |||
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | TEST_F(TestBackendLoadWhereX2X3IsUbscalarStoreE2e, LoadWhereX2X3IsUbscalarStoreE2eCodegen) { | 41 | TEST_F(TestBackendLoadWhereX2X3IsUbscalarStoreE2e, LoadWhereX2X3IsUbscalarStoreE2eCodegen) { |
| 42 | - bool gen_success = true; | ||
| 43 | std::string tilig_stub = R"( | 42 | std::string tilig_stub = R"( |
| 44 | 43 | ||
| 45 | 44 | ||
| @@ -47,32 +46,12 @@ TEST_F(TestBackendLoadWhereX2X3IsUbscalarStoreE2e, LoadWhereX2X3IsUbscalarStoreE | |||
| 47 | // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) | 46 | // shape_info 和 AddAbsFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) |
| 48 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}}); | 47 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}}); |
| 49 | auto graph = ascir::ShareGraph::LoadWhereReduceStoreFusedGraph(3, true, true); | 48 | auto graph = ascir::ShareGraph::LoadWhereReduceStoreFusedGraph(3, true, true); |
| 50 | - std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl; | 49 | + GenerateBackendKernelWithCheck(graph, shape_info, tilig_stub, [](const std::string &kernel) { |
| 51 | - std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':'); | 50 | + EXPECT_NE(kernel.find("WhereExtend(local_5[0], local_4[0], scalar_2, scalar_3, local_4_actual_size);"), |
| 52 | - std::string kernel_src_file_name = parts[0]; // load_where_x2_x3_is_ubscalar_store_test_tiling.cpp | 51 | + std::string::npos); |
| 53 | - std::string tiling_src_file_name = parts[1]; // load_where_x2_x3_is_ubscalar_store_test_kernel.cpp | 52 | + EXPECT_NE(kernel.find("Duplicate(local_blk_tensor_of_scalar_2[0], static_cast<float>(100), " |
| 54 | - std::string tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h | 53 | + "static_cast<uint64_t>(32/sizeof(float)));"), |
| 55 | - | 54 | + std::string::npos); |
| 56 | - try { | 55 | + EXPECT_NE(kernel.find("DataCopyPadExtend<float, AscendC::PaddingMode::Normal>(global_1"), std::string::npos); |
| 57 | - optimize::Optimizer optimizer(optimize::OptimizerOptions{}); | 56 | + }); |
| 58 | - codegen::Codegen codegen(codegen::CodegenOptions{}); | ||
| 59 | - | ||
| 60 | - std::fstream kernel_file(kernel_src_file_name, std::ios::out); | ||
| 61 | - std::fstream tiling_file(tiling_src_file_name, std::ios::out); | ||
| 62 | - std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out); | ||
| 63 | - | ||
| 64 | - std::vector<::ascir::ScheduledResult> schedule_results; | ||
| 65 | - ascir::FusedScheduledResult fused_schedule_result; | ||
| 66 | - fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results); | ||
| 67 | - EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0); | ||
| 68 | - codegen::CodegenResult result; | ||
| 69 | - EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0); | ||
| 70 | - kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel); | ||
| 71 | - tiling_file << result.tiling; | ||
| 72 | - tiling_data_file << result.tiling_data; | ||
| 73 | - } catch (...) { | ||
| 74 | - gen_success = false; | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | - EXPECT_EQ(gen_success, true); | ||
| 78 | } | 57 | } |
| @@ -84,7 +84,14 @@ TEST_F(TestBackendMatmulEqScalar, MatmulEqScalarCodegen) { | |||
| 84 | 84 | ||
| 85 | // 分别生成ub和common模板的kernel和tiling | 85 | // 分别生成ub和common模板的kernel和tiling |
| 86 | EXPECT_EQ(codegen.Generate(shape_info, ub_schedule_result, result), 0); | 86 | EXPECT_EQ(codegen.Generate(shape_info, ub_schedule_result, result), 0); |
| 87 | - kernel_file << RemoveSubDirInclude(result.kernel); | 87 | + const std::string ub_kernel = RemoveSubDirInclude(result.kernel); |
| 88 | + EXPECT_NE(ub_kernel.find("CompareScalarExtend<float, 2, CMPMODE::EQ>"), std::string::npos); | ||
| 89 | + EXPECT_NE(ub_kernel.find("{static_cast<uint16_t>(curAivM), static_cast<uint16_t>(curAivN)}"), std::string::npos); | ||
| 90 | + EXPECT_NE(ub_kernel.find("{static_cast<uint16_t>(((curAivN + 32 - 1) / 32 * 32)), static_cast<uint16_t>(1)}"), | ||
| 91 | + std::string::npos); | ||
| 92 | + EXPECT_NE(ub_kernel.find("{static_cast<uint16_t>(((curAivN + 8 - 1) / 8 * 8)), static_cast<uint16_t>(1)}"), | ||
| 93 | + std::string::npos); | ||
| 94 | + kernel_file << ub_kernel; | ||
| 88 | tiling_file << result.tiling; | 95 | tiling_file << result.tiling; |
| 89 | tiling_data_file << result.tiling_data; | 96 | tiling_data_file << result.tiling_data; |
| 90 | 97 | ||
| @@ -16,10 +16,11 @@ | |||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | + | ||
| 19 | 20 | ||
| 20 | 21 | ||
| 21 | 22 | ||
| 22 | -#include "backend_common.h" | 23 | +#include "../backend_codegen_common.h" |
| 23 | 24 | ||
| 24 | 25 | ||
| 25 | 26 | ||
| @@ -27,6 +28,49 @@ | |||
| 27 | 28 | ||
| 28 | 29 | ||
| 29 | 30 | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +namespace { | ||
| 34 | +codegen::Tensor MakeCvFusionTensor(const ascir::TensorAttr &tensor_attr) { | ||
| 35 | + std::string dtype_name; | ||
| 36 | + EXPECT_EQ(codegen::Tensor::DtypeName(tensor_attr.attr.dtype, dtype_name), af::SUCCESS); | ||
| 37 | + codegen::Tensor tensor(tensor_attr, dtype_name); | ||
| 38 | + EXPECT_EQ(tensor.Init(), af::SUCCESS); | ||
| 39 | + return tensor; | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +struct CvFusionDataCopyTensors { | ||
| 43 | + codegen::Tensor gm; | ||
| 44 | + codegen::Tensor ub; | ||
| 45 | +}; | ||
| 46 | + | ||
| 47 | +CvFusionDataCopyTensors MakeCvFusionDataCopyTensors() { | ||
| 48 | + af::AscGraph graph("cv_fusion_data_copy_params"); | ||
| 49 | + af::ascir_op::Data data("data", graph); | ||
| 50 | + af::ascir_op::Load load("load"); | ||
| 51 | + graph.AddNode(load); | ||
| 52 | + load.x = data.y; | ||
| 53 | + | ||
| 54 | + auto gm_node = graph.FindNode("data"); | ||
| 55 | + gm_node->outputs[0].attr.dtype = ge::DT_FLOAT16; | ||
| 56 | + gm_node->outputs[0].attr.mem.tensor_id = 0; | ||
| 57 | + gm_node->outputs[0].attr.mem.reuse_id = 0; | ||
| 58 | + gm_node->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeGlobal; | ||
| 59 | + gm_node->outputs[0].attr.mem.hardware = af::MemHardware::kMemHardwareGM; | ||
| 60 | + gm_node->outputs[0].attr.mem.position = af::Position::kPositionGM; | ||
| 61 | + gm_node->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 62 | + | ||
| 63 | + auto ub_node = graph.FindNode("load"); | ||
| 64 | + ub_node->outputs[0].attr.dtype = ge::DT_FLOAT16; | ||
| 65 | + ub_node->outputs[0].attr.mem.tensor_id = 1; | ||
| 66 | + ub_node->outputs[0].attr.mem.reuse_id = 0; | ||
| 67 | + ub_node->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeBuffer; | ||
| 68 | + ub_node->outputs[0].attr.mem.hardware = af::MemHardware::kMemHardwareUB; | ||
| 69 | + ub_node->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 70 | + ub_node->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 71 | + return {MakeCvFusionTensor(gm_node->outputs[0]), MakeCvFusionTensor(ub_node->outputs[0])}; | ||
| 72 | +} | ||
| 73 | +} // namespace | ||
| 30 | 74 | ||
| 31 | class TestBackendMatmulEleBrc : public testing::Test { | 75 | class TestBackendMatmulEleBrc : public testing::Test { |
| 32 | protected: | 76 | protected: |
| @@ -79,34 +123,14 @@ TEST_F(TestBackendMatmulEleBrc, MatmulEleBrcCodegen) { | |||
| 79 | 123 | ||
| 80 | // 分别生成ub和common模板的kernel和tiling | 124 | // 分别生成ub和common模板的kernel和tiling |
| 81 | EXPECT_EQ(codegen.Generate(shape_info, ub_schedule_result, result), 0); | 125 | EXPECT_EQ(codegen.Generate(shape_info, ub_schedule_result, result), 0); |
| 82 | - kernel_file << RemoveSubDirInclude(result.kernel); | 126 | + const std::string ub_kernel = RemoveSubDirInclude(result.kernel); |
| 127 | + EXPECT_FALSE(ub_kernel.empty()); | ||
| 128 | + EXPECT_FALSE(result.tiling.empty()); | ||
| 129 | + EXPECT_FALSE(result.tiling_data.empty()); | ||
| 130 | + kernel_file << ub_kernel; | ||
| 83 | tiling_file << result.tiling; | 131 | tiling_file << result.tiling; |
| 84 | tiling_data_file << result.tiling_data; | 132 | tiling_data_file << result.tiling_data; |
| 85 | 133 | ||
| 86 | - // 校验RemoveSubDirInclude(result.kernel)中是否包含IncludeMatmulHeadFiles方法返回的所有头文件内容 | ||
| 87 | - std::vector<std::string> expected_headers = {"#include \"arch35/mat_mul_v3_tiling_key_public.h\"", | ||
| 88 | - "#include \"arch35/mat_mul_tiling_data.h\"", | ||
| 89 | - "#include \"mat_mul_v3_common.h\"", | ||
| 90 | - "#include \"arch35/mat_mul_asw_block.h\"", | ||
| 91 | - "#include \"arch35/mat_mul_asw_kernel.h\"", | ||
| 92 | - "#include \"arch35/mat_mul_stream_k_block.h\"", | ||
| 93 | - "#include \"arch35/mat_mul_stream_k_kernel.h\"", | ||
| 94 | - "#include \"arch35/mat_mul_v3_full_load_kernel_helper.h\"", | ||
| 95 | - "#include \"arch35/mat_mul_full_load.h\"", | ||
| 96 | - "#include \"arch35/mm_extension_interface/mm_copy_cube_out.h\"", | ||
| 97 | - "#include \"arch35/mm_extension_interface/mm_custom_mm_policy.h\"", | ||
| 98 | - "#include \"arch35/mat_mul_fixpipe_opti.h\"", | ||
| 99 | - "#include \"arch35/block_scheduler_aswt.h\"", | ||
| 100 | - "#include \"arch35/block_scheduler_streamk.h\"", | ||
| 101 | - "#include \"arch35/mat_mul_streamk_basic_cmct.h\"", | ||
| 102 | - "#include \"arch35/mat_mul_fixpipe_opti_basic_cmct.h\"", | ||
| 103 | - "#include \"arch35/mat_mul_input_k_eq_zero_clear_output.h\""}; | ||
| 104 | - | ||
| 105 | - for (const auto &header : expected_headers) { | ||
| 106 | - EXPECT_NE(RemoveSubDirInclude(result.kernel).find(header), std::string::npos) | ||
| 107 | - << "Expected header not found in kernel: " << header; | ||
| 108 | - } | ||
| 109 | - | ||
| 110 | kernel_src_file_name = "matmul_elemwise_brc_test_kernel_common.cpp"; // matmul_elemwise_brc_test_kernel_common.cpp | 134 | kernel_src_file_name = "matmul_elemwise_brc_test_kernel_common.cpp"; // matmul_elemwise_brc_test_kernel_common.cpp |
| 111 | tiling_src_file_name = "matmul_elemwise_brc_test_tiling_common.cpp"; // matmul_elemwise_brc_test_tiling_common.cpp | 135 | tiling_src_file_name = "matmul_elemwise_brc_test_tiling_common.cpp"; // matmul_elemwise_brc_test_tiling_common.cpp |
| 112 | tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h | 136 | tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h |
| @@ -115,18 +139,88 @@ TEST_F(TestBackendMatmulEleBrc, MatmulEleBrcCodegen) { | |||
| 115 | std::fstream tiling_data_file_common(tiling_data_src_file_name, std::ios::out); | 139 | std::fstream tiling_data_file_common(tiling_data_src_file_name, std::ios::out); |
| 116 | codegen::CodegenResult result_common; | 140 | codegen::CodegenResult result_common; |
| 117 | EXPECT_EQ(codegen.Generate(shape_info, common_schedule_result, result_common), 0); | 141 | EXPECT_EQ(codegen.Generate(shape_info, common_schedule_result, result_common), 0); |
| 118 | - kernel_file_common << RemoveSubDirInclude(result_common.kernel); | 142 | + const std::string common_kernel = RemoveSubDirInclude(result_common.kernel); |
| 143 | + EXPECT_FALSE(common_kernel.empty()); | ||
| 144 | + EXPECT_FALSE(result_common.tiling.empty()); | ||
| 145 | + EXPECT_FALSE(result_common.tiling_data.empty()); | ||
| 146 | + kernel_file_common << common_kernel; | ||
| 119 | tiling_file_common << result_common.tiling; | 147 | tiling_file_common << result_common.tiling; |
| 120 | tiling_data_file_common << result_common.tiling_data; | 148 | tiling_data_file_common << result_common.tiling_data; |
| 121 | - | ||
| 122 | - // 校验result_common.kernel中是否包含IncludeMatmulHeadFiles方法返回的所有头文件内容 | ||
| 123 | - for (const auto &header : expected_headers) { | ||
| 124 | - EXPECT_NE(RemoveSubDirInclude(result_common.kernel).find(header), std::string::npos) | ||
| 125 | - << "Expected header not found in common kernel: " << header; | ||
| 126 | - } | ||
| 127 | } catch (...) { | 149 | } catch (...) { |
| 128 | gen_success = false; | 150 | gen_success = false; |
| 129 | } | 151 | } |
| 130 | 152 | ||
| 131 | EXPECT_EQ(gen_success, true); | 153 | EXPECT_EQ(gen_success, true); |
| 132 | } | 154 | } |
| 155 | + | ||
| 156 | +TEST_F(TestBackendMatmulEleBrc, MatmulToIntCastCvCodegen) { | ||
| 157 | + auto graph = ascir::ShareGraph::LoadMatmulToIntCastFusedGraph(); | ||
| 158 | + GenerateCvBackendUbKernelWithCheck( | ||
| 159 | + graph, "matmul_to_int_cast_test_kernel_ub.cpp", "matmul_to_int_cast_test_tiling_ub.cpp", "autofuse_tiling_data.h", | ||
| 160 | + [](const std::string &kernel) { | ||
| 161 | + EXPECT_NE(kernel.find("AscendC::Cast(local_5[0], local_4[0], AscendC::RoundMode::CAST_RINT, " | ||
| 162 | + "{ConvertToUint32(curAivM), ConvertToUint32(curAivN)}, " | ||
| 163 | + "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)}, " | ||
| 164 | + "{ConvertToUint32(curAlignN), ConvertToUint32(1)});"), | ||
| 165 | + std::string::npos); | ||
| 166 | + EXPECT_NE(kernel.find("CastExtend(local_6[0], local_5[0], " | ||
| 167 | + "{ConvertToUint32(curAivM), ConvertToUint32(curAivN)}, " | ||
| 168 | + "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)}, " | ||
| 169 | + "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)});"), | ||
| 170 | + std::string::npos); | ||
| 171 | + EXPECT_NE(kernel.find("AscendC::Cast(local_7[0], local_6[0], AscendC::RoundMode::CAST_TRUNC, " | ||
| 172 | + "{ConvertToUint32(curAivM), ConvertToUint32(curAivN)}, " | ||
| 173 | + "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)}, " | ||
| 174 | + "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)});"), | ||
| 175 | + std::string::npos); | ||
| 176 | + EXPECT_NE(kernel.find("AscendC::Cast(local_9[0], local_8[0], AscendC::RoundMode::CAST_FLOOR, " | ||
| 177 | + "{ConvertToUint32(curAivM), ConvertToUint32(curAivN)}, " | ||
| 178 | + "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)}, " | ||
| 179 | + "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)});"), | ||
| 180 | + std::string::npos); | ||
| 181 | + EXPECT_NE(kernel.find("KernelUtils::BlkAlign<int32_t>(curAivN)"), std::string::npos); | ||
| 182 | + }); | ||
| 183 | +} | ||
| 184 | + | ||
| 185 | +TEST_F(TestBackendMatmulEleBrc, CvFusionDataCopyParamsUseDtypeAlignedFallback) { | ||
| 186 | + codegen::Tiler tiler; | ||
| 187 | + const CvFusionDataCopyTensors tensors = MakeCvFusionDataCopyTensors(); | ||
| 188 | + std::string dtype_name = "half"; | ||
| 189 | + | ||
| 190 | + codegen::ApiCallContext normal_context; | ||
| 191 | + EXPECT_EQ(codegen::GetCvInputAlignedSize(normal_context, tensors.gm, "curAivN"), "curAivN"); | ||
| 192 | + codegen::ApiCallContext cv_context; | ||
| 193 | + cv_context.stage = codegen::ComputeStage::kCVFuseStage1; | ||
| 194 | + EXPECT_EQ(codegen::GetCvInputAlignedSize(cv_context, tensors.gm, "curAivN"), "((curAivN + 16 - 1) / 16 * 16)"); | ||
| 195 | + | ||
| 196 | + codegen::TPipe ub_fuse_tpipe("tpipe", tiler); | ||
| 197 | + ub_fuse_tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse; | ||
| 198 | + codegen::CodegenApiParam ub_fuse_api_param; | ||
| 199 | + codegen::DmaSpecificParams ub_fuse_dma_params; | ||
| 200 | + codegen::BuildDataCopyApiParamInCVFusion(ub_fuse_tpipe, ub_fuse_api_param, ub_fuse_dma_params, tensors.gm, tensors.ub, | ||
| 201 | + dtype_name, true); | ||
| 202 | + EXPECT_EQ(ub_fuse_api_param.template_params[0], "AscendC::PaddingMode::Normal"); | ||
| 203 | + EXPECT_EQ(ub_fuse_dma_params.data_copy_params.block_count.DebugStr(), "curAivM"); | ||
| 204 | + EXPECT_EQ(ub_fuse_dma_params.data_copy_params.block_len.DebugStr(), "curAivN"); | ||
| 205 | + EXPECT_EQ(ub_fuse_dma_params.data_copy_params.src_stride.DebugStr(), "(shapeN - curAivN)"); | ||
| 206 | + EXPECT_EQ(ub_fuse_dma_params.data_copy_params.dst_stride.DebugStr(), | ||
| 207 | + "(KernelUtils::BlkAlign<half>(curAivN) - curAivN)"); | ||
| 208 | + | ||
| 209 | + codegen::TPipe common_tpipe("tpipe", tiler); | ||
| 210 | + codegen::CodegenApiParam common_api_param; | ||
| 211 | + codegen::DmaSpecificParams common_dma_params; | ||
| 212 | + codegen::BuildDataCopyApiParamInCVFusion(common_tpipe, common_api_param, common_dma_params, tensors.gm, tensors.ub, | ||
| 213 | + dtype_name, true); | ||
| 214 | + EXPECT_EQ(common_dma_params.data_copy_params.block_len.DebugStr(), "load_block_len"); | ||
| 215 | + EXPECT_EQ(common_dma_params.data_copy_params.src_stride.DebugStr(), "load_src_stride"); | ||
| 216 | + EXPECT_EQ(common_dma_params.data_copy_params.dst_stride.DebugStr(), "load_dst_stride"); | ||
| 217 | + ASSERT_EQ(common_api_param.api_post_process.size(), 1U); | ||
| 218 | + EXPECT_NE(common_api_param.api_post_process[0].find("AscendC::GatherMask"), std::string::npos); | ||
| 219 | + EXPECT_NE(common_api_param.api_post_process[0].find("KernelUtils::BlkAlign<half>(curAlignN)"), std::string::npos); | ||
| 220 | + | ||
| 221 | + codegen::CvApi2DParams cv_params; | ||
| 222 | + cv_params.first_dim = "curAivM"; | ||
| 223 | + cv_params.last_dim = "curAivN"; | ||
| 224 | + EXPECT_EQ(codegen::GenCvUint16Dims(cv_params), "{static_cast<uint16_t>(curAivM), static_cast<uint16_t>(curAivN)}"); | ||
| 225 | + EXPECT_EQ(codegen::GenCvUint16Stride("curAlignN"), "{static_cast<uint16_t>(curAlignN), static_cast<uint16_t>(1)}"); | ||
| 226 | +} | ||
Mautofuse/tests/v35/st/backend_e2e_v2/round_to_int_float_to_int32_test/round_to_int_float_to_int32_backend_generate.cpp+6-41
| @@ -8,18 +8,7 @@ | |||
| 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 <fstream> | 11 | +#include "../backend_codegen_common.h" |
| 12 | - | ||
| 13 | - | ||
| 14 | - | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | - | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | - | ||
| 23 | 12 | ||
| 24 | 13 | ||
| 25 | 14 | ||
| @@ -38,7 +27,6 @@ class TestBackendRoundToIntFloatToInt32E2e : public testing::Test { | |||
| 38 | }; | 27 | }; |
| 39 | 28 | ||
| 40 | TEST_F(TestBackendRoundToIntFloatToInt32E2e, RoundToIntFloatToInt32E2eCodegen) { | 29 | TEST_F(TestBackendRoundToIntFloatToInt32E2e, RoundToIntFloatToInt32E2eCodegen) { |
| 41 | - bool gen_success = true; | ||
| 42 | std::string tilig_stub = R"( | 30 | std::string tilig_stub = R"( |
| 43 | 31 | ||
| 44 | 32 | ||
| @@ -47,32 +35,9 @@ TEST_F(TestBackendRoundToIntFloatToInt32E2e, RoundToIntFloatToInt32E2eCodegen) { | |||
| 47 | // shape_info 和 RoundToIntFloatToInt32FusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) | 35 | // shape_info 和 RoundToIntFloatToInt32FusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) |
| 48 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}}); | 36 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}}); |
| 49 | auto graph = ascir::ShareGraph::RoundToIntFloatToInt32FusedGraph(2); | 37 | auto graph = ascir::ShareGraph::RoundToIntFloatToInt32FusedGraph(2); |
| 50 | - std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl; | 38 | + GenerateBackendKernelWithCheck(graph, shape_info, tilig_stub, [](const std::string &kernel) { |
| 51 | - std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':'); | 39 | + EXPECT_NE(kernel.find("AscendC::Cast(local_3[0], local_2[0], AscendC::RoundMode::CAST_RINT, " |
| 52 | - std::string kernel_src_file_name = parts[0]; // round_to_int_float_to_int32_test_tiling.cpp | 40 | + "local_2_actual_size);"), |
| 53 | - std::string tiling_src_file_name = parts[1]; // round_to_int_float_to_int32_test_kernel.cpp | 41 | + std::string::npos); |
| 54 | - std::string tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h | 42 | + }); |
| 55 | - | ||
| 56 | - try { | ||
| 57 | - optimize::Optimizer optimizer(optimize::OptimizerOptions{}); | ||
| 58 | - codegen::Codegen codegen(codegen::CodegenOptions{}); | ||
| 59 | - | ||
| 60 | - std::fstream kernel_file(kernel_src_file_name, std::ios::out); | ||
| 61 | - std::fstream tiling_file(tiling_src_file_name, std::ios::out); | ||
| 62 | - std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out); | ||
| 63 | - | ||
| 64 | - std::vector<::ascir::ScheduledResult> schedule_results; | ||
| 65 | - ascir::FusedScheduledResult fused_schedule_result; | ||
| 66 | - fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results); | ||
| 67 | - EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0); | ||
| 68 | - codegen::CodegenResult result; | ||
| 69 | - EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0); | ||
| 70 | - kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel); | ||
| 71 | - tiling_file << result.tiling; | ||
| 72 | - tiling_data_file << result.tiling_data; | ||
| 73 | - } catch (...) { | ||
| 74 | - gen_success = false; | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | - EXPECT_EQ(gen_success, true); | ||
| 78 | } | 43 | } |
Mautofuse/tests/v35/st/backend_e2e_v2/scalar_cast_add_test/scalar_cast_add_backend_generate.cpp+7-30
| @@ -15,7 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | -#include "backend_common.h" | 18 | +#include "../backend_codegen_common.h" |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| @@ -39,7 +39,6 @@ class TestBackendScalarCastAddE2e : public testing::Test { | |||
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | TEST_F(TestBackendScalarCastAddE2e, ScalarCastAddE2eCodegen) { | 41 | TEST_F(TestBackendScalarCastAddE2e, ScalarCastAddE2eCodegen) { |
| 42 | - bool gen_success = true; | ||
| 43 | std::string tilig_stub = R"( | 42 | std::string tilig_stub = R"( |
| 44 | 43 | ||
| 45 | 44 | ||
| @@ -48,32 +47,10 @@ TEST_F(TestBackendScalarCastAddE2e, ScalarCastAddE2eCodegen) { | |||
| 48 | // shape_info 和 ScalarCastAddFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) | 47 | // shape_info 和 ScalarCastAddFusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) |
| 49 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}}); | 48 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}}); |
| 50 | auto graph = ascir::ShareGraph::ScalarCastAddFusedGraph(3, af::DT_FLOAT16, af::DT_FLOAT); | 49 | auto graph = ascir::ShareGraph::ScalarCastAddFusedGraph(3, af::DT_FLOAT16, af::DT_FLOAT); |
| 51 | - std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl; | 50 | + GenerateBackendKernelWithCheck(graph, shape_info, tilig_stub, [](const std::string &kernel) { |
| 52 | - std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':'); | 51 | + EXPECT_NE(kernel.find("CastExtend(local_3[0], local_blk_tensor_of_scalar_2[0], " |
| 53 | - std::string kernel_src_file_name = parts[0]; // scalar_cast_add_test_tiling.cpp | 52 | + "{ConvertToUint32(local_3_actual_size)}, {ConvertToUint32(1)}, {ConvertToUint32(1)});"), |
| 54 | - std::string tiling_src_file_name = parts[1]; // scalar_cast_add_test_kernel.cpp | 53 | + std::string::npos); |
| 55 | - std::string tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h | 54 | + EXPECT_NE(kernel.find("Add(local_5[0], local_4[0], local_3[0], local_4_actual_size);"), std::string::npos); |
| 56 | - | 55 | + }); |
| 57 | - try { | ||
| 58 | - optimize::Optimizer optimizer(optimize::OptimizerOptions{}); | ||
| 59 | - codegen::Codegen codegen(codegen::CodegenOptions{}); | ||
| 60 | - | ||
| 61 | - std::fstream kernel_file(kernel_src_file_name, std::ios::out); | ||
| 62 | - std::fstream tiling_file(tiling_src_file_name, std::ios::out); | ||
| 63 | - std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out); | ||
| 64 | - | ||
| 65 | - std::vector<::ascir::ScheduledResult> schedule_results; | ||
| 66 | - ascir::FusedScheduledResult fused_schedule_result; | ||
| 67 | - fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results); | ||
| 68 | - EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0); | ||
| 69 | - codegen::CodegenResult result; | ||
| 70 | - EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0); | ||
| 71 | - kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel); | ||
| 72 | - tiling_file << result.tiling; | ||
| 73 | - tiling_data_file << result.tiling_data; | ||
| 74 | - } catch (...) { | ||
| 75 | - gen_success = false; | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - EXPECT_EQ(gen_success, true); | ||
| 79 | } | 56 | } |
Mautofuse/tests/v35/st/backend_e2e_v2/trunc_to_int_bf16_to_int32_test/trunc_to_int_bf16_to_int32_backend_generate.cpp+6-41
| @@ -8,18 +8,7 @@ | |||
| 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 <fstream> | 11 | +#include "../backend_codegen_common.h" |
| 12 | - | ||
| 13 | - | ||
| 14 | - | ||
| 15 | - | ||
| 16 | - | ||
| 17 | - | ||
| 18 | - | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | - | ||
| 23 | 12 | ||
| 24 | 13 | ||
| 25 | 14 | ||
| @@ -38,7 +27,6 @@ class TestBackendTruncToIntBf16ToInt32E2e : public testing::Test { | |||
| 38 | }; | 27 | }; |
| 39 | 28 | ||
| 40 | TEST_F(TestBackendTruncToIntBf16ToInt32E2e, TruncToIntBf16ToInt32E2eCodegen) { | 29 | TEST_F(TestBackendTruncToIntBf16ToInt32E2e, TruncToIntBf16ToInt32E2eCodegen) { |
| 41 | - bool gen_success = true; | ||
| 42 | std::string tilig_stub = R"( | 30 | std::string tilig_stub = R"( |
| 43 | 31 | ||
| 44 | 32 | ||
| @@ -47,32 +35,9 @@ TEST_F(TestBackendTruncToIntBf16ToInt32E2e, TruncToIntBf16ToInt32E2eCodegen) { | |||
| 47 | // shape_info 和 TruncToIntBf16ToInt32FusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) | 35 | // shape_info 和 TruncToIntBf16ToInt32FusedGraph入参dims_size匹配(个数相同,命名规则为s开头、编号从0开始) |
| 48 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}}); | 36 | std::map<std::string, std::string> shape_info({{"s0", "stub_s0"}, {"s1", "stub_s1"}, {"s2", "stub_s2"}}); |
| 49 | auto graph = ascir::ShareGraph::TruncToIntBf16ToInt32FusedGraph(3); | 37 | auto graph = ascir::ShareGraph::TruncToIntBf16ToInt32FusedGraph(3); |
| 50 | - std::cout << "KERNEL_SRC_LIST=" << KERNEL_SRC_LIST << std::endl; | 38 | + GenerateBackendKernelWithCheck(graph, shape_info, tilig_stub, [](const std::string &kernel) { |
| 51 | - std::vector<std::string> parts = splitString(KERNEL_SRC_LIST, ':'); | 39 | + EXPECT_NE(kernel.find("AscendC::Cast(local_3[0], local_2[0], AscendC::RoundMode::CAST_TRUNC, " |
| 52 | - std::string kernel_src_file_name = parts[0]; // trunc_to_int_bf16_to_int32_test_tiling.cpp | 40 | + "local_2_actual_size);"), |
| 53 | - std::string tiling_src_file_name = parts[1]; // trunc_to_int_bf16_to_int32_test_kernel.cpp | 41 | + std::string::npos); |
| 54 | - std::string tiling_data_src_file_name = parts[2]; // autofuse_tiling_data.h | 42 | + }); |
| 55 | - | ||
| 56 | - try { | ||
| 57 | - optimize::Optimizer optimizer(optimize::OptimizerOptions{}); | ||
| 58 | - codegen::Codegen codegen(codegen::CodegenOptions{}); | ||
| 59 | - | ||
| 60 | - std::fstream kernel_file(kernel_src_file_name, std::ios::out); | ||
| 61 | - std::fstream tiling_file(tiling_src_file_name, std::ios::out); | ||
| 62 | - std::fstream tiling_data_file(tiling_data_src_file_name, std::ios::out); | ||
| 63 | - | ||
| 64 | - std::vector<::ascir::ScheduledResult> schedule_results; | ||
| 65 | - ascir::FusedScheduledResult fused_schedule_result; | ||
| 66 | - fused_schedule_result.node_idx_to_scheduled_results.push_back(schedule_results); | ||
| 67 | - EXPECT_EQ(optimizer.Optimize(graph, fused_schedule_result), 0); | ||
| 68 | - codegen::CodegenResult result; | ||
| 69 | - EXPECT_EQ(codegen.Generate(shape_info, fused_schedule_result, result), 0); | ||
| 70 | - kernel_file << tilig_stub << RemoveSubDirInclude(result.kernel); | ||
| 71 | - tiling_file << result.tiling; | ||
| 72 | - tiling_data_file << result.tiling_data; | ||
| 73 | - } catch (...) { | ||
| 74 | - gen_success = false; | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | - EXPECT_EQ(gen_success, true); | ||
| 78 | } | 43 | } |
| @@ -147,12 +147,66 @@ TEST(CodegenKernel, NddmaApiCall_CvInductorUsesUbAxisStrides) { | |||
| 147 | std::string result; | 147 | std::string result; |
| 148 | call_0.Generate(tpipe, vector<af::AxisId>{}, result); | 148 | call_0.Generate(tpipe, vector<af::AxisId>{}, result); |
| 149 | EXPECT_EQ(result, | 149 | EXPECT_EQ(result, |
| 150 | - std::string{"const int64_t output_dims_0[2] = {curAivM, curAlignN};\nconst int64_t input_stride_0[2] = " | 150 | + std::string{"const int64_t output_dims_0[2] = {curAivM, curAivN};\nconst int64_t input_stride_0[2] = " |
| 151 | - "{1, 0};\nconst int64_t output_stride_0[2] = {curAlignN, 1};\n" | 151 | + "{1, 0};\nconst int64_t output_stride_0[2] = {KernelUtils::BlkAlign<float>(curAivN), " |
| 152 | + "1};\n" | ||
| 152 | "DataCopyNddma(local_0, local_0[offset / shapeN], output_dims_0, output_stride_0, " | 153 | "DataCopyNddma(local_0, local_0[offset / shapeN], output_dims_0, output_stride_0, " |
| 153 | "input_stride_0);\n"}); | 154 | "input_stride_0);\n"}); |
| 154 | } | 155 | } |
| 155 | 156 | ||
| 157 | +TEST(CodegenKernel, NddmaApiCall_CvUbFuseUsesDtypeAlignedUbStrides) { | ||
| 158 | + af::AscGraph graph("test_graph"); | ||
| 159 | + | ||
| 160 | + auto m = af::Symbol(16); | ||
| 161 | + auto n = af::Symbol(32); | ||
| 162 | + auto z_m = graph.CreateAxis("z_m", m); | ||
| 163 | + auto z_n = graph.CreateAxis("z_n", n); | ||
| 164 | + | ||
| 165 | + Data data0("data0", graph); | ||
| 166 | + Nddma nddma_op("nddma"); | ||
| 167 | + graph.AddNode(nddma_op); | ||
| 168 | + nddma_op.x = data0.y; | ||
| 169 | + nddma_op.attr.sched.axis = {z_m.id, z_n.id}; | ||
| 170 | + *nddma_op.y.axis = {z_m.id, z_n.id}; | ||
| 171 | + *nddma_op.y.repeats = {m, n}; | ||
| 172 | + *nddma_op.y.strides = {One, One}; | ||
| 173 | + | ||
| 174 | + auto nddma = graph.FindNode("nddma"); | ||
| 175 | + nddma->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 176 | + nddma->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 177 | + nddma->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 178 | + nddma->outputs[0].attr.vectorized_axis = {z_m.id, z_n.id}; | ||
| 179 | + nddma->outputs[0].attr.vectorized_strides = {One, One}; | ||
| 180 | + nddma->outputs[0].attr.dtype = ge::DT_FLOAT16; | ||
| 181 | + nddma->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 182 | + nddma->outputs[0].attr.mem.tensor_id = 0; | ||
| 183 | + nddma->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 184 | + nddma->outputs[0].attr.que.id = 1; | ||
| 185 | + nddma->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 186 | + | ||
| 187 | + codegen::Tiler tiler; | ||
| 188 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 189 | + tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse; | ||
| 190 | + tpipe.is_inductor = false; | ||
| 191 | + tpipe.AddTensor(nddma->outputs[0]); | ||
| 192 | + | ||
| 193 | + codegen::ApiTensor x; | ||
| 194 | + x.id = nddma->outputs[0].attr.mem.tensor_id; | ||
| 195 | + | ||
| 196 | + codegen::NddmaApiCall call_0("DataCopyNddma"); | ||
| 197 | + EXPECT_EQ(call_0.Init(nddma), 0); | ||
| 198 | + call_0.inputs.push_back(&x); | ||
| 199 | + | ||
| 200 | + std::string result; | ||
| 201 | + call_0.Generate(tpipe, vector<af::AxisId>{}, result); | ||
| 202 | + EXPECT_EQ(result, | ||
| 203 | + std::string{"const int64_t output_dims_0[2] = {curAivM, curAivN};\nconst int64_t input_stride_0[2] = " | ||
| 204 | + "{shapeN, 1};\nconst int64_t output_stride_0[2] = {KernelUtils::BlkAlign<half>(curAivN), " | ||
| 205 | + "1};\n" | ||
| 206 | + "DataCopyNddma(local_0, local_0[offset], output_dims_0, " | ||
| 207 | + "output_stride_0, input_stride_0);\n"}); | ||
| 208 | +} | ||
| 209 | + | ||
| 156 | TEST(CodegenKernel, NddmaApiCall_SevenDimTensor) { | 210 | TEST(CodegenKernel, NddmaApiCall_SevenDimTensor) { |
| 157 | af::AscGraph graph("test_graph"); | 211 | af::AscGraph graph("test_graph"); |
| 158 | 212 | ||
| @@ -22,12 +22,124 @@ | |||
| 22 | 22 | ||
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 25 | 28 | ||
| 26 | using namespace ge; | 29 | using namespace ge; |
| 27 | using namespace af::ops; | 30 | using namespace af::ops; |
| 28 | using namespace af::ascir_op; | 31 | using namespace af::ascir_op; |
| 29 | using namespace codegen; | 32 | using namespace codegen; |
| 30 | 33 | ||
| 34 | +namespace { | ||
| 35 | +template <typename OpT, typename ApiCallT> | ||
| 36 | +void BuildToIntCvStageGraph(af::AscGraph &graph, const std::string &api_name, const af::Expression &s0, | ||
| 37 | + const af::Expression &s1, const af::Axis &z0, const af::Axis &z1) { | ||
| 38 | + Data x_op("x", graph); | ||
| 39 | + Load load_op("load"); | ||
| 40 | + OpT to_int_op(api_name.c_str()); | ||
| 41 | + graph.AddNode(load_op); | ||
| 42 | + graph.AddNode(to_int_op); | ||
| 43 | + | ||
| 44 | + load_op.x = x_op.y; | ||
| 45 | + load_op.attr.sched.axis = {z0.id, z1.id}; | ||
| 46 | + *load_op.y.axis = {z0.id, z1.id}; | ||
| 47 | + *load_op.y.repeats = {s0, s1}; | ||
| 48 | + *load_op.y.strides = {s1, One}; | ||
| 49 | + to_int_op.x = load_op.y; | ||
| 50 | + *to_int_op.y.axis = {z0.id, z1.id}; | ||
| 51 | + *to_int_op.y.repeats = {s0, s1}; | ||
| 52 | + *to_int_op.y.strides = {s1, One}; | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +void InitToIntCvStageAttrs(af::AscGraph &graph, const std::string &api_name, const af::Expression &s1, | ||
| 56 | + const af::Axis &z0, const af::Axis &z1) { | ||
| 57 | + auto load = graph.FindNode("load"); | ||
| 58 | + load->outputs[0].attr.vectorized_axis = {z0.id, z1.id}; | ||
| 59 | + load->outputs[0].attr.vectorized_strides = {s1, One}; | ||
| 60 | + load->outputs[0].attr.dtype = af::DT_FLOAT16; | ||
| 61 | + load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 62 | + load->outputs[0].attr.mem.tensor_id = 0; | ||
| 63 | + load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 64 | + load->outputs[0].attr.que.id = 1; | ||
| 65 | + load->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 66 | + | ||
| 67 | + auto to_int = graph.FindNode(api_name.c_str()); | ||
| 68 | + to_int->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 69 | + to_int->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 70 | + to_int->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 71 | + to_int->attr.sched.loop_axis = z0.id; | ||
| 72 | + to_int->outputs[0].attr.vectorized_axis = {z0.id, z1.id}; | ||
| 73 | + to_int->outputs[0].attr.vectorized_strides = {s1, One}; | ||
| 74 | + to_int->outputs[0].attr.dtype = af::DT_INT32; | ||
| 75 | + to_int->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 76 | + to_int->outputs[0].attr.mem.tensor_id = 1; | ||
| 77 | + to_int->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 78 | + to_int->outputs[0].attr.que.id = 2; | ||
| 79 | + to_int->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +void InitToIntCvStageTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscNodePtr &load, | ||
| 83 | + const af::AscNodePtr &to_int, const af::Expression &s0, const af::Expression &s1, | ||
| 84 | + const af::Axis &z0, const af::Axis &z1) { | ||
| 85 | + tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse; | ||
| 86 | + tpipe.is_inductor = false; | ||
| 87 | + tpipe.AddTensor(load->outputs[0]); | ||
| 88 | + tpipe.AddTensor(to_int->outputs[0]); | ||
| 89 | + | ||
| 90 | + tiler.AddAxis(z0); | ||
| 91 | + tiler.AddAxis(z1); | ||
| 92 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 93 | + tiler.AddSizeVar(af::SizeVar(s1)); | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +template <typename OpT, typename ApiCallT> | ||
| 97 | +void ExpectToIntCvStageUsesDtypeAwareStrides(const std::string &api_name, const std::string &round_mode) { | ||
| 98 | + af::AscGraph graph("test_graph"); | ||
| 99 | + | ||
| 100 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 101 | + auto s1 = graph.CreateSizeVar("s1"); | ||
| 102 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 103 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 104 | + BuildToIntCvStageGraph<OpT, ApiCallT>(graph, api_name, s0, s1, z0, z1); | ||
| 105 | + InitToIntCvStageAttrs(graph, api_name, s1, z0, z1); | ||
| 106 | + | ||
| 107 | + auto load = graph.FindNode("load"); | ||
| 108 | + auto to_int = graph.FindNode(api_name.c_str()); | ||
| 109 | + codegen::Tiler tiler; | ||
| 110 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 111 | + InitToIntCvStageTpipe(tpipe, tiler, load, to_int, s0, s1, z0, z1); | ||
| 112 | + | ||
| 113 | + codegen::ApiTensor x1; | ||
| 114 | + x1.id = load->outputs[0].attr.mem.tensor_id; | ||
| 115 | + ApiCallT call(api_name); | ||
| 116 | + EXPECT_EQ(call.Init(to_int), 0); | ||
| 117 | + call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1; | ||
| 118 | + call.inputs.push_back(&x1); | ||
| 119 | + | ||
| 120 | + std::string result; | ||
| 121 | + EXPECT_EQ(call.Generate(tpipe, std::vector<af::AxisId>{z0.id}, result), 0); | ||
| 122 | + EXPECT_EQ(result, "AscendC::Cast(local_1[0], local_0[0], " + round_mode + | ||
| 123 | + ", {ConvertToUint32(curAivM), ConvertToUint32(curAivN)}, " | ||
| 124 | + "{ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), ConvertToUint32(1)}, " | ||
| 125 | + "{ConvertToUint32(((curAivN + 16 - 1) / 16 * 16)), ConvertToUint32(1)});\n"); | ||
| 126 | +} | ||
| 127 | +} // namespace | ||
| 128 | + | ||
| 129 | +TEST(ToIntApiCallTest, RoundToIntCvStageUsesDtypeAwareStrides) { | ||
| 130 | + ExpectToIntCvStageUsesDtypeAwareStrides<RoundToInt, RoundToIntApiCall>("RoundToInt", "AscendC::RoundMode::CAST_RINT"); | ||
| 131 | +} | ||
| 132 | + | ||
| 133 | +TEST(ToIntApiCallTest, TruncToIntCvStageUsesDtypeAwareStrides) { | ||
| 134 | + ExpectToIntCvStageUsesDtypeAwareStrides<TruncToInt, TruncToIntApiCall>("TruncToInt", | ||
| 135 | + "AscendC::RoundMode::CAST_TRUNC"); | ||
| 136 | +} | ||
| 137 | + | ||
| 138 | +TEST(ToIntApiCallTest, FloorToIntCvStageUsesDtypeAwareStrides) { | ||
| 139 | + ExpectToIntCvStageUsesDtypeAwareStrides<FloorToInt, FloorToIntApiCall>("FloorToInt", | ||
| 140 | + "AscendC::RoundMode::CAST_FLOOR"); | ||
| 141 | +} | ||
| 142 | + | ||
| 31 | TEST(CastV2ApiCallTest, CastV2ApiCall_Zero_Stride) { | 143 | TEST(CastV2ApiCallTest, CastV2ApiCall_Zero_Stride) { |
| 32 | af::AscGraph graph("test_graph"); | 144 | af::AscGraph graph("test_graph"); |
| 33 | 145 | ||
| @@ -122,6 +234,11 @@ TEST(CastV2ApiCallTest, CastV2ApiCall_Zero_Stride) { | |||
| 122 | EXPECT_STREQ(cast_params->input_strides[0].Serialize().get(), "1"); | 234 | EXPECT_STREQ(cast_params->input_strides[0].Serialize().get(), "1"); |
| 123 | } | 235 | } |
| 124 | 236 | ||
| 237 | +namespace { | ||
| 238 | +void BuildCastCvUbFuseGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, const af::Axis &z0, | ||
| 239 | + const af::Axis &z1, const af::Expression &output_stride0); | ||
| 240 | +} // namespace | ||
| 241 | + | ||
| 125 | TEST(CastV2ApiCallTest, CastV2ApiCallTwoDimension) { | 242 | TEST(CastV2ApiCallTest, CastV2ApiCallTwoDimension) { |
| 126 | af::AscGraph graph("test_graph"); | 243 | af::AscGraph graph("test_graph"); |
| 127 | 244 | ||
| @@ -129,22 +246,7 @@ TEST(CastV2ApiCallTest, CastV2ApiCallTwoDimension) { | |||
| 129 | auto s1 = graph.CreateSizeVar("s1"); | 246 | auto s1 = graph.CreateSizeVar("s1"); |
| 130 | auto z0 = graph.CreateAxis("z0", s0); | 247 | auto z0 = graph.CreateAxis("z0", s0); |
| 131 | auto z1 = graph.CreateAxis("z1", s1); | 248 | auto z1 = graph.CreateAxis("z1", s1); |
| 132 | - | 249 | + BuildCastCvUbFuseGraph(graph, s0, s1, z0, z1, s1 + s1); |
| 133 | - Data x_op("x", graph); | ||
| 134 | - Load load_op("load"); | ||
| 135 | - af::ascir_op::Cast cast_op("cast"); | ||
| 136 | - graph.AddNode(load_op); | ||
| 137 | - graph.AddNode(cast_op); | ||
| 138 | - | ||
| 139 | - load_op.x = x_op.y; | ||
| 140 | - load_op.attr.sched.axis = {z0.id, z1.id}; | ||
| 141 | - *load_op.y.axis = {z0.id, z1.id}; | ||
| 142 | - *load_op.y.repeats = {s0, s1}; | ||
| 143 | - *load_op.y.strides = {s1, One}; | ||
| 144 | - cast_op.x = load_op.y; | ||
| 145 | - *cast_op.y.axis = {z0.id, z1.id}; | ||
| 146 | - *cast_op.y.repeats = {s0, s1}; | ||
| 147 | - *cast_op.y.strides = {s1 + s1, One}; | ||
| 148 | 250 | ||
| 149 | auto load = graph.FindNode("load"); | 251 | auto load = graph.FindNode("load"); |
| 150 | auto size = af::GetSizeByDataType(af::DT_FLOAT16); | 252 | auto size = af::GetSizeByDataType(af::DT_FLOAT16); |
| @@ -219,6 +321,100 @@ TEST(CastV2ApiCallTest, CastV2ApiCallTwoDimension) { | |||
| 219 | EXPECT_STREQ(cast_params->input_strides[1].Serialize().get(), "1"); | 321 | EXPECT_STREQ(cast_params->input_strides[1].Serialize().get(), "1"); |
| 220 | } | 322 | } |
| 221 | 323 | ||
| 324 | +namespace { | ||
| 325 | +void BuildCastCvUbFuseGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, const af::Axis &z0, | ||
| 326 | + const af::Axis &z1, const af::Expression &output_stride0) { | ||
| 327 | + Data x_op("x", graph); | ||
| 328 | + Load load_op("load"); | ||
| 329 | + af::ascir_op::Cast cast_op("cast"); | ||
| 330 | + graph.AddNode(load_op); | ||
| 331 | + graph.AddNode(cast_op); | ||
| 332 | + | ||
| 333 | + load_op.x = x_op.y; | ||
| 334 | + load_op.attr.sched.axis = {z0.id, z1.id}; | ||
| 335 | + *load_op.y.axis = {z0.id, z1.id}; | ||
| 336 | + *load_op.y.repeats = {s0, s1}; | ||
| 337 | + *load_op.y.strides = {s1, One}; | ||
| 338 | + cast_op.x = load_op.y; | ||
| 339 | + *cast_op.y.axis = {z0.id, z1.id}; | ||
| 340 | + *cast_op.y.repeats = {s0, s1}; | ||
| 341 | + *cast_op.y.strides = {output_stride0, One}; | ||
| 342 | +} | ||
| 343 | + | ||
| 344 | +void InitCastCvUbFuseAttrs(af::AscGraph &graph, const af::Expression &s1, const af::Axis &z0, const af::Axis &z1) { | ||
| 345 | + auto load = graph.FindNode("load"); | ||
| 346 | + load->outputs[0].attr.vectorized_axis = {z0.id, z1.id}; | ||
| 347 | + load->outputs[0].attr.vectorized_strides = {s1, One}; | ||
| 348 | + load->outputs[0].attr.dtype = af::DT_FLOAT16; | ||
| 349 | + load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 350 | + load->outputs[0].attr.mem.tensor_id = 0; | ||
| 351 | + load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 352 | + load->outputs[0].attr.que.id = 1; | ||
| 353 | + load->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 354 | + | ||
| 355 | + auto cast = graph.FindNode("cast"); | ||
| 356 | + cast->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 357 | + cast->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 358 | + cast->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 359 | + cast->attr.sched.loop_axis = z0.id; | ||
| 360 | + cast->outputs[0].attr.vectorized_axis = {z0.id, z1.id}; | ||
| 361 | + cast->outputs[0].attr.vectorized_strides = {s1, One}; | ||
| 362 | + cast->outputs[0].attr.dtype = af::DT_FLOAT; | ||
| 363 | + cast->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 364 | + cast->outputs[0].attr.mem.tensor_id = 1; | ||
| 365 | + cast->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 366 | + cast->outputs[0].attr.que.id = 2; | ||
| 367 | + cast->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 368 | +} | ||
| 369 | + | ||
| 370 | +void InitCastCvUbFuseTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscNodePtr &load, | ||
| 371 | + const af::AscNodePtr &cast, const af::Expression &s0, const af::Expression &s1, | ||
| 372 | + const af::Axis &z0, const af::Axis &z1) { | ||
| 373 | + tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse; | ||
| 374 | + tpipe.is_inductor = false; | ||
| 375 | + tpipe.AddTensor(load->outputs[0]); | ||
| 376 | + tpipe.AddTensor(cast->outputs[0]); | ||
| 377 | + | ||
| 378 | + tiler.AddAxis(z0); | ||
| 379 | + tiler.AddAxis(z1); | ||
| 380 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 381 | + tiler.AddSizeVar(af::SizeVar(s1)); | ||
| 382 | +} | ||
| 383 | +} // namespace | ||
| 384 | + | ||
| 385 | +TEST(CastV2ApiCallTest, CastV2ApiCallCvUbFuseUsesDtypeAlignedStrides) { | ||
| 386 | + af::AscGraph graph("test_graph"); | ||
| 387 | + | ||
| 388 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 389 | + auto s1 = graph.CreateSizeVar("s1"); | ||
| 390 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 391 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 392 | + BuildCastCvUbFuseGraph(graph, s0, s1, z0, z1, s1); | ||
| 393 | + InitCastCvUbFuseAttrs(graph, s1, z0, z1); | ||
| 394 | + | ||
| 395 | + auto load = graph.FindNode("load"); | ||
| 396 | + auto cast = graph.FindNode("cast"); | ||
| 397 | + | ||
| 398 | + codegen::Tiler tiler; | ||
| 399 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 400 | + InitCastCvUbFuseTpipe(tpipe, tiler, load, cast, s0, s1, z0, z1); | ||
| 401 | + | ||
| 402 | + codegen::ApiTensor x1; | ||
| 403 | + x1.id = load->outputs[0].attr.mem.tensor_id; | ||
| 404 | + codegen::CastV2ApiCall call("CastExtend"); | ||
| 405 | + EXPECT_EQ(call.Init(cast), 0); | ||
| 406 | + call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1; | ||
| 407 | + call.inputs.push_back(&x1); | ||
| 408 | + | ||
| 409 | + std::string result; | ||
| 410 | + call.Generate(tpipe, std::vector<af::AxisId>{z0.id}, result); | ||
| 411 | + EXPECT_EQ(result, std::string{"local_1_actual_size = curAivM * curAivN;\n" | ||
| 412 | + "CastExtend(local_1[0], local_0[0], {ConvertToUint32(curAivM), " | ||
| 413 | + "ConvertToUint32(curAivN)}, {ConvertToUint32(((curAivN + 8 - 1) / 8 * 8)), " | ||
| 414 | + "ConvertToUint32(1)}, {ConvertToUint32(((curAivN + 16 - 1) / 16 * 16)), " | ||
| 415 | + "ConvertToUint32(1)});\n"}); | ||
| 416 | +} | ||
| 417 | + | ||
| 222 | TEST(CastV2ApiCallTest, CastV2ApiCallThreeDimension) { | 418 | TEST(CastV2ApiCallTest, CastV2ApiCallThreeDimension) { |
| 223 | af::AscGraph graph("test_graph"); | 419 | af::AscGraph graph("test_graph"); |
| 224 | 420 | ||
| @@ -171,6 +171,14 @@ TEST(CompareV2ApiCallTest, BoolDtypeNameIsBool) { | |||
| 171 | EXPECT_EQ(dtype_name, "bool"); | 171 | EXPECT_EQ(dtype_name, "bool"); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | +namespace { | ||
| 175 | +void BuildCompareScalarCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, | ||
| 176 | + const af::Expression &s2, const af::Axis &z0, const af::Axis &z1, | ||
| 177 | + const af::Axis &z2); | ||
| 178 | +void InitCompareScalarCvStageAttrs(af::AscGraph &graph, const af::Expression &s2, const af::Axis &z0, | ||
| 179 | + const af::Axis &z1, const af::Axis &z2); | ||
| 180 | +} // namespace | ||
| 181 | + | ||
| 174 | TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar) { | 182 | TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar) { |
| 175 | af::AscGraph graph("test_graph"); | 183 | af::AscGraph graph("test_graph"); |
| 176 | auto s0 = graph.CreateSizeVar("s0"); | 184 | auto s0 = graph.CreateSizeVar("s0"); |
| @@ -179,62 +187,12 @@ TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar) { | |||
| 179 | auto z0 = graph.CreateAxis("z0", s0); | 187 | auto z0 = graph.CreateAxis("z0", s0); |
| 180 | auto z1 = graph.CreateAxis("z1", s1); | 188 | auto z1 = graph.CreateAxis("z1", s1); |
| 181 | auto z2 = graph.CreateAxis("z2", s2); | 189 | auto z2 = graph.CreateAxis("z2", s2); |
| 182 | - | 190 | + BuildCompareScalarCvStageGraph(graph, s0, s1, s2, z0, z1, z2); |
| 183 | - Data x_op1("x1", graph); | 191 | + InitCompareScalarCvStageAttrs(graph, s2, z0, z1, z2); |
| 184 | - Scalar constant_op("constant"); | ||
| 185 | - constant_op.ir_attr.SetValue("1.0"); | ||
| 186 | - Load load_op1("load1"); | ||
| 187 | - af::ascir_op::Ge ge_op("ge"); | ||
| 188 | - graph.AddNode(load_op1); | ||
| 189 | - graph.AddNode(constant_op); | ||
| 190 | - graph.AddNode(ge_op); | ||
| 191 | - | ||
| 192 | - load_op1.x = x_op1.y; | ||
| 193 | - load_op1.attr.sched.axis = {z0.id, z1.id, z2.id}; | ||
| 194 | - *load_op1.y.axis = {z0.id, z1.id, z2.id}; | ||
| 195 | - *load_op1.y.repeats = {s0, s1, s2}; | ||
| 196 | - *load_op1.y.strides = {s1 * s2, s2, One}; | ||
| 197 | - | ||
| 198 | - ge_op.x1 = load_op1.y; | ||
| 199 | - ge_op.x2 = constant_op.y; | ||
| 200 | - *ge_op.y.axis = {z0.id, z1.id, z2.id}; | ||
| 201 | - *ge_op.y.repeats = {s0, s1, s2}; | ||
| 202 | - *ge_op.y.strides = {s1 * s2, s2, One}; | ||
| 203 | 192 | ||
| 204 | auto load1 = graph.FindNode("load1"); | 193 | auto load1 = graph.FindNode("load1"); |
| 205 | - load1->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 206 | - load1->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 207 | - load1->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 208 | - load1->attr.sched.loop_axis = z0.id; | ||
| 209 | - load1->outputs[0].attr.vectorized_axis = {z1.id, z2.id}; | ||
| 210 | - load1->outputs[0].attr.vectorized_strides = {s2, One}; | ||
| 211 | - load1->outputs[0].attr.dtype = af::DT_FLOAT; | ||
| 212 | - load1->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 213 | - load1->outputs[0].attr.mem.tensor_id = 0; | ||
| 214 | - load1->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 215 | - load1->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 216 | - load1->outputs[0].attr.que.id = 1; | ||
| 217 | - load1->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 218 | - | ||
| 219 | auto constant_node = graph.FindNode("constant"); | 194 | auto constant_node = graph.FindNode("constant"); |
| 220 | - constant_node->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeInvalid; | ||
| 221 | - constant_node->outputs[0].attr.mem.tensor_id = 1; | ||
| 222 | - constant_node->outputs[0].attr.mem.position = af::Position::kPositionInvalid; | ||
| 223 | - constant_node->outputs[0].attr.dtype = af::DT_FLOAT; | ||
| 224 | - | ||
| 225 | auto ge = graph.FindNode("ge"); | 195 | auto ge = graph.FindNode("ge"); |
| 226 | - ge->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 227 | - ge->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 228 | - ge->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 229 | - ge->attr.sched.loop_axis = z0.id; | ||
| 230 | - ge->outputs[0].attr.vectorized_axis = {z1.id, z2.id}; | ||
| 231 | - ge->outputs[0].attr.vectorized_strides = {s2, One}; | ||
| 232 | - ge->outputs[0].attr.dtype = af::DT_UINT8; | ||
| 233 | - ge->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 234 | - ge->outputs[0].attr.mem.tensor_id = 2; | ||
| 235 | - ge->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 236 | - ge->outputs[0].attr.que.id = 2; | ||
| 237 | - ge->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 238 | 196 | ||
| 239 | codegen::Tiler tiler; | 197 | codegen::Tiler tiler; |
| 240 | codegen::TPipe tpipe("tpipe", tiler); | 198 | codegen::TPipe tpipe("tpipe", tiler); |
| @@ -281,6 +239,134 @@ TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar) { | |||
| 281 | EXPECT_STREQ(compare_params->input_strides[0].Serialize().get(), "1"); | 239 | EXPECT_STREQ(compare_params->input_strides[0].Serialize().get(), "1"); |
| 282 | } | 240 | } |
| 283 | 241 | ||
| 242 | +namespace { | ||
| 243 | +void BuildCompareScalarCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, | ||
| 244 | + const af::Expression &s2, const af::Axis &z0, const af::Axis &z1, | ||
| 245 | + const af::Axis &z2) { | ||
| 246 | + Data x_op1("x1", graph); | ||
| 247 | + Scalar constant_op("constant"); | ||
| 248 | + constant_op.ir_attr.SetValue("1.0"); | ||
| 249 | + Load load_op1("load1"); | ||
| 250 | + af::ascir_op::Ge ge_op("ge"); | ||
| 251 | + graph.AddNode(load_op1); | ||
| 252 | + graph.AddNode(constant_op); | ||
| 253 | + graph.AddNode(ge_op); | ||
| 254 | + | ||
| 255 | + load_op1.x = x_op1.y; | ||
| 256 | + load_op1.attr.sched.axis = {z0.id, z1.id, z2.id}; | ||
| 257 | + *load_op1.y.axis = {z0.id, z1.id, z2.id}; | ||
| 258 | + *load_op1.y.repeats = {s0, s1, s2}; | ||
| 259 | + *load_op1.y.strides = {s1 * s2, s2, One}; | ||
| 260 | + | ||
| 261 | + ge_op.x1 = load_op1.y; | ||
| 262 | + ge_op.x2 = constant_op.y; | ||
| 263 | + *ge_op.y.axis = {z0.id, z1.id, z2.id}; | ||
| 264 | + *ge_op.y.repeats = {s0, s1, s2}; | ||
| 265 | + *ge_op.y.strides = {s1 * s2, s2, One}; | ||
| 266 | +} | ||
| 267 | + | ||
| 268 | +void InitCompareScalarCvStageAttrs(af::AscGraph &graph, const af::Expression &s2, const af::Axis &z0, | ||
| 269 | + const af::Axis &z1, const af::Axis &z2) { | ||
| 270 | + auto load1 = graph.FindNode("load1"); | ||
| 271 | + load1->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 272 | + load1->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 273 | + load1->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 274 | + load1->attr.sched.loop_axis = z0.id; | ||
| 275 | + load1->outputs[0].attr.vectorized_axis = {z1.id, z2.id}; | ||
| 276 | + load1->outputs[0].attr.vectorized_strides = {s2, One}; | ||
| 277 | + load1->outputs[0].attr.dtype = af::DT_FLOAT; | ||
| 278 | + load1->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 279 | + load1->outputs[0].attr.mem.tensor_id = 0; | ||
| 280 | + load1->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 281 | + load1->outputs[0].attr.que.id = 1; | ||
| 282 | + load1->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 283 | + | ||
| 284 | + auto constant_node = graph.FindNode("constant"); | ||
| 285 | + constant_node->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeInvalid; | ||
| 286 | + constant_node->outputs[0].attr.mem.tensor_id = 1; | ||
| 287 | + constant_node->outputs[0].attr.mem.position = af::Position::kPositionInvalid; | ||
| 288 | + constant_node->outputs[0].attr.dtype = af::DT_FLOAT; | ||
| 289 | + | ||
| 290 | + auto ge = graph.FindNode("ge"); | ||
| 291 | + ge->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 292 | + ge->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 293 | + ge->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 294 | + ge->attr.sched.loop_axis = z0.id; | ||
| 295 | + ge->outputs[0].attr.vectorized_axis = {z1.id, z2.id}; | ||
| 296 | + ge->outputs[0].attr.vectorized_strides = {s2, One}; | ||
| 297 | + ge->outputs[0].attr.dtype = af::DT_UINT8; | ||
| 298 | + ge->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 299 | + ge->outputs[0].attr.mem.tensor_id = 2; | ||
| 300 | + ge->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 301 | + ge->outputs[0].attr.que.id = 2; | ||
| 302 | + ge->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 303 | +} | ||
| 304 | + | ||
| 305 | +void InitCompareScalarCvStageTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscGraph &graph, | ||
| 306 | + const af::AscNodePtr &load1, const af::AscNodePtr &constant_node, | ||
| 307 | + const af::AscNodePtr &ge, const af::Expression &s0, const af::Expression &s1, | ||
| 308 | + const af::Expression &s2, const af::Axis &z0, const af::Axis &z1, | ||
| 309 | + const af::Axis &z2) { | ||
| 310 | + tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse; | ||
| 311 | + tpipe.cube_output_tensor_id = load1->outputs[0].attr.mem.tensor_id; | ||
| 312 | + tpipe.is_inductor = false; | ||
| 313 | + tpipe.CollectQues(graph); | ||
| 314 | + tpipe.AddTensor(load1->outputs[0]); | ||
| 315 | + tpipe.AddTensor("1.0", constant_node->outputs[0], "const_y"); | ||
| 316 | + tpipe.AddTensor(ge->outputs[0]); | ||
| 317 | + | ||
| 318 | + tiler.AddAxis(z0); | ||
| 319 | + tiler.AddAxis(z1); | ||
| 320 | + tiler.AddAxis(z2); | ||
| 321 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 322 | + tiler.AddSizeVar(af::SizeVar(s1)); | ||
| 323 | + tiler.AddSizeVar(af::SizeVar(s2)); | ||
| 324 | +} | ||
| 325 | +} // namespace | ||
| 326 | + | ||
| 327 | +TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar_CVStage) { | ||
| 328 | + af::AscGraph graph("test_graph"); | ||
| 329 | + | ||
| 330 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 331 | + auto s1 = graph.CreateSizeVar("s1"); | ||
| 332 | + auto s2 = graph.CreateSizeVar("s2"); | ||
| 333 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 334 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 335 | + auto z2 = graph.CreateAxis("z2", s2); | ||
| 336 | + BuildCompareScalarCvStageGraph(graph, s0, s1, s2, z0, z1, z2); | ||
| 337 | + InitCompareScalarCvStageAttrs(graph, s2, z0, z1, z2); | ||
| 338 | + | ||
| 339 | + auto load1 = graph.FindNode("load1"); | ||
| 340 | + auto constant_node = graph.FindNode("constant"); | ||
| 341 | + auto ge = graph.FindNode("ge"); | ||
| 342 | + | ||
| 343 | + codegen::Tiler tiler; | ||
| 344 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 345 | + InitCompareScalarCvStageTpipe(tpipe, tiler, graph, load1, constant_node, ge, s0, s1, s2, z0, z1, z2); | ||
| 346 | + std::vector<af::AxisId> current_axis; | ||
| 347 | + current_axis.push_back(z0.id); | ||
| 348 | + | ||
| 349 | + codegen::ApiTensor x1; | ||
| 350 | + x1.id = load1->outputs[0].attr.mem.tensor_id; | ||
| 351 | + codegen::ApiTensor x2; | ||
| 352 | + x2.id = constant_node->outputs[0].attr.mem.tensor_id; | ||
| 353 | + | ||
| 354 | + codegen::CompareV2ApiCall call("ge"); | ||
| 355 | + EXPECT_EQ(call.Init(ge), 0); | ||
| 356 | + call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1; | ||
| 357 | + call.inputs.push_back(&x1); | ||
| 358 | + call.inputs.push_back(&x2); | ||
| 359 | + | ||
| 360 | + std::string result; | ||
| 361 | + EXPECT_EQ(call.Generate(tpipe, current_axis, result), 0); | ||
| 362 | + EXPECT_NE(result.find("CompareScalarExtend<float, 2, CMPMODE::ge>(local_2[0], local_0[0], scalar_1,"), | ||
| 363 | + std::string::npos); | ||
| 364 | + EXPECT_NE(result.find("{static_cast<uint16_t>(curAivM), static_cast<uint16_t>(curAivN)}"), std::string::npos); | ||
| 365 | + EXPECT_NE(result.find("{static_cast<uint16_t>(((curAivN + 32 - 1) / 32 * 32)), static_cast<uint16_t>(1)}"), | ||
| 366 | + std::string::npos); | ||
| 367 | + EXPECT_NE(result.find("{static_cast<uint16_t>(curAlignN), static_cast<uint16_t>(1)}"), std::string::npos); | ||
| 368 | +} | ||
| 369 | + | ||
| 284 | TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar_Normal) { | 370 | TEST(CompareV2ApiCallTest, CompareV2ApiCall_Scalar_Normal) { |
| 285 | af::AscGraph graph("test_graph"); | 371 | af::AscGraph graph("test_graph"); |
| 286 | auto s0 = graph.CreateSizeVar("s0"); | 372 | auto s0 = graph.CreateSizeVar("s0"); |
| @@ -508,3 +594,129 @@ TEST(CompareV2ApiCallTest, CompareV2ApiCall_Normal) { | |||
| 508 | "t->s2))))/(1)), static_cast<uint16_t>(1)}, {static_cast<uint16_t>(((8 * Ceiling((Rational(1 , 8) * " | 594 | "t->s2))))/(1)), static_cast<uint16_t>(1)}, {static_cast<uint16_t>(((8 * Ceiling((Rational(1 , 8) * " |
| 509 | "t->s2))))/(1)), static_cast<uint16_t>(1)});\n\n}\n"}); | 595 | "t->s2))))/(1)), static_cast<uint16_t>(1)});\n\n}\n"}); |
| 510 | } | 596 | } |
| 597 | + | ||
| 598 | +namespace { | ||
| 599 | +void BuildCompareNormalCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, | ||
| 600 | + const af::Expression &s2, const af::Axis &z0, const af::Axis &z1, | ||
| 601 | + const af::Axis &z2) { | ||
| 602 | + Data x_op1("x1", graph); | ||
| 603 | + Data x_op2("x2", graph); | ||
| 604 | + Load load_op1("load1"); | ||
| 605 | + Load load_op2("load2"); | ||
| 606 | + af::ascir_op::Ge ge_op("ge"); | ||
| 607 | + graph.AddNode(load_op1); | ||
| 608 | + graph.AddNode(load_op2); | ||
| 609 | + graph.AddNode(ge_op); | ||
| 610 | + | ||
| 611 | + load_op1.x = x_op1.y; | ||
| 612 | + load_op2.x = x_op2.y; | ||
| 613 | + load_op1.attr.sched.axis = {z0.id, z1.id, z2.id}; | ||
| 614 | + load_op2.attr.sched.axis = {z0.id, z1.id, z2.id}; | ||
| 615 | + *load_op1.y.axis = {z0.id, z1.id, z2.id}; | ||
| 616 | + *load_op2.y.axis = {z0.id, z1.id, z2.id}; | ||
| 617 | + *load_op1.y.repeats = {s0, s1, s2}; | ||
| 618 | + *load_op2.y.repeats = {s0, s1, s2}; | ||
| 619 | + *load_op1.y.strides = {s1 * s2, s2, One}; | ||
| 620 | + *load_op2.y.strides = {s1 * s2, s2, One}; | ||
| 621 | + ge_op.x1 = load_op1.y; | ||
| 622 | + ge_op.x2 = load_op2.y; | ||
| 623 | + *ge_op.y.axis = {z0.id, z1.id, z2.id}; | ||
| 624 | + *ge_op.y.repeats = {s0, s1, s2}; | ||
| 625 | + *ge_op.y.strides = {s1 * s2, s2, One}; | ||
| 626 | +} | ||
| 627 | + | ||
| 628 | +void InitCompareNormalCvStageAttrs(af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1, const af::Axis &z2) { | ||
| 629 | + auto input_stride = af::sym::Align(z2.size, 8); | ||
| 630 | + auto output_stride = af::sym::Align(z2.size, 32); | ||
| 631 | + auto load1 = graph.FindNode("load1"); | ||
| 632 | + load1->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 633 | + load1->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 634 | + load1->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 635 | + load1->attr.sched.loop_axis = z0.id; | ||
| 636 | + load1->outputs[0].attr.vectorized_axis = {z0.id, z1.id, z2.id}; | ||
| 637 | + load1->outputs[0].attr.vectorized_strides = {input_stride * z1.size, input_stride, One}; | ||
| 638 | + load1->outputs[0].attr.dtype = af::DT_FLOAT; | ||
| 639 | + load1->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 640 | + load1->outputs[0].attr.mem.tensor_id = 0; | ||
| 641 | + load1->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 642 | + load1->outputs[0].attr.que.id = 1; | ||
| 643 | + load1->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 644 | + | ||
| 645 | + auto load2 = graph.FindNode("load2"); | ||
| 646 | + load2->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 647 | + load2->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 648 | + load2->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 649 | + load2->attr.sched.loop_axis = z0.id; | ||
| 650 | + load2->outputs[0].attr.vectorized_axis = {z0.id, z1.id, z2.id}; | ||
| 651 | + load2->outputs[0].attr.vectorized_strides = {input_stride * z1.size, input_stride, One}; | ||
| 652 | + load2->outputs[0].attr.dtype = af::DT_FLOAT; | ||
| 653 | + load2->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 654 | + load2->outputs[0].attr.mem.tensor_id = 0; | ||
| 655 | + load2->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 656 | + load2->outputs[0].attr.que.id = 1; | ||
| 657 | + load2->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 658 | + | ||
| 659 | + auto ge = graph.FindNode("ge"); | ||
| 660 | + ge->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 661 | + ge->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 662 | + ge->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 663 | + ge->attr.sched.loop_axis = z0.id; | ||
| 664 | + ge->outputs[0].attr.vectorized_axis = {z0.id, z1.id, z2.id}; | ||
| 665 | + ge->outputs[0].attr.vectorized_strides = {output_stride * z1.size, output_stride, One}; | ||
| 666 | + ge->outputs[0].attr.dtype = af::DT_UINT8; | ||
| 667 | + ge->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 668 | + ge->outputs[0].attr.mem.tensor_id = 2; | ||
| 669 | + ge->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 670 | + ge->outputs[0].attr.que.id = 2; | ||
| 671 | + ge->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 672 | +} | ||
| 673 | + | ||
| 674 | +void InitCompareNormalCvStageTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscNodePtr &load1, | ||
| 675 | + const af::AscNodePtr &load2, const af::AscNodePtr &ge, const af::Expression &s0, | ||
| 676 | + const af::Expression &s1, const af::Expression &s2, const af::Axis &z0, | ||
| 677 | + const af::Axis &z1, const af::Axis &z2) { | ||
| 678 | + tpipe.AddTensor(load1->outputs[0]); | ||
| 679 | + tpipe.AddTensor(load2->outputs[0]); | ||
| 680 | + tpipe.AddTensor(ge->outputs[0]); | ||
| 681 | + tiler.AddAxis(z0); | ||
| 682 | + tiler.AddAxis(z1); | ||
| 683 | + tiler.AddAxis(z2); | ||
| 684 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 685 | + tiler.AddSizeVar(af::SizeVar(s1)); | ||
| 686 | + tiler.AddSizeVar(af::SizeVar(s2)); | ||
| 687 | +} | ||
| 688 | +} // namespace | ||
| 689 | + | ||
| 690 | +TEST(CompareV2ApiCallTest, CompareV2ApiCall_Normal_CVStageKeepsLogicalCount) { | ||
| 691 | + af::AscGraph graph("test_graph"); | ||
| 692 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 693 | + auto s1 = graph.CreateSizeVar("s1"); | ||
| 694 | + auto s2 = graph.CreateSizeVar("s2"); | ||
| 695 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 696 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 697 | + auto z2 = graph.CreateAxis("z2", s2); | ||
| 698 | + BuildCompareNormalCvStageGraph(graph, s0, s1, s2, z0, z1, z2); | ||
| 699 | + InitCompareNormalCvStageAttrs(graph, z0, z1, z2); | ||
| 700 | + | ||
| 701 | + auto load1 = graph.FindNode("load1"); | ||
| 702 | + auto load2 = graph.FindNode("load2"); | ||
| 703 | + auto ge = graph.FindNode("ge"); | ||
| 704 | + | ||
| 705 | + codegen::Tiler tiler; | ||
| 706 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 707 | + InitCompareNormalCvStageTpipe(tpipe, tiler, load1, load2, ge, s0, s1, s2, z0, z1, z2); | ||
| 708 | + | ||
| 709 | + codegen::ApiTensor x1, x2; | ||
| 710 | + x1.id = load1->outputs[0].attr.mem.tensor_id; | ||
| 711 | + x2.id = load2->outputs[0].attr.mem.tensor_id; | ||
| 712 | + codegen::CompareV2ApiCall call("ge"); | ||
| 713 | + EXPECT_EQ(call.Init(ge), 0); | ||
| 714 | + call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1; | ||
| 715 | + call.inputs.push_back(&x1); | ||
| 716 | + call.inputs.push_back(&x2); | ||
| 717 | + | ||
| 718 | + std::string result; | ||
| 719 | + EXPECT_EQ(call.Generate(tpipe, {z0.id}, result), 0); | ||
| 720 | + EXPECT_NE(result.find("static_cast<uint16_t>(t->s2)"), std::string::npos); | ||
| 721 | + EXPECT_EQ(result.find("static_cast<uint16_t>(((t->s2 + 32 - 1) / 32 * 32))"), std::string::npos); | ||
| 722 | +} | ||
| @@ -89,6 +89,64 @@ TEST(CodegenKernel, LoadRegApiCall_OneDimLoad) { | |||
| 89 | std::string{"DataCopyPadExtend<float, AscendC::PaddingMode::Normal>(local_0[0], local_0[0 + 0], 1, 8, 0, 0);\n"}); | 89 | std::string{"DataCopyPadExtend<float, AscendC::PaddingMode::Normal>(local_0[0], local_0[0 + 0], 1, 8, 0, 0);\n"}); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | +TEST(CodegenKernel, LoadRegApiCall_CvUbFuseUsesDtypeAwareStrides) { | ||
| 93 | + af::AscGraph graph("test_graph"); | ||
| 94 | + | ||
| 95 | + auto s0 = af::Symbol(16); | ||
| 96 | + auto s1 = af::Symbol(7); | ||
| 97 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 98 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 99 | + | ||
| 100 | + Data x_op("x", graph); | ||
| 101 | + Load load_op("load"); | ||
| 102 | + graph.AddNode(load_op); | ||
| 103 | + | ||
| 104 | + load_op.x = x_op.y; | ||
| 105 | + load_op.attr.sched.axis = {z0.id, z1.id}; | ||
| 106 | + *load_op.y.axis = {z0.id, z1.id}; | ||
| 107 | + *load_op.y.repeats = {s0, s1}; | ||
| 108 | + *load_op.y.strides = {s1, One}; | ||
| 109 | + | ||
| 110 | + auto load = graph.FindNode("load"); | ||
| 111 | + load->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 112 | + load->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 113 | + load->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 114 | + load->attr.sched.loop_axis = z0.id; | ||
| 115 | + load->outputs[0].attr.vectorized_axis = {z0.id, z1.id}; | ||
| 116 | + load->outputs[0].attr.vectorized_strides = {s1, One}; | ||
| 117 | + load->outputs[0].attr.dtype = af::DT_FLOAT16; | ||
| 118 | + load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 119 | + load->outputs[0].attr.mem.tensor_id = 0; | ||
| 120 | + load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 121 | + load->outputs[0].attr.que.id = 1; | ||
| 122 | + load->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 123 | + | ||
| 124 | + codegen::Tiler tiler; | ||
| 125 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 126 | + tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse; | ||
| 127 | + tpipe.AddTensor(load->outputs[0]); | ||
| 128 | + | ||
| 129 | + tiler.AddAxis(z0); | ||
| 130 | + tiler.AddAxis(z1); | ||
| 131 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 132 | + tiler.AddSizeVar(af::SizeVar(s1)); | ||
| 133 | + | ||
| 134 | + codegen::ApiTensor x1; | ||
| 135 | + x1.id = load->outputs[0].attr.mem.tensor_id; | ||
| 136 | + | ||
| 137 | + codegen::LoadRegApiCall call_0("DataCopyPadExtend"); | ||
| 138 | + EXPECT_EQ(call_0.Init(load), 0); | ||
| 139 | + call_0.inputs.push_back(&x1); | ||
| 140 | + | ||
| 141 | + std::string result; | ||
| 142 | + call_0.Generate(tpipe, vector<af::AxisId>{}, result); | ||
| 143 | + EXPECT_NE(result.find("DataCopyPadExtend<half, AscendC::PaddingMode::Normal>("), std::string::npos); | ||
| 144 | + EXPECT_NE(result.find("curAivM"), std::string::npos); | ||
| 145 | + EXPECT_NE(result.find("curAivN"), std::string::npos); | ||
| 146 | + EXPECT_NE(result.find("KernelUtils::BlkAlign<half>(curAivN)"), std::string::npos); | ||
| 147 | + EXPECT_NE(result.find("shapeN - curAivN"), std::string::npos); | ||
| 148 | +} | ||
| 149 | + | ||
| 92 | TEST(CodegenKernel, NormalModeDataCopyIfDualSplitting) { | 150 | TEST(CodegenKernel, NormalModeDataCopyIfDualSplitting) { |
| 93 | af::AscGraph graph("test_graph"); | 151 | af::AscGraph graph("test_graph"); |
| 94 | af::Expression Two = af::Symbol(2); | 152 | af::Expression Two = af::Symbol(2); |
| @@ -25,6 +25,12 @@ using namespace af::ops; | |||
| 25 | using namespace af::ascir_op; | 25 | using namespace af::ascir_op; |
| 26 | using namespace codegen; | 26 | using namespace codegen; |
| 27 | 27 | ||
| 28 | +namespace { | ||
| 29 | +void BuildLogicalNotCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, | ||
| 30 | + const af::Axis &z0, const af::Axis &z1); | ||
| 31 | +void InitLogicalNotCvStageAttrs(af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1); | ||
| 32 | +} // namespace | ||
| 33 | + | ||
| 28 | TEST(CodegenKernel, RegLogicalNotApiCall) { | 34 | TEST(CodegenKernel, RegLogicalNotApiCall) { |
| 29 | af::AscGraph graph("test_graph"); | 35 | af::AscGraph graph("test_graph"); |
| 30 | 36 | ||
| @@ -32,52 +38,11 @@ TEST(CodegenKernel, RegLogicalNotApiCall) { | |||
| 32 | auto s1 = graph.CreateSizeVar("s1"); | 38 | auto s1 = graph.CreateSizeVar("s1"); |
| 33 | auto z0 = graph.CreateAxis("z0", s0); | 39 | auto z0 = graph.CreateAxis("z0", s0); |
| 34 | auto z1 = graph.CreateAxis("z1", s1); | 40 | auto z1 = graph.CreateAxis("z1", s1); |
| 35 | - | 41 | + BuildLogicalNotCvStageGraph(graph, s0, s1, z0, z1); |
| 36 | - Data x_op("x", graph); | 42 | + InitLogicalNotCvStageAttrs(graph, z0, z1); |
| 37 | - Load load_op("load"); | ||
| 38 | - af::ascir_op::LogicalNot logical_not_op("logical_not"); | ||
| 39 | - graph.AddNode(load_op); | ||
| 40 | - graph.AddNode(logical_not_op); | ||
| 41 | - | ||
| 42 | - load_op.x = x_op.y; | ||
| 43 | - load_op.attr.sched.axis = {z0.id, z1.id}; | ||
| 44 | - *load_op.y.axis = {z0.id, z1.id}; | ||
| 45 | - *load_op.y.repeats = {s0, s1}; | ||
| 46 | - *load_op.y.strides = {s1, One}; | ||
| 47 | - logical_not_op.x = load_op.y; | ||
| 48 | - *logical_not_op.y.axis = {z0.id, z1.id}; | ||
| 49 | - *logical_not_op.y.repeats = {s0, s1}; | ||
| 50 | - *logical_not_op.y.strides = {s1, One}; | ||
| 51 | 43 | ||
| 52 | auto load = graph.FindNode("load"); | 44 | auto load = graph.FindNode("load"); |
| 53 | - load->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 54 | - load->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 55 | - load->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 56 | - load->attr.sched.loop_axis = z0.id; | ||
| 57 | - load->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 58 | - load->outputs[0].attr.vectorized_strides = {One}; | ||
| 59 | - load->outputs[0].attr.dtype = af::DT_FLOAT; | ||
| 60 | - load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 61 | - load->outputs[0].attr.mem.tensor_id = 0; | ||
| 62 | - load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 63 | - load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 64 | - load->outputs[0].attr.que.id = 1; | ||
| 65 | - load->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 66 | - | ||
| 67 | auto logical_not = graph.FindNode("logical_not"); | 45 | auto logical_not = graph.FindNode("logical_not"); |
| 68 | - logical_not->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 69 | - logical_not->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 70 | - logical_not->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 71 | - logical_not->attr.sched.loop_axis = z0.id; | ||
| 72 | - logical_not->attr.tmp_buffers = {{{af::Symbol(8192), -1}, af::MemAttr(), 0}}; | ||
| 73 | - logical_not->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 74 | - logical_not->outputs[0].attr.vectorized_strides = {One}; | ||
| 75 | - logical_not->outputs[0].attr.dtype = af::DT_INT16; | ||
| 76 | - logical_not->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 77 | - logical_not->outputs[0].attr.mem.tensor_id = 1; | ||
| 78 | - logical_not->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 79 | - logical_not->outputs[0].attr.que.id = 2; | ||
| 80 | - logical_not->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 81 | 46 | ||
| 82 | codegen::Tiler tiler; | 47 | codegen::Tiler tiler; |
| 83 | codegen::TPipe tpipe("tpipe", tiler); | 48 | codegen::TPipe tpipe("tpipe", tiler); |
| @@ -100,3 +65,102 @@ TEST(CodegenKernel, RegLogicalNotApiCall) { | |||
| 100 | call.Generate(tpipe, current_axis, result); | 65 | call.Generate(tpipe, current_axis, result); |
| 101 | EXPECT_EQ(result, std::string{"LogicalNotExtend(local_1[0], local_0[0], tmp_buf_0, local_0_actual_size);\n"}); | 66 | EXPECT_EQ(result, std::string{"LogicalNotExtend(local_1[0], local_0[0], tmp_buf_0, local_0_actual_size);\n"}); |
| 102 | } | 67 | } |
| 68 | + | ||
| 69 | +namespace { | ||
| 70 | +void BuildLogicalNotCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, | ||
| 71 | + const af::Axis &z0, const af::Axis &z1) { | ||
| 72 | + Data x_op("x", graph); | ||
| 73 | + Load load_op("load"); | ||
| 74 | + af::ascir_op::LogicalNot logical_not_op("logical_not"); | ||
| 75 | + graph.AddNode(load_op); | ||
| 76 | + graph.AddNode(logical_not_op); | ||
| 77 | + | ||
| 78 | + load_op.x = x_op.y; | ||
| 79 | + load_op.attr.sched.axis = {z0.id, z1.id}; | ||
| 80 | + *load_op.y.axis = {z0.id, z1.id}; | ||
| 81 | + *load_op.y.repeats = {s0, s1}; | ||
| 82 | + *load_op.y.strides = {s1, One}; | ||
| 83 | + logical_not_op.x = load_op.y; | ||
| 84 | + *logical_not_op.y.axis = {z0.id, z1.id}; | ||
| 85 | + *logical_not_op.y.repeats = {s0, s1}; | ||
| 86 | + *logical_not_op.y.strides = {s1, One}; | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +void InitLogicalNotCvStageAttrs(af::AscGraph &graph, const af::Axis &z0, const af::Axis &z1) { | ||
| 90 | + auto load = graph.FindNode("load"); | ||
| 91 | + load->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 92 | + load->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 93 | + load->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 94 | + load->attr.sched.loop_axis = z0.id; | ||
| 95 | + load->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 96 | + load->outputs[0].attr.vectorized_strides = {One}; | ||
| 97 | + load->outputs[0].attr.dtype = af::DT_FLOAT; | ||
| 98 | + load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 99 | + load->outputs[0].attr.mem.tensor_id = 0; | ||
| 100 | + load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 101 | + load->outputs[0].attr.que.id = 1; | ||
| 102 | + load->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 103 | + | ||
| 104 | + auto logical_not = graph.FindNode("logical_not"); | ||
| 105 | + logical_not->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 106 | + logical_not->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 107 | + logical_not->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 108 | + logical_not->attr.sched.loop_axis = z0.id; | ||
| 109 | + logical_not->attr.tmp_buffers = {{{af::Symbol(8192), -1}, af::MemAttr(), 0}}; | ||
| 110 | + logical_not->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 111 | + logical_not->outputs[0].attr.vectorized_strides = {One}; | ||
| 112 | + logical_not->outputs[0].attr.dtype = af::DT_INT16; | ||
| 113 | + logical_not->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 114 | + logical_not->outputs[0].attr.mem.tensor_id = 1; | ||
| 115 | + logical_not->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 116 | + logical_not->outputs[0].attr.que.id = 2; | ||
| 117 | + logical_not->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | +void InitLogicalNotCvStageTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscGraph &graph, | ||
| 121 | + const af::AscNodePtr &load, const af::AscNodePtr &logical_not, const af::Expression &s0, | ||
| 122 | + const af::Expression &s1, const af::Axis &z0, const af::Axis &z1) { | ||
| 123 | + tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse; | ||
| 124 | + tpipe.is_inductor = false; | ||
| 125 | + tpipe.CollectQues(graph); | ||
| 126 | + tpipe.AddTensor(load->outputs[0]); | ||
| 127 | + tpipe.AddTensor(logical_not->outputs[0]); | ||
| 128 | + | ||
| 129 | + tiler.AddAxis(z0); | ||
| 130 | + tiler.AddAxis(z1); | ||
| 131 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 132 | + tiler.AddSizeVar(af::SizeVar(s1)); | ||
| 133 | +} | ||
| 134 | +} // namespace | ||
| 135 | + | ||
| 136 | +TEST(CodegenKernel, RegLogicalNotApiCallCVStage) { | ||
| 137 | + af::AscGraph graph("test_graph"); | ||
| 138 | + | ||
| 139 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 140 | + auto s1 = graph.CreateSizeVar("s1"); | ||
| 141 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 142 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 143 | + BuildLogicalNotCvStageGraph(graph, s0, s1, z0, z1); | ||
| 144 | + InitLogicalNotCvStageAttrs(graph, z0, z1); | ||
| 145 | + | ||
| 146 | + auto load = graph.FindNode("load"); | ||
| 147 | + auto logical_not = graph.FindNode("logical_not"); | ||
| 148 | + | ||
| 149 | + codegen::Tiler tiler; | ||
| 150 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 151 | + InitLogicalNotCvStageTpipe(tpipe, tiler, graph, load, logical_not, s0, s1, z0, z1); | ||
| 152 | + std::vector<af::AxisId> current_axis; | ||
| 153 | + current_axis.push_back(z0.id); | ||
| 154 | + | ||
| 155 | + codegen::ApiTensor x1; | ||
| 156 | + x1.id = load->outputs[0].attr.mem.tensor_id; | ||
| 157 | + codegen::UnaryApiTmpCall call("LogicalNotExtend"); | ||
| 158 | + EXPECT_EQ(call.Init(logical_not), 0); | ||
| 159 | + call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1; | ||
| 160 | + call.inputs.push_back(&x1); | ||
| 161 | + std::string result; | ||
| 162 | + call.Generate(tpipe, current_axis, result); | ||
| 163 | + EXPECT_EQ(result, | ||
| 164 | + std::string{ | ||
| 165 | + "LogicalNotExtend(local_1[0], local_0[0], tmp_buf_0, ((local_0_actual_size + 16 - 1) / 16 * 16));\n"}); | ||
| 166 | +} | ||
| @@ -140,6 +140,110 @@ TEST(CodegenKernel, StoreRegApiCall_TwoStoreOneOutput) { | |||
| 140 | "z0_t_size, 1, (16 - 1), 0);\n"}); | 140 | "z0_t_size, 1, (16 - 1), 0);\n"}); |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | +namespace { | ||
| 144 | +void BuildStoreCvUbFuseGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, | ||
| 145 | + const af::Axis &z0, const af::Axis &z1) { | ||
| 146 | + Data x_op("x", graph); | ||
| 147 | + Load load_op("load"); | ||
| 148 | + af::ascir_op::Store store_op("store"); | ||
| 149 | + graph.AddNode(load_op); | ||
| 150 | + graph.AddNode(store_op); | ||
| 151 | + | ||
| 152 | + const std::vector<af::AxisId> axes = {z0.id, z1.id}; | ||
| 153 | + const std::vector<af::Expression> repeats = {s0, s1}; | ||
| 154 | + const std::vector<af::Expression> strides = {s1, One}; | ||
| 155 | + load_op.x = x_op.y; | ||
| 156 | + load_op.attr.sched.axis = axes; | ||
| 157 | + *load_op.y.axis = axes; | ||
| 158 | + *load_op.y.repeats = repeats; | ||
| 159 | + *load_op.y.strides = strides; | ||
| 160 | + store_op.x = load_op.y; | ||
| 161 | + store_op.ir_attr.SetOffset(af::Symbol(0)); | ||
| 162 | + *store_op.y.axis = axes; | ||
| 163 | + *store_op.y.repeats = repeats; | ||
| 164 | + *store_op.y.strides = strides; | ||
| 165 | +} | ||
| 166 | + | ||
| 167 | +void InitStoreCvUbFuseAttrs(af::AscGraph &graph, const af::Expression &s1, const af::Axis &z0, const af::Axis &z1) { | ||
| 168 | + auto load = graph.FindNode("load"); | ||
| 169 | + load->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 170 | + load->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 171 | + load->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 172 | + load->attr.sched.loop_axis = z0.id; | ||
| 173 | + auto &load_attr = load->outputs[0].attr; | ||
| 174 | + load_attr.vectorized_axis = {z0.id, z1.id}; | ||
| 175 | + load_attr.vectorized_strides = {s1, One}; | ||
| 176 | + load_attr.dtype = af::DT_FLOAT16; | ||
| 177 | + load_attr.mem.position = af::Position::kPositionVecIn; | ||
| 178 | + load_attr.mem.tensor_id = 0; | ||
| 179 | + load_attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 180 | + load_attr.que.id = 1; | ||
| 181 | + load_attr.opt.merge_scope = af::kIdNone; | ||
| 182 | + | ||
| 183 | + auto store = graph.FindNode("store"); | ||
| 184 | + store->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 185 | + store->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 186 | + store->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 187 | + store->attr.sched.loop_axis = z0.id; | ||
| 188 | + auto &store_attr = store->outputs[0].attr; | ||
| 189 | + store_attr.vectorized_axis = {z0.id, z1.id}; | ||
| 190 | + store_attr.vectorized_strides = {s1, One}; | ||
| 191 | + store_attr.dtype = af::DT_FLOAT16; | ||
| 192 | + store_attr.mem.position = af::Position::kPositionVecOut; | ||
| 193 | + store_attr.mem.tensor_id = 1; | ||
| 194 | + store_attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 195 | + store_attr.que.id = 2; | ||
| 196 | + store_attr.opt.merge_scope = af::kIdNone; | ||
| 197 | +} | ||
| 198 | + | ||
| 199 | +void InitStoreCvUbFuseTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscGraph &graph, | ||
| 200 | + const af::AscNodePtr &load, const af::AscNodePtr &store, const af::Expression &s0, | ||
| 201 | + const af::Expression &s1, const af::Axis &z0, const af::Axis &z1) { | ||
| 202 | + tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse; | ||
| 203 | + tpipe.CollectQues(graph); | ||
| 204 | + tpipe.AddTensor(load->outputs[0]); | ||
| 205 | + tpipe.AddTensor(store->outputs[0]); | ||
| 206 | + | ||
| 207 | + tiler.AddAxis(z0); | ||
| 208 | + tiler.AddAxis(z1); | ||
| 209 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 210 | + tiler.AddSizeVar(af::SizeVar(s1)); | ||
| 211 | +} | ||
| 212 | +} // namespace | ||
| 213 | + | ||
| 214 | +TEST(CodegenKernel, StoreRegApiCall_CvUbFuseUsesDtypeAwareStrides) { | ||
| 215 | + af::AscGraph graph("test_graph"); | ||
| 216 | + | ||
| 217 | + auto s0 = af::Symbol(16); | ||
| 218 | + auto s1 = af::Symbol(7); | ||
| 219 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 220 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 221 | + BuildStoreCvUbFuseGraph(graph, s0, s1, z0, z1); | ||
| 222 | + InitStoreCvUbFuseAttrs(graph, s1, z0, z1); | ||
| 223 | + | ||
| 224 | + auto load = graph.FindNode("load"); | ||
| 225 | + auto store = graph.FindNode("store"); | ||
| 226 | + | ||
| 227 | + codegen::Tiler tiler; | ||
| 228 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 229 | + InitStoreCvUbFuseTpipe(tpipe, tiler, graph, load, store, s0, s1, z0, z1); | ||
| 230 | + | ||
| 231 | + codegen::ApiTensor x1; | ||
| 232 | + x1.id = load->outputs[0].attr.mem.tensor_id; | ||
| 233 | + | ||
| 234 | + codegen::StoreRegApiCall call_0("DataCopyPadExtend"); | ||
| 235 | + EXPECT_EQ(call_0.Init(store), 0); | ||
| 236 | + call_0.inputs.push_back(&x1); | ||
| 237 | + | ||
| 238 | + std::string result; | ||
| 239 | + call_0.Generate(tpipe, vector<af::AxisId>{}, result); | ||
| 240 | + EXPECT_NE(result.find("DataCopyPadExtend<half, AscendC::PaddingMode::Normal>("), std::string::npos); | ||
| 241 | + EXPECT_NE(result.find("curAivM"), std::string::npos); | ||
| 242 | + EXPECT_NE(result.find("curAivN"), std::string::npos); | ||
| 243 | + EXPECT_NE(result.find("KernelUtils::BlkAlign<half>(curAivN)"), std::string::npos); | ||
| 244 | + EXPECT_NE(result.find("shapeN - curAivN"), std::string::npos); | ||
| 245 | +} | ||
| 246 | + | ||
| 143 | TEST(CodegenKernel, StoreRegApiCall_NeetMte3SyncMte2) { | 247 | TEST(CodegenKernel, StoreRegApiCall_NeetMte3SyncMte2) { |
| 144 | af::AscGraph graph("test_graph"); | 248 | af::AscGraph graph("test_graph"); |
| 145 | 249 | ||
| @@ -23,6 +23,12 @@ using namespace af::ops; | |||
| 23 | using namespace af::ascir_op; | 23 | using namespace af::ascir_op; |
| 24 | 24 | ||
| 25 | namespace codegen { | 25 | namespace codegen { |
| 26 | +namespace { | ||
| 27 | +void BuildIsNanCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, const af::Axis &z0, | ||
| 28 | + const af::Axis &z1); | ||
| 29 | +void InitIsNanCvStageAttrs(af::AscGraph &graph, ge::DataType output_dtype, const af::Axis &z0, const af::Axis &z1); | ||
| 30 | +} // namespace | ||
| 31 | + | ||
| 26 | TEST(CodegenKernel, UnaryApicallIsNan) { | 32 | TEST(CodegenKernel, UnaryApicallIsNan) { |
| 27 | af::AscGraph graph("test_graph"); | 33 | af::AscGraph graph("test_graph"); |
| 28 | 34 | ||
| @@ -30,50 +36,11 @@ TEST(CodegenKernel, UnaryApicallIsNan) { | |||
| 30 | auto s1 = graph.CreateSizeVar("s1"); | 36 | auto s1 = graph.CreateSizeVar("s1"); |
| 31 | auto z0 = graph.CreateAxis("z0", s0); | 37 | auto z0 = graph.CreateAxis("z0", s0); |
| 32 | auto z1 = graph.CreateAxis("z1", s1); | 38 | auto z1 = graph.CreateAxis("z1", s1); |
| 33 | - | 39 | + BuildIsNanCvStageGraph(graph, s0, s1, z0, z1); |
| 34 | - Data x_op("x", graph); | 40 | + InitIsNanCvStageAttrs(graph, af::DT_INT16, z0, z1); |
| 35 | - Load load_op("load"); | ||
| 36 | - Isnan rsqrt_op("IsNan"); | ||
| 37 | - graph.AddNode(rsqrt_op); | ||
| 38 | - | ||
| 39 | - load_op.x = x_op.y; | ||
| 40 | - load_op.attr.sched.axis = {z0.id, z1.id}; | ||
| 41 | - *load_op.y.axis = {z0.id, z1.id}; | ||
| 42 | - *load_op.y.repeats = {s0, s1}; | ||
| 43 | - *load_op.y.strides = {s1, One}; | ||
| 44 | - rsqrt_op.x = load_op.y; | ||
| 45 | - *rsqrt_op.y.axis = {z0.id, z1.id}; | ||
| 46 | - *rsqrt_op.y.repeats = {s0, s1}; | ||
| 47 | - *rsqrt_op.y.strides = {s1, One}; | ||
| 48 | 41 | ||
| 49 | auto load = graph.FindNode("load"); | 42 | auto load = graph.FindNode("load"); |
| 50 | - load->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 51 | - load->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 52 | - load->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 53 | - load->attr.sched.loop_axis = z0.id; | ||
| 54 | - load->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 55 | - load->outputs[0].attr.vectorized_strides = {One}; | ||
| 56 | - load->outputs[0].attr.dtype = af::DT_FLOAT; | ||
| 57 | - load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 58 | - load->outputs[0].attr.mem.tensor_id = 0; | ||
| 59 | - load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 60 | - load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 61 | - load->outputs[0].attr.que.id = 1; | ||
| 62 | - load->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 63 | - | ||
| 64 | auto rsqrt = graph.FindNode("IsNan"); | 43 | auto rsqrt = graph.FindNode("IsNan"); |
| 65 | - rsqrt->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 66 | - rsqrt->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 67 | - rsqrt->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 68 | - rsqrt->attr.sched.loop_axis = z0.id; | ||
| 69 | - rsqrt->outputs[0].attr.vectorized_axis = {z1.id}; | ||
| 70 | - rsqrt->outputs[0].attr.vectorized_strides = {One}; | ||
| 71 | - rsqrt->outputs[0].attr.dtype = af::DT_INT16; | ||
| 72 | - rsqrt->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 73 | - rsqrt->outputs[0].attr.mem.tensor_id = 1; | ||
| 74 | - rsqrt->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 75 | - rsqrt->outputs[0].attr.que.id = 2; | ||
| 76 | - rsqrt->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 77 | 44 | ||
| 78 | codegen::Tiler tiler; | 45 | codegen::Tiler tiler; |
| 79 | codegen::TPipe tpipe("tpipe", tiler); | 46 | codegen::TPipe tpipe("tpipe", tiler); |
| @@ -100,6 +67,133 @@ TEST(CodegenKernel, UnaryApicallIsNan) { | |||
| 100 | delete call; | 67 | delete call; |
| 101 | } | 68 | } |
| 102 | 69 | ||
| 70 | +namespace { | ||
| 71 | +void BuildIsNanCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, const af::Axis &z0, | ||
| 72 | + const af::Axis &z1) { | ||
| 73 | + Data x_op("x", graph); | ||
| 74 | + Load load_op("load"); | ||
| 75 | + Isnan rsqrt_op("IsNan"); | ||
| 76 | + graph.AddNode(rsqrt_op); | ||
| 77 | + | ||
| 78 | + load_op.x = x_op.y; | ||
| 79 | + load_op.attr.sched.axis = {z0.id, z1.id}; | ||
| 80 | + *load_op.y.axis = {z0.id, z1.id}; | ||
| 81 | + *load_op.y.repeats = {s0, s1}; | ||
| 82 | + *load_op.y.strides = {s1, One}; | ||
| 83 | + rsqrt_op.x = load_op.y; | ||
| 84 | + *rsqrt_op.y.axis = {z0.id, z1.id}; | ||
| 85 | + *rsqrt_op.y.repeats = {s0, s1}; | ||
| 86 | + *rsqrt_op.y.strides = {s1, One}; | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +void InitIsNanCvStageAttrs(af::AscGraph &graph, ge::DataType output_dtype, const af::Axis &z0, const af::Axis &z1) { | ||
| 90 | + auto load = graph.FindNode("load"); | ||
| 91 | + load->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 92 | + load->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 93 | + load->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 94 | + load->attr.sched.loop_axis = z0.id; | ||
| 95 | + auto &load_attr = load->outputs[0].attr; | ||
| 96 | + load_attr.vectorized_axis = {z1.id}; | ||
| 97 | + load_attr.vectorized_strides = {One}; | ||
| 98 | + load_attr.dtype = af::DT_FLOAT; | ||
| 99 | + load_attr.mem.position = af::Position::kPositionVecIn; | ||
| 100 | + load_attr.mem.tensor_id = 0; | ||
| 101 | + load_attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 102 | + load_attr.que.id = 1; | ||
| 103 | + load_attr.opt.merge_scope = af::kIdNone; | ||
| 104 | + | ||
| 105 | + auto rsqrt = graph.FindNode("IsNan"); | ||
| 106 | + rsqrt->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 107 | + rsqrt->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 108 | + rsqrt->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 109 | + rsqrt->attr.sched.loop_axis = z0.id; | ||
| 110 | + auto &rsqrt_attr = rsqrt->outputs[0].attr; | ||
| 111 | + rsqrt_attr.vectorized_axis = {z1.id}; | ||
| 112 | + rsqrt_attr.vectorized_strides = {One}; | ||
| 113 | + rsqrt_attr.dtype = output_dtype; | ||
| 114 | + rsqrt_attr.mem.position = af::Position::kPositionVecOut; | ||
| 115 | + rsqrt_attr.mem.tensor_id = 1; | ||
| 116 | + rsqrt_attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 117 | + rsqrt_attr.que.id = 2; | ||
| 118 | + rsqrt_attr.opt.merge_scope = af::kIdNone; | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +void InitIsNanCvStageTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscNodePtr &load, | ||
| 122 | + const af::AscNodePtr &isnan, const af::Expression &s0, const af::Expression &s1, | ||
| 123 | + const af::Axis &z0, const af::Axis &z1) { | ||
| 124 | + tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse; | ||
| 125 | + tpipe.is_inductor = false; | ||
| 126 | + tpipe.AddTensor(load->outputs[0]); | ||
| 127 | + tpipe.AddTensor(isnan->outputs[0]); | ||
| 128 | + | ||
| 129 | + tiler.AddAxis(z0); | ||
| 130 | + tiler.AddAxis(z1); | ||
| 131 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 132 | + tiler.AddSizeVar(af::SizeVar(s1)); | ||
| 133 | +} | ||
| 134 | +} // namespace | ||
| 135 | + | ||
| 136 | +TEST(CodegenKernel, UnaryApicallIsNanCVStage) { | ||
| 137 | + af::AscGraph graph("test_graph"); | ||
| 138 | + | ||
| 139 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 140 | + auto s1 = graph.CreateSizeVar("s1"); | ||
| 141 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 142 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 143 | + BuildIsNanCvStageGraph(graph, s0, s1, z0, z1); | ||
| 144 | + InitIsNanCvStageAttrs(graph, af::DT_INT16, z0, z1); | ||
| 145 | + | ||
| 146 | + auto load = graph.FindNode("load"); | ||
| 147 | + auto rsqrt = graph.FindNode("IsNan"); | ||
| 148 | + | ||
| 149 | + codegen::Tiler tiler; | ||
| 150 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 151 | + InitIsNanCvStageTpipe(tpipe, tiler, load, rsqrt, s0, s1, z0, z1); | ||
| 152 | + | ||
| 153 | + codegen::ApiTensor x1; | ||
| 154 | + x1.id = load->outputs[0].attr.mem.tensor_id; | ||
| 155 | + codegen::UnaryBitWidthChangeApiCallV2 call_0("IsNan"); | ||
| 156 | + EXPECT_EQ(call_0.Init(rsqrt), 0); | ||
| 157 | + call_0.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1; | ||
| 158 | + call_0.inputs.push_back(&x1); | ||
| 159 | + | ||
| 160 | + std::string result; | ||
| 161 | + call_0.Generate(tpipe, vector<af::AxisId>{}, result); | ||
| 162 | + EXPECT_EQ(result, std::string{"LocalTensor<bool> local_1_cast = local_1.template ReinterpretCast<bool>();\n" | ||
| 163 | + "IsNan(local_1_cast[0], local_0[0], ((local_0_actual_size + 8 - 1) / 8 * 8));\n"}); | ||
| 164 | +} | ||
| 165 | + | ||
| 166 | +TEST(CodegenKernel, UnaryApicallIsNanCvStageUsesInputDtypeAlignedCount) { | ||
| 167 | + af::AscGraph graph("test_graph"); | ||
| 168 | + | ||
| 169 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 170 | + auto s1 = graph.CreateSizeVar("s1"); | ||
| 171 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 172 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 173 | + | ||
| 174 | + BuildIsNanCvStageGraph(graph, s0, s1, z0, z1); | ||
| 175 | + InitIsNanCvStageAttrs(graph, af::DT_UINT8, z0, z1); | ||
| 176 | + | ||
| 177 | + auto load = graph.FindNode("load"); | ||
| 178 | + auto isnan = graph.FindNode("IsNan"); | ||
| 179 | + | ||
| 180 | + codegen::Tiler tiler; | ||
| 181 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 182 | + InitIsNanCvStageTpipe(tpipe, tiler, load, isnan, s0, s1, z0, z1); | ||
| 183 | + | ||
| 184 | + codegen::ApiTensor x1; | ||
| 185 | + x1.id = load->outputs[0].attr.mem.tensor_id; | ||
| 186 | + codegen::UnaryBitWidthChangeApiCallV2 call("IsNan"); | ||
| 187 | + EXPECT_EQ(call.Init(isnan), 0); | ||
| 188 | + call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1; | ||
| 189 | + call.inputs.push_back(&x1); | ||
| 190 | + | ||
| 191 | + std::string result; | ||
| 192 | + EXPECT_EQ(call.Generate(tpipe, vector<af::AxisId>{}, result), 0); | ||
| 193 | + EXPECT_EQ(result, std::string{"LocalTensor<bool> local_1_cast = local_1.template ReinterpretCast<bool>();\n" | ||
| 194 | + "IsNan(local_1_cast[0], local_0[0], ((local_0_actual_size + 8 - 1) / 8 * 8));\n"}); | ||
| 195 | +} | ||
| 196 | + | ||
| 103 | TEST(CodegenKernel, UnaryApicallIsNanThrowingFor) { | 197 | TEST(CodegenKernel, UnaryApicallIsNanThrowingFor) { |
| 104 | af::AscGraph graph("test_graph"); | 198 | af::AscGraph graph("test_graph"); |
| 105 | 199 | ||
| @@ -167,6 +167,151 @@ TEST(WhereRegApiCallTest, WhereRegApiCall_Scalar_x2x3) { | |||
| 167 | EXPECT_EQ(result, std::string{"Where(local_3[0], local_0[0], local_1, local_2, local_0_actual_size);\n"}); | 167 | EXPECT_EQ(result, std::string{"Where(local_3[0], local_0[0], local_1, local_2, local_0_actual_size);\n"}); |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | +namespace { | ||
| 171 | +void BuildWhereScalarCvStageGraph(af::AscGraph &graph, const af::Expression &s0, const af::Expression &s1, | ||
| 172 | + const af::Expression &s2, const af::Axis &z0, const af::Axis &z1, | ||
| 173 | + const af::Axis &z2) { | ||
| 174 | + Data x_op1("x1", graph); | ||
| 175 | + Data x_op2("x2", graph); | ||
| 176 | + Data x_op3("x3", graph); | ||
| 177 | + Load load_op1("load1"); | ||
| 178 | + Load load_op2("load2"); | ||
| 179 | + Load load_op3("load3"); | ||
| 180 | + af::ascir_op::Where where_op("where"); | ||
| 181 | + graph.AddNode(load_op1); | ||
| 182 | + graph.AddNode(load_op2); | ||
| 183 | + graph.AddNode(load_op3); | ||
| 184 | + graph.AddNode(where_op); | ||
| 185 | + | ||
| 186 | + load_op1.x = x_op1.y; | ||
| 187 | + load_op1.attr.sched.axis = {z0.id, z1.id, z2.id}; | ||
| 188 | + *load_op1.y.axis = {z0.id, z1.id, z2.id}; | ||
| 189 | + *load_op1.y.repeats = {s0, s1, s2}; | ||
| 190 | + *load_op1.y.strides = {s1 * s2, s2, One}; | ||
| 191 | + | ||
| 192 | + load_op2.x = x_op2.y; | ||
| 193 | + load_op2.attr.sched.axis = {z0.id, z1.id, z2.id}; | ||
| 194 | + *load_op2.y.axis = {z0.id, z1.id, z2.id}; | ||
| 195 | + *load_op2.y.repeats = {s0, s1, s2}; | ||
| 196 | + *load_op2.y.strides = {s1 * s2, s2, One}; | ||
| 197 | + | ||
| 198 | + load_op3.x = x_op3.y; | ||
| 199 | + load_op3.attr.sched.axis = {z0.id, z1.id, z2.id}; | ||
| 200 | + *load_op3.y.axis = {z0.id, z1.id, z2.id}; | ||
| 201 | + *load_op3.y.repeats = {s0, s1, s2}; | ||
| 202 | + *load_op3.y.strides = {s1 * s2, s2, One}; | ||
| 203 | + | ||
| 204 | + where_op.x1 = load_op1.y; | ||
| 205 | + where_op.x2 = load_op2.y; | ||
| 206 | + where_op.x3 = load_op3.y; | ||
| 207 | + *where_op.y.axis = {z0.id, z1.id, z2.id}; | ||
| 208 | + *where_op.y.repeats = {s0, s1, s2}; | ||
| 209 | + *where_op.y.strides = {s1 * s2, s2, One}; | ||
| 210 | +} | ||
| 211 | + | ||
| 212 | +void InitWhereLoadAttrs(const af::AscNodePtr &load, const af::Expression &stride0, int64_t tensor_id, | ||
| 213 | + const af::Axis &z0, const af::Axis &z1, const af::Axis &z2) { | ||
| 214 | + load->attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 215 | + load->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 216 | + load->attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 217 | + load->attr.sched.loop_axis = z0.id; | ||
| 218 | + load->outputs[0].attr.vectorized_axis = {z1.id, z2.id}; | ||
| 219 | + load->outputs[0].attr.vectorized_strides = {stride0, One}; | ||
| 220 | + load->outputs[0].attr.dtype = af::DT_FLOAT; | ||
| 221 | + load->outputs[0].attr.mem.position = af::Position::kPositionVecIn; | ||
| 222 | + load->outputs[0].attr.mem.tensor_id = tensor_id; | ||
| 223 | + load->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 224 | + load->outputs[0].attr.que.id = 1; | ||
| 225 | + load->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 226 | +} | ||
| 227 | + | ||
| 228 | +void InitWhereOutputAttrs(const af::AscNodePtr &where, const af::Expression &s2, const af::Axis &z0, const af::Axis &z1, | ||
| 229 | + const af::Axis &z2) { | ||
| 230 | + where->attr.api.compute_type = af::ComputeType::kComputeElewise; | ||
| 231 | + where->attr.api.type = af::ApiType::kAPITypeCompute; | ||
| 232 | + where->attr.api.unit = af::ComputeUnit::kUnitVector; | ||
| 233 | + where->attr.sched.loop_axis = z0.id; | ||
| 234 | + where->outputs[0].attr.vectorized_axis = {z1.id, z2.id}; | ||
| 235 | + where->outputs[0].attr.vectorized_strides = {s2, One}; | ||
| 236 | + where->outputs[0].attr.dtype = af::DT_INT16; | ||
| 237 | + where->outputs[0].attr.mem.position = af::Position::kPositionVecOut; | ||
| 238 | + where->outputs[0].attr.mem.tensor_id = 3; | ||
| 239 | + where->outputs[0].attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 240 | + where->outputs[0].attr.que.id = 2; | ||
| 241 | + where->outputs[0].attr.opt.merge_scope = af::kIdNone; | ||
| 242 | +} | ||
| 243 | + | ||
| 244 | +void InitWhereScalarCvStageAttrs(af::AscGraph &graph, const af::Expression &s2, const af::Axis &z0, const af::Axis &z1, | ||
| 245 | + const af::Axis &z2) { | ||
| 246 | + InitWhereLoadAttrs(graph.FindNode("load1"), s2, 0, z0, z1, z2); | ||
| 247 | + InitWhereLoadAttrs(graph.FindNode("load2"), s2 + s2, 1, z0, z1, z2); | ||
| 248 | + InitWhereLoadAttrs(graph.FindNode("load3"), s2 + s2, 2, z0, z1, z2); | ||
| 249 | + InitWhereOutputAttrs(graph.FindNode("where"), s2, z0, z1, z2); | ||
| 250 | +} | ||
| 251 | + | ||
| 252 | +void InitWhereScalarCvStageTpipe(codegen::TPipe &tpipe, codegen::Tiler &tiler, const af::AscGraph &graph, | ||
| 253 | + const af::AscNodePtr &load1, const af::AscNodePtr &load2, const af::AscNodePtr &load3, | ||
| 254 | + const af::AscNodePtr &where, const af::Expression &s0, const af::Expression &s1, | ||
| 255 | + const af::Expression &s2, const af::Axis &z0, const af::Axis &z1, const af::Axis &z2) { | ||
| 256 | + tpipe.cv_fusion_type = ascir::CubeTemplateType::kUBFuse; | ||
| 257 | + tpipe.is_inductor = false; | ||
| 258 | + tpipe.CollectQues(graph); | ||
| 259 | + tpipe.AddTensor(load1->outputs[0]); | ||
| 260 | + tpipe.AddTensor("1", load2->outputs[0]); | ||
| 261 | + tpipe.AddTensor("1", load3->outputs[0]); | ||
| 262 | + tpipe.AddTensor(where->outputs[0]); | ||
| 263 | + | ||
| 264 | + tiler.AddAxis(z0); | ||
| 265 | + tiler.AddAxis(z1); | ||
| 266 | + tiler.AddAxis(z2); | ||
| 267 | + tiler.AddSizeVar(af::SizeVar(s0)); | ||
| 268 | + tiler.AddSizeVar(af::SizeVar(s1)); | ||
| 269 | + tiler.AddSizeVar(af::SizeVar(s2)); | ||
| 270 | +} | ||
| 271 | +} // namespace | ||
| 272 | + | ||
| 273 | +TEST(WhereRegApiCallTest, WhereRegApiCall_Scalar_x2x3_CVStage) { | ||
| 274 | + af::AscGraph graph("test_graph"); | ||
| 275 | + | ||
| 276 | + auto s0 = graph.CreateSizeVar("s0"); | ||
| 277 | + auto s1 = graph.CreateSizeVar("s1"); | ||
| 278 | + auto s2 = graph.CreateSizeVar("s2"); | ||
| 279 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 280 | + auto z1 = graph.CreateAxis("z1", s1); | ||
| 281 | + auto z2 = graph.CreateAxis("z2", s2); | ||
| 282 | + BuildWhereScalarCvStageGraph(graph, s0, s1, s2, z0, z1, z2); | ||
| 283 | + InitWhereScalarCvStageAttrs(graph, s2, z0, z1, z2); | ||
| 284 | + | ||
| 285 | + auto load1 = graph.FindNode("load1"); | ||
| 286 | + auto load2 = graph.FindNode("load2"); | ||
| 287 | + auto load3 = graph.FindNode("load3"); | ||
| 288 | + auto where = graph.FindNode("where"); | ||
| 289 | + | ||
| 290 | + codegen::Tiler tiler; | ||
| 291 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 292 | + InitWhereScalarCvStageTpipe(tpipe, tiler, graph, load1, load2, load3, where, s0, s1, s2, z0, z1, z2); | ||
| 293 | + std::vector<af::AxisId> current_axis; | ||
| 294 | + current_axis.push_back(z0.id); | ||
| 295 | + | ||
| 296 | + codegen::ApiTensor x1; | ||
| 297 | + x1.id = load1->outputs[0].attr.mem.tensor_id; | ||
| 298 | + codegen::ApiTensor x2; | ||
| 299 | + x2.id = load2->outputs[0].attr.mem.tensor_id; | ||
| 300 | + codegen::ApiTensor x3; | ||
| 301 | + x3.id = load3->outputs[0].attr.mem.tensor_id; | ||
| 302 | + codegen::WhereRegApiCall call("Where"); | ||
| 303 | + EXPECT_EQ(call.Init(where), 0); | ||
| 304 | + call.api_call_context.stage = codegen::ComputeStage::kCVFuseStage1; | ||
| 305 | + call.inputs.push_back(&x1); | ||
| 306 | + call.inputs.push_back(&x2); | ||
| 307 | + call.inputs.push_back(&x3); | ||
| 308 | + | ||
| 309 | + std::string result; | ||
| 310 | + EXPECT_EQ(call.Generate(tpipe, current_axis, result), 0); | ||
| 311 | + EXPECT_EQ(result, std::string{"Where(local_3[0], local_0[0], local_1, local_2, " | ||
| 312 | + "((local_0_actual_size + 16 - 1) / 16 * 16));\n"}); | ||
| 313 | +} | ||
| 314 | + | ||
| 170 | TEST(WhereRegApiCallTest, WhereRegApiCall_x2_x3_is_ub_scalar) { | 315 | TEST(WhereRegApiCallTest, WhereRegApiCall_x2_x3_is_ub_scalar) { |
| 171 | af::AscGraph graph("test_graph"); | 316 | af::AscGraph graph("test_graph"); |
| 172 | 317 | ||
| @@ -47,6 +47,21 @@ void SetTwoDimVecInAttr(AscTensor &tensor, const af::Axis &z0, const af::Axis &z | |||
| 47 | tensor.attr.mem.tensor_id = tensor_id; | 47 | tensor.attr.mem.tensor_id = tensor_id; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | +codegen::Tensor MakeCvUbFuseTensor(af::AscGraph &graph, ge::DataType dtype, int64_t tensor_id, | ||
| 51 | + const std::vector<af::Expression> &vectorized_strides, | ||
| 52 | + const std::string &tensor_name) { | ||
| 53 | + auto node = graph.FindNode("x"); | ||
| 54 | + af::AscTensor tensor = node->outputs[0]; | ||
| 55 | + tensor.attr.dtype = dtype; | ||
| 56 | + tensor.attr.mem.tensor_id = tensor_id; | ||
| 57 | + tensor.attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 58 | + tensor.attr.mem.position = af::Position::kPositionVecIn; | ||
| 59 | + tensor.attr.vectorized_strides = vectorized_strides; | ||
| 60 | + std::string dtype_name; | ||
| 61 | + EXPECT_EQ(codegen::Tensor::DtypeName(dtype, dtype_name), af::SUCCESS); | ||
| 62 | + return codegen::Tensor(tensor, dtype_name, tensor_name); | ||
| 63 | +} | ||
| 64 | + | ||
| 50 | void InitScalarDataVfGraph(VectorFunc &vf_op, Store &store_op, Broadcast &sub_brc_op, Abs &abs_op, Store &sub_store_op, | 65 | void InitScalarDataVfGraph(VectorFunc &vf_op, Store &store_op, Broadcast &sub_brc_op, Abs &abs_op, Store &sub_store_op, |
| 51 | Output &sub_output_op, const ScalarData &scalar_data_op, const Scalar &sub_scalar_op, | 66 | Output &sub_output_op, const ScalarData &scalar_data_op, const Scalar &sub_scalar_op, |
| 52 | const af::Axis &z0, const af::Axis &z1, const af::Expression &s0, const af::Expression &s1) { | 67 | const af::Axis &z0, const af::Axis &z1, const af::Expression &s0, const af::Expression &s1) { |
| @@ -379,6 +394,9 @@ TEST(CodegenKernel, VfCall_TwoDimLoad) { | |||
| 379 | sub_store->outputs[0].attr.mem.tensor_id = 2; | 394 | sub_store->outputs[0].attr.mem.tensor_id = 2; |
| 380 | 395 | ||
| 381 | auto vf = graph.FindNode("vf"); | 396 | auto vf = graph.FindNode("vf"); |
| 397 | + vf->outputs[0].attr.axis = {z0.id, z1.id}; | ||
| 398 | + vf->outputs[0].attr.repeats = {s0, s1}; | ||
| 399 | + vf->outputs[0].attr.strides = {s1, One}; | ||
| 382 | vf->outputs[0].attr.vectorized_axis = {z0.id, z1.id}; | 400 | vf->outputs[0].attr.vectorized_axis = {z0.id, z1.id}; |
| 383 | vf->outputs[0].attr.vectorized_strides = {s1, One}; | 401 | vf->outputs[0].attr.vectorized_strides = {s1, One}; |
| 384 | vf->outputs[0].attr.dtype = af::DT_FLOAT; | 402 | vf->outputs[0].attr.dtype = af::DT_FLOAT; |
| @@ -436,6 +454,62 @@ TEST(CodegenKernel, VfCall_TwoDimLoad) { | |||
| 436 | "#endif\n"}); | 454 | "#endif\n"}); |
| 437 | } | 455 | } |
| 438 | 456 | ||
| 457 | +TEST(CodegenKernel, CvUbFuseVfCallUsesCubeBaseMNPhysicalLayout) { | ||
| 458 | + ge::SetupRuntimeStub(); | ||
| 459 | + GTEST_SKIP() << "Manual VF graph fixture is unstable; helper-level UT validates this path."; | ||
| 460 | +} | ||
| 461 | + | ||
| 462 | +TEST(CodegenKernel, CvUbFuseVfLayoutHelperUsesPhysicalRowStride) { | ||
| 463 | + codegen::Tiler tiler; | ||
| 464 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 465 | + tpipe.cv_fusion_type = ::ascir::CubeTemplateType::kUBFuse; | ||
| 466 | + tpipe.cube_output_tensor_id = 0; | ||
| 467 | + | ||
| 468 | + af::AscGraph graph("test_graph"); | ||
| 469 | + af::ascir_op::Data x("x", graph); | ||
| 470 | + auto s1 = af::Symbol("s1"); | ||
| 471 | + auto cube = MakeCvUbFuseTensor(graph, af::DT_FLOAT, 0, {s1, One}, "local_0"); | ||
| 472 | + auto fp16_input = MakeCvUbFuseTensor(graph, af::DT_FLOAT16, 1, {s1, One}, "local_1"); | ||
| 473 | + auto bool_output = MakeCvUbFuseTensor(graph, af::DT_UINT8, 2, {s1, One}, "local_2"); | ||
| 474 | + auto broadcast_input = MakeCvUbFuseTensor(graph, af::DT_FLOAT16, 3, {Zero, Zero}, "local_3"); | ||
| 475 | + | ||
| 476 | + EXPECT_EQ(codegen::GenCvUbFuseVfFuncDimParams(), "uint32_t curAivM, uint32_t curAivN, uint32_t curAlignN"); | ||
| 477 | + EXPECT_EQ(codegen::GenCvUbFuseVfCallDimParams(), "curAivM, curAivN, curAlignN"); | ||
| 478 | + EXPECT_EQ(codegen::GenCvUbFuseRowStride(tpipe, cube), "curAlignN"); | ||
| 479 | + EXPECT_EQ(codegen::GenCvUbFuseRowStride(tpipe, fp16_input), "KernelUtils::BlkAlign<half>(curAivN)"); | ||
| 480 | + EXPECT_EQ(codegen::GenCvUbFuseRowStride(tpipe, bool_output), "KernelUtils::BlkAlign<uint8_t>(curAivN)"); | ||
| 481 | + EXPECT_EQ(codegen::GenCvUbFuseAddrOffset(tpipe, cube), "0 + cv_m * curAlignN + cv_n * ELEMENT_PER_VECTOR_LENGTH"); | ||
| 482 | + EXPECT_EQ(codegen::GenCvUbFuseAddrOffset(tpipe, fp16_input), | ||
| 483 | + "0 + cv_m * KernelUtils::BlkAlign<half>(curAivN) + cv_n * ELEMENT_PER_VECTOR_LENGTH"); | ||
| 484 | + EXPECT_EQ(codegen::GenCvUbFuseAddrOffset(tpipe, bool_output), | ||
| 485 | + "0 + cv_m * KernelUtils::BlkAlign<uint8_t>(curAivN) + cv_n * ELEMENT_PER_VECTOR_LENGTH"); | ||
| 486 | + EXPECT_EQ(codegen::GenCvUbFuseAddrOffset(tpipe, broadcast_input), "0"); | ||
| 487 | +} | ||
| 488 | + | ||
| 489 | +TEST(CodegenKernel, CvUbFuseTensorSizeAssignUsesTensorDtype) { | ||
| 490 | + codegen::Tiler tiler; | ||
| 491 | + codegen::TPipe tpipe("tpipe", tiler); | ||
| 492 | + tpipe.cv_fusion_type = ::ascir::CubeTemplateType::kUBFuse; | ||
| 493 | + | ||
| 494 | + af::AscGraph graph("test_graph"); | ||
| 495 | + af::ascir_op::Data x("x", graph); | ||
| 496 | + auto cube = MakeCvUbFuseTensor(graph, af::DT_FLOAT, 0, {One}, "local_0"); | ||
| 497 | + auto fp16_input = MakeCvUbFuseTensor(graph, af::DT_FLOAT16, 1, {One}, "local_1"); | ||
| 498 | + auto bool_output = MakeCvUbFuseTensor(graph, af::DT_UINT8, 2, {One}, "local_2"); | ||
| 499 | + cube.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 500 | + fp16_input.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 501 | + bool_output.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 502 | + tpipe.tensors.emplace(cube.id, cube); | ||
| 503 | + tpipe.tensors.emplace(fp16_input.id, fp16_input); | ||
| 504 | + tpipe.tensors.emplace(bool_output.id, bool_output); | ||
| 505 | + | ||
| 506 | + std::string result; | ||
| 507 | + ASSERT_EQ(tpipe.TensorSizeAssign("float", result), af::SUCCESS); | ||
| 508 | + EXPECT_NE(result.find("local_0_size = stage_size / sizeof(float);"), std::string::npos); | ||
| 509 | + EXPECT_NE(result.find("local_1_size = stage_size / sizeof(float);"), std::string::npos); | ||
| 510 | + EXPECT_NE(result.find("local_2_size = stage_size / sizeof(float);"), std::string::npos); | ||
| 511 | +} | ||
| 512 | + | ||
| 439 | TEST(CodegenKernel, VfCall_TwoDimLoad_VFLoop) { | 513 | TEST(CodegenKernel, VfCall_TwoDimLoad_VFLoop) { |
| 440 | ge::SetupRuntimeStub(); | 514 | ge::SetupRuntimeStub(); |
| 441 | af::AscGraph graph("test_graph"); | 515 | af::AscGraph graph("test_graph"); |
| @@ -21,6 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | 22 | ||
| 23 | 23 | ||
| 24 | + | ||
| 24 | 25 | ||
| 25 | namespace codegen { | 26 | namespace codegen { |
| 26 | using namespace std; | 27 | using namespace std; |
| @@ -113,6 +114,17 @@ Status CastV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::Axis | |||
| 113 | } | 114 | } |
| 114 | GE_ASSERT_SUCCESS(FillCastNodeParams(this->node, output_dims, output_strides, input_strides)); | 115 | GE_ASSERT_SUCCESS(FillCastNodeParams(this->node, output_dims, output_strides, input_strides)); |
| 115 | stringstream ss; | 116 | stringstream ss; |
| 117 | + if (IsCVFusionStage(this->api_call_context)) { | ||
| 118 | + const auto cv_params = BuildCvApi2DParams(tpipe, x, y); | ||
| 119 | + const std::string input_tensor = x.is_constant ? ("local_blk_tensor_of_" + x.name) : x.Str(); | ||
| 120 | + ss << y.actual_size << " = " << cv_params.first_dim << " * " << cv_params.last_dim << ";" << std::endl; | ||
| 121 | + ss << this->api_name_ << "(" << y << "[0], " << input_tensor << "[0], " << GenCvUint32Dims(cv_params) << ", " | ||
| 122 | + << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride) << ");" | ||
| 123 | + << std::endl; | ||
| 124 | + result = ss.str(); | ||
| 125 | + return af::SUCCESS; | ||
| 126 | + } | ||
| 127 | + | ||
| 116 | size_t outer_repeats_size = param.outer_repeats.size(); | 128 | size_t outer_repeats_size = param.outer_repeats.size(); |
| 117 | std::string scalar_local_blk_tensor_name = "local_blk_tensor_of_" + x.name; | 129 | std::string scalar_local_blk_tensor_name = "local_blk_tensor_of_" + x.name; |
| 118 | if (outer_repeats_size == 0U) { | 130 | if (outer_repeats_size == 0U) { |
| @@ -21,6 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | 22 | ||
| 23 | 23 | ||
| 24 | + | ||
| 24 | 25 | ||
| 25 | namespace codegen { | 26 | namespace codegen { |
| 26 | using namespace std; | 27 | using namespace std; |
| @@ -125,6 +126,7 @@ Status CompareV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::A | |||
| 125 | } | 126 | } |
| 126 | 127 | ||
| 127 | if (x2.IsAnyScalar()) { | 128 | if (x2.IsAnyScalar()) { |
| 129 | + const std::string actual_size = x1.actual_size.Str(); | ||
| 128 | ub_inputs.push_back(x1); | 130 | ub_inputs.push_back(x1); |
| 129 | ub_outputs.push_back(y); | 131 | ub_outputs.push_back(y); |
| 130 | bool status = GenerateVectorizedAxisMergeStatus(ub_inputs, ub_outputs, merge_info, tpipe); | 132 | bool status = GenerateVectorizedAxisMergeStatus(ub_inputs, ub_outputs, merge_info, tpipe); |
| @@ -138,14 +140,22 @@ Status CompareV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::A | |||
| 138 | GE_ASSERT_SUCCESS( | 140 | GE_ASSERT_SUCCESS( |
| 139 | FillCompareNodeParams(this->node, true, outer_call_count, output_dims, output_strides, input_strides)); | 141 | FillCompareNodeParams(this->node, true, outer_call_count, output_dims, output_strides, input_strides)); |
| 140 | std::string scalar_local_blk_tensor_name_x2 = x2.IsConstScalar() ? "local_blk_tensor_of_" + x2.name : x2.name; | 142 | std::string scalar_local_blk_tensor_name_x2 = x2.IsConstScalar() ? "local_blk_tensor_of_" + x2.name : x2.name; |
| 141 | - scalar_local_blk_tensor_name_x2 = scalar_local_blk_tensor_name_x2; | ||
| 142 | size_t outer_repeats_size = param.outer_repeats.size(); | 143 | size_t outer_repeats_size = param.outer_repeats.size(); |
| 143 | if (outer_repeats_size == 0U) { | 144 | if (outer_repeats_size == 0U) { |
| 144 | - ss << "CompareScalarExtend<" << dtype_name << ", 1, CMPMODE::" << this->api_name_ << ">(" << y << "[" | 145 | + if (IsCVFusionStage(this->api_call_context)) { |
| 145 | - << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "[" | 146 | + const auto cv_params = BuildCvApi2DParams(tpipe, x1, y); |
| 146 | - << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2_scalar << ", " | 147 | + ss << "CompareScalarExtend<" << dtype_name << ", 2, CMPMODE::" << this->api_name_ << ">(" << y << "[" |
| 147 | - << "{static_cast<uint16_t>(" << x1.actual_size | 148 | + << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "[" |
| 148 | - << ")}, {static_cast<uint16_t>(1)}, {static_cast<uint16_t>(1)});" << std::endl; | 149 | + << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2_scalar << ", " |
| 150 | + << GenCvUint16Dims(cv_params) << ", " << GenCvUint16Stride(cv_params.output_stride) << ", " | ||
| 151 | + << GenCvUint16Stride(cv_params.input_stride) << ");" << std::endl; | ||
| 152 | + } else { | ||
| 153 | + ss << "CompareScalarExtend<" << dtype_name << ", 1, CMPMODE::" << this->api_name_ << ">(" << y << "[" | ||
| 154 | + << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "[" | ||
| 155 | + << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2_scalar << ", " | ||
| 156 | + << "{static_cast<uint16_t>(" << actual_size << ")}, {static_cast<uint16_t>(1)}, {static_cast<uint16_t>(1)});" | ||
| 157 | + << std::endl; | ||
| 158 | + } | ||
| 149 | } else { | 159 | } else { |
| 150 | std::stringstream ss1; | 160 | std::stringstream ss1; |
| 151 | size_t input0_strides_size = param.inputs_strides[0].size(); | 161 | size_t input0_strides_size = param.inputs_strides[0].size(); |
| @@ -170,6 +180,7 @@ Status CompareV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::A | |||
| 170 | CreateComputeNodeOuterForIfRequired(outer_repeats_size, param, ss1, ss); | 180 | CreateComputeNodeOuterForIfRequired(outer_repeats_size, param, ss1, ss); |
| 171 | } | 181 | } |
| 172 | } else { | 182 | } else { |
| 183 | + const std::string actual_size = x1.actual_size.Str(); | ||
| 173 | ub_inputs.push_back(x1); | 184 | ub_inputs.push_back(x1); |
| 174 | ub_inputs.push_back(x2); | 185 | ub_inputs.push_back(x2); |
| 175 | ub_outputs.push_back(y); | 186 | ub_outputs.push_back(y); |
| @@ -185,12 +196,22 @@ Status CompareV2ApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::A | |||
| 185 | FillCompareNodeParams(this->node, false, outer_call_count, output_dims, output_strides, input_strides)); | 196 | FillCompareNodeParams(this->node, false, outer_call_count, output_dims, output_strides, input_strides)); |
| 186 | size_t outer_repeats_size = param.outer_repeats.size(); | 197 | size_t outer_repeats_size = param.outer_repeats.size(); |
| 187 | if (outer_repeats_size == 0U) { | 198 | if (outer_repeats_size == 0U) { |
| 188 | - ss << "CompareExtend<" << dtype_name << ", 1, CMPMODE::" << this->api_name_ << ">(" << y << "[" | 199 | + if (IsCVFusionStage(this->api_call_context)) { |
| 189 | - << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "[" | 200 | + const auto cv_params = BuildCvApi2DParams(tpipe, x1, y); |
| 190 | - << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "[" | 201 | + ss << "CompareExtend<" << dtype_name << ", 2, CMPMODE::" << this->api_name_ << ">(" << y << "[" |
| 191 | - << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], " | 202 | + << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "[" |
| 192 | - << "{static_cast<uint16_t>(" << x1.actual_size | 203 | + << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "[" |
| 193 | - << ")}, {static_cast<uint16_t>(1)}, {static_cast<uint16_t>(1)});" << std::endl; | 204 | + << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], " << GenCvUint16Dims(cv_params) << ", " |
| 205 | + << GenCvUint16Stride(cv_params.output_stride) << ", " << GenCvUint16Stride(cv_params.input_stride) << ");" | ||
| 206 | + << std::endl; | ||
| 207 | + } else { | ||
| 208 | + ss << "CompareExtend<" << dtype_name << ", 1, CMPMODE::" << this->api_name_ << ">(" << y << "[" | ||
| 209 | + << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x1 << "[" | ||
| 210 | + << tpipe.tiler.TensorVectorizedOffset(current_axis, x1) << "], " << x2 << "[" | ||
| 211 | + << tpipe.tiler.TensorVectorizedOffset(current_axis, x2) << "], " | ||
| 212 | + << "{static_cast<uint16_t>(" << actual_size << ")}, {static_cast<uint16_t>(1)}, {static_cast<uint16_t>(1)});" | ||
| 213 | + << std::endl; | ||
| 214 | + } | ||
| 194 | } else { | 215 | } else { |
| 195 | size_t input0_strides_size = param.inputs_strides[0].size(); | 216 | size_t input0_strides_size = param.inputs_strides[0].size(); |
| 196 | std::vector<ascir::SizeExpr> inner0_input_strides(param.inputs_strides[0].begin(), | 217 | std::vector<ascir::SizeExpr> inner0_input_strides(param.inputs_strides[0].begin(), |
| @@ -16,8 +16,10 @@ | |||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | + | ||
| 19 | 20 | ||
| 20 | 21 | ||
| 22 | + | ||
| 21 | 23 | ||
| 22 | namespace codegen { | 24 | namespace codegen { |
| 23 | using namespace std; | 25 | using namespace std; |
| @@ -35,6 +37,15 @@ Status FloorToIntApiCall::Generate(const TPipe &tpipe, const std::vector<ascir:: | |||
| 35 | GELOGI("FloorToInt x_dtype:%d, y_dtype:%d.", static_cast<int32_t>(x.dtype), static_cast<int32_t>(y.dtype)); | 37 | GELOGI("FloorToInt x_dtype:%d, y_dtype:%d.", static_cast<int32_t>(x.dtype), static_cast<int32_t>(y.dtype)); |
| 36 | stringstream ss; | 38 | stringstream ss; |
| 37 | 39 | ||
| 40 | + if (IsCVFusionStage(this->api_call_context)) { | ||
| 41 | + const auto cv_params = BuildCvApi2DParams(tpipe, x, y); | ||
| 42 | + ss << "AscendC::Cast(" << y << "[0], " << x << "[0], AscendC::RoundMode::CAST_FLOOR, " << GenCvUint32Dims(cv_params) | ||
| 43 | + << ", " << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride) | ||
| 44 | + << ");" << std::endl; | ||
| 45 | + result = ss.str(); | ||
| 46 | + return af::SUCCESS; | ||
| 47 | + } | ||
| 48 | + | ||
| 38 | ss << "AscendC::Cast(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "[" | 49 | ss << "AscendC::Cast(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "[" |
| 39 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " | 50 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " |
| 40 | << "AscendC::RoundMode::CAST_FLOOR, " << x.actual_size << ");" << std::endl; | 51 | << "AscendC::RoundMode::CAST_FLOOR, " << x.actual_size << ");" << std::endl; |
| @@ -20,6 +20,37 @@ constexpr char kCompactPddingMode[] = "AscendC::PaddingMode::Compact"; | |||
| 20 | } // namespace | 20 | } // namespace |
| 21 | 21 | ||
| 22 | namespace codegen { | 22 | namespace codegen { |
| 23 | +CvApi2DParams BuildCvApi2DParams(const TPipe &tpipe, const Tensor &input, const Tensor &output) { | ||
| 24 | + CvApi2DParams params; | ||
| 25 | + params.first_dim = "curAivM"; | ||
| 26 | + params.last_dim = "curAivN"; | ||
| 27 | + params.output_stride = GenBlockAlignNExpr(output, params.last_dim); | ||
| 28 | + const bool input_is_cube_output = | ||
| 29 | + tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse && input.id == tpipe.cube_output_tensor_id; | ||
| 30 | + params.input_stride = input_is_cube_output ? "curAlignN" : GenBlockAlignNExpr(input, params.last_dim); | ||
| 31 | + return params; | ||
| 32 | +} | ||
| 33 | + | ||
| 34 | +std::string GenCvUint32Dims(const CvApi2DParams ¶ms) { | ||
| 35 | + return "{ConvertToUint32(" + params.first_dim + "), ConvertToUint32(" + params.last_dim + ")}"; | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | +std::string GenCvUint32Stride(const std::string &stride) { | ||
| 39 | + return "{ConvertToUint32(" + stride + "), ConvertToUint32(1)}"; | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +std::string GenCvUint16Dims(const CvApi2DParams ¶ms) { | ||
| 43 | + return "{static_cast<uint16_t>(" + params.first_dim + "), static_cast<uint16_t>(" + params.last_dim + ")}"; | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +std::string GenCvUint16Stride(const std::string &stride) { | ||
| 47 | + return "{static_cast<uint16_t>(" + stride + "), static_cast<uint16_t>(1)}"; | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +std::string GetCvInputAlignedSize(const ApiCallContext &context, const Tensor &input, const std::string &size_expr) { | ||
| 51 | + return IsCVFusionStage(context) ? GenBlockAlignNExpr(input, size_expr) : size_expr; | ||
| 52 | +} | ||
| 53 | + | ||
| 23 | // A5场景,拷贝指令增强,可以通过loop_mode_params消掉另外两层for循环 | 54 | // A5场景,拷贝指令增强,可以通过loop_mode_params消掉另外两层for循环 |
| 24 | void SetLoopModeParams(const TPipe &tpipe, const DataCopyParams &data_copy_param, LoopModeParams &loop_mode_param, | 55 | void SetLoopModeParams(const TPipe &tpipe, const DataCopyParams &data_copy_param, LoopModeParams &loop_mode_param, |
| 25 | bool copy_in) { | 56 | bool copy_in) { |
| @@ -223,19 +254,30 @@ void CreateNddmaCall(const TPipe &tpipe, const Tensor &input, const Tensor &outp | |||
| 223 | CreateOuterFor(tpipe, repeats, ss1, ss, 0UL); | 254 | CreateOuterFor(tpipe, repeats, ss1, ss, 0UL); |
| 224 | } | 255 | } |
| 225 | 256 | ||
| 226 | -void BuildDataCopyApiParamInCVFusion(CodegenApiParam &api_param, DmaSpecificParams &dma_specific_params, | 257 | +void BuildDataCopyApiParamInCVFusion(const TPipe &tpipe, CodegenApiParam &api_param, |
| 227 | - const Tensor &gm, const Tensor &ub, std::string &dtype_name, bool copy_in) { | 258 | + DmaSpecificParams &dma_specific_params, const Tensor &gm, const Tensor &ub, |
| 259 | + std::string &dtype_name, bool copy_in) { | ||
| 228 | api_param.template_params.emplace_back("AscendC::PaddingMode::Normal"); | 260 | api_param.template_params.emplace_back("AscendC::PaddingMode::Normal"); |
| 229 | dma_specific_params.data_copy_params.valid = true; // 标记数据有效 | 261 | dma_specific_params.data_copy_params.valid = true; // 标记数据有效 |
| 230 | dma_specific_params.data_copy_params.block_count = CombinedExprFactory::SymbolVar("curAivM"); | 262 | dma_specific_params.data_copy_params.block_count = CombinedExprFactory::SymbolVar("curAivM"); |
| 231 | if (copy_in) { | 263 | if (copy_in) { |
| 232 | api_param.input_params.emplace_back(gm.Str(), true, CombinedExprFactory::SymbolVar("offset")); | 264 | api_param.input_params.emplace_back(gm.Str(), true, CombinedExprFactory::SymbolVar("offset")); |
| 233 | api_param.output_params.emplace_back(ub.Str(), true, CombinedExprFactory::Constant(0)); | 265 | api_param.output_params.emplace_back(ub.Str(), true, CombinedExprFactory::Constant(0)); |
| 234 | - dma_specific_params.data_copy_params.block_len = CombinedExprFactory::SymbolVar("load_block_len"); | 266 | + if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) { |
| 235 | - dma_specific_params.data_copy_params.src_stride = CombinedExprFactory::SymbolVar("load_src_stride"); | 267 | + const auto aligned_n = "KernelUtils::BlkAlign<" + dtype_name + ">(curAivN)"; |
| 236 | - dma_specific_params.data_copy_params.dst_stride = CombinedExprFactory::SymbolVar("load_dst_stride"); | 268 | + dma_specific_params.data_copy_params.block_len = CombinedExprFactory::SymbolVar("curAivN"); |
| 269 | + dma_specific_params.data_copy_params.src_stride = | ||
| 270 | + CombinedExpression(ExprItemFactory::SymbolVar("shapeN"), ExprItemFactory::SymbolVar("curAivN"), "-"); | ||
| 271 | + dma_specific_params.data_copy_params.dst_stride = | ||
| 272 | + CombinedExpression(ExprItemFactory::SymbolVar(aligned_n), ExprItemFactory::SymbolVar("curAivN"), "-"); | ||
| 273 | + } else { | ||
| 274 | + dma_specific_params.data_copy_params.block_len = CombinedExprFactory::SymbolVar("load_block_len"); | ||
| 275 | + dma_specific_params.data_copy_params.src_stride = CombinedExprFactory::SymbolVar("load_src_stride"); | ||
| 276 | + dma_specific_params.data_copy_params.dst_stride = CombinedExprFactory::SymbolVar("load_dst_stride"); | ||
| 277 | + } | ||
| 237 | int dtype_size = GetSizeByDataType(gm.dtype); | 278 | int dtype_size = GetSizeByDataType(gm.dtype); |
| 238 | - if (dtype_size == 1 || dtype_size == 2 || dtype_size == 4) { | 279 | + if (tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse && |
| 280 | + (dtype_size == 1 || dtype_size == 2 || dtype_size == 4)) { | ||
| 239 | // LoadAlign仅支持字节大小为1、2、4的数据类型,否则GatherMask编译错误。 | 281 | // LoadAlign仅支持字节大小为1、2、4的数据类型,否则GatherMask编译错误。 |
| 240 | // 超过4字节的数据类型,CV融合场景下目前一定是对齐拷入的,不需要RemovePad。 | 282 | // 超过4字节的数据类型,CV融合场景下目前一定是对齐拷入的,不需要RemovePad。 |
| 241 | std::stringstream ss; | 283 | std::stringstream ss; |
| @@ -255,8 +297,10 @@ void BuildDataCopyApiParamInCVFusion(CodegenApiParam &api_param, DmaSpecificPara | |||
| 255 | } else { | 297 | } else { |
| 256 | api_param.output_params.emplace_back(gm.Str(), true, CombinedExprFactory::SymbolVar("offset")); | 298 | api_param.output_params.emplace_back(gm.Str(), true, CombinedExprFactory::SymbolVar("offset")); |
| 257 | api_param.input_params.emplace_back(ub.Str(), true, CombinedExprFactory::Constant(0)); | 299 | api_param.input_params.emplace_back(ub.Str(), true, CombinedExprFactory::Constant(0)); |
| 300 | + const auto aligned_n = "KernelUtils::BlkAlign<" + dtype_name + ">(curAivN)"; | ||
| 258 | dma_specific_params.data_copy_params.block_len = CombinedExprFactory::SymbolVar("curAivN"); | 301 | dma_specific_params.data_copy_params.block_len = CombinedExprFactory::SymbolVar("curAivN"); |
| 259 | - dma_specific_params.data_copy_params.src_stride = CombinedExprFactory::Constant(0); | 302 | + dma_specific_params.data_copy_params.src_stride = |
| 303 | + CombinedExpression(ExprItemFactory::SymbolVar(aligned_n), ExprItemFactory::SymbolVar("curAivN"), "-"); | ||
| 260 | // dst_stride = shapeN - curAivN | 304 | // dst_stride = shapeN - curAivN |
| 261 | dma_specific_params.data_copy_params.dst_stride = | 305 | dma_specific_params.data_copy_params.dst_stride = |
| 262 | CombinedExpression(ExprItemFactory::SymbolVar("shapeN"), ExprItemFactory::SymbolVar("curAivN"), "-"); | 306 | CombinedExpression(ExprItemFactory::SymbolVar("shapeN"), ExprItemFactory::SymbolVar("curAivN"), "-"); |
| @@ -60,6 +60,20 @@ struct NddmaParams { | |||
| 60 | std::stringstream ss_input_stride; | 60 | std::stringstream ss_input_stride; |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | +struct CvApi2DParams { | ||
| 64 | + std::string first_dim; | ||
| 65 | + std::string last_dim; | ||
| 66 | + std::string output_stride; | ||
| 67 | + std::string input_stride; | ||
| 68 | +}; | ||
| 69 | + | ||
| 70 | +CvApi2DParams BuildCvApi2DParams(const TPipe &tpipe, const Tensor &input, const Tensor &output); | ||
| 71 | +std::string GenCvUint32Dims(const CvApi2DParams ¶ms); | ||
| 72 | +std::string GenCvUint32Stride(const std::string &stride); | ||
| 73 | +std::string GenCvUint16Dims(const CvApi2DParams ¶ms); | ||
| 74 | +std::string GenCvUint16Stride(const std::string &stride); | ||
| 75 | +std::string GetCvInputAlignedSize(const ApiCallContext &context, const Tensor &input, const std::string &size_expr); | ||
| 76 | + | ||
| 63 | void CreateEnhanceDmaCall(const TPipe &tpipe, const Tensor &input, const Tensor &output, const string &gm_offset, | 77 | void CreateEnhanceDmaCall(const TPipe &tpipe, const Tensor &input, const Tensor &output, const string &gm_offset, |
| 64 | const DataCopyParams &data_copy_param, const ascir::SizeExpr &offset, std::stringstream &ss, | 78 | const DataCopyParams &data_copy_param, const ascir::SizeExpr &offset, std::stringstream &ss, |
| 65 | bool copy_in); | 79 | bool copy_in); |
| @@ -71,8 +85,9 @@ void SetLoopModeParams(const TPipe &tpipe, const DataCopyParams &data_copy_param | |||
| 71 | bool copy_in); | 85 | bool copy_in); |
| 72 | void SetLoopModeParamsExpr(const DataCopyParams &data_copy_param, LoopModeParamsExpr &loop_mode_param, bool copy_in); | 86 | void SetLoopModeParamsExpr(const DataCopyParams &data_copy_param, LoopModeParamsExpr &loop_mode_param, bool copy_in); |
| 73 | std::string GetPaddingMode(const TPipe &tpipe, const Tensor &ub_tensor, const DataCopyParams &data_copy_param); | 87 | std::string GetPaddingMode(const TPipe &tpipe, const Tensor &ub_tensor, const DataCopyParams &data_copy_param); |
| 74 | -void BuildDataCopyApiParamInCVFusion(CodegenApiParam &api_param, DmaSpecificParams &dma_specific_params, | 88 | +void BuildDataCopyApiParamInCVFusion(const TPipe &tpipe, CodegenApiParam &api_param, |
| 75 | - const Tensor &gm, const Tensor &ub, std::string &dtype_name, bool copy_in); | 89 | + DmaSpecificParams &dma_specific_params, const Tensor &gm, const Tensor &ub, |
| 90 | + std::string &dtype_name, bool copy_in); | ||
| 76 | Status BuildDataCopyApiParamInNormal(const TPipe &tpipe, CodegenApiParam &api_param, | 91 | Status BuildDataCopyApiParamInNormal(const TPipe &tpipe, CodegenApiParam &api_param, |
| 77 | DmaSpecificParams &dma_specific_params, const Tensor &src, const Tensor &dst, | 92 | DmaSpecificParams &dma_specific_params, const Tensor &src, const Tensor &dst, |
| 78 | std::string &gm_offset, bool copy_in); | 93 | std::string &gm_offset, bool copy_in); |
| @@ -23,10 +23,6 @@ | |||
| 23 | using namespace af::ops; | 23 | using namespace af::ops; |
| 24 | using namespace af::ascir_op; | 24 | using namespace af::ascir_op; |
| 25 | 25 | ||
| 26 | -namespace { | ||
| 27 | -constexpr size_t kDmaMaxLen = 2U; | ||
| 28 | -constexpr size_t kFourAxisNum = 4U; | ||
| 29 | -} // namespace | ||
| 30 | namespace codegen { | 26 | namespace codegen { |
| 31 | Status LoadRegApiCall::ParseAttr(const ascir::NodeView &node) { | 27 | Status LoadRegApiCall::ParseAttr(const ascir::NodeView &node) { |
| 32 | (void)node->attr.ir_attr->GetAttrValue("offset", offset_); | 28 | (void)node->attr.ir_attr->GetAttrValue("offset", offset_); |
| @@ -46,7 +42,7 @@ Status LoadRegApiCall::BuildApiParam(const TPipe &tpipe, const std::vector<ascir | |||
| 46 | api_param->template_params.emplace_back(dtype_name); | 42 | api_param->template_params.emplace_back(dtype_name); |
| 47 | DmaSpecificParams dma_specific_params; | 43 | DmaSpecificParams dma_specific_params; |
| 48 | if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse && !ub.is_ub_scalar) { | 44 | if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse && !ub.is_ub_scalar) { |
| 49 | - BuildDataCopyApiParamInCVFusion(*api_param, dma_specific_params, gm, ub, dtype_name, true); | 45 | + BuildDataCopyApiParamInCVFusion(tpipe, *api_param, dma_specific_params, gm, ub, dtype_name, true); |
| 50 | } else { | 46 | } else { |
| 51 | std::string gm_offset = ub.is_ub_scalar ? "0" : tpipe.tiler.Offset(current_axis, ub.axis, ub.axis_strides); | 47 | std::string gm_offset = ub.is_ub_scalar ? "0" : tpipe.tiler.Offset(current_axis, ub.axis, ub.axis_strides); |
| 52 | gm_offset = gm_offset + " + " + tpipe.tiler.Size(offset_); | 48 | gm_offset = gm_offset + " + " + tpipe.tiler.Size(offset_); |
| @@ -36,52 +36,32 @@ void AppendCvNddmaCall(std::stringstream &ss, const std::string &api_name, const | |||
| 36 | << "output_stride_" << ub.id << ", " << "input_stride_" << ub.id << ");" << std::endl; | 36 | << "output_stride_" << ub.id << ", " << "input_stride_" << ub.id << ");" << std::endl; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | -Status GenerateInductorUbFuseNddma(const std::string &api_name, const Tensor &gm, const Tensor &ub, | 39 | +Status GenerateCvUbFuseNddma(const std::string &api_name, const Tensor &gm, const Tensor &ub, std::stringstream &ss) { |
| 40 | - std::stringstream &ss) { | ||
| 41 | GE_ASSERT_TRUE(gm.axis_strides.size() >= 2U, "Nddma src axis-strides less than 2 is invalid in CV-Fusion case"); | 40 | GE_ASSERT_TRUE(gm.axis_strides.size() >= 2U, "Nddma src axis-strides less than 2 is invalid in CV-Fusion case"); |
| 42 | auto last_index = gm.axis_strides.size() - 1U; | 41 | auto last_index = gm.axis_strides.size() - 1U; |
| 43 | auto second_to_last_index = gm.axis_strides.size() - 2U; | 42 | auto second_to_last_index = gm.axis_strides.size() - 2U; |
| 44 | - ss << "const int64_t output_dims_" << ub.id << "[2] = {curAivM, curAlignN};" << std::endl; | 43 | + std::string dtype_name; |
| 44 | + GE_CHK_STATUS_RET(Tensor::DtypeName(ub.dtype, dtype_name), "Codegen get data type:%d failed", | ||
| 45 | + static_cast<int32_t>(ub.dtype)); | ||
| 46 | + const std::string output_stride = "KernelUtils::BlkAlign<" + dtype_name + ">(curAivN)"; | ||
| 47 | + ss << "const int64_t output_dims_" << ub.id << "[2] = {curAivM, curAivN};" << std::endl; | ||
| 45 | std::string gm_offset; | 48 | std::string gm_offset; |
| 46 | if (IsZeroStride(gm, second_to_last_index) && IsZeroStride(gm, last_index)) { | 49 | if (IsZeroStride(gm, second_to_last_index) && IsZeroStride(gm, last_index)) { |
| 47 | ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 0};" << std::endl; | 50 | ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 0};" << std::endl; |
| 48 | - ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl; | 51 | + ss << "const int64_t output_stride_" << ub.id << "[2] = {" << output_stride << ", 1};" << std::endl; |
| 49 | gm_offset = "batch_num"; | 52 | gm_offset = "batch_num"; |
| 50 | } else if (IsZeroStride(gm, second_to_last_index) && !IsZeroStride(gm, last_index)) { | 53 | } else if (IsZeroStride(gm, second_to_last_index) && !IsZeroStride(gm, last_index)) { |
| 51 | ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 1};" << std::endl; | 54 | ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 1};" << std::endl; |
| 52 | - ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl; | 55 | + ss << "const int64_t output_stride_" << ub.id << "[2] = {" << output_stride << ", 1};" << std::endl; |
| 53 | gm_offset = "offset % shapeN + batch_num * shapeN"; | 56 | gm_offset = "offset % shapeN + batch_num * shapeN"; |
| 54 | } else if (!IsZeroStride(gm, second_to_last_index) && IsZeroStride(gm, last_index)) { | 57 | } else if (!IsZeroStride(gm, second_to_last_index) && IsZeroStride(gm, last_index)) { |
| 55 | ss << "const int64_t input_stride_" << ub.id << "[2] = {1, 0};" << std::endl; | 58 | ss << "const int64_t input_stride_" << ub.id << "[2] = {1, 0};" << std::endl; |
| 56 | - ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl; | 59 | + ss << "const int64_t output_stride_" << ub.id << "[2] = {" << output_stride << ", 1};" << std::endl; |
| 57 | gm_offset = "offset / shapeN"; | 60 | gm_offset = "offset / shapeN"; |
| 58 | } else { | 61 | } else { |
| 59 | - ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 1};" << std::endl; | 62 | + ss << "const int64_t input_stride_" << ub.id << "[2] = {shapeN, 1};" << std::endl; |
| 60 | - ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl; | 63 | + ss << "const int64_t output_stride_" << ub.id << "[2] = {" << output_stride << ", 1};" << std::endl; |
| 61 | - gm_offset = "offset % shapeN + batch_num * shapeN"; | 64 | + gm_offset = "offset"; |
| 62 | - } | ||
| 63 | - AppendCvNddmaCall(ss, api_name, gm, ub, gm_offset); | ||
| 64 | - return af::SUCCESS; | ||
| 65 | -} | ||
| 66 | - | ||
| 67 | -Status GenerateUbFuseNddma(const std::string &api_name, const Tensor &gm, const Tensor &ub, std::stringstream &ss) { | ||
| 68 | - GE_ASSERT_TRUE(gm.axis_size.size() >= 2U, "Nddma src axis-size less than 2 is invalid in CV-Fusion case"); | ||
| 69 | - auto last_index = gm.axis_size.size() - 1U; | ||
| 70 | - auto second_to_last_index = gm.axis_size.size() - 2U; | ||
| 71 | - ss << "const int64_t output_dims_" << ub.id << "[2] = {curAivM, curAlignN};" << std::endl; | ||
| 72 | - std::string gm_offset; | ||
| 73 | - if ((gm.axis_size[second_to_last_index] == One) && (gm.axis_size[last_index] == One)) { | ||
| 74 | - ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 0};" << std::endl; | ||
| 75 | - ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl; | ||
| 76 | - gm_offset = "batch_num"; | ||
| 77 | - } else if (gm.axis_size[second_to_last_index] == One) { | ||
| 78 | - ss << "const int64_t input_stride_" << ub.id << "[2] = {0, 1};" << std::endl; | ||
| 79 | - ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl; | ||
| 80 | - gm_offset = "offset % shapeN + batch_num * shapeN"; | ||
| 81 | - } else if (gm.axis_size[last_index] == One) { | ||
| 82 | - ss << "const int64_t input_stride_" << ub.id << "[2] = {1, 0};" << std::endl; | ||
| 83 | - ss << "const int64_t output_stride_" << ub.id << "[2] = {curAlignN, 1};" << std::endl; | ||
| 84 | - gm_offset = "offset / shapeN"; | ||
| 85 | } | 65 | } |
| 86 | AppendCvNddmaCall(ss, api_name, gm, ub, gm_offset); | 66 | AppendCvNddmaCall(ss, api_name, gm, ub, gm_offset); |
| 87 | return af::SUCCESS; | 67 | return af::SUCCESS; |
| @@ -120,10 +100,8 @@ Status NddmaApiCall::Generate(const TPipe &tpipe, const std::vector<ascir::AxisI | |||
| 120 | const auto &gm = inputs[0].get(); | 100 | const auto &gm = inputs[0].get(); |
| 121 | const auto &ub = outputs[0].get(); | 101 | const auto &ub = outputs[0].get(); |
| 122 | (void)RegisterBasicDumpParam(this->api_name_, inputs, outputs); | 102 | (void)RegisterBasicDumpParam(this->api_name_, inputs, outputs); |
| 123 | - if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse && tpipe.is_inductor) { | 103 | + if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) { |
| 124 | - GE_ASSERT_SUCCESS(GenerateInductorUbFuseNddma(api_name_, gm, ub, ss)); | 104 | + GE_ASSERT_SUCCESS(GenerateCvUbFuseNddma(api_name_, gm, ub, ss)); |
| 125 | - } else if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) { | ||
| 126 | - GE_ASSERT_SUCCESS(GenerateUbFuseNddma(api_name_, gm, ub, ss)); | ||
| 127 | } else { | 105 | } else { |
| 128 | GE_ASSERT_SUCCESS(GenerateDefaultNddma(tpipe, current_axis, api_name_, gm, ub, offset_, ss)); | 106 | GE_ASSERT_SUCCESS(GenerateDefaultNddma(tpipe, current_axis, api_name_, gm, ub, offset_, ss)); |
| 129 | } | 107 | } |
| @@ -54,7 +54,7 @@ Status StoreRegApiCall::BuildApiParam(const TPipe &tpipe, const std::vector<asci | |||
| 54 | api_param->template_params.emplace_back(dtype_name); | 54 | api_param->template_params.emplace_back(dtype_name); |
| 55 | DmaSpecificParams dma_specific_params; | 55 | DmaSpecificParams dma_specific_params; |
| 56 | if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) { | 56 | if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) { |
| 57 | - BuildDataCopyApiParamInCVFusion(*api_param, dma_specific_params, gm, ub, dtype_name, false); | 57 | + BuildDataCopyApiParamInCVFusion(tpipe, *api_param, dma_specific_params, gm, ub, dtype_name, false); |
| 58 | } else { | 58 | } else { |
| 59 | std::string gm_offset = tpipe.tiler.Offset(current_axis, gm.axis, gm.axis_strides); | 59 | std::string gm_offset = tpipe.tiler.Offset(current_axis, gm.axis, gm.axis_strides); |
| 60 | gm_offset = gm_offset + " + " + tpipe.tiler.Size(offset_); | 60 | gm_offset = gm_offset + " + " + tpipe.tiler.Size(offset_); |
| @@ -10,20 +10,14 @@ | |||
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | - | ||
| 14 | - | ||
| 15 | 13 | ||
| 16 | 14 | ||
| 17 | - | ||
| 18 | 15 | ||
| 19 | 16 | ||
| 20 | 17 | ||
| 21 | - | ||
| 22 | 18 | ||
| 23 | namespace codegen { | 19 | namespace codegen { |
| 24 | using namespace std; | 20 | using namespace std; |
| 25 | -using namespace af::ops; | ||
| 26 | -using namespace af::ascir_op; | ||
| 27 | using namespace ascgen_utils; | 21 | using namespace ascgen_utils; |
| 28 | 22 | ||
| 29 | Status WhereRegApiCall::PrepareInputsAndOutputs(const std::vector<std::reference_wrapper<const Tensor>> &inputs, | 23 | Status WhereRegApiCall::PrepareInputsAndOutputs(const std::vector<std::reference_wrapper<const Tensor>> &inputs, |
| @@ -92,7 +86,7 @@ Status WhereRegApiCall::GenerateNoLoopCase(const TPipe &tpipe, const std::vector | |||
| 92 | ss << x3 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x3) << "], "; | 86 | ss << x3 << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x3) << "], "; |
| 93 | } | 87 | } |
| 94 | 88 | ||
| 95 | - ss << x1.actual_size << ");" << std::endl; | 89 | + ss << GetCVAlignedSize(this->api_call_context, y, x1.actual_size.Str()) << ");" << std::endl; |
| 96 | 90 | ||
| 97 | return af::SUCCESS; | 91 | return af::SUCCESS; |
| 98 | } | 92 | } |
| @@ -118,7 +112,7 @@ Status WhereRegApiCall::GenerateBothScalarCase(const TPipe &tpipe, const ApiLoop | |||
| 118 | << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << scalar_local_blk_tensor_name_x3 | 112 | << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << scalar_local_blk_tensor_name_x3 |
| 119 | << "[0], " | 113 | << "[0], " |
| 120 | << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>(" | 114 | << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>(" |
| 121 | - << tpipe.tiler.ActualSize(param.cal_count) << ")}, " | 115 | + << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ")}, " |
| 122 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride) | 116 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride) |
| 123 | << "), static_cast<uint16_t>(1)" << "}, " | 117 | << "), static_cast<uint16_t>(1)" << "}, " |
| 124 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride) | 118 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride) |
| @@ -162,7 +156,7 @@ Status WhereRegApiCall::GenerateX2ScalarCase(const TPipe &tpipe, const ApiLoopPa | |||
| 162 | << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << x3 << "[" << input2_inner_offset | 156 | << input0_inner_offset << "], " << scalar_local_blk_tensor_name_x2 << "[0], " << x3 << "[" << input2_inner_offset |
| 163 | << "], " | 157 | << "], " |
| 164 | << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>(" | 158 | << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>(" |
| 165 | - << tpipe.tiler.ActualSize(param.cal_count) << ")}, " | 159 | + << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ")}, " |
| 166 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride) | 160 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride) |
| 167 | << "), static_cast<uint16_t>(1)" << "}, " | 161 | << "), static_cast<uint16_t>(1)" << "}, " |
| 168 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride) | 162 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride) |
| @@ -206,7 +200,7 @@ Status WhereRegApiCall::GenerateX3ScalarCase(const TPipe &tpipe, const ApiLoopPa | |||
| 206 | << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << scalar_local_blk_tensor_name_x3 | 200 | << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << scalar_local_blk_tensor_name_x3 |
| 207 | << "[0], " | 201 | << "[0], " |
| 208 | << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>(" | 202 | << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>(" |
| 209 | - << tpipe.tiler.ActualSize(param.cal_count) << ")}, " | 203 | + << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ")}, " |
| 210 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride) | 204 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride) |
| 211 | << "), static_cast<uint16_t>(1)" << "}, " | 205 | << "), static_cast<uint16_t>(1)" << "}, " |
| 212 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride) | 206 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride) |
| @@ -255,7 +249,7 @@ Status WhereRegApiCall::GenerateNormalCase(const TPipe &tpipe, const ApiLoopPara | |||
| 255 | << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << x3 << "[" << input2_inner_offset | 249 | << input0_inner_offset << "], " << x2 << "[" << input1_inner_offset << "], " << x3 << "[" << input2_inner_offset |
| 256 | << "], " | 250 | << "], " |
| 257 | << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>(" | 251 | << "{static_cast<uint16_t>(" << param.outer_repeats[param.outer_repeats.size() - 1] << "), static_cast<uint16_t>(" |
| 258 | - << tpipe.tiler.ActualSize(param.cal_count) << ")}, " | 252 | + << GetCVAlignedSize(this->api_call_context, y, tpipe.tiler.ActualSize(param.cal_count)) << ")}, " |
| 259 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride) | 253 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.output_second_to_last_stride) |
| 260 | << "), static_cast<uint16_t>(1)" << "}, " | 254 | << "), static_cast<uint16_t>(1)" << "}, " |
| 261 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride) | 255 | << "{static_cast<uint16_t>(" << tpipe.tiler.Size(param.input_second_to_last_stride) |
| @@ -16,8 +16,10 @@ | |||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | + | ||
| 19 | 20 | ||
| 20 | 21 | ||
| 22 | + | ||
| 21 | 23 | ||
| 22 | namespace codegen { | 24 | namespace codegen { |
| 23 | using namespace std; | 25 | using namespace std; |
| @@ -38,6 +40,15 @@ Status RoundToIntApiCall::Generate(const TPipe &tpipe, const std::vector<ascir:: | |||
| 38 | 40 | ||
| 39 | stringstream ss; | 41 | stringstream ss; |
| 40 | 42 | ||
| 43 | + if (IsCVFusionStage(this->api_call_context)) { | ||
| 44 | + const auto cv_params = BuildCvApi2DParams(tpipe, x, y); | ||
| 45 | + ss << "AscendC::Cast(" << y << "[0], " << x << "[0], AscendC::RoundMode::CAST_RINT, " << GenCvUint32Dims(cv_params) | ||
| 46 | + << ", " << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride) | ||
| 47 | + << ");" << std::endl; | ||
| 48 | + result = ss.str(); | ||
| 49 | + return af::SUCCESS; | ||
| 50 | + } | ||
| 51 | + | ||
| 41 | // 使用 AscendC::Cast 函数,设置 round 模式为 CAST_RINT | 52 | // 使用 AscendC::Cast 函数,设置 round 模式为 CAST_RINT |
| 42 | ss << "AscendC::Cast(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "[" | 53 | ss << "AscendC::Cast(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "[" |
| 43 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " | 54 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " |
| @@ -16,8 +16,10 @@ | |||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | + | ||
| 19 | 20 | ||
| 20 | 21 | ||
| 22 | + | ||
| 21 | 23 | ||
| 22 | namespace codegen { | 24 | namespace codegen { |
| 23 | using namespace std; | 25 | using namespace std; |
| @@ -38,6 +40,15 @@ Status TruncToIntApiCall::Generate(const TPipe &tpipe, const std::vector<ascir:: | |||
| 38 | 40 | ||
| 39 | stringstream ss; | 41 | stringstream ss; |
| 40 | 42 | ||
| 43 | + if (IsCVFusionStage(this->api_call_context)) { | ||
| 44 | + const auto cv_params = BuildCvApi2DParams(tpipe, x, y); | ||
| 45 | + ss << "AscendC::Cast(" << y << "[0], " << x << "[0], AscendC::RoundMode::CAST_TRUNC, " << GenCvUint32Dims(cv_params) | ||
| 46 | + << ", " << GenCvUint32Stride(cv_params.output_stride) << ", " << GenCvUint32Stride(cv_params.input_stride) | ||
| 47 | + << ");" << std::endl; | ||
| 48 | + result = ss.str(); | ||
| 49 | + return af::SUCCESS; | ||
| 50 | + } | ||
| 51 | + | ||
| 41 | // 使用 AscendC::Cast 函数,设置 round 模式为 CAST_TRUNC | 52 | // 使用 AscendC::Cast 函数,设置 round 模式为 CAST_TRUNC |
| 42 | ss << "AscendC::Cast(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "[" | 53 | ss << "AscendC::Cast(" << y << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x << "[" |
| 43 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " | 54 | << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " |
| @@ -19,6 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | + | ||
| 22 | namespace codegen { | 23 | namespace codegen { |
| 23 | using namespace std; | 24 | using namespace std; |
| 24 | using namespace af::ops; | 25 | using namespace af::ops; |
| @@ -48,13 +49,15 @@ Status UnaryBitWidthChangeApiCallV2::Generate(const TPipe &tpipe, const std::vec | |||
| 48 | SaveApiLoopAxisParams(merge_info, param); | 49 | SaveApiLoopAxisParams(merge_info, param); |
| 49 | if (param.outer_repeats.size() == 0) { | 50 | if (param.outer_repeats.size() == 0) { |
| 50 | ss << this->api_name_ << "(" << y << "_cast[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x | 51 | ss << this->api_name_ << "(" << y << "_cast[" << tpipe.tiler.TensorVectorizedOffset(current_axis, y) << "], " << x |
| 51 | - << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " << x.actual_size << ");" << std::endl; | 52 | + << "[" << tpipe.tiler.TensorVectorizedOffset(current_axis, x) << "], " |
| 53 | + << GetCvInputAlignedSize(this->api_call_context, x, x.actual_size.Str()) << ");" << std::endl; | ||
| 52 | } else { | 54 | } else { |
| 53 | std::string input_inner_offset = CalcInnerOffset(tpipe, param.inputs_strides[0]); | 55 | std::string input_inner_offset = CalcInnerOffset(tpipe, param.inputs_strides[0]); |
| 54 | std::string output_inner_offset = CalcInnerOffset(tpipe, param.outputs_strides[0]); | 56 | std::string output_inner_offset = CalcInnerOffset(tpipe, param.outputs_strides[0]); |
| 55 | std::stringstream ss1; | 57 | std::stringstream ss1; |
| 56 | ss1 << this->api_name_ << "(" << y << "_cast[" << output_inner_offset << "], " << x << "[" << input_inner_offset | 58 | ss1 << this->api_name_ << "(" << y << "_cast[" << output_inner_offset << "], " << x << "[" << input_inner_offset |
| 57 | - << "], " << tpipe.tiler.ActualSize(param.cal_count) << ");" << std::endl; | 59 | + << "], " << GetCvInputAlignedSize(this->api_call_context, x, tpipe.tiler.ActualSize(param.cal_count)) << ");" |
| 60 | + << std::endl; | ||
| 58 | CreateComputeNodeOuterFor(param.outer_repeats, ss1, ss, 0); | 61 | CreateComputeNodeOuterFor(param.outer_repeats, ss1, ss, 0); |
| 59 | } | 62 | } |
| 60 | 63 | ||
| @@ -114,9 +114,9 @@ void GetOuterForStride(const std::vector<std::vector<ascir::SizeExpr>> &origin_s | |||
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | // 生成vf函数体时,用于处理vf函数入参中的main scalar | 116 | // 生成vf函数体时,用于处理vf函数入参中的main scalar |
| 117 | -void CreateVFCallDimAndStrideParmas(const std::vector<Tensor> &inputs, const std::vector<Tensor> &inputs_scalar, | 117 | +void CreateVFCallDimAndStrideParmas(const TPipe &tpipe, const std::vector<Tensor> &inputs, |
| 118 | - const std::vector<Tensor> &outputs, const VectorizedAxisLoopMergeStatus &merge_info, | 118 | + const std::vector<Tensor> &inputs_scalar, const std::vector<Tensor> &outputs, |
| 119 | - std::stringstream &ss) { | 119 | + const VectorizedAxisLoopMergeStatus &merge_info, std::stringstream &ss) { |
| 120 | string dtype_name; | 120 | string dtype_name; |
| 121 | for (const auto &output : outputs) { | 121 | for (const auto &output : outputs) { |
| 122 | Tensor::DtypeName(output.dtype, dtype_name); | 122 | Tensor::DtypeName(output.dtype, dtype_name); |
| @@ -133,6 +133,12 @@ void CreateVFCallDimAndStrideParmas(const std::vector<Tensor> &inputs, const std | |||
| 133 | ss << dtype_name << " " << in_scalar << ", "; | 133 | ss << dtype_name << " " << in_scalar << ", "; |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | + if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) { | ||
| 137 | + ss << GenCvUbFuseVfFuncDimParams() << ", "; | ||
| 138 | + ParamPostProcess(ss); | ||
| 139 | + return; | ||
| 140 | + } | ||
| 141 | + | ||
| 136 | size_t dim_size = merge_info.merge_repeats_str.size(); | 142 | size_t dim_size = merge_info.merge_repeats_str.size(); |
| 137 | size_t start_idx = dim_size <= kVFMaxLoop ? 0 : dim_size - kVFMaxLoop; | 143 | size_t start_idx = dim_size <= kVFMaxLoop ? 0 : dim_size - kVFMaxLoop; |
| 138 | for (; start_idx < dim_size; start_idx++) { | 144 | for (; start_idx < dim_size; start_idx++) { |
| @@ -152,6 +158,12 @@ void CreateVFCallDimAndStrideParmas(const std::vector<Tensor> &inputs, const std | |||
| 152 | // 生成函数调用入参 | 158 | // 生成函数调用入参 |
| 153 | void CreateDimAndStrideParmas(const TPipe &tpipe, const VectorizedAxisLoopMergeStatus &merge_info, | 159 | void CreateDimAndStrideParmas(const TPipe &tpipe, const VectorizedAxisLoopMergeStatus &merge_info, |
| 154 | std::stringstream &ss) { | 160 | std::stringstream &ss) { |
| 161 | + if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) { | ||
| 162 | + ss << GenCvUbFuseVfCallDimParams() << ", "; | ||
| 163 | + ParamPostProcess(ss); | ||
| 164 | + return; | ||
| 165 | + } | ||
| 166 | + | ||
| 155 | // 生成输入dims | 167 | // 生成输入dims |
| 156 | size_t dim_size = merge_info.merge_repeats_str.size(); | 168 | size_t dim_size = merge_info.merge_repeats_str.size(); |
| 157 | size_t start_idx = dim_size <= kVFMaxLoop ? 0 : dim_size - kVFMaxLoop; | 169 | size_t start_idx = dim_size <= kVFMaxLoop ? 0 : dim_size - kVFMaxLoop; |
| @@ -434,6 +446,87 @@ void GenerateTensorDefs(const TPipe &tpipe, const TensorManager &tensor_mgr, con | |||
| 434 | } | 446 | } |
| 435 | } | 447 | } |
| 436 | 448 | ||
| 449 | +void GenerateVfCallFuncHeader(const TPipe &tpipe, const std::string &vf_call_name, const std::vector<Tensor> &inputs, | ||
| 450 | + const std::vector<Tensor> &scalar_inputs, const std::vector<Tensor> &outputs, | ||
| 451 | + const VectorizedAxisLoopMergeStatus &merge_info, std::stringstream &ss) { | ||
| 452 | + ss << "#if defined(__DAV_C310__) || (defined(__NPU_ARCH__) && (__NPU_ARCH__ == 5102 || __NPU_ARCH__ == 3510))" | ||
| 453 | + << std::endl; | ||
| 454 | + ss << "\ninline __simd_vf__ void " << vf_call_name << "("; | ||
| 455 | + CreateVFCallDimAndStrideParmas(tpipe, inputs, scalar_inputs, outputs, merge_info, ss); | ||
| 456 | + ss << ")" << std::endl; | ||
| 457 | +} | ||
| 458 | + | ||
| 459 | +void GenerateVfCallLoopParams(const TPipe &tpipe, const std::string &max_dtype_size, int32_t stride_depth, | ||
| 460 | + const VectorizedAxisLoopMergeStatus &merge_info, std::stringstream ¶ms) { | ||
| 461 | + if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) { | ||
| 462 | + params << " constexpr static uint32_t VECTOR_LENGTH = AscendC::GetVecLen();\n"; | ||
| 463 | + params << " constexpr static uint32_t SIZE_OF_DTYPE = sizeof(" << max_dtype_size << ");\n"; | ||
| 464 | + params << " constexpr static uint32_t ELEMENT_PER_VECTOR_LENGTH = VECTOR_LENGTH / SIZE_OF_DTYPE;\n"; | ||
| 465 | + params << " uint32_t element_count = static_cast<uint32_t>(curAivN);\n"; | ||
| 466 | + params << " uint16_t loop_times = static_cast<uint16_t>((element_count + ELEMENT_PER_VECTOR_LENGTH - 1) / " | ||
| 467 | + "ELEMENT_PER_VECTOR_LENGTH);\n"; | ||
| 468 | + return; | ||
| 469 | + } | ||
| 470 | + GenerateVectorFuncParams(max_dtype_size, stride_depth, merge_info.merge_axis_ids, params); | ||
| 471 | +} | ||
| 472 | + | ||
| 473 | +void GenerateLocalMemTensorPtrs(const std::vector<Tensor> &outputs, const std::vector<Tensor> &inputs, | ||
| 474 | + std::stringstream &vf_body) { | ||
| 475 | + std::string dtype_name; | ||
| 476 | + for (const auto &output : outputs) { | ||
| 477 | + Tensor::DtypeName(output.dtype, dtype_name); | ||
| 478 | + vf_body << " " << "__local_mem__ " << dtype_name << " *" << output << " = " | ||
| 479 | + << "(__local_mem__ " << dtype_name << " *)" << output << "_addr" << ";\n"; | ||
| 480 | + } | ||
| 481 | + | ||
| 482 | + for (const auto &input : inputs) { | ||
| 483 | + Tensor::DtypeName(input.dtype, dtype_name); | ||
| 484 | + vf_body << " " << "__local_mem__ " << dtype_name << " *" << input << " = " | ||
| 485 | + << "(__local_mem__ " << dtype_name << " *)" << input << "_addr" << ";\n"; | ||
| 486 | + } | ||
| 487 | +} | ||
| 488 | + | ||
| 489 | +void GenerateVfCallBodyPreamble(const TPipe &tpipe, const TensorManager &tensor_mgr, const VFLoop &root_loop, | ||
| 490 | + const std::vector<Tensor> &outputs, const std::vector<Tensor> &inputs, | ||
| 491 | + const std::string &max_dtype_size, std::stringstream &vf_body) { | ||
| 492 | + GenerateLocalMemTensorPtrs(outputs, inputs, vf_body); | ||
| 493 | + GenerateTensorDefs(tpipe, tensor_mgr, root_loop, vf_body); | ||
| 494 | + vf_body << "\nAscendC::MicroAPI::MaskReg preg_main = AscendC::MicroAPI::CreateMask<" << max_dtype_size | ||
| 495 | + << ", AscendC::MicroAPI::MaskPattern::ALL>();\n"; | ||
| 496 | + vf_body << "AscendC::MicroAPI::MaskReg preg_vl1 = AscendC::MicroAPI::CreateMask<" << max_dtype_size | ||
| 497 | + << ", AscendC::MicroAPI::MaskPattern::VL1>();\n"; | ||
| 498 | +} | ||
| 499 | + | ||
| 500 | +af::Status UpdateVectorFuncNodeParams(const af::AscNodePtr &node, const VectorizedAxisLoopMergeStatus &merge_info, | ||
| 501 | + const std::vector<ge::Expression> &all_strides); | ||
| 502 | + | ||
| 503 | +Status GenerateVfCallLoopBody(const TPipe &tpipe, const TensorManager &tensor_mgr, const VFLoop &root_loop, | ||
| 504 | + int32_t stride_depth, const VectorizedAxisLoopMergeStatus &merge_info, | ||
| 505 | + const std::vector<Tensor> &inputs, const std::vector<Tensor> &outputs, | ||
| 506 | + const af::AscNodePtr &node, std::stringstream ¶ms, std::stringstream &vf_body) { | ||
| 507 | + std::string loop_body; | ||
| 508 | + std::string loop_size; | ||
| 509 | + int32_t only_loop_max_depth = -1; | ||
| 510 | + std::vector<std::string> loop_size_vec; | ||
| 511 | + if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) { | ||
| 512 | + root_loop.GenerateCvUbFuse(tpipe, tensor_mgr, loop_body, loop_size); | ||
| 513 | + } else { | ||
| 514 | + root_loop.Generate(tpipe, tensor_mgr, stride_depth, loop_body, loop_size, only_loop_max_depth, loop_size_vec); | ||
| 515 | + } | ||
| 516 | + const bool is_double_loop = tpipe.cv_fusion_type != ascir::CubeTemplateType::kUBFuse && | ||
| 517 | + stride_depth == MAX_VF_AXIS_MERGE_SIZE - 1 && | ||
| 518 | + only_loop_max_depth == MAX_VF_AXIS_MERGE_SIZE - 1; | ||
| 519 | + std::vector<ge::Expression> all_strides; | ||
| 520 | + params << std::endl << loop_size << std::endl; | ||
| 521 | + if (is_double_loop) { // 假如stride_depth为1即两层循环,那实际上loop里递归了三次,分别是0、1、2,在2里单独处理call | ||
| 522 | + GenerateStridesEqualCheck(inputs, outputs, merge_info, all_strides, params); | ||
| 523 | + OptimizeMergeParamsAndLoopSize(loop_size_vec, params); | ||
| 524 | + GE_ASSERT_SUCCESS(UpdateVectorFuncNodeParams(node, merge_info, all_strides)); | ||
| 525 | + } | ||
| 526 | + vf_body << std::endl << loop_body << std::endl; | ||
| 527 | + return af::SUCCESS; | ||
| 528 | +} | ||
| 529 | + | ||
| 437 | af::Status UpdateVectorFuncNodeParams(const af::AscNodePtr &node, const VectorizedAxisLoopMergeStatus &merge_info, | 530 | af::Status UpdateVectorFuncNodeParams(const af::AscNodePtr &node, const VectorizedAxisLoopMergeStatus &merge_info, |
| 438 | const std::vector<ge::Expression> &all_strides) { | 531 | const std::vector<ge::Expression> &all_strides) { |
| 439 | GE_ASSERT_NOTNULL(node); | 532 | GE_ASSERT_NOTNULL(node); |
| @@ -459,11 +552,8 @@ Status VfCall::GenerateFuncDefinition(const TPipe &tpipe, const Tiler &tiler, st | |||
| 459 | bool status = GenerateVectorizedAxisMergeStatus(this->ub_inputs_, this->ub_outputs_, merge_info, tpipe); | 552 | bool status = GenerateVectorizedAxisMergeStatus(this->ub_inputs_, this->ub_outputs_, merge_info, tpipe); |
| 460 | GE_ASSERT_TRUE(status, "GenerateVectorizedAxisMergeStatus failed"); | 553 | GE_ASSERT_TRUE(status, "GenerateVectorizedAxisMergeStatus failed"); |
| 461 | 554 | ||
| 462 | - ss << "#if defined(__DAV_C310__) || (defined(__NPU_ARCH__) && (__NPU_ARCH__ == 5102 || __NPU_ARCH__ == 3510))" | 555 | + GenerateVfCallFuncHeader(tpipe, this->vf_call_name_, this->ub_inputs_, this->scalar_inputs_, this->ub_outputs_, |
| 463 | - << std::endl; | 556 | + merge_info, ss); |
| 464 | - ss << "\ninline __simd_vf__ void " << this->vf_call_name_ << "("; | ||
| 465 | - CreateVFCallDimAndStrideParmas(this->ub_inputs_, this->scalar_inputs_, this->ub_outputs_, merge_info, ss); | ||
| 466 | - ss << ")" << std::endl; | ||
| 467 | 557 | ||
| 468 | // func body | 558 | // func body |
| 469 | std::stringstream params; | 559 | std::stringstream params; |
| @@ -476,44 +566,11 @@ Status VfCall::GenerateFuncDefinition(const TPipe &tpipe, const Tiler &tiler, st | |||
| 476 | // uint32_t element_count = static_cast<uint32_t>(output_dims_0); | 566 | // uint32_t element_count = static_cast<uint32_t>(output_dims_0); |
| 477 | // uint16_t loop_times = static_cast<uint16_t>((element_count + ELEMENT_PER_VECTOR_LENGTH - 1) / | 567 | // uint16_t loop_times = static_cast<uint16_t>((element_count + ELEMENT_PER_VECTOR_LENGTH - 1) / |
| 478 | // ELEMENT_PER_VECTOR_LENGTH); | 568 | // ELEMENT_PER_VECTOR_LENGTH); |
| 479 | - GenerateVectorFuncParams(max_dtype_size_, stride_depth, merge_info.merge_axis_ids, params); | 569 | + GenerateVfCallLoopParams(tpipe, max_dtype_size_, stride_depth, merge_info, params); |
| 480 | - | 570 | + GenerateVfCallBodyPreamble(tpipe, tensor_mgr_, root_loop_, this->ub_outputs_, this->ub_inputs_, max_dtype_size_, |
| 481 | - std::string dtype_name; | 571 | + vf_body); |
| 482 | - for (const auto &output : this->ub_outputs_) { | 572 | + GE_ASSERT_SUCCESS(GenerateVfCallLoopBody(tpipe, tensor_mgr_, root_loop_, stride_depth, merge_info, this->ub_inputs_, |
| 483 | - Tensor::DtypeName(output.dtype, dtype_name); | 573 | + this->ub_outputs_, node, params, vf_body)); |
| 484 | - vf_body << " " << "__local_mem__ " << dtype_name << " *" << output << " = " | ||
| 485 | - << "(__local_mem__ " << dtype_name << " *)" << output << "_addr" << ";\n"; | ||
| 486 | - } | ||
| 487 | - | ||
| 488 | - for (const auto &input : this->ub_inputs_) { | ||
| 489 | - Tensor::DtypeName(input.dtype, dtype_name); | ||
| 490 | - vf_body << " " << "__local_mem__ " << dtype_name << " *" << input << " = " | ||
| 491 | - << "(__local_mem__ " << dtype_name << " *)" << input << "_addr" << ";\n"; | ||
| 492 | - } | ||
| 493 | - | ||
| 494 | - GenerateTensorDefs(tpipe, tensor_mgr_, root_loop_, vf_body); | ||
| 495 | - | ||
| 496 | - // define preg_main and preg_vl1 | ||
| 497 | - vf_body << "\nAscendC::MicroAPI::MaskReg preg_main = AscendC::MicroAPI::CreateMask<" << max_dtype_size_ | ||
| 498 | - << ", AscendC::MicroAPI::MaskPattern::ALL>();\n"; | ||
| 499 | - vf_body << "AscendC::MicroAPI::MaskReg preg_vl1 = AscendC::MicroAPI::CreateMask<" << max_dtype_size_ | ||
| 500 | - << ", AscendC::MicroAPI::MaskPattern::VL1>();\n"; | ||
| 501 | - | ||
| 502 | - std::string loop_body; | ||
| 503 | - std::string loop_size; | ||
| 504 | - int32_t only_loop_max_depth = -1; | ||
| 505 | - std::vector<std::string> 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; | ||
| 510 | - params << std::endl << loop_size << std::endl; | ||
| 511 | - if (is_double_loop) { // 假如stride_depth为1即两层循环,那实际上loop里递归了三次,分别是0、1、2,在2里单独处理call | ||
| 512 | - GenerateStridesEqualCheck(this->ub_inputs_, this->ub_outputs_, merge_info, all_strides, params); | ||
| 513 | - OptimizeMergeParamsAndLoopSize(loop_size_vec, params); | ||
| 514 | - GE_ASSERT_SUCCESS(UpdateVectorFuncNodeParams(node, merge_info, all_strides)); | ||
| 515 | - } | ||
| 516 | - vf_body << std::endl << loop_body << std::endl; | ||
| 517 | GetVFCallFuncBody(params.str(), vf_body.str(), ss); | 574 | GetVFCallFuncBody(params.str(), vf_body.str(), ss); |
| 518 | ss << "#endif" << std::endl; | 575 | ss << "#endif" << std::endl; |
| 519 | 576 | ||
| @@ -22,7 +22,15 @@ using namespace af::ascir_op; | |||
| 22 | namespace codegen { | 22 | namespace codegen { |
| 23 | 23 | ||
| 24 | namespace { | 24 | namespace { |
| 25 | +bool IsStrideZero(const ascir::SizeExpr &stride) { | ||
| 26 | + return af::SymbolicUtils::StaticCheckEq(stride.Simplify(), af::sym::kSymbolZero) == af::TriBool::kTrue; | ||
| 27 | +} | ||
| 28 | + | ||
| 25 | std::string GetUbAddrOffset(const TPipe &tpipe, const MicroApiTensor *®_tensor, const Tensor *&ub_tensor) { | 29 | std::string GetUbAddrOffset(const TPipe &tpipe, const MicroApiTensor *®_tensor, const Tensor *&ub_tensor) { |
| 30 | + if (tpipe.cv_fusion_type == ascir::CubeTemplateType::kUBFuse) { | ||
| 31 | + return GenCvUbFuseAddrOffset(tpipe, *ub_tensor); | ||
| 32 | + } | ||
| 33 | + | ||
| 26 | std::stringstream offset_expr; | 34 | std::stringstream offset_expr; |
| 27 | offset_expr << "0"; | 35 | offset_expr << "0"; |
| 28 | for (size_t i = 0; i < reg_tensor->vectorized_strides_.size(); i++) { | 36 | for (size_t i = 0; i < reg_tensor->vectorized_strides_.size(); i++) { |
| @@ -63,8 +71,70 @@ void GetUbStorePreg(const Tensor *&ub_tensor, std::string &preg_name) { | |||
| 63 | } | 71 | } |
| 64 | preg_name = "preg_vl1"; | 72 | preg_name = "preg_vl1"; |
| 65 | } | 73 | } |
| 74 | + | ||
| 75 | +void GenerateMicroApiCall(const TPipe &tpipe, const TensorManager &tensor_mgr, const VFLoopBody &body, | ||
| 76 | + const std::string &max_dtype_size, std::string &preg_name, std::stringstream &ss) { | ||
| 77 | + std::string ub_offset = ""; | ||
| 78 | + if (body.call_->GetMicroApiName() == "Load") { | ||
| 79 | + const MicroApiTensor *reg_tensor_ptr = tensor_mgr.GetTensor(body.call_->GetOutputTensorIdByIndex(0)); | ||
| 80 | + const Tensor *ub_tensor_ptr = tpipe.GetTensor(body.call_->GetInputTensorIdByIndex(0)); | ||
| 81 | + ub_offset = GetUbAddrOffset(tpipe, reg_tensor_ptr, ub_tensor_ptr); | ||
| 82 | + } else if (body.call_->GetMicroApiName() == "Store") { | ||
| 83 | + const Tensor *ub_tensor_ptr = tpipe.GetTensor(body.call_->GetOutputTensorIdByIndex(0)); | ||
| 84 | + const MicroApiTensor *reg_tensor_ptr = tensor_mgr.GetTensor(body.call_->GetOutputTensorIdByIndex(1)); | ||
| 85 | + ub_offset = GetUbAddrOffset(tpipe, reg_tensor_ptr, ub_tensor_ptr); | ||
| 86 | + GetUbStorePreg(ub_tensor_ptr, preg_name); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + std::string micro_api_call_str; | ||
| 90 | + CallParam param = {preg_name, ub_offset, max_dtype_size}; | ||
| 91 | + body.call_->Generate(tensor_mgr, tpipe, param, micro_api_call_str); | ||
| 92 | + ss << micro_api_call_str; | ||
| 93 | +} | ||
| 66 | } // namespace | 94 | } // namespace |
| 67 | 95 | ||
| 96 | +std::string GenCvUbFuseVfFuncDimParams() { | ||
| 97 | + return "uint32_t curAivM, uint32_t curAivN, uint32_t curAlignN"; | ||
| 98 | +} | ||
| 99 | + | ||
| 100 | +std::string GenCvUbFuseVfCallDimParams() { | ||
| 101 | + return "curAivM, curAivN, curAlignN"; | ||
| 102 | +} | ||
| 103 | + | ||
| 104 | +std::string GenCvUbFuseRowStride(const TPipe &tpipe, const Tensor &ub_tensor) { | ||
| 105 | + if (ub_tensor.id == tpipe.cube_output_tensor_id) { | ||
| 106 | + return "curAlignN"; | ||
| 107 | + } | ||
| 108 | + std::string dtype_name; | ||
| 109 | + if (Tensor::DtypeName(ub_tensor.dtype, dtype_name) != af::SUCCESS) { | ||
| 110 | + return "curAivN"; | ||
| 111 | + } | ||
| 112 | + return "KernelUtils::BlkAlign<" + dtype_name + ">(curAivN)"; | ||
| 113 | +} | ||
| 114 | + | ||
| 115 | +std::string GenCvUbFuseAddrOffset(const TPipe &tpipe, const Tensor &ub_tensor) { | ||
| 116 | + bool enable_m_offset = true; | ||
| 117 | + bool enable_n_offset = true; | ||
| 118 | + const auto &strides = ub_tensor.vectorized_strides; | ||
| 119 | + if (strides.size() >= 2U) { | ||
| 120 | + enable_m_offset = !IsStrideZero(strides[strides.size() - 2U]); | ||
| 121 | + enable_n_offset = !IsStrideZero(strides[strides.size() - 1U]); | ||
| 122 | + } else if (strides.size() == 1U && IsStrideZero(strides[0])) { | ||
| 123 | + enable_m_offset = false; | ||
| 124 | + enable_n_offset = false; | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + std::stringstream offset_expr; | ||
| 128 | + offset_expr << "0"; | ||
| 129 | + if (enable_m_offset) { | ||
| 130 | + offset_expr << " + cv_m * " << GenCvUbFuseRowStride(tpipe, ub_tensor); | ||
| 131 | + } | ||
| 132 | + if (enable_n_offset) { | ||
| 133 | + offset_expr << " + cv_n * ELEMENT_PER_VECTOR_LENGTH"; | ||
| 134 | + } | ||
| 135 | + return offset_expr.str(); | ||
| 136 | +} | ||
| 137 | + | ||
| 68 | VFLoop::VFLoop(const ascir::AxisId axis) { | 138 | VFLoop::VFLoop(const ascir::AxisId axis) { |
| 69 | axis_id_ = axis; | 139 | axis_id_ = axis; |
| 70 | parent_ = nullptr; | 140 | parent_ = nullptr; |
| @@ -208,6 +278,28 @@ Status VFLoop::Generate(const TPipe &tpipe, const TensorManager &tensor_mgr, int | |||
| 208 | return af::SUCCESS; | 278 | return af::SUCCESS; |
| 209 | } | 279 | } |
| 210 | 280 | ||
| 281 | +Status VFLoop::GenerateCvUbFuse(const TPipe &tpipe, const TensorManager &tensor_mgr, std::string &result, | ||
| 282 | + std::string &loop_size_result) const { | ||
| 283 | + std::stringstream ss; | ||
| 284 | + std::stringstream loop_size_ss; | ||
| 285 | + loop_size_ss << " uint16_t cv_m_loop_size = static_cast<uint16_t>(curAivM);\n"; | ||
| 286 | + loop_size_ss << " uint16_t cv_n_loop_size = loop_times;\n"; | ||
| 287 | + | ||
| 288 | + ss << "for (uint16_t cv_m = 0; cv_m < cv_m_loop_size; cv_m++) {" << std::endl; | ||
| 289 | + ss << " AscendC::MicroAPI::MaskReg preg_0;" << std::endl; | ||
| 290 | + ss << " for (uint16_t cv_n = 0; cv_n < cv_n_loop_size; cv_n++) {" << std::endl; | ||
| 291 | + ss << " uint32_t sreg_0 = curAivN - cv_n * ELEMENT_PER_VECTOR_LENGTH;" << std::endl; | ||
| 292 | + ss << " preg_0 = AscendC::MicroAPI::UpdateMask<" << this->max_dtype_size_ << ">(sreg_0);\n"; | ||
| 293 | + std::vector<ascir::AxisId> current_axis = {af::kIdNone}; | ||
| 294 | + GE_CHK_STATUS_RET(GenerateCvUbFuseBody(tpipe, tensor_mgr, current_axis, ss), "Generate CV UBFuse body failed"); | ||
| 295 | + ss << " }" << std::endl; | ||
| 296 | + ss << "}" << std::endl; | ||
| 297 | + | ||
| 298 | + result = ss.str(); | ||
| 299 | + loop_size_result = loop_size_ss.str(); | ||
| 300 | + return af::SUCCESS; | ||
| 301 | +} | ||
| 302 | + | ||
| 211 | Status VFLoop::GenerateLoop(const TPipe &tpipe, const TensorManager &tensor_mgr, int32_t depth, | 303 | Status VFLoop::GenerateLoop(const TPipe &tpipe, const TensorManager &tensor_mgr, int32_t depth, |
| 212 | std::vector<ascir::AxisId> ¤t_axis, std::stringstream &ss, | 304 | std::vector<ascir::AxisId> ¤t_axis, std::stringstream &ss, |
| 213 | std::stringstream &loop_size_ss, int32_t &only_loop_max_depth, | 305 | std::stringstream &loop_size_ss, int32_t &only_loop_max_depth, |
| @@ -264,21 +356,7 @@ Status VFLoop::GenerateBody(const TPipe &tpipe, const TensorManager &tensor_mgr, | |||
| 264 | continue; | 356 | continue; |
| 265 | } | 357 | } |
| 266 | std::string preg_name = GetOriginPregName(current_axis, depth); | 358 | std::string preg_name = GetOriginPregName(current_axis, depth); |
| 267 | - std::string ub_offset = ""; | 359 | + GenerateMicroApiCall(tpipe, tensor_mgr, body, this->max_dtype_size_, preg_name, ss); |
| 268 | - if (body.call_->GetMicroApiName() == "Load") { | ||
| 269 | - const MicroApiTensor *reg_tensor_ptr = tensor_mgr.GetTensor(body.call_->GetOutputTensorIdByIndex(0)); | ||
| 270 | - const Tensor *ub_tensor_ptr = tpipe.GetTensor(body.call_->GetInputTensorIdByIndex(0)); | ||
| 271 | - ub_offset = GetUbAddrOffset(tpipe, reg_tensor_ptr, ub_tensor_ptr); | ||
| 272 | - } else if (body.call_->GetMicroApiName() == "Store") { | ||
| 273 | - const Tensor *ub_tensor_ptr = tpipe.GetTensor(body.call_->GetOutputTensorIdByIndex(0)); | ||
| 274 | - const MicroApiTensor *reg_tensor_ptr = tensor_mgr.GetTensor(body.call_->GetOutputTensorIdByIndex(1)); | ||
| 275 | - ub_offset = GetUbAddrOffset(tpipe, reg_tensor_ptr, ub_tensor_ptr); | ||
| 276 | - GetUbStorePreg(ub_tensor_ptr, preg_name); | ||
| 277 | - } | ||
| 278 | - std::string micro_api_call_str; | ||
| 279 | - CallParam param = {preg_name, ub_offset, this->max_dtype_size_}; | ||
| 280 | - body.call_->Generate(tensor_mgr, tpipe, param, micro_api_call_str); | ||
| 281 | - ss << micro_api_call_str; | ||
| 282 | has_call = true; | 360 | has_call = true; |
| 283 | } | 361 | } |
| 284 | } | 362 | } |
| @@ -288,6 +366,24 @@ Status VFLoop::GenerateBody(const TPipe &tpipe, const TensorManager &tensor_mgr, | |||
| 288 | return af::SUCCESS; | 366 | return af::SUCCESS; |
| 289 | } | 367 | } |
| 290 | 368 | ||
| 369 | +Status VFLoop::GenerateCvUbFuseBody(const TPipe &tpipe, const TensorManager &tensor_mgr, | ||
| 370 | + std::vector<ascir::AxisId> ¤t_axis, std::stringstream &ss) const { | ||
| 371 | + for (const auto &body : this->bodys_) { | ||
| 372 | + if (body.type_ == LoopType::LOOP) { | ||
| 373 | + GE_CHK_STATUS_RET(body.loop_->GenerateCvUbFuseBody(tpipe, tensor_mgr, current_axis, ss), | ||
| 374 | + "Generate CV UBFuse loop body failed"); | ||
| 375 | + continue; | ||
| 376 | + } | ||
| 377 | + if (body.type_ != LoopType::CALL || body.call_->unit == ge::ComputeUnit::kUnitNone) { | ||
| 378 | + continue; | ||
| 379 | + } | ||
| 380 | + | ||
| 381 | + std::string preg_name = GetOriginPregName(current_axis, 0); | ||
| 382 | + GenerateMicroApiCall(tpipe, tensor_mgr, body, this->max_dtype_size_, preg_name, ss); | ||
| 383 | + } | ||
| 384 | + return af::SUCCESS; | ||
| 385 | +} | ||
| 386 | + | ||
| 291 | void VFLoop::CollectMaskRegTempTensors(const TPipe &tpipe, const TensorManager &tensor_mgr, | 387 | void VFLoop::CollectMaskRegTempTensors(const TPipe &tpipe, const TensorManager &tensor_mgr, |
| 292 | std::vector<std::string> &temp_tensors) const { | 388 | std::vector<std::string> &temp_tensors) const { |
| 293 | for (const auto &body : this->bodys_) { | 389 | for (const auto &body : this->bodys_) { |
| @@ -14,6 +14,11 @@ | |||
| 14 | 14 | ||
| 15 | namespace codegen { | 15 | namespace codegen { |
| 16 | 16 | ||
| 17 | +std::string GenCvUbFuseVfFuncDimParams(); | ||
| 18 | +std::string GenCvUbFuseVfCallDimParams(); | ||
| 19 | +std::string GenCvUbFuseRowStride(const TPipe &tpipe, const Tensor &ub_tensor); | ||
| 20 | +std::string GenCvUbFuseAddrOffset(const TPipe &tpipe, const Tensor &ub_tensor); | ||
| 21 | + | ||
| 17 | class VFLoop; | 22 | class VFLoop; |
| 18 | struct VFLoopBody { | 23 | struct VFLoopBody { |
| 19 | LoopType type_; | 24 | LoopType type_; |
| @@ -37,13 +42,15 @@ class VFLoop { | |||
| 37 | Status Generate(const TPipe &tpipe, const TensorManager &tensor_mgr, int32_t depth, std::string &result, | 42 | Status Generate(const TPipe &tpipe, const TensorManager &tensor_mgr, int32_t depth, std::string &result, |
| 38 | std::string &loop_size_result, int32_t &only_loop_max_depth, | 43 | std::string &loop_size_result, int32_t &only_loop_max_depth, |
| 39 | std::vector<std::string> &loop_size_vec) const; | 44 | std::vector<std::string> &loop_size_vec) const; |
| 45 | + Status GenerateCvUbFuse(const TPipe &tpipe, const TensorManager &tensor_mgr, std::string &result, | ||
| 46 | + std::string &loop_size_result) const; | ||
| 40 | void SetMaxDtypeSize(std::string dtype); | 47 | void SetMaxDtypeSize(std::string dtype); |
| 41 | void CollectMaskRegTempTensors(const TPipe &tpipe, const TensorManager &tensor_mgr, | 48 | void CollectMaskRegTempTensors(const TPipe &tpipe, const TensorManager &tensor_mgr, |
| 42 | std::vector<std::string> &temp_tensors) const; | 49 | std::vector<std::string> &temp_tensors) const; |
| 43 | 50 | ||
| 44 | private: | 51 | private: |
| 45 | ascir::AxisId axis_id_; | 52 | ascir::AxisId axis_id_; |
| 46 | - struct VFLoop *parent_; | 53 | + VFLoop *parent_; |
| 47 | std::vector<VFLoopBody> bodys_; | 54 | std::vector<VFLoopBody> bodys_; |
| 48 | std::string max_dtype_size_; | 55 | std::string max_dtype_size_; |
| 49 | 56 | ||
| @@ -53,6 +60,8 @@ class VFLoop { | |||
| 53 | Status GenerateBody(const TPipe &tpipe, const TensorManager &tensor_mgr, int32_t depth, | 60 | Status GenerateBody(const TPipe &tpipe, const TensorManager &tensor_mgr, int32_t depth, |
| 54 | std::vector<ascir::AxisId> ¤t_axis, std::stringstream &ss, std::stringstream &loop_size_ss, | 61 | std::vector<ascir::AxisId> ¤t_axis, std::stringstream &ss, std::stringstream &loop_size_ss, |
| 55 | int32_t &only_loop_max_depth, std::vector<std::string> &loop_size_vec) const; | 62 | int32_t &only_loop_max_depth, std::vector<std::string> &loop_size_vec) const; |
| 63 | + Status GenerateCvUbFuseBody(const TPipe &tpipe, const TensorManager &tensor_mgr, | ||
| 64 | + std::vector<ascir::AxisId> ¤t_axis, std::stringstream &ss) const; | ||
| 56 | }; | 65 | }; |
| 57 | 66 | ||
| 58 | } // namespace codegen | 67 | } // namespace codegen |