1 /**
2 * Copyright 2020-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 "utils/trace_base.h"
18
19 #include <vector>
20 #include <string>
21 #include <utility>
22 #include <algorithm>
23
24 #include "ir/graph_utils.h"
25
26 namespace mindspore {
27 namespace trace {
28 namespace {
GetSourceCodeDebugInfoVec(DebugInfoPtr debug_info,bool is_debug=false)29 std::vector<DebugInfoPtr> GetSourceCodeDebugInfoVec(DebugInfoPtr debug_info, bool is_debug = false) {
30 std::vector<DebugInfoPtr> debug_with_loc_vec;
31 HashSet<DebugInfoPtr> visited;
32 while (debug_info != nullptr) {
33 if (visited.find(debug_info) != visited.end()) {
34 int i = 0;
35 for (const auto &info : debug_with_loc_vec) {
36 auto loc = info->location();
37 MS_LOG(ERROR) << "[" << std::to_string(i) << "]: " << info.get()
38 << ", loc: " << (loc == nullptr ? "null" : loc->ToString());
39 ++i;
40 }
41 auto loc = debug_info->location();
42 MS_LOG(INTERNAL_EXCEPTION) << "Find loop debug info: " << debug_info.get()
43 << ", loc: " << (loc == nullptr ? "null" : loc->ToString()) << ".\n"
44 << "Please set 'compile_config.ENABLE_FIX_CODE_LINE=0' to avoid this problem.";
45 }
46 auto loc = debug_info->location();
47 MS_LOG(DEBUG) << "Visited Insert debug info: " << debug_info.get()
48 << ", loc: " << (loc == nullptr ? "null" : loc->ToString());
49 (void)visited.insert(debug_info);
50 if (is_debug || debug_info->location() != nullptr) {
51 debug_with_loc_vec.push_back(debug_info);
52 MS_LOG(DEBUG) << "debug loc: " << debug_info->location()->DebugString();
53 }
54 if (debug_info->trace_info() != nullptr) {
55 MS_LOG(DEBUG) << "trace: " << debug_info->trace_info()->name();
56 debug_info = debug_info->trace_info()->debug_info();
57 } else {
58 break;
59 }
60 }
61 return debug_with_loc_vec;
62 }
63
ReplaceLinefeed(std::string * txt)64 void ReplaceLinefeed(std::string *txt) {
65 MS_EXCEPTION_IF_NULL(txt);
66 std::vector<int> erases;
67 constexpr char cr = '\r';
68 constexpr char lf = '\n';
69 constexpr char slash = '/';
70 for (size_t i = 0; i < txt->length(); i++) {
71 if ((*txt)[i] == lf) {
72 (*txt)[i] = slash;
73 }
74 if ((*txt)[i] == cr) {
75 (*txt)[i] = slash;
76 if (i + 1 < txt->length() && (*txt)[i + 1] == lf) {
77 erases.emplace_back(i + 1);
78 i++;
79 }
80 }
81 }
82 constexpr auto n = 1;
83 std::reverse(erases.begin(), erases.end());
84 for (const auto &index : erases) {
85 txt->erase(index, n);
86 }
87 }
88 } // namespace
89
GetSourceCodeDebugInfo(const DebugInfoPtr & info)90 DebugInfoPtr GetSourceCodeDebugInfo(const DebugInfoPtr &info) {
91 DebugInfoPtr debug_info = info;
92 while (debug_info != nullptr) {
93 auto loc = debug_info->location();
94 if (debug_info->location() != nullptr) {
95 MS_LOG(DEBUG) << "debug loc: " << debug_info->location()->DebugString();
96 return debug_info;
97 }
98 if (debug_info->trace_info() == nullptr) {
99 break;
100 }
101 MS_LOG(DEBUG) << "trace: " << debug_info->trace_info()->name();
102 debug_info = debug_info->trace_info()->debug_info();
103 }
104 return info;
105 }
106
GetDebugInfoStr(const DebugInfoPtr & info,const std::string & prefix,SourceLineTip tip,bool is_debug)107 std::string GetDebugInfoStr(const DebugInfoPtr &info, const std::string &prefix, SourceLineTip tip, bool is_debug) {
108 if (info == nullptr) {
109 return "";
110 }
111 DebugInfoPtr debug_info;
112 if (!is_debug) {
113 debug_info = GetSourceCodeDebugInfo(info);
114 } else {
115 debug_info = info;
116 }
117 bool has_shadow = false;
118 if (!debug_info->shadow_debug_infos_map().empty()) {
119 has_shadow = true;
120 }
121
122 if (debug_info->location() == nullptr) {
123 return "";
124 }
125 auto line_str = debug_info->location()->ToString(tip);
126 if (tip == kSourceLineTipDiscard) {
127 ReplaceLinefeed(&line_str);
128 }
129 std::stringstream ss;
130 ss << prefix << line_str;
131 if (has_shadow) {
132 ss << "\n[shadow]";
133 }
134 return ss.str();
135 }
136
DumpSourceLines(const AnfNodePtr & node,bool has_title)137 std::string DumpSourceLines(const AnfNodePtr &node, bool has_title) {
138 auto vec_source = GetSourceLineList(node);
139 if (vec_source.empty()) {
140 return "";
141 }
142 std::ostringstream oss;
143 for (auto &src_info : vec_source) {
144 oss << src_info;
145 }
146 if (oss.str().empty()) {
147 return "";
148 }
149 const std::string prefix = has_title ? "#dmsg#The Function Call Stack:#dmsg#" : "\n";
150 return prefix + oss.str();
151 }
152
DumpSourceLines(AnfNode * node,bool has_title)153 std::string DumpSourceLines(AnfNode *node, bool has_title) {
154 if (node == nullptr) {
155 MS_LOG(WARNING) << "Node is null";
156 return "";
157 }
158 AnfNodePtr ptr = std::static_pointer_cast<AnfNode>(node->shared_from_this());
159 return DumpSourceLines(ptr, has_title);
160 }
161
GetSourceLineFromDebugInfo(const DebugInfoPtr & debug_info,std::vector<std::string> * result,const std::string & prefix="")162 void GetSourceLineFromDebugInfo(const DebugInfoPtr &debug_info, std::vector<std::string> *result,
163 const std::string &prefix = "") {
164 MS_EXCEPTION_IF_NULL(result);
165 auto info_vec = GetSourceCodeDebugInfoVec(debug_info);
166 const std::string spaces(prefix.size(), ' ');
167 bool first_line = true;
168 HashSet<std::string> exist_locations;
169 for (const auto &info : info_vec) {
170 MS_EXCEPTION_IF_NULL(info);
171 auto loc = info->location();
172 if (loc == nullptr) {
173 continue;
174 }
175 auto loc_str = loc->ToString(kSourceLineTipDiscard);
176 if (exist_locations.find(loc_str) != exist_locations.cend()) {
177 continue;
178 }
179 (void)exist_locations.insert(loc_str);
180 ReplaceLinefeed(&loc_str);
181 if (first_line) {
182 result->push_back(std::string(prefix).append(loc_str).append("\n"));
183 first_line = false;
184 } else {
185 result->push_back(std::string(spaces).append(loc_str).append("\n"));
186 }
187 }
188 }
189
GetFusedDebugInfos(const NodeDebugInfoSet & fused_debug_infos,std::vector<std::string> * result)190 void GetFusedDebugInfos(const NodeDebugInfoSet &fused_debug_infos, std::vector<std::string> *result) {
191 MS_EXCEPTION_IF_NULL(result);
192 (void)result->emplace_back("Corresponding code candidate:\n");
193 // Flag to mark whether fused_debug_infos has valid print.
194 bool is_empty = true;
195 for (const auto &debug_info : fused_debug_infos) {
196 std::vector<std::string> debug_info_vec_str;
197 GetSourceLineFromDebugInfo(debug_info, &debug_info_vec_str, kSectionPrefix);
198 if (!debug_info_vec_str.empty()) {
199 (void)result->insert(result->cend(), debug_info_vec_str.cbegin(), debug_info_vec_str.cend());
200 is_empty = false;
201 }
202 }
203
204 if (is_empty) {
205 result->pop_back();
206 }
207 }
208
GetPrimalDebugInfos(const CNodePtr & cnode,std::vector<std::string> * result)209 void GetPrimalDebugInfos(const CNodePtr &cnode, std::vector<std::string> *result) {
210 MS_EXCEPTION_IF_NULL(cnode);
211 MS_EXCEPTION_IF_NULL(result);
212 auto primal_debug_infos = cnode->primal_debug_infos();
213 if (!primal_debug_infos.empty()) {
214 (void)result->emplace_back("Corresponding forward node candidate:\n");
215 for (const auto &primal_debug_info : primal_debug_infos) {
216 std::vector<std::string> debug_info_vec_str;
217 GetSourceLineFromDebugInfo(primal_debug_info, &debug_info_vec_str, kSectionPrefix);
218 if (!debug_info_vec_str.empty()) {
219 (void)result->insert(result->cend(), debug_info_vec_str.cbegin(), debug_info_vec_str.cend());
220 }
221 }
222 }
223 }
GetSourceLineList(const DebugInfoPtr & debug_info)224 std::vector<std::string> GetSourceLineList(const DebugInfoPtr &debug_info) {
225 std::vector<std::string> result;
226 GetSourceLineFromDebugInfo(debug_info, &result);
227 return result;
228 }
229
GetSourceLineList(const AnfNodePtr & node)230 std::vector<std::string> GetSourceLineList(const AnfNodePtr &node) {
231 std::vector<std::string> result;
232 if (node == nullptr) {
233 MS_LOG(WARNING) << "Node is null";
234 return result;
235 }
236 if (!node->isa<CNode>()) {
237 GetSourceLineFromDebugInfo(node->debug_info(), &result);
238 return result;
239 }
240 auto cnode = node->cast<CNodePtr>();
241 auto fused_debug_infos = cnode->fused_debug_infos();
242 if (fused_debug_infos.empty()) {
243 GetSourceLineFromDebugInfo(node->debug_info(), &result);
244 } else {
245 GetFusedDebugInfos(fused_debug_infos, &result);
246 }
247 GetPrimalDebugInfos(cnode, &result);
248 return result;
249 }
250
GetSourceLocationList(const AnfNodePtr & node)251 std::vector<LocationPtr> GetSourceLocationList(const AnfNodePtr &node) {
252 std::vector<LocationPtr> result;
253 if (node == nullptr) {
254 MS_LOG(WARNING) << "Node is null";
255 return result;
256 }
257 auto info_vec = GetSourceCodeDebugInfoVec(node->debug_info());
258 for (const auto &info : info_vec) {
259 MS_EXCEPTION_IF_NULL(info);
260 if (info->location() != nullptr) {
261 result.emplace_back(info->location());
262 }
263 }
264 return result;
265 }
266
GetTracedDebugInfoStr(const DebugInfoPtr & debug_info,bool is_debug)267 std::string GetTracedDebugInfoStr(const DebugInfoPtr &debug_info, bool is_debug) {
268 if (debug_info == nullptr) {
269 MS_LOG(WARNING) << "debug_info is null";
270 return "";
271 }
272 auto info_vec = GetSourceCodeDebugInfoVec(debug_info, is_debug);
273 std::ostringstream oss;
274 for (auto iter = info_vec.crbegin(); iter != info_vec.crend(); ++iter) {
275 const auto &info = *iter;
276 MS_EXCEPTION_IF_NULL(info);
277 auto loc = info->location();
278 if (loc == nullptr) {
279 oss << "Location miss\n";
280 continue;
281 }
282 oss << "# " << loc->ToString() << "\n";
283 }
284 return oss.str();
285 }
286 } // namespace trace
287 } // namespace mindspore
288