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.
components.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
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 all
15 // 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  * \file timemory/components/data_tracker/components.hpp
27  * \brief Implementation of the data_tracker component(s)
28  */
29 
30 #pragma once
31 
36 #include "timemory/mpl/types.hpp"
38 #include "timemory/units.hpp"
39 
40 #if defined(TIMEMORY_PYBIND11_SOURCE)
41 # include "pybind11/cast.h"
42 # include "pybind11/pybind11.h"
43 # include "pybind11/stl.h"
44 #endif
45 
46 #include <cassert>
47 #include <cstdint>
48 #include <limits>
49 #include <memory>
50 #include <sstream>
51 #include <string>
52 #include <type_traits>
53 #include <unordered_map>
54 #include <utility>
55 
56 //======================================================================================//
57 //
58 namespace tim
59 {
60 namespace component
61 {
62 /// \struct tim::component::data_tracker
63 /// \brief This component is provided to facilitate data tracking. The first
64 /// template parameter is the type of data to be tracked, the second is a custom tag
65 /// for differentiating trackers which handle the same data types but record
66 /// different high-level data.
67 ///
68 /// Usage:
69 /// \code{.cpp}
70 /// // declarations
71 ///
72 /// struct myproject {};
73 ///
74 /// using itr_tracker_type = data_tracker<uint64_t, myproject>;
75 /// using err_tracker_type = data_tracker<double, myproject>;
76 ///
77 /// // add statistics capabilities
78 /// TIMEMORY_STATISTICS_TYPE(itr_tracker_type, int64_t)
79 /// TIMEMORY_STATISTICS_TYPE(err_tracker_type, double)
80 ///
81 /// // set the label and descriptions
82 /// TIMEMORY_METADATA_SPECIALIZATION(
83 /// itr_tracker_type, "myproject_iterations", "short desc", "long description")
84 ///
85 /// TIMEMORY_METADATA_SPECIALIZATION(
86 /// err_tracker_type, "myproject_convergence", "short desc", "long description")
87 ///
88 /// // this is the generic bundle pairing a timer with an iteration tracker
89 /// // using this and not updating the iteration tracker will create entries
90 /// // in the call-graph with zero iterations.
91 /// using bundle_t = tim::auto_tuple<wall_clock, itr_tracker_type>;
92 ///
93 /// // this is a dedicated bundle for adding data-tracker entries. This style
94 /// // can also be used with the iteration tracker or you can bundle
95 /// // both trackers together. The auto_tuple will call start on construction
96 /// // and stop on destruction so once can construct a nameless temporary of the
97 /// // this bundle type and call store(...) on the nameless tmp. This will
98 /// // ensure that the statistics are updated for each entry
99 /// //
100 /// using err_bundle_t = tim::auto_tuple<err_tracker_type>;
101 ///
102 /// // usage in a function is implied below
103 ///
104 /// double err = std::numeric_limits<double>::max();
105 /// const double tolerance = 1.0e-6;
106 ///
107 /// bundle_t t("iteration_time");
108 ///
109 /// while(err > tolerance)
110 /// {
111 /// // store the starting error
112 /// double initial_err = err;
113 ///
114 /// // add 1 for each iteration. Stats only updated when t is destroyed or t.stop() is
115 /// // called t.store(std::plus<uint64_t>{}, 1);
116 ///
117 /// // ... do something ...
118 ///
119 /// // construct a nameless temporary which records the change in the error and
120 /// // update the statistics <-- "foo" will have mean/min/max/stddev of the
121 /// // error
122 /// err_bundle_t{ "foo" }.store(err - initial_err);
123 ///
124 /// // NOTE: std::plus is used with t above bc it has multiple components so std::plus
125 /// // helps ensure 1 doesn't get added to some other component with `store(int)`
126 /// // In above err_bundle_t, there is only one component so there is not concern.
127 /// }
128 /// \endcode
129 ///
130 /// When creating new data trackers, it is recommended to have this in header:
131 ///
132 /// \code{.cpp}
133 /// TIMEMORY_DECLARE_EXTERN_COMPONENT(custom_data_tracker_t, true, data_type)
134 /// \endcode
135 ///
136 /// And this in *one* source file (preferably one that is not re-compiled often)
137 ///
138 /// \code{.cpp}
139 /// TIMEMORY_INSTANTIATE_EXTERN_COMPONENT(custom_data_tracker_t, true, data_type)
140 /// TIMEMORY_INITIALIZE_STORAGE(custom_data_tracker_t)
141 /// \endcode
142 ///
143 /// where `custom_data_tracker_t` is the custom data tracker type (or an alias to the
144 /// type) and `data_type` is the data type being tracked.
145 ///
146 template <typename InpT, typename Tag>
147 struct data_tracker : public base<data_tracker<InpT, Tag>, InpT>
148 {
149  using value_type = InpT;
153 
154  friend struct data::handler<InpT, Tag>;
155  friend struct operation::record<this_type>;
156  friend struct operation::start<this_type>;
157  friend struct operation::stop<this_type>;
158  friend struct operation::set_started<this_type>;
159  friend struct operation::set_stopped<this_type>;
160 
161 private:
162  // private aliases
163  template <typename T, typename U = int>
164  using enable_if_acceptable_t =
166 
167  template <typename FuncT, typename T, typename U = int>
168  using enable_if_acceptable_and_func_t =
170  std::is_function<FuncT>::value,
171  U>;
172 
173  using value_ptr_t = std::shared_ptr<value_type>;
174  using secondary_map_t = std::unordered_map<std::string, this_type>;
175  using secondary_ptr_t = std::shared_ptr<secondary_map_t>;
176  using start_t =
178  using stop_t =
181 
182 public:
183  //----------------------------------------------------------------------------------//
184  //
185  // standard interface
186  //
187  //----------------------------------------------------------------------------------//
188  /// a reference is returned here so that it can be easily updated
189  static std::string& label();
190 
191  /// a reference is returned here so that it can be easily updated
192  static std::string& description();
193 
194  /// this returns a reference so that it can be easily modified
195  static auto& get_unit()
196  {
197  static auto _unit = base_type::get_unit();
198  return _unit;
199  }
200 
201  // default set of ctor and assign
202  TIMEMORY_DEFAULT_OBJECT(data_tracker)
203 
204  void start() {}
205  void stop() {}
206 
207  /// get the data in the final form after unit conversion
208  TIMEMORY_NODISCARD auto get() const { return handler_type::get(*this); }
209 
210  /// get the data in a form suitable for display
211  TIMEMORY_NODISCARD auto get_display() const
212  {
213  return handler_type::get_display(*this);
214  }
215 
216  /// map of the secondary entries. When TIMEMORY_ADD_SECONDARY is enabled
217  /// contents of this map will be added as direct children of the current
218  /// node in the call-graph.
219  auto get_secondary() const
220  {
221  return (m_secondary) ? *m_secondary : secondary_map_t{};
222  }
223 
230  using base_type::get_value;
231  using base_type::laps;
232  using base_type::load;
233 
234  //----------------------------------------------------------------------------------//
235  //
236  // store
237  //
238  //----------------------------------------------------------------------------------//
239  /// store some data. Uses \ref tim::data::handler for the type.
240  template <typename T>
241  void store(T&& val, enable_if_acceptable_t<T, int> = 0);
242 
243  /// overload which takes a handler to ensure proper overload resolution
244  template <typename T>
245  void store(handler_type&&, T&& val, enable_if_acceptable_t<T, int> = 0);
246 
247  /// overload which uses a lambda to bypass the default behavior of how the
248  /// handler updates the values
249  template <typename FuncT, typename T>
250  auto store(FuncT&& f, T&& val, enable_if_acceptable_t<T, int> = 0)
251  -> decltype(std::declval<handler_type>().store(*this, std::forward<FuncT>(f),
252  std::forward<T>(val)),
253  void());
254 
255  /// overload which uses a lambda to bypass the default behavior of how the
256  /// handler updates the values and takes a handler to ensure proper overload
257  /// resolution
258  template <typename FuncT, typename T>
259  auto store(handler_type&&, FuncT&& f, T&& val, enable_if_acceptable_t<T, int> = 0)
260  -> decltype(std::declval<handler_type>().store(*this, std::forward<FuncT>(f),
261  std::forward<T>(val)),
262  void());
263 
264  //----------------------------------------------------------------------------------//
265  //
266  // mark begin
267  //
268  //----------------------------------------------------------------------------------//
269  /// The combination of `mark_begin(...)` and `mark_end(...)` can be used to
270  /// store some initial data which may be needed later. When `mark_end(...)` is
271  /// called, the value is updated with the difference of the value provided to
272  /// `mark_end` and the temporary stored during `mark_begin`.
273  template <typename T>
274  void mark_begin(T&& val, enable_if_acceptable_t<T, int> = 0);
275 
276  /// overload which takes a handler to ensure proper overload resolution
277  template <typename T>
278  void mark_begin(handler_type&&, T&& val, enable_if_acceptable_t<T, int> = 0);
279 
280  /// overload which uses a lambda to bypass the default behavior of how the
281  /// handler updates the values
282  template <typename FuncT, typename T>
283  void mark_begin(FuncT&& f, T&& val, enable_if_acceptable_t<T, int> = 0);
284 
285  /// overload which uses a lambda to bypass the default behavior of how the
286  /// handler updates the values and takes a handler to ensure proper
287  /// overload resolution
288  template <typename FuncT, typename T>
289  void mark_begin(handler_type&&, FuncT&& f, T&& val,
290  enable_if_acceptable_t<T, int> = 0);
291 
292  //----------------------------------------------------------------------------------//
293  //
294  // mark end
295  //
296  //----------------------------------------------------------------------------------//
297  /// The combination of `mark_begin(...)` and `mark_end(...)` can be used to
298  /// store some initial data which may be needed later. When `mark_end(...)` is
299  /// called, the value is updated with the difference of the value provided to
300  /// `mark_end` and the temporary stored during `mark_begin`. It may be valid
301  /// to call `mark_end` without calling `mark_begin` but the result will effectively
302  /// be a more expensive version of calling `store`.
303  template <typename T>
304  void mark_end(T&& val, enable_if_acceptable_t<T, int> = 0);
305 
306  /// overload which takes a handler to ensure proper overload resolution
307  template <typename T>
308  void mark_end(handler_type&&, T&& val, enable_if_acceptable_t<T, int> = 0);
309 
310  /// overload which uses a lambda to bypass the default behavior of how the
311  /// handler updates the values
312  template <typename FuncT, typename T>
313  void mark_end(FuncT&& f, T&& val, enable_if_acceptable_t<T, int> = 0);
314 
315  /// overload which uses a lambda to bypass the default behavior of how the
316  /// handler updates the values and takes a handler to ensure proper
317  /// overload resolution
318  template <typename FuncT, typename T>
319  void mark_end(handler_type&&, FuncT&& f, T&& val, enable_if_acceptable_t<T, int> = 0);
320 
321  //----------------------------------------------------------------------------------//
322  //
323  // add secondary
324  //
325  //----------------------------------------------------------------------------------//
326  /// add a secondary value to the current node in the call-graph.
327  /// When TIMEMORY_ADD_SECONDARY is enabled contents of this map will be added as
328  /// direct children of the current node in the call-graph. This is useful
329  /// for finer-grained details that might not always be desirable to display
330  template <typename T>
331  this_type* add_secondary(const std::string& _key, T&& val,
332  enable_if_acceptable_t<T, int> = 0);
333 
334  /// overload which takes a handler to ensure proper overload resolution
335  template <typename T>
336  this_type* add_secondary(const std::string& _key, handler_type&& h, T&& val,
337  enable_if_acceptable_t<T, int> = 0);
338 
339  /// overload which uses a lambda to bypass the default behavior of how the
340  /// handler updates the values
341  template <typename FuncT, typename T>
342  this_type* add_secondary(const std::string& _key, FuncT&& f, T&& val,
343  enable_if_acceptable_and_func_t<FuncT, T, int> = 0);
344 
345  /// overload which uses a lambda to bypass the default behavior of how the
346  /// handler updates the values and takes a handler to ensure proper
347  /// overload resolution
348  template <typename FuncT, typename T>
349  this_type* add_secondary(const std::string& _key, handler_type&& h, FuncT&& f,
350  T&& val, enable_if_acceptable_and_func_t<FuncT, T, int> = 0);
351 
352  //----------------------------------------------------------------------------------//
353  //
354  // non-standard interface
355  //
356  //----------------------------------------------------------------------------------//
357 
358  /// set the current value
359  void set_value(const value_type& v) { value = v; }
360 
361  /// set the current value via move
362  void set_value(value_type&& v) { value = std::move(v); }
363 
364  using base_type::value;
365 
366 private:
367  /// map of the secondary entries. When TIMEMORY_ADD_SECONDARY is enabled
368  /// contents of this map will be added as direct children of the current
369  /// node in the call-graph
370  auto get_secondary_map()
371  {
372  if(!m_secondary)
373  m_secondary = std::make_shared<secondary_map_t>();
374  return m_secondary;
375  }
376 
377  void allocate_temporary() const
378  {
379  if(!m_last)
380  const_cast<this_type*>(this)->m_last = std::make_shared<value_type>();
381  }
382 
383  value_type& get_temporary() { return (allocate_temporary(), *m_last); }
384  const value_type& get_temporary() const { return (allocate_temporary(), *m_last); }
385 
386 private:
387  value_ptr_t m_last{ nullptr };
388  secondary_ptr_t m_secondary{ nullptr };
389 };
390 //
391 /// \typedef typename T::handler_type tim::component::data_handler_t
392 /// \brief an alias for getting the handle_type of a data tracker
393 template <typename T>
394 using data_handler_t = typename T::handler_type;
395 //
396 /// \typedef tim::component::data_tracker<intmax_t, TIMEMORY_API>
397 /// tim::component::data_tracker_integer
398 ///
399 /// \brief Specialization of \ref tim::component::data_tracker for storing signed integer
400 /// data
402 //
403 /// \typedef tim::component::data_tracker<size_t, TIMEMORY_API>
404 /// tim::component::data_tracker_unsigned
405 ///
406 /// \brief Specialization of \ref tim::component::data_tracker for storing unsigned
407 /// integer data
409 //
410 /// \typedef tim::component::data_tracker<double, TIMEMORY_API>
411 /// tim::component::data_tracker_floating
412 ///
413 /// \brief Specialization of \ref tim::component::data_tracker for storing floating point
414 /// data
416 //
417 //
418 template <typename InpT, typename Tag>
419 inline std::string&
421 {
422  static std::string _instance = []() {
425  return TIMEMORY_JOIN("_", typeid(Tag).name(), typeid(InpT).name());
426  }();
427  return _instance;
428 }
429 //
430 template <typename InpT, typename Tag>
433 {
434  static std::string _instance = []() {
436  {
437  auto meta_desc = metadata<this_type>::description();
438  if(settings::verbose() > 0 || settings::debug())
439  {
440  auto meta_extra_desc = metadata<this_type>::extra_description();
441  meta_desc += ". ";
442  meta_desc += meta_extra_desc;
443  }
444  return meta_desc;
445  }
446  std::stringstream ss;
447  ss << "Data tracker for data of type " << demangle<InpT>() << " for "
448  << demangle<Tag>();
449  return ss.str();
450  }();
451  return _instance;
452 }
453 //
454 template <typename InpT, typename Tag>
455 template <typename T>
456 void
457 data_tracker<InpT, Tag>::store(T&& val, enable_if_acceptable_t<T, int>)
458 {
459  handler_type::store(*this, compute_type::divide(std::forward<T>(val), get_unit()));
460  if(!get_is_running())
461  ++laps;
462 }
463 //
464 template <typename InpT, typename Tag>
465 template <typename T>
466 void
467 data_tracker<InpT, Tag>::store(handler_type&&, T&& val, enable_if_acceptable_t<T, int>)
468 {
469  handler_type::store(*this, compute_type::divide(std::forward<T>(val), get_unit()));
470  if(!get_is_running())
471  ++laps;
472 }
473 //
474 template <typename InpT, typename Tag>
475 template <typename FuncT, typename T>
476 auto
477 data_tracker<InpT, Tag>::store(FuncT&& f, T&& val, enable_if_acceptable_t<T, int>)
478  -> decltype(std::declval<handler_type>().store(*this, std::forward<FuncT>(f),
479  std::forward<T>(val)),
480  void())
481 {
482  handler_type::store(*this, std::forward<FuncT>(f),
483  compute_type::divide(std::forward<T>(val), get_unit()));
484  if(!get_is_running())
485  ++laps;
486 }
487 //
488 template <typename InpT, typename Tag>
489 template <typename FuncT, typename T>
490 auto
492  enable_if_acceptable_t<T, int>)
493  -> decltype(std::declval<handler_type>().store(*this, std::forward<FuncT>(f),
494  std::forward<T>(val)),
495  void())
496 {
497  handler_type::store(*this, std::forward<FuncT>(f),
498  compute_type::divide(std::forward<T>(val), get_unit()));
499  if(!get_is_running())
500  ++laps;
501 }
502 //
503 template <typename InpT, typename Tag>
504 template <typename T>
505 void
506 data_tracker<InpT, Tag>::mark_begin(T&& val, enable_if_acceptable_t<T, int>)
507 {
508  handler_type::begin(get_temporary(),
509  compute_type::divide(std::forward<T>(val), get_unit()));
510 }
511 //
512 template <typename InpT, typename Tag>
513 template <typename T>
514 void
515 data_tracker<InpT, Tag>::mark_end(T&& val, enable_if_acceptable_t<T, int>)
516 {
517  handler_type::end(*this, compute_type::divide(std::forward<T>(val), get_unit()));
518  if(!get_is_running())
519  ++laps;
520 }
521 //
522 template <typename InpT, typename Tag>
523 template <typename T>
524 void
526  enable_if_acceptable_t<T, int>)
527 {
528  handler_type::begin(get_temporary(),
529  compute_type::divide(std::forward<T>(val), get_unit()));
530 }
531 //
532 template <typename InpT, typename Tag>
533 template <typename T>
534 void
535 data_tracker<InpT, Tag>::mark_end(handler_type&&, T&& val, enable_if_acceptable_t<T, int>)
536 {
537  handler_type::end(*this, compute_type::divide(std::forward<T>(val), get_unit()));
538  if(!get_is_running())
539  ++laps;
540 }
541 //
542 template <typename InpT, typename Tag>
543 template <typename FuncT, typename T>
544 void
545 data_tracker<InpT, Tag>::mark_begin(FuncT&& f, T&& val, enable_if_acceptable_t<T, int>)
546 {
547  handler_type::begin(get_temporary(), std::forward<FuncT>(f),
548  compute_type::divide(std::forward<T>(val), get_unit()));
549 }
550 //
551 template <typename InpT, typename Tag>
552 template <typename FuncT, typename T>
553 void
554 data_tracker<InpT, Tag>::mark_end(FuncT&& f, T&& val, enable_if_acceptable_t<T, int>)
555 {
556  handler_type::end(*this, std::forward<FuncT>(f),
557  compute_type::divide(std::forward<T>(val), get_unit()));
558  if(!get_is_running())
559  ++laps;
560 }
561 //
562 template <typename InpT, typename Tag>
563 template <typename FuncT, typename T>
564 void
566  enable_if_acceptable_t<T, int>)
567 {
568  handler_type::begin(get_temporary(), std::forward<FuncT>(f),
569  compute_type::divide(std::forward<T>(val), get_unit()));
570 }
571 //
572 template <typename InpT, typename Tag>
573 template <typename FuncT, typename T>
574 void
576  enable_if_acceptable_t<T, int>)
577 {
578  handler_type::end(*this, std::forward<FuncT>(f),
579  compute_type::divide(std::forward<T>(val), get_unit()));
580  if(!get_is_running())
581  ++laps;
582 }
583 //
584 template <typename InpT, typename Tag>
585 template <typename T>
588  enable_if_acceptable_t<T, int>)
589 {
590  this_type _tmp;
591  start_t _start(_tmp);
592  _tmp.store(std::forward<T>(val));
593  stop_t _stop(_tmp);
594  auto& _map = *get_secondary_map();
595  _map.insert({ _key, _tmp });
596  return &(_map[_key]);
597 }
598 //
599 template <typename InpT, typename Tag>
600 template <typename T>
603  enable_if_acceptable_t<T, int>)
604 {
605  this_type _tmp;
606  start_t _start(_tmp);
607  _tmp.store(std::forward<handler_type>(h), std::forward<T>(val));
608  stop_t _stop(_tmp);
609  auto& _map = *get_secondary_map();
610  _map.insert({ _key, _tmp });
611  return &(_map[_key]);
612 }
613 //
614 template <typename InpT, typename Tag>
615 template <typename FuncT, typename T>
617 data_tracker<InpT, Tag>::add_secondary(const std::string& _key, FuncT&& f, T&& val,
618  enable_if_acceptable_and_func_t<FuncT, T, int>)
619 {
620  this_type _tmp;
621  start_t _start(_tmp);
622  _tmp.store(std::forward<FuncT>(f), std::forward<T>(val));
623  stop_t _stop(_tmp);
624  auto& _map = *get_secondary_map();
625  _map.insert({ _key, _tmp });
626  return &(_map[_key]);
627 }
628 //
629 template <typename InpT, typename Tag>
630 template <typename FuncT, typename T>
633  FuncT&& f, T&& val,
634  enable_if_acceptable_and_func_t<FuncT, T, int>)
635 {
636  this_type _tmp;
637  start_t _start(_tmp);
638  _tmp.store(std::forward<handler_type>(h), std::forward<FuncT>(f),
639  std::forward<T>(val));
640  stop_t _stop(_tmp);
641  auto& _map = *get_secondary_map();
642  _map.insert({ _key, _tmp });
643  return &(_map[_key]);
644 }
645 //
646 } // namespace component
647 } // namespace tim
648 //
649 //======================================================================================//
typename T::handler_type data_handler_t
an alias for getting the handle_type of a data tracker
Definition: components.hpp:394
typename std::enable_if< B, T >::type enable_if_t
Definition: types.hpp:58
void store(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:546
Tp & divide(Tp &, const Up &)
Definition: math.hpp:858
Definition: kokkosp.cpp:38
tim::mpl::apply< std::string > string
Definition: macros.hpp:52
The declaration for the types for settings without definitions.
decltype(auto) load()
bool get_is_flat() const
Definition: data.hpp:458
auto get_iterator() const
bool get_depth_change() const
Definition: data.hpp:459
static int64_t get_unit()
bool get_is_on_stack() const
Definition: data.hpp:456
bool get_is_transient() const
Definition: data.hpp:457
bool get_is_running() const
Definition: data.hpp:455
This component is provided to facilitate data tracking. The first template parameter is the type of d...
Definition: components.hpp:148
auto get() const
get the data in the final form after unit conversion
Definition: components.hpp:208
static auto & get_unit()
this returns a reference so that it can be easily modified
Definition: components.hpp:195
this_type * add_secondary(const std::string &_key, T &&val, enable_if_acceptable_t< T, int >=0)
add a secondary value to the current node in the call-graph. When TIMEMORY_ADD_SECONDARY is enabled c...
void mark_begin(T &&val, enable_if_acceptable_t< T, int >=0)
The combination of mark_begin(...) and mark_end(...) can be used to store some initial data which may...
Definition: components.hpp:506
auto get_display() const
get the data in a form suitable for display
Definition: components.hpp:211
static std::string & label()
a reference is returned here so that it can be easily updated
Definition: components.hpp:420
void mark_end(T &&val, enable_if_acceptable_t< T, int >=0)
The combination of mark_begin(...) and mark_end(...) can be used to store some initial data which may...
Definition: components.hpp:515
this_type * add_secondary(const std::string &_key, handler_type &&h, T &&val, enable_if_acceptable_t< T, int >=0)
overload which takes a handler to ensure proper overload resolution
data::handler< InpT, Tag > handler_type
Definition: components.hpp:152
this_type * add_secondary(const std::string &_key, handler_type &&h, FuncT &&f, T &&val, enable_if_acceptable_and_func_t< FuncT, T, int >=0)
overload which uses a lambda to bypass the default behavior of how the handler updates the values and...
static std::string & description()
a reference is returned here so that it can be easily updated
Definition: components.hpp:432
void set_value(const value_type &v)
set the current value
Definition: components.hpp:359
this_type * add_secondary(const std::string &_key, FuncT &&f, T &&val, enable_if_acceptable_and_func_t< FuncT, T, int >=0)
overload which uses a lambda to bypass the default behavior of how the handler updates the values
auto get_secondary() const
map of the secondary entries. When TIMEMORY_ADD_SECONDARY is enabled contents of this map will be add...
Definition: components.hpp:219
data_tracker< InpT, Tag > this_type
Definition: components.hpp:150
void store(T &&val, enable_if_acceptable_t< T, int >=0)
store some data. Uses tim::data::handler for the type.
Definition: components.hpp:457
void set_value(value_type &&v)
set the current value via move
Definition: components.hpp:362
Provides forward declaration support for assigning static metadata properties. This is most useful fo...
Definition: metadata.hpp:44
static std::string extra_description()
Definition: metadata.hpp:51
static std::string description()
Definition: metadata.hpp:77
static decltype(auto) get_display(const T &obj)
this function is returns the current value in a form suitable for display. It may be necessary to spe...
Definition: handler.hpp:68
static decltype(auto) get(const T &obj)
this function is returns the current value
Definition: handler.hpp:60
Struct for performing math operations on complex data structures without using globally overload oper...
Definition: math.hpp:967
This operation class is similar to pointer_operator but can handle non-pointer types.
Definition: generic.hpp:55
This operation attempts to call a member function which the component provides to internally store wh...
Definition: types.hpp:472
This operation attempts to call a member function which the component provides to internally store wh...
Definition: types.hpp:505
#define TIMEMORY_JOIN(delim,...)
Definition: macros.hpp:89