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 artdaq::MetricManager metricMan_;
00077 metricMan = &metricMan_;
00078 my_rank = 0;
00079
00080 fhicl::ParameterSet metric_pset;
00081 try {
00082 metric_pset = pset.get<fhicl::ParameterSet>("metrics");
00083 }
00084 catch (...) {}
00085
00086 if (metric_pset.is_empty()) {
00087 TLOG(TLVL_INFO) << "No metric plugins appear to be defined";
00088 }
00089 try {
00090 metricMan_.initialize(metric_pset, "artdaqDriver");
00091 metricMan_.do_start();
00092 }
00093 catch (...) {
00094 }
00095 artdaq::FragmentPtrs frags;
00097
00098
00099
00100 fhicl::ParameterSet event_builder_pset = pset.get<fhicl::ParameterSet>("event_builder");
00101
00102 artdaq::SharedMemoryEventManager event_manager(event_builder_pset, pset);
00104
00105 int events_to_generate = pset.get<int>("events_to_generate", 0);
00106 int event_count = 0;
00107 artdaq::Fragment::sequence_id_t previous_sequence_id = -1;
00108
00109 if (commandable_gen) {
00110 commandable_gen->StartCmd(run, timeout, timestamp);
00111 }
00112
00113 TLOG(50) << "driver main before event_manager.startRun";
00114 event_manager.startRun(run);
00115
00116
00117
00118
00119
00120 while ((commandable_gen && commandable_gen->getNext(frags)) ||
00121 (gen && gen->getNext(frags))) {
00122 TLOG(50) << "driver main: getNext returned frags.size()=" << std::to_string(frags.size()) << " current event_count=" << event_count;
00123 for (auto & val : frags) {
00124 if (val->sequenceID() != previous_sequence_id) {
00125 ++event_count;
00126 previous_sequence_id = val->sequenceID();
00127 }
00128 if (events_to_generate != 0 && event_count > events_to_generate) {
00129 if (commandable_gen) {
00130 commandable_gen->StopCmd(timeout, timestamp);
00131 }
00132 break;
00133 }
00134
00135 auto start_time = std::chrono::steady_clock::now();
00136 bool sts = false;
00137 auto loop_count = 0;
00138 while (!sts)
00139 {
00140 artdaq::FragmentPtr tempFrag;
00141 sts = event_manager.AddFragment(std::move(val), 1000000, tempFrag);
00142 if (!sts && event_count <= 10 && loop_count > 100)
00143 {
00144 TLOG(TLVL_ERROR) << "Fragment was not added after " << artdaq::TimeUtils::GetElapsedTime(start_time) << " s. Check art thread status!";
00145 event_manager.endOfData();
00146 exit(1);
00147 }
00148 val = std::move(tempFrag);
00149 if (!sts)
00150 {
00151 loop_count++;
00152
00153 }
00154 }
00155 }
00156 frags.clear();
00157
00158 if (events_to_generate != 0 && event_count >= events_to_generate) {
00159 if (commandable_gen) {
00160 commandable_gen->StopCmd(timeout, timestamp);
00161 }
00162 break;
00163 }
00164 }
00165
00166 if (commandable_gen) {
00167 commandable_gen->joinThreads();
00168 }
00169
00170 TLOG(TLVL_INFO) << "Fragments generated, waiting for art to process them.";
00171 auto art_wait_start_time = std::chrono::steady_clock::now();
00172 auto last_delta_time = std::chrono::steady_clock::now();
00173 auto last_count = event_manager.size() - event_manager.WriteReadyCount(false);
00174
00175 while (last_count > 0 && artdaq::TimeUtils::GetElapsedTime(last_delta_time) < 1.0)
00176 {
00177 auto this_count = event_manager.size() - event_manager.WriteReadyCount(false);
00178 if (this_count != last_count) {
00179 last_delta_time = std::chrono::steady_clock::now();
00180 last_count = this_count;
00181 }
00182 usleep(1000);
00183 }
00184
00185 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).";
00186 event_manager.endRun();
00187 usleep(artdaq::TimeUtils::GetElapsedTimeMicroseconds(art_wait_start_time));
00188
00189 TLOG(TLVL_INFO) << "Shutting down art";
00190 bool endSucceeded = false;
00191 int attemptsToEnd = 1;
00192 endSucceeded = event_manager.endOfData();
00193 while (!endSucceeded && attemptsToEnd < 3) {
00194 ++attemptsToEnd;
00195 endSucceeded = event_manager.endOfData();
00196 }
00197 if (!endSucceeded) {
00198 TLOG(TLVL_ERROR) << "Failed to shut down the reader and the SharedMemoryEventManager "
00199 << "because the endOfData marker could not be pushed "
00200 << "onto the queue.";
00201 }
00202
00203 metricMan_.do_stop();
00204 return 0;
00205 }
00206 catch (std::string & x)
00207 {
00208 std::cerr << "Exception (type string) caught in artdaqDriver: " << x << '\n';
00209 return 1;
00210 }
00211 catch (char const * m)
00212 {
00213 std::cerr << "Exception (type char const*) caught in artdaqDriver: ";
00214 if (m)
00215 {
00216 std::cerr << m;
00217 }
00218 else
00219 {
00220 std::cerr << "[the value was a null pointer, so no message is available]";
00221 }
00222 std::cerr << '\n';
00223 }
00224 catch (...) {
00225 artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no,
00226 "Exception caught in artdaqDriver");
00227 }
00228
00229
00230 template<typename B, typename D>
00231 std::unique_ptr<D>
00232 dynamic_unique_ptr_cast(std::unique_ptr<B>& p)
00233 {
00234 D* result = dynamic_cast<D*>(p.get());
00235
00236 if (result) {
00237 p.release();
00238 return std::unique_ptr<D>(result);
00239 }
00240 return nullptr;
00241 }