run_art.cc
Go to the documentation of this file.
2 // vim: set sw=2 expandtab :
3 
15 #include "boost/program_options.hpp"
17 #include "cetlib/HorizontalRule.h"
19 #include "cetlib/ostream_handle.h"
20 #include "cetlib_except/exception.h"
21 #include "fhiclcpp/ParameterSet.h"
25 #include "fhiclcpp/parse.h"
27 
28 #include <cassert>
29 #include <exception>
30 #include <iostream>
31 #include <string>
32 
33 #ifdef __linux__
34 #include <malloc.h>
35 #endif // __linux__
36 
37 using namespace std;
38 using namespace string_literals;
39 
41 
42 namespace {
43 
45  make_ostream_handle(std::string const& filename)
46  {
47  assert(!filename.empty());
48  if (art::detail::output_to_stderr(filename)) {
49  return cet::ostream_handle{std::cerr};
50  } else if (art::detail::output_to_stdout(filename)) {
51  return cet::ostream_handle{std::cout};
52  } else {
53  auto os = cet::ostream_handle{filename};
54  if (!os) {
56  << "Unable to write post-processed configuration to specified file "
57  << filename << ".\n";
58  }
59  return os;
60  }
61  }
62 
64  get_print_mode(std::string const& mode)
65  {
66  if (mode == "raw") {
68  } else if (mode == "annotate") {
70  } else if (mode == "prefix-annotate") {
72  }
74  << "Unrecognized ParameterSet printing mode: " << mode << '\n';
75  }
76 
78  banner(std::string const& filename)
79  {
80  std::string result = "** Config output ";
81  bool const to_terminal = art::detail::output_to_stderr(filename) ||
83  result +=
84  to_terminal ? "follows" : std::string("to file '" + filename + "'");
85  result += " **\n";
86  return result;
87  }
88 
89  void
90  print_config(fhicl::ParameterSet const& main_pset,
91  std::string const& output_file,
92  std::string const& mode)
93  {
94  std::cerr << banner(output_file);
95  auto os = make_ostream_handle(output_file);
96  os << main_pset.to_indented_string(0, get_print_mode(mode));
97  }
98 
99  enum class debug_processing : std::size_t {
100  config_summary,
101  config_out,
102  debug_config,
103  validate_config,
104  none
105  };
106 
108  debug_processing_mode(fhicl::ParameterSet const& scheduler_pset)
109  {
110  if (not scheduler_pset.has_key("debug")) {
111  return debug_processing::none;
112  }
113 
114  auto const processing_options = {
115  "config-summary", "config-out", "debug-config", "validate-config"};
116 
117  auto const option = scheduler_pset.get<std::string>("debug.option");
118  auto pos = cet::find_in_all(processing_options, option);
119  if (pos == cend(processing_options)) {
120  throw art::Exception{
122  "An error was encountered while processing debugging options"}
123  << "The debugging option '" << option << "' is not supported.\n"
124  << "If you did not explicitly provide this value in your configuration "
125  "file, please contact artists@fnal.gov and report this error. "
126  "Otherwise,\n"
127  << "choose from 'configSummary', 'configOut', 'debugConfig', or "
128  "'validateConfig'.\n";
129  }
130 
131  auto const index = std::distance(cbegin(processing_options), pos);
132  return static_cast<debug_processing>(index);
133  }
134 
135 } // unnamed namespace
136 
137 namespace bpo = boost::program_options;
138 
139 namespace art {
140 
141  int
142  run_art(int argc,
143  char** argv,
144  bpo::options_description& all_desc,
145  OptionsHandlers&& handlers)
146  {
147  // This must be added separately: how to deal with any non-option arguments.
148  bpo::positional_options_description pd;
149  // A single non-option argument will be taken to be the source data file.
150  pd.add("source", -1);
151  // Parse the command line.
152  bpo::variables_map vm;
153  try {
154  bpo::store(bpo::command_line_parser(argc, argv)
155  .options(all_desc)
156  .style(bpo::command_line_style::default_style &
157  ~bpo::command_line_style::allow_guessing)
158  .positional(pd)
159  .run(),
160  vm);
161  bpo::notify(vm);
162  }
163  catch (bpo::error const& e) {
164  cerr << "Exception from command line processing in " << argv[0] << ": "
165  << e.what() << "\n";
166  return 88;
167  }
168  // Preliminary argument checking.
169  for (auto& handler : handlers) {
170  auto const result = handler->checkOptions(vm);
171  if (result != 0) {
172  return result;
173  }
174  }
175  // Processing of arguments and post-processing of config.
176  fhicl::intermediate_table raw_config;
177  for (auto& handler : handlers) {
178  auto const result = handler->processOptions(vm, raw_config);
179  if (result != 0) {
180  return result;
181  }
182  }
183 
184  // If configuration pruning has been enabled, remove unused module
185  // configurations.
187  auto const scheduler_key = fhicl_key("services", "scheduler");
188  auto enabled_modules = detail::EnabledModules::none();
189  assert(exists_outside_prolog(raw_config, scheduler_key));
190  try {
191  auto const pruneConfigKey = fhicl_key(scheduler_key, "pruneConfig");
192  auto const reportUnusedKey = fhicl_key(scheduler_key, "reportUnused");
193  assert(exists_outside_prolog(raw_config, pruneConfigKey));
194  assert(exists_outside_prolog(raw_config, reportUnusedKey));
195  bool const prune_config = raw_config.get<bool>(pruneConfigKey);
196  bool const report_unused = raw_config.get<bool>(reportUnusedKey);
197  enabled_modules = detail::prune_config_if_enabled(
198  prune_config, report_unused, raw_config);
199  }
200  catch (Exception const& e) {
201  printArtException(e, "art");
202  return e.returnCode();
203  }
204  catch (cet::exception const& e) {
205  printArtException(e, "art");
206  return 65;
207  }
208  catch (std::bad_alloc const& bda) {
209  printBadAllocException("art");
210  return 68;
211  }
212  catch (std::exception const& e) {
213  printStdException(e, "art");
214  return 66;
215  }
216  catch (...) {
217  printUnknownException("art");
218  return 67;
219  }
220 
221  //
222  // Make the parameter set from the intermediate table.
223  //
224  fhicl::ParameterSet main_pset;
225  try {
226  main_pset = fhicl::ParameterSet::make(raw_config);
227  }
228  catch (cet::exception const& e) {
229  constexpr cet::HorizontalRule rule{36};
230  cerr << "ERROR: Failed to create a parameter set from parsed "
231  "configuration with exception "
232  << e.what() << ".\n";
233  cerr << " Intermediate configuration state follows:\n"
234  << rule('-') << '\n'
235  << rule('-') << '\n';
236  for (auto const& [key, value] : raw_config) {
237  cerr << key << ": " << value.to_string() << '\n';
238  }
239  cerr << rule('-') << '\n' << rule('-') << '\n';
240  return 91;
241  }
242  // Main parameter set must be placed in registry manually.
243  try {
245  }
246  catch (...) {
247  cerr << "Uncaught exception while inserting main parameter set into "
248  "registry.\n";
249  throw;
250  }
251  return run_art_common_(main_pset, enabled_modules);
252  }
253 
254  int
255  run_art_string_config(string const& config_string)
256  {
257  //
258  // Make the parameter set from the configuration string:
259  //
260  auto enabled_modules = detail::EnabledModules::none();
261  fhicl::ParameterSet main_pset;
262  try {
263  // create an intermediate table from the input string
264  auto raw_config = fhicl::parse_document(config_string);
265  enabled_modules =
266  detail::prune_config_if_enabled(false, true, raw_config);
267  // run post-processing
268  bpo::variables_map vm;
269  BasicPostProcessor bpp;
270  bpp.processOptions(vm, raw_config);
271  // create the parameter set
272  main_pset = fhicl::ParameterSet::make(raw_config);
273  }
274  catch (cet::exception& e) {
275  constexpr cet::HorizontalRule rule{36};
276  cerr << "ERROR: Failed to create a parameter set from an input "
277  "configuration string with exception "
278  << e.what() << ".\n";
279  cerr << " Input configuration string follows:\n"
280  << rule('-') << rule('-') << "\n";
281  cerr << config_string << "\n";
282  cerr << rule('-') << rule('-') << '\n';
283  return 91;
284  }
285  // Main parameter set must be placed in registry manually.
286  try {
288  }
289  catch (...) {
290  cerr << "Uncaught exception while inserting main parameter set into "
291  "registry.\n";
292  throw;
293  }
294  return run_art_common_(main_pset, enabled_modules);
295  }
296 
297  int
299  detail::EnabledModules const& enabled_modules)
300  {
301 #ifdef __linux__
302  // Tell the system memory allocator to only use one arena: they
303  // are 64 MiB in size, and the default is 8 * num_of_cores. Using
304  // the default means that when using 40 threads we get 40 arenas,
305  // which means we have 40 * 64 MiB = 2560 MiB of virtual address
306  // space devoted to per-thread heaps!!!
307  mallopt(M_ARENA_MAX, 1);
308 #endif // __linux__
309 
310  auto const services_pset =
311  main_pset.get<fhicl::ParameterSet>("services", {});
312  auto const scheduler_pset =
313  services_pset.get<fhicl::ParameterSet>("scheduler", {});
314 
315  // Handle early configuration-debugging
316  auto const debug_mode = debug_processing_mode(scheduler_pset);
317  if (debug_mode != debug_processing::none) {
318  auto const debug_pset = scheduler_pset.get<fhicl::ParameterSet>("debug");
319  auto const filename = debug_pset.get<std::string>("fileName");
320  auto const mode = debug_pset.get<std::string>("printMode");
321 
322  switch (debug_mode) {
323  case debug_processing::validate_config: {
324  [[fallthrough]];
325  }
326  case debug_processing::config_out: {
327  print_config(main_pset, filename, mode);
328  break;
329  }
330  case debug_processing::debug_config: {
331  print_config(main_pset, filename, mode);
332  return detail::info_success();
333  }
334  case debug_processing::config_summary: {
335  detail::print_config_summary(main_pset, mode, enabled_modules);
336  return detail::info_success();
337  }
338  case debug_processing::none:
339  break;
340  }
341  }
342  //
343  // Start the messagefacility
344  //
345  mf::SetIteration("JobSetup");
346  try {
348  services_pset.get<fhicl::ParameterSet>("message", {}));
349  }
350  catch (cet::exception const& e) {
351  cerr << e.what() << '\n';
352  return 69;
353  }
354  catch (exception const& e) {
355  cerr << e.what() << '\n';
356  return 70;
357  }
358  catch (...) {
359  cerr << "Caught unknown exception while initializing the message "
360  "facility.\n";
361  return 71;
362  }
363  mf::LogInfo("MF_INIT_OK") << "Messagelogger initialization complete.";
364  //
365  // Start the EventProcessor
366  //
367  int rc{0};
368  try {
369  EventProcessor ep{main_pset, enabled_modules};
370  // Behavior of validate_config is to validate FHiCL syntax *and*
371  // user-specified configurations of paths, modules, services,
372  // etc. It is thus possible that an exception thrown during
373  // construction of the EventProcessor object can have nothing to
374  // do with a configuration error.
375  if (debug_mode == debug_processing::validate_config) {
376  return detail::info_success();
377  }
378  if (scheduler_pset.has_key("dataDependencyGraph")) {
379  return detail::info_success();
380  }
381  auto ep_rc = ep.runToCompletion();
382  if (ep_rc == EventProcessor::epSignal) {
383  cerr << "Art has handled signal " << art::shutdown_flag << ".\n";
384  if (scheduler_pset.get<bool>("errorOnSIGINT")) {
385  rc = 128 + art::shutdown_flag;
386  }
387  }
388  }
389  catch (Exception const& e) {
390  rc = e.returnCode();
391  printArtException(e, "art");
392  }
393  catch (cet::exception const& e) {
394  rc = 65;
395  printArtException(e, "art");
396  }
397  catch (detail::collected_exception const& e) {
398  rc = 1;
399  // LogSystem already adds a newline, so trim the one that's
400  // already in the exception message.
401  std::string const msg{e.what()};
402  mf::LogSystem("ArtException") << msg.substr(0, msg.find_last_of("\n"));
403  }
404  catch (bad_alloc const& bda) {
405  rc = 68;
406  printBadAllocException("art");
407  }
408  catch (exception const& e) {
409  rc = 66;
410  printStdException(e, "art");
411  }
412  catch (...) {
413  rc = 67;
414  printUnknownException("art");
415  }
416  return rc;
417  }
418 
419 } // namespace art
void SetIteration(string const &val)
static ParameterSetID const & put(ParameterSet const &ps)
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
Definition: StdUtils.h:87
static QCString result
bool exists_outside_prolog(fhicl::intermediate_table const &config, std::string const &key)
void msg(const char *fmt,...)
Definition: message.cpp:107
void print_config_summary(fhicl::ParameterSet const &pset, std::string const &verbosity, EnabledModules const &enabled_modules)
int run_art_common_(fhicl::ParameterSet const &main_pset, detail::EnabledModules const &enabled_modules)
Definition: run_art.cc:298
std::string string
Definition: nybbler.cc:12
static ParameterSet make(intermediate_table const &tbl)
Definition: ParameterSet.cc:68
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
char const * what() const noexcept override
int run_art_string_config(string const &config_string)
Definition: run_art.cc:255
error
Definition: include.cc:26
STL namespace.
void printStdException(std::exception const &e, char const *prog)
string filename
Definition: train.py:213
std::atomic< int > shutdown_flag
void printUnknownException(char const *prog)
EnabledModules prune_config_if_enabled(bool prune_config, bool report_enabled, fhicl::intermediate_table &config)
void StartMessageFacility(fhicl::ParameterSet const &pset, string const &applicationName)
const double e
def key(type, name=None)
Definition: graph.py:13
T get(std::string const &key) const
Definition: ParameterSet.h:271
std::enable_if_t< std::is_convertible_v< T, std::string >, std::string > fhicl_key(T const &name)
Definition: fhicl_key.h:12
std::string to_indented_string() const
std::vector< std::unique_ptr< art::OptionsHandler >> OptionsHandlers
MaybeLogger_< ELseverityLevel::ELsev_severe, false > LogSystem
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
bool has_key(std::string const &key) const
int processOptions(bpo::variables_map const &vm, fhicl::intermediate_table &raw_config)
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
bool output_to_stderr(std::string const &spec)
Definition: output_to.cc:15
debug_processing
Definition: run_art.cc:99
intermediate_table parse_document(std::string const &filename, cet::filepath_maker &maker)
Definition: parse.cc:720
int run_art(int argc, char **argv, bpo::options_description &all_desc, OptionsHandlers &&handlers)
Definition: run_art.cc:142
T get(std::string const &name)
void printArtException(cet::exception const &e, char const *prog)
auto find_in_all(FwdCont &, Datum const &)
constexpr int info_success()
Definition: info_success.h:8
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
Definition: StdUtils.h:82
static msg_handler handler
Definition: qglobal.cpp:234
void printBadAllocException(char const *prog)
bool output_to_stdout(std::string const &spec)
Definition: output_to.cc:21
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33