LCOV - code coverage report
Current view: top level - ut/autofuse/ascir/meta - ascend_graph_code_dumper.cpp Coverage Total Hit
Test: CHG Lines: 100.0 % 2 2
Test Date: 2026-08-20 14:28:35
Legend: Lines:     hit not hit

            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          261 :   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           55 :     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
        

Generated by: LCOV version 2.3.2-1