1 #ifndef artdaq_ArtModules_detail_SharedMemoryReader_hh
2 #define artdaq_ArtModules_detail_SharedMemoryReader_hh
4 #include "art/Framework/Core/Frameworkfwd.h"
5 #include "artdaq-core/Utilities/ExceptionHandler.hh"
6 #include "artdaq/DAQdata/Globals.hh"
9 #include "art/Framework/Core/FileBlock.h"
10 #include "art/Framework/Core/ProductRegistryHelper.h"
11 #include "art/Framework/IO/Sources/SourceHelper.h"
12 #include "art/Framework/IO/Sources/put_product_in_principal.h"
13 #include "art/Framework/Principal/EventPrincipal.h"
14 #include "art/Framework/Principal/RunPrincipal.h"
15 #include "art/Framework/Principal/SubRunPrincipal.h"
16 #include "art/Framework/Services/Registry/ServiceHandle.h"
17 #include "artdaq-core/Core/SharedMemoryEventReceiver.hh"
18 #include "artdaq-core/Core/SharedMemoryManager.hh"
19 #include "artdaq-core/Data/ContainerFragment.hh"
20 #include "artdaq-core/Data/Fragment.hh"
21 #include "artdaq-core/Utilities/TimeUtils.hh"
22 #include "artdaq/ArtModules/ArtdaqSharedMemoryService.h"
23 #include "canvas/Persistency/Provenance/FileFormatVersion.h"
24 #include "fhiclcpp/ParameterSet.h"
28 #include "artdaq-core/Data/RawEvent.hh"
30 #define build_key(seed) seed + ((GetPartitionNumber() + 1) << 16) + (getppid() & 0xFFFF)
48 virtual void SetBasicTypes(std::map<Fragment::type_t, std::string>
const& type_map)
56 virtual void AddExtraType(artdaq::Fragment::type_t type_id, std::string type_name)
68 return unidentified_instance_name;
78 std::set<std::string> output;
81 std::string instance_name = map_iter.second;
82 if (!output.count(instance_name))
84 output.insert(instance_name);
85 TLOG_TRACE(
"DefaultFragmentTypeTranslator") <<
"Adding product instance name \"" << map_iter.second
86 <<
"\" to list of expected names";
90 auto container_type = type_map_.find(Fragment::type_t(artdaq::Fragment::ContainerFragmentType));
91 if (container_type != type_map_.end())
93 std::string container_type_name = container_type->second;
94 std::set<std::string> tmp_copy = output;
95 for (
const auto& set_iter : tmp_copy)
97 output.insert(container_type_name + set_iter);
110 virtual std::pair<bool, std::string>
114 bool success_code =
true;
115 std::string instance_name;
117 auto primary_type =
type_map_.find(fragment.type());
118 if (primary_type != type_map_end)
120 instance_name = primary_type->second;
121 if (fragment.type() == artdaq::Fragment::ContainerFragmentType)
123 artdaq::ContainerFragment cf(fragment);
124 auto contained_type =
type_map_.find(cf.fragment_type());
125 if (contained_type != type_map_end)
127 instance_name += contained_type->second;
133 instance_name = unidentified_instance_name;
134 success_code =
false;
137 return std::make_pair(success_code, instance_name);
147 template<std::map<artdaq::Fragment::type_t, std::
string> getDefaultTypes() = artdaq::Fragment::MakeSystemTypeMap,
148 class FTT = artdaq::detail::DefaultFragmentTypeTranslator>
190 art::ProductRegistryHelper& help,
191 art::SourceHelper
const& pm)
204 volatile bool keep_looping =
true;
212 art::ServiceHandle<ArtdaqSharedMemoryService> shm;
221 auto extraTypes = ps.get<std::vector<std::pair<Fragment::type_t, std::string>>>(
"fragment_type_map", std::vector<std::pair<Fragment::type_t, std::string>>());
222 for (
auto it = extraTypes.begin(); it != extraTypes.end(); ++it)
226 std::set<std::string> instance_names =
translator_.GetAllProductInstanceNames();
227 for (
const auto& set_iter : instance_names)
232 TLOG_INFO(
"SharedMemoryReader") <<
"SharedMemoryReader initialized with ParameterSet: " << ps.to_string();
235 #if ART_HEX_VERSION < 0x30000
244 SharedMemoryReader(fhicl::ParameterSet
const& ps, art::ProductRegistryHelper& help, art::SourceHelper
const& pm,
245 art::MasterProductRegistry&)
263 void readFile(std::string
const&, art::FileBlock*& fb)
265 TLOG_ARB(5,
"SharedMemoryReader") <<
"readFile enter/start";
266 fb =
new art::FileBlock(art::FileFormatVersion(1,
"RawEvent2011"),
"nothing");
274 TLOG(TLVL_DEBUG,
"SharedMemoryReader") <<
"hasMoreData returning " << std::boolalpha << !
shutdownMsgReceived;
287 bool readNext(art::RunPrincipal*
const& inR, art::SubRunPrincipal*
const& inSR, art::RunPrincipal*& outR,
288 art::SubRunPrincipal*& outSR, art::EventPrincipal*& outE)
290 TLOG_DEBUG(
"SharedMemoryReader") <<
"readNext BEGIN";
291 art::ServiceHandle<ArtdaqSharedMemoryService> shm;
309 TLOG_INFO(
"SharedMemoryReader") <<
"Shutdown Message received, returning false (should exit art)";
313 auto read_start_time = std::chrono::steady_clock::now();
315 std::unordered_map<artdaq::Fragment::type_t, std::unique_ptr<artdaq::Fragments>> eventMap;
316 while (eventMap.size() == 0 && artdaq::TimeUtils::GetElapsedTime(read_start_time) <
waiting_time)
318 eventMap = shm->ReceiveEvent(
false);
320 if (eventMap.size() == 0)
322 TLOG_ERROR(
"SharedMemoryReader") <<
"No data received after " <<
waiting_time <<
" seconds. Returning false (should exit art)";
327 auto got_event_time = std::chrono::steady_clock::now();
328 auto firstFragmentType = eventMap.begin()->first;
329 TLOG_DEBUG(
"SharedMemoryReader") <<
"First Fragment type is " << (int)firstFragmentType <<
" ("
336 if (firstFragmentType == Fragment::EndOfDataFragmentType)
338 TLOG_DEBUG(
"SharedMemoryReader") <<
"Received shutdown message, returning false";
343 auto evtHeader = shm->GetEventHeader();
344 size_t qsize = shm->GetQueueSize();
349 art::Timestamp currentTime = 0;
351 art::TimeValue_t lo_res_time = time(0);
352 TLOG_ARB(15,
"SharedMemoryReader") <<
"lo_res_time = " << lo_res_time;
353 currentTime = ((lo_res_time & 0xffffffff) << 32);
355 timespec hi_res_time;
356 int retcode = clock_gettime(CLOCK_REALTIME, &hi_res_time);
357 TLOG_ARB(15,
"SharedMemoryReader") <<
"hi_res_time tv_sec = " << hi_res_time.tv_sec
358 <<
" tv_nsec = " << hi_res_time.tv_nsec <<
" (retcode = " << retcode <<
")";
361 currentTime = ((hi_res_time.tv_sec & 0xffffffff) << 32) | (hi_res_time.tv_nsec & 0xffffffff);
365 TLOG_ERROR(
"SharedMemoryReader")
366 <<
"Unable to fetch a high-resolution time with clock_gettime for art::Event Timestamp. "
367 <<
"The art::Event Timestamp will be zero for event " << evtHeader->event_id;
371 if (inR == 0 || inR->run() != evtHeader->run_id)
373 outR =
pmaker.makeRunPrincipal(evtHeader->run_id, currentTime);
376 if (firstFragmentType == Fragment::EndOfRunFragmentType)
378 art::EventID
const evid(art::EventID::flushEvent());
379 outR =
pmaker.makeRunPrincipal(evid.runID(), currentTime);
380 outSR =
pmaker.makeSubRunPrincipal(evid.subRunID(), currentTime);
381 outE =
pmaker.makeEventPrincipal(evid, currentTime);
384 else if (firstFragmentType == Fragment::EndOfSubrunFragmentType)
387 if (inR == 0 || inR->run() != evtHeader->run_id)
389 outSR =
pmaker.makeSubRunPrincipal(evtHeader->run_id, evtHeader->subrun_id, currentTime);
390 #if ART_HEX_VERSION > 0x30000
391 art::EventID
const evid(art::EventID::flushEvent(outSR->subRunID()));
393 art::EventID
const evid(art::EventID::flushEvent(outSR->id()));
395 outE =
pmaker.makeEventPrincipal(evid, currentTime);
403 #if ART_HEX_VERSION > 0x30000
404 if (inSR != 0 && !inSR->subRunID().isFlush() && inSR->subRun() == evtHeader->subrun_id)
406 if (inSR != 0 && !inSR->id().isFlush() && inSR->subRun() == evtHeader->subrun_id)
409 #if ART_HEX_VERSION > 0x30000
410 art::EventID
const evid(art::EventID::flushEvent(inR->runID()));
412 art::EventID
const evid(art::EventID::flushEvent(inR->id()));
414 outSR =
pmaker.makeSubRunPrincipal(evid.subRunID(), currentTime);
415 outE =
pmaker.makeEventPrincipal(evid, currentTime);
422 outSR =
pmaker.makeSubRunPrincipal(evtHeader->run_id, evtHeader->subrun_id, currentTime);
423 #if ART_HEX_VERSION > 0x30000
424 art::EventID
const evid(art::EventID::flushEvent(outSR->subRunID()));
426 art::EventID
const evid(art::EventID::flushEvent(outSR->id()));
428 outE =
pmaker.makeEventPrincipal(evid, currentTime);
439 art::SubRunID subrun_check(evtHeader->run_id, evtHeader->subrun_id);
440 #if ART_HEX_VERSION > 0x30000
441 if (inSR == 0 || subrun_check != inSR->subRunID())
444 if (inSR == 0 || subrun_check != inSR->id())
447 outSR =
pmaker.makeSubRunPrincipal(evtHeader->run_id, evtHeader->subrun_id, currentTime);
449 outE =
pmaker.makeEventPrincipal(evtHeader->run_id, evtHeader->subrun_id, evtHeader->event_id, currentTime);
451 double fragmentLatency = 0;
452 double fragmentLatencyMax = 0.0;
453 size_t fragmentCount = 0;
456 for (
auto& fragmentTypePair : eventMap)
458 auto type_code = fragmentTypePair.first;
459 TLOG_TRACE(
"SharedMemoryReader") <<
"Before GetFragmentsByType call, type is " << (int)type_code;
460 TLOG_TRACE(
"SharedMemoryReader") <<
"After GetFragmentsByType call, number of fragments is " << fragmentTypePair.second->size();
462 std::unordered_map<std::string, std::unique_ptr<Fragments>> derived_fragments;
463 for (
auto& frag : *fragmentTypePair.second)
466 auto latency_s = frag.getLatency(
true);
467 double latency = latency_s.tv_sec + (latency_s.tv_nsec / 1000000000.0);
469 fragmentLatency += latency;
471 if (latency > fragmentLatencyMax) fragmentLatencyMax = latency;
473 std::pair<bool, std::string> instance_name_result =
475 std::string label = instance_name_result.second;
476 if (!instance_name_result.first)
478 TLOG_WARNING(
"SharedMemoryReader")
479 <<
"UnknownFragmentType: The product instance name mapping for fragment type \"" << ((int)type_code)
480 <<
"\" is not known. Fragments of this "
483 if (!derived_fragments.count(label))
485 derived_fragments[label] = std::make_unique<Fragments>();
487 derived_fragments[label]->emplace_back(std::move(frag));
489 for (
auto& type : derived_fragments)
491 put_product_in_principal(std::move(type.second),
497 TLOG_TRACE(
"SharedMemoryReader") <<
"After putting fragments in event";
499 auto read_finish_time = std::chrono::steady_clock::now();
500 auto qcap = shm->GetQueueCapacity();
501 TLOG_ARB(10,
"SharedMemoryReader") <<
"readNext: bytesRead=" <<
bytesRead <<
" qsize=" << qsize <<
" cap=" << qcap
502 <<
" metricMan=" << (
void*)metricMan.get();
505 metricMan->sendMetric(
"Avg Processing Time", artdaq::TimeUtils::GetElapsedTime(
last_read_time, read_start_time),
506 "s", 2, MetricMode::Average);
507 metricMan->sendMetric(
"Avg Input Wait Time", artdaq::TimeUtils::GetElapsedTime(read_start_time, got_event_time),
508 "s", 3, MetricMode::Average);
509 metricMan->sendMetric(
"Avg Read Time", artdaq::TimeUtils::GetElapsedTime(got_event_time, read_finish_time),
"s",
510 3, MetricMode::Average);
511 metricMan->sendMetric(
"bytesRead",
bytesRead,
"B", 3, MetricMode::LastPoint);
513 metricMan->sendMetric(
"queue%Used", static_cast<unsigned long int>(qsize * 100 / qcap),
"%", 5,
514 MetricMode::LastPoint);
516 metricMan->sendMetric(
"SharedMemoryReader Latency", fragmentLatency / fragmentCount,
"s", 4, MetricMode::Average);
517 metricMan->sendMetric(
"SharedMemoryReader Maximum Latency", fragmentLatencyMax,
"s", 4, MetricMode::Maximum);
520 TLOG_TRACE(
"SharedMemoryReader") <<
"Returning from readNext";
bool hasMoreData() const
Whether more data is expected from the SharedMemoryReader.
void closeCurrentFile()
Emulate closing a file. No-Op.
bool readNext(art::RunPrincipal *const &inR, art::SubRunPrincipal *const &inSR, art::RunPrincipal *&outR, art::SubRunPrincipal *&outSR, art::EventPrincipal *&outE)
Dequeue a RawEvent and declare its Fragment contents to art, creating Run, SubRun, and EventPrincipal objects as necessary.
size_t bytesRead
running total of number of bytes received
The SharedMemoryReader is a class which implements the methods needed by art::Source.
FTT translator_
An instance of the template parameter FragmentTypeTranslator that translates Fragment Type IDs to str...
SharedMemoryReader(SharedMemoryReader const &)=delete
Copy Constructor is deleted.
std::string pretend_module_name
The module name to store data under.
bool shutdownMsgReceived
Whether a shutdown message has been received.
bool resume_after_timeout
Whether to resume if the dequeue action times out.
double waiting_time
The amount of time to wait for an event from the queue.
SharedMemoryReader(fhicl::ParameterSet const &ps, art::ProductRegistryHelper &help, art::SourceHelper const &pm)
SharedMemoryReader Constructor.
unsigned readNext_calls_
The number of times readNext has been called.
virtual void SetBasicTypes(std::map< Fragment::type_t, std::string > const &type_map)
Sets the basic types to be translated. (Should not include "container" types.)
void readFile(std::string const &, art::FileBlock *&fb)
Emulate opening a file.
bool outputFileCloseNeeded
If an explicit output file close message is needed.
virtual void AddExtraType(artdaq::Fragment::type_t type_id, std::string type_name)
Adds an additional type to be translated.
SharedMemoryReader & operator=(SharedMemoryReader const &)=delete
Copy Assignment operator is deleted.
virtual std::string GetInstanceNameForType(artdaq::Fragment::type_t type_id, std::string unidentified_instance_name)
Returns the basic translation for the specified type. Defaults to the specified unidentified_instance...
art::SourceHelper const & pmaker
An art::SourceHelper instance.
virtual std::pair< bool, std::string > GetInstanceNameForFragment(artdaq::Fragment const &fragment, std::string unidentified_instance_name)
Returns the product instance name for the specified fragment, based on the types that have been speci...
std::string unidentified_instance_name
The name to use for unknown Fragment types.
std::map< Fragment::type_t, std::string > type_map_
Map relating Fragment Type to strings.
virtual std::set< std::string > GetAllProductInstanceNames()
Returns the full set of product instance names which may be present in the data, based on the types t...
SharedMemoryReader(fhicl::ParameterSet const &ps, art::ProductRegistryHelper &help, art::SourceHelper const &pm, art::MasterProductRegistry &)
SharedMemoryReader Constructor.
The DefaultFragmentTypeTranslator class provides default behavior for experiment-specific customizati...
std::chrono::steady_clock::time_point last_read_time
Time last read was completed.
virtual ~SharedMemoryReader()
SharedMemoryReader destructor.