LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
DebugOptionsHandler.cc
Go to the documentation of this file.
2 
9 
10 #include <string>
11 #include <tuple>
12 
13 using namespace std::string_literals;
16 
17 art::DebugOptionsHandler::DebugOptionsHandler(bpo::options_description& desc)
18 {
19  bpo::options_description debug_options{"Debugging options"};
20  // clang-format off
21  debug_options.add_options()
22  ("mt-diagnostics,M",
23  bpo::value<std::string>(),
24  "Log art-specific multi-threading diagnostics to "
25  "the provided destination.")
26  ( "trace", "Activate tracing.")
27  ( "no-trace", "Deactivate tracing.")
28  ("timing", "Activate monitoring of time spent per event/module.")
29  ("timing-db",
30  bpo::value<std::string>(),
31  "Output time-tracking data to SQLite3 database with name <db-file>.")
32  ( "no-timing", "Deactivate time tracking.")
33  ("memcheck-db",
34  bpo::value<std::string>(),
35  "Output memory use data to SQLite3 database with name <db-file>.")
36  ( "no-memcheck", "Deactivate monitoring of memory use.")
37  ("data-dependency-graph,g",
38  bpo::value<std::string>(),
39  "Print DOT file that shows the dependency graph of "
40  "modules, based on the specified paths and 'consumes' "
41  "statements invoked by users; call constructors of all "
42  "modules and exit just before processing the event loop.")
43  ("validate-config",
44  bpo::value<std::string>(),
45  "Output post-processed configuration to <file>; call constructors of all "
46  "sources, modules and services, performing extra configuration "
47  "verification. Exit just before processing the event loop.")
48  ("config-summary",
49  bpo::value<std::string>()->implicit_value("brief"),
50  "Output summary of full program configuration. Allowed values include "
51  "'brief', 'detailed', and 'full'.")
52  ("config-out",
53  bpo::value<std::string>(),
54  "Output post-processed configuration to <file> and continue with job.")
55  ("debug-config",
56  bpo::value<std::string>(),
57  "Output post-processed configuration to <file> and exit.")
58  ("annotate", "Include configuration parameter source information.")
59  ("prefix-annotate",
60  "Include configuration parameter source information "
61  "on line preceding parameter declaration.");
62  // clang-format on
63  desc.add(debug_options);
64 }
65 
66 int
67 art::DebugOptionsHandler::doCheckOptions(bpo::variables_map const& vm)
68 {
69  if (vm.count("trace") + vm.count("no-trace") > 1) {
71  << "Options --trace and --no-trace are incompatible.\n";
72  }
73  if (vm.count("timing") + vm.count("no-timing") > 1) {
75  << "Options --timing and --no-timing are incompatible.\n";
76  }
77  if (vm.count("timing-db") + vm.count("no-timing") > 1) {
79  << "Options --timing-db and --no-timing are incompatible.\n";
80  }
81  if (vm.count("memcheck-db") + vm.count("no-memcheck") > 1) {
83  << "Options --memcheck-db and --no-memcheck are incompatible.\n";
84  }
85  unsigned const config_out_count = vm.count("validate-config") +
86  vm.count("debug-config") +
87  vm.count("config-out");
88  if (config_out_count + vm.count("config-summary") > 1) {
90  << "Options --validate-config, --debug-config, --config-out, and "
91  "--config-summary are incompatible.\n";
92  }
93  unsigned const annotate_count =
94  vm.count("annotate") + vm.count("prefix-annotate");
95  if (annotate_count > 1) {
97  << "Options --annotate and --prefix-annotate are incompatible, and may "
98  "be specified only once.\n";
99  }
100 
101  if (annotate_count == 1 && config_out_count == 0) {
103  << "Options --annotate and --prefix-annotate may be specified only for "
104  "the\n"
105  "--debug-config, --config-out, or --validate-config program "
106  "options.\n";
107  }
108 
109  return 0;
110 }
111 
112 int
114  bpo::variables_map const& vm,
115  fhicl::intermediate_table& raw_config)
116 {
117 
118  using namespace fhicl::detail;
119 
120  auto const scheduler_key = fhicl_key("services", "scheduler");
121  std::string const debug_table{fhicl_key(scheduler_key, "debug")};
122  std::string option;
123  std::string fn;
124 
125  // Remove any previously-defined "services.scheduler.debug" parameter.
126  raw_config.erase(debug_table);
127  raw_config.erase(
128  fhicl_key(scheduler_key, "configOut")); // legacy configuration
129 
130  auto debugging_options = {
131  "config-summary", "config-out", "debug-config", "validate-config"};
132  for (auto const opt : debugging_options) {
133  if (vm.count(opt)) {
134  tie(option, fn) = make_tuple(opt, vm[opt].as<std::string>());
135  break;
136  }
137  }
138 
139  std::string mode;
140  if (option == "config-summary") {
141  mode = vm["config-summary"].as<std::string>();
142  } else {
143  if (vm.count("annotate")) {
144  mode = "annotate";
145  } else if (vm.count("prefix-annotate")) {
146  mode = "prefix-annotate";
147  } else {
148  mode = "raw";
149  }
150  }
151 
152  if (!option.empty()) {
153  raw_config.put(fhicl_key(debug_table, "option"), option);
154  raw_config.put(fhicl_key(debug_table, "fileName"), fn);
155  raw_config.put(fhicl_key(debug_table, "printMode"), mode);
156  }
157 
158  std::string graph_option{"data-dependency-graph"};
159  if (vm.count(graph_option)) {
160  raw_config.put("services.scheduler.dataDependencyGraph",
161  vm[graph_option].as<std::string>());
162  }
163 
164  if (vm.count("trace")) {
165  raw_config.putEmptyTable("services.Tracer");
166  } else if (vm.count("no-trace")) {
167  raw_config.erase("services.Tracer");
168  }
169  auto const timingdb = vm.count("timing-db");
170  if (vm.count("timing") || timingdb) {
171  raw_config.putEmptyTable("services.TimeTracker");
172  if (timingdb)
173  raw_config.put("services.TimeTracker.dbOutput.filename",
174  vm["timing-db"].as<std::string>());
175  } else if (vm.count("no-timing")) {
176  raw_config.erase("services.TimeTracker");
177  }
178  if (vm.count("memcheck-db")) {
179  raw_config.put("services.MemoryTracker.dbOutput.filename",
180  vm["memcheck-db"].as<std::string>());
181  } else if (vm.count("no-memcheck")) {
182  raw_config.erase("services.MemoryTracker");
183  }
184 
185  // messagefacility configuration.
186  auto const message_key = fhicl_key("services", "message");
187  auto const dests_key = fhicl_key(message_key, "destinations");
188  if (!detail::exists_outside_prolog(raw_config, message_key)) {
189  raw_config.put(fhicl_key(dests_key, "STDOUT.categories.ArtReport.limit"),
190  100);
191  raw_config.put(fhicl_key(dests_key, "STDOUT.categories.default.limit"), -1);
192  raw_config.put(fhicl_key(dests_key, "STDOUT.type"), "cout");
193  raw_config.put(fhicl_key(dests_key, "STDOUT.threshold"), "INFO");
194  }
195  assert(detail::exists_outside_prolog(raw_config, dests_key));
196  auto const& dests = raw_config.get<table_t const&>(dests_key);
197 
198  // By default, suppress all logging of messages of MTdiagnostics category.
199  for (auto const& p : dests) {
200  std::string const& dest_name = p.first;
201  if (dest_name == "statistics"s)
202  continue; // statistics are special -- see below
203  raw_config.put(
204  fhicl_key(dests_key, dest_name, "categories.MTdiagnostics.limit"), 0);
205  }
206 
207  // The statistics destination represents a table of named destinations.
208  auto const& stats_dest_key = fhicl_key(dests_key, "statistics");
209  if (detail::exists_outside_prolog(raw_config, stats_dest_key)) {
210  auto const& stats_dests = raw_config.get<table_t const&>(stats_dest_key);
211  for (auto const& p : stats_dests) {
212  std::string const& dest_name = p.first;
213  raw_config.put(
214  fhicl_key(stats_dest_key, dest_name, "categories.MTdiagnostics.limit"),
215  0);
216  }
217  }
218 
219  if (vm.count("mt-diagnostics") > 0) {
220  auto const dest = vm["mt-diagnostics"].as<std::string>();
221  if (detail::output_to_stdout(dest)) {
222  // Special handling since the 'cout' destination is already the
223  // default per above.
224  raw_config.put(
225  fhicl_key(dests_key, "STDOUT.categories.MTdiagnostics.limit"), -1);
226  return 0;
227  }
228 
229  auto const mt_dest_key = fhicl_key(dests_key, "MTdiagnostics");
230  if (detail::output_to_stderr(dest)) {
231  raw_config.put(fhicl_key(mt_dest_key, "type"), "cerr");
232  } else {
233  raw_config.put(fhicl_key(mt_dest_key, "type"), "file");
234  raw_config.put(fhicl_key(mt_dest_key, "filename"), dest);
235  }
236  raw_config.put(fhicl_key(mt_dest_key, "categories.MTdiagnostics.limit"),
237  -1);
238  raw_config.put(fhicl_key(mt_dest_key, "categories.default.limit"), 0);
239  }
240 
241  return 0;
242 }
int doProcessOptions(bpo::variables_map const &vm, fhicl::intermediate_table &raw_config) override
bool exists_outside_prolog(fhicl::intermediate_table const &config, std::string const &key)
int doCheckOptions(bpo::variables_map const &vm) override
std::enable_if_t< std::is_convertible_v< T, std::string >, std::string > fhicl_key(T const &name)
Definition: fhicl_key.h:12
shims::map< std::string, extended_value > table_t
bool put(std::string const &name, std::string const &value, bool in_prolog=false)
DebugOptionsHandler(bpo::options_description &desc)
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
bool putEmptyTable(std::string const &name, bool in_prolog=false)
void erase(std::string const &key, bool in_prolog=false)
T get(std::string const &name)
bool output_to_stdout(std::string const &spec)
Definition: output_to.cc:21