timemory 3.3.0
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
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
46namespace tim
47{
48/// \class tim::bundle
49/// \brief Static polymorphic base class for component bundlers
50template <typename... Tp>
51class 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
110template <typename Tag, typename BundleT, typename TupleT>
111class bundle<Tag, BundleT, TupleT>
112: public api_bundle<Tag, typename TupleT::available_type>
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
142protected:
146 using reference_type = typename TupleT::reference_type;
147
148public:
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
160public:
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
173public:
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>
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&&) = default;
220
221 // this_type operators
222 bundle& operator=(const bundle& rhs);
223 bundle& operator=(bundle&&) = 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>
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+(this_type lhs, const this_type& rhs) { return lhs += rhs; }
259 friend this_type operator-(this_type lhs, const this_type& rhs) { return lhs -= rhs; }
260
261 template <typename Op>
263 const Op& rhs)
264 {
265 return lhs *= rhs;
266 }
267
268 template <typename Op>
270 const Op& rhs)
271 {
272 return lhs /= rhs;
273 }
274
275 friend std::ostream& operator<<(std::ostream& os, const bundle& obj)
276 {
277 obj.print<true, true>(os);
278 return os;
279 }
280
281 bundle clone(bool store, scope::config _scope = scope::get_default());
282
283public:
284 /// Query at compile-time whether a user_bundle exists in the set of components.
285 /// user_bundle are more restricted versions of component bundlers but allow
286 /// runtime insertion of components.
287 static constexpr bool has_user_bundle() { return bundle_type::has_user_bundle_v; }
288
289 /// Query at compile-time whether initialization can occur on the stack
290 template <typename U>
291 static constexpr bool can_stack_init()
292 {
293 using T = remove_pointer_decay_t<U>;
295 }
296
297 /// Query at compile-time whether initialization can occur on the heap
298 template <typename U>
299 static constexpr bool can_heap_init()
300 {
301 using T = remove_pointer_decay_t<U>;
303 }
304
305 /// Query at compile-time whether initialization can occur via a placement new.
306 /// Placement new init allows for the combination of optional initialization without
307 /// a heap allocation. Not currently available.
308 template <typename U>
309 static constexpr bool can_placement_init()
310 {
311 return false;
312 }
313
314 /// Query at compile-time whether the specified type can be initialized
315 template <typename U>
316 static constexpr bool can_init()
317 {
318 using T = remove_pointer_decay_t<U>;
319 return can_stack_init<T>() || can_heap_init<T>() || can_placement_init<T>() ||
320 (trait::is_available<T>::value && has_user_bundle());
321 }
322
323 /// Query at compile-time whether initialization will occur on the heap.
324 /// `can_heap_init<T>() && !will_heap_init<T>()` will indicate that a
325 /// stack-allocated instance of the same type exists.
326 template <typename U>
327 static constexpr bool will_heap_init()
328 {
329 using T = remove_pointer_decay_t<U>;
330 return can_init<T>() && !can_stack_init<T>();
331 }
332
333 /// Query at compile-time whether initialization will happen with an opaque wrapper
334 /// (i.e. via user bundle). In this situation, initialization arguments are ignored
335 /// and the component will only be initialized with the \ref tim::scope::config of the
336 /// bundle.
337 template <typename U>
338 static constexpr bool will_opaque_init()
339 {
340 using T = remove_pointer_decay_t<U>;
341 return !can_stack_init<T>() && !can_heap_init<T>() &&
342 (trait::is_available<T>::value && has_user_bundle());
343 }
344
345 /// Query at compile-time whether type can be constructed with the given argument
346 /// types. if type is not available, then it probably won't be defined, so this
347 /// places the `trait::is_available<T>` check in the template parameters and the
348 /// `std::is_constructible<T, ...>` in the body to avoid undefined behavior
349 template <typename U, typename... Args, typename T = remove_pointer_decay_t<U>,
351 static constexpr bool is_constructible()
352 {
353 return std::is_constructible<T, Args...>::value;
354 }
355
356 /// Return false if the type is not available
357 template <typename U, typename... Args, typename T = remove_pointer_decay_t<U>,
359 static constexpr bool is_constructible()
360 {
361 return false;
362 }
363
364 /// Query at compile-time whether type supports default construction. If type is not
365 /// available, then it probably won't be defined, so this places the
366 /// `trait::is_available<T>` check in the template parameters and the
367 /// `std::is_constructible<T, ...>` in the body to avoid undefined behavior
368 template <typename U, typename T = remove_pointer_decay_t<U>,
369 enable_if_t<trait::is_available<T>::value> = 0>
370 static constexpr bool is_default_constructible()
371 {
372 return std::is_default_constructible<T>::value;
373 }
374
375 /// Return false if the type is not available
376 template <typename U, typename T = remove_pointer_decay_t<U>,
377 enable_if_t<!trait::is_available<T>::value> = 0>
378 static constexpr bool is_default_constructible()
379 {
380 return false;
381 }
382
383public:
384 /// requests the component initialize their storage
385 static void init_storage();
386
387 /// tells each component to push itself into the call-stack hierarchy
388 this_type& push();
389
390 /// tells each component to pop itself off of the call-stack hierarchy
391 this_type& pop();
392
393 /// selective push
394 template <typename... Tp>
396
397 /// selective push
398 template <typename... Tp>
400
401 /// selective push with scope configuration
402 template <typename... Tp>
404
405 /// selective push with scope configuration
406 template <typename... Tp>
408
409 /// selective pop
410 template <typename... Tp>
412
413 /// selective pop
414 template <typename... Tp>
416
417 /// requests each component record a measurment
418 template <typename... Args>
419 this_type& measure(Args&&...);
420
421 /// requests each component take a sample (if supported)
422 template <typename... Args>
423 this_type& sample(Args&&...);
424
425 /// invokes start on all the components
426 template <typename... Args>
427 this_type& start(Args&&...);
428
429 /// invokes stop on all the components
430 template <typename... Args>
431 this_type& stop(Args&&...);
432
433 /// requests each component perform a measurement
434 template <typename... Args>
435 this_type& record(Args&&...);
436
437 /// invokes reset member function on all the components
438 template <typename... Args>
439 this_type& reset(Args&&...);
440
441 /// variant of start() which excludes push()
442 template <typename... Args>
444
445 /// variant of stop() which excludes pop()
446 template <typename... Args>
448
449 /// variant of start() which only gets applied to Tp types
450 template <typename... Tp, typename... Args>
452
453 /// variant of start() which gets applied to non-Tp types
454 template <typename... Tp, typename... Args>
456
457 /// variant of stop() which only gets applied to Tp types
458 template <typename... Tp, typename... Args>
460
461 /// variant of stop() which gets applied to non-Tp types
462 template <typename... Tp, typename... Args>
464
465 using bundle_type::get_prefix;
466 using bundle_type::get_scope;
467 using bundle_type::get_store;
468 using bundle_type::hash;
469 using bundle_type::key;
470 using bundle_type::laps;
471 using bundle_type::prefix;
472 using bundle_type::size;
473 using bundle_type::store;
474
475 /// query the number of (compile-time) fixed components
476 static constexpr uint64_t fixed_count();
477
478 /// query the number of (run-time) optional components
479 static constexpr uint64_t optional_count();
480
481 /// number of objects that will be performing measurements
482 uint64_t count();
483
484 /// when chaining together operations, this function enables executing a function
485 /// inside the chain
486 template <typename FuncT, typename... Args>
487 decltype(auto) execute(FuncT&& func, Args&&... args);
488
489 /// construct the objects that have constructors with matching arguments
490 template <typename... Args>
492
493 /// provide preliminary info to the objects with matching arguments. This is typically
494 /// used to notify a component that it has been bundled alongside another component
495 /// that it can extract data from.
496 template <typename... Args>
498
499 /// provide conclusive info to the objects with matching arguments. This is typically
500 /// used by components to extract data from another component it has been bundled
501 /// alongside, e.g. the cpu_util component can extract data from \ref
502 /// tim::component::wall_clock and \ref tim::component::cpu_clock
503 template <typename... Args>
504 this_type& derive(Args&&... _args);
505
506 /// mark an atomic event
507 template <typename... Args>
508 this_type& mark(Args&&... _args);
509
510 /// mark a beginning position in the execution (typically used by asynchronous
511 /// structures)
512 template <typename... Args>
514
515 /// mark a beginning position in the execution (typically used by asynchronous
516 /// structures)
517 template <typename... Args>
519
520 /// store a value
521 template <typename... Args>
522 this_type& store(Args&&... _args);
523
524 /// allow the components to inspect the incoming arguments before start
525 /// or out-going return value before returning (typically using in GOTCHA components)
526 template <typename... Args>
527 this_type& audit(Args&&... _args);
528
529 /// perform an add_secondary operation. This operation allows components to add
530 /// additional entries to storage which are their direct descendant
531 template <typename... Args>
533
534 /// perform an add_secondary operation. This operation allows components to add
535 /// additional entries to storage which are their direct descendant
536 template <typename... Args>
538
539 /// generic member function for invoking user-provided operations
540 /// \tparam OpT Operation struct
541 template <template <typename> class OpT, typename... Args>
542 this_type& invoke(Args&&... _args);
543
544 /// generic member function for invoking user-provided operations on a specific
545 /// set of component types
546 /// \tparam OpT Operation struct
547 template <template <typename> class OpT, typename... Tp, typename... Args>
549
550 /// generic member function for invoking user-provided operations on all types
551 /// that are not listed
552 /// \tparam OpT Operation struct
553 template <template <typename> class OpT, typename... Tp, typename... Args>
555
556 template <bool PrintPrefix = true, bool PrintLaps = true>
557 this_type& print(std::ostream& os, bool _endl = false) const;
558
559 /// returns a tuple of invoking get() on all the components
560 template <typename... Args>
561 auto get(Args&&...) const;
562
563 /// returns a tuple of the component label + invoking get() on all the components
564 template <typename... Args>
565 auto get_labeled(Args&&...) const;
566
567 /// returns a reference to the underlying tuple of components
568 data_type& data();
569
570 /// returns a const reference to the underlying tuple of components
571 const data_type& data() const;
572
573 /// get a component from the bundle
574 template <typename U>
575 decltype(auto) get();
576
577 /// get a component from the bundle
578 template <typename U>
579 decltype(auto) get() const;
580
581 /// get a component from the bundle and apply function if the pointer is valid
582 template <typename U, typename FuncT>
583 decltype(auto) get(FuncT&&);
584
585 /// get a component from the bundle
586 template <typename U, typename FuncT>
587 decltype(auto) get(FuncT&&) const;
588
589 /// performs an opaque search. Opaque searches are generally provided by user_bundles
590 /// with a functor such as this:
591 ///
592 /// \code{.cpp}
593 /// auto _get = [](void* v_this, void*& ptr, size_t _hash) {
594 /// {
595 /// if(!ptr && v_this && _hash == typeid_hash<Tp>())
596 /// {
597 /// Tp* _this = static_cast<Tp*>(v_this);
598 /// _this->get(ptr, _hash);
599 /// }
600 /// return ptr;
601 /// };
602 /// \endcode
603 ///
604 /// And the component provides this function:
605 ///
606 /// \code{.cpp}
607 /// template <typename Tp, typename Value>
608 /// void
609 /// base<Tp, Value>::get(void*& ptr, size_t _hash) const
610 /// {
611 /// if(!ptr && _hash == typeid_hash<Tp>())
612 /// ptr = reinterpret_cast<void*>(const_cast<base_type*>(this));
613 /// }
614 /// \endcode
615 ///
616 this_type& get(void*& ptr, hash_value_t _hash) const;
617
618 /// this is a simple alternative to get<T>() when used from SFINAE in operation
619 /// namespace which has a struct get also templated. Usage there can cause error
620 /// with older compilers
621 template <typename U>
622 auto get_component(
623 enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
624 is_one_of<remove_pointer_decay_t<U>, data_type>::value,
625 int> = 0);
626
627 template <typename U>
628 auto get_component(
629 enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
630 is_one_of<remove_pointer_decay_t<U>*, data_type>::value,
631 int> = 0);
632
633 /// returns a reference from a stack component instead of a pointer
634 template <typename U>
635 auto& get_reference(
636 enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
637 is_one_of<remove_pointer_decay_t<U>, data_type>::value,
638 int> = 0);
639
640 /// returns a reference from a heap component instead of a pointer
641 template <typename U>
642 auto& get_reference(
643 enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
644 is_one_of<remove_pointer_decay_t<U>*, data_type>::value,
645 int> = 0);
646
647 /// create an optional type that is in variadic list AND is available AND
648 /// accepts arguments
649 template <typename U, typename T = remove_pointer_decay_t<U>, typename... Args>
650 enable_if_t<will_heap_init<T>() && !will_opaque_init<T>(), bool> init(
651 Args&&... _args, enable_if_t<is_constructible<T, Args...>(), int> = 0)
652 {
653 T*& _obj = std::get<index_of<T*, data_type>::value>(m_data);
654 if(!_obj)
655 {
657 {
658 printf("[bundle::init]> initializing type '%s'...\n",
659 demangle<T>().c_str());
660 }
661 if(!bundle_type::init_buffer())
662 {
663 _obj = new T(std::forward<Args>(_args)...);
664 }
665 else
666 {
667 T in(std::forward<Args>(_args)...);
668 _obj = m_buffer->write(&in).second;
669 }
670 set_prefix(_obj, internal_tag{});
671 set_scope(_obj, internal_tag{});
672 return true;
673 }
674
675 static std::atomic<int> _count(0);
676 if((settings::verbose() > 1 || settings::debug()) && _count++ == 0)
677 {
678 std::string _id = demangle<T>();
679 fprintf(stderr,
680 "[bundle::init]> skipping re-initialization of type"
681 " \"%s\"...\n",
682 _id.c_str());
683 }
684
685 return false;
686 }
687
688 /// create an optional type that is in variadic list AND is available but is not
689 /// constructible with provided arguments
690 template <typename U, typename T = remove_pointer_decay_t<U>, typename... Args>
691 enable_if_t<will_heap_init<T>() && !will_opaque_init<T>(), bool> init(
692 Args&&...,
693 enable_if_t<!is_constructible<T, Args...>() && is_default_constructible<T>(),
694 long> = 0)
695 {
696 T*& _obj = std::get<index_of<T*, data_type>::value>(m_data);
697 if(!_obj)
698 {
700 {
701 fprintf(stderr, "[bundle::init]> initializing type '%s'...\n",
702 demangle<T>().c_str());
703 }
704 if(!bundle_type::init_buffer())
705 {
706 _obj = new T{};
707 }
708 else
709 {
710 T in{};
711 _obj = m_buffer->write(&in).second;
712 }
713 set_prefix(_obj, internal_tag{});
714 set_scope(_obj, internal_tag{});
715 return true;
716 }
717
718 static std::atomic<int> _count(0);
719 if((settings::verbose() > 1 || settings::debug()) && _count++ == 0)
720 {
721 fprintf(stderr,
722 "[bundle::init]> skipping re-initialization of type "
723 "\"%s\"...\n",
724 demangle<T>().c_str());
725 }
726
727 return false;
728 }
729
730 /// try to re-create a stack object with provided arguments
731 template <typename U, typename T = remove_pointer_decay_t<U>, typename... Args>
732 bool init(Args&&... _args, enable_if_t<can_stack_init<T>(), int> = 0)
733 {
734 IF_CONSTEXPR(can_heap_init<T>())
735 {
736 static std::atomic<int> _count(0);
737 if((settings::verbose() > 1 || settings::debug()) && _count++ == 0)
738 {
739 fprintf(stderr,
740 "[bundle::init]> type exists as a heap-allocated instance "
741 "and stack-allocated instance: \"%s\"...\n",
742 demangle<T>().c_str());
743 }
744 }
745 T& _obj = std::get<index_of<T, data_type>::value>(m_data);
746 operation::construct<T>{ _obj, std::forward<Args>(_args)... };
747 set_prefix(&_obj, internal_tag{});
748 set_scope(&_obj, internal_tag{});
749 return true;
750 }
751
752 /// if a type is not in variadic list but a \ref tim::component::user_bundle is
753 /// available, add it in there
754 template <typename U, typename T = remove_pointer_decay_t<U>, typename... Args>
755 bool init(Args&&..., enable_if_t<will_opaque_init<T>(), long> = 0)
756 {
757 using bundle_t = decay_t<decltype(
758 std::get<0>(std::declval<typename bundle_type::user_bundle_types>()))>;
759 static_assert(trait::is_user_bundle<bundle_t>::value, "Error! Not a user_bundle");
760 this->init<bundle_t>();
761 auto* _bundle = this->get<bundle_t>();
762 if(_bundle)
763 {
764 _bundle->insert(component::factory::get_opaque<T>(m_scope),
765 component::factory::get_typeids<T>());
766 return true;
767 }
768 return false;
769 }
770
771 /// do nothing if type not available, not one of the variadic types, and there
772 /// is no user bundle available
773 template <typename U, typename T = remove_pointer_decay_t<U>, typename... Args>
776 bundle_type::has_user_bundle_v),
777 bool>
778 init(Args&&...)
779 {
780 return false;
781 }
782
783 /// \brief variadic initialization
784 /// \tparam T components to initialize
785 /// \tparam Args arguments to pass to the construction of the component
786 template <typename... T, typename... Args>
787 std::array<bool, sizeof...(T)> initialize(Args&&... args);
788
789 /// delete any optional types currently allocated
790 template <typename... Tail>
792
793 /// apply a member function to a stack type that is in variadic list AND is available
794 template <typename T, typename Func, typename... Args,
796 this_type& type_apply(Func&& _func, Args&&... _args)
797 {
798 auto* _obj = get<T>();
799 ((*_obj).*(_func))(std::forward<Args>(_args)...);
800 return get_this_type();
801 }
802
803 /// apply a member function to either a heap type or a type that is in a user_bundle
804 template <typename T, typename Func, typename... Args,
806 this_type& type_apply(Func&& _func, Args&&... _args);
807
808 /// ignore applying a member function because the type is not present
809 template <typename T, typename Func, typename... Args,
811 this_type& type_apply(Func&&, Args&&...);
812
813 void set_prefix(const string_t&) const;
817
818 TIMEMORY_INLINE void rekey(const string_t& _key);
819 TIMEMORY_INLINE void rekey(captured_location_t _loc);
820 TIMEMORY_INLINE void rekey(uint64_t _hash);
821
822 /// returns a stack-object for calling stop
823 scope::transient_destructor get_scope_destructor();
824
825 /// returns a stack-object for calling some member functions when the scope is exited.
826 scope::transient_destructor get_scope_destructor(
828
829 const data_type& get_data() const { return m_data; }
830
831protected:
832 template <typename T>
833 void set_scope(T* obj, internal_tag) const;
834
835 template <typename T>
836 void set_prefix(T* obj, internal_tag) const;
837
838protected:
839 // objects
840 using bundle_type::m_buffer;
841 using bundle_type::m_config;
842 using bundle_type::m_enabled;
843 using bundle_type::m_hash;
844 using bundle_type::m_is_active;
845 using bundle_type::m_is_pushed;
846 using bundle_type::m_laps;
847 using bundle_type::m_scope;
848 using bundle_type::m_store;
849 mutable data_type m_data{};
850
851private:
852 this_type& get_this_type() { return static_cast<this_type&>(*this); }
853 this_type& get_this_type() const
854 {
855 return const_cast<this_type&>(static_cast<const this_type&>(*this));
856 }
857
858 static this_type*& get_last_instance()
859 {
860 static thread_local this_type* _instance = nullptr;
861 return _instance;
862 }
863
864 static void update_last_instance(this_type* _new_instance,
865 this_type*& _old_instance = get_last_instance(),
866 bool _stop_last = false)
867 {
868 if(_stop_last && _old_instance && _old_instance != _new_instance)
869 _old_instance->stop();
870 _old_instance = _new_instance;
871 }
872
873 template <template <typename> class OpT, typename... Tp, typename... Args>
874 void invoke_piecewise(type_list<Tp...>, Args&&... _args);
875
876public:
877 // archive serialization
878 template <typename Archive>
879 void serialize(Archive& ar, const unsigned int);
880};
881//
882//----------------------------------------------------------------------------------//
883//
884template <typename Tag, typename BundleT, typename TupleT>
885constexpr uint64_t
887{
888 return (size() -
891}
892
893//----------------------------------------------------------------------------------//
894//
895template <typename Tag, typename BundleT, typename TupleT>
896constexpr uint64_t
898{
899 return mpl::get_tuple_size<
901}
902
903//----------------------------------------------------------------------------------//
904//
905template <typename Tag, typename BundleT, typename TupleT>
906template <typename FuncT, typename... Args>
907decltype(auto)
908bundle<Tag, BundleT, TupleT>::execute(FuncT&& func, Args&&... args)
909{
910 return mpl::execute(get_this_type(),
911 std::forward<FuncT>(func)(std::forward<Args>(args)...));
912}
913
914//----------------------------------------------------------------------------------//
915//
916template <typename Tag, typename BundleT, typename TupleT>
917template <typename U>
918decltype(auto)
920{
921 return tim::variadic::impl::get<U, Tag>(m_data);
922}
923
924//----------------------------------------------------------------------------------//
925//
926template <typename Tag, typename BundleT, typename TupleT>
927template <typename U>
928decltype(auto)
930{
931 return tim::variadic::impl::get<U, Tag>(m_data);
932}
933
934//----------------------------------------------------------------------------------//
935//
936template <typename Tag, typename BundleT, typename TupleT>
937template <typename U, typename FuncT>
938decltype(auto)
940{
941 auto* _obj = tim::variadic::impl::get<U, Tag>(m_data);
942 if(_obj)
943 return std::forward<FuncT>(_func)(_obj);
944 using return_type = decltype(_func(std::declval<decltype(_obj)>()));
945#if defined(CXX17)
946 if constexpr(std::is_void<decay_t<return_type>>::value)
947 return;
948 else if constexpr(std::is_pointer<decay_t<return_type>>::value)
949 return static_cast<decay_t<return_type>>(nullptr);
950 else
951 return decltype(_func(std::declval<decltype(_obj)>())){};
952#else
953 return return_type();
954#endif
955}
956
957//----------------------------------------------------------------------------------//
958//
959template <typename Tag, typename BundleT, typename TupleT>
960template <typename U, typename FuncT>
961decltype(auto)
962bundle<Tag, BundleT, TupleT>::get(FuncT&& _func) const
963{
964 auto* _obj = tim::variadic::impl::get<U, Tag>(m_data);
965 if(_obj)
966 return std::forward<FuncT>(_func)(_obj);
967 using return_type = decltype(_func(std::declval<decltype(_obj)>()));
968#if defined(CXX17)
969 if constexpr(std::is_void<decay_t<return_type>>::value)
970 return;
971 else if constexpr(std::is_pointer<decay_t<return_type>>::value)
972 return static_cast<decay_t<return_type>>(nullptr);
973 else
974 return decltype(_func(std::declval<decltype(_obj)>())){};
975#else
976 return return_type();
977#endif
978}
979
980//----------------------------------------------------------------------------------//
981//
982template <typename Tag, typename BundleT, typename TupleT>
983template <typename U>
985 enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
986 is_one_of<remove_pointer_decay_t<U>, data_type>::value,
987 int>)
988{
989 return get<remove_pointer_decay_t<U>>();
990}
991
992//----------------------------------------------------------------------------------//
993//
994template <typename Tag, typename BundleT, typename TupleT>
995template <typename U>
997 enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
998 is_one_of<remove_pointer_decay_t<U>*, data_type>::value,
999 int>)
1000{
1001 return get<remove_pointer_decay_t<U>>();
1002}
1003
1004//----------------------------------------------------------------------------------//
1005//
1006template <typename Tag, typename BundleT, typename TupleT>
1007template <typename U>
1009 enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
1010 is_one_of<remove_pointer_decay_t<U>, data_type>::value,
1011 int>)
1012{
1013 return std::get<index_of<remove_pointer_decay_t<U>, data_type>::value>(m_data);
1014}
1015
1016//----------------------------------------------------------------------------------//
1017//
1018template <typename Tag, typename BundleT, typename TupleT>
1019template <typename U>
1021 enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value &&
1022 is_one_of<remove_pointer_decay_t<U>*, data_type>::value,
1023 int>)
1024{
1025 return std::get<index_of<remove_pointer_decay_t<U>*, data_type>::value>(m_data);
1026}
1027//
1028//----------------------------------------------------------------------------------//
1029//
1030template <typename Tag, typename BundleT, typename TupleT>
1031void
1033{
1034 m_hash = add_hash_id(_key);
1035 set_prefix(_key);
1036}
1037//
1038//----------------------------------------------------------------------------------//
1039//
1040template <typename Tag, typename BundleT, typename TupleT>
1041void
1043{
1044 m_hash = _loc.get_hash();
1045 set_prefix(_loc);
1046}
1047//
1048//----------------------------------------------------------------------------------//
1049//
1050template <typename Tag, typename BundleT, typename TupleT>
1051void
1053{
1054 m_hash = _hash;
1055 set_prefix(_hash);
1056}
1057//
1058//----------------------------------------------------------------------------------//
1059//
1060/*
1061template <typename Tag, typename BundleT, typename TupleT
1062 >
1063class bundle<Tag, BundleT, TransformT<>, std::tuple<Types...>>
1064: public bundle<Tag, BundleT, TupleT>
1065{
1066 TIMEMORY_DEFAULT_OBJECT(bundle)
1067
1068 template <typename... Args>
1069 bundle(Args&&... args)
1070 : bundle<Tag, BundleT, TupleT>{ std::forward<Args>(args)... }
1071 {}
1072};
1073//
1074//----------------------------------------------------------------------------------//
1075//
1076template <typename Tag, typename BundleT, typename TupleT
1077 >
1078class bundle<Tag, BundleT, TransformT<>, type_list<Types...>>
1079: public bundle<Tag, BundleT, TupleT>
1080{
1081 TIMEMORY_DEFAULT_OBJECT(bundle)
1082
1083 template <typename... Args>
1084 bundle(Args&&... args)
1085 : bundle<Tag, BundleT, TupleT>{ std::forward<Args>(args)... }
1086 {}
1087};
1088*/
1089} // namespace tim
1090
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
auto get(Args &&...) const
returns a tuple of invoking get() on all the components
static constexpr bool is_default_constructible()
Query at compile-time whether type supports default construction. If type is not available,...
Definition: bundle.hpp:370
typename TupleT::template data_type< Tag > data_type
Definition: bundle.hpp:153
this_type & record(Args &&...)
requests each component perform a measurement
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:732
typename TupleT::template component_type< BundleT > component_type
Definition: bundle.hpp:152
this_type & start(mpl::lightweight, Args &&...)
variant of start() which excludes push()
typename TupleT::type_list_type type_list_type
Definition: bundle.hpp:154
this_type & reset(Args &&...)
invokes reset member function on all the components
this_type & mark(Args &&... _args)
mark an atomic event
this_type & invoke(mpl::piecewise_select< Tp... >, Args &&... _args)
generic member function for invoking user-provided operations on a specific set of component types
this_type & push(mpl::piecewise_ignore< Tp... >)
selective push
this_type & audit(Args &&... _args)
allow the components to inspect the incoming arguments before start or out-going return value before ...
typename TupleT::template type< BundleT > type
Definition: bundle.hpp:151
auto get_labeled(Args &&...) const
returns a tuple of the component label + invoking get() on all the components
this_type & operator-=(Op &&rhs)
Definition: bundle.hpp:230
tim::variadic::impl::quirk_config< T, reference_type, U... > quirk_config
Definition: bundle.hpp:164
enable_if_t< will_heap_init< T >() &&!will_opaque_init< T >(), bool > init(Args &&... _args, enable_if_t< is_constructible< T, Args... >(), int >=0)
create an optional type that is in variadic list AND is available AND accepts arguments
Definition: bundle.hpp:650
typename bundle_type::size_type size_type
Definition: bundle.hpp:156
this_type & disable()
delete any optional types currently allocated
static constexpr bool can_stack_init()
Query at compile-time whether initialization can occur on the stack.
Definition: bundle.hpp:291
static constexpr bool will_heap_init()
Query at compile-time whether initialization will occur on the heap. can_heap_init<T>() && !...
Definition: bundle.hpp:327
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:691
this_type & mark_end(Args &&... _args)
mark a beginning position in the execution (typically used by asynchronous structures)
this_type & stop(mpl::piecewise_ignore< Tp... >, Args &&...)
variant of stop() which gets applied to non-Tp types
decltype(auto) execute(FuncT &&func, Args &&... args)
when chaining together operations, this function enables executing a function inside the chain
const data_type & get_data() const
Definition: bundle.hpp:829
static constexpr bool will_opaque_init()
Query at compile-time whether initialization will happen with an opaque wrapper (i....
Definition: bundle.hpp:338
this_type & start(Args &&...)
invokes start on all the components
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:755
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:287
friend this_type operator+(this_type lhs, const this_type &rhs)
Definition: bundle.hpp:258
this_type & stop(mpl::piecewise_select< Tp... >, Args &&...)
variant of stop() which only gets applied to Tp types
this_type & sample(Args &&...)
requests each component take a sample (if supported)
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:778
this_type & invoke(mpl::piecewise_ignore< Tp... >, Args &&... _args)
generic member function for invoking user-provided operations on all types that are not listed
this_type & mark_begin(Args &&... _args)
mark a beginning position in the execution (typically used by asynchronous structures)
decltype(auto) get(FuncT &&)
get a component from the bundle and apply function if the pointer is valid
this_type & start(mpl::piecewise_ignore< Tp... >, Args &&...)
variant of start() which gets applied to non-Tp types
this_type & store(Args &&... _args)
store a value
this_type & construct(Args &&... _args)
construct the objects that have constructors with matching arguments
this_type & start(mpl::piecewise_select< Tp... >, Args &&...)
variant of start() which only gets applied to Tp types
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:796
this_type & add_secondary(Args &&... _args)
perform an add_secondary operation. This operation allows components to add additional entries to sto...
this_type & operator*=(Op &&rhs)
Definition: bundle.hpp:244
this_type & push(mpl::piecewise_ignore< Tp... >, scope::config)
selective push with scope configuration
typename bundle_type::string_t string_t
Definition: bundle.hpp:145
typename TupleT::template this_type< BundleT > this_type
Definition: bundle.hpp:150
this_type & assemble(Args &&... _args)
provide preliminary info to the objects with matching arguments. This is typically used to notify a c...
typename TupleT::reference_type reference_type
Definition: bundle.hpp:146
this_type & stop(Args &&...)
invokes stop on all the components
this_type & operator/=(Op &&rhs)
Definition: bundle.hpp:251
this_type & measure(Args &&...)
requests each component record a measurment
static constexpr bool is_this_type()
Query whether type matches this_type.
Definition: bundle.hpp:168
friend this_type operator-(this_type lhs, const this_type &rhs)
Definition: bundle.hpp:259
this_type & invoke(Args &&... _args)
generic member function for invoking user-provided operations
this_type & stop(mpl::lightweight, Args &&...)
variant of stop() which excludes pop()
this_type & derive(Args &&... _args)
provide conclusive info to the objects with matching arguments. This is typically used by components ...
bundle & operator=(bundle &&)=default
decltype(auto) get() const
get a component from the bundle
decltype(auto) get()
get a component from the bundle
static constexpr bool can_heap_init()
Query at compile-time whether initialization can occur on the heap.
Definition: bundle.hpp:299
friend enable_if_t<!std::is_arithmetic< Op >::value, this_type > operator*(this_type lhs, const Op &rhs)
Definition: bundle.hpp:262
static constexpr bool is_constructible()
Query at compile-time whether type can be constructed with the given argument types....
Definition: bundle.hpp:351
this_type & print(std::ostream &os, bool _endl=false) const
this_type & type_apply(Func &&, Args &&...)
ignore applying a member function because the type is not present
static constexpr bool can_init()
Query at compile-time whether the specified type can be initialized.
Definition: bundle.hpp:316
this_type & operator+=(Op &&rhs)
Definition: bundle.hpp:237
this_type & update_statistics(Args &&... _args)
perform an add_secondary operation. This operation allows components to add additional entries to sto...
this_type & push(mpl::piecewise_select< Tp... >, scope::config)
selective push with scope configuration
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:309
std::function< void(this_type &)> initializer_type
Definition: bundle.hpp:157
this_type & pop(mpl::piecewise_ignore< Tp... >)
selective pop
this_type & push(mpl::piecewise_select< Tp... >)
selective push
this_type & pop(mpl::piecewise_select< Tp... >)
selective pop
friend enable_if_t<!std::is_arithmetic< Op >::value, this_type > operator/(this_type lhs, const Op &rhs)
Definition: bundle.hpp:269
decltype(auto) get(FuncT &&) const
get a component from the bundle
friend std::ostream & operator<<(std::ostream &os, const bundle &obj)
Definition: bundle.hpp:275
#define IF_CONSTEXPR(...)
Definition: language.hpp:72
std::string string_t
Definition: library.cpp:57
void serialize(std::string fname, exec_data< Counter > &obj)
Definition: counter.hpp:325
hash_value_t add_hash_id(hash_map_ptr_t &_hash_map, string_view_cref_t _prefix)
add an string to the given hash-map (if it doesn't already exist) and return the hash
Definition: types.hpp:190
size_t hash_value_t
Definition: types.hpp:84
void set_scope(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:810
void set_prefix(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:774
void store(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:564
void pop(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:739
void push(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:704
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
std::bitset< scope_count > data_type
Definition: types.hpp:399
std::array< Tp, N > & operator+=(std::array< Tp, N > &, Other &&)
std::array< Tp, N > & operator-=(std::array< Tp, N > &, const std::array< Tp, N > &)
Definition: stl.hpp:96
A light-weight alternative to std::function. Pass any callback - including capturing lambdas - cheapl...
Definition: kokkosp.cpp:39
std::array< char *, 4 > _args
std::string string_t
Definition: utility.hpp:98
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
tim::mpl::apply< std::string > string
Definition: macros.hpp:53
const std::string std::ostream * os
typename impl::is_one_of< Tp, Types > is_one_of
check if type is in expansion
Definition: types.hpp:777
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:453
const hash_value_t & get_hash() const
trait that signifies that an implementation for the component is available. When this is set to false...
Definition: types.hpp:355
trait that designates the type is a user-bundle