1 #include "TRACE/tracemf.h"
2 #define TRACE_NAME "GenToBuffer"
4 #include "artdaq-core/Utilities/configureMessageFacility.hh"
5 #include "artdaq/Application/LoadParameterSet.hh"
6 #include "artdaq/DAQdata/Globals.hh"
7 #include "artdaq/DAQrate/FragmentBuffer.hh"
8 #include "artdaq/DAQrate/RequestBuffer.hh"
9 #include "artdaq/Generators/CommandableFragmentGenerator.hh"
10 #include "artdaq/Generators/makeCommandableFragmentGenerator.hh"
12 #include "fhiclcpp/ParameterSet.h"
13 #include "fhiclcpp/types/Atom.h"
14 #include "fhiclcpp/types/Comment.h"
15 #include "fhiclcpp/types/Name.h"
16 #include "fhiclcpp/types/Table.h"
17 #include "fhiclcpp/types/TableFragment.h"
19 #include <boost/program_options.hpp>
20 namespace bpo = boost::program_options;
21 #include <boost/thread.hpp>
37 : generator_ptr_(nullptr)
44 generator_ptr_->SetRequestBuffer(request_buffer_ptr_);
45 fragment_buffer_ptr_->SetRequestBuffer(request_buffer_ptr_);
54 metricMan->do_start();
55 request_buffer_ptr_->setRunning(
true);
56 generator_ptr_->StartCmd(run_number, 0, 0);
59 boost::thread::attributes attrs;
60 attrs.set_stack_size(4096 * 2000);
61 receive_thread_.reset(
new boost::thread(attrs, boost::bind(&GenToBufferTest::receive_fragments,
this)));
62 send_thread_.reset(
new boost::thread(attrs, boost::bind(&GenToBufferTest::send_fragments,
this)));
69 generator_ptr_->StopCmd(0, 0);
70 fragment_buffer_ptr_->Stop();
71 request_buffer_ptr_->setRunning(
false);
74 if (receive_thread_ && receive_thread_->joinable()) receive_thread_->join();
75 if (send_thread_ && send_thread_->joinable()) send_thread_->join();
86 void receive_fragments()
88 TLOG(TLVL_DEBUG) <<
"Waiting for first fragment.";
89 artdaq::FragmentPtrs frags;
93 while (active && running_)
95 auto loop_start = std::chrono::steady_clock::now();
96 TLOG(18) <<
"receive_fragments getNext start";
97 active = generator_ptr_->getNext(frags);
98 TLOG(18) <<
"receive_fragments getNext done (active=" << active <<
")";
99 auto after_getnext = std::chrono::steady_clock::now();
106 if (!active && generator_ptr_ && generator_ptr_->exception())
108 TLOG(TLVL_ERROR) <<
"Generator has an exception, aborting!";
112 if (!active) {
break; }
114 if (frags.size() > 0)
116 metricMan->sendMetric(
"Fragments Generated", frags.size(),
"fragments", 3, artdaq::MetricMode::Accumulate | artdaq::MetricMode::Rate | artdaq::MetricMode::Average);
118 TLOG(18) <<
"receive_fragments AddFragmentsToBuffer start";
119 fragment_buffer_ptr_->AddFragmentsToBuffer(std::move(frags));
120 TLOG(18) <<
"receive_fragments AddFragmentsToBuffer done";
121 auto after_addFragsToBuffer = std::chrono::steady_clock::now();
122 metricMan->sendMetric(
"FragmentBufferAddTime", artdaq::TimeUtils::GetElapsedTime(after_getnext, after_addFragsToBuffer),
"s", 3, artdaq::MetricMode::Accumulate | artdaq::MetricMode::Average | artdaq::MetricMode::Minimum | artdaq::MetricMode::Maximum);
124 metricMan->sendMetric(
"GetNextTime", artdaq::TimeUtils::GetElapsedTime(loop_start, after_getnext),
"s", 3, artdaq::MetricMode::Accumulate | artdaq::MetricMode::Average | artdaq::MetricMode::Minimum | artdaq::MetricMode::Maximum);
128 TLOG(TLVL_DEBUG) <<
"receive_fragments loop end";
131 void send_fragments()
133 TLOG(TLVL_DEBUG) <<
"Waiting for first fragment.";
134 artdaq::FragmentPtrs frags;
138 while (active && running_)
140 auto loop_start = std::chrono::steady_clock::now();
142 TLOG(18) <<
"send_fragments applyRequests start";
143 active = fragment_buffer_ptr_->applyRequests(frags);
144 TLOG(18) <<
"send_fragments applyRequests done (active=" << active <<
")";
146 auto after_requests = std::chrono::steady_clock::now();
147 if (!active) {
break; }
149 for (
auto& fragPtr : frags)
153 TLOG(TLVL_WARNING) <<
"Encountered a bad fragment pointer in fragment " << fragment_count_ <<
". "
154 <<
"This is most likely caused by a problem with the Fragment Generator!";
157 if (fragment_count_ == 0)
159 TLOG(TLVL_DEBUG) <<
"Received first Fragment from Fragment Generator, sequence ID " << fragPtr->sequenceID() <<
", size = " << fragPtr->sizeBytes() <<
" bytes.";
161 artdaq::Fragment::sequence_id_t sequence_id = fragPtr->sequenceID();
162 SetMFIteration(
"Sequence ID " + std::to_string(sequence_id));
164 TLOG(17) <<
"send_fragments seq=" << sequence_id <<
" sendFragment start";
168 TLOG(((fragment_count_ == 1) ? TLVL_DEBUG
169 : (((fragment_count_ % 250) == 0) ? 13 : 14)))
170 << ((fragment_count_ == 1)
171 ?
"Sent first Fragment"
172 :
"Sending fragment " + std::to_string(fragment_count_))
173 <<
" with SeqID " << sequence_id <<
".";
176 metricMan->sendMetric(
"Fragments Discarded", frags.size(),
"fragments", 3, artdaq::MetricMode::Accumulate | artdaq::MetricMode::Rate | artdaq::MetricMode::Average);
178 auto after_frag_check = std::chrono::steady_clock::now();
179 metricMan->sendMetric(
"ApplyRequestsTime", artdaq::TimeUtils::GetElapsedTime(loop_start, after_requests),
"s", 3, artdaq::MetricMode::Average | artdaq::MetricMode::Accumulate | artdaq::MetricMode::Maximum | artdaq::MetricMode::Minimum);
180 metricMan->sendMetric(
"FragmentDiscardTime", artdaq::TimeUtils::GetElapsedTime(after_requests, after_frag_check),
"s", 3, artdaq::MetricMode::Average | artdaq::MetricMode::Accumulate);
182 std::this_thread::yield();
188 metricMan->do_stop();
190 TLOG(TLVL_DEBUG) <<
"send_fragments loop end";
194 std::unique_ptr<CommandableFragmentGenerator> generator_ptr_;
195 std::unique_ptr<FragmentBuffer> fragment_buffer_ptr_;
196 std::shared_ptr<RequestBuffer> request_buffer_ptr_;
197 std::atomic<size_t> fragment_count_;
198 std::atomic<bool> running_;
199 std::unique_ptr<boost::thread> receive_thread_;
200 std::unique_ptr<boost::thread> send_thread_;
204 int main(
int argc,
char* argv[])
206 artdaq::configureMessageFacility(
"RequestSender");
208 struct FragmentReceiverConfig
210 fhicl::TableFragment<artdaq::CommandableFragmentGenerator::Config> generatorConfig;
211 fhicl::TableFragment<artdaq::FragmentBuffer::Config> fragmentBufferConfig;
216 fhicl::Table<FragmentReceiverConfig> frConfig{fhicl::Name{
"fragment_receiver"}};
221 fhicl::Table<DAQConfig> daq{fhicl::Name{
"daq"}};
222 fhicl::Table<artdaq::MetricManager::Config> metrics{fhicl::Name{
"metrics"}};
223 fhicl::Atom<double> test_duration_s{fhicl::Name{
"test_duration_s"}, fhicl::Comment{
"Duration, in seconds, for the test"}, 60.0};
224 fhicl::Atom<size_t> time_between_requests_us{fhicl::Name{
"time_between_requests_us"}, fhicl::Comment{
"Amount of time to wait between generated requests, in us"}, 1000};
225 fhicl::Atom<artdaq::Fragment::timestamp_t> timestamp_increment{fhicl::Name{
"timestamp_increment"}, fhicl::Comment{
"Amount to increment the timestamp for each request"}, 1};
226 fhicl::Atom<int> run_number{fhicl::Name{
"run_number"}, fhicl::Comment{
"Run Number to use for the test"}, 101};
229 auto pset = LoadParameterSet<Config>(argc, argv,
"GenToBuffer",
"This test application evaluates the rate of Fragment Generation and Request Application.");
232 metricMan->initialize(pset.get<fhicl::ParameterSet>(
"metrics", fhicl::ParameterSet()),
"GenToBuffer");
234 if (pset.has_key(
"daq"))
236 fr_pset = pset.get<fhicl::ParameterSet>(
"daq");
239 if (fr_pset.has_key(
"fragment_receiver"))
241 fr_pset = fr_pset.get<fhicl::ParameterSet>(
"fragment_receiver");
245 auto buf = gtbt.GetRequestBuffer();
247 auto start_time = std::chrono::steady_clock::now();
248 auto duration = pset.get<
double>(
"test_duration_s", 60);
249 artdaq::Fragment::sequence_id_t seq = 0;
250 artdaq::Fragment::timestamp_t timestamp = 1;
251 auto time_between_requests_us = pset.get<
size_t>(
"time_between_requests_us", 1000);
252 auto timestamp_scale = pset.get<artdaq::Fragment::timestamp_t>(
"timestamp_increment", 1);
254 gtbt.start(pset.get<
int>(
"run_number", 101));
256 while (artdaq::TimeUtils::GetElapsedTime(start_time) < duration)
258 buf->push(++seq, timestamp);
259 timestamp += timestamp_scale;
261 auto us_since_start = artdaq::TimeUtils::GetElapsedTimeMicroseconds(start_time);
262 int64_t time_diff = seq * time_between_requests_us - us_since_start;
263 TLOG(40) <<
"Time Diff: " << time_diff <<
", Time since start: " << us_since_start <<
", current epoch: " << seq * time_between_requests_us;
Test fixture for GenToBuffer_t.
std::shared_ptr< RequestBuffer > GetRequestBuffer()
Get a handle to the RequestBuffer.
Configuration for simple_metric_sender.
void start(int run_number)
Start the test fixture.
std::unique_ptr< CommandableFragmentGenerator > makeCommandableFragmentGenerator(std::string const &generator_plugin_spec, fhicl::ParameterSet const &ps)
Load a CommandableFragmentGenerator plugin.
FragmentBuffer is a FragmentGenerator-derived abstract class that defines the interface for a Fragmen...
Holds requests from RequestReceiver while they are being processed.
void stop()
Stop the test fixture.
GenToBufferTest(fhicl::ParameterSet const &ps)
GenToBufferTest constructor.