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