RunController.cc
Go to the documentation of this file.
1 #include <sstream>
2 #include <iostream>
3 
4 #include <boost/lexical_cast.hpp>
5 
6 #include <fwk/CentralConfig.h>
7 #include <fwk/RunController.h>
8 #include <utl/ErrorLogger.h>
9 #include <fwk/VModule.h>
10 #include <utl/Reader.h>
11 #include <evt/Event.h>
12 #include <utl/AugerException.h>
13 #include <utl/TabularStream.h>
14 #include <utl/StringCompare.h>
15 
16 using namespace std;
17 using namespace utl;
18 
19 
20 namespace fwk {
21 
22  RunController::RunController() :
23  fCurEvent(new evt::Event)
24  {
25  ErrorLogger::GetInstance();
26  }
27 
28 
29  VModule&
30  RunController::GetModule(const string& moduleName)
31  const
32  {
33  auto* const m = VModuleFactory::Create(moduleName);
34 
35  fUsedModuleNames.insert(moduleName);
36 
37  if (!m) {
38  ostringstream emsg;
39  emsg << "No module creator found for module with name '" << moduleName << "'. "
40  "Most likely reasons:\n"
41  "1) You misspelled the module name, or the module doesn't exist.\n"
42  "2) You declared a default constructor for your module\n"
43  " but did not provide an implementation.\n"
44  "3) You linked with static libraries (currently not supported)\n"
45  "4) Your application was not linked to AugerModules (check with ldd and your compiler options).";
46  ERROR(emsg);
47  throw utl::ModuleSequenceException("cannot create module");
48  }
49  return *m;
50  }
51 
52 
53  bool
54  RunController::HasModule(const string& moduleName)
55  const
56  {
57  auto* const m = VModuleFactory::Create(moduleName);
58  return m;
59  }
60 
61 
62  int
64  const
65  {
67  }
68 
69 
70  string
72  const
73  {
74  ostringstream modules;
75  for (auto it = VModuleFactory::Begin(); it != VModuleFactory::End(); ++it) {
76  auto* const m = VModuleFactory::Create(it->first);
77  if (m)
78  modules << it->first << " (version: "
79  << m->GetVersionInfo(VModule::eRevisionNumber)
80  << ")\n";
81  }
82  return modules.str();
83  }
84 
85 
86  // use AttributeMap to return stuff like
87  // name : module name
88  // version : svn version
89  // last mod : last modified
90  // last editor : last editor
91 
92  void
94  {
95  // Attempt to find the sequence.
96 
97  // catch exceptions from central config here ?
98 
99  CentralConfig* cc = nullptr;
100  try {
101  // assumes central config has already been given name of bootstrap file
103  } catch (AugerException& ex) {
104  ostringstream msg;
105  msg << "Failure configuring the framework. "
106  "A exception of type " << ex.GetExceptionName() << " was thrown. "
107  "Message: " << ex.GetMessage() << " "
108  "Cannot recover. Terminating";
109  ERROR(msg);
110  exit(EXIT_FAILURE);
111  }
112 
113  //fUsedModuleNames.clear();
114 
115  Branch topB = cc->GetTopBranch("ModuleSequence");
116  if (!topB) {
117  ostringstream emsg;
118  emsg << "Error in RunController. "
119  "Unable to find the module sequencing information! "
120  "Is the ModuleSequence configLink correctly defined in the bootstrap file?";
121  ERROR(emsg);
122  throw utl::ModuleSequenceException("missing <ModuleSequence>");
123  } else
124  InitBranch(topB);
125  }
126 
127 
128  void
130  {
131  // initialize only those modules requested in the control file
132  GetNextModuleName(currentB);
133 
134  for (const auto& mn : fUniqueModuleNames) {
135 
136  auto& mod = GetModule(mn);
137 
138  mod.InitTiming();
139 
140  cerr << "--> Running Init() of module '" << mn << "'\n";
141 
142  const auto flag = mod.Init();
143 
144  cerr << "--> Finished Init() of module '" << mn << "', "
145  "status: " << VModule::GetResultFlagByName(flag) << '\n';
146 
147  if (flag == VModule::eFailure)
148  throw utl::ModuleSequenceException("Init() failed");
149 
150  }
151  }
152 
153 
154  // Find next module name in the XML file (recursive)
155  void
157  {
158  if (currentB.GetName() == "module") {
159  const string modName = currentB.Get<string>();
160  fUniqueModuleNames.insert(modName);
161  }
162 
163  for (Branch cb = currentB.GetFirstChild(); cb; cb = cb.GetNextSibling())
164  GetNextModuleName(cb);
165  }
166 
167 
168  void
170  {
171  Branch topB = CentralConfig::GetInstance()->GetTopBranch("ModuleSequence");
172  DoRunSequence(topB);
173  }
174 
175 
176  void
178  {
179  DoRunSequence(currentB);
180  }
181 
182 
183  void
185  {
186  Branch topB = CentralConfig::GetInstance()->GetTopBranch("ModuleSequence");
187  FinishBranch(topB);
188  }
189 
190 
191  void
193  {
194  fStopwatch.Stop();
195  const double totalUTime = fStopwatch.GetCPUTime(Stopwatch::eUser)/second;
196  const double totalSTime = fStopwatch.GetCPUTime(Stopwatch::eSystem)/second;
197  const double totalTime = fStopwatch.GetCPUTime()/second;
198  double moduleUTimeSum = 0;
199  double moduleSTimeSum = 0;
200 
201  ostringstream failureMessage;
202 
203  TabularStream tab("r: . . .");
204 
205  tab << "Module" << endc << "USR" << endc << "SYS" << endc << "%" << endr
206  << hline;
207 
208  for (const auto& mn : fUniqueModuleNames) {
209 
210  auto& mod = GetModule(mn);
211 
212  auto& stopwatch = mod.GetStopwatch();
213  const double moduleUTime = stopwatch.GetCPUTime(Stopwatch::eUser) / second;
214  const double moduleSTime = stopwatch.GetCPUTime(Stopwatch::eSystem) / second;
215  moduleUTimeSum += moduleUTime;
216  moduleSTimeSum += moduleSTime;
217  const double frac = round(1000*(moduleUTime + moduleSTime) / totalTime) / 10;
218 
219  tab << mn << endc << moduleUTime << endc << moduleSTime << endc << frac << endr;
220 
221  cerr << "--> Running Finish() of module '" << mn << "'\n";
222 
223  const auto flag = mod.Finish();
224 
225  cerr << "--> Finished Finish() of module '" << mn << "', "
226  "status: " << VModule::GetResultFlagByName(flag) << '\n';
227 
228  if (flag == VModule::eFailure)
229  failureMessage << (failureMessage.str().empty() ? "" : "\n")
230  << "Received failure message from Finish() of module: " << mn;
231  }
232 
233  const auto failureStr = failureMessage.str();
234  if (!failureStr.empty())
235  ERROR(failureStr);
236 
237  if (!fRunData.GetNamedCounters().empty()) {
238  TabularStream tab("r: r");
239  tab << "Item" << endc << "Count" << endr
240  << hline;
241  for (const auto& c : fRunData.GetNamedCounters())
242  tab << c.first << endc << c.second << endr;
243  tab << delr;
244  INFO("Performance counters:\n" + tab.Str());
245  }
246 
247  const double frac = round(1000*(moduleUTimeSum + moduleSTimeSum) / totalTime) / 10;
248  tab << hline
249  << "All modules" << endc << moduleUTimeSum << endc
250  << moduleSTimeSum << endc << frac << endr
251  << "Total" << endc << totalUTime << endc << totalSTime << endc << 100;
252  ostringstream info;
253  info << "\n\nCPU user and system time in Module::Run()\n"
254  << tab << '\n';
255  const double time = fRealTimeStopwatch.Stop();
256  info << "Total real time of the run: " << time/second << " s";
257  INFO(info);
258 
259  if (!failureStr.empty())
260  throw utl::ModuleSequenceException(failureStr);
261  }
262 
263 
264  string
266  {
267  switch (status) {
268  case eNoBreak: return "eNoBreak";
269  case eBreak: return "eBreak";
270  case eContinue: return "eContinue";
271  default: return "Unknown";
272  }
273  }
274 
275 
276  // Sequence the modules (call their Run methods)
277  // according to the sequence specified in the XML file.
278  void
280  {
281  Branch modControl = currentB.GetChild("moduleControl");
282 
283  if (!modControl) {
284  INFO("No <moduleControl> tag was found in the module sequencing file. No sequencing will be done.");
285  return;
286  }
287 
288  for (Branch cb = modControl.GetFirstChild(); cb; cb = cb.GetNextSibling()) {
289  const auto status = DoNextInSequence(cb);
290  if (status != eNoBreak) {
291  ostringstream err;
292  err << "Module sequence cannot handle the " << GetBreakStatusByName(status) << " return value. "
293  "Please, fix your module sequence.";
294  ERROR(err);
295  throw utl::ModuleSequenceException(err.str());
296  }
297  }
298  }
299 
300 
301  // Invoke Run method the appropriate number of times
302  // for the next module in the sequence (recursive)
305  {
306  if (!currentB)
307  return eNoBreak; // null branch
308 
309  if (currentB.GetName() == "loop" ||
310  currentB.GetName() == "try") {
311 
312  bool unboundedLoopFlag = false; // true if user requests an unbounded loop,
313  int loopInt = 1; // otherwise, loop this number of times.
314  const auto& attMap = currentB.GetAttributes();
315  const auto attEnd = attMap.end();
316 
317  const auto numTimesIt = attMap.find("numTimes");
318  if (numTimesIt != attEnd) {
319  if (StringEquivalent(numTimesIt->second, "unbounded"))
320  unboundedLoopFlag = true;
321  else
322  loopInt = boost::lexical_cast<int>(numTimesIt->second);
323  }
324 
325  // Allow the tag to be called either save or pushEventToStack
326  const auto pushEventToStackIt = attMap.find("pushEventToStack");
327  const auto saveIt = attMap.find("save");
328 
329  bool saveFlag = false;
330 
331  if (saveIt != attEnd) {
332 
333  ostringstream warn;
334  warn << "The 'save' loop attribute is deprecated (people find it unclear). "
335  "Please use 'pushEventToStack' instead.";
336  WARNING(warn);
337 
338  // this error can probably be encoded with xsd
339  if (pushEventToStackIt != attEnd) {
340  ostringstream err;
341  err << "You can have either a 'save' or 'pushEventToStack' attribute"
342  "in the loop tag, but not both.";
343  ERROR(err);
344  throw utl::ModuleSequenceException(err.str());
345  }
346 
347  if (StringEquivalent(saveIt->second, "yes"))
348  saveFlag = true;
349 
350  }
351 
352  if (pushEventToStackIt != attEnd &&
353  StringEquivalent(pushEventToStackIt->second, "yes"))
354  saveFlag = true;
355 
356  evt::Event* const savedEvent = saveFlag ? new evt::Event(*fCurEvent) : nullptr;
357 
358  for (int iLoop = 0; unboundedLoopFlag || iLoop < loopInt; ++iLoop) {
359 
360  if (iLoop && savedEvent)
361  *fCurEvent = *savedEvent;
362 
363  BreakStatus innerBreakStatus = eNoBreak;
364  for (Branch cb = currentB.GetFirstChild(); cb; cb = cb.GetNextSibling()) {
365  const auto outerBreakStatus = DoNextInSequence(cb); // doing next in the sequence (recursive)
366  if (outerBreakStatus == eBreak) {
367  innerBreakStatus = eBreak;
368  break;
369  } else if (outerBreakStatus == eContinue)
370  break;
371  }
372 
373  if (innerBreakStatus == eBreak)
374  break;
375 
376  }
377 
378  delete savedEvent;
379  return eNoBreak;
380 
381  } else if (currentB.GetName() == "module") {
382 
383  string modName;
384  currentB.GetData(modName);
385 
386  cerr << "--> Running Run() of module '" << modName << "'\n";
387 
388  // store the module name so that it can be queried
389  fCurrentModule = modName;
390 
391  // run the module
392  const auto status = GetModule(modName).RunWithTiming(*fCurEvent);
393 
394  cerr << "--> Finished running module '" << modName << "' "
395  "with status " << VModule::GetResultFlagByName(status) << '\n';
396 
397  if (status == VModule::eFailure) {
398  cerr << " +--> Calling Finish() methods of all modules\n";
399  Finish();
400  throw utl::ModuleSequenceException("Module sequence failure");
401  }
402 
403  switch (status) {
404  case VModule::eBreakLoop: return eBreak;
405  case VModule::eContinueLoop: return eContinue;
406  default: return eNoBreak;
407  }
408 
409  } else {
410 
411  ostringstream err;
412  err << "Encountered a Branch in XML file with name <" << currentB.GetName() << ">. "
413  "RunController can only process Branches called <loop> or <module>.";
414  ERROR(err);
415  throw utl::ModuleSequenceException("unknown branch");
416 
417  }
418 
419  return eNoBreak;
420  }
421 
422 
424  {
425  delete fCurEvent;
426 
427  ErrorLogger::GetInstance().WriteErrorMessagesToStream();
428  }
429 
430 }
bool HasModule(const std::string &moduleName) const
std::set< std::string > fUsedModuleNames
Definition: RunController.h:79
std::string GetRegisteredModuleNames() const
Get list of all module builder names and module versions in the registry.
Base class for all exceptions used in the auger offline code.
virtual void Init()
Skip remaining modules in the current loop and continue with next iteration of the loop...
Definition: VModule.h:68
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
Exception to use in case of module sequencing failures.
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
static Iterator Begin()
Begin iterator over the internal map (read only)
int exit
Definition: dump1090.h:237
void RunBranch(utl::Branch &currentB)
bool StringEquivalent(const std::string &a, const std::string &b, Predicate p)
Utility to compare strings for equivalence. It takes a predicate to determine the equivalence of indi...
Definition: StringCompare.h:38
T Get() const
Definition: Branch.h:271
AttributeMap GetAttributes() const
Get a map&lt;string, string&gt; containing all the attributes of this Branch.
Definition: Branch.cc:267
Branch GetNextSibling() const
Get next sibling of this branch.
Definition: Branch.cc:284
ResultFlag RunWithTiming(evt::Event &event)
Definition: VModule.h:98
static std::string GetBreakStatusByName(const BreakStatus status)
Class representing a document branch.
Definition: Branch.h:107
Break current loop. It works for nested loops too!
Definition: VModule.h:66
const EndRow endr
const double second
Definition: GalacticUnits.h:32
const int tab
Definition: SdInspector.cc:35
static std::string GetResultFlagByName(const ResultFlag flag)
Definition: VModule.cc:8
class to format data in tabular form
static Iterator End()
End iterator over the internal map (read only)
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
static unsigned int GetNumberOfCreators()
Get number of object types know to this factory.
Definition: ObjectFactory.h:98
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
std::string GetName() const
function to get the Branch name
Definition: Branch.cc:374
Module interface.
Definition: VModule.h:53
int GetNumberOfRegisteredModules() const
Return number of registered modules.
void DoRunSequence(utl::Branch &currentB)
std::string Str()
evt::Event * fCurEvent
Definition: RunController.h:81
void GetNextModuleName(utl::Branch &currentB)
std::string fCurrentModule
Definition: RunController.h:85
virtual void Finish()
const DeleteRow delr
static CentralConfig * GetInstance()
Use this the first time you get an instance of central configuration.
Report failure to RunController, causing RunController to terminate execution.
Definition: VModule.h:64
Main configuration utility.
Definition: CentralConfig.h:51
void FinishBranch(utl::Branch &currentB)
utl::RealTimeStopwatch fRealTimeStopwatch
Definition: RunController.h:84
Branch GetFirstChild() const
Get first child of this Branch.
Definition: Branch.cc:98
double Stop()
returns time since last call to Start()
void InitBranch(utl::Branch &currentB)
double GetCPUTime(const CPUTime kind=eTotal)
Definition: Stopwatch.cc:52
double mod(const double d, const double periode)
NamedCounters & GetNamedCounters()
Definition: RunData.h:23
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
const HLine hline('-')
virtual ~RunController()
utl::Stopwatch fStopwatch
Definition: RunController.h:83
const EndColumn endc
virtual void Run()
const std::string & GetMessage() const
Retrieve the message from the exception.
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)
std::set< std::string > fUniqueModuleNames
Definition: RunController.h:77
static ObjectPtrType Create(const IdentifierType &id)
Create an object (0-argument constructor)
VModule & GetModule(const std::string &moduleName) const
Get module by name.
BreakStatus DoNextInSequence(utl::Branch &currentB)

, generated on Tue Sep 26 2023.