11 #include "TRACE/tracemf.h"
12 #define TRACE_NAME "artdaqDriver"
13 #include "artdaq-core/Data/Fragment.hh"
15 #include "artdaq-core/Plugins/FragmentGenerator.hh"
16 #include "artdaq-core/Plugins/makeFragmentGenerator.hh"
17 #include "artdaq-core/Utilities/ExceptionHandler.hh"
18 #include "artdaq-utilities/Plugins/MetricManager.hh"
19 #include "artdaq/Application/LoadParameterSet.hh"
20 #include "artdaq/ArtModules/detail/ArtConfig.hh"
21 #include "artdaq/DAQdata/GenericFragmentSimulator.hh"
22 #include "artdaq/DAQdata/Globals.hh"
23 #include "artdaq/DAQrate/SharedMemoryEventManager.hh"
24 #include "artdaq/Generators/makeCommandableFragmentGenerator.hh"
26 #include "fhiclcpp/ParameterSet.h"
28 #include <boost/program_options.hpp>
35 volatile int events_to_generate;
36 void sig_handler(
int ) { events_to_generate = -1; }
38 template<
typename B,
typename D>
40 dynamic_unique_ptr_cast(std::unique_ptr<B>& p);
42 int main(
int argc,
char* argv[])
47 fhicl::Atom<int> run_number{fhicl::Name{
"run_number"}, fhicl::Comment{
"Run number to use for output file"}, 1};
48 fhicl::Atom<bool> debug_cout{fhicl::Name{
"debug_cout"}, fhicl::Comment{
"Whether to print debug messages to console"},
false};
49 fhicl::Atom<uint64_t> transition_timeout{fhicl::Name{
"transition_timeout"}, fhicl::Comment{
"Timeout to use (in seconds) for automatic transitions"}, 30};
50 fhicl::Table<artdaq::CommandableFragmentGenerator::Config> generator{fhicl::Name{
"fragment_receiver"}};
51 fhicl::Table<artdaq::MetricManager::Config> metrics{fhicl::Name{
"metrics"}};
52 fhicl::Table<artdaq::SharedMemoryEventManager::Config> event_builder{fhicl::Name{
"event_builder"}};
53 fhicl::Atom<int> events_to_generate{fhicl::Name{
"events_to_generate"}, fhicl::Comment{
"Number of events to generate and process"}, 0};
54 fhicl::TableFragment<art::Config> art_config;
56 auto pset = LoadParameterSet<Config>(argc, argv,
"driver",
"The artdaqDriver executable runs a Fragment Generator and an art process, acting as a \"unit integration\" test for a data source");
58 int run = pset.get<
int>(
"run_number", 1);
59 bool debug = pset.get<
bool>(
"debug_cout",
false);
60 auto timeout = pset.get<uint64_t>(
"transition_timeout", 30);
61 uint64_t timestamp = 0;
63 app_name =
"artdaqDriver";
65 artdaq::configureMessageFacility(app_name.c_str(),
true, debug);
67 auto fragment_receiver_pset = pset.get<fhicl::ParameterSet>(
"fragment_receiver");
69 std::unique_ptr<artdaq::FragmentGenerator>
70 gen(artdaq::makeFragmentGenerator(fragment_receiver_pset.get<std::string>(
"generator"),
71 fragment_receiver_pset));
73 std::unique_ptr<artdaq::CommandableFragmentGenerator> commandable_gen =
78 fhicl::ParameterSet metric_pset;
81 metric_pset = pset.get<fhicl::ParameterSet>(
"metrics");
86 if (metric_pset.is_empty())
88 TLOG(TLVL_INFO) <<
"No metric plugins appear to be defined";
92 metricMan->initialize(metric_pset, app_name);
93 metricMan->do_start();
98 artdaq::FragmentPtrs frags;
103 auto event_builder_pset = pset.get<fhicl::ParameterSet>(
"event_builder");
104 auto art_pset = pset.get<fhicl::ParameterSet>(
"art", pset);
109 int events_to_generate = pset.get<
int>(
"events_to_generate", 0);
111 artdaq::Fragment::sequence_id_t previous_sequence_id = -1;
115 commandable_gen->
StartCmd(run, timeout, timestamp);
118 TLOG(50) <<
"driver main before event_manager.startRun";
119 event_manager.startRun(run);
125 while ((commandable_gen && commandable_gen->
getNext(frags)) ||
126 (gen && gen->getNext(frags)))
128 TLOG(50) <<
"driver main: getNext returned frags.size()=" << frags.size() <<
" current event_count=" << event_count;
129 for (
auto& val : frags)
131 if (val->sequenceID() != previous_sequence_id)
134 previous_sequence_id = val->sequenceID();
136 if (events_to_generate != 0 && event_count > events_to_generate)
140 commandable_gen->
StopCmd(timeout, timestamp);
145 auto start_time = std::chrono::steady_clock::now();
150 artdaq::FragmentPtr tempFrag;
151 sts = event_manager.AddFragment(std::move(val), 1000000, tempFrag);
152 if (!sts && event_count <= 10 && loop_count > 100)
154 TLOG(TLVL_ERROR) <<
"Fragment was not added after " << artdaq::TimeUtils::GetElapsedTime(start_time) <<
" s. Check art thread status!";
155 event_manager.endOfData();
158 val = std::move(tempFrag);
168 if (events_to_generate != 0 && event_count >= events_to_generate)
172 commandable_gen->
StopCmd(timeout, timestamp);
184 volatile bool keep_looping =
true;
191 TLOG(TLVL_INFO) <<
"Fragments generated, waiting for art to process them.";
192 auto art_wait_start_time = std::chrono::steady_clock::now();
193 auto last_delta_time = std::chrono::steady_clock::now();
194 auto last_count = event_manager.size() - event_manager.WriteReadyCount(
false);
196 while (last_count > 0 && artdaq::TimeUtils::GetElapsedTime(last_delta_time) < 1.0)
198 auto this_count = event_manager.size() - event_manager.WriteReadyCount(
false);
199 if (this_count != last_count)
201 last_delta_time = std::chrono::steady_clock::now();
202 last_count = this_count;
207 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).";
208 event_manager.endRun();
209 usleep(artdaq::TimeUtils::GetElapsedTimeMicroseconds(art_wait_start_time));
211 TLOG(TLVL_INFO) <<
"Shutting down art";
212 bool endSucceeded =
false;
213 int attemptsToEnd = 1;
214 endSucceeded = event_manager.endOfData();
215 while (!endSucceeded && attemptsToEnd < 3)
218 endSucceeded = event_manager.endOfData();
222 TLOG(TLVL_ERROR) <<
"Failed to shut down the reader and the SharedMemoryEventManager "
223 <<
"because the endOfData marker could not be pushed "
224 <<
"onto the queue.";
227 metricMan->do_stop();
232 catch (std::string& x)
234 std::cerr <<
"Exception (type string) caught in artdaqDriver: " << x <<
'\n';
237 catch (
char const* m)
239 std::cerr <<
"Exception (type char const*) caught in artdaqDriver: ";
246 std::cerr <<
"[the value was a null pointer, so no message is available]";
252 artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no,
253 "Exception caught in artdaqDriver");
257 template<
typename B,
typename D>
259 dynamic_unique_ptr_cast(std::unique_ptr<B>& p)
261 D* result =
dynamic_cast<D*
>(p.release());
265 return std::unique_ptr<D>(result);
The SharedMemoryEventManager is a SharedMemoryManger which tracks events as they are built...
static void CleanUpGlobals()
Clean up statically-allocated Manager class instances.
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...
Configuration for simple_metric_sender.
CommandableFragmentGenerator is a FragmentGenerator-derived abstract class that defines the interface...
void joinThreads()
Join any data-taking threads. Should be called when destructing CommandableFragmentGenerator.