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