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