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.
definition.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 /**
26  * \file timemory/config/definition.hpp
27  * \brief The definitions for the types in config
28  */
29 
30 #pragma once
31 
36 
37 #if defined(TIMEMORY_CONFIG_SOURCE) || !defined(TIMEMORY_USE_CONFIG_EXTERN)
38 //
39 # include "timemory/backends/process.hpp"
41 # include "timemory/mpl/filters.hpp"
45 
46 # include <fstream>
47 # include <string>
48 
49 namespace tim
50 {
51 //
52 //--------------------------------------------------------------------------------------//
53 //
54 // config
55 //
56 //--------------------------------------------------------------------------------------//
57 //
59 timemory_init(int argc, char** argv, const std::string& _prefix,
60  const std::string& _suffix)
61 {
62  static auto _settings = settings::shared_instance();
64  {
65  if(_settings->get_debug() || _settings->get_verbose() > 3)
66  PRINT_HERE("%s", "");
67 
68  if(_settings->get_enable_signal_handler())
69  {
70  auto default_signals = signal_settings::get_default();
71  for(const auto& itr : default_signals)
73  // should return default and any modifications from environment
74  auto enabled_signals = signal_settings::get_enabled();
75  enable_signal_detection(enabled_signals);
76  }
77 
78  auto _ncfg = _settings->get_suppress_config();
79  if(!_ncfg)
80  {
81  // default configuration files
82  std::set<std::string> _dcfg = {
83  get_env<string_t>("HOME") + std::string("/.timemory.cfg"),
84  get_env<string_t>("HOME") + std::string("/.timemory.json"),
85  get_env<string_t>("HOME") + std::string("/.config/timemory.cfg"),
86  get_env<string_t>("HOME") + std::string("/.config/timemory.json")
87  };
88 
89  auto _cfg = _settings->get_config_file();
90  auto _files = tim::delimit(_cfg, ",;");
91  for(const auto& citr : _files)
92  {
93  std::ifstream ifs(citr);
94  if(ifs)
95  {
96  _settings->read(ifs, citr);
97  }
98  else if(_dcfg.find(citr) == _dcfg.end())
99  {
100  TIMEMORY_EXCEPTION(std::string("Error reading configuration file: ") +
101  citr);
102  }
103  }
104  }
105  }
106 
107  std::string exe_name = (argc > 0) ? argv[0] : "";
108 
109  while(exe_name.find('\\') != std::string::npos)
110  exe_name = exe_name.substr(exe_name.find_last_of('\\') + 1);
111 
112  while(exe_name.find('/') != std::string::npos)
113  exe_name = exe_name.substr(exe_name.find_last_of('/') + 1);
114 
115  static const std::vector<std::string> _exe_suffixes = { ".py", ".exe" };
116  for(const auto& ext : _exe_suffixes)
117  {
118  if(exe_name.find(ext) != std::string::npos)
119  exe_name.erase(exe_name.find(ext), ext.length() + 1);
120  }
121 
123  for(auto& itr : exe_name)
124  {
125  if(itr == '_')
126  itr = '-';
127  }
128 
129  size_t pos = std::string::npos;
130  while((pos = exe_name.find("--")) != std::string::npos)
131  exe_name.erase(pos, 1);
132 
133  if(exe_name.empty())
134  exe_name = "timemory-output";
135 
136  if(_settings)
137  {
138  _settings->get_output_path() = exe_name;
139 
140  // allow environment overrides
142 
143  if(_settings->get_enable_signal_handler())
144  {
145  auto _exit_action = [](int nsig) {
146  auto _manager = manager::master_instance();
147  if(_manager)
148  {
149  std::cout << "Finalizing after signal: " << nsig << " :: "
150  << signal_settings::str(static_cast<sys_signal>(nsig))
151  << std::endl;
152  _manager->finalize();
153  }
154  };
155  signal_settings::set_exit_action(_exit_action);
156  }
157 
159  }
160 
161  static auto _manager = manager::instance();
162  if(_manager)
163  {
164  _manager->update_metadata_prefix();
165  }
166 }
167 //
168 //--------------------------------------------------------------------------------------//
169 //
172  const std::string& _suffix)
173 {
174  auto* cstr = const_cast<char*>(exe_name.c_str());
175  auto _argc = 1;
176  auto* _argv = &cstr;
177  timemory_init(_argc, _argv, _prefix, _suffix);
178 }
179 //
180 //--------------------------------------------------------------------------------------//
181 //
183 timemory_init(int* argc, char*** argv, const std::string& _prefix,
184  const std::string& _suffix)
185 {
186  if(settings::mpi_init())
187  {
188  if(settings::debug())
189  PRINT_HERE("%s", "initializing mpi");
190 
191  mpi::initialize(argc, argv);
192  }
193 
195  {
196  if(settings::debug())
197  PRINT_HERE("%s", "initializing upcxx");
198 
199  upc::initialize();
200  }
201 
202  timemory_init(*argc, *argv, _prefix, _suffix);
204 }
205 //
206 //--------------------------------------------------------------------------------------//
207 //
209 timemory_init(int* argc, char*** argv, argparse::argument_parser& parser,
210  const std::string& _prefix, const std::string& _suffix)
211 {
212  if(settings::mpi_init())
213  {
214  if(settings::debug())
215  PRINT_HERE("%s", "initializing mpi");
216 
217  mpi::initialize(argc, argv);
218  }
219 
221  {
222  if(settings::debug())
223  PRINT_HERE("%s", "initializing upcxx");
224 
225  upc::initialize();
226  }
227 
228  timemory_init(*argc, *argv, _prefix, _suffix);
230 }
231 //
232 //--------------------------------------------------------------------------------------//
233 //
235 timemory_init(std::vector<std::string>& args, argparse::argument_parser& parser,
236  const std::string& _prefix, const std::string& _suffix)
237 {
238  int argc = args.size();
239  char** argv = new char*[argc];
240  for(int i = 0; i < argc; ++i)
241  {
242  auto len = args.at(i).length();
243  argv[i] = new char[len + 1];
244  strcpy(argv[i], args.at(i).c_str());
245  argv[i][len] = '\0';
246  }
247 
248  if(settings::mpi_init())
249  {
250  if(settings::debug())
251  PRINT_HERE("%s", "initializing mpi");
252 
253  mpi::initialize(argc, argv);
254  }
255 
257  {
258  if(settings::debug())
259  PRINT_HERE("%s", "initializing upcxx");
260 
261  upc::initialize();
262  }
263 
265  timemory_argparse(args, &parser);
266 
267  for(int i = 0; i < argc; ++i)
268  delete[] argv[i];
269  delete[] argv;
270 }
271 //
272 //--------------------------------------------------------------------------------------//
273 //
275 timemory_argparse(int* argc, char*** argv, argparse::argument_parser* parser,
277 {
278  // if pointers are null, return
279  if(!argc || !argv)
280  return;
281 
282  // if only one argument, return
283  if(*argc < 2)
284  return;
285 
288 
289  // print help
290  auto help_action = [](parser_t& p) {
291  if(dmp::rank() == 0)
292  p.print_help("-- <NON_TIMEMORY_ARGS>");
293  exit(EXIT_SUCCESS);
294  };
295 
296  auto err_action = [=](const parser_err_t& _err) {
297  if(dmp::rank() == 0 && _err)
298  std::cerr << "[timemory_argparse]> Error! " << _err << std::endl;
299  };
300 
301  // if argument parser was not provided
302  bool _cleanup_parser = parser == nullptr;
304  parser = new parser_t{ (*argv)[0] };
305 
306  // if settings instance was not provided
307  bool _cleanup_settings = _settings == nullptr;
308  static auto _shared_settings = tim::settings::shared_instance();
309  if(_cleanup_settings && !_shared_settings)
310  return;
312  _settings = _shared_settings.get();
313 
314  // enable help
316  parser->on_error([=](parser_t& p, const parser_err_t& _err) {
317  err_action(_err);
318  if(dmp::rank() == 0 && _settings->get_verbose() > 0)
319  p.print_help("-- <NON_TIMEMORY_ARGS>");
320  });
321 
322  // add the arguments in the order they were appended to the settings
323  for(const auto& itr : _settings->ordering())
324  {
325  auto sitr = _settings->find(itr);
326  if(sitr != _settings->end() && sitr->second)
327  {
328  sitr->second->add_argument(*parser);
329  }
330  }
331 
333  .names({ "--timemory-args" })
334  .description("A generic option for any setting. Each argument MUST be passed in "
335  "form: 'NAME=VALUE'. E.g. --timemory-args "
336  "\"papi_events=PAPI_TOT_INS,PAPI_TOT_CYC\" text_output=off")
337  .action([&](parser_t& p) {
338  // get the options
339  auto vopt = p.get<std::vector<std::string>>("timemory-args");
340  for(auto& str : vopt)
341  {
342  // get the args
343  auto vec = tim::delimit(str, " \t;:");
344  for(const auto& itr : vec)
345  {
346  DEBUG_PRINT_HERE("Processing: %s", itr.c_str());
347  auto _pos = itr.find('=');
348  auto _key = itr.substr(0, _pos);
349  auto _val = (_pos == std::string::npos) ? "" : itr.substr(_pos + 1);
350  if(!_settings->update(_key, _val, false))
351  {
352  std::cerr << "[timemory_argparse]> Warning! For "
353  "--timemory-args, key \""
354  << _key << "\" is not a recognized setting. \"" << _val
355  << "\" was not applied." << std::endl;
356  }
357  }
358  }
359  });
360 
362  if(parser->exists("help"))
364 
365  // cleanup if argparse was not provided
366  if(_cleanup_parser)
367  delete parser;
368 }
369 //
370 //--------------------------------------------------------------------------------------//
371 //
373 timemory_argparse(std::vector<std::string>& args, argparse::argument_parser* parser,
375 {
376  int argc = args.size();
377  char** argv = new char*[argc];
378  for(int i = 0; i < argc; ++i)
379  {
380  // intentional memory leak
381  auto len = args.at(i).length();
382  argv[i] = new char[len + 1];
383  strcpy(argv[i], args.at(i).c_str());
384  argv[i][len] = '\0';
385  }
386 
388 
389  // updates args
390  args.clear();
391  for(int i = 0; i < argc; ++i)
392  args.emplace_back(argv[i]);
393 }
394 //
395 //--------------------------------------------------------------------------------------//
396 //
397 TIMEMORY_CONFIG_LINKAGE(void) // NOLINT
399 {
400  auto* _settings = settings::instance();
401  auto _manager = manager::instance();
402 
403  if(_manager)
404  {
405  if(_settings && _settings->get_debug())
406  PRINT_HERE("%s", "finalizing manager");
407  _manager->finalize();
408  }
409 
410  if(_settings)
411  {
412  if(_settings->get_upcxx_finalize())
413  {
414  if(_settings->get_debug())
415  PRINT_HERE("%s", "finalizing upcxx");
416 
417  upc::finalize();
418  }
419 
420  if(_settings->get_mpi_finalize())
421  {
422  if(_settings->get_debug())
423  PRINT_HERE("%s", "finalizing mpi");
424  mpi::finalize();
425  }
426 
427  if(_settings->get_debug() || _settings->get_verbose() > 3)
428  PRINT_HERE("%s", "");
429 
430  if(_settings->get_enable_signal_handler())
431  {
432  if(_settings->get_debug())
433  PRINT_HERE("%s", "disabling signal detection");
435  }
436 
437  if(_settings->get_debug())
438  PRINT_HERE("%s", "done");
439  }
440 }
441 //
442 } // namespace tim
443 //
444 //--------------------------------------------------------------------------------------//
445 //
446 #endif // defined(TIMEMORY_CONFIG_SOURCE) || !defined(TIMEMORY_USE_CONFIG_EXTERN)
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.
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 signal_set_t get_default()
Definition: signals.hpp:312
The declaration for the types for config without definitions.
Include the macros for config.
Declare the config types.
The declaration for the types for manager without definitions.
Definition: kokkosp.cpp:38
bool _cleanup_settings
Definition: definition.hpp:307
char const std::string & _prefix
Definition: definition.hpp:59
void timemory_finalize()
finalization of the specified types
bool _cleanup_parser
Definition: definition.hpp:302
timemory_argparse(argc, argv)
std::string exe_name
Definition: definition.hpp:107
bool enable_signal_detection(signal_settings::signal_set_t=signal_settings::get_default())
Definition: signals.hpp:368
sys_signal
Definition: declaration.hpp:70
void initialize(CompList< CompTypes... > &obj, std::initializer_list< EnumT > components)
Definition: initialize.hpp:53
upcxx_init
Definition: settings.cpp:1400
void timemory_init(Args &&... _args)
Definition: declaration.hpp:49
auto err_action
Definition: definition.hpp:296
char ** argv
Definition: definition.hpp:59
auto help_action
Definition: definition.hpp:290
char argparse::argument_parser & parser
Definition: definition.hpp:209
char argparse::argument_parser tim::settings * _settings
Definition: definition.hpp:277
tim::mpl::apply< std::string > string
Definition: macros.hpp:52
size_t pos
Definition: definition.hpp:129
void disable_signal_detection()
Definition: signals.hpp:379
mpi_init
Definition: settings.cpp:1395
typename parser_t::result_type parser_err_t
Definition: definition.hpp:287
void finalize()
Definition: types.hpp:119
description("A generic option for any setting. Each argument MUST be passed in " "form: 'NAME=VALUE'. E.g. --timemory-args " "\"papi_events=PAPI_TOT_INS,PAPI_TOT_CYC\" text_output=off") .action([&](parser_t &p)
Definition: definition.hpp:334
TIMEMORY_CONFIG_LINKAGE(void) timemory_init(int argc
Definition: definition.hpp:170
ContainerT delimit(const std::string &line, const std::string &delimiters="\"',;: ", PredicateT &&predicate=[](const std::string &s) -> std::string { return s;})
Definition: utility.hpp:666
char const std::string const std::string & _suffix
Definition: definition.hpp:61
The declaration for the types for settings without definitions.
argument & names(const std::vector< std::string > &names)
Definition: argparse.hpp:384
void on_error(ErrorFuncT &&_func)
Definition: argparse.hpp:980
bool exists(const std::string &name) const
Returns whether or not an option was found in the arguments. Only useful after a call to parse or par...
Definition: argparse.hpp:913
known_args_t parse_known_args(int argc, char **argv, const std::string &_delim="--", int verbose_level=0)
Basic variant of parse_known_args which does not replace argc/argv and does not provide an array of s...
Definition: argparse.hpp:766
arg_result get(size_t _idx, Tp &_value)
Definition: argparse.hpp:675
void print_help(const std::string &_extra="")
Definition: argparse.cpp:109
argument & enable_help()
Add a help command.
Definition: argparse.hpp:872
static pointer_t shared_instance()
static void store_command_line(int argc, char **argv)
Definition: settings.cpp:222
static void parse(settings *=instance< TIMEMORY_API >())
Definition: settings.cpp:340
static settings * instance()
Definition: settings.hpp:502
#define DEBUG_PRINT_HERE(...)
Definition: macros.hpp:163
#define PRINT_HERE(...)
Definition: macros.hpp:147
#define TIMEMORY_EXCEPTION(...)
Definition: types.hpp:137