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