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