1 #ifndef KMP_STATS_H
2 #define KMP_STATS_H
3 
4 /** @file kmp_stats.h
5  * Functions for collecting statistics.
6  */
7 
8 
9 //===----------------------------------------------------------------------===//
10 //
11 //                     The LLVM Compiler Infrastructure
12 //
13 // This file is dual licensed under the MIT and the University of Illinois Open
14 // Source Licenses. See LICENSE.txt for details.
15 //
16 //===----------------------------------------------------------------------===//
17 
18 #include "kmp_config.h"
19 
20 #if KMP_STATS_ENABLED
21 /*
22  * Statistics accumulator.
23  * Accumulates number of samples and computes min, max, mean, standard deviation on the fly.
24  *
25  * Online variance calculation algorithm from http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#On-line_algorithm
26  */
27 
28 #include <limits>
29 #include <math.h>
30 #include <vector>
31 #include <string>
32 #include <stdint.h>
33 #include <new> // placement new
34 #include "kmp_stats_timing.h"
35 
36 /*
37  * Enable developer statistics here if you want them. They are more detailed than is useful for application characterisation and
38  * are intended for the runtime library developer.
39  */
40 // #define KMP_DEVELOPER_STATS 1
41 
42 /*!
43  * @ingroup STATS_GATHERING
44  * \brief flags to describe the statistic (timer or counter)
45  *
46  */
47 enum stats_flags_e {
48     noTotal      = 1<<0,     //!< do not show a TOTAL_aggregation for this statistic
49     onlyInMaster = 1<<1,     //!< statistic is valid only for master
50     noUnits      = 1<<2,     //!< statistic doesn't need units printed next to it in output
51     notInMaster  = 1<<3,     //!< statistic is valid only for non-master threads
52     logEvent     = 1<<4      //!< statistic can be logged on the event timeline when KMP_STATS_EVENTS is on (valid only for timers)
53 };
54 
55 /*!
56  * @ingroup STATS_GATHERING
57  * \brief the states which a thread can be in
58  *
59  */
60 enum stats_state_e {
61     IDLE,
62     SERIAL_REGION,
63     FORK_JOIN_BARRIER,
64     PLAIN_BARRIER,
65     TASKWAIT,
66     TASKYIELD,
67     TASKGROUP,
68     IMPLICIT_TASK,
69     EXPLICIT_TASK
70 };
71 
72 /*!
73  * \brief Add new counters under KMP_FOREACH_COUNTER() macro in kmp_stats.h
74  *
75  * @param macro a user defined macro that takes three arguments - macro(COUNTER_NAME, flags, arg)
76  * @param arg a user defined argument to send to the user defined macro
77  *
78  * \details A counter counts the occurrence of some event.
79  * Each thread accumulates its own count, at the end of execution the counts are aggregated treating each thread
80  * as a separate measurement. (Unless onlyInMaster is set, in which case there's only a single measurement).
81  * The min,mean,max are therefore the values for the threads.
82  * Adding the counter here and then putting a KMP_BLOCK_COUNTER(name) at the point you want to count is all you need to do.
83  * All of the tables and printing is generated from this macro.
84  * Format is "macro(name, flags, arg)"
85  *
86  * @ingroup STATS_GATHERING
87  */
88 #define KMP_FOREACH_COUNTER(macro, arg)                         \
89     macro (OMP_PARALLEL, stats_flags_e::onlyInMaster | stats_flags_e::noTotal, arg) \
90     macro (OMP_NESTED_PARALLEL, 0, arg)                         \
91     macro (OMP_FOR_static, 0, arg)                              \
92     macro (OMP_FOR_dynamic, 0, arg)                             \
93     macro (OMP_DISTRIBUTE, 0, arg)                              \
94     macro (OMP_BARRIER, 0, arg)                                 \
95     macro (OMP_CRITICAL,0, arg)                                 \
96     macro (OMP_SINGLE, 0, arg)                                  \
97     macro (OMP_MASTER, 0, arg)                                  \
98     macro (OMP_TEAMS, 0, arg)                                   \
99     macro (OMP_set_lock, 0, arg)                                \
100     macro (OMP_test_lock, 0, arg)                               \
101     macro (REDUCE_wait, 0, arg)                                 \
102     macro (REDUCE_nowait, 0, arg)                               \
103     macro (OMP_TASKYIELD, 0, arg)                               \
104     macro (OMP_TASKLOOP, 0, arg)                                \
105     macro (TASK_executed, 0, arg)                               \
106     macro (TASK_cancelled, 0, arg)                              \
107     macro (TASK_stolen, 0, arg)
108 
109 /*!
110  * \brief Add new timers under KMP_FOREACH_TIMER() macro in kmp_stats.h
111  *
112  * @param macro a user defined macro that takes three arguments - macro(TIMER_NAME, flags, arg)
113  * @param arg a user defined argument to send to the user defined macro
114  *
115  * \details A timer collects multiple samples of some count in each thread and then finally aggregates alll of the samples from all of the threads.
116  * For most timers the printing code also provides an aggregation over the thread totals. These are printed as TOTAL_foo.
117  * The count is normally a time (in ticks), hence the name "timer". (But can be any value, so we use this for "number of arguments passed to fork"
118  * as well).
119  * For timers the threads are not significant, it's the individual observations that count, so the statistics are at that level.
120  * Format is "macro(name, flags, arg)"
121  *
122  * @ingroup STATS_GATHERING2
123  */
124 #define KMP_FOREACH_TIMER(macro, arg)                              \
125     macro (OMP_worker_thread_life, stats_flags_e::logEvent, arg)   \
126     macro (FOR_static_scheduling, 0, arg)                          \
127     macro (FOR_dynamic_scheduling, 0, arg)                         \
128     macro (OMP_critical,  0, arg)                                  \
129     macro (OMP_critical_wait,  0, arg)                             \
130     macro (OMP_single,    0, arg)                                  \
131     macro (OMP_master,    0, arg)                                  \
132     macro (OMP_idle, stats_flags_e::logEvent, arg)                 \
133     macro (OMP_plain_barrier, stats_flags_e::logEvent, arg)        \
134     macro (OMP_fork_barrier, stats_flags_e::logEvent, arg)         \
135     macro (OMP_join_barrier, stats_flags_e::logEvent, arg)         \
136     macro (OMP_parallel, stats_flags_e::logEvent, arg)             \
137     macro (OMP_task_immediate, 0, arg)                             \
138     macro (OMP_task_taskwait, 0, arg)                              \
139     macro (OMP_task_taskyield, 0, arg)                             \
140     macro (OMP_task_taskgroup, 0, arg)                             \
141     macro (OMP_task_join_bar, 0, arg)                              \
142     macro (OMP_task_plain_bar, 0, arg)                             \
143     macro (OMP_serial, stats_flags_e::logEvent, arg)               \
144     macro (OMP_taskloop_scheduling, 0, arg)                        \
145     macro (OMP_set_numthreads,    stats_flags_e::noUnits | stats_flags_e::noTotal, arg) \
146     macro (OMP_PARALLEL_args,     stats_flags_e::noUnits | stats_flags_e::noTotal, arg) \
147     macro (FOR_static_iterations, stats_flags_e::noUnits | stats_flags_e::noTotal, arg) \
148     macro (FOR_dynamic_iterations,stats_flags_e::noUnits | stats_flags_e::noTotal, arg) \
149     KMP_FOREACH_DEVELOPER_TIMER(macro, arg)
150 
151 
152 // OMP_start_end          -- Time from when OpenMP is initialized until the stats are printed at exit
153 // OMP_serial             -- Thread zero time executing serial code
154 // OMP_work               -- Elapsed time in code dispatched by a fork (measured in the thread)
155 // OMP_barrier            -- Time at "real" barriers (includes task time)
156 // FOR_static_scheduling  -- Time spent doing scheduling for a static "for"
157 // FOR_dynamic_scheduling -- Time spent doing scheduling for a dynamic "for"
158 // OMP_idle               -- Worker threads time spent waiting for inclusion in a parallel region
159 // OMP_plain_barrier      -- Time spent in a barrier construct
160 // OMP_fork_join_barrier  -- Time spent in a the fork-join barrier surrounding a parallel region
161 // OMP_parallel           -- Time spent inside a parallel construct
162 // OMP_task_immediate     -- Time spent executing non-deferred tasks
163 // OMP_task_taskwait      -- Time spent executing tasks inside a taskwait construct
164 // OMP_task_taskyield     -- Time spent executing tasks inside a taskyield construct
165 // OMP_task_taskgroup     -- Time spent executing tasks inside a taskygroup construct
166 // OMP_task_join_bar      -- Time spent executing tasks inside a join barrier
167 // OMP_task_plain_bar     -- Time spent executing tasks inside a barrier construct
168 // OMP_single             -- Time spent executing a "single" region
169 // OMP_master             -- Time spent executing a "master" region
170 // OMP_set_numthreads     -- Values passed to omp_set_num_threads
171 // OMP_PARALLEL_args      -- Number of arguments passed to a parallel region
172 // FOR_static_iterations  -- Number of available parallel chunks of work in a static for
173 // FOR_dynamic_iterations -- Number of available parallel chunks of work in a dynamic for
174 //                           Both adjust for any chunking, so if there were an iteration count of 20 but a chunk size of 10, we'd record 2.
175 
176 #if (KMP_DEVELOPER_STATS)
177 // Timers which are of interest to runtime library developers, not end users.
178 // These have to be explicitly enabled in addition to the other stats.
179 
180 // KMP_fork_barrier       -- time in __kmp_fork_barrier
181 // KMP_join_barrier       -- time in __kmp_join_barrier
182 // KMP_barrier            -- time in __kmp_barrier
183 // KMP_end_split_barrier  -- time in __kmp_end_split_barrier
184 // KMP_setup_icv_copy     -- time in __kmp_setup_icv_copy
185 // KMP_icv_copy           -- start/stop timer for any ICV copying
186 // KMP_linear_gather      -- time in __kmp_linear_barrier_gather
187 // KMP_linear_release     -- time in __kmp_linear_barrier_release
188 // KMP_tree_gather        -- time in __kmp_tree_barrier_gather
189 // KMP_tree_release       -- time in __kmp_tree_barrier_release
190 // KMP_hyper_gather       -- time in __kmp_hyper_barrier_gather
191 // KMP_hyper_release      -- time in __kmp_hyper_barrier_release
192 # define KMP_FOREACH_DEVELOPER_TIMER(macro, arg) \
193     macro (KMP_fork_call, 0, arg)                \
194     macro (KMP_join_call, 0, arg)                \
195     macro (KMP_end_split_barrier, 0, arg)        \
196     macro (KMP_hier_gather, 0, arg)              \
197     macro (KMP_hier_release, 0, arg)             \
198     macro (KMP_hyper_gather, 0, arg)             \
199     macro (KMP_hyper_release, 0, arg)            \
200     macro (KMP_linear_gather, 0, arg)            \
201     macro (KMP_linear_release, 0, arg)           \
202     macro (KMP_tree_gather, 0, arg)              \
203     macro (KMP_tree_release, 0, arg)             \
204     macro (USER_resume, 0, arg)                  \
205     macro (USER_suspend, 0, arg)                 \
206     macro (KMP_allocate_team, 0, arg)            \
207     macro (KMP_setup_icv_copy, 0, arg)           \
208     macro (USER_icv_copy, 0, arg)
209 #else
210 # define KMP_FOREACH_DEVELOPER_TIMER(macro, arg)
211 #endif
212 
213 /*!
214  * \brief Add new explicit timers under KMP_FOREACH_EXPLICIT_TIMER() macro.
215  *
216  * @param macro a user defined macro that takes three arguments - macro(TIMER_NAME, flags, arg)
217  * @param arg a user defined argument to send to the user defined macro
218  *
219  * \warning YOU MUST HAVE THE SAME NAMED TIMER UNDER KMP_FOREACH_TIMER() OR ELSE BAD THINGS WILL HAPPEN!
220  *
221  * \details Explicit timers are ones where we need to allocate a timer itself (as well as the accumulated timing statistics).
222  * We allocate these on a per-thread basis, and explicitly start and stop them.
223  * Block timers just allocate the timer itself on the stack, and use the destructor to notice block exit; they don't
224  * need to be defined here.
225  * The name here should be the same as that of a timer above.
226  *
227  * @ingroup STATS_GATHERING
228 */
229 #define KMP_FOREACH_EXPLICIT_TIMER(macro, arg) \
230     KMP_FOREACH_TIMER(macro, arg)
231 
232 #define ENUMERATE(name,ignore,prefix) prefix##name,
233 enum timer_e {
234     KMP_FOREACH_TIMER(ENUMERATE, TIMER_)
235     TIMER_LAST
236 };
237 
238 enum explicit_timer_e {
239     KMP_FOREACH_EXPLICIT_TIMER(ENUMERATE, EXPLICIT_TIMER_)
240     EXPLICIT_TIMER_LAST
241 };
242 
243 enum counter_e {
244     KMP_FOREACH_COUNTER(ENUMERATE, COUNTER_)
245     COUNTER_LAST
246 };
247 #undef ENUMERATE
248 
249 class timerPair {
250     explicit_timer_e timer_index;
251     timer_e timer;
252  public:
253     timerPair(explicit_timer_e ti, timer_e t) : timer_index(ti), timer(t) {}
254     inline explicit_timer_e get_index() const { return timer_index; }
255     inline timer_e get_timer() const { return timer; }
256     bool operator==(const timerPair & rhs) {
257         return this->get_index() == rhs.get_index();
258     }
259     bool operator!=(const timerPair & rhs) {
260         return !(*this == rhs);
261     }
262 };
263 
264 class statistic
265 {
266     double   minVal;
267     double   maxVal;
268     double   meanVal;
269     double   m2;
270     uint64_t sampleCount;
271 
272  public:
273     statistic() { reset(); }
274     statistic (statistic const &o): minVal(o.minVal), maxVal(o.maxVal), meanVal(o.meanVal), m2(o.m2), sampleCount(o.sampleCount) {}
275 
276     double   getMin()   const { return minVal; }
277     double   getMean()  const { return meanVal; }
278     double   getMax()   const { return maxVal; }
279     uint64_t getCount() const { return sampleCount; }
280     double   getSD()    const { return sqrt(m2/sampleCount); }
281     double   getTotal() const { return sampleCount*meanVal; }
282 
283     void reset()
284     {
285         minVal =  std::numeric_limits<double>::max();
286         maxVal = -std::numeric_limits<double>::max();
287         meanVal= 0.0;
288         m2     = 0.0;
289         sampleCount = 0;
290     }
291     void addSample(double sample);
292     void scale    (double factor);
293     void scaleDown(double f)  { scale (1./f); }
294     statistic & operator+= (statistic const & other);
295 
296     std::string format(char unit, bool total=false) const;
297 };
298 
299 struct statInfo
300 {
301     const char * name;
302     uint32_t     flags;
303 };
304 
305 class timeStat : public statistic
306 {
307     static statInfo timerInfo[];
308 
309  public:
310     timeStat() : statistic() {}
311     static const char * name(timer_e e) { return timerInfo[e].name; }
312     static bool  noTotal    (timer_e e) { return timerInfo[e].flags & stats_flags_e::noTotal;      }
313     static bool  masterOnly (timer_e e) { return timerInfo[e].flags & stats_flags_e::onlyInMaster; }
314     static bool  workerOnly (timer_e e) { return timerInfo[e].flags & stats_flags_e::notInMaster;  }
315     static bool  noUnits    (timer_e e) { return timerInfo[e].flags & stats_flags_e::noUnits;      }
316     static bool  logEvent   (timer_e e) { return timerInfo[e].flags & stats_flags_e::logEvent;     }
317     static void  clearEventFlags()      {
318         for(int i=0;i<TIMER_LAST;i++) {
319             timerInfo[i].flags &= (~(stats_flags_e::logEvent));
320         }
321     }
322 };
323 
324 // Where we need explicitly to start and end the timer, this version can be used
325 // Since these timers normally aren't nicely scoped, so don't have a good place to live
326 // on the stack of the thread, they're more work to use.
327 class explicitTimer
328 {
329     timeStat * stat;
330     tsc_tick_count startTime;
331     tsc_tick_count pauseStartTime;
332     tsc_tick_count::tsc_interval_t totalPauseTime;
333 
334  public:
335     explicitTimer () : stat(0), startTime(0), pauseStartTime(0), totalPauseTime() { }
336     explicitTimer (timeStat * s) : stat(s), startTime(), pauseStartTime(0), totalPauseTime() { }
337 
338     void setStat (timeStat *s) { stat = s; }
339     void start(timer_e timerEnumValue);
340     void pause() { pauseStartTime = tsc_tick_count::now(); }
341     void resume() { totalPauseTime += (tsc_tick_count::now() - pauseStartTime); }
342     void stop(timer_e timerEnumValue, kmp_stats_list* stats_ptr = nullptr);
343     void reset() { startTime = 0; pauseStartTime = 0; totalPauseTime = 0; }
344 };
345 
346 // Where all you need is to time a block, this is enough.
347 // (It avoids the need to have an explicit end, leaving the scope suffices.)
348 class blockTimer : public explicitTimer
349 {
350     timer_e timerEnumValue;
351  public:
352     blockTimer (timeStat * s, timer_e newTimerEnumValue) : timerEnumValue(newTimerEnumValue), explicitTimer(s) { start(timerEnumValue); }
353     ~blockTimer() { stop(timerEnumValue); }
354 };
355 
356 // Where you need to partition a threads clock ticks into separate states
357 // e.g., a partitionedTimers class with two timers of EXECUTING_TASK, and
358 //   DOING_NOTHING would render these conditions:
359 //   time(EXECUTING_TASK) + time(DOING_NOTHING) = total time thread is alive
360 //   No clock tick in the EXECUTING_TASK is a member of DOING_NOTHING and vice versa
361 class partitionedTimers
362 {
363  private:
364     explicitTimer* timers[EXPLICIT_TIMER_LAST+1];
365     std::vector<timerPair> timer_stack;
366  public:
367     partitionedTimers();
368     void add_timer(explicit_timer_e timer_index, explicitTimer* timer_pointer);
369     void init(timerPair timer_index);
370     void push(timerPair timer_index);
371     void pop();
372     void windup();
373 };
374 
375 // Special wrapper around the partioned timers to aid timing code blocks
376 // It avoids the need to have an explicit end, leaving the scope suffices.
377 class blockPartitionedTimer
378 {
379     partitionedTimers* part_timers;
380     timerPair timer_pair;
381  public:
382     blockPartitionedTimer(partitionedTimers* pt, timerPair tp) : part_timers(pt), timer_pair(tp) { part_timers->push(timer_pair); }
383    ~blockPartitionedTimer() { part_timers->pop(); }
384 };
385 
386 // Special wrapper around the thread state to aid in keeping state in code blocks
387 // It avoids the need to have an explicit end, leaving the scope suffices.
388 class blockThreadState
389 {
390     stats_state_e* state_pointer;
391     stats_state_e  old_state;
392  public:
393     blockThreadState(stats_state_e* thread_state_pointer, stats_state_e new_state) : state_pointer(thread_state_pointer), old_state(*thread_state_pointer) {
394         *state_pointer = new_state;
395     }
396    ~blockThreadState() { *state_pointer = old_state;  }
397 };
398 
399 // If all you want is a count, then you can use this...
400 // The individual per-thread counts will be aggregated into a statistic at program exit.
401 class counter
402 {
403     uint64_t value;
404     static const statInfo counterInfo[];
405 
406  public:
407     counter() : value(0) {}
408     void increment() { value++; }
409     uint64_t getValue() const { return value; }
410     void reset() { value = 0; }
411     static const char * name(counter_e e) { return counterInfo[e].name; }
412     static bool  masterOnly (counter_e e) { return counterInfo[e].flags & stats_flags_e::onlyInMaster; }
413 };
414 
415 /* ****************************************************************
416     Class to implement an event
417 
418     There are four components to an event: start time, stop time
419     nest_level, and timer_name.
420     The start and stop time should be obvious (recorded in clock ticks).
421     The nest_level relates to the bar width in the timeline graph.
422     The timer_name is used to determine which timer event triggered this event.
423 
424     the interface to this class is through four read-only operations:
425     1) getStart()     -- returns the start time as 64 bit integer
426     2) getStop()      -- returns the stop time as 64 bit integer
427     3) getNestLevel() -- returns the nest level of the event
428     4) getTimerName() -- returns the timer name that triggered event
429 
430     *MORE ON NEST_LEVEL*
431     The nest level is used in the bar graph that represents the timeline.
432     Its main purpose is for showing how events are nested inside eachother.
433     For example, say events, A, B, and C are recorded.  If the timeline
434     looks like this:
435 
436 Begin -------------------------------------------------------------> Time
437          |    |          |        |          |              |
438          A    B          C        C          B              A
439        start start     start     end        end            end
440 
441        Then A, B, C will have a nest level of 1, 2, 3 respectively.
442        These values are then used to calculate the barwidth so you can
443        see that inside A, B has occurred, and inside B, C has occurred.
444        Currently, this is shown with A's bar width being larger than B's
445        bar width, and B's bar width being larger than C's bar width.
446 
447 **************************************************************** */
448 class kmp_stats_event {
449     uint64_t start;
450     uint64_t stop;
451     int nest_level;
452     timer_e timer_name;
453  public:
454     kmp_stats_event() : start(0), stop(0), nest_level(0), timer_name(TIMER_LAST) {}
455     kmp_stats_event(uint64_t strt, uint64_t stp, int nst, timer_e nme) : start(strt), stop(stp), nest_level(nst), timer_name(nme) {}
456     inline uint64_t  getStart() const { return start; }
457     inline uint64_t  getStop() const  { return stop;  }
458     inline int       getNestLevel() const { return nest_level; }
459     inline timer_e   getTimerName() const { return timer_name; }
460 };
461 
462 /* ****************************************************************
463     Class to implement a dynamically expandable array of events
464 
465     ---------------------------------------------------------
466     | event 1 | event 2 | event 3 | event 4 | ... | event N |
467     ---------------------------------------------------------
468 
469     An event is pushed onto the back of this array at every
470     explicitTimer->stop() call.  The event records the thread #,
471     start time, stop time, and nest level related to the bar width.
472 
473     The event vector starts at size INIT_SIZE and grows (doubles in size)
474     if needed.  An implication of this behavior is that log(N)
475     reallocations are needed (where N is number of events).  If you want
476     to avoid reallocations, then set INIT_SIZE to a large value.
477 
478     the interface to this class is through six operations:
479     1) reset() -- sets the internal_size back to 0 but does not deallocate any memory
480     2) size()  -- returns the number of valid elements in the vector
481     3) push_back(start, stop, nest, timer_name) -- pushes an event onto
482                                                    the back of the array
483     4) deallocate() -- frees all memory associated with the vector
484     5) sort() -- sorts the vector by start time
485     6) operator[index] or at(index) -- returns event reference at that index
486 
487 **************************************************************** */
488 class kmp_stats_event_vector {
489     kmp_stats_event* events;
490     int internal_size;
491     int allocated_size;
492     static const int INIT_SIZE = 1024;
493  public:
494     kmp_stats_event_vector() {
495         events = (kmp_stats_event*)__kmp_allocate(sizeof(kmp_stats_event)*INIT_SIZE);
496         internal_size = 0;
497         allocated_size = INIT_SIZE;
498     }
499    ~kmp_stats_event_vector() {}
500     inline void reset() { internal_size = 0; }
501     inline int  size() const { return internal_size; }
502     void push_back(uint64_t start_time, uint64_t stop_time, int nest_level, timer_e name) {
503         int i;
504         if(internal_size == allocated_size) {
505             kmp_stats_event* tmp = (kmp_stats_event*)__kmp_allocate(sizeof(kmp_stats_event)*allocated_size*2);
506             for(i=0;i<internal_size;i++) tmp[i] = events[i];
507             __kmp_free(events);
508             events = tmp;
509             allocated_size*=2;
510         }
511         events[internal_size] = kmp_stats_event(start_time, stop_time, nest_level, name);
512         internal_size++;
513         return;
514     }
515     void deallocate();
516     void sort();
517     const kmp_stats_event & operator[](int index) const { return events[index]; }
518           kmp_stats_event & operator[](int index) { return events[index]; }
519     const kmp_stats_event & at(int index) const { return events[index]; }
520           kmp_stats_event & at(int index) { return events[index]; }
521 };
522 
523 /* ****************************************************************
524     Class to implement a doubly-linked, circular, statistics list
525 
526     |---| ---> |---| ---> |---| ---> |---| ---> ... next
527     |   |      |   |      |   |      |   |
528     |---| <--- |---| <--- |---| <--- |---| <--- ... prev
529     Sentinel   first      second     third
530     Node       node       node       node
531 
532     The Sentinel Node is the user handle on the list.
533     The first node corresponds to thread 0's statistics.
534     The second node corresponds to thread 1's statistics and so on...
535 
536     Each node has a _timers, _counters, and _explicitTimers array to
537     hold that thread's statistics.  The _explicitTimers
538     point to the correct _timer and update its statistics at every stop() call.
539     The explicitTimers' pointers are set up in the constructor.
540     Each node also has an event vector to hold that thread's timing events.
541     The event vector expands as necessary and records the start-stop times
542     for each timer.
543 
544     The nestLevel variable is for plotting events and is related
545     to the bar width in the timeline graph.
546 
547     Every thread will have a __thread local pointer to its node in
548     the list.  The sentinel node is used by the master thread to
549     store "dummy" statistics before __kmp_create_worker() is called.
550 
551 **************************************************************** */
552 class kmp_stats_list {
553     int gtid;
554     timeStat      _timers[TIMER_LAST+1];
555     counter       _counters[COUNTER_LAST+1];
556     explicitTimer _explicitTimers[EXPLICIT_TIMER_LAST+1];
557     partitionedTimers _partitionedTimers;
558     int           _nestLevel; // one per thread
559     kmp_stats_event_vector _event_vector;
560     kmp_stats_list* next;
561     kmp_stats_list* prev;
562     stats_state_e state;
563     int thread_is_idle_flag;
564  public:
565     kmp_stats_list() : _nestLevel(0), _event_vector(), next(this), prev(this),
566       state(IDLE), thread_is_idle_flag(0) {
567 #define doInit(name,ignore1,ignore2) \
568         getExplicitTimer(EXPLICIT_TIMER_##name)->setStat(getTimer(TIMER_##name)); \
569         _partitionedTimers.add_timer(EXPLICIT_TIMER_##name, getExplicitTimer(EXPLICIT_TIMER_##name));
570         KMP_FOREACH_EXPLICIT_TIMER(doInit,0);
571 #undef doInit
572     }
573    ~kmp_stats_list() { }
574     inline timeStat *      getTimer(timer_e idx)                  { return &_timers[idx]; }
575     inline counter  *      getCounter(counter_e idx)              { return &_counters[idx]; }
576     inline explicitTimer * getExplicitTimer(explicit_timer_e idx) { return &_explicitTimers[idx]; }
577     inline partitionedTimers * getPartitionedTimers()             { return &_partitionedTimers; }
578     inline timeStat *      getTimers()                            { return _timers; }
579     inline counter  *      getCounters()                          { return _counters; }
580     inline explicitTimer * getExplicitTimers()                    { return _explicitTimers; }
581     inline kmp_stats_event_vector & getEventVector()              { return _event_vector; }
582     inline void resetEventVector()                                { _event_vector.reset(); }
583     inline void incrementNestValue()                              { _nestLevel++; }
584     inline int  getNestValue()                                    { return _nestLevel; }
585     inline void decrementNestValue()                              { _nestLevel--; }
586     inline int  getGtid() const                                   { return gtid; }
587     inline void setGtid(int newgtid)                              { gtid = newgtid; }
588     inline void setState(stats_state_e newstate)                  { state = newstate; }
589     inline stats_state_e getState() const                         { return state; }
590     inline stats_state_e * getStatePointer()                      { return &state; }
591     inline bool  isIdle()                                         { return thread_is_idle_flag==1; }
592     inline void setIdleFlag()                                     { thread_is_idle_flag = 1; }
593     inline void resetIdleFlag()                                   { thread_is_idle_flag = 0; }
594     kmp_stats_list* push_back(int gtid); // returns newly created list node
595     inline void     push_event(uint64_t start_time, uint64_t stop_time, int nest_level, timer_e name) {
596         _event_vector.push_back(start_time, stop_time, nest_level, name);
597     }
598     void deallocate();
599     class iterator;
600     kmp_stats_list::iterator begin();
601     kmp_stats_list::iterator end();
602     int size();
603     class iterator {
604         kmp_stats_list* ptr;
605         friend kmp_stats_list::iterator kmp_stats_list::begin();
606         friend kmp_stats_list::iterator kmp_stats_list::end();
607       public:
608         iterator();
609        ~iterator();
610         iterator operator++();
611         iterator operator++(int dummy);
612         iterator operator--();
613         iterator operator--(int dummy);
614         bool operator!=(const iterator & rhs);
615         bool operator==(const iterator & rhs);
616         kmp_stats_list* operator*() const; // dereference operator
617     };
618 };
619 
620 /* ****************************************************************
621    Class to encapsulate all output functions and the environment variables
622 
623    This module holds filenames for various outputs (normal stats, events, plot file),
624    as well as coloring information for the plot file.
625 
626    The filenames and flags variables are read from environment variables.
627    These are read once by the constructor of the global variable __kmp_stats_output
628    which calls init().
629 
630    During this init() call, event flags for the timeStat::timerInfo[] global array
631    are cleared if KMP_STATS_EVENTS is not true (on, 1, yes).
632 
633    The only interface function that is public is outputStats(heading).  This function
634    should print out everything it needs to, either to files or stderr,
635    depending on the environment variables described below
636 
637    ENVIRONMENT VARIABLES:
638    KMP_STATS_FILE -- if set, all statistics (not events) will be printed to this file,
639                      otherwise, print to stderr
640    KMP_STATS_THREADS -- if set to "on", then will print per thread statistics to either
641                         KMP_STATS_FILE or stderr
642    KMP_STATS_PLOT_FILE -- if set, print the ploticus plot file to this filename,
643                           otherwise, the plot file is sent to "events.plt"
644    KMP_STATS_EVENTS -- if set to "on", then log events, otherwise, don't log events
645    KMP_STATS_EVENTS_FILE -- if set, all events are outputted to this file,
646                             otherwise, output is sent to "events.dat"
647 
648 **************************************************************** */
649 class kmp_stats_output_module {
650 
651  public:
652     struct rgb_color {
653         float r;
654         float g;
655         float b;
656     };
657 
658  private:
659     std::string outputFileName;
660     static const char* eventsFileName;
661     static const char* plotFileName;
662     static int printPerThreadFlag;
663     static int printPerThreadEventsFlag;
664     static const rgb_color globalColorArray[];
665     static       rgb_color timerColorInfo[];
666 
667     void init();
668     static void setupEventColors();
669     static void printPloticusFile();
670     static void printHeaderInfo(FILE *statsOut);
671     static void printTimerStats(FILE *statsOut, statistic const * theStats, statistic const * totalStats);
672     static void printCounterStats(FILE *statsOut, statistic const * theStats);
673     static void printCounters(FILE * statsOut, counter const * theCounters);
674     static void printEvents(FILE * eventsOut, kmp_stats_event_vector* theEvents, int gtid);
675     static rgb_color getEventColor(timer_e e) { return timerColorInfo[e]; }
676     static void windupExplicitTimers();
677     bool eventPrintingEnabled() const         { return printPerThreadEventsFlag; }
678 
679  public:
680     kmp_stats_output_module() { init(); }
681     void outputStats(const char* heading);
682 };
683 
684 #ifdef __cplusplus
685 extern "C" {
686 #endif
687 void __kmp_stats_init();
688 void __kmp_stats_fini();
689 void __kmp_reset_stats();
690 void __kmp_output_stats(const char *);
691 void __kmp_accumulate_stats_at_exit(void);
692 // thread local pointer to stats node within list
693 extern __thread kmp_stats_list* __kmp_stats_thread_ptr;
694 // head to stats list.
695 extern kmp_stats_list* __kmp_stats_list;
696 // lock for __kmp_stats_list
697 extern kmp_tas_lock_t  __kmp_stats_lock;
698 // reference start time
699 extern tsc_tick_count __kmp_stats_start_time;
700 // interface to output
701 extern kmp_stats_output_module __kmp_stats_output;
702 
703 #ifdef __cplusplus
704 }
705 #endif
706 
707 // Simple, standard interfaces that drop out completely if stats aren't enabled
708 
709 
710 /*!
711  * \brief Uses specified timer (name) to time code block.
712  *
713  * @param name timer name as specified under the KMP_FOREACH_TIMER() macro
714  *
715  * \details Use KMP_TIME_BLOCK(name) macro to time a code block.  This will record the time taken in the block
716  * and use the destructor to stop the timer.  Convenient!
717  * With this definition you can't have more than one KMP_TIME_BLOCK in the same code block.
718  * I don't think that's a problem.
719  *
720  * @ingroup STATS_GATHERING
721 */
722 #define KMP_TIME_BLOCK(name) \
723     blockTimer __BLOCKTIME__(__kmp_stats_thread_ptr->getTimer(TIMER_##name), TIMER_##name)
724 
725 /*!
726  * \brief Adds value to specified timer (name).
727  *
728  * @param name timer name as specified under the KMP_FOREACH_TIMER() macro
729  * @param value double precision sample value to add to statistics for the timer
730  *
731  * \details Use KMP_COUNT_VALUE(name, value) macro to add a particular value to a timer statistics.
732  *
733  * @ingroup STATS_GATHERING
734 */
735 #define KMP_COUNT_VALUE(name, value) \
736     __kmp_stats_thread_ptr->getTimer(TIMER_##name)->addSample(value)
737 
738 /*!
739  * \brief Increments specified counter (name).
740  *
741  * @param name counter name as specified under the KMP_FOREACH_COUNTER() macro
742  *
743  * \details Use KMP_COUNT_BLOCK(name, value) macro to increment a statistics counter for the executing thread.
744  *
745  * @ingroup STATS_GATHERING
746 */
747 #define KMP_COUNT_BLOCK(name) \
748    __kmp_stats_thread_ptr->getCounter(COUNTER_##name)->increment()
749 
750 /*!
751  * \brief "Starts" an explicit timer which will need a corresponding KMP_STOP_EXPLICIT_TIMER() macro.
752  *
753  * @param name explicit timer name as specified under the KMP_FOREACH_EXPLICIT_TIMER() macro
754  *
755  * \details Use to start a timer.  This will need a corresponding KMP_STOP_EXPLICIT_TIMER()
756  * macro to stop the timer unlike the KMP_TIME_BLOCK(name) macro which has an implicit stopping macro at the end
757  * of the code block.  All explicit timers are stopped at library exit time before the final statistics are outputted.
758  *
759  * @ingroup STATS_GATHERING
760 */
761 #define KMP_START_EXPLICIT_TIMER(name) \
762     __kmp_stats_thread_ptr->getExplicitTimer(EXPLICIT_TIMER_##name)->start(TIMER_##name)
763 
764 /*!
765  * \brief "Stops" an explicit timer.
766  *
767  * @param name explicit timer name as specified under the KMP_FOREACH_EXPLICIT_TIMER() macro
768  *
769  * \details Use KMP_STOP_EXPLICIT_TIMER(name) to stop a timer.  When this is done, the time between the last KMP_START_EXPLICIT_TIMER(name)
770  * and this KMP_STOP_EXPLICIT_TIMER(name) will be added to the timer's stat value.  The timer will then be reset.
771  * After the KMP_STOP_EXPLICIT_TIMER(name) macro is called, another call to KMP_START_EXPLICIT_TIMER(name) will start the timer once again.
772  *
773  * @ingroup STATS_GATHERING
774 */
775 #define KMP_STOP_EXPLICIT_TIMER(name) \
776     __kmp_stats_thread_ptr->getExplicitTimer(EXPLICIT_TIMER_##name)->stop(TIMER_##name)
777 
778 /*!
779  * \brief Outputs the current thread statistics and reset them.
780  *
781  * @param heading_string heading put above the final stats output
782  *
783  * \details Explicitly stops all timers and outputs all stats.
784  * Environment variable, `OMPTB_STATSFILE=filename`, can be used to output the stats to a filename instead of stderr
785  * Environment variable, `OMPTB_STATSTHREADS=true|undefined`, can be used to output thread specific stats
786  * For now the `OMPTB_STATSTHREADS` environment variable can either be defined with any value, which will print out thread
787  * specific stats, or it can be undefined (not specified in the environment) and thread specific stats won't be printed
788  * It should be noted that all statistics are reset when this macro is called.
789  *
790  * @ingroup STATS_GATHERING
791 */
792 #define KMP_OUTPUT_STATS(heading_string) \
793     __kmp_output_stats(heading_string)
794 
795 /*!
796  * \brief Initializes the paritioned timers to begin with name.
797  *
798  * @param name timer which you want this thread to begin with
799  *
800  * @ingroup STATS_GATHERING
801 */
802 #define KMP_INIT_PARTITIONED_TIMERS(name) \
803     __kmp_stats_thread_ptr->getPartitionedTimers()->init(timerPair(EXPLICIT_TIMER_##name, TIMER_##name))
804 
805 #define KMP_TIME_PARTITIONED_BLOCK(name) \
806     blockPartitionedTimer __PBLOCKTIME__(__kmp_stats_thread_ptr->getPartitionedTimers(), \
807         timerPair(EXPLICIT_TIMER_##name, TIMER_##name))
808 
809 #define KMP_PUSH_PARTITIONED_TIMER(name) \
810     __kmp_stats_thread_ptr->getPartitionedTimers()->push(timerPair(EXPLICIT_TIMER_##name, TIMER_##name))
811 
812 #define KMP_POP_PARTITIONED_TIMER() \
813     __kmp_stats_thread_ptr->getPartitionedTimers()->pop()
814 
815 #define KMP_SET_THREAD_STATE(state_name) \
816     __kmp_stats_thread_ptr->setState(state_name)
817 
818 #define KMP_GET_THREAD_STATE() \
819     __kmp_stats_thread_ptr->getState()
820 
821 #define KMP_SET_THREAD_STATE_BLOCK(state_name) \
822     blockThreadState __BTHREADSTATE__(__kmp_stats_thread_ptr->getStatePointer(), state_name)
823 
824 /*!
825  * \brief resets all stats (counters to 0, timers to 0 elapsed ticks)
826  *
827  * \details Reset all stats for all threads.
828  *
829  * @ingroup STATS_GATHERING
830 */
831 #define KMP_RESET_STATS()  __kmp_reset_stats()
832 
833 #if (KMP_DEVELOPER_STATS)
834 # define KMP_TIME_DEVELOPER_BLOCK(n)             KMP_TIME_BLOCK(n)
835 # define KMP_COUNT_DEVELOPER_VALUE(n,v)          KMP_COUNT_VALUE(n,v)
836 # define KMP_COUNT_DEVELOPER_BLOCK(n)            KMP_COUNT_BLOCK(n)
837 # define KMP_START_DEVELOPER_EXPLICIT_TIMER(n)   KMP_START_EXPLICIT_TIMER(n)
838 # define KMP_STOP_DEVELOPER_EXPLICIT_TIMER(n)    KMP_STOP_EXPLICIT_TIMER(n)
839 # define KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(n) KMP_TIME_PARTITIONED_BLOCK(n)
840 #else
841 // Null definitions
842 # define KMP_TIME_DEVELOPER_BLOCK(n)             ((void)0)
843 # define KMP_COUNT_DEVELOPER_VALUE(n,v)          ((void)0)
844 # define KMP_COUNT_DEVELOPER_BLOCK(n)            ((void)0)
845 # define KMP_START_DEVELOPER_EXPLICIT_TIMER(n)   ((void)0)
846 # define KMP_STOP_DEVELOPER_EXPLICIT_TIMER(n)    ((void)0)
847 # define KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(n) ((void)0)
848 #endif
849 
850 #else // KMP_STATS_ENABLED
851 
852 // Null definitions
853 #define KMP_TIME_BLOCK(n)             ((void)0)
854 #define KMP_COUNT_VALUE(n,v)          ((void)0)
855 #define KMP_COUNT_BLOCK(n)            ((void)0)
856 #define KMP_START_EXPLICIT_TIMER(n)   ((void)0)
857 #define KMP_STOP_EXPLICIT_TIMER(n)    ((void)0)
858 
859 #define KMP_OUTPUT_STATS(heading_string) ((void)0)
860 #define KMP_RESET_STATS()  ((void)0)
861 
862 #define KMP_TIME_DEVELOPER_BLOCK(n)             ((void)0)
863 #define KMP_COUNT_DEVELOPER_VALUE(n,v)          ((void)0)
864 #define KMP_COUNT_DEVELOPER_BLOCK(n)            ((void)0)
865 #define KMP_START_DEVELOPER_EXPLICIT_TIMER(n)   ((void)0)
866 #define KMP_STOP_DEVELOPER_EXPLICIT_TIMER(n)    ((void)0)
867 #define KMP_INIT_PARTITIONED_TIMERS(name)       ((void)0)
868 #define KMP_TIME_PARTITIONED_BLOCK(name)        ((void)0)
869 #define KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(n) ((void)0)
870 #define KMP_PUSH_PARTITIONED_TIMER(name)        ((void)0)
871 #define KMP_POP_PARTITIONED_TIMER()             ((void)0)
872 #define KMP_SET_THREAD_STATE(state_name)        ((void)0)
873 #define KMP_GET_THREAD_STATE()                  ((void)0)
874 #define KMP_SET_THREAD_STATE_BLOCK(state_name)  ((void)0)
875 #endif  // KMP_STATS_ENABLED
876 
877 #endif // KMP_STATS_H
878