14cc4bb4cSJim Cownie /** @file kmp_stats.cpp
24cc4bb4cSJim Cownie  * Statistics gathering and processing.
34cc4bb4cSJim Cownie  */
44cc4bb4cSJim Cownie 
54cc4bb4cSJim Cownie //===----------------------------------------------------------------------===//
64cc4bb4cSJim Cownie //
757b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
857b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
957b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
104cc4bb4cSJim Cownie //
114cc4bb4cSJim Cownie //===----------------------------------------------------------------------===//
124cc4bb4cSJim Cownie 
134cc4bb4cSJim Cownie #include "kmp.h"
144cc4bb4cSJim Cownie #include "kmp_lock.h"
154cc4bb4cSJim Cownie #include "kmp_stats.h"
163041982dSJonathan Peyton #include "kmp_str.h"
174cc4bb4cSJim Cownie 
184cc4bb4cSJim Cownie #include <algorithm>
196e98d798SJonathan Peyton #include <ctime>
203041982dSJonathan Peyton #include <iomanip>
213041982dSJonathan Peyton #include <sstream>
223041982dSJonathan Peyton #include <stdlib.h> // for atexit
23f0682ac4SJonathan Peyton #include <cmath>
244cc4bb4cSJim Cownie 
254cc4bb4cSJim Cownie #define STRINGIZE2(x) #x
264cc4bb4cSJim Cownie #define STRINGIZE(x) STRINGIZE2(x)
274cc4bb4cSJim Cownie 
284cc4bb4cSJim Cownie #define expandName(name, flags, ignore) {STRINGIZE(name), flags},
294cc4bb4cSJim Cownie statInfo timeStat::timerInfo[] = {
303041982dSJonathan Peyton     KMP_FOREACH_TIMER(expandName, 0){"TIMER_LAST", 0}};
314cc4bb4cSJim Cownie const statInfo counter::counterInfo[] = {
323041982dSJonathan Peyton     KMP_FOREACH_COUNTER(expandName, 0){"COUNTER_LAST", 0}};
334cc4bb4cSJim Cownie #undef expandName
344cc4bb4cSJim Cownie 
354cc4bb4cSJim Cownie #define expandName(ignore1, ignore2, ignore3) {0.0, 0.0, 0.0},
364cc4bb4cSJim Cownie kmp_stats_output_module::rgb_color kmp_stats_output_module::timerColorInfo[] = {
373041982dSJonathan Peyton     KMP_FOREACH_TIMER(expandName, 0){0.0, 0.0, 0.0}};
384cc4bb4cSJim Cownie #undef expandName
394cc4bb4cSJim Cownie 
403041982dSJonathan Peyton const kmp_stats_output_module::rgb_color
413041982dSJonathan Peyton     kmp_stats_output_module::globalColorArray[] = {
424cc4bb4cSJim Cownie         {1.0, 0.0, 0.0}, // red
434cc4bb4cSJim Cownie         {1.0, 0.6, 0.0}, // orange
444cc4bb4cSJim Cownie         {1.0, 1.0, 0.0}, // yellow
454cc4bb4cSJim Cownie         {0.0, 1.0, 0.0}, // green
464cc4bb4cSJim Cownie         {0.0, 0.0, 1.0}, // blue
474cc4bb4cSJim Cownie         {0.6, 0.2, 0.8}, // purple
484cc4bb4cSJim Cownie         {1.0, 0.0, 1.0}, // magenta
494cc4bb4cSJim Cownie         {0.0, 0.4, 0.2}, // dark green
504cc4bb4cSJim Cownie         {1.0, 1.0, 0.6}, // light yellow
514cc4bb4cSJim Cownie         {0.6, 0.4, 0.6}, // dirty purple
524cc4bb4cSJim Cownie         {0.0, 1.0, 1.0}, // cyan
534cc4bb4cSJim Cownie         {1.0, 0.4, 0.8}, // pink
544cc4bb4cSJim Cownie         {0.5, 0.5, 0.5}, // grey
554cc4bb4cSJim Cownie         {0.8, 0.7, 0.5}, // brown
564cc4bb4cSJim Cownie         {0.6, 0.6, 1.0}, // light blue
574cc4bb4cSJim Cownie         {1.0, 0.7, 0.5}, // peach
584cc4bb4cSJim Cownie         {0.8, 0.5, 1.0}, // lavender
594cc4bb4cSJim Cownie         {0.6, 0.0, 0.0}, // dark red
604cc4bb4cSJim Cownie         {0.7, 0.6, 0.0}, // gold
614cc4bb4cSJim Cownie         {0.0, 0.0, 0.0} // black
624cc4bb4cSJim Cownie };
634cc4bb4cSJim Cownie 
644cc4bb4cSJim Cownie // Ensure that the atexit handler only runs once.
654cc4bb4cSJim Cownie static uint32_t statsPrinted = 0;
664cc4bb4cSJim Cownie 
674cc4bb4cSJim Cownie // output interface
685375fe82SJonathan Peyton static kmp_stats_output_module *__kmp_stats_global_output = NULL;
694cc4bb4cSJim Cownie 
706b316febSTerry Wilmarth double logHistogram::binMax[] = {1.e1l, 1.e2l, 1.e3l, 1.e4l, 1.e5l, 1.e6l,
716b316febSTerry Wilmarth                                  1.e7l, 1.e8l, 1.e9l, 1.e10l, 1.e11l, 1.e12l,
726b316febSTerry Wilmarth                                  1.e13l, 1.e14l, 1.e15l, 1.e16l, 1.e17l, 1.e18l,
736b316febSTerry Wilmarth                                  1.e19l, 1.e20l, 1.e21l, 1.e22l, 1.e23l, 1.e24l,
746b316febSTerry Wilmarth                                  1.e25l, 1.e26l, 1.e27l, 1.e28l, 1.e29l, 1.e30l,
756b316febSTerry Wilmarth                                  // Always have infinity be the last value
766b316febSTerry Wilmarth                                  std::numeric_limits<double>::infinity()};
77f0682ac4SJonathan Peyton 
784cc4bb4cSJim Cownie /* ************* statistic member functions ************* */
794cc4bb4cSJim Cownie 
addSample(double sample)803041982dSJonathan Peyton void statistic::addSample(double sample) {
81f0682ac4SJonathan Peyton   sample -= offset;
82f0682ac4SJonathan Peyton   KMP_DEBUG_ASSERT(std::isfinite(sample));
83f0682ac4SJonathan Peyton 
844cc4bb4cSJim Cownie   double delta = sample - meanVal;
854cc4bb4cSJim Cownie 
864cc4bb4cSJim Cownie   sampleCount = sampleCount + 1;
874cc4bb4cSJim Cownie   meanVal = meanVal + delta / sampleCount;
884cc4bb4cSJim Cownie   m2 = m2 + delta * (sample - meanVal);
894cc4bb4cSJim Cownie 
904cc4bb4cSJim Cownie   minVal = std::min(minVal, sample);
914cc4bb4cSJim Cownie   maxVal = std::max(maxVal, sample);
92f0682ac4SJonathan Peyton   if (collectingHist)
93f0682ac4SJonathan Peyton     hist.addSample(sample);
944cc4bb4cSJim Cownie }
954cc4bb4cSJim Cownie 
operator +=(const statistic & other)963041982dSJonathan Peyton statistic &statistic::operator+=(const statistic &other) {
97f0682ac4SJonathan Peyton   if (other.sampleCount == 0)
98f0682ac4SJonathan Peyton     return *this;
99f0682ac4SJonathan Peyton 
1003041982dSJonathan Peyton   if (sampleCount == 0) {
1014cc4bb4cSJim Cownie     *this = other;
1024cc4bb4cSJim Cownie     return *this;
1034cc4bb4cSJim Cownie   }
1044cc4bb4cSJim Cownie 
1054cc4bb4cSJim Cownie   uint64_t newSampleCount = sampleCount + other.sampleCount;
1064cc4bb4cSJim Cownie   double dnsc = double(newSampleCount);
1074cc4bb4cSJim Cownie   double dsc = double(sampleCount);
1084cc4bb4cSJim Cownie   double dscBydnsc = dsc / dnsc;
1094cc4bb4cSJim Cownie   double dosc = double(other.sampleCount);
1104cc4bb4cSJim Cownie   double delta = other.meanVal - meanVal;
1114cc4bb4cSJim Cownie 
1123041982dSJonathan Peyton   // Try to order these calculations to avoid overflows. If this were Fortran,
1133041982dSJonathan Peyton   // then the compiler would not be able to re-order over brackets. In C++ it
1143041982dSJonathan Peyton   // may be legal to do that (we certainly hope it doesn't, and CC+ Programming
1153041982dSJonathan Peyton   // Language 2nd edition suggests it shouldn't, since it says that exploitation
1163041982dSJonathan Peyton   // of associativity can only be made if the operation really is associative
1173041982dSJonathan Peyton   // (which floating addition isn't...)).
1184cc4bb4cSJim Cownie   meanVal = meanVal * dscBydnsc + other.meanVal * (1 - dscBydnsc);
1194cc4bb4cSJim Cownie   m2 = m2 + other.m2 + dscBydnsc * dosc * delta * delta;
1204cc4bb4cSJim Cownie   minVal = std::min(minVal, other.minVal);
1214cc4bb4cSJim Cownie   maxVal = std::max(maxVal, other.maxVal);
1224cc4bb4cSJim Cownie   sampleCount = newSampleCount;
123f0682ac4SJonathan Peyton   if (collectingHist)
124f0682ac4SJonathan Peyton     hist += other.hist;
1254cc4bb4cSJim Cownie 
1264cc4bb4cSJim Cownie   return *this;
1274cc4bb4cSJim Cownie }
1284cc4bb4cSJim Cownie 
scale(double factor)1293041982dSJonathan Peyton void statistic::scale(double factor) {
1304cc4bb4cSJim Cownie   minVal = minVal * factor;
1314cc4bb4cSJim Cownie   maxVal = maxVal * factor;
1324cc4bb4cSJim Cownie   meanVal = meanVal * factor;
1334cc4bb4cSJim Cownie   m2 = m2 * factor * factor;
1344cc4bb4cSJim Cownie   return;
1354cc4bb4cSJim Cownie }
1364cc4bb4cSJim Cownie 
format(char unit,bool total) const1373041982dSJonathan Peyton std::string statistic::format(char unit, bool total) const {
1386b316febSTerry Wilmarth   std::string result = formatSI((double)sampleCount, 9, ' ');
1394cc4bb4cSJim Cownie 
1403041982dSJonathan Peyton   if (sampleCount == 0) {
141c1a7c97cSJonathan Peyton     result = result + std::string(", ") + formatSI(0.0, 9, unit);
142c1a7c97cSJonathan Peyton     result = result + std::string(", ") + formatSI(0.0, 9, unit);
143c1a7c97cSJonathan Peyton     result = result + std::string(", ") + formatSI(0.0, 9, unit);
144c1a7c97cSJonathan Peyton     if (total)
145c1a7c97cSJonathan Peyton       result = result + std::string(", ") + formatSI(0.0, 9, unit);
146c1a7c97cSJonathan Peyton     result = result + std::string(", ") + formatSI(0.0, 9, unit);
1473041982dSJonathan Peyton   } else {
1484cc4bb4cSJim Cownie     result = result + std::string(", ") + formatSI(minVal, 9, unit);
1494cc4bb4cSJim Cownie     result = result + std::string(", ") + formatSI(meanVal, 9, unit);
1504cc4bb4cSJim Cownie     result = result + std::string(", ") + formatSI(maxVal, 9, unit);
1514cc4bb4cSJim Cownie     if (total)
1523041982dSJonathan Peyton       result =
1533041982dSJonathan Peyton           result + std::string(", ") + formatSI(meanVal * sampleCount, 9, unit);
1544cc4bb4cSJim Cownie     result = result + std::string(", ") + formatSI(getSD(), 9, unit);
155c1a7c97cSJonathan Peyton   }
1564cc4bb4cSJim Cownie   return result;
1574cc4bb4cSJim Cownie }
1584cc4bb4cSJim Cownie 
159f0682ac4SJonathan Peyton /* ************* histogram member functions ************* */
160f0682ac4SJonathan Peyton 
161f0682ac4SJonathan Peyton // Lowest bin that has anything in it
minBin() const162f0682ac4SJonathan Peyton int logHistogram::minBin() const {
163f0682ac4SJonathan Peyton   for (int i = 0; i < numBins; i++) {
164f0682ac4SJonathan Peyton     if (bins[i].count != 0)
165f0682ac4SJonathan Peyton       return i - logOffset;
166f0682ac4SJonathan Peyton   }
167f0682ac4SJonathan Peyton   return -logOffset;
168f0682ac4SJonathan Peyton }
169f0682ac4SJonathan Peyton 
170f0682ac4SJonathan Peyton // Highest bin that has anything in it
maxBin() const171f0682ac4SJonathan Peyton int logHistogram::maxBin() const {
172f0682ac4SJonathan Peyton   for (int i = numBins - 1; i >= 0; i--) {
173f0682ac4SJonathan Peyton     if (bins[i].count != 0)
174f0682ac4SJonathan Peyton       return i - logOffset;
175f0682ac4SJonathan Peyton   }
176f0682ac4SJonathan Peyton   return -logOffset;
177f0682ac4SJonathan Peyton }
178f0682ac4SJonathan Peyton 
179f0682ac4SJonathan Peyton // Which bin does this sample belong in ?
findBin(double sample)180f0682ac4SJonathan Peyton uint32_t logHistogram::findBin(double sample) {
181f0682ac4SJonathan Peyton   double v = std::fabs(sample);
182f0682ac4SJonathan Peyton   // Simply loop up looking which bin to put it in.
183f0682ac4SJonathan Peyton   // According to a micro-architect this is likely to be faster than a binary
184f0682ac4SJonathan Peyton   // search, since
185f0682ac4SJonathan Peyton   // it will only have one branch mis-predict
1866b316febSTerry Wilmarth   for (int b = 0; b < numBins - 1; b++)
187f0682ac4SJonathan Peyton     if (binMax[b] > v)
188f0682ac4SJonathan Peyton       return b;
1896b316febSTerry Wilmarth   return numBins - 1;
190f0682ac4SJonathan Peyton }
191f0682ac4SJonathan Peyton 
addSample(double sample)192f0682ac4SJonathan Peyton void logHistogram::addSample(double sample) {
193f0682ac4SJonathan Peyton   if (sample == 0.0) {
194f0682ac4SJonathan Peyton     zeroCount += 1;
195f0682ac4SJonathan Peyton #ifdef KMP_DEBUG
196f0682ac4SJonathan Peyton     _total++;
197f0682ac4SJonathan Peyton     check();
198f0682ac4SJonathan Peyton #endif
199f0682ac4SJonathan Peyton     return;
200f0682ac4SJonathan Peyton   }
201f0682ac4SJonathan Peyton   KMP_DEBUG_ASSERT(std::isfinite(sample));
202f0682ac4SJonathan Peyton   uint32_t bin = findBin(sample);
203f0682ac4SJonathan Peyton   KMP_DEBUG_ASSERT(0 <= bin && bin < numBins);
204f0682ac4SJonathan Peyton 
205f0682ac4SJonathan Peyton   bins[bin].count += 1;
206f0682ac4SJonathan Peyton   bins[bin].total += sample;
207f0682ac4SJonathan Peyton #ifdef KMP_DEBUG
208f0682ac4SJonathan Peyton   _total++;
209f0682ac4SJonathan Peyton   check();
210f0682ac4SJonathan Peyton #endif
211f0682ac4SJonathan Peyton }
212f0682ac4SJonathan Peyton 
213f0682ac4SJonathan Peyton // This may not be the format we want, but it'll do for now
format(char unit) const214f0682ac4SJonathan Peyton std::string logHistogram::format(char unit) const {
215f0682ac4SJonathan Peyton   std::stringstream result;
216f0682ac4SJonathan Peyton 
217f0682ac4SJonathan Peyton   result << "Bin,                Count,     Total\n";
218f0682ac4SJonathan Peyton   if (zeroCount) {
219f0682ac4SJonathan Peyton     result << "0,              " << formatSI(zeroCount, 9, ' ') << ", ",
220f0682ac4SJonathan Peyton         formatSI(0.0, 9, unit);
221f0682ac4SJonathan Peyton     if (count(minBin()) == 0)
222f0682ac4SJonathan Peyton       return result.str();
223f0682ac4SJonathan Peyton     result << "\n";
224f0682ac4SJonathan Peyton   }
225f0682ac4SJonathan Peyton   for (int i = minBin(); i <= maxBin(); i++) {
2266b316febSTerry Wilmarth     result << "10**" << i << "<=v<";
2276b316febSTerry Wilmarth     if (i + 1 == numBins - 1)
2286b316febSTerry Wilmarth       result << "infinity, ";
2296b316febSTerry Wilmarth     else
2306b316febSTerry Wilmarth       result << "10**" << (i + 1) << ", ";
2316b316febSTerry Wilmarth     result << formatSI(count(i), 9, ' ') << ", " << formatSI(total(i), 9, unit);
232f0682ac4SJonathan Peyton     if (i != maxBin())
233f0682ac4SJonathan Peyton       result << "\n";
234f0682ac4SJonathan Peyton   }
235f0682ac4SJonathan Peyton 
236f0682ac4SJonathan Peyton   return result.str();
237f0682ac4SJonathan Peyton }
238f0682ac4SJonathan Peyton 
2394cc4bb4cSJim Cownie /* ************* explicitTimer member functions ************* */
2404cc4bb4cSJim Cownie 
start(tsc_tick_count tick)241f0682ac4SJonathan Peyton void explicitTimer::start(tsc_tick_count tick) {
242f0682ac4SJonathan Peyton   startTime = tick;
24311dc82faSJonathan Peyton   totalPauseTime = 0;
2444cc4bb4cSJim Cownie   if (timeStat::logEvent(timerEnumValue)) {
2454cc4bb4cSJim Cownie     __kmp_stats_thread_ptr->incrementNestValue();
2464cc4bb4cSJim Cownie   }
2474cc4bb4cSJim Cownie   return;
2484cc4bb4cSJim Cownie }
2494cc4bb4cSJim Cownie 
stop(tsc_tick_count tick,kmp_stats_list * stats_ptr)250f0682ac4SJonathan Peyton void explicitTimer::stop(tsc_tick_count tick,
2513041982dSJonathan Peyton                          kmp_stats_list *stats_ptr /* = nullptr */) {
2524cc4bb4cSJim Cownie   if (startTime.getValue() == 0)
2534cc4bb4cSJim Cownie     return;
2544cc4bb4cSJim Cownie 
255f0682ac4SJonathan Peyton   stat->addSample(((tick - startTime) - totalPauseTime).ticks());
2564cc4bb4cSJim Cownie 
2574cc4bb4cSJim Cownie   if (timeStat::logEvent(timerEnumValue)) {
2585375fe82SJonathan Peyton     if (!stats_ptr)
2595375fe82SJonathan Peyton       stats_ptr = __kmp_stats_thread_ptr;
2603041982dSJonathan Peyton     stats_ptr->push_event(
2613041982dSJonathan Peyton         startTime.getValue() - __kmp_stats_start_time.getValue(),
262f0682ac4SJonathan Peyton         tick.getValue() - __kmp_stats_start_time.getValue(),
2633041982dSJonathan Peyton         __kmp_stats_thread_ptr->getNestValue(), timerEnumValue);
2645375fe82SJonathan Peyton     stats_ptr->decrementNestValue();
2654cc4bb4cSJim Cownie   }
2664cc4bb4cSJim Cownie 
2673041982dSJonathan Peyton   /* We accept the risk that we drop a sample because it really did start at
2683041982dSJonathan Peyton      t==0. */
2694cc4bb4cSJim Cownie   startTime = 0;
2704cc4bb4cSJim Cownie   return;
2714cc4bb4cSJim Cownie }
2724cc4bb4cSJim Cownie 
27311dc82faSJonathan Peyton /* ************* partitionedTimers member functions ************* */
partitionedTimers()2743041982dSJonathan Peyton partitionedTimers::partitionedTimers() { timer_stack.reserve(8); }
27511dc82faSJonathan Peyton 
27642016791SKazuaki Ishizaki // initialize the partitioned timers to an initial timer
init(explicitTimer timer)277f0682ac4SJonathan Peyton void partitionedTimers::init(explicitTimer timer) {
27811dc82faSJonathan Peyton   KMP_DEBUG_ASSERT(this->timer_stack.size() == 0);
279f0682ac4SJonathan Peyton   timer_stack.push_back(timer);
280f0682ac4SJonathan Peyton   timer_stack.back().start(tsc_tick_count::now());
28111dc82faSJonathan Peyton }
28211dc82faSJonathan Peyton 
28311dc82faSJonathan Peyton // stop/save the current timer, and start the new timer (timer_pair)
28411dc82faSJonathan Peyton // There is a special condition where if the current timer is equal to
28511dc82faSJonathan Peyton // the one you are trying to push, then it only manipulates the stack,
28611dc82faSJonathan Peyton // and it won't stop/start the currently running timer.
push(explicitTimer timer)287f0682ac4SJonathan Peyton void partitionedTimers::push(explicitTimer timer) {
28811dc82faSJonathan Peyton   // get the current timer
289f0682ac4SJonathan Peyton   // pause current timer
29011dc82faSJonathan Peyton   // push new timer
29111dc82faSJonathan Peyton   // start the new timer
292f0682ac4SJonathan Peyton   explicitTimer *current_timer, *new_timer;
293f0682ac4SJonathan Peyton   size_t stack_size;
29411dc82faSJonathan Peyton   KMP_DEBUG_ASSERT(this->timer_stack.size() > 0);
295f0682ac4SJonathan Peyton   timer_stack.push_back(timer);
296f0682ac4SJonathan Peyton   stack_size = timer_stack.size();
297f0682ac4SJonathan Peyton   current_timer = &(timer_stack[stack_size - 2]);
298f0682ac4SJonathan Peyton   new_timer = &(timer_stack[stack_size - 1]);
299f0682ac4SJonathan Peyton   tsc_tick_count tick = tsc_tick_count::now();
300f0682ac4SJonathan Peyton   current_timer->pause(tick);
301f0682ac4SJonathan Peyton   new_timer->start(tick);
30211dc82faSJonathan Peyton }
30311dc82faSJonathan Peyton 
30411dc82faSJonathan Peyton // stop/discard the current timer, and start the previously saved timer
pop()30511dc82faSJonathan Peyton void partitionedTimers::pop() {
30611dc82faSJonathan Peyton   // get the current timer
307f0682ac4SJonathan Peyton   // stop current timer (record event/sample)
30811dc82faSJonathan Peyton   // pop current timer
309f0682ac4SJonathan Peyton   // get the new current timer and resume
310f0682ac4SJonathan Peyton   explicitTimer *old_timer, *new_timer;
311f0682ac4SJonathan Peyton   size_t stack_size = timer_stack.size();
312f0682ac4SJonathan Peyton   KMP_DEBUG_ASSERT(stack_size > 1);
313f0682ac4SJonathan Peyton   old_timer = &(timer_stack[stack_size - 1]);
314f0682ac4SJonathan Peyton   new_timer = &(timer_stack[stack_size - 2]);
315f0682ac4SJonathan Peyton   tsc_tick_count tick = tsc_tick_count::now();
316f0682ac4SJonathan Peyton   old_timer->stop(tick);
317f0682ac4SJonathan Peyton   new_timer->resume(tick);
31811dc82faSJonathan Peyton   timer_stack.pop_back();
31911dc82faSJonathan Peyton }
320f0682ac4SJonathan Peyton 
exchange(explicitTimer timer)321f0682ac4SJonathan Peyton void partitionedTimers::exchange(explicitTimer timer) {
322f0682ac4SJonathan Peyton   // get the current timer
323f0682ac4SJonathan Peyton   // stop current timer (record event/sample)
324f0682ac4SJonathan Peyton   // push new timer
325f0682ac4SJonathan Peyton   // start the new timer
326f0682ac4SJonathan Peyton   explicitTimer *current_timer, *new_timer;
327f0682ac4SJonathan Peyton   size_t stack_size;
328f0682ac4SJonathan Peyton   KMP_DEBUG_ASSERT(this->timer_stack.size() > 0);
329f0682ac4SJonathan Peyton   tsc_tick_count tick = tsc_tick_count::now();
330f0682ac4SJonathan Peyton   stack_size = timer_stack.size();
331f0682ac4SJonathan Peyton   current_timer = &(timer_stack[stack_size - 1]);
332f0682ac4SJonathan Peyton   current_timer->stop(tick);
333f0682ac4SJonathan Peyton   timer_stack.pop_back();
334f0682ac4SJonathan Peyton   timer_stack.push_back(timer);
335f0682ac4SJonathan Peyton   new_timer = &(timer_stack[stack_size - 1]);
336f0682ac4SJonathan Peyton   new_timer->start(tick);
33711dc82faSJonathan Peyton }
33811dc82faSJonathan Peyton 
33911dc82faSJonathan Peyton // Wind up all the currently running timers.
34011dc82faSJonathan Peyton // This pops off all the timers from the stack and clears the stack
34111dc82faSJonathan Peyton // After this is called, init() must be run again to initialize the
34211dc82faSJonathan Peyton // stack of timers
windup()34311dc82faSJonathan Peyton void partitionedTimers::windup() {
34411dc82faSJonathan Peyton   while (timer_stack.size() > 1) {
34511dc82faSJonathan Peyton     this->pop();
34611dc82faSJonathan Peyton   }
347f0682ac4SJonathan Peyton   // Pop the timer from the init() call
34811dc82faSJonathan Peyton   if (timer_stack.size() > 0) {
349f0682ac4SJonathan Peyton     timer_stack.back().stop(tsc_tick_count::now());
35011dc82faSJonathan Peyton     timer_stack.pop_back();
35111dc82faSJonathan Peyton   }
35211dc82faSJonathan Peyton }
35311dc82faSJonathan Peyton 
3544cc4bb4cSJim Cownie /* ************* kmp_stats_event_vector member functions ************* */
3554cc4bb4cSJim Cownie 
deallocate()3564cc4bb4cSJim Cownie void kmp_stats_event_vector::deallocate() {
3574cc4bb4cSJim Cownie   __kmp_free(events);
3584cc4bb4cSJim Cownie   internal_size = 0;
3594cc4bb4cSJim Cownie   allocated_size = 0;
3604cc4bb4cSJim Cownie   events = NULL;
3614cc4bb4cSJim Cownie }
3624cc4bb4cSJim Cownie 
3634cc4bb4cSJim Cownie // This function is for qsort() which requires the compare function to return
3643041982dSJonathan Peyton // either a negative number if event1 < event2, a positive number if event1 >
3653041982dSJonathan Peyton // event2 or zero if event1 == event2. This sorts by start time (lowest to
3663041982dSJonathan Peyton // highest).
compare_two_events(const void * event1,const void * event2)3674cc4bb4cSJim Cownie int compare_two_events(const void *event1, const void *event2) {
368f0682ac4SJonathan Peyton   const kmp_stats_event *ev1 = RCAST(const kmp_stats_event *, event1);
369f0682ac4SJonathan Peyton   const kmp_stats_event *ev2 = RCAST(const kmp_stats_event *, event2);
3704cc4bb4cSJim Cownie 
3713041982dSJonathan Peyton   if (ev1->getStart() < ev2->getStart())
3723041982dSJonathan Peyton     return -1;
3733041982dSJonathan Peyton   else if (ev1->getStart() > ev2->getStart())
3743041982dSJonathan Peyton     return 1;
3753041982dSJonathan Peyton   else
3763041982dSJonathan Peyton     return 0;
3774cc4bb4cSJim Cownie }
3784cc4bb4cSJim Cownie 
sort()3794cc4bb4cSJim Cownie void kmp_stats_event_vector::sort() {
3804cc4bb4cSJim Cownie   qsort(events, internal_size, sizeof(kmp_stats_event), compare_two_events);
3814cc4bb4cSJim Cownie }
3824cc4bb4cSJim Cownie 
3834cc4bb4cSJim Cownie /* ************* kmp_stats_list member functions ************* */
3844cc4bb4cSJim Cownie 
3854cc4bb4cSJim Cownie // returns a pointer to newly created stats node
push_back(int gtid)3864cc4bb4cSJim Cownie kmp_stats_list *kmp_stats_list::push_back(int gtid) {
3873041982dSJonathan Peyton   kmp_stats_list *newnode =
3883041982dSJonathan Peyton       (kmp_stats_list *)__kmp_allocate(sizeof(kmp_stats_list));
3893041982dSJonathan Peyton   // placement new, only requires space and pointer and initializes (so
3903041982dSJonathan Peyton   // __kmp_allocate instead of C++ new[] is used)
3914cc4bb4cSJim Cownie   new (newnode) kmp_stats_list();
3924cc4bb4cSJim Cownie   newnode->setGtid(gtid);
3934cc4bb4cSJim Cownie   newnode->prev = this->prev;
3944cc4bb4cSJim Cownie   newnode->next = this;
3954cc4bb4cSJim Cownie   newnode->prev->next = newnode;
3964cc4bb4cSJim Cownie   newnode->next->prev = newnode;
3974cc4bb4cSJim Cownie   return newnode;
3984cc4bb4cSJim Cownie }
deallocate()3994cc4bb4cSJim Cownie void kmp_stats_list::deallocate() {
4004cc4bb4cSJim Cownie   kmp_stats_list *ptr = this->next;
4014cc4bb4cSJim Cownie   kmp_stats_list *delptr = this->next;
4024cc4bb4cSJim Cownie   while (ptr != this) {
4034cc4bb4cSJim Cownie     delptr = ptr;
4044cc4bb4cSJim Cownie     ptr = ptr->next;
4054cc4bb4cSJim Cownie     // placement new means we have to explicitly call destructor.
4064cc4bb4cSJim Cownie     delptr->_event_vector.deallocate();
4074cc4bb4cSJim Cownie     delptr->~kmp_stats_list();
4084cc4bb4cSJim Cownie     __kmp_free(delptr);
4094cc4bb4cSJim Cownie   }
4104cc4bb4cSJim Cownie }
begin()4114cc4bb4cSJim Cownie kmp_stats_list::iterator kmp_stats_list::begin() {
4124cc4bb4cSJim Cownie   kmp_stats_list::iterator it;
4134cc4bb4cSJim Cownie   it.ptr = this->next;
4144cc4bb4cSJim Cownie   return it;
4154cc4bb4cSJim Cownie }
end()4164cc4bb4cSJim Cownie kmp_stats_list::iterator kmp_stats_list::end() {
4174cc4bb4cSJim Cownie   kmp_stats_list::iterator it;
4184cc4bb4cSJim Cownie   it.ptr = this;
4194cc4bb4cSJim Cownie   return it;
4204cc4bb4cSJim Cownie }
size()4214cc4bb4cSJim Cownie int kmp_stats_list::size() {
4224cc4bb4cSJim Cownie   int retval;
4234cc4bb4cSJim Cownie   kmp_stats_list::iterator it;
4243041982dSJonathan Peyton   for (retval = 0, it = begin(); it != end(); it++, retval++) {
4253041982dSJonathan Peyton   }
4264cc4bb4cSJim Cownie   return retval;
4274cc4bb4cSJim Cownie }
4284cc4bb4cSJim Cownie 
4294cc4bb4cSJim Cownie /* ************* kmp_stats_list::iterator member functions ************* */
4304cc4bb4cSJim Cownie 
iterator()4314cc4bb4cSJim Cownie kmp_stats_list::iterator::iterator() : ptr(NULL) {}
~iterator()4324cc4bb4cSJim Cownie kmp_stats_list::iterator::~iterator() {}
operator ++()4334cc4bb4cSJim Cownie kmp_stats_list::iterator kmp_stats_list::iterator::operator++() {
4344cc4bb4cSJim Cownie   this->ptr = this->ptr->next;
4354cc4bb4cSJim Cownie   return *this;
4364cc4bb4cSJim Cownie }
operator ++(int dummy)4374cc4bb4cSJim Cownie kmp_stats_list::iterator kmp_stats_list::iterator::operator++(int dummy) {
4384cc4bb4cSJim Cownie   this->ptr = this->ptr->next;
4394cc4bb4cSJim Cownie   return *this;
4404cc4bb4cSJim Cownie }
operator --()4414cc4bb4cSJim Cownie kmp_stats_list::iterator kmp_stats_list::iterator::operator--() {
4424cc4bb4cSJim Cownie   this->ptr = this->ptr->prev;
4434cc4bb4cSJim Cownie   return *this;
4444cc4bb4cSJim Cownie }
operator --(int dummy)4454cc4bb4cSJim Cownie kmp_stats_list::iterator kmp_stats_list::iterator::operator--(int dummy) {
4464cc4bb4cSJim Cownie   this->ptr = this->ptr->prev;
4474cc4bb4cSJim Cownie   return *this;
4484cc4bb4cSJim Cownie }
operator !=(const kmp_stats_list::iterator & rhs)4494cc4bb4cSJim Cownie bool kmp_stats_list::iterator::operator!=(const kmp_stats_list::iterator &rhs) {
4504cc4bb4cSJim Cownie   return this->ptr != rhs.ptr;
4514cc4bb4cSJim Cownie }
operator ==(const kmp_stats_list::iterator & rhs)4524cc4bb4cSJim Cownie bool kmp_stats_list::iterator::operator==(const kmp_stats_list::iterator &rhs) {
4534cc4bb4cSJim Cownie   return this->ptr == rhs.ptr;
4544cc4bb4cSJim Cownie }
operator *() const4554cc4bb4cSJim Cownie kmp_stats_list *kmp_stats_list::iterator::operator*() const {
4564cc4bb4cSJim Cownie   return this->ptr;
4574cc4bb4cSJim Cownie }
4584cc4bb4cSJim Cownie 
4594cc4bb4cSJim Cownie /* *************  kmp_stats_output_module functions ************** */
4604cc4bb4cSJim Cownie 
4614cc4bb4cSJim Cownie const char *kmp_stats_output_module::eventsFileName = NULL;
4624cc4bb4cSJim Cownie const char *kmp_stats_output_module::plotFileName = NULL;
4634cc4bb4cSJim Cownie int kmp_stats_output_module::printPerThreadFlag = 0;
4644cc4bb4cSJim Cownie int kmp_stats_output_module::printPerThreadEventsFlag = 0;
4654cc4bb4cSJim Cownie 
lastName(char * name)466f0682ac4SJonathan Peyton static char const *lastName(char *name) {
4676b316febSTerry Wilmarth   int l = (int)strlen(name);
468f0682ac4SJonathan Peyton   for (int i = l - 1; i >= 0; --i) {
469f0682ac4SJonathan Peyton     if (name[i] == '.')
470f0682ac4SJonathan Peyton       name[i] = '_';
471f0682ac4SJonathan Peyton     if (name[i] == '/')
472f0682ac4SJonathan Peyton       return name + i + 1;
473f0682ac4SJonathan Peyton   }
474f0682ac4SJonathan Peyton   return name;
475f0682ac4SJonathan Peyton }
476f0682ac4SJonathan Peyton 
477f0682ac4SJonathan Peyton /* Read the name of the executable from /proc/self/cmdline */
getImageName(char * buffer,size_t buflen)478f0682ac4SJonathan Peyton static char const *getImageName(char *buffer, size_t buflen) {
479f0682ac4SJonathan Peyton   FILE *f = fopen("/proc/self/cmdline", "r");
480f0682ac4SJonathan Peyton   buffer[0] = char(0);
481f0682ac4SJonathan Peyton   if (!f)
482f0682ac4SJonathan Peyton     return buffer;
483f0682ac4SJonathan Peyton 
484f0682ac4SJonathan Peyton   // The file contains char(0) delimited words from the commandline.
485f0682ac4SJonathan Peyton   // This just returns the last filename component of the first word on the
486f0682ac4SJonathan Peyton   // line.
487f0682ac4SJonathan Peyton   size_t n = fread(buffer, 1, buflen, f);
488f0682ac4SJonathan Peyton   if (n == 0) {
489f0682ac4SJonathan Peyton     fclose(f);
490f0682ac4SJonathan Peyton     KMP_CHECK_SYSFAIL("fread", 1)
491f0682ac4SJonathan Peyton   }
492f0682ac4SJonathan Peyton   fclose(f);
493f0682ac4SJonathan Peyton   buffer[buflen - 1] = char(0);
494f0682ac4SJonathan Peyton   return lastName(buffer);
495f0682ac4SJonathan Peyton }
496f0682ac4SJonathan Peyton 
getTime(char * buffer,size_t buflen,bool underscores=false)497f0682ac4SJonathan Peyton static void getTime(char *buffer, size_t buflen, bool underscores = false) {
498f0682ac4SJonathan Peyton   time_t timer;
499f0682ac4SJonathan Peyton 
500f0682ac4SJonathan Peyton   time(&timer);
501f0682ac4SJonathan Peyton 
502f0682ac4SJonathan Peyton   struct tm *tm_info = localtime(&timer);
503f0682ac4SJonathan Peyton   if (underscores)
504f0682ac4SJonathan Peyton     strftime(buffer, buflen, "%Y-%m-%d_%H%M%S", tm_info);
505f0682ac4SJonathan Peyton   else
506f0682ac4SJonathan Peyton     strftime(buffer, buflen, "%Y-%m-%d %H%M%S", tm_info);
507f0682ac4SJonathan Peyton }
508f0682ac4SJonathan Peyton 
509f0682ac4SJonathan Peyton /* Generate a stats file name, expanding prototypes */
generateFilename(char const * prototype,char const * imageName)510f0682ac4SJonathan Peyton static std::string generateFilename(char const *prototype,
511f0682ac4SJonathan Peyton                                     char const *imageName) {
512f0682ac4SJonathan Peyton   std::string res;
513f0682ac4SJonathan Peyton 
514f0682ac4SJonathan Peyton   for (int i = 0; prototype[i] != char(0); i++) {
515f0682ac4SJonathan Peyton     char ch = prototype[i];
516f0682ac4SJonathan Peyton 
517f0682ac4SJonathan Peyton     if (ch == '%') {
518f0682ac4SJonathan Peyton       i++;
519f0682ac4SJonathan Peyton       if (prototype[i] == char(0))
520f0682ac4SJonathan Peyton         break;
521f0682ac4SJonathan Peyton 
522f0682ac4SJonathan Peyton       switch (prototype[i]) {
523f0682ac4SJonathan Peyton       case 't': // Insert time and date
524f0682ac4SJonathan Peyton       {
525f0682ac4SJonathan Peyton         char date[26];
526f0682ac4SJonathan Peyton         getTime(date, sizeof(date), true);
527f0682ac4SJonathan Peyton         res += date;
528f0682ac4SJonathan Peyton       } break;
529f0682ac4SJonathan Peyton       case 'e': // Insert executable name
530f0682ac4SJonathan Peyton         res += imageName;
531f0682ac4SJonathan Peyton         break;
532f0682ac4SJonathan Peyton       case 'p': // Insert pid
533f0682ac4SJonathan Peyton       {
534f0682ac4SJonathan Peyton         std::stringstream ss;
535f0682ac4SJonathan Peyton         ss << getpid();
536f0682ac4SJonathan Peyton         res += ss.str();
537f0682ac4SJonathan Peyton       } break;
538f0682ac4SJonathan Peyton       default:
539f0682ac4SJonathan Peyton         res += prototype[i];
540f0682ac4SJonathan Peyton         break;
541f0682ac4SJonathan Peyton       }
542f0682ac4SJonathan Peyton     } else
543f0682ac4SJonathan Peyton       res += ch;
544f0682ac4SJonathan Peyton   }
545f0682ac4SJonathan Peyton   return res;
546f0682ac4SJonathan Peyton }
547f0682ac4SJonathan Peyton 
5483041982dSJonathan Peyton // init() is called very near the beginning of execution time in the constructor
5493041982dSJonathan Peyton // of __kmp_stats_global_output
init()5503041982dSJonathan Peyton void kmp_stats_output_module::init() {
551f0682ac4SJonathan Peyton 
5524cc4bb4cSJim Cownie   char *statsFileName = getenv("KMP_STATS_FILE");
5534cc4bb4cSJim Cownie   eventsFileName = getenv("KMP_STATS_EVENTS_FILE");
5544cc4bb4cSJim Cownie   plotFileName = getenv("KMP_STATS_PLOT_FILE");
5554cc4bb4cSJim Cownie   char *threadStats = getenv("KMP_STATS_THREADS");
5564cc4bb4cSJim Cownie   char *threadEvents = getenv("KMP_STATS_EVENTS");
5574cc4bb4cSJim Cownie 
5584cc4bb4cSJim Cownie   // set the stats output filenames based on environment variables and defaults
55998b76f6fSJonathan Peyton   if (statsFileName) {
560f0682ac4SJonathan Peyton     char imageName[1024];
561f0682ac4SJonathan Peyton     // Process any escapes (e.g., %p, %e, %t) in the name
562f0682ac4SJonathan Peyton     outputFileName = generateFilename(
563f0682ac4SJonathan Peyton         statsFileName, getImageName(&imageName[0], sizeof(imageName)));
56498b76f6fSJonathan Peyton   }
5654cc4bb4cSJim Cownie   eventsFileName = eventsFileName ? eventsFileName : "events.dat";
5664cc4bb4cSJim Cownie   plotFileName = plotFileName ? plotFileName : "events.plt";
5674cc4bb4cSJim Cownie 
5683041982dSJonathan Peyton   // set the flags based on environment variables matching: true, on, 1, .true.
5693041982dSJonathan Peyton   // , .t. , yes
5704cc4bb4cSJim Cownie   printPerThreadFlag = __kmp_str_match_true(threadStats);
5714cc4bb4cSJim Cownie   printPerThreadEventsFlag = __kmp_str_match_true(threadEvents);
5724cc4bb4cSJim Cownie 
5734cc4bb4cSJim Cownie   if (printPerThreadEventsFlag) {
5744cc4bb4cSJim Cownie     // assigns a color to each timer for printing
5754cc4bb4cSJim Cownie     setupEventColors();
5764cc4bb4cSJim Cownie   } else {
5774cc4bb4cSJim Cownie     // will clear flag so that no event will be logged
5784cc4bb4cSJim Cownie     timeStat::clearEventFlags();
5794cc4bb4cSJim Cownie   }
5804cc4bb4cSJim Cownie }
5814cc4bb4cSJim Cownie 
setupEventColors()5824cc4bb4cSJim Cownie void kmp_stats_output_module::setupEventColors() {
5834cc4bb4cSJim Cownie   int i;
5844cc4bb4cSJim Cownie   int globalColorIndex = 0;
5854cc4bb4cSJim Cownie   int numGlobalColors = sizeof(globalColorArray) / sizeof(rgb_color);
5864cc4bb4cSJim Cownie   for (i = 0; i < TIMER_LAST; i++) {
5874cc4bb4cSJim Cownie     if (timeStat::logEvent((timer_e)i)) {
5884cc4bb4cSJim Cownie       timerColorInfo[i] = globalColorArray[globalColorIndex];
5894cc4bb4cSJim Cownie       globalColorIndex = (globalColorIndex + 1) % numGlobalColors;
5904cc4bb4cSJim Cownie     }
5914cc4bb4cSJim Cownie   }
5924cc4bb4cSJim Cownie }
5934cc4bb4cSJim Cownie 
printTimerStats(FILE * statsOut,statistic const * theStats,statistic const * totalStats)5943041982dSJonathan Peyton void kmp_stats_output_module::printTimerStats(FILE *statsOut,
5953041982dSJonathan Peyton                                               statistic const *theStats,
5963041982dSJonathan Peyton                                               statistic const *totalStats) {
597f0682ac4SJonathan Peyton   fprintf(statsOut,
598f0682ac4SJonathan Peyton           "Timer,                             SampleCount,    Min,      "
5993041982dSJonathan Peyton           "Mean,       Max,     Total,        SD\n");
6006e98d798SJonathan Peyton   for (timer_e s = timer_e(0); s < TIMER_LAST; s = timer_e(s + 1)) {
6014cc4bb4cSJim Cownie     statistic const *stat = &theStats[s];
6026e98d798SJonathan Peyton     char tag = timeStat::noUnits(s) ? ' ' : 'T';
603e2554af8SJonathan Peyton 
604f0682ac4SJonathan Peyton     fprintf(statsOut, "%-35s, %s\n", timeStat::name(s),
6053041982dSJonathan Peyton             stat->format(tag, true).c_str());
60653eca521SJonathan Peyton   }
607e2554af8SJonathan Peyton   // Also print the Total_ versions of times.
60853eca521SJonathan Peyton   for (timer_e s = timer_e(0); s < TIMER_LAST; s = timer_e(s + 1)) {
60953eca521SJonathan Peyton     char tag = timeStat::noUnits(s) ? ' ' : 'T';
6106e98d798SJonathan Peyton     if (totalStats && !timeStat::noTotal(s))
611f0682ac4SJonathan Peyton       fprintf(statsOut, "Total_%-29s, %s\n", timeStat::name(s),
6123041982dSJonathan Peyton               totalStats[s].format(tag, true).c_str());
6134cc4bb4cSJim Cownie   }
614f0682ac4SJonathan Peyton 
61542016791SKazuaki Ishizaki   // Print histogram of statistics
616f0682ac4SJonathan Peyton   if (theStats[0].haveHist()) {
617f0682ac4SJonathan Peyton     fprintf(statsOut, "\nTimer distributions\n");
618f0682ac4SJonathan Peyton     for (int s = 0; s < TIMER_LAST; s++) {
619f0682ac4SJonathan Peyton       statistic const *stat = &theStats[s];
620f0682ac4SJonathan Peyton 
621f0682ac4SJonathan Peyton       if (stat->getCount() != 0) {
622f0682ac4SJonathan Peyton         char tag = timeStat::noUnits(timer_e(s)) ? ' ' : 'T';
623f0682ac4SJonathan Peyton 
624f0682ac4SJonathan Peyton         fprintf(statsOut, "%s\n", timeStat::name(timer_e(s)));
625f0682ac4SJonathan Peyton         fprintf(statsOut, "%s\n", stat->getHist()->format(tag).c_str());
626f0682ac4SJonathan Peyton       }
627f0682ac4SJonathan Peyton     }
628f0682ac4SJonathan Peyton   }
629e2554af8SJonathan Peyton }
630e2554af8SJonathan Peyton 
printCounterStats(FILE * statsOut,statistic const * theStats)6313041982dSJonathan Peyton void kmp_stats_output_module::printCounterStats(FILE *statsOut,
6323041982dSJonathan Peyton                                                 statistic const *theStats) {
6333041982dSJonathan Peyton   fprintf(statsOut, "Counter,                 ThreadCount,    Min,      Mean,  "
6343041982dSJonathan Peyton                     "     Max,     Total,        SD\n");
6354cc4bb4cSJim Cownie   for (int s = 0; s < COUNTER_LAST; s++) {
6364cc4bb4cSJim Cownie     statistic const *stat = &theStats[s];
6373041982dSJonathan Peyton     fprintf(statsOut, "%-25s, %s\n", counter::name(counter_e(s)),
6383041982dSJonathan Peyton             stat->format(' ', true).c_str());
6394cc4bb4cSJim Cownie   }
640f0682ac4SJonathan Peyton   // Print histogram of counters
641f0682ac4SJonathan Peyton   if (theStats[0].haveHist()) {
642f0682ac4SJonathan Peyton     fprintf(statsOut, "\nCounter distributions\n");
643f0682ac4SJonathan Peyton     for (int s = 0; s < COUNTER_LAST; s++) {
644f0682ac4SJonathan Peyton       statistic const *stat = &theStats[s];
645f0682ac4SJonathan Peyton 
646f0682ac4SJonathan Peyton       if (stat->getCount() != 0) {
647f0682ac4SJonathan Peyton         fprintf(statsOut, "%s\n", counter::name(counter_e(s)));
648f0682ac4SJonathan Peyton         fprintf(statsOut, "%s\n", stat->getHist()->format(' ').c_str());
649f0682ac4SJonathan Peyton       }
650f0682ac4SJonathan Peyton     }
651f0682ac4SJonathan Peyton   }
6524cc4bb4cSJim Cownie }
6534cc4bb4cSJim Cownie 
printCounters(FILE * statsOut,counter const * theCounters)6543041982dSJonathan Peyton void kmp_stats_output_module::printCounters(FILE *statsOut,
6553041982dSJonathan Peyton                                             counter const *theCounters) {
6564cc4bb4cSJim Cownie   // We print all the counters even if they are zero.
6574cc4bb4cSJim Cownie   // That makes it easier to slice them into a spreadsheet if you need to.
6584cc4bb4cSJim Cownie   fprintf(statsOut, "\nCounter,                    Count\n");
6594cc4bb4cSJim Cownie   for (int c = 0; c < COUNTER_LAST; c++) {
6604cc4bb4cSJim Cownie     counter const *stat = &theCounters[c];
6613041982dSJonathan Peyton     fprintf(statsOut, "%-25s, %s\n", counter::name(counter_e(c)),
6626b316febSTerry Wilmarth             formatSI((double)stat->getValue(), 9, ' ').c_str());
6634cc4bb4cSJim Cownie   }
6644cc4bb4cSJim Cownie }
6654cc4bb4cSJim Cownie 
printEvents(FILE * eventsOut,kmp_stats_event_vector * theEvents,int gtid)6663041982dSJonathan Peyton void kmp_stats_output_module::printEvents(FILE *eventsOut,
6673041982dSJonathan Peyton                                           kmp_stats_event_vector *theEvents,
6683041982dSJonathan Peyton                                           int gtid) {
6694cc4bb4cSJim Cownie   // sort by start time before printing
6704cc4bb4cSJim Cownie   theEvents->sort();
6714cc4bb4cSJim Cownie   for (int i = 0; i < theEvents->size(); i++) {
6724cc4bb4cSJim Cownie     kmp_stats_event ev = theEvents->at(i);
6734cc4bb4cSJim Cownie     rgb_color color = getEventColor(ev.getTimerName());
674529e0d2eSJonathan Peyton     fprintf(eventsOut, "%d %llu %llu %1.1f rgb(%1.1f,%1.1f,%1.1f) %s\n", gtid,
675529e0d2eSJonathan Peyton             static_cast<unsigned long long>(ev.getStart()),
676529e0d2eSJonathan Peyton             static_cast<unsigned long long>(ev.getStop()),
677529e0d2eSJonathan Peyton             1.2 - (ev.getNestLevel() * 0.2), color.r, color.g, color.b,
678529e0d2eSJonathan Peyton             timeStat::name(ev.getTimerName()));
6794cc4bb4cSJim Cownie   }
6804cc4bb4cSJim Cownie   return;
6814cc4bb4cSJim Cownie }
6824cc4bb4cSJim Cownie 
windupExplicitTimers()6833041982dSJonathan Peyton void kmp_stats_output_module::windupExplicitTimers() {
6843041982dSJonathan Peyton   // Wind up any explicit timers. We assume that it's fair at this point to just
6854c6a098aSKazuaki Ishizaki   // walk all the explicit timers in all threads and say "it's over".
6864cc4bb4cSJim Cownie   // If the timer wasn't running, this won't record anything anyway.
6874cc4bb4cSJim Cownie   kmp_stats_list::iterator it;
6885375fe82SJonathan Peyton   for (it = __kmp_stats_list->begin(); it != __kmp_stats_list->end(); it++) {
68911dc82faSJonathan Peyton     kmp_stats_list *ptr = *it;
69011dc82faSJonathan Peyton     ptr->getPartitionedTimers()->windup();
691f0682ac4SJonathan Peyton     ptr->endLife();
6924cc4bb4cSJim Cownie   }
6934cc4bb4cSJim Cownie }
6944cc4bb4cSJim Cownie 
printPloticusFile()6954cc4bb4cSJim Cownie void kmp_stats_output_module::printPloticusFile() {
6964cc4bb4cSJim Cownie   int i;
6975375fe82SJonathan Peyton   int size = __kmp_stats_list->size();
6985aafdd7bSPeyton, Jonathan L   kmp_safe_raii_file_t plotOut(plotFileName, "w+");
6994cc4bb4cSJim Cownie   fprintf(plotOut, "#proc page\n"
7004cc4bb4cSJim Cownie                    "   pagesize: 15 10\n"
7014cc4bb4cSJim Cownie                    "   scale: 1.0\n\n");
7024cc4bb4cSJim Cownie 
703309b00a4SShilei Tian   fprintf(plotOut,
704309b00a4SShilei Tian           "#proc getdata\n"
7054cc4bb4cSJim Cownie           "   file: %s\n\n",
7064cc4bb4cSJim Cownie           eventsFileName);
7074cc4bb4cSJim Cownie 
708309b00a4SShilei Tian   fprintf(plotOut,
709309b00a4SShilei Tian           "#proc areadef\n"
7104cc4bb4cSJim Cownie           "   title: OpenMP Sampling Timeline\n"
7114cc4bb4cSJim Cownie           "   titledetails: align=center size=16\n"
7124cc4bb4cSJim Cownie           "   rectangle: 1 1 13 9\n"
7134cc4bb4cSJim Cownie           "   xautorange: datafield=2,3\n"
7144cc4bb4cSJim Cownie           "   yautorange: -1 %d\n\n",
7154cc4bb4cSJim Cownie           size);
7164cc4bb4cSJim Cownie 
7174cc4bb4cSJim Cownie   fprintf(plotOut, "#proc xaxis\n"
7184cc4bb4cSJim Cownie                    "   stubs: inc\n"
7194cc4bb4cSJim Cownie                    "   stubdetails: size=12\n"
7204cc4bb4cSJim Cownie                    "   label: Time (ticks)\n"
7214cc4bb4cSJim Cownie                    "   labeldetails: size=14\n\n");
7224cc4bb4cSJim Cownie 
723309b00a4SShilei Tian   fprintf(plotOut,
724309b00a4SShilei Tian           "#proc yaxis\n"
7254cc4bb4cSJim Cownie           "   stubs: inc 1\n"
7264cc4bb4cSJim Cownie           "   stubrange: 0 %d\n"
7274cc4bb4cSJim Cownie           "   stubdetails: size=12\n"
7284cc4bb4cSJim Cownie           "   label: Thread #\n"
7294cc4bb4cSJim Cownie           "   labeldetails: size=14\n\n",
7304cc4bb4cSJim Cownie           size - 1);
7314cc4bb4cSJim Cownie 
7324cc4bb4cSJim Cownie   fprintf(plotOut, "#proc bars\n"
7334cc4bb4cSJim Cownie                    "   exactcolorfield: 5\n"
7344cc4bb4cSJim Cownie                    "   axis: x\n"
7354cc4bb4cSJim Cownie                    "   locfield: 1\n"
7364cc4bb4cSJim Cownie                    "   segmentfields: 2 3\n"
7374cc4bb4cSJim Cownie                    "   barwidthfield: 4\n\n");
7384cc4bb4cSJim Cownie 
7394cc4bb4cSJim Cownie   // create legend entries corresponding to the timer color
7404cc4bb4cSJim Cownie   for (i = 0; i < TIMER_LAST; i++) {
7414cc4bb4cSJim Cownie     if (timeStat::logEvent((timer_e)i)) {
7424cc4bb4cSJim Cownie       rgb_color c = getEventColor((timer_e)i);
743309b00a4SShilei Tian       fprintf(plotOut,
744309b00a4SShilei Tian               "#proc legendentry\n"
7454cc4bb4cSJim Cownie               "   sampletype: color\n"
7464cc4bb4cSJim Cownie               "   label: %s\n"
7474cc4bb4cSJim Cownie               "   details: rgb(%1.1f,%1.1f,%1.1f)\n\n",
7483041982dSJonathan Peyton               timeStat::name((timer_e)i), c.r, c.g, c.b);
7494cc4bb4cSJim Cownie     }
7504cc4bb4cSJim Cownie   }
7514cc4bb4cSJim Cownie 
7524cc4bb4cSJim Cownie   fprintf(plotOut, "#proc legend\n"
7534cc4bb4cSJim Cownie                    "   format: down\n"
7544cc4bb4cSJim Cownie                    "   location: max max\n\n");
7554cc4bb4cSJim Cownie   return;
7564cc4bb4cSJim Cownie }
7574cc4bb4cSJim Cownie 
outputEnvVariable(FILE * statsOut,char const * name)758f0682ac4SJonathan Peyton static void outputEnvVariable(FILE *statsOut, char const *name) {
759f0682ac4SJonathan Peyton   char const *value = getenv(name);
760f0682ac4SJonathan Peyton   fprintf(statsOut, "# %s = %s\n", name, value ? value : "*unspecified*");
761f0682ac4SJonathan Peyton }
762f0682ac4SJonathan Peyton 
7633041982dSJonathan Peyton /* Print some useful information about
7643041982dSJonathan Peyton    * the date and time this experiment ran.
7653041982dSJonathan Peyton    * the machine on which it ran.
7663041982dSJonathan Peyton    We output all of this as stylised comments, though we may decide to parse
7673041982dSJonathan Peyton    some of it. */
printHeaderInfo(FILE * statsOut)7683041982dSJonathan Peyton void kmp_stats_output_module::printHeaderInfo(FILE *statsOut) {
7696e98d798SJonathan Peyton   std::time_t now = std::time(0);
7706e98d798SJonathan Peyton   char buffer[40];
7716e98d798SJonathan Peyton   char hostName[80];
7726e98d798SJonathan Peyton 
7736e98d798SJonathan Peyton   std::strftime(&buffer[0], sizeof(buffer), "%c", std::localtime(&now));
7746e98d798SJonathan Peyton   fprintf(statsOut, "# Time of run: %s\n", &buffer[0]);
7756e98d798SJonathan Peyton   if (gethostname(&hostName[0], sizeof(hostName)) == 0)
7766e98d798SJonathan Peyton     fprintf(statsOut, "# Hostname: %s\n", &hostName[0]);
7776e98d798SJonathan Peyton #if KMP_ARCH_X86 || KMP_ARCH_X86_64
7786e98d798SJonathan Peyton   fprintf(statsOut, "# CPU:  %s\n", &__kmp_cpuinfo.name[0]);
7793041982dSJonathan Peyton   fprintf(statsOut, "# Family: %d, Model: %d, Stepping: %d\n",
7803041982dSJonathan Peyton           __kmp_cpuinfo.family, __kmp_cpuinfo.model, __kmp_cpuinfo.stepping);
78120c1e4e6SJonathan Peyton   if (__kmp_cpuinfo.frequency == 0)
78220c1e4e6SJonathan Peyton     fprintf(statsOut, "# Nominal frequency: Unknown\n");
78320c1e4e6SJonathan Peyton   else
7843041982dSJonathan Peyton     fprintf(statsOut, "# Nominal frequency: %sz\n",
7853041982dSJonathan Peyton             formatSI(double(__kmp_cpuinfo.frequency), 9, 'H').c_str());
786f0682ac4SJonathan Peyton   outputEnvVariable(statsOut, "KMP_HW_SUBSET");
787f0682ac4SJonathan Peyton   outputEnvVariable(statsOut, "KMP_AFFINITY");
788f0682ac4SJonathan Peyton   outputEnvVariable(statsOut, "KMP_BLOCKTIME");
789f0682ac4SJonathan Peyton   outputEnvVariable(statsOut, "KMP_LIBRARY");
790f0682ac4SJonathan Peyton   fprintf(statsOut, "# Production runtime built " __DATE__ " " __TIME__ "\n");
7916e98d798SJonathan Peyton #endif
7926e98d798SJonathan Peyton }
7936e98d798SJonathan Peyton 
outputStats(const char * heading)7943041982dSJonathan Peyton void kmp_stats_output_module::outputStats(const char *heading) {
7956e98d798SJonathan Peyton   // Stop all the explicit timers in all threads
7963041982dSJonathan Peyton   // Do this before declaring the local statistics because thay have
7973041982dSJonathan Peyton   // constructors so will take time to create.
7986e98d798SJonathan Peyton   windupExplicitTimers();
7996e98d798SJonathan Peyton 
8004cc4bb4cSJim Cownie   statistic allStats[TIMER_LAST];
8013041982dSJonathan Peyton   statistic totalStats[TIMER_LAST]; /* Synthesized, cross threads versions of
8023041982dSJonathan Peyton                                        normal timer stats */
8034cc4bb4cSJim Cownie   statistic allCounters[COUNTER_LAST];
8044cc4bb4cSJim Cownie 
8055aafdd7bSPeyton, Jonathan L   kmp_safe_raii_file_t statsOut;
8065aafdd7bSPeyton, Jonathan L   if (!outputFileName.empty()) {
8075aafdd7bSPeyton, Jonathan L     statsOut.open(outputFileName.c_str(), "a+");
8085aafdd7bSPeyton, Jonathan L   } else {
8095aafdd7bSPeyton, Jonathan L     statsOut.set_stderr();
8105aafdd7bSPeyton, Jonathan L   }
8114cc4bb4cSJim Cownie 
8125aafdd7bSPeyton, Jonathan L   kmp_safe_raii_file_t eventsOut;
8134cc4bb4cSJim Cownie   if (eventPrintingEnabled()) {
8145aafdd7bSPeyton, Jonathan L     eventsOut.open(eventsFileName, "w+");
8154cc4bb4cSJim Cownie   }
8164cc4bb4cSJim Cownie 
8176e98d798SJonathan Peyton   printHeaderInfo(statsOut);
8184cc4bb4cSJim Cownie   fprintf(statsOut, "%s\n", heading);
8194cc4bb4cSJim Cownie   // Accumulate across threads.
8204cc4bb4cSJim Cownie   kmp_stats_list::iterator it;
8215375fe82SJonathan Peyton   for (it = __kmp_stats_list->begin(); it != __kmp_stats_list->end(); it++) {
8224cc4bb4cSJim Cownie     int t = (*it)->getGtid();
8234cc4bb4cSJim Cownie     // Output per thread stats if requested.
8246e98d798SJonathan Peyton     if (printPerThreadFlag) {
8254cc4bb4cSJim Cownie       fprintf(statsOut, "Thread %d\n", t);
826e2554af8SJonathan Peyton       printTimerStats(statsOut, (*it)->getTimers(), 0);
8274cc4bb4cSJim Cownie       printCounters(statsOut, (*it)->getCounters());
8284cc4bb4cSJim Cownie       fprintf(statsOut, "\n");
8294cc4bb4cSJim Cownie     }
8304cc4bb4cSJim Cownie     // Output per thread events if requested.
8314cc4bb4cSJim Cownie     if (eventPrintingEnabled()) {
8324cc4bb4cSJim Cownie       kmp_stats_event_vector events = (*it)->getEventVector();
8334cc4bb4cSJim Cownie       printEvents(eventsOut, &events, t);
8344cc4bb4cSJim Cownie     }
8354cc4bb4cSJim Cownie 
836e2554af8SJonathan Peyton     // Accumulate timers.
8376e98d798SJonathan Peyton     for (timer_e s = timer_e(0); s < TIMER_LAST; s = timer_e(s + 1)) {
8384cc4bb4cSJim Cownie       // See if we should ignore this timer when aggregating
839*97d000cfStlwilmar       if ((timeStat::masterOnly(s) && (t != 0)) || // Timer only valid on
840*97d000cfStlwilmar           // primary thread and this thread is worker
8413041982dSJonathan Peyton           (timeStat::workerOnly(s) && (t == 0)) // Timer only valid on worker
842*97d000cfStlwilmar           // and this thread is the primary thread
8433041982dSJonathan Peyton           ) {
8444cc4bb4cSJim Cownie         continue;
8454cc4bb4cSJim Cownie       }
8464cc4bb4cSJim Cownie 
8476e98d798SJonathan Peyton       statistic *threadStat = (*it)->getTimer(s);
8484cc4bb4cSJim Cownie       allStats[s] += *threadStat;
849e2554af8SJonathan Peyton 
8506e98d798SJonathan Peyton       // Add Total stats for timers that are valid in more than one thread
8516e98d798SJonathan Peyton       if (!timeStat::noTotal(s))
852e2554af8SJonathan Peyton         totalStats[s].addSample(threadStat->getTotal());
853e2554af8SJonathan Peyton     }
8544cc4bb4cSJim Cownie 
855e2554af8SJonathan Peyton     // Accumulate counters.
8566e98d798SJonathan Peyton     for (counter_e c = counter_e(0); c < COUNTER_LAST; c = counter_e(c + 1)) {
8576e98d798SJonathan Peyton       if (counter::masterOnly(c) && t != 0)
8584cc4bb4cSJim Cownie         continue;
8596b316febSTerry Wilmarth       allCounters[c].addSample((double)(*it)->getCounter(c)->getValue());
8604cc4bb4cSJim Cownie     }
8614cc4bb4cSJim Cownie   }
8624cc4bb4cSJim Cownie 
8634cc4bb4cSJim Cownie   if (eventPrintingEnabled()) {
8644cc4bb4cSJim Cownie     printPloticusFile();
8654cc4bb4cSJim Cownie   }
8664cc4bb4cSJim Cownie 
8674cc4bb4cSJim Cownie   fprintf(statsOut, "Aggregate for all threads\n");
868e2554af8SJonathan Peyton   printTimerStats(statsOut, &allStats[0], &totalStats[0]);
8694cc4bb4cSJim Cownie   fprintf(statsOut, "\n");
870e2554af8SJonathan Peyton   printCounterStats(statsOut, &allCounters[0]);
8714cc4bb4cSJim Cownie }
8724cc4bb4cSJim Cownie 
8734cc4bb4cSJim Cownie /* *************  exported C functions ************** */
8744cc4bb4cSJim Cownie 
8753041982dSJonathan Peyton // no name mangling for these functions, we want the c files to be able to get
8763041982dSJonathan Peyton // at these functions
8774cc4bb4cSJim Cownie extern "C" {
8784cc4bb4cSJim Cownie 
__kmp_reset_stats()8793041982dSJonathan Peyton void __kmp_reset_stats() {
8804cc4bb4cSJim Cownie   kmp_stats_list::iterator it;
8815375fe82SJonathan Peyton   for (it = __kmp_stats_list->begin(); it != __kmp_stats_list->end(); it++) {
8824cc4bb4cSJim Cownie     timeStat *timers = (*it)->getTimers();
8834cc4bb4cSJim Cownie     counter *counters = (*it)->getCounters();
8844cc4bb4cSJim Cownie 
8854cc4bb4cSJim Cownie     for (int t = 0; t < TIMER_LAST; t++)
8864cc4bb4cSJim Cownie       timers[t].reset();
8874cc4bb4cSJim Cownie 
8884cc4bb4cSJim Cownie     for (int c = 0; c < COUNTER_LAST; c++)
8894cc4bb4cSJim Cownie       counters[c].reset();
8904cc4bb4cSJim Cownie 
8914cc4bb4cSJim Cownie     // reset the event vector so all previous events are "erased"
8924cc4bb4cSJim Cownie     (*it)->resetEventVector();
8934cc4bb4cSJim Cownie   }
8944cc4bb4cSJim Cownie }
8954cc4bb4cSJim Cownie 
8963041982dSJonathan Peyton // This function will reset all stats and stop all threads' explicit timers if
8973041982dSJonathan Peyton // they haven't been stopped already.
__kmp_output_stats(const char * heading)8983041982dSJonathan Peyton void __kmp_output_stats(const char *heading) {
8995375fe82SJonathan Peyton   __kmp_stats_global_output->outputStats(heading);
9004cc4bb4cSJim Cownie   __kmp_reset_stats();
9014cc4bb4cSJim Cownie }
9024cc4bb4cSJim Cownie 
__kmp_accumulate_stats_at_exit(void)9033041982dSJonathan Peyton void __kmp_accumulate_stats_at_exit(void) {
9044cc4bb4cSJim Cownie   // Only do this once.
9054cc4bb4cSJim Cownie   if (KMP_XCHG_FIXED32(&statsPrinted, 1) != 0)
9064cc4bb4cSJim Cownie     return;
9074cc4bb4cSJim Cownie 
9084cc4bb4cSJim Cownie   __kmp_output_stats("Statistics on exit");
9094cc4bb4cSJim Cownie }
9104cc4bb4cSJim Cownie 
__kmp_stats_init(void)9113041982dSJonathan Peyton void __kmp_stats_init(void) {
9125375fe82SJonathan Peyton   __kmp_init_tas_lock(&__kmp_stats_lock);
9135375fe82SJonathan Peyton   __kmp_stats_start_time = tsc_tick_count::now();
9145375fe82SJonathan Peyton   __kmp_stats_global_output = new kmp_stats_output_module();
9155375fe82SJonathan Peyton   __kmp_stats_list = new kmp_stats_list();
9165375fe82SJonathan Peyton }
9175375fe82SJonathan Peyton 
__kmp_stats_fini(void)9183041982dSJonathan Peyton void __kmp_stats_fini(void) {
9195375fe82SJonathan Peyton   __kmp_accumulate_stats_at_exit();
9205375fe82SJonathan Peyton   __kmp_stats_list->deallocate();
9215375fe82SJonathan Peyton   delete __kmp_stats_global_output;
9225375fe82SJonathan Peyton   delete __kmp_stats_list;
9234cc4bb4cSJim Cownie }
9244cc4bb4cSJim Cownie 
9254cc4bb4cSJim Cownie } // extern "C"
926