Make the DDUMP tracing feature output the cycle number and
[gem5.git] / base / trace.cc
1 /*
2 * Copyright (c) 2001-2004 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <ctype.h>
30 #include <fstream>
31 #include <iostream>
32 #include <list>
33 #include <string>
34 #include <vector>
35
36 #include "base/misc.hh"
37 #include "base/trace.hh"
38 #include "base/str.hh"
39
40 using namespace std;
41
42 namespace Trace {
43 const string DefaultName("global");
44 FlagVec flags(NumFlags, false);
45
46 //
47 // This variable holds the output stream for debug information. Other
48 // than setting up/redirecting this stream, do *NOT* reference this
49 // directly; use DebugOut() (see below) to access this stream for
50 // output.
51 //
52 ostream *dprintf_stream = &cerr;
53
54 int dprintf_ignore_size;
55 vector<string> dprintf_ignore;
56 vector<vector<string> > ignore_tokens;
57 vector<int> ignore_size;
58
59 bool
60 dprintf_ignore_name(const string &name)
61 {
62 vector<string> name_tokens;
63 tokenize(name_tokens, name, '.');
64 int ntsize = name_tokens.size();
65
66 for (int i = 0; i < dprintf_ignore_size; ++i) {
67 bool match = true;
68 int jstop = ignore_size[i];
69 for (int j = 0; j < jstop; ++j) {
70 if (j >= ntsize)
71 break;
72
73 const string &ignore = ignore_tokens[i][j];
74 if (ignore != "*" && ignore != name_tokens[j]) {
75 match = false;
76 break;
77 }
78 }
79
80 if (match == true)
81 return true;
82 }
83
84 return false;
85 }
86
87
88 Log theLog;
89
90 Log::Log()
91 {
92 size = 0;
93 buffer = NULL;
94 }
95
96
97 void
98 Log::init(int _size)
99 {
100 if (buffer != NULL) {
101 fatal("Trace::Log::init called twice!");
102 }
103
104 size = _size;
105
106 buffer = new (Record *)[size];
107
108 for (int i = 0; i < size; ++i) {
109 buffer[i] = NULL;
110 }
111
112 nextRecPtr = &buffer[0];
113 wrapRecPtr = &buffer[size];
114 }
115
116
117 Log::~Log()
118 {
119 for (int i = 0; i < size; ++i) {
120 delete buffer[i];
121 }
122
123 delete [] buffer;
124 }
125
126
127 void
128 Log::append(Record *rec)
129 {
130 // dump record to output stream if there's one open
131 if (dprintf_stream != NULL) {
132 rec->dump(*dprintf_stream);
133 }
134
135 // no buffering: justget rid of it now
136 if (buffer == NULL) {
137 delete rec;
138 return;
139 }
140
141 Record *oldRec = *nextRecPtr;
142
143 if (oldRec != NULL) {
144 // log has wrapped: overwrite
145 delete oldRec;
146 }
147
148 *nextRecPtr = rec;
149
150 if (++nextRecPtr == wrapRecPtr) {
151 nextRecPtr = &buffer[0];
152 }
153 }
154
155
156 void
157 Log::dump(ostream &os)
158 {
159 if (buffer == NULL) {
160 return;
161 }
162
163 Record **bufPtr = nextRecPtr;
164
165 if (*bufPtr == NULL) {
166 // next record slot is empty: log must not be full yet.
167 // start dumping from beginning of buffer
168 bufPtr = buffer;
169 }
170
171 do {
172 Record *rec = *bufPtr;
173
174 rec->dump(os);
175
176 if (++bufPtr == wrapRecPtr) {
177 bufPtr = &buffer[0];
178 }
179 } while (bufPtr != nextRecPtr);
180 }
181
182 PrintfRecord::~PrintfRecord()
183 {
184 delete &args;
185 }
186
187 void
188 PrintfRecord::dump(ostream &os)
189 {
190 string fmt = "";
191
192 if (!name.empty()) {
193 fmt = "%s: " + fmt;
194 args.prepend(name);
195 }
196
197 if (cycle != (Tick)-1) {
198 fmt = "%7d: " + fmt;
199 args.prepend(cycle);
200 }
201
202 fmt += format;
203
204 args.dump(os, fmt);
205 os.flush();
206 }
207
208 DataRecord::DataRecord(Tick _cycle, const string &_name,
209 const void *_data, int _len)
210 : Record(_cycle), name(_name), len(_len)
211 {
212 data = new uint8_t[len];
213 memcpy(data, _data, len);
214 }
215
216 DataRecord::~DataRecord()
217 {
218 delete [] data;
219 }
220
221 void
222 DataRecord::dump(ostream &os)
223 {
224 int c, i, j;
225
226 for (i = 0; i < len; i += 16) {
227 ccprintf(os, "%d: %s: %08x ", cycle, name, i);
228 c = len - i;
229 if (c > 16) c = 16;
230
231 for (j = 0; j < c; j++) {
232 ccprintf(os, "%02x ", data[i + j] & 0xff);
233 if ((j & 0xf) == 7 && j > 0)
234 ccprintf(os, " ");
235 }
236
237 for (; j < 16; j++)
238 ccprintf(os, " ");
239 ccprintf(os, " ");
240
241 for (j = 0; j < c; j++) {
242 int ch = data[i + j] & 0x7f;
243 ccprintf(os,
244 "%c", (char)(isprint(ch) ? ch : ' '));
245 }
246
247 ccprintf(os, "\n");
248
249 if (c < 16)
250 break;
251 }
252 }
253 } // namespace Trace
254
255 //
256 // Returns the current output stream for debug information. As a
257 // wrapper around Trace::dprintf_stream, this handles cases where debug
258 // information is generated in the process of parsing .ini options,
259 // before we process the option that sets up the debug output stream
260 // itself.
261 //
262 std::ostream &
263 DebugOut()
264 {
265 return *Trace::dprintf_stream;
266 }
267
268 /////////////////////////////////////////////
269 //
270 // C-linkage functions for invoking from gdb
271 //
272 /////////////////////////////////////////////
273
274 //
275 // Dump trace buffer to specified file (cout if NULL)
276 //
277 extern "C"
278 void
279 dumpTrace(const char *filename)
280 {
281 if (filename != NULL) {
282 ofstream out(filename);
283 Trace::theLog.dump(out);
284 out.close();
285 }
286 else {
287 Trace::theLog.dump(cout);
288 }
289 }
290
291
292 //
293 // Turn on/off trace output to cerr. Typically used when trace output
294 // is only going to circular buffer, but you want to see what's being
295 // sent there as you step through some code in gdb. This uses the
296 // same facility as the "trace to file" feature, and will print error
297 // messages rather than clobbering an existing ostream pointer.
298 //
299 extern "C"
300 void
301 echoTrace(bool on)
302 {
303 if (on) {
304 if (Trace::dprintf_stream != NULL) {
305 cerr << "Already echoing trace to a file... go do a 'tail -f'"
306 << " on that file instead." << endl;
307 } else {
308 Trace::dprintf_stream = &cerr;
309 }
310 } else {
311 if (Trace::dprintf_stream != &cerr) {
312 cerr << "Not echoing trace to cerr." << endl;
313 } else {
314 Trace::dprintf_stream = NULL;
315 }
316 }
317 }
318
319 extern "C"
320 void
321 printTraceFlags()
322 {
323 using namespace Trace;
324 for (int i = 0; i < numFlagStrings; ++i)
325 if (flags[i])
326 cprintf("%s\n", flagStrings[i]);
327 }
328
329 void
330 tweakTraceFlag(const char *string, bool value)
331 {
332 using namespace Trace;
333 std::string str(string);
334
335 for (int i = 0; i < numFlagStrings; ++i) {
336 if (str != flagStrings[i])
337 continue;
338
339 int idx = i;
340
341 if (idx < NumFlags) {
342 flags[idx] = value;
343 } else {
344 idx -= NumFlags;
345 if (idx >= NumCompoundFlags) {
346 ccprintf(cerr, "Invalid compound flag");
347 return;
348 }
349
350 const Flags *flagVec = compoundFlags[idx];
351
352 for (int j = 0; flagVec[j] != -1; ++j) {
353 if (flagVec[j] >= NumFlags) {
354 ccprintf(cerr, "Invalid compound flag");
355 return;
356 }
357 flags[flagVec[j]] = value;
358 }
359 }
360
361 cprintf("flag %s was %s\n", string, value ? "set" : "cleared");
362 return;
363 }
364
365 cprintf("could not find flag %s\n", string);
366 }
367
368 extern "C"
369 void
370 setTraceFlag(const char *string)
371 {
372 tweakTraceFlag(string, true);
373 }
374
375 extern "C"
376 void
377 clearTraceFlag(const char *string)
378 {
379 tweakTraceFlag(string, false);
380 }