| @@ -45,7 +45,7 @@ using abstract::AnfNodeConfigPtr; | |||
| std::string GetAbstractStr(const abstract::AbstractBasePtr &abs) { | |||
| if (abs == nullptr) { | |||
| return "Null Abstract"; | |||
| return "NullAbstract"; | |||
| } | |||
| auto shape = abs->BuildShape()->cast<abstract::ShapePtr>(); | |||
| TypePtr type = abs->BuildType(); | |||
| @@ -132,7 +132,8 @@ class AnalyzedFuncGraphExporter : public AnfExporter { | |||
| std::string GetNodeType(const AnfNodePtr &nd) override; | |||
| AbstractBasePtr GetNodeAbstract(const AnfNodePtr &nd); | |||
| AnfNodeConfigPtr GetFordwardConfigPtr(const AnfNodeConfigPtr &cfg); | |||
| AnalysisContextPtr ProcessFuncGraphCall(const CNodePtr &node); | |||
| std::vector<AnalysisContextPtr> ProcessFuncGraphCall(const CNodePtr &node, std::string *const op_comment); | |||
| void OutputStatementComment(std::ofstream &ofs, const CNodePtr &node, const std::vector<AnalysisContextPtr> &ctxs); | |||
| // key: context, val: whether the context has already been printed | |||
| std::unordered_map<AnalysisContextPtr, bool> context_map_; | |||
| @@ -170,21 +171,7 @@ std::string AnalyzedFuncGraphExporter::GetNodeType(const AnfNodePtr &node) { | |||
| if (ret == nullptr) { | |||
| return "Undefined"; | |||
| } | |||
| auto abs = ret->abstract(); | |||
| if (abs == nullptr) { | |||
| return "Undefined"; | |||
| } | |||
| auto dtype = abs->BuildType(); | |||
| auto shape = abs->BuildShape(); | |||
| std::ostringstream oss; | |||
| if (dtype != nullptr && abs->isa<abstract::AbstractTensor>() && shape != nullptr) { | |||
| oss << dtype->DumpText() << shape->DumpText(); | |||
| } else if (dtype != nullptr) { | |||
| oss << dtype->DumpText(); | |||
| } else { | |||
| oss << "Undefined"; | |||
| } | |||
| return oss.str(); | |||
| return GetAbstractStr(ret->abstract()); | |||
| } | |||
| AbstractBasePtr AnalyzedFuncGraphExporter::GetNodeAbstract(const AnfNodePtr &node) { | |||
| @@ -210,44 +197,115 @@ AnfNodeConfigPtr AnalyzedFuncGraphExporter::GetFordwardConfigPtr(const AnfNodeCo | |||
| return cur_cfg; | |||
| } | |||
| AnalysisContextPtr AnalyzedFuncGraphExporter::ProcessFuncGraphCall(const CNodePtr &node) { | |||
| std::vector<AnalysisContextPtr> AnalyzedFuncGraphExporter::ProcessFuncGraphCall(const CNodePtr &node, | |||
| std::string *const op_comment) { | |||
| std::vector<AnalysisContextPtr> ret_contexts; | |||
| if (node == nullptr) { | |||
| return nullptr; | |||
| return ret_contexts; | |||
| } | |||
| auto cfg = engine_->MakeConfig(node, cur_ctx_); | |||
| cfg = GetFordwardConfigPtr(cfg); | |||
| auto cnode = dyn_cast<CNode>(cfg->node()); | |||
| if (cnode == nullptr) { | |||
| MS_LOG(DEBUG) << "CNode is nullptr"; | |||
| return nullptr; | |||
| return ret_contexts; | |||
| } | |||
| ret_contexts.resize(cnode->size()); | |||
| const auto &inputs = cnode->inputs(); | |||
| auto op_abs = GetNodeAbstract(inputs[0]); | |||
| if (op_abs == nullptr) { | |||
| MS_LOG(DEBUG) << "Abstract of inputs[0] of cnode " << cnode->ToString() << " is nullptr"; | |||
| return nullptr; | |||
| } | |||
| for (size_t i = 0; i < inputs.size(); ++i) { | |||
| auto op_abs = GetNodeAbstract(inputs[i]); | |||
| if (op_abs == nullptr) { | |||
| MS_LOG(DEBUG) << "Abstract of inputs[" << i << "] of cnode " << cnode->ToString() << " is nullptr"; | |||
| continue; | |||
| } | |||
| if (!op_abs->isa<abstract::FuncGraphAbstractClosure>() && !op_abs->isa<abstract::MetaFuncGraphAbstractClosure>()) { | |||
| MS_LOG(DEBUG) << "Inputs[0] of cnode " << cnode->ToString() << " is of type " << op_abs->type_name() | |||
| << ", not function, ignore it"; | |||
| return nullptr; | |||
| if (!op_abs->isa<abstract::FuncGraphAbstractClosure>() && !op_abs->isa<abstract::MetaFuncGraphAbstractClosure>()) { | |||
| MS_LOG(DEBUG) << "Inputs[" << i << "] of cnode " << cnode->ToString() << " is of type " << op_abs->type_name() | |||
| << ", not function, ignore it"; | |||
| // Get prototype of VirtualEvaluator for printing | |||
| if (i == 0 && op_abs->isa<abstract::VirtualAbstractClosure>()) { | |||
| auto func = dyn_cast<abstract::VirtualAbstractClosure>(op_abs); | |||
| std::ostringstream oss; | |||
| oss << "("; | |||
| bool first_flag = false; | |||
| for (const auto &arg : func->args_spec_list()) { | |||
| if (!first_flag) { | |||
| first_flag = true; | |||
| } else { | |||
| oss << ", "; | |||
| } | |||
| oss << GetAbstractStr(arg); | |||
| } | |||
| oss << ") -> " << GetAbstractStr(func->output()) << " "; | |||
| *op_comment = oss.str(); | |||
| } | |||
| continue; | |||
| } | |||
| auto evaluator = engine_->GetEvaluatorFor(dyn_cast<abstract::AbstractFunction>(op_abs)); | |||
| if (!evaluator->isa<abstract::BaseFuncGraphEvaluator>()) { | |||
| MS_LOG(DEBUG) << "Evaluator for inputs[" << i << "] of cnode " << cnode->ToString() << " is of type " | |||
| << evaluator->type_name() << ", not BaseFuncGraphEvaluator, ignore it."; | |||
| continue; | |||
| } | |||
| auto base_fg_evaluator = dyn_cast<abstract::BaseFuncGraphEvaluator>(evaluator); | |||
| auto ctx = base_fg_evaluator->graph_context(); | |||
| if (ctx != nullptr && context_map_.insert({ctx, false}).second) { | |||
| MS_LOG(DEBUG) << "Add new context, ctx.addr = " << ctx.get() << "ctx = " << ctx->ToString(); | |||
| context_vec_.push_back(ctx); | |||
| } | |||
| ret_contexts[i] = ctx; | |||
| } | |||
| return ret_contexts; | |||
| } | |||
| auto evaluator = engine_->GetEvaluatorFor(dyn_cast<abstract::AbstractFunction>(op_abs)); | |||
| if (!evaluator->isa<abstract::BaseFuncGraphEvaluator>()) { | |||
| MS_LOG(DEBUG) << "Evaluator for inputs[0] of cnode " << cnode->ToString() << " is of type " | |||
| << evaluator->type_name() << ", not BaseFuncGraphEvaluator, ignore it."; | |||
| return nullptr; | |||
| void AnalyzedFuncGraphExporter::OutputStatementComment(std::ofstream &ofs, const CNodePtr &node, | |||
| const std::vector<AnalysisContextPtr> &ctxs) { | |||
| if (node == nullptr) { | |||
| return; | |||
| } | |||
| auto base_fg_evaluator = dyn_cast<abstract::BaseFuncGraphEvaluator>(evaluator); | |||
| auto ctx = base_fg_evaluator->graph_context(); | |||
| if (ctx != nullptr && context_map_.insert({ctx, false}).second) { | |||
| MS_LOG(DEBUG) << "Add new context, ctx.addr = " << ctx.get() << "ctx = " << ctx->ToString(); | |||
| context_vec_.push_back(ctx); | |||
| // output type of each input argument | |||
| auto &inputs = node->inputs(); | |||
| if (inputs.size() > 1) { | |||
| ofs << " #("; | |||
| for (size_t i = 1; i < inputs.size(); ++i) { | |||
| if (i != 1) { | |||
| ofs << ", "; | |||
| } | |||
| AnfNodePtr arg = inputs[i]; | |||
| ofs << GetNodeType(arg); | |||
| } | |||
| ofs << ")"; | |||
| } | |||
| // output other comment, map the graph name to original representation(containing unicode character) | |||
| std::ostringstream comment; | |||
| comment << " #"; | |||
| bool has_comment = false; | |||
| for (size_t i = 0; i < inputs.size(); ++i) { | |||
| AnfNodePtr arg = inputs[i]; | |||
| if (!IsValueNode<FuncGraph>(arg)) { | |||
| continue; | |||
| } | |||
| if (!has_comment) { | |||
| has_comment = true; | |||
| } else { | |||
| comment << ","; | |||
| } | |||
| FuncGraphPtr fg = GetValueNode<FuncGraphPtr>(arg); | |||
| std::string func_graph_id = fg->debug_info()->get_id(); | |||
| comment << " fg_" << func_graph_id << "=" << fg->ToString() << "." << func_graph_id; | |||
| if (ctxs.size() > i && ctxs[i] != nullptr) { | |||
| comment << "(@ctx.addr=" << ctxs[i].get() << ")"; | |||
| } | |||
| } | |||
| if (has_comment) { | |||
| ofs << comment.str(); | |||
| } | |||
| return ctx; | |||
| ofs << " #scope: " << node->scope()->name(); | |||
| } | |||
| void AnalyzedFuncGraphExporter::OutputCNode(std::ofstream &ofs, const CNodePtr &cnode, const FuncGraphPtr &func_graph, | |||
| @@ -278,10 +336,15 @@ void AnalyzedFuncGraphExporter::OutputCNode(std::ofstream &ofs, const CNodePtr & | |||
| ofs << ")"; | |||
| // process function graph call | |||
| auto ctx = ProcessFuncGraphCall(cnode); | |||
| std::string op_comment; | |||
| auto contexts = ProcessFuncGraphCall(cnode, &op_comment); | |||
| AnalysisContextPtr ctx = contexts.empty() ? nullptr : contexts[0]; | |||
| if (!op_comment.empty()) { | |||
| ofs << " #" << GetAnfNodeText(func_graph, inputs[0], *apply_map) << ".prototype = " << op_comment; | |||
| } | |||
| // output comment | |||
| OutputStatementComment(ofs, cnode); | |||
| OutputStatementComment(ofs, cnode, contexts); | |||
| if (ctx != nullptr) { | |||
| ofs << " @ctx.addr=" << ctx.get(); | |||
| } | |||
| @@ -432,10 +495,10 @@ void GetEvalStackInfo(std::ostringstream &oss) { | |||
| } | |||
| OutputAnalyzedGraphWithType(); | |||
| oss << "\nThe function call stack:\n"; | |||
| oss << "\nThe function call stack (See file 'analyze_fail.dat' for details):\n"; | |||
| int index = 0; | |||
| std::string last_py_func = ""; | |||
| std::string last_location_info = ""; | |||
| for (size_t i = 0; i < stack.size(); ++i) { | |||
| auto node_cfg = stack[i]; | |||
| @@ -446,13 +509,13 @@ void GetEvalStackInfo(std::ostringstream &oss) { | |||
| } | |||
| auto debug_info = cnode->debug_info(); | |||
| auto this_py_func = debug_info->get_python_func_belonged(); | |||
| if (i > 0 && (this_py_func == last_py_func)) { | |||
| MS_LOG(DEBUG) << "Python function of elements[" << i << "] is same as previous."; | |||
| auto this_location_info = trace::GetDebugInfo(debug_info, std::string("")); | |||
| if (this_location_info.empty() || this_location_info == last_location_info) { | |||
| continue; | |||
| } | |||
| last_py_func = this_py_func; | |||
| oss << "# " << index++ << " " << trace::GetDebugInfo(debug_info, std::string("")); | |||
| last_location_info = this_location_info; | |||
| oss << "# " << index++ << " " << this_location_info; | |||
| } | |||
| stack.clear(); | |||
| @@ -463,6 +526,7 @@ void GetEvalStackInfo(std::ostringstream &oss) { | |||
| static std::stack<std::pair<abstract::EvaluatorPtr, abstract::AnfNodeConfigPtr>> graph_infer_stack; | |||
| // trace the cnode infer debug info | |||
| static std::vector<abstract::AnfNodeConfigPtr> cnode_debug_stack{}; | |||
| void TraceGraphEvalEnter(const abstract::EvaluatorPtr &eval, const abstract::AnfNodeConfigPtr &node) { | |||
| if (eval == nullptr) { | |||
| MS_LOG(EXCEPTION) << "GraphInferEnter got null eval"; | |||