27#include "timemory/backends/process.hpp"
28#include "timemory/backends/threading.hpp"
61#if !defined(TIMEMORY_STORAGE_HIDE_DEFINITION)
67: m_is_master(_is_master)
68, m_instance_id(_instance_id)
69, m_label(
std::move(_label))
77 "Error! base::storage is master but is not zero instance", _id,
90 "Warning! base::storage is not master but is zero instance", _id,
104 "base::storage instance %i deleted for %s",
113 static std::atomic<int> _instance(0);
123# if defined(TIMEMORY_USE_GPERFTOOLS) || defined(TIMEMORY_USE_GPERFTOOLS_PROFILER) || \
124 defined(TIMEMORY_USE_GPERFTOOLS_TCMALLOC)
128 gperftools::profiler_stop();
129 }
catch(std::exception& e)
131 std::cerr <<
"Error calling gperftools::profiler_stop(): " << e.what()
132 <<
". Continuing..." << std::endl;
193template <
typename Type>
197 return get_singleton() ? get_singleton()->instance_ptr() :
nullptr;
202template <
typename Type>
204storage<Type, true>::noninit_master_instance()
206 return get_singleton() ? get_singleton()->master_instance_ptr() :
nullptr;
211template <
typename Type>
213storage<Type, true>::master_is_finalizing()
215 static bool _instance =
false;
221template <
typename Type>
223storage<Type, true>::worker_is_finalizing()
225 static thread_local bool _instance = master_is_finalizing();
231template <
typename Type>
233storage<Type, true>::is_finalizing()
235 return worker_is_finalizing() || master_is_finalizing();
240template <
typename Type>
242storage<Type, true>::instance_count()
244 static std::atomic<int64_t> _counter{ 0 };
254template <
typename Type>
256storage<Type, false>::noninit_instance()
258 return get_singleton() ? get_singleton()->instance_ptr() :
nullptr;
263template <
typename Type>
265storage<Type, false>::noninit_master_instance()
267 return get_singleton() ? get_singleton()->master_instance_ptr() :
nullptr;
272template <
typename Type>
274storage<Type, false>::master_is_finalizing()
276 static bool _instance =
false;
282template <
typename Type>
284storage<Type, false>::worker_is_finalizing()
286 static thread_local bool _instance = master_is_finalizing();
292template <
typename Type>
294storage<Type, false>::is_finalizing()
296 return worker_is_finalizing() || master_is_finalizing();
301template <
typename Type>
303storage<Type, false>::instance_count()
305 static std::atomic<int64_t> _counter{ 0 };
316template <
typename Type>
317storage<Type, true>::storage()
318: base_type(singleton_t::is_master_thread(), instance_count()++,
demangle<Type>())
326 static std::atomic<int32_t> _skip_once(0);
330 auto _master = singleton_t::master_instance();
333 hash_map_t _hash_ids = *_master->get_hash_ids();
335 for(
const auto& itr : _hash_ids)
338 m_hash_ids->insert({ itr.first, itr.second });
340 for(
const auto& itr : _hash_aliases)
348 get_shared_manager();
354template <
typename Type>
359 auto _debug = m_settings->get_debug();
362 (
long) m_instance_id);
364 auto _main_instance = singleton_t::master_instance();
371 m_label.c_str(), (
long) m_instance_id);
372 _main_instance->merge(
this);
377 "[%s|%li]> skipping merge into non-existent primary "
379 m_label.c_str(), (
long) m_instance_id);
383 if(m_graph_data_instance)
386 (
long) m_instance_id);
387 delete m_graph_data_instance;
390 m_graph_data_instance =
nullptr;
393 (
long) m_instance_id);
398template <
typename Type>
406 m_settings->get_debug() && m_settings->get_verbose() > 1, 16);
407 m_initialized =
true;
412template <
typename Type>
424 m_settings->get_debug() && m_settings->get_verbose() > 1, 16);
427 worker_is_finalizing() =
true;
429 master_is_finalizing() =
true;
432 using fini_t = operation::fini<Type>;
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>{});
446template <
typename Type>
450 if(!m_stack.empty() && m_settings->get_stack_clearing())
452 std::unordered_set<Type*> _stack = m_stack;
453 for(
auto& itr : _stack)
455 operation::generic_operator<Type, operation::start<Type>,
TIMEMORY_API>{
458 operation::generic_operator<Type, operation::pop_node<Type>,
TIMEMORY_API>{
468template <
typename Type>
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>{} };
481 return m_global_init;
486template <
typename Type>
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>{} };
500 return m_thread_init;
505template <
typename Type>
514 demangle<Type>().c_str(), (
int) m_thread_idx);
515 if(!m_is_master && master_instance())
516 master_instance()->data_init();
525template <
typename Type>
526const typename storage<Type, true>::graph_data_t&
527storage<Type, true>::data()
const
532 static thread_local auto _init =
const_cast<type_t*
>(
this)->data_init();
540template <
typename Type>
541const typename storage<Type, true>::graph_t&
542storage<Type, true>::graph()
const
547 static thread_local auto _init =
const_cast<type_t*
>(
this)->data_init();
550 return _data().graph();
555template <
typename Type>
557storage<Type, true>::depth()
const
562 static thread_local auto _init =
const_cast<type_t*
>(
this)->data_init();
565 return (is_finalizing()) ? 0 : _data().depth();
570template <
typename Type>
571typename storage<Type, true>::graph_data_t&
572storage<Type, true>::data()
576 static thread_local auto _init = data_init();
584template <
typename Type>
585typename storage<Type, true>::graph_t&
586storage<Type, true>::graph()
590 static thread_local auto _init = data_init();
593 return _data().graph();
598template <
typename Type>
600storage<Type, true>::current()
604 static thread_local auto _init = data_init();
607 return _data().current();
612template <
typename Type>
616 return _data().pop_graph();
621template <
typename Type>
623storage<Type, true>::stack_pop(Type* obj)
625 auto itr = m_stack.find(obj);
626 if(itr != m_stack.end())
632template <
typename Type>
634storage<Type, true>::check_consistency()
636 auto* ptr = &_data();
637 if(ptr != m_graph_data_instance)
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));
646template <
typename Type>
648storage<Type, true>::ensure_init()
654 if(m_node_ids.empty() || m_graph_data_instance ==
nullptr)
660template <
typename Type>
662storage<Type, true>::get_prefix(
const graph_node& node)
664 auto _ret = operation::decode<TIMEMORY_API>{}(m_hash_ids, m_hash_aliases, node.id());
665 if(
_ret.find(
"unknown-hash=") == 0)
667 if(!m_is_master && singleton_t::master_instance())
669 auto _master = singleton_t::master_instance();
670 return _master->get_prefix(node);
673 return operation::decode<TIMEMORY_API>{}(node.id());
676#if defined(TIMEMORY_TESTING) || defined(TIMEMORY_INTERNAL_TESTING)
677 if(
_ret.empty() ||
_ret.find(
"unknown-hash=") == 0)
688template <
typename Type>
690storage<Type, true>::get_prefix(
const uint64_t&
id)
693 if(
_ret.find(
"unknown-hash=") == 0)
695 if(!m_is_master && singleton_t::master_instance())
697 auto _master = singleton_t::master_instance();
698 return _master->get_prefix(
id);
704#if defined(TIMEMORY_TESTING) || defined(TIMEMORY_INTERNAL_TESTING)
705 if(
_ret.empty() ||
_ret.find(
"unknown-hash=") == 0)
716template <
typename Type>
717typename storage<Type, true>::graph_data_t&
718storage<Type, true>::_data()
720 if(m_graph_data_instance ==
nullptr)
722 auto_lock_t lk(singleton_t::get_mutex(), std::defer_lock);
724 if(!m_is_master && master_instance())
726 static thread_local bool _data_init = master_instance()->data_init();
727 auto& m = master_instance()->data();
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);
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;
751 if(!m_graph_data_instance)
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);
756 m_graph_data_instance->depth() = 1;
757 m_graph_data_instance->sea_level() = 1;
759 m_graph_data_instance->set_master(&m);
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;
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);
781 if(m_node_ids.empty() && m_graph_data_instance)
783 m_node_ids.emplace(0, iterator_hash_submap_t{});
784 m_node_ids.at(0).emplace(0, m_graph_data_instance->current());
788 m_initialized =
true;
789 return *m_graph_data_instance;
794template <
typename Type>
796storage<Type, true>::merge()
798 if(!m_is_master || !m_initialized)
801 auto m_children = singleton_t::children();
802 if(m_children.empty())
805 for(
auto& itr : m_children)
809 auto_lock_t l(singleton_t::get_mutex(), std::defer_lock);
813 for(
auto& itr : m_children)
814 singleton_t::remove(itr);
827template <
typename Type>
829storage<Type, true>::merge(this_type* itr)
832 operation::finalize::merge<Type, true>(*
this, *itr);
837template <
typename Type>
838typename storage<Type, true>::result_array_t
841 result_array_t
_ret{};
842 operation::finalize::get<Type, true>{ *
this }(
_ret);
848template <
typename Type>
849template <
typename Tp>
853 return operation::finalize::get<Type, true>{ *
this }(
_ret);
858template <
typename Type>
859typename storage<Type, true>::dmp_result_t
860storage<Type, true>::mpi_get()
863 operation::finalize::mpi_get<Type, true>{ *
this }(
_ret);
869template <
typename Type>
870template <
typename Tp>
872storage<Type, true>::mpi_get(Tp&
_ret)
874 return operation::finalize::mpi_get<Type, true>{ *
this }(
_ret);
879template <
typename Type>
880typename storage<Type, true>::dmp_result_t
881storage<Type, true>::upc_get()
884 operation::finalize::upc_get<Type, true>{ *
this }(
_ret);
890template <
typename Type>
891template <
typename Tp>
893storage<Type, true>::upc_get(Tp&
_ret)
895 return operation::finalize::upc_get<Type, true>{ *
this }(
_ret);
900template <
typename Type>
901typename storage<Type, true>::dmp_result_t
902storage<Type, true>::dmp_get()
905 operation::finalize::dmp_get<Type, true>{ *
this }(
_ret);
911template <
typename Type>
912template <
typename Tp>
914storage<Type, true>::dmp_get(Tp&
_ret)
916 return operation::finalize::dmp_get<Type, true>{ *
this }(
_ret);
921template <
typename Type>
923storage<Type, true>::internal_print()
927 if(!m_initialized && !m_finalized)
930 auto _is_primary = singleton_t::is_master(
this);
931 auto _primary_instance = singleton_t::master_instance();
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);
943 if(_primary_instance)
944 _primary_instance->merge(
this);
954 instance_count().store(0);
959 if(!m_graph_data_instance)
961 instance_count().store(0);
966 if(_data().graph().size() <= 1)
968 instance_count().store(0);
973 if(m_settings->get_auto_output())
975 m_printer.reset(
new printer_t(Type::get_label(),
this, m_settings));
978 m_manager->add_entries(this->size());
980 m_printer->execute();
983 instance_count().store(0);
989template <
typename Type>
991storage<Type, true>::get_shared_manager()
993 using func_t = std::function<void()>;
996 if(!this_type::is_finalizing())
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");
1006 auto _pos = std::string::npos;
1007 while((_pos = _label.find_first_of(
" -")) != std::string::npos)
1008 _label = _label.replace(_pos, 1,
"_");
1010 for(
auto& itr : _label)
1013 for(
auto itr : {
':',
'<',
'>' })
1015 while((_pos = _label.find(itr)) != std::string::npos)
1016 _pos = _label.erase(_pos, 1).find(itr);
1018 std::stringstream env_var;
1019 env_var <<
"TIMEMORY_" << _label <<
"_ENABLED";
1020 auto _enabled = tim::get_env<bool>(env_var.str(),
true);
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();
1029 auto _cleanup = [_is_master, _instance_id]() {
1039 func_t _finalize = [&]() {
1040 auto _instance = this_type::get_singleton();
1043 auto _debug_v = m_settings->get_debug();
1044 auto _verb_v = m_settings->get_verbose();
1045 if(_debug_v || _verb_v > 1)
1047 PRINT_HERE(
"[%s] %s", demangle<Type>().c_str(),
1048 "calling singleton::reset(this)");
1050 _instance->reset(
this);
1053 if(_debug_v || _verb_v > 1)
1055 PRINT_HERE(
"[%s] %s", demangle<Type>().c_str(),
1056 "calling singleton::reset()");
1072 demangle<Type>(), m_instance_id, std::move(_sync));
1073 m_manager->add_synchronization(demangle<Type>(), m_instance_id,
1077 m_manager->add_finalizer(demangle<Type>(), std::move(_cleanup),
1078 std::move(_finalize), m_is_master,
1079 trait::fini_priority<Type>::value);
1090template <
typename Type>
1092: base_type(singleton_t::is_master_thread(), instance_count()++,
demangle<Type>())
1097 get_shared_manager();
1104template <
typename Type>
1113template <
typename Type>
1117 if(!m_stack.empty() && m_settings->get_stack_clearing())
1119 std::unordered_set<Type*> _stack = m_stack;
1120 for(
auto& itr : _stack)
1121 operation::stop<Type>{ *itr };
1128template <
typename Type>
1137 m_settings->get_debug() && m_settings->get_verbose() > 1, 16);
1139 m_initialized =
true;
1141 using init_t = operation::init<Type>;
1147 init_t(upcast, operation::mode_constant<operation::init_mode::thread>{});
1151 init_t(upcast, operation::mode_constant<operation::init_mode::global>{});
1152 init_t(upcast, operation::mode_constant<operation::init_mode::thread>{});
1158template <
typename Type>
1170 using fini_t = operation::fini<Type>;
1178 worker_is_finalizing() =
true;
1179 fini_t(upcast, operation::mode_constant<operation::fini_mode::thread>{});
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>{});
1192template <
typename Type>
1194storage<Type, false>::stack_pop(Type* obj)
1196 auto itr = m_stack.find(obj);
1197 if(itr != m_stack.end())
1205template <
typename Type>
1207storage<Type, false>::merge()
1209 auto m_children = singleton_t::children();
1210 if(m_children.size() == 0)
1213 if(m_settings->get_stack_clearing())
1215 for(
auto& itr : m_children)
1224template <
typename Type>
1226storage<Type, false>::merge(this_type* itr)
1229 operation::finalize::merge<Type, false>(*
this, *itr);
1234template <
typename Type>
1236storage<Type, false>::get_shared_manager()
1238 using func_t = std::function<void()>;
1241 if(!this_type::is_finalizing())
1245 if(m_manager->is_finalizing())
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");
1253 auto _pos = std::string::npos;
1254 while((_pos = _label.find_first_of(
" -")) != std::string::npos)
1255 _label = _label.replace(_pos, 1,
"_");
1257 for(
auto& itr : _label)
1260 for(
auto itr : {
':',
'<',
'>' })
1262 while((_pos = _label.find(itr)) != std::string::npos)
1263 _pos = _label.erase(_pos, 1).find(itr);
1265 std::stringstream env_var;
1266 env_var <<
"TIMEMORY_" << _label <<
"_ENABLED";
1267 auto _enabled = tim::get_env<bool>(env_var.str(),
true);
1270 auto _cleanup = [&]() {};
1271 func_t _finalize = [&]() {
1272 auto _instance = this_type::get_singleton();
1275 auto _debug_v = m_settings->get_debug();
1276 auto _verb_v = m_settings->get_verbose();
1277 if(_debug_v || _verb_v > 1)
1279 PRINT_HERE(
"[%s] %s", demangle<Type>().c_str(),
1280 "calling singleton::reset(this)");
1282 _instance->reset(
this);
1285 if(_debug_v || _verb_v > 1)
1287 PRINT_HERE(
"[%s] %s", demangle<Type>().c_str(),
1288 "calling singleton::reset()");
1301 m_manager->add_finalizer(demangle<Type>(), std::move(_cleanup),
1302 std::move(_finalize), m_is_master,
1303 trait::fini_priority<Type>::value);
storage(bool _is_master, int64_t _instance_id, std::string _label)
virtual bool thread_init()
virtual bool global_init()
virtual void initialize()
virtual void stack_clear()
std::shared_ptr< settings > m_settings
hash_value_t add_hash_id(const std::string &_prefix)
hash_map_ptr_t m_hash_ids
void free_shared_manager()
static std::atomic< int > & storage_once_flag()
static void stop_profiler()
std::shared_ptr< manager > m_manager
hash_alias_ptr_t m_hash_aliases
void add_file_output(const string_t &_category, const string_t &_label, const string_t &_file)
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.
static bool is_main_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.
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
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
std::unordered_map< hash_value_t, hash_value_t > hash_alias_map_t
std::unordered_map< hash_value_t, std::string > hash_map_t
void pop(TupleT< Tp... > &obj, Args &&... args)
char const std::string & _prefix
std::unique_lock< mutex_t > auto_lock_t
Unique lock type around mutex_t.
void initialize(CompList< CompTypes... > &obj, std::initializer_list< EnumT > components)
typename std::remove_pointer< U >::type remove_pointer_t
typename std::decay< T >::type decay_t
Alias template for decay.
std::string demangle(const char *_mangled_name, int *_status=nullptr)
tim::mpl::apply< std::string > string
auto get(const auto_bundle< Tag, Types... > &_obj)
void consume_parameters(ArgsT &&...)
The declaration for the types for storage without definitions.
Include the macros for storage.
#define TIMEMORY_STORAGE_LINKAGE
Declare the storage types.
static bool & has_storage()
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,...)
#define TIMEMORY_CONDITIONAL_DEMANGLED_BACKTRACE(CONDITION, DEPTH)
#define DEBUG_PRINT_HERE(...)
#define TIMEMORY_EXCEPTION(...)