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