• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2019-2022 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "pipeline/jit/ps/debug/trace.h"
18 
19 #include <iostream>
20 #include <map>
21 #include <vector>
22 #include <string>
23 #include <utility>
24 #include <algorithm>
25 
26 #include "utils/hash_map.h"
27 #include "utils/hash_set.h"
28 #include "frontend/operator/composite/composite.h"
29 #include "ir/tensor.h"
30 #include "include/common/debug/common.h"
31 #include "include/common/debug/anf_ir_dump.h"
32 #include "pipeline/jit/ps/static_analysis/evaluator.h"
33 #include "pipeline/jit/ps/static_analysis/async_eval_result.h"
34 #include "utils/log_adapter.h"
35 #include "include/common/utils/comm_manager.h"
36 #include "abstract/abstract_value.h"
37 #include "utils/file_utils.h"
38 #include "utils/ms_exception.h"
39 
40 namespace mindspore {
41 // namespace to support debug trace information
42 namespace trace {
43 using abstract::AbstractBasePtr;
44 using abstract::AnalysisContextPtr;
45 using abstract::AnalysisEnginePtr;
46 using abstract::AnfNodeConfigPtr;
47 
GetAbstractStr(const abstract::AbstractBasePtr & abs)48 std::string GetAbstractStr(const abstract::AbstractBasePtr &abs) {
49   if (abs == nullptr) {
50     return "<NullAbstract>";
51   }
52   auto shape = abs->BuildShape()->cast<abstract::BaseShapePtr>();
53   TypePtr type = abs->BuildType();
54   std::ostringstream oss;
55   if ((shape != nullptr) && (type != nullptr)) {
56     oss << "<" << type << ", " << shape->ToString() << ">";
57   } else if (type != nullptr) {
58     oss << "<" << type << ">";
59   } else {
60     oss << "<null>";
61   }
62   return oss.str();
63 }
64 
GetGraphParamString(const FuncGraphPtr & graph,const abstract::AbstractBasePtrList & args_abs_list)65 std::string GetGraphParamString(const FuncGraphPtr &graph, const abstract::AbstractBasePtrList &args_abs_list) {
66   MS_EXCEPTION_IF_NULL(graph);
67   std::ostringstream oss;
68   oss << "graph:" << graph->ToString() << " with args[";
69   auto params = graph->parameters();
70   if (params.size() < args_abs_list.size()) {
71     MS_INTERNAL_EXCEPTION(TypeError) << "The size of parameters less than args_abs_list's size.";
72   }
73   for (size_t i = 0; i < args_abs_list.size(); i++) {
74     auto parameter = params[i];
75     MS_EXCEPTION_IF_NULL(parameter);
76     oss << parameter->ToString() << ":<" << GetAbstractStr(args_abs_list[i]) << ">,";
77   }
78   oss << "]";
79   oss << GetDebugInfoStr(graph->debug_info(), "", kSourceLineTipDiscard);
80   return oss.str();
81 }
82 
DumpInferStack(std::ostringstream & oss)83 void DumpInferStack(std::ostringstream &oss) {
84   auto graph_stack = GetCurrentGraphEvalStack();
85   if (graph_stack.empty()) {
86     return;
87   }
88   std::vector<std::pair<abstract::AnalysisContextPtr, abstract::AnfNodeConfigPtr>> infer_vec;
89   while (!graph_stack.empty()) {
90     auto top = graph_stack.back();
91     infer_vec.push_back(top);
92     graph_stack.pop_back();
93   }
94   std::reverse(infer_vec.begin(), infer_vec.end());
95   int index = 0;
96   for (const auto &item : infer_vec) {
97     auto context = item.first;
98     if (context == nullptr) {
99       MS_LOG(INTERNAL_EXCEPTION) << "DumpInferStack failed, got null graph context";
100     }
101     auto graph = context->func_graph();
102     if (graph == nullptr) {  // Top context.
103       continue;
104     }
105     const auto &args_abs_list = context->args_abs_list();
106     if (graph->parameters().size() < args_abs_list.size()) {
107       continue;
108     }
109     oss << "    #" << index++ << " " << GetGraphParamString(graph, args_abs_list) << "\n";
110   }
111 }
112 
TraceGraphEval()113 void TraceGraphEval() {
114   auto &graph_stack = GetCurrentGraphEvalStack();
115   if (graph_stack.empty()) {
116     MS_LOG(INFO) << "Length of analysis graph stack is empty.";
117     return;
118   }
119   std::ostringstream oss;
120   oss << "\n*******************************graph evaluate stack**********************************";
121   oss << std::endl;
122   DumpInferStack(oss);
123   oss << "\n*************************************************************************************";
124   MS_LOG(INFO) << oss.str();
125 }
126 
127 class AnalyzeFailExporter {
128  public:
AnalyzeFailExporter()129   AnalyzeFailExporter() {
130     is_top_graph_ = false;
131     exported_.clear();
132   }
~AnalyzeFailExporter()133   ~AnalyzeFailExporter() {}
134 
135   bool ExportFuncGraph(const std::string &filename, const TraceCNodeEvalStack &node_config_stack);
136 
137  protected:
138   void OutputCNode(const CNodePtr &node, const FuncGraphPtr &sub_graph, const OrderedMap<AnfNodePtr, int32_t> &para_map,
139                    const std::shared_ptr<SubGraphIRInfo> &gsub);
140   AbstractBasePtr GetNodeAbstract(const AnfNodePtr &node);
141   AnfNodeConfigPtr GetForwardConfig(const AnfNodeConfigPtr &cfg);
142   void ProcessFuncGraphCall(const CNodePtr &node, std::string *const op_comment);
143   mindspore::HashMap<FuncGraphPtr, TaggedNodeMap> CreateTaggedNodeMap(
144     const std::vector<abstract::AnfNodeConfigPtr> &node_config_stack);
145   void ExportOneFuncGraph(const FuncGraphPtr &func_graph, const TaggedNodeMap &tagged_cnodes_map,
146                           std::ostringstream &oss, OrderedMap<AnfNodePtr, int32_t> *para_map, int32_t total_para);
147   void OutputStatementComment(const CNodePtr &node, const FuncGraphPtr &func_graph, std::ostringstream &oss);
148   std::string OuputIrStyleCNodes(const FuncGraphPtr &func_graph, const std::vector<AnfNodePtr> &nodes,
149                                  const TaggedNodeMap &tagged_cnodes_map, int32_t total_para,
150                                  OrderedMap<AnfNodePtr, int32_t> *para_map);
151   std::string GetNodeType(const AnfNodePtr &node);
152 
153  private:
154   AnalysisContextPtr current_context_ = nullptr;
155   AnalysisEnginePtr engine_ = nullptr;
156   OrderedMap<FuncGraphPtr, ParamIndexMap> exported_;
157   bool is_top_graph_;
158 };
159 
CreateTaggedNodeMap(const std::vector<abstract::AnfNodeConfigPtr> & node_config_stack)160 mindspore::HashMap<FuncGraphPtr, TaggedNodeMap> AnalyzeFailExporter::CreateTaggedNodeMap(
161   const std::vector<abstract::AnfNodeConfigPtr> &node_config_stack) {
162   mindspore::HashSet<abstract::AnfNodeConfigPtr> forwarded_configs;  // Check if config. is forwarded.
163   mindspore::HashMap<FuncGraphPtr, TaggedNodeMap> tagged_func_graphs;
164   size_t index = 0;
165   for (auto &node_config : node_config_stack) {
166     MS_EXCEPTION_IF_NULL(node_config);
167 
168     // Record new config in set.
169     auto new_config = GetForwardConfig(node_config);
170     if (new_config != node_config) {
171       MS_LOG(DEBUG) << "The node_config is forwarded, old config: " << node_config->ToString()
172                     << ", new_config: " << new_config->ToString();
173       forwarded_configs.emplace(new_config);
174     }
175 
176     // Ignore the new config.
177     if (forwarded_configs.find(node_config) != forwarded_configs.end()) {
178       continue;
179     }
180 
181     auto fg = node_config->func_graph();
182     MS_EXCEPTION_IF_NULL(fg);
183     auto node = node_config->node();
184     tagged_func_graphs[fg][node] = index;
185     index++;
186   }
187   return tagged_func_graphs;
188 }
189 
OutputAnalyzedGraphWithType(const string & file_path)190 bool OutputAnalyzedGraphWithType(const string &file_path) {
191   AnalyzeFailExporter exporter;
192   return exporter.ExportFuncGraph(file_path, GetCNodeDebugStack());
193 }
194 
PrintTupleNodeUsedFlagsDat(const abstract::AbstractSequencePtr & sequence_abs,std::ostringstream & buffer)195 void PrintTupleNodeUsedFlagsDat(const abstract::AbstractSequencePtr &sequence_abs, std::ostringstream &buffer) {
196   if (sequence_abs == nullptr || sequence_abs->sequence_nodes() == nullptr || sequence_abs->sequence_nodes()->empty()) {
197     return;
198   }
199 
200   buffer << ", sequence_nodes={";
201   for (size_t i = 0; i < sequence_abs->sequence_nodes()->size(); ++i) {
202     auto node = (*sequence_abs->sequence_nodes())[i].lock();
203     if (node == nullptr) {
204       MS_LOG(DEBUG) << "The node in sequence_nodes is free.";
205       buffer << "node={<freed node>}";
206     } else {
207       buffer << "node={" << node->DebugString();
208       auto flags = GetSequenceNodeElementsUseFlags(node);
209       if (flags != nullptr) {
210         buffer << ", elements_use_flags: {ptr: " << flags << ", value: " << (*flags) << "}";
211       }
212       buffer << "}";
213     }
214     if (i != sequence_abs->sequence_nodes()->size() - 1) {
215       buffer << ", ";
216     }
217   }
218   buffer << "}";
219 }
220 
GetNodeTypeOrigin(const AnfNodePtr & nd)221 std::string GetNodeTypeOrigin(const AnfNodePtr &nd) {
222   MS_EXCEPTION_IF_NULL(nd);
223   ValuePtr tensor_value = nullptr;
224   StringImmPtr ref_key = nullptr;
225   abstract::AbstractSequencePtr sequence_abs = nullptr;
226   auto abstract = nd->abstract();
227   if (abstract != nullptr) {
228     if (abstract->isa<abstract::AbstractTensor>()) {
229       tensor_value = abstract->BuildValue();
230     }
231     if (auto ref_tensor = abstract->cast_ptr<abstract::AbstractRefTensor>(); ref_tensor != nullptr) {
232       ref_key = dyn_cast<StringImm>(ref_tensor->ref_key_value());
233     } else if (auto map_tensor = abstract->cast_ptr<abstract::AbstractMapTensor>(); map_tensor != nullptr) {
234       ref_key = dyn_cast<StringImm>(map_tensor->ref_key_value());
235     }
236     sequence_abs = dyn_cast<abstract::AbstractSequence>(abstract);
237   }
238   abstract::BaseShapePtr shape = nd->Shape() == nullptr ? nullptr : dyn_cast<abstract::BaseShape>(nd->Shape());
239   TypePtr type = dyn_cast<Type>(nd->Type());
240   std::ostringstream oss;
241   if ((shape != nullptr) && (type != nullptr)) {
242     oss << "<" << type << ", " << shape->ToString();
243     if (tensor_value != nullptr && tensor_value != kValueAny) {
244       oss << ", value=...";
245     }
246     if (ref_key != nullptr) {
247       oss << ", ref_key=" << ref_key->value();
248     }
249     PrintTupleNodeUsedFlagsDat(sequence_abs, oss);
250     oss << ">";
251   } else if (type != nullptr) {
252     oss << "<" << type;
253     if (tensor_value != nullptr && tensor_value != kValueAny) {
254       oss << ", value=...";
255     }
256     if (ref_key != nullptr) {
257       oss << ", ref_key=" << ref_key->value();
258     }
259     PrintTupleNodeUsedFlagsDat(sequence_abs, oss);
260     oss << ">";
261   } else {
262     oss << "<null>";
263   }
264   return oss.str();
265 }
266 
GetNodeType(const AnfNodePtr & node)267 std::string AnalyzeFailExporter::GetNodeType(const AnfNodePtr &node) {
268   if (current_context_ == nullptr) {
269     return GetNodeTypeOrigin(node);
270   }
271 
272   MS_EXCEPTION_IF_NULL(engine_);
273   try {
274     FuncGraphPtr dummy_call_func_graph = nullptr;
275     auto cfg = engine_->MakeConfig(node, current_context_, dummy_call_func_graph);
276     auto res = abstract::AnalysisResultCacheMgr::GetInstance().GetValue(cfg);
277     if (res != nullptr) {
278       return GetAbstractStr(res->abstract());
279     }
280   } catch (const std::exception &e) {
281     MS_LOG(INFO) << "Exception: " << e.what();
282   }
283   return "<null>";
284 }
285 
GetNodeAbstract(const AnfNodePtr & node)286 AbstractBasePtr AnalyzeFailExporter::GetNodeAbstract(const AnfNodePtr &node) {
287   if (current_context_ == nullptr) {
288     return nullptr;
289   }
290   MS_EXCEPTION_IF_NULL(engine_);
291   try {
292     FuncGraphPtr dummy_call_func_graph = nullptr;
293     auto cfg = engine_->MakeConfig(node, current_context_, dummy_call_func_graph);
294     auto res = abstract::AnalysisResultCacheMgr::GetInstance().GetValue(cfg);
295     return res == nullptr ? nullptr : res->abstract();
296   } catch (const std::exception &e) {
297     MS_LOG(INFO) << "Exception: " << e.what();
298   }
299   return nullptr;
300 }
301 
GetForwardConfig(const AnfNodeConfigPtr & cfg)302 AnfNodeConfigPtr AnalyzeFailExporter::GetForwardConfig(const AnfNodeConfigPtr &cfg) {
303   MS_EXCEPTION_IF_NULL(cfg);
304   MS_EXCEPTION_IF_NULL(engine_);
305   AnfNodeConfigPtr cur_cfg = cfg;
306   auto iter = engine_->anfnode_config_map().find(cur_cfg);
307   while (iter != engine_->anfnode_config_map().end()) {
308     auto node = cur_cfg->node();
309     cur_cfg = iter->second;
310     MS_LOG(DEBUG) << "Get forward node: " << node << "[" << node->DebugString() << "] --> " << cur_cfg->node() << "["
311                   << cur_cfg->node()->DebugString() << "]";
312     iter = engine_->anfnode_config_map().find(cur_cfg);
313   }
314   return cur_cfg;
315 }
316 
ProcessFuncGraphCall(const CNodePtr & node,std::string * const op_comment)317 void AnalyzeFailExporter::ProcessFuncGraphCall(const CNodePtr &node, std::string *const op_comment) {
318   if (node == nullptr) {
319     MS_LOG(ERROR) << "Node is nullptr";
320     return;
321   }
322   CNodePtr cnode = nullptr;
323   try {
324     FuncGraphPtr dummy_call_func_graph = nullptr;
325     auto cfg = engine_->MakeConfig(node, current_context_, dummy_call_func_graph);
326     cfg = GetForwardConfig(cfg);
327     MS_EXCEPTION_IF_NULL(cfg);
328     cnode = dyn_cast<CNode>(cfg->node());
329   } catch (const std::exception &e) {
330     MS_LOG(INFO) << "Exception: " << e.what();
331   }
332   if (cnode == nullptr) {
333     MS_LOG(INFO) << "CNode is nullptr";
334     return;
335   }
336 
337   const auto &inputs = cnode->inputs();
338   for (size_t i = 0; i < inputs.size(); ++i) {
339     auto op_abs = GetNodeAbstract(inputs[i]);
340     if (op_abs == nullptr) {
341       MS_LOG(DEBUG) << "Abstract of inputs[" << i << "] of cnode " << cnode->ToString() << "  is nullptr";
342       continue;
343     }
344 
345     if (!op_abs->isa<abstract::FuncGraphAbstractClosure>() && !op_abs->isa<abstract::MetaFuncGraphAbstractClosure>()) {
346       MS_LOG(DEBUG) << "Inputs[" << i << "] of cnode " << cnode->ToString() << " is of type " << op_abs->type_name()
347                     << ", not function, ignore it";
348       // Get prototype of VirtualEvaluator for printing
349       if (i == 0 && op_abs->isa<abstract::VirtualAbstractClosure>()) {
350         auto func = dyn_cast<abstract::VirtualAbstractClosure>(op_abs);
351         std::ostringstream oss;
352         oss << "(";
353         bool first_flag = false;
354         for (const auto &arg : func->args_abs_list()) {
355           if (!first_flag) {
356             first_flag = true;
357           } else {
358             oss << ", ";
359           }
360           oss << GetAbstractStr(arg);
361         }
362         oss << ") -> " << GetAbstractStr(func->output()) << " ";
363         *op_comment = oss.str();
364       }
365     }
366   }
367 }
368 
OutputStatementComment(const CNodePtr & node,const FuncGraphPtr & func_graph,std::ostringstream & oss)369 void AnalyzeFailExporter::OutputStatementComment(const CNodePtr &node, const FuncGraphPtr &func_graph,
370                                                  std::ostringstream &oss) {
371   if (node == nullptr) {
372     return;
373   }
374   // Output type of each input argument
375   auto &inputs = node->inputs();
376   if (node != func_graph->get_return()) {
377     if (inputs.size() > 1) {
378       oss << "\n      : (";
379       for (size_t i = 1; i < inputs.size(); ++i) {
380         if (i != 1) {
381           oss << ", ";
382         }
383         AnfNodePtr arg = inputs[i];
384         oss << GetNodeType(arg);
385       }
386       oss << ")"
387           << " -> "
388           << "(" << GetNodeType(node) << ")";
389     }
390   } else {
391     oss << "\n      : (" << GetNodeType(node) << ")";
392   }
393   // Output other comment, map the graph name to original representation(containing unicode character)
394   oss << "\n";
395   oss << "      #scope: (" << node->scope()->name() << ")";
396 }
397 
OutputCNode(const CNodePtr & node,const FuncGraphPtr & sub_graph,const OrderedMap<AnfNodePtr,int32_t> & para_map,const std::shared_ptr<SubGraphIRInfo> & gsub)398 void AnalyzeFailExporter::OutputCNode(const CNodePtr &node, const FuncGraphPtr &sub_graph,
399                                       const OrderedMap<AnfNodePtr, int32_t> &para_map,
400                                       const std::shared_ptr<SubGraphIRInfo> &gsub) {
401   if (node != sub_graph->get_return()) {
402     gsub->buffer << "  %" << gsub->local_var << "(" << node->ToString() << ")"
403                  << " = ";
404     gsub->local_var_map[node] = gsub->local_var++;
405   } else {
406     gsub->buffer << "  ";
407   }
408 
409   if (node->inputs().empty()) {
410     MS_LOG(INTERNAL_EXCEPTION) << "Input of CNode is empty";
411   }
412 
413   // Print operator
414   DumpOperator(node, gsub);
415 
416   // Print operands
417   DumpOperands(node, para_map, gsub);
418 
419   // Print operator attrs
420   AnfNodePtr op = node->input(0);
421   DumpOperateAttrs(op, gsub);
422 
423   // Print cnode attrs
424   DumpCNodeAttrs(node, gsub);
425 
426   // Print cnode primal attrs
427   DumpCNodePrimalAttrs(node, gsub);
428 
429   // Print parallel info
430   DumpParallelInfo(node, gsub);
431 
432   // Process function graph call
433   std::string op_comment;
434   ProcessFuncGraphCall(node, &op_comment);
435   if (!op_comment.empty()) {
436     auto &inputs = node->inputs();
437     std::shared_ptr<SubGraphIRInfo> input_gsub = std::make_shared<SubGraphIRInfo>();
438     input_gsub->local_var = 0;
439     DumpOperator(inputs[0], input_gsub);
440     gsub->buffer << "    #" << input_gsub->buffer.str() << ".prototype = " << op_comment;
441   }
442   // Output comment
443   OutputStatementComment(node, sub_graph, gsub->buffer);
444   gsub->buffer << "\n";
445 }
446 
OuputIrStyleCNodes(const FuncGraphPtr & func_graph,const std::vector<AnfNodePtr> & nodes,const TaggedNodeMap & tagged_cnodes_map,int32_t total_para,OrderedMap<AnfNodePtr,int32_t> * para_map)447 std::string AnalyzeFailExporter::OuputIrStyleCNodes(const FuncGraphPtr &func_graph,
448                                                     const std::vector<AnfNodePtr> &nodes,
449                                                     const TaggedNodeMap &tagged_cnodes_map, int32_t total_para,
450                                                     OrderedMap<AnfNodePtr, int32_t> *para_map) {
451   MS_EXCEPTION_IF_NULL(func_graph);
452   auto &parameters = func_graph->parameters();
453   std::shared_ptr<SubGraphIRInfo> gsub = std::make_shared<SubGraphIRInfo>();
454   gsub->local_var = 0;
455   if (!is_top_graph_) {
456     if (parameters.size() == 1) {
457       MS_EXCEPTION_IF_NULL(parameters[0]);
458       gsub->buffer << "%para" << (*para_map)[parameters[0]] << "_" << parameters[0]->ToString();
459     } else if (parameters.size() > 1) {
460       for (size_t idx = 0; idx < parameters.size() - 1; idx++) {
461         MS_EXCEPTION_IF_NULL(parameters[idx]);
462         gsub->buffer << "%para" << (*para_map)[parameters[idx]] << "_" << parameters[idx]->ToString();
463         gsub->buffer << ", ";
464       }
465       MS_EXCEPTION_IF_NULL(parameters[parameters.size() - 1]);
466       gsub->buffer << "%para" << (*para_map)[parameters[parameters.size() - 1]] << "_"
467                    << parameters[parameters.size() - 1]->ToString();
468     }
469   } else {
470     is_top_graph_ = false;
471   }
472   gsub->buffer << ") {\n";
473   ParamIndexMap param_map;
474   exported_[func_graph] = param_map;
475   gsub->local_var = 0;
476   for (size_t idx = 0; idx < parameters.size(); idx++) {
477     MS_EXCEPTION_IF_NULL(parameters[idx]);
478     if ((*para_map).count(parameters[idx]) == 0) {
479       (*para_map)[parameters[idx]] = total_para++;
480     }
481   }
482   for (const AnfNodePtr &node : nodes) {
483     MS_EXCEPTION_IF_NULL(node);
484     if (!node->isa<CNode>()) {
485       continue;
486     }
487     auto cnode = node->cast<CNodePtr>();
488     if (!tagged_cnodes_map.empty()) {
489       auto iter = tagged_cnodes_map.find(node);
490       if (iter != tagged_cnodes_map.end()) {
491         gsub->buffer << "\n#------------------------> " << iter->second << "\n";
492       }
493     }
494     OutputCNode(cnode, func_graph, *para_map, gsub);
495     if (trace::GetGlobalTraceLabelType() == trace::TraceLabelType::kWithUniqueId) {
496       gsub->buffer << trace::GetDebugInfoStr(cnode->debug_info(), "      # ", kSourceLineTipDiscard) << "#"
497                    << trace::Label(cnode->debug_info()) << "\n";
498     } else {
499       std::string dgi = trace::GetDebugInfoStr(cnode->debug_info(), "      # ", kSourceLineTipDiscard);
500       if (dgi != "") {
501         gsub->buffer << trace::GetDebugInfoStr(cnode->debug_info(), "      # ", kSourceLineTipDiscard) << "\n";
502       }
503     }
504   }
505   return gsub->buffer.str();
506 }
507 
ExportOneFuncGraph(const FuncGraphPtr & func_graph,const TaggedNodeMap & tagged_cnodes_map,std::ostringstream & oss,OrderedMap<AnfNodePtr,int32_t> * para_map,int32_t total_para)508 void AnalyzeFailExporter::ExportOneFuncGraph(const FuncGraphPtr &func_graph, const TaggedNodeMap &tagged_cnodes_map,
509                                              std::ostringstream &oss, OrderedMap<AnfNodePtr, int32_t> *para_map,
510                                              int32_t total_para) {
511   if (func_graph == nullptr) {
512     return;
513   }
514 
515   std::vector<AnfNodePtr> nodes = TopoSort(func_graph->get_return(), SuccIncoming, AlwaysInclude);
516 
517   if (*(func_graph->indirect())) {
518     oss << "indirect: " << *(func_graph->indirect()) << "\n";
519   }
520   oss << "subgraph attr:" << std::endl;
521   for (const auto &attr : func_graph->attrs()) {
522     oss << attr.first << ": ";
523     MS_EXCEPTION_IF_NULL(attr.second);
524     if (attr.second->isa<BoolImm>()) {
525       oss << GetValue<bool>(attr.second);
526     } else if (attr.second->isa<StringImm>()) {
527       oss << (GetValue<std::string>(attr.second));
528     }
529     oss << std::endl;
530   }
531   oss << "subgraph instance: " << func_graph->ToString() << " : " << func_graph.get() << std::endl;
532   // Dump side effect info.
533   auto effect_info = func_graph->GetEffectInfo();
534   if (effect_info.HasEffect()) {
535     oss << "# " << effect_info.ToString() << '\n';
536   }
537   if (trace::GetGlobalTraceLabelType() == trace::TraceLabelType::kWithUniqueId) {
538     oss << trace::GetDebugInfoStr(func_graph->debug_info(), "# ", kSourceLineTipDiscard) << "#"
539         << trace::Label(func_graph->debug_info()) << "\n";
540   } else {
541     oss << trace::GetDebugInfoStr(func_graph->debug_info(), "# ", kSourceLineTipDiscard) << "\n";
542   }
543   oss << "subgraph @" << func_graph->ToString();
544   if (func_graph->parent() != nullptr) {
545     oss << " parent: [subgraph @" << func_graph->parent()->ToString() << "]";
546   }
547   oss << "(";
548   oss << OuputIrStyleCNodes(func_graph, nodes, tagged_cnodes_map, total_para, para_map);
549 
550   oss << "}\n";
551 
552   OutputOrderList(func_graph, oss);
553 }
554 
ExportFuncGraph(const std::string & filename,const TraceCNodeEvalStack & node_config_stack)555 bool AnalyzeFailExporter::ExportFuncGraph(const std::string &filename, const TraceCNodeEvalStack &node_config_stack) {
556   if (node_config_stack.empty()) {
557     MS_LOG(DEBUG) << "Node configs is empty";
558     return false;
559   }
560   auto real_filepath = Common::CreatePrefixPath(filename);
561   if (!real_filepath.has_value()) {
562     MS_LOG(ERROR) << "The export ir path: " << filename << " is not illegal.";
563     return false;
564   }
565   ChangeFileMode(real_filepath.value(), S_IWUSR);
566   std::ofstream ofs(real_filepath.value());
567   if (!ofs.is_open()) {
568     MS_LOG(ERROR) << "Open file '" << real_filepath.value() << "' failed!" << ErrnoToString(errno);
569     return false;
570   }
571   ofs << "# ===============================================================================================\n"
572       << "# The following shows the last analyze fail log message.\n"
573       << "# ===============================================================================================\n\n"
574       << "----------------------------------------------------\n"
575       << "- Caught exception:\n"
576       << "----------------------------------------------------\n"
577       << StaticAnalysisException::Instance().msg();
578 
579   ofs << "# ===============================================================================================\n"
580       << "# The following shows the IR when the function graphs evaluation fails to help locate the problem.\n"
581       << "# You can search the last ------------------------> to the node which is evaluated failure.\n"
582       << "# Refer to https://www.mindspore.cn/search?inputValue=analyze_fail.ir to get more instructions.\n"
583       << "# ===============================================================================================\n\n";
584 
585   if (engine_ == nullptr) {
586     engine_ = node_config_stack.front()->engine();
587   }
588   auto top_func = node_config_stack.front()->func_graph();
589   std::ostringstream head_buffer;
590   MS_EXCEPTION_IF_NULL(top_func);
591   is_top_graph_ = true;
592   auto sub_graphs = top_func->func_graphs_used_total();
593   std::ostringstream oss;
594   DumpGlobalInfoEntry(top_func, oss, sub_graphs.size());
595   OrderedMap<AnfNodePtr, int32_t> para_map;
596   int32_t total_para = DumpParams(top_func, oss, &para_map);
597   ofs << oss.str();
598   ofs << std::endl;
599   ofs << head_buffer.str();
600   auto tagged_func_graphs = CreateTaggedNodeMap(node_config_stack);
601   mindspore::HashSet<FuncGraphPtr> printed_func_graphs;  // Check if func graph has been printed.
602   // Output graph on the analysis stack
603   for (const auto &node_config : node_config_stack) {
604     MS_EXCEPTION_IF_NULL(node_config);
605     auto fg = node_config->func_graph();
606     MS_LOG(INFO) << "Node: " << node_config->node()->DebugString()
607                  << ", FV: " << (node_config->func_graph() != node_config->context()->func_graph())
608                  << ", calling func graph: " << node_config->func_graph()->ToString()
609                  << ", context func graph: " << node_config->context()->func_graph()->ToString();
610     if (fg == nullptr) {
611       MS_LOG(ERROR) << "FuncGraph is null, context: " << node_config->ToString();
612       continue;
613     }
614     if (printed_func_graphs.find(fg) != printed_func_graphs.end()) {
615       continue;
616     }
617     (void)printed_func_graphs.emplace(fg);
618 
619     current_context_ = node_config->context();  // Set current context.
620     std::ostringstream buffer;
621     ExportOneFuncGraph(fg, tagged_func_graphs[fg], buffer, &para_map, total_para);
622     ofs << buffer.str() << "\n\n";
623   }
624   current_context_ = nullptr;
625 
626   ofs << "# ===============================================================================================\n";
627   ofs << "# The total of function graphs in evaluation stack: ";
628   auto ignored_num = (node_config_stack.size() - printed_func_graphs.size());
629   if (ignored_num == 0) {
630     ofs << node_config_stack.size() << "\n";
631   } else {
632     ofs << printed_func_graphs.size() << "/" << node_config_stack.size() << " (Ignored " << ignored_num
633         << " internal frames).\n";
634   }
635   ofs << "# ===============================================================================================\n";
636 
637   ofs << "\n\n# ===============================================================================================\n";
638   ofs << "# The rest function graphs are the following:\n";
639   ofs << "# ===============================================================================================\n";
640 
641   bool has_rest_fg = false;
642   TaggedNodeMap empty_map;
643   for (const auto &fg : top_func->func_graphs_used_total()) {
644     if (!printed_func_graphs.emplace(fg).second) {
645       continue;
646     }
647     std::ostringstream buffer;
648     ExportOneFuncGraph(fg, empty_map, buffer, &para_map, total_para);
649     ofs << buffer.str() << "\n\n";
650     has_rest_fg = true;
651   }
652   if (!has_rest_fg) {
653     ofs << "No more function graphs.\n\n";
654   }
655 
656   ofs.close();
657   ChangeFileMode(real_filepath.value(), S_IRUSR);
658   return true;
659 }
660 
GetEvalFailDatPath()661 std::string GetEvalFailDatPath() {
662   std::string path;
663   auto ms_om_path = common::GetEnv("MS_OM_PATH");
664   if (!ms_om_path.empty()) {
665     path = ms_om_path;
666   } else {
667     path = ".";
668   }
669   path += "/rank_" + std::to_string(GetRank()) + "/om/analyze_fail.ir";
670   // Support "../" in path.
671   auto realpath = Common::CreatePrefixPath(path, true);
672   if (!realpath.has_value()) {
673     MS_EXCEPTION(ValueError) << "Get real path failed. path=" << path;
674   }
675   return realpath.value();
676 }
677 
GetEvalStackInfo(std::ostringstream & oss)678 void GetEvalStackInfo(std::ostringstream &oss) {
679   MS_LOG(INFO) << "Get graph analysis information begin";
680   auto stack = GetCNodeDebugStack();
681   if (stack.empty()) {
682     MS_LOG(INFO) << "Length of analysis information stack is empty.";
683     return;
684   }
685 
686   oss << "\n";
687   int index = 0;
688   int file_oss_index = 0;
689   std::string last_location_info = "";
690   const size_t max_stack_depth = 50;
691   bool print_ellipsis = false;
692   const size_t half = 2;
693   if (stack.size() > max_stack_depth) {
694     oss << "The depth of the current stack is " << stack.size() << ".\n"
695         << "You can get more call stack information in analyze_fail.ir.\n\n";
696   }
697   std::ostringstream file_oss;
698   file_oss << "\n";
699 
700   for (size_t i = 0; i < stack.size(); ++i) {
701     auto node_config = stack[i];
702     MS_EXCEPTION_IF_NULL(node_config);
703     auto cnode = dyn_cast<CNode>(node_config->node());
704     if (cnode == nullptr) {
705       MS_LOG(DEBUG) << "CNode of elements[" << i << "] is nullptr.";
706       continue;
707     }
708 
709     auto debug_info = cnode->debug_info();
710     auto this_location_info = trace::GetDebugInfoStr(debug_info);
711     if (this_location_info.empty() || this_location_info == last_location_info) {
712       continue;
713     }
714     last_location_info = this_location_info;
715     file_oss << "# " << file_oss_index++ << " " << this_location_info;
716     if ((i <= max_stack_depth / half) || (i >= (stack.size() - max_stack_depth / half))) {
717       oss << "# " << index++ << " " << this_location_info;
718     } else {
719       if (!print_ellipsis) {
720         print_ellipsis = true;
721         oss << "......\n\n";
722       }
723       index++;
724     }
725   }
726   bool empty_stack_info = oss.str() == "\n";
727 
728 #ifndef ENABLE_SECURITY
729   std::string msg =
730     "\n----------------------------------------------------\n"
731     "- The Traceback of Net Construct Code:\n"
732     "----------------------------------------------------" +
733     file_oss.str() + "\n";
734   StaticAnalysisException::Instance().AppendMsg(msg);
735   std::string file_name = GetEvalFailDatPath();
736   auto ret = OutputAnalyzedGraphWithType(file_name);
737   if (ret) {
738     oss << " (See file '" << file_name
739         << "' for more details. Get instructions about `analyze_fail.ir` at "
740            "https://www.mindspore.cn/search?inputValue=analyze_fail.ir)";
741   }
742 #endif
743   stack.clear();
744   MS_LOG(INFO) << "Get graph analysis information end";
745   if (empty_stack_info) {
746     oss.str("");
747   }
748 }
749 
750 // Trace the graph evaluator stack
751 thread_local TraceGraphEvalStack graph_infer_stack;
752 // Trace the cnode infer debug info
753 thread_local TraceCNodeEvalStack cnode_debug_stack{};
754 
TraceGraphEvalEnter(const abstract::AnalysisContextPtr & context,const abstract::AnfNodeConfigPtr & node)755 void TraceGraphEvalEnter(const abstract::AnalysisContextPtr &context, const abstract::AnfNodeConfigPtr &node) {
756   if (context == nullptr) {
757     MS_LOG(INTERNAL_EXCEPTION) << "GraphInferEnter got null context";
758   }
759   (void)graph_infer_stack.push_back(std::pair<abstract::AnalysisContextPtr, abstract::AnfNodeConfigPtr>(context, node));
760 }
761 
TraceGraphEvalLeave(const abstract::AnalysisContextPtr & context)762 void TraceGraphEvalLeave(const abstract::AnalysisContextPtr &context) {
763   if (context == nullptr) {
764     MS_LOG(INTERNAL_EXCEPTION) << "The context is null.";
765   }
766   if (graph_infer_stack.empty()) {
767     MS_LOG(INTERNAL_EXCEPTION) << "The call stack is empty.";
768   }
769   if (context != graph_infer_stack.back().first) {
770     MS_LOG(INTERNAL_EXCEPTION) << "Different context: " << context->func_graph()->ToString() << ", "
771                                << graph_infer_stack.back().first->func_graph()->ToString();
772   }
773   graph_infer_stack.pop_back();
774 }
775 
TraceGraphEvalStackPrepare(const TraceGraphEvalStack & graph_evals)776 void TraceGraphEvalStackPrepare(const TraceGraphEvalStack &graph_evals) {
777   (void)graph_infer_stack.insert(graph_infer_stack.end(), graph_evals.begin(), graph_evals.end());
778 }
779 
TraceEvalCNodeStackPrepare(const TraceCNodeEvalStack & cnode_evals)780 void TraceEvalCNodeStackPrepare(const TraceCNodeEvalStack &cnode_evals) {
781   (void)cnode_debug_stack.insert(cnode_debug_stack.end(), cnode_evals.begin(), cnode_evals.end());
782 }
783 
TraceEvalCNodeEnter(const abstract::AnfNodeConfigPtr & node_config)784 void TraceEvalCNodeEnter(const abstract::AnfNodeConfigPtr &node_config) { cnode_debug_stack.push_back(node_config); }
785 
TraceEvalCNodeLeave()786 void TraceEvalCNodeLeave() { cnode_debug_stack.pop_back(); }
787 
GetCNodeDebugStack()788 TraceCNodeEvalStack &GetCNodeDebugStack() { return cnode_debug_stack; }
789 
GetCurrentGraphEvalStack()790 TraceGraphEvalStack &GetCurrentGraphEvalStack() { return graph_infer_stack; }
791 
ClearTraceStack()792 void ClearTraceStack() {
793   while (!graph_infer_stack.empty()) {
794     graph_infer_stack.pop_back();
795   }
796   cnode_debug_stack.clear();
797 }
798 
PrintMessage(std::ostringstream & oss,const std::string & content,bool add_title)799 void PrintMessage(std::ostringstream &oss, const std::string &content, bool add_title) {
800   if (add_title) {
801     const std::string &message = oss.str();
802     size_t length = message.length();
803     if ((length != 0) && (message[length - 1] != '\n')) {
804       oss << "\n";
805     }
806 
807     oss << "\n----------------------------------------------------\n"
808         << "- The Traceback of Net Construct Code:"
809         << "\n----------------------------------------------------";
810   }
811   oss << content;
812 }
813 
GetTraceStackInfo(std::ostringstream & oss,bool add_title)814 void GetTraceStackInfo(std::ostringstream &oss, bool add_title) {
815   static bool running = false;
816   // Avoid to trace recursively
817   if (running) {
818     return;
819   }
820   running = true;
821   try {
822     TraceGraphEval();
823     std::ostringstream trace_info;
824     StaticAnalysisException::Instance().AppendMsg(oss.str());
825     GetEvalStackInfo(trace_info);
826     if (trace_info.str().empty()) {
827       const DebugInfoPtr &debug_info = TraceManager::parser_debug_info();
828       if (debug_info != nullptr && TraceManager::parser_debug_info_flag() == true) {
829         auto debug_str = trace::GetTracedDebugInfoStr(debug_info);
830         if (!debug_str.empty()) {
831           std::ostringstream content;
832           content << "\n\n" << debug_str;
833           PrintMessage(oss, content.str(), add_title);
834         }
835       }
836     } else {
837       PrintMessage(oss, trace_info.str(), add_title);
838     }
839   } catch (...) {
840     MS_LOG(INFO) << " Print trace information exception.";
841   }
842   running = false;
843 }
844 
GetTraceStackInfoStr(const AnfNodePtr & node,bool add_title)845 std::string GetTraceStackInfoStr(const AnfNodePtr &node, bool add_title) {
846   if (node == nullptr) {
847     return std::string();
848   }
849   if (node->debug_info() == nullptr) {
850     return std::string();
851   }
852   auto debug_str = trace::GetTracedDebugInfoStr(node->debug_info());
853   if (debug_str.empty()) {
854     return std::string();
855   }
856   std::ostringstream oss;
857   std::ostringstream content;
858   content << "\n\n" << debug_str;
859   PrintMessage(oss, content.str(), add_title);
860   return oss.str();
861 }
862 
863 // Register trace provider to LogWriter.
864 struct TraceProviderRegister {
TraceProviderRegistermindspore::trace::TraceProviderRegister865   TraceProviderRegister() noexcept { LogWriter::SetTraceProvider(GetTraceStackInfo); }
866   ~TraceProviderRegister() = default;
867 } trace_provider_register;
868 
869 // Register trace cnode provider to AbstractBase.
870 struct TraceNodeProviderRegister {
TraceNodeProviderRegistermindspore::trace::TraceNodeProviderRegister871   TraceNodeProviderRegister() noexcept {
872     abstract::AbstractBase::set_trace_node_provider([](AnfNodePtr *node) {
873       auto stack = GetCNodeDebugStack();
874       if (!stack.empty()) {
875         auto conf = stack.back();
876         *node = conf->node();
877       }
878     });
879   }
880   ~TraceNodeProviderRegister() = default;
881 } trace_node_provider_register;
882 
883 // Register trace node stack provider.
884 struct GetTraceStrProviderRegister {
GetTraceStrProviderRegistermindspore::trace::GetTraceStrProviderRegister885   GetTraceStrProviderRegister() noexcept { LogWriter::SetGetTraceStrProvider(GetTraceStackInfoStr); }
886   ~GetTraceStrProviderRegister() = default;
887 } get_trace_str_provider_register;
888 }  // namespace trace
889 }  // namespace mindspore
890