Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
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 : #include "ascend_graph_code_dumper.h"
11 : #include "ascendc_ir/utils/asc_graph_utils.h"
12 :
13 : namespace af {
14 : namespace ascir {
15 : namespace {
16 :
17 : static const std::map<ge::DataType, std::string> ge_dtype_2_python_type = {
18 : {ge::DT_FLOAT, "ascir.dtypes.float32"},
19 : {ge::DT_FLOAT16, "ascir.dtypes.float16"},
20 : {ge::DT_INT8, "ascir.dtypes.int8"},
21 : {ge::DT_INT32, "ascir.dtypes.int32"},
22 : {ge::DT_UINT8, "ascir.dtypes.uint8"},
23 : {ge::DT_INT16, "ascir.dtypes.int16"},
24 : {ge::DT_UINT16, "ascir.dtypes.uint16"},
25 : {ge::DT_UINT32, "ascir.dtypes.uint32"},
26 : {ge::DT_INT64, "ascir.dtypes.int64"},
27 : {ge::DT_UINT64, "ascir.dtypes.uint64"},
28 : {ge::DT_DOUBLE, "ascir.dtypes.double"},
29 : {ge::DT_BOOL, "ascir.dtypes.bool"},
30 : {ge::DT_STRING, "ascir.dtypes.string"},
31 : {ge::DT_DUAL_SUB_INT8, "ascir.dtypes.dual_sub_int8"},
32 : {ge::DT_DUAL_SUB_UINT8, "ascir.dtypes.dual_sub_uint8"},
33 : {ge::DT_COMPLEX64, "ascir.dtypes.complex64"},
34 : {ge::DT_COMPLEX128, "ascir.dtypes.complex128"},
35 : {ge::DT_QINT8, "ascir.dtypes.qint8"},
36 : {ge::DT_QINT16, "ascir.dtypes.qint16"},
37 : {ge::DT_QINT32, "ascir.dtypes.qint32"},
38 : {ge::DT_QUINT8, "ascir.dtypes.quint8"},
39 : {ge::DT_QUINT16, "ascir.dtypes.quint16"},
40 : {ge::DT_RESOURCE, "ascir.dtypes.resource"},
41 : {ge::DT_STRING_REF, "ascir.dtypes.string_ref"},
42 : {ge::DT_DUAL, "ascir.dtypes.dual"},
43 : {ge::DT_VARIANT, "ascir.dtypes.variant"},
44 : {ge::DT_BF16, "ascir.dtypes.bf16"},
45 : {ge::DT_UNDEFINED, "ascir.dtypes.undefined"},
46 : {ge::DT_INT4, "ascir.dtypes.int4"},
47 : {ge::DT_UINT1, "ascir.dtypes.uint1"},
48 : {ge::DT_INT2, "ascir.dtypes.int2"},
49 : {ge::DT_UINT2, "ascir.dtypes.uint2"},
50 : {ge::DT_COMPLEX32, "ascir.dtypes.complex32"},
51 : {ge::DT_HIFLOAT8, "ascir.dtypes.hifloat8"},
52 : {ge::DT_FLOAT8_E5M2, "ascir.dtypes.float8_e5m2"},
53 : {ge::DT_FLOAT8_E4M3FN, "ascir.dtypes.float8_e4m3fn"},
54 : {ge::DT_FLOAT8_E8M0, "ascir.dtypes.float8_e8m0"},
55 : {ge::DT_FLOAT6_E3M2, "ascir.dtypes.float6_e3m2"},
56 : {ge::DT_FLOAT6_E2M3, "ascir.dtypes.float6_e2m3"},
57 : {ge::DT_FLOAT4_E2M1, "ascir.dtypes.float4_e2m1"},
58 : {ge::DT_FLOAT4_E1M2, "ascir.dtypes.float4_e1m2"},
59 : };
60 :
61 : void GeneratePythonHeader(std::ofstream &output_file, const std::string &graph_type) {
62 : output_file << "# Python code to construct " << graph_type << "\n";
63 : output_file << "from autofuse.pyautofuse import ascir\n";
64 : output_file << "from autofuse.pyautofuse import Autofuser, AutofuserOptions\n\n";
65 : }
66 :
67 : void GeneratePythonFooter(std::ofstream &output_file) {
68 : output_file << "fuser = Autofuser(AutofuserOptions())\n";
69 : output_file << "schedule_results = fuser.schedule(graph)\n";
70 : output_file << "tiling_def, host_impl, device_impl = fuser.codegen(schedule_results)\n";
71 : }
72 :
73 : void FloatHandle(const af::AscNodeAttr *asc_node_attr, const std::string &name, std::string &value_string) {
74 : float value;
75 : GE_CHK_BOOL_EXEC(asc_node_attr != nullptr, return, "asc_node_attr is nullptr");
76 : auto &ir_attr = asc_node_attr->ir_attr;
77 : GE_CHK_BOOL_EXEC(ir_attr != nullptr, return, "asc_node_attr->ir_attr is nullptr");
78 : if (ir_attr->GetAttrValue(name, value) == GRAPH_FAILED) {
79 : return;
80 : }
81 : value_string = std::to_string(value);
82 : }
83 :
84 : void Int64Handle(const af::AscNodeAttr *asc_node_attr, const std::string &name, std::string &value_string) {
85 : int64_t value;
86 : GE_CHK_BOOL_EXEC(asc_node_attr != nullptr, return, "asc_node_attr is nullptr");
87 : auto &ir_attr = asc_node_attr->ir_attr;
88 : GE_CHK_BOOL_EXEC(ir_attr != nullptr, return, "asc_node_attr->ir_attr is nullptr");
89 : if (ir_attr->GetAttrValue(name, value) == GRAPH_FAILED) {
90 : return;
91 : }
92 : value_string = std::to_string(value);
93 : }
94 :
95 : void StringHandle(const af::AscNodeAttr *asc_node_attr, const std::string &name, std::string &value_string) {
96 : std::string value;
97 : GE_CHK_BOOL_EXEC(asc_node_attr != nullptr, return, "asc_node_attr is nullptr");
98 : auto &ir_attr = asc_node_attr->ir_attr;
99 : GE_CHK_BOOL_EXEC(ir_attr != nullptr, return, "asc_node_attr->ir_attr is nullptr");
100 : if (ir_attr->GetAttrValue(name, value) == GRAPH_FAILED) {
101 : return;
102 : }
103 : value_string = "'" + value + "'";
104 : }
105 :
106 : void ExpressionHandle(const af::AscNodeAttr *asc_node_attr, const std::string &name, std::string &value_string) {
107 : af::Expression value;
108 : GE_CHK_BOOL_EXEC(asc_node_attr != nullptr, return, "asc_node_attr is nullptr");
109 : auto &ir_attr = asc_node_attr->ir_attr;
110 : GE_CHK_BOOL_EXEC(ir_attr != nullptr, return, "asc_node_attr->ir_attr is nullptr");
111 : if (ir_attr->GetAttrValue(name, value) == GRAPH_FAILED) {
112 : return;
113 : }
114 : value_string = value.Serialize().get();
115 : }
116 :
117 : using handle_ptr = void (*)(const af::AscNodeAttr *asc_node_attr, const std::string &name, std::string &value_string);
118 : const std::unordered_map<std::string, handle_ptr> IrAttrHandleMap = {
119 : {"float", FloatHandle}, {"int64_t", Int64Handle}, {"std::string", StringHandle}, {"Expression", ExpressionHandle}};
120 :
121 : bool IsNodeWithIrInputs(const af::NodePtr &node) {
122 : const auto &op_desc = node->GetOpDesc();
123 : GE_ASSERT_NOTNULL(op_desc);
124 : return !op_desc->GetIrInputs().empty();
125 : }
126 :
127 : bool IsNodeWithIrOutputs(const af::NodePtr &node) {
128 : const auto &op_desc = node->GetOpDesc();
129 : GE_ASSERT_NOTNULL(op_desc);
130 : return !op_desc->GetIrOutputs().empty();
131 : }
132 :
133 : std::string GetOutputName(const af::NodePtr &src_node, uint32_t idx) {
134 : if (!IsNodeWithIrOutputs(src_node) && (src_node->GetType() == "AscGraph" || src_node->GetType() == "AscBackend")) {
135 : return "y[" + std::to_string(idx) + "]";
136 : }
137 : const auto &op_desc = src_node->GetOpDesc();
138 : GE_ASSERT_NOTNULL(op_desc);
139 : const auto &ir_outputs = op_desc->GetIrOutputs();
140 : std::map<size_t, std::pair<size_t, size_t>> ir_output_2_ranges;
141 : GE_ASSERT_GRAPH_SUCCESS(af::OpDescUtils::GetIrOutputDescRange(op_desc, ir_output_2_ranges));
142 :
143 245 : for (const auto &ir_output_2_range : ir_output_2_ranges) {
144 : if (idx >= ir_output_2_range.second.first &&
145 : idx < ir_output_2_range.second.first + ir_output_2_range.second.second) {
146 : GE_ASSERT_TRUE(ir_output_2_range.first < ir_outputs.size());
147 : if (ir_outputs.at(ir_output_2_range.first).second == af::IrOutputType::kIrOutputDynamic) {
148 : return ir_outputs.at(ir_output_2_range.first).first + "[" +
149 : std::to_string(idx - ir_output_2_range.second.first) + "]";
150 : }
151 : }
152 : }
153 :
154 : const auto &idx2name = src_node->GetOpDesc()->GetAllOutputIndexToName();
155 : auto out_name_iter = idx2name.find(idx);
156 : GE_ASSERT_TRUE(out_name_iter != idx2name.end());
157 : return out_name_iter->second;
158 : }
159 :
160 : bool GetDynamicOutputCount(const af::OpDescPtr &op_desc, uint32_t &dynamic_output_count) {
161 : GE_ASSERT_NOTNULL(op_desc);
162 : const auto &ir_outputs = op_desc->GetIrOutputs();
163 : if (ir_outputs.size() != 1U || ir_outputs[0U].second != af::IrOutputType::kIrOutputDynamic) {
164 : return false;
165 : }
166 :
167 : std::map<size_t, std::pair<size_t, size_t>> ir_output_2_ranges;
168 : GE_ASSERT_GRAPH_SUCCESS(af::OpDescUtils::GetIrOutputDescRange(op_desc, ir_output_2_ranges));
169 : const auto range_iter = ir_output_2_ranges.find(0U);
170 : GE_ASSERT_TRUE(range_iter != ir_output_2_ranges.end());
171 : dynamic_output_count = static_cast<uint32_t>(range_iter->second.second);
172 : return true;
173 : }
174 :
175 : std::string GetPythonNodeNameByOriginName(const std::string &origin_name,
176 : const std::shared_ptr<NameGenerator> &name_generator) {
177 : const auto &name_mapping_info = name_generator->GetNameMapping();
178 : const auto &iter = name_mapping_info.find(origin_name);
179 : if (iter == name_mapping_info.end()) {
180 : GELOGW("%s has not been added to name map, may be topo is wrong", origin_name.c_str());
181 : return "";
182 : }
183 : return iter->second;
184 : }
185 :
186 : std::string GenerateDataTypeCode(ge::DataType dtype) {
187 : auto iter = ge_dtype_2_python_type.find(dtype);
188 : GE_WARN_ASSERT(iter != ge_dtype_2_python_type.end(), "DataType [%s] is not supported by python now",
189 : TypeUtils::DataTypeToSerialString(dtype).c_str());
190 : return iter->second;
191 : }
192 :
193 : std::string GenerateAxisCode(const std::vector<int64_t> &axis, const std::vector<af::AxisPtr> &axis_ptrs) {
194 : std::string axis_code = "[";
195 : for (size_t i = 0; i < axis.size(); ++i) {
196 : GE_ASSERT_TRUE(axis[i] >= 0);
197 : GE_ASSERT_TRUE(static_cast<size_t>(axis[i]) < axis_ptrs.size());
198 : axis_code += axis_ptrs[axis[i]]->name;
199 : if (i < axis.size() - 1) {
200 : axis_code += ", ";
201 : }
202 : }
203 : axis_code += "]";
204 : return axis_code;
205 : }
206 :
207 : std::string GenerateAxisRepeatCode(const std::vector<af::Expression> &repeats) {
208 : std::string axis_repeat_code = "[";
209 : for (size_t i = 0; i < repeats.size(); ++i) {
210 : axis_repeat_code += repeats[i].Str().get();
211 : if (i < repeats.size() - 1) {
212 : axis_repeat_code += ", ";
213 : }
214 : }
215 : axis_repeat_code += "]";
216 : return axis_repeat_code;
217 : }
218 :
219 : std::string GenerateAxisStrideCode(const std::vector<af::Expression> &strides) {
220 : std::string axis_strides_code = "[";
221 : for (size_t i = 0; i < strides.size(); ++i) {
222 : axis_strides_code += strides[i].Str().get();
223 : if (i < strides.size() - 1) {
224 : axis_strides_code += ", ";
225 : }
226 : }
227 : axis_strides_code += "]";
228 : return axis_strides_code;
229 : }
230 : } // namespace
231 :
232 : void PythonCodeDumper::GenerateInputCode(const std::string &op_name, const std::string &input_name,
233 : const af::NodePtr &src_node, uint32_t out_idx, std::ostream &output_file) {
234 : std::string out_name = GetOutputName(src_node, out_idx);
235 : output_file << op_name << "." << input_name << " = "
236 : << GetPythonNodeNameByOriginName(src_node->GetName(), name_generator_) << "." << out_name << "\n";
237 : }
238 :
239 : Status PythonCodeDumper::GenerateDynamicInputCode(
240 : const af::Node::Vistor<std::pair<af::NodePtr, af::OutDataAnchorPtr>> &src_nodes, size_t start_index, size_t count,
241 : const std::string &op_name, const std::string &input_name, std::ostream &output_file) {
242 : std::string dynamic_inputs_code = "[";
243 : for (size_t i = start_index; i < start_index + count; ++i) {
244 : GE_ASSERT_TRUE(i < src_nodes.size());
245 : const auto &src_node = src_nodes.at(i).first;
246 : uint32_t out_idx = src_nodes.at(i).second->GetIdx();
247 : std::string out_name = GetOutputName(src_node, out_idx);
248 : dynamic_inputs_code += GetPythonNodeNameByOriginName(src_node->GetName(), name_generator_) + "." + out_name;
249 : if (i < start_index + count - 1) {
250 : dynamic_inputs_code += ", ";
251 : }
252 : }
253 : dynamic_inputs_code += "]";
254 : output_file << op_name << "." << input_name << " = " << dynamic_inputs_code << "\n";
255 : return SUCCESS;
256 : }
257 :
258 : void PythonCodeDumper::GenerateHeader(std::ofstream &output_file) {
259 : GeneratePythonHeader(output_file, "AscGraph");
260 : }
261 :
262 : Status PythonCodeDumper::GenerateNodeCode(const af::NodePtr &node, std::ostream &output_file) {
263 : GE_ASSERT_NOTNULL(node);
264 : GELOGD("Start to gen node code for %s %s", node->GetNamePtr(), node->GetTypePtr());
265 : node_name_of_python_ = name_generator_->GenerateUniqueName(*node);
266 : auto op_desc = node->GetOpDesc();
267 : GE_ASSERT_NOTNULL(op_desc);
268 : uint32_t dynamic_output_count = 0U;
269 : const auto has_dynamic_output = GetDynamicOutputCount(op_desc, dynamic_output_count);
270 : if (node->GetInDataNodesSize() == 0U) {
271 : output_file << node_name_of_python_ << " = ascir.ops." << node->GetType() << "(" << "\"" << node->GetName() << "\"";
272 : if (has_dynamic_output) {
273 : output_file << ", " << dynamic_output_count;
274 : }
275 : output_file << ", graph)" << std::endl;
276 : } else {
277 : // 有数据输入的节点,不需要graph的入参,通过连边时加入graph中
278 : output_file << node_name_of_python_ << " = ascir.ops." << node->GetType() << "(" << "\"" << node->GetName() << "\"";
279 : if (has_dynamic_output) {
280 : output_file << ", " << dynamic_output_count;
281 : }
282 : output_file << ")" << std::endl;
283 : }
284 : auto &&node_attr_group = op_desc->GetOrCreateAttrsGroup<af::AscNodeAttr>();
285 : GE_ASSERT_NOTNULL(node_attr_group);
286 : if (!node_attr_group->sched.axis.empty()) {
287 : std::string axis_code;
288 : axis_code.push_back('[');
289 : for (size_t i = 0U; i < node_attr_group->sched.axis.size(); ++i) {
290 : auto one_axis = node_attr_group->sched.axis[i];
291 : GE_ASSERT_TRUE(one_axis >= 0);
292 : GE_ASSERT_TRUE(static_cast<size_t>(one_axis) < asis_ptrs.size());
293 : axis_code += asis_ptrs[one_axis]->name;
294 : if (i < node_attr_group->sched.axis.size() - 1) {
295 : axis_code += ", ";
296 : }
297 : }
298 : axis_code.push_back(']');
299 : output_file << node_name_of_python_ << ".attr.sched.axis = " << axis_code << std::endl;
300 : }
301 : return SUCCESS;
302 : }
303 :
304 : Status PythonCodeDumper::GenerateDataEdgeCode(
305 : const af::Node::Vistor<std::pair<af::NodePtr, af::OutDataAnchorPtr>> &src_nodes, const af::NodePtr &dst_node,
306 : std::ostream &output_file) {
307 : const auto &op_desc = dst_node->GetOpDesc();
308 : GE_ASSERT_NOTNULL(op_desc);
309 : if (src_nodes.empty()) {
310 : GELOGD("[%s:%s] has no input.", op_desc->GetNamePtr(), op_desc->GetTypePtr());
311 : return SUCCESS;
312 : }
313 : GELOGD("Start to add input for node [%s:%s]", op_desc->GetNamePtr(), op_desc->GetTypePtr());
314 : const auto &ir_inputs = op_desc->GetIrInputs();
315 : size_t ir_input_index = 0U;
316 : std::map<size_t, std::pair<size_t, size_t>> ir_input_2_range;
317 : GE_ASSERT_GRAPH_SUCCESS(af::OpDescUtils::GetIrInputRawDescRange(op_desc, ir_input_2_range));
318 : if (dst_node->GetType() == "Output" && src_nodes.size() > 1) {
319 : return GenerateDynamicInputCode(src_nodes, 0, src_nodes.size(), node_name_of_python_, ir_inputs[0].first,
320 : output_file);
321 : }
322 : for (size_t index = 0; index < src_nodes.size(); ++ir_input_index) {
323 : const auto &ir_input_2_range_iter = ir_input_2_range.find(ir_input_index);
324 : GE_ASSERT_TRUE(ir_input_2_range_iter != ir_input_2_range.end());
325 : GELOGI("ir input:%zu with range [%zu, %zu)", ir_input_index, ir_input_2_range_iter->second.first,
326 : ir_input_2_range_iter->second.first + ir_input_2_range_iter->second.second);
327 : GE_ASSERT_TRUE(ir_input_index < ir_inputs.size());
328 : const auto &ir_input_name_2_input_type = ir_inputs[ir_input_index];
329 : const auto &ir_input_type = ir_input_name_2_input_type.second;
330 : const auto &input_name = ir_input_name_2_input_type.first;
331 : if (ir_input_type == af::IrInputType::kIrInputRequired) {
332 : GE_ASSERT_EQ(ir_input_2_range_iter->second.second, 1U);
333 : const auto &src_node = src_nodes.at(index).first;
334 : uint32_t out_idx = src_nodes.at(index).second->GetIdx();
335 : GenerateInputCode(node_name_of_python_, input_name, src_node, out_idx, output_file);
336 : ++index;
337 : } else if (ir_input_type == af::IrInputType::kIrInputDynamic) {
338 : GE_ASSERT_EQ(index, ir_input_2_range_iter->second.first);
339 : GE_ASSERT_TRUE(ir_input_2_range_iter->second.second > 0U);
340 : GE_ASSERT_SUCCESS(GenerateDynamicInputCode(src_nodes, index, ir_input_2_range_iter->second.second,
341 : node_name_of_python_, input_name, output_file));
342 : index += ir_input_2_range_iter->second.second;
343 : } else {
344 : GE_ASSERT_TRUE(ir_input_type == af::IrInputType::kIrInputOptional);
345 : if (ir_input_2_range_iter->second.second == 0U) {
346 : GELOGI(" optional input[%zu] has no input nodes.", ir_input_index);
347 : } else {
348 : GE_ASSERT_EQ(1U, ir_input_2_range_iter->second.second);
349 : const auto &src_node = src_nodes.at(index).first;
350 : uint32_t out_idx = src_nodes.at(index).second->GetIdx();
351 : GenerateInputCode(node_name_of_python_, input_name, src_node, out_idx, output_file);
352 : ++index;
353 : }
354 : }
355 : }
356 : return SUCCESS;
357 : }
358 :
359 : void PythonCodeDumper::GenerateGraphInstance(const af::AscGraph &asc_graph, std::ostream &output_file) {
360 : output_file << "graph = ascir.HintGraph(" << "\"" << asc_graph.GetName() << "\"" << ")\n";
361 : for (const auto &size_var : asc_graph.GetAllSizeVar()) {
362 : if (!size_var->expr.IsConstExpr()) {
363 : output_file << size_var->expr.Str().get() << " = graph.create_size(" << "\"" << size_var->expr.Str().get() << "\""
364 : << ")\n";
365 : }
366 : }
367 : asis_ptrs = asc_graph.GetAllAxis();
368 : for (const auto &axis : asis_ptrs) {
369 : output_file << axis->name << " = " << "" << "graph.create_axis(" << "\"" << axis->name << "\"" << ", "
370 : << axis->size.Str().get() << ")\n";
371 : }
372 : }
373 :
374 : Status PythonCodeDumper::GenerateTensorCode(const af::NodePtr &node, std::ostream &output_file) {
375 : GELOGD("Start to gen tensor code for %s %s", node->GetNamePtr(), node->GetTypePtr());
376 : auto op_desc = node->GetOpDesc();
377 : GE_ASSERT_NOTNULL(op_desc);
378 :
379 : size_t output_index = 0U;
380 : for (const auto &tensor_desc : op_desc->GetAllOutputsDescPtr()) {
381 : const auto out_name = GetOutputName(node, static_cast<uint32_t>(output_index++));
382 : auto dtype = static_cast<ge::DataType>(tensor_desc->GetDataType());
383 : auto python_dtype = GenerateDataTypeCode(dtype);
384 : output_file << node_name_of_python_ << "." << out_name << ".dtype = " << python_dtype << std::endl;
385 : auto tensor_group_attr = tensor_desc->GetAttrsGroup<af::AscTensorAttr>();
386 : GE_ASSERT_NOTNULL(tensor_group_attr);
387 : if (tensor_group_attr->axis.empty()) {
388 : continue;
389 : }
390 :
391 : const auto &axis_code = GenerateAxisCode(tensor_group_attr->axis, asis_ptrs);
392 : output_file << node_name_of_python_ << "." << out_name << ".axis = " << axis_code << std::endl;
393 : const auto &axis_repeat_code = GenerateAxisRepeatCode(tensor_group_attr->repeats);
394 : output_file << node_name_of_python_ << "." << out_name << ".size = " << axis_repeat_code << std::endl;
395 : const auto &axis_stride_code = GenerateAxisStrideCode(tensor_group_attr->strides);
396 : output_file << node_name_of_python_ << "." << out_name << ".strides = " << axis_stride_code << std::endl;
397 : }
398 : return SUCCESS;
399 : }
400 :
401 : Status PythonCodeDumper::GenerateIrAttrCode(const af::NodePtr &node, std::ostream &output_file) {
402 : GE_ASSERT_NOTNULL(node);
403 : GELOGD("Start to gen node code for %s %s", node->GetNamePtr(), node->GetTypePtr());
404 : auto op_desc = node->GetOpDesc();
405 : GE_ASSERT_NOTNULL(op_desc);
406 : auto &&node_attr_group = op_desc->GetOrCreateAttrsGroup<af::AscNodeAttr>();
407 : GE_ASSERT_NOTNULL(node_attr_group);
408 : auto it = types_to_ascir_.find(node->GetType());
409 : if (it == types_to_ascir_.end()) {
410 : GELOGD("%s is not registered.", node->GetType().c_str());
411 : return SUCCESS;
412 : }
413 : for (const auto &attr_def : it->second.GetAttrDefs()) {
414 : if (IrAttrHandleMap.find(attr_def.asc_ir_type) == IrAttrHandleMap.end()) {
415 : GELOGW("This ir_attr data type [%s] does not implement the dump function", attr_def.asc_ir_type.c_str());
416 : continue;
417 : }
418 : std::string value;
419 53 : IrAttrHandleMap.at(attr_def.asc_ir_type)(node_attr_group, attr_def.name, value);
420 : if (value.empty()) {
421 : continue;
422 : }
423 : output_file << node_name_of_python_ << ".attr.ir_attr." << attr_def.name << " = " << value << std::endl;
424 : }
425 : return SUCCESS;
426 : }
427 :
428 : void PythonCodeDumper::GenerateFooter(std::ofstream &output_file) {
429 : GeneratePythonFooter(output_file);
430 : }
431 :
432 : Status PythonCodeDumper::DumpAscGraphNode(const af::AscGraph &graph, std::ostream &output_file) {
433 : GenerateGraphInstance(graph, output_file);
434 : for (const auto &node : graph.GetAllNodes()) {
435 : GELOGD("Start to gen code for %s %s", node->GetNamePtr(), node->GetTypePtr());
436 : GE_ASSERT_SUCCESS(GenerateNodeCode(node, output_file));
437 : const auto &input_nodes = node->GetInDataNodesAndAnchors();
438 : GE_ASSERT_SUCCESS(GenerateDataEdgeCode(input_nodes, node, output_file));
439 : GE_ASSERT_SUCCESS(GenerateTensorCode(node, output_file));
440 : GE_ASSERT_SUCCESS(GenerateIrAttrCode(node, output_file));
441 : }
442 : return SUCCESS;
443 : }
444 :
445 : Status PythonCodeDumper::Dump(const af::AscGraph &graph, const std::string &out_file_path) {
446 : std::ofstream output_file(out_file_path);
447 : GE_ASSERT_TRUE(output_file.is_open(), "out_file_path %s is invalid", out_file_path.c_str());
448 : GenerateHeader(output_file);
449 : GE_ASSERT_SUCCESS(DumpAscGraphNode(graph, output_file));
450 : GenerateFooter(output_file);
451 : output_file.close();
452 : return SUCCESS;
453 : }
454 :
455 : void PythonCodeDumperFused::GenerateHeader(std::ofstream &output_file) {
456 : GeneratePythonHeader(output_file, "ComputeGraph");
457 : }
458 :
459 : void PythonCodeDumperFused::GenerateFooter(std::ofstream &output_file) const {
460 : GeneratePythonFooter(output_file);
461 : }
462 :
463 : Status PythonCodeDumperFused::GenerateDataEdgeCodeWithOutIr(
464 : const af::Node::Vistor<std::pair<af::NodePtr, af::OutDataAnchorPtr>> &src_nodes, const af::NodePtr &dst_node,
465 : std::ofstream &output_file) {
466 : const auto &op_desc = dst_node->GetOpDesc();
467 : GE_ASSERT_NOTNULL(op_desc);
468 : if (src_nodes.empty()) {
469 : GELOGD("[%s:%s] has no input.", op_desc->GetNamePtr(), op_desc->GetTypePtr());
470 : return SUCCESS;
471 : }
472 : GELOGD("Start to add input for node [%s:%s]", op_desc->GetNamePtr(), op_desc->GetTypePtr());
473 : GE_ASSERT_TRUE(dst_node->GetType() == "AscGraph" || dst_node->GetType() == "AscBackend");
474 :
475 : std::string dynamic_inputs_code = "[";
476 : for (size_t index = 0; index < src_nodes.size(); ++index) {
477 : const auto &src_node = src_nodes.at(index).first;
478 : uint32_t out_idx = src_nodes.at(index).second->GetIdx();
479 : std::string out_name = GetOutputName(src_node, out_idx);
480 : dynamic_inputs_code += GetPythonNodeNameByOriginName(src_node->GetName(), name_generator_) + "." + out_name;
481 : if (index < src_nodes.size() - 1) {
482 : dynamic_inputs_code += ", ";
483 : }
484 : }
485 : dynamic_inputs_code += "]";
486 : output_file << node_name_of_python_ << ".x" << " = " << dynamic_inputs_code << "\n";
487 : return SUCCESS;
488 : }
489 :
490 : Status PythonCodeDumperFused::GenerateDataEdgeCode(
491 : const af::Node::Vistor<std::pair<af::NodePtr, af::OutDataAnchorPtr>> &src_nodes, const af::NodePtr &dst_node,
492 : std::ofstream &output_file) {
493 : if (!IsNodeWithIrInputs(dst_node)) {
494 : GELOGW("%s has no ir inputs information", dst_node->GetName().c_str());
495 : return GenerateDataEdgeCodeWithOutIr(src_nodes, dst_node, output_file);
496 : }
497 : code_dumper_asc_graph_.GenerateDataEdgeCode(src_nodes, dst_node, output_file);
498 : return SUCCESS;
499 : }
500 :
501 : void PythonCodeDumperFused::GenerateGraphInstance(const af::ComputeGraph &compute_graph,
502 : std::ofstream &output_file) const {
503 : output_file << "graph = ascir.FusedGraph(" << "\"" << compute_graph.GetName() << "\"" << ")\n";
504 : }
505 :
506 : Status PythonCodeDumperFused::DumpAscGraphNode(const af::NodePtr &node, std::ofstream &output_file) {
507 : const auto op_desc = node->GetOpDesc();
508 : GE_ASSERT_NOTNULL(op_desc);
509 : std::string asc_graph_str = "";
510 : af::AscGraph asc_graph("");
511 : GE_ASSERT_TRUE(af::AttrUtils::GetStr(op_desc, "ascgraph", asc_graph_str));
512 : GE_ASSERT_GRAPH_SUCCESS(af::AscGraphUtils::DeserializeFromReadable(asc_graph_str, asc_graph));
513 :
514 : node_name_of_python_ = name_generator_->GenerateUniqueName(*node);
515 : output_file << "\ndef Get" << node_name_of_python_ << "():\n";
516 : std::ostringstream asc_graph_out;
517 : auto asc_graph_node_dump = PythonCodeDumper(name_generator_);
518 : GE_ASSERT_GRAPH_SUCCESS(asc_graph_node_dump.DumpAscGraphNode(asc_graph, asc_graph_out));
519 : std::istringstream asc_graph_in(asc_graph_out.str());
520 : for (std::string line; std::getline(asc_graph_in, line);) {
521 : output_file << " " << line << "\n";
522 : }
523 : output_file << " return graph\n";
524 :
525 : output_file << "\n"
526 : << node_name_of_python_ << " = ascir.ops." << node->GetType() << "('" << node->GetName() << "', Get"
527 : << node_name_of_python_ << "(), graph)" << std::endl;
528 :
529 : code_dumper_asc_graph_.node_name_of_python_ = node_name_of_python_;
530 : const auto &input_nodes = node->GetInDataNodesAndAnchors();
531 : GenerateDataEdgeCode(input_nodes, node, output_file);
532 : output_file << std::endl;
533 : return SUCCESS;
534 : }
535 :
536 : Status PythonCodeDumperFused::Dump(const af::ComputeGraph &graph, const std::string &out_file_path) {
537 : std::ofstream output_file(out_file_path);
538 : GE_ASSERT_TRUE(output_file.is_open(), "out_file_path %s is invalid", out_file_path.c_str());
539 : GenerateHeader(output_file);
540 : GenerateGraphInstance(graph, output_file);
541 : auto nodes = graph.GetAllNodes();
542 : for (const auto &node : nodes) {
543 : if (node->GetType() == "AscGraph" || node->GetType() == "AscBackend") {
544 : GE_ASSERT_SUCCESS(DumpAscGraphNode(node, output_file));
545 : continue;
546 : }
547 : GELOGD("Start to gen code for %s %s", node->GetNamePtr(), node->GetTypePtr());
548 : GE_ASSERT_SUCCESS(code_dumper_asc_graph_.GenerateNodeCode(node, output_file));
549 : const auto &input_nodes = node->GetInDataNodesAndAnchors();
550 : node_name_of_python_ = code_dumper_asc_graph_.node_name_of_python_;
551 : GE_ASSERT_SUCCESS(GenerateDataEdgeCode(input_nodes, node, output_file));
552 : GE_ASSERT_SUCCESS(code_dumper_asc_graph_.GenerateTensorCode(node, output_file));
553 : GE_ASSERT_SUCCESS(code_dumper_asc_graph_.GenerateIrAttrCode(node, output_file));
554 : }
555 : GenerateFooter(output_file);
556 : output_file.close();
557 : return SUCCESS;
558 : }
559 :
560 : } // namespace ascir
561 : } // namespace af
|