$treeview $search $mathjax $extrastylesheet
artdaq
v3_04_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 // 00002 // artdaqDriver is a program for testing the behavior of the generic 00003 // RawInput source. Run 'artdaqDriver --help' to get a description of the 00004 // expected command-line parameters. 00005 // 00006 // 00007 // The current version generates simple data fragments, for testing 00008 // that data are transmitted without corruption from the 00009 // artdaq::Eventevent_manager through to the artdaq::RawInput source. 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 // pull out the Metric part of the ParameterSet 00078 fhicl::ParameterSet metric_pset; 00079 try { 00080 metric_pset = pset.get<fhicl::ParameterSet>("metrics"); 00081 } 00082 catch (...) {} // OK if there's no metrics table defined in the FHiCL 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 // Note: we are constrained to doing all this here rather than 00096 // encapsulated neatly in a function due to the lieftime issues 00097 // associated with async threads and std::string::c_str(). 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 // Read or generate fragments as rapidly as possible, and feed them 00115 // into the Eventevent_manager. The throughput resulting from this design 00116 // choice is likely to have the fragment reading (or generation) 00117 // speed as the limiting factor 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 //usleep(10000); 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)); // Wait as long again for EndRun message to go through 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 00203 artdaq::Globals::CleanUpGlobals(); 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 }