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