artdaq  v3_05_00
genToArt.cc
1 // genToArt
3 //
4 // This application is intended to invoke a configurable set of fragment
5 // generators, and funnel the result to an invocation of art. This is
6 // not an MPI application (see caveat below), so is not intended for
7 // high performance production DAQ scenarios -- for that, see the pmt
8 // application driver and its associated applcations boardreader and
9 // eventbuilder.
11 
12 #define TRACE_NAME "genToArt"
13 
14 #include "artdaq-core/Data/detail/RawFragmentHeader.hh"
15 #include "artdaq-core/Data/Fragment.hh"
16 #include "art/Framework/Art/artapp.h"
17 #include "canvas/Utilities/Exception.h"
18 #include "artdaq-core/Generators/FragmentGenerator.hh"
19 #include "artdaq/DAQdata/GenericFragmentSimulator.hh"
20 #include "artdaq/Generators/CommandableFragmentGenerator.hh"
21 #include "artdaq/DAQrate/SharedMemoryEventManager.hh"
22 #include "artdaq-core/Generators/makeFragmentGenerator.hh"
23 #include "artdaq-core/Core/SimpleMemoryReader.hh"
24 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh"
25 #include "cetlib/container_algorithms.h"
26 #include "fhiclcpp/ParameterSet.h"
27 #include "fhiclcpp/make_ParameterSet.h"
28 
29 #include <boost/program_options.hpp>
30 
31 #include <deque>
32 #include <iostream>
33 #include <map>
34 #include <memory>
35 #include <string>
36 #include <utility>
37 
38 namespace bpo = boost::program_options;
39 
40 namespace
41 {
49  int process_cmd_line(int argc, char** argv,
50  bpo::variables_map& vm)
51  {
52  std::ostringstream descstr;
53  descstr << argv[0]
54  << " <-c <config-file>> <other-options> [<source-file>]+";
55  bpo::options_description desc(descstr.str());
56  desc.add_options()
57  ("config,c", bpo::value<std::string>(), "Configuration file.")
58  ("help,h", "produce help message");
59  try
60  {
61  bpo::store(bpo::command_line_parser(argc, argv).options(desc).run(), vm);
62  bpo::notify(vm);
63  }
64  catch (bpo::error const& e)
65  {
66  TLOG(TLVL_ERROR) << "Exception from command line processing in " << argv[0]
67  << ": " << e.what();
68  return -1;
69  }
70  if (vm.count("help"))
71  {
72  std::cout << desc << std::endl;
73  return 1;
74  }
75  if (!vm.count("config"))
76  {
77  TLOG(TLVL_ERROR) << "Exception from command line processing in " << argv[0]
78  << ": no configuration file given.\n"
79  << "For usage and an options list, please do '"
80  << argv[0] << " --help"
81  << "'.";
82  return 2;
83  }
84  return 0;
85  }
86 
92  {
93  public:
99  ThrottledGenerator(std::string const& generator,
100  fhicl::ParameterSet const& ps);
101 
107  bool getNext(artdaq::FragmentPtrs& newFrags);
108 
113  size_t numFragIDs() const;
114 
121  void start(int run, uint64_t timeout, uint64_t timestamp) const
122  {
123  auto gen_ptr = dynamic_cast<artdaq::CommandableFragmentGenerator*>(generator_.get());
124  if (gen_ptr != nullptr) gen_ptr->StartCmd(run, timeout, timestamp);
125  }
131  void stop(uint64_t timeout, uint64_t timestamp) const
132  {
133  auto gen_ptr = dynamic_cast<artdaq::CommandableFragmentGenerator*>(generator_.get());
134  if (gen_ptr != nullptr) gen_ptr->StopCmd(timeout, timestamp);
135  }
136 
137  private:
138  bool generateFragments_();
139 
140  std::unique_ptr<artdaq::FragmentGenerator> generator_;
141  size_t const numFragIDs_;
142  std::map<artdaq::Fragment::fragment_id_t,
143  std::deque<artdaq::FragmentPtr>> frags_;
144  };
145 
146  ThrottledGenerator::
147  ThrottledGenerator(std::string const& generator,
148  fhicl::ParameterSet const& ps)
149  :
150  generator_(artdaq::makeFragmentGenerator(generator, ps))
151  , numFragIDs_(generator_->fragmentIDs().size())
152  , frags_()
153  {
154  assert(generator_);
155  }
156 
157  bool
159  getNext(artdaq::FragmentPtrs& newFrags)
160  {
161  if (frags_.size() && frags_.begin()->second.size())
162  { // Something stored.
163  for (auto& fQp : frags_)
164  {
165  assert(fQp.second.size());
166  newFrags.emplace_back(std::move(fQp.second.front()));
167  fQp.second.pop_front();
168  }
169  }
170  else
171  { // Need fresh fragments.
172  return generateFragments_() && getNext(newFrags);
173  }
174  return true;
175  }
176 
177  bool
178  ThrottledGenerator::
179  generateFragments_()
180  {
181  artdaq::FragmentPtrs incomingFrags;
182  bool result{ false };
183  while ((result = generator_->getNext(incomingFrags)) &&
184  incomingFrags.empty())
185  {
186  }
187  for (auto&& frag : incomingFrags)
188  {
189  frags_[frag->fragmentID()].emplace_back(std::move(frag));
190  }
191  return result;
192  }
193 
194  size_t
196  numFragIDs() const
197  {
198  return numFragIDs_;
199  }
200 
201  // artdaq::FragmentGenerator &
202  // ThrottledGenerator::
203  // generator() const
204  // {
205  // return *generator_;
206  // }
207 
225  int process_data(fhicl::ParameterSet const& pset)
226  {
227  auto const gta_pset = pset.get<fhicl::ParameterSet>("genToArt");
228 
229  // Make the generators based on the configuration.
230  std::vector<ThrottledGenerator> generators;
231 
232  auto const fr_pset = gta_pset.get<std::vector<fhicl::ParameterSet>>("fragment_receivers");
233  for (auto const& gen_ps : fr_pset)
234  {
235  generators.emplace_back(gen_ps.get<std::string>("generator"),
236  gen_ps);
237  }
238 
239  artdaq::FragmentPtrs frags;
240  auto eb_pset = gta_pset.get<fhicl::ParameterSet>("event_builder", {});
241  size_t expected_frags_per_event = 0;
242  for (auto& gen : generators)
243  {
244  gen.start(1000, 0, 0);
245  expected_frags_per_event += gen.numFragIDs();
246  }
247  eb_pset.put_or_replace<size_t>("expected_fragments_per_event", expected_frags_per_event);
248 
249  artdaq::SharedMemoryEventManager store(eb_pset, pset);
250  store.startRun(gta_pset.get<int>("run_number", 1000));
251 
252  auto const events_to_generate =
253  gta_pset.get<artdaq::Fragment::sequence_id_t>("events_to_generate", 0xFFFFFFFFFFFFFFFF);
254  auto const reset_sequenceID = pset.get<bool>("reset_sequenceID", true);
255  bool done = false;
256  for (artdaq::Fragment::sequence_id_t event_count = 1;
257  (events_to_generate == 0xFFFFFFFFFFFFFFFF
258  || event_count <= events_to_generate) && (!done);
259  ++event_count)
260  {
261  for (auto& gen : generators)
262  {
263  done |= !gen.getNext(frags);
264  }
265  TLOG(TLVL_TRACE) << "There are " << frags.size() << " Fragments in event " << event_count << ".";
266  artdaq::Fragment::sequence_id_t current_sequence_id = -1;
267  for (auto& val : frags)
268  {
269  if (reset_sequenceID)
270  {
271  TLOG(TLVL_DEBUG) << "Setting fragment sequence id to " << event_count;
272  val->setSequenceID(event_count);
273  }
274  if (current_sequence_id ==
275  static_cast<artdaq::Fragment::sequence_id_t>(-1))
276  {
277  current_sequence_id = val->sequenceID();
278  }
279  else if (val->sequenceID() != current_sequence_id)
280  {
281  throw art::Exception(art::errors::DataCorruption)
282  << "Data corruption: apparently related fragments have "
283  << " different sequence IDs: "
284  << val->sequenceID()
285  << " and "
286  << current_sequence_id
287  << ".\n";
288  }
289 
290  auto start_time = std::chrono::steady_clock::now();
291  bool sts = false;
292  auto loop_count = 0;
293  while (!sts)
294  {
295  artdaq::FragmentPtr tempFrag;
296  sts = store.AddFragment(std::move(val), 1000000, tempFrag);
297  if (!sts && event_count <= 10 && loop_count > 100)
298  {
299  TLOG(TLVL_ERROR) << "Fragment was not added after " << artdaq::TimeUtils::GetElapsedTime(start_time) << " s. Check art thread status!";
300  store.endOfData();
301  exit(1);
302  }
303  val = std::move(tempFrag);
304  if (!sts)
305  {
306  loop_count++;
307  usleep(10000);
308  }
309  }
310  }
311  frags.clear();
312  TLOG(TLVL_TRACE) << "Event " << event_count << " END";
313  }
314  for (auto& gen : generators)
315  {
316  gen.stop(0, 0);
317  }
318 
319  bool endSucceeded = store.endOfData();
320  if (endSucceeded)
321  {
322  return 0;
323  }
324  else
325  {
326  return 15;
327  }
328  }
329 }
330 
331 int main(int argc, char* argv[]) try
332 {
333  artdaq::configureMessageFacility("genToArt");
334  // Command line handling.
335  bpo::variables_map vm;
336  auto result = process_cmd_line(argc, argv, vm);
337  if (result != 0)
338  {
339  return (result);
340  }
341  // Read FHiCL configuration file.
342  fhicl::ParameterSet pset;
343  if (getenv("FHICL_FILE_PATH") == nullptr)
344  {
345  TLOG(TLVL_ERROR)
346  << "INFO: environment variable FHICL_FILE_PATH was not set. Using \".\"\n";
347  setenv("FHICL_FILE_PATH", ".", 0);
348  }
349  artdaq::SimpleLookupPolicy lookup_policy("FHICL_FILE_PATH");
350  make_ParameterSet(vm["config"].as<std::string>(), lookup_policy, pset);
351  return process_data(pset);
352 }
353 catch (std::string& x)
354 {
355  TLOG(TLVL_ERROR) << "Exception (type string) caught in genToArt: " << x << '\n';
356  return 1;
357 }
358 catch (char const* m)
359 {
360  TLOG(TLVL_ERROR) << "Exception (type char const*) caught in genToArt: ";
361  if (m)
362  {
363  TLOG(TLVL_ERROR) << m;
364  }
365  else
366  {
367  TLOG(TLVL_ERROR) << "[the value was a null pointer, so no message is available]";
368  }
369 }
void start(int run, uint64_t timeout, uint64_t timestamp) const
Send start signal to FragmentGenerator, if it&#39;s a CommandableFragmentGenerator.
Definition: genToArt.cc:121
The SharedMemoryEventManager is a SharedMemoryManger which tracks events as they are built...
void StopCmd(uint64_t timeout, uint64_t timestamp)
Stop the CommandableFragmentGenerator.
void StartCmd(int run, uint64_t timeout, uint64_t timestamp)
Start the CommandableFragmentGenerator.
int process_cmd_line(int argc, char **argv, bpo::variables_map &vm)
Process the command line.
Definition: genToArt.cc:49
bool getNext(artdaq::FragmentPtrs &newFrags)
Get the next fragment from the generator.
Definition: genToArt.cc:159
CommandableFragmentGenerator is a FragmentGenerator-derived abstract class that defines the interface...
int process_data(fhicl::ParameterSet const &pset)
Run the test, instantiating configured generators and an EventStore.
Definition: genToArt.cc:225
void stop(uint64_t timeout, uint64_t timestamp) const
Send stop signal to FragmentGenerator, if it&#39;s a CommandableFragmentGenerator.
Definition: genToArt.cc:131
size_t numFragIDs() const
Get the number of Fragment IDs handled by this generator.
Definition: genToArt.cc:196
ThrottledGenerator: ensure that we only get one fragment per type at a time from the generator...
Definition: genToArt.cc:91