You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

trace.cc 17 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. /**
  2. * Copyright 2019-2020 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. #include "debug/trace.h"
  17. #include <iostream>
  18. #include <fstream>
  19. #include <map>
  20. #include <unordered_map>
  21. #include <vector>
  22. #include <string>
  23. #include <sstream>
  24. #include <utility>
  25. #include <stack>
  26. #include <algorithm>
  27. #include "ir/meta_func_graph.h"
  28. #include "utils/graph_utils.h"
  29. #include "operator/composite/composite.h"
  30. #include "ir/tensor.h"
  31. #include "debug/anf_ir_utils.h"
  32. #include "pipeline/static_analysis/evaluator.h"
  33. namespace mindspore {
  34. // namespace to support debug trace infomation
  35. namespace trace {
  36. using abstract::AbstractBasePtr;
  37. using abstract::AnalysisContextPtr;
  38. using abstract::AnalysisEnginePtr;
  39. using abstract::AnfNodeConfigPtr;
  40. std::string GetAbstractStr(const abstract::AbstractBasePtr &abs) {
  41. if (abs == nullptr) {
  42. return "Null Abstract";
  43. }
  44. auto shape = abs->BuildShape()->cast<abstract::ShapePtr>();
  45. TypePtr type = abs->BuildType();
  46. std::ostringstream oss;
  47. if ((shape != nullptr) && (type != nullptr)) {
  48. oss << type->DumpText() << shape->DumpText();
  49. } else if (type != nullptr) {
  50. oss << type->DumpText();
  51. } else {
  52. oss << "Undefined";
  53. }
  54. return oss.str();
  55. }
  56. std::string GetGraphParamString(const FuncGraphPtr &graph, abstract::AbstractBasePtrList args_spec_list) {
  57. std::ostringstream oss;
  58. oss << "graph:" << graph->ToString() << " with args[";
  59. auto params = graph->parameters();
  60. for (size_t i = 0; i < args_spec_list.size(); i++) {
  61. oss << params[i]->ToString() << ":<" << GetAbstractStr(args_spec_list[i]) << ">,";
  62. }
  63. oss << "]";
  64. oss << GetDebugInfo(graph->debug_info(), kSourceLineTipDiscard);
  65. return oss.str();
  66. }
  67. void DumpInferStack(std::ostringstream &oss) {
  68. auto &infer_stack = GetCurrenGraphInferStack();
  69. if (infer_stack.empty()) {
  70. return;
  71. }
  72. std::vector<std::pair<abstract::EvaluatorPtr, abstract::AnfNodeConfigPtr>> infer_vec;
  73. while (!infer_stack.empty()) {
  74. auto top = infer_stack.top();
  75. infer_vec.push_back(top);
  76. infer_stack.pop();
  77. }
  78. std::reverse(infer_vec.begin(), infer_vec.end());
  79. int index = 0;
  80. for (auto &item : infer_vec) {
  81. auto graph_infer = std::dynamic_pointer_cast<abstract::BaseFuncGraphEvaluator>(item.first);
  82. if (graph_infer == nullptr) {
  83. MS_LOG(WARNING) << "DumpInferStack failed, got null graph evaluator";
  84. infer_vec.clear();
  85. break;
  86. }
  87. auto graph_context = graph_infer->graph_context();
  88. if (graph_context == nullptr) {
  89. MS_LOG(INFO) << "Null context continue";
  90. continue;
  91. }
  92. auto graph = graph_context->func_graph();
  93. auto args_spec_list = graph_context->args_spec_list();
  94. oss << " #" << index++ << " " << GetGraphParamString(graph, args_spec_list);
  95. }
  96. }
  97. void TraceGraphEval() {
  98. auto &infer_stack = GetCurrenGraphInferStack();
  99. std::ostringstream oss;
  100. if (infer_stack.empty()) {
  101. return;
  102. }
  103. MS_LOG(INFO) << "\n*******************************graph evaluate stack**********************************";
  104. oss << std::endl;
  105. DumpInferStack(oss);
  106. MS_LOG(INFO) << oss.str();
  107. MS_LOG(INFO) << "\n*************************************************************************************";
  108. }
  109. class AnalyzedFuncGraphExporter : public AnfExporter {
  110. public:
  111. AnalyzedFuncGraphExporter() : AnfExporter("", true, false) {}
  112. ~AnalyzedFuncGraphExporter() override = default;
  113. void ExportFuncGraph(const std::string &filename, const std::vector<abstract::AnfNodeConfigPtr> &node_cfgs);
  114. void ExportOneFuncGraph(std::ofstream &ofs, const FuncGraphPtr &func_graph);
  115. void OutputCNodes(std::ofstream &ofs, const std::vector<AnfNodePtr> &nodes, const FuncGraphPtr &func_graph);
  116. void OutputCNode(std::ofstream &ofs, const CNodePtr &cnode, const FuncGraphPtr &func_graph, int *idx,
  117. std::map<AnfNodePtr, int> *const apply_map);
  118. private:
  119. std::string GetNodeType(const AnfNodePtr &nd) override;
  120. AbstractBasePtr GetNodeAbstract(const AnfNodePtr &nd);
  121. AnfNodeConfigPtr GetFordwardConfigPtr(const AnfNodeConfigPtr &cfg);
  122. AnalysisContextPtr ProcessFuncGraphCall(const CNodePtr &node);
  123. // key: context, val: whether the context has already been printed
  124. std::unordered_map<AnalysisContextPtr, bool> context_map_;
  125. std::vector<AnalysisContextPtr> context_vec_;
  126. AnalysisContextPtr cur_ctx_ = nullptr;
  127. AnalysisEnginePtr engine_ = nullptr;
  128. };
  129. std::unordered_map<FuncGraphPtr, TaggedNodeMap> CalcTaggedFuncGraphs() {
  130. std::unordered_map<FuncGraphPtr, TaggedNodeMap> tagged_func_graphs;
  131. auto &list = GetCNodeDebugStack();
  132. for (size_t i = 0; i < list.size(); ++i) {
  133. auto node_cfg = list[i];
  134. auto fg = node_cfg->context()->func_graph();
  135. auto node = node_cfg->node();
  136. tagged_func_graphs[fg][node] = i;
  137. }
  138. return tagged_func_graphs;
  139. }
  140. void OutputAnalyzedGraphWithType() {
  141. AnalyzedFuncGraphExporter exporter;
  142. exporter.ExportFuncGraph("analyze_fail.dat", GetCNodeDebugStack());
  143. }
  144. std::string AnalyzedFuncGraphExporter::GetNodeType(const AnfNodePtr &node) {
  145. if (cur_ctx_ == nullptr) {
  146. return AnfExporter::GetNodeType(node);
  147. }
  148. MS_EXCEPTION_IF_NULL(engine_);
  149. auto cfg = engine_->MakeConfig(node, cur_ctx_);
  150. auto ret = engine_->cache().GetValue(cfg);
  151. if (ret == nullptr) {
  152. return "Undefined";
  153. }
  154. auto abs = ret->abstract();
  155. if (abs == nullptr) {
  156. return "Undefined";
  157. }
  158. auto dtype = abs->BuildType();
  159. auto shape = abs->BuildShape();
  160. std::ostringstream oss;
  161. if (dtype != nullptr && abs->isa<abstract::AbstractTensor>() && shape != nullptr) {
  162. oss << dtype->DumpText() << shape->DumpText();
  163. } else if (dtype != nullptr) {
  164. oss << dtype->DumpText();
  165. } else {
  166. oss << "Undefined";
  167. }
  168. return oss.str();
  169. }
  170. AbstractBasePtr AnalyzedFuncGraphExporter::GetNodeAbstract(const AnfNodePtr &node) {
  171. if (cur_ctx_ == nullptr) {
  172. return nullptr;
  173. }
  174. MS_EXCEPTION_IF_NULL(engine_);
  175. auto cfg = engine_->MakeConfig(node, cur_ctx_);
  176. auto ret = engine_->cache().GetValue(cfg);
  177. return ret == nullptr ? nullptr : ret->abstract();
  178. }
  179. AnfNodeConfigPtr AnalyzedFuncGraphExporter::GetFordwardConfigPtr(const AnfNodeConfigPtr &cfg) {
  180. AnfNodeConfigPtr cur_cfg = cfg;
  181. auto iter = engine_->anfnode_config_map().find(cur_cfg);
  182. while (iter != engine_->anfnode_config_map().end()) {
  183. auto node = cur_cfg->node();
  184. cur_cfg = iter->second;
  185. MS_LOG(DEBUG) << "Get forword node: " << node.get() << "[" << node->ToString() << "] --> " << cur_cfg->node().get()
  186. << "[" << cur_cfg->node()->ToString() << "]";
  187. iter = engine_->anfnode_config_map().find(cur_cfg);
  188. }
  189. return cur_cfg;
  190. }
  191. AnalysisContextPtr AnalyzedFuncGraphExporter::ProcessFuncGraphCall(const CNodePtr &node) {
  192. if (node == nullptr) {
  193. return nullptr;
  194. }
  195. auto cfg = engine_->MakeConfig(node, cur_ctx_);
  196. cfg = GetFordwardConfigPtr(cfg);
  197. auto cnode = dyn_cast<CNode>(cfg->node());
  198. if (cnode == nullptr) {
  199. MS_LOG(DEBUG) << "CNode is nullptr";
  200. return nullptr;
  201. }
  202. const auto &inputs = cnode->inputs();
  203. auto op_abs = GetNodeAbstract(inputs[0]);
  204. if (op_abs == nullptr) {
  205. MS_LOG(DEBUG) << "Abstract of inputs[0] of cnode " << cnode->ToString() << " is nullptr";
  206. return nullptr;
  207. }
  208. if (!op_abs->isa<abstract::FuncGraphAbstractClosure>() && !op_abs->isa<abstract::MetaFuncGraphAbstractClosure>()) {
  209. MS_LOG(DEBUG) << "Inputs[0] of cnode " << cnode->ToString() << " is of type " << op_abs->type_name()
  210. << ", not function, ignore it";
  211. return nullptr;
  212. }
  213. auto evaluator = engine_->GetEvaluatorFor(dyn_cast<abstract::AbstractFunction>(op_abs));
  214. if (!evaluator->isa<abstract::BaseFuncGraphEvaluator>()) {
  215. MS_LOG(DEBUG) << "Evaluator for inputs[0] of cnode " << cnode->ToString() << " is of type "
  216. << evaluator->type_name() << ", not BaseFuncGraphEvaluator, ignore it.";
  217. return nullptr;
  218. }
  219. auto base_fg_evaluator = dyn_cast<abstract::BaseFuncGraphEvaluator>(evaluator);
  220. auto ctx = base_fg_evaluator->graph_context();
  221. if (ctx != nullptr && context_map_.insert({ctx, false}).second) {
  222. MS_LOG(DEBUG) << "Add new context, ctx.addr = " << ctx.get() << "ctx = " << ctx->ToString();
  223. context_vec_.push_back(ctx);
  224. }
  225. return ctx;
  226. }
  227. void AnalyzedFuncGraphExporter::OutputCNode(std::ofstream &ofs, const CNodePtr &cnode, const FuncGraphPtr &func_graph,
  228. int *idx, std::map<AnfNodePtr, int> *const apply_map) {
  229. auto &inputs = cnode->inputs();
  230. std::string op_text = GetAnfNodeText(func_graph, inputs[0], *apply_map);
  231. // non-return node
  232. if (cnode != func_graph->get_return()) {
  233. int apply_idx = (*idx)++;
  234. (*apply_map)[cnode] = apply_idx;
  235. std::string type_info = GetNodeType(cnode);
  236. if (type_info == "Undefined") {
  237. ofs << " %" << apply_idx << " = " << op_text << "(";
  238. } else {
  239. ofs << " %" << apply_idx << " : " << type_info << " = " << op_text << "(";
  240. }
  241. } else {
  242. ofs << " " << op_text << "(";
  243. }
  244. for (size_t i = 1; i < inputs.size(); ++i) {
  245. if (i != 1) {
  246. ofs << ", ";
  247. }
  248. AnfNodePtr arg = inputs[i];
  249. ofs << GetAnfNodeText(func_graph, arg, *apply_map);
  250. }
  251. ofs << ")";
  252. // process function graph call
  253. auto ctx = ProcessFuncGraphCall(cnode);
  254. // output comment
  255. OutputStatementComment(ofs, cnode);
  256. if (ctx != nullptr) {
  257. ofs << " @ctx.addr=" << ctx.get();
  258. }
  259. ofs << "\n";
  260. if (label_manage::GetGlobalTraceLabelType() == label_manage::TraceLabelType::kWithUniqueId) {
  261. ofs << trace::GetDebugInfo(cnode->debug_info(), " # ", kSourceLineTipDiscard) << "#"
  262. << label_manage::Label(cnode->debug_info()) << "\n";
  263. } else {
  264. ofs << trace::GetDebugInfo(cnode->debug_info(), " # ", kSourceLineTipDiscard) << "\n";
  265. }
  266. }
  267. void AnalyzedFuncGraphExporter::OutputCNodes(std::ofstream &ofs, const std::vector<AnfNodePtr> &nodes,
  268. const FuncGraphPtr &func_graph) {
  269. if (func_graph == nullptr) {
  270. return;
  271. }
  272. int idx = 1;
  273. std::map<AnfNodePtr, int> apply_map;
  274. for (const AnfNodePtr &node : nodes) {
  275. MS_EXCEPTION_IF_NULL(node);
  276. if (!node->isa<CNode>()) {
  277. continue;
  278. }
  279. auto iter = tagged_cnodes_.find(node);
  280. if (iter != tagged_cnodes_.end()) {
  281. ofs << "\n#------------------------> " << iter->second << "\n";
  282. }
  283. auto cnode = node->cast<CNodePtr>();
  284. OutputCNode(ofs, cnode, func_graph, &idx, &apply_map);
  285. }
  286. }
  287. void AnalyzedFuncGraphExporter::ExportOneFuncGraph(std::ofstream &ofs, const FuncGraphPtr &func_graph) {
  288. if (func_graph == nullptr) {
  289. return;
  290. }
  291. std::vector<AnfNodePtr> nodes = TopoSort(func_graph->get_return(), SuccIncoming, AlwaysInclude);
  292. std::vector<AnfNodePtr> parameters = func_graph->parameters();
  293. OrderedMap<AnfNodePtr, int, ParamPtrHasher, ParamPtrEqual> param_map;
  294. ofs << "# [No." << (exported.size() + 1) << "] " << func_graph->DumpText() << "."
  295. << func_graph->debug_info()->get_id();
  296. if (cur_ctx_ != nullptr) {
  297. ofs << " @ctx.addr=" << cur_ctx_.get();
  298. }
  299. ofs << "\n";
  300. if (label_manage::GetGlobalTraceLabelType() == label_manage::TraceLabelType::kWithUniqueId) {
  301. ofs << trace::GetDebugInfo(func_graph->debug_info(), "# ", kSourceLineTipDiscard) << "#"
  302. << label_manage::Label(func_graph->debug_info()) << "\n";
  303. } else {
  304. ofs << trace::GetDebugInfo(func_graph->debug_info(), "# ", kSourceLineTipDiscard) << "\n";
  305. }
  306. ofs << "funcgraph fg_" << func_graph->debug_info()->get_id();
  307. // output name of parent of graph if exists
  308. if (func_graph->parent() != nullptr) {
  309. ofs << "[fg_" << func_graph->parent()->debug_info()->get_id() << "]";
  310. }
  311. ofs << "(\n";
  312. OutputParameters(ofs, parameters, &param_map);
  313. exported[func_graph] = param_map;
  314. ofs << (!parameters.empty() ? " " : "") << ") {\n";
  315. OutputCNodes(ofs, nodes, func_graph);
  316. ofs << "}\n";
  317. }
  318. void AnalyzedFuncGraphExporter::ExportFuncGraph(const std::string &filename,
  319. const std::vector<abstract::AnfNodeConfigPtr> &node_cfgs) {
  320. if (node_cfgs.empty()) {
  321. MS_LOG(DEBUG) << "Node configs is empty";
  322. return;
  323. }
  324. context_map_.clear();
  325. context_vec_.clear();
  326. std::ofstream ofs(filename);
  327. if (!ofs.is_open()) {
  328. MS_LOG(ERROR) << "Open file '" << filename << "' failed!";
  329. return;
  330. }
  331. param_index = 1;
  332. auto tagged_func_graphs = CalcTaggedFuncGraphs();
  333. // first output graph on the analysis stack
  334. for (const auto &node_cfg : node_cfgs) {
  335. auto ctx = node_cfg->context();
  336. if (engine_ == nullptr) {
  337. engine_ = node_cfg->engine();
  338. }
  339. if (context_map_.insert({ctx, false}).second) {
  340. context_vec_.push_back(ctx);
  341. }
  342. // the graph has already been printed
  343. if (context_map_[ctx]) {
  344. continue;
  345. }
  346. context_map_[ctx] = true;
  347. auto fg = ctx->func_graph();
  348. // set current context
  349. cur_ctx_ = ctx;
  350. tagged_cnodes_ = tagged_func_graphs[fg];
  351. ExportOneFuncGraph(ofs, fg);
  352. ofs << "\n\n";
  353. }
  354. tagged_cnodes_.clear();
  355. // print seperator between function graphs on analyzed graph call stack and others
  356. ofs << "#===============================================================================\n\n\n";
  357. // second output other graphs
  358. size_t ctx_idx = 0;
  359. while (ctx_idx < context_vec_.size()) {
  360. auto ctx = context_vec_[ctx_idx++];
  361. if (context_map_[ctx]) {
  362. continue;
  363. }
  364. context_map_[ctx] = true;
  365. cur_ctx_ = ctx;
  366. ExportOneFuncGraph(ofs, ctx->func_graph());
  367. ofs << "\n\n";
  368. }
  369. ofs << "# num of total function graphs: " << context_map_.size() << "\n";
  370. ofs.close();
  371. }
  372. void GetEvalStackInfo(std::ostringstream &oss) {
  373. MS_LOG(INFO) << "Get graph analysis information begin";
  374. auto stack = GetCNodeDebugStack();
  375. if (stack.empty()) {
  376. MS_LOG(INFO) << "Length of analysis information stack is empty.";
  377. return;
  378. }
  379. OutputAnalyzedGraphWithType();
  380. oss << "\nThe function call stack:\n";
  381. int index = 0;
  382. std::string last_py_func = "";
  383. for (size_t i = 0; i < stack.size(); ++i) {
  384. auto node_cfg = stack[i];
  385. auto cnode = dyn_cast<CNode>(node_cfg->node());
  386. if (cnode == nullptr) {
  387. MS_LOG(DEBUG) << "CNode of elements[" << i << "] is nullptr.";
  388. continue;
  389. }
  390. auto debug_info = cnode->debug_info();
  391. auto this_py_func = debug_info->get_python_func_belonged();
  392. if (i > 0 && (this_py_func == last_py_func)) {
  393. MS_LOG(DEBUG) << "Python function of elements[" << i << "] is same as previous.";
  394. continue;
  395. }
  396. last_py_func = this_py_func;
  397. oss << "# " << index++ << " " << trace::GetDebugInfo(debug_info, std::string(""));
  398. }
  399. stack.clear();
  400. MS_LOG(INFO) << "Get graph analysis information *end*";
  401. }
  402. // trace the graph evaluator stack
  403. static std::stack<std::pair<abstract::EvaluatorPtr, abstract::AnfNodeConfigPtr>> graph_infer_stack;
  404. // trace the cnode infer debug info
  405. static std::vector<abstract::AnfNodeConfigPtr> cnode_debug_stack{};
  406. void TraceGraphEvalEnter(const abstract::EvaluatorPtr &eval, const abstract::AnfNodeConfigPtr &node) {
  407. if (eval == nullptr) {
  408. MS_LOG(EXCEPTION) << "GraphInferEnter got null eval";
  409. }
  410. if (eval->isa<abstract::FuncGraphEvaluator>() || eval->isa<abstract::MetaFuncGraphEvaluator>()) {
  411. graph_infer_stack.emplace(std::pair<abstract::EvaluatorPtr, abstract::AnfNodeConfigPtr>(eval, node));
  412. }
  413. }
  414. void TraceGraphEvalLeave(const abstract::EvaluatorPtr &eval) {
  415. if (eval == nullptr) {
  416. MS_LOG(EXCEPTION) << "GraphInferEnter got null eval";
  417. }
  418. if (eval->isa<abstract::FuncGraphEvaluator>() || eval->isa<abstract::MetaFuncGraphEvaluator>()) {
  419. graph_infer_stack.pop();
  420. }
  421. }
  422. void TraceEvalCNodeEnter(const abstract::AnfNodeConfigPtr &node_cfg) { cnode_debug_stack.push_back(node_cfg); }
  423. void TraceEvalCNodeLeave() { cnode_debug_stack.pop_back(); }
  424. std::vector<abstract::AnfNodeConfigPtr> &GetCNodeDebugStack() { return cnode_debug_stack; }
  425. std::stack<std::pair<abstract::EvaluatorPtr, abstract::AnfNodeConfigPtr>> &GetCurrenGraphInferStack() {
  426. return graph_infer_stack;
  427. }
  428. void ClearTraceStack() {
  429. while (!graph_infer_stack.empty()) {
  430. graph_infer_stack.pop();
  431. }
  432. cnode_debug_stack.clear();
  433. }
  434. } // namespace trace
  435. } // namespace mindspore