xref: /freebsd-src/contrib/llvm-project/openmp/runtime/src/kmp_stats.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
10b57cec5SDimitry Andric /** @file kmp_stats.cpp
20b57cec5SDimitry Andric  * Statistics gathering and processing.
30b57cec5SDimitry Andric  */
40b57cec5SDimitry Andric 
50b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
80b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
90b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "kmp.h"
140b57cec5SDimitry Andric #include "kmp_lock.h"
150b57cec5SDimitry Andric #include "kmp_stats.h"
160b57cec5SDimitry Andric #include "kmp_str.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include <algorithm>
190b57cec5SDimitry Andric #include <ctime>
200b57cec5SDimitry Andric #include <iomanip>
210b57cec5SDimitry Andric #include <sstream>
220b57cec5SDimitry Andric #include <stdlib.h> // for atexit
230b57cec5SDimitry Andric #include <cmath>
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric #define STRINGIZE2(x) #x
260b57cec5SDimitry Andric #define STRINGIZE(x) STRINGIZE2(x)
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #define expandName(name, flags, ignore) {STRINGIZE(name), flags},
290b57cec5SDimitry Andric statInfo timeStat::timerInfo[] = {
300b57cec5SDimitry Andric     KMP_FOREACH_TIMER(expandName, 0){"TIMER_LAST", 0}};
310b57cec5SDimitry Andric const statInfo counter::counterInfo[] = {
320b57cec5SDimitry Andric     KMP_FOREACH_COUNTER(expandName, 0){"COUNTER_LAST", 0}};
330b57cec5SDimitry Andric #undef expandName
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric #define expandName(ignore1, ignore2, ignore3) {0.0, 0.0, 0.0},
360b57cec5SDimitry Andric kmp_stats_output_module::rgb_color kmp_stats_output_module::timerColorInfo[] = {
370b57cec5SDimitry Andric     KMP_FOREACH_TIMER(expandName, 0){0.0, 0.0, 0.0}};
380b57cec5SDimitry Andric #undef expandName
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric const kmp_stats_output_module::rgb_color
410b57cec5SDimitry Andric     kmp_stats_output_module::globalColorArray[] = {
420b57cec5SDimitry Andric         {1.0, 0.0, 0.0}, // red
430b57cec5SDimitry Andric         {1.0, 0.6, 0.0}, // orange
440b57cec5SDimitry Andric         {1.0, 1.0, 0.0}, // yellow
450b57cec5SDimitry Andric         {0.0, 1.0, 0.0}, // green
460b57cec5SDimitry Andric         {0.0, 0.0, 1.0}, // blue
470b57cec5SDimitry Andric         {0.6, 0.2, 0.8}, // purple
480b57cec5SDimitry Andric         {1.0, 0.0, 1.0}, // magenta
490b57cec5SDimitry Andric         {0.0, 0.4, 0.2}, // dark green
500b57cec5SDimitry Andric         {1.0, 1.0, 0.6}, // light yellow
510b57cec5SDimitry Andric         {0.6, 0.4, 0.6}, // dirty purple
520b57cec5SDimitry Andric         {0.0, 1.0, 1.0}, // cyan
530b57cec5SDimitry Andric         {1.0, 0.4, 0.8}, // pink
540b57cec5SDimitry Andric         {0.5, 0.5, 0.5}, // grey
550b57cec5SDimitry Andric         {0.8, 0.7, 0.5}, // brown
560b57cec5SDimitry Andric         {0.6, 0.6, 1.0}, // light blue
570b57cec5SDimitry Andric         {1.0, 0.7, 0.5}, // peach
580b57cec5SDimitry Andric         {0.8, 0.5, 1.0}, // lavender
590b57cec5SDimitry Andric         {0.6, 0.0, 0.0}, // dark red
600b57cec5SDimitry Andric         {0.7, 0.6, 0.0}, // gold
610b57cec5SDimitry Andric         {0.0, 0.0, 0.0} // black
620b57cec5SDimitry Andric };
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric // Ensure that the atexit handler only runs once.
650b57cec5SDimitry Andric static uint32_t statsPrinted = 0;
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric // output interface
680b57cec5SDimitry Andric static kmp_stats_output_module *__kmp_stats_global_output = NULL;
690b57cec5SDimitry Andric 
70e8d8bef9SDimitry Andric double logHistogram::binMax[] = {1.e1l, 1.e2l, 1.e3l, 1.e4l, 1.e5l, 1.e6l,
71e8d8bef9SDimitry Andric                                  1.e7l, 1.e8l, 1.e9l, 1.e10l, 1.e11l, 1.e12l,
72e8d8bef9SDimitry Andric                                  1.e13l, 1.e14l, 1.e15l, 1.e16l, 1.e17l, 1.e18l,
73e8d8bef9SDimitry Andric                                  1.e19l, 1.e20l, 1.e21l, 1.e22l, 1.e23l, 1.e24l,
74e8d8bef9SDimitry Andric                                  1.e25l, 1.e26l, 1.e27l, 1.e28l, 1.e29l, 1.e30l,
75e8d8bef9SDimitry Andric                                  // Always have infinity be the last value
76e8d8bef9SDimitry Andric                                  std::numeric_limits<double>::infinity()};
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric /* ************* statistic member functions ************* */
790b57cec5SDimitry Andric 
addSample(double sample)800b57cec5SDimitry Andric void statistic::addSample(double sample) {
810b57cec5SDimitry Andric   sample -= offset;
820b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(std::isfinite(sample));
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   double delta = sample - meanVal;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   sampleCount = sampleCount + 1;
870b57cec5SDimitry Andric   meanVal = meanVal + delta / sampleCount;
880b57cec5SDimitry Andric   m2 = m2 + delta * (sample - meanVal);
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric   minVal = std::min(minVal, sample);
910b57cec5SDimitry Andric   maxVal = std::max(maxVal, sample);
920b57cec5SDimitry Andric   if (collectingHist)
930b57cec5SDimitry Andric     hist.addSample(sample);
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
operator +=(const statistic & other)960b57cec5SDimitry Andric statistic &statistic::operator+=(const statistic &other) {
970b57cec5SDimitry Andric   if (other.sampleCount == 0)
980b57cec5SDimitry Andric     return *this;
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   if (sampleCount == 0) {
1010b57cec5SDimitry Andric     *this = other;
1020b57cec5SDimitry Andric     return *this;
1030b57cec5SDimitry Andric   }
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   uint64_t newSampleCount = sampleCount + other.sampleCount;
1060b57cec5SDimitry Andric   double dnsc = double(newSampleCount);
1070b57cec5SDimitry Andric   double dsc = double(sampleCount);
1080b57cec5SDimitry Andric   double dscBydnsc = dsc / dnsc;
1090b57cec5SDimitry Andric   double dosc = double(other.sampleCount);
1100b57cec5SDimitry Andric   double delta = other.meanVal - meanVal;
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   // Try to order these calculations to avoid overflows. If this were Fortran,
1130b57cec5SDimitry Andric   // then the compiler would not be able to re-order over brackets. In C++ it
1140b57cec5SDimitry Andric   // may be legal to do that (we certainly hope it doesn't, and CC+ Programming
1150b57cec5SDimitry Andric   // Language 2nd edition suggests it shouldn't, since it says that exploitation
1160b57cec5SDimitry Andric   // of associativity can only be made if the operation really is associative
1170b57cec5SDimitry Andric   // (which floating addition isn't...)).
1180b57cec5SDimitry Andric   meanVal = meanVal * dscBydnsc + other.meanVal * (1 - dscBydnsc);
1190b57cec5SDimitry Andric   m2 = m2 + other.m2 + dscBydnsc * dosc * delta * delta;
1200b57cec5SDimitry Andric   minVal = std::min(minVal, other.minVal);
1210b57cec5SDimitry Andric   maxVal = std::max(maxVal, other.maxVal);
1220b57cec5SDimitry Andric   sampleCount = newSampleCount;
1230b57cec5SDimitry Andric   if (collectingHist)
1240b57cec5SDimitry Andric     hist += other.hist;
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   return *this;
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric 
scale(double factor)1290b57cec5SDimitry Andric void statistic::scale(double factor) {
1300b57cec5SDimitry Andric   minVal = minVal * factor;
1310b57cec5SDimitry Andric   maxVal = maxVal * factor;
1320b57cec5SDimitry Andric   meanVal = meanVal * factor;
1330b57cec5SDimitry Andric   m2 = m2 * factor * factor;
1340b57cec5SDimitry Andric   return;
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
format(char unit,bool total) const1370b57cec5SDimitry Andric std::string statistic::format(char unit, bool total) const {
138e8d8bef9SDimitry Andric   std::string result = formatSI((double)sampleCount, 9, ' ');
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   if (sampleCount == 0) {
1410b57cec5SDimitry Andric     result = result + std::string(", ") + formatSI(0.0, 9, unit);
1420b57cec5SDimitry Andric     result = result + std::string(", ") + formatSI(0.0, 9, unit);
1430b57cec5SDimitry Andric     result = result + std::string(", ") + formatSI(0.0, 9, unit);
1440b57cec5SDimitry Andric     if (total)
1450b57cec5SDimitry Andric       result = result + std::string(", ") + formatSI(0.0, 9, unit);
1460b57cec5SDimitry Andric     result = result + std::string(", ") + formatSI(0.0, 9, unit);
1470b57cec5SDimitry Andric   } else {
1480b57cec5SDimitry Andric     result = result + std::string(", ") + formatSI(minVal, 9, unit);
1490b57cec5SDimitry Andric     result = result + std::string(", ") + formatSI(meanVal, 9, unit);
1500b57cec5SDimitry Andric     result = result + std::string(", ") + formatSI(maxVal, 9, unit);
1510b57cec5SDimitry Andric     if (total)
1520b57cec5SDimitry Andric       result =
1530b57cec5SDimitry Andric           result + std::string(", ") + formatSI(meanVal * sampleCount, 9, unit);
1540b57cec5SDimitry Andric     result = result + std::string(", ") + formatSI(getSD(), 9, unit);
1550b57cec5SDimitry Andric   }
1560b57cec5SDimitry Andric   return result;
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric /* ************* histogram member functions ************* */
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric // Lowest bin that has anything in it
minBin() const1620b57cec5SDimitry Andric int logHistogram::minBin() const {
1630b57cec5SDimitry Andric   for (int i = 0; i < numBins; i++) {
1640b57cec5SDimitry Andric     if (bins[i].count != 0)
1650b57cec5SDimitry Andric       return i - logOffset;
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric   return -logOffset;
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric // Highest bin that has anything in it
maxBin() const1710b57cec5SDimitry Andric int logHistogram::maxBin() const {
1720b57cec5SDimitry Andric   for (int i = numBins - 1; i >= 0; i--) {
1730b57cec5SDimitry Andric     if (bins[i].count != 0)
1740b57cec5SDimitry Andric       return i - logOffset;
1750b57cec5SDimitry Andric   }
1760b57cec5SDimitry Andric   return -logOffset;
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric // Which bin does this sample belong in ?
findBin(double sample)1800b57cec5SDimitry Andric uint32_t logHistogram::findBin(double sample) {
1810b57cec5SDimitry Andric   double v = std::fabs(sample);
1820b57cec5SDimitry Andric   // Simply loop up looking which bin to put it in.
1830b57cec5SDimitry Andric   // According to a micro-architect this is likely to be faster than a binary
1840b57cec5SDimitry Andric   // search, since
1850b57cec5SDimitry Andric   // it will only have one branch mis-predict
186e8d8bef9SDimitry Andric   for (int b = 0; b < numBins - 1; b++)
1870b57cec5SDimitry Andric     if (binMax[b] > v)
1880b57cec5SDimitry Andric       return b;
189e8d8bef9SDimitry Andric   return numBins - 1;
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric 
addSample(double sample)1920b57cec5SDimitry Andric void logHistogram::addSample(double sample) {
1930b57cec5SDimitry Andric   if (sample == 0.0) {
1940b57cec5SDimitry Andric     zeroCount += 1;
1950b57cec5SDimitry Andric #ifdef KMP_DEBUG
1960b57cec5SDimitry Andric     _total++;
1970b57cec5SDimitry Andric     check();
1980b57cec5SDimitry Andric #endif
1990b57cec5SDimitry Andric     return;
2000b57cec5SDimitry Andric   }
2010b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(std::isfinite(sample));
2020b57cec5SDimitry Andric   uint32_t bin = findBin(sample);
2030b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(0 <= bin && bin < numBins);
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric   bins[bin].count += 1;
2060b57cec5SDimitry Andric   bins[bin].total += sample;
2070b57cec5SDimitry Andric #ifdef KMP_DEBUG
2080b57cec5SDimitry Andric   _total++;
2090b57cec5SDimitry Andric   check();
2100b57cec5SDimitry Andric #endif
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric // This may not be the format we want, but it'll do for now
format(char unit) const2140b57cec5SDimitry Andric std::string logHistogram::format(char unit) const {
2150b57cec5SDimitry Andric   std::stringstream result;
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric   result << "Bin,                Count,     Total\n";
2180b57cec5SDimitry Andric   if (zeroCount) {
2190b57cec5SDimitry Andric     result << "0,              " << formatSI(zeroCount, 9, ' ') << ", ",
2200b57cec5SDimitry Andric         formatSI(0.0, 9, unit);
2210b57cec5SDimitry Andric     if (count(minBin()) == 0)
2220b57cec5SDimitry Andric       return result.str();
2230b57cec5SDimitry Andric     result << "\n";
2240b57cec5SDimitry Andric   }
2250b57cec5SDimitry Andric   for (int i = minBin(); i <= maxBin(); i++) {
226e8d8bef9SDimitry Andric     result << "10**" << i << "<=v<";
227e8d8bef9SDimitry Andric     if (i + 1 == numBins - 1)
228e8d8bef9SDimitry Andric       result << "infinity, ";
229e8d8bef9SDimitry Andric     else
230e8d8bef9SDimitry Andric       result << "10**" << (i + 1) << ", ";
231e8d8bef9SDimitry Andric     result << formatSI(count(i), 9, ' ') << ", " << formatSI(total(i), 9, unit);
2320b57cec5SDimitry Andric     if (i != maxBin())
2330b57cec5SDimitry Andric       result << "\n";
2340b57cec5SDimitry Andric   }
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   return result.str();
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric /* ************* explicitTimer member functions ************* */
2400b57cec5SDimitry Andric 
start(tsc_tick_count tick)2410b57cec5SDimitry Andric void explicitTimer::start(tsc_tick_count tick) {
2420b57cec5SDimitry Andric   startTime = tick;
2430b57cec5SDimitry Andric   totalPauseTime = 0;
2440b57cec5SDimitry Andric   if (timeStat::logEvent(timerEnumValue)) {
2450b57cec5SDimitry Andric     __kmp_stats_thread_ptr->incrementNestValue();
2460b57cec5SDimitry Andric   }
2470b57cec5SDimitry Andric   return;
2480b57cec5SDimitry Andric }
2490b57cec5SDimitry Andric 
stop(tsc_tick_count tick,kmp_stats_list * stats_ptr)2500b57cec5SDimitry Andric void explicitTimer::stop(tsc_tick_count tick,
2510b57cec5SDimitry Andric                          kmp_stats_list *stats_ptr /* = nullptr */) {
2520b57cec5SDimitry Andric   if (startTime.getValue() == 0)
2530b57cec5SDimitry Andric     return;
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric   stat->addSample(((tick - startTime) - totalPauseTime).ticks());
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   if (timeStat::logEvent(timerEnumValue)) {
2580b57cec5SDimitry Andric     if (!stats_ptr)
2590b57cec5SDimitry Andric       stats_ptr = __kmp_stats_thread_ptr;
2600b57cec5SDimitry Andric     stats_ptr->push_event(
2610b57cec5SDimitry Andric         startTime.getValue() - __kmp_stats_start_time.getValue(),
2620b57cec5SDimitry Andric         tick.getValue() - __kmp_stats_start_time.getValue(),
2630b57cec5SDimitry Andric         __kmp_stats_thread_ptr->getNestValue(), timerEnumValue);
2640b57cec5SDimitry Andric     stats_ptr->decrementNestValue();
2650b57cec5SDimitry Andric   }
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric   /* We accept the risk that we drop a sample because it really did start at
2680b57cec5SDimitry Andric      t==0. */
2690b57cec5SDimitry Andric   startTime = 0;
2700b57cec5SDimitry Andric   return;
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric /* ************* partitionedTimers member functions ************* */
partitionedTimers()2740b57cec5SDimitry Andric partitionedTimers::partitionedTimers() { timer_stack.reserve(8); }
2750b57cec5SDimitry Andric 
2765ffd83dbSDimitry Andric // initialize the partitioned timers to an initial timer
init(explicitTimer timer)2770b57cec5SDimitry Andric void partitionedTimers::init(explicitTimer timer) {
2780b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(this->timer_stack.size() == 0);
2790b57cec5SDimitry Andric   timer_stack.push_back(timer);
2800b57cec5SDimitry Andric   timer_stack.back().start(tsc_tick_count::now());
2810b57cec5SDimitry Andric }
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric // stop/save the current timer, and start the new timer (timer_pair)
2840b57cec5SDimitry Andric // There is a special condition where if the current timer is equal to
2850b57cec5SDimitry Andric // the one you are trying to push, then it only manipulates the stack,
2860b57cec5SDimitry Andric // and it won't stop/start the currently running timer.
push(explicitTimer timer)2870b57cec5SDimitry Andric void partitionedTimers::push(explicitTimer timer) {
2880b57cec5SDimitry Andric   // get the current timer
2890b57cec5SDimitry Andric   // pause current timer
2900b57cec5SDimitry Andric   // push new timer
2910b57cec5SDimitry Andric   // start the new timer
2920b57cec5SDimitry Andric   explicitTimer *current_timer, *new_timer;
2930b57cec5SDimitry Andric   size_t stack_size;
2940b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(this->timer_stack.size() > 0);
2950b57cec5SDimitry Andric   timer_stack.push_back(timer);
2960b57cec5SDimitry Andric   stack_size = timer_stack.size();
2970b57cec5SDimitry Andric   current_timer = &(timer_stack[stack_size - 2]);
2980b57cec5SDimitry Andric   new_timer = &(timer_stack[stack_size - 1]);
2990b57cec5SDimitry Andric   tsc_tick_count tick = tsc_tick_count::now();
3000b57cec5SDimitry Andric   current_timer->pause(tick);
3010b57cec5SDimitry Andric   new_timer->start(tick);
3020b57cec5SDimitry Andric }
3030b57cec5SDimitry Andric 
3040b57cec5SDimitry Andric // stop/discard the current timer, and start the previously saved timer
pop()3050b57cec5SDimitry Andric void partitionedTimers::pop() {
3060b57cec5SDimitry Andric   // get the current timer
3070b57cec5SDimitry Andric   // stop current timer (record event/sample)
3080b57cec5SDimitry Andric   // pop current timer
3090b57cec5SDimitry Andric   // get the new current timer and resume
3100b57cec5SDimitry Andric   explicitTimer *old_timer, *new_timer;
3110b57cec5SDimitry Andric   size_t stack_size = timer_stack.size();
3120b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(stack_size > 1);
3130b57cec5SDimitry Andric   old_timer = &(timer_stack[stack_size - 1]);
3140b57cec5SDimitry Andric   new_timer = &(timer_stack[stack_size - 2]);
3150b57cec5SDimitry Andric   tsc_tick_count tick = tsc_tick_count::now();
3160b57cec5SDimitry Andric   old_timer->stop(tick);
3170b57cec5SDimitry Andric   new_timer->resume(tick);
3180b57cec5SDimitry Andric   timer_stack.pop_back();
3190b57cec5SDimitry Andric }
3200b57cec5SDimitry Andric 
exchange(explicitTimer timer)3210b57cec5SDimitry Andric void partitionedTimers::exchange(explicitTimer timer) {
3220b57cec5SDimitry Andric   // get the current timer
3230b57cec5SDimitry Andric   // stop current timer (record event/sample)
3240b57cec5SDimitry Andric   // push new timer
3250b57cec5SDimitry Andric   // start the new timer
3260b57cec5SDimitry Andric   explicitTimer *current_timer, *new_timer;
3270b57cec5SDimitry Andric   size_t stack_size;
3280b57cec5SDimitry Andric   KMP_DEBUG_ASSERT(this->timer_stack.size() > 0);
3290b57cec5SDimitry Andric   tsc_tick_count tick = tsc_tick_count::now();
3300b57cec5SDimitry Andric   stack_size = timer_stack.size();
3310b57cec5SDimitry Andric   current_timer = &(timer_stack[stack_size - 1]);
3320b57cec5SDimitry Andric   current_timer->stop(tick);
3330b57cec5SDimitry Andric   timer_stack.pop_back();
3340b57cec5SDimitry Andric   timer_stack.push_back(timer);
3350b57cec5SDimitry Andric   new_timer = &(timer_stack[stack_size - 1]);
3360b57cec5SDimitry Andric   new_timer->start(tick);
3370b57cec5SDimitry Andric }
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric // Wind up all the currently running timers.
3400b57cec5SDimitry Andric // This pops off all the timers from the stack and clears the stack
3410b57cec5SDimitry Andric // After this is called, init() must be run again to initialize the
3420b57cec5SDimitry Andric // stack of timers
windup()3430b57cec5SDimitry Andric void partitionedTimers::windup() {
3440b57cec5SDimitry Andric   while (timer_stack.size() > 1) {
3450b57cec5SDimitry Andric     this->pop();
3460b57cec5SDimitry Andric   }
3470b57cec5SDimitry Andric   // Pop the timer from the init() call
3480b57cec5SDimitry Andric   if (timer_stack.size() > 0) {
3490b57cec5SDimitry Andric     timer_stack.back().stop(tsc_tick_count::now());
3500b57cec5SDimitry Andric     timer_stack.pop_back();
3510b57cec5SDimitry Andric   }
3520b57cec5SDimitry Andric }
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric /* ************* kmp_stats_event_vector member functions ************* */
3550b57cec5SDimitry Andric 
deallocate()3560b57cec5SDimitry Andric void kmp_stats_event_vector::deallocate() {
3570b57cec5SDimitry Andric   __kmp_free(events);
3580b57cec5SDimitry Andric   internal_size = 0;
3590b57cec5SDimitry Andric   allocated_size = 0;
3600b57cec5SDimitry Andric   events = NULL;
3610b57cec5SDimitry Andric }
3620b57cec5SDimitry Andric 
3630b57cec5SDimitry Andric // This function is for qsort() which requires the compare function to return
3640b57cec5SDimitry Andric // either a negative number if event1 < event2, a positive number if event1 >
3650b57cec5SDimitry Andric // event2 or zero if event1 == event2. This sorts by start time (lowest to
3660b57cec5SDimitry Andric // highest).
compare_two_events(const void * event1,const void * event2)3670b57cec5SDimitry Andric int compare_two_events(const void *event1, const void *event2) {
3680b57cec5SDimitry Andric   const kmp_stats_event *ev1 = RCAST(const kmp_stats_event *, event1);
3690b57cec5SDimitry Andric   const kmp_stats_event *ev2 = RCAST(const kmp_stats_event *, event2);
3700b57cec5SDimitry Andric 
3710b57cec5SDimitry Andric   if (ev1->getStart() < ev2->getStart())
3720b57cec5SDimitry Andric     return -1;
3730b57cec5SDimitry Andric   else if (ev1->getStart() > ev2->getStart())
3740b57cec5SDimitry Andric     return 1;
3750b57cec5SDimitry Andric   else
3760b57cec5SDimitry Andric     return 0;
3770b57cec5SDimitry Andric }
3780b57cec5SDimitry Andric 
sort()3790b57cec5SDimitry Andric void kmp_stats_event_vector::sort() {
3800b57cec5SDimitry Andric   qsort(events, internal_size, sizeof(kmp_stats_event), compare_two_events);
3810b57cec5SDimitry Andric }
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric /* ************* kmp_stats_list member functions ************* */
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric // returns a pointer to newly created stats node
push_back(int gtid)3860b57cec5SDimitry Andric kmp_stats_list *kmp_stats_list::push_back(int gtid) {
3870b57cec5SDimitry Andric   kmp_stats_list *newnode =
3880b57cec5SDimitry Andric       (kmp_stats_list *)__kmp_allocate(sizeof(kmp_stats_list));
3890b57cec5SDimitry Andric   // placement new, only requires space and pointer and initializes (so
3900b57cec5SDimitry Andric   // __kmp_allocate instead of C++ new[] is used)
3910b57cec5SDimitry Andric   new (newnode) kmp_stats_list();
3920b57cec5SDimitry Andric   newnode->setGtid(gtid);
3930b57cec5SDimitry Andric   newnode->prev = this->prev;
3940b57cec5SDimitry Andric   newnode->next = this;
3950b57cec5SDimitry Andric   newnode->prev->next = newnode;
3960b57cec5SDimitry Andric   newnode->next->prev = newnode;
3970b57cec5SDimitry Andric   return newnode;
3980b57cec5SDimitry Andric }
deallocate()3990b57cec5SDimitry Andric void kmp_stats_list::deallocate() {
4000b57cec5SDimitry Andric   kmp_stats_list *ptr = this->next;
4010b57cec5SDimitry Andric   kmp_stats_list *delptr = this->next;
4020b57cec5SDimitry Andric   while (ptr != this) {
4030b57cec5SDimitry Andric     delptr = ptr;
4040b57cec5SDimitry Andric     ptr = ptr->next;
4050b57cec5SDimitry Andric     // placement new means we have to explicitly call destructor.
4060b57cec5SDimitry Andric     delptr->_event_vector.deallocate();
4070b57cec5SDimitry Andric     delptr->~kmp_stats_list();
4080b57cec5SDimitry Andric     __kmp_free(delptr);
4090b57cec5SDimitry Andric   }
4100b57cec5SDimitry Andric }
begin()4110b57cec5SDimitry Andric kmp_stats_list::iterator kmp_stats_list::begin() {
4120b57cec5SDimitry Andric   kmp_stats_list::iterator it;
4130b57cec5SDimitry Andric   it.ptr = this->next;
4140b57cec5SDimitry Andric   return it;
4150b57cec5SDimitry Andric }
end()4160b57cec5SDimitry Andric kmp_stats_list::iterator kmp_stats_list::end() {
4170b57cec5SDimitry Andric   kmp_stats_list::iterator it;
4180b57cec5SDimitry Andric   it.ptr = this;
4190b57cec5SDimitry Andric   return it;
4200b57cec5SDimitry Andric }
size()4210b57cec5SDimitry Andric int kmp_stats_list::size() {
4220b57cec5SDimitry Andric   int retval;
4230b57cec5SDimitry Andric   kmp_stats_list::iterator it;
4240b57cec5SDimitry Andric   for (retval = 0, it = begin(); it != end(); it++, retval++) {
4250b57cec5SDimitry Andric   }
4260b57cec5SDimitry Andric   return retval;
4270b57cec5SDimitry Andric }
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric /* ************* kmp_stats_list::iterator member functions ************* */
4300b57cec5SDimitry Andric 
iterator()4310b57cec5SDimitry Andric kmp_stats_list::iterator::iterator() : ptr(NULL) {}
~iterator()4320b57cec5SDimitry Andric kmp_stats_list::iterator::~iterator() {}
operator ++()4330b57cec5SDimitry Andric kmp_stats_list::iterator kmp_stats_list::iterator::operator++() {
4340b57cec5SDimitry Andric   this->ptr = this->ptr->next;
4350b57cec5SDimitry Andric   return *this;
4360b57cec5SDimitry Andric }
operator ++(int dummy)4370b57cec5SDimitry Andric kmp_stats_list::iterator kmp_stats_list::iterator::operator++(int dummy) {
4380b57cec5SDimitry Andric   this->ptr = this->ptr->next;
4390b57cec5SDimitry Andric   return *this;
4400b57cec5SDimitry Andric }
operator --()4410b57cec5SDimitry Andric kmp_stats_list::iterator kmp_stats_list::iterator::operator--() {
4420b57cec5SDimitry Andric   this->ptr = this->ptr->prev;
4430b57cec5SDimitry Andric   return *this;
4440b57cec5SDimitry Andric }
operator --(int dummy)4450b57cec5SDimitry Andric kmp_stats_list::iterator kmp_stats_list::iterator::operator--(int dummy) {
4460b57cec5SDimitry Andric   this->ptr = this->ptr->prev;
4470b57cec5SDimitry Andric   return *this;
4480b57cec5SDimitry Andric }
operator !=(const kmp_stats_list::iterator & rhs)4490b57cec5SDimitry Andric bool kmp_stats_list::iterator::operator!=(const kmp_stats_list::iterator &rhs) {
4500b57cec5SDimitry Andric   return this->ptr != rhs.ptr;
4510b57cec5SDimitry Andric }
operator ==(const kmp_stats_list::iterator & rhs)4520b57cec5SDimitry Andric bool kmp_stats_list::iterator::operator==(const kmp_stats_list::iterator &rhs) {
4530b57cec5SDimitry Andric   return this->ptr == rhs.ptr;
4540b57cec5SDimitry Andric }
operator *() const4550b57cec5SDimitry Andric kmp_stats_list *kmp_stats_list::iterator::operator*() const {
4560b57cec5SDimitry Andric   return this->ptr;
4570b57cec5SDimitry Andric }
4580b57cec5SDimitry Andric 
4590b57cec5SDimitry Andric /* *************  kmp_stats_output_module functions ************** */
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric const char *kmp_stats_output_module::eventsFileName = NULL;
4620b57cec5SDimitry Andric const char *kmp_stats_output_module::plotFileName = NULL;
4630b57cec5SDimitry Andric int kmp_stats_output_module::printPerThreadFlag = 0;
4640b57cec5SDimitry Andric int kmp_stats_output_module::printPerThreadEventsFlag = 0;
4650b57cec5SDimitry Andric 
lastName(char * name)4660b57cec5SDimitry Andric static char const *lastName(char *name) {
467e8d8bef9SDimitry Andric   int l = (int)strlen(name);
4680b57cec5SDimitry Andric   for (int i = l - 1; i >= 0; --i) {
4690b57cec5SDimitry Andric     if (name[i] == '.')
4700b57cec5SDimitry Andric       name[i] = '_';
4710b57cec5SDimitry Andric     if (name[i] == '/')
4720b57cec5SDimitry Andric       return name + i + 1;
4730b57cec5SDimitry Andric   }
4740b57cec5SDimitry Andric   return name;
4750b57cec5SDimitry Andric }
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric /* Read the name of the executable from /proc/self/cmdline */
getImageName(char * buffer,size_t buflen)4780b57cec5SDimitry Andric static char const *getImageName(char *buffer, size_t buflen) {
4790b57cec5SDimitry Andric   FILE *f = fopen("/proc/self/cmdline", "r");
4800b57cec5SDimitry Andric   buffer[0] = char(0);
4810b57cec5SDimitry Andric   if (!f)
4820b57cec5SDimitry Andric     return buffer;
4830b57cec5SDimitry Andric 
4840b57cec5SDimitry Andric   // The file contains char(0) delimited words from the commandline.
4850b57cec5SDimitry Andric   // This just returns the last filename component of the first word on the
4860b57cec5SDimitry Andric   // line.
4870b57cec5SDimitry Andric   size_t n = fread(buffer, 1, buflen, f);
4880b57cec5SDimitry Andric   if (n == 0) {
4890b57cec5SDimitry Andric     fclose(f);
4900b57cec5SDimitry Andric     KMP_CHECK_SYSFAIL("fread", 1)
4910b57cec5SDimitry Andric   }
4920b57cec5SDimitry Andric   fclose(f);
4930b57cec5SDimitry Andric   buffer[buflen - 1] = char(0);
4940b57cec5SDimitry Andric   return lastName(buffer);
4950b57cec5SDimitry Andric }
4960b57cec5SDimitry Andric 
getTime(char * buffer,size_t buflen,bool underscores=false)4970b57cec5SDimitry Andric static void getTime(char *buffer, size_t buflen, bool underscores = false) {
4980b57cec5SDimitry Andric   time_t timer;
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric   time(&timer);
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric   struct tm *tm_info = localtime(&timer);
5030b57cec5SDimitry Andric   if (underscores)
5040b57cec5SDimitry Andric     strftime(buffer, buflen, "%Y-%m-%d_%H%M%S", tm_info);
5050b57cec5SDimitry Andric   else
5060b57cec5SDimitry Andric     strftime(buffer, buflen, "%Y-%m-%d %H%M%S", tm_info);
5070b57cec5SDimitry Andric }
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric /* Generate a stats file name, expanding prototypes */
generateFilename(char const * prototype,char const * imageName)5100b57cec5SDimitry Andric static std::string generateFilename(char const *prototype,
5110b57cec5SDimitry Andric                                     char const *imageName) {
5120b57cec5SDimitry Andric   std::string res;
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   for (int i = 0; prototype[i] != char(0); i++) {
5150b57cec5SDimitry Andric     char ch = prototype[i];
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric     if (ch == '%') {
5180b57cec5SDimitry Andric       i++;
5190b57cec5SDimitry Andric       if (prototype[i] == char(0))
5200b57cec5SDimitry Andric         break;
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric       switch (prototype[i]) {
5230b57cec5SDimitry Andric       case 't': // Insert time and date
5240b57cec5SDimitry Andric       {
5250b57cec5SDimitry Andric         char date[26];
5260b57cec5SDimitry Andric         getTime(date, sizeof(date), true);
5270b57cec5SDimitry Andric         res += date;
5280b57cec5SDimitry Andric       } break;
5290b57cec5SDimitry Andric       case 'e': // Insert executable name
5300b57cec5SDimitry Andric         res += imageName;
5310b57cec5SDimitry Andric         break;
5320b57cec5SDimitry Andric       case 'p': // Insert pid
5330b57cec5SDimitry Andric       {
5340b57cec5SDimitry Andric         std::stringstream ss;
5350b57cec5SDimitry Andric         ss << getpid();
5360b57cec5SDimitry Andric         res += ss.str();
5370b57cec5SDimitry Andric       } break;
5380b57cec5SDimitry Andric       default:
5390b57cec5SDimitry Andric         res += prototype[i];
5400b57cec5SDimitry Andric         break;
5410b57cec5SDimitry Andric       }
5420b57cec5SDimitry Andric     } else
5430b57cec5SDimitry Andric       res += ch;
5440b57cec5SDimitry Andric   }
5450b57cec5SDimitry Andric   return res;
5460b57cec5SDimitry Andric }
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric // init() is called very near the beginning of execution time in the constructor
5490b57cec5SDimitry Andric // of __kmp_stats_global_output
init()5500b57cec5SDimitry Andric void kmp_stats_output_module::init() {
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric   char *statsFileName = getenv("KMP_STATS_FILE");
5530b57cec5SDimitry Andric   eventsFileName = getenv("KMP_STATS_EVENTS_FILE");
5540b57cec5SDimitry Andric   plotFileName = getenv("KMP_STATS_PLOT_FILE");
5550b57cec5SDimitry Andric   char *threadStats = getenv("KMP_STATS_THREADS");
5560b57cec5SDimitry Andric   char *threadEvents = getenv("KMP_STATS_EVENTS");
5570b57cec5SDimitry Andric 
5580b57cec5SDimitry Andric   // set the stats output filenames based on environment variables and defaults
5590b57cec5SDimitry Andric   if (statsFileName) {
5600b57cec5SDimitry Andric     char imageName[1024];
5610b57cec5SDimitry Andric     // Process any escapes (e.g., %p, %e, %t) in the name
5620b57cec5SDimitry Andric     outputFileName = generateFilename(
5630b57cec5SDimitry Andric         statsFileName, getImageName(&imageName[0], sizeof(imageName)));
5640b57cec5SDimitry Andric   }
5650b57cec5SDimitry Andric   eventsFileName = eventsFileName ? eventsFileName : "events.dat";
5660b57cec5SDimitry Andric   plotFileName = plotFileName ? plotFileName : "events.plt";
5670b57cec5SDimitry Andric 
5680b57cec5SDimitry Andric   // set the flags based on environment variables matching: true, on, 1, .true.
5690b57cec5SDimitry Andric   // , .t. , yes
5700b57cec5SDimitry Andric   printPerThreadFlag = __kmp_str_match_true(threadStats);
5710b57cec5SDimitry Andric   printPerThreadEventsFlag = __kmp_str_match_true(threadEvents);
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric   if (printPerThreadEventsFlag) {
5740b57cec5SDimitry Andric     // assigns a color to each timer for printing
5750b57cec5SDimitry Andric     setupEventColors();
5760b57cec5SDimitry Andric   } else {
5770b57cec5SDimitry Andric     // will clear flag so that no event will be logged
5780b57cec5SDimitry Andric     timeStat::clearEventFlags();
5790b57cec5SDimitry Andric   }
5800b57cec5SDimitry Andric }
5810b57cec5SDimitry Andric 
setupEventColors()5820b57cec5SDimitry Andric void kmp_stats_output_module::setupEventColors() {
5830b57cec5SDimitry Andric   int i;
5840b57cec5SDimitry Andric   int globalColorIndex = 0;
5850b57cec5SDimitry Andric   int numGlobalColors = sizeof(globalColorArray) / sizeof(rgb_color);
5860b57cec5SDimitry Andric   for (i = 0; i < TIMER_LAST; i++) {
5870b57cec5SDimitry Andric     if (timeStat::logEvent((timer_e)i)) {
5880b57cec5SDimitry Andric       timerColorInfo[i] = globalColorArray[globalColorIndex];
5890b57cec5SDimitry Andric       globalColorIndex = (globalColorIndex + 1) % numGlobalColors;
5900b57cec5SDimitry Andric     }
5910b57cec5SDimitry Andric   }
5920b57cec5SDimitry Andric }
5930b57cec5SDimitry Andric 
printTimerStats(FILE * statsOut,statistic const * theStats,statistic const * totalStats)5940b57cec5SDimitry Andric void kmp_stats_output_module::printTimerStats(FILE *statsOut,
5950b57cec5SDimitry Andric                                               statistic const *theStats,
5960b57cec5SDimitry Andric                                               statistic const *totalStats) {
5970b57cec5SDimitry Andric   fprintf(statsOut,
5980b57cec5SDimitry Andric           "Timer,                             SampleCount,    Min,      "
5990b57cec5SDimitry Andric           "Mean,       Max,     Total,        SD\n");
6000b57cec5SDimitry Andric   for (timer_e s = timer_e(0); s < TIMER_LAST; s = timer_e(s + 1)) {
6010b57cec5SDimitry Andric     statistic const *stat = &theStats[s];
6020b57cec5SDimitry Andric     char tag = timeStat::noUnits(s) ? ' ' : 'T';
6030b57cec5SDimitry Andric 
6040b57cec5SDimitry Andric     fprintf(statsOut, "%-35s, %s\n", timeStat::name(s),
6050b57cec5SDimitry Andric             stat->format(tag, true).c_str());
6060b57cec5SDimitry Andric   }
6070b57cec5SDimitry Andric   // Also print the Total_ versions of times.
6080b57cec5SDimitry Andric   for (timer_e s = timer_e(0); s < TIMER_LAST; s = timer_e(s + 1)) {
6090b57cec5SDimitry Andric     char tag = timeStat::noUnits(s) ? ' ' : 'T';
6100b57cec5SDimitry Andric     if (totalStats && !timeStat::noTotal(s))
6110b57cec5SDimitry Andric       fprintf(statsOut, "Total_%-29s, %s\n", timeStat::name(s),
6120b57cec5SDimitry Andric               totalStats[s].format(tag, true).c_str());
6130b57cec5SDimitry Andric   }
6140b57cec5SDimitry Andric 
6155ffd83dbSDimitry Andric   // Print histogram of statistics
6160b57cec5SDimitry Andric   if (theStats[0].haveHist()) {
6170b57cec5SDimitry Andric     fprintf(statsOut, "\nTimer distributions\n");
6180b57cec5SDimitry Andric     for (int s = 0; s < TIMER_LAST; s++) {
6190b57cec5SDimitry Andric       statistic const *stat = &theStats[s];
6200b57cec5SDimitry Andric 
6210b57cec5SDimitry Andric       if (stat->getCount() != 0) {
6220b57cec5SDimitry Andric         char tag = timeStat::noUnits(timer_e(s)) ? ' ' : 'T';
6230b57cec5SDimitry Andric 
6240b57cec5SDimitry Andric         fprintf(statsOut, "%s\n", timeStat::name(timer_e(s)));
6250b57cec5SDimitry Andric         fprintf(statsOut, "%s\n", stat->getHist()->format(tag).c_str());
6260b57cec5SDimitry Andric       }
6270b57cec5SDimitry Andric     }
6280b57cec5SDimitry Andric   }
6290b57cec5SDimitry Andric }
6300b57cec5SDimitry Andric 
printCounterStats(FILE * statsOut,statistic const * theStats)6310b57cec5SDimitry Andric void kmp_stats_output_module::printCounterStats(FILE *statsOut,
6320b57cec5SDimitry Andric                                                 statistic const *theStats) {
6330b57cec5SDimitry Andric   fprintf(statsOut, "Counter,                 ThreadCount,    Min,      Mean,  "
6340b57cec5SDimitry Andric                     "     Max,     Total,        SD\n");
6350b57cec5SDimitry Andric   for (int s = 0; s < COUNTER_LAST; s++) {
6360b57cec5SDimitry Andric     statistic const *stat = &theStats[s];
6370b57cec5SDimitry Andric     fprintf(statsOut, "%-25s, %s\n", counter::name(counter_e(s)),
6380b57cec5SDimitry Andric             stat->format(' ', true).c_str());
6390b57cec5SDimitry Andric   }
6400b57cec5SDimitry Andric   // Print histogram of counters
6410b57cec5SDimitry Andric   if (theStats[0].haveHist()) {
6420b57cec5SDimitry Andric     fprintf(statsOut, "\nCounter distributions\n");
6430b57cec5SDimitry Andric     for (int s = 0; s < COUNTER_LAST; s++) {
6440b57cec5SDimitry Andric       statistic const *stat = &theStats[s];
6450b57cec5SDimitry Andric 
6460b57cec5SDimitry Andric       if (stat->getCount() != 0) {
6470b57cec5SDimitry Andric         fprintf(statsOut, "%s\n", counter::name(counter_e(s)));
6480b57cec5SDimitry Andric         fprintf(statsOut, "%s\n", stat->getHist()->format(' ').c_str());
6490b57cec5SDimitry Andric       }
6500b57cec5SDimitry Andric     }
6510b57cec5SDimitry Andric   }
6520b57cec5SDimitry Andric }
6530b57cec5SDimitry Andric 
printCounters(FILE * statsOut,counter const * theCounters)6540b57cec5SDimitry Andric void kmp_stats_output_module::printCounters(FILE *statsOut,
6550b57cec5SDimitry Andric                                             counter const *theCounters) {
6560b57cec5SDimitry Andric   // We print all the counters even if they are zero.
6570b57cec5SDimitry Andric   // That makes it easier to slice them into a spreadsheet if you need to.
6580b57cec5SDimitry Andric   fprintf(statsOut, "\nCounter,                    Count\n");
6590b57cec5SDimitry Andric   for (int c = 0; c < COUNTER_LAST; c++) {
6600b57cec5SDimitry Andric     counter const *stat = &theCounters[c];
6610b57cec5SDimitry Andric     fprintf(statsOut, "%-25s, %s\n", counter::name(counter_e(c)),
662e8d8bef9SDimitry Andric             formatSI((double)stat->getValue(), 9, ' ').c_str());
6630b57cec5SDimitry Andric   }
6640b57cec5SDimitry Andric }
6650b57cec5SDimitry Andric 
printEvents(FILE * eventsOut,kmp_stats_event_vector * theEvents,int gtid)6660b57cec5SDimitry Andric void kmp_stats_output_module::printEvents(FILE *eventsOut,
6670b57cec5SDimitry Andric                                           kmp_stats_event_vector *theEvents,
6680b57cec5SDimitry Andric                                           int gtid) {
6690b57cec5SDimitry Andric   // sort by start time before printing
6700b57cec5SDimitry Andric   theEvents->sort();
6710b57cec5SDimitry Andric   for (int i = 0; i < theEvents->size(); i++) {
6720b57cec5SDimitry Andric     kmp_stats_event ev = theEvents->at(i);
6730b57cec5SDimitry Andric     rgb_color color = getEventColor(ev.getTimerName());
6740b57cec5SDimitry Andric     fprintf(eventsOut, "%d %llu %llu %1.1f rgb(%1.1f,%1.1f,%1.1f) %s\n", gtid,
6750b57cec5SDimitry Andric             static_cast<unsigned long long>(ev.getStart()),
6760b57cec5SDimitry Andric             static_cast<unsigned long long>(ev.getStop()),
6770b57cec5SDimitry Andric             1.2 - (ev.getNestLevel() * 0.2), color.r, color.g, color.b,
6780b57cec5SDimitry Andric             timeStat::name(ev.getTimerName()));
6790b57cec5SDimitry Andric   }
6800b57cec5SDimitry Andric   return;
6810b57cec5SDimitry Andric }
6820b57cec5SDimitry Andric 
windupExplicitTimers()6830b57cec5SDimitry Andric void kmp_stats_output_module::windupExplicitTimers() {
6840b57cec5SDimitry Andric   // Wind up any explicit timers. We assume that it's fair at this point to just
685480093f4SDimitry Andric   // walk all the explicit timers in all threads and say "it's over".
6860b57cec5SDimitry Andric   // If the timer wasn't running, this won't record anything anyway.
6870b57cec5SDimitry Andric   kmp_stats_list::iterator it;
6880b57cec5SDimitry Andric   for (it = __kmp_stats_list->begin(); it != __kmp_stats_list->end(); it++) {
6890b57cec5SDimitry Andric     kmp_stats_list *ptr = *it;
6900b57cec5SDimitry Andric     ptr->getPartitionedTimers()->windup();
6910b57cec5SDimitry Andric     ptr->endLife();
6920b57cec5SDimitry Andric   }
6930b57cec5SDimitry Andric }
6940b57cec5SDimitry Andric 
printPloticusFile()6950b57cec5SDimitry Andric void kmp_stats_output_module::printPloticusFile() {
6960b57cec5SDimitry Andric   int i;
6970b57cec5SDimitry Andric   int size = __kmp_stats_list->size();
698e8d8bef9SDimitry Andric   kmp_safe_raii_file_t plotOut(plotFileName, "w+");
6990b57cec5SDimitry Andric   fprintf(plotOut, "#proc page\n"
7000b57cec5SDimitry Andric                    "   pagesize: 15 10\n"
7010b57cec5SDimitry Andric                    "   scale: 1.0\n\n");
7020b57cec5SDimitry Andric 
703*fe6060f1SDimitry Andric   fprintf(plotOut,
704*fe6060f1SDimitry Andric           "#proc getdata\n"
7050b57cec5SDimitry Andric           "   file: %s\n\n",
7060b57cec5SDimitry Andric           eventsFileName);
7070b57cec5SDimitry Andric 
708*fe6060f1SDimitry Andric   fprintf(plotOut,
709*fe6060f1SDimitry Andric           "#proc areadef\n"
7100b57cec5SDimitry Andric           "   title: OpenMP Sampling Timeline\n"
7110b57cec5SDimitry Andric           "   titledetails: align=center size=16\n"
7120b57cec5SDimitry Andric           "   rectangle: 1 1 13 9\n"
7130b57cec5SDimitry Andric           "   xautorange: datafield=2,3\n"
7140b57cec5SDimitry Andric           "   yautorange: -1 %d\n\n",
7150b57cec5SDimitry Andric           size);
7160b57cec5SDimitry Andric 
7170b57cec5SDimitry Andric   fprintf(plotOut, "#proc xaxis\n"
7180b57cec5SDimitry Andric                    "   stubs: inc\n"
7190b57cec5SDimitry Andric                    "   stubdetails: size=12\n"
7200b57cec5SDimitry Andric                    "   label: Time (ticks)\n"
7210b57cec5SDimitry Andric                    "   labeldetails: size=14\n\n");
7220b57cec5SDimitry Andric 
723*fe6060f1SDimitry Andric   fprintf(plotOut,
724*fe6060f1SDimitry Andric           "#proc yaxis\n"
7250b57cec5SDimitry Andric           "   stubs: inc 1\n"
7260b57cec5SDimitry Andric           "   stubrange: 0 %d\n"
7270b57cec5SDimitry Andric           "   stubdetails: size=12\n"
7280b57cec5SDimitry Andric           "   label: Thread #\n"
7290b57cec5SDimitry Andric           "   labeldetails: size=14\n\n",
7300b57cec5SDimitry Andric           size - 1);
7310b57cec5SDimitry Andric 
7320b57cec5SDimitry Andric   fprintf(plotOut, "#proc bars\n"
7330b57cec5SDimitry Andric                    "   exactcolorfield: 5\n"
7340b57cec5SDimitry Andric                    "   axis: x\n"
7350b57cec5SDimitry Andric                    "   locfield: 1\n"
7360b57cec5SDimitry Andric                    "   segmentfields: 2 3\n"
7370b57cec5SDimitry Andric                    "   barwidthfield: 4\n\n");
7380b57cec5SDimitry Andric 
7390b57cec5SDimitry Andric   // create legend entries corresponding to the timer color
7400b57cec5SDimitry Andric   for (i = 0; i < TIMER_LAST; i++) {
7410b57cec5SDimitry Andric     if (timeStat::logEvent((timer_e)i)) {
7420b57cec5SDimitry Andric       rgb_color c = getEventColor((timer_e)i);
743*fe6060f1SDimitry Andric       fprintf(plotOut,
744*fe6060f1SDimitry Andric               "#proc legendentry\n"
7450b57cec5SDimitry Andric               "   sampletype: color\n"
7460b57cec5SDimitry Andric               "   label: %s\n"
7470b57cec5SDimitry Andric               "   details: rgb(%1.1f,%1.1f,%1.1f)\n\n",
7480b57cec5SDimitry Andric               timeStat::name((timer_e)i), c.r, c.g, c.b);
7490b57cec5SDimitry Andric     }
7500b57cec5SDimitry Andric   }
7510b57cec5SDimitry Andric 
7520b57cec5SDimitry Andric   fprintf(plotOut, "#proc legend\n"
7530b57cec5SDimitry Andric                    "   format: down\n"
7540b57cec5SDimitry Andric                    "   location: max max\n\n");
7550b57cec5SDimitry Andric   return;
7560b57cec5SDimitry Andric }
7570b57cec5SDimitry Andric 
outputEnvVariable(FILE * statsOut,char const * name)7580b57cec5SDimitry Andric static void outputEnvVariable(FILE *statsOut, char const *name) {
7590b57cec5SDimitry Andric   char const *value = getenv(name);
7600b57cec5SDimitry Andric   fprintf(statsOut, "# %s = %s\n", name, value ? value : "*unspecified*");
7610b57cec5SDimitry Andric }
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric /* Print some useful information about
7640b57cec5SDimitry Andric    * the date and time this experiment ran.
7650b57cec5SDimitry Andric    * the machine on which it ran.
7660b57cec5SDimitry Andric    We output all of this as stylised comments, though we may decide to parse
7670b57cec5SDimitry Andric    some of it. */
printHeaderInfo(FILE * statsOut)7680b57cec5SDimitry Andric void kmp_stats_output_module::printHeaderInfo(FILE *statsOut) {
7690b57cec5SDimitry Andric   std::time_t now = std::time(0);
7700b57cec5SDimitry Andric   char buffer[40];
7710b57cec5SDimitry Andric   char hostName[80];
7720b57cec5SDimitry Andric 
7730b57cec5SDimitry Andric   std::strftime(&buffer[0], sizeof(buffer), "%c", std::localtime(&now));
7740b57cec5SDimitry Andric   fprintf(statsOut, "# Time of run: %s\n", &buffer[0]);
7750b57cec5SDimitry Andric   if (gethostname(&hostName[0], sizeof(hostName)) == 0)
7760b57cec5SDimitry Andric     fprintf(statsOut, "# Hostname: %s\n", &hostName[0]);
7770b57cec5SDimitry Andric #if KMP_ARCH_X86 || KMP_ARCH_X86_64
7780b57cec5SDimitry Andric   fprintf(statsOut, "# CPU:  %s\n", &__kmp_cpuinfo.name[0]);
7790b57cec5SDimitry Andric   fprintf(statsOut, "# Family: %d, Model: %d, Stepping: %d\n",
7800b57cec5SDimitry Andric           __kmp_cpuinfo.family, __kmp_cpuinfo.model, __kmp_cpuinfo.stepping);
7810b57cec5SDimitry Andric   if (__kmp_cpuinfo.frequency == 0)
7820b57cec5SDimitry Andric     fprintf(statsOut, "# Nominal frequency: Unknown\n");
7830b57cec5SDimitry Andric   else
7840b57cec5SDimitry Andric     fprintf(statsOut, "# Nominal frequency: %sz\n",
7850b57cec5SDimitry Andric             formatSI(double(__kmp_cpuinfo.frequency), 9, 'H').c_str());
7860b57cec5SDimitry Andric   outputEnvVariable(statsOut, "KMP_HW_SUBSET");
7870b57cec5SDimitry Andric   outputEnvVariable(statsOut, "KMP_AFFINITY");
7880b57cec5SDimitry Andric   outputEnvVariable(statsOut, "KMP_BLOCKTIME");
7890b57cec5SDimitry Andric   outputEnvVariable(statsOut, "KMP_LIBRARY");
7900b57cec5SDimitry Andric   fprintf(statsOut, "# Production runtime built " __DATE__ " " __TIME__ "\n");
7910b57cec5SDimitry Andric #endif
7920b57cec5SDimitry Andric }
7930b57cec5SDimitry Andric 
outputStats(const char * heading)7940b57cec5SDimitry Andric void kmp_stats_output_module::outputStats(const char *heading) {
7950b57cec5SDimitry Andric   // Stop all the explicit timers in all threads
7960b57cec5SDimitry Andric   // Do this before declaring the local statistics because thay have
7970b57cec5SDimitry Andric   // constructors so will take time to create.
7980b57cec5SDimitry Andric   windupExplicitTimers();
7990b57cec5SDimitry Andric 
8000b57cec5SDimitry Andric   statistic allStats[TIMER_LAST];
8010b57cec5SDimitry Andric   statistic totalStats[TIMER_LAST]; /* Synthesized, cross threads versions of
8020b57cec5SDimitry Andric                                        normal timer stats */
8030b57cec5SDimitry Andric   statistic allCounters[COUNTER_LAST];
8040b57cec5SDimitry Andric 
805e8d8bef9SDimitry Andric   kmp_safe_raii_file_t statsOut;
806e8d8bef9SDimitry Andric   if (!outputFileName.empty()) {
807e8d8bef9SDimitry Andric     statsOut.open(outputFileName.c_str(), "a+");
808e8d8bef9SDimitry Andric   } else {
809e8d8bef9SDimitry Andric     statsOut.set_stderr();
810e8d8bef9SDimitry Andric   }
8110b57cec5SDimitry Andric 
812e8d8bef9SDimitry Andric   kmp_safe_raii_file_t eventsOut;
8130b57cec5SDimitry Andric   if (eventPrintingEnabled()) {
814e8d8bef9SDimitry Andric     eventsOut.open(eventsFileName, "w+");
8150b57cec5SDimitry Andric   }
8160b57cec5SDimitry Andric 
8170b57cec5SDimitry Andric   printHeaderInfo(statsOut);
8180b57cec5SDimitry Andric   fprintf(statsOut, "%s\n", heading);
8190b57cec5SDimitry Andric   // Accumulate across threads.
8200b57cec5SDimitry Andric   kmp_stats_list::iterator it;
8210b57cec5SDimitry Andric   for (it = __kmp_stats_list->begin(); it != __kmp_stats_list->end(); it++) {
8220b57cec5SDimitry Andric     int t = (*it)->getGtid();
8230b57cec5SDimitry Andric     // Output per thread stats if requested.
8240b57cec5SDimitry Andric     if (printPerThreadFlag) {
8250b57cec5SDimitry Andric       fprintf(statsOut, "Thread %d\n", t);
8260b57cec5SDimitry Andric       printTimerStats(statsOut, (*it)->getTimers(), 0);
8270b57cec5SDimitry Andric       printCounters(statsOut, (*it)->getCounters());
8280b57cec5SDimitry Andric       fprintf(statsOut, "\n");
8290b57cec5SDimitry Andric     }
8300b57cec5SDimitry Andric     // Output per thread events if requested.
8310b57cec5SDimitry Andric     if (eventPrintingEnabled()) {
8320b57cec5SDimitry Andric       kmp_stats_event_vector events = (*it)->getEventVector();
8330b57cec5SDimitry Andric       printEvents(eventsOut, &events, t);
8340b57cec5SDimitry Andric     }
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric     // Accumulate timers.
8370b57cec5SDimitry Andric     for (timer_e s = timer_e(0); s < TIMER_LAST; s = timer_e(s + 1)) {
8380b57cec5SDimitry Andric       // See if we should ignore this timer when aggregating
839*fe6060f1SDimitry Andric       if ((timeStat::masterOnly(s) && (t != 0)) || // Timer only valid on
840*fe6060f1SDimitry Andric           // primary thread and this thread is worker
8410b57cec5SDimitry Andric           (timeStat::workerOnly(s) && (t == 0)) // Timer only valid on worker
842*fe6060f1SDimitry Andric           // and this thread is the primary thread
8430b57cec5SDimitry Andric           ) {
8440b57cec5SDimitry Andric         continue;
8450b57cec5SDimitry Andric       }
8460b57cec5SDimitry Andric 
8470b57cec5SDimitry Andric       statistic *threadStat = (*it)->getTimer(s);
8480b57cec5SDimitry Andric       allStats[s] += *threadStat;
8490b57cec5SDimitry Andric 
8500b57cec5SDimitry Andric       // Add Total stats for timers that are valid in more than one thread
8510b57cec5SDimitry Andric       if (!timeStat::noTotal(s))
8520b57cec5SDimitry Andric         totalStats[s].addSample(threadStat->getTotal());
8530b57cec5SDimitry Andric     }
8540b57cec5SDimitry Andric 
8550b57cec5SDimitry Andric     // Accumulate counters.
8560b57cec5SDimitry Andric     for (counter_e c = counter_e(0); c < COUNTER_LAST; c = counter_e(c + 1)) {
8570b57cec5SDimitry Andric       if (counter::masterOnly(c) && t != 0)
8580b57cec5SDimitry Andric         continue;
859e8d8bef9SDimitry Andric       allCounters[c].addSample((double)(*it)->getCounter(c)->getValue());
8600b57cec5SDimitry Andric     }
8610b57cec5SDimitry Andric   }
8620b57cec5SDimitry Andric 
8630b57cec5SDimitry Andric   if (eventPrintingEnabled()) {
8640b57cec5SDimitry Andric     printPloticusFile();
8650b57cec5SDimitry Andric   }
8660b57cec5SDimitry Andric 
8670b57cec5SDimitry Andric   fprintf(statsOut, "Aggregate for all threads\n");
8680b57cec5SDimitry Andric   printTimerStats(statsOut, &allStats[0], &totalStats[0]);
8690b57cec5SDimitry Andric   fprintf(statsOut, "\n");
8700b57cec5SDimitry Andric   printCounterStats(statsOut, &allCounters[0]);
8710b57cec5SDimitry Andric }
8720b57cec5SDimitry Andric 
8730b57cec5SDimitry Andric /* *************  exported C functions ************** */
8740b57cec5SDimitry Andric 
8750b57cec5SDimitry Andric // no name mangling for these functions, we want the c files to be able to get
8760b57cec5SDimitry Andric // at these functions
8770b57cec5SDimitry Andric extern "C" {
8780b57cec5SDimitry Andric 
__kmp_reset_stats()8790b57cec5SDimitry Andric void __kmp_reset_stats() {
8800b57cec5SDimitry Andric   kmp_stats_list::iterator it;
8810b57cec5SDimitry Andric   for (it = __kmp_stats_list->begin(); it != __kmp_stats_list->end(); it++) {
8820b57cec5SDimitry Andric     timeStat *timers = (*it)->getTimers();
8830b57cec5SDimitry Andric     counter *counters = (*it)->getCounters();
8840b57cec5SDimitry Andric 
8850b57cec5SDimitry Andric     for (int t = 0; t < TIMER_LAST; t++)
8860b57cec5SDimitry Andric       timers[t].reset();
8870b57cec5SDimitry Andric 
8880b57cec5SDimitry Andric     for (int c = 0; c < COUNTER_LAST; c++)
8890b57cec5SDimitry Andric       counters[c].reset();
8900b57cec5SDimitry Andric 
8910b57cec5SDimitry Andric     // reset the event vector so all previous events are "erased"
8920b57cec5SDimitry Andric     (*it)->resetEventVector();
8930b57cec5SDimitry Andric   }
8940b57cec5SDimitry Andric }
8950b57cec5SDimitry Andric 
8960b57cec5SDimitry Andric // This function will reset all stats and stop all threads' explicit timers if
8970b57cec5SDimitry Andric // they haven't been stopped already.
__kmp_output_stats(const char * heading)8980b57cec5SDimitry Andric void __kmp_output_stats(const char *heading) {
8990b57cec5SDimitry Andric   __kmp_stats_global_output->outputStats(heading);
9000b57cec5SDimitry Andric   __kmp_reset_stats();
9010b57cec5SDimitry Andric }
9020b57cec5SDimitry Andric 
__kmp_accumulate_stats_at_exit(void)9030b57cec5SDimitry Andric void __kmp_accumulate_stats_at_exit(void) {
9040b57cec5SDimitry Andric   // Only do this once.
9050b57cec5SDimitry Andric   if (KMP_XCHG_FIXED32(&statsPrinted, 1) != 0)
9060b57cec5SDimitry Andric     return;
9070b57cec5SDimitry Andric 
9080b57cec5SDimitry Andric   __kmp_output_stats("Statistics on exit");
9090b57cec5SDimitry Andric }
9100b57cec5SDimitry Andric 
__kmp_stats_init(void)9110b57cec5SDimitry Andric void __kmp_stats_init(void) {
9120b57cec5SDimitry Andric   __kmp_init_tas_lock(&__kmp_stats_lock);
9130b57cec5SDimitry Andric   __kmp_stats_start_time = tsc_tick_count::now();
9140b57cec5SDimitry Andric   __kmp_stats_global_output = new kmp_stats_output_module();
9150b57cec5SDimitry Andric   __kmp_stats_list = new kmp_stats_list();
9160b57cec5SDimitry Andric }
9170b57cec5SDimitry Andric 
__kmp_stats_fini(void)9180b57cec5SDimitry Andric void __kmp_stats_fini(void) {
9190b57cec5SDimitry Andric   __kmp_accumulate_stats_at_exit();
9200b57cec5SDimitry Andric   __kmp_stats_list->deallocate();
9210b57cec5SDimitry Andric   delete __kmp_stats_global_output;
9220b57cec5SDimitry Andric   delete __kmp_stats_list;
9230b57cec5SDimitry Andric }
9240b57cec5SDimitry Andric 
9250b57cec5SDimitry Andric } // extern "C"
926