1 // $Id: dynatracer.cpp,v 1.10 2011/03/07 06:08:47 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.cpp", but CVS makes that *so* difficult ...
12
13 //------------------------------------------------------------------------------------
14
15 // If using the Dynameter, must define next symbol before including "local_build.h".
16 // And set its value to start at zero in first user and increase sequentially in each later using file.
17 #define DYNAMETER_FILE_INDEX 0
18 // Must include next file before testing LAMARC_QA_DYNAMETER and before including "dynatracer.h".
19 #include "local_build.h"
20 #include "dynatracer.h"
21
22 //------------------------------------------------------------------------------------
23
24 // If LAMARC_QA_DYNAMETER is now defined, compile the rest of the file. But if not, skip to the end.
25 // This file is included in the build, but when LAMARC_QA_DYNAMETER is not defined, the rest is skipped
26 // (except for the definition of rdtsc() at the very end).
27 #ifdef LAMARC_QA_DYNAMETER
28
29 //------------------------------------------------------------------------------------
30
31 #include <iostream>
32 #include <iomanip>
33 #include "timex.h" // for GetTime()
34
35 using namespace std;
36
37 //------------------------------------------------------------------------------------
38 // Experimental overloaded definitions for new and delete.
39
40 #ifdef LAMARC_QA_MEMORYTRACE // Under construction - not running in current distribution.
41
operator new(size_t size)42 void * operator new (size_t size)
43 {
44 void * ptr = malloc(size);
45 #ifdef LAMARC_QA_MEMORYPRINT
46 printf("operator new: %lu bytes at %p\n", size, ptr);
47 #endif // LAMARC_QA_MEMORYPRINT
48 if(!ptr)
49 printf("operator new: OUT OF MEMORY\n");
50 return ptr;
51 }
52
53 //------------------------------------------------------------------------------------
54
operator new[](size_t size)55 void * operator new [] (size_t size)
56 {
57 void * ptr = malloc(size);
58 #ifdef LAMARC_QA_MEMORYPRINT
59 printf("operator new []: %lu bytes at %p\n", size, ptr);
60 #endif // LAMARC_QA_MEMORYPRINT
61 if(!ptr)
62 {
63 printf("operator new []: OUT OF MEMORY\n");
64 }
65 return ptr;
66 }
67
68 //------------------------------------------------------------------------------------
69
operator delete(void * ptr)70 void operator delete (void * ptr)
71 {
72 #ifdef LAMARC_QA_MEMORYPRINT
73 printf("operator delete: %p\n", ptr);
74 #endif // LAMARC_QA_MEMORYPRINT
75 if(ptr)
76 free(ptr);
77 else
78 printf("operator delete: NULL POINTER\n");
79 }
80
81 //------------------------------------------------------------------------------------
82
operator delete[](void * ptr)83 void operator delete [] (void * ptr)
84 {
85 #ifdef LAMARC_QA_MEMORYPRINT
86 printf("operator delete []: %p\n", ptr);
87 #endif // LAMARC_QA_MEMORYPRINT
88 if(ptr)
89 free(ptr);
90 else
91 printf("operator delete []: NULL POINTER\n");
92 }
93
94 //------------------------------------------------------------------------------------
95
operator delete(void * ptr,size_t size)96 void operator delete (void * ptr, size_t size)
97 {
98 #ifdef LAMARC_QA_MEMORYPRINT
99 printf("operator delete: %lu bytes at %p\n", size, ptr);
100 #endif // LAMARC_QA_MEMORYPRINT
101 if(ptr)
102 free(ptr);
103 else
104 printf("operator delete: NULL POINTER\n");
105 }
106
107 //------------------------------------------------------------------------------------
108
operator delete[](void * ptr,size_t size)109 void operator delete [] (void * ptr, size_t size)
110 {
111 #ifdef LAMARC_QA_MEMORYPRINT
112 printf("operator delete []: %lu bytes at %p\n", size, ptr);
113 #endif // LAMARC_QA_MEMORYPRINT
114 if(ptr)
115 free(ptr);
116 else
117 printf("operator delete []: NULL POINTER\n");
118 }
119
120 //------------------------------------------------------------------------------------
121
operator new(size_t size,char * file,unsigned int line)122 void * operator new (size_t size, char * file, unsigned int line)
123 {
124 void * ptr = malloc(size);
125 printf("operator NEW: %lu bytes at %p, File: %s, Line: %u\n", size, ptr, file, line);
126 if(!ptr)
127 printf("operator NEW: OUT OF MEMORY\n");
128 return ptr;
129 }
130
131 //------------------------------------------------------------------------------------
132
operator new[](size_t size,char * file,unsigned int line)133 void * operator new [] (size_t size, char * file, unsigned int line)
134 {
135 void * ptr = malloc(size);
136 printf("operator NEW []: %lu bytes at %p, File: %s, Line: %u\n", size, ptr, file, line);
137 if(!ptr)
138 printf("operator NEW []: OUT OF MEMORY\n");
139 return ptr;
140 }
141
142 #endif // LAMARC_QA_MEMORYTRACE - End of experimental code - not running in current distribution.
143
144 //------------------------------------------------------------------------------------
145 // Constructor and expansion of StartDynameter().
146
LocalDynameter(const char * const srcFunctionName,const char * const srcFileName,const unsigned int srcLineNumber,const unsigned int globalDynameterIdx)147 LocalDynameter::LocalDynameter(const char * const srcFunctionName, // Supplied by __PRETTY_FUNCTION__ macro
148 const char * const srcFileName, // Supplied by __FILE__ macro
149 const unsigned int srcLineNumber, // Supplied by __LINE__ macro
150 // Next argument supplied by macro expansion as: DYNACOUNTER_START + __COUNTER__ .
151 // DYNACOUNTER_START must be defined at the beginning of each file that uses it
152 // to the starting range of indices for that file to use. Then __COUNTER__ increments
153 // automatically through the range. Count the number of calls in each file so the next
154 // file to use tracing/metering can initialize its range to start with the next value
155 // (<last-in-current-file> + 1).
156 const unsigned int globalDynameterIdx)
157 :
158 m_fcnEntryTime(rdtsc()), // Clock count at initial function entry.
159 m_srcFunctionName(srcFunctionName), // Function name decorated with class and argument signature.
160 m_srcFileName(srcFileName), // Source file name.
161 #if (LAMARC_QA_DYNAMETER >= 3u)
162 m_tracePrintoutOK(true), // Controls suppression of trace printout (elision).
163 #endif // (LAMARC_QA_DYNAMETER >= 3u)
164 m_calleeRuntime(0u), // Accumulated runtime of callees.
165 m_globalDynameterPtr(NULL), // Pointer to GlobalDynameter object in GlobalDynameterArray.
166 m_srcLineNumber(srcLineNumber) // Source line number.
167 {
168 // Clocks since last clock tracing/metering sample before current call.
169 const unsigned long long int sinceLastBeforeCall = m_fcnEntryTime - s_lastClock;
170
171 if(s_currentMeterPtr)
172 {
173 // If call to this function was made from another - ie, not the top-level invocation -
174 // set my "parent Meter pointer" to that parent's LocalDynameter object and bump trace level.
175 m_parentMeterPtr = s_currentMeterPtr;
176 #if (LAMARC_QA_DYNAMETER >= 3u)
177 m_tracePrintoutOK = s_currentMeterPtr->m_tracePrintoutOK;
178 m_traceLevel = s_currentMeterPtr->m_traceLevel + 1u;
179 #endif // (LAMARC_QA_DYNAMETER >= 3u)
180 }
181 else
182 {
183 // If this is first call - ie, at toplevel - set a few variables.
184 m_parentMeterPtr = NULL;
185
186 #if (LAMARC_QA_DYNAMETER >= 3u)
187 m_traceLevel = 0u;
188 cout << "Trace Count Limit (max num calls to same function): ";
189 cin >> s_traceCountLimit;
190 cout << endl;
191 #endif // (LAMARC_QA_DYNAMETER >= 3u)
192
193 // Set slots of GlobalDynameterArray to NULL here, in case implicit initialization doesn't.
194 for(unsigned int fcn_idx = 0u; fcn_idx < DYNAMETER_ARRAYSIZE; ++fcn_idx)
195 {
196 s_GlobalDynameterArray[fcn_idx] = NULL;
197 }
198
199 // Print opening trace messages no matter the range to be traced dynamically.
200 s_traceOut.open("TracePrint.out", ios::out);
201 s_traceOut << scientific << setprecision(6);
202
203 s_traceOut << "Tracing output started: " << PrintTime(GetTime(), "%c")
204 << "\n\nDynameter Version: " << LAMARC_QA_DYNAMETER
205 << "\nCPU_TICKS_PER_SECOND: " << CPU_TICKS_PER_SECOND
206 #if (LAMARC_QA_DYNAMETER >= 3u)
207 << "\nTrace max funcall limit: " << s_traceCountLimit
208 #endif // (LAMARC_QA_DYNAMETER >= 3u)
209 << "\n\nSize of int: " << sizeof(int)
210 << "\nSize of long int: " << sizeof(long int)
211 << "\nSize of long long int: " << sizeof(long long int)
212 << "\nSize of float: " << sizeof(float)
213 << "\nSize of double: " << sizeof(double)
214 << "\nSize of long double: " << sizeof(long double)
215 << "\nSize of int pointer: " << sizeof(int *)
216 << "\nSize of void pointer: " << sizeof(void *) << "\n\n";
217 }
218
219 // And set the "global" current Meter Object pointer to ME (ie, I'M the function currently running).
220 s_currentMeterPtr = this;
221
222 DebugAssert(globalDynameterIdx < DYNAMETER_ARRAYSIZE, "GlobalDynameterArray index overflow");
223 m_globalDynameterPtr = s_GlobalDynameterArray[globalDynameterIdx];
224
225 if(m_globalDynameterPtr)
226 {
227 // If already allocated (second or later call), update these data members.
228 if(sinceLastBeforeCall > m_globalDynameterPtr->m_maxSinceLastBeforeCall)
229 m_globalDynameterPtr->m_maxSinceLastBeforeCall = sinceLastBeforeCall;
230 ++m_globalDynameterPtr->m_selfNumberOfCalls;
231 }
232 else
233 {
234 // If GlobalDynameter object has not yet been allocated and entered into GlobalDynameterArray, do so now.
235 // Note that these objects may be entered into array in non-sequential array index order,
236 // which is why we must keep track of total number as well as NULL/non-NULLness of each entry.
237 // Increment global count of GlobalDynameter objects allocated and use value as fcn's order-of-first-call.
238 m_globalDynameterPtr = new GlobalDynameter(srcFunctionName, srcFileName, ++s_GlobalDynameterCount,
239 0u, 0u, sinceLastBeforeCall);
240 s_GlobalDynameterArray[globalDynameterIdx] = m_globalDynameterPtr;
241 }
242
243 // Increment the total number of traced calls so far - used to print total count at end and
244 // (more importantly) to restrict printing of dynamic tracing/metering information to subset of all traced calls.
245 ++s_totalNumberOfCalls;
246
247 #if (LAMARC_QA_DYNAMETER >= 3u)
248 if(m_tracePrintoutOK && (m_globalDynameterPtr->m_selfNumberOfCalls <= s_traceCountLimit))
249 {
250 if(s_ellipsisCounter > 0u)
251 print_ellipsis(s_traceOut);
252
253 print_indentation(s_traceOut);
254 s_traceOut << ">> " << srcFunctionName << " in " << m_srcFileName << ", Line " << srcLineNumber << '\n';
255 print_indentation(s_traceOut);
256
257 s_traceOut << "| "
258 << (static_cast<double>(m_fcnEntryTime - s_startClock) / CPU_TICKS_PER_SECOND)
259 << " now. "
260 << (static_cast<double>(sinceLastBeforeCall) / CPU_TICKS_PER_SECOND)
261 << " before. "
262 << m_globalDynameterPtr->m_selfNumberOfCalls
263 << " self, "
264 << s_totalNumberOfCalls
265 << " total.\n";
266
267 print_indentation(s_traceOut);
268 s_traceOut << "|\n";
269 }
270 else
271 {
272 ++s_ellipsisCounter;
273 ++s_printoutsElided;
274 m_tracePrintoutOK = false;
275 }
276 #endif // (LAMARC_QA_DYNAMETER >= 3u)
277
278 s_lastClock = m_fcnEntryTime;
279 if(sinceLastBeforeCall > s_maxSinceLastBeforeCall)
280 s_maxSinceLastBeforeCall = sinceLastBeforeCall;
281 }
282
283 //------------------------------------------------------------------------------------
284 // Destructor. Automatically provides functionality of trace-printing on leaving function.
285
~LocalDynameter()286 LocalDynameter::~LocalDynameter()
287 {
288 // Set on each call (ie, updated to current time).
289 const unsigned long long int nowClock = rdtsc();
290 const unsigned long long int myTotalRuntime = nowClock - m_fcnEntryTime;
291 const unsigned long long int mySelfRuntime = myTotalRuntime - m_calleeRuntime;
292
293 #if (LAMARC_QA_DYNAMETER >= 3u)
294 if(m_tracePrintoutOK && (m_globalDynameterPtr->m_selfNumberOfCalls <= s_traceCountLimit))
295 {
296 if(s_ellipsisCounter > 0u)
297 {
298 // Trace printout elided last before this call probably was indented one level deeper.
299 ++m_traceLevel;
300 print_ellipsis(s_traceOut);
301 --m_traceLevel;
302 }
303
304 print_indentation(s_traceOut);
305 // Member variables used since all values printed here must be stored; destructor takes no arguments.
306 s_traceOut << "<< " << m_srcFunctionName << " in " << m_srcFileName << ", Line " << m_srcLineNumber << '\n';
307 print_indentation(s_traceOut);
308
309 s_traceOut << " "
310 << (static_cast<double>(nowClock - s_startClock) / CPU_TICKS_PER_SECOND)
311 << " now. "
312 << (static_cast<double>(nowClock - s_lastClock) / CPU_TICKS_PER_SECOND)
313 << " before. "
314 << (static_cast<double>(m_calleeRuntime) / CPU_TICKS_PER_SECOND)
315 << " callees. "
316 << (static_cast<double>(mySelfRuntime) / CPU_TICKS_PER_SECOND)
317 << " self. "
318 << (static_cast<double>(myTotalRuntime) / CPU_TICKS_PER_SECOND)
319 << " total. "
320 << m_globalDynameterPtr->m_selfNumberOfCalls
321 << " self, "
322 << s_totalNumberOfCalls
323 << " total.\n";
324
325 print_indentation(s_traceOut);
326 s_traceOut << '\n';
327 }
328 else
329 {
330 ++s_ellipsisCounter;
331 ++s_printoutsElided;
332 }
333 #endif // (LAMARC_QA_DYNAMETER >= 3u)
334
335 s_lastClock = nowClock;
336
337 // Insert the information accumulated in this dynamic object into the permanent structure holding global data.
338 // The GlobalDynameter object is assumed to exist (m_globalDynameterPtr is non-NULL) because otherwise 'new' would
339 // have thrown a 'bad_alloc' exception.
340 m_globalDynameterPtr->m_calleeRuntime += m_calleeRuntime;
341 m_globalDynameterPtr->m_selfRuntime += mySelfRuntime;
342
343 // Pop the metering tool stack: set current object pointer to my parent.
344 s_currentMeterPtr = m_parentMeterPtr;
345
346 if(m_parentMeterPtr)
347 {
348 // If parent is non-NULL, increment his kid's runtime by my own.
349 m_parentMeterPtr->m_calleeRuntime += myTotalRuntime;
350 }
351 else
352 {
353 // If we've popped back to top-level, ie, the toplevel destructor, write trailer and close file.
354 // Print closing trace messages no matter the range to be traced dynamically.
355 // First write the summary data stored in the GlobalDynameterArray objects.
356 s_traceOut << "\nTrace information on "
357 << s_GlobalDynameterCount
358 << " functions traced of "
359 << DYNAMETER_ARRAYSIZE
360 << " function slots available.\n";
361
362 // "Squish" all populated entries down to contiguous set at "low" end of array.
363 // All functions will have slots reserved at compile time for themselves, but
364 // functions not called during this run will contain empty slots in this array.
365 unsigned int target = 0u, source = 0u;
366 while(source < DYNAMETER_ARRAYSIZE)
367 {
368 if(s_GlobalDynameterArray[source]) // Source populated.
369 {
370 if(s_GlobalDynameterArray[target]) // Source populated; Target populated.
371 {
372 if(source == target) // If tracking same slot, bump both indices.
373 ++source; // Otherwise bump only target.
374 ++target;
375 }
376 else // Source populated; Target empty.
377 {
378 s_GlobalDynameterArray[target] = s_GlobalDynameterArray[source]; // Swap source into target.
379 s_GlobalDynameterArray[source] = NULL; // "Swap" means "clear source slot".
380 ++target; // This pair now OK; bump both indices.
381 ++source;
382 }
383 }
384 else // Source empty; target may be empty or populated.
385 {
386 ++source; // Bump only source (look for populated slot).
387 }
388 DebugAssert(target <= source, "Bug in GlobalDynameterArray squisher");
389 }
390 DebugAssert((source == DYNAMETER_ARRAYSIZE) && (target == s_GlobalDynameterCount),
391 "Bug in GlobalDynameterArray compactor");
392
393 TablePrinter("Traced functions unordered:",
394 "FcnsUnsorted.txt");
395
396 sort(s_GlobalDynameterArray, s_GlobalDynameterArray + s_GlobalDynameterCount, NumSelfCalls);
397 TablePrinter("Traced functions ordered by number of calls:",
398 "FcnsNumCalls.txt");
399
400 sort(s_GlobalDynameterArray, s_GlobalDynameterArray + s_GlobalDynameterCount, MaxSinceLastBefore);
401 TablePrinter("Traced functions ordered by max time since last before call:",
402 "FcnsMaxTimeBefore.txt");
403
404 sort(s_GlobalDynameterArray, s_GlobalDynameterArray + s_GlobalDynameterCount, CalleeRuntimePerCall);
405 TablePrinter("Traced functions ordered by callee runtime per call:",
406 "FcnsCalleeTimePerCall.txt");
407
408 sort(s_GlobalDynameterArray, s_GlobalDynameterArray + s_GlobalDynameterCount, CalleeRuntimeAggregate);
409 TablePrinter("Traced functions ordered by callee runtime, aggregate:",
410 "FcnsCalleeTimeAggregate.txt");
411
412 sort(s_GlobalDynameterArray, s_GlobalDynameterArray + s_GlobalDynameterCount, SelfRuntimePerCall);
413 TablePrinter("Traced functions ordered by self runtime (excluding callees) per call:",
414 "FcnsSelfTimePerCall.txt");
415
416 sort(s_GlobalDynameterArray, s_GlobalDynameterArray + s_GlobalDynameterCount, SelfRuntimeAggregate);
417 TablePrinter("Traced functions ordered by self runtime (excluding callees), aggregate:",
418 "FcnsSelfTimeAggregate.txt");
419
420 sort(s_GlobalDynameterArray, s_GlobalDynameterArray + s_GlobalDynameterCount, TotalRuntimePerCall);
421 TablePrinter("Traced functions ordered by total runtime (self plus callees) per call:",
422 "FcnsTotalTimePerCall.txt");
423
424 sort(s_GlobalDynameterArray, s_GlobalDynameterArray + s_GlobalDynameterCount, TotalRuntimeAggregate);
425 TablePrinter("Traced functions ordered by total runtime (self plus callees), aggregate:",
426 "FcnsTotalTimeAggregate.txt");
427
428 s_traceOut << "\nTracing output done: " << PrintTime(GetTime(), "%c")
429 << "\nTotal number of calls: " << s_totalNumberOfCalls
430 #if (LAMARC_QA_DYNAMETER >= 3u)
431 << "\nTrace max funcall limit: " << s_traceCountLimit
432 << "\nTrace print calls elided: " << s_printoutsElided
433 #endif // (LAMARC_QA_DYNAMETER >= 3u)
434 << "\n\nDynameter Version: " << LAMARC_QA_DYNAMETER
435 << "\nCPU_TICKS_PER_SECOND: " << CPU_TICKS_PER_SECOND
436 << "\n\nSize of int: " << sizeof(int)
437 << "\nSize of long int: " << sizeof(long int)
438 << "\nSize of long long int: " << sizeof(long long int)
439 << "\nSize of float: " << sizeof(float)
440 << "\nSize of double: " << sizeof(double)
441 << "\nSize of long double: " << sizeof(long double)
442 << "\nSize of int pointer: " << sizeof(int *)
443 << "\nSize of void pointer: " << sizeof(void *)
444 << "\n\nMax since last trace: "
445 << (static_cast<double>(LocalDynameter::s_maxSinceLastBeforeCall) / CPU_TICKS_PER_SECOND)
446 << " sec (over all function calls).\n";
447
448 s_traceOut.close();
449 }
450 }
451
452 //------------------------------------------------------------------------------------
453 // Private utility member function.
454
455 #if (LAMARC_QA_DYNAMETER >= 3u)
456
print_indentation(ofstream & stream)457 void LocalDynameter::print_indentation(ofstream & stream)
458 {
459 stream << ' ';
460 for(unsigned int trace_idx = 0u; trace_idx < m_traceLevel; ++trace_idx)
461 stream << "| ";
462 }
463
464 #endif // (LAMARC_QA_DYNAMETER >= 3u)
465
466 //------------------------------------------------------------------------------------
467 // Private utility member function.
468
469 #if (LAMARC_QA_DYNAMETER >= 3u)
470
print_ellipsis(ofstream & stream)471 void LocalDynameter::print_ellipsis(ofstream & stream)
472 {
473 print_indentation(stream);
474 stream << "... " << s_ellipsisCounter << " trace printouts elided.\n";
475 print_indentation(stream);
476 stream << '\n';
477 s_ellipsisCounter = 0u;
478 }
479
480 #endif // (LAMARC_QA_DYNAMETER >= 3u)
481
482 //------------------------------------------------------------------------------------
483 // Private utility member function.
484
TablePrinter(const string heading,const string filename)485 void LocalDynameter::TablePrinter(const string heading, const string filename)
486 {
487 ofstream os;
488 os.open(filename.c_str(), ios::out);
489 os << scientific << setprecision(6);
490 os << heading << '\n';
491
492 for(unsigned int fcn_idx = 0u; fcn_idx < s_GlobalDynameterCount; ++fcn_idx)
493 {
494 GlobalDynameter * pGlobalDynameter = s_GlobalDynameterArray[fcn_idx];
495 DebugAssert(pGlobalDynameter, "Bug in GlobalDynameterArray display");
496
497 const unsigned long long int selfNumCalls = pGlobalDynameter->m_selfNumberOfCalls;
498 const unsigned long long int calleeRuntime = pGlobalDynameter->m_calleeRuntime;
499 const unsigned long long int selfRuntime = pGlobalDynameter->m_selfRuntime;
500 const unsigned long long int maxSinceLastBeforeCall = pGlobalDynameter->m_maxSinceLastBeforeCall;
501
502 os << '\n' << fcn_idx
503 << ":\t" << pGlobalDynameter->m_srcFunctionName
504 << " in file " << pGlobalDynameter->m_srcFileName
505 << "\n\t" << selfNumCalls << " calls (order "
506 << pGlobalDynameter->m_ordinalCount << ") "
507 << (static_cast<double>(maxSinceLastBeforeCall) / CPU_TICKS_PER_SECOND)
508 << " before. "
509 << (static_cast<double>(calleeRuntime / selfNumCalls) / CPU_TICKS_PER_SECOND)
510 << '/'
511 << (static_cast<double>(calleeRuntime) / CPU_TICKS_PER_SECOND)
512 << " callees. "
513 << (static_cast<double>(selfRuntime / selfNumCalls) / CPU_TICKS_PER_SECOND)
514 << '/'
515 << (static_cast<double>(selfRuntime) / CPU_TICKS_PER_SECOND)
516 << " self. "
517 << (static_cast<double>((selfRuntime + calleeRuntime) / selfNumCalls) / CPU_TICKS_PER_SECOND)
518 << '/'
519 << (static_cast<double>(selfRuntime + calleeRuntime) / CPU_TICKS_PER_SECOND)
520 << " total.\n";
521 }
522
523 os.close();
524 }
525
526 //------------------------------------------------------------------------------------
527 // Constructor for GlobalDynameter called by LocalDynameter constructor to store per-function results.
528
GlobalDynameter(const char * const srcFunctionName,const char * const srcFileName,const unsigned int ordinalCount,const unsigned long long int calleeRuntime,const unsigned long long int selfRuntime,const unsigned long long int maxSinceLastBeforeCall)529 GlobalDynameter::GlobalDynameter(const char * const srcFunctionName,
530 const char * const srcFileName,
531 const unsigned int ordinalCount,
532 const unsigned long long int calleeRuntime,
533 const unsigned long long int selfRuntime,
534 const unsigned long long int maxSinceLastBeforeCall)
535 :
536 m_srcFunctionName(srcFunctionName), // Function name decorated with class and argument signature.
537 m_srcFileName(srcFileName), // Source file name.
538 m_ordinalCount(ordinalCount), // Ordinal count of this function's call of all traced.
539 m_calleeRuntime(calleeRuntime), // Accumulated runtime of callees.
540 m_selfRuntime(selfRuntime), // Accumulated runtime of this function (not including callees).
541 m_maxSinceLastBeforeCall(maxSinceLastBeforeCall), // Max time since last timing measurement (CPU cycles).
542 m_selfNumberOfCalls(1u) // Count of number of times this function called.
543 { }
544
545 //------------------------------------------------------------------------------------
546 // Sorts by number of self calls (decreasing order).
547
NumSelfCalls(const GlobalDynameter * const x_ptr,const GlobalDynameter * const y_ptr)548 bool NumSelfCalls(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr)
549 {
550 return x_ptr->m_selfNumberOfCalls > y_ptr->m_selfNumberOfCalls;
551 }
552
553 //------------------------------------------------------------------------------------
554 // Sorts by max time since last trace probe before current call (decreasing order).
555
MaxSinceLastBefore(const GlobalDynameter * const x_ptr,const GlobalDynameter * const y_ptr)556 bool MaxSinceLastBefore(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr)
557 {
558 return x_ptr->m_maxSinceLastBeforeCall > y_ptr->m_maxSinceLastBeforeCall;
559 }
560
561 //------------------------------------------------------------------------------------
562 // Sorts by callee runtime per call (total over all callees) (decreasing order).
563
CalleeRuntimePerCall(const GlobalDynameter * const x_ptr,const GlobalDynameter * const y_ptr)564 bool CalleeRuntimePerCall(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr)
565 {
566 return (x_ptr->m_calleeRuntime / x_ptr->m_selfNumberOfCalls)
567 > (y_ptr->m_calleeRuntime / y_ptr->m_selfNumberOfCalls);
568 }
569
570 //------------------------------------------------------------------------------------
571 // Sorts by callee runtime aggregate (summed over all calls) (decreasing order).
572
CalleeRuntimeAggregate(const GlobalDynameter * const x_ptr,const GlobalDynameter * const y_ptr)573 bool CalleeRuntimeAggregate(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr)
574 {
575 return x_ptr->m_calleeRuntime > y_ptr->m_calleeRuntime;
576 }
577
578 //------------------------------------------------------------------------------------
579 // Sorts by self runtime per call (excluding all callees) (decreasing order).
580
SelfRuntimePerCall(const GlobalDynameter * const x_ptr,const GlobalDynameter * const y_ptr)581 bool SelfRuntimePerCall(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr)
582 {
583 return (x_ptr->m_selfRuntime / x_ptr->m_selfNumberOfCalls) > (y_ptr->m_selfRuntime / y_ptr->m_selfNumberOfCalls);
584 }
585
586 //------------------------------------------------------------------------------------
587 // Sorts by self runtime aggregate (excluding callees, summed over all calls) (decreasing order).
588
SelfRuntimeAggregate(const GlobalDynameter * const x_ptr,const GlobalDynameter * const y_ptr)589 bool SelfRuntimeAggregate(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr)
590 {
591 return x_ptr->m_selfRuntime > y_ptr->m_selfRuntime;
592 }
593
594 //------------------------------------------------------------------------------------
595 // Sorts by total runtime per call (sum of self plus callee runtime) (decreasing order).
596
TotalRuntimePerCall(const GlobalDynameter * const x_ptr,const GlobalDynameter * const y_ptr)597 bool TotalRuntimePerCall(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr)
598 {
599 return
600 ((x_ptr->m_selfRuntime + x_ptr->m_calleeRuntime) / x_ptr->m_selfNumberOfCalls)
601 >
602 ((y_ptr->m_selfRuntime + y_ptr->m_calleeRuntime) / y_ptr->m_selfNumberOfCalls);
603 }
604
605 //------------------------------------------------------------------------------------
606 // Sorts by total runtime aggregate (self plus callee, summed over all calls) (decreasing order).
607
TotalRuntimeAggregate(const GlobalDynameter * const x_ptr,const GlobalDynameter * const y_ptr)608 bool TotalRuntimeAggregate(const GlobalDynameter * const x_ptr, const GlobalDynameter * const y_ptr)
609 {
610 return (x_ptr->m_selfRuntime + x_ptr->m_calleeRuntime) > (y_ptr->m_selfRuntime + y_ptr->m_calleeRuntime);
611 }
612
613 //------------------------------------------------------------------------------------
614
615 #endif // LAMARC_QA_DYNAMETER
616
617 //------------------------------------------------------------------------------------
618 // CPU cycle counter used by tracing/metering and other timing functions.
619
620 #if defined(LAMARC_QA_DYNAMETER) || defined(LAMARC_QA_TIMINGTEST)
621
rdtsc()622 unsigned long long int rdtsc()
623 {
624 unsigned int a, d;
625 __asm__ volatile("rdtsc" : "=a" (a), "=d" (d));
626 return (static_cast<unsigned long long int>(a)) | ((static_cast<unsigned long long int>(d)) << 32);
627 }
628
629 #endif // defined(LAMARC_QA_DYNAMETER) || defined(LAMARC_QA_TIMINGTEST)
630
631 //____________________________________________________________________________________
632