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.
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
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//
58namespace tim
59{
60namespace 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///
146template <typename InpT, typename Tag>
147struct 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 // a pair
162 template <typename LhsT, typename RhsT, typename HashT = std::hash<LhsT>>
163 class vector_map : public std::vector<std::pair<LhsT, RhsT>>
164 {
165 public:
166 using value_type = std::pair<LhsT, RhsT>;
167 using base_type = std::vector<value_type>;
168 using iterator = typename base_type::iterator;
169 using const_iterator = typename base_type::const_iterator;
170 using hash_type = HashT;
171 using key_type = LhsT;
172 using mapped_type = RhsT;
173
174 template <typename... Args>
175 vector_map(Args&&... args)
176 : base_type{ std::forward<Args>(args)... }
177 {}
178
179 template <typename... Args>
180 std::pair<iterator, bool> emplace(Args&&... args)
181 {
182 return { base_type::emplace(base_type::end(), std::forward<Args>(args)...),
183 true };
184 }
185
186 iterator find(const key_type& _key)
187 {
188 auto _hkey = hash_type{}(_key);
189 for(auto itr = base_type::begin(); itr != base_type::end(); ++itr)
190 {
191 if(hash_type{}(itr->first) == _hkey)
192 return itr;
193 }
194 return base_type::end();
195 }
196
197 const_iterator find(const key_type& _key) const
198 {
199 auto _hkey = hash_type{}(_key);
200 for(auto itr = base_type::begin(); itr != base_type::end(); ++itr)
201 {
202 if(hash_type{}(itr->first) == _hkey)
203 return itr;
204 }
205 return base_type::end();
206 }
207
208 mapped_type& operator[](const key_type& _key) { return find(_key)->second; }
209 };
210
211private:
212 // private aliases
213 template <typename T, typename U = int>
214 using enable_if_acceptable_t =
216
217 using value_ptr_t = std::shared_ptr<value_type>;
218 using secondary_map_t = vector_map<std::string, this_type>;
219 using secondary_ptr_t = std::shared_ptr<secondary_map_t>;
220 using start_t =
222 using stop_t =
225
226public:
227 //----------------------------------------------------------------------------------//
228 //
229 // standard interface
230 //
231 //----------------------------------------------------------------------------------//
232 /// a reference is returned here so that it can be easily updated
233 static std::string& label();
234
235 /// a reference is returned here so that it can be easily updated
236 static std::string& description();
237
238 /// this returns a reference so that it can be easily modified
239 static auto& get_unit()
240 {
241 static auto _unit = base_type::get_unit();
242 return _unit;
243 }
244
245 // default set of ctor and assign
246 TIMEMORY_DEFAULT_OBJECT(data_tracker)
247
248 void start() {}
249 void stop() {}
250
251 /// get the data in the final form after unit conversion
252 auto get() const { return handler_type::get(*this); }
253
254 /// get the data in a form suitable for display
255 auto get_display() const { return handler_type::get_display(*this); }
256
257 /// map of the secondary entries. When TIMEMORY_ADD_SECONDARY is enabled
258 /// contents of this map will be added as direct children of the current
259 /// node in the call-graph.
260 auto get_secondary() const
261 {
262 return (m_secondary) ? *m_secondary : secondary_map_t{};
263 }
264
271 using base_type::get_value;
272 using base_type::laps;
273 using base_type::load;
274
275 //----------------------------------------------------------------------------------//
276 //
277 // store
278 //
279 //----------------------------------------------------------------------------------//
280 /// store some data. Uses \ref tim::data::handler for the type.
281 template <typename T>
282 void store(T&& val, enable_if_acceptable_t<T, int> = 0);
283
284 /// overload which takes a handler to ensure proper overload resolution
285 template <typename T>
286 void store(handler_type&&, T&& val, enable_if_acceptable_t<T, int> = 0);
287
288 /// overload which uses a lambda to bypass the default behavior of how the
289 /// handler updates the values
290 template <typename FuncT, typename T>
291 auto store(FuncT&& f, T&& val, enable_if_acceptable_t<T, int> = 0)
292 -> decltype(std::declval<handler_type>().store(*this, std::forward<FuncT>(f),
293 std::forward<T>(val)),
294 void());
295
296 /// overload which uses a lambda to bypass the default behavior of how the
297 /// handler updates the values and takes a handler to ensure proper overload
298 /// resolution
299 template <typename FuncT, typename T>
300 auto store(handler_type&&, FuncT&& f, T&& val, enable_if_acceptable_t<T, int> = 0)
301 -> decltype(std::declval<handler_type>().store(*this, std::forward<FuncT>(f),
302 std::forward<T>(val)),
303 void());
304
305 //----------------------------------------------------------------------------------//
306 //
307 // mark begin
308 //
309 //----------------------------------------------------------------------------------//
310 /// The combination of `mark_begin(...)` and `mark_end(...)` can be used to
311 /// store some initial data which may be needed later. When `mark_end(...)` is
312 /// called, the value is updated with the difference of the value provided to
313 /// `mark_end` and the temporary stored during `mark_begin`.
314 template <typename T>
315 void mark_begin(T&& val, enable_if_acceptable_t<T, int> = 0);
316
317 /// overload which takes a handler to ensure proper overload resolution
318 template <typename T>
319 void mark_begin(handler_type&&, T&& val, enable_if_acceptable_t<T, int> = 0);
320
321 /// overload which uses a lambda to bypass the default behavior of how the
322 /// handler updates the values
323 template <typename FuncT, typename T>
324 void mark_begin(FuncT&& f, T&& val, enable_if_acceptable_t<T, int> = 0);
325
326 /// overload which uses a lambda to bypass the default behavior of how the
327 /// handler updates the values and takes a handler to ensure proper
328 /// overload resolution
329 template <typename FuncT, typename T>
330 void mark_begin(handler_type&&, FuncT&& f, T&& val,
331 enable_if_acceptable_t<T, int> = 0);
332
333 //----------------------------------------------------------------------------------//
334 //
335 // mark end
336 //
337 //----------------------------------------------------------------------------------//
338 /// The combination of `mark_begin(...)` and `mark_end(...)` can be used to
339 /// store some initial data which may be needed later. When `mark_end(...)` is
340 /// called, the value is updated with the difference of the value provided to
341 /// `mark_end` and the temporary stored during `mark_begin`. It may be valid
342 /// to call `mark_end` without calling `mark_begin` but the result will effectively
343 /// be a more expensive version of calling `store`.
344 template <typename T>
345 void mark_end(T&& val, enable_if_acceptable_t<T, int> = 0);
346
347 /// overload which takes a handler to ensure proper overload resolution
348 template <typename T>
349 void mark_end(handler_type&&, T&& val, enable_if_acceptable_t<T, int> = 0);
350
351 /// overload which uses a lambda to bypass the default behavior of how the
352 /// handler updates the values
353 template <typename FuncT, typename T>
354 void mark_end(FuncT&& f, T&& val, enable_if_acceptable_t<T, int> = 0);
355
356 /// overload which uses a lambda to bypass the default behavior of how the
357 /// handler updates the values and takes a handler to ensure proper
358 /// overload resolution
359 template <typename FuncT, typename T>
360 void mark_end(handler_type&&, FuncT&& f, T&& val, enable_if_acceptable_t<T, int> = 0);
361
362 //----------------------------------------------------------------------------------//
363 //
364 // add secondary
365 //
366 //----------------------------------------------------------------------------------//
367 /// add a secondary value to the current node in the call-graph.
368 /// When TIMEMORY_ADD_SECONDARY is enabled contents of this map will be added as
369 /// direct children of the current node in the call-graph. This is useful
370 /// for finer-grained details that might not always be desirable to display
371 template <typename T>
372 this_type* add_secondary(const std::string& _key, T&& val,
373 enable_if_acceptable_t<T, int> = 0);
374
375 /// overload which takes a handler to ensure proper overload resolution
376 template <typename T>
378 enable_if_acceptable_t<T, int> = 0);
379
380 /// overload which uses a lambda to bypass the default behavior of how the
381 /// handler updates the values
382 template <typename FuncT, typename T>
383 this_type* add_secondary(const std::string& _key, FuncT&& f, T&& val,
384 enable_if_acceptable_t<T, int> = 0);
385
386 /// overload which uses a lambda to bypass the default behavior of how the
387 /// handler updates the values and takes a handler to ensure proper
388 /// overload resolution
389 template <typename FuncT, typename T>
390 this_type* add_secondary(const std::string& _key, handler_type&& h, FuncT&& f,
391 T&& val, enable_if_acceptable_t<T, int> = 0);
392
393 //----------------------------------------------------------------------------------//
394 //
395 // non-standard interface
396 //
397 //----------------------------------------------------------------------------------//
398
399 /// set the current value
400 void set_value(const value_type& v) { value = v; }
401
402 /// set the current value via move
403 void set_value(value_type&& v) { value = std::move(v); }
404
405 using base_type::value;
406
407 void set_last(value_type&& _v) { m_last_value = std::move(_v); }
408 void set_last(value_type& _v) { m_last_value = _v; }
409 value_type get_last() const { return m_last_value; }
410
411private:
412 /// map of the secondary entries. When TIMEMORY_ADD_SECONDARY is enabled
413 /// contents of this map will be added as direct children of the current
414 /// node in the call-graph
415 auto get_secondary_map()
416 {
417 if(!m_secondary)
418 m_secondary = std::make_shared<secondary_map_t>();
419 return m_secondary;
420 }
421
422 void allocate_temporary() const
423 {
424 if(!m_last)
425 m_last = std::make_shared<value_type>();
426 }
427
428 value_type& get_temporary() { return (allocate_temporary(), *m_last); }
429 const value_type& get_temporary() const { return (allocate_temporary(), *m_last); }
430
431private:
432 mutable value_ptr_t m_last{ nullptr };
433 secondary_ptr_t m_secondary{ nullptr };
434 value_type m_last_value{};
435};
436//
437/// \typedef typename T::handler_type tim::component::data_handler_t
438/// \brief an alias for getting the handle_type of a data tracker
439template <typename T>
440using data_handler_t = typename T::handler_type;
441//
442/// \typedef tim::component::data_tracker<intmax_t, TIMEMORY_API>
443/// tim::component::data_tracker_integer
444///
445/// \brief Specialization of \ref tim::component::data_tracker for storing signed integer
446/// data
448//
449/// \typedef tim::component::data_tracker<size_t, TIMEMORY_API>
450/// tim::component::data_tracker_unsigned
451///
452/// \brief Specialization of \ref tim::component::data_tracker for storing unsigned
453/// integer data
455//
456/// \typedef tim::component::data_tracker<double, TIMEMORY_API>
457/// tim::component::data_tracker_floating
458///
459/// \brief Specialization of \ref tim::component::data_tracker for storing floating point
460/// data
462//
463//
464template <typename InpT, typename Tag>
465inline std::string&
467{
468 static std::string _instance = []() {
471 return TIMEMORY_JOIN("_", typeid(Tag).name(), typeid(InpT).name());
472 }();
473 return _instance;
474}
475//
476template <typename InpT, typename Tag>
479{
480 static std::string _instance = []() {
482 {
483 auto meta_desc = metadata<this_type>::description();
485 {
486 auto meta_extra_desc = metadata<this_type>::extra_description();
487 meta_desc += ". ";
488 meta_desc += meta_extra_desc;
489 }
490 return meta_desc;
491 }
492 std::stringstream ss;
493 ss << "Data tracker for data of type " << demangle<InpT>() << " for "
494 << demangle<Tag>();
495 return ss.str();
496 }();
497 return _instance;
498}
499//
500template <typename InpT, typename Tag>
501template <typename T>
502void
503data_tracker<InpT, Tag>::store(T&& val, enable_if_acceptable_t<T, int>)
504{
505 set_last(compute_type::divide(std::forward<T>(val), get_unit()));
506 handler_type::store(*this, get_last());
507 if(!get_is_running())
508 ++laps;
509}
510//
511template <typename InpT, typename Tag>
512template <typename T>
513void
514data_tracker<InpT, Tag>::store(handler_type&&, T&& val, enable_if_acceptable_t<T, int>)
515{
516 set_last(compute_type::divide(std::forward<T>(val), get_unit()));
517 handler_type::store(*this, get_last());
518 if(!get_is_running())
519 ++laps;
520}
521//
522template <typename InpT, typename Tag>
523template <typename FuncT, typename T>
524auto
525data_tracker<InpT, Tag>::store(FuncT&& f, T&& val, enable_if_acceptable_t<T, int>)
526 -> decltype(std::declval<handler_type>().store(*this, std::forward<FuncT>(f),
527 std::forward<T>(val)),
528 void())
529{
530 set_last(compute_type::divide(std::forward<T>(val), get_unit()));
531 handler_type::store(*this, std::forward<FuncT>(f), get_last());
532 if(!get_is_running())
533 ++laps;
534}
535//
536template <typename InpT, typename Tag>
537template <typename FuncT, typename T>
538auto
540 enable_if_acceptable_t<T, int>)
541 -> decltype(std::declval<handler_type>().store(*this, std::forward<FuncT>(f),
542 std::forward<T>(val)),
543 void())
544{
545 set_last(compute_type::divide(std::forward<T>(val), get_unit()));
546 handler_type::store(*this, std::forward<FuncT>(f), get_last());
547 if(!get_is_running())
548 ++laps;
549}
550//
551template <typename InpT, typename Tag>
552template <typename T>
553void
554data_tracker<InpT, Tag>::mark_begin(T&& val, enable_if_acceptable_t<T, int>)
555{
556 handler_type::begin(get_temporary(),
557 compute_type::divide(std::forward<T>(val), get_unit()));
558}
559//
560template <typename InpT, typename Tag>
561template <typename T>
562void
563data_tracker<InpT, Tag>::mark_end(T&& val, enable_if_acceptable_t<T, int>)
564{
565 handler_type::end(*this, compute_type::divide(std::forward<T>(val), get_unit()));
566 if(!get_is_running())
567 ++laps;
568}
569//
570template <typename InpT, typename Tag>
571template <typename T>
572void
574 enable_if_acceptable_t<T, int>)
575{
576 handler_type::begin(get_temporary(),
577 compute_type::divide(std::forward<T>(val), get_unit()));
578}
579//
580template <typename InpT, typename Tag>
581template <typename T>
582void
583data_tracker<InpT, Tag>::mark_end(handler_type&&, T&& val, enable_if_acceptable_t<T, int>)
584{
585 handler_type::end(*this, compute_type::divide(std::forward<T>(val), get_unit()));
586 if(!get_is_running())
587 ++laps;
588}
589//
590template <typename InpT, typename Tag>
591template <typename FuncT, typename T>
592void
593data_tracker<InpT, Tag>::mark_begin(FuncT&& f, T&& val, enable_if_acceptable_t<T, int>)
594{
595 handler_type::begin(get_temporary(), std::forward<FuncT>(f),
596 compute_type::divide(std::forward<T>(val), get_unit()));
597}
598//
599template <typename InpT, typename Tag>
600template <typename FuncT, typename T>
601void
602data_tracker<InpT, Tag>::mark_end(FuncT&& f, T&& val, enable_if_acceptable_t<T, int>)
603{
604 handler_type::end(*this, std::forward<FuncT>(f),
605 compute_type::divide(std::forward<T>(val), get_unit()));
606 if(!get_is_running())
607 ++laps;
608}
609//
610template <typename InpT, typename Tag>
611template <typename FuncT, typename T>
612void
614 enable_if_acceptable_t<T, int>)
615{
616 handler_type::begin(get_temporary(), std::forward<FuncT>(f),
617 compute_type::divide(std::forward<T>(val), get_unit()));
618}
619//
620template <typename InpT, typename Tag>
621template <typename FuncT, typename T>
622void
624 enable_if_acceptable_t<T, int>)
625{
626 handler_type::end(*this, std::forward<FuncT>(f),
627 compute_type::divide(std::forward<T>(val), get_unit()));
628 if(!get_is_running())
629 ++laps;
630}
631//
632template <typename InpT, typename Tag>
633template <typename T>
636 enable_if_acceptable_t<T, int>)
637{
638 this_type _tmp{};
639 if(get_is_running())
640 start_t{ _tmp };
641 _tmp.store(std::forward<T>(val));
642 if(get_is_running())
643 stop_t{ _tmp };
644 auto& _map = *get_secondary_map();
645 _map.emplace(_key, std::move(_tmp));
646 return &(_map[_key]);
647}
648//
649template <typename InpT, typename Tag>
650template <typename T>
653 enable_if_acceptable_t<T, int>)
654{
655 this_type _tmp{};
656 if(get_is_running())
657 start_t{ _tmp };
658 _tmp.store(std::forward<handler_type>(h), std::forward<T>(val));
659 if(get_is_running())
660 stop_t{ _tmp };
661 auto& _map = *get_secondary_map();
662 if(_map.empty())
663 _map.reserve(20);
664 _map.emplace(_key, std::move(_tmp));
665 return &(_map[_key]);
666}
667//
668template <typename InpT, typename Tag>
669template <typename FuncT, typename T>
672 enable_if_acceptable_t<T, int>)
673{
674 this_type _tmp{};
675 if(get_is_running())
676 start_t{ _tmp };
677 _tmp.store(std::forward<FuncT>(f), std::forward<T>(val));
678 if(get_is_running())
679 stop_t{ _tmp };
680 auto& _map = *get_secondary_map();
681 if(_map.empty())
682 _map.reserve(20);
683 _map.emplace(_key, std::move(_tmp));
684 return &(_map[_key]);
685}
686//
687template <typename InpT, typename Tag>
688template <typename FuncT, typename T>
691 FuncT&& f, T&& val, enable_if_acceptable_t<T, int>)
692{
693 this_type _tmp{};
694 if(get_is_running())
695 start_t{ _tmp };
696 _tmp.store(std::forward<handler_type>(h), std::forward<FuncT>(f),
697 std::forward<T>(val));
698 if(get_is_running())
699 stop_t{ _tmp };
700 auto& _map = *get_secondary_map();
701 if(_map.empty())
702 _map.reserve(20);
703 _map.emplace(_key, std::move(_tmp));
704 return &(_map[_key]);
705}
706//
707} // namespace component
708} // namespace tim
709//
710//======================================================================================//
typename base_type::const_iterator const_iterator
Definition: components.hpp:169
std::pair< iterator, bool > emplace(Args &&... args)
Definition: components.hpp:180
typename base_type::iterator iterator
Definition: components.hpp:168
iterator find(const key_type &_key)
Definition: components.hpp:186
std::vector< value_type > base_type
Definition: components.hpp:167
mapped_type & operator[](const key_type &_key)
Definition: components.hpp:208
const_iterator find(const key_type &_key) const
Definition: components.hpp:197
STL namespace.
typename T::handler_type data_handler_t
an alias for getting the handle_type of a data tracker
Definition: components.hpp:440
typename std::enable_if< B, T >::type enable_if_t
Definition: types.hpp:58
return _hash_map end()
void store(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:564
auto divide(Tp &_lhs, Up _rhs, type_list<>,...) -> decltype(_lhs/=_rhs, void())
Definition: divide.hpp:43
Definition: kokkosp.cpp:39
tim::mpl::apply< std::string > string
Definition: macros.hpp:53
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:252
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:554
auto get_display() const
get the data in a form suitable for display
Definition: components.hpp:255
static std::string & label()
a reference is returned here so that it can be easily updated
Definition: components.hpp:466
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:563
this_type * add_secondary(const std::string &_key, handler_type &&h, FuncT &&f, T &&val, enable_if_acceptable_t< T, int >=0)
overload which uses a lambda to bypass the default behavior of how the handler updates the values and...
data::handler< InpT, Tag > handler_type
Definition: components.hpp:152
static std::string & description()
a reference is returned here so that it can be easily updated
Definition: components.hpp:478
static auto & get_unit()
this returns a reference so that it can be easily modified
Definition: components.hpp:239
void set_last(value_type &&_v)
Definition: components.hpp:407
value_type get_last() const
Definition: components.hpp:409
void set_value(const value_type &v)
set the current value
Definition: components.hpp:400
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:260
void store(T &&val, enable_if_acceptable_t< T, int >=0)
store some data. Uses tim::data::handler for the type.
Definition: components.hpp:503
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
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 set_value(value_type &&v)
set the current value via move
Definition: components.hpp:403
void set_last(value_type &_v)
Definition: components.hpp:408
this_type * add_secondary(const std::string &_key, FuncT &&f, T &&val, enable_if_acceptable_t< T, int >=0)
overload which uses a lambda to bypass the default behavior of how the handler updates the values
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: compute.hpp:53
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:469
This operation attempts to call a member function which the component provides to internally store wh...
Definition: types.hpp:502
#define TIMEMORY_JOIN(delim,...)
Definition: macros.hpp:90