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