timemory  3.2.1
Modular C++ Toolkit for Performance Analysis and Logging. Profiling API and Tools for C, C++, CUDA, Fortran, and Python. The C++ template API is essentially a framework to creating tools: it is designed to provide a unifying interface for recording various performance measurements alongside data logging and interfaces to other tools.
bundle.hpp
Go to the documentation of this file.
1 // MIT License
2 //
3 // Copyright (c) 2020, The Regents of the University of California,
4 // through Lawrence Berkeley National Laboratory (subject to receipt of any
5 // required approvals from the U.S. Dept. of Energy). All rights reserved.
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // SOFTWARE.
24 //
25 
26 #pragma once
27 
29 #include "timemory/mpl/apply.hpp"
30 #include "timemory/mpl/filters.hpp"
36 
37 #include <cstdint>
38 #include <cstdio>
39 #include <fstream>
40 #include <functional>
41 #include <iomanip>
42 #include <ios>
43 #include <iostream>
44 #include <string>
45 
46 namespace tim
47 {
48 /// \class tim::bundle
49 /// \brief Static polymorphic base class for component bundlers
50 template <typename...>
51 class bundle;
52 //
53 /// \class tim::bundle< Tag, BundleT, TupleT >
54 /// \tparam Tag API tag type, e.g. `TIMEMORY_API`
55 /// \tparam BundleT The empty or empty + tag derived type.
56 /// \tparam TupleT The set of components wrapped in a type which provides the appropriate
57 /// aliases.
58 ///
59 /// \brief Example:
60 /// `bundle<Tag, component_bundle<Foo>, mixed_wrapper_types<concat<Bar, Baz>>>` will
61 /// use `Tag` + `trait::is_available<Tag>` or `trait::runtime_available<Tag>` to disable
62 /// this bundle at compile-time or run-time, respectively. It will covert
63 /// `component_bundle<Foo>` to `component_bundle<Foo, Bar, Baz>` for purposes of function
64 /// signatures and it will instantiate `std::tuple<...>` depending on the compile-time
65 /// availability of `Bar` and `Baz`. `mixed_wrapper_types` is a dummy type with the
66 /// appropriate aliases to perform these conversions. Here is a theoretical implementation
67 /// of `mixed_wrapper_types` (which supports allocating components on the stack and the
68 /// heap):
69 ///
70 /// \code{.cpp}
71 /// template <typename... T>
72 /// struct heap_wrapper_types
73 /// {
74 /// TIMEMORY_DELETED_OBJECT(heap_wrapper_types)
75 ///
76 /// /// the set of types, unaltered, in a type_list
77 /// using type_list_type = type_list<T...>;
78 ///
79 /// /// the set of types without any pointers
80 /// using reference_type = type_list<std::remove_pointer_t<T>...>;
81 ///
82 /// /// type list of the available types
83 /// using available_type = type_list_t<reference_type>;
84 ///
85 /// /// the original bundle type
86 /// template <typename BundleT>
87 /// using this_type = convert_t<type_list<T...>, BundleT>;
88 ///
89 /// /// the type after available_t<concat<...>>
90 /// template <typename BundleT>
91 /// using type = convert_t<available_type, BundleT>;
92 ///
93 /// /// conversion to equivalent wrapper requiring explicit start/stop
94 /// template <typename BundleT>
95 /// using component_type = convert_t<type_list<T...>, BundleT>;
96 ///
97 /// /// conversion to equivalent wrapper which automatically starts/stops
98 /// template <typename BundleT>
99 /// using auto_type = concepts::auto_type_t<convert_t<type_list_type, BundleT>>;
100 ///
101 /// /// the valid types to instantiate in a tuple
102 /// template <typename ApiT = TIMEMORY_API>
103 /// using data_type = conditional_t<
104 /// trait::is_available<ApiT>::value,
105 /// convert_t<add_pointer_if_not_t<non_placeholder_t<non_quirk_t<type_list_t<T...>>>>,
106 /// std::tuple<>>,
107 /// std::tuple<>>;
108 /// };
109 /// \endcode
110 template <typename Tag, typename BundleT, typename TupleT>
113 {
114  template <typename U>
115  using remove_pointer_decay_t = std::remove_pointer_t<decay_t<U>>;
116 
117  template <typename... Tp>
118  friend class impl::base_bundle;
119 
120  template <typename... Tp>
121  friend class auto_base_bundle;
122 
123  template <typename... Tp>
124  friend class auto_bundle;
125 
126  template <typename... Tp>
127  friend class auto_tuple;
128 
129  template <typename... Tp>
130  friend class auto_list;
131 
132 #if defined(TIMEMORY_USE_DEPRECATED)
133  template <typename TupleC, typename ListC>
134  friend class component_hybrid;
135 
136  template <typename TupleC, typename ListC>
137  friend class auto_hybrid;
138 #endif
139 
140  using internal_tag = tim::variadic::impl::internal_tag;
141 
142 protected:
145  using string_t = typename bundle_type::string_t;
146  using reference_type = typename TupleT::reference_type;
147 
148 public:
150  using this_type = typename TupleT::template this_type<BundleT>;
151  using type = typename TupleT::template type<BundleT>;
152  using component_type = typename TupleT::template component_type<BundleT>;
153  using data_type = typename TupleT::template data_type<Tag>;
154  using type_list_type = typename TupleT::type_list_type;
156  using size_type = typename bundle_type::size_type;
157  using initializer_type = std::function<void(this_type&)>;
159 
160 public:
161  static initializer_type& get_initializer();
162 
163  template <typename T, typename... U>
164  using quirk_config = tim::variadic::impl::quirk_config<T, reference_type, U...>;
165 
166  /// Query whether type matches this_type
167  template <typename U>
168  static constexpr bool is_this_type()
169  {
170  return std::is_same<decay_t<U>, this_type>::value;
171  }
172 
173 public:
174  bundle();
175 
176  template <typename... T>
177  explicit bundle(const string_t& _key, quirk::config<T...>,
178  transient_func_t = get_initializer());
179 
180  template <typename... T>
181  explicit bundle(hash_value_t _hash, quirk::config<T...>,
182  transient_func_t = get_initializer());
183 
184  template <typename... T>
185  explicit bundle(const captured_location_t& _loc, quirk::config<T...>,
186  transient_func_t = get_initializer());
187 
188  template <typename... T>
189  explicit bundle(const string_t& _key, bool _store, quirk::config<T...>,
190  transient_func_t = get_initializer());
191 
192  template <typename... T>
193  explicit bundle(const captured_location_t& _loc, bool _store, quirk::config<T...>,
194  transient_func_t = get_initializer());
195 
196  explicit bundle(hash_value_t _hash, bool _store = true,
197  scope::config _scope = scope::get_default(),
198  transient_func_t = get_initializer());
199 
200  explicit bundle(const string_t& _key, bool _store = true,
201  scope::config _scope = scope::get_default(),
202  transient_func_t = get_initializer());
203 
204  explicit bundle(const captured_location_t& _loc, bool _store = true,
205  scope::config _scope = scope::get_default(),
206  transient_func_t = get_initializer());
207 
208  explicit bundle(hash_value_t _hash, scope::config _scope,
209  transient_func_t = get_initializer());
210 
211  explicit bundle(const string_t& _key, scope::config _scope,
212  transient_func_t = get_initializer());
213 
214  explicit bundle(const captured_location_t& _loc, scope::config _scope,
215  transient_func_t = get_initializer());
216 
217  ~bundle();
218  bundle(const bundle& rhs);
219  bundle(bundle&&) noexcept = default;
220 
221  // this_type operators
222  bundle& operator=(const bundle& rhs);
223  bundle& operator=(bundle&&) noexcept = default;
224 
225  this_type& operator-=(const this_type& rhs);
226  this_type& operator+=(const this_type& rhs);
227 
228  // generic operators
229  template <typename Op, enable_if_t<!is_this_type<Op>()> = 0>
230  this_type& operator-=(Op&& rhs)
231  {
232  invoke::invoke<operation::minus, Tag>(m_data, std::forward<Op>(rhs));
233  return get_this_type();
234  }
235 
236  template <typename Op, enable_if_t<!is_this_type<Op>()> = 0>
238  {
239  invoke::invoke<operation::plus, Tag>(m_data, std::forward<Op>(rhs));
240  return get_this_type();
241  }
242 
243  template <typename Op, enable_if_t<!is_this_type<Op>()> = 0>
245  {
246  invoke::invoke<operation::multiply, Tag>(m_data, std::forward<Op>(rhs));
247  return get_this_type();
248  }
249 
250  template <typename Op, enable_if_t<!is_this_type<Op>()> = 0>
252  {
253  invoke::invoke<operation::divide, Tag>(m_data, std::forward<Op>(rhs));
254  return get_this_type();
255  }
256 
257  // friend operators
258  friend this_type operator+(const this_type& lhs, const this_type& rhs)
259  {
260  return this_type{ lhs } += rhs;
261  }
262 
263  friend this_type operator-(const this_type& lhs, const this_type& rhs)
264  {
265  return this_type{ lhs } -= rhs;
266  }
267 
268  template <typename Op>
269  friend this_type operator*(const this_type& lhs, Op&& rhs)
270  {
271  return this_type{ lhs } *= std::forward<Op>(rhs);
272  }
273 
274  template <typename Op>
275  friend this_type operator/(const this_type& lhs, Op&& rhs)
276  {
277  return this_type{ lhs } /= std::forward<Op>(rhs);
278  }
279 
280  friend std::ostream& operator<<(std::ostream& os, const bundle& obj)
281  {
282  obj.print<true, true>(os);
283  return os;
284  }
285 
286  bundle clone(bool store, scope::config _scope = scope::get_default());
287 
288 public:
289  /// Query at compile-time whether a user_bundle exists in the set of components.
290  /// user_bundle are more restricted versions of component bundlers but allow
291  /// runtime insertion of components.
292  static constexpr bool has_user_bundle() { return bundle_type::has_user_bundle_v; }
293 
294  /// Query at compile-time whether initialization can occur on the stack
295  template <typename U>
296  static constexpr bool can_stack_init()
297  {
298  using T = remove_pointer_decay_t<U>;
300  }
301 
302  /// Query at compile-time whether initialization can occur on the heap
303  template <typename U>
304  static constexpr bool can_heap_init()
305  {
306  using T = remove_pointer_decay_t<U>;
308  }
309 
310  /// Query at compile-time whether initialization can occur via a placement new.
311  /// Placement new init allows for the combination of optional initialization without
312  /// a heap allocation. Not currently available.
313  template <typename U>
314  static constexpr bool can_placement_init()
315  {
316  return false;
317  }
318 
319  /// Query at compile-time whether the specified type can be initialized
320  template <typename U>
321  static constexpr bool can_init()
322  {
323  using T = remove_pointer_decay_t<U>;
324  return can_stack_init<T>() || can_heap_init<T>() || can_placement_init<T>() ||
325  (trait::is_available<T>::value && has_user_bundle());
326  }
327 
328  /// Query at compile-time whether initialization will occur on the heap.
329  /// `can_heap_init<T>() && !will_heap_init<T>()` will indicate that a
330  /// stack-allocated instance of the same type exists.
331  template <typename U>
332  static constexpr bool will_heap_init()
333  {
334  using T = remove_pointer_decay_t<U>;
335  return can_init<T>() && !can_stack_init<T>();
336  }
337 
338  /// Query at compile-time whether initialization will happen with an opaque wrapper
339  /// (i.e. via user bundle). In this situation, initialization arguments are ignored
340  /// and the component will only be initialized with the \ref tim::scope::config of the
341  /// bundle.
342  template <typename U>
343  static constexpr bool will_opaque_init()
344  {
345  using T = remove_pointer_decay_t<U>;
346  return !can_stack_init<T>() && !can_heap_init<T>() &&
347  (trait::is_available<T>::value && has_user_bundle());
348  }
349 
350  /// Query at compile-time whether type can be constructed with the given argument
351  /// types. if type is not available, then it probably won't be defined, so this
352  /// places the `trait::is_available<T>` check in the template parameters and the
353  /// `std::is_constructible<T, ...>` in the body to avoid undefined behavior
354  template <typename U, typename... Args, typename T = remove_pointer_decay_t<U>,
356  static constexpr bool is_constructible()
357  {
358  return std::is_constructible<T, Args...>::value;
359  }
360 
361  /// Return false if the type is not available
362  template <typename U, typename... Args, typename T = remove_pointer_decay_t<U>,
364  static constexpr bool is_constructible()
365  {
366  return false;
367  }
368 
369  /// Query at compile-time whether type supports default construction. If type is not
370  /// available, then it probably won't be defined, so this places the
371  /// `trait::is_available<T>` check in the template parameters and the
372  /// `std::is_constructible<T, ...>` in the body to avoid undefined behavior
373  template <typename U, typename T = remove_pointer_decay_t<U>,
374  enable_if_t<trait::is_available<T>::value> = 0>
375  static constexpr bool is_default_constructible()
376  {
377  return std::is_default_constructible<T>::value;
378  }
379 
380  /// Return false if the type is not available
381  template <typename U, typename T = remove_pointer_decay_t<U>,
382  enable_if_t<!trait::is_available<T>::value> = 0>
383  static constexpr bool is_default_constructible()
384  {
385  return false;
386  }
387 
388 public:
389  /// requests the component initialize their storage
390  static void init_storage();
391 
392  /// tells each component to push itself into the call-stack hierarchy
393  this_type& push();
394 
395  /// tells each component to pop itself off of the call-stack hierarchy
396  this_type& pop();
397 
398  /// selective push
399  template <typename... Tp>
401 
402  /// selective push with scope configuration
403  template <typename... Tp>
405 
406  /// selective pop
407  template <typename... Tp>
409 
410  /// requests each component record a measurment
411  template <typename... Args>
412  this_type& measure(Args&&...);
413 
414  /// requests each component take a sample (if supported)
415  template <typename... Args>
416  this_type& sample(Args&&...);
417 
418  /// invokes start on all the components
419  template <typename... Args>
420  this_type& start(Args&&...);
421 
422  /// invokes stop on all the components
423  template <typename... Args>
424  this_type& stop(Args&&...);
425 
426  /// requests each component perform a measurement
427  template <typename... Args>
428  this_type& record(Args&&...);
429 
430  /// invokes reset member function on all the components
431  template <typename... Args>
432  this_type& reset(Args&&...);
433 
434  /// variant of start() which excludes push()
435  template <typename... Args>
437 
438  /// variant of stop() which excludes pop()
439  template <typename... Args>
441 
442  /// variant of start() which only gets applied to Tp types
443  template <typename... Tp, typename... Args>
445 
446  /// variant of stop() which only gets applied to Tp types
447  template <typename... Tp, typename... Args>
449 
450  using bundle_type::get_prefix;
451  using bundle_type::get_scope;
452  using bundle_type::get_store;
453  using bundle_type::hash;
454  using bundle_type::key;
455  using bundle_type::laps;
456  using bundle_type::prefix;
457  using bundle_type::size;
458  using bundle_type::store;
459 
460  /// query the number of (compile-time) fixed components
461  static constexpr uint64_t fixed_count();
462 
463  /// query the number of (run-time) optional components
464  static constexpr uint64_t optional_count();
465 
466  /// number of objects that will be performing measurements
467  uint64_t count();
468 
469  /// when chaining together operations, this function enables executing a function
470  /// inside the chain
471  template <typename FuncT, typename... Args>
472  decltype(auto) execute(FuncT&& func, Args&&... args);
473 
474  /// construct the objects that have constructors with matching arguments
475  template <typename... Args>
476  this_type& construct(Args&&... _args);
477 
478  /// provide preliminary info to the objects with matching arguments. This is typically
479  /// used to notify a component that it has been bundled alongside another component
480  /// that it can extract data from.
481  template <typename... Args>
482  this_type& assemble(Args&&... _args);
483 
484  /// provide conclusive info to the objects with matching arguments. This is typically
485  /// used by components to extract data from another component it has been bundled
486  /// alongside, e.g. the cpu_util component can extract data from \ref
487  /// tim::component::wall_clock and \ref tim::component::cpu_clock
488  template <typename... Args>
489  this_type& derive(Args&&... _args);
490 
491  /// mark an atomic event
492  template <typename... Args>
493  this_type& mark(Args&&... _args);
494 
495  /// mark a beginning position in the execution (typically used by asynchronous
496  /// structures)
497  template <typename... Args>
498  this_type& mark_begin(Args&&... _args);
499 
500  /// mark a beginning position in the execution (typically used by asynchronous
501  /// structures)
502  template <typename... Args>
503  this_type& mark_end(Args&&... _args);
504 
505  /// store a value
506  template <typename... Args>
507  this_type& store(Args&&... _args);
508 
509  /// allow the components to inspect the incoming arguments before start
510  /// or out-going return value before returning (typically using in GOTCHA components)
511  template <typename... Args>
512  this_type& audit(Args&&... _args);
513 
514  /// perform an add_secondary operation. This operation allows components to add
515  /// additional entries to storage which are their direct descendant
516  template <typename... Args>
517  this_type& add_secondary(Args&&... _args);
518 
519  /// generic member function for invoking user-provided operations
520  /// \tparam OpT Operation struct
521  template <template <typename> class OpT, typename... Args>
522  this_type& invoke(Args&&... _args);
523 
524  /// generic member function for invoking user-provided operations on a specific
525  /// set of component types
526  /// \tparam OpT Operation struct
527  template <template <typename> class OpT, typename... Tp, typename... Args>
528  this_type& invoke(mpl::piecewise_select<Tp...>, Args&&... _args);
529 
530  template <bool PrintPrefix = true, bool PrintLaps = true>
531  this_type& print(std::ostream& os, bool _endl = false) const;
532 
533  /// returns a tuple of invoking get() on all the components
534  template <typename... Args>
535  auto get(Args&&...) const;
536 
537  /// returns a tuple of the component label + invoking get() on all the components
538  template <typename... Args>
539  auto get_labeled(Args&&...) const;
540 
541  /// returns a reference to the underlying tuple of components
542  data_type& data();
543 
544  /// returns a const reference to the underlying tuple of components
545  const data_type& data() const;
546 
547  /// get a component from the bundle
548  template <typename U>
549  decltype(auto) get();
550 
551  /// get a component from the bundle
552  template <typename U>
553  decltype(auto) get() const;
554 
555  /// performs an opaque search. Opaque searches are generally provided by user_bundles
556  /// with a functor such as this:
557  ///
558  /// \code{.cpp}
559  /// auto _get = [](void* v_this, void*& ptr, size_t _hash) {
560  /// {
561  /// if(!ptr && v_this && _hash == typeid_hash<Tp>())
562  /// {
563  /// Tp* _this = static_cast<Tp*>(v_this);
564  /// _this->get(ptr, _hash);
565  /// }
566  /// return ptr;
567  /// };
568  /// \endcode
569  ///
570  /// And the component provides this function:
571  ///
572  /// \code{.cpp}
573  /// template <typename Tp, typename Value>
574  /// void
575  /// base<Tp, Value>::get(void*& ptr, size_t _hash) const
576  /// {
577  /// if(!ptr && _hash == typeid_hash<Tp>())
578  /// ptr = reinterpret_cast<void*>(const_cast<base_type*>(this));
579  /// }
580  /// \endcode
581  ///
582  this_type& get(void*& ptr, hash_value_t _hash) const;
583 
584  /// this is a simple alternative to get<T>() when used from SFINAE in operation
585  /// namespace which has a struct get also templated. Usage there can cause error
586  /// with older compilers
587  template <typename U>
588  auto get_component(
589  enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
590  is_one_of<remove_pointer_decay_t<U>, data_type>::value,
591  int> = 0);
592 
593  template <typename U>
594  auto get_component(
595  enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
596  is_one_of<remove_pointer_decay_t<U>*, data_type>::value,
597  int> = 0);
598 
599  /// returns a reference from a stack component instead of a pointer
600  template <typename U>
601  auto& get_reference(
602  enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
603  is_one_of<remove_pointer_decay_t<U>, data_type>::value,
604  int> = 0);
605 
606  /// returns a reference from a heap component instead of a pointer
607  template <typename U>
608  auto& get_reference(
609  enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
610  is_one_of<remove_pointer_decay_t<U>*, data_type>::value,
611  int> = 0);
612 
613  /// create an optional type that is in variadic list AND is available AND
614  /// accepts arguments
615  template <typename U, typename T = remove_pointer_decay_t<U>, typename... Args>
616  enable_if_t<will_heap_init<T>() && !will_opaque_init<T>(), bool> init(
617  Args&&... _args, enable_if_t<is_constructible<T, Args...>(), int> = 0)
618  {
619  T*& _obj = std::get<index_of<T*, data_type>::value>(m_data);
620  if(!_obj)
621  {
622  if(settings::debug())
623  {
624  printf("[bundle::init]> initializing type '%s'...\n",
625  demangle<T>().c_str());
626  }
627  _obj = new T(std::forward<Args>(_args)...);
628  set_prefix(_obj, internal_tag{});
629  set_scope(_obj, internal_tag{});
630  return true;
631  }
632 
633  static std::atomic<int> _count(0);
634  if((settings::verbose() > 1 || settings::debug()) && _count++ == 0)
635  {
636  std::string _id = demangle<T>();
637  fprintf(stderr,
638  "[bundle::init]> skipping re-initialization of type"
639  " \"%s\"...\n",
640  _id.c_str());
641  }
642 
643  return false;
644  }
645 
646  /// create an optional type that is in variadic list AND is available but is not
647  /// constructible with provided arguments
648  template <typename U, typename T = remove_pointer_decay_t<U>, typename... Args>
649  enable_if_t<will_heap_init<T>() && !will_opaque_init<T>(), bool> init(
650  Args&&...,
651  enable_if_t<!is_constructible<T, Args...>() && is_default_constructible<T>(),
652  long> = 0)
653  {
654  T*& _obj = std::get<index_of<T*, data_type>::value>(m_data);
655  if(!_obj)
656  {
657  if(settings::debug())
658  {
659  fprintf(stderr, "[bundle::init]> initializing type '%s'...\n",
660  demangle<T>().c_str());
661  }
662  _obj = new T{};
663  set_prefix(_obj, internal_tag{});
664  set_scope(_obj, internal_tag{});
665  return true;
666  }
667 
668  static std::atomic<int> _count(0);
669  if((settings::verbose() > 1 || settings::debug()) && _count++ == 0)
670  {
671  fprintf(stderr,
672  "[bundle::init]> skipping re-initialization of type "
673  "\"%s\"...\n",
674  demangle<T>().c_str());
675  }
676 
677  return false;
678  }
679 
680  /// try to re-create a stack object with provided arguments
681  template <typename U, typename T = remove_pointer_decay_t<U>, typename... Args>
682  bool init(Args&&... _args, enable_if_t<can_stack_init<T>(), int> = 0)
683  {
684  IF_CONSTEXPR(can_heap_init<T>())
685  {
686  static std::atomic<int> _count(0);
687  if((settings::verbose() > 1 || settings::debug()) && _count++ == 0)
688  {
689  fprintf(stderr,
690  "[bundle::init]> type exists as a heap-allocated instance "
691  "and stack-allocated instance: \"%s\"...\n",
692  demangle<T>().c_str());
693  }
694  }
695  T& _obj = std::get<index_of<T, data_type>::value>(m_data);
696  operation::construct<T>{ _obj, std::forward<Args>(_args)... };
697  set_prefix(&_obj, internal_tag{});
698  set_scope(&_obj, internal_tag{});
699  return true;
700  }
701 
702  /// if a type is not in variadic list but a \ref tim::component::user_bundle is
703  /// available, add it in there
704  template <typename U, typename T = remove_pointer_decay_t<U>, typename... Args>
705  bool init(Args&&..., enable_if_t<will_opaque_init<T>(), long> = 0)
706  {
707  using bundle_t = decay_t<decltype(
708  std::get<0>(std::declval<typename bundle_type::user_bundle_types>()))>;
709  static_assert(trait::is_user_bundle<bundle_t>::value, "Error! Not a user_bundle");
710  this->init<bundle_t>();
711  auto* _bundle = this->get<bundle_t>();
712  if(_bundle)
713  {
714  _bundle->insert(component::factory::get_opaque<T>(m_scope),
715  component::factory::get_typeids<T>());
716  return true;
717  }
718  return false;
719  }
720 
721  /// do nothing if type not available, not one of the variadic types, and there
722  /// is no user bundle available
723  template <typename U, typename T = remove_pointer_decay_t<U>, typename... Args>
726  bundle_type::has_user_bundle_v),
727  bool>
728  init(Args&&...)
729  {
730  return false;
731  }
732 
733  /// \brief variadic initialization
734  /// \tparam T components to initialize
735  /// \tparam Args arguments to pass to the construction of the component
736  template <typename... T, typename... Args>
737  std::array<bool, sizeof...(T)> initialize(Args&&... args);
738 
739  /// delete any optional types currently allocated
740  template <typename... Tail>
742 
743  /// apply a member function to a stack type that is in variadic list AND is available
744  template <typename T, typename Func, typename... Args,
746  this_type& type_apply(Func&& _func, Args&&... _args)
747  {
748  auto* _obj = get<T>();
749  ((*_obj).*(_func))(std::forward<Args>(_args)...);
750  return get_this_type();
751  }
752 
753  /// apply a member function to either a heap type or a type that is in a user_bundle
754  template <typename T, typename Func, typename... Args,
756  this_type& type_apply(Func&& _func, Args&&... _args);
757 
758  /// ignore applying a member function because the type is not present
759  template <typename T, typename Func, typename... Args,
761  this_type& type_apply(Func&&, Args&&...);
762 
763  void set_prefix(const string_t&) const;
767 
768  TIMEMORY_INLINE void rekey(const string_t& _key);
769  TIMEMORY_INLINE void rekey(captured_location_t _loc);
770  TIMEMORY_INLINE void rekey(uint64_t _hash);
771 
772  /// returns a stack-object for calling stop
773  scope::transient_destructor get_scope_destructor();
774 
775  /// returns a stack-object for calling some member functions when the scope is exited.
776  scope::transient_destructor get_scope_destructor(
778 
779  const data_type& get_data() const { return m_data; }
780 
781 protected:
782  template <typename T>
783  void set_scope(T* obj, internal_tag) const;
784 
785  template <typename T>
786  void set_prefix(T* obj, internal_tag) const;
787 
788 protected:
789  // objects
790  using bundle_type::m_config;
791  using bundle_type::m_enabled;
792  using bundle_type::m_hash;
793  using bundle_type::m_is_active;
794  using bundle_type::m_is_pushed;
795  using bundle_type::m_laps;
796  using bundle_type::m_scope;
797  using bundle_type::m_store;
798  mutable data_type m_data{};
799 
800 private:
801  this_type& get_this_type() { return static_cast<this_type&>(*this); }
802  this_type& get_this_type() const
803  {
804  return const_cast<this_type&>(static_cast<const this_type&>(*this));
805  }
806 
807  static this_type*& get_last_instance()
808  {
809  static thread_local this_type* _instance = nullptr;
810  return _instance;
811  }
812 
813  static void update_last_instance(this_type* _new_instance,
814  this_type*& _old_instance = get_last_instance(),
815  bool _stop_last = false)
816  {
817  if(_stop_last && _old_instance && _old_instance != _new_instance)
818  _old_instance->stop();
819  _old_instance = _new_instance;
820  }
821 
822 public:
823  // archive serialization
824  template <typename Archive>
825  void serialize(Archive& ar, const unsigned int);
826 };
827 //
828 //----------------------------------------------------------------------------------//
829 //
830 template <typename Tag, typename BundleT, typename TupleT>
831 constexpr uint64_t
833 {
834  return (size() -
837 }
838 
839 //----------------------------------------------------------------------------------//
840 //
841 template <typename Tag, typename BundleT, typename TupleT>
842 constexpr uint64_t
844 {
845  return mpl::get_tuple_size<
847 }
848 
849 //----------------------------------------------------------------------------------//
850 //
851 template <typename Tag, typename BundleT, typename TupleT>
852 template <typename FuncT, typename... Args>
853 decltype(auto)
854 bundle<Tag, BundleT, TupleT>::execute(FuncT&& func, Args&&... args)
855 {
856  return mpl::execute(get_this_type(),
857  std::forward<FuncT>(func)(std::forward<Args>(args)...));
858 }
859 
860 //----------------------------------------------------------------------------------//
861 //
862 template <typename Tag, typename BundleT, typename TupleT>
863 template <typename U>
864 decltype(auto)
865 bundle<Tag, BundleT, TupleT>::get()
866 {
867  return tim::variadic::impl::get<U, Tag>(m_data);
868 }
869 
870 //----------------------------------------------------------------------------------//
871 //
872 template <typename Tag, typename BundleT, typename TupleT>
873 template <typename U>
874 decltype(auto)
875 bundle<Tag, BundleT, TupleT>::get() const
876 {
877  return tim::variadic::impl::get<U, Tag>(m_data);
878 }
879 
880 //----------------------------------------------------------------------------------//
881 //
882 template <typename Tag, typename BundleT, typename TupleT>
883 template <typename U>
884 auto
886  enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
887  is_one_of<remove_pointer_decay_t<U>, data_type>::value,
888  int>)
889 {
890  return get<remove_pointer_decay_t<U>>();
891 }
892 
893 //----------------------------------------------------------------------------------//
894 //
895 template <typename Tag, typename BundleT, typename TupleT>
896 template <typename U>
897 auto
899  enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
900  is_one_of<remove_pointer_decay_t<U>*, data_type>::value,
901  int>)
902 {
903  return get<remove_pointer_decay_t<U>>();
904 }
905 
906 //----------------------------------------------------------------------------------//
907 //
908 template <typename Tag, typename BundleT, typename TupleT>
909 template <typename U>
910 auto&
912  enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
913  is_one_of<remove_pointer_decay_t<U>, data_type>::value,
914  int>)
915 {
916  return std::get<index_of<remove_pointer_decay_t<U>, data_type>::value>(m_data);
917 }
918 
919 //----------------------------------------------------------------------------------//
920 //
921 template <typename Tag, typename BundleT, typename TupleT>
922 template <typename U>
923 auto&
925  enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
926  is_one_of<remove_pointer_decay_t<U>*, data_type>::value,
927  int>)
928 {
929  return std::get<index_of<remove_pointer_decay_t<U>*, data_type>::value>(m_data);
930 }
931 //
932 //----------------------------------------------------------------------------------//
933 //
934 template <typename Tag, typename BundleT, typename TupleT>
935 void
937 {
938  m_hash = add_hash_id(_key);
939  set_prefix(_key);
940 }
941 //
942 //----------------------------------------------------------------------------------//
943 //
944 template <typename Tag, typename BundleT, typename TupleT>
945 void
947 {
948  m_hash = _loc.get_hash();
949  set_prefix(_loc);
950 }
951 //
952 //----------------------------------------------------------------------------------//
953 //
954 template <typename Tag, typename BundleT, typename TupleT>
955 void
957 {
958  m_hash = _hash;
959  set_prefix(_hash);
960 }
961 //
962 //----------------------------------------------------------------------------------//
963 //
964 /*
965 template <typename Tag, typename BundleT, typename TupleT
966  >
967 class bundle<Tag, BundleT, TransformT<>, std::tuple<Types...>>
968 : public bundle<Tag, BundleT, TupleT>
969 {
970  TIMEMORY_DEFAULT_OBJECT(bundle)
971 
972  template <typename... Args>
973  bundle(Args&&... args)
974  : bundle<Tag, BundleT, TupleT>{ std::forward<Args>(args)... }
975  {}
976 };
977 //
978 //----------------------------------------------------------------------------------//
979 //
980 template <typename Tag, typename BundleT, typename TupleT
981  >
982 class bundle<Tag, BundleT, TransformT<>, type_list<Types...>>
983 : public bundle<Tag, BundleT, TupleT>
984 {
985  TIMEMORY_DEFAULT_OBJECT(bundle)
986 
987  template <typename... Args>
988  bundle(Args&&... args)
989  : bundle<Tag, BundleT, TupleT>{ std::forward<Args>(args)... }
990  {}
991 };
992 */
993 } // namespace tim
994 
This is a variadic component wrapper where all components are optional at runtime....
Definition: auto_list.hpp:91
This is a variadic component wrapper where all components are allocated on the stack and cannot be di...
Definition: auto_tuple.hpp:65
Example: bundle<Tag, component_bundle<Foo>, mixed_wrapper_types<concat<Bar, Baz>>> will use Tag + tra...
Definition: bundle.hpp:113
static constexpr bool is_default_constructible()
Query at compile-time whether type supports default construction. If type is not available,...
Definition: bundle.hpp:375
typename TupleT::template data_type< Tag > data_type
Definition: bundle.hpp:153
bool init(Args &&... _args, enable_if_t< can_stack_init< T >(), int >=0)
try to re-create a stack object with provided arguments
Definition: bundle.hpp:682
typename TupleT::template component_type< BundleT > component_type
Definition: bundle.hpp:152
this_type & type_apply(Func &&, Args &&...)
ignore applying a member function because the type is not present
typename TupleT::type_list_type type_list_type
Definition: bundle.hpp:154
enable_if_t<!trait::is_available< T >::value||!(is_one_of< T *, data_type >::value||is_one_of< T, data_type >::value||bundle_type::has_user_bundle_v), bool > init(Args &&...)
do nothing if type not available, not one of the variadic types, and there is no user bundle availabl...
Definition: bundle.hpp:728
const data_type & get_data() const
Definition: bundle.hpp:779
this_type & operator+=(Op &&rhs)
Definition: bundle.hpp:237
typename TupleT::template type< BundleT > type
Definition: bundle.hpp:151
tim::variadic::impl::quirk_config< T, reference_type, U... > quirk_config
Definition: bundle.hpp:164
typename bundle_type::size_type size_type
Definition: bundle.hpp:156
static constexpr bool can_stack_init()
Query at compile-time whether initialization can occur on the stack.
Definition: bundle.hpp:296
static constexpr bool will_heap_init()
Query at compile-time whether initialization will occur on the heap. can_heap_init<T>() && !...
Definition: bundle.hpp:332
this_type & operator*=(Op &&rhs)
Definition: bundle.hpp:244
this_type & type_apply(Func &&_func, Args &&... _args)
apply a member function to a stack type that is in variadic list AND is available
Definition: bundle.hpp:746
this_type & stop(mpl::piecewise_select< Tp... >, Args &&...)
variant of stop() which only gets applied to Tp types
static constexpr bool will_opaque_init()
Query at compile-time whether initialization will happen with an opaque wrapper (i....
Definition: bundle.hpp:343
this_type & disable()
delete any optional types currently allocated
this_type & start(Args &&...)
invokes start on all the components
this_type & operator/=(Op &&rhs)
Definition: bundle.hpp:251
friend std::ostream & operator<<(std::ostream &os, const bundle &obj)
Definition: bundle.hpp:280
this_type & pop(mpl::piecewise_select< Tp... >)
selective pop
bool init(Args &&..., enable_if_t< will_opaque_init< T >(), long >=0)
if a type is not in variadic list but a tim::component::user_bundle is available, add it in there
Definition: bundle.hpp:705
static constexpr bool has_user_bundle()
Query at compile-time whether a user_bundle exists in the set of components. user_bundle are more res...
Definition: bundle.hpp:292
friend this_type operator/(const this_type &lhs, Op &&rhs)
Definition: bundle.hpp:275
enable_if_t< will_heap_init< T >) &&!will_opaque_init< T >), bool > init(Args &&..., enable_if_t<!is_constructible< T, Args... >() &&is_default_constructible< T >(), long >=0)
create an optional type that is in variadic list AND is available but is not constructible with provi...
Definition: bundle.hpp:649
this_type & push(mpl::piecewise_select< Tp... >)
selective push
this_type & record(Args &&...)
requests each component perform a measurement
bundle(bundle &&) noexcept=default
typename bundle_type::string_t string_t
Definition: bundle.hpp:145
friend this_type operator*(const this_type &lhs, Op &&rhs)
Definition: bundle.hpp:269
typename TupleT::template this_type< BundleT > this_type
Definition: bundle.hpp:150
typename TupleT::reference_type reference_type
Definition: bundle.hpp:146
this_type & reset(Args &&...)
invokes reset member function on all the components
this_type & start(mpl::lightweight, Args &&...)
variant of start() which excludes push()
static constexpr bool is_this_type()
Query whether type matches this_type.
Definition: bundle.hpp:168
this_type & push(mpl::piecewise_select< Tp... >, scope::config)
selective push with scope configuration
this_type & stop(mpl::lightweight, Args &&...)
variant of stop() which excludes pop()
static constexpr bool can_heap_init()
Query at compile-time whether initialization can occur on the heap.
Definition: bundle.hpp:304
static constexpr bool is_constructible()
Query at compile-time whether type can be constructed with the given argument types....
Definition: bundle.hpp:356
this_type & start(mpl::piecewise_select< Tp... >, Args &&...)
variant of start() which only gets applied to Tp types
static constexpr bool can_init()
Query at compile-time whether the specified type can be initialized.
Definition: bundle.hpp:321
friend this_type operator-(const this_type &lhs, const this_type &rhs)
Definition: bundle.hpp:263
this_type & measure(Args &&...)
requests each component record a measurment
friend this_type operator+(const this_type &lhs, const this_type &rhs)
Definition: bundle.hpp:258
static constexpr bool can_placement_init()
Query at compile-time whether initialization can occur via a placement new. Placement new init allows...
Definition: bundle.hpp:314
this_type & stop(Args &&...)
invokes stop on all the components
std::function< void(this_type &)> initializer_type
Definition: bundle.hpp:157
this_type & sample(Args &&...)
requests each component take a sample (if supported)
#define IF_CONSTEXPR(...)
Definition: language.hpp:72
std::string string_t
Definition: library.cpp:56
std::shared_ptr< DataType > execute(std::shared_ptr< DataType > _data=std::make_shared< DataType >())
void serialize(std::string fname, exec_data< Counter > &obj)
Definition: counter.hpp:322
void set_scope(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:792
void assemble(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:850
void mark_begin(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:474
void set_prefix(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:756
void audit(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:921
void store(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:546
void derive(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:886
void pop(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:721
void push(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:686
void mark_end(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:510
void mark(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:439
void print(std::ostream &os, Args &&... args)
Definition: functional.cpp:159
impl::filter_false< Predicate, std::tuple< Sequence... > > type
Definition: available.hpp:259
auto execute(BundleT &&_bundle, FuncT &&_func, Args &&... _args, enable_if_t< is_invocable< FuncT, Args... >::value &&!std::is_void< std::result_of_t< FuncT(Args...)>>::value, int >)
a generic type for indicating that function call or constructor should be as lightweight as possible.
Definition: types.hpp:328
Ret invoke(string_view_t &&label, Func &&func, Args &&... args)
Definition: invoker.hpp:39
std::bitset< scope_count > data_type
Definition: types.hpp:395
A light-weight alternative to std::function. Pass any callback - including capturing lambdas - cheapl...
Definition: kokkosp.cpp:38
size_t hash_value_t
Definition: types.hpp:81
add_secondary
Definition: settings.cpp:1371
std::string string_t
Definition: utility.hpp:105
void initialize(CompList< CompTypes... > &obj, std::initializer_list< EnumT > components)
Definition: initialize.hpp:53
typename std::decay< T >::type decay_t
Alias template for decay.
Definition: types.hpp:194
typename std::enable_if< B, T >::type enable_if_t
Alias template for enable_if.
Definition: types.hpp:190
auto get_labeled(const auto_bundle< Tag, Types... > &_obj)
void init(Args &&... args)
Definition: types.hpp:111
tim::mpl::apply< std::string > string
Definition: macros.hpp:52
hash_value_t add_hash_id(hash_map_ptr_t &_hash_map, const string_view_t &_prefix)
add an string to the given hash-map (if it doesn't already exist) and return the hash
Definition: types.hpp:187
typename impl::is_one_of< Tp, Types > is_one_of
check if type is in expansion
Definition: types.hpp:738
auto get(const auto_bundle< Tag, Types... > &_obj)
Static polymorphic base class for automatic start/stop bundlers.
Definition: types.hpp:72
Static polymorphic base class for component bundlers.
Definition: bundle.hpp:51
This is a variadic component wrapper which combines the features of tim::auto_tuple<T....
Definition: types.hpp:75
Declare the operations types.
The purpose of this operation class is construct an object with specific args.
Definition: construct.hpp:52
a variadic type which holds zero or more quirks that are passed to the constructor of a component bun...
Definition: quirks.hpp:39
this data type encodes the options of storage scope. The default is hierarchical (tree) scope....
Definition: types.hpp:446
const hash_value_t & get_hash() const
trait that signifies that an implementation for the component is available. When this is set to false...
trait that designates the type is a user-bundle
typename typename typename
Definition: types.hpp:226