artdaq  v3_09_01
DispatcherCore.cc
1 #include <bitset>
2 #include <cerrno>
3 #include <iomanip>
4 #include <sstream>
5 
6 #include <csignal>
7 
8 #include <boost/algorithm/string.hpp>
9 #include <boost/exception/all.hpp>
10 #include <boost/filesystem.hpp>
11 #include <boost/throw_exception.hpp>
12 #include <boost/tokenizer.hpp>
13 #include <utility>
14 
15 #include "fhiclcpp/ParameterSet.h"
16 
17 #include "artdaq/DAQdata/Globals.hh" // include these 2 first -
18 #define TRACE_NAME (app_name + "_DispatcherCore").c_str()
19 
20 #include "artdaq-core/Core/SimpleMemoryReader.hh"
21 #include "artdaq-core/Data/RawEvent.hh"
22 
23 #include "artdaq/Application/DispatcherCore.hh"
24 #include "artdaq/TransferPlugins/MakeTransferPlugin.hh"
25 
26 bool artdaq::DispatcherCore::initialize(fhicl::ParameterSet const& pset)
27 {
28  TLOG(TLVL_DEBUG) << "initialize method called with DAQ "
29  << "ParameterSet = \"" << pset.to_string() << "\".";
30 
31  pset_ = pset;
32  // 04-Apr-2019, KAB: added support for art config params to be in an "art" block
33  if (pset_.has_key("art"))
34  {
35  pset_ = pset_.get<fhicl::ParameterSet>("art");
36  }
37  pset_.erase("outputs");
38  pset_.erase("physics");
39  pset_.erase("daq");
40 
41  TLOG(TLVL_DEBUG) << "Pieces of the input pset that are saved for later: \"" << pset_.to_string() << "\".";
42 
43  // pull out the relevant parts of the ParameterSet
44  fhicl::ParameterSet daq_pset;
45  try
46  {
47  daq_pset = pset.get<fhicl::ParameterSet>("daq");
48  }
49  catch (...)
50  {
51  TLOG(TLVL_ERROR)
52  << "Unable to find the DAQ parameters in the initialization "
53  << "ParameterSet: \"" + pset.to_string() + "\".";
54  return false;
55  }
56  fhicl::ParameterSet agg_pset;
57  try
58  {
59  agg_pset = daq_pset.get<fhicl::ParameterSet>("dispatcher", daq_pset.get<fhicl::ParameterSet>("aggregator"));
60  }
61  catch (...)
62  {
63  TLOG(TLVL_ERROR)
64  << "Unable to find the Dispatcher parameters in the DAQ "
65  << "initialization ParameterSet: \"" + daq_pset.to_string() + "\".";
66  return false;
67  }
68 
69  broadcast_mode_ = agg_pset.get<bool>("broadcast_mode", true);
70  if (broadcast_mode_ && !agg_pset.has_key("broadcast_mode"))
71  {
72  agg_pset.put<bool>("broadcast_mode", true);
73  }
74 
75  agg_pset.erase("restart_crashed_art_processes");
76  agg_pset.put<bool>("restart_crashed_art_processes", false);
77 
78  agg_pset.erase("art_analyzer_count");
79  agg_pset.put<int>("art_analyzer_count", 0);
80 
81  // initialize the MetricManager and the names of our metrics
82  fhicl::ParameterSet metric_pset;
83 
84  try
85  {
86  metric_pset = daq_pset.get<fhicl::ParameterSet>("metrics");
87  }
88  catch (...)
89  {} // OK if there's no metrics table defined in the FHiCL
90 
91  return initializeDataReceiver(pset, agg_pset, metric_pset);
92 }
93 
94 std::string artdaq::DispatcherCore::register_monitor(fhicl::ParameterSet const& pset)
95 {
96  TLOG(TLVL_DEBUG) << "DispatcherCore::register_monitor called with argument \"" << pset.to_string() << "\"";
97  check_filters_();
98 
99  try
100  {
101  TLOG(TLVL_DEBUG) << "Getting unique_label from input ParameterSet";
102  auto const& label = pset.get<std::string>("unique_label");
103  TLOG(TLVL_DEBUG) << "Unique label is " << label;
104  {
105  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
106  if (registered_monitors_.count(label) != 0u)
107  {
108  throw cet::exception("DispatcherCore") << "Unique label already exists!"; // NOLINT(cert-err60-cpp)
109  }
110 
111  registered_monitors_[label] = pset;
112  }
113 
114  // ELF, Jul 21, 2020: This can take a long time, and we don't want to block the XMLRPC thread
115  boost::thread thread([=] { start_art_process_(label); });
116  thread.detach();
117  }
118  catch (const cet::exception& e)
119  {
120  std::stringstream errmsg;
121  errmsg << "Unable to create a Transfer plugin with the FHiCL code \"" << pset.to_string() << "\", a new monitor has not been registered" << std::endl;
122  errmsg << "Exception: " << e.what();
123  TLOG(TLVL_ERROR) << errmsg.str();
124  return errmsg.str();
125  }
126  catch (const boost::exception& e)
127  {
128  std::stringstream errmsg;
129  errmsg << "Unable to create a Transfer plugin with the FHiCL code \"" << pset.to_string() << "\", a new monitor has not been registered" << std::endl;
130  errmsg << "Exception: " << boost::diagnostic_information(e);
131  TLOG(TLVL_ERROR) << errmsg.str();
132  return errmsg.str();
133  }
134  catch (const std::exception& e)
135  {
136  std::stringstream errmsg;
137  errmsg << "Unable to create a Transfer plugin with the FHiCL code \"" << pset.to_string() << "\", a new monitor has not been registered" << std::endl;
138  errmsg << "Exception: " << e.what();
139  TLOG(TLVL_ERROR) << errmsg.str();
140  return errmsg.str();
141  }
142  catch (...)
143  {
144  std::stringstream errmsg;
145  errmsg << "Unable to create a Transfer plugin with the FHiCL code \"" << pset.to_string() << "\", a new monitor has not been registered";
146  TLOG(TLVL_ERROR) << errmsg.str();
147  return errmsg.str();
148  }
149 
150  return "Success";
151 }
152 
153 std::string artdaq::DispatcherCore::unregister_monitor(std::string const& label)
154 {
155  TLOG(TLVL_DEBUG) << "DispatcherCore::unregister_monitor called with argument \"" << label << "\"";
156  check_filters_();
157 
158  try
159  {
160  {
161  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
162  if (registered_monitors_.count(label) == 0)
163  {
164  std::stringstream errmsg;
165  errmsg << "Warning in DispatcherCore::unregister_monitor: unable to find requested transfer plugin with "
166  << "label \"" << label << "\"";
167  TLOG(TLVL_WARNING) << errmsg.str();
168  return errmsg.str();
169  }
170 
171  registered_monitors_.erase(label);
172  }
173 
174  // ELF, Jul 21, 2020: This can take a long time, and we don't want to block the XMLRPC thread
175  boost::thread thread([=] { stop_art_process_(label); });
176  thread.detach();
177  }
178  catch (...)
179  {
180  std::stringstream errmsg;
181  errmsg << "Unable to unregister transfer plugin with label \"" << label << "\"";
182  return errmsg.str();
183  }
184 
185  return "Success";
186 }
187 
188 fhicl::ParameterSet artdaq::DispatcherCore::merge_parameter_sets_(fhicl::ParameterSet const& skel, const std::string& label, const fhicl::ParameterSet& pset)
189 {
190  fhicl::ParameterSet generated_pset(skel);
191  fhicl::ParameterSet generated_outputs;
192  fhicl::ParameterSet generated_physics;
193  fhicl::ParameterSet generated_physics_analyzers;
194  fhicl::ParameterSet generated_physics_producers;
195  fhicl::ParameterSet generated_physics_filters;
196  std::unordered_map<std::string, std::vector<std::string>> generated_physics_filter_paths;
197 
198  TLOG(TLVL_DEBUG) << "merge_parameter_sets_: Generating fhicl for monitor " << label;
199 
200  try
201  {
202  auto path = pset.get<std::vector<std::string>>("path");
203 
204  auto filters = pset.get<std::vector<fhicl::ParameterSet>>("filter_paths", std::vector<fhicl::ParameterSet>());
205  for (auto& filter : filters)
206  {
207  try
208  {
209  auto name = filter.get<std::string>("name");
210  auto path = filter.get<std::vector<std::string>>("path");
211  if (generated_physics_filter_paths.count(name) != 0u)
212  {
213  bool matched = generated_physics_filter_paths[name].size() == path.size();
214  for (size_t ii = 0; matched && ii < generated_physics_filter_paths[name].size(); ++ii)
215  {
216  matched = matched && path[ii] == generated_physics_filter_paths[name][ii];
217  }
218 
219  if (matched)
220  {
221  // Path is already configured
222  continue;
223  }
224 
225  auto newname = label + name;
226  generated_physics_filter_paths[newname] = path;
227  }
228  else
229  {
230  generated_physics_filter_paths[name] = path;
231  }
232  }
233  catch (...)
234  {
235  }
236  }
237 
238  // outputs section
239  auto outputs = pset.get<fhicl::ParameterSet>("outputs");
240  if (outputs.get_pset_names().size() > 1 || outputs.get_pset_names().empty())
241  {
242  // Only one output allowed per monitor
243  }
244  auto output_name = outputs.get_pset_names()[0];
245  auto output_pset = outputs.get<fhicl::ParameterSet>(output_name);
246  generated_outputs.put(label + output_name, output_pset);
247  bool outputInPath = false;
248  for (auto& ii : path)
249  {
250  if (ii == output_name)
251  {
252  ii = label + output_name;
253  outputInPath = true;
254  }
255  }
256  if (!outputInPath)
257  {
258  path.push_back(label + output_name);
259  }
260 
261  //physics section
262  auto physics_pset = pset.get<fhicl::ParameterSet>("physics");
263 
264  if (physics_pset.has_key("analyzers"))
265  {
266  auto analyzers = physics_pset.get<fhicl::ParameterSet>("analyzers");
267  for (const auto& key : analyzers.get_pset_names())
268  {
269  if (generated_physics_analyzers.has_key(key) && analyzers.get<fhicl::ParameterSet>(key) == generated_physics_analyzers.get<fhicl::ParameterSet>(key))
270  {
271  // Module is already configured
272  continue;
273  }
274  if (generated_physics_analyzers.has_key(key))
275  {
276  // Module already exists with name, rename
277  auto newkey = label + key;
278  generated_physics_analyzers.put<fhicl::ParameterSet>(newkey, analyzers.get<fhicl::ParameterSet>(key));
279  for (auto& ii : path)
280  {
281  if (ii == key)
282  {
283  ii = newkey;
284  }
285  }
286  }
287  else
288  {
289  generated_physics_analyzers.put<fhicl::ParameterSet>(key, analyzers.get<fhicl::ParameterSet>(key));
290  }
291  }
292  }
293  if (physics_pset.has_key("producers"))
294  {
295  auto producers = physics_pset.get<fhicl::ParameterSet>("producers");
296  for (const auto& key : producers.get_pset_names())
297  {
298  if (generated_physics_producers.has_key(key) && producers.get<fhicl::ParameterSet>(key) == generated_physics_producers.get<fhicl::ParameterSet>(key))
299  {
300  // Module is already configured
301  continue;
302  }
303  if (generated_physics_producers.has_key(key))
304  {
305  // Module already exists with name, rename
306  auto newkey = label + key;
307  generated_physics_producers.put<fhicl::ParameterSet>(newkey, producers.get<fhicl::ParameterSet>(key));
308  for (auto& ii : path)
309  {
310  if (ii == key)
311  {
312  ii = newkey;
313  }
314  }
315  }
316  else
317  {
318  generated_physics_producers.put<fhicl::ParameterSet>(key, producers.get<fhicl::ParameterSet>(key));
319  }
320  }
321  }
322  if (physics_pset.has_key("filters"))
323  {
324  auto filters = physics_pset.get<fhicl::ParameterSet>("filters");
325  for (const auto& key : filters.get_pset_names())
326  {
327  if (generated_physics_filters.has_key(key) && filters.get<fhicl::ParameterSet>(key) == generated_physics_filters.get<fhicl::ParameterSet>(key))
328  {
329  // Module is already configured
330  continue;
331  }
332  if (generated_physics_filters.has_key(key))
333  {
334  // Module already exists with name, rename
335  auto newkey = label + key;
336  generated_physics_filters.put<fhicl::ParameterSet>(newkey, filters.get<fhicl::ParameterSet>(key));
337  for (auto& ii : path)
338  {
339  if (ii == key)
340  {
341  ii = newkey;
342  }
343  }
344  }
345  else
346  {
347  generated_physics_filters.put<fhicl::ParameterSet>(key, filters.get<fhicl::ParameterSet>(key));
348  }
349  }
350  }
351  generated_physics.put<std::vector<std::string>>(label, path);
352  }
353  catch (cet::exception& e)
354  {
355  // Error in parsing input fhicl
356  TLOG(TLVL_ERROR) << "merge_parameter_sets_: Error processing input fhicl: " << e.what();
357  }
358 
359  TLOG(TLVL_DEBUG) << "merge_parameter_sets_: Building final ParameterSet";
360  generated_pset.put("outputs", generated_outputs);
361 
362  generated_physics.put("analyzers", generated_physics_analyzers);
363  generated_physics.put("producers", generated_physics_producers);
364  generated_physics.put("filters", generated_physics_filters);
365 
366  for (auto& path : generated_physics_filter_paths)
367  {
368  generated_physics.put(path.first, path.second);
369  }
370 
371  generated_pset.put("physics", generated_physics);
372 
373  return generated_pset;
374 }
375 
376 fhicl::ParameterSet artdaq::DispatcherCore::generate_filter_fhicl_()
377 {
378  TLOG(TLVL_DEBUG) << "generate_filter_fhicl_ BEGIN";
379  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
380  fhicl::ParameterSet generated_pset = pset_;
381 
382  for (auto& monitor : registered_monitors_)
383  {
384  auto label = monitor.first;
385  auto pset = monitor.second;
386  generated_pset = merge_parameter_sets_(generated_pset, label, pset);
387  }
388 
389  TLOG(TLVL_DEBUG) << "generate_filter_fhicl_ returning ParameterSet: " << generated_pset.to_string();
390  return generated_pset;
391 }
392 
393 void artdaq::DispatcherCore::check_filters_()
394 {
395  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
396  auto it = registered_monitors_.begin();
397  while (it != registered_monitors_.end())
398  {
399  if (registered_monitor_pids_.count(it->first) != 0u)
400  {
401  if (!event_store_ptr_)
402  {
403  registered_monitor_pids_.erase(it->first);
404  }
405  else
406  {
407  auto pid = registered_monitor_pids_[it->first];
408  auto sts = kill(pid, 0);
409  if (sts < 0)
410  {
411  registered_monitor_pids_.erase(it->first);
412  }
413  }
414  }
415  ++it;
416  }
417 }
418 
419 void artdaq::DispatcherCore::start_art_process_(std::string const& label)
420 {
421  if (event_store_ptr_ != nullptr)
422  {
423  if (broadcast_mode_)
424  {
425  fhicl::ParameterSet pset;
426  {
427  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
428  pset = registered_monitors_[label];
429  }
430  fhicl::ParameterSet ps = merge_parameter_sets_(pset_, label, pset);
431  TLOG(TLVL_DEBUG) << "Starting art process with received fhicl";
432  auto pid = event_store_ptr_->StartArtProcess(ps);
433  {
434  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
435  registered_monitor_pids_[label] = pid;
436  }
437  }
438  else
439  {
440  TLOG(TLVL_DEBUG) << "Calling ReconfigureArt";
441  fhicl::ParameterSet generated_fhicl;
442  {
443  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
444  generated_fhicl = generate_filter_fhicl_();
445  }
446  event_store_ptr_->ReconfigureArt(generated_fhicl);
447  TLOG(TLVL_DEBUG) << "Done with ReconfigureArt";
448  }
449  }
450  else
451  {
452  TLOG(TLVL_ERROR) << "Unable to add monitor as there is no SharedMemoryEventManager instance!";
453  }
454 }
455 
456 void artdaq::DispatcherCore::stop_art_process_(std::string const& label)
457 {
458  if (event_store_ptr_ != nullptr)
459  {
460  if (broadcast_mode_)
461  {
462  if (registered_monitor_pids_.count(label) != 0u)
463  {
464  std::set<pid_t> pids;
465  {
466  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
467  pids.insert(registered_monitor_pids_[label]);
468  registered_monitor_pids_.erase(label);
469  }
470  TLOG(TLVL_DEBUG) << "Calling ShutdownArtProcesses";
471  event_store_ptr_->ShutdownArtProcesses(pids);
472  TLOG(TLVL_DEBUG) << "Done with ShutdownArtProcesses";
473  }
474  }
475  else
476  {
477  TLOG(TLVL_DEBUG) << "Calling ReconfigureArt";
478  fhicl::ParameterSet generated_fhicl;
479  {
480  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
481  generated_fhicl = generate_filter_fhicl_();
482  }
483  event_store_ptr_->ReconfigureArt(generated_fhicl);
484  TLOG(TLVL_DEBUG) << "Done with ReconfigureArt";
485  }
486  }
487 }
std::string unregister_monitor(std::string const &label)
Delete the TransferInterface having the given unique label.
std::string register_monitor(fhicl::ParameterSet const &pset)
Create a new TransferInterface instance using the given configuration.
bool initializeDataReceiver(fhicl::ParameterSet const &pset, fhicl::ParameterSet const &data_pset, fhicl::ParameterSet const &metric_pset)
Initialize the DataReceiverCore (should be called from initialize() overrides.
bool initialize(fhicl::ParameterSet const &pset) override
Processes the initialize request.