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