artdaq  v2_03_02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
driver.cc
1 //
2 // artdaqDriver is a program for testing the behavior of the generic
3 // RawInput source. Run 'artdaqDriver --help' to get a description of the
4 // expected command-line parameters.
5 //
6 //
7 // The current version generates simple data fragments, for testing
8 // that data are transmitted without corruption from the
9 // artdaq::EventStore through to the artdaq::RawInput source.
10 //
11 
12 #include "art/Framework/Art/artapp.h"
13 #include "artdaq-core/Generators/FragmentGenerator.hh"
14 #include "artdaq-core/Data/Fragment.hh"
15 #include "artdaq-core/Utilities/ExceptionHandler.hh"
16 #include "artdaq/DAQdata/GenericFragmentSimulator.hh"
17 
18 #include "artdaq/DAQdata/Globals.hh"
19 #include "artdaq-core/Generators/makeFragmentGenerator.hh"
20 #include "artdaq/Application/makeCommandableFragmentGenerator.hh"
21 #include "artdaq-utilities/Plugins/MetricManager.hh"
22 #include "artdaq/DAQrate/EventStore.hh"
23 #include "artdaq-core/Core/SimpleQueueReader.hh"
24 #include "cetlib/container_algorithms.h"
25 #include "cetlib/filepath_maker.h"
26 #include "fhiclcpp/ParameterSet.h"
27 #include "fhiclcpp/make_ParameterSet.h"
28 #include <boost/program_options.hpp>
29 
30 #include <signal.h>
31 #include <iostream>
32 #include <memory>
33 #include <utility>
34 
35 using namespace std;
36 using namespace fhicl;
37 namespace bpo = boost::program_options;
38 
39 volatile int events_to_generate;
40 void sig_handler(int) { events_to_generate = -1; }
41 
42 template<typename B, typename D>
43 std::unique_ptr<D>
44 dynamic_unique_ptr_cast(std::unique_ptr<B>& p);
45 
46 int main(int argc, char * argv[]) try
47 {
48  std::ostringstream descstr;
49  descstr << argv[0]
50  << " <-c <config-file>> <other-options> [<source-file>]+";
51  bpo::options_description desc(descstr.str());
52  desc.add_options()
53  ("config,c", bpo::value<std::string>(), "Configuration file.")
54  ("help,h", "produce help message");
55  bpo::variables_map vm;
56  try {
57  bpo::store(bpo::command_line_parser(argc, argv).options(desc).run(), vm);
58  bpo::notify(vm);
59  }
60  catch (bpo::error const & e) {
61  std::cerr << "Exception from command line processing in " << argv[0]
62  << ": " << e.what() << "\n";
63  return -1;
64  }
65  if (vm.count("help")) {
66  std::cout << desc << std::endl;
67  return 1;
68  }
69  if (!vm.count("config")) {
70  std::cerr << "Exception from command line processing in " << argv[0]
71  << ": no configuration file given.\n"
72  << "For usage and an options list, please do '"
73  << argv[0] << " --help"
74  << "'.\n";
75  return 2;
76  }
77  ParameterSet pset;
78  if (getenv("FHICL_FILE_PATH") == nullptr) {
79  std::cerr
80  << "INFO: environment variable FHICL_FILE_PATH was not set. Using \".\"\n";
81  setenv("FHICL_FILE_PATH", ".", 0);
82  }
83  cet::filepath_lookup_after1 lookup_policy("FHICL_FILE_PATH");
84  make_ParameterSet(vm["config"].as<std::string>(), lookup_policy, pset);
85 
86  int run = pset.get<int>("run_number", 1);
87  uint64_t timeout = pset.get<uint64_t>("transition_timeout", 30);
88  uint64_t timestamp = 0;
89 
90  artdaq::configureMessageFacility("artdaqDriver");
91 
92  ParameterSet fragment_receiver_pset = pset.get<ParameterSet>("fragment_receiver");
93 
94  std::unique_ptr<artdaq::FragmentGenerator>
95  gen(artdaq::makeFragmentGenerator(fragment_receiver_pset.get<std::string>("generator"),
96  fragment_receiver_pset));
97 
98  std::unique_ptr<artdaq::CommandableFragmentGenerator> commandable_gen =
99  dynamic_unique_ptr_cast<artdaq::FragmentGenerator, artdaq::CommandableFragmentGenerator>(gen);
100 
101  artdaq::MetricManager metricMan_;
102  metricMan = &metricMan_;
103  my_rank = 0;
104  // pull out the Metric part of the ParameterSet
105  fhicl::ParameterSet metric_pset;
106  try {
107  metric_pset = pset.get<fhicl::ParameterSet>("metrics");
108  }
109  catch (...) {} // OK if there's no metrics table defined in the FHiCL
110 
111  if (metric_pset.is_empty()) {
112  TLOG_INFO("artdaqDriver") << "No metric plugins appear to be defined" << TLOG_ENDL;
113  }
114  try {
115  metricMan_.initialize(metric_pset, "artdaqDriver");
116  metricMan_.do_start();
117  }
118  catch (...) {
119  }
120  artdaq::FragmentPtrs frags;
122  // Note: we are constrained to doing all this here rather than
123  // encapsulated neatly in a function due to the lieftime issues
124  // associated with async threads and std::string::c_str().
125  ParameterSet event_builder_pset = pset.get<ParameterSet>("event_builder");
126  bool const want_artapp(event_builder_pset.get<bool>("use_art", false));
127  std::ostringstream os;
128  if (!want_artapp) {
129  os << event_builder_pset.get<int>("events_expected_in_SimpleQueueReader");
130  }
131  std::string const oss(os.str());
132  const char * args[2]{ "SimpleQueueReader", oss.c_str() };
133  int es_argc(want_artapp ? argc : 2);
134  char **es_argv(want_artapp ? argv : const_cast<char**>(args));
136  es_fcn(want_artapp ? &artapp : &artdaq::simpleQueueReaderApp);
137  artdaq::EventStore store(event_builder_pset, event_builder_pset.get<size_t>("expected_fragments_per_event"),
138  pset.get<artdaq::EventStore::run_id_t>("run_number"),
139  es_argc,
140  es_argv,
141  es_fcn);
143 
144  int events_to_generate = pset.get<int>("events_to_generate", 0);
145  int event_count = 0;
146  artdaq::Fragment::sequence_id_t previous_sequence_id = -1;
147 
148  if (commandable_gen) {
149  commandable_gen->StartCmd(run, timeout, timestamp);
150  }
151 
152  TRACE( 50, "driver main before store.startRun" );
153  store.startRun( run );
154 
155  // Read or generate fragments as rapidly as possible, and feed them
156  // into the EventStore. The throughput resulting from this design
157  // choice is likely to have the fragment reading (or generation)
158  // speed as the limiting factor
159  while ((commandable_gen && commandable_gen->getNext(frags)) ||
160  (gen && gen->getNext(frags))) {
161  TRACE( 50, "driver main: getNext returned frags.size()=%zd current event_count=%d"
162  ,frags.size(),event_count );
163  for (auto & val : frags) {
164  if (val->sequenceID() != previous_sequence_id) {
165  ++event_count;
166  previous_sequence_id = val->sequenceID();
167  }
168  if (events_to_generate != 0 && event_count > events_to_generate) {
169  if (commandable_gen) {
170  commandable_gen->StopCmd(timeout, timestamp);
171  }
172  break;
173  }
174  store.insert(std::move(val));
175  }
176  frags.clear();
177 
178  if (events_to_generate != 0 && event_count >= events_to_generate) {
179  if (commandable_gen) {
180  commandable_gen->StopCmd(timeout, timestamp);
181  }
182  break;
183  }
184  }
185 
186 
187  int readerReturnValue;
188  bool endSucceeded = false;
189  int attemptsToEnd = 1;
190  endSucceeded = store.endOfData(readerReturnValue);
191  while (!endSucceeded && attemptsToEnd < 3) {
192  ++attemptsToEnd;
193  endSucceeded = store.endOfData(readerReturnValue);
194  }
195  if (!endSucceeded) {
196  std::cerr << "Failed to shut down the reader and the event store "
197  << "because the endOfData marker could not be pushed "
198  << "onto the queue." << std::endl;
199  }
200 
201  metricMan_.do_stop();
202  return readerReturnValue;
203 }
204 catch (std::string & x)
205 {
206  cerr << "Exception (type string) caught in artdaqDriver: " << x << '\n';
207  return 1;
208 }
209 catch (char const * m)
210 {
211  cerr << "Exception (type char const*) caught in artdaqDriver: ";
212  if (m)
213  {
214  cerr << m;
215  }
216  else
217  {
218  cerr << "[the value was a null pointer, so no message is available]";
219  }
220  cerr << '\n';
221 }
222 catch (...) {
223  artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no,
224  "Exception caught in artdaqDriver");
225 }
226 
227 
228 template<typename B, typename D>
229 std::unique_ptr<D>
230 dynamic_unique_ptr_cast(std::unique_ptr<B>& p)
231 {
232  D* result = dynamic_cast<D*>(p.get());
233 
234  if (result) {
235  p.release();
236  return std::unique_ptr<D>(result);
237  }
238  return nullptr;
239 }
void StopCmd(uint64_t timeout, uint64_t timestamp)
Stop the CommandableFragmentGenerator.
void configureMessageFacility(char const *progname, bool useConsole=true)
Configure and start the message facility. Provide the program name so that messages will be appropria...
void StartCmd(int run, uint64_t timeout, uint64_t timestamp)
Start the CommandableFragmentGenerator.
bool getNext(FragmentPtrs &output) overridefinal
getNext calls either applyRequests or getNext_ to get any data that is ready to be sent to the EventB...
CommandableFragmentGenerator is a FragmentGenerator-derived abstract class that defines the interface...
The EventStore class collects Fragment objects, until it receives a complete event, at which point the event is handed over to the art thread.
Definition: EventStore.hh:49
int( ART_CMDLINE_FCN)(int, char **)
An art function that accepts standard C main arguments.
Definition: EventStore.hh:56
RawEvent::run_id_t run_id_t
Copy RawEvent::run_id_t into local scope.
Definition: EventStore.hh:64