Limit size of log_signal buffer to 100 elements
[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 log("\n");
94 if (header_count.size() > 0)
95 header_count.back()++;
96 for (int c : header_count)
97 log("%d.", c);
98 log(" ");
99 logv(format, ap);
100 log_flush();
101
102 if (int(header_count.size()) <= log_verbose_level && log_errfile != NULL) {
103 for (int c : header_count)
104 fprintf(log_errfile, "%d.", c);
105 fprintf(log_errfile, " ");
106 vfprintf(log_errfile, format, ap);
107 fflush(log_errfile);
108 }
109 }
110
111 void logv_error(const char *format, va_list ap)
112 {
113 log("ERROR: ");
114 logv(format, ap);
115 if (log_errfile != NULL) {
116 fprintf(log_errfile, "ERROR: ");
117 vfprintf(log_errfile, format, ap);
118 }
119 log_flush();
120 exit(1);
121 }
122
123 void log(const char *format, ...)
124 {
125 va_list ap;
126 va_start(ap, format);
127 logv(format, ap);
128 va_end(ap);
129 }
130
131 void log_header(const char *format, ...)
132 {
133 va_list ap;
134 va_start(ap, format);
135 logv_header(format, ap);
136 va_end(ap);
137 }
138
139 void log_error(const char *format, ...)
140 {
141 va_list ap;
142 va_start(ap, format);
143 logv_error(format, ap);
144 }
145
146 void log_cmd_error(const char *format, ...)
147 {
148 va_list ap;
149 va_start(ap, format);
150
151 if (log_cmd_error_throw) {
152 log("ERROR: ");
153 logv(format, ap);
154 log_flush();
155 throw log_cmd_error_expection();
156 }
157
158 logv_error(format, ap);
159 }
160
161 void log_push()
162 {
163 header_count.push_back(0);
164 }
165
166 void log_pop()
167 {
168 header_count.pop_back();
169 string_buf.clear();
170 string_buf_size = 0;
171 log_flush();
172 }
173
174 void log_reset_stack()
175 {
176 while (header_count.size() > 1)
177 header_count.pop_back();
178 string_buf.clear();
179 string_buf_size = 0;
180 log_flush();
181 }
182
183 void log_flush()
184 {
185 for (auto f : log_files)
186 fflush(f);
187 }
188
189 void log_dump_val_worker(RTLIL::SigSpec v) {
190 log("%s", log_signal(v));
191 }
192
193 const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
194 {
195 char *ptr;
196 size_t size;
197
198 FILE *f = open_memstream(&ptr, &size);
199 ILANG_BACKEND::dump_sigspec(f, sig, autoint);
200 fputc(0, f);
201 fclose(f);
202
203 if (string_buf_size < 100)
204 string_buf_size++;
205 else
206 string_buf.pop_front();
207 string_buf.push_back(ptr);
208 free(ptr);
209
210 return string_buf.back().c_str();
211 }
212
213 const char *log_id(RTLIL::IdString str)
214 {
215 const char *p = str;
216 log_assert(RTLIL::IdString::global_refcount_storage_[str.index_] > 1);
217 if (p[0] == '\\' && p[1] != '$' && p[1] != 0)
218 return p+1;
219 return p;
220 }
221
222 void log_cell(RTLIL::Cell *cell, std::string indent)
223 {
224 char *ptr;
225 size_t size;
226
227 FILE *f = open_memstream(&ptr, &size);
228 ILANG_BACKEND::dump_cell(f, indent, cell);
229 fputc(0, f);
230 fclose(f);
231
232 log("%s", ptr);
233 free(ptr);
234 }
235
236 // ---------------------------------------------------
237 // This is the magic behind the code coverage counters
238 // ---------------------------------------------------
239
240 std::map<std::string, std::pair<std::string, int>> extra_coverage_data;
241
242 void cover_extra(std::string parent, std::string id, bool increment) {
243 if (extra_coverage_data.count(id) == 0) {
244 for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++)
245 if (p->id == parent)
246 extra_coverage_data[id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
247 log_assert(extra_coverage_data.count(id));
248 }
249 if (increment)
250 extra_coverage_data[id].second++;
251 }
252
253 std::map<std::string, std::pair<std::string, int>> get_coverage_data()
254 {
255 std::map<std::string, std::pair<std::string, int>> coverage_data;
256
257 for (auto &it : pass_register) {
258 std::string key = stringf("passes.%s", it.first.c_str());
259 coverage_data[key].first = stringf("%s:%d:%s", __FILE__, __LINE__, __FUNCTION__);
260 coverage_data[key].second += it.second->call_counter;
261 }
262
263 for (auto &it : extra_coverage_data) {
264 if (coverage_data.count(it.first))
265 log("WARNING: found duplicate coverage id \"%s\".\n", it.first.c_str());
266 coverage_data[it.first].first = it.second.first;
267 coverage_data[it.first].second += it.second.second;
268 }
269
270 for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) {
271 if (coverage_data.count(p->id))
272 log("WARNING: found duplicate coverage id \"%s\".\n", p->id);
273 coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
274 coverage_data[p->id].second += p->counter;
275 }
276
277 for (auto &it : coverage_data)
278 if (!it.second.first.compare(0, strlen(YOSYS_SRC "/"), YOSYS_SRC "/"))
279 it.second.first = it.second.first.substr(strlen(YOSYS_SRC "/"));
280
281 return coverage_data;
282 }
283
284 YOSYS_NAMESPACE_END
285