5b18e3d6c3705fdae1bd085905b7ad909ba16c7f
[yosys.git] / kernel / log.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/yosys.h"
21 #include "libs/sha1/sha1.h"
22 #include "backends/ilang/ilang_backend.h"
23
24 #if !defined(_WIN32) || defined(__MINGW32__)
25 # include <sys/time.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <vector>
33 #include <list>
34
35 YOSYS_NAMESPACE_BEGIN
36
37 std::vector<FILE*> log_files;
38 std::vector<std::ostream*> log_streams;
39 FILE *log_errfile = NULL;
40 SHA1 *log_hasher = NULL;
41
42 bool log_time = false;
43 bool log_cmd_error_throw = false;
44 bool log_quiet_warnings = false;
45 int log_verbose_level;
46
47 std::vector<int> header_count;
48 std::set<RTLIL::IdString> log_id_cache;
49 std::list<std::string> string_buf;
50 int string_buf_size = 0;
51
52 static struct timeval initial_tv = { 0, 0 };
53 static bool next_print_log = false;
54 static int log_newline_count = 0;
55
56 #if defined(_WIN32) && !defined(__MINGW32__)
57 // this will get time information and return it in timeval, simulating gettimeofday()
58 int gettimeofday(struct timeval *tv, struct timezone *tz)
59 {
60 LARGE_INTEGER counter;
61 LARGE_INTEGER freq;
62
63 QueryPerformanceFrequency(&freq);
64 QueryPerformanceCounter(&counter);
65
66 counter.QuadPart *= 1000000;
67 counter.QuadPart /= freq.QuadPart;
68
69 tv->tv_sec = long(counter.QuadPart / 1000000);
70 tv->tv_usec = counter.QuadPart % 1000000;
71
72 return 0;
73 }
74 #endif
75
76 void logv(const char *format, va_list ap)
77 {
78 while (format[0] == '\n' && format[1] != 0) {
79 log("\n");
80 format++;
81 }
82
83 std::string str = vstringf(format, ap);
84
85 if (str.empty())
86 return;
87
88 size_t nnl_pos = str.find_last_not_of('\n');
89 if (nnl_pos == std::string::npos)
90 log_newline_count += GetSize(str);
91 else
92 log_newline_count = GetSize(str) - nnl_pos - 1;
93
94 if (log_hasher)
95 log_hasher->update(str);
96
97 if (log_time)
98 {
99 std::string time_str;
100
101 if (next_print_log || initial_tv.tv_sec == 0) {
102 next_print_log = false;
103 struct timeval tv;
104 gettimeofday(&tv, NULL);
105 if (initial_tv.tv_sec == 0)
106 initial_tv = tv;
107 if (tv.tv_usec < initial_tv.tv_usec) {
108 tv.tv_sec--;
109 tv.tv_usec += 1000000;
110 }
111 tv.tv_sec -= initial_tv.tv_sec;
112 tv.tv_usec -= initial_tv.tv_usec;
113 time_str += stringf("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec));
114 }
115
116 if (format[0] && format[strlen(format)-1] == '\n')
117 next_print_log = true;
118
119 for (auto f : log_files)
120 fputs(time_str.c_str(), f);
121
122 for (auto f : log_streams)
123 *f << time_str;
124 }
125
126 for (auto f : log_files)
127 fputs(str.c_str(), f);
128
129 for (auto f : log_streams)
130 *f << str;
131 }
132
133 void logv_header(const char *format, va_list ap)
134 {
135 bool pop_errfile = false;
136
137 log_spacer();
138 if (header_count.size() > 0)
139 header_count.back()++;
140
141 if (int(header_count.size()) <= log_verbose_level && log_errfile != NULL) {
142 log_files.push_back(log_errfile);
143 pop_errfile = true;
144 }
145
146 for (int c : header_count)
147 log("%d.", c);
148 log(" ");
149 logv(format, ap);
150 log_flush();
151
152 if (pop_errfile)
153 log_files.pop_back();
154 }
155
156 void logv_warning(const char *format, va_list ap)
157 {
158 if (log_errfile != NULL && !log_quiet_warnings)
159 log_files.push_back(log_errfile);
160
161 log("Warning: ");
162 logv(format, ap);
163 log_flush();
164
165 if (log_errfile != NULL && !log_quiet_warnings)
166 log_files.pop_back();
167 }
168
169 void logv_error(const char *format, va_list ap)
170 {
171 if (log_errfile != NULL)
172 log_files.push_back(log_errfile);
173
174 log("ERROR: ");
175 logv(format, ap);
176 log_flush();
177 exit(1);
178 }
179
180 void log(const char *format, ...)
181 {
182 va_list ap;
183 va_start(ap, format);
184 logv(format, ap);
185 va_end(ap);
186 }
187
188 void log_header(const char *format, ...)
189 {
190 va_list ap;
191 va_start(ap, format);
192 logv_header(format, ap);
193 va_end(ap);
194 }
195
196 void log_warning(const char *format, ...)
197 {
198 va_list ap;
199 va_start(ap, format);
200 logv_warning(format, ap);
201 va_end(ap);
202 }
203
204 void log_error(const char *format, ...)
205 {
206 va_list ap;
207 va_start(ap, format);
208 logv_error(format, ap);
209 }
210
211 void log_cmd_error(const char *format, ...)
212 {
213 va_list ap;
214 va_start(ap, format);
215
216 if (log_cmd_error_throw) {
217 log("ERROR: ");
218 logv(format, ap);
219 log_flush();
220 throw log_cmd_error_exception();
221 }
222
223 logv_error(format, ap);
224 }
225
226 void log_spacer()
227 {
228 while (log_newline_count < 2)
229 log("\n");
230 }
231
232 void log_push()
233 {
234 header_count.push_back(0);
235 }
236
237 void log_pop()
238 {
239 header_count.pop_back();
240 log_id_cache.clear();
241 string_buf.clear();
242 string_buf_size = 0;
243 log_flush();
244 }
245
246 void log_reset_stack()
247 {
248 while (header_count.size() > 1)
249 header_count.pop_back();
250 log_id_cache.clear();
251 string_buf.clear();
252 string_buf_size = 0;
253 log_flush();
254 }
255
256 void log_flush()
257 {
258 for (auto f : log_files)
259 fflush(f);
260
261 for (auto f : log_streams)
262 f->flush();
263 }
264
265 void log_dump_val_worker(RTLIL::SigSpec v) {
266 log("%s", log_signal(v));
267 }
268
269 const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
270 {
271 std::stringstream buf;
272 ILANG_BACKEND::dump_sigspec(buf, sig, autoint);
273
274 if (string_buf_size < 100)
275 string_buf_size++;
276 else
277 string_buf.pop_front();
278 string_buf.push_back(buf.str());
279
280 return string_buf.back().c_str();
281 }
282
283 const char *log_id(RTLIL::IdString str)
284 {
285 log_id_cache.insert(str);
286 const char *p = str.c_str();
287 if (p[0] == '\\' && p[1] != '$' && p[1] != 0)
288 return p+1;
289 return p;
290 }
291
292 void log_cell(RTLIL::Cell *cell, std::string indent)
293 {
294 std::stringstream buf;
295 ILANG_BACKEND::dump_cell(buf, indent, cell);
296 log("%s", buf.str().c_str());
297 }
298
299 // ---------------------------------------------------
300 // This is the magic behind the code coverage counters
301 // ---------------------------------------------------
302 #ifdef YOSYS_ENABLE_COVER
303
304 dict<std::string, std::pair<std::string, int>> extra_coverage_data;
305
306 void cover_extra(std::string parent, std::string id, bool increment) {
307 if (extra_coverage_data.count(id) == 0) {
308 for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++)
309 if (p->id == parent)
310 extra_coverage_data[id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
311 log_assert(extra_coverage_data.count(id));
312 }
313 if (increment)
314 extra_coverage_data[id].second++;
315 }
316
317 dict<std::string, std::pair<std::string, int>> get_coverage_data()
318 {
319 dict<std::string, std::pair<std::string, int>> coverage_data;
320
321 for (auto &it : pass_register) {
322 std::string key = stringf("passes.%s", it.first.c_str());
323 coverage_data[key].first = stringf("%s:%d:%s", __FILE__, __LINE__, __FUNCTION__);
324 coverage_data[key].second += it.second->call_counter;
325 }
326
327 for (auto &it : extra_coverage_data) {
328 if (coverage_data.count(it.first))
329 log_warning("found duplicate coverage id \"%s\".\n", it.first.c_str());
330 coverage_data[it.first].first = it.second.first;
331 coverage_data[it.first].second += it.second.second;
332 }
333
334 for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) {
335 if (coverage_data.count(p->id))
336 log_warning("found duplicate coverage id \"%s\".\n", p->id);
337 coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
338 coverage_data[p->id].second += p->counter;
339 }
340
341 for (auto &it : coverage_data)
342 if (!it.second.first.compare(0, strlen(YOSYS_SRC "/"), YOSYS_SRC "/"))
343 it.second.first = it.second.first.substr(strlen(YOSYS_SRC "/"));
344
345 return coverage_data;
346 }
347
348 #endif
349
350 YOSYS_NAMESPACE_END
351