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