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