LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
ProcessingOptionsHandler.cc
Go to the documentation of this file.
2 
7 #include "tbb/task_arena.h"
8 
9 #include <string>
10 
11 using namespace std::string_literals;
13 
14 namespace {
15 
17 
18  // For 'fillTable' the behavior is as follows:
19  //
20  // (1) If the program option is specified at the command line, the
21  // corresponding FHiCL parameter is added to the intermediate
22  // table (if it doesn't already exist), or the corresponding
23  // value is overwritten (if the parameter does already exist).
24  //
25  // (2) If the program option is not specified AND the FHiCL file
26  // does not have the corresponding parameter, then a default
27  // value of 'true' is added to the FHiCL configuration.
28  //
29  // This function could be made more general, but there is currently
30  // no need.
31 
32  void
33  fillTable(std::string const& bpo_key,
34  std::string const& fhicl_key,
35  bpo::variables_map const& vm,
37  bool const default_value)
38  {
39  if (vm.count(bpo_key)) {
40  config.put(fhicl_key, vm[bpo_key].as<bool>());
41  } else if (!exists_outside_prolog(config, fhicl_key)) {
42  config.put(fhicl_key, default_value);
43  }
44  }
45 
46 } // namespace
47 
49  bpo::options_description& desc)
50 {
51  bpo::options_description processing_options{"Processing options"};
52  // clang-format off
53  processing_options.add_options()
54  ("parallelism,j",
55  bpo::value<int>(),
56  "Number of threads AND schedules to use for event processing "
57  "(default = 1, 0 = all cores).")
58  ("nschedules",
59  bpo::value<int>(),
60  "Number of schedules to use for event processing (default = 1)")
61  // Note: tbb wants nthreads to be an int!
62  ("nthreads",
63  bpo::value<int>(),
64  "Number of threads to use for event processing (default = 1, 0 = all "
65  "cores)")
66  ("default-exceptions",
67  "Some exceptions may be handled differently by default (e.g. "
68  "ProductNotFound).")
69  ("rethrow-default", "All exceptions default to rethrow.")
70  ("rethrow-all",
71  "All exceptions overridden to rethrow (cf rethrow-default).")
72  ("errorOnMissingConsumes",
73  bpo::value<bool>()->implicit_value(true, "true"),
74  "If 'true', then an exception will be thrown if any module attempts "
75  "to retrieve a product via the 'getBy*' interface without specifying "
76  "the appropriate 'consumes<T>(...)' statement in the module constructor.")
77  ("errorOnSIGINT",
78  bpo::value<bool>()->implicit_value(true, "true"),
79  "If 'true', a signal received from the user yields an art return code "
80  "corresponding to an error; otherwise return 0.");
81  // clang-format on
82  desc.add(processing_options);
83 }
84 
85 int
86 art::ProcessingOptionsHandler::doCheckOptions(bpo::variables_map const& vm)
87 {
88  if ((vm.count("rethrow-all") + vm.count("rethrow-default") +
89  vm.count("no-rethrow-default")) > 1) {
91  << "Options --default-exceptions, --rethrow-all, and --rethrow-default\n"
92  << "are mutually incompatible.\n";
93  }
94 
95  // 'parallelism' is incompatible with either 'nthreads' or
96  // 'nschedules'.
97  if (vm.count("parallelism")) {
98  if (vm.count("nthreads") or vm.count("nschedules")) {
99  throw Exception(errors::Configuration) << "The -j/--parallelism option "
100  "cannot be used with either "
101  "--nthreads or --nschedules.\n";
102  }
103  }
104 
105  if (vm.count("nthreads") and vm["nthreads"].as<int>() < 0) {
107  << "Option --nthreads must greater than or equal to 0.";
108  }
109  if (vm.count("nschedules") and vm["nschedules"].as<int>() < 1) {
111  << "Option --nschedules must be at least 1.\n";
112  }
113  return 0;
114 }
115 
116 int
118  bpo::variables_map const& vm,
119  fhicl::intermediate_table& raw_config)
120 {
121  auto const scheduler_key = fhicl_key("services", "scheduler");
122 
123  if (vm.count("rethrow-all") == 1 || vm.count("rethrow-default") == 1) {
124  raw_config.put(fhicl_key(scheduler_key, "defaultExceptions"), false);
125  if (vm.count("rethrow-all") == 1) {
126  raw_config.putEmptySequence(fhicl_key(scheduler_key, "IgnoreCompletely"));
127  raw_config.putEmptySequence(fhicl_key(scheduler_key, "SkipEvent"));
128  raw_config.putEmptySequence(fhicl_key(scheduler_key, "FailModule"));
129  raw_config.putEmptySequence(fhicl_key(scheduler_key, "FailPath"));
130  }
131  }
132 
133  fillTable("errorOnMissingConsumes",
134  fhicl_key(scheduler_key, "errorOnMissingConsumes"),
135  vm,
136  raw_config,
137  false);
138  fillTable("errorOnSIGINT",
139  fhicl_key(scheduler_key, "errorOnSIGINT"),
140  vm,
141  raw_config,
142  true);
143 
144  auto const num_schedules_key = fhicl_key(scheduler_key, "num_schedules");
145  auto const num_threads_key = fhicl_key(scheduler_key, "num_threads");
146  if (vm.count("parallelism")) {
147  // 'nthreads' and 'nschedules' are set to the same value.
148  auto const j = vm["parallelism"].as<int>();
149  auto const nthreads =
150  (j == 0) ? tbb::this_task_arena::max_concurrency() : j;
151  raw_config.put(num_schedules_key, nthreads);
152  raw_config.put(num_threads_key, nthreads);
153  return 0;
154  }
155 
156  if (vm.count("nschedules")) {
157  raw_config.put(num_schedules_key, vm["nschedules"].as<int>());
158  }
159  if (vm.count("nthreads")) {
160  auto const nt = vm["nthreads"].as<int>();
161  auto const nthreads =
162  (nt == 0) ? tbb::this_task_arena::max_concurrency() : nt;
163  raw_config.put(num_threads_key, nthreads);
164  }
165 
166  // If 'nschedules' or 'nthreads' does not exist in configuration,
167  // assign the default value of 1.
168  if (not exists_outside_prolog(raw_config, num_schedules_key)) {
169  raw_config.put(num_schedules_key, 1);
170  }
171  if (not exists_outside_prolog(raw_config, num_threads_key)) {
172  raw_config.put(num_threads_key, 1);
173  }
174 
175  return 0;
176 }
int doCheckOptions(bpo::variables_map const &vm) override
ProcessingOptionsHandler(bpo::options_description &desc)
bool exists_outside_prolog(fhicl::intermediate_table const &config, std::string const &key)
bool putEmptySequence(std::string const &name, bool in_prolog=false)
std::enable_if_t< std::is_convertible_v< T, std::string >, std::string > fhicl_key(T const &name)
Definition: fhicl_key.h:12
bool put(std::string const &name, std::string const &value, bool in_prolog=false)
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
int doProcessOptions(bpo::variables_map const &vm, fhicl::intermediate_table &raw_config) override