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/user_bundle/components.hpp
27  * \brief Implementation of the user_bundle component(s)
28  */
29 
30 #pragma once
31 
33 #include "timemory/components/user_bundle/backends.hpp"
35 #include "timemory/mpl/apply.hpp"
36 #include "timemory/mpl/types.hpp"
40 #include "timemory/units.hpp"
42 
43 #include <algorithm>
44 #include <functional>
45 #include <regex>
46 #include <string>
47 #include <unordered_map>
48 #include <utility>
49 #include <vector>
50 
51 //======================================================================================//
52 //
53 namespace tim
54 {
55 //
56 //--------------------------------------------------------------------------------------//
57 //
58 namespace env
59 {
60 //
61 using user_bundle_spec_t = std::function<std::string()>;
62 //
64  std::unordered_map<size_t, std::vector<user_bundle_spec_t>>;
65 //
66 //--------------------------------------------------------------------------------------//
67 /// non-static so that projects can globally change this for their project/API
68 template <typename ApiT>
70 {
71  static user_bundle_variables_t _instance{};
72  return _instance;
73 }
74 //
75 #if defined(TIMEMORY_USER_BUNDLE_HEADER_MODE)
76 /// static so that projects cannot globally change this
78 static inline user_bundle_variables_t& get_user_bundle_variables(project::kokkosp);
79 //
80 inline std::vector<TIMEMORY_COMPONENT>
81 get_bundle_components(const std::vector<user_bundle_spec_t>& _priority);
82 #else
83 /// static so that projects cannot globally change this
86 //
87 std::vector<TIMEMORY_COMPONENT>
88 get_bundle_components(const std::vector<user_bundle_spec_t>& _priority);
89 #endif
90 //
91 //--------------------------------------------------------------------------------------//
92 //
93 template <size_t Idx, typename Api, typename AltApi = Api>
94 void
95 initialize_bundle(AltApi _api = AltApi{})
96 {
97  using user_bundle_type = component::user_bundle<Idx, Api>;
98  auto& variables = env::get_user_bundle_variables(_api);
99  auto itr = variables.find(Idx);
100  if(itr != variables.end())
101  {
102  auto _enum = env::get_bundle_components(itr->second);
103  tim::configure<user_bundle_type>(_enum);
104  }
105 }
106 //
107 } // namespace env
108 //
109 //--------------------------------------------------------------------------------------//
110 //
111 namespace component
112 {
113 //
114 //--------------------------------------------------------------------------------------//
115 //
116 // USER BUNDLE
117 //
118 //--------------------------------------------------------------------------------------//
119 //
120 template <size_t Idx, typename Tag>
122 : public base<user_bundle<Idx, Tag>, void>
124 {
125 public:
126  static constexpr auto index = Idx;
127  using tag_type = Tag;
128  using mutex_t = std::mutex;
129  using lock_t = std::unique_lock<mutex_t>;
131 
132  using value_type = void;
136 
137  friend struct operation::record<this_type>;
138  friend struct operation::start<this_type>;
139  friend struct operation::stop<this_type>;
140  friend struct operation::set_started<this_type>;
141  friend struct operation::set_stopped<this_type>;
142 
143  using start_func_t = std::function<void*(const string_t&, scope::config)>;
144  using stop_func_t = std::function<void(void*)>;
145  using get_func_t = std::function<void(void*, void*&, size_t)>;
146  using delete_func_t = std::function<void(void*)>;
147 
148  static string_t label() { return "user_bundle"; }
150  {
151  return "Generic bundle of components designed for runtime configuration by a "
152  "user via environment variables and/or direct insertion";
153  }
154  static value_type record() {}
155 
156  static void global_init() TIMEMORY_VISIBILITY("default");
157  static void global_init(storage_type*) { global_init(); }
158 
159  using opaque_array_t = std::vector<opaque>;
160  using typeid_vec_t = std::vector<size_t>;
161  using typeid_set_t = std::set<size_t>;
162 
163  static size_t bundle_size() { return get_data().size(); }
164 
165 public:
166  //----------------------------------------------------------------------------------//
167  // Captures the statically-defined data so these can be changed without
168  // affecting this instance
169  //
171  : m_scope(scope::get_default())
173  , m_bundle(get_data())
174  {}
175 
177  : base_type(rhs)
178  , m_scope(rhs.m_scope)
179  , m_prefix(rhs.m_prefix)
180  , m_typeids(rhs.m_typeids)
181  , m_bundle(rhs.m_bundle)
182  {
183  for(auto& itr : m_bundle)
184  itr.set_copy(true);
185  }
186 
187  explicit user_bundle(const char* _prefix, scope::config _scope = scope::get_default())
188  : m_scope(_scope)
189  , m_prefix(_prefix)
191  , m_bundle(get_data())
192  {}
193 
194  user_bundle(const char* _prefix, opaque_array_t _bundle_vec, typeid_vec_t _typeids,
195  scope::config _scope = scope::get_default())
196  : m_scope(_scope)
197  , m_prefix(_prefix)
198  , m_typeids(std::move(_typeids))
199  , m_bundle(std::move(_bundle_vec))
200  {}
201 
202  user_bundle(const char* _prefix, opaque_array_t _bundle_vec,
203  const typeid_set_t& _typeids, scope::config _scope = scope::get_default())
204  : m_scope(_scope)
205  , m_prefix(_prefix)
206  , m_bundle(std::move(_bundle_vec))
207  {
208  m_typeids.reserve(_typeids.size());
209  for(const auto& itr : _typeids)
210  m_typeids.emplace_back(itr);
211  }
212 
214  {
215  for(auto& itr : m_bundle)
216  itr.cleanup();
217  }
218 
220  {
221  if(this == &rhs)
222  return *this;
223 
224  base_type::operator=(rhs);
225  m_scope = rhs.m_scope;
226  m_prefix = rhs.m_prefix;
227  m_typeids = rhs.m_typeids;
228  m_bundle = rhs.m_bundle;
229  for(auto& itr : m_bundle)
230  itr.set_copy(true);
231 
232  return *this;
233  }
234 
235  user_bundle(user_bundle&& rhs) noexcept
236  : base_type(std::move(rhs))
237  , m_scope(std::move(rhs.m_scope))
238  , m_prefix(std::move(rhs.m_prefix))
239  , m_typeids(std::move(rhs.m_typeids))
240  , m_bundle(std::move(rhs.m_bundle))
241  {
242  rhs.m_bundle.clear();
243  }
244 
246  {
247  if(this != &rhs)
248  {
249  base_type::operator=(std::move(rhs));
250  m_scope = std::move(rhs.m_scope);
251  m_prefix = std::move(rhs.m_prefix);
252  m_typeids = std::move(rhs.m_typeids);
253  m_bundle = std::move(rhs.m_bundle);
254  rhs.m_bundle.clear();
255  }
256  return *this;
257  }
258 
259 public:
260  // Configure the tool for a specific component
261  static void configure(opaque&& obj, std::set<size_t>&& _typeids)
262  {
263  if(obj)
264  {
265  lock_t lk(get_lock());
266  size_t sum = 0;
267  for(auto&& itr : _typeids)
268  {
269  if(itr > 0 && contains(itr, get_typeids()))
270  {
271  if(settings::verbose() > 1 || settings::debug())
272  PRINT_HERE("Skipping duplicate typeid: %lu", (unsigned long) itr);
273  return;
274  }
275  sum += itr;
276  if(itr > 0)
277  get_typeids().emplace_back(itr);
278  }
279  if(sum == 0)
280  {
281  PRINT_HERE("No typeids. Sum: %lu", (unsigned long) sum);
282  return;
283  }
284  get_data().emplace_back(std::move(obj));
285  }
286  }
287 
288  template <typename Type, typename... Types, typename... Args>
289  static void configure(Args&&... args)
290  {
291  this_type::configure(factory::get_opaque<Type>(std::forward<Args>(args)...),
292  factory::get_typeids<Type>());
293 
295  this_type::configure(factory::get_opaque<Types>(std::forward<Args>(args)...),
296  factory::get_typeids<Types>()));
297  }
298 
299  //----------------------------------------------------------------------------------//
300  // Explicitly clear the previous configurations
301  //
302  static void reset()
303  {
304  if(settings::verbose() > 3 || settings::debug())
305  PRINT_HERE("Resetting %s", demangle<this_type>().c_str());
306  lock_t lk(get_lock());
307  get_data().clear();
308  get_typeids().clear();
309  }
310 
311 public:
312  //----------------------------------------------------------------------------------//
313  // Member functions
314  //
315  void setup()
316  {
317  if(!m_setup)
318  {
319  m_setup = true;
320  for(auto& itr : m_bundle)
321  itr.setup(m_prefix, m_scope);
322  }
323  }
324 
325  void push()
326  {
327  setup();
328  for(auto& itr : m_bundle)
329  itr.push(m_prefix, m_scope);
330  }
331 
332  void sample()
333  {
334  setup();
335  for(auto& itr : m_bundle)
336  itr.sample();
337  }
338 
339  void start()
340  {
341  setup();
342  for(auto& itr : m_bundle)
343  itr.start();
344  }
345 
346  void stop()
347  {
348  for(auto& itr : m_bundle)
349  itr.stop();
350  }
351 
352  void pop()
353  {
354  for(auto& itr : m_bundle)
355  itr.pop();
356  }
357 
358  void clear()
359  {
361  stop();
362  m_typeids.clear();
363  m_bundle.clear();
364  m_setup = false;
365  }
366 
367  template <typename T>
368  T* get()
369  {
370  auto _typeid_hash = typeid_hash<T>();
371  void* void_ptr = nullptr;
372  for(auto& itr : m_bundle)
373  {
374  itr.get(void_ptr, _typeid_hash);
375  if(void_ptr)
376  return static_cast<T*>(void_ptr);
377  }
378  return static_cast<T*>(void_ptr);
379  }
380 
381  void get(void*& ptr, size_t _hash) const
382  {
383  if(ptr == nullptr)
384  {
385  for(const auto& itr : m_bundle)
386  {
387  itr.get(ptr, _hash);
388  if(ptr)
389  break;
390  }
391  }
392  }
393 
394  void get() {}
395 
396  void set_prefix(const char* _prefix)
397  {
398  m_prefix = _prefix;
399  m_setup = false;
400  }
401 
402  void set_scope(const scope::config& val)
403  {
404  m_scope = val;
405  m_setup = false;
406  }
407 
408  TIMEMORY_NODISCARD size_t size() const { return m_bundle.size(); }
409 
410 public:
411  // Configure the tool for a specific component
412  void insert(opaque&& obj, typeid_set_t&& _typeids)
413  {
414  if(obj)
415  {
416  size_t sum = 0;
417  for(auto&& itr : _typeids)
418  {
419  if(itr > 0 && contains(itr, m_typeids))
420  {
421  if(settings::verbose() > 1 || settings::debug())
422  PRINT_HERE("Skipping duplicate typeid: %lu", (unsigned long) itr);
423  return;
424  }
425  sum += itr;
426  if(itr > 0)
427  m_typeids.emplace_back(itr);
428  }
429  if(sum == 0)
430  {
431  PRINT_HERE("No typeids. Sum: %lu", (unsigned long) sum);
432  return;
433  }
434  m_bundle.emplace_back(std::move(obj));
435  }
436  }
437 
438  template <typename Type, typename... Types, typename... Args>
439  void insert(Args... args)
440  {
441  this->insert(factory::get_opaque<Type>(args...), factory::get_typeids<Type>());
442  TIMEMORY_FOLD_EXPRESSION(this->insert(factory::get_opaque<Types>(args...),
443  factory::get_typeids<Types>()));
444  }
445 
446 protected:
447  bool m_setup = false;
449  const char* m_prefix = nullptr;
452 
453 protected:
454  static bool contains(size_t _val, const typeid_vec_t& _targ)
455  {
456  return std::any_of(_targ.begin(), _targ.end(),
457  [&_val](auto itr) { return (itr == _val); });
458  }
459 
460 private:
461  struct persistent_data
462  {
463  mutex_t m_lock;
464  opaque_array_t m_data = {};
465  typeid_vec_t m_typeids = {};
466  };
467 
468  //----------------------------------------------------------------------------------//
469  // Persistent data
470  //
471  static persistent_data& get_persistent_data() TIMEMORY_VISIBILITY("default");
472 
473 public:
474  //----------------------------------------------------------------------------------//
475  // Bundle data
476  //
477  static opaque_array_t& get_data() { return get_persistent_data().m_data; }
478 
479  //----------------------------------------------------------------------------------//
480  // The configuration strings
481  //
482  static typeid_vec_t& get_typeids() { return get_persistent_data().m_typeids; }
483 
484  //----------------------------------------------------------------------------------//
485  // Get lock
486  //
487  static mutex_t& get_lock() { return get_persistent_data().m_lock; }
488 };
489 //
490 //--------------------------------------------------------------------------------------//
491 //
492 template <size_t Idx, typename Tag>
493 void
495 {
496  if(settings::verbose() > 2 || settings::debug())
497  PRINT_HERE("Global initialization of %s", demangle<this_type>().c_str());
498  env::initialize_bundle<Idx, Tag>();
499 }
500 //
501 //--------------------------------------------------------------------------------------//
502 //
503 template <size_t Idx, typename Tag>
506 {
507  static persistent_data _instance{};
508  return _instance;
509 }
510 //
511 //--------------------------------------------------------------------------------------//
512 //
513 } // namespace component
514 } // namespace tim
515 //
516 //======================================================================================//
517 
518 #if defined(TIMEMORY_USER_BUNDLE_HEADER_MODE)
520 #endif
Forward declaration of user_bundle components. User-bundles are similar to the classical profiling in...
std::vector< TIMEMORY_COMPONENT > get_bundle_components(const std::vector< user_bundle_spec_t > &_priority)
Definition: components.cpp:93
void initialize_bundle(AltApi _api=AltApi{})
Definition: components.hpp:95
std::function< std::string()> user_bundle_spec_t
Definition: components.hpp:61
std::unordered_map< size_t, std::vector< user_bundle_spec_t > > user_bundle_variables_t
Definition: components.hpp:64
user_bundle_variables_t & get_user_bundle_variables(TIMEMORY_API)
static so that projects cannot globally change this
Definition: components.cpp:37
Definition: kokkosp.cpp:38
char const std::string & _prefix
Definition: definition.hpp:59
std::recursive_mutex mutex_t
Recursive mutex is used for convenience since the performance penalty vs. a regular mutex is not real...
Definition: utility.hpp:111
tim::mpl::apply< std::string > string
Definition: macros.hpp:52
The declaration for the types for settings without definitions.
bool get_is_running() const
Definition: data.hpp:455
storage< Tp, Value > storage_type
Definition: declaration.hpp:90
void get(void *&ptr, size_t _hash) const
Definition: components.hpp:381
static bool contains(size_t _val, const typeid_vec_t &_targ)
Definition: components.hpp:454
user_bundle & operator=(user_bundle &&rhs) noexcept
Definition: components.hpp:245
user_bundle(const char *_prefix, opaque_array_t _bundle_vec, const typeid_set_t &_typeids, scope::config _scope=scope::get_default())
Definition: components.hpp:202
static void configure(opaque &&obj, std::set< size_t > &&_typeids)
Definition: components.hpp:261
static void global_init(storage_type *)
Definition: components.hpp:157
static value_type record()
Definition: components.hpp:154
void insert(opaque &&obj, typeid_set_t &&_typeids)
Definition: components.hpp:412
std::function< void(void *, void *&, size_t)> get_func_t
Definition: components.hpp:145
user_bundle(user_bundle &&rhs) noexcept
Definition: components.hpp:235
static string_t description()
Definition: components.hpp:149
static constexpr auto index
Definition: components.hpp:126
static opaque_array_t & get_data()
Definition: components.hpp:477
std::function< void *(const string_t &, scope::config)> start_func_t
Definition: components.hpp:143
static size_t bundle_size()
Definition: components.hpp:163
void insert(Args... args)
Definition: components.hpp:439
typename base_type::storage_type storage_type
Definition: components.hpp:135
void set_scope(const scope::config &val)
Definition: components.hpp:402
user_bundle(const char *_prefix, opaque_array_t _bundle_vec, typeid_vec_t _typeids, scope::config _scope=scope::get_default())
Definition: components.hpp:194
std::unique_lock< mutex_t > lock_t
Definition: components.hpp:129
static void configure(Args &&... args)
Definition: components.hpp:289
user_bundle(const user_bundle &rhs)
Definition: components.hpp:176
static mutex_t & get_lock()
Definition: components.hpp:487
static string_t label()
Definition: components.hpp:148
user_bundle(const char *_prefix, scope::config _scope=scope::get_default())
Definition: components.hpp:187
user_bundle & operator=(const user_bundle &rhs)
Definition: components.hpp:219
std::function< void(void *)> delete_func_t
Definition: components.hpp:146
std::vector< opaque > opaque_array_t
Definition: components.hpp:159
void set_prefix(const char *_prefix)
Definition: components.hpp:396
std::set< size_t > typeid_set_t
Definition: components.hpp:161
std::function< void(void *)> stop_func_t
Definition: components.hpp:144
std::vector< size_t > typeid_vec_t
Definition: components.hpp:160
base< this_type, value_type > base_type
Definition: components.hpp:134
static typeid_vec_t & get_typeids()
Definition: components.hpp:482
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
this data type encodes the options of storage scope. The default is hierarchical (tree) scope....
Definition: types.hpp:446
#define PRINT_HERE(...)
Definition: macros.hpp:147
#define TIMEMORY_FOLD_EXPRESSION(...)
Definition: types.hpp:55