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.
definition.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 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#pragma once
26
27#include "timemory/backends/process.hpp"
28#include "timemory/backends/threading.hpp"
44
45#include <fstream>
46#include <memory>
47#include <utility>
48
49namespace tim
50{
51//
52//--------------------------------------------------------------------------------------//
53//
54// base::storage
55//
56//--------------------------------------------------------------------------------------//
57//
58namespace base
59{
60//
61#if !defined(TIMEMORY_STORAGE_HIDE_DEFINITION)
62//
63//--------------------------------------------------------------------------------------//
64//
66storage::storage(bool _is_master, int64_t _instance_id, std::string _label)
67: m_is_master(_is_master)
68, m_instance_id(_instance_id)
69, m_label(std::move(_label))
70, m_manager(::tim::manager::instance())
71, m_settings(::tim::settings::shared_instance())
72{
73 if(m_is_master && m_instance_id > 0)
74 {
75 int _id = m_instance_id;
76 PRINT_HERE("%s: %i (%s)",
77 "Error! base::storage is master but is not zero instance", _id,
78 m_label.c_str());
79 if(m_instance_id > 10)
80 {
81 // at this point we have a recursive loop
82 TIMEMORY_EXCEPTION("Duplication!")
83 }
84 }
85
86 if(!m_is_master && m_instance_id == 0)
87 {
88 int _id = m_instance_id;
89 PRINT_HERE("%s: %i (%s)",
90 "Warning! base::storage is not master but is zero instance", _id,
91 m_label.c_str());
92 }
93
94 CONDITIONAL_PRINT_HERE(m_settings->get_debug(), "%s: %i (%s)",
95 "base::storage instance created", (int) m_instance_id,
96 m_label.c_str());
97}
98//
99//--------------------------------------------------------------------------------------//
100//
102{
104 "base::storage instance %i deleted for %s",
105 (int) m_instance_id, m_label.c_str());
106}
107//
108//--------------------------------------------------------------------------------------//
109//
110TIMEMORY_STORAGE_LINKAGE std::atomic<int>&
112{
113 static std::atomic<int> _instance(0);
114 return _instance;
115}
116//
117//--------------------------------------------------------------------------------------//
118//
121{
122 // disable gperf if profiling
123# if defined(TIMEMORY_USE_GPERFTOOLS) || defined(TIMEMORY_USE_GPERFTOOLS_PROFILER) || \
124 defined(TIMEMORY_USE_GPERFTOOLS_TCMALLOC)
125 try
126 {
127 if(storage_once_flag()++ == 0)
128 gperftools::profiler_stop();
129 } catch(std::exception& e)
130 {
131 std::cerr << "Error calling gperftools::profiler_stop(): " << e.what()
132 << ". Continuing..." << std::endl;
133 }
134# endif
135}
136//
137//--------------------------------------------------------------------------------------//
138//
140storage::add_hash_id(uint64_t _lhs, uint64_t _rhs)
141{
143}
144//
145//--------------------------------------------------------------------------------------//
146//
149{
151}
152//
153//--------------------------------------------------------------------------------------//
154//
156storage::add_file_output(const std::string& _category, const std::string& _label,
157 const std::string& _file)
158{
159 if(m_manager)
160 m_manager->add_file_output(_category, _label, _file);
161}
162//
163//--------------------------------------------------------------------------------------//
164//
167{
168 if(m_manager)
169 m_manager->remove_finalizer(m_label);
170}
171//
172#endif
173//--------------------------------------------------------------------------------------//
174//
175} // namespace base
176//
177//--------------------------------------------------------------------------------------//
178//
179namespace impl
180{
181//
182//======================================================================================//
183//
184// impl::storage<Type, bool>
185// impl::storage
186//
187//======================================================================================//
188//
189// TRUE
190//
191//--------------------------------------------------------------------------------------//
192//
193template <typename Type>
196{
197 return get_singleton() ? get_singleton()->instance_ptr() : nullptr;
198}
199//
200//--------------------------------------------------------------------------------------//
201//
202template <typename Type>
204storage<Type, true>::noninit_master_instance()
205{
206 return get_singleton() ? get_singleton()->master_instance_ptr() : nullptr;
207}
208//
209//--------------------------------------------------------------------------------------//
210//
211template <typename Type>
212bool&
213storage<Type, true>::master_is_finalizing()
214{
215 static bool _instance = false;
216 return _instance;
217}
218//
219//--------------------------------------------------------------------------------------//
220//
221template <typename Type>
222bool&
223storage<Type, true>::worker_is_finalizing()
224{
225 static thread_local bool _instance = master_is_finalizing();
226 return _instance;
227}
228//
229//--------------------------------------------------------------------------------------//
230//
231template <typename Type>
232bool
233storage<Type, true>::is_finalizing()
234{
235 return worker_is_finalizing() || master_is_finalizing();
236}
237//
238//--------------------------------------------------------------------------------------//
239//
240template <typename Type>
241std::atomic<int64_t>&
242storage<Type, true>::instance_count()
243{
244 static std::atomic<int64_t> _counter{ 0 };
245 return _counter;
246}
247//
248//--------------------------------------------------------------------------------------//
249//
250// FALSE
251//
252//--------------------------------------------------------------------------------------//
253//
254template <typename Type>
256storage<Type, false>::noninit_instance()
257{
258 return get_singleton() ? get_singleton()->instance_ptr() : nullptr;
259}
260//
261//--------------------------------------------------------------------------------------//
262//
263template <typename Type>
265storage<Type, false>::noninit_master_instance()
266{
267 return get_singleton() ? get_singleton()->master_instance_ptr() : nullptr;
268}
269//
270//--------------------------------------------------------------------------------------//
271//
272template <typename Type>
273bool&
274storage<Type, false>::master_is_finalizing()
275{
276 static bool _instance = false;
277 return _instance;
278}
279//
280//--------------------------------------------------------------------------------------//
281//
282template <typename Type>
283bool&
284storage<Type, false>::worker_is_finalizing()
285{
286 static thread_local bool _instance = master_is_finalizing();
287 return _instance;
288}
289//
290//--------------------------------------------------------------------------------------//
291//
292template <typename Type>
293bool
294storage<Type, false>::is_finalizing()
295{
296 return worker_is_finalizing() || master_is_finalizing();
297}
298//
299//--------------------------------------------------------------------------------------//
300//
301template <typename Type>
302std::atomic<int64_t>&
303storage<Type, false>::instance_count()
304{
305 static std::atomic<int64_t> _counter{ 0 };
306 return _counter;
307}
308//
309//======================================================================================//
310//
311// impl::storage<Type, true>
312// impl::storage_true
313//
314//======================================================================================//
315//
316template <typename Type>
317storage<Type, true>::storage()
318: base_type(singleton_t::is_master_thread(), instance_count()++, demangle<Type>())
319{
320 CONDITIONAL_PRINT_HERE(m_settings->get_debug(), "constructing %s", m_label.c_str());
322 m_settings->get_debug() && m_settings->get_verbose() > 1, 16);
323
325
326 static std::atomic<int32_t> _skip_once(0);
327 if(_skip_once++ > 0)
328 {
329 // make sure all worker instances have a copy of the hash id and aliases
330 auto _master = singleton_t::master_instance();
331 if(_master)
332 {
333 hash_map_t _hash_ids = *_master->get_hash_ids();
334 hash_alias_map_t _hash_aliases = *_master->get_hash_aliases();
335 for(const auto& itr : _hash_ids)
336 {
337 if(m_hash_ids->find(itr.first) == m_hash_ids->end())
338 m_hash_ids->insert({ itr.first, itr.second });
339 }
340 for(const auto& itr : _hash_aliases)
341 {
342 if(m_hash_aliases->find(itr.first) == m_hash_aliases->end())
343 m_hash_aliases->insert({ itr.first, itr.second });
344 }
345 }
346 }
347
348 get_shared_manager();
349 // m_printer = std::make_shared<printer_t>(Type::get_label(), this);
350}
351//
352//--------------------------------------------------------------------------------------//
353//
354template <typename Type>
356{
358
359 auto _debug = m_settings->get_debug();
360
361 CONDITIONAL_PRINT_HERE(_debug, "[%s|%li]> destroying storage", m_label.c_str(),
362 (long) m_instance_id);
363
364 auto _main_instance = singleton_t::master_instance();
365
366 if(!m_is_master)
367 {
368 if(_main_instance)
369 {
370 CONDITIONAL_PRINT_HERE(_debug, "[%s|%li]> merging into primary instance",
371 m_label.c_str(), (long) m_instance_id);
372 _main_instance->merge(this);
373 }
374 else
375 {
377 "[%s|%li]> skipping merge into non-existent primary "
378 "instance",
379 m_label.c_str(), (long) m_instance_id);
380 }
381 }
382
383 if(m_graph_data_instance)
384 {
385 CONDITIONAL_PRINT_HERE(_debug, "[%s|%li]> deleting graph data", m_label.c_str(),
386 (long) m_instance_id);
387 delete m_graph_data_instance;
388 }
389
390 m_graph_data_instance = nullptr;
391
392 CONDITIONAL_PRINT_HERE(_debug, "[%s|%li]> storage destroyed", m_label.c_str(),
393 (long) m_instance_id);
394}
395//
396//--------------------------------------------------------------------------------------//
397//
398template <typename Type>
399void
401{
402 if(m_initialized)
403 return;
404 CONDITIONAL_PRINT_HERE(m_settings->get_debug(), "initializing %s", m_label.c_str());
406 m_settings->get_debug() && m_settings->get_verbose() > 1, 16);
407 m_initialized = true;
408}
409//
410//--------------------------------------------------------------------------------------//
411//
412template <typename Type>
413void
415{
416 if(m_finalized)
417 return;
418
419 if(!m_initialized)
420 return;
421
422 CONDITIONAL_PRINT_HERE(m_settings->get_debug(), "finalizing %s", m_label.c_str());
424 m_settings->get_debug() && m_settings->get_verbose() > 1, 16);
425
426 m_finalized = true;
427 worker_is_finalizing() = true;
428 if(m_is_master)
429 master_is_finalizing() = true;
430 manager::instance()->is_finalizing(true);
431
432 using fini_t = operation::fini<Type>;
433 using ValueT = typename trait::collects_data<Type>::type;
434 auto upcast = static_cast<tim::storage<Type, ValueT>*>(this);
435
436 if(m_thread_init)
437 fini_t(upcast, operation::mode_constant<operation::fini_mode::thread>{});
438 if(m_is_master && m_global_init)
439 fini_t(upcast, operation::mode_constant<operation::fini_mode::global>{});
440
441 CONDITIONAL_PRINT_HERE(m_settings->get_debug(), "finalized %s", m_label.c_str());
442}
443//
444//--------------------------------------------------------------------------------------//
445//
446template <typename Type>
447void
449{
450 if(!m_stack.empty() && m_settings->get_stack_clearing())
451 {
452 std::unordered_set<Type*> _stack = m_stack;
453 for(auto& itr : _stack)
454 {
455 operation::generic_operator<Type, operation::start<Type>, TIMEMORY_API>{
456 *itr
457 };
458 operation::generic_operator<Type, operation::pop_node<Type>, TIMEMORY_API>{
459 *itr
460 };
461 }
462 }
463 m_stack.clear();
464}
465//
466//--------------------------------------------------------------------------------------//
467//
468template <typename Type>
469bool
471{
472 if(!m_global_init)
473 {
474 CONDITIONAL_PRINT_HERE(m_settings->get_debug(), "[%s|%i]> invoking global_init",
475 demangle<Type>().c_str(), (int) m_thread_idx);
476 if(!m_is_master && master_instance())
477 master_instance()->global_init();
478 m_global_init = true;
479 operation::init<Type>{ operation::mode_constant<operation::init_mode::global>{} };
480 }
481 return m_global_init;
482}
483//
484//--------------------------------------------------------------------------------------//
485//
486template <typename Type>
487bool
489{
490 if(!m_thread_init)
491 {
492 global_init();
493 CONDITIONAL_PRINT_HERE(m_settings->get_debug(), "[%s|%i]> invoking thread_init",
494 demangle<Type>().c_str(), (int) m_thread_idx);
495 if(!m_is_master && master_instance())
496 master_instance()->thread_init();
497 m_thread_init = true;
498 operation::init<Type>{ operation::mode_constant<operation::init_mode::thread>{} };
499 }
500 return m_thread_init;
501}
502//
503//--------------------------------------------------------------------------------------//
504//
505template <typename Type>
506bool
508{
509 if(!m_data_init)
510 {
511 global_init();
512 thread_init();
513 CONDITIONAL_PRINT_HERE(m_settings->get_debug(), "[%s|%i]> invoking data_init",
514 demangle<Type>().c_str(), (int) m_thread_idx);
515 if(!m_is_master && master_instance())
516 master_instance()->data_init();
517 m_data_init = true;
518 check_consistency();
519 }
520 return m_data_init;
521}
522//
523//--------------------------------------------------------------------------------------//
524//
525template <typename Type>
526const typename storage<Type, true>::graph_data_t&
527storage<Type, true>::data() const
528{
529 if(!is_finalizing())
530 {
531 using type_t = decay_t<remove_pointer_t<decltype(this)>>;
532 static thread_local auto _init = const_cast<type_t*>(this)->data_init();
533 consume_parameters(_init);
534 }
535 return _data();
536}
537//
538//--------------------------------------------------------------------------------------//
539//
540template <typename Type>
541const typename storage<Type, true>::graph_t&
542storage<Type, true>::graph() const
543{
544 if(!is_finalizing())
545 {
546 using type_t = decay_t<remove_pointer_t<decltype(this)>>;
547 static thread_local auto _init = const_cast<type_t*>(this)->data_init();
548 consume_parameters(_init);
549 }
550 return _data().graph();
551}
552//
553//--------------------------------------------------------------------------------------//
554//
555template <typename Type>
556int64_t
557storage<Type, true>::depth() const
558{
559 if(!is_finalizing())
560 {
561 using type_t = decay_t<remove_pointer_t<decltype(this)>>;
562 static thread_local auto _init = const_cast<type_t*>(this)->data_init();
563 consume_parameters(_init);
564 }
565 return (is_finalizing()) ? 0 : _data().depth();
566}
567//
568//--------------------------------------------------------------------------------------//
569//
570template <typename Type>
571typename storage<Type, true>::graph_data_t&
572storage<Type, true>::data()
573{
574 if(!is_finalizing())
575 {
576 static thread_local auto _init = data_init();
577 consume_parameters(_init);
578 }
579 return _data();
580}
581//
582//--------------------------------------------------------------------------------------//
583//
584template <typename Type>
585typename storage<Type, true>::graph_t&
586storage<Type, true>::graph()
587{
588 if(!is_finalizing())
589 {
590 static thread_local auto _init = data_init();
591 consume_parameters(_init);
592 }
593 return _data().graph();
594}
595//
596//--------------------------------------------------------------------------------------//
597//
598template <typename Type>
600storage<Type, true>::current()
601{
602 if(!is_finalizing())
603 {
604 static thread_local auto _init = data_init();
605 consume_parameters(_init);
606 }
607 return _data().current();
608}
609//
610//--------------------------------------------------------------------------------------//
611//
612template <typename Type>
615{
616 return _data().pop_graph();
617}
618//
619//--------------------------------------------------------------------------------------//
620//
621template <typename Type>
622void
623storage<Type, true>::stack_pop(Type* obj)
624{
625 auto itr = m_stack.find(obj);
626 if(itr != m_stack.end())
627 m_stack.erase(itr);
628}
629//
630//--------------------------------------------------------------------------------------//
631//
632template <typename Type>
633void
634storage<Type, true>::check_consistency()
635{
636 auto* ptr = &_data();
637 if(ptr != m_graph_data_instance)
638 {
639 fprintf(stderr, "[%s]> mismatched graph data on master thread: %p vs. %p\n",
640 m_label.c_str(), (void*) ptr, static_cast<void*>(m_graph_data_instance));
641 }
642}
643//
644//--------------------------------------------------------------------------------------//
645//
646template <typename Type>
647void
648storage<Type, true>::ensure_init()
649{
650 global_init();
651 thread_init();
652 data_init();
653 // check this now to ensure everything is initialized
654 if(m_node_ids.empty() || m_graph_data_instance == nullptr)
655 initialize();
656}
657//
658//--------------------------------------------------------------------------------------//
659//
660template <typename Type>
662storage<Type, true>::get_prefix(const graph_node& node)
663{
664 auto _ret = operation::decode<TIMEMORY_API>{}(m_hash_ids, m_hash_aliases, node.id());
665 if(_ret.find("unknown-hash=") == 0)
666 {
667 if(!m_is_master && singleton_t::master_instance())
668 {
669 auto _master = singleton_t::master_instance();
670 return _master->get_prefix(node);
671 }
672
673 return operation::decode<TIMEMORY_API>{}(node.id());
674 }
675
676#if defined(TIMEMORY_TESTING) || defined(TIMEMORY_INTERNAL_TESTING)
677 if(_ret.empty() || _ret.find("unknown-hash=") == 0)
678 {
679 TIMEMORY_EXCEPTION("Hash-lookup error!")
680 }
681#endif
682
683 return _ret;
684}
685//
686//--------------------------------------------------------------------------------------//
687//
688template <typename Type>
690storage<Type, true>::get_prefix(const uint64_t& id)
691{
692 auto _ret = get_hash_identifier(m_hash_ids, m_hash_aliases, id);
693 if(_ret.find("unknown-hash=") == 0)
694 {
695 if(!m_is_master && singleton_t::master_instance())
696 {
697 auto _master = singleton_t::master_instance();
698 return _master->get_prefix(id);
699 }
700
701 return get_hash_identifier(id);
702 }
703
704#if defined(TIMEMORY_TESTING) || defined(TIMEMORY_INTERNAL_TESTING)
705 if(_ret.empty() || _ret.find("unknown-hash=") == 0)
706 {
707 TIMEMORY_EXCEPTION("Hash-lookup error!")
708 }
709#endif
710
711 return _ret;
712}
713//
714//--------------------------------------------------------------------------------------//
715//
716template <typename Type>
717typename storage<Type, true>::graph_data_t&
718storage<Type, true>::_data()
719{
720 if(m_graph_data_instance == nullptr)
721 {
722 auto_lock_t lk(singleton_t::get_mutex(), std::defer_lock);
723
724 if(!m_is_master && master_instance())
725 {
726 static thread_local bool _data_init = master_instance()->data_init();
727 auto& m = master_instance()->data();
728 consume_parameters(_data_init);
729
730 if(!lk.owns_lock())
731 lk.lock();
732
734 m_settings->get_debug(), "[%s]> Worker: %i, master ptr: %p",
735 demangle<Type>().c_str(), (int) m_thread_idx, (void*) &m);
737 m_settings->get_debug() && m_settings->get_verbose() > 1, 16);
738 if(m.current())
739 {
740 auto _current = m.current();
741 auto _id = _current->id();
742 auto _depth = _current->depth();
743 graph_node_t node(_id, operation::dummy<Type>{}(), _depth, m_thread_idx);
744 if(!m_graph_data_instance)
745 m_graph_data_instance = new graph_data_t(node, _depth, &m);
746 m_graph_data_instance->depth() = _depth;
747 m_graph_data_instance->sea_level() = _depth;
748 }
749 else
750 {
751 if(!m_graph_data_instance)
752 {
753 graph_node_t node(0, operation::dummy<Type>{}(), 1, m_thread_idx);
754 m_graph_data_instance = new graph_data_t(node, 1, &m);
755 }
756 m_graph_data_instance->depth() = 1;
757 m_graph_data_instance->sea_level() = 1;
758 }
759 m_graph_data_instance->set_master(&m);
760 }
761 else
762 {
763 if(!lk.owns_lock())
764 lk.lock();
765
766 std::string _prefix = "> [tot] total";
768 graph_node_t node(0, operation::dummy<Type>{}(), 0, m_thread_idx);
769 if(!m_graph_data_instance)
770 m_graph_data_instance = new graph_data_t(node, 0, nullptr);
771 m_graph_data_instance->depth() = 0;
772 m_graph_data_instance->sea_level() = 0;
773 CONDITIONAL_PRINT_HERE(m_settings->get_debug(),
774 "[%s]> Master: %i, master ptr: %p",
775 demangle<Type>().c_str(), (int) m_thread_idx,
776 (void*) m_graph_data_instance);
778 m_settings->get_debug() && m_settings->get_verbose() > 1, 16);
779 }
780
781 if(m_node_ids.empty() && m_graph_data_instance)
782 {
783 m_node_ids.emplace(0, iterator_hash_submap_t{});
784 m_node_ids.at(0).emplace(0, m_graph_data_instance->current());
785 }
786 }
787
788 m_initialized = true;
789 return *m_graph_data_instance;
790}
791//
792//--------------------------------------------------------------------------------------//
793//
794template <typename Type>
795void
796storage<Type, true>::merge()
797{
798 if(!m_is_master || !m_initialized)
799 return;
800
801 auto m_children = singleton_t::children();
802 if(m_children.empty())
803 return;
804
805 for(auto& itr : m_children)
806 merge(itr);
807
808 // create lock
809 auto_lock_t l(singleton_t::get_mutex(), std::defer_lock);
810 if(!l.owns_lock())
811 l.lock();
812
813 for(auto& itr : m_children)
814 singleton_t::remove(itr);
815
816 // for(auto& itr : m_children)
817 // {
818 // if(itr != this)
819 // itr->data().clear();
820 // }
821
822 stack_clear();
823}
824//
825//--------------------------------------------------------------------------------------//
826//
827template <typename Type>
828void
829storage<Type, true>::merge(this_type* itr)
830{
831 if(itr)
832 operation::finalize::merge<Type, true>(*this, *itr);
833}
834//
835//--------------------------------------------------------------------------------------//
836//
837template <typename Type>
838typename storage<Type, true>::result_array_t
840{
841 result_array_t _ret{};
842 operation::finalize::get<Type, true>{ *this }(_ret);
843 return _ret;
844}
845//
846//--------------------------------------------------------------------------------------//
847//
848template <typename Type>
849template <typename Tp>
850Tp&
852{
853 return operation::finalize::get<Type, true>{ *this }(_ret);
854}
855//
856//--------------------------------------------------------------------------------------//
857//
858template <typename Type>
859typename storage<Type, true>::dmp_result_t
860storage<Type, true>::mpi_get()
861{
862 dmp_result_t _ret{};
863 operation::finalize::mpi_get<Type, true>{ *this }(_ret);
864 return _ret;
865}
866//
867//--------------------------------------------------------------------------------------//
868//
869template <typename Type>
870template <typename Tp>
871Tp&
872storage<Type, true>::mpi_get(Tp& _ret)
873{
874 return operation::finalize::mpi_get<Type, true>{ *this }(_ret);
875}
876//
877//--------------------------------------------------------------------------------------//
878//
879template <typename Type>
880typename storage<Type, true>::dmp_result_t
881storage<Type, true>::upc_get()
882{
883 dmp_result_t _ret{};
884 operation::finalize::upc_get<Type, true>{ *this }(_ret);
885 return _ret;
886}
887//
888//--------------------------------------------------------------------------------------//
889//
890template <typename Type>
891template <typename Tp>
892Tp&
893storage<Type, true>::upc_get(Tp& _ret)
894{
895 return operation::finalize::upc_get<Type, true>{ *this }(_ret);
896}
897//
898//--------------------------------------------------------------------------------------//
899//
900template <typename Type>
901typename storage<Type, true>::dmp_result_t
902storage<Type, true>::dmp_get()
903{
904 dmp_result_t _ret{};
905 operation::finalize::dmp_get<Type, true>{ *this }(_ret);
906 return _ret;
907}
908//
909//--------------------------------------------------------------------------------------//
910//
911template <typename Type>
912template <typename Tp>
913Tp&
914storage<Type, true>::dmp_get(Tp& _ret)
915{
916 return operation::finalize::dmp_get<Type, true>{ *this }(_ret);
917}
918//
919//--------------------------------------------------------------------------------------//
920//
921template <typename Type>
922void
923storage<Type, true>::internal_print()
924{
926
927 if(!m_initialized && !m_finalized)
928 return;
929
930 auto _is_primary = singleton_t::is_master(this);
931 auto _primary_instance = singleton_t::master_instance();
932
933 if(!_is_primary && !_primary_instance && common_singleton::is_main_thread())
934 {
935 PRINT_HERE("[%s]> storage instance (%p) on main thread is not designated as the "
936 "primary but there is a nullptr to primary. Designating as primary",
937 m_label.c_str(), (void*) this);
938 _is_primary = true;
939 }
940
941 if(!_is_primary)
942 {
943 if(_primary_instance)
944 _primary_instance->merge(this);
945 finalize();
946 }
947 else
948 {
949 merge();
950 finalize();
951
953 {
954 instance_count().store(0);
955 return;
956 }
957
958 // if the graph wasn't ever initialized, exit
959 if(!m_graph_data_instance)
960 {
961 instance_count().store(0);
962 return;
963 }
964
965 // no entries
966 if(_data().graph().size() <= 1)
967 {
968 instance_count().store(0);
969 return;
970 }
971
972 // generate output
973 if(m_settings->get_auto_output())
974 {
975 m_printer.reset(new printer_t(Type::get_label(), this, m_settings));
976
977 if(m_manager)
978 m_manager->add_entries(this->size());
979
980 m_printer->execute();
981 }
982
983 instance_count().store(0);
984 }
985}
986//
987//--------------------------------------------------------------------------------------//
988//
989template <typename Type>
990void
991storage<Type, true>::get_shared_manager()
992{
993 using func_t = std::function<void()>;
994
995 // only perform this operation when not finalizing
996 if(!this_type::is_finalizing())
997 {
998 if(!m_manager)
999 return;
1000
1001 auto _label = demangle(Type::label());
1002 std::regex _namespace_re{ "^(tim::[a-z_]+::|tim::)([a-z].*)" };
1003 if(std::regex_search(_label, _namespace_re))
1004 _label = std::regex_replace(_label, _namespace_re, "$2");
1005 // replace spaces with underscores
1006 auto _pos = std::string::npos;
1007 while((_pos = _label.find_first_of(" -")) != std::string::npos)
1008 _label = _label.replace(_pos, 1, "_");
1009 // convert to upper-case
1010 for(auto& itr : _label)
1011 itr = toupper(itr);
1012 // handle any remaining brackets or colons
1013 for(auto itr : { ':', '<', '>' })
1014 {
1015 while((_pos = _label.find(itr)) != std::string::npos)
1016 _pos = _label.erase(_pos, 1).find(itr);
1017 }
1018 std::stringstream env_var;
1019 env_var << "TIMEMORY_" << _label << "_ENABLED";
1020 auto _enabled = tim::get_env<bool>(env_var.str(), true);
1022
1023 auto _instance_id = m_instance_id;
1024 bool _is_master = m_is_master;
1025 auto _sync = [&]() {
1026 if(m_graph_data_instance)
1027 this->data().sync_sea_level();
1028 };
1029 auto _cleanup = [_is_master, _instance_id]() {
1030 if(_is_master)
1031 return;
1033 manager::master_instance()->remove_synchronization(demangle<Type>(),
1034 _instance_id);
1035 if(manager::instance())
1036 manager::instance()->remove_synchronization(demangle<Type>(),
1037 _instance_id);
1038 };
1039 func_t _finalize = [&]() {
1040 auto _instance = this_type::get_singleton();
1041 if(_instance)
1042 {
1043 auto _debug_v = m_settings->get_debug();
1044 auto _verb_v = m_settings->get_verbose();
1045 if(_debug_v || _verb_v > 1)
1046 {
1047 PRINT_HERE("[%s] %s", demangle<Type>().c_str(),
1048 "calling singleton::reset(this)");
1049 }
1050 _instance->reset(this);
1051 if((m_is_master || common_singleton::is_main_thread()) && _instance)
1052 {
1053 if(_debug_v || _verb_v > 1)
1054 {
1055 PRINT_HERE("[%s] %s", demangle<Type>().c_str(),
1056 "calling singleton::reset()");
1057 }
1058 _instance->reset();
1059 }
1060 }
1061 else
1062 {
1063 DEBUG_PRINT_HERE("[%s]> %p", demangle<Type>().c_str(), (void*) _instance);
1064 }
1065 if(m_is_master)
1067 };
1068
1069 if(!m_is_master)
1070 {
1071 manager::master_instance()->add_synchronization(
1072 demangle<Type>(), m_instance_id, std::move(_sync));
1073 m_manager->add_synchronization(demangle<Type>(), m_instance_id,
1074 std::move(_sync));
1075 }
1076
1077 m_manager->add_finalizer(demangle<Type>(), std::move(_cleanup),
1078 std::move(_finalize), m_is_master,
1079 trait::fini_priority<Type>::value);
1080 }
1081}
1082//
1083//======================================================================================//
1084//
1085// impl::storage<Type, false>
1086// impl::storage_false
1087//
1088//======================================================================================//
1089//
1090template <typename Type>
1092: base_type(singleton_t::is_master_thread(), instance_count()++, demangle<Type>())
1093{
1094 CONDITIONAL_PRINT_HERE(m_settings->get_debug(), "constructing %s", m_label.c_str());
1096 m_settings->get_debug() && m_settings->get_verbose() > 1, 16);
1097 get_shared_manager();
1099 // m_printer = std::make_shared<printer_t>(Type::get_label(), this);
1100}
1101//
1102//--------------------------------------------------------------------------------------//
1103//
1104template <typename Type>
1106{
1108 CONDITIONAL_PRINT_HERE(m_settings->get_debug(), "destroying %s", m_label.c_str());
1109}
1110//
1111//--------------------------------------------------------------------------------------//
1112//
1113template <typename Type>
1114void
1116{
1117 if(!m_stack.empty() && m_settings->get_stack_clearing())
1118 {
1119 std::unordered_set<Type*> _stack = m_stack;
1120 for(auto& itr : _stack)
1121 operation::stop<Type>{ *itr };
1122 }
1123 m_stack.clear();
1124}
1125//
1126//--------------------------------------------------------------------------------------//
1127//
1128template <typename Type>
1129void
1131{
1132 if(m_initialized)
1133 return;
1134
1135 CONDITIONAL_PRINT_HERE(m_settings->get_debug(), "initializing %s", m_label.c_str());
1137 m_settings->get_debug() && m_settings->get_verbose() > 1, 16);
1138
1139 m_initialized = true;
1140
1141 using init_t = operation::init<Type>;
1142 using ValueT = typename trait::collects_data<Type>::type;
1143 auto upcast = static_cast<tim::storage<Type, ValueT>*>(this);
1144
1145 if(!m_is_master)
1146 {
1147 init_t(upcast, operation::mode_constant<operation::init_mode::thread>{});
1148 }
1149 else
1150 {
1151 init_t(upcast, operation::mode_constant<operation::init_mode::global>{});
1152 init_t(upcast, operation::mode_constant<operation::init_mode::thread>{});
1153 }
1154}
1155//
1156//--------------------------------------------------------------------------------------//
1157//
1158template <typename Type>
1159void
1161{
1162 if(m_finalized)
1163 return;
1164
1165 if(!m_initialized)
1166 return;
1167
1168 CONDITIONAL_PRINT_HERE(m_settings->get_debug(), "finalizing %s", m_label.c_str());
1169
1170 using fini_t = operation::fini<Type>;
1171 using ValueT = typename trait::collects_data<Type>::type;
1172 auto upcast = static_cast<tim::storage<Type, ValueT>*>(this);
1173
1174 m_finalized = true;
1175 manager::instance()->is_finalizing(true);
1176 if(!m_is_master)
1177 {
1178 worker_is_finalizing() = true;
1179 fini_t(upcast, operation::mode_constant<operation::fini_mode::thread>{});
1180 }
1181 else
1182 {
1183 master_is_finalizing() = true;
1184 worker_is_finalizing() = true;
1185 fini_t(upcast, operation::mode_constant<operation::fini_mode::thread>{});
1186 fini_t(upcast, operation::mode_constant<operation::fini_mode::global>{});
1187 }
1188}
1189//
1190//--------------------------------------------------------------------------------------//
1191//
1192template <typename Type>
1193void
1194storage<Type, false>::stack_pop(Type* obj)
1195{
1196 auto itr = m_stack.find(obj);
1197 if(itr != m_stack.end())
1198 {
1199 m_stack.erase(itr);
1200 }
1201}
1202//
1203//--------------------------------------------------------------------------------------//
1204//
1205template <typename Type>
1206void
1207storage<Type, false>::merge()
1208{
1209 auto m_children = singleton_t::children();
1210 if(m_children.size() == 0)
1211 return;
1212
1213 if(m_settings->get_stack_clearing())
1214 {
1215 for(auto& itr : m_children)
1216 merge(itr);
1217 }
1218
1219 stack_clear();
1220}
1221//
1222//--------------------------------------------------------------------------------------//
1223//
1224template <typename Type>
1225void
1226storage<Type, false>::merge(this_type* itr)
1227{
1228 if(itr)
1229 operation::finalize::merge<Type, false>(*this, *itr);
1230}
1231//
1232//--------------------------------------------------------------------------------------//
1233//
1234template <typename Type>
1235void
1236storage<Type, false>::get_shared_manager()
1237{
1238 using func_t = std::function<void()>;
1239
1240 // only perform this operation when not finalizing
1241 if(!this_type::is_finalizing())
1242 {
1243 if(!m_manager)
1244 return;
1245 if(m_manager->is_finalizing())
1246 return;
1247
1248 auto _label = demangle(Type::label());
1249 std::regex _namespace_re{ "^(tim::[a-z_]+::|tim::)([a-z].*)" };
1250 if(std::regex_search(_label, _namespace_re))
1251 _label = std::regex_replace(_label, _namespace_re, "$2");
1252 // replace spaces with underscores
1253 auto _pos = std::string::npos;
1254 while((_pos = _label.find_first_of(" -")) != std::string::npos)
1255 _label = _label.replace(_pos, 1, "_");
1256 // convert to upper-case
1257 for(auto& itr : _label)
1258 itr = toupper(itr);
1259 // handle any remaining brackets or colons
1260 for(auto itr : { ':', '<', '>' })
1261 {
1262 while((_pos = _label.find(itr)) != std::string::npos)
1263 _pos = _label.erase(_pos, 1).find(itr);
1264 }
1265 std::stringstream env_var;
1266 env_var << "TIMEMORY_" << _label << "_ENABLED";
1267 auto _enabled = tim::get_env<bool>(env_var.str(), true);
1269
1270 auto _cleanup = [&]() {};
1271 func_t _finalize = [&]() {
1272 auto _instance = this_type::get_singleton();
1273 if(_instance)
1274 {
1275 auto _debug_v = m_settings->get_debug();
1276 auto _verb_v = m_settings->get_verbose();
1277 if(_debug_v || _verb_v > 1)
1278 {
1279 PRINT_HERE("[%s] %s", demangle<Type>().c_str(),
1280 "calling singleton::reset(this)");
1281 }
1282 _instance->reset(this);
1283 if((m_is_master || common_singleton::is_main_thread()) && _instance)
1284 {
1285 if(_debug_v || _verb_v > 1)
1286 {
1287 PRINT_HERE("[%s] %s", demangle<Type>().c_str(),
1288 "calling singleton::reset()");
1289 }
1290 _instance->reset();
1291 }
1292 }
1293 else
1294 {
1295 DEBUG_PRINT_HERE("[%s]> %p", demangle<Type>().c_str(), (void*) _instance);
1296 }
1297 if(m_is_master)
1299 };
1300
1301 m_manager->add_finalizer(demangle<Type>(), std::move(_cleanup),
1302 std::move(_finalize), m_is_master,
1303 trait::fini_priority<Type>::value);
1304 }
1305}
1306//
1307//--------------------------------------------------------------------------------------//
1308//
1309} // namespace impl
1310} // namespace tim
1311//
1312//--------------------------------------------------------------------------------------//
1313//
storage(bool _is_master, int64_t _instance_id, std::string _label)
Definition: definition.hpp:66
virtual bool thread_init()
Definition: types.hpp:103
virtual bool global_init()
Definition: types.hpp:102
virtual void initialize()
Definition: types.hpp:100
virtual void stack_clear()
Definition: types.hpp:98
std::shared_ptr< settings > m_settings
Definition: types.hpp:151
int64_t m_instance_id
Definition: types.hpp:146
string_t m_label
Definition: types.hpp:147
hash_value_t add_hash_id(const std::string &_prefix)
Definition: definition.hpp:148
virtual void finalize()
Definition: types.hpp:101
hash_map_ptr_t m_hash_ids
Definition: types.hpp:148
void free_shared_manager()
Definition: definition.hpp:166
static std::atomic< int > & storage_once_flag()
Definition: definition.hpp:111
static void stop_profiler()
Definition: definition.hpp:120
std::shared_ptr< manager > m_manager
Definition: types.hpp:150
hash_alias_ptr_t m_hash_aliases
Definition: types.hpp:149
virtual bool data_init()
Definition: types.hpp:104
void add_file_output(const string_t &_category, const string_t &_label, const string_t &_file)
Definition: definition.hpp:156
static pointer_t instance()
Get a shared pointer to the instance for the current thread.
static pointer_t master_instance()
Get a shared pointer to the instance on the primary thread.
typename singleton_t::pointer pointer
typename base_type::iterator iterator
Definition for global and thread-local finalization functions for a component.
Definition for global and thread-local initialzation functions for a component.
The declaration for the types for manager without definitions.
STL namespace.
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
bool get_hash_identifier(const hash_map_ptr_t &_hash_map, const hash_alias_ptr_t &_hash_alias, hash_value_t _hash_id, std::string *&_ret)
const hash_alias_ptr_t hash_value_t std::string *& _ret
Definition: definition.hpp:300
std::unordered_map< hash_value_t, hash_value_t > hash_alias_map_t
Definition: types.hpp:86
std::unordered_map< hash_value_t, std::string > hash_map_t
Definition: types.hpp:85
size_t hash_value_t
Definition: types.hpp:84
void pop(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:739
const auto & _file
Definition: definition.hpp:72
Definition: kokkosp.cpp:39
char const std::string & _prefix
Definition: config.cpp:55
std::unique_lock< mutex_t > auto_lock_t
Unique lock type around mutex_t.
Definition: locking.hpp:42
void initialize(CompList< CompTypes... > &obj, std::initializer_list< EnumT > components)
Definition: initialize.hpp:53
typename std::remove_pointer< U >::type remove_pointer_t
Definition: types.hpp:569
typename std::decay< T >::type decay_t
Alias template for decay.
Definition: types.hpp:194
std::string demangle(const char *_mangled_name, int *_status=nullptr)
Definition: demangle.hpp:47
tim::mpl::apply< std::string > string
Definition: macros.hpp:53
void finalize()
Definition: types.hpp:119
auto get(const auto_bundle< Tag, Types... > &_obj)
void consume_parameters(ArgsT &&...)
Definition: types.hpp:285
The declaration for the types for storage without definitions.
Include the macros for storage.
#define TIMEMORY_STORAGE_LINKAGE
Definition: macros.hpp:50
Declare the storage types.
static bool & has_storage()
Definition: properties.hpp:98
component_value_type_t< T > type
static bool get(enable_if_t< is_available< U >::value &&get_value< U >(), int >=0)
GET specialization if component is available.
static bool set(bool val, enable_if_t< is_available< U >::value &&get_value< U >(), int >=0)
SET specialization if component is available.
#define CONDITIONAL_PRINT_HERE(CONDITION,...)
Definition: macros.hpp:183
#define TIMEMORY_CONDITIONAL_DEMANGLED_BACKTRACE(CONDITION, DEPTH)
Definition: macros.hpp:202
#define DEBUG_PRINT_HERE(...)
Definition: macros.hpp:168
#define PRINT_HERE(...)
Definition: macros.hpp:152
#define TIMEMORY_EXCEPTION(...)
Definition: types.hpp:138