artdaq_demo_hdf5  v1_01_01
HDFFileReader.hh
1 #ifndef artdaq_ArtModules_detail_HDFFileReader_hh
2 #define artdaq_ArtModules_detail_HDFFileReader_hh
3 
4 #include "artdaq/DAQdata/Globals.hh"
5 
6 #include "artdaq-core/Data/ContainerFragment.hh"
7 #include "artdaq-core/Data/Fragment.hh"
8 #include "artdaq-core/Data/RawEvent.hh"
9 #include "artdaq-core/Utilities/ExceptionHandler.hh"
10 #include "artdaq-core/Utilities/TimeUtils.hh"
11 #include "artdaq-demo-hdf5/HDF5/MakeDatasetPlugin.hh"
12 #include "artdaq/ArtModules/ArtdaqFragmentNamingService.h"
13 
14 #include "art/Framework/Core/Frameworkfwd.h"
15 
16 #include "art/Framework/Core/FileBlock.h"
17 #include "art/Framework/Core/ProductRegistryHelper.h"
18 #include "art/Framework/IO/Sources/SourceHelper.h"
19 #include "art/Framework/IO/Sources/put_product_in_principal.h"
20 #include "art/Framework/Principal/EventPrincipal.h"
21 #include "art/Framework/Principal/RunPrincipal.h"
22 #include "art/Framework/Principal/SubRunPrincipal.h"
23 #include "art/Framework/Services/Registry/ServiceHandle.h"
24 #include "canvas/Persistency/Provenance/FileFormatVersion.h"
25 #include "fhiclcpp/ParameterSet.h"
26 
27 #include <sys/time.h>
28 #include <map>
29 #include <string>
30 
31 namespace artdaq {
32 namespace detail {
33 
38 {
42  HDFFileReader(HDFFileReader const&) = delete;
43 
48  HDFFileReader& operator=(HDFFileReader const&) = delete;
52  HDFFileReader(HDFFileReader&&) = delete;
53 
59 
60  art::SourceHelper const& pmaker;
61  std::string pretend_module_name;
63  size_t bytesRead;
64  std::chrono::steady_clock::time_point last_read_time;
65  unsigned readNext_calls_;
66  std::unique_ptr<artdaq::hdf5::FragmentDataset> inputFile_;
67 
80  HDFFileReader(fhicl::ParameterSet const& ps,
81  art::ProductRegistryHelper& help,
82  art::SourceHelper const& pm)
83  : pmaker(pm)
84  , pretend_module_name(ps.get<std::string>("raw_data_label", "daq"))
85  , shutdownMsgReceived(false)
86  , bytesRead(0)
87  , last_read_time(std::chrono::steady_clock::now())
88  , readNext_calls_(0)
89  {
90 #if 0
91  volatile bool keep_looping = true;
92  while (keep_looping)
93  {
94  usleep(10000);
95  }
96 #endif
97  art::ServiceHandle<ArtdaqFragmentNamingServiceInterface> translator;
98  inputFile_ = artdaq::hdf5::MakeDatasetPlugin(ps, "dataset");
99 
100  help.reconstitutes<Fragments, art::InEvent>(pretend_module_name, translator->GetUnidentifiedInstanceName());
101 
102  // Workaround for #22979
103  help.reconstitutes<Fragments, art::InRun>(pretend_module_name, translator->GetUnidentifiedInstanceName());
104  help.reconstitutes<Fragments, art::InSubRun>(pretend_module_name, translator->GetUnidentifiedInstanceName());
105 
106  try
107  {
108  if (metricMan)
109  {
110  metricMan->initialize(ps.get<fhicl::ParameterSet>("metrics", fhicl::ParameterSet()), "art");
111  metricMan->do_start();
112  }
113  }
114  catch (...)
115  {
116  artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no, "Error loading metrics in HDFFileReader()");
117  }
118 
119  std::set<std::string> instance_names = translator->GetAllProductInstanceNames();
120  for (const auto& set_iter : instance_names)
121  {
122  help.reconstitutes<Fragments, art::InEvent>(pretend_module_name, set_iter);
123  }
124 
125  TLOG_INFO("HDFFileReader") << "HDFFileReader initialized with ParameterSet: " << ps.to_string();
126  }
127 
128 #if ART_HEX_VERSION < 0x30000
129 
137  HDFFileReader(fhicl::ParameterSet const& ps, art::ProductRegistryHelper& help, art::SourceHelper const& pm,
138  art::MasterProductRegistry&)
139  : HDFFileReader(ps, help, pm) {}
140 #endif
141 
145  virtual ~HDFFileReader() {}
146 
151 
156  void readFile(std::string const&, art::FileBlock*& fb)
157  {
158  TLOG_ARB(5, "HDFFileReader") << "readFile enter/start";
159  fb = new art::FileBlock(art::FileFormatVersion(1, "RawEvent2011"), "nothing");
160  }
161 
166  bool hasMoreData() const
167  {
168  TLOG(TLVL_DEBUG, "HDFFileReader") << "hasMoreData returning " << std::boolalpha << !shutdownMsgReceived;
169  return (!shutdownMsgReceived);
170  }
171 
182  bool readNext(art::RunPrincipal* const& inR, art::SubRunPrincipal* const& inSR, art::RunPrincipal*& outR,
183  art::SubRunPrincipal*& outSR, art::EventPrincipal*& outE)
184  {
185  TLOG_DEBUG("HDFFileReader") << "readNext BEGIN";
186  art::ServiceHandle<ArtdaqFragmentNamingServiceInterface> translator;
187 
188  // Establish default 'results'
189  outR = nullptr;
190  outSR = nullptr;
191  outE = nullptr;
192  // Try to get an event from the queue. We'll continuously loop, either until:
193  // 1) we have read a RawEvent off the queue, or
194  // 2) we have timed out, AND we are told the when we timeout we
195  // should stop.
196  // In any case, if we time out, we emit an informational message.
197 
199  {
200  TLOG_INFO("HDFFileReader") << "Shutdown Message received, returning false (should exit art)";
201  return false;
202  }
203 
204  auto read_start_time = std::chrono::steady_clock::now();
205 
206  std::unordered_map<artdaq::Fragment::type_t, std::unique_ptr<artdaq::Fragments>> eventMap = inputFile_->readNextEvent();
207  if (eventMap.empty())
208  {
209  TLOG_ERROR("HDFFileReader") << "No data received, either because of incompatible plugin or end of file. Returning false (should exit art)";
210  shutdownMsgReceived = true;
211  return false;
212  }
213 
214  auto got_event_time = std::chrono::steady_clock::now();
215  auto firstFragmentType = eventMap.begin()->first;
216  TLOG_DEBUG("HDFFileReader") << "First Fragment type is " << static_cast<int>(firstFragmentType) << " ("
217  << translator->GetInstanceNameForType(firstFragmentType) << ")";
218  // We return false, indicating we're done reading, if:
219  // 1) we did not obtain an event, because we timed out and were
220  // configured NOT to keep trying after a timeout, or
221  // 2) the event we read was the end-of-data marker: a null
222  // pointer
223  if (firstFragmentType == Fragment::EndOfDataFragmentType)
224  {
225  TLOG_DEBUG("HDFFileReader") << "Received shutdown message, returning false";
226  shutdownMsgReceived = true;
227  return false;
228  }
229 
230  auto evtHeader = inputFile_->getEventHeader(eventMap.begin()->second->at(0).sequenceID());
231  if (evtHeader == nullptr)
232  {
233  TLOG_DEBUG("HDFFileReader") << "Did not receive Event Header for sequence ID " << eventMap.begin()->second->at(0).sequenceID() << ", skipping event";
234  return true;
235  }
236  else
237  {
238  TLOG_TRACE("HDFFileReader") << "EventHeader has Run " << evtHeader->run_id << ", SubRun " << evtHeader->subrun_id << ", Event " << evtHeader->event_id << ", SeqID " << evtHeader->sequence_id << ", IsComplete " << evtHeader->is_complete;
239  }
240  // Check the number of fragments in the RawEvent. If we have a single
241  // fragment and that fragment is marked as EndRun or EndSubrun we'll create
242  // the special principals for that.
243  art::Timestamp currentTime = 0;
244 #if 0
245  art::TimeValue_t lo_res_time = time(0);
246  TLOG_ARB(15, "HDFFileReader") << "lo_res_time = " << lo_res_time;
247  currentTime = ((lo_res_time & 0xffffffff) << 32);
248 #endif
249  timespec hi_res_time;
250  int retcode = clock_gettime(CLOCK_REALTIME, &hi_res_time);
251  TLOG_ARB(15, "HDFFileReader") << "hi_res_time tv_sec = " << hi_res_time.tv_sec
252  << " tv_nsec = " << hi_res_time.tv_nsec << " (retcode = " << retcode << ")";
253  if (retcode == 0)
254  {
255  currentTime = ((hi_res_time.tv_sec & 0xffffffff) << 32) | (hi_res_time.tv_nsec & 0xffffffff);
256  }
257  else
258  {
259  TLOG_ERROR("HDFFileReader")
260  << "Unable to fetch a high-resolution time with clock_gettime for art::Event Timestamp. "
261  << "The art::Event Timestamp will be zero for event " << evtHeader->event_id;
262  }
263 
264  // make new run if inR is 0 or if the run has changed
265  if (inR == nullptr || inR->run() != evtHeader->run_id)
266  {
267  outR = pmaker.makeRunPrincipal(evtHeader->run_id, currentTime);
268  }
269 
270  if (firstFragmentType == Fragment::EndOfRunFragmentType)
271  {
272  art::EventID const evid(art::EventID::flushEvent());
273  outR = pmaker.makeRunPrincipal(evid.runID(), currentTime);
274  outSR = pmaker.makeSubRunPrincipal(evid.subRunID(), currentTime);
275  outE = pmaker.makeEventPrincipal(evid, currentTime);
276  return true;
277  }
278  else if (firstFragmentType == Fragment::EndOfSubrunFragmentType)
279  {
280  // Check if inR == 0 or is a new run
281  if (inR == nullptr || inR->run() != evtHeader->run_id)
282  {
283  outSR = pmaker.makeSubRunPrincipal(evtHeader->run_id, evtHeader->subrun_id, currentTime);
284 #if ART_HEX_VERSION > 0x30000
285  art::EventID const evid(art::EventID::flushEvent(outSR->subRunID()));
286 #else
287  art::EventID const evid(art::EventID::flushEvent(outSR->id()));
288 #endif
289  outE = pmaker.makeEventPrincipal(evid, currentTime);
290  }
291  else
292  {
293  // If the previous subrun was neither 0 nor flush and was identical with the current
294  // subrun, then it must have been associated with a data event. In that case, we need
295  // to generate a flush event with a valid run but flush subrun and event number in order
296  // to end the subrun.
297 #if ART_HEX_VERSION > 0x30000
298  if (inSR != nullptr && !inSR->subRunID().isFlush() && inSR->subRun() == evtHeader->subrun_id)
299 #else
300  if (inSR != nullptr && !inSR->id().isFlush() && inSR->subRun() == evtHeader->subrun_id)
301 #endif
302  {
303 #if ART_HEX_VERSION > 0x30000
304  art::EventID const evid(art::EventID::flushEvent(inR->runID()));
305 #else
306  art::EventID const evid(art::EventID::flushEvent(inR->id()));
307 #endif
308  outSR = pmaker.makeSubRunPrincipal(evid.subRunID(), currentTime);
309  outE = pmaker.makeEventPrincipal(evid, currentTime);
310  // If this is either a new or another empty subrun, then generate a flush event with
311  // valid run and subrun numbers but flush event number
312  //} else if(inSR==0 || inSR->id().isFlush()){
313  }
314  else
315  {
316  outSR = pmaker.makeSubRunPrincipal(evtHeader->run_id, evtHeader->subrun_id, currentTime);
317 #if ART_HEX_VERSION > 0x30000
318  art::EventID const evid(art::EventID::flushEvent(outSR->subRunID()));
319 #else
320  art::EventID const evid(art::EventID::flushEvent(outSR->id()));
321 #endif
322  outE = pmaker.makeEventPrincipal(evid, currentTime);
323  // Possible error condition
324  //} else {
325  }
326  outR = nullptr;
327  }
328  // outputFileCloseNeeded = true;
329  return true;
330  }
331 
332  // make new subrun if inSR is 0 or if the subrun has changed
333  art::SubRunID subrun_check(evtHeader->run_id, evtHeader->subrun_id);
334 #if ART_HEX_VERSION > 0x30000
335  if (inSR == nullptr || subrun_check != inSR->subRunID())
336  {
337 #else
338  if (inSR == nullptr || subrun_check != inSR->id())
339  {
340 #endif
341  outSR = pmaker.makeSubRunPrincipal(evtHeader->run_id, evtHeader->subrun_id, currentTime);
342  }
343  outE = pmaker.makeEventPrincipal(evtHeader->run_id, evtHeader->subrun_id, evtHeader->event_id, currentTime);
344 
345  // insert the Fragments of each type into the EventPrincipal
346  for (auto& fragmentTypePair : eventMap)
347  {
348  auto type_code = fragmentTypePair.first;
349  TLOG_TRACE("HDFFileReader") << "Before GetFragmentsByType call, type is " << static_cast<int>(type_code);
350  TLOG_TRACE("HDFFileReader") << "After GetFragmentsByType call, number of fragments is " << fragmentTypePair.second->size();
351 
352  std::unordered_map<std::string, std::unique_ptr<Fragments>> derived_fragments;
353  for (auto& frag : *fragmentTypePair.second)
354  {
355  bytesRead += frag.sizeBytes();
356 
357  std::pair<bool, std::string> instance_name_result =
358  translator->GetInstanceNameForFragment(frag);
359  std::string label = instance_name_result.second;
360  if (!instance_name_result.first)
361  {
362  TLOG_WARNING("HDFFileReader")
363  << "UnknownFragmentType: The product instance name mapping for fragment type \"" << static_cast<int>(type_code)
364  << "\" is not known. Fragments of this "
365  << "type will be stored in the event with an instance name of \"" << label << "\".";
366  }
367  if (!derived_fragments.count(label))
368  {
369  derived_fragments[label] = std::make_unique<Fragments>();
370  }
371  auto fragSize = frag.size();
372  TLOG_TRACE("HDFFileReader") << "Moving Fragment with size " << fragSize << " from type map (type=" << type_code << ") to derived map label=" << label;
373  derived_fragments[label]->emplace_back(std::move(frag));
374  }
375  TLOG_TRACE("HDFFileReader") << "Placing derived fragments in outE";
376  for (auto& type : derived_fragments)
377  {
378  put_product_in_principal(std::move(type.second),
379  *outE,
381  type.first);
382  }
383  }
384  TLOG_TRACE("HDFFileReader") << "After putting fragments in event";
385 
386  auto read_finish_time = std::chrono::steady_clock::now();
387  TLOG_ARB(10, "HDFFileReader") << "readNext: bytesRead=" << bytesRead << " metricMan=" << static_cast<void*>(metricMan.get());
388  if (metricMan)
389  {
390  metricMan->sendMetric("Avg Processing Time", artdaq::TimeUtils::GetElapsedTime(last_read_time, read_start_time),
391  "s", 2, MetricMode::Average);
392  metricMan->sendMetric("Avg Input Wait Time", artdaq::TimeUtils::GetElapsedTime(read_start_time, got_event_time),
393  "s", 3, MetricMode::Average);
394  metricMan->sendMetric("Avg Read Time", artdaq::TimeUtils::GetElapsedTime(got_event_time, read_finish_time), "s",
395  3, MetricMode::Average);
396  metricMan->sendMetric("bytesRead", bytesRead, "B", 3, MetricMode::LastPoint);
397  }
398 
399  TLOG_TRACE("HDFFileReader") << "Returning from readNext";
400  last_read_time = std::chrono::steady_clock::now();
401  return true;
402  }
403 };
404 } // namespace detail
405 } // namespace artdaq
406 
407 #endif /* artdaq_ArtModules_detail_HDFFileReader_hh */
The HDFFileReader is a class which implements the methods needed by art::Source.
art::SourceHelper const & pmaker
An art::SourceHelper instance.
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.
HDFFileReader(HDFFileReader const &)=delete
Copy Constructor is deleted.
std::string pretend_module_name
The module name to store data under.
HDFFileReader(fhicl::ParameterSet const &ps, art::ProductRegistryHelper &help, art::SourceHelper const &pm)
HDFFileReader Constructor.
HDFFileReader & operator=(HDFFileReader const &)=delete
Copy Assignment operator is deleted.
bool shutdownMsgReceived
Whether a shutdown message has been received.
void readFile(std::string const &, art::FileBlock *&fb)
Emulate opening a file.
std::unique_ptr< artdaq::hdf5::FragmentDataset > inputFile_
The Dataset plugin which this input source will be reading from.
HDFFileReader(fhicl::ParameterSet const &ps, art::ProductRegistryHelper &help, art::SourceHelper const &pm, art::MasterProductRegistry &)
HDFFileReader Constructor.
virtual ~HDFFileReader()
HDFFileReader destructor.
size_t bytesRead
running total of number of bytes received
unsigned readNext_calls_
The number of times readNext has been called.
void closeCurrentFile()
Emulate closing a file. No-Op.
std::chrono::steady_clock::time_point last_read_time
Time last read was completed.
bool hasMoreData() const
Whether more data is expected from the HDFFileReader.