trace.cc revision 1030
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 40using namespace std; 41 42namespace Trace { 43const string DefaultName("global"); 44FlagVec 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// 52ostream *dprintf_stream = &cerr; 53 54int dprintf_ignore_size; 55vector<string> dprintf_ignore; 56vector<vector<string> > ignore_tokens; 57vector<int> ignore_size; 58 59bool 60dprintf_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 88Log theLog; 89 90Log::Log() 91{ 92 size = 0; 93 buffer = NULL; 94} 95 96 97void 98Log::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 117Log::~Log() 118{ 119 for (int i = 0; i < size; ++i) { 120 delete buffer[i]; 121 } 122 123 delete [] buffer; 124} 125 126 127void 128Log::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 156void 157Log::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 182PrintfRecord::~PrintfRecord() 183{ 184 delete &args; 185} 186 187void 188PrintfRecord::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 208DataRecord::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 216DataRecord::~DataRecord() 217{ 218 delete [] data; 219} 220 221void 222DataRecord::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// 262std::ostream & 263DebugOut() 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// 277extern "C" 278void 279dumpTrace(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// 299extern "C" 300void 301echoTrace(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 319extern "C" 320void 321printTraceFlags() 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 329void 330tweakTraceFlag(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 368extern "C" 369void 370setTraceFlag(const char *string) 371{ 372 tweakTraceFlag(string, true); 373} 374 375extern "C" 376void 377clearTraceFlag(const char *string) 378{ 379 tweakTraceFlag(string, false); 380} 381