1/**
2 * Copyright (c) Glow Contributors. See CONTRIBUTORS file.
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 "glow/Graph/Log.h"
18
19#include "glow/Flags/Flags.h"
20#include "glow/Graph/Graph.h"
21#include "glow/Graph/Node.h"
22#include "glow/Graph/NodeValue.h"
23#include "llvm/Support/CommandLine.h"
24#include "llvm/Support/FileSystem.h"
25#include "llvm/Support/FormatVariadic.h"
26#include "llvm/Support/raw_ostream.h"
27
28namespace glow {
29
30/// Log version number.
31static constexpr auto logVersionNo_ = "v1.0.0";
32
33static llvm::cl::opt<bool, true>
34 enableCompilationLogOpt("compilation-log",
35 llvm::cl::desc("Dump Compilation Log"),
36 llvm::cl::location(flags::DumpCompilationLog));
37
38static llvm::cl::opt<bool> verboseCompilationLogOpt(
39 "verbose-compilation", llvm::cl::init(false),
40 llvm::cl::desc("Log empty passes to Compilation Log"));
41
42bool LogEvent::dump(llvm::raw_fd_ostream &ostream) {
43 ostream << llvm::formatv("{ \"name\":\"{0}\",", name);
44
45 if (!children.empty()) {
46 ostream << llvm::format(", \"children\":\n");
47 dumpChildren(ostream);
48 }
49
50 ostream << std::string("}");
51 return true;
52}
53
54bool LogEvent::dumpChildren(llvm::raw_fd_ostream &ostream) {
55 ostream << std::string("[");
56 bool first = true;
57 for (auto *c : children) {
58 DCHECK(c);
59 if (c->silent()) {
60 continue;
61 }
62
63 if (first) {
64 first = false;
65 } else {
66 ostream << std::string(",\n");
67 }
68
69 c->dump(ostream);
70 }
71 ostream << std::string("]");
72 return true;
73}
74
75LogEvent *LogEvent::clone() {
76 LogEvent *copy = new LogEvent(name);
77 copy->parent = parent;
78 for (auto *c : children) {
79 copy->children.push_back(c->clone());
80 }
81 return copy;
82}
83
84bool LogScope::dump(llvm::raw_fd_ostream &ostream) {
85 if (silent()) {
86 return false;
87 }
88
89 ostream << llvm::formatv("{\"{0}\":", name);
90 dumpChildren(ostream);
91 ostream << std::string("}");
92 return true;
93}
94
95bool LogScope::silent() {
96 if (children.empty()) {
97 return true;
98 }
99
100 for (auto &c : children) {
101 if (!c->silent()) {
102 return false;
103 }
104 }
105
106 return true;
107}
108
109LogEvent *LogScope::clone() {
110 LogEvent *copy = new LogScope(name);
111 copy->parent = parent;
112 for (auto *c : children) {
113 copy->children.push_back(c->clone());
114 }
115 return copy;
116}
117
118LogCreate::LogCreate(const Node *node) : LogEvent(node->getName()) {
119 kindName = node->getKindName();
120
121 inputs.resize(node->getNumInputs());
122 for (size_t idx = 0; idx < node->getNumInputs(); idx++) {
123 auto &nv = node->getNthInput(idx);
124 inputs[idx] =
125 llvm::formatv("\"{0}:{1}\"", nv.getNode()->getName(), nv.getResNo());
126 }
127}
128
129LogCreate::LogCreate(llvm::StringRef n, llvm::StringRef k,
130 std::vector<std::string> &i)
131 : LogEvent(n), kindName(k) {
132 std::copy(i.begin(), i.end(), inputs.begin());
133}
134
135bool LogCreate::dump(llvm::raw_fd_ostream &ostream) {
136 ostream << llvm::formatv(
137 "{\"create\":\"{0}\", \"kind\":\"{1}\", \"inputs\": [", name, kindName);
138
139 if (!inputs.empty()) {
140 ostream << "\n" + llvm::join(inputs.begin(), inputs.end(), ",\n");
141 }
142
143 ostream << std::string("]}");
144 return true;
145}
146
147LogEvent *LogCreate::clone() {
148 LogEvent *copy = new LogCreate(name, kindName, inputs);
149 copy->parent = parent;
150 for (auto *c : children) {
151 copy->children.push_back(c->clone());
152 }
153 return copy;
154}
155
156LogDelete::LogDelete(const Node *node) : LogEvent(node->getName()) {
157 kindName = node->getKindName();
158}
159
160LogDelete::LogDelete(llvm::StringRef n, llvm::StringRef k)
161 : LogEvent(n), kindName(k) {}
162
163bool LogDelete::dump(llvm::raw_fd_ostream &ostream) {
164 ostream << llvm::formatv("{\"delete\":\"{0}\", \"kind\":\"{1}\"}", name,
165 kindName);
166 return true;
167}
168
169LogEvent *LogDelete::clone() {
170 LogEvent *copy = new LogDelete(name, kindName);
171 copy->parent = parent;
172 for (auto *c : children) {
173 copy->children.push_back(c->clone());
174 }
175 return copy;
176}
177
178LogInputChange::LogInputChange(const Node *user, const NodeValue &before,
179 const NodeValue &after)
180 : LogEvent(user->getName()) {
181 kindName = user->getKindName();
182 beforeName =
183 llvm::formatv("{0}:{1}", before.getNode()->getName(), before.getResNo());
184 afterName = "NONE";
185 if (after.getNode()) {
186 afterName =
187 llvm::formatv("{0}:{1}", after.getNode()->getName(), after.getResNo());
188 }
189}
190
191LogInputChange::LogInputChange(llvm::StringRef n, llvm::StringRef k,
192 llvm::StringRef b, llvm::StringRef a)
193 : LogEvent(n), kindName(k), beforeName(b), afterName(a) {}
194
195bool LogInputChange::dump(llvm::raw_fd_ostream &ostream) {
196 ostream << llvm::formatv("{\"input_change\":\"{0}\", \"kind\":\"{1}\", "
197 "\"before\":\"{2}\", \"after\":\"{3}\"}",
198 name, kindName, beforeName, afterName);
199 return true;
200}
201
202LogEvent *LogInputChange::clone() {
203 LogEvent *copy = new LogInputChange(name, kindName, beforeName, afterName);
204 copy->parent = parent;
205 for (auto *c : children) {
206 copy->children.push_back(c->clone());
207 }
208 return copy;
209}
210
211LogContext::LogContext(Module *parent)
212 : currentScope_(&topScope_), parent_(parent) {}
213
214void LogContext::pushEvent(LogEvent *ev) { currentScope_->pushEvent(ev); }
215
216void LogContext::pushLogScope(llvm::StringRef scopeName) {
217 LogScope *scope = new LogScope(scopeName);
218 currentScope_->pushEvent(scope);
219 currentScope_ = currentScope_->children.back();
220}
221
222void LogContext::popLogScope() {
223 DCHECK(currentScope_->parent);
224 currentScope_ = currentScope_->parent;
225}
226
227void LogContext::dumpLog(llvm::StringRef compileLogFilename) {
228 if (!flags::DumpCompilationLog) {
229 return;
230 }
231
232 llvm::outs() << "Writing compilation log file to: " << compileLogFilename
233 << '\n';
234 std::error_code EC;
235 llvm::raw_fd_ostream myfile(compileLogFilename, EC);
236 myfile << llvm::formatv("{ \"log\":\"Glow Compilation Log\", "
237 "\"version\":\"{0}\", ",
238 logVersionNo_);
239#ifdef GIT_SHA1
240 myfile << llvm::formatv("\"commitHash\":\"{0}\", ", GIT_SHA1);
241#endif
242#ifdef GIT_DATE
243 myfile << llvm::formatv("\"commitDate\":\"{0}\", ", GIT_DATE);
244#endif
245 myfile << std::string("\"passes\":");
246 topScope_.dumpChildren(myfile);
247 myfile << std::string("}\n");
248}
249
250/// Logs the node creation with a list of input nodes.
251void LogContext::logNodeCreation(const Node &newNode, bool logIntoModule) {
252 if (!flags::DumpCompilationLog) {
253 return;
254 }
255
256 LogEvent *ev = new LogCreate(&newNode);
257 if (logIntoModule) {
258 parent_->getModuleLogContext()->pushEvent(ev);
259 } else {
260 currentScope_->pushEvent(ev);
261 }
262}
263
264/// Logs the node deletion.
265void LogContext::logNodeDeletion(const Node &deletedNode, bool logIntoModule) {
266 if (!flags::DumpCompilationLog) {
267 return;
268 }
269
270 LogEvent *ev = new LogDelete(&deletedNode);
271 if (logIntoModule) {
272 parent_->getModuleLogContext()->pushEvent(ev);
273 } else {
274 currentScope_->pushEvent(ev);
275 }
276}
277
278/// Logs node's input changes.
279void LogContext::logNodeInputChange(const Node &user,
280 const NodeValue &prevOprVal,
281 const NodeValue &newOprVal) {
282 if (!flags::DumpCompilationLog) {
283 return;
284 }
285
286 LogEvent *ev = new LogInputChange(&user, prevOprVal, newOprVal);
287 currentScope_->pushEvent(ev);
288}
289
290LogEvent *LogContext::getClonedScope() { return topScope_.clone(); }
291
292ScopedLogBlock::ScopedLogBlock(std::shared_ptr<LogContext> ctx,
293 llvm::StringRef name)
294 : ctx_(ctx), name_(name) {
295 ctx_->pushLogScope(name_);
296};
297
298ScopedLogBlock::~ScopedLogBlock() { end(); };
299
300void ScopedLogBlock::end() {
301 if (!end_) {
302 ctx_->popLogScope();
303 }
304 end_ = true;
305}
306
307} // namespace glow
308