otsdaq  3.06.00
ARTDAQEventBuilderTable_table.cc
1 #include "otsdaq/Macros/TablePluginMacros.h"
2 #include "otsdaq/TablePlugins/ARTDAQEventBuilderTable.h"
3 
4 #include <fstream> // for std::ofstream
5 
6 using namespace ots;
7 
8 // clang-format off
9 
10 #define SLOWCONTROL_PV_FILE_PATH \
11  std::string( \
12  getenv("OTSDAQ_EPICS_DATA")? \
13  (std::string(getenv("OTSDAQ_EPICS_DATA")) + "/" + __ENV__("MU2E_OWNER") + "_otsdaq_artdaqEventBuilder-ai.dbg"): \
14  (EPICS_CONFIG_PATH + "/_otsdaq_artdaqEventBuilder-ai.dbg") )
15 
16 // clang-format on
17 
18 //==============================================================================
19 ARTDAQEventBuilderTable::ARTDAQEventBuilderTable(void)
20  : TableBase("ARTDAQEventBuilderTable")
21  , ARTDAQTableBase("ARTDAQEventBuilderTable")
22  , SlowControlsTableBase("ARTDAQEventBuilderTable")
23 {
25  // WARNING: the names used in C++ MUST match the Table INFO //
27  __COUT__ << "ARTDAQEventBuilderTable Constructed." << __E__;
28 } // end constructor()
29 
30 //==============================================================================
31 ARTDAQEventBuilderTable::~ARTDAQEventBuilderTable(void) {}
32 
33 //==============================================================================
35 {
36  lastConfigManager_ = configManager;
37  if(!ARTDAQTableBase::doGenFiles(configManager))
38  {
39  __COUTS__(3) << "ARTDAQTableBase indicates file generation can be skipped."
40  << __E__;
41  return;
42  }
43 
44  __COUTS__(3) << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << __E__;
45  __COUTS__(3) << configManager->__SELF_NODE__ << __E__;
46 
47  genFlatFHiCL();
48 } // end init()
49 
50 //==============================================================================
51 void ARTDAQEventBuilderTable::genFlatFHiCL(void)
52 {
53  // handle fcl file generation, wherever the level of this table
54 
55  auto builders = lastConfigManager_->getNode(ARTDAQTableBase::getTableName())
56  .getChildren(
57  /*default filterMap*/ std::map<std::string /*relative-path*/,
58  std::string /*value*/>(),
59  /*default byPriority*/ false,
60  /*TRUE! onlyStatusTrue*/ true);
61 
62  std::string lastBuilderFcl[2],
63  flattenedLastFclParts
64  [2]; //same handling as otsdaq/otsdaq/TablePlugins/ARTDAQTableBase/ARTDAQTableBase.cc:1986
65  for(auto& builder : builders)
66  {
67  const std::string& builderUID = builder.first;
68  __COUTV__(builderUID);
69 
70  std::string returnFcl, processName;
71  bool needToFlatten = true;
72  bool captureAsLastFcl =
73  builders.size() && //init to true if multiple builders left to handle
74  (&builder != &builders.back());
75  outputDataReceiverFHICL(builder.second,
76  ARTDAQAppType::EventBuilder,
77  DEFAULT_MAX_FRAGMENT_SIZE,
78  DEFAULT_ROUTING_TIMEOUT_MS,
79  DEFAULT_ROUTING_RETRY_COUNT,
80  captureAsLastFcl ? &returnFcl : nullptr);
81 
82  //Speed-up Philosophy:
83  // flattenFHICL is expensive, so try to identify multinodes with fcl that only differ by process_name,
84  // i.e., ignore starting comments and process name, then compare fcl.
85  // Note: not much gain for any other node types but Event Builders, which tend to only differ by process_name in their fcl
86 
87  auto cmi =
88  returnFcl.find("# otsdaq-ARTDAQ builder UID:"); //find starting comments
89  if(cmi != std::string::npos)
90  cmi = returnFcl.find('\n', cmi);
91  if(cmi != std::string::npos)
92  {
93  size_t pnj = std::string::npos;
94  auto pni = returnFcl.find("\tprocess_name: ", cmi); //find process name
95  if(pni != std::string::npos)
96  {
97  pni += std::string("\tprocess_name: ").size(); //move past field name
98  pnj = returnFcl.find('\n', pni);
99  }
100  if(pnj != std::string::npos)
101  {
102  processName = returnFcl.substr(pni, pnj - pni);
103  __COUT__ << "Found process name = " << processName << __E__;
104 
105  bool sameFirst = false;
106  //check before process name (ignoring comments)
107  std::string newPiece = returnFcl.substr(cmi, pni - cmi);
108  if(flattenedLastFclParts[0].size() && lastBuilderFcl[0].size() &&
109  lastBuilderFcl[0] == newPiece)
110  {
111  __COUT__ << "Same first fcl" << __E__;
112  sameFirst = true;
113  }
114  else if(TTEST(20))
115  {
116  __COUTVS__(20, lastBuilderFcl[0]);
117  __COUTVS__(20, newPiece);
118  for(size_t i = 0, j = 0;
119  i < lastBuilderFcl[0].size() && j < newPiece.size();
120  ++i, ++j)
121  {
122  if(lastBuilderFcl[0][i] != newPiece[j])
123  {
124  __COUTVS__(20, i);
125  __COUTVS__(20, j);
126  __COUTVS__(20, lastBuilderFcl[0].substr(i, 30));
127  __COUTVS__(20, newPiece.substr(j, 30));
128  break;
129  }
130  }
131  }
132  if(captureAsLastFcl) //if more, save piece
133  lastBuilderFcl[0] = newPiece;
134 
135  //check after process name
136  newPiece = returnFcl.substr(pnj);
137  if(lastBuilderFcl[0].size() && lastBuilderFcl[1] == newPiece)
138  {
139  __COUT__ << "Same second fcl" << __E__;
140  if(sameFirst) //found opportunity for shortcut-to-flatten!
141  {
142  std::chrono::steady_clock::time_point startClock =
143  std::chrono::steady_clock::now();
144  __COUT__ << "Found fcl match! Reuse for " << builderUID << __E__;
145  captureAsLastFcl =
146  false; //do not overwrite current last fcl now!
147  needToFlatten = false;
148 
149  //do rapid flatten here
150  std::string outFile =
151  getFlatFHICLFilename(ARTDAQAppType::EventBuilder, builderUID);
152  __COUTVS__(3, outFile);
153  std::ofstream ofs{outFile};
154  if(!ofs)
155  {
156  __SS__ << "Failed to open fhicl output file '" << outFile
157  << "!'" << __E__;
158  __SS_THROW__;
159  }
160  std::ostringstream out;
161  out << flattenedLastFclParts[0] << "process_name: \""
162  << processName << "\"" << flattenedLastFclParts[1];
163 
164  ofs << out.str();
165  fclMap_[ARTDAQAppType::EventBuilder][builder.first] = out.str();
166 
167  __COUTT__ << builderUID << " Flatten Clock time = "
168  << artdaq::TimeUtils::GetElapsedTime(startClock)
169  << __E__;
170  continue; //done with shortcut-to-flatten
171  } //end shortcut-to-flatten handling
172  }
173  if(captureAsLastFcl) //if interesting for more, save piece
174  lastBuilderFcl[1] = newPiece;
175  }
176  }
177 
178  std::string& returnFclRef = returnFcl;
179  if(needToFlatten)
180  {
181  ARTDAQTableBase::flattenFHICL(
182  ARTDAQAppType::EventBuilder,
183  builderUID,
184  &(fclMap_[ARTDAQAppType::EventBuilder]
185  [builder.first])); //captureAsLastFcl ? &returnFcl : nullptr);
186 
187  if(captureAsLastFcl)
188  returnFclRef = fclMap_[ARTDAQAppType::EventBuilder][builder.first];
189  }
190  else
191  __COUT__ << "Skipping full flatten for " << builderUID << __E__;
192 
193  //save parts without process name
194  __COUTV__(captureAsLastFcl);
195  if(captureAsLastFcl)
196  {
197  size_t pnj = std::string::npos;
198  auto pni = returnFclRef.find("process_name:"); //find process name
199  if(pni != std::string::npos)
200  {
201  //enforce white space before process name
202  if(pni &&
203  (returnFclRef[pni - 1] == ' ' || returnFclRef[pni - 1] == '\n' ||
204  returnFclRef[pni - 1] == '\t'))
205  pnj = returnFclRef.find('\n', pni);
206  }
207  if(pnj != std::string::npos)
208  {
209  __COUT__
210  << "Found flattened '" //Note: returnFclRef.substr(pni, pnj - pni) includes "process_name:"
211  << returnFclRef.substr(pni, pnj - pni) << "' at pos " << pni << " of "
212  << returnFclRef.size() << __E__;
213  flattenedLastFclParts[0] = returnFclRef.substr(0, pni);
214  flattenedLastFclParts[1] = returnFclRef.substr(pnj);
215  }
216  else
217  {
218  __COUT_WARN__ << "Failed to capture fcl for " << processName << "!"
219  << __E__;
220  }
221  }
222  } //end builder fcl handling loop
223  __COUTS__(3) << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << __E__;
224 } // end init()
225 
226 //==============================================================================
227 unsigned int ARTDAQEventBuilderTable::slowControlsHandlerConfig(
228  std::stringstream& out,
229  ConfigurationManager* configManager,
230  std::vector<std::pair<std::string /*channelName*/, std::vector<std::string>>>*
231  channelList /*= 0*/
232 ) const
233 {
235  // generate xdaq run parameter file
236 
237  std::string tabStr = "";
238  std::string commentStr = "";
239 
240  // loop through ARTDAQ EventBuilder records starting at ARTDAQSupervisorTable
241  std::vector<std::pair<std::string, ConfigurationTree>> artdaqRecords =
242  configManager->getNode("ARTDAQSupervisorTable").getChildren();
243 
244  unsigned int numberOfEventBuiderMetricParameters = 0;
245 
246  for(auto& artdaqPair : artdaqRecords) // start main artdaq record loop
247  {
248  if(artdaqPair.second.getNode(colARTDAQSupervisor_.colLinkToEventBuilders_)
249  .isDisconnected())
250  continue;
251 
252  std::vector<std::pair<std::string, ConfigurationTree>> eventBuilderRecords =
253  artdaqPair.second.getNode(colARTDAQSupervisor_.colLinkToEventBuilders_)
254  .getChildren();
255 
256  for(auto& eventBuilderPair :
257  eventBuilderRecords) // start main eventBuilder record loop
258  {
259  if(!eventBuilderPair.second.status())
260  continue;
261 
262  try
263  {
264  if(eventBuilderPair.second.getNode("daqLink").isDisconnected())
265  continue;
266 
267  auto daqLink = eventBuilderPair.second.getNode("daqLink");
268 
269  if(daqLink.getNode("daqMetricsLink").isDisconnected())
270  continue;
271 
272  auto daqMetricsLinks = daqLink.getNode("daqMetricsLink").getChildren();
273  for(auto& daqMetricsLink :
274  daqMetricsLinks) // start daqMetricsLinks record loop
275  {
276  if(!daqMetricsLink.second.status())
277  continue;
278 
279  if(daqMetricsLink.second.getNode("metricParametersLink")
280  .isDisconnected())
281  continue;
282 
283  // ConfigurationTree slowControlsLink = configManager->getNode("ARTDAQMetricAlarmThresholdsTable");
284  ConfigurationTree slowControlsLink =
285  eventBuilderPair.second.getNode("MetricAlarmThresholdsLink");
286 
287  auto metricParametersLinks =
288  daqMetricsLink.second.getNode("metricParametersLink")
289  .getChildren();
290  for(auto& metricParametersLink :
291  metricParametersLinks) // start daq MetricParametersLinks record loop
292  {
293  if(!metricParametersLink.second.status())
294  continue;
295 
296  std::string subsystem =
297  metricParametersLink.second.getNode("metricParameterValue")
298  .getValueWithDefault<std::string>(std::string("TDAQ_") +
299  __ENV__("MU2E_OWNER"));
300  if(subsystem.find("Mu2e:") != std::string::npos)
301  subsystem = subsystem.replace(subsystem.find("Mu2e:"), 5, "");
302  while(subsystem.find("\"") != std::string::npos)
303  subsystem = subsystem.replace(subsystem.find("\""), 1, "");
304 
305  numberOfEventBuiderMetricParameters =
306  slowControlsHandler(out,
307  tabStr,
308  commentStr,
309  subsystem,
310  eventBuilderPair.first,
311  slowControlsLink,
312  channelList);
313 
314  __COUT__ << "EventBuilder '" << eventBuilderPair.first
315  << "' number of metrics for slow controls: "
316  << numberOfEventBuiderMetricParameters << __E__;
317  }
318  }
319  }
320  catch(const std::runtime_error& e)
321  {
322  __COUT_ERR__ << "Ignoring EventBuilder error: " << e.what() << __E__;
323  }
324  }
325  }
326 
327  return numberOfEventBuiderMetricParameters;
328 } // end slowControlsHandlerConfig()
329 
330 //==============================================================================
333 {
334  return SLOWCONTROL_PV_FILE_PATH;
335 }
336 
337 DEFINE_OTS_TABLE(ARTDAQEventBuilderTable)
void init(ConfigurationManager *configManager) override
Methods.
virtual std::string setFilePath(void) const override
return out file path
<virtual so future plugins can inherit from multiple table base classes
static void outputDataReceiverFHICL(const ConfigurationTree &receiverNode, ARTDAQAppType appType, size_t maxFragmentSizeBytes=DEFAULT_MAX_FRAGMENT_SIZE, size_t routingTimeoutMs=DEFAULT_ROUTING_TIMEOUT_MS, size_t routingRetryCount=DEFAULT_ROUTING_RETRY_COUNT, std::string *returnFcl=nullptr)
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
"root/parent/parent/"
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
navigating between nodes
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, std::string > filterMap=std::map< std::string, std::string >(), bool byPriority=false, bool onlyStatusTrue=false) const
<virtual so future plugins can inherit from multiple table base classes
const std::string & getTableName(void) const
Getters.
Definition: TableBase.cc:814
defines used also by OtsConfigurationWizardSupervisor