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.
library.cpp
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#if !defined(TIMEMORY_LIBRARY_SOURCE)
26# define TIMEMORY_LIBRARY_SOURCE 1
27#endif
28
30
31#include "timemory/config.hpp"
32#include "timemory/library.h"
34#include "timemory/timemory.hpp"
35#include "timemory/trace.hpp"
36
37#include <cstdarg>
38#include <deque>
39#include <iostream>
40#include <stack>
41#include <unordered_map>
42#include <unordered_set>
43#include <vector>
44
45using namespace tim::component;
46
47//======================================================================================//
48
49extern "C"
50{
53}
54
55//======================================================================================//
56
59using toolset_t = typename library_toolset_t::component_type;
60using region_map_t = std::unordered_map<std::string, std::stack<uint64_t>>;
61using record_map_t = std::unordered_map<uint64_t, toolset_t>;
62using component_enum_t = std::vector<TIMEMORY_COMPONENT>;
63using components_stack_t = std::deque<component_enum_t>;
64
65static std::string spacer =
66 "#-------------------------------------------------------------------------#";
67
68//--------------------------------------------------------------------------------------//
69
70static record_map_t&
71get_record_map()
72{
73 static thread_local record_map_t _instance;
74 return _instance;
75}
76
77//--------------------------------------------------------------------------------------//
78
79static region_map_t&
80get_region_map()
81{
82 static thread_local region_map_t _instance;
83 return _instance;
84}
85
86//--------------------------------------------------------------------------------------//
87
89get_components_stack()
90{
91 static auto _leader_tid = std::this_thread::get_id();
92 static components_stack_t _leader_instance;
93 static thread_local components_stack_t _worker_instance = _leader_instance;
94 return (std::this_thread::get_id() == _leader_tid) ? _leader_instance
95 : _worker_instance;
96}
97
98//--------------------------------------------------------------------------------------//
99// default components to record
100//
101inline std::string&
103{
104 static std::string _instance =
105 tim::get_env<std::string>("TIMEMORY_GLOBAL_COMPONENTS", "wall_clock");
106 return _instance;
107}
108
109//--------------------------------------------------------------------------------------//
110// current set of components being recorded
111//
112inline component_enum_t&
114{
115 auto& _stack = get_components_stack();
116 if(_stack.empty())
117 {
118 _stack.push_back(
119 tim::enumerate_components(get_default_components(), "TIMEMORY_COMPONENTS"));
120 }
121 return _stack.back();
122}
123
124//--------------------------------------------------------------------------------------//
125
126std::array<bool, 2>&
128{
129 static auto _instance = std::array<bool, 2>({ { false, false } });
130 return _instance;
131}
132
133//--------------------------------------------------------------------------------------//
134//
135// timemory symbols
136//
137//--------------------------------------------------------------------------------------//
138
139extern "C"
140{
141 //----------------------------------------------------------------------------------//
142 // get a unique id
143 //
145 {
146 // the maps are thread-local so no concerns for data-race here since
147 // two threads updating at once and subsequently losing once of the updates
148 // still results in a unique id for that thread
149 static uint64_t uniqID = 0;
150 return uniqID++;
151 }
152
153 //----------------------------------------------------------------------------------//
154 // create a toolset of measurements
155 //
156 void timemory_create_record(const char* name, uint64_t* id, int n, int* ctypes)
157 {
159 {
160 (*timemory_create_function)(name, id, n, ctypes);
161 return;
162 }
163 // else: provide default behavior
164
165 static thread_local auto& _record_map = get_record_map();
167 _record_map.insert({ *id, toolset_t(name, true) });
168 tim::initialize(_record_map[*id], n, ctypes);
169 _record_map[*id].start();
170 if(_record_map.bucket_count() > _record_map.size())
171 _record_map.rehash(_record_map.size() + 10);
172 }
173
174 //----------------------------------------------------------------------------------//
175 // destroy a toolset of measurements
176 //
177 void timemory_delete_record(uint64_t id)
178 {
180 {
181 (*timemory_delete_function)(id);
182 }
183 else if(get_record_map().find(id) != get_record_map().end())
184 {
185 static thread_local auto& _record_map = get_record_map();
186 // stop recording, destroy objects, and erase key from map
187 _record_map[id].stop();
188 _record_map.erase(id);
189 }
190 }
191
192 //----------------------------------------------------------------------------------//
193 //
194 //
196
197 //----------------------------------------------------------------------------------//
198 //
199 //
201 {
202 if(name)
203 {
204 char* _name[1] = { name };
205 timemory_init_library(1, _name);
206 }
207 }
208
209 //----------------------------------------------------------------------------------//
210 // initialize the library
211 //
212 void timemory_init_library(int argc, char** argv)
213 {
215 if(get_library_state()[0])
216 return;
217 get_library_state()[0] = true;
218
219 if(argc < 1 && argv)
220 argc = 1;
221 if(argv == nullptr)
222 {
223 argc = 0;
224 }
225 else
226 {
227 int i = 0;
228 for(; i < argc; ++i)
229 {
230 if(argv[i] == nullptr)
231 {
232 argc = i;
233 break;
234 }
235 }
236 }
237
238 if(tim::settings::verbose() > 0)
239 {
240 printf("%s\n", spacer.c_str());
241 printf("\tInitialization of timemory library...\n");
242 printf("%s\n\n", spacer.c_str());
243 }
244
245 if(argc > 0 && argv)
247 tim::manager::instance()->update_metadata_prefix();
248 // tim::settings::parse();
249 }
250
251 //----------------------------------------------------------------------------------//
252 // finalize the library
254 {
256 get_library_state()[1] = true;
257
258 auto _manager = tim::manager::master_instance();
260 if(!_manager || !_settings)
261 return;
262
263 if(_settings->get_enabled() == false && get_record_map().empty())
264 return;
265
266 auto& _record_map = get_record_map();
267
268 if(_settings->get_verbose() > 0)
269 {
270 printf("\n%s\n", spacer.c_str());
271 printf("\tFinalization of timemory library...\n");
272 printf("%s\n\n", spacer.c_str());
273 }
274
275 // put keys into a set so that a potential LD_PRELOAD for timemory_delete_record
276 // is called and there is not a concern for the map iterator
277 std::unordered_set<uint64_t> keys;
278 for(auto& itr : _record_map)
279 keys.insert(itr.first);
280
281 // delete all the records
282 for(const auto& itr : keys)
284
285 // clear the map
286 _record_map.clear();
287
288 // have the manager finalize
290 tim::manager::instance()->finalize();
291
292 // do the finalization
294
295 // just in case
296 _settings->get_enabled() = false;
297
298 // set the finalization state to true
299 tim::dmp::set_finalized(true);
300
301 // reset manager
302 tim::manager::instance().reset();
303
304 // PGI and Intel compilers don't respect destruction order
305#if defined(__PGI) || defined(__INTEL_COMPILER)
306 _settings->get_output() = false;
307#endif
308 }
309
310 //----------------------------------------------------------------------------------//
311 // pause the collection
312 //
313 void timemory_pause(void) { tim::settings::enabled() = false; }
314
315 //----------------------------------------------------------------------------------//
316 // resume the collection
317 //
319
320 //----------------------------------------------------------------------------------//
321
322 void timemory_set_default(const char* _component_string)
323 {
326 tim::get_env<std::string>("TIMEMORY_GLOBAL_COMPONENTS", _component_string);
327 // tim::set_env("TIMEMORY_COMPONENTS", _component_string, 0);
328 static thread_local auto& _stack = get_components_stack();
329 if(_stack.empty())
331 }
332
333 //----------------------------------------------------------------------------------//
334
335 void timemory_set_environ(const char* evar, const char* eval, int over, int parse)
336 {
338 if(evar && eval)
339 {
340 tim::set_env(evar, eval, over);
341 if(parse > 0)
343 }
344 }
345
346 //----------------------------------------------------------------------------------//
347
348 void timemory_add_components(const char* _component_string)
349 {
351 auto& _stack = get_current_components();
352 for(auto itr : tim::enumerate_components(_component_string))
353 _stack.push_back(itr);
354 }
355
356 //----------------------------------------------------------------------------------//
357
358 void timemory_remove_components(const char* _component_string)
359 {
361 auto& _stack = get_current_components();
362 for(auto itr : tim::enumerate_components(_component_string))
363 _stack.erase(std::remove(_stack.begin(), _stack.end(), itr), _stack.end());
364 }
365
366 //----------------------------------------------------------------------------------//
367
368 void timemory_push_components(const char* _component_string)
369 {
371 static thread_local auto& _stack = get_components_stack();
372 _stack.push_back(tim::enumerate_components(_component_string));
373 }
374
375 //----------------------------------------------------------------------------------//
376
377 void timemory_push_components_enum(int types, ...)
378 {
380 static thread_local auto& _stack = get_components_stack();
381
382 component_enum_t comp({ types });
383 va_list args;
384 va_start(args, types);
385 for(int i = 0; i < TIMEMORY_COMPONENTS_END; ++i)
386 {
387 auto enum_arg = va_arg(args, int);
388 if(enum_arg >= TIMEMORY_COMPONENTS_END)
389 break;
390 comp.push_back(enum_arg);
391 }
392 va_end(args);
393
394 _stack.push_back(comp);
395 }
396
397 //----------------------------------------------------------------------------------//
398
400 {
402 static thread_local auto& _stack = get_components_stack();
403 if(_stack.size() > 1)
404 _stack.pop_back();
405 }
406
407 //----------------------------------------------------------------------------------//
408
409 void timemory_begin_record(const char* name, uint64_t* id)
410 {
412 if(!lk || tim::settings::enabled() == false)
413 {
415 return;
416 }
417 auto& comp = get_current_components();
418 timemory_create_record(name, id, comp.size(), (int*) (comp.data()));
419
420#if defined(DEBUG)
421 if(tim::settings::verbose() > 2)
422 printf("beginning record for '%s' (id = %lli)...\n", name,
423 (long long int) *id);
424#endif
425 }
426
427 //----------------------------------------------------------------------------------//
428
429 void timemory_begin_record_types(const char* name, uint64_t* id, const char* ctypes)
430 {
432 if(!lk || tim::settings::enabled() == false)
433 {
435 return;
436 }
437
438 auto comp = tim::enumerate_components(std::string(ctypes));
439 timemory_create_record(name, id, comp.size(), (int*) (comp.data()));
440
441#if defined(DEBUG)
442 if(tim::settings::verbose() > 2)
443 printf("beginning record for '%s' (id = %lli)...\n", name,
444 (long long int) *id);
445#endif
446 }
447
448 //----------------------------------------------------------------------------------//
449
450 void timemory_begin_record_enum(const char* name, uint64_t* id, ...)
451 {
453 if(!lk || tim::settings::enabled() == false)
454 {
456 return;
457 }
458
459 component_enum_t comp;
460 va_list args;
461 va_start(args, id);
462 for(int i = 0; i < TIMEMORY_COMPONENTS_END; ++i)
463 {
464 auto enum_arg = va_arg(args, int);
465 if(enum_arg >= TIMEMORY_COMPONENTS_END)
466 break;
467 comp.push_back(enum_arg);
468 }
469 va_end(args);
470
471 timemory_create_record(name, id, comp.size(), (int*) (comp.data()));
472
473#if defined(DEBUG)
474 if(tim::settings::verbose() > 2)
475 printf("beginning record for '%s' (id = %lli)...\n", name,
476 (long long int) *id);
477#endif
478 }
479
480 //----------------------------------------------------------------------------------//
481
482 uint64_t timemory_get_begin_record(const char* name)
483 {
485 if(!lk || tim::settings::enabled() == false)
487
488 uint64_t id = 0;
489 auto& comp = get_current_components();
490 timemory_create_record(name, &id, comp.size(), (int*) (comp.data()));
491
492#if defined(DEBUG)
493 if(tim::settings::verbose() > 2)
494 printf("beginning record for '%s' (id = %lli)...\n", name,
495 (long long int) id);
496#endif
497
498 return id;
499 }
500
501 //----------------------------------------------------------------------------------//
502
503 uint64_t timemory_get_begin_record_types(const char* name, const char* ctypes)
504 {
506 if(!lk || tim::settings::enabled() == false)
508
509 uint64_t id = 0;
510 auto comp = tim::enumerate_components(std::string(ctypes));
511 timemory_create_record(name, &id, comp.size(), (int*) (comp.data()));
512
513#if defined(DEBUG)
514 if(tim::settings::verbose() > 2)
515 printf("beginning record for '%s' (id = %lli)...\n", name,
516 (long long int) id);
517#endif
518
519 return id;
520 }
521
522 //----------------------------------------------------------------------------------//
523
524 uint64_t timemory_get_begin_record_enum(const char* name, ...)
525 {
527 if(!lk || tim::settings::enabled() == false)
529
530 uint64_t id = 0;
531
532 component_enum_t comp;
533 va_list args;
534 va_start(args, name);
535 for(int i = 0; i < TIMEMORY_COMPONENTS_END; ++i)
536 {
537 auto enum_arg = va_arg(args, int);
538 if(enum_arg >= TIMEMORY_COMPONENTS_END)
539 break;
540 comp.push_back(enum_arg);
541 }
542 va_end(args);
543
544 timemory_create_record(name, &id, comp.size(), (int*) (comp.data()));
545
546#if defined(DEBUG)
547 if(tim::settings::verbose() > 2)
548 printf("beginning record for '%s' (id = %lli)...\n", name,
549 (long long int) id);
550#endif
551
552 return id;
553 }
554
555 //----------------------------------------------------------------------------------//
556
557 void timemory_end_record(uint64_t id)
558 {
560 if(!lk || id == std::numeric_limits<uint64_t>::max())
561 return;
562
564
565#if defined(DEBUG)
566 if(tim::settings::verbose() > 2)
567 printf("ending record for %lli...\n", (long long int) id);
568#endif
569 }
570
571 //----------------------------------------------------------------------------------//
572
573 void timemory_push_region(const char* name)
574 {
576 if(!lk)
577 return;
578 auto& region_map = get_region_map();
579 lk.release();
580 auto idx = timemory_get_begin_record(name);
582 region_map[name].push(idx);
583 }
584
585 //----------------------------------------------------------------------------------//
586
587 void timemory_pop_region(const char* name)
588 {
590 if(!lk)
591 return;
592 auto& region_map = get_region_map();
593 auto itr = region_map.find(name);
594 if(itr == region_map.end() || (itr != region_map.end() && itr->second.empty()))
595 fprintf(stderr, "Warning! region '%s' does not exist!\n", name);
596 else
597 {
598 uint64_t idx = itr->second.top();
599 lk.release();
602 itr->second.pop();
603 }
604 }
605
606 //==================================================================================//
607 //
608 // Symbols for Fortran
609 //
610 //==================================================================================//
611
612 void timemory_create_record_(const char* name, uint64_t* id, int n, int* ct)
613 {
614 timemory_create_record(name, id, n, ct);
615 }
616
618
619 void timemory_init_library_(int argc, char** argv)
620 {
622 }
623
625
627 {
629 }
630
632 {
634 }
635
637
638 void timemory_begin_record_(const char* name, uint64_t* id)
639 {
640 timemory_begin_record(name, id);
641 }
642
643 void timemory_begin_record_types_(const char* name, uint64_t* id, const char* ctypes)
644 {
645 timemory_begin_record_types(name, id, ctypes);
646 }
647
648 uint64_t timemory_get_begin_record_(const char* name)
649 {
650 return timemory_get_begin_record(name);
651 }
652
653 uint64_t timemory_get_begin_record_types_(const char* name, const char* ctypes)
654 {
655 return timemory_get_begin_record_types(name, ctypes);
656 }
657
658 void timemory_end_record_(uint64_t id) { return timemory_end_record(id); }
659
660 void timemory_push_region_(const char* name) { return timemory_push_region(name); }
661
662 void timemory_pop_region_(const char* name) { return timemory_pop_region(name); }
663
664 //======================================================================================//
665
666} // extern "C"
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.
void(* timemory_delete_func_t)(uint64_t)
function pointer type for timemory_delete_function
Definition: library.h:338
void(* timemory_create_func_t)(const char *, uint64_t *, int, int *)
Definition: library.h:334
#define TIMEMORY_COMPONENTS_END
Definition: enum.h:155
void timemory_pause(void)
Turn off timemory collection.
Definition: library.cpp:313
void timemory_init_library_(int argc, char **argv)
Definition: library.cpp:619
void timemory_push_components_enum(int types,...)
Replace the current set of components with a new set of components with the set of enumerations provi...
Definition: library.cpp:377
void timemory_create_record(const char *name, uint64_t *id, int n, int *ctypes)
Definition: library.cpp:156
timemory_create_func_t timemory_create_function
The function pointer to set to customize which components are used by library interface.
Definition: library.cpp:51
void timemory_begin_record_(const char *name, uint64_t *id)
Definition: library.cpp:638
std::unordered_map< uint64_t, toolset_t > record_map_t
Definition: library.cpp:61
timemory_delete_func_t timemory_delete_function
The function pointer to set which deletes an entry created by timemory_create_function.
Definition: library.cpp:52
void timemory_create_record_(const char *name, uint64_t *id, int n, int *ct)
Definition: library.cpp:612
void timemory_set_environ(const char *evar, const char *eval, int over, int parse)
Definition: library.cpp:335
uint64_t timemory_get_unique_id(void)
Returns a unique integer for a thread.
Definition: library.cpp:144
void timemory_push_region(const char *name)
Definition: library.cpp:573
void timemory_delete_record(uint64_t id)
Deletes the record created by timemory_create_record.
Definition: library.cpp:177
void timemory_end_record(uint64_t id)
Definition: library.cpp:557
uint64_t timemory_get_begin_record_types(const char *name, const char *ctypes)
Variant to timemory_begin_record_types which returns a unique integer.
Definition: library.cpp:503
std::string string_t
Definition: library.cpp:57
std::unordered_map< std::string, std::stack< uint64_t > > region_map_t
Definition: library.cpp:60
uint64_t timemory_get_begin_record_enum(const char *name,...)
Variant to timemory_begin_record_enum which returns a unique integer.
Definition: library.cpp:524
void timemory_begin_record_enum(const char *name, uint64_t *id,...)
Similar to timemory_begin_record but accepts a specific enumerated set of components,...
Definition: library.cpp:450
void timemory_pop_components(void)
Inverse of the last timemory_push_components or timemory_push_components_enum call....
Definition: library.cpp:399
void timemory_pop_components_(void)
Definition: library.cpp:636
void timemory_add_components(const char *_component_string)
Add some components to the current set of components being collected Any components which are current...
Definition: library.cpp:348
void timemory_set_default_(const char *components)
Definition: library.cpp:626
void timemory_pop_region(const char *name)
Definition: library.cpp:587
bool timemory_library_is_initialized(void)
Returns whether the library is initialized or not.
Definition: library.cpp:195
void timemory_resume(void)
Turn on timemory collection.
Definition: library.cpp:318
void timemory_begin_record_types_(const char *name, uint64_t *id, const char *ctypes)
Definition: library.cpp:643
void timemory_init_library(int argc, char **argv)
Initializes timemory. Not strictly necessary but highly recommended.
Definition: library.cpp:212
std::vector< TIMEMORY_COMPONENT > component_enum_t
Definition: library.cpp:62
void timemory_remove_components(const char *_component_string)
Remove some components to the current set of components being collected. Any components which are not...
Definition: library.cpp:358
std::array< bool, 2 > & get_library_state()
Definition: library.cpp:127
std::string & get_default_components()
Definition: library.cpp:102
void timemory_push_region_(const char *name)
Definition: library.cpp:660
uint64_t timemory_get_begin_record_types_(const char *name, const char *ctypes)
Definition: library.cpp:653
void timemory_delete_record_(uint64_t id)
Definition: library.cpp:617
void timemory_finalize_library_(void)
Definition: library.cpp:624
void timemory_push_components(const char *_component_string)
Replace the current set of components with a new set of components.
Definition: library.cpp:368
void timemory_push_components_(const char *components)
Definition: library.cpp:631
uint64_t timemory_get_begin_record_(const char *name)
Definition: library.cpp:648
void timemory_named_init_library(char *name)
Definition: library.cpp:200
void timemory_pop_region_(const char *name)
Definition: library.cpp:662
void timemory_end_record_(uint64_t id)
Definition: library.cpp:658
std::deque< component_enum_t > components_stack_t
Definition: library.cpp:63
void timemory_begin_record_types(const char *name, uint64_t *id, const char *ctypes)
Similar to timemory_begin_record but accepts a specific set of components as a string.
Definition: library.cpp:429
uint64_t timemory_get_begin_record(const char *name)
Variant to timemory_begin_record which returns a unique integer.
Definition: library.cpp:482
component_enum_t & get_current_components()
Definition: library.cpp:113
void timemory_set_default(const char *_component_string)
Pass in a default set of components to use. Will be overridden by TIMEMORY_COMPONENTS environment var...
Definition: library.cpp:322
void timemory_begin_record(const char *name, uint64_t *id)
Definition: library.cpp:409
void timemory_finalize_library(void)
Finalizes timemory. Output will be generated. Any attempt to store data within timemory storage is un...
Definition: library.cpp:253
typename library_toolset_t::component_type toolset_t
Definition: library.cpp:59
TIMEMORY_LIBRARY_TYPE library_toolset_t
Definition: library.cpp:58
::tim::statistics< Tp > max(::tim::statistics< Tp > lhs, const Tp &rhs)
Definition: statistics.hpp:320
A lightweight synchronization object for preventing recursion. The first template parameter should ha...
Definition: trace.hpp:135
void set_env(const std::string &env_var, const Tp &_val, int override)
void timemory_finalize()
finalization of the specified types
void initialize(CompList< CompTypes... > &obj, std::initializer_list< EnumT > components)
Definition: initialize.hpp:53
std::vector< TIMEMORY_COMPONENT > enumerate_components(const Container< StringT, ExtraArgs... > &component_names)
description: use this function to generate an array of enumerations from a list of string that can be...
Definition: enumerate.hpp:62
void timemory_init(Args &&... _args)
Definition: config.hpp:49
char ** argv
Definition: config.cpp:55
char argparse::argument_parser tim::settings * _settings
Definition: config.cpp:255
tim::mpl::apply< std::string > string
Definition: macros.hpp:53
components
Definition: settings.cpp:1700
static void parse(settings *=instance< TIMEMORY_API >())
Definition: settings.cpp:410
static settings * instance()
Definition: settings.hpp:536
#define TIMEMORY_LIBRARY_TYPE
Definition: types.hpp:275