1f082603956a9a5459676b1db1f6e8240076aaa2
[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 #include <sys/time.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <vector>
30 #include <list>
31
32 YOSYS_NAMESPACE_BEGIN
33
34 std::vector<FILE*> log_files;
35 FILE *log_errfile = NULL;
36 SHA1 *log_hasher = NULL;
37
38 bool log_time = false;
39 bool log_cmd_error_throw = false;
40 int log_verbose_level;
41
42 std::vector<int> header_count;
43 std::list<std::string> string_buf;
44 int string_buf_size = 0;
45
46 static struct timeval initial_tv = { 0, 0 };
47 static bool next_print_log = false;
48
49 void logv(const char *format, va_list ap)
50 {
51 while (format[0] == '\n' && format[1] != 0) {
52 log("\n");
53 format++;
54 }
55
56 std::string str = vstringf(format, ap);
57
58 if (log_hasher)
59 log_hasher->update(str);
60
61 if (log_time)
62 {
63 std::string time_str;
64
65 if (next_print_log || initial_tv.tv_sec == 0) {
66 next_print_log = false;
67 struct timeval tv;
68 gettimeofday(&tv, NULL);
69 if (initial_tv.tv_sec == 0)
70 initial_tv = tv;
71 if (tv.tv_usec < initial_tv.tv_usec) {
72 tv.tv_sec--;
73 tv.tv_usec += 1000000;
74 }
75 tv.tv_sec -= initial_tv.tv_sec;
76 tv.tv_usec -= initial_tv.tv_usec;
77 time_str += stringf("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec));
78 }
79
80 if (format[0] && format[strlen(format)-1] == '\n')
81 next_print_log = true;
82
83 for (auto f : log_files)
84 fputs(time_str.c_str(), f);
85 }
86
87 for (auto f : log_files)
88 fputs(str.c_str(), f);
89 }
90
91 void logv_header(const char *format, va_list ap)
92 {
93 bool pop_errfile = false;
94
95 log("\n");
96 if (header_count.size() > 0)
97 header_count.back()++;
98
99 if (int(header_count.size()) <= log_verbose_level && log_errfile != NULL) {
100 log_files.push_back(log_errfile);
101 pop_errfile = true;
102 }
103
104 for (int c : header_count)
105 log("%d.", c);
106 log(" ");
107 logv(format, ap);
108 log_flush();
109
110 if (pop_errfile)
111 log_files.pop_back();
112 }
113
114 void logv_error(const char *format, va_list ap)
115 {
116 if (log_errfile != NULL)
117 log_files.push_back(log_errfile);
118
119 log("ERROR: ");
120 logv(format, ap);
121 log_flush();
122 exit(1);
123 }
124
125 void log(const char *format, ...)
126 {
127 va_list ap;
128 va_start(ap, format);
129 logv(format, ap);
130 va_end(ap);
131 }
132
133 void log_header(const char *format, ...)
134 {
135 va_list ap;
136 va_start(ap, format);
137 logv_header(format, ap);
138 va_end(ap);
139 }
140
141 void log_error(const char *format, ...)
142 {
143 va_list ap;
144 va_start(ap, format);
145 logv_error(format, ap);
146 }
147
148 void log_cmd_error(const char *format, ...)
149 {
150 va_list ap;
151 va_start(ap, format);
152
153 if (log_cmd_error_throw) {
154 log("ERROR: ");
155 logv(format, ap);
156 log_flush();
157 throw log_cmd_error_expection();
158 }
159
160 logv_error(format, ap);
161 }
162
163 void log_push()
164 {
165 header_count.push_back(0);
166 }
167
168 void log_pop()
169 {
170 header_count.pop_back();
171 string_buf.clear();
172 string_buf_size = 0;
173 log_flush();
174 }
175
176 void log_reset_stack()
177 {
178 while (header_count.size() > 1)
179 header_count.pop_back();
180 string_buf.clear();
181 string_buf_size = 0;
182 log_flush();
183 }
184
185 void log_flush()
186 {
187 for (auto f : log_files)
188 fflush(f);
189 }
190
191 void log_dump_val_worker(RTLIL::SigSpec v) {
192 log("%s", log_signal(v));
193 }
194
195 const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
196 {
197 char *ptr;
198 size_t size;
199
200 FILE *f = open_memstream(&ptr, &size);
201 ILANG_BACKEND::dump_sigspec(f, sig, autoint);
202 fputc(0, f);
203 fclose(f);
204
205 if (string_buf_size < 100)
206 string_buf_size++;
207 else
208 string_buf.pop_front();
209 string_buf.push_back(ptr);
210 free(ptr);
211
212 return string_buf.back().c_str();
213 }
214
215 const char *log_id(RTLIL::IdString str)
216 {
217 const char *p = str.c_str();
218 log_assert(RTLIL::IdString::global_refcount_storage_[str.index_] > 1);
219 if (p[0] == '\\' && p[1] != '$' && p[1] != 0)
220 return p+1;
221 return p;
222 }
223
224 void log_cell(RTLIL::Cell *cell, std::string indent)
225 {
226 char *ptr;
227 size_t size;
228
229 FILE *f = open_memstream(&ptr, &size);
230 ILANG_BACKEND::dump_cell(f, indent, cell);
231 fputc(0, f);
232 fclose(f);
233
234 log("%s", ptr);
235 free(ptr);
236 }
237
238 // ---------------------------------------------------
239 // This is the magic behind the code coverage counters
240 // ---------------------------------------------------
241 #ifdef COVER_ACTIVE
242
243 std::map<std::string, std::pair<std::string, int>> extra_coverage_data;
244
245 void cover_extra(std::string parent, std::string id, bool increment) {
246 if (extra_coverage_data.count(id) == 0) {
247 for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++)
248 if (p->id == parent)
249 extra_coverage_data[id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
250 log_assert(extra_coverage_data.count(id));
251 }
252 if (increment)
253 extra_coverage_data[id].second++;
254 }
255
256 std::map<std::string, std::pair<std::string, int>> get_coverage_data()
257 {
258 std::map<std::string, std::pair<std::string, int>> coverage_data;
259
260 for (auto &it : pass_register) {
261 std::string key = stringf("passes.%s", it.first.c_str());
262 coverage_data[key].first = stringf("%s:%d:%s", __FILE__, __LINE__, __FUNCTION__);
263 coverage_data[key].second += it.second->call_counter;
264 }
265
266 for (auto &it : extra_coverage_data) {
267 if (coverage_data.count(it.first))
268 log("WARNING: found duplicate coverage id \"%s\".\n", it.first.c_str());
269 coverage_data[it.first].first = it.second.first;
270 coverage_data[it.first].second += it.second.second;
271 }
272
273 for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) {
274 if (coverage_data.count(p->id))
275 log("WARNING: found duplicate coverage id \"%s\".\n", p->id);
276 coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
277 coverage_data[p->id].second += p->counter;
278 }
279
280 for (auto &it : coverage_data)
281 if (!it.second.first.compare(0, strlen(YOSYS_SRC "/"), YOSYS_SRC "/"))
282 it.second.first = it.second.first.substr(strlen(YOSYS_SRC "/"));
283
284 return coverage_data;
285 }
286
287 #endif
288
289 YOSYS_NAMESPACE_END
290