LLVM OpenMP* Runtime Library
kmp_stats.h
1 #ifndef KMP_STATS_H
2 #define KMP_STATS_H
3 
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 <string>
31 #include <stdint.h>
32 #include <new> // placement new
33 #include "kmp_stats_timing.h"
34 
35 /*
36  * Enable developer statistics here if you want them. They are more detailed than is useful for application characterisation and
37  * are intended for the runtime library developer.
38  */
39 // #define KMP_DEVELOPER_STATS 1
40 
47  public:
48  const static int onlyInMaster = 1<<0;
49  const static int noUnits = 1<<1;
50  const static int synthesized = 1<<2;
51  const static int notInMaster = 1<<3;
52  const static int logEvent = 1<<4;
53 };
54 
71 #define KMP_FOREACH_COUNTER(macro, arg) \
72  macro (OMP_PARALLEL, stats_flags_e::onlyInMaster, arg) \
73  macro (OMP_NESTED_PARALLEL, 0, arg) \
74  macro (OMP_FOR_static, 0, arg) \
75  macro (OMP_FOR_dynamic, 0, arg) \
76  macro (OMP_DISTRIBUTE, 0, arg) \
77  macro (OMP_BARRIER, 0, arg) \
78  macro (OMP_CRITICAL,0, arg) \
79  macro (OMP_SINGLE, 0, arg) \
80  macro (OMP_MASTER, 0, arg) \
81  macro (OMP_TEAMS, 0, arg) \
82  macro (OMP_set_lock, 0, arg) \
83  macro (OMP_test_lock, 0, arg) \
84  macro (REDUCE_wait, 0, arg) \
85  macro (REDUCE_nowait, 0, arg) \
86  macro (OMP_TASKYIELD, 0, arg) \
87  macro (TASK_executed, 0, arg) \
88  macro (TASK_cancelled, 0, arg) \
89  macro (TASK_stolen, 0, arg) \
90  macro (LAST,0,arg)
91 
92 // OMP_PARALLEL_args -- the number of arguments passed to a fork
93 // FOR_static_iterations -- Number of available parallel chunks of work in a static for
94 // FOR_dynamic_iterations -- Number of available parallel chunks of work in a dynamic for
95 // Both adjust for any chunking, so if there were an iteration count of 20 but a chunk size of 10, we'd record 2.
96 
111 #define KMP_FOREACH_TIMER(macro, arg) \
112  macro (OMP_start_end, stats_flags_e::onlyInMaster, arg) \
113  macro (OMP_serial, stats_flags_e::onlyInMaster, arg) \
114  macro (OMP_work, 0, arg) \
115  macro (Total_work, stats_flags_e::synthesized, arg) \
116  macro (OMP_barrier, 0, arg) \
117  macro (Total_barrier, stats_flags_e::synthesized, arg) \
118  macro (FOR_static_iterations, stats_flags_e::noUnits, arg) \
119  macro (FOR_static_scheduling, 0, arg) \
120  macro (FOR_dynamic_iterations, stats_flags_e::noUnits, arg) \
121  macro (FOR_dynamic_scheduling, 0, arg) \
122  macro (TASK_execution, 0, arg) \
123  macro (OMP_set_numthreads, stats_flags_e::noUnits, arg) \
124  macro (OMP_PARALLEL_args, stats_flags_e::noUnits, arg) \
125  macro (OMP_single, 0, arg) \
126  macro (OMP_master, 0, arg) \
127  KMP_FOREACH_DEVELOPER_TIMER(macro, arg) \
128  macro (LAST,0, arg)
129 
130 
131 // OMP_start_end -- time from when OpenMP is initialized until the stats are printed at exit
132 // OMP_serial -- thread zero time executing serial code
133 // OMP_work -- elapsed time in code dispatched by a fork (measured in the thread)
134 // Total_work -- a synthesized statistic summarizing how much parallel work each thread executed.
135 // OMP_barrier -- time at "real" barriers
136 // Total_barrier -- a synthesized statistic summarizing how much time at real barriers in each thread
137 // FOR_static_scheduling -- time spent doing scheduling for a static "for"
138 // FOR_dynamic_scheduling -- time spent doing scheduling for a dynamic "for"
139 
140 #if (KMP_DEVELOPER_STATS)
141 // Timers which are of interest tio runtime library developers, not end users.
142 // THese have to be explicitly enabled in addition to the other stats.
143 
144 // KMP_fork_barrier -- time in __kmp_fork_barrier
145 // KMP_join_barrier -- time in __kmp_join_barrier
146 // KMP_barrier -- time in __kmp_barrier
147 // KMP_end_split_barrier -- time in __kmp_end_split_barrier
148 // KMP_setup_icv_copy -- time in __kmp_setup_icv_copy
149 // KMP_icv_copy -- start/stop timer for any ICV copying
150 // KMP_linear_gather -- time in __kmp_linear_barrier_gather
151 // KMP_linear_release -- time in __kmp_linear_barrier_release
152 // KMP_tree_gather -- time in __kmp_tree_barrier_gather
153 // KMP_tree_release -- time in __kmp_tree_barrier_release
154 // KMP_hyper_gather -- time in __kmp_hyper_barrier_gather
155 // KMP_hyper_release -- time in __kmp_hyper_barrier_release
156 # define KMP_FOREACH_DEVELOPER_TIMER(macro, arg) \
157  macro (KMP_fork_call, 0, arg) \
158  macro (KMP_join_call, 0, arg) \
159  macro (KMP_fork_barrier, stats_flags_e::logEvent, arg) \
160  macro (KMP_join_barrier, stats_flags_e::logEvent, arg) \
161  macro (KMP_barrier, 0, arg) \
162  macro (KMP_end_split_barrier, 0, arg) \
163  macro (KMP_hier_gather, 0, arg) \
164  macro (KMP_hier_release, 0, arg) \
165  macro (KMP_hyper_gather, stats_flags_e::logEvent, arg) \
166  macro (KMP_hyper_release, stats_flags_e::logEvent, arg) \
167  macro (KMP_linear_gather, 0, arg) \
168  macro (KMP_linear_release, 0, arg) \
169  macro (KMP_tree_gather, 0, arg) \
170  macro (KMP_tree_release, 0, arg) \
171  macro (USER_master_invoke, stats_flags_e::logEvent, arg) \
172  macro (USER_worker_invoke, stats_flags_e::logEvent, arg) \
173  macro (USER_resume, stats_flags_e::logEvent, arg) \
174  macro (USER_suspend, stats_flags_e::logEvent, arg) \
175  macro (USER_launch_thread_loop, stats_flags_e::logEvent, arg) \
176  macro (KMP_allocate_team, 0, arg) \
177  macro (KMP_setup_icv_copy, 0, arg) \
178  macro (USER_icv_copy, 0, arg)
179 #else
180 # define KMP_FOREACH_DEVELOPER_TIMER(macro, arg)
181 #endif
182 
199 #define KMP_FOREACH_EXPLICIT_TIMER(macro, arg) \
200  macro(OMP_serial, 0, arg) \
201  macro(OMP_start_end, 0, arg) \
202  macro(OMP_single, 0, arg) \
203  macro(OMP_master, 0, arg) \
204  KMP_FOREACH_EXPLICIT_DEVELOPER_TIMER(macro,arg) \
205  macro(LAST, 0, arg)
206 
207 #if (KMP_DEVELOPER_STATS)
208 # define KMP_FOREACH_EXPLICIT_DEVELOPER_TIMER(macro, arg) \
209  macro(USER_launch_thread_loop, stats_flags_e::logEvent, arg)
210 #else
211 # define KMP_FOREACH_EXPLICIT_DEVELOPER_TIMER(macro, arg)
212 #endif
213 
214 #define ENUMERATE(name,ignore,prefix) prefix##name,
215 enum timer_e {
216  KMP_FOREACH_TIMER(ENUMERATE, TIMER_)
217 };
218 
219 enum explicit_timer_e {
220  KMP_FOREACH_EXPLICIT_TIMER(ENUMERATE, EXPLICIT_TIMER_)
221 };
222 
223 enum counter_e {
224  KMP_FOREACH_COUNTER(ENUMERATE, COUNTER_)
225 };
226 #undef ENUMERATE
227 
228 class statistic
229 {
230  double minVal;
231  double maxVal;
232  double meanVal;
233  double m2;
234  uint64_t sampleCount;
235 
236  public:
237  statistic() { reset(); }
238  statistic (statistic const &o): minVal(o.minVal), maxVal(o.maxVal), meanVal(o.meanVal), m2(o.m2), sampleCount(o.sampleCount) {}
239 
240  double getMin() const { return minVal; }
241  double getMean() const { return meanVal; }
242  double getMax() const { return maxVal; }
243  uint64_t getCount() const { return sampleCount; }
244  double getSD() const { return sqrt(m2/sampleCount); }
245  double getTotal() const { return sampleCount*meanVal; }
246 
247  void reset()
248  {
249  minVal = std::numeric_limits<double>::max();
250  maxVal = -std::numeric_limits<double>::max();
251  meanVal= 0.0;
252  m2 = 0.0;
253  sampleCount = 0;
254  }
255  void addSample(double sample);
256  void scale (double factor);
257  void scaleDown(double f) { scale (1./f); }
258  statistic & operator+= (statistic const & other);
259 
260  std::string format(char unit, bool total=false) const;
261 };
262 
263 struct statInfo
264 {
265  const char * name;
266  uint32_t flags;
267 };
268 
269 class timeStat : public statistic
270 {
271  static statInfo timerInfo[];
272 
273  public:
274  timeStat() : statistic() {}
275  static const char * name(timer_e e) { return timerInfo[e].name; }
276  static bool masterOnly (timer_e e) { return timerInfo[e].flags & stats_flags_e::onlyInMaster; }
277  static bool workerOnly (timer_e e) { return timerInfo[e].flags & stats_flags_e::notInMaster; }
278  static bool noUnits (timer_e e) { return timerInfo[e].flags & stats_flags_e::noUnits; }
279  static bool synthesized(timer_e e) { return timerInfo[e].flags & stats_flags_e::synthesized; }
280  static bool logEvent (timer_e e) { return timerInfo[e].flags & stats_flags_e::logEvent; }
281  static void clearEventFlags() {
282  int i;
283  for(i=0;i<TIMER_LAST;i++) {
284  timerInfo[i].flags &= (~(stats_flags_e::logEvent));
285  }
286  }
287 };
288 
289 // Where we need explicitly to start and end the timer, this version can be used
290 // Since these timers normally aren't nicely scoped, so don't have a good place to live
291 // on the stack of the thread, they're more work to use.
292 class explicitTimer
293 {
294  timeStat * stat;
295  tsc_tick_count startTime;
296 
297  public:
298  explicitTimer () : stat(0), startTime(0) { }
299  explicitTimer (timeStat * s) : stat(s), startTime() { }
300 
301  void setStat (timeStat *s) { stat = s; }
302  void start(timer_e timerEnumValue);
303  void stop(timer_e timerEnumValue);
304  void reset() { startTime = 0; }
305 };
306 
307 // Where all you need is to time a block, this is enough.
308 // (It avoids the need to have an explicit end, leaving the scope suffices.)
309 class blockTimer : public explicitTimer
310 {
311  timer_e timerEnumValue;
312  public:
313  blockTimer (timeStat * s, timer_e newTimerEnumValue) : timerEnumValue(newTimerEnumValue), explicitTimer(s) { start(timerEnumValue); }
314  ~blockTimer() { stop(timerEnumValue); }
315 };
316 
317 // If all you want is a count, then you can use this...
318 // The individual per-thread counts will be aggregated into a statistic at program exit.
319 class counter
320 {
321  uint64_t value;
322  static const statInfo counterInfo[];
323 
324  public:
325  counter() : value(0) {}
326  void increment() { value++; }
327  uint64_t getValue() const { return value; }
328  void reset() { value = 0; }
329  static const char * name(counter_e e) { return counterInfo[e].name; }
330  static bool masterOnly (counter_e e) { return counterInfo[e].flags & stats_flags_e::onlyInMaster; }
331 };
332 
333 /* ****************************************************************
334  Class to implement an event
335 
336  There are four components to an event: start time, stop time
337  nest_level, and timer_name.
338  The start and stop time should be obvious (recorded in clock ticks).
339  The nest_level relates to the bar width in the timeline graph.
340  The timer_name is used to determine which timer event triggered this event.
341 
342  the interface to this class is through four read-only operations:
343  1) getStart() -- returns the start time as 64 bit integer
344  2) getStop() -- returns the stop time as 64 bit integer
345  3) getNestLevel() -- returns the nest level of the event
346  4) getTimerName() -- returns the timer name that triggered event
347 
348  *MORE ON NEST_LEVEL*
349  The nest level is used in the bar graph that represents the timeline.
350  Its main purpose is for showing how events are nested inside eachother.
351  For example, say events, A, B, and C are recorded. If the timeline
352  looks like this:
353 
354 Begin -------------------------------------------------------------> Time
355  | | | | | |
356  A B C C B A
357  start start start end end end
358 
359  Then A, B, C will have a nest level of 1, 2, 3 respectively.
360  These values are then used to calculate the barwidth so you can
361  see that inside A, B has occurred, and inside B, C has occurred.
362  Currently, this is shown with A's bar width being larger than B's
363  bar width, and B's bar width being larger than C's bar width.
364 
365 **************************************************************** */
366 class kmp_stats_event {
367  uint64_t start;
368  uint64_t stop;
369  int nest_level;
370  timer_e timer_name;
371  public:
372  kmp_stats_event() : start(0), stop(0), nest_level(0), timer_name(TIMER_LAST) {}
373  kmp_stats_event(uint64_t strt, uint64_t stp, int nst, timer_e nme) : start(strt), stop(stp), nest_level(nst), timer_name(nme) {}
374  inline uint64_t getStart() const { return start; }
375  inline uint64_t getStop() const { return stop; }
376  inline int getNestLevel() const { return nest_level; }
377  inline timer_e getTimerName() const { return timer_name; }
378 };
379 
380 /* ****************************************************************
381  Class to implement a dynamically expandable array of events
382 
383  ---------------------------------------------------------
384  | event 1 | event 2 | event 3 | event 4 | ... | event N |
385  ---------------------------------------------------------
386 
387  An event is pushed onto the back of this array at every
388  explicitTimer->stop() call. The event records the thread #,
389  start time, stop time, and nest level related to the bar width.
390 
391  The event vector starts at size INIT_SIZE and grows (doubles in size)
392  if needed. An implication of this behavior is that log(N)
393  reallocations are needed (where N is number of events). If you want
394  to avoid reallocations, then set INIT_SIZE to a large value.
395 
396  the interface to this class is through six operations:
397  1) reset() -- sets the internal_size back to 0 but does not deallocate any memory
398  2) size() -- returns the number of valid elements in the vector
399  3) push_back(start, stop, nest, timer_name) -- pushes an event onto
400  the back of the array
401  4) deallocate() -- frees all memory associated with the vector
402  5) sort() -- sorts the vector by start time
403  6) operator[index] or at(index) -- returns event reference at that index
404 
405 **************************************************************** */
406 class kmp_stats_event_vector {
407  kmp_stats_event* events;
408  int internal_size;
409  int allocated_size;
410  static const int INIT_SIZE = 1024;
411  public:
412  kmp_stats_event_vector() {
413  events = (kmp_stats_event*)__kmp_allocate(sizeof(kmp_stats_event)*INIT_SIZE);
414  internal_size = 0;
415  allocated_size = INIT_SIZE;
416  }
417  ~kmp_stats_event_vector() {}
418  inline void reset() { internal_size = 0; }
419  inline int size() const { return internal_size; }
420  void push_back(uint64_t start_time, uint64_t stop_time, int nest_level, timer_e name) {
421  int i;
422  if(internal_size == allocated_size) {
423  kmp_stats_event* tmp = (kmp_stats_event*)__kmp_allocate(sizeof(kmp_stats_event)*allocated_size*2);
424  for(i=0;i<internal_size;i++) tmp[i] = events[i];
425  __kmp_free(events);
426  events = tmp;
427  allocated_size*=2;
428  }
429  events[internal_size] = kmp_stats_event(start_time, stop_time, nest_level, name);
430  internal_size++;
431  return;
432  }
433  void deallocate();
434  void sort();
435  const kmp_stats_event & operator[](int index) const { return events[index]; }
436  kmp_stats_event & operator[](int index) { return events[index]; }
437  const kmp_stats_event & at(int index) const { return events[index]; }
438  kmp_stats_event & at(int index) { return events[index]; }
439 };
440 
441 /* ****************************************************************
442  Class to implement a doubly-linked, circular, statistics list
443 
444  |---| ---> |---| ---> |---| ---> |---| ---> ... next
445  | | | | | | | |
446  |---| <--- |---| <--- |---| <--- |---| <--- ... prev
447  Sentinel first second third
448  Node node node node
449 
450  The Sentinel Node is the user handle on the list.
451  The first node corresponds to thread 0's statistics.
452  The second node corresponds to thread 1's statistics and so on...
453 
454  Each node has a _timers, _counters, and _explicitTimers array to
455  hold that thread's statistics. The _explicitTimers
456  point to the correct _timer and update its statistics at every stop() call.
457  The explicitTimers' pointers are set up in the constructor.
458  Each node also has an event vector to hold that thread's timing events.
459  The event vector expands as necessary and records the start-stop times
460  for each timer.
461 
462  The nestLevel variable is for plotting events and is related
463  to the bar width in the timeline graph.
464 
465  Every thread will have a __thread local pointer to its node in
466  the list. The sentinel node is used by the master thread to
467  store "dummy" statistics before __kmp_create_worker() is called.
468 
469 **************************************************************** */
470 class kmp_stats_list {
471  int gtid;
472  timeStat _timers[TIMER_LAST+1];
473  counter _counters[COUNTER_LAST+1];
474  explicitTimer _explicitTimers[EXPLICIT_TIMER_LAST+1];
475  int _nestLevel; // one per thread
476  kmp_stats_event_vector _event_vector;
477  kmp_stats_list* next;
478  kmp_stats_list* prev;
479  public:
480  kmp_stats_list() : next(this) , prev(this) , _event_vector(), _nestLevel(0) {
481 #define doInit(name,ignore1,ignore2) \
482  getExplicitTimer(EXPLICIT_TIMER_##name)->setStat(getTimer(TIMER_##name));
483  KMP_FOREACH_EXPLICIT_TIMER(doInit,0);
484 #undef doInit
485  }
486  ~kmp_stats_list() { }
487  inline timeStat * getTimer(timer_e idx) { return &_timers[idx]; }
488  inline counter * getCounter(counter_e idx) { return &_counters[idx]; }
489  inline explicitTimer * getExplicitTimer(explicit_timer_e idx) { return &_explicitTimers[idx]; }
490  inline timeStat * getTimers() { return _timers; }
491  inline counter * getCounters() { return _counters; }
492  inline explicitTimer * getExplicitTimers() { return _explicitTimers; }
493  inline kmp_stats_event_vector & getEventVector() { return _event_vector; }
494  inline void resetEventVector() { _event_vector.reset(); }
495  inline void incrementNestValue() { _nestLevel++; }
496  inline int getNestValue() { return _nestLevel; }
497  inline void decrementNestValue() { _nestLevel--; }
498  inline int getGtid() const { return gtid; }
499  inline void setGtid(int newgtid) { gtid = newgtid; }
500  kmp_stats_list* push_back(int gtid); // returns newly created list node
501  inline void push_event(uint64_t start_time, uint64_t stop_time, int nest_level, timer_e name) {
502  _event_vector.push_back(start_time, stop_time, nest_level, name);
503  }
504  void deallocate();
505  class iterator;
506  kmp_stats_list::iterator begin();
507  kmp_stats_list::iterator end();
508  int size();
509  class iterator {
510  kmp_stats_list* ptr;
511  friend kmp_stats_list::iterator kmp_stats_list::begin();
512  friend kmp_stats_list::iterator kmp_stats_list::end();
513  public:
514  iterator();
515  ~iterator();
516  iterator operator++();
517  iterator operator++(int dummy);
518  iterator operator--();
519  iterator operator--(int dummy);
520  bool operator!=(const iterator & rhs);
521  bool operator==(const iterator & rhs);
522  kmp_stats_list* operator*() const; // dereference operator
523  };
524 };
525 
526 /* ****************************************************************
527  Class to encapsulate all output functions and the environment variables
528 
529  This module holds filenames for various outputs (normal stats, events, plot file),
530  as well as coloring information for the plot file.
531 
532  The filenames and flags variables are read from environment variables.
533  These are read once by the constructor of the global variable __kmp_stats_output
534  which calls init().
535 
536  During this init() call, event flags for the timeStat::timerInfo[] global array
537  are cleared if KMP_STATS_EVENTS is not true (on, 1, yes).
538 
539  The only interface function that is public is outputStats(heading). This function
540  should print out everything it needs to, either to files or stderr,
541  depending on the environment variables described below
542 
543  ENVIRONMENT VARIABLES:
544  KMP_STATS_FILE -- if set, all statistics (not events) will be printed to this file,
545  otherwise, print to stderr
546  KMP_STATS_THREADS -- if set to "on", then will print per thread statistics to either
547  KMP_STATS_FILE or stderr
548  KMP_STATS_PLOT_FILE -- if set, print the ploticus plot file to this filename,
549  otherwise, the plot file is sent to "events.plt"
550  KMP_STATS_EVENTS -- if set to "on", then log events, otherwise, don't log events
551  KMP_STATS_EVENTS_FILE -- if set, all events are outputted to this file,
552  otherwise, output is sent to "events.dat"
553 
554 **************************************************************** */
555 class kmp_stats_output_module {
556 
557  public:
558  struct rgb_color {
559  float r;
560  float g;
561  float b;
562  };
563 
564  private:
565  static const char* outputFileName;
566  static const char* eventsFileName;
567  static const char* plotFileName;
568  static int printPerThreadFlag;
569  static int printPerThreadEventsFlag;
570  static const rgb_color globalColorArray[];
571  static rgb_color timerColorInfo[];
572 
573  void init();
574  static void setupEventColors();
575  static void printPloticusFile();
576  static void printStats(FILE *statsOut, statistic const * theStats, bool areTimers);
577  static void printCounters(FILE * statsOut, counter const * theCounters);
578  static void printEvents(FILE * eventsOut, kmp_stats_event_vector* theEvents, int gtid);
579  static rgb_color getEventColor(timer_e e) { return timerColorInfo[e]; }
580  static void windupExplicitTimers();
581  bool eventPrintingEnabled() {
582  if(printPerThreadEventsFlag) return true;
583  else return false;
584  }
585  bool perThreadPrintingEnabled() {
586  if(printPerThreadFlag) return true;
587  else return false;
588  }
589 
590  public:
591  kmp_stats_output_module() { init(); }
592  void outputStats(const char* heading);
593 };
594 
595 #ifdef __cplusplus
596 extern "C" {
597 #endif
598 void __kmp_stats_init();
599 void __kmp_reset_stats();
600 void __kmp_output_stats(const char *);
601 void __kmp_accumulate_stats_at_exit(void);
602 // thread local pointer to stats node within list
603 extern __thread kmp_stats_list* __kmp_stats_thread_ptr;
604 // head to stats list.
605 extern kmp_stats_list __kmp_stats_list;
606 // lock for __kmp_stats_list
607 extern kmp_tas_lock_t __kmp_stats_lock;
608 // reference start time
609 extern tsc_tick_count __kmp_stats_start_time;
610 // interface to output
611 extern kmp_stats_output_module __kmp_stats_output;
612 
613 #ifdef __cplusplus
614 }
615 #endif
616 
617 // Simple, standard interfaces that drop out completely if stats aren't enabled
618 
619 
632 #define KMP_TIME_BLOCK(name) \
633  blockTimer __BLOCKTIME__(__kmp_stats_thread_ptr->getTimer(TIMER_##name), TIMER_##name)
634 
645 #define KMP_COUNT_VALUE(name, value) \
646  __kmp_stats_thread_ptr->getTimer(TIMER_##name)->addSample(value)
647 
657 #define KMP_COUNT_BLOCK(name) \
658  __kmp_stats_thread_ptr->getCounter(COUNTER_##name)->increment()
659 
671 #define KMP_START_EXPLICIT_TIMER(name) \
672  __kmp_stats_thread_ptr->getExplicitTimer(EXPLICIT_TIMER_##name)->start(TIMER_##name)
673 
685 #define KMP_STOP_EXPLICIT_TIMER(name) \
686  __kmp_stats_thread_ptr->getExplicitTimer(EXPLICIT_TIMER_##name)->stop(TIMER_##name)
687 
702 #define KMP_OUTPUT_STATS(heading_string) \
703  __kmp_output_stats(heading_string)
704 
712 #define KMP_RESET_STATS() __kmp_reset_stats()
713 
714 #if (KMP_DEVELOPER_STATS)
715 # define KMP_TIME_DEVELOPER_BLOCK(n) KMP_TIME_BLOCK(n)
716 # define KMP_COUNT_DEVELOPER_VALUE(n,v) KMP_COUNT_VALUE(n,v)
717 # define KMP_COUNT_DEVELOPER_BLOCK(n) KMP_COUNT_BLOCK(n)
718 # define KMP_START_DEVELOPER_EXPLICIT_TIMER(n) KMP_START_EXPLICIT_TIMER(n)
719 # define KMP_STOP_DEVELOPER_EXPLICIT_TIMER(n) KMP_STOP_EXPLICIT_TIMER(n)
720 #else
721 // Null definitions
722 # define KMP_TIME_DEVELOPER_BLOCK(n) ((void)0)
723 # define KMP_COUNT_DEVELOPER_VALUE(n,v) ((void)0)
724 # define KMP_COUNT_DEVELOPER_BLOCK(n) ((void)0)
725 # define KMP_START_DEVELOPER_EXPLICIT_TIMER(n) ((void)0)
726 # define KMP_STOP_DEVELOPER_EXPLICIT_TIMER(n) ((void)0)
727 #endif
728 
729 #else // KMP_STATS_ENABLED
730 
731 // Null definitions
732 #define KMP_TIME_BLOCK(n) ((void)0)
733 #define KMP_COUNT_VALUE(n,v) ((void)0)
734 #define KMP_COUNT_BLOCK(n) ((void)0)
735 #define KMP_START_EXPLICIT_TIMER(n) ((void)0)
736 #define KMP_STOP_EXPLICIT_TIMER(n) ((void)0)
737 
738 #define KMP_OUTPUT_STATS(heading_string) ((void)0)
739 #define KMP_RESET_STATS() ((void)0)
740 
741 #define KMP_TIME_DEVELOPER_BLOCK(n) ((void)0)
742 #define KMP_COUNT_DEVELOPER_VALUE(n,v) ((void)0)
743 #define KMP_COUNT_DEVELOPER_BLOCK(n) ((void)0)
744 #define KMP_START_DEVELOPER_EXPLICIT_TIMER(n) ((void)0)
745 #define KMP_STOP_DEVELOPER_EXPLICIT_TIMER(n) ((void)0)
746 #endif // KMP_STATS_ENABLED
747 
748 #endif // KMP_STATS_H
flags to describe the statistic ( timers or counter )
Definition: kmp_stats.h:46
static const int noUnits
statistic doesn&#39;t need units printed next to it in output
Definition: kmp_stats.h:49
static const int synthesized
statistic&#39;s value is created atexit time in the __kmp_output_stats function
Definition: kmp_stats.h:50
#define KMP_FOREACH_EXPLICIT_TIMER(macro, arg)
Add new explicit timers under KMP_FOREACH_EXPLICIT_TIMER() macro.
Definition: kmp_stats.h:199
static const int notInMaster
statistic is valid for non-master threads
Definition: kmp_stats.h:51
static const int onlyInMaster
statistic is valid only for master
Definition: kmp_stats.h:48
#define KMP_FOREACH_COUNTER(macro, arg)
Add new counters under KMP_FOREACH_COUNTER() macro in kmp_stats.h.
Definition: kmp_stats.h:71
static const int logEvent
statistic can be logged when KMP_STATS_EVENTS is on (valid only for timers)
Definition: kmp_stats.h:52