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