artdaq  v3_09_02
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  TLOG(TLVL_DEBUG) << "Successfully registered monitor";
151  return "Success";
152 }
153 
154 std::string artdaq::DispatcherCore::unregister_monitor(std::string const& label)
155 {
156  TLOG(TLVL_DEBUG) << "DispatcherCore::unregister_monitor called with argument \"" << label << "\"";
157  check_filters_();
158 
159  try
160  {
161  {
162  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
163  if (registered_monitors_.count(label) == 0)
164  {
165  std::stringstream errmsg;
166  errmsg << "Warning in DispatcherCore::unregister_monitor: unable to find requested transfer plugin with "
167  << "label \"" << label << "\"";
168  TLOG(TLVL_WARNING) << errmsg.str();
169  return errmsg.str();
170  }
171 
172  registered_monitors_.erase(label);
173  }
174 
175  // ELF, Jul 21, 2020: This can take a long time, and we don't want to block the XMLRPC thread
176  boost::thread thread([=] { stop_art_process_(label); });
177  thread.detach();
178  }
179  catch (...)
180  {
181  std::stringstream errmsg;
182  errmsg << "Unable to unregister transfer plugin with label \"" << label << "\"";
183  TLOG(TLVL_ERROR) << errmsg.str();
184  return errmsg.str();
185  }
186 
187  TLOG(TLVL_DEBUG) << "unregister_monitor completed successfully";
188  return "Success";
189 }
190 
191 fhicl::ParameterSet artdaq::DispatcherCore::merge_parameter_sets_(fhicl::ParameterSet const& skel, const std::string& label, const fhicl::ParameterSet& pset)
192 {
193  fhicl::ParameterSet generated_pset(skel);
194  fhicl::ParameterSet generated_outputs;
195  fhicl::ParameterSet generated_physics;
196  fhicl::ParameterSet generated_physics_analyzers;
197  fhicl::ParameterSet generated_physics_producers;
198  fhicl::ParameterSet generated_physics_filters;
199  std::unordered_map<std::string, std::vector<std::string>> generated_physics_filter_paths;
200 
201  TLOG(TLVL_DEBUG) << "merge_parameter_sets_: Generating fhicl for monitor " << label;
202 
203  try
204  {
205  auto path = pset.get<std::vector<std::string>>("path");
206 
207  auto filters = pset.get<std::vector<fhicl::ParameterSet>>("filter_paths", std::vector<fhicl::ParameterSet>());
208  for (auto& filter : filters)
209  {
210  try
211  {
212  auto name = filter.get<std::string>("name");
213  auto path = filter.get<std::vector<std::string>>("path");
214  if (generated_physics_filter_paths.count(name) != 0u)
215  {
216  bool matched = generated_physics_filter_paths[name].size() == path.size();
217  for (size_t ii = 0; matched && ii < generated_physics_filter_paths[name].size(); ++ii)
218  {
219  matched = matched && path[ii] == generated_physics_filter_paths[name][ii];
220  }
221 
222  if (matched)
223  {
224  // Path is already configured
225  continue;
226  }
227 
228  auto newname = label + name;
229  generated_physics_filter_paths[newname] = path;
230  }
231  else
232  {
233  generated_physics_filter_paths[name] = path;
234  }
235  }
236  catch (...)
237  {
238  }
239  }
240 
241  // outputs section
242  auto outputs = pset.get<fhicl::ParameterSet>("outputs");
243  if (outputs.get_pset_names().size() > 1 || outputs.get_pset_names().empty())
244  {
245  // Only one output allowed per monitor
246  }
247  auto output_name = outputs.get_pset_names()[0];
248  auto output_pset = outputs.get<fhicl::ParameterSet>(output_name);
249  generated_outputs.put(label + output_name, output_pset);
250  bool outputInPath = false;
251  for (auto& ii : path)
252  {
253  if (ii == output_name)
254  {
255  ii = label + output_name;
256  outputInPath = true;
257  }
258  }
259  if (!outputInPath)
260  {
261  path.push_back(label + output_name);
262  }
263 
264  //physics section
265  auto physics_pset = pset.get<fhicl::ParameterSet>("physics");
266 
267  if (physics_pset.has_key("analyzers"))
268  {
269  auto analyzers = physics_pset.get<fhicl::ParameterSet>("analyzers");
270  for (const auto& key : analyzers.get_pset_names())
271  {
272  if (generated_physics_analyzers.has_key(key) && analyzers.get<fhicl::ParameterSet>(key) == generated_physics_analyzers.get<fhicl::ParameterSet>(key))
273  {
274  // Module is already configured
275  continue;
276  }
277  if (generated_physics_analyzers.has_key(key))
278  {
279  // Module already exists with name, rename
280  auto newkey = label + key;
281  generated_physics_analyzers.put<fhicl::ParameterSet>(newkey, analyzers.get<fhicl::ParameterSet>(key));
282  for (auto& ii : path)
283  {
284  if (ii == key)
285  {
286  ii = newkey;
287  }
288  }
289  }
290  else
291  {
292  generated_physics_analyzers.put<fhicl::ParameterSet>(key, analyzers.get<fhicl::ParameterSet>(key));
293  }
294  }
295  }
296  if (physics_pset.has_key("producers"))
297  {
298  auto producers = physics_pset.get<fhicl::ParameterSet>("producers");
299  for (const auto& key : producers.get_pset_names())
300  {
301  if (generated_physics_producers.has_key(key) && producers.get<fhicl::ParameterSet>(key) == generated_physics_producers.get<fhicl::ParameterSet>(key))
302  {
303  // Module is already configured
304  continue;
305  }
306  if (generated_physics_producers.has_key(key))
307  {
308  // Module already exists with name, rename
309  auto newkey = label + key;
310  generated_physics_producers.put<fhicl::ParameterSet>(newkey, producers.get<fhicl::ParameterSet>(key));
311  for (auto& ii : path)
312  {
313  if (ii == key)
314  {
315  ii = newkey;
316  }
317  }
318  }
319  else
320  {
321  generated_physics_producers.put<fhicl::ParameterSet>(key, producers.get<fhicl::ParameterSet>(key));
322  }
323  }
324  }
325  if (physics_pset.has_key("filters"))
326  {
327  auto filters = physics_pset.get<fhicl::ParameterSet>("filters");
328  for (const auto& key : filters.get_pset_names())
329  {
330  if (generated_physics_filters.has_key(key) && filters.get<fhicl::ParameterSet>(key) == generated_physics_filters.get<fhicl::ParameterSet>(key))
331  {
332  // Module is already configured
333  continue;
334  }
335  if (generated_physics_filters.has_key(key))
336  {
337  // Module already exists with name, rename
338  auto newkey = label + key;
339  generated_physics_filters.put<fhicl::ParameterSet>(newkey, filters.get<fhicl::ParameterSet>(key));
340  for (auto& ii : path)
341  {
342  if (ii == key)
343  {
344  ii = newkey;
345  }
346  }
347  }
348  else
349  {
350  generated_physics_filters.put<fhicl::ParameterSet>(key, filters.get<fhicl::ParameterSet>(key));
351  }
352  }
353  }
354  generated_physics.put<std::vector<std::string>>(label, path);
355  }
356  catch (cet::exception& e)
357  {
358  // Error in parsing input fhicl
359  TLOG(TLVL_ERROR) << "merge_parameter_sets_: Error processing input fhicl: " << e.what();
360  }
361 
362  TLOG(TLVL_DEBUG) << "merge_parameter_sets_: Building final ParameterSet";
363  generated_pset.put("outputs", generated_outputs);
364 
365  generated_physics.put("analyzers", generated_physics_analyzers);
366  generated_physics.put("producers", generated_physics_producers);
367  generated_physics.put("filters", generated_physics_filters);
368 
369  for (auto& path : generated_physics_filter_paths)
370  {
371  generated_physics.put(path.first, path.second);
372  }
373 
374  generated_pset.put("physics", generated_physics);
375 
376  return generated_pset;
377 }
378 
379 fhicl::ParameterSet artdaq::DispatcherCore::generate_filter_fhicl_()
380 {
381  TLOG(TLVL_DEBUG) << "generate_filter_fhicl_ BEGIN";
382  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
383  fhicl::ParameterSet generated_pset = pset_;
384 
385  for (auto& monitor : registered_monitors_)
386  {
387  auto label = monitor.first;
388  auto pset = monitor.second;
389  generated_pset = merge_parameter_sets_(generated_pset, label, pset);
390  }
391 
392  TLOG(TLVL_DEBUG) << "generate_filter_fhicl_ returning ParameterSet: " << generated_pset.to_string();
393  return generated_pset;
394 }
395 
396 void artdaq::DispatcherCore::check_filters_()
397 {
398  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
399  auto it = registered_monitors_.begin();
400  while (it != registered_monitors_.end())
401  {
402  if (registered_monitor_pids_.count(it->first) != 0u)
403  {
404  if (!event_store_ptr_)
405  {
406  registered_monitor_pids_.erase(it->first);
407  }
408  else
409  {
410  auto pid = registered_monitor_pids_[it->first];
411  auto sts = kill(pid, 0);
412  if (sts < 0)
413  {
414  registered_monitor_pids_.erase(it->first);
415  }
416  }
417  }
418  ++it;
419  }
420 }
421 
422 void artdaq::DispatcherCore::start_art_process_(std::string const& label)
423 {
424  if (event_store_ptr_ != nullptr)
425  {
426  if (broadcast_mode_)
427  {
428  fhicl::ParameterSet pset;
429  {
430  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
431  pset = registered_monitors_[label];
432  }
433  fhicl::ParameterSet ps = merge_parameter_sets_(pset_, label, pset);
434  TLOG(TLVL_DEBUG) << "Starting art process with received fhicl";
435  auto pid = event_store_ptr_->StartArtProcess(ps);
436  {
437  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
438  registered_monitor_pids_[label] = pid;
439  }
440  }
441  else
442  {
443  TLOG(TLVL_DEBUG) << "Calling ReconfigureArt";
444  fhicl::ParameterSet generated_fhicl;
445  {
446  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
447  generated_fhicl = generate_filter_fhicl_();
448  }
449  event_store_ptr_->ReconfigureArt(generated_fhicl);
450  TLOG(TLVL_DEBUG) << "Done with ReconfigureArt";
451  }
452  }
453  else
454  {
455  TLOG(TLVL_ERROR) << "Unable to add monitor as there is no SharedMemoryEventManager instance!";
456  }
457 }
458 
459 void artdaq::DispatcherCore::stop_art_process_(std::string const& label)
460 {
461  if (event_store_ptr_ != nullptr)
462  {
463  if (broadcast_mode_)
464  {
465  if (registered_monitor_pids_.count(label) != 0u)
466  {
467  std::set<pid_t> pids;
468  {
469  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
470  pids.insert(registered_monitor_pids_[label]);
471  registered_monitor_pids_.erase(label);
472  }
473  TLOG(TLVL_DEBUG) << "Calling ShutdownArtProcesses";
474  event_store_ptr_->ShutdownArtProcesses(pids);
475  TLOG(TLVL_DEBUG) << "Done with ShutdownArtProcesses";
476  }
477  }
478  else
479  {
480  TLOG(TLVL_DEBUG) << "Calling ReconfigureArt";
481  fhicl::ParameterSet generated_fhicl;
482  {
483  std::lock_guard<std::mutex> lock(dispatcher_transfers_mutex_);
484  generated_fhicl = generate_filter_fhicl_();
485  }
486  event_store_ptr_->ReconfigureArt(generated_fhicl);
487  TLOG(TLVL_DEBUG) << "Done with ReconfigureArt";
488  }
489  }
490 }
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.