00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #define TRACE_NAME "artdaqDriver"
00012
00013 #include "art/Framework/Art/artapp.h"
00014 #include "artdaq-core/Generators/FragmentGenerator.hh"
00015 #include "artdaq-core/Data/Fragment.hh"
00016 #include "artdaq-core/Utilities/ExceptionHandler.hh"
00017 #include "artdaq/DAQdata/GenericFragmentSimulator.hh"
00018
00019 #include "artdaq/DAQdata/Globals.hh"
00020 #include "artdaq-core/Generators/makeFragmentGenerator.hh"
00021 #include "artdaq/Application/makeCommandableFragmentGenerator.hh"
00022 #include "artdaq-utilities/Plugins/MetricManager.hh"
00023 #include "artdaq-core/Core/SimpleMemoryReader.hh"
00024 #include "cetlib/filepath_maker.h"
00025 #include "fhiclcpp/ParameterSet.h"
00026 #include "fhiclcpp/make_ParameterSet.h"
00027 #include <boost/program_options.hpp>
00028
00029 #include <signal.h>
00030 #include <iostream>
00031 #include <memory>
00032 #include <utility>
00033 #include "artdaq/DAQrate/SharedMemoryEventManager.hh"
00034 #include "artdaq/Application/LoadParameterSet.hh"
00035
00036 namespace bpo = boost::program_options;
00037
00038 volatile int events_to_generate;
00039 void sig_handler(int) { events_to_generate = -1; }
00040
00041 template<typename B, typename D>
00042 std::unique_ptr<D>
00043 dynamic_unique_ptr_cast(std::unique_ptr<B>& p);
00044
00045 int main(int argc, char * argv[]) try
00046 {
00047 struct Config
00048 {
00049 fhicl::Atom<int> run_number{ fhicl::Name{"run_number"}, fhicl::Comment{"Run number to use for output file"}, 1 };
00050 fhicl::Atom<bool> debug_cout{ fhicl::Name{"debug_cout"}, fhicl::Comment{"Whether to print debug messages to console"}, false };
00051 fhicl::Atom<uint64_t> transition_timeout{ fhicl::Name{"transition_timeout"}, fhicl::Comment{"Timeout to use (in seconds) for automatic transitions"}, 30 };
00052 fhicl::Table<artdaq::CommandableFragmentGenerator::Config> generator{ fhicl::Name{ "fragment_receiver" } };
00053 fhicl::Table<artdaq::MetricManager::Config> metrics{ fhicl::Name{"metrics"} };
00054 fhicl::Table<artdaq::SharedMemoryEventManager::Config> event_builder{ fhicl::Name{"event_builder"} };
00055 fhicl::Atom<int> events_to_generate{ fhicl::Name{"events_to_generate"}, fhicl::Comment{"Number of events to generate and process"}, 0 };
00056 fhicl::TableFragment<art::Config> art_config;
00057 };
00058 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");
00059
00060 int run = pset.get<int>("run_number", 1);
00061 bool debug = pset.get<bool>("debug_cout", false);
00062 uint64_t timeout = pset.get<uint64_t>("transition_timeout", 30);
00063 uint64_t timestamp = 0;
00064
00065 artdaq::configureMessageFacility("artdaqDriver", true, debug);
00066
00067 fhicl::ParameterSet fragment_receiver_pset = pset.get<fhicl::ParameterSet>("fragment_receiver");
00068
00069 std::unique_ptr<artdaq::FragmentGenerator>
00070 gen(artdaq::makeFragmentGenerator(fragment_receiver_pset.get<std::string>("generator"),
00071 fragment_receiver_pset));
00072
00073 std::unique_ptr<artdaq::CommandableFragmentGenerator> commandable_gen =
00074 dynamic_unique_ptr_cast<artdaq::FragmentGenerator, artdaq::CommandableFragmentGenerator>(gen);
00075
00076 my_rank = 0;
00077
00078 fhicl::ParameterSet metric_pset;
00079 try {
00080 metric_pset = pset.get<fhicl::ParameterSet>("metrics");
00081 }
00082 catch (...) {}
00083
00084 if (metric_pset.is_empty()) {
00085 TLOG(TLVL_INFO) << "No metric plugins appear to be defined";
00086 }
00087 try {
00088 metricMan->initialize(metric_pset, "artdaqDriver");
00089 metricMan->do_start();
00090 }
00091 catch (...) {
00092 }
00093 artdaq::FragmentPtrs frags;
00095
00096
00097
00098 fhicl::ParameterSet event_builder_pset = pset.get<fhicl::ParameterSet>("event_builder");
00099
00100 artdaq::SharedMemoryEventManager event_manager(event_builder_pset, pset);
00102
00103 int events_to_generate = pset.get<int>("events_to_generate", 0);
00104 int event_count = 0;
00105 artdaq::Fragment::sequence_id_t previous_sequence_id = -1;
00106
00107 if (commandable_gen) {
00108 commandable_gen->StartCmd(run, timeout, timestamp);
00109 }
00110
00111 TLOG(50) << "driver main before event_manager.startRun";
00112 event_manager.startRun(run);
00113
00114
00115
00116
00117
00118 while ((commandable_gen && commandable_gen->getNext(frags)) ||
00119 (gen && gen->getNext(frags))) {
00120 TLOG(50) << "driver main: getNext returned frags.size()=" << frags.size() << " current event_count=" << event_count;
00121 for (auto & val : frags) {
00122 if (val->sequenceID() != previous_sequence_id) {
00123 ++event_count;
00124 previous_sequence_id = val->sequenceID();
00125 }
00126 if (events_to_generate != 0 && event_count > events_to_generate) {
00127 if (commandable_gen) {
00128 commandable_gen->StopCmd(timeout, timestamp);
00129 }
00130 break;
00131 }
00132
00133 auto start_time = std::chrono::steady_clock::now();
00134 bool sts = false;
00135 auto loop_count = 0;
00136 while (!sts)
00137 {
00138 artdaq::FragmentPtr tempFrag;
00139 sts = event_manager.AddFragment(std::move(val), 1000000, tempFrag);
00140 if (!sts && event_count <= 10 && loop_count > 100)
00141 {
00142 TLOG(TLVL_ERROR) << "Fragment was not added after " << artdaq::TimeUtils::GetElapsedTime(start_time) << " s. Check art thread status!";
00143 event_manager.endOfData();
00144 exit(1);
00145 }
00146 val = std::move(tempFrag);
00147 if (!sts)
00148 {
00149 loop_count++;
00150
00151 }
00152 }
00153 }
00154 frags.clear();
00155
00156 if (events_to_generate != 0 && event_count >= events_to_generate) {
00157 if (commandable_gen) {
00158 commandable_gen->StopCmd(timeout, timestamp);
00159 }
00160 break;
00161 }
00162 }
00163
00164 if (commandable_gen) {
00165 commandable_gen->joinThreads();
00166 }
00167
00168 TLOG(TLVL_INFO) << "Fragments generated, waiting for art to process them.";
00169 auto art_wait_start_time = std::chrono::steady_clock::now();
00170 auto last_delta_time = std::chrono::steady_clock::now();
00171 auto last_count = event_manager.size() - event_manager.WriteReadyCount(false);
00172
00173 while (last_count > 0 && artdaq::TimeUtils::GetElapsedTime(last_delta_time) < 1.0)
00174 {
00175 auto this_count = event_manager.size() - event_manager.WriteReadyCount(false);
00176 if (this_count != last_count) {
00177 last_delta_time = std::chrono::steady_clock::now();
00178 last_count = this_count;
00179 }
00180 usleep(1000);
00181 }
00182
00183 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).";
00184 event_manager.endRun();
00185 usleep(artdaq::TimeUtils::GetElapsedTimeMicroseconds(art_wait_start_time));
00186
00187 TLOG(TLVL_INFO) << "Shutting down art";
00188 bool endSucceeded = false;
00189 int attemptsToEnd = 1;
00190 endSucceeded = event_manager.endOfData();
00191 while (!endSucceeded && attemptsToEnd < 3) {
00192 ++attemptsToEnd;
00193 endSucceeded = event_manager.endOfData();
00194 }
00195 if (!endSucceeded) {
00196 TLOG(TLVL_ERROR) << "Failed to shut down the reader and the SharedMemoryEventManager "
00197 << "because the endOfData marker could not be pushed "
00198 << "onto the queue.";
00199 }
00200
00201 metricMan->do_stop();
00202 return 0;
00203 }
00204 catch (std::string & x)
00205 {
00206 std::cerr << "Exception (type string) caught in artdaqDriver: " << x << '\n';
00207 return 1;
00208 }
00209 catch (char const * m)
00210 {
00211 std::cerr << "Exception (type char const*) caught in artdaqDriver: ";
00212 if (m)
00213 {
00214 std::cerr << m;
00215 }
00216 else
00217 {
00218 std::cerr << "[the value was a null pointer, so no message is available]";
00219 }
00220 std::cerr << '\n';
00221 }
00222 catch (...) {
00223 artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no,
00224 "Exception caught in artdaqDriver");
00225 }
00226
00227
00228 template<typename B, typename D>
00229 std::unique_ptr<D>
00230 dynamic_unique_ptr_cast(std::unique_ptr<B>& p)
00231 {
00232 D* result = dynamic_cast<D*>(p.get());
00233
00234 if (result) {
00235 p.release();
00236 return std::unique_ptr<D>(result);
00237 }
00238 return nullptr;
00239 }