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> ¶_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> ¶_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 ¶meters = 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, ¶_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, ¶_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, ¶_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