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.
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#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//
45namespace tim
46{
47namespace trait
48{
49//
50//--------------------------------------------------------------------------------------//
51//
52template <>
53struct python_args<TIMEMORY_RECORD, component::caliper_loop_marker>
54{
56};
57//
58template <>
59struct python_args<TIMEMORY_MARK_BEGIN, component::caliper_loop_marker>
60{
62};
63//
64template <>
65struct python_args<TIMEMORY_MARK_END, component::caliper_loop_marker>
66{
68};
69} // namespace trait
70//
71//--------------------------------------------------------------------------------------//
72//
73namespace 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);
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
134private:
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///
153struct 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 {
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 static 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 auto cnt = instance_tracker_t::start();
276 if(cnt == 0)
277 {
279 "Starting Caliper ConfigManager");
280 get_manager().start();
281 }
282 }
283
284 void stop()
285 {
286 auto cnt = instance_tracker_t::stop();
287 if(cnt == 0)
288 {
290 "Flushing Caliper ConfigManager");
291 get_manager().flush();
292 }
293 }
294};
295//
296//--------------------------------------------------------------------------------------//
297//
298/// \struct tim::component::caliper_marker
299/// \brief Standard marker for the Caliper Performance Analysis Toolbox
300///
301struct caliper_marker
302: public base<caliper_marker, void>
303, public caliper_common
304{
305 // timemory component api
306 using value_type = void;
309
310 static std::string label() { return "caliper_marker"; }
312 {
313 return "Generic forwarding of markers to Caliper instrumentation";
314 }
315
316 TIMEMORY_DEFAULT_OBJECT(caliper_marker)
317
318 void start()
319 {
320 if(m_prefix == nullptr)
321 return;
322 DEBUG_PRINT_HERE("'%s'", m_prefix);
323 cali_begin_string(m_id, m_prefix);
324 }
325 void stop()
326 {
327 if(m_prefix == nullptr)
328 return;
329 DEBUG_PRINT_HERE("'%s'", m_prefix);
330 cali_safe_end_string(m_id, m_prefix);
331 }
332
333 void set_prefix(const char* _prefix) { m_prefix = _prefix; }
334
335private:
336 const char* m_prefix = nullptr;
337 cali_id_t m_id = cali_create_attribute("timemory", CALI_TYPE_STRING,
339
340public:
341 // emulate CALI_MARK_BEGIN and CALI_MARK_END via static calls which require a string
342 static void start(const std::string& _name) { CALI_MARK_BEGIN(_name.c_str()); }
343 static void stop(const std::string& _name) { CALI_MARK_END(_name.c_str()); }
344
345#if defined(TIMEMORY_PYBIND11_SOURCE)
346 //
347 /// this is called by python api
348 ///
349 /// Use this to add customizations to the python module. The instance
350 /// of the component is within in a variadic wrapper which is used
351 /// elsewhere to ensure that calling mark_begin(...) on a component
352 /// without that member function is not invalid
353 ///
354 template <template <typename...> class BundleT>
355 static void configure(project::python,
356 pybind11::class_<BundleT<caliper_marker>>& _pyclass)
357 {
358 // define two lambdas to pass to pybind11 instead of &caliper_marker
359 // and &caliper_marker::stop because it would be ambiguous
360 auto _bregion = [](const std::string& _name) { caliper_marker::start(_name); };
361 auto _eregion = [](const std::string& _name) { caliper_marker::stop(_name); };
362 // define these as static member functions so that they can be called
363 // without object
364 _pyclass.def_static("begin_region", _bregion, "Begin a user-defined region");
365 _pyclass.def_static("end_region", _eregion, "End a user-defined region");
366 //
367 // add CALI_ATTRIBUTES
368 pybind11::enum_<cali_attr_properties> _pyattr(
369 _pyclass, "Attribute", pybind11::arithmetic(), "Attributes");
370 _pyattr.value("Nested", CALI_ATTR_NESTED)
371 .value("ThreadScope", CALI_ATTR_SCOPE_THREAD)
372 .value("ProcessScope", CALI_ATTR_SCOPE_PROCESS)
373 .value("TaskScope", CALI_ATTR_SCOPE_TASK);
374 // no need to add bindings to default start/stop, those are already added
375 }
376#endif
377};
378//
379//--------------------------------------------------------------------------------------//
380//
381/// \struct tim::component::caliper_loop_marker
382/// \brief Loop marker for the Caliper Performance Analysis Toolbox
383///
384struct caliper_loop_marker
385: public base<caliper_loop_marker, void>
386, public caliper_common
387{
388 // timemory component api
389 using value_type = void;
392
393 static std::string label() { return "caliper_loop_marker"; }
395 {
396 return "Variant of caliper_marker with support for loop marking";
397 }
398
399 TIMEMORY_DEFAULT_OBJECT(caliper_loop_marker)
400
401 void start()
402 {
403 DEBUG_PRINT_HERE("%s", m_prefix);
404 cali_begin_string(m_id, m_prefix);
405 m_id = cali_make_loop_iteration_attribute(m_prefix);
406 m_itr = 0;
407 }
408 void stop() { cali_end(m_id); }
409
411 {
412 DEBUG_PRINT_HERE("%s", m_prefix);
413 cali_begin_int(m_id, m_itr++);
414 }
415 void mark_end()
416 {
417 DEBUG_PRINT_HERE("%s", m_prefix);
418 cali_end(m_id);
419 }
420
421 template <typename T, enable_if_t<std::is_integral<T>::value, int> = 0>
422 void mark_begin(T itr)
423 {
424 DEBUG_PRINT_HERE("%s @ %i", m_prefix, (int) itr);
425 m_itr = itr;
426 cali_begin_int(m_id, m_itr++);
427 }
428
429 template <typename T, enable_if_t<std::is_integral<T>::value, int> = 0>
430 void mark_end(T)
431 {
432 DEBUG_PRINT_HERE("%s @ %i", m_prefix, (int) m_itr);
433 cali_end(m_id);
434 }
435
436 template <typename T, enable_if_t<std::is_integral<T>::value, int> = 0>
438 {
439 DEBUG_PRINT_HERE("%s @ %i", m_prefix, (int) itr);
440 m_itr = itr;
441 cali_begin_int(m_id, m_itr++);
442 return tim::scope::destructor([=]() { cali_end(m_id); });
443 }
444
445 void set_prefix(const char* _prefix) { m_prefix = _prefix; }
446
447#if defined(TIMEMORY_PYBIND11_SOURCE)
448 template <template <typename...> class BundleT>
449 static void configure(project::python, pybind11::class_<BundleT<caliper_marker>>&)
450 {}
451#endif
452
453private:
454 size_t m_itr = 0;
455 cali_id_t m_id = cali_create_attribute("timemory", CALI_TYPE_STRING,
457 const char* m_prefix = nullptr;
458};
459//
460} // namespace component
461} // namespace tim
462//
463//======================================================================================//
@ TIMEMORY_MARK_END
Definition: enum.h:690
@ TIMEMORY_MARK_BEGIN
Definition: enum.h:689
@ TIMEMORY_RECORD
Definition: enum.h:686
void stop(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:386
void start(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:316
trait that designates the type supports these arguments from python. Specializations MUST be structur...
Definition: kokkosp.cpp:39
std::array< char *, 4 > _args
char const std::string & _prefix
Definition: config.cpp:55
flat_profile
Definition: settings.cpp:1797
tim::mpl::apply< std::string > string
Definition: macros.hpp:53
void consume_parameters(ArgsT &&...)
Definition: types.hpp:285
lightweight tuple-alternative for meta-programming logic
Definition: types.hpp:233
static void enable_process_scope()
Definition: timemory.hpp:121
static std::string label()
Definition: timemory.hpp:125
static attributes_t & get_attributes()
Definition: timemory.hpp:94
static void enable_thread_scope()
Definition: timemory.hpp:122
static std::string description()
Definition: timemory.hpp:126
static std::string & get_channel()
Definition: timemory.hpp:92
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:445
tim::scope::destructor record(T itr)
Definition: timemory.hpp:437
static std::string description()
Definition: timemory.hpp:394
Standard marker for the Caliper Performance Analysis Toolbox.
Definition: components.hpp:56
static void stop(const std::string &_name)
Definition: timemory.hpp:343
static void start(const std::string &_name)
Definition: timemory.hpp:342
static std::string description()
Definition: timemory.hpp:311
static std::string label()
Definition: timemory.hpp:310
void set_prefix(const char *_prefix)
Definition: timemory.hpp:333
provides an object which can be returned from functions that will execute the lambda provided during ...
Definition: types.hpp:700
#define CONDITIONAL_PRINT_HERE(CONDITION,...)
Definition: macros.hpp:183
#define DEBUG_PRINT_HERE(...)
Definition: macros.hpp:168