artdaq  v3_12_02
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 #include "TRACE/tracemf.h"
13 #define TRACE_NAME "genToArt"
14 
15 #include "artdaq-core/Data/Fragment.hh"
16 #include "artdaq-core/Data/detail/RawFragmentHeader.hh"
17 #include "artdaq-core/Plugins/FragmentGenerator.hh"
18 #include "artdaq-core/Plugins/makeFragmentGenerator.hh"
19 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh"
20 #include "artdaq/DAQdata/GenericFragmentSimulator.hh"
21 #include "artdaq/DAQrate/SharedMemoryEventManager.hh"
22 #include "artdaq/Generators/CommandableFragmentGenerator.hh"
23 #include "canvas/Utilities/Exception.h"
24 #include "cetlib/container_algorithms.h"
25 #include "fhiclcpp/ParameterSet.h"
26 
27 #include <boost/program_options.hpp>
28 
29 #include <deque>
30 #include <iostream>
31 #include <map>
32 #include <memory>
33 #include <string>
34 #include <utility>
35 
36 namespace bpo = boost::program_options;
37 
38 namespace {
46 int process_cmd_line(int argc, char** argv,
47  bpo::variables_map& vm)
48 {
49  std::ostringstream descstr;
50  descstr << *argv
51  << " <-c <config-file>> <other-options> [<source-file>]+";
52  bpo::options_description desc(descstr.str());
53  desc.add_options()("config,c", bpo::value<std::string>(), "Configuration file.")("help,h", "produce help message");
54  try
55  {
56  bpo::store(bpo::command_line_parser(argc, argv).options(desc).run(), vm);
57  bpo::notify(vm);
58  }
59  catch (bpo::error const& e)
60  {
61  TLOG(TLVL_ERROR) << "Exception from command line processing in " << *argv
62  << ": " << e.what();
63  return -1;
64  }
65  if (vm.count("help") != 0u)
66  {
67  std::cout << desc << std::endl;
68  return 1;
69  }
70  if (vm.count("config") == 0u)
71  {
72  TLOG(TLVL_ERROR) << "Exception from command line processing in " << *argv
73  << ": no configuration file given.\n"
74  << "For usage and an options list, please do '"
75  << *argv << " --help"
76  << "'.";
77  return 2;
78  }
79  return 0;
80 }
81 
87 {
88 public:
94  ThrottledGenerator(std::string const& generator,
95  fhicl::ParameterSet const& ps);
96 
102  bool getNext(artdaq::FragmentPtrs& newFrags);
103 
108  size_t numFragIDs() const;
109 
116  void start(int run, uint64_t timeout, uint64_t timestamp) const
117  {
118  auto gen_ptr = dynamic_cast<artdaq::CommandableFragmentGenerator*>(generator_.get());
119  if (gen_ptr != nullptr)
120  {
121  gen_ptr->StartCmd(run, timeout, timestamp);
122  }
123  }
129  void stop(uint64_t timeout, uint64_t timestamp) const
130  {
131  auto gen_ptr = dynamic_cast<artdaq::CommandableFragmentGenerator*>(generator_.get());
132  if (gen_ptr != nullptr)
133  {
134  gen_ptr->StopCmd(timeout, timestamp);
135  }
136  }
137 
138 private:
139  bool generateFragments_();
140 
141  std::unique_ptr<artdaq::FragmentGenerator> generator_;
142  size_t const numFragIDs_;
143  std::map<artdaq::Fragment::fragment_id_t,
144  std::deque<artdaq::FragmentPtr>>
145  frags_;
146 };
147 
148 ThrottledGenerator::
149  ThrottledGenerator(std::string const& generator,
150  fhicl::ParameterSet const& ps)
151  : generator_(artdaq::makeFragmentGenerator(generator, ps))
152  , numFragIDs_(generator_->fragmentIDs().size())
153 
154 {
155  assert(generator_);
156 }
157 
159  getNext(artdaq::FragmentPtrs& newFrags)
160 {
161  if ((!frags_.empty()) && (!frags_.begin()->second.empty()))
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 ThrottledGenerator::
178  generateFragments_()
179 {
180  artdaq::FragmentPtrs incomingFrags;
181  bool result{false};
182  while ((result = generator_->getNext(incomingFrags)) &&
183  incomingFrags.empty())
184  {
185  }
186  for (auto&& frag : incomingFrags)
187  {
188  frags_[frag->fragmentID()].emplace_back(std::move(frag));
189  }
190  return result;
191 }
192 
193 size_t
195  numFragIDs() const
196 {
197  return numFragIDs_;
198 }
199 
200 // artdaq::FragmentGenerator &
201 // ThrottledGenerator::
202 // generator() const
203 // {
204 // return *generator_;
205 // }
206 
224 int process_data(fhicl::ParameterSet const& pset)
225 {
226  auto const gta_pset = pset.get<fhicl::ParameterSet>("genToArt");
227 
228  // Make the generators based on the configuration.
229  std::vector<ThrottledGenerator> generators;
230 
231  auto const fr_pset = gta_pset.get<std::vector<fhicl::ParameterSet>>("fragment_receivers");
232  generators.reserve(fr_pset.size());
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 || event_count <= events_to_generate) && (!done);
258  ++event_count)
259  {
260  for (auto& gen : generators)
261  {
262  done |= !gen.getNext(frags);
263  }
264  TLOG(TLVL_DEBUG + 33) << "There are " << frags.size() << " Fragments in event " << event_count << ".";
265  artdaq::Fragment::sequence_id_t current_sequence_id = -1;
266  for (auto& val : frags)
267  {
268  if (reset_sequenceID)
269  {
270  TLOG(TLVL_DEBUG + 32) << "Setting fragment sequence id to " << event_count;
271  val->setSequenceID(event_count);
272  }
273  if (current_sequence_id ==
274  static_cast<artdaq::Fragment::sequence_id_t>(-1))
275  {
276  current_sequence_id = val->sequenceID();
277  }
278  else if (val->sequenceID() != current_sequence_id)
279  {
280  throw art::Exception(art::errors::DataCorruption) // NOLINT(cert-err60-cpp)
281  << "Data corruption: apparently related fragments have "
282  << " different sequence IDs: "
283  << val->sequenceID()
284  << " and "
285  << current_sequence_id
286  << ".\n";
287  }
288 
289  auto start_time = std::chrono::steady_clock::now();
290  bool sts = false;
291  auto loop_count = 0;
292  while (!sts)
293  {
294  artdaq::FragmentPtr tempFrag;
295  sts = store.AddFragment(std::move(val), 1000000, tempFrag);
296  if (!sts && event_count <= 10 && loop_count > 100)
297  {
298  TLOG(TLVL_ERROR) << "Fragment was not added after " << artdaq::TimeUtils::GetElapsedTime(start_time) << " s. Check art thread status!";
299  store.endOfData();
300  exit(1);
301  }
302  val = std::move(tempFrag);
303  if (!sts)
304  {
305  loop_count++;
306  usleep(10000);
307  }
308  }
309  }
310  frags.clear();
311  TLOG(TLVL_DEBUG + 33) << "Event " << event_count << " END";
312  }
313  for (auto& gen : generators)
314  {
315  gen.stop(0, 0);
316  }
317 
318  bool endSucceeded = store.endOfData();
319  if (endSucceeded)
320  {
321  return 0;
322  }
323 
324  return 15;
325 }
326 } // namespace
327 
328 int main(int argc, char* argv[])
329 try
330 {
331  artdaq::configureMessageFacility("genToArt");
332  // Command line handling.
333  bpo::variables_map vm;
334  auto result = process_cmd_line(argc, argv, vm);
335  if (result != 0)
336  {
337  return (result);
338  }
339  // Read FHiCL configuration file.
340  if (getenv("FHICL_FILE_PATH") == nullptr)
341  {
342  TLOG(TLVL_ERROR)
343  << "INFO: environment variable FHICL_FILE_PATH was not set. Using \".\"\n";
344  setenv("FHICL_FILE_PATH", ".", 0);
345  }
346  artdaq::SimpleLookupPolicy lookup_policy("FHICL_FILE_PATH");
347  auto pset = fhicl::ParameterSet::make(vm["config"].as<std::string>(), lookup_policy);
348  return process_data(pset);
349 }
350 catch (std::exception& x)
351 {
352  TLOG(TLVL_ERROR) << "Exception (type std::exception) caught in genToArt: " << x.what() << '\n';
353  return 1;
354 }
355 catch (...)
356 {
357  return -1;
358 }
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:116
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:46
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:224
void stop(uint64_t timeout, uint64_t timestamp) const
Send stop signal to FragmentGenerator, if it&#39;s a CommandableFragmentGenerator.
Definition: genToArt.cc:129
size_t numFragIDs() const
Get the number of Fragment IDs handled by this generator.
Definition: genToArt.cc:195
ThrottledGenerator: ensure that we only get one fragment per type at a time from the generator...
Definition: genToArt.cc:86