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.
manager.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// maybe included directly in header-only mode but pragma once will cause warnings
26#ifndef TIMEMORY_MANAGER_MANAGER_CPP_
27#define TIMEMORY_MANAGER_MANAGER_CPP_ 1
28
30
31#include "timemory/backends/process.hpp"
38
39//--------------------------------------------------------------------------------------//
40//
41// if not using extern and not compiling manager library, everything
42// in this file gets excluded by the pre-processor
43//
44//--------------------------------------------------------------------------------------//
45//
46#if defined(TIMEMORY_MANAGER_SOURCE) || defined(TIMEMORY_MANAGER_INLINE)
47//
48//--------------------------------------------------------------------------------------//
49//
50# include "timemory/api.hpp"
51# include "timemory/backends/cpu.hpp"
52# include "timemory/backends/threading.hpp"
58# include "timemory/version.h"
59
60# include <algorithm>
61# include <atomic>
62# include <cctype>
63# include <fstream>
64# include <iosfwd>
65# include <locale>
66# include <memory>
67# include <string>
68# include <utility>
69# include <vector>
70
71namespace tim
72{
73//
74//--------------------------------------------------------------------------------------//
75//
76// manager
77//
78//----------------------------------------------------------------------------------//
79//
82: m_instance_count(f_manager_instance_count()++)
83, m_rank(dmp::rank())
84, m_thread_index(threading::get_id())
85, m_thread_id(std::this_thread::get_id())
86, m_lock(std::make_shared<auto_lock_t>(m_mutex, std::defer_lock))
87, m_hash_ids(get_hash_ids())
88, m_hash_aliases(get_hash_aliases())
89{
90 f_thread_counter()++;
91
92 static bool _once = [=] {
93 auto _launch_date =
95 auto _launch_time =
97 auto _cpu_info = cpu::get_info();
98 auto _user = get_env<std::string>("USER", "nobody");
99
100 for(auto&& itr : { "SHELL", "HOME", "PWD" })
101 {
102 auto _var = get_env<std::string>(itr, "");
103 if(!_var.empty())
104 add_metadata(itr, _var);
105 }
106
107 add_metadata("USER", _user);
108 add_metadata("LAUNCH_DATE", _launch_date);
109 add_metadata("LAUNCH_TIME", _launch_time);
110 add_metadata("TIMEMORY_API", demangle<TIMEMORY_API>());
111
112# if defined(TIMEMORY_VERSION_STRING)
113 add_metadata("TIMEMORY_VERSION", TIMEMORY_VERSION_STRING);
114# endif
115
116# if defined(TIMEMORY_GIT_DESCRIBE)
117 add_metadata("TIMEMORY_GIT_DESCRIBE", TIMEMORY_GIT_DESCRIBE);
118# endif
119
120# if defined(TIMEMORY_GIT_REVISION)
121 add_metadata("TIMEMORY_GIT_REVISION", TIMEMORY_GIT_REVISION);
122# endif
123
124 add_metadata("CPU_MODEL", _cpu_info.model);
125 add_metadata("CPU_VENDOR", _cpu_info.vendor);
126 add_metadata("CPU_FEATURES", _cpu_info.features);
127 add_metadata("CPU_FREQUENCY", _cpu_info.frequency);
128 add_metadata("HW_CONCURRENCY", threading::affinity::hw_concurrency());
129 add_metadata("HW_PHYSICAL_CPU", threading::affinity::hw_physicalcpu());
130
131 for(int i = 0; i < 3; ++i)
132 {
133 auto _cache_size = cpu::cache_size::get(i + 1);
134 std::stringstream _cache_lvl;
135 _cache_lvl << "HW_L" << (i + 1) << "_CACHE_SIZE";
136 add_metadata(_cache_lvl.str(), _cache_size);
137 }
138
139# if !defined(TIMEMORY_DISABLE_BANNER)
140 if(m_settings->get_banner())
141 printf("#------------------------- tim::manager initialized "
142 "[pid=%i] -------------------------#\n",
143 process::get_id());
144# endif
145 auto_lock_t _lk{ type_mutex<manager>() };
146 // set to zero to we can track if user added metadata
147 f_manager_persistent_data().metadata_count = 0;
148 return true;
149 }();
150 consume_parameters(_once);
151
153 threading::affinity::set();
154
155 if(m_settings && m_settings->get_initialized())
156 initialize();
157}
158//
159//----------------------------------------------------------------------------------//
160//
163{
164 auto _remain = --f_manager_instance_count();
165 bool _last = (get_shared_ptr_pair<this_type, TIMEMORY_API>().second == nullptr ||
166 _remain == 0 || m_instance_count == 0);
167
168 if(_last)
169 {
170 f_thread_counter().store(0, std::memory_order_relaxed);
171 }
172
173# if !defined(TIMEMORY_DISABLE_BANNER)
174 if(_last && m_settings && m_settings->get_banner())
175 {
176 printf("#---------------------- tim::manager destroyed "
177 "[rank=%i][pid=%i] "
178 "----------------------#\n",
179 m_rank, process::get_id());
180 }
181# endif
182}
183//
184//----------------------------------------------------------------------------------//
185//
188{
189 if(f_debug())
190 PRINT_HERE("cleaning %s", key.c_str());
191
192 auto _cleanup = [&](auto& _functors) {
193 auto _orig = _functors.size();
194 auto itr = _functors.begin();
195 for(; itr != _functors.end(); ++itr)
196 {
197 if(itr->first == key)
198 break;
199 }
200
201 if(itr != _functors.end())
202 {
203 itr->second();
204 _functors.erase(itr);
205 }
206
207 if(f_debug())
208 PRINT_HERE("%s [size: %i]", "cleaned", (int) (_orig - _functors.size()));
209 };
210
211 _cleanup(m_finalizer_cleanups);
212}
213//
214//----------------------------------------------------------------------------------//
215//
218{
219 m_is_finalizing = true;
220 auto _orig_sz = m_finalizer_cleanups.size();
221
222 if(f_debug())
223 {
224 PRINT_HERE("%s [size: %i]", "cleaning", (int) m_finalizer_cleanups.size());
225 }
226
227 auto _cleanup = [](finalizer_list_t& _functors) {
228 // reverse to delete the most recent additions first
229 std::reverse(_functors.begin(), _functors.end());
230 // invoke all the functions
231 for(auto& itr : _functors)
232 itr.second();
233 // remove all these functors
234 _functors.clear();
235 };
236
237 _cleanup(m_finalizer_cleanups);
238
239 if(f_debug())
240 {
241 PRINT_HERE("%s [size: %i]", "cleaned",
242 (int) (_orig_sz - m_finalizer_cleanups.size()));
243 }
244}
245//
246//----------------------------------------------------------------------------------//
247//
250{
251 if(m_is_initialized)
252 return;
253 m_is_initialized = true;
254 bool _owns = m_lock->owns_lock();
255 if(!_owns)
256 m_lock->lock();
257 m_initializers.erase(std::remove_if(m_initializers.begin(), m_initializers.end(),
258 [](auto& itr) { return itr(); }),
259 m_initializers.end());
260 if(!_owns)
261 m_lock->unlock();
262}
263//
264//----------------------------------------------------------------------------------//
265//
268{
269 auto _print_size = [&](const char* _msg) {
270 if(f_debug())
271 {
272 auto _get_sz = [](auto& _mdata) {
273 int _val = 0;
274 for(auto& itr : _mdata)
275 _val += itr.second.size();
276 return _val;
277 };
278 PRINT_HERE("%s [master: %i/%i, worker: %i/%i, other: %i]", _msg,
279 _get_sz(m_master_cleanup), _get_sz(m_master_finalizers),
280 _get_sz(m_worker_cleanup), _get_sz(m_worker_finalizers),
281 (int) m_pointer_fini.size());
282 }
283 };
284
285 auto _finalize = [](finalizer_pmap_t& _pdata) {
286 for(auto& _functors : _pdata)
287 {
288 // reverse to delete the most recent additions first
289 std::reverse(_functors.second.begin(), _functors.second.end());
290 // invoke all the functions
291 for(auto& itr : _functors.second)
292 itr.second();
293 // remove all these finalizers
294 _functors.second.clear();
295 }
296 };
297
298 m_is_finalizing = true;
299 m_rank = std::max<int32_t>(m_rank, dmp::rank());
300
301 _print_size("finalizing");
302
303 cleanup();
304
305 _print_size("finalizing (pre-storage-cleanup)");
306
307 //
308 // ideally, only one of these will be populated
309 // these clear the stack before outputting
310 //
311 // finalize workers first
312 _finalize(m_worker_cleanup);
313 // finalize masters second
314 _finalize(m_master_cleanup);
315
316 _print_size("finalizing (pre-storage-finalization)");
317
318 //
319 // ideally, only one of these will be populated
320 //
321 // finalize workers first
322 _finalize(m_worker_finalizers);
323 // finalize masters second
324 _finalize(m_master_finalizers);
325
326 _print_size("finalizing (pre-pointer-finalization)");
327
328 for(auto& itr : m_pointer_fini)
329 itr.second();
330
331 m_pointer_fini.clear();
332
333 m_is_finalizing = false;
334
335 _print_size("finalized");
336
337 if(m_instance_count == 0 && m_rank == 0)
338 {
340 internal_write_metadata("manager::finalize");
341 }
342
343 m_is_finalized = true;
344}
345//
346//----------------------------------------------------------------------------------//
347//
350{
351 if(f_debug())
352 PRINT_HERE("%s", "finalizing...");
353
354 if(!manager::f_use_exit_hook())
355 return;
356
357 try
358 {
359 auto master_count = f_manager_instance_count().load();
360 if(master_count > 0)
361 {
362 auto master_manager =
363 get_shared_ptr_pair_main_instance<manager, TIMEMORY_API>();
364 if(master_manager)
365 {
366 master_manager->internal_write_metadata("manager::exit_hook");
367 master_manager.reset();
368 }
369 }
370 } catch(...)
371 {}
372
373 if(f_debug())
374 PRINT_HERE("%s", "finalizing...");
375}
376//
377//----------------------------------------------------------------------------------//
378//
381{
382 m_rank = std::max<int32_t>(m_rank, dmp::rank());
383 if(m_write_metadata < 0)
384 return;
385 auto _settings = f_settings();
386 if(!_settings)
387 return;
388 auto _outp_prefix = _settings->get_global_output_prefix();
389 m_metadata_prefix = _outp_prefix;
390 if(f_debug())
391 PRINT_HERE("[rank=%i][id=%i] metadata prefix: '%s'", m_rank, m_instance_count,
392 m_metadata_prefix.c_str());
393}
394//
395//----------------------------------------------------------------------------------//
396//
397TIMEMORY_MANAGER_LINKAGE(std::ostream&)
398manager::write_metadata(std::ostream& ofs)
399{
400 auto_lock_t _lk(type_mutex<manager>(), std::defer_lock);
401
402 if(!_lk.owns_lock())
403 _lk.lock();
404
405 auto _settings = f_settings();
406
407 // ensure json write final block during destruction before the file is closed
408 using policy_type = policy::output_archive_t<manager>;
409 auto oa = policy_type::get(ofs);
410 oa->setNextName("timemory");
411 oa->startNode();
412 {
413 oa->setNextName("metadata");
414 oa->startNode();
415 // user
416 {
417 auto& _info_metadata = f_manager_persistent_data().info_metadata;
418 auto& _func_metadata = f_manager_persistent_data().func_metadata;
419 oa->setNextName("info");
420 oa->startNode();
421 for(const auto& itr : _info_metadata)
422 (*oa)(cereal::make_nvp(itr.first.c_str(), itr.second));
423 for(const auto& itr : _func_metadata)
424 itr(static_cast<void*>(oa.get()));
425 oa->finishNode();
426 }
427 // settings
428 if(_settings)
429 {
431 }
432 // output
433 {
434 oa->setNextName("output");
435 oa->startNode();
436 for(const auto& itr : m_output_files)
437 (*oa)(cereal::make_nvp(itr.first.c_str(), itr.second));
438 oa->finishNode();
439 }
440 // environment
441 {
443 }
444 //
445 oa->finishNode();
446 }
447 oa->finishNode();
448 return ofs;
449}
450//
451//----------------------------------------------------------------------------------//
452//
454manager::write_metadata(const std::string& _output_dir, const char* context)
455{
456 if(m_rank != 0)
457 {
458 if(f_debug())
459 PRINT_HERE("[%s]> metadata disabled for rank %i", context, (int) m_rank);
460 return;
461 }
462
463 if(tim::get_env<bool>("TIMEMORY_CXX_PLOT_MODE", false))
464 {
465 if(f_debug())
466 PRINT_HERE("[%s]> plot mode enabled. Skipping metadata", context);
467 return;
468 }
469
470 auto fname = settings::compose_output_filename("metadata", "json", false, -1, false,
471 _output_dir);
472 auto hname = settings::compose_output_filename("functions", "json", false, -1, false,
473 _output_dir);
474
475 auto _settings = f_settings();
476 auto _banner = (_settings) ? _settings->get_banner() : false;
477
478 auto_lock_t _lk{ type_mutex<manager>(), std::defer_lock };
479 if(!_lk.owns_lock())
480 _lk.lock();
481
482 std::map<std::string, std::set<size_t>> _hashes{};
483 if(m_hash_ids && m_hash_aliases)
484 {
485 for(const auto& itr : (*m_hash_aliases))
486 {
487 auto hitr = m_hash_ids->find(itr.second);
488 if(hitr != m_hash_ids->end())
489 {
490 _hashes[operation::decode<TIMEMORY_API>{}(hitr->second)].insert(
491 itr.first);
492 _hashes[operation::decode<TIMEMORY_API>{}(hitr->second)].insert(
493 hitr->first);
494 }
495 }
496 for(const auto& itr : (*m_hash_ids))
497 _hashes[operation::decode<TIMEMORY_API>{}(itr.second)].insert(itr.first);
498 }
499
500 // if there were no hashes generated, writing metadata is optional and the user
501 // did not add to metadata -> return
502 if(_hashes.empty() && m_write_metadata < 1 &&
503 f_manager_persistent_data().metadata_count == 0)
504 return;
505
506 if((f_verbose() >= 0 || _banner || f_debug()) && !_hashes.empty())
507 printf("\n[metadata::%s]> Outputting '%s' and '%s'...\n", context, fname.c_str(),
508 hname.c_str());
509 else if((f_verbose() >= 0 || _banner || f_debug()) && _hashes.empty())
510 printf("\n[metadata::%s]> Outputting '%s'...\n", context, fname.c_str());
511
512 std::ofstream ofs{};
513 if(filepath::open(ofs, fname))
514 {
515 write_metadata(ofs);
516 }
517 if(ofs)
518 ofs << std::endl;
519 else
520 printf("[manager]> Warning! Error opening '%s'...\n", fname.c_str());
521 ofs.close();
522
523 if(_hashes.empty())
524 return;
525
526 std::ofstream hfs{};
527 if(filepath::open(hfs, hname))
528 {
529 // ensure json write final block during destruction before the file is closed
530 using policy_type = policy::output_archive_t<manager>;
531 auto oa = policy_type::get(hfs);
532 oa->setNextName("timemory");
533 oa->startNode();
534 {
535 oa->setNextName("functions");
536 oa->startNode();
537 // hash-keys
538 {
539 for(const auto& itr : _hashes)
540 (*oa)(cereal::make_nvp(itr.first.c_str(), itr.second));
541 }
542 //
543 oa->finishNode();
544 }
545 oa->finishNode();
546 }
547 if(hfs)
548 hfs << std::endl;
549 else
550 printf("[manager]> Warning! Error opening '%s'...\n", hname.c_str());
551
552 hfs.close();
553}
554//
555//----------------------------------------------------------------------------------//
556//
558manager::internal_write_metadata(const char* context)
559{
560 if(m_rank != 0)
561 {
562 if(f_debug())
563 PRINT_HERE("[%s]> metadata disabled for rank %i", context, (int) m_rank);
564 return;
565 }
566
567 if(m_num_entries < 1 && m_write_metadata < 1)
568 {
569 if(f_debug())
570 PRINT_HERE("[%s]> No components generated output. Skipping metadata",
571 context);
572 return;
573 }
574
575 if(tim::get_env<bool>("TIMEMORY_CXX_PLOT_MODE", false))
576 {
577 if(f_debug())
578 PRINT_HERE("[%s]> plot mode enabled. Skipping metadata", context);
579 return;
580 }
581 auto _settings = f_settings();
582 if(!_settings)
583 {
584 if(f_debug())
585 PRINT_HERE("[%s]> Null pointer to settings", context);
586 return;
587 }
588
589 bool _auto_output = _settings->get_auto_output();
590 bool _file_output = _settings->get_file_output();
591 auto _outp_prefix = _settings->get_global_output_prefix();
592
593 static bool written = false;
594 if(written || m_write_metadata < 1)
595 {
596 if(f_debug() && written)
597 PRINT_HERE("[%s]> metadata already written", context);
598 if(f_debug() && m_write_metadata < 1)
599 PRINT_HERE("[%s]> metadata disabled: %i", context, (int) m_write_metadata);
600 return;
601 }
602
603 if((!_auto_output || !_file_output) && m_write_metadata < 1)
604 {
605 if(f_debug() && !_auto_output)
606 PRINT_HERE("[%s]> metadata disabled because auto output disabled", context);
607 if(f_debug() && !_file_output)
608 PRINT_HERE("[%s]> metadata disabled because file output disabled", context);
609 return;
610 }
611
612 written = true;
613 m_write_metadata = -1;
614
615 if(f_debug())
616 PRINT_HERE("metadata prefix: '%s'", m_metadata_prefix.c_str());
617
618 // get the output prefix if not already set
619 if(m_metadata_prefix.empty())
620 m_metadata_prefix = _outp_prefix;
621
622 if(f_debug())
623 PRINT_HERE("metadata prefix: '%s'", m_metadata_prefix.c_str());
624
625 // remove any non-ascii characters
626 auto only_ascii = [](char c) { return isascii(c) == 0; };
627 m_metadata_prefix.erase(
628 std::remove_if(m_metadata_prefix.begin(), m_metadata_prefix.end(), only_ascii),
629 m_metadata_prefix.end());
630
631 if(f_debug())
632 PRINT_HERE("metadata prefix: '%s'", m_metadata_prefix.c_str());
633
634 // if empty, set to default
635 if(m_metadata_prefix.empty())
636 m_metadata_prefix = "timemory-output/";
637
638 if(f_debug())
639 PRINT_HERE("metadata prefix: '%s'", m_metadata_prefix.c_str());
640
641 // if first char is a control character, the statics probably got deleted
642 std::locale _lc{};
643 if(std::iscntrl(m_metadata_prefix[0], _lc))
644 m_metadata_prefix = "timemory-output/";
645
646 if(f_debug())
647 PRINT_HERE("metadata prefix: '%s'", m_metadata_prefix.c_str());
648
649 write_metadata(m_metadata_prefix, context);
650}
651//
652//--------------------------------------------------------------------------------------//
653//
655manager::add_file_output(const string_t& _category, const string_t& _label,
656 const string_t& _file)
657{
658 m_output_files[_category][_label].insert(_file);
659}
660//
661//--------------------------------------------------------------------------------------//
662//
664manager::add_text_output(const string_t& _label, const string_t& _file)
665{
666 add_file_output("text", _label, _file);
667 auto _settings = f_settings();
668 if(_settings && _settings->get_ctest_notes())
670}
671//
672//--------------------------------------------------------------------------------------//
673//
675manager::add_json_output(const string_t& _label, const string_t& _file)
676{
677 add_file_output("json", _label, _file);
678}
679//
680//----------------------------------------------------------------------------------//
681//
683manager::remove_cleanup(void* _key)
684{
685 if(m_pointer_fini.find(_key) != m_pointer_fini.end())
686 m_pointer_fini.erase(_key);
687}
688//
689//----------------------------------------------------------------------------------//
690//
693{
694 auto _remove_functor = [&](finalizer_list_t& _functors) {
695 for(auto itr = _functors.begin(); itr != _functors.end(); ++itr)
696 {
697 if(itr->first == _key)
698 {
699 _functors.erase(itr);
700 return;
701 }
702 }
703 };
704
705 _remove_functor(m_finalizer_cleanups);
706}
707//
708//----------------------------------------------------------------------------------//
709//
712{
713 auto _remove_finalizer = [&](finalizer_pmap_t& _pdata) {
714 for(auto& _functors : _pdata)
715 {
716 for(auto itr = _functors.second.begin(); itr != _functors.second.end(); ++itr)
717 {
718 if(itr->first == _key)
719 {
720 _functors.second.erase(itr);
721 return;
722 }
723 }
724 }
725 };
726
727 _remove_finalizer(m_master_cleanup);
728 _remove_finalizer(m_worker_cleanup);
729 _remove_finalizer(m_master_finalizers);
730 _remove_finalizer(m_worker_finalizers);
731}
732//
733//----------------------------------------------------------------------------------//
734//
736manager::add_metadata(const std::string& _key, const char* _value)
737{
738 auto_lock_t _lk(type_mutex<manager>());
739 ++f_manager_persistent_data().metadata_count;
740 f_manager_persistent_data().info_metadata.insert({ _key, std::string{ _value } });
741}
742//
743//----------------------------------------------------------------------------------//
744//
746manager::add_metadata(const std::string& _key, const std::string& _value)
747{
748 auto_lock_t _lk(type_mutex<manager>());
749 ++f_manager_persistent_data().metadata_count;
750 f_manager_persistent_data().info_metadata.insert({ _key, _value });
751}
752//
753//----------------------------------------------------------------------------------//
754//
756manager::add_synchronization(const std::string& _key, int64_t _id,
757 std::function<void()> _func)
758{
759 m_mutex.lock();
760 m_synchronize[_key].emplace(_id, std::move(_func));
761 m_mutex.unlock();
762}
763//
764//----------------------------------------------------------------------------------//
765//
767manager::remove_synchronization(const std::string& _key, int64_t _id)
768{
769 m_mutex.lock();
770 if(m_synchronize[_key].find(_id) != m_synchronize[_key].end())
771 m_synchronize[_key].erase(_id);
772 m_mutex.unlock();
773}
774//
775//----------------------------------------------------------------------------------//
776//
779{
780 for(auto& itr : m_synchronize)
781 {
782 for(auto& fitr : itr.second)
783 {
784 fitr.second();
785 }
786 }
787}
788//
789//----------------------------------------------------------------------------------//
790//
791/*TIMEMORY_MANAGER_LINKAGE(manager::comm_group_t)
792manager::get_communicator_group()
793{
794 int32_t max_concurrency = std::thread::hardware_concurrency();
795 // We want on-node communication only
796 int32_t nthreads = f_thread_counter().load();
797 int32_t max_processes = max_concurrency / nthreads;
798 int32_t mpi_node_default = mpi::size() / max_processes;
799 if(mpi_node_default < 1)
800 mpi_node_default = 1;
801 int32_t mpi_node_count = get_env<int32_t>("TIMEMORY_NODE_COUNT", mpi_node_default);
802 int32_t mpi_split_size = mpi::rank() / (mpi::size() / mpi_node_count);
803
804 // Split the communicator based on the number of nodes and use the
805 // original rank for ordering
806 mpi::comm_t local_mpi_comm;
807 mpi::comm_split(mpi::comm_world_v, mpi_split_size, mpi::rank(), &local_mpi_comm);
808
809# if defined(DEBUG)
810 if(f_verbose() > 1 || f_debug())
811 {
812 int32_t local_mpi_rank = mpi::rank(local_mpi_comm);
813 int32_t local_mpi_size = mpi::size(local_mpi_comm);
814 int32_t local_mpi_file = mpi::rank() / local_mpi_size;
815
816 std::stringstream _info;
817 _info << "\t" << mpi::rank() << " Rank : " << mpi::rank() << std::endl;
818 _info << "\t" << mpi::rank() << " Size : " << mpi::size() << std::endl;
819 _info << "\t" << mpi::rank() << " Node : " << mpi_node_count << std::endl;
820 _info << "\t" << mpi::rank() << " Local Size: " << local_mpi_size << std::endl;
821 _info << "\t" << mpi::rank() << " Local Rank: " << local_mpi_rank << std::endl;
822 _info << "\t" << mpi::rank() << " Local File: " << local_mpi_file << std::endl;
823 std::cout << "tim::manager::" << __FUNCTION__ << "\n" << _info.str();
824 }
825# endif
826
827 auto local_rank = mpi::rank() / mpi::size(local_mpi_comm);
828 // check
829 assert(local_rank == mpi::get_node_index());
830
831 return comm_group_t(local_mpi_comm, local_rank);
832}*/
833//
834//----------------------------------------------------------------------------------//
835//
836// persistent data for instance counting, threading counting, and exit-hook control
837//
838TIMEMORY_MANAGER_LINKAGE(manager::persistent_data&)
839manager::f_manager_persistent_data()
840{
841 static persistent_data _instance{};
842 return _instance;
843}
844//
845//----------------------------------------------------------------------------------//
846//
847// get either master or thread-local instance
848//
851{
852 static thread_local auto _inst =
853 get_shared_ptr_pair_instance<manager, TIMEMORY_API>();
854 return _inst;
855}
856//
857//----------------------------------------------------------------------------------//
858//
859// get master instance
860//
863{
864 static auto _pinst = get_shared_ptr_pair_main_instance<manager, TIMEMORY_API>();
865 manager::f_manager_persistent_data().master_instance = _pinst;
866 return _pinst;
867}
868//
869//----------------------------------------------------------------------------------//
870//
873{
874 if(!master_instance())
875 return true;
876 return (std::this_thread::get_id() == master_instance()->m_thread_id);
877}
878//
879//----------------------------------------------------------------------------------//
880//
883{
884 static auto _pinst = tim::get_shared_ptr_pair<manager, TIMEMORY_API>();
885 manager::set_persistent_master(_pinst.first);
886 return _pinst.first.get();
887}
888//
889//----------------------------------------------------------------------------------//
890//
893{
894 static auto _preloaded = []() {
895 auto library_ctor = tim::get_env<bool>("TIMEMORY_LIBRARY_CTOR", true);
896 if(!library_ctor)
897 return true;
898
899 auto ld_preload = tim::get_env<std::string>("LD_PRELOAD", "", false);
900 auto dyld_preload = tim::get_env<std::string>("DYLD_INSERT_LIBRARIES", "", false);
901 std::regex lib_regex("libtimemory");
902 if(std::regex_search(ld_preload, lib_regex) ||
903 std::regex_search(dyld_preload, lib_regex))
904 {
905 tim::set_env("TIMEMORY_LIBRARY_CTOR", "OFF", 1);
906 return true;
907 }
908 return false;
909 }();
910
911 if(_preloaded)
912 return;
913
915 auto _debug = (_settings) ? _settings->get_debug() : false;
916 auto _verbose = (_settings) ? _settings->get_verbose() : 0;
917
918 static thread_local bool _once = false;
919 if(_once)
920 return;
921 _once = true;
922
923 auto* _inst = timemory_manager_master_instance();
924 if(_settings)
925 {
926 _settings->init_config();
927 static auto _dir = _settings->get_output_path();
928 static auto _prefix = _settings->get_output_prefix();
929 static auto _time_output = _settings->get_time_output();
930 static auto _time_format = _settings->get_time_format();
931 tim::consume_parameters(_dir, _prefix, _time_output, _time_format);
932 }
933
934 if(_debug || _verbose > 3)
935 printf("[%s]> initializing manager...\n", __FUNCTION__);
936
937 auto _master = manager::master_instance();
938 auto _worker = manager::instance();
939
940 if(!_master && _inst)
941 _master.reset(_inst);
942 else if(!_master)
943 _master = manager::master_instance();
944
945 if(_worker == _master)
946 {
947 // this will create a recursive-dynamic-library load situation
948 // since the timemory-config library depends on the manager library
949 // std::atexit(tim::timemory_finalize);
950 }
951 else
952 {
953 printf("[%s]> manager :: master != worker : %p vs. %p. TLS behavior is abnormal. "
954 "Report any issues to https://github.com/NERSC/timemory/issues\n",
955 __FUNCTION__, (void*) _master.get(), (void*) _worker.get());
957 {
958 auto default_signals = signal_settings::get_default();
959 for(const auto& itr : default_signals)
961 // should return default and any modifications from environment
962 auto enabled_signals = signal_settings::get_enabled();
963 enable_signal_detection(enabled_signals);
964 auto _exit_action = [=](int nsig) {
965 if(_master)
966 {
967 std::cout << "Finalizing after signal: " << nsig << " :: "
968 << signal_settings::str(static_cast<sys_signal>(nsig))
969 << std::endl;
970 _master->finalize();
971 }
972 };
974 }
975 }
976}
977//
978//--------------------------------------------------------------------------------------//
979//
980namespace
981{
982auto timemory_library_is_constructed = (timemory_library_constructor(), true);
983}
984//
985//--------------------------------------------------------------------------------------//
986//
987} // namespace tim
988//
989//--------------------------------------------------------------------------------------//
990//
991#endif
992
993// formerly in manager/extern.cpp
994#if defined(TIMEMORY_MANAGER_SOURCE)
998//
999# include "timemory/environment.hpp"
1000# include "timemory/hash.hpp"
1001# include "timemory/plotting.hpp"
1002# include "timemory/settings.hpp"
1003#endif
1004
1005#endif // TIMEMORY_MANAGER_MANAGER_CPP_
static void serialize_environment(Archive &ar)
void add_file_output(const string_t &_category, const string_t &_label, const string_t &_file)
std::deque< finalizer_pair_t > finalizer_list_t
Definition: manager.hpp:85
void synchronize()
Synchronizes thread-data for storage.
std::unique_lock< mutex_t > auto_lock_t
Definition: manager.hpp:79
static void add_metadata(const std::string &, const Tp &)
Add a metadata entry of a non-string type. If this fails to serialize, either include either the appr...
Definition: manager.hpp:479
void remove_cleanup(void *)
remove a cleanup functor
void remove_synchronization(const std::string &, int64_t)
Remove function for synchronizing data in threads.
static pointer_t instance()
Get a shared pointer to the instance for the current thread.
void add_text_output(const string_t &_label, const string_t &_file)
static pointer_t master_instance()
Get a shared pointer to the instance on the primary thread.
void add_json_output(const string_t &_label, const string_t &_file)
std::map< int32_t, finalizer_list_t > finalizer_pmap_t
Definition: manager.hpp:86
std::shared_ptr< this_type > pointer_t
Definition: manager.hpp:73
static void set_persistent_master(pointer_t _pinst)
This function stores the primary manager instance for the application.
Definition: manager.hpp:395
void update_metadata_prefix()
Updates settings, rank, output prefix, etc.
static void exit_hook()
The exit hook function.
void initialize()
static bool get_is_main_thread()
Return whether this is the main thread.
void internal_write_metadata(const char *="")
void cleanup()
void write_metadata(const std::string &, const char *="")
Print metadata to filename.
void finalize()
void remove_finalizer(const std::string &)
remove a finalizer functor
void add_synchronization(const std::string &, int64_t, std::function< void()>)
Add function for synchronizing data in threads.
static std::string str(const sys_signal &)
Definition: signals.hpp:147
static void enable(const sys_signal &)
Definition: signals.hpp:74
static signal_set_t get_enabled()
Definition: signals.hpp:296
static void set_exit_action(signal_function_t _f)
Definition: signals.hpp:280
static bool is_active()
Definition: signals.hpp:248
static signal_set_t get_default()
Definition: signals.hpp:312
std::string string_t
Definition: library.cpp:57
#define TIMEMORY_MANAGER_LINKAGE(...)
Definition: macros.hpp:42
#define TIMEMORY_MANAGER_LINKAGE_API
Definition: macros.hpp:43
bool open(std::ofstream &_ofs, std::string _fpath, Args &&... _args)
Definition: filepath.hpp:207
return _hash_map end()
hash_alias_ptr_t & get_hash_aliases()
hash_map_ptr_t & get_hash_ids()
_reported insert(_hash_id)
const string_t const string_t & _dir
Definition: definition.hpp:52
const auto & _file
Definition: definition.hpp:72
Definition: kokkosp.cpp:39
cpu_affinity
Definition: settings.cpp:1674
char const std::string & _prefix
Definition: config.cpp:55
void set_env(const std::string &env_var, const Tp &_val, int override)
std::unique_lock< mutex_t > auto_lock_t
Unique lock type around mutex_t.
Definition: locking.hpp:42
TIMEMORY_SETTINGS_INLINE std::string get_local_datetime(const char *dt_format, std::time_t *dt_curr)
Definition: settings.cpp:120
bool enable_signal_detection(signal_settings::signal_set_t=signal_settings::get_default())
Definition: signals.hpp:368
sys_signal
Definition: declaration.hpp:69
void initialize(CompList< CompTypes... > &obj, std::initializer_list< EnumT > components)
Definition: initialize.hpp:53
char argparse::argument_parser tim::settings * _settings
Definition: config.cpp:255
tim::mpl::apply< std::string > string
Definition: macros.hpp:53
void timemory_library_constructor()
manager * timemory_manager_master_instance()
auto get(const auto_bundle< Tag, Types... > &_obj)
void consume_parameters(ArgsT &&...)
Definition: types.hpp:285
arg_result get(size_t _idx, Tp &_value)
Definition: argparse.hpp:674
static pointer_t shared_instance()
static string_t compose_output_filename(string_t _tag, string_t _ext, bool _use_suffix=use_output_suffix(), int32_t _suffix=default_process_suffix(), bool _make_dir=false, std::string _explicit={})
Definition: settings.cpp:322
static std::time_t * get_launch_time(Tag={})
Definition: settings.hpp:456
static void serialize_settings(Archive &)
Definition: settings.hpp:569
#define PRINT_HERE(...)
Definition: macros.hpp:152