Support for FP Paired Single Operations
[gem5.git] / base / trace.cc
1 /*
2 * Copyright (c) 2001-2005 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 ObjectMatch ignore;
55
56 Log theLog;
57
58 Log::Log()
59 {
60 size = 0;
61 buffer = NULL;
62 }
63
64
65 void
66 Log::init(int _size)
67 {
68 if (buffer != NULL) {
69 fatal("Trace::Log::init called twice!");
70 }
71
72 size = _size;
73
74 buffer = new Record *[size];
75
76 for (int i = 0; i < size; ++i) {
77 buffer[i] = NULL;
78 }
79
80 nextRecPtr = &buffer[0];
81 wrapRecPtr = &buffer[size];
82 }
83
84
85 Log::~Log()
86 {
87 for (int i = 0; i < size; ++i) {
88 delete buffer[i];
89 }
90
91 delete [] buffer;
92 }
93
94
95 void
96 Log::append(Record *rec)
97 {
98 // dump record to output stream if there's one open
99 if (dprintf_stream != NULL) {
100 rec->dump(*dprintf_stream);
101 } else {
102 rec->dump(cout);
103 }
104
105 // no buffering: justget rid of it now
106 if (buffer == NULL) {
107 delete rec;
108 return;
109 }
110
111 Record *oldRec = *nextRecPtr;
112
113 if (oldRec != NULL) {
114 // log has wrapped: overwrite
115 delete oldRec;
116 }
117
118 *nextRecPtr = rec;
119
120 if (++nextRecPtr == wrapRecPtr) {
121 nextRecPtr = &buffer[0];
122 }
123 }
124
125
126 void
127 Log::dump(ostream &os)
128 {
129 if (buffer == NULL) {
130 return;
131 }
132
133 Record **bufPtr = nextRecPtr;
134
135 if (*bufPtr == NULL) {
136 // next record slot is empty: log must not be full yet.
137 // start dumping from beginning of buffer
138 bufPtr = buffer;
139 }
140
141 do {
142 Record *rec = *bufPtr;
143
144 rec->dump(os);
145
146 if (++bufPtr == wrapRecPtr) {
147 bufPtr = &buffer[0];
148 }
149 } while (bufPtr != nextRecPtr);
150 }
151
152 PrintfRecord::~PrintfRecord()
153 {
154 delete &args;
155 }
156
157 void
158 PrintfRecord::dump(ostream &os)
159 {
160 string fmt = "";
161
162 if (!name.empty()) {
163 fmt = "%s: " + fmt;
164 args.prepend(name);
165 }
166
167 if (cycle != (Tick)-1) {
168 fmt = "%7d: " + fmt;
169 args.prepend(cycle);
170 }
171
172 fmt += format;
173
174 args.dump(os, fmt);
175 os.flush();
176 }
177
178 DataRecord::DataRecord(Tick _cycle, const string &_name,
179 const void *_data, int _len)
180 : Record(_cycle), name(_name), len(_len)
181 {
182 data = new uint8_t[len];
183 memcpy(data, _data, len);
184 }
185
186 DataRecord::~DataRecord()
187 {
188 delete [] data;
189 }
190
191 void
192 DataRecord::dump(ostream &os)
193 {
194 int c, i, j;
195
196 for (i = 0; i < len; i += 16) {
197 ccprintf(os, "%d: %s: %08x ", cycle, name, i);
198 c = len - i;
199 if (c > 16) c = 16;
200
201 for (j = 0; j < c; j++) {
202 ccprintf(os, "%02x ", data[i + j] & 0xff);
203 if ((j & 0xf) == 7 && j > 0)
204 ccprintf(os, " ");
205 }
206
207 for (; j < 16; j++)
208 ccprintf(os, " ");
209 ccprintf(os, " ");
210
211 for (j = 0; j < c; j++) {
212 int ch = data[i + j] & 0x7f;
213 ccprintf(os,
214 "%c", (char)(isprint(ch) ? ch : ' '));
215 }
216
217 ccprintf(os, "\n");
218
219 if (c < 16)
220 break;
221 }
222 }
223 } // namespace Trace
224
225 //
226 // Returns the current output stream for debug information. As a
227 // wrapper around Trace::dprintf_stream, this handles cases where debug
228 // information is generated in the process of parsing .ini options,
229 // before we process the option that sets up the debug output stream
230 // itself.
231 //
232 std::ostream &
233 DebugOut()
234 {
235 return *Trace::dprintf_stream;
236 }
237
238 /////////////////////////////////////////////
239 //
240 // C-linkage functions for invoking from gdb
241 //
242 /////////////////////////////////////////////
243
244 //
245 // Dump trace buffer to specified file (cout if NULL)
246 //
247 extern "C"
248 void
249 dumpTrace(const char *filename)
250 {
251 if (filename != NULL) {
252 ofstream out(filename);
253 Trace::theLog.dump(out);
254 out.close();
255 }
256 else {
257 Trace::theLog.dump(cout);
258 }
259 }
260
261
262 //
263 // Turn on/off trace output to cerr. Typically used when trace output
264 // is only going to circular buffer, but you want to see what's being
265 // sent there as you step through some code in gdb. This uses the
266 // same facility as the "trace to file" feature, and will print error
267 // messages rather than clobbering an existing ostream pointer.
268 //
269 extern "C"
270 void
271 echoTrace(bool on)
272 {
273 if (on) {
274 if (Trace::dprintf_stream != NULL) {
275 cerr << "Already echoing trace to a file... go do a 'tail -f'"
276 << " on that file instead." << endl;
277 } else {
278 Trace::dprintf_stream = &cerr;
279 }
280 } else {
281 if (Trace::dprintf_stream != &cerr) {
282 cerr << "Not echoing trace to cerr." << endl;
283 } else {
284 Trace::dprintf_stream = NULL;
285 }
286 }
287 }
288
289 extern "C"
290 void
291 printTraceFlags()
292 {
293 using namespace Trace;
294 for (int i = 0; i < numFlagStrings; ++i)
295 if (flags[i])
296 cprintf("%s\n", flagStrings[i]);
297 }
298
299 void
300 tweakTraceFlag(const char *string, bool value)
301 {
302 using namespace Trace;
303 std::string str(string);
304
305 for (int i = 0; i < numFlagStrings; ++i) {
306 if (str != flagStrings[i])
307 continue;
308
309 int idx = i;
310
311 if (idx < NumFlags) {
312 flags[idx] = value;
313 } else {
314 idx -= NumFlags;
315 if (idx >= NumCompoundFlags) {
316 ccprintf(cerr, "Invalid compound flag");
317 return;
318 }
319
320 const Flags *flagVec = compoundFlags[idx];
321
322 for (int j = 0; flagVec[j] != -1; ++j) {
323 if (flagVec[j] >= NumFlags) {
324 ccprintf(cerr, "Invalid compound flag");
325 return;
326 }
327 flags[flagVec[j]] = value;
328 }
329 }
330
331 cprintf("flag %s was %s\n", string, value ? "set" : "cleared");
332 return;
333 }
334
335 cprintf("could not find flag %s\n", string);
336 }
337
338 extern "C"
339 void
340 setTraceFlag(const char *string)
341 {
342 tweakTraceFlag(string, true);
343 }
344
345 extern "C"
346 void
347 clearTraceFlag(const char *string)
348 {
349 tweakTraceFlag(string, false);
350 }