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.
timemory.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 "caliper/ConfigManager.h"
28 #include "caliper/cali.h"
29 
30 #include "timemory/api.hpp"
33 
34 #if defined(TIMEMORY_PYBIND11_SOURCE)
35 # include "pybind11/cast.h"
36 # include "pybind11/pybind11.h"
37 # include "pybind11/stl.h"
38 #endif
39 
40 #include <map>
41 #include <vector>
42 
43 //======================================================================================//
44 //
45 namespace tim
46 {
47 namespace trait
48 {
49 //
50 //--------------------------------------------------------------------------------------//
51 //
52 template <>
53 struct python_args<TIMEMORY_RECORD, component::caliper_loop_marker>
54 {
56 };
57 //
58 template <>
59 struct python_args<TIMEMORY_MARK_BEGIN, component::caliper_loop_marker>
60 {
62 };
63 //
64 template <>
65 struct python_args<TIMEMORY_MARK_END, component::caliper_loop_marker>
66 {
68 };
69 } // namespace trait
70 //
71 //--------------------------------------------------------------------------------------//
72 //
73 namespace component
74 {
76 {
77  using attributes_t = int;
78 
79  static void _init()
80  {
82  puts("Initializing caliper...");
83  cali_init();
84  }
85 
86  static void init()
87  {
88  static bool _ini = (_init(), true);
89  consume_parameters(_ini);
90  }
91 
92  static std::string& get_channel() { return get_persistent_data().channel; }
93 
94  static attributes_t& get_attributes() { return get_persistent_data().attributes; }
95 
97  {
98  return (get_nested() | CALI_ATTR_SCOPE_THREAD);
99  }
100 
102  {
103  return (tim::settings::flat_profile()) ? 0 : CALI_ATTR_NESTED;
104  }
105 
106  static auto get_process_scope()
107  {
108  return attributes_t(get_nested() | CALI_ATTR_SCOPE_PROCESS);
109  }
110 
111  static auto get_thread_scope()
112  {
113  return attributes_t(get_nested() | CALI_ATTR_SCOPE_THREAD);
114  }
115 
116  static auto get_task_scope()
117  {
118  return attributes_t(get_nested() | CALI_ATTR_SCOPE_TASK);
119  }
120 
124 
125  static std::string label() { return "caliper"; }
127  {
128  return "Forwards markers to Caliper instrumentation";
129  }
130 
131  // when inherited types are constructed
133 
134 private:
135  struct persistent_data
136  {
137  std::string channel = "timemory";
138  attributes_t attributes = (get_nested() | CALI_ATTR_SCOPE_THREAD);
139  };
140 
141  static persistent_data& get_persistent_data()
142  {
143  static auto _instance = persistent_data{};
144  return _instance;
145  }
146 };
147 //
148 //--------------------------------------------------------------------------------------//
149 //
150 /// \struct tim::component::caliper_config
151 /// \brief Component which provides Caliper `cali::ConfigManager`.
152 ///
153 struct caliper_config
154 : public base<caliper_config, void>
155 , private policy::instance_tracker<caliper_config, false>
156 {
157  using value_type = void;
159  using arg_map_t = std::map<std::string, std::string>;
160  using arg_vec_t = std::vector<std::string>;
161 
162  static std::string label() { return "caliper_config"; }
163  static std::string description() { return "Caliper configuration manager"; }
164 
165  static auto& get_manager()
166  {
167  static cali::ConfigManager _instance;
168  return _instance;
169  }
170 
171  static void configure(const arg_vec_t& _args, const arg_map_t& _kwargs = {})
172  {
173  std::string cmd{};
174  {
175  std::stringstream ss;
176  for(auto& itr : _args)
177  ss << "," << itr;
178  if(!ss.str().empty())
179  cmd = ss.str().substr(1);
180  }
181  {
182  std::stringstream ss;
183  for(auto& itr : _kwargs)
184  {
185  auto _arg = itr.second;
186  if(_arg.empty())
187  {
188  ss << "," << itr.first;
189  }
190  else
191  {
192  ss << "," << itr.first << "=(" << _arg << ")";
193  }
194  }
195  if(!ss.str().empty())
196  {
197  if(!cmd.empty())
198  cmd += ",";
199  cmd += ss.str().substr(1);
200  }
201  }
202  if(!cmd.empty())
203  {
205  std::cerr << "Configuring caliper with :: " << cmd << std::endl;
206  get_manager().add(cmd.c_str());
207  if(get_manager().error())
208  {
209  std::cerr << "Caliper config error: " << get_manager().error_msg()
210  << std::endl;
211  }
212  }
213  else
214  {
216  std::cerr << "Caliper was not configured" << std::endl;
217  }
218  }
219 
220 #if defined(TIMEMORY_PYBIND11_SOURCE)
221  //
222  /// this is called by python api
223  ///
224  /// args --> pybind11::args --> pybind11::tuple
225  /// kwargs --> pybind11::kwargs --> pybind11::dict
226  ///
227  void configure(project::python, pybind11::args _args, pybind11::kwargs _kwargs)
228  {
229  std::string cmd = "";
230  {
231  std::stringstream ss;
232  for(auto& itr : _args)
233  ss << "," << itr.cast<std::string>();
234  if(!ss.str().empty())
235  cmd = ss.str().substr(1);
236  }
237  {
238  std::stringstream ss;
239  for(auto& itr : _kwargs)
240  {
241  auto _arg = itr.second.cast<std::string>();
242  if(_arg.empty())
243  ss << "," << itr.first.cast<std::string>();
244  else
245  {
246  ss << "," << itr.first.cast<std::string>() << "=(" << _arg << ")";
247  }
248  }
249  if(!ss.str().empty())
250  {
251  if(!cmd.empty())
252  cmd += ",";
253  cmd += ss.str().substr(1);
254  }
255  }
256  if(!cmd.empty())
257  {
259  std::cerr << "Configuring caliper with :: " << cmd << std::endl;
260  get_manager().add(cmd.c_str());
261  if(get_manager().error())
262  std::cerr << "Caliper config error: " << get_manager().error_msg()
263  << std::endl;
264  }
265  else
266  {
268  std::cerr << "Caliper was not configured" << std::endl;
269  }
270  }
271 #endif
272 
273  void start()
274  {
275  DEBUG_PRINT_HERE("%s", "Starting Caliper ConfigManager");
276  auto cnt = instance_tracker_t::start();
277  if(cnt == 0)
278  get_manager().start();
279  }
280 
281  void stop()
282  {
283  DEBUG_PRINT_HERE("%s", "Flushing Caliper ConfigManager");
284  auto cnt = instance_tracker_t::stop();
285  if(cnt == 0)
286  get_manager().flush();
287  }
288 };
289 //
290 //--------------------------------------------------------------------------------------//
291 //
292 /// \struct tim::component::caliper_marker
293 /// \brief Standard marker for the Caliper Performance Analysis Toolbox
294 ///
295 struct caliper_marker
296 : public base<caliper_marker, void>
297 , public caliper_common
298 {
299  // timemory component api
300  using value_type = void;
303 
304  static std::string label() { return "caliper_marker"; }
306  {
307  return "Generic forwarding of markers to Caliper instrumentation";
308  }
309 
310  TIMEMORY_DEFAULT_OBJECT(caliper_marker)
311 
312  void start()
313  {
314  DEBUG_PRINT_HERE("%s", m_prefix);
315  cali_begin_string(m_id, m_prefix);
316  }
317  void stop()
318  {
319  DEBUG_PRINT_HERE("%s", m_prefix);
320  cali_safe_end_string(m_id, m_prefix);
321  }
322 
323  void set_prefix(const char* _prefix) { m_prefix = _prefix; }
324 
325 private:
326  const char* m_prefix = nullptr;
327  cali_id_t m_id = cali_create_attribute("timemory", CALI_TYPE_STRING,
329 
330 public:
331  // emulate CALI_MARK_BEGIN and CALI_MARK_END via static calls which require a string
332  static void start(const std::string& _name) { CALI_MARK_BEGIN(_name.c_str()); }
333  static void stop(const std::string& _name) { CALI_MARK_END(_name.c_str()); }
334 
335 #if defined(TIMEMORY_PYBIND11_SOURCE)
336  //
337  /// this is called by python api
338  ///
339  /// Use this to add customizations to the python module. The instance
340  /// of the component is within in a variadic wrapper which is used
341  /// elsewhere to ensure that calling mark_begin(...) on a component
342  /// without that member function is not invalid
343  ///
344  template <template <typename...> class BundleT>
345  static void configure(project::python,
346  pybind11::class_<BundleT<caliper_marker>>& _pyclass)
347  {
348  // define two lambdas to pass to pybind11 instead of &caliper_marker
349  // and &caliper_marker::stop because it would be ambiguous
350  auto _bregion = [](const std::string& _name) { caliper_marker::start(_name); };
351  auto _eregion = [](const std::string& _name) { caliper_marker::stop(_name); };
352  // define these as static member functions so that they can be called
353  // without object
354  _pyclass.def_static("begin_region", _bregion, "Begin a user-defined region");
355  _pyclass.def_static("end_region", _eregion, "End a user-defined region");
356  //
357  // add CALI_ATTRIBUTES
358  pybind11::enum_<cali_attr_properties> _pyattr(
359  _pyclass, "Attribute", pybind11::arithmetic(), "Attributes");
360  _pyattr.value("Nested", CALI_ATTR_NESTED)
361  .value("ThreadScope", CALI_ATTR_SCOPE_THREAD)
362  .value("ProcessScope", CALI_ATTR_SCOPE_PROCESS)
363  .value("TaskScope", CALI_ATTR_SCOPE_TASK);
364  // no need to add bindings to default start/stop, those are already added
365  }
366 #endif
367 };
368 //
369 //--------------------------------------------------------------------------------------//
370 //
371 /// \struct tim::component::caliper_loop_marker
372 /// \brief Loop marker for the Caliper Performance Analysis Toolbox
373 ///
374 struct caliper_loop_marker
375 : public base<caliper_loop_marker, void>
376 , public caliper_common
377 {
378  // timemory component api
379  using value_type = void;
382 
383  static std::string label() { return "caliper_loop_marker"; }
385  {
386  return "Variant of caliper_marker with support for loop marking";
387  }
388 
389  TIMEMORY_DEFAULT_OBJECT(caliper_loop_marker)
390 
391  void start()
392  {
393  DEBUG_PRINT_HERE("%s", m_prefix);
394  cali_begin_string(m_id, m_prefix);
395  m_id = cali_make_loop_iteration_attribute(m_prefix);
396  m_itr = 0;
397  }
398  void stop() { cali_end(m_id); }
399 
400  void mark_begin()
401  {
402  DEBUG_PRINT_HERE("%s", m_prefix);
403  cali_begin_int(m_id, m_itr++);
404  }
405  void mark_end()
406  {
407  DEBUG_PRINT_HERE("%s", m_prefix);
408  cali_end(m_id);
409  }
410 
411  template <typename T, enable_if_t<std::is_integral<T>::value, int> = 0>
412  void mark_begin(T itr)
413  {
414  DEBUG_PRINT_HERE("%s @ %i", m_prefix, (int) itr);
415  m_itr = itr;
416  cali_begin_int(m_id, m_itr++);
417  }
418 
419  template <typename T, enable_if_t<std::is_integral<T>::value, int> = 0>
420  void mark_end(T)
421  {
422  DEBUG_PRINT_HERE("%s @ %i", m_prefix, (int) m_itr);
423  cali_end(m_id);
424  }
425 
426  template <typename T, enable_if_t<std::is_integral<T>::value, int> = 0>
428  {
429  DEBUG_PRINT_HERE("%s @ %i", m_prefix, (int) itr);
430  m_itr = itr;
431  cali_begin_int(m_id, m_itr++);
432  return tim::scope::destructor([=]() { cali_end(m_id); });
433  }
434 
435  void set_prefix(const char* _prefix) { m_prefix = _prefix; }
436 
437 #if defined(TIMEMORY_PYBIND11_SOURCE)
438  template <template <typename...> class BundleT>
439  static void configure(project::python, pybind11::class_<BundleT<caliper_marker>>&)
440  {}
441 #endif
442 
443 private:
444  size_t m_itr = 0;
445  cali_id_t m_id = cali_create_attribute("timemory", CALI_TYPE_STRING,
447  const char* m_prefix = nullptr;
448 };
449 //
450 } // namespace component
451 } // namespace tim
452 //
453 //======================================================================================//
@ TIMEMORY_MARK_END
Definition: enum.h:664
@ TIMEMORY_MARK_BEGIN
Definition: enum.h:663
@ TIMEMORY_RECORD
Definition: enum.h:660
void stop(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:368
void start(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:298
trait that designates the type supports these arguments from python. Specializations MUST be structur...
Definition: kokkosp.cpp:38
char const std::string & _prefix
Definition: definition.hpp:59
flat_profile
Definition: settings.cpp:1491
void consume_parameters(ArgsT &&...) TIMEMORY_HIDDEN
Definition: types.hpp:285
tim::mpl::apply< std::string > string
Definition: macros.hpp:52
lightweight tuple-alternative for meta-programming logic
Definition: types.hpp:233
The declaration for the types for settings without definitions.
static std::string & get_channel()
Definition: timemory.hpp:92
static void enable_process_scope()
Definition: timemory.hpp:121
static std::string label()
Definition: timemory.hpp:125
static void enable_thread_scope()
Definition: timemory.hpp:122
static std::string description()
Definition: timemory.hpp:126
static attributes_t & get_attributes()
Definition: timemory.hpp:94
static attributes_t get_default_attributes()
Definition: timemory.hpp:96
static attributes_t get_nested()
Definition: timemory.hpp:101
static void configure(const arg_vec_t &_args, const arg_map_t &_kwargs={})
Definition: timemory.hpp:171
std::map< std::string, std::string > arg_map_t
Definition: timemory.hpp:159
static std::string description()
Definition: timemory.hpp:163
static std::string label()
Definition: timemory.hpp:162
std::vector< std::string > arg_vec_t
Definition: timemory.hpp:160
Loop marker for the Caliper Performance Analysis Toolbox.
Definition: components.hpp:69
void set_prefix(const char *_prefix)
Definition: timemory.hpp:435
tim::scope::destructor record(T itr)
Definition: timemory.hpp:427
static std::string description()
Definition: timemory.hpp:384
Standard marker for the Caliper Performance Analysis Toolbox.
Definition: components.hpp:56
static void stop(const std::string &_name)
Definition: timemory.hpp:333
static void start(const std::string &_name)
Definition: timemory.hpp:332
static std::string description()
Definition: timemory.hpp:305
static std::string label()
Definition: timemory.hpp:304
void set_prefix(const char *_prefix)
Definition: timemory.hpp:323
provides an object which can be returned from functions that will execute the lambda provided during ...
Definition: types.hpp:700
#define DEBUG_PRINT_HERE(...)
Definition: macros.hpp:163