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