1 #ifndef TDICT_HPP_
2 #define TDICT_HPP_
3 
4 #include <map>
5 #include <string>
6 #include <sstream>
7 #include <pthread.h>
8 #include "timing.h"
9 #include <cstddef>   // for NULL
10 #include <utility>    // for pair
11 #include "macros.h"   // for ASSERT_ALWAYS, CADO_CONCATENATE3, MAYBE_UNUSED
12 struct cxx_param_list;
13 
14 /* Uncomment this flag if you believe that the fine-grain -T timings
15  * negatively impact the performance */
16 #define xxxDISABLE_TIMINGS
17 
18 namespace tdict {
19     struct timer_none {
20         typedef int type;
operator ()tdict::timer_none21         inline type operator()() const { return 0; }
22     };
23 }
24 #ifndef DISABLE_TIMINGS
25 
26 /* This header file defines objects for a "timing dictionary".
27  *
28  *  - We define "timing slots", which are the main thrust of the idea.
29  *  - Actual "timing dictionaries" are mainly std::map types using timing
30  *    slots as keys.
31  *  - We also define "timing dictionary sentries", which are convenience
32  *    objects meant to record time spent within a given scope.
33  *
34  * Timing slots are print-capable objects, which can be manipulated like
35  * plain integers, for speed. Each of these objects can be printed in a
36  * per-object defined manner. The actual plain integer is proxied via the
37  * tdict::key type, but that one really resolves to an integer.
38  *
39  * The translation from the timing slot object to an integer
40  * (tdict::key) is done at compile time.
41  *
42  * The reverse translation from tdict::key to strings is done by
43  * the standard output operators.
44  *
45  * Two types of tdict objects are defined by default.
46  *
47  * The class "tdict::basic" can be used for
48  * slots with only one given meaning. These get declared as:
49  *
50  * tdict::basic ORANGES("number of oranges");
51  * tdict::basic PEARS("number of pears");
52  * map<tdict::key, int> tab;      // a "timing dictionary"
53  * tab[ORANGES]++;
54  * tab[PEARS]++;
55  * tab[ORANGES]++;
56  * tab[ORANGES]++;
57  * for(auto const& a : tab) {
58  *        cout << a.first << ": " << a.second << endl;
59  * }
60  *
61  * The second class "tdict::slot_parametric" takes a paramter and one
62  * (or optionally two) strings at construction time. The printed version
63  * is [first string][parameter][second string].
64  *
65  * tdict::slot_parametric GRAPE("grape with ", " seeds");
66  *
67  * To actually convert that into a key, you need to provide the
68  * slot_parametric object with one argument, as in:
69  *
70  * tab[GRAPE(2)]++
71  *
72  * Behind the scenes, tdict::key actually encodes both the object
73  * unique identifier as well as a parameter in the integer key. As it is
74  * currently written (all in the tdict::key type), 16 bits are for
75  * the tdict object identifier, and 16 for the parameter.
76  *
77  * Lifetime of tdict objects is understood as being global.
78  * However, scope-limited is also ok. Upon destruction, the slot is kept
79  * in the global tdict registry (to guarantee global uniqueness),
80  * so use with extreme care. Also, having it scope-limited is not thread-safe.
81  */
82 namespace tdict {
83 
84     extern int global_enable;
85 
86     /* to print a key object (e.g. from gdb) use
87      * tdict::slot_base::print(k)
88      */
89     class key {
90         int magic;
91         friend class slot_base;
92         public:
dict_key() const93         int dict_key() const { return magic >> 16; }
parameter() const94         int parameter() const { return magic & 65535; }
encode(int arg) const95         key encode(int arg) const { key res(0); res.magic = magic + arg; return res;}
key(int a)96         key(int a) { magic = a << 16; }
97         friend bool operator<(key const& o1, key const& o2);
98     };
operator <(key const & o1,key const & o2)99     inline bool operator<(key const& o1, key const& o2) { return o1.magic < o2.magic; }
100     class slot_base {
101 
102         slot_base(slot_base const&) = delete;
103         public:
104         typedef std::map<key, const tdict::slot_base*> dict_t;
105         protected:
106         key k;
107         private:
get_dict(int x MAYBE_UNUSED=0)108         static dict_t& get_dict(int x MAYBE_UNUSED = 0) {
109             /* The code below leaks, I know. Unfortunately I can't stow
110              * the static member initialization in an other compilation
111              * unit, or SIOF will kill me. See also "Meyers Singleton".
112              *
113              * #else branch is an ad hoc hack which kinda works here.
114              * We destroy the singleton on the last tdict::slot_base
115              * destructor.  It's not ideal, since we really really must
116              * make sure the tdict::key objects never escape the
117              * scope of existence of the associated tdict::slot_base
118              * object themselves -- which is not guaranteed by the
119              * interface.
120              */
121 #if 1
122             static dict_t d;   /* trusty leaky */
123             return d;
124 #else
125             static dict_t * d;
126             static size_t nkeys;
127             if (x > 0) {
128                 if (nkeys++ == 0) {
129                     d = new dict_t();
130                 }
131             } else if (x < 0) {
132                 if (--nkeys == 0) {
133                     delete d;
134                     d = NULL;
135                 }
136             }
137             return d;
138 #endif
139         };
140         static pthread_mutex_t m;
lock()141         static void lock(){pthread_mutex_lock(&m);}
unlock()142         static void unlock(){pthread_mutex_unlock(&m);}
143         public:
144         // helgrind complains, here. I think that helgrind is wrong.
145         // key base_key() const { lock(); key ret = k; unlock(); return ret; }
base_key() const146         key const & base_key() const { return k; }
slot_base()147         slot_base() : k(0) {
148             lock();
149             dict_t& dict(get_dict(1));
150             k = key(dict.size());
151             dict[k.dict_key()] = this;
152             unlock();
153         }
~slot_base()154         ~slot_base() {
155             lock();
156             dict_t& dict(get_dict());
157             dict[k] = NULL;
158             get_dict(-1);
159             unlock();
160         }
161         public:
print(key x)162         static std::string print(key x) {
163             lock();
164             dict_t& dict(get_dict());
165             dict_t::const_iterator it = dict.find(x.dict_key());
166             if (it == dict.end()) {
167                 unlock();
168                 throw "Bad magic";
169             }
170             const tdict::slot_base * b = it->second;
171             if (b == NULL) {
172                 unlock();
173                 return "FIXME: deleted timer";
174             }
175             unlock();
176             return b->_print(x.parameter());
177         }
178         virtual std::string _print(int) const = 0;
179     };
operator <<(std::ostream & o,key const & k)180     inline std::ostream& operator<<(std::ostream& o, key const& k) {
181         return o << slot_base::print(k);
182     }
183 
184     class slot : public slot_base {
185         std::string text;
186         public:
slot(std::string const & s)187         slot(std::string const& s) : text(s) {}
_print(int) const188         virtual std::string _print(int) const { return text; }
operator key() const189         operator key() const { return base_key(); }
190     };
191 
192     class slot_parametric : public slot_base {
193         std::string s,t;
194         public:
slot_parametric(std::string const & s)195         slot_parametric(std::string const& s) : s(s) { }
slot_parametric(std::string const & s,std::string const & t)196         slot_parametric(std::string const& s, std::string const& t) : s(s), t(t) { }
operator ()(int p) const197         key operator()(int p) const {
198             return base_key().encode(p);
199         }
_print(int p) const200         virtual std::string _print(int p) const {
201             std::ostringstream ss;
202             ss << s << p << t;
203             return ss.str();
204         }
205     };
206 
207     struct timer_seconds_thread {
208         typedef double type;
operator ()tdict::timer_seconds_thread209         type operator()() const {
210             if (tdict::global_enable)
211                 return seconds_thread();
212             else
213                 return 0;
214         }
215     };
216     struct timer_seconds_thread_and_wct {
217         struct type {
218             double t = 0;
219             double w = 0;
220             type(type const&) = default;
221             type(type&&) = default;
222             type() = default;
typetdict::timer_seconds_thread_and_wct::type223             type(int) : t(0), w(0) {}
typetdict::timer_seconds_thread_and_wct::type224             type(double t, double w) : t(t), w(w) {}
operator -=tdict::timer_seconds_thread_and_wct::type225             type& operator-=(type const & o) {
226                 t-=o.t;
227                 w-=o.w;
228                 return *this;
229             }
operator +=tdict::timer_seconds_thread_and_wct::type230             type& operator+=(type const & o) {
231                 t+=o.t;
232                 w+=o.w;
233                 return *this;
234             }
operator >tdict::timer_seconds_thread_and_wct::type235             bool operator>(double const& c) const {
236                 return w > c;
237             }
238         };
operator ()tdict::timer_seconds_thread_and_wct239         type operator()() const {
240             if (tdict::global_enable)
241                 return type(seconds_thread(), wct_seconds());
242             else
243                 return type();
244         }
245     };
246 #ifdef  HAVE_GCC_STYLE_AMD64_INLINE_ASM
247     struct timer_ticks {
248         typedef uint64_t type;
operator ()tdict::timer_ticks249         type operator()() const {
250             if (tdict::global_enable)
251                 return cputicks();
252             else
253                 return 0;
254         }
255     };
256 #endif
257 
258     std::ostream& operator<<(std::ostream & o, timer_seconds_thread_and_wct::type const & a);
259 
260     /*
261     template<typename T>
262         class sentry {
263             std::map<key, timer_data_type> & m;
264             key k;
265             public:
266             sentry(std::map<key, timer_data_type> & m, key const& k) : k(k), m(m) {
267                 m[k] -= T()();
268             }
269             ~sentry() {
270                 m[k] += T()();
271             }
272         };
273         */
274 
275     template<typename T>
276     struct tree {
277         typedef T timer_type;
278         typedef typename T::type timer_data_type;
279         timer_data_type self;
280         bool scoping;
281         int category;
282         typedef std::map<tdict::key, tree<T> > M_t;
283         M_t M;
284         tree<T> * current;   /* could be NULL */
285         tree<T> * parent;   /* could be NULL */
treetdict::tree286         tree() : self(timer_data_type()), scoping(true), category(-1), current(NULL), parent(this) { }
runningtdict::tree287         bool running() const { return current != NULL; }
stoptdict::tree288         void stop() {
289             if (!running()) return;
290             timer_data_type v = T()();
291             current->self += v;
292             current = NULL;
293             return;
294         }
starttdict::tree295         void start() {
296             if (running()) return;
297             timer_data_type v = T()();
298             self -= v;
299             current = this;
300         }
add_foreign_timetdict::tree301         void add_foreign_time(timer_data_type const & t) {
302             self += t;
303         }
set_current_categorytdict::tree304         void set_current_category(int c) {
305             ASSERT_ALWAYS(running());
306             /* We used to forbid setting a category for the root of the
307              * tree. However, this looks like an artificial restriction.
308              * ASSERT_ALWAYS(current != this);
309              */
310             current->category = c;
311         }
312 
313 
stop_and_starttdict::tree314         timer_data_type stop_and_start() {
315             ASSERT_ALWAYS(running());
316             timer_data_type v = T()();
317             timer_data_type res = current->self + v;
318             current->self = -v;
319             return res;
320         }
321         struct accounting_base {
322             tree& t;
accounting_basetdict::tree::accounting_base323             inline accounting_base(tree& t): t(t) {}
~accounting_basetdict::tree::accounting_base324             inline ~accounting_base() {}
325         };
326         /* This one is useful so that ctor/dtor order works right.
327         */
328         struct accounting_activate : public accounting_base {
accounting_activatetdict::tree::accounting_activate329             inline accounting_activate(tree& t): accounting_base(t) { accounting_base::t.start(); }
~accounting_activatetdict::tree::accounting_activate330             inline ~accounting_activate() { accounting_base::t.stop(); }
331         };
332         struct accounting_activate_recursive : public accounting_base {
333             bool act = false;
accounting_activate_recursivetdict::tree::accounting_activate_recursive334             inline accounting_activate_recursive(tree& t): accounting_base(t), act(!t.running()) { if (act) accounting_base::t.start(); }
~accounting_activate_recursivetdict::tree::accounting_activate_recursive335             inline ~accounting_activate_recursive() { if (act) accounting_base::t.stop(); }
336         };
337         template<typename BB>
338             struct accounting_child_meta : public BB {
accounting_child_metatdict::tree::accounting_child_meta339                 accounting_child_meta(tree& t, tdict::key k): BB(t) {
340                     ASSERT_ALWAYS(BB::t.running());
341                     timer_data_type v = T()();
342                     BB::t.current->self += v;
343                     tree<T> * kid = &(BB::t.current->M[k]);  /* auto-vivifies */
344                     kid->parent = BB::t.current;
345                     kid->self -=  v;
346                     kid->scoping = true;
347                     BB::t.current = kid;
348                 }
~accounting_child_metatdict::tree::accounting_child_meta349                 ~accounting_child_meta() {
350                     timer_data_type v = T()();
351                     BB::t.current->self += v;
352                     /* It could be that we are one level below. */
353                     for(;!BB::t.current->scoping;) {
354                         BB::t.current = BB::t.current->parent;
355                     }
356                     BB::t.current = BB::t.current->parent;
357                     BB::t.current->self -= v;
358                 }
359             };
360         typedef accounting_child_meta<accounting_base> accounting_child;
361         typedef accounting_child_meta<accounting_activate> accounting_child_autoactivate;
362         typedef accounting_child_meta<accounting_activate_recursive> accounting_child_autoactivate_recursive;
363 
364         struct accounting_debug : public accounting_base {
365             std::ostream& o;
accounting_debugtdict::tree::accounting_debug366             inline accounting_debug(tree& t, std::ostream&o): accounting_base(t), o(o) {}
~accounting_debugtdict::tree::accounting_debug367             inline ~accounting_debug() {
368                 o << "# debug print\n";
369                 o << accounting_base::t.display();
370                 o << "# --\n";
371             }
372         };
373         /* We make this an object for consistency with the child case, but
374          * really we don't have to */
375         struct accounting_sibling {
accounting_siblingtdict::tree::accounting_sibling376             accounting_sibling(tree& t, tdict::key k) {
377                 ASSERT_ALWAYS(t.running());
378                 timer_data_type v = T()();
379                 tree<T> * kid;
380                 if (t.current->scoping) {
381                     kid = &(t.current->M[k]);  /* auto-vivifies */
382                     kid->parent = t.current;
383                 } else {
384                     kid = &(t.current->parent->M[k]);  /* auto-vivifies */
385                     kid->parent = t.current->parent;
386                 }
387                 t.current->self += v;
388                 kid->scoping = false;
389                 kid->self -=  v;
390                 t.current = kid;
391             }
392         };
393         /* mostly the same as the previous, except that we return to
394          * the main "bookkeeping" timer attached to this level of the
395          * tree.
396          */
397         struct accounting_bookkeeping {
accounting_bookkeepingtdict::tree::accounting_bookkeeping398             accounting_bookkeeping(tree& t) {
399                 ASSERT_ALWAYS(t.running());
400                 timer_data_type v = T()();
401                 if (!t.current->scoping) {
402                     t.current->self += v;
403                     t.current = t.current->parent;
404                     t.current->self -= v;
405                 }
406             }
407         };
408 
409         private:
_displaytdict::tree410         std::ostream& _display(std::ostream& o, std::string const& prefix) const {
411             // o << prefix << self << " (self)\n";
412             std::ostringstream ss;
413             ss << prefix << " ";
414             for(auto const & a : M) {
415                 o << prefix << a.second.self << " " << a.first;
416 #define DEBUG_CATEGORY
417 #ifdef DEBUG_CATEGORY
418                 if (a.second.category >= 0)
419                     o << " ; category " << a.second.category;
420 #endif
421                 o << "\n";
422                 a.second._display(o, ss.str());
423             }
424             return o;
425         }
426 
filter_by_categorytdict::tree427         void filter_by_category(std::map<int, timer_data_type> & D, int inherited) const {
428             int flag = inherited;
429             if (category >= 0)
430                 flag = category;
431             D[flag] += self;
432             for(auto const & a : M) {
433                 a.second.filter_by_category(D, flag);
434             }
435         }
436 
437         public:
filter_by_categorytdict::tree438         std::map<int, timer_data_type> filter_by_category() const {
439             std::map<int, timer_data_type> res;
440             filter_by_category(res, -1);
441             return res;
442         }
total_counted_timetdict::tree443         double total_counted_time() const {
444             double t = self;
445             for(auto const & a : M)
446                 t += a.second.total_counted_time();
447             return t;
448         }
displaytdict::tree449         std::string display(double bookkeeping_cutoff = 1e-5) const {
450             ASSERT_ALWAYS(!running());
451             std::ostringstream ss;
452             if (self > bookkeeping_cutoff)
453                 ss << "# " << self << " (bookkeeping)\n";
454             _display(ss, "# ");
455             return ss.str();
456         }
operator +=tdict::tree457         tree& operator+=(tree const& t) {
458             self += t.self;
459             ASSERT_ALWAYS(category < 0 || t.category < 0 || category == t.category);
460             if (t.category >= 0)
461                 category = t.category;
462             for(typename M_t::const_iterator a = t.M.begin() ; a != t.M.end() ; a++) {
463                 M[a->first] += a->second;
464             }
465             return *this;
466         }
steal_children_timingstdict::tree467         tree& steal_children_timings(tree & t) {
468             ASSERT_ALWAYS(t.running());
469             ASSERT_ALWAYS(t.current = &t);
470             ASSERT_ALWAYS(t.category < 0);
471             for(typename M_t::iterator a = t.M.begin() ; a != t.M.end() ; a++) {
472                 M[a->first] += a->second;
473             }
474             t.M.clear();
475             return *this;
476         }
477     };
478 
479     /* This is used to that timings obtained from a quick, and
480      * rather inaccurate timer u can be scaled to participate in
481      * the counts in the timer t.
482      * The timer t must be running, because the time captured
483      * while u is running will be used as a base. All timer counts that
484      * appear in u will be scaled to that base, according to the
485      * proportion of the timer counts that they represent in u.
486      * (tying an all-zero timer u is a no-op).
487      */
488     template<typename T, typename U> struct tie_timer : public tree<U> {
489         typename tree<T>::accounting_child t_sentry;
490         typename T::type t0;
tie_timertdict::tie_timer491         tie_timer(tree<T>& t, tdict::key k) : t_sentry(t, k), t0(T()())
492         {
493             ASSERT_ALWAYS(t.running());
494             tree<U>::start();
495         }
sum_utdict::tie_timer496         static typename U::type sum_u(tree<U> const& u) {
497             typename U::type s = u.self;
498             for(auto const & a : u.M)
499                 s += sum_u(a.second);
500             return s;
501         }
502 
~tie_timertdict::tie_timer503         ~tie_timer() {
504             /* For consistency (at least given the current way we
505              * expect the code to work), we have a scoping object
506              * on timer t. The dtor of this scoping object will
507              * add to t's current count.
508              * What we have to do is to reconstruct the timings
509              * for the objects that would have existed under t if
510              * we had used the same timer consistently. Our first
511              * task is thus to determine the scale, which means
512              * that we'll make a measurement _just for that
513              * purpose_.
514              */
515             tree<T>& t = t_sentry.t;
516             ASSERT_ALWAYS_NOTHROW(t.running());
517             ASSERT_ALWAYS_NOTHROW(tree<U>::running());
518             tree<U>::stop();
519             typename U::type scale_u = sum_u(*this);
520             if (scale_u == 0) return;
521             /* compute the scale, and leave essentially zero time
522              * to count on the t object */
523             typename T::type scale_t = T()() - t0;
524             ASSERT_ALWAYS_NOTHROW(t.running());
525             merge_scaled(*t.current, *this, scale_t, scale_u);
526             t.self -= scale_t;
527             /* well, really, this one is quite pedantic */
528         }
merge_scaledtdict::tie_timer529         static void merge_scaled(tree<T>& t, tree<U> const& u, typename T::type scale_t, typename U::type scale_u)
530         {
531             t.self += u.self * scale_t / scale_u;
532             for(auto const & a : u.M)
533                 merge_scaled(t.M[a.first], a.second, scale_t, scale_u);
534         }
535     };
536 
537     void declare_usage(cxx_param_list & pl);
538     void configure_switches(cxx_param_list & pl);
539     void configure_aliases(cxx_param_list & pl);
540 };
541 
542 // timer_seconds_thread_and_wct is not satisfactory.
543 // typedef tdict::tree<tdict::timer_seconds_thread_and_wct> timetree_t;
544 typedef tdict::tree<tdict::timer_seconds_thread> timetree_t;
545 
546 /* The fast_timetree_t promises to make no system call whatsoever, and to
547  * do what it can to get _some_ sense of a timing value, with no pretense
548  * of being accurate.
549  */
550 #ifdef  HAVE_GCC_STYLE_AMD64_INLINE_ASM
551 typedef tdict::tree<tdict::timer_ticks> fast_timetree_t;
552 #else
553 typedef tdict::tree<tdict::timer_none> fast_timetree_t;
554 #endif
555 
556 extern template class std::map<tdict::key, tdict::slot_base const *>;
557 
558 extern template struct tdict::tree<tdict::timer_seconds_thread>;
559 extern template class std::map<tdict::key, tdict::tree<tdict::timer_seconds_thread> >;
560 // extern template struct std::pair<tdict::key const, tdict::slot_base const *>;
561 extern template struct tdict::tree<tdict::timer_seconds_thread>::accounting_child_meta<tdict::tree<tdict::timer_seconds_thread>::accounting_base>;
562 
563 #ifdef  HAVE_GCC_STYLE_AMD64_INLINE_ASM
564 extern template struct tdict::tree<tdict::timer_ticks>;
565 extern template class std::map<tdict::key, tdict::tree<tdict::timer_ticks> >;
566 extern template struct tdict::tree<tdict::timer_ticks>::accounting_child_meta<tdict::tree<tdict::timer_ticks>::accounting_base>;
567 #else
568 extern template struct tdict::tree<tdict::timer_none>;
569 extern template class std::map<tdict::key, tdict::tree<tdict::timer_none> >;
570 extern template struct tdict::tree<tdict::timer_none>::accounting_child_meta<tdict::tree<tdict::timer_none>::accounting_base>;
571 #endif
572 
573 #if 0
574 
575 // an example. In fact this one is already covered by tdict::parametric
576 
577 /* This is an anonymous class, intentionally. We have no use for the
578  * class name. The object is the whole story. The object registers with
579  * the global tdict layer, and gets a unique key. Eventually, how
580  * the object reacts to operator() to encode its arguments in its 16-bit
581  * value space is really what we're interested in.
582  */
583 
584 class : public tdict::slot_base {
585     public:
586         tdict::key operator()(int p) const { return k.encode(p); }
587         virtual std::string _print(int p) const {
588             std::ostringstream ss;
589             ss << "inner loop with " << p << " legs";
590             return ss.str();
591         }
592 } TT_INNER_LOOP;
593 #endif
594 
595 #define UNIQUE_ID(t) CADO_CONCATENATE3(uid_,t,__LINE__)
596 
597 /* Note that in most cases we *can't* play do-while(0) here, because that
598  * would scope the timer object, which is precisely what we want to
599  * avoid. In cases where the dtor is trivial, we can, since it makes no
600  * difference.
601  */
602 #if 0
603 #define TIMER_DEBUG_MESSAGE_(T) do {					\
604         fprintf(stderr, "@ %s:%d\n", __func__, __LINE__);		\
605     } while (0)
606 #else
607 #define TIMER_DEBUG_MESSAGE_(T) /* */
608 #endif
609 #define TIMER_TYPE_(T)   std::remove_reference<decltype(T)>::type
610 #define CHILD_TIMER(T, name)                                            \
611     TIMER_DEBUG_MESSAGE_(T);                                         	\
612     static tdict::slot UNIQUE_ID(slot)(name);		                \
613     typename TIMER_TYPE_(T)::accounting_child UNIQUE_ID(sentry)(T,UNIQUE_ID(slot))
614 #define CHILD_TIMER_PARAMETRIC(T, name, arg, suffix)                    \
615     TIMER_DEBUG_MESSAGE_(T);                                         	\
616     static tdict::slot_parametric UNIQUE_ID(slot)(name, suffix);    	\
617     typename TIMER_TYPE_(T)::accounting_child UNIQUE_ID(sentry)(T,UNIQUE_ID(slot)(arg))
618 #define SIBLING_TIMER(T, name) do {					\
619         TIMER_DEBUG_MESSAGE_(T);					\
620         static tdict::slot x(name);					\
621         typename TIMER_TYPE_(T)::accounting_sibling UNIQUE_ID(sentry) (T,x);	\
622     } while (0)
623 #define SIBLING_TIMER_PARAMETRIC(T, name, arg, suffix) do {		\
624         TIMER_DEBUG_MESSAGE_(T);					\
625         static tdict::slot_parametric x(name, suffix);			\
626         typename TIMER_TYPE_(T)::accounting_sibling UNIQUE_ID(sentry) (T,x(arg));\
627     } while (0)
628 #define BOOKKEEPING_TIMER(T)						\
629     TIMER_DEBUG_MESSAGE_(T);						\
630     typename TIMER_TYPE_(T)::accounting_bookkeeping UNIQUE_ID(sentry) (T);
631 #define ACTIVATE_TIMER(T)						\
632     TIMER_DEBUG_MESSAGE_(T);						\
633     typename TIMER_TYPE_(T)::accounting_activate UNIQUE_ID(sentry) (T);
634 #define ACTIVATE_TIMER_IF_NOT_RUNNING(T)				\
635     TIMER_DEBUG_MESSAGE_(T);						\
636     typename TIMER_TYPE_(T)::accounting_activate_recursive UNIQUE_ID(sentry) (T);
637 #define DEBUG_DISPLAY_TIMER_AT_DTOR(T,o)				\
638     TIMER_DEBUG_MESSAGE_(T);						\
639     typename TIMER_TYPE_(T)::accounting_debug UNIQUE_ID(sentry) (T, o);
640 #define CHILD_TIMER_FUZZY(T, U, name)                \
641     static tdict::slot UNIQUE_ID(slot)(name);		                \
642     tdict::tie_timer<typename TIMER_TYPE_(T)::timer_type, fast_timetree_t::timer_type> U(T, UNIQUE_ID(slot))
643 
644 
645 typedef tdict::tie_timer<timetree_t::timer_type, fast_timetree_t::timer_type> fuzzy_diverted_timetree_t;
646 
647 #else /* DISABLE_TIMINGS */
648 
649 struct timetree_t {
650     typedef double timer_data_type;
651     typedef tdict::timer_none timer_type;
filter_by_categorytimetree_t652     std::map<int, double> filter_by_category() const {
653         /* always an empty map */
654         return std::map<int, double>();
655     }
filter_by_categorytimetree_t656     void filter_by_category(std::map<int, double> &, int) const { }
operator +=timetree_t657     timetree_t& operator+=(timetree_t const&) { return *this; }
total_counted_timetimetree_t658     double total_counted_time() const { return 0; }
displaytimetree_t659     std::string display() const { return std::string(); }
660     /* what should we do */
runningtimetree_t661     bool running() const { return false; }
noptimetree_t662     inline void nop() const {}
starttimetree_t663     inline void start() const {}
stoptimetree_t664     inline void stop() const {}
add_foreign_timetimetree_t665     void add_foreign_time(timer_data_type const &) const {}
666 };
667 
668 typedef timetree_t fast_timetree_t;
669 
670 namespace tdict {
671     struct tie_timer : public timetree_t {
672         tie_timer() = default;
673     };
674 };
675 typedef tdict::tie_timer fuzzy_diverted_timetree_t;
676 
677 namespace tdict {
678     extern int global_enable;
679     void declare_usage(cxx_param_list & pl);
680     void configure_switches(cxx_param_list & pl);
681     void configure_aliases(cxx_param_list & pl);
682 };
683 
684 #define CHILD_TIMER(T, name) T.nop()
685 #define CHILD_TIMER_PARAMETRIC(T, name, arg, suffix) T.nop()
686 #define SIBLING_TIMER(T, name) T.nop()
687 #define SIBLING_TIMER_PARAMETRIC(T, name, arg, suffix) T.nop()
688 #define BOOKKEEPING_TIMER(T) T.nop()
689 #define ACTIVATE_TIMER(T) T.nop()
690 #define DEBUG_DISPLAY_TIMER_AT_DTOR(T,o) T.nop()
691 
692 #endif
693 
694 #endif	/* TDICT_HPP_ */
695