artdaq  v3_02_00
shared_memory_reader_t.cc
1 #define TRACE_NAME "shared_memory_reader_t"
2 
3 #include "artdaq/ArtModules/detail/SharedMemoryReader.hh"
4 #include "artdaq/DAQrate/SharedMemoryEventManager.hh"
5 
6 #include "art/Framework/Core/FileBlock.h"
7 //#include "art/Framework/Core/RootDictionaryManager.h"
8 #include "art/Framework/IO/Sources/SourceHelper.h"
9 #include "art/Framework/Principal/Event.h"
10 #include "art/Framework/Principal/EventPrincipal.h"
11 #include "art/Framework/Principal/Handle.h"
12 #include "art/Framework/Principal/RunPrincipal.h"
13 #include "art/Framework/Principal/SubRunPrincipal.h"
14 //#include "art/Persistency/Provenance/BranchIDListHelper.h"
15 #if ART_HEX_VERSION < 0x20900
16 #include "art/Persistency/Provenance/BranchIDListRegistry.h"
17 #include "canvas/Utilities/GetPassID.h"
18 #endif
19 #include "art/Persistency/Provenance/MasterProductRegistry.h"
20 #include "art/Persistency/Provenance/ProductMetaData.h"
21 #include "canvas/Persistency/Provenance/EventID.h"
22 #include "canvas/Persistency/Provenance/FileFormatVersion.h"
23 #include "canvas/Persistency/Provenance/ModuleDescription.h"
24 #include "canvas/Persistency/Provenance/Parentage.h"
25 #include "canvas/Persistency/Provenance/ProcessConfiguration.h"
26 #include "canvas/Persistency/Provenance/RunID.h"
27 #include "canvas/Persistency/Provenance/SubRunID.h"
28 #include "canvas/Persistency/Provenance/Timestamp.h"
29 #include "canvas/Utilities/Exception.h"
30 #include "art/Version/GetReleaseVersion.h"
31 #include "artdaq-core/Data/Fragment.hh"
32 #include "artdaq-core/Utilities/configureMessageFacility.hh"
33 #include "fhiclcpp/make_ParameterSet.h"
34 
35 #define BOOST_TEST_MODULE shared_memory_reader_t
36 #include <boost/test/auto_unit_test.hpp>
37 
38 #include <iostream>
39 #include <memory>
40 #include <string>
41 
46 {
47 public:
52 
56  typedef std::map<std::string, art::BranchKey> BKmap_t;
57 
59  std::map<std::string, std::unique_ptr<art::ProcessConfiguration>> processConfigurations_;
60 
70  art::ProcessConfiguration*
71  fake_single_module_process(std::string const& tag,
72  std::string const& processName,
73  fhicl::ParameterSet const& moduleParams,
74  std::string const& release = art::getReleaseVersion()
75 #if ART_HEX_VERSION < 0x20800
76  , std::string const& pass = art::getPassID()
77 #endif
78  );
79 
87  std::unique_ptr<art::BranchDescription>
88  fake_single_process_branch(std::string const& tag,
89  std::string const& processName,
90  std::string const& productInstanceName = std::string());
91 
95  void finalize();
96 
97  art::MasterProductRegistry productRegistry_;
98  //art::RootDictionaryManager rdm_;
99 };
100 
102  :
103  branchKeys_()
104  , processConfigurations_()
105  , productRegistry_()//,
106 // rdm_()
107 {
108  // We can only insert products registered in the MasterProductRegistry.
109  productRegistry_.addProduct(fake_single_process_branch("hlt", "HLT"));
110  productRegistry_.addProduct(fake_single_process_branch("prod", "PROD"));
111  productRegistry_.addProduct(fake_single_process_branch("test", "TEST"));
112  productRegistry_.addProduct(fake_single_process_branch("user", "USER"));
113  productRegistry_.addProduct(fake_single_process_branch("rick", "USER2", "rick"));
114 }
115 
116 void
118 {
119  productRegistry_.setFrozen();
120 #if ART_HEX_VERSION < 0x20900
121  art::BranchIDListRegistry::updateFromProductRegistry(productRegistry_);
122 #endif
123  art::ProductMetaData::create_instance(productRegistry_);
124 }
125 
126 art::ProcessConfiguration*
128 fake_single_module_process(std::string const& tag,
129  std::string const& processName,
130  fhicl::ParameterSet const& moduleParams,
131  std::string const& release
132 #if ART_HEX_VERSION < 0x20800
133  , std::string const& pass
134 #endif
135 )
136 {
137  fhicl::ParameterSet processParams;
138  processParams.put(processName, moduleParams);
139  processParams.put<std::string>("process_name",
140  processName);
141  auto emplace_pair =
142  processConfigurations_.emplace(tag,
143  std::make_unique<art::ProcessConfiguration>(processName, processParams.id(), release, pass));
144  return emplace_pair.first->second.get();
145 }
146 
147 std::unique_ptr<art::BranchDescription>
149 fake_single_process_branch(std::string const& tag,
150  std::string const& processName,
151  std::string const& productInstanceName)
152 {
153  std::string moduleLabel = processName + "dummyMod";
154  std::string moduleClass("DummyModule");
155  fhicl::ParameterSet modParams;
156  modParams.put<std::string>("module_type", moduleClass);
157  modParams.put<std::string>("module_label", moduleLabel);
158  art::ProcessConfiguration* process =
159  fake_single_module_process(tag, processName, modParams);
160  art::ModuleDescription mod(modParams.id(),
161  moduleClass,
162  moduleLabel,
163  *process);
164  art::TypeID dummyType(typeid(int));
165  art::BranchDescription* result =
166  new art::BranchDescription(
167  art::InEvent,
168  art::TypeLabel(dummyType,
169  productInstanceName),
170  mod);
171 
172 
173  branchKeys_.insert(std::make_pair(tag, art::BranchKey(*result)));
174  return std::unique_ptr<art::BranchDescription>(result);
175 }
176 
181 {
186  {
187  static bool once(true);
188  if (once)
189  {
190  artdaq::configureMessageFacility("shared_memory_reader_t");
191  (void)reader(); // Force initialization.
192  art::ModuleDescription md(fhicl::ParameterSet().id(),
193  "_NAMEERROR_",
194  "_LABELERROR_",
195  *gf().processConfigurations_["daq"]);
196  // These _xERROR_ strings should never appear in branch names; they
197  // are here as tracers to help identify any failures in coding.
198  helper().registerProducts(gf().productRegistry_, md);
199  gf().finalize();
200  once = false;
201  }
202  }
203 
209  {
210  static MPRGlobalTestFixture mpr;
211  return mpr;
212  }
213 
218  art::ProductRegistryHelper& helper()
219  {
220  static art::ProductRegistryHelper s_helper;
221  return s_helper;
222  }
223 
228  art::SourceHelper& source_helper()
229  {
230  static std::unique_ptr<art::SourceHelper>
231  s_source_helper;
232  if (!s_source_helper)
233  {
234  fhicl::ParameterSet sourceParams;
235  std::string moduleType{ "DummySource" };
236  std::string moduleLabel{ "daq" };
237  sourceParams.put<std::string>("module_type", moduleType);
238  sourceParams.put<std::string>("module_label", moduleLabel);
239  auto pc_ptr = gf().fake_single_module_process(moduleLabel,
240  "TEST",
241  sourceParams);
242  art::ModuleDescription md(sourceParams.id(),
243  moduleType,
244  moduleLabel,
245  *pc_ptr);
246  s_source_helper = std::make_unique<art::SourceHelper>(md);
247  }
248  return *s_source_helper;
249  }
250 
255  uint32_t getKey()
256  {
257  static uint32_t key = static_cast<uint32_t>(std::hash<std::string>()("shared_memory_reader_t"));
258  return key;
259  }
264  uint32_t getBroadcastKey()
265  {
266  static uint32_t key = static_cast<uint32_t>(std::hash<std::string>()("shared_memory_reader_t BROADCAST"));
267  return key;
268  }
269 
275  {
276  writer();
277  fhicl::ParameterSet pset;
278  pset.put("shared_memory_key", getKey());
279  pset.put("broadcast_shared_memory_key", getBroadcastKey());
280  pset.put("max_event_size_bytes", 0x100000);
281  pset.put("buffer_count", 10);
283  s_reader(pset,
284  helper(),
285  source_helper(),
286  gf().productRegistry_);
287  static bool reader_initialized = false;
288  if (!reader_initialized)
289  {
290  s_reader.fragment_type_map_[1] = "ABCDEF";
291  helper().reconstitutes<artdaq::Fragments, art::InEvent>("daq", "ABCDEF");
292  reader_initialized = true;
293  }
294  return s_reader;
295  }
296 
302  {
303  fhicl::ParameterSet pset;
304  pset.put("shared_memory_key", getKey());
305  pset.put("broadcast_shared_memory_key", getBroadcastKey());
306  pset.put("max_event_size_bytes", 0x100000);
307  pset.put("art_analyzer_count", 0);
308  pset.put("stale_buffer_timeout_usec", 100000);
309  pset.put("expected_fragments_per_event", 1);
310  pset.put("buffer_count", 10);
312  s_writer(pset, pset);
313  return s_writer;
314 
315  }
316 };
317 
318 BOOST_FIXTURE_TEST_SUITE(shared_memory_reader_t, ShmRTestFixture)
319 
320 namespace
321 {
332  std::unique_ptr<art::RunPrincipal>&& run,
333  std::unique_ptr<art::SubRunPrincipal>&& subrun,
334  art::EventID const& eventid)
335  {
336  BOOST_REQUIRE(run || subrun == nullptr); // Sanity check.
337  std::vector<artdaq::Fragment::value_type> fakeData{ 1, 2, 3, 4 };
338  artdaq::FragmentPtr
339  tmpFrag(artdaq::Fragment::dataFrag(eventid.event(),
340  0,
341  fakeData.begin(),
342  fakeData.end()));
343  tmpFrag->setUserType(1);
344 
345  writer.startRun(eventid.run());
346 
347 
348  auto iter = tmpFrag->dataBegin();
349  std::ostringstream str;
350  str << "{";
351  while (iter != tmpFrag->dataEnd())
352  {
353  str << std::to_string(*iter) << ", ";
354  ++iter;
355 
356  }
357  str << "}";
358  TLOG(TLVL_DEBUG) << "Fragment to art: " << str.str();
359 
360 
361  artdaq::FragmentPtr tempFrag;
362  auto sts = writer.AddFragment(std::move(tmpFrag), 1000000, tempFrag);
363  BOOST_REQUIRE_EQUAL(sts, true);
364 
365  while (writer.GetLockedBufferCount())
366  {
367  writer.sendMetrics();
368  usleep(100000);
369  }
370 
371  art::EventPrincipal* newevent = nullptr;
372  art::SubRunPrincipal* newsubrun = nullptr;
373  art::RunPrincipal* newrun = nullptr;
374  bool rc = reader.readNext(run.get(), subrun.get(), newrun, newsubrun, newevent);
375  BOOST_REQUIRE(rc);
376  if (run.get() && run->run() == eventid.run())
377  {
378  BOOST_CHECK(newrun == nullptr);
379  }
380  else
381  {
382  BOOST_CHECK(newrun);
383  BOOST_CHECK(newrun->id() == eventid.runID());
384  }
385  if (!newrun && subrun.get() && subrun->subRun() == eventid.subRun())
386  {
387  BOOST_CHECK(newsubrun == nullptr);
388  }
389  else
390  {
391  BOOST_CHECK(newsubrun);
392  BOOST_CHECK(newsubrun->id() == eventid.subRunID());
393  }
394  BOOST_CHECK(newevent);
395  BOOST_CHECK(newevent->id() == eventid);
396  art::Event e(*newevent, art::ModuleDescription());
397  art::Handle<std::vector<artdaq::Fragment>> h;
398  e.getByLabel("daq", "ABCDEF", h);
399  BOOST_CHECK(h.isValid());
400  BOOST_CHECK(h->size() == 1);
401 
402  auto iter2 = h->front().dataBegin();
403  std::ostringstream str2;
404  str2 << "{";
405  while (iter2 != h->front().dataEnd())
406  {
407  str2 << std::to_string(*iter2) << ", ";
408  ++iter2;
409 
410  }
411  str2 << "}";
412  TLOG(TLVL_DEBUG) << "Fragment from art: " << str2.str();
413 
414  BOOST_CHECK(std::equal(fakeData.begin(),
415  fakeData.end(),
416  h->front().dataBegin()));
417  delete(newrun);
418  delete(newsubrun);
419  delete(newevent);
420  }
421 }
422 
423 BOOST_AUTO_TEST_CASE(nonempty_event)
424 {
425  art::EventID eventid(2112, 1, 3);
426  art::Timestamp now;
427  basic_test(reader(), writer(),
428  std::unique_ptr<art::RunPrincipal>(source_helper().makeRunPrincipal(eventid.run(), now)),
429  std::unique_ptr<art::SubRunPrincipal>(source_helper().makeSubRunPrincipal(eventid.run(), eventid.subRun(), now)),
430  eventid);
431 }
432 
433 BOOST_AUTO_TEST_CASE(first_event)
434 {
435  art::EventID eventid(2112, 1, 3);
436  art::Timestamp now;
437  basic_test(reader(), writer(),
438  nullptr,
439  nullptr,
440  eventid);
441 }
442 
443 BOOST_AUTO_TEST_CASE(new_subrun)
444 {
445  art::EventID eventid(2112, 1, 3);
446  art::Timestamp now;
447  basic_test(reader(), writer(),
448  std::unique_ptr<art::RunPrincipal>(source_helper().makeRunPrincipal(eventid.run(), now)),
449  std::unique_ptr<art::SubRunPrincipal>(source_helper().makeSubRunPrincipal(eventid.run(), 0, now)),
450  eventid);
451 }
452 
453 BOOST_AUTO_TEST_CASE(new_run)
454 {
455  art::EventID eventid(2112, 1, 3);
456  art::Timestamp now;
457  basic_test(reader(), writer(),
458  std::unique_ptr<art::RunPrincipal>(source_helper().makeRunPrincipal(eventid.run() - 1, now)),
459  std::unique_ptr<art::SubRunPrincipal>(source_helper().makeSubRunPrincipal(eventid.run() - 1,
460  eventid.subRun(),
461  now)),
462  eventid);
463 }
464 
465 BOOST_AUTO_TEST_CASE(end_of_data)
466 {
467  // Tell 'reader' the name of the file we are to read. This is pretty
468  // much irrelevant for SharedMemoryReader, but we'll stick to the
469  // interface demanded by Source<T>...
470  std::string const fakeFileName("no such file exists");
471  art::FileBlock* pFile = nullptr;
472  reader().readFile(fakeFileName, pFile);
473  BOOST_CHECK(pFile);
474  BOOST_CHECK(pFile->fileFormatVersion() == art::FileFormatVersion(1, "RawEvent2011"));
475  BOOST_CHECK(pFile->tree() == nullptr);
476 
477  BOOST_CHECK(!pFile->fastClonable());
478  // Test the end-of-data handling. Reading an end-of-data should result in readNext() returning false,
479  // and should return null pointers for new-run, -subrun and -event.
480  // Prepare our 'previous run/subrun/event'..
481  art::RunID runid(2112);
482  art::SubRunID subrunid(2112, 1);
483  art::EventID eventid(2112, 1, 3);
484  art::Timestamp now;
485  std::unique_ptr<art::RunPrincipal> run(source_helper().makeRunPrincipal(runid.run(), now));
486  std::unique_ptr<art::SubRunPrincipal> subrun(source_helper().makeSubRunPrincipal(runid.run(), subrunid.subRun(), now));
487  std::unique_ptr<art::EventPrincipal> event(source_helper().makeEventPrincipal(runid.run(),
488  subrunid.subRun(),
489  eventid.event(),
490  now));
491  writer().endOfData();
492  art::EventPrincipal* newevent = nullptr;
493  art::SubRunPrincipal* newsubrun = nullptr;
494  art::RunPrincipal* newrun = nullptr;
495  bool rc = reader().readNext(run.get(), subrun.get(), newrun, newsubrun, newevent);
496  BOOST_CHECK(!rc);
497  BOOST_CHECK(newrun == nullptr);
498  BOOST_CHECK(newsubrun == nullptr);
499  BOOST_CHECK(newevent == nullptr);
500 }
501 
502 BOOST_AUTO_TEST_SUITE_END()
SharedMemoryReader Test Fixture.
std::map< std::string, std::unique_ptr< art::ProcessConfiguration > > processConfigurations_
Configurations.
The SharedMemoryReader is a class which implements the methods needed by art::Source.
void finalize()
Finalizes the ProductRegistry.
size_t GetLockedBufferCount()
Returns the number of buffers currently owned by this manager.
The SharedMemoryEventManager is a SharedMemoryManger which tracks events as they are built...
ShmRTestFixture()
ShmRTestFixture Constructor.
artdaq::SharedMemoryEventManager & writer()
Get the instance of the SharedMemoryEventManager.
art::MasterProductRegistry productRegistry_
MasterProductRegistry instance.
uint32_t getBroadcastKey()
Gets the key for the broadcast shared memory segment.
art::ProcessConfiguration * fake_single_module_process(std::string const &tag, std::string const &processName, fhicl::ParameterSet const &moduleParams, std::string const &release=art::getReleaseVersion(), std::string const &pass=art::getPassID())
Create the ProcessConfiguration for a single module art process.
void basic_test(artdaq::detail::SharedMemoryReader<> &reader, artdaq::SharedMemoryEventManager &writer, std::unique_ptr< art::RunPrincipal > &&run, std::unique_ptr< art::SubRunPrincipal > &&subrun, art::EventID const &eventid)
Run a basic checkout of the SharedMemoryReader.
std::unique_ptr< art::BranchDescription > fake_single_process_branch(std::string const &tag, std::string const &processName, std::string const &productInstanceName=std::string())
Create a BranchDescription for a process.
MasterProductRegistry Test Fixture.
uint32_t getKey()
Gets the key for the shared memory segment.
void sendMetrics()
Send metrics to the MetricManager, if one has been instantiated in the application.
std::map< std::string, art::BranchKey > BKmap_t
BKmap_t associates a string with a art::BranchKey.
MPRGlobalTestFixture()
MPRGlobalTestFixture Constructor.
artdaq::detail::SharedMemoryReader & reader()
Get an artdaq::detail::SharedMemoryReader object, creating a static instance if necessary.
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.
BKmap_t branchKeys_
Keys in this test fixture.
std::map< Fragment::type_t, std::string > fragment_type_map_
The Fragment type names that this SharedMemoryReader knows about.
MPRGlobalTestFixture & gf()
Get a MPRGlobalTestFixture, creating a static instance if necessary.
art::SourceHelper & source_helper()
Get an art::SourceHelper object, creating a static instance if necessary.
art::ProductRegistryHelper & helper()
Get an art::ProductRegistryHelper, creating a static instance if necessary.
void startRun(run_id_t runID)
Start a Run.