trace.cc revision 600
19380SAndreas.Sandberg@ARM.com/* 23005Sstever@eecs.umich.edu * Copyright (c) 2003 The Regents of The University of Michigan 33005Sstever@eecs.umich.edu * All rights reserved. 49380SAndreas.Sandberg@ARM.com * 59380SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without 69380SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are 79380SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright 89380SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer; 99380SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright 109380SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the 119380SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution; 129380SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its 133005Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from 143005Sstever@eecs.umich.edu * this software without specific prior written permission. 153005Sstever@eecs.umich.edu * 163005Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173005Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183005Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193005Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203005Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213005Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223005Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233005Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243005Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253005Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263005Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273005Sstever@eecs.umich.edu */ 283005Sstever@eecs.umich.edu 293005Sstever@eecs.umich.edu#include <ctype.h> 303005Sstever@eecs.umich.edu#include <fstream> 313005Sstever@eecs.umich.edu#include <iostream> 323005Sstever@eecs.umich.edu#include <list> 333005Sstever@eecs.umich.edu#include <string> 343005Sstever@eecs.umich.edu#include <vector> 353005Sstever@eecs.umich.edu 369380SAndreas.Sandberg@ARM.com#include "base/misc.hh" 373005Sstever@eecs.umich.edu#include "base/trace.hh" 383005Sstever@eecs.umich.edu#include "base/str.hh" 399380SAndreas.Sandberg@ARM.com 404966Ssaidi@eecs.umich.eduusing namespace std; 419826Sandreas.hansson@arm.com 4211837Swendy.elsasser@arm.comnamespace Trace { 439826Sandreas.hansson@arm.comconst string DefaultName("global"); 449380SAndreas.Sandberg@ARM.comFlagVec 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 187 188void 189PrintfRecord::dump(ostream &os) 190{ 191 string fmt = ""; 192 193 if (!name.empty()) { 194 fmt = "%s: " + fmt; 195 args.prepend(name); 196 } 197 198 if (cycle != (Tick)-1) { 199 fmt = "%7d: " + fmt; 200 args.prepend(cycle); 201 } 202 203 fmt += format; 204 205 args.dump(os, fmt); 206 os.flush(); 207} 208 209 210 211RawDataRecord::RawDataRecord(Tick _cycle, const void *_data, int _len) 212 : Record(_cycle), len(_len) 213{ 214 data = new uint8_t[len]; 215 memcpy(data, _data, len); 216} 217 218 219RawDataRecord::~RawDataRecord() 220{ 221 delete [] data; 222} 223 224 225void 226RawDataRecord::dump(ostream &os) 227{ 228 int c, i, j; 229 230 for (i = 0; i < len; i += 16) { 231 ccprintf(os, "%08x ", i); 232 c = len - i; 233 if (c > 16) c = 16; 234 235 for (j = 0; j < c; j++) { 236 ccprintf(os, "%02x ", data[i + j] & 0xff); 237 if ((j & 0xf) == 7 && j > 0) 238 ccprintf(os, " "); 239 } 240 241 for (; j < 16; j++) 242 ccprintf(os, " "); 243 ccprintf(os, " "); 244 245 for (j = 0; j < c; j++) { 246 int ch = data[i + j] & 0x7f; 247 ccprintf(os, 248 "%c", (char)(isprint(ch) ? ch : ' ')); 249 } 250 251 ccprintf(os, "\n"); 252 253 if (c < 16) 254 break; 255 } 256} 257} // namespace Trace 258 259// 260// Returns the current output stream for debug information. As a 261// wrapper around Trace::dprintf_stream, this handles cases where debug 262// information is generated in the process of parsing .ini options, 263// before we process the option that sets up the debug output stream 264// itself. 265// 266std::ostream & 267DebugOut() 268{ 269 return *Trace::dprintf_stream; 270} 271 272///////////////////////////////////////////// 273// 274// C-linkage functions for invoking from gdb 275// 276///////////////////////////////////////////// 277 278// 279// Dump trace buffer to specified file (cout if NULL) 280// 281extern "C" 282void 283dumpTrace(const char *filename) 284{ 285 if (filename != NULL) { 286 ofstream out(filename); 287 Trace::theLog.dump(out); 288 out.close(); 289 } 290 else { 291 Trace::theLog.dump(cout); 292 } 293} 294 295 296// 297// Turn on/off trace output to cerr. Typically used when trace output 298// is only going to circular buffer, but you want to see what's being 299// sent there as you step through some code in gdb. This uses the 300// same facility as the "trace to file" feature, and will print error 301// messages rather than clobbering an existing ostream pointer. 302// 303extern "C" 304void 305echoTrace(bool on) 306{ 307 if (on) { 308 if (Trace::dprintf_stream != NULL) { 309 cerr << "Already echoing trace to a file... go do a 'tail -f'" 310 << " on that file instead." << endl; 311 } else { 312 Trace::dprintf_stream = &cerr; 313 } 314 } else { 315 if (Trace::dprintf_stream != &cerr) { 316 cerr << "Not echoing trace to cerr." << endl; 317 } else { 318 Trace::dprintf_stream = NULL; 319 } 320 } 321} 322 323extern "C" 324void 325printTraceFlags() 326{ 327 using namespace Trace; 328 for (int i = 0; i < numFlagStrings; ++i) 329 if (flags[i]) 330 cprintf("%s\n", flagStrings[i]); 331} 332 333void 334tweakTraceFlag(const char *string, bool value) 335{ 336 using namespace Trace; 337 std::string str(string); 338 339 for (int i = 0; i < numFlagStrings; ++i) { 340 if (str != flagStrings[i]) 341 continue; 342 343 int idx = i; 344 345 if (idx < NumFlags) { 346 flags[idx] = value; 347 } else { 348 idx -= NumFlags; 349 if (idx >= NumCompoundFlags) { 350 ccprintf(cerr, "Invalid compound flag"); 351 return; 352 } 353 354 const Flags *flagVec = compoundFlags[idx]; 355 356 for (int j = 0; flagVec[j] != -1; ++j) { 357 if (flagVec[j] >= NumFlags) { 358 ccprintf(cerr, "Invalid compound flag"); 359 return; 360 } 361 flags[flagVec[j]] = value; 362 } 363 } 364 365 cprintf("flag %s was %s\n", string, value ? "set" : "cleared"); 366 return; 367 } 368 369 cprintf("could not find flag %s\n", string); 370} 371 372extern "C" 373void 374setTraceFlag(const char *string) 375{ 376 tweakTraceFlag(string, true); 377} 378 379extern "C" 380void 381clearTraceFlag(const char *string) 382{ 383 tweakTraceFlag(string, false); 384} 385