artdaq  v3_01_00
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::Eventevent_manager through to the artdaq::RawInput source.
10 //
11 #define TRACE_NAME "artdaqDriver"
12 
13 #include "art/Framework/Art/artapp.h"
14 #include "artdaq-core/Generators/FragmentGenerator.hh"
15 #include "artdaq-core/Data/Fragment.hh"
16 #include "artdaq-core/Utilities/ExceptionHandler.hh"
17 #include "artdaq/DAQdata/GenericFragmentSimulator.hh"
18 
19 #include "artdaq/DAQdata/Globals.hh"
20 #include "artdaq-core/Generators/makeFragmentGenerator.hh"
21 #include "artdaq/Application/makeCommandableFragmentGenerator.hh"
22 #include "artdaq-utilities/Plugins/MetricManager.hh"
23 #include "artdaq-core/Core/SimpleMemoryReader.hh"
24 #include "cetlib/filepath_maker.h"
25 #include "fhiclcpp/ParameterSet.h"
26 #include "fhiclcpp/make_ParameterSet.h"
27 #include <boost/program_options.hpp>
28 
29 #include <signal.h>
30 #include <iostream>
31 #include <memory>
32 #include <utility>
33 #include "artdaq/DAQrate/SharedMemoryEventManager.hh"
34 #include "artdaq/Application/LoadParameterSet.hh"
35 
36 namespace bpo = boost::program_options;
37 
38 volatile int events_to_generate;
39 void sig_handler(int) { events_to_generate = -1; }
40 
41 template<typename B, typename D>
42 std::unique_ptr<D>
43 dynamic_unique_ptr_cast(std::unique_ptr<B>& p);
44 
45 int main(int argc, char * argv[]) try
46 {
47  auto pset = LoadParameterSet(argc, argv);
48 
49  int run = pset.get<int>("run_number", 1);
50  bool debug = pset.get<bool>("debug_cout", false);
51  uint64_t timeout = pset.get<uint64_t>("transition_timeout", 30);
52  uint64_t timestamp = 0;
53 
54  artdaq::configureMessageFacility("artdaqDriver", true, debug);
55 
56  fhicl::ParameterSet fragment_receiver_pset = pset.get<fhicl::ParameterSet>("fragment_receiver");
57 
58  std::unique_ptr<artdaq::FragmentGenerator>
59  gen(artdaq::makeFragmentGenerator(fragment_receiver_pset.get<std::string>("generator"),
60  fragment_receiver_pset));
61 
62  std::unique_ptr<artdaq::CommandableFragmentGenerator> commandable_gen =
63  dynamic_unique_ptr_cast<artdaq::FragmentGenerator, artdaq::CommandableFragmentGenerator>(gen);
64 
65  artdaq::MetricManager metricMan_;
66  metricMan = &metricMan_;
67  my_rank = 0;
68  // pull out the Metric part of the ParameterSet
69  fhicl::ParameterSet metric_pset;
70  try {
71  metric_pset = pset.get<fhicl::ParameterSet>("metrics");
72  }
73  catch (...) {} // OK if there's no metrics table defined in the FHiCL
74 
75  if (metric_pset.is_empty()) {
76  TLOG(TLVL_INFO) << "No metric plugins appear to be defined";
77  }
78  try {
79  metricMan_.initialize(metric_pset, "artdaqDriver");
80  metricMan_.do_start();
81  }
82  catch (...) {
83  }
84  artdaq::FragmentPtrs frags;
86  // Note: we are constrained to doing all this here rather than
87  // encapsulated neatly in a function due to the lieftime issues
88  // associated with async threads and std::string::c_str().
89  fhicl::ParameterSet event_builder_pset = pset.get<fhicl::ParameterSet>("event_builder");
90 
91  artdaq::SharedMemoryEventManager event_manager(event_builder_pset, pset);
93 
94  int events_to_generate = pset.get<int>("events_to_generate", 0);
95  int event_count = 0;
96  artdaq::Fragment::sequence_id_t previous_sequence_id = -1;
97 
98  if (commandable_gen) {
99  commandable_gen->StartCmd(run, timeout, timestamp);
100  }
101 
102  TLOG(50) << "driver main before event_manager.startRun";
103  event_manager.startRun(run);
104 
105  // Read or generate fragments as rapidly as possible, and feed them
106  // into the Eventevent_manager. The throughput resulting from this design
107  // choice is likely to have the fragment reading (or generation)
108  // speed as the limiting factor
109  while ((commandable_gen && commandable_gen->getNext(frags)) ||
110  (gen && gen->getNext(frags))) {
111  TLOG(50) << "driver main: getNext returned frags.size()=" << std::to_string(frags.size()) << " current event_count=" << event_count;
112  for (auto & val : frags) {
113  if (val->sequenceID() != previous_sequence_id) {
114  ++event_count;
115  previous_sequence_id = val->sequenceID();
116  }
117  if (events_to_generate != 0 && event_count > events_to_generate) {
118  if (commandable_gen) {
119  commandable_gen->StopCmd(timeout, timestamp);
120  }
121  break;
122  }
123  artdaq::FragmentPtr tempFrag;
124  auto sts = event_manager.AddFragment(std::move(val), 1000000, tempFrag);
125  if (!sts)
126  {
127  TLOG(TLVL_ERROR) << "Fragment was not added after 1s. Check art process status!";
128  exit(1);
129  }
130  }
131  frags.clear();
132 
133  if (events_to_generate != 0 && event_count >= events_to_generate) {
134  if (commandable_gen) {
135  commandable_gen->StopCmd(timeout, timestamp);
136  }
137  break;
138  }
139  }
140 
141  if (commandable_gen) {
142  commandable_gen->joinThreads();
143  }
144 
145  TLOG(TLVL_INFO) << "Fragments generated, waiting for art to process them.";
146  auto art_wait_start_time = std::chrono::steady_clock::now();
147  auto last_delta_time = std::chrono::steady_clock::now();
148  auto last_count = event_manager.size() - event_manager.WriteReadyCount(false);
149 
150  while (last_count > 0 && artdaq::TimeUtils::GetElapsedTime(last_delta_time) < 1.0)
151  {
152  auto this_count = event_manager.size() - event_manager.WriteReadyCount(false);
153  if (this_count != last_count) {
154  last_delta_time = std::chrono::steady_clock::now();
155  last_count = this_count;
156  }
157  usleep(1000);
158  }
159 
160  TLOG(TLVL_INFO) << "Ending Run, waited " << std::setprecision(2) << artdaq::TimeUtils::GetElapsedTime(art_wait_start_time) << " seconds for art to process events. (" << last_count << " buffers remain).";
161  event_manager.endRun();
162  usleep(artdaq::TimeUtils::GetElapsedTimeMicroseconds(art_wait_start_time)); // Wait as long again for EndRun message to go through
163 
164  TLOG(TLVL_INFO) << "Shutting down art";
165  bool endSucceeded = false;
166  int attemptsToEnd = 1;
167  endSucceeded = event_manager.endOfData();
168  while (!endSucceeded && attemptsToEnd < 3) {
169  ++attemptsToEnd;
170  endSucceeded = event_manager.endOfData();
171  }
172  if (!endSucceeded) {
173  TLOG(TLVL_ERROR) << "Failed to shut down the reader and the SharedMemoryEventManager "
174  << "because the endOfData marker could not be pushed "
175  << "onto the queue.";
176  }
177 
178  metricMan_.do_stop();
179  return 0;
180 }
181 catch (std::string & x)
182 {
183  std::cerr << "Exception (type string) caught in artdaqDriver: " << x << '\n';
184  return 1;
185 }
186 catch (char const * m)
187 {
188  std::cerr << "Exception (type char const*) caught in artdaqDriver: ";
189  if (m)
190  {
191  std::cerr << m;
192  }
193  else
194  {
195  std::cerr << "[the value was a null pointer, so no message is available]";
196  }
197  std::cerr << '\n';
198 }
199 catch (...) {
200  artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no,
201  "Exception caught in artdaqDriver");
202 }
203 
204 
205 template<typename B, typename D>
206 std::unique_ptr<D>
207 dynamic_unique_ptr_cast(std::unique_ptr<B>& p)
208 {
209  D* result = dynamic_cast<D*>(p.get());
210 
211  if (result) {
212  p.release();
213  return std::unique_ptr<D>(result);
214  }
215  return nullptr;
216 }
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.
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...
void joinThreads()
Join any data-taking threads. Should be called when destructing CommandableFragmentGenerator.