artdaq  v3_12_02
ListenTransferWrapper.cc
1 #include "artdaq/DAQdata/Globals.hh"
2 #define TRACE_NAME "ListenTransferWrapper"
3 
4 #include "artdaq-core/Data/Fragment.hh"
5 #include "artdaq-core/Utilities/ExceptionHandler.hh"
6 #include "artdaq-core/Utilities/TimeUtils.hh"
7 #include "artdaq/ArtModules/detail/ListenTransferWrapper.hh"
8 #include "artdaq/DAQdata/NetMonHeader.hh"
9 #include "artdaq/TransferPlugins/MakeTransferPlugin.hh"
10 
11 #include "cetlib/BasicPluginFactory.h"
12 #include "cetlib_except/exception.h"
13 #include "fhiclcpp/ParameterSet.h"
14 
15 #include <csignal>
16 #include <iostream>
17 #include <limits>
18 #include <memory>
19 #include <sstream>
20 #include <string>
21 
22 namespace {
23 volatile std::sig_atomic_t gListenSignalStatus = 0;
24 }
25 
30 void listen_signal_handler(int signal)
31 {
32  gListenSignalStatus = signal;
33 }
34 
36  : timeoutInUsecs_(pset.get<std::size_t>("timeoutInUsecs", 100000))
37  , last_received_data_()
38  , last_report_(std::chrono::steady_clock::now())
39  , transfer_(nullptr)
40  , pset_(pset)
41  , maxEventsBeforeInit_(pset.get<std::size_t>("maxEventsBeforeInit", 5))
42  , allowedFragmentTypes_(pset.get<std::vector<int>>("allowedFragmentTypes", {226, 227, 229}))
43  , runningStateTimeout_(pset.get<double>("dispatcherConnectTimeout", 0))
44  , runningStateInterval_us_(pset.get<size_t>("dispatcherConnectRetryInterval_us", 1000000))
45  , quitOnFragmentIntegrityProblem_(pset.get<bool>("quitOnFragmentIntegrityProblem", true))
46  , multi_run_mode_(pset.get<bool>("allowMultipleRuns", true))
47 {
48  std::signal(SIGINT, listen_signal_handler);
49 
50  try
51  {
52  if (metricMan)
53  {
54  metricMan->initialize(pset.get<fhicl::ParameterSet>("metrics", fhicl::ParameterSet()), "Online Monitor");
55  metricMan->do_start();
56  }
57  }
58  catch (...)
59  {
60  artdaq::ExceptionHandler(
61  artdaq::ExceptionHandlerRethrow::no,
62  "ListenTransferWrapper: could not configure metrics");
63  }
64 
65  try
66  {
67  transfer_ = artdaq::MakeTransferPlugin(pset_, "transfer_plugin", artdaq::TransferInterface::Role::kReceive);
68  }
69  catch (...)
70  {
71  artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no, "ListenTransferWrapper: failure in call to MakeTransferPlugin");
72  }
73 
74  // Clamp possible values
75  if (runningStateInterval_us_ < 1000)
76  {
77  TLOG(TLVL_WARNING) << "Invalid value " << runningStateInterval_us_ << " us detected for dispatcherConnectRetryInterval_us. Setting to 1000 us";
78  runningStateInterval_us_ = 1000;
79  }
80  if (runningStateInterval_us_ > 30000000)
81  {
82  TLOG(TLVL_WARNING) << "Invalid value " << runningStateInterval_us_ << " us detected for dispatcherConnectRetryInterval_us. Setting to 30,000,000 us";
83  runningStateInterval_us_ = 30000000;
84  }
85 }
86 
88 {
89  artdaq::FragmentPtrs fragmentPtrs;
90  bool receivedFragment = false;
91  static bool initialized = false;
92  static size_t fragments_received = 0;
93 
94  while (gListenSignalStatus == 0)
95  {
96  receivedFragment = false;
97  auto fragmentPtr = std::make_unique<artdaq::Fragment>();
98 
99  while (!receivedFragment)
100  {
101  if (gListenSignalStatus != 0)
102  {
103  TLOG(TLVL_INFO) << "Ctrl-C appears to have been hit";
104  return fragmentPtrs;
105  }
106 
107  try
108  {
109  auto result = transfer_->receiveFragment(*fragmentPtr, timeoutInUsecs_);
110 
112  {
113  receivedFragment = true;
114  fragments_received++;
115 
116  static size_t cntr = 0;
117  auto mod = ++cntr % 10;
118  auto suffix = "-th";
119  if (mod == 1)
120  {
121  suffix = "-st";
122  }
123  if (mod == 2)
124  {
125  suffix = "-nd";
126  }
127  if (mod == 3)
128  {
129  suffix = "-rd";
130  }
131  TLOG(TLVL_INFO) << "Received " << cntr << suffix << " event, "
132  << "seqID == " << fragmentPtr->sequenceID()
133  << ", type == " << fragmentPtr->typeString();
134  last_received_data_ = std::chrono::steady_clock::now();
135  continue;
136  }
138  {
139  TLOG(TLVL_ERROR) << "Transfer Plugin disconnected or other unrecoverable error. Shutting down.";
140  if (multi_run_mode_)
141  {
142  initialized = false;
143  continue;
144  }
145  return fragmentPtrs;
146  }
147  else
148  {
149  auto tlvl = TLVL_DEBUG + 33;
150  if (artdaq::TimeUtils::GetElapsedTime(last_report_) > 1.0 && artdaq::TimeUtils::GetElapsedTime(last_received_data_) > 1.0)
151  {
152  tlvl = TLVL_WARNING;
153  last_report_ = std::chrono::steady_clock::now();
154  }
155 
156  auto last_received_milliseconds = artdaq::TimeUtils::GetElapsedTimeMilliseconds(last_received_data_);
157 
158  // 02-Jun-2018, KAB: added status/result printout
159  // to-do: add another else clause that explicitly checks for RECV_TIMEOUT
160  TLOG(tlvl) << "Timeout occurred in call to transfer_->receiveFragmentFrom; will try again"
161  << ", status = " << result << ", last received data " << last_received_milliseconds << " ms ago.";
162  }
163  }
164  catch (...)
165  {
166  artdaq::ExceptionHandler(
167  artdaq::ExceptionHandlerRethrow::yes,
168  "Problem receiving data in ListenTransferWrapper::receiveMessage");
169  }
170  }
171 
172  if (fragmentPtr->type() == artdaq::Fragment::EndOfSubrunFragmentType || fragmentPtr->type() == artdaq::Fragment::EndOfRunFragmentType)
173  {
174  // Ignore these for now
175  continue;
176  }
177 
178  if (fragmentPtr->type() == artdaq::Fragment::EndOfDataFragmentType)
179  {
180  // if (monitorRegistered_)
181  //{
182  // unregisterMonitor();
183  // }
184  if (multi_run_mode_)
185  {
186  // initialized = false;
187  continue;
188  }
189 
190  return fragmentPtrs;
191  }
192 
193  checkIntegrity(*fragmentPtr);
194 
195  if (initialized || fragmentPtr->type() == artdaq::Fragment::InitFragmentType)
196  {
197  if (initialized && fragmentPtr->type() == artdaq::Fragment::InitFragmentType)
198  {
199  // Ignore reinit for now, maybe handle in ArtdaqInputHelper later
200  continue;
201  }
202  initialized = true;
203  fragmentPtrs.push_back(std::move(fragmentPtr));
204  break;
205  }
206 
207  if (fragments_received > maxEventsBeforeInit_)
208  {
209  throw cet::exception("ListenTransferWrapper") << "First " << maxEventsBeforeInit_ << " events received did not include the \"Init\" event containing necessary info for art; exiting..."; // NOLINT(cert-err60-cpp)
210  }
211  }
212 
213  return fragmentPtrs;
214 }
215 
216 std::unordered_map<artdaq::Fragment::type_t, std::unique_ptr<artdaq::Fragments>>
218 {
219  std::unordered_map<artdaq::Fragment::type_t, std::unique_ptr<artdaq::Fragments>> output;
220 
221  auto ptrs = receiveMessage();
222  for (auto& ptr : ptrs)
223  {
224  auto fragType = ptr->type();
225  auto fragPtr = ptr.release();
226  ptr.reset(nullptr);
227 
228  if (output.count(fragType) == 0u)
229  {
230  output[fragType] = std::make_unique<artdaq::Fragments>();
231  }
232 
233  output[fragType]->emplace_back(std::move(*fragPtr));
234  }
235 
236  return output;
237 }
238 
239 void artdaq::ListenTransferWrapper::checkIntegrity(
240  const artdaq::Fragment& fragment) const
241 {
242  const size_t artdaqheader = artdaq::detail::RawFragmentHeader::num_words() *
243  sizeof(artdaq::detail::RawFragmentHeader::RawDataType);
244  const auto payload = static_cast<size_t>(fragment.dataEndBytes() - fragment.dataBeginBytes());
245  const size_t metadata = sizeof(artdaq::NetMonHeader);
246  const size_t totalsize = fragment.sizeBytes();
247 
248  const auto type = static_cast<size_t>(fragment.type());
249 
250  if (totalsize != artdaqheader + metadata + payload)
251  {
252  std::stringstream errmsg;
253  errmsg << "Error: artdaq fragment of type " << fragment.typeString() << ", sequence ID " << fragment.sequenceID() << " has internally inconsistent measures of its size, signalling data corruption: in bytes,"
254  << " total size = " << totalsize << ", artdaq fragment header = " << artdaqheader << ", metadata = " << metadata << ", payload = " << payload;
255 
256  TLOG(TLVL_ERROR) << errmsg.str();
257 
258  if (quitOnFragmentIntegrityProblem_)
259  {
260  throw cet::exception("ListenTransferWrapper") << errmsg.str(); // NOLINT(cert-err60-cpp)
261  }
262 
263  return;
264  }
265 
266  auto findloc = std::find(allowedFragmentTypes_.begin(), allowedFragmentTypes_.end(), static_cast<int>(type));
267 
268  if (findloc == allowedFragmentTypes_.end())
269  {
270  std::stringstream errmsg;
271  errmsg << "Error: artdaq fragment appears to have type "
272  << type << ", not found in the allowed fragment types list";
273 
274  TLOG(TLVL_ERROR) << errmsg.str();
275  if (quitOnFragmentIntegrityProblem_)
276  {
277  throw cet::exception("ListenTransferWrapper") << errmsg.str(); // NOLINT(cert-err60-cpp)
278  }
279 
280  return;
281  }
282 }
283 
285 {
287 }
static void CleanUpGlobals()
Clean up statically-allocated Manager class instances.
Definition: Globals.hh:156
virtual ~ListenTransferWrapper()
ListenTransferWrapper Destructor.
std::unordered_map< artdaq::Fragment::type_t, std::unique_ptr< artdaq::Fragments > > receiveMessages()
Receive all messsages for an event from ArtdaqSharedMemoryService.
std::unique_ptr< artdaq::TransferInterface > MakeTransferPlugin(const fhicl::ParameterSet &pset, const std::string &plugin_label, TransferInterface::Role role)
Load a TransferInterface plugin.
This TransferInterface is a Receiver.
Header with length information for NetMonTransport messages.
Definition: NetMonHeader.hh:13
Value that is to be returned when a Transfer plugin determines that no more data will be arriving...
artdaq::FragmentPtrs receiveMessage()
Receive a Fragment from the TransferInterface, and send it to art.
volatile std::sig_atomic_t gListenSignalStatus
Stores singal from signal handler.
For code clarity, things checking for successful receive should check retval &gt;= NO_RANK_INFO.
ListenTransferWrapper(const fhicl::ParameterSet &pset)
ListenTransferWrapper Constructor.