]> git.uio.no Git - u/mrichter/AliRoot.git/blame - HLT/trigger/AliHLTGlobalTriggerComponent.cxx
Updated DA documentation + correct location of OCDB snapshot, agreed with Barth.
[u/mrichter/AliRoot.git] / HLT / trigger / AliHLTGlobalTriggerComponent.cxx
CommitLineData
3da1c6d7 1// $Id$
1b9a175e 2/**************************************************************************
3 * This file is property of and copyright by the ALICE HLT Project *
4 * ALICE Experiment at CERN, All rights reserved. *
5 * *
6 * Primary Authors: Artur Szostak <artursz@iafrica.com> *
7 * for The ALICE HLT Project. *
8 * *
9 * Permission to use, copy, modify and distribute this software and its *
10 * documentation strictly for non-commercial purposes is hereby granted *
11 * without fee, provided that the above copyright notice appears in all *
12 * copies and that both the copyright notice and this permission notice *
13 * appear in the supporting documentation. The authors make no claims *
14 * about the suitability of this software for any purpose. It is *
15 * provided "as is" without express or implied warranty. *
16 **************************************************************************/
17
18/// @file AliHLTGlobalTriggerComponent.cxx
19/// @author Artur Szostak <artursz@iafrica.com>
20/// @date 26 Nov 2008
21/// @brief Implementation of the AliHLTGlobalTriggerComponent component class.
22///
23/// The AliHLTGlobalTriggerComponentComponent class applies the global HLT trigger to all
24/// trigger information produced by components deriving from AliHLTTrigger.
25
26#include "AliHLTGlobalTriggerComponent.h"
e2bb8ddd 27#include "AliHLTGlobalTriggerDecision.h"
28#include "AliHLTGlobalTrigger.h"
52f67e50 29#include "AliHLTGlobalTriggerConfig.h"
30#include "AliHLTTriggerMenu.h"
474952b2 31#include "AliHLTCTPData.h"
3da1c6d7 32#include "AliCDBManager.h"
33#include "AliCDBStorage.h"
34#include "AliCDBEntry.h"
e2bb8ddd 35#include "TUUID.h"
36#include "TROOT.h"
72bc5ab0 37#include "TSystem.h"
52f67e50 38#include "TRegexp.h"
39#include "TClonesArray.h"
40#include "TObjString.h"
1b820a65 41#include "TString.h"
52f67e50 42#include "TInterpreter.h"
d4ed5215 43#include "TDatime.h"
81d62bb4 44#include "TClass.h"
e2bb8ddd 45#include <fstream>
46#include <cerrno>
566a01d0 47#include <cassert>
81d62bb4 48#include <vector>
49#include <algorithm>
1b9a175e 50
51ClassImp(AliHLTGlobalTriggerComponent)
52
3da1c6d7 53const char* AliHLTGlobalTriggerComponent::fgkTriggerMenuCDBPath = "HLT/ConfigHLT/HLTGlobalTrigger";
54
1b9a175e 55
81d62bb4 56namespace
57{
58 /**
59 * This method is used as a comparison functor with the STL sort routines.
60 */
61 bool AliHLTDescendingNumbers(UInt_t a, UInt_t b)
62 {
63 return a > b;
64 }
65} // end of namespace
66
67
1b9a175e 68AliHLTGlobalTriggerComponent::AliHLTGlobalTriggerComponent() :
e2bb8ddd 69 AliHLTTrigger(),
52f67e50 70 fTrigger(NULL),
72bc5ab0 71 fDebugMode(false),
566a01d0 72 fRuntimeCompile(true),
73 fSkipCTPCounters(false),
81d62bb4 74 fDeleteCodeFile(false),
566a01d0 75 fCodeFileName(),
81d62bb4 76 fClassName(),
77 fCTPDecisions(NULL),
78 fBufferSizeConst(2*(sizeof(AliHLTGlobalTriggerDecision) + sizeof(AliHLTReadoutList))),
79 fBufferSizeMultiplier(1.),
80 fIncludePaths(TObjString::Class()),
1b820a65 81 fIncludeFiles(TObjString::Class()),
82 fLibStateAtLoad()
1b9a175e 83{
84 // Default constructor.
acc7214e 85
86 ClearInfoForNewEvent(false);
1b9a175e 87}
88
89
90AliHLTGlobalTriggerComponent::~AliHLTGlobalTriggerComponent()
91{
92 // Default destructor.
e2bb8ddd 93
94 if (fTrigger != NULL) delete fTrigger;
566a01d0 95
96 if (fCTPDecisions) {
97 fCTPDecisions->Delete();
98 delete fCTPDecisions;
99 }
1b9a175e 100}
101
102
025443e0 103void AliHLTGlobalTriggerComponent::GetOutputDataTypes(AliHLTComponentDataTypeList& list) const
104{
105 // Returns the kAliHLTDataTypeGlobalTrigger type as output.
106 list.push_back(kAliHLTDataTypeGlobalTrigger);
107}
108
109
1b9a175e 110void AliHLTGlobalTriggerComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
111{
112 // Returns the output data size estimate.
113
81d62bb4 114 constBase = fBufferSizeConst;
115 inputMultiplier = fBufferSizeMultiplier;
1b9a175e 116}
117
118
52f67e50 119Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
1b9a175e 120{
e2bb8ddd 121 // Initialises the global trigger component.
122
52f67e50 123 fDebugMode = false;
81d62bb4 124 fClassName = "";
125 fCodeFileName = "";
126 fDeleteCodeFile = false;
52f67e50 127 const char* configFileName = NULL;
128 const char* codeFileName = NULL;
81d62bb4 129 fIncludePaths.Clear();
130 fIncludeFiles.Clear();
52f67e50 131
132 for (int i = 0; i < argc; i++)
133 {
134 if (strcmp(argv[i], "-config") == 0)
135 {
136 if (configFileName != NULL)
137 {
138 HLTWarning("Trigger configuration macro was already specified."
139 " Will replace previous value given by -config."
140 );
141 }
142 if (argc <= i+1)
143 {
144 HLTError("The trigger configuration macro filename was not specified." );
145 return -EINVAL;
146 }
147 configFileName = argv[i+1];
148 i++;
149 continue;
150 }
151
152 if (strcmp(argv[i], "-includepath") == 0)
153 {
154 if (argc <= i+1)
155 {
156 HLTError("The include path was not specified." );
157 return -EINVAL;
158 }
81d62bb4 159 new (fIncludePaths[fIncludePaths.GetEntriesFast()]) TObjString(argv[i+1]);
52f67e50 160 i++;
161 continue;
162 }
163
164 if (strcmp(argv[i], "-include") == 0)
165 {
166 if (argc <= i+1)
167 {
168 HLTError("The include file name was not specified." );
169 return -EINVAL;
170 }
81d62bb4 171 new (fIncludeFiles[fIncludeFiles.GetEntriesFast()]) TObjString(argv[i+1]);
52f67e50 172 i++;
173 continue;
174 }
175
176 if (strcmp(argv[i], "-debug") == 0)
177 {
178 if (fDebugMode == true)
179 {
180 HLTWarning("The debug flag was already specified. Ignoring this instance.");
181 }
182 fDebugMode = true;
566a01d0 183 continue;
184 }
185
186 if (strcmp(argv[i], "-cint") == 0)
187 {
188 fRuntimeCompile = false;
52f67e50 189 continue;
190 }
191
192 if (strcmp(argv[i], "-usecode") == 0)
193 {
194 if (codeFileName != NULL)
195 {
196 HLTWarning("Custom trigger code file was already specified."
197 " Will replace previous value given by -usecode."
198 );
199 }
200 if (argc <= i+1)
201 {
202 HLTError("The custom trigger code filename was not specified." );
203 return -EINVAL;
204 }
205 codeFileName = argv[i+1];
206 if (argc <= i+2)
207 {
208 HLTError("The custom trigger class name was not specified." );
209 return -EINVAL;
210 }
81d62bb4 211 fClassName = argv[i+2];
52f67e50 212 i += 2;
213 continue;
214 }
474952b2 215
216 if (strcmp(argv[i], "-skipctp") == 0)
217 {
218 HLTInfo("Skipping CTP counters in trigger decision");
566a01d0 219 fSkipCTPCounters=true;
474952b2 220 continue;
221 }
222
52f67e50 223 HLTError("Unknown option '%s'.", argv[i]);
224 return -EINVAL;
225 } // for loop
226
227 const AliHLTTriggerMenu* menu = NULL;
228 if (configFileName != NULL)
229 {
230 TString cmd = ".x ";
231 cmd += configFileName;
232 gROOT->ProcessLine(cmd);
233 menu = AliHLTGlobalTriggerConfig::Menu();
234 }
235
3da1c6d7 236 // Try load the trigger menu from the CDB if it is not loaded yet with the
237 // -config option
81d62bb4 238 int result = -ENOENT;
239 if (menu == NULL)
3da1c6d7 240 {
81d62bb4 241 result = LoadTriggerMenu(fgkTriggerMenuCDBPath, menu);
3da1c6d7 242 }
52f67e50 243 if (menu == NULL)
244 {
245 HLTError("No trigger menu configuration found or specified.");
81d62bb4 246 return result;
52f67e50 247 }
248
52f67e50 249 if (codeFileName == NULL)
250 {
81d62bb4 251 result = GenerateTrigger(menu, fClassName, fCodeFileName, fIncludePaths, fIncludeFiles);
252 if (result == 0) fDeleteCodeFile = true;
52f67e50 253 }
254 else
255 {
81d62bb4 256 result = LoadTriggerClass(codeFileName, fIncludePaths);
257 if (result == 0) fCodeFileName = codeFileName;
52f67e50 258 }
e2bb8ddd 259 if (result != 0) return result;
260
81d62bb4 261 fTrigger = AliHLTGlobalTrigger::CreateNew(fClassName.Data());
e2bb8ddd 262 if (fTrigger == NULL)
263 {
81d62bb4 264 HLTError("Could not create a new instance of '%s'.", fClassName.Data());
e2bb8ddd 265 return -EIO;
266 }
267
52f67e50 268 fTrigger->FillFromMenu(*menu);
325e5e42 269 if (fTrigger->CallFailed()) return -EPROTO;
474952b2 270
271 // setup the CTP accounting in AliHLTComponent
566a01d0 272 SetupCTPData();
474952b2 273
acc7214e 274 // Set the default values from the trigger menu.
275 SetDescription(menu->DefaultDescription());
276 SetTriggerDomain(menu->DefaultTriggerDomain());
277
e2bb8ddd 278 return 0;
279}
280
1b9a175e 281
e2bb8ddd 282Int_t AliHLTGlobalTriggerComponent::DoDeinit()
283{
284 // Cleans up the global trigger component.
285
286 if (fTrigger != NULL)
287 {
288 delete fTrigger;
289 fTrigger = NULL;
290 }
291
566a01d0 292 if (fCTPDecisions) {
293 fCTPDecisions->Delete();
294 delete fCTPDecisions;
295 }
296 fCTPDecisions=NULL;
81d62bb4 297
298 Int_t result = UnloadTriggerClass(fCodeFileName);
299 if (result != 0) return result;
300
301 if (fDeleteCodeFile and !fCodeFileName.IsNull() && gSystem->AccessPathName(fCodeFileName)==0 && !fDebugMode) {
302 fCodeFileName.ReplaceAll(".cxx", "*");
303 TString command="rm "; command+=fCodeFileName;
304 gSystem->Exec(command);
305 }
306 fCodeFileName="";
307 fDeleteCodeFile=false;
566a01d0 308
1b9a175e 309 return 0;
310}
4f1d6b68 311
312
313AliHLTComponent* AliHLTGlobalTriggerComponent::Spawn()
314{
315 // Creates a new object instance.
316
317 return new AliHLTGlobalTriggerComponent;
318}
319
e2bb8ddd 320
321int AliHLTGlobalTriggerComponent::DoTrigger()
322{
323 // This method will apply the global trigger decision.
324
325 if (fTrigger == NULL)
326 {
327 HLTFatal("Global trigger implementation object is NULL!");
328 return -EIO;
329 }
2974f8dc 330
331 AliHLTUInt32_t eventType=0;
332 if (!IsDataEvent(&eventType)) {
333 if (eventType==gkAliEventTypeEndOfRun) PrintStatistics(fTrigger, kHLTLogImportant, 0);
334 return 0;
335 }
336
81d62bb4 337 // Copy the trigger counters in case we need to set them back to their original
338 // value because the PushBack method fails with ENOSPC.
339 TArrayL64 originalCounters = fTrigger->GetCounters();
325e5e42 340 if (fTrigger->CallFailed()) return -EPROTO;
81d62bb4 341
e2bb8ddd 342 fTrigger->NewEvent();
325e5e42 343 if (fTrigger->CallFailed()) return -EPROTO;
e2bb8ddd 344
345 // Fill in the input data.
346 const TObject* obj = GetFirstInputObject();
347 while (obj != NULL)
52f67e50 348 {
349 fTrigger->Add(obj, GetDataType(), GetSpecification());
325e5e42 350 if (fTrigger->CallFailed()) return -EPROTO;
52f67e50 351 obj = GetNextInputObject();
352 }
353
a489a8dd 354 // add trigger decisions for every CTP class
355 const AliHLTCTPData* pCTPData=CTPData();
356 if (pCTPData) {
566a01d0 357 AddCTPDecisions(fTrigger, pCTPData, GetTriggerData());
a489a8dd 358 }
359
52f67e50 360 // Calculate the global trigger result and trigger domain, then create and push
361 // back the new global trigger decision object.
362 TString description;
acc7214e 363 AliHLTTriggerDomain triggerDomain;
364 bool triggerResult = fTrigger->CalculateTriggerDecision(triggerDomain, description);
325e5e42 365 if (fTrigger->CallFailed()) return -EPROTO;
acc7214e 366 AliHLTGlobalTriggerDecision decision(
367 triggerResult,
368 // The following will cause the decision to be generated with default values
369 // (set in fTriggerDomain and fDescription) if the trigger result is false.
370 (triggerResult == true) ? triggerDomain : GetTriggerDomain(),
371 (triggerResult == true) ? description.Data() : GetDescription()
372 );
48d98db9 373
374 // mask the readout list according to the CTP trigger
375 // if the classes have been initialized (mask non-zero)
48d98db9 376 if (pCTPData && pCTPData->Mask()) {
377 AliHLTEventDDL eventDDL=pCTPData->ReadoutList(*GetTriggerData());
378 AliHLTReadoutList ctpreadout(eventDDL);
45398383 379 ctpreadout.Enable(AliHLTReadoutList::kHLT);
380 AliHLTReadoutList maskedList=decision.ReadoutList();
381 maskedList.AndEq(ctpreadout);
382 decision.ReadoutList(maskedList);
48d98db9 383 }
384
81d62bb4 385 decision.SetCounters(fTrigger->GetCounters(), GetEventCount()+1);
325e5e42 386 if (fTrigger->CallFailed()) return -EPROTO;
387
d4ed5215 388 static UInt_t lastTime=0;
389 TDatime time;
390 if (time.Get()-lastTime>5) {
391 lastTime=time.Get();
2974f8dc 392 PrintStatistics(fTrigger);
d4ed5215 393 }
52f67e50 394
395 // Add the input objects used to the global decision.
396 obj = GetFirstInputObject();
397 while (obj != NULL)
e2bb8ddd 398 {
399 if (obj->IsA() == AliHLTTriggerDecision::Class())
400 {
52f67e50 401 decision.AddTriggerInput( *static_cast<const AliHLTTriggerDecision*>(obj) );
e2bb8ddd 402 }
403 else
404 {
52f67e50 405 decision.AddInputObject(obj);
e2bb8ddd 406 }
407 obj = GetNextInputObject();
408 }
2974f8dc 409
566a01d0 410 if (!fSkipCTPCounters && CTPData()) decision.AddInputObject(CTPData());
474952b2 411
2974f8dc 412 CreateEventDoneReadoutFilter(decision.TriggerDomain(), 3);
413 CreateEventDoneReadoutFilter(decision.TriggerDomain(), 4);
025443e0 414 if (TriggerEvent(&decision, kAliHLTDataTypeGlobalTrigger) == -ENOSPC)
81d62bb4 415 {
416 // Increase the estimated buffer space required if the PushBack methods in TriggerEvent
417 // returned the "no buffer space" error code. Also remember to set the trigger counters
418 // back to what they were, otherwise triggers will be double counted when we try to reprocess
419 // this event with larger buffers.
420 fBufferSizeConst += 1024*1024;
421 fBufferSizeMultiplier *= 2.;
422 fTrigger->SetCounters(originalCounters);
325e5e42 423 if (fTrigger->CallFailed()) return -EPROTO;
81d62bb4 424 return -ENOSPC;
425 }
426 return 0;
427}
428
429
430int AliHLTGlobalTriggerComponent::Reconfigure(const char* cdbEntry, const char* chainId)
431{
432 // Reconfigure the component by loading the trigger menu and recreating the
433 // trigger logic class.
434
435 const char* path = fgkTriggerMenuCDBPath;
436 const char* id = "(unknown)";
437 if (cdbEntry != NULL) path = cdbEntry;
438 if (chainId != NULL and chainId[0] != '\0') id = chainId;
439 HLTInfo("Reconfiguring from '%s' for chain component '%s'.", path, id);
440
441 const AliHLTTriggerMenu* menu = NULL;
442 int result = LoadTriggerMenu(path, menu);
443 if (result != 0) return result;
444
445 TString className;
446 TString codeFileName;
447 result = GenerateTrigger(menu, className, codeFileName, fIncludePaths, fIncludeFiles);
448 if (result != 0) return result;
449
450 AliHLTGlobalTrigger* trigger = AliHLTGlobalTrigger::CreateNew(className.Data());
451 if (trigger == NULL)
452 {
453 HLTError("Could not create a new instance of '%s'.", className.Data());
454 // Make sure to cleanup after the new code file.
455 UnloadTriggerClass(codeFileName);
456 if (not codeFileName.IsNull() and gSystem->AccessPathName(codeFileName)==0 and not fDebugMode)
457 {
458 codeFileName.ReplaceAll(".cxx", "*");
459 TString command="rm "; command+=codeFileName;
460 gSystem->Exec(command);
461 }
462 return -EIO;
463 }
464
465 if (fTrigger != NULL)
466 {
467 delete fTrigger;
468 fTrigger = NULL;
469 }
470
471 fTrigger = trigger;
472 fTrigger->FillFromMenu(*menu);
325e5e42 473 if (fTrigger->CallFailed()) return -EPROTO;
81d62bb4 474
475 // Set the default values from the trigger menu.
476 SetDescription(menu->DefaultDescription());
477 SetTriggerDomain(menu->DefaultTriggerDomain());
478
479 // Cleanup the old class code.
480 UnloadTriggerClass(fCodeFileName);
481 if (fDeleteCodeFile and not fCodeFileName.IsNull() and gSystem->AccessPathName(fCodeFileName)==0 and not fDebugMode)
482 {
483 fCodeFileName.ReplaceAll(".cxx", "*");
484 TString command="rm "; command+=fCodeFileName;
485 gSystem->Exec(command);
486 }
487 fCodeFileName = codeFileName;
488 fDeleteCodeFile = true; // Since we generated a new class.
489
490 return 0;
491}
492
493
494int AliHLTGlobalTriggerComponent::LoadTriggerMenu(const char* cdbPath, const AliHLTTriggerMenu*& menu)
495{
496 // Loads the trigger menu object from the CDB path.
497
498 HLTDebug("Trying to load trigger menu from '%s'.", cdbPath);
499 if (AliCDBManager::Instance() == NULL)
500 {
501 HLTError("CDB manager object not found.");
502 return -EIO;
503 }
504 AliCDBStorage* store = AliCDBManager::Instance()->GetDefaultStorage();
505 if (store == NULL)
506 {
507 HLTError("Could not get the the default storage for the CDB.");
508 return -EIO;
509 }
510 Int_t version = store->GetLatestVersion(cdbPath, GetRunNo());
511 Int_t subVersion = store->GetLatestSubVersion(cdbPath, GetRunNo(), version);
512 AliCDBEntry* entry = AliCDBManager::Instance()->Get(cdbPath, GetRunNo(), version, subVersion);
513 if (entry == NULL)
514 {
515 HLTError("Could not get the CDB entry for \"%s\".", cdbPath);
516 return -EIO;
517 }
518 TObject* obj = entry->GetObject();
519 if (obj == NULL)
520 {
521 HLTError("Configuration object for \"%s\" is missing.", cdbPath);
522 return -ENOENT;
523 }
524 if (obj->IsA() != AliHLTTriggerMenu::Class())
525 {
526 HLTError("Wrong type for configuration object in \"%s\". Found a %s but we expect a AliHLTTriggerMenu.",
527 cdbPath, obj->ClassName()
528 );
529 return -EPROTO;
530 }
531 menu = static_cast<AliHLTTriggerMenu*>(obj);
e2bb8ddd 532 return 0;
533}
534
535
52f67e50 536int AliHLTGlobalTriggerComponent::GenerateTrigger(
81d62bb4 537 const AliHLTTriggerMenu* menu, TString& name, TString& filename,
52f67e50 538 const TClonesArray& includePaths, const TClonesArray& includeFiles
539 )
e2bb8ddd 540{
541 // Generates the global trigger class that will implement the specified trigger menu.
52f67e50 542 // See header for more details.
e2bb8ddd 543
81d62bb4 544 HLTDebug("Generating custom HLT trigger class named %s using trigger menu %p.", ((void*)menu), name.Data());
545
e2bb8ddd 546 // Create a new UUID and replace the '-' characters with '_' to make it a valid
547 // C++ symbol name.
548 TUUID uuid;
549 TString uuidstr = uuid.AsString();
550 for (Int_t i = 0; i < uuidstr.Length(); i++)
551 {
552 if (uuidstr[i] == '-') uuidstr[i] = '_';
553 }
554
555 // Create the name of the new class.
556 name = "AliHLTGlobalTriggerImpl_";
557 name += uuidstr;
81d62bb4 558 filename = name + ".cxx";
e2bb8ddd 559
52f67e50 560 // Open a text file to write the code and generate the new class.
81d62bb4 561 fstream code(filename.Data(), ios_base::out | ios_base::trunc);
e2bb8ddd 562 if (not code.good())
563 {
81d62bb4 564 HLTError("Could not open file '%s' for writing.", filename.Data());
e2bb8ddd 565 return -EIO;
566 }
567
52f67e50 568 TClonesArray symbols(AliHLTTriggerMenuSymbol::Class());
569 int result = BuildSymbolList(menu, symbols);
570 if (result != 0) return result;
571
81d62bb4 572 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
52f67e50 573 code << "#include <cstring>" << endl;
574 code << "#include \"TString.h\"" << endl;
575 code << "#include \"TClonesArray.h\"" << endl;
81d62bb4 576 code << "#include \"AliHLTLogging.h\"" << endl;
e2bb8ddd 577 code << "#include \"AliHLTGlobalTrigger.h\"" << endl;
578 code << "#include \"AliHLTGlobalTriggerDecision.h\"" << endl;
52f67e50 579 code << "#include \"AliHLTDomainEntry.h\"" << endl;
580 code << "#include \"AliHLTTriggerDomain.h\"" << endl;
581 code << "#include \"AliHLTReadoutList.h\"" << endl;
582 code << "#include \"AliHLTTriggerMenu.h\"" << endl;
583 code << "#include \"AliHLTTriggerMenuItem.h\"" << endl;
584 code << "#include \"AliHLTTriggerMenuSymbol.h\"" << endl;
585
586 // Add any include files that were specified on the command line.
587 for (Int_t i = 0; i < includeFiles.GetEntriesFast(); i++)
588 {
7da191b6 589 TString file = static_cast<TObjString*>(includeFiles.UncheckedAt(i))->String();
52f67e50 590 code << "#include \"" << file.Data() << "\"" << endl;
591 }
592
81d62bb4 593 if (fDebugMode)
594 {
595 code << "#else" << endl;
596 code << "const char* gFunctionName = \"???\";" << endl;
597 code << "#define HLTDebug(msg) if (CheckFilter(kHLTLogDebug) && CheckGroup(Class_Name())) SendMessage(kHLTLogDebug, Class_Name(), ::gFunctionName, __FILE__, __LINE__, msg)" << endl;
598 }
599 code << "#endif" << endl;
600
601 code << "class " << name << " :" << endl;
602 // Add appropriate #ifdef sections since we need to prevent inheritance from
603 // AliHLTGlobalTrigger. CINT does not seem to support multiple inheritance nor
604 // multiple levels of inheritance. Neither of the following schemes worked:
605 //
606 // 1) class AliHLTGlobalTrigger : public AliHLTLogging {};
607 // class AliHLTGlobalTriggerImpl_xyz : public AliHLTGlobalTrigger {};
608 //
609 // 2) class AliHLTGlobalTrigger {};
610 // class AliHLTGlobalTriggerImpl_xyz : public AliHLTGlobalTrigger, public AliHLTLogging {};
611 //
612 // Thus, we are forced to just inherit from AliHLTLogging when running in the CINT
613 // interpreter. But we anyway have to call the global trigger implementation class
614 // through the AliHLTGlobalTriggerWrapper so this is not such a problem.
615 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
616 code << " public AliHLTGlobalTrigger," << endl;
617 code << "#endif" << endl;
618 code << " public AliHLTLogging" << endl;
e2bb8ddd 619 code << "{" << endl;
620 code << "public:" << endl;
52f67e50 621
81d62bb4 622 // Generate constructor method.
623 code << " " << name << "() :" << endl;
624 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
625 code << " AliHLTGlobalTrigger()," << endl;
626 code << "#endif" << endl;
627 code << " AliHLTLogging()";
52f67e50 628 // Write the symbols in the trigger menu in the initialisation list.
629 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
630 {
631 code << "," << endl;
632 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
633 code << " " << symbol->Name() << "()," << endl;
634 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
635 {
636 code << " " << symbol->Name() << "TriggerDomain()," << endl;
637 }
638 code << " " << symbol->Name() << "DomainEntry(kAliHLTAnyDataType)";
639 }
640 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
641 {
642 code << "," << endl << " fMenuItemDescription" << i << "()";
643 }
644 code << endl << " {" << endl;
645 if (fDebugMode)
646 {
81d62bb4 647 code << "#ifdef __CINT__" << endl;
648 code << " gFunctionName = \"" << name.Data() <<"\";" << endl;
649 code << "#endif" << endl;
52f67e50 650 code << " SetLocalLoggingLevel(kHLTLogAll);" << endl;
81d62bb4 651 code << " HLTDebug(Form(\"Creating new instance at %p.\", this));" << endl;
52f67e50 652 }
e2bb8ddd 653 code << " }" << endl;
52f67e50 654
e2bb8ddd 655 code << " virtual ~" << name << "() {" << endl;
52f67e50 656 if (fDebugMode)
657 {
81d62bb4 658 code << "#ifdef __CINT__" << endl;
659 code << " gFunctionName = \"~" << name.Data() << "\";" << endl;
660 code << "#endif" << endl;
661 code << " HLTDebug(Form(\"Deleting instance at %p.\", this));" << endl;
52f67e50 662 }
e2bb8ddd 663 code << " }" << endl;
52f67e50 664
665 // Generate the FillFromMenu method.
666 code << " virtual void FillFromMenu(const AliHLTTriggerMenu& menu) {" << endl;
667 if (fDebugMode)
668 {
81d62bb4 669 code << "#ifdef __CINT__" << endl;
670 code << " gFunctionName = \"FillFromMenu\";" << endl;
671 code << "#endif" << endl;
672 code << " HLTDebug(Form(\"Filling description entries from trigger menu for global trigger %p.\", this));" << endl;
52f67e50 673 }
81d62bb4 674 code << " fCounter.Set(menu.NumberOfItems());" << endl;
52f67e50 675 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
676 {
677 code << " fMenuItemDescription" << i << " = (menu.Item(" << i
678 << ") != NULL) ? menu.Item(" << i << ")->Description() : \"\";" << endl;
679 }
680 if (fDebugMode)
681 {
81d62bb4 682 code << " HLTDebug(Form(\"Finished filling description entries from trigger menu.\"));" << endl;
683 code << " HLTDebug(Form(\"Filling domain entries from trigger menu symbols for global trigger %p.\", this));" << endl;
52f67e50 684 }
685 code << " for (Int_t i = 0; i < menu.SymbolArray().GetEntriesFast(); i++) {" << endl;
325e5e42 686 // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
687 // Have to use the TClass system for extra protection.
688 code << " if (menu.SymbolArray().UncheckedAt(i) == NULL) continue;" << endl;
689 code << " if (menu.SymbolArray().UncheckedAt(i)->IsA() != AliHLTTriggerMenuSymbol::Class()) continue;" << endl;
52f67e50 690 code << " const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const"
691 " AliHLTTriggerMenuSymbol*>(menu.SymbolArray().UncheckedAt(i));" << endl;
692 code << " if (symbol == NULL) continue;" << endl;
693 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
694 {
695 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
025443e0 696 code << " if (strcmp(symbol->RealName(), \"" << symbol->RealName() << "\") == 0) {" << endl;
52f67e50 697 if (fDebugMode)
698 {
81d62bb4 699 code << " HLTDebug(Form(\"Assinging domain entry value corresponding with symbol '%s' to '%s'.\","
025443e0 700 " symbol->RealName(), symbol->BlockType().AsString().Data()));" << endl;
52f67e50 701 }
702 code << " " << symbol->Name() << "DomainEntry = symbol->BlockType();" << endl;
703 code << " continue;" << endl;
704 code << " }" << endl;
705 }
706 code << " }" << endl;
707 if (fDebugMode)
708 {
81d62bb4 709 code << " HLTDebug(Form(\"Finished filling domain entries from trigger menu symbols.\"));" << endl;
52f67e50 710 }
e2bb8ddd 711 code << " }" << endl;
52f67e50 712
713 // Generate the NewEvent method.
714 code << " virtual void NewEvent() {" << endl;
715 if (fDebugMode)
716 {
81d62bb4 717 code << "#ifdef __CINT__" << endl;
718 code << " gFunctionName = \"NewEvent\";" << endl;
719 code << "#endif" << endl;
720 code << " HLTDebug(Form(\"New event for global trigger object %p, initialising variables to default values.\", this));" << endl;
52f67e50 721 }
722 // Write code to initialise the symbols in the trigger menu to their default values.
723 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
724 {
725 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
81d62bb4 726 // CINT has problems with the implicit equals operator for complex types, so if
727 // the type has a equals operater we need to write the operator call explicitly.
728 TClass* clas = TClass::GetClass(symbol->Type());
729 if (clas != NULL and clas->GetMethodAny("operator=") != NULL)
730 {
731 code << " " << symbol->Name() << ".operator = (" << symbol->DefaultValue() << ");" << endl;
732 }
733 else
734 {
735 code << " " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
736 }
52f67e50 737 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
738 {
739 code << " " << symbol->Name() << "TriggerDomain.Clear();" << endl;
740 }
741 }
742 if (fDebugMode)
743 {
81d62bb4 744 code << " HLTDebug(Form(\"Finished initialising variables.\"));" << endl;
52f67e50 745 }
e2bb8ddd 746 code << " }" << endl;
52f67e50 747
748 // Generate the Add method.
749 code << " virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
81d62bb4 750 if (fDebugMode)
751 {
752 code << "#ifdef __CINT__" << endl;
753 code << " gFunctionName = \"Add\";" << endl;
754 code << "#endif" << endl;
755 }
52f67e50 756 code << " AliHLTDomainEntry _type_spec_(_type_, _spec_);" << endl;
757 if (fDebugMode)
758 {
81d62bb4 759 code << " HLTDebug(Form(\"Adding TObject %p, with class name '%s' from data block"
52f67e50 760 " '%s', to global trigger object %p\", _object_, _object_->ClassName(),"
81d62bb4 761 " _type_spec_.AsString().Data(), this));" << endl;
52f67e50 762 code << " _object_->Print();" << endl;
763 code << " bool _object_assigned_ = false;" << endl;
764 }
765 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
766 {
767 // Write code to check if the block type, specification and class name is correct.
768 // Then write code to assign the variable from the input object.
769 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
770 TString expr = symbol->AssignExpression();
771 if (expr == "") continue; // Skip entries that have no assignment expression.
772 bool isTrigDecision = strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0;
773 if (fDebugMode)
774 {
775 if (isTrigDecision)
776 {
81d62bb4 777 code << " HLTDebug(Form(\"Trying to match input object to class '"
f48dcb4e 778 << symbol->ObjectClass() << "', trigger name '" << symbol->RealName()
52f67e50 779 << "' and block type '%s'\", " << symbol->Name()
81d62bb4 780 << "DomainEntry.AsString().Data()));" << endl;
52f67e50 781 }
782 else
783 {
81d62bb4 784 code << " HLTDebug(Form(\"Trying to match input object to class '"
52f67e50 785 << symbol->ObjectClass() << "' and block type '%s'\", "
81d62bb4 786 << symbol->Name() << "DomainEntry.AsString().Data()));" << endl;
52f67e50 787 }
788 }
325e5e42 789 // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
790 // Have to use the TClass system for extra protection.
791 code << " const " << symbol->ObjectClass() << "* " << symbol->Name() << "_object_ = NULL;" << endl;
792 code << " if (_object_->IsA() == " << symbol->ObjectClass() << "::Class()) " << symbol->Name()
52f67e50 793 << "_object_ = dynamic_cast<const " << symbol->ObjectClass()
794 << "*>(_object_);" << endl;
81d62bb4 795 code << " if (" << symbol->Name() << "_object_ != NULL && ";
52f67e50 796 if (isTrigDecision)
797 {
798 code << "strcmp(" << symbol->Name() << "_object_->Name(), \""
e9f09f57 799 << symbol->RealName() << "\") == 0 && ";
52f67e50 800 }
801 code << symbol->Name() << "DomainEntry == _type_spec_) {" << endl;
802 TString fullname = symbol->Name();
803 fullname += "_object_";
804 expr.ReplaceAll("this", fullname);
805 code << " this->" << symbol->Name() << " = " << expr.Data() << ";" << endl;
806 if (isTrigDecision)
807 {
808 code << " this->" << symbol->Name() << "TriggerDomain = "
809 << fullname.Data() << "->TriggerDomain();" << endl;
810 }
811 if (fDebugMode)
812 {
81d62bb4 813 code << " HLTDebug(Form(\"Added TObject %p with class name '%s' to variable "
814 << symbol->Name() << "\", _object_, _object_->ClassName()));" << endl;
52f67e50 815 code << " _object_assigned_ = true;" << endl;
816 }
817 code << " }" << endl;
818 }
819 if (fDebugMode)
820 {
81d62bb4 821 code << " if (! _object_assigned_) {" << endl;
822 code << " HLTDebug(Form(\"Did not assign TObject %p"
823 " with class name '%s' to any variable.\", _object_, _object_->ClassName()));"
52f67e50 824 << endl;
81d62bb4 825 code << " }" << endl;
52f67e50 826 }
e2bb8ddd 827 code << " }" << endl;
52f67e50 828
829 // Generate the CalculateTriggerDecision method.
81d62bb4 830 // This requires code to be generated that checks which items in the trigger menu
831 // have their conditions asserted and then the trigger domain is generated from
832 // those fired items.
833 // The processing will start from the highest priority trigger group and stop
834 // after at least one trigger from the current priority group being processed
835 // is positive. For each priority group all the trigger menu items are checked.
836 // Their combined trigger condition expression must be true for the trigger priority
837 // group to be triggered positive. The full condition expression is formed by
838 // concatenating the individual condition expressions. If no trailing operators are
839 // used in the individual expressions then the default condition operator is placed
840 // between two concatenated condition expressions.
841 // If a trigger priority group has at least one trigger fired then the trigger domain
842 // is calculated such that it will give the same result as the concatenated trigger
843 // domain merging expressions for all the individual trigger menu items with
844 // positive results. Again, if no trailing operators are used in the individual
845 // merging expressions then the default domain operator is placed between two
846 // expression fragments.
52f67e50 847 code << " virtual bool CalculateTriggerDecision(AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl;
848 if (fDebugMode)
849 {
81d62bb4 850 code << "#ifdef __CINT__" << endl;
851 code << " gFunctionName = \"CalculateTriggerDecision\";" << endl;
852 code << "#endif" << endl;
853 code << " HLTDebug(Form(\"Calculating global HLT trigger result with trigger object at %p.\", this));" << endl;
52f67e50 854 }
81d62bb4 855
856 // Build a list of priorities used in the trigger menu.
857 std::vector<UInt_t> priorities;
52f67e50 858 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
859 {
860 const AliHLTTriggerMenuItem* item = menu->Item(i);
81d62bb4 861 bool priorityNotInList = std::find(priorities.begin(), priorities.end(), item->Priority()) == priorities.end();
862 if (priorityNotInList) priorities.push_back(item->Priority());
863 }
864 std::sort(priorities.begin(), priorities.end(), AliHLTDescendingNumbers);
865 // From the priority list, build the priority groups in the correct order,
866 // i.e. highest priority first.
867 // The priority group is a list of vectors of integers. The integers are the
868 // index numbers into the trigger menu item list for the items which form part
869 // of the priority group.
870 std::vector<std::vector<Int_t> > priorityGroup;
871 priorityGroup.insert(priorityGroup.begin(), priorities.size(), std::vector<Int_t>());
872 for (size_t n = 0; n < priorities.size(); n++)
873 {
874 UInt_t priority = priorities[n];
875 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
52f67e50 876 {
81d62bb4 877 const AliHLTTriggerMenuItem* item = menu->Item(i);
878 if (item->Priority() == priority) priorityGroup[n].push_back(i);
52f67e50 879 }
81d62bb4 880 }
881
882 for (size_t n = 0; n < priorityGroup.size(); n++)
883 {
52f67e50 884 if (fDebugMode)
885 {
81d62bb4 886 code << " HLTDebug(Form(\"Processing trigger priority group " << priorities[n] << "\"));" << endl;
52f67e50 887 }
81d62bb4 888 code << " ";
889 if (n == 0) code << "UInt_t ";
890 code << "_previous_match_ = 0xFFFFFFFF;" << endl;
891 code << " ";
892 if (n == 0) code << "bool ";
893 code << "_trigger_matched_ = false;" << endl;
894 code << " ";
895 if (n == 0) code << "bool ";
896 code << "_group_result_ = false;" << endl;
897 std::vector<TString> conditionOperator;
898 conditionOperator.insert(conditionOperator.begin(), priorityGroup[n].size(), TString(""));
899 std::vector<TString> domainOperator;
900 domainOperator.insert(domainOperator.begin(), priorityGroup[n].size(), TString(""));
901 for (size_t m = 0; m < priorityGroup[n].size(); m++)
52f67e50 902 {
81d62bb4 903 UInt_t i = priorityGroup[n][m];
904 const AliHLTTriggerMenuItem* item = menu->Item(i);
905 TString triggerCondition = item->TriggerCondition();
906 TString mergeExpr = item->MergeExpression();
907 // Replace the symbols found in the trigger condition and merging expressions
908 // with appropriate compilable versions.
909 for (Int_t j = 0; j < symbols.GetEntriesFast(); j++)
910 {
911 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(j) );
912 bool symbolNamesDifferent = strcmp(symbol->RealName(), symbol->Name()) != 0;
913 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
914 {
915 TString newname = symbol->Name();
916 newname += "TriggerDomain";
917 mergeExpr.ReplaceAll(symbol->RealName(), newname);
918 }
919 else
920 {
921 if (symbolNamesDifferent) mergeExpr.ReplaceAll(symbol->RealName(), symbol->Name());
922 }
923 if (symbolNamesDifferent) triggerCondition.ReplaceAll(symbol->RealName(), symbol->Name());
924 }
925 // We allow the trigger conditions and merging expressions to have trailing operators.
926 // Thus, we need to extract the operators and cleanup the expressions so that they will
927 // compile. This means that we silently ignore the trailing operator if not needed.
928 if (ExtractedOperator(triggerCondition, conditionOperator[m]))
929 {
930 // If the trailing operator is the same as the default operator then reset
931 // the value in the operator list so that the default is used in the generated
932 // code. This creates more compact code.
933 if (conditionOperator[m] == menu->DefaultConditionOperator()) conditionOperator[m] = "";
934 }
935 if (ExtractedOperator(mergeExpr, domainOperator[m]))
936 {
937 if (domainOperator[m] == menu->DefaultDomainOperator()) domainOperator[m] = "";
938 }
939 if (fDebugMode)
940 {
941 code << " HLTDebug(Form(\"Trying trigger condition " << i
942 << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));"
943 << endl;
944 }
945 code << " ";
946 if (n == 0 and m == 0) code << "bool ";
947 code << "_item_result_ = false;" << endl;
948 code << " if (" << triggerCondition << ") {" << endl;
949 code << " ++fCounter[" << i << "];" << endl;
950 const char* indentation = "";
951 if (item->PreScalar() != 0)
952 {
953 indentation = " ";
954 code << " if ((fCounter[" << i << "] % " << item->PreScalar() << ") == 1) {" << endl;
955 }
956 code << indentation << " _item_result_ = true;" << endl;
957 if (fDebugMode)
958 {
959 code << indentation << " HLTDebug(Form(\"Matched trigger condition " << i
960 << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));" << endl;
961 }
962 if (item->PreScalar() != 0)
963 {
964 code << " }" << endl;
965 }
966 code << " }" << endl;
967 if (m == 0)
968 {
969 // Since this is the first item of the trigger group,
970 // the generated trigger logic can be simplified a little.
971 code << " _group_result_ = _item_result_;" << endl;
972 code << " if (_item_result_) {" << endl;
973 code << " _domain_ = " << mergeExpr.Data() << ";" << endl;
974 code << " _description_ = fMenuItemDescription" << i << ";" << endl;
975 code << " _previous_match_ = " << i << ";" << endl;
976 code << " _trigger_matched_ = true;" << endl;
977 code << " }" << endl;
978 }
979 else
980 {
325e5e42 981 if (conditionOperator[m-1] == "")
81d62bb4 982 {
983 code << " _group_result_ = _group_result_ "
984 << menu->DefaultConditionOperator() << " _item_result_;" << endl;
985 }
986 else
987 {
325e5e42 988 code << " _group_result_ = _group_result_ "
989 << conditionOperator[m-1] << " _item_result_;" << endl;
81d62bb4 990 }
991 code << " if (_item_result_) {" << endl;
992 code << " if (_trigger_matched_) {" << endl;
325e5e42 993 bool switchWillBeEmpty = true;
81d62bb4 994 for (size_t k = 0; k < m; k++)
995 {
996 if (domainOperator[k] == "") continue;
997 switchWillBeEmpty = false;
998 }
999 if (switchWillBeEmpty)
1000 {
1001 code << " _domain_ = _domain_ " << menu->DefaultDomainOperator() << " "
1002 << mergeExpr.Data() << ";" << endl;
1003 }
1004 else
1005 {
1006 code << " switch(_previous_match_) {" << endl;
1007 for (size_t k = 0; k < m; k++)
1008 {
1009 if (domainOperator[k] == "") continue;
1010 code << " case " << k << ": _domain_ = _domain_ "
1011 << domainOperator[k] << " " << mergeExpr.Data() << "; break;" << endl;
1012 }
1013 code << " default: _domain_ = _domain_ "
1014 << menu->DefaultDomainOperator() << " " << mergeExpr.Data() << ";" << endl;
1015 code << " }" << endl;
1016 }
1017 code << " _description_ += \",\";" << endl;
1018 code << " _description_ += fMenuItemDescription" << i << ";" << endl;
1019 code << " } else {" << endl;
1020 code << " _domain_ = " << mergeExpr.Data() << ";" << endl;
1021 code << " _description_ = fMenuItemDescription" << i << ";" << endl;
1022 code << " }" << endl;
1023 code << " _previous_match_ = " << i << ";" << endl;
1024 code << " _trigger_matched_ = true;" << endl;
1025 code << " }" << endl;
1026 }
52f67e50 1027 }
81d62bb4 1028 code << " if (_group_result_) {" << endl;
52f67e50 1029 if (fDebugMode)
1030 {
81d62bb4 1031 if (n < priorities.size() - 1)
1032 {
1033 code << " HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n]
1034 << ". Stopping processing here because all other trigger groups have lower priority.\"));" << endl;
1035 }
1036 else
1037 {
1038 code << " HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n] << ".\"));" << endl;
1039 }
52f67e50 1040 }
81d62bb4 1041 code << " return true;" << endl;
52f67e50 1042 code << " }" << endl;
1043 }
81d62bb4 1044 code << " _domain_.Clear();" << endl;
1045 code << " _description_ = \"\";" << endl;
1046 code << " return false;" << endl;
e2bb8ddd 1047 code << " }" << endl;
52f67e50 1048
81d62bb4 1049 // Generate getter and setter methods for the counters.
1050 code << " const TArrayL64& GetCounters() const { return fCounter; }" << endl;
1051 code << " void SetCounters(const TArrayL64& counters) { fCounter = counters; }" << endl;
52f67e50 1052
e2bb8ddd 1053 code << "private:" << endl;
52f67e50 1054 // Add the symbols in the trigger menu to the list of private variables.
1055 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1056 {
1057 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1058 code << " " << symbol->Type() << " " << symbol->Name() << ";" << endl;
1059 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
1060 {
1061 code << " AliHLTTriggerDomain " << symbol->Name() << "TriggerDomain;" << endl;
1062 }
1063 code << " AliHLTDomainEntry " << symbol->Name() << "DomainEntry;" << endl;
1064 }
1065 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1066 {
1067 code << " TString fMenuItemDescription" << i << ";" << endl;
1068 }
81d62bb4 1069 code << " TArrayL64 fCounter;" << endl;
1070 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
1071 code << " ClassDef(" << name.Data() << ", 0)" << endl;
1072 code << "#else" << endl;
1073 code << " virtual const char* Class_Name() const { return \"" << name.Data() << "\"; }" << endl;
1074 code << "#endif" << endl;
e2bb8ddd 1075 code << "};" << endl;
81d62bb4 1076 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
1077 code << "ClassImp(" << name.Data() << ")" << endl;
1078 code << "#endif" << endl;
e2bb8ddd 1079
1080 code.close();
1081
52f67e50 1082 // Now we need to compile and load the new class.
81d62bb4 1083 result = LoadTriggerClass(filename, includePaths);
52f67e50 1084 return result;
1085}
1086
1087
1088int AliHLTGlobalTriggerComponent::LoadTriggerClass(
1089 const char* filename, const TClonesArray& includePaths
1090 )
1091{
1092 // Loads the code for a custom global trigger class implementation on the fly.
1093
81d62bb4 1094 HLTDebug("Loading HLT trigger class from file '%s'.", filename);
1095
52f67e50 1096 TString compiler = gSystem->GetBuildCompilerVersion();
566a01d0 1097 if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc")))
1098 {
1099 TString includePath;
1100#if defined(PKGINCLUDEDIR)
1101 // this is especially for the HLT build system where the package is installed
1102 // in a specific directory including proper treatment of include files
1103 includePath.Form("-I%s", PKGINCLUDEDIR);
1104#else
1105 // the default AliRoot behavior, all include files can be found in the
1106 // $ALICE_ROOT subfolders
1107 includePath = "-I${ALICE_ROOT}/include -I${ALICE_ROOT}/HLT/BASE -I${ALICE_ROOT}/HLT/trigger";
1108#endif
52f67e50 1109 // Add any include paths that were specified on the command line.
1110 for (Int_t i = 0; i < includePaths.GetEntriesFast(); i++)
1111 {
7da191b6 1112 TString path = static_cast<TObjString*>(includePaths.UncheckedAt(i))->String();
81d62bb4 1113 includePath += " -I";
52f67e50 1114 includePath += path;
1115 }
81d62bb4 1116 HLTDebug("using include settings: %s", includePath.Data());
52f67e50 1117 gSystem->SetIncludePath(includePath);
1118 gSystem->SetFlagsOpt("-O3 -DNDEBUG");
1119 gSystem->SetFlagsDebug("-g3 -DDEBUG -D__DEBUG");
1120
1121 int result = kTRUE;
1122 if (fDebugMode)
1123 {
1124 result = gSystem->CompileMacro(filename, "g");
1125 }
1126 else
1127 {
1128 result = gSystem->CompileMacro(filename, "O");
1129 }
1130 if (result != kTRUE)
1131 {
1132 HLTFatal("Could not compile and load global trigger menu implementation.");
1133 return -ENOENT;
1134 }
1135 }
1136 else
1137 {
1b820a65 1138 // Store the library state to be checked later in UnloadTriggerClass.
1139 fLibStateAtLoad = gSystem->GetLibraries();
1140
52f67e50 1141 // If we do not support the compiler then try interpret the class instead.
81d62bb4 1142 TString cmd = ".L ";
52f67e50 1143 cmd += filename;
1144 Int_t errorcode = TInterpreter::kNoError;
1145 gROOT->ProcessLine(cmd, &errorcode);
1146 if (errorcode != TInterpreter::kNoError)
1147 {
1148 HLTFatal("Could not load interpreted global trigger menu implementation"
1149 " (Interpreter error code = %d).",
1150 errorcode
1151 );
1152 return -ENOENT;
1153 }
1154 }
1155
1156 return 0;
1157}
1158
1159
81d62bb4 1160int AliHLTGlobalTriggerComponent::UnloadTriggerClass(const char* filename)
1161{
1162 // Unloads the code previously loaded by LoadTriggerClass.
1163
1164 HLTDebug("Unloading HLT trigger class in file '%s'.", filename);
1165
1166 TString compiler = gSystem->GetBuildCompilerVersion();
1167 if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc")))
1168 {
1b820a65 1169 // Generate the library name.
81d62bb4 1170 TString libname = filename;
1171 Ssiz_t dotpos = libname.Last('.');
1172 if (0 <= dotpos and dotpos < libname.Length()) libname[dotpos] = '_';
1173 libname += ".";
1174 libname += gSystem->GetSoExt();
1175
1b820a65 1176 // This is a workaround for a problem with unloading shared libraries in ROOT.
1177 // If the trigger logic library is loaded before the libAliHLTHOMER.so library
1178 // or any other library is loaded afterwards, then during the gInterpreter->UnloadFile
1179 // call all the subsequent libraries get unloded. This means that any objects created
1180 // from classes implemented in the libAliHLTHOMER.so library will generate segfaults
1181 // since the executable code has been unloaded.
1182 // We need to check if there are any more libraries loaded after the class we
1183 // are unloading and in that case don't unload the class.
1184 TString libstring = gSystem->GetLibraries();
1185 TString token, lastlib;
1186 Ssiz_t from = 0;
1187 Int_t numOfLibs = 0, posOfLib = -1;
1188 while (libstring.Tokenize(token, from, " "))
1189 {
1190 ++numOfLibs;
1191 lastlib = token;
1192 if (token.Contains(libname)) posOfLib = numOfLibs;
1193 }
1194 if (numOfLibs != posOfLib)
1195 {
1196 HLTWarning(Form("ROOT limitation! Cannot properly cleanup and unload the shared"
1197 " library '%s' since another library '%s' was loaded afterwards. Trying to"
1198 " unload this library will remove the others and lead to serious memory faults.",
1199 libname.Data(), lastlib.Data()
1200 ));
1201 return 0;
1202 }
1203
81d62bb4 1204 char* path = NULL;
1205 int result = 0;
1206 if ((path = gSystem->DynamicPathName(libname)) != NULL)
1207 {
1208 result = gInterpreter->UnloadFile(path);
1209 delete [] path;
1210 }
1211 if (result != TInterpreter::kNoError) return -ENOENT;
1212 }
1213 else
1214 {
1b820a65 1215 // This is again a workaround for the problem with unloading files in ROOT.
1216 // If the trigger logic class is loaded before the libAliHLTHOMER.so library
1217 // or any other library is loaded afterwards, then during the gInterpreter->UnloadFile
1218 // call all the subsequent libraries get unloded.
1219 // We need to check if the list of loaded libraries has changed since the last
1220 // call to LoadTriggerClass. If it has then don't unload the class.
1221 if (fLibStateAtLoad != gSystem->GetLibraries())
1222 {
1223 TString libstring = gSystem->GetLibraries();
1224 TString token;
1225 Ssiz_t from = 0;
1226 while (libstring.Tokenize(token, from, " "))
1227 {
1228 if (not fLibStateAtLoad.Contains(token)) break;
1229 }
1230 HLTWarning(Form("ROOT limitation! Cannot properly cleanup and unload the file"
1231 " '%s' since another library '%s' was loaded afterwards. Trying to unload"
1232 " this file will remove the other library and lead to serious memory faults.",
1233 filename, token.Data()
1234 ));
1235 return 0;
1236 }
1237
1238 // If we did not compile the trigger logic then remove the interpreted class.
81d62bb4 1239 TString cmd = ".U ";
1240 cmd += filename;
1241 Int_t errorcode = TInterpreter::kNoError;
1242 gROOT->ProcessLine(cmd, &errorcode);
1243 if (errorcode != TInterpreter::kNoError)
1244 {
1245 HLTFatal("Could not unload interpreted global trigger menu implementation"
1246 " (Interpreter error code = %d).",
1247 errorcode
1248 );
1249 return -ENOENT;
1250 }
1251 }
1252
1253 return 0;
1254}
1255
1256
52f67e50 1257int AliHLTGlobalTriggerComponent::FindSymbol(const char* name, const TClonesArray& list)
1258{
1259 // Searches for the named symbol in the given list.
1260 // See header for more details.
1261
1262 for (int i = 0; i < list.GetEntriesFast(); i++)
1263 {
1264 const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(i) );
1265 if (symbol == NULL) continue;
1266 if (strcmp(symbol->Name(), name) == 0) return i;
1267 }
1268 return -1;
1269}
1270
1271
1272int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, TClonesArray& list)
1273{
1274 // Builds the list of symbols to use in the custom global trigger menu
1275 // implementation class.
1276 // See header for more details.
1277
025443e0 1278 // Note: when we build the symbol list we must use the symbol name as returned
1279 // by the Name() method and not the RealName() method when using FindSymbol.
1280 // This is so that we avoid problems with the generated code not compiling
1281 // because names like "abc-xyz" and "abc_xyz" are synonymous.
1282 // Name() returns the converted C++ symbol name as used in the generated code.
1283
52f67e50 1284 for (UInt_t i = 0; i < menu->NumberOfSymbols(); i++)
1285 {
1286 const AliHLTTriggerMenuSymbol* symbol = menu->Symbol(i);
1287 if (FindSymbol(symbol->Name(), list) != -1)
1288 {
1289 HLTError("Multiple symbols with the name '%s' defined in the trigger menu.", symbol->Name());
1290 return -EIO;
1291 }
1292 new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
1293 }
1294
f48dcb4e 1295 TRegexp exp("[_a-zA-Z][-_a-zA-Z0-9]*");
3da1c6d7 1296 TRegexp hexexp("x[a-fA-F0-9]+");
52f67e50 1297 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1298 {
1299 const AliHLTTriggerMenuItem* item = menu->Item(i);
81d62bb4 1300 TString str = item->TriggerCondition();
52f67e50 1301 Ssiz_t start = 0;
1302 do
1303 {
1304 Ssiz_t length = 0;
1305 Ssiz_t pos = exp.Index(str, &length, start);
1306 if (pos == kNPOS) break;
52f67e50 1307 start = pos+length;
1308
3da1c6d7 1309 // Check if there is a numerical character before the found
1310 // regular expression. If so, then the symbol is not a valid one
1311 // and should be skipped.
1312 if (pos > 0)
1313 {
1314 bool notValid = false;
1315 switch (str[pos-1])
1316 {
1317 case '0': case '1': case '2': case '3': case '4':
1318 case '5': case '6': case '7': case '8': case '9':
1319 notValid = true;
1320 break;
1321 default:
1322 notValid = false;
1323 break;
1324 }
1325 if (notValid) continue;
1326 }
1327 TString s = str(pos, length);
1328
52f67e50 1329 if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
1330 s == "compl" or s == "not" or s == "not_eq" or s == "or" or
1331 s == "or_eq" or s == "xor" or s == "xor_eq" or s == "true" or
1332 s == "false"
1333 )
1334 {
1335 // Ignore iso646.h and other keywords.
1336 continue;
1337 }
3da1c6d7 1338
025443e0 1339 // Need to create the symbols first and check if its name is in the list
1340 // before actually adding it to the symbols list.
1341 AliHLTTriggerMenuSymbol newSymbol;
1342 newSymbol.Name(s.Data());
1343 newSymbol.Type("bool");
1344 newSymbol.ObjectClass("AliHLTTriggerDecision");
1345 newSymbol.AssignExpression("this->Result()");
1346 newSymbol.DefaultValue("false");
1347 if (FindSymbol(newSymbol.Name(), list) == -1)
52f67e50 1348 {
52f67e50 1349 new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
1350 }
1351 }
1352 while (start < str.Length());
1353 }
1354
e2bb8ddd 1355 return 0;
1356}
1357
81d62bb4 1358
1359bool AliHLTGlobalTriggerComponent::ExtractedOperator(TString& expr, TString& op)
1360{
1361 // Extracts the trailing operator from the expression.
1362
1363 Ssiz_t i = 0;
1364 // First skip the trailing whitespace.
1365 bool whitespace = true;
1366 for (i = expr.Length()-1; i >= 0 and whitespace; i--)
1367 {
1368 switch (expr[i])
1369 {
1370 case ' ': case '\t': case '\r': case '\n':
1371 whitespace = true;
1372 break;
1373 default:
1374 whitespace = false;
1375 }
1376 }
1377 if (i < 0 or whitespace) return false;
1378
1379 // Now find the first whitespace character before the trailing symbol.
1380 bool nonwhitespace = true;
1381 for (; i >= 0 and nonwhitespace; i--)
1382 {
1383 switch (expr[i])
1384 {
1385 case ' ': case '\t': case '\r': case '\n':
1386 nonwhitespace = false;
1387 break;
1388 default:
1389 nonwhitespace = true;
1390 }
1391 }
1392 if (i < 0 or nonwhitespace) return false;
1393
1394 // Extract the last symbols and check if it is a valid operator.
1395 TString s = expr;
1396 s.Remove(0, i+2);
1397 if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
1398 s == "compl" or s == "not" or s == "not_eq" or s == "or" or
1399 s == "or_eq" or s == "xor" or s == "xor_eq" or s == "&&" or
1400 s == "&=" or s == "&" or s == "|" or s == "~" or s == "!" or
1401 s == "!=" or s == "||" or s == "|=" or s == "^" or s == "^=" or
1402 s == "==" or s == "+" or s == "-" or s == "*" or s == "/" or
1403 s == "%" or s == ">" or s == "<" or s == ">=" or s == "<="
1404 )
1405 {
1406 expr.Remove(i+1);
1407 op = s;
1408 return true;
1409 }
1410
1411 return false;
1412}
1413
1414
2974f8dc 1415int AliHLTGlobalTriggerComponent::PrintStatistics(const AliHLTGlobalTrigger* pTrigger, AliHLTComponentLogSeverity level, int offset) const
1416{
1417 // print some statistics
8b29f84f 1418 int totalEvents=GetEventCount()+offset;
325e5e42 1419 const TArrayL64& counters = pTrigger->GetCounters();
1420 if (pTrigger->CallFailed()) return -EPROTO;
1421 for (int i = 0; i < counters.GetSize(); i++) {
1422 ULong64_t count = counters[i];
8b29f84f 1423 float ratio=0;
1424 if (totalEvents>0) ratio=100*(float)count/totalEvents;
81d62bb4 1425 HLTLog(level, "Item %d: total events: %d - counted events: %llu (%.1f%%)", i, totalEvents, count, ratio);
2974f8dc 1426 }
2974f8dc 1427 return 0;
1428}
566a01d0 1429
1430int AliHLTGlobalTriggerComponent::AddCTPDecisions(AliHLTGlobalTrigger* pTrigger, const AliHLTCTPData* pCTPData, const AliHLTComponentTriggerData* trigData)
1431{
1432 // add trigger decisions for the valid CTP classes
1433 if (!pCTPData || !pTrigger) return 0;
1434
1435 AliHLTUInt64_t triggerMask=pCTPData->Mask();
1436 AliHLTUInt64_t bit0=0x1;
1437 if (!fCTPDecisions) {
1438 fCTPDecisions=new TClonesArray(AliHLTTriggerDecision::Class(), gkNCTPTriggerClasses);
1439 if (!fCTPDecisions) return -ENOMEM;
1440
1441 fCTPDecisions->ExpandCreate(gkNCTPTriggerClasses);
1442 for (int i=0; i<gkNCTPTriggerClasses; i++) {
1443 const char* name=pCTPData->Name(i);
1444 if (triggerMask&(bit0<<i) && name) {
1445 AliHLTTriggerDecision* pDecision=dynamic_cast<AliHLTTriggerDecision*>(fCTPDecisions->At(i));
1446 assert(pDecision);
1447 if (!pDecision) {
1448 delete fCTPDecisions;
1449 fCTPDecisions=NULL;
1450 return -ENOENT;
1451 }
1452 pDecision->Name(name);
1453 }
1454 }
1455 }
1456
1457 for (int i=0; i<gkNCTPTriggerClasses; i++) {
1458 const char* name=pCTPData->Name(i);
1459 if ((triggerMask&(bit0<<i))==0 || name==NULL) continue;
1460 AliHLTTriggerDecision* pDecision=dynamic_cast<AliHLTTriggerDecision*>(fCTPDecisions->At(i));
1461 HLTDebug("updating CTP trigger decision %d %s (%p casted %p)", i, name, fCTPDecisions->At(i), pDecision);
1462 if (!pDecision) return -ENOENT;
1463
1464 bool result=false;
1465 if (trigData) result=pCTPData->EvaluateCTPTriggerClass(name, *trigData);
1466 else result=pCTPData->EvaluateCTPTriggerClass(name);
1467 pDecision->Result(result);
1468 pDecision->TriggerDomain().Clear();
1469 if (trigData) pDecision->TriggerDomain().Add(pCTPData->ReadoutList(*trigData));
1470 else pDecision->TriggerDomain().Add(pCTPData->ReadoutList());
1471
1472 pTrigger->Add(fCTPDecisions->At(i), kAliHLTDataTypeTriggerDecision, kAliHLTVoidDataSpec);
325e5e42 1473 if (pTrigger->CallFailed()) return -EPROTO;
566a01d0 1474 }
1475
1476 return 0;
1477}