1 // $Id: dynatracer.h,v 1.10 2011/07/09 22:30:19 bobgian Exp $ 2 3 /* 4 * Copyright 2009-2010 Bob Giansiracusa, Mary Kuhner, Jon Yamato, and Joseph Felsenstein 5 * 6 * This software is distributed free of charge for non-commercial use 7 * and is copyrighted. Of course, we do not guarantee that the software 8 * works, and are not responsible for any damage you may cause or have. 9 */ 10 11 // The name of this file should be changed to "dynameter.h", but CVS makes that *so* difficult ... 12 #ifndef DYNATRACER_H 13 #define DYNATRACER_H 14 15 //------------------------------------------------------------------------------------ 16 // Must include this file first, before testing LAMARC_QA_DYNAMETER for definedness, 17 // because this is the file which defines that symbol! 18 19 #include "local_build.h" 20 21 //------------------------------------------------------------------------------------ 22 23 #ifdef LAMARC_QA_DYNAMETER 24 #include <fstream> // Required to define std::ofstream. 25 #include "dynacount.h" // Required to define DYNAMETER_ARRAYSIZE. 26 27 //------------------------------------------------------------------------------------ 28 29 // Used in experimental code - not used in current distribution. 30 // #define LAMARC_QA_MEMORYTRACE 31 // #define LAMARC_QA_MEMORYPRINT 32 33 //------------------------------------------------------------------------------------ 34 // Definition of experimental class for testing overloading of new and delete. 35 36 #ifdef LAMARC_QA_MEMORYTRACE // Under construction - not running in current distribution. 37 38 class S 39 { 40 private: 41 int i[100]; 42 public: S()43 S() { puts("S::S()"); } ~S()44 ~S() { puts("S::~S()"); } 45 }; 46 47 #endif // LAMARC_QA_MEMORYTRACE - End of experimental code - not running in current distribution. 48 49 //------------------------------------------------------------------------------------ 50 // Experimental test of overloading global and class new. 51 52 #ifdef LAMARC_QA_MEMORYTRACE // Under construction - not running in current distribution. 53 54 #define NEW new(__FILE__, __LINE__) 55 #define DELETE printf("delete: %s at %u\n", __FILE__, __LINE__) ; delete 56 57 extern void * operator new (size_t size, char * file, unsigned int line); 58 extern void * operator new [] (size_t size, char * file, unsigned int line); 59 60 #endif // LAMARC_QA_MEMORYTRACE - End of experimental code - not running in current distribution. 61 62 //------------------------------------------------------------------------------------ 63 // Experimental test of overloading global and class delete. 64 65 #ifdef LAMARC_QA_MEMORYTRACE // Under construction - not running in current distribution. 66 67 extern void operator delete (void * ptr); 68 extern void operator delete [] (void * ptr); 69 70 extern void operator delete (void * ptr, size_t size); 71 extern void operator delete [] (void * ptr, size_t size); 72 73 #endif // LAMARC_QA_MEMORYTRACE - End of experimental code - not running in current distribution. 74 75 //------------------------------------------------------------------------------------ 76 // Class which defines accumulation of non-dynamic tracing/metering information (total calls/timing, etc). 77 78 class GlobalDynameter 79 { 80 friend class LocalDynameter; 81 82 // Utility sorting functions. 83 friend bool NumSelfCalls(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 84 friend bool MaxSinceLastBefore(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 85 friend bool CalleeRuntimePerCall(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 86 friend bool CalleeRuntimeAggregate(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 87 friend bool SelfRuntimePerCall(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 88 friend bool SelfRuntimeAggregate(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 89 friend bool TotalRuntimePerCall(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 90 friend bool TotalRuntimeAggregate(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 91 92 private: 93 const char * const m_srcFunctionName; // Function name decorated with class and argument signature. 94 const char * const m_srcFileName; // Source file name. 95 const unsigned int m_ordinalCount; // This function's order of first call (relative to all others). 96 unsigned long long int m_calleeRuntime; // Accum runtime of functions called by this one (callees). 97 unsigned long long int m_selfRuntime; // Accum runtime of this function (not including callees). 98 unsigned long long int m_maxSinceLastBeforeCall; // Max ticks since last metering tool access before current call. 99 unsigned long long int m_selfNumberOfCalls; // Num traced calls to this function (not necessarily printed). 100 101 // Constructor for GlobalDynameter called by LocalDynameter constructor to store per-function results. 102 GlobalDynameter(const char * const srcFunctionName, 103 const char * const srcFileName, 104 const unsigned int ordinalCount, 105 const unsigned long long int calleeRuntime, 106 const unsigned long long int selfRuntime, 107 const unsigned long long int maxSinceLastBeforeCall); 108 109 // Default constructor - should never get called. 110 GlobalDynameter(); 111 112 }; // class GlobalDynameter 113 114 //------------------------------------------------------------------------------------ 115 // Class which defines dynamic tracing/metering activity (per-call information, dynamic call chain, etc). 116 117 class LocalDynameter 118 { 119 private: 120 const unsigned long long int m_fcnEntryTime; // Clock count at initial function entry. 121 const char * const m_srcFunctionName; // Function name decorated with class and argument signature. 122 const char * const m_srcFileName; // Source file name. 123 #if (LAMARC_QA_DYNAMETER >= 3u) 124 bool m_tracePrintoutOK; // Flag indicating state of trace printout suppression. 125 unsigned int m_traceLevel; // "Local" value (per class object - ie, at given fcn level). 126 #endif // (LAMARC_QA_DYNAMETER >= 3u) 127 unsigned long long int m_calleeRuntime; // Accumulated runtime of functions called by this one (callees). 128 GlobalDynameter * m_globalDynameterPtr; // Pointer to GlobalDynameter object in GlobalDynameterArray. 129 LocalDynameter * m_parentMeterPtr; // Pointer to my parent (or NULL). 130 unsigned int m_srcLineNumber; // Source line number where constructor called. 131 132 // "Global" pointer to LocalDynameter object of function currently on top of run-time stack. 133 static LocalDynameter * s_currentMeterPtr; 134 135 // Accumulates max time from previous trace recording to current call, over all calls to all functions. 136 static unsigned long long int s_maxSinceLastBeforeCall; 137 138 // Total number of function calls traced so far (all functions). 139 static unsigned long long int s_totalNumberOfCalls; 140 141 static std::ofstream s_traceOut; // File stream for tracing/metering output. 142 143 // Array of pointers to GlobalDynameter objects holding trace data. 144 static GlobalDynameter * s_GlobalDynameterArray[DYNAMETER_ARRAYSIZE]; 145 146 // Number of GlobalDynameter objects populating above array - ie, number of functions traced so far this run. 147 // This is used as an ordinal count for GlobalDynameter objects (gives order of each function's first call). 148 static unsigned int s_GlobalDynameterCount; 149 150 #if (LAMARC_QA_DYNAMETER >= 3u) 151 152 // User-settable limit to depth of tracing based on number of calls to same function. 153 static unsigned int s_traceCountLimit; 154 155 // Flag/counter to control whether (and how) ellipsis indication is printed when dynamic tracing is suppressed. 156 static unsigned int s_ellipsisCounter; 157 158 // Count of total number of elided tracing printouts. 159 static unsigned int s_printoutsElided; 160 161 // Utility function. Prints marks indicating level of function-call nesting. 162 void print_indentation(std::ofstream & stream); 163 164 // Utility function. Prints message indicating number of elided tracing printouts. 165 void print_ellipsis(std::ofstream & stream); 166 167 #endif // (LAMARC_QA_DYNAMETER >= 3u) 168 169 // Utility function. Prints summary statistics on all traced functions. 170 void TablePrinter(const std::string heading, const std::string filename); 171 172 public: 173 // Set at first call and used as zero-point of elapsed time for run. 174 static unsigned long long int s_startClock; 175 176 // Set at first call and updated at end of each call, irrespective of trace level at call. 177 static unsigned long long int s_lastClock; 178 179 // Constructor/Printer. 180 // Note: If macro __PRETTY_FUNCTION__ (which includes signature and class name in string) is unavailable, 181 // use more generally available macro __FUNCTION__ instead (no signature or class name in string). 182 LocalDynameter(const char * const srcFunctionName, // Supplied by __PRETTY_FUNCTION__ macro 183 const char * const srcFileName, // Supplied by __FILE__ macro 184 const unsigned int srcLineNumber, // Supplied by __LINE__ macro 185 const unsigned int globalDynameterIdx); // Supplied by DYNACOUNTER_START + __COUNTER__ 186 187 // Destructor/Printer. 188 ~LocalDynameter(); 189 190 }; // class LocalDynameter 191 192 //------------------------------------------------------------------------------------ 193 // Utility functions for sorting. 194 // All comparison functions yield sorts in decreasing (non-increasing) order. 195 196 // Utility function. Sorts by number of self calls. 197 extern bool NumSelfCalls(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 198 199 // Utility function. Sorts by max time since last trace probe before current call. 200 extern bool MaxSinceLastBefore(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 201 202 // Utility function. Sorts by callee runtime per call (total over all callees). 203 extern bool CalleeRuntimePerCall(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 204 205 // Utility function. Sorts by callee runtime aggregate (summed over all calls). 206 extern bool CalleeRuntimeAggregate(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 207 208 // Utility function. Sorts by self runtime per call (excluding all callees). 209 extern bool SelfRuntimePerCall(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 210 211 // Utility function. Sorts by self runtime aggregate (excluding callees, summed over all calls). 212 extern bool SelfRuntimeAggregate(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 213 214 // Utility function. Sorts by total runtime per call (sum of self plus callee runtime). 215 extern bool TotalRuntimePerCall(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 216 217 // Utility function. Sorts by total runtime aggregate (sum of self plus callee, summed over all calls). 218 extern bool TotalRuntimeAggregate(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr); 219 220 //------------------------------------------------------------------------------------ 221 222 #endif // LAMARC_QA_DYNAMETER 223 224 //------------------------------------------------------------------------------------ 225 // External function declarations. 226 227 #if defined(LAMARC_QA_DYNAMETER) || defined(LAMARC_QA_TIMINGTEST) 228 229 // Timer utility function (CPU cycle counter). 230 // This function is used by the Dynameter constructors (in expansion of the StartDynameter() macro) 231 // and corresponding destructors. It is also called in a few other places to "reset" the tracing/metering 232 // clock (ie, after human interaction finishes). 233 // 234 // It is also used for timing in versions LAMARC in which the Dynameter subsystem is not present 235 // (ie, LAMARC_QA_DYNAMETER is not defined); hence the OR in the "#if defined" above to allow its 236 // definition if LAMARC_QA_TIMINGTEST is defined. 237 // 238 extern unsigned long long int rdtsc(); 239 240 #endif // defined(LAMARC_QA_DYNAMETER) || defined(LAMARC_QA_TIMINGTEST) 241 242 //------------------------------------------------------------------------------------ 243 // Macros which invoke tracing/metering functionality. 244 // 245 // Note: If predefined macro __PRETTY_FUNCTION__ (which includes signature and class name in string) is unavailable, 246 // use predefined (and more generally available) macro __FUNCTION__ instead (no signature or class name in string). 247 // 248 // Note that they expand into other than ordinary function calls (ie, declarations) if LAMARC_QA_DYNAMETER 249 // is defined, which is why inline function definitions are insufficient. If LAMARC_QA_DYNAMETER is NOT 250 // defined, they expand into whitespace (and therefore are invisible in non-tracing/metering-mode compilations). 251 252 #ifdef LAMARC_QA_DYNAMETER 253 254 #define StartDynameter() \ 255 LocalDynameter traceObj(__PRETTY_FUNCTION__, \ 256 __FILE__, \ 257 __LINE__, \ 258 DYNACOUNTER_START + __COUNTER__) 259 260 #else // LAMARC_QA_DYNAMETER 261 262 #define StartDynameter() 263 264 #endif // LAMARC_QA_DYNAMETER 265 266 //------------------------------------------------------------------------------------ 267 // Simulation of ASSERT macro, except that it runs whether in debug mode or not. 268 // These macros are present whether LAMARC_QA_DYNAMETER is defined or not; hence, 269 // they are available for general debugging (not just when using the metering tool). 270 271 #define DebugAssert(condition, message) \ 272 if(!(condition)) \ 273 { \ 274 std::cerr << std::endl \ 275 << "DebugAssert " << message << ": " << #condition \ 276 << std::endl \ 277 << "Function: " << __PRETTY_FUNCTION__ \ 278 << std::endl \ 279 << "Filename: " << __FILE__ << " (line " << __LINE__ << ")" \ 280 << std::endl << std::endl \ 281 << "Compiled on " << __DATE__ << " at " << __TIME__ \ 282 << std::endl; \ 283 exit(1); \ 284 } 285 286 //------------------------------------------------------------------------------------ 287 // Simulation of ASSERT macro, except that it runs whether in debug mode or not. 288 // Like DebugAssert except that it logs information about where it was called from tracing/metering macro. 289 // srcLineNumber of ZERO means line number could not be ascertained. 290 // Caller function name (srcFuncName) can be either Short (__FUNCTION__) or Fancy version (__PRETTY_FUNCTION__). 291 292 #define TraceAssert(condition, message, srcFuncName, srcFileName, srcLineNumber) \ 293 if(!(condition)) \ 294 { \ 295 std::cerr << std::endl \ 296 << "TraceAssert " << message << ": " << #condition \ 297 << std::endl \ 298 << "Main function: " << __PRETTY_FUNCTION__ \ 299 << std::endl \ 300 << "Main filename: " << __FILE__ << " (line " << __LINE__ << ")" \ 301 << std::endl << std::endl \ 302 << "Caller function: " << srcFuncName \ 303 << std::endl \ 304 << "Caller filename: " << srcFileName << " (line " << srcLineNumber << ")" \ 305 << std::endl << std::endl \ 306 << "Compiled on " << __DATE__ << " at " << __TIME__ \ 307 << std::endl; \ 308 exit(1); \ 309 } 310 311 //------------------------------------------------------------------------------------ 312 313 #endif // DYNATRACER_H 314 315 //____________________________________________________________________________________ 316