2 /**************************************************************************
3 * This file is property of and copyright by the ALICE HLT Project *
4 * ALICE Experiment at CERN, All rights reserved. *
6 * Primary Authors: Artur Szostak <artursz@iafrica.com> *
7 * for The ALICE HLT Project. *
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 **************************************************************************/
18 /// @file AliHLTGlobalTriggerComponent.cxx
19 /// @author Artur Szostak <artursz@iafrica.com>
21 /// @brief Implementation of the AliHLTGlobalTriggerComponent component class.
23 /// The AliHLTGlobalTriggerComponent class applies the global HLT trigger to all
24 /// trigger information produced by components deriving from AliHLTTrigger.
26 #include "AliHLTGlobalTriggerComponent.h"
27 #include "AliHLTGlobalTriggerDecision.h"
28 #include "AliHLTGlobalTrigger.h"
29 #include "AliHLTGlobalTriggerConfig.h"
30 #include "AliHLTTriggerMenu.h"
31 #include "AliHLTCTPData.h"
32 #include "AliCDBManager.h"
33 #include "AliCDBStorage.h"
34 #include "AliCDBEntry.h"
35 #include "AliRawDataHeader.h"
40 #include "TClonesArray.h"
41 #include "TObjString.h"
43 #include "TInterpreter.h"
54 ClassImp(AliHLTGlobalTriggerComponent)
56 const char* AliHLTGlobalTriggerComponent::fgkTriggerMenuCDBPath = "HLT/ConfigHLT/HLTGlobalTrigger";
62 * This method is used as a comparison functor with the STL sort routines.
64 bool AliHLTDescendingNumbers(UInt_t a, UInt_t b)
71 AliHLTGlobalTriggerComponent::AliHLTGlobalTriggerComponent() :
75 fRuntimeCompile(true),
76 fDeleteCodeFile(false),
77 fMakeSoftwareTriggers(true),
81 fBufferSizeConst(2*(sizeof(AliHLTGlobalTriggerDecision) + sizeof(AliHLTReadoutList))),
82 fBufferSizeMultiplier(1.),
83 fIncludePaths(TObjString::Class()),
84 fIncludeFiles(TObjString::Class()),
87 fDataEventsOnly(true),
90 fSoftwareTrigger(true, "SOFTWARE"),
91 fTotalEventCounter(0),
94 // Default constructor.
96 ClearInfoForNewEvent(false);
100 AliHLTGlobalTriggerComponent::~AliHLTGlobalTriggerComponent()
102 // Default destructor.
104 if (fTrigger != NULL) delete fTrigger;
107 fCTPDecisions->Delete();
108 delete fCTPDecisions;
113 void AliHLTGlobalTriggerComponent::GetOutputDataTypes(AliHLTComponentDataTypeList& list) const
115 // Returns the kAliHLTDataTypeGlobalTrigger type as output.
116 list.push_back(kAliHLTDataTypeGlobalTrigger);
120 void AliHLTGlobalTriggerComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
122 // Returns the output data size estimate.
124 constBase = fBufferSizeConst;
125 inputMultiplier = fBufferSizeMultiplier;
129 Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
131 // Initialises the global trigger component.
136 fDeleteCodeFile = false;
137 fMakeSoftwareTriggers = true;
138 const char* configFileName = NULL;
139 const char* codeFileName = NULL;
140 fIncludePaths.Clear();
141 fIncludeFiles.Clear();
142 SetBit(kIncludeInput);
143 fDataEventsOnly = true;
144 UInt_t randomSeed = 0;
145 bool randomSeedSet = false;
148 for (int i = 0; i < argc; i++)
150 if (strcmp(argv[i], "-config") == 0)
152 if (configFileName != NULL)
154 HLTWarning("Trigger configuration macro was already specified."
155 " Will replace previous value given by -config."
160 HLTError("The trigger configuration macro filename was not specified." );
163 configFileName = argv[i+1];
168 if (strcmp(argv[i], "-includepath") == 0)
172 HLTError("The include path was not specified." );
177 new (fIncludePaths[fIncludePaths.GetEntriesFast()]) TObjString(argv[i+1]);
179 catch (const std::bad_alloc&)
181 HLTError("Could not allocate more memory for the fIncludePaths array.");
188 if (strcmp(argv[i], "-include") == 0)
192 HLTError("The include file name was not specified." );
197 new (fIncludeFiles[fIncludeFiles.GetEntriesFast()]) TObjString(argv[i+1]);
199 catch (const std::bad_alloc&)
201 HLTError("Could not allocate more memory for the fIncludeFiles array.");
208 if (strcmp(argv[i], "-debug") == 0)
210 if (fDebugMode == true)
212 HLTWarning("The debug flag was already specified. Ignoring this instance.");
218 if (strcmp(argv[i], "-cint") == 0)
220 fRuntimeCompile = false;
224 if (strcmp(argv[i], "-usecode") == 0)
226 if (codeFileName != NULL)
228 HLTWarning("Custom trigger code file was already specified."
229 " Will replace previous value given by -usecode."
234 HLTError("The custom trigger code filename was not specified." );
237 codeFileName = argv[i+1];
240 HLTError("The custom trigger class name was not specified." );
243 fClassName = argv[i+2];
248 if (strcmp(argv[i], "-skipctp") == 0)
250 HLTInfo("Skipping CTP counters in trigger decision");
255 if (strcmp(argv[i], "-forward-input") == 0)
257 HLTInfo("Forwarding input objects and trigger decisions");
258 SetBit(kForwardInput);
259 SetBit(kIncludeShort);
260 SetBit(kIncludeInput, false);
264 if (strstr(argv[i], "-include-input") == argv[i])
266 SetBit(kForwardInput,false);
267 TString param=argv[i];
268 param.ReplaceAll("-include-input", "");
269 if (param.CompareTo("=none")==0)
271 HLTInfo("skipping objects and trigger decisions");
272 SetBit(kIncludeShort, false);
273 SetBit(kIncludeInput, false);
275 else if (param.CompareTo("=short")==0)
277 HLTInfo("including short info on objects and trigger decisions");
278 SetBit(kIncludeShort);
279 SetBit(kIncludeInput, false);
281 else if (param.CompareTo("=both")==0)
283 HLTInfo("including input objects, trigger decisions and short info");
284 SetBit(kIncludeShort);
285 SetBit(kIncludeInput);
287 else if (param.CompareTo("=objects")==0 || param.IsNull())
289 HLTInfo("including input objects and trigger decisions");
290 SetBit(kIncludeShort, false);
291 SetBit(kIncludeInput);
295 HLTError("unknown parameter '%s' for argument '-include-input'", param.Data());
300 if (strcmp(argv[i], "-process-all-events") == 0)
302 fDataEventsOnly = false;
306 if (strstr(argv[i], "-monitoring") == argv[i])
308 TString param=argv[i];
309 param.ReplaceAll("-monitoring", "");
313 // enable monitoring trigger for all events
317 // enable monitoring trigger once every n seconds
318 param.ReplaceAll("=", "");
319 if (param.IsDigit()) {
320 fMonitorPeriod=param.Atoi();
322 HLTError("expecting number as parameter for argument '-monitoring=', got %s, skipping monitoring trigger", param.Data());
328 if (strcmp(argv[i], "-dont-make-software-triggers") == 0)
330 fMakeSoftwareTriggers = false;
333 if (strcmp(argv[i], "-randomseed") == 0)
337 HLTWarning("The random seed was already specified previously with the option -randomseed."
338 "Will replace the previous value of %d with the new one.",
344 HLTError("The number to use as the seed was not specified for the -randomseed option." );
347 TString numstr = argv[i+1];
348 if (not numstr.IsDigit())
350 HLTError("The number specified in the -randomseed option is not a valid decimal integer." );
353 randomSeed = numstr.Atoi();
354 randomSeedSet = true;
359 HLTError("Unknown option '%s'.", argv[i]);
363 const AliHLTTriggerMenu* menu = NULL;
364 if (configFileName != NULL)
367 cmd += configFileName;
368 gROOT->ProcessLine(cmd);
369 menu = AliHLTGlobalTriggerConfig::Menu();
372 // Try load the trigger menu from the CDB if it is not loaded yet with the
374 int result = -ENOENT;
377 result = LoadTriggerMenu(fgkTriggerMenuCDBPath, menu);
381 HLTError("No trigger menu configuration found or specified.");
385 if (codeFileName == NULL)
387 result = GenerateTrigger(menu, fClassName, fCodeFileName, fIncludePaths, fIncludeFiles);
388 if (result == 0) fDeleteCodeFile = true;
392 result = LoadTriggerClass(codeFileName, fIncludePaths);
393 if (result == 0) fCodeFileName = codeFileName;
395 if (result != 0) return result;
399 fTrigger = AliHLTGlobalTrigger::CreateNew(fClassName.Data());
401 catch (const std::bad_alloc&)
403 HLTError("Could not allocate memory for the AliHLTGlobalTrigger instance.");
406 if (fTrigger == NULL)
408 HLTError("Could not create a new instance of '%s'.", fClassName.Data());
412 fTrigger->FillFromMenu(*menu);
413 if (fTrigger->CallFailed()) return -EPROTO;
415 // setup the CTP accounting in AliHLTComponent
418 // Set the default values from the trigger menu.
419 SetDescription(menu->DefaultDescription());
420 SetTriggerDomain(menu->DefaultTriggerDomain());
422 // Initialise the random number generator seed value.
423 // NOTE: The GenerateTrigger method called above will set the fUniqueID value
424 // with a random value based on a GUID that should be unique across the system.
425 // This is then used as the seed to the random number generator if the -randomseed
426 // option is not used.
427 if (not randomSeedSet) randomSeed = fUniqueID;
428 gRandom->SetSeed(randomSeed);
430 fTotalEventCounter = 0;
435 Int_t AliHLTGlobalTriggerComponent::DoDeinit()
437 // Cleans up the global trigger component.
439 if (fTrigger != NULL)
446 fCTPDecisions->Delete();
447 delete fCTPDecisions;
452 Int_t result = UnloadTriggerClass(fCodeFileName);
453 if (result != 0) return result;
455 if (fDeleteCodeFile and !fCodeFileName.IsNull() && gSystem->AccessPathName(fCodeFileName)==0 && !fDebugMode) {
456 fCodeFileName.ReplaceAll(".cxx", "*");
457 TString command="rm "; command+=fCodeFileName;
458 gSystem->Exec(command);
461 fDeleteCodeFile=false;
467 AliHLTComponent* AliHLTGlobalTriggerComponent::Spawn()
469 // Creates a new object instance.
470 AliHLTComponent* comp = NULL;
473 comp = new AliHLTGlobalTriggerComponent;
475 catch (const std::bad_alloc&)
477 HLTError("Could not allocate memory for a new instance of AliHLTGlobalTriggerComponent.");
484 int AliHLTGlobalTriggerComponent::DoTrigger()
486 // This method will apply the global trigger decision.
488 if (fTrigger == NULL)
490 HLTFatal("Global trigger implementation object is NULL!");
494 AliHLTUInt32_t eventType=0;
495 if (!IsDataEvent(&eventType)) {
498 if (eventType == gkAliEventTypeEndOfRun) PrintStatistics(fTrigger, kHLTLogImportant);
499 IgnoreEvent(); // dont generate any trigger decision.
504 fCDH = NULL; // have to reset this in case ExtractTriggerData fails.
505 ExtractTriggerData(*GetTriggerData(), NULL, NULL, &fCDH, NULL);
507 // Copy the trigger counters in case we need to set them back to their original
508 // value because the PushBack method fails with ENOSPC.
509 TArrayL64 originalCounters = fTrigger->GetCounters();
510 if (fTrigger->CallFailed()) return -EPROTO;
512 fTrigger->NewEvent();
513 if (fTrigger->CallFailed()) return -EPROTO;
515 // Fill in the input data.
516 const TObject* obj = GetFirstInputObject();
519 fTrigger->Add(obj, GetDataType(), GetSpecification());
520 if (fTrigger->CallFailed()) return -EPROTO;
521 obj = GetNextInputObject();
524 // add trigger decisions for every CTP class
525 const AliHLTCTPData* pCTPData=CTPData();
527 AddCTPDecisions(fTrigger, pCTPData, GetTriggerData());
530 bool softwareTriggerIsValid = FillSoftwareTrigger();
531 if (softwareTriggerIsValid)
533 fTrigger->Add(&fSoftwareTrigger, kAliHLTDataTypeTriggerDecision, kAliHLTVoidDataSpec);
536 // Calculate the global trigger result and trigger domain, then create and push
537 // back the new global trigger decision object.
539 AliHLTTriggerDomain triggerDomain;
540 bool triggerResult = false;
541 bool matchedItems = fTrigger->CalculateTriggerDecision(triggerResult, triggerDomain, description);
542 if (fTrigger->CallFailed()) return -EPROTO;
543 AliHLTGlobalTriggerDecision decision(
545 // The following will cause the decision to be generated with default values
546 // (set in fTriggerDomain and fDescription) if the trigger result is false.
547 (matchedItems == true) ? triggerDomain : GetTriggerDomain(),
548 (matchedItems == true) ? description.Data() : GetDescription()
551 decision.SetUniqueID(fUniqueID);
552 decision.SetCounters(fTrigger->GetCounters(), fTotalEventCounter+1);
553 if (fTrigger->CallFailed()) return -EPROTO;
555 TClonesArray shortInfo(TNamed::Class(), GetNumberOfInputBlocks());
557 // Add the input objects used to make the global decision.
558 obj = GetFirstInputObject();
561 const AliHLTTriggerDecision* intrig = dynamic_cast<const AliHLTTriggerDecision*>(obj);
563 if (TestBit(kForwardInput)) Forward(obj);
565 if (TestBit(kIncludeInput))
569 decision.AddTriggerInput(*intrig);
573 // The const_cast should be safe in this case because the list of inputObjects
574 // will be added to the global decision with AddInputObjectRef, which only
575 // modifies the kCanDelete bit and nothing else.
576 // This is necessary since GetFirstInputObject only returns const objects.
577 decision.AddInputObjectRef( const_cast<TObject*>(obj) );
581 if (TestBit(kIncludeShort))
583 int entries = shortInfo.GetEntriesFast();
586 new (shortInfo[entries]) TNamed(obj->GetName(), obj->GetTitle());
588 catch (const std::bad_alloc&)
590 HLTError("Could not allocate more memory for the short list of input objects.");
595 shortInfo[entries]->SetBit(BIT(16)); // indicate that this is a trigger decision
596 shortInfo[entries]->SetBit(BIT(15), intrig->Result());
600 obj = GetNextInputObject();
602 if (TestBit(kIncludeShort)) decision.AddInputObjectRef(&shortInfo);
604 // The const_cast should be safe in this case because AddInputObjectRef just
605 // modifies the kCanDelete bit and nothing else.
606 if (!TestBit(kSkipCTP) && CTPData()) decision.AddInputObjectRef(const_cast<AliHLTCTPData*>(CTPData()));
608 if (softwareTriggerIsValid and TestBit(kIncludeInput)) decision.AddTriggerInput(fSoftwareTrigger);
610 static UInt_t lastTime=0;
612 if (time.Get()-lastTime>60)
615 PrintStatistics(fTrigger, kHLTLogImportant);
617 else if (eventType==gkAliEventTypeEndOfRun)
619 PrintStatistics(fTrigger, kHLTLogImportant);
622 // add readout filter to event done data
623 CreateEventDoneReadoutFilter(decision.TriggerDomain(), 3);
625 // add monitoring filter to event done data if enabled by setting
626 // a monitoring period >=0: -1 means off, 0 means for every event
627 // configured by argument '-monitoring[=n]'
628 if (fMonitorPeriod>=0) {
629 static UInt_t lastMonitorEvent=0;
631 AliHLTTriggerDomain monitoringFilter(decision.TriggerDomain());
632 if (decision.Result() &&
633 int(time.Get()-lastMonitorEvent)>fMonitorPeriod) {
634 lastMonitorEvent=time.Get();
635 // add monitoring event command for triggered events
636 CreateEventDoneReadoutFilter(decision.TriggerDomain(), 5);
638 // empty filter list if events are not triggered
639 // or within the monitoring interval
640 monitoringFilter.Clear();
642 // add monitoring filter list
643 CreateEventDoneReadoutFilter(monitoringFilter, 4);
646 // Mask the readout list according to the CTP trigger
647 // if the classes have been initialized (mask non-zero).
648 // If we are dealing with a software trigger on the other hand then
649 // mask with the participating detector list.
650 // In both cases we must make sure that HLT is part of the readout mask.
651 if (CTPData() != NULL and CTPData()->Mask() != 0x0)
653 AliHLTReadoutList readoutlist = decision.ReadoutList();
654 AliHLTReadoutList ctpreadout = CTPData()->ReadoutList(*GetTriggerData());
655 ctpreadout.Enable(AliHLTReadoutList::kHLT);
656 readoutlist.AndEq(ctpreadout);
657 decision.ReadoutList(readoutlist); // override the readout list with the masked one.
659 else if (softwareTriggerIsValid)
661 assert(fCDH != NULL);
662 AliHLTReadoutList readoutlist = decision.ReadoutList();
663 UInt_t detectors = fCDH->GetSubDetectors();
664 AliHLTReadoutList softwareReadout(Int_t(detectors | AliHLTReadoutList::kHLT));
665 readoutlist.AndEq(softwareReadout);
666 decision.ReadoutList(readoutlist); // override the readout list with the masked one.
669 if (TriggerEvent(&decision, kAliHLTDataTypeGlobalTrigger) == -ENOSPC)
671 // Increase the estimated buffer space required if the PushBack methods in TriggerEvent
672 // returned the "no buffer space" error code. Also remember to set the trigger counters
673 // back to what they were, otherwise triggers will be double counted when we try to reprocess
674 // this event with larger buffers.
675 fBufferSizeConst += 1024*1024;
676 fBufferSizeMultiplier *= 2.;
677 fTrigger->SetCounters(originalCounters);
678 if (fTrigger->CallFailed()) return -EPROTO;
682 ++fTotalEventCounter;
687 int AliHLTGlobalTriggerComponent::Reconfigure(const char* cdbEntry, const char* chainId)
689 // Reconfigure the component by loading the trigger menu and recreating the
690 // trigger logic class.
692 const char* path = fgkTriggerMenuCDBPath;
693 const char* id = "(unknown)";
694 if (cdbEntry != NULL) path = cdbEntry;
695 if (chainId != NULL and chainId[0] != '\0') id = chainId;
696 HLTInfo("Reconfiguring from '%s' for chain component '%s'.", path, id);
698 const AliHLTTriggerMenu* menu = NULL;
699 int result = LoadTriggerMenu(path, menu);
700 if (result != 0) return result;
703 TString codeFileName;
704 result = GenerateTrigger(menu, className, codeFileName, fIncludePaths, fIncludeFiles);
705 if (result != 0) return result;
707 AliHLTGlobalTrigger* trigger = NULL;
710 trigger = AliHLTGlobalTrigger::CreateNew(className.Data());
712 catch (const std::bad_alloc&)
714 HLTError("Could not allocate memory for the AliHLTGlobalTrigger instance.");
719 HLTError("Could not create a new instance of '%s'.", className.Data());
720 // Make sure to cleanup after the new code file.
721 UnloadTriggerClass(codeFileName);
722 if (not codeFileName.IsNull() and gSystem->AccessPathName(codeFileName)==0 and not fDebugMode)
724 codeFileName.ReplaceAll(".cxx", "*");
725 TString command="rm "; command+=codeFileName;
726 gSystem->Exec(command);
731 if (fTrigger != NULL)
738 fTrigger->FillFromMenu(*menu);
739 if (fTrigger->CallFailed()) return -EPROTO;
741 // Set the default values from the trigger menu.
742 SetDescription(menu->DefaultDescription());
743 SetTriggerDomain(menu->DefaultTriggerDomain());
745 // Cleanup the old class code.
746 UnloadTriggerClass(fCodeFileName);
747 if (fDeleteCodeFile and not fCodeFileName.IsNull() and gSystem->AccessPathName(fCodeFileName)==0 and not fDebugMode)
749 fCodeFileName.ReplaceAll(".cxx", "*");
750 TString command="rm "; command+=fCodeFileName;
751 gSystem->Exec(command);
753 fCodeFileName = codeFileName;
754 fDeleteCodeFile = true; // Since we generated a new class.
760 int AliHLTGlobalTriggerComponent::LoadTriggerMenu(const char* cdbPath, const AliHLTTriggerMenu*& menu)
762 // Loads the trigger menu object from the CDB path.
764 HLTDebug("Trying to load trigger menu from '%s'.", cdbPath);
765 TObject* obj = LoadAndExtractOCDBObject(cdbPath);
768 HLTError("Configuration object for \"%s\" is missing.", cdbPath);
771 if (obj->IsA() != AliHLTTriggerMenu::Class())
773 HLTError("Wrong type for configuration object in \"%s\". Found a %s but we expect a AliHLTTriggerMenu.",
774 cdbPath, obj->ClassName()
778 menu = static_cast<AliHLTTriggerMenu*>(obj);
783 void AliHLTGlobalTriggerComponent::GenerateFileName(TString& name, TString& filename)
785 // Creates a unique file name for the generated code.
787 TUUID guid = GenerateGUID();
794 fUniqueID = bufAsInt[0];
795 TString guidstr = guid.AsString();
796 // Replace '-' with '_' in string.
797 for (int i = 0; i < guidstr.Length(); ++i)
799 if (guidstr[i] == '-') guidstr[i] = '_';
801 name = "AliHLTGlobalTriggerImpl_";
803 filename = name + ".cxx";
805 // For good measure, check that the file names are not used. If they are then regenerate.
806 fstream file(filename.Data(), ios_base::in);
810 GenerateFileName(name, filename);
815 int AliHLTGlobalTriggerComponent::GenerateTrigger(
816 const AliHLTTriggerMenu* menu, TString& name, TString& filename,
817 const TClonesArray& includePaths, const TClonesArray& includeFiles
820 // Generates the global trigger class that will implement the specified trigger menu.
821 // See header for more details.
823 GenerateFileName(name, filename);
824 HLTDebug("Generating custom HLT trigger class named %s, in file %s, using trigger menu %p.",
825 name.Data(), filename.Data(), ((void*)menu)
828 // Open a text file to write the code and generate the new class.
829 fstream code(filename.Data(), ios_base::out | ios_base::trunc);
832 HLTError("Could not open file '%s' for writing.", filename.Data());
836 TClonesArray symbols(AliHLTTriggerMenuSymbol::Class());
837 int result = BuildSymbolList(menu, symbols);
838 if (result != 0) return result;
840 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
841 code << "#include <cstring>" << endl;
842 code << "#include \"TClass.h\"" << endl;
843 code << "#include \"TString.h\"" << endl;
844 code << "#include \"TClonesArray.h\"" << endl;
845 code << "#include \"TRandom3.h\"" << endl;
846 code << "#include \"AliHLTLogging.h\"" << endl;
847 code << "#include \"AliHLTGlobalTrigger.h\"" << endl;
848 code << "#include \"AliHLTGlobalTriggerDecision.h\"" << endl;
849 code << "#include \"AliHLTDomainEntry.h\"" << endl;
850 code << "#include \"AliHLTTriggerDomain.h\"" << endl;
851 code << "#include \"AliHLTReadoutList.h\"" << endl;
852 code << "#include \"AliHLTTriggerMenu.h\"" << endl;
853 code << "#include \"AliHLTTriggerMenuItem.h\"" << endl;
854 code << "#include \"AliHLTTriggerMenuSymbol.h\"" << endl;
856 // Add any include files that were specified on the command line.
857 for (Int_t i = 0; i < includeFiles.GetEntriesFast(); i++)
859 TString file = static_cast<TObjString*>(includeFiles.UncheckedAt(i))->String();
860 code << "#include \"" << file.Data() << "\"" << endl;
865 code << "#else" << endl;
866 code << "const char* gFunctionName = \"???\";" << endl;
867 code << "#define HLTDebug(msg) if (CheckFilter(kHLTLogDebug) && CheckGroup(Class_Name())) SendMessage(kHLTLogDebug, Class_Name(), ::gFunctionName, __FILE__, __LINE__, msg)" << endl;
869 code << "#endif" << endl;
871 code << "class " << name << " :" << endl;
872 // Add appropriate #ifdef sections since we need to prevent inheritance from
873 // AliHLTGlobalTrigger. CINT does not seem to support multiple inheritance nor
874 // multiple levels of inheritance. Neither of the following schemes worked:
876 // 1) class AliHLTGlobalTrigger : public AliHLTLogging {};
877 // class AliHLTGlobalTriggerImpl_xyz : public AliHLTGlobalTrigger {};
879 // 2) class AliHLTGlobalTrigger {};
880 // class AliHLTGlobalTriggerImpl_xyz : public AliHLTGlobalTrigger, public AliHLTLogging {};
882 // Thus, we are forced to just inherit from AliHLTLogging when running in the CINT
883 // interpreter. But we anyway have to call the global trigger implementation class
884 // through the AliHLTGlobalTriggerWrapper so this is not such a problem.
885 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
886 code << " public AliHLTGlobalTrigger," << endl;
887 code << "#endif" << endl;
888 code << " public AliHLTLogging" << endl;
890 code << "public:" << endl;
892 // Generate constructor method.
893 code << " " << name << "() :" << endl;
894 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
895 code << " AliHLTGlobalTrigger()," << endl;
896 code << "#endif" << endl;
897 code << " AliHLTLogging()";
898 // Write the symbols in the trigger menu in the initialisation list.
899 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
902 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
903 code << " " << symbol->Name() << "()," << endl;
904 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
906 code << " " << symbol->Name() << "TriggerDomain()," << endl;
908 code << " " << symbol->Name() << "DomainEntry(kAliHLTAnyDataType)";
910 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
912 code << "," << endl << " fMenuItemDescription" << i << "()";
914 code << endl << " {" << endl;
917 code << "#ifdef __CINT__" << endl;
918 code << " gFunctionName = \"" << name.Data() <<"\";" << endl;
919 code << "#endif" << endl;
920 code << " SetLocalLoggingLevel(kHLTLogAll);" << endl;
921 code << " HLTDebug(Form(\"Creating new instance at %p.\", this));" << endl;
923 code << " }" << endl;
925 code << " virtual ~" << name << "() {" << endl;
928 code << "#ifdef __CINT__" << endl;
929 code << " gFunctionName = \"~" << name.Data() << "\";" << endl;
930 code << "#endif" << endl;
931 code << " HLTDebug(Form(\"Deleting instance at %p.\", this));" << endl;
933 code << " }" << endl;
935 // Generate the FillFromMenu method.
936 code << " virtual void FillFromMenu(const AliHLTTriggerMenu& menu) {" << endl;
939 code << "#ifdef __CINT__" << endl;
940 code << " gFunctionName = \"FillFromMenu\";" << endl;
941 code << "#endif" << endl;
942 code << " HLTDebug(Form(\"Filling description entries from trigger menu for global trigger %p.\", this));" << endl;
944 code << " fCounter.Set(menu.NumberOfItems());" << endl;
945 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
947 code << " fMenuItemDescription" << i << " = (menu.Item(" << i
948 << ") != NULL) ? menu.Item(" << i << ")->Description() : \"\";" << endl;
952 code << " HLTDebug(Form(\"Finished filling description entries from trigger menu.\"));" << endl;
953 code << " HLTDebug(Form(\"Filling domain entries from trigger menu symbols for global trigger %p.\", this));" << endl;
955 code << " for (Int_t i = 0; i < menu.SymbolArray().GetEntriesFast(); i++) {" << endl;
956 // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
957 // Have to use the TClass system for extra protection.
958 code << " if (menu.SymbolArray().UncheckedAt(i) == NULL) continue;" << endl;
959 code << " if (menu.SymbolArray().UncheckedAt(i)->IsA() != AliHLTTriggerMenuSymbol::Class()) continue;" << endl;
960 code << " const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const"
961 " AliHLTTriggerMenuSymbol*>(menu.SymbolArray().UncheckedAt(i));" << endl;
962 code << " if (symbol == NULL) continue;" << endl;
963 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
965 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
966 code << " if (strcmp(symbol->RealName(), \"" << symbol->RealName() << "\") == 0) {" << endl;
969 code << " HLTDebug(Form(\"Assinging domain entry value corresponding with symbol '%s' to '%s'.\","
970 " symbol->RealName(), symbol->BlockType().AsString().Data()));" << endl;
972 code << " " << symbol->Name() << "DomainEntry = symbol->BlockType();" << endl;
973 code << " continue;" << endl;
974 code << " }" << endl;
976 code << " }" << endl;
977 // The following is an optimisation where symbols without any assignment operators
978 // are treated as constant and only initialised in FillFromMenu rather than reseting
979 // them in the NewEvent method.
980 // Note: we putting this initialisation into the constructor can lead to seg faults
981 // under CINT interpretation. Thus we must put it into the FillFromMenu method instead.
982 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
984 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
985 if (TString(symbol->AssignExpression()) != "") continue;
986 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0) continue;
987 // CINT has problems with the implicit equals operator for complex types, so if
988 // the type has an equals operater we need to write the operator call explicitly.
989 TClass* clas = TClass::GetClass(symbol->Type());
990 if (clas != NULL and clas->GetMethodAny("operator=") != NULL)
992 code << " " << symbol->Name() << ".operator = (" << symbol->DefaultValue() << ");" << endl;
996 code << " " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
1001 code << " HLTDebug(Form(\"Finished filling domain entries from trigger menu symbols.\"));" << endl;
1003 code << " }" << endl;
1005 // Generate the NewEvent method.
1006 code << " virtual void NewEvent() {" << endl;
1009 code << "#ifdef __CINT__" << endl;
1010 code << " gFunctionName = \"NewEvent\";" << endl;
1011 code << "#endif" << endl;
1012 code << " HLTDebug(Form(\"New event for global trigger object %p, initialising variables to default values.\", this));" << endl;
1014 // Write code to initialise the symbols in the trigger menu to their default values.
1015 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1017 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1018 // The following is an optimisation. If the symbol does not have an assignment expression
1019 // then it is effectively a constant symbol and can be initialised earlier and only once.
1020 // In this case we initialise it in the FillFromMenu method instead.
1021 if (TString(symbol->AssignExpression()) == "") continue;
1022 // CINT has problems with the implicit equals operator for complex types, so if
1023 // the type has an equals operater we need to write the operator call explicitly.
1024 TClass* clas = TClass::GetClass(symbol->Type());
1025 if (clas != NULL and clas->GetMethodAny("operator=") != NULL)
1027 code << " " << symbol->Name() << ".operator = (" << symbol->DefaultValue() << ");" << endl;
1031 code << " " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
1033 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
1035 code << " " << symbol->Name() << "TriggerDomain.Clear();" << endl;
1040 code << " HLTDebug(Form(\"Finished initialising variables.\"));" << endl;
1042 code << " }" << endl;
1044 // Generate the Add method.
1045 bool haveAssignments = false;
1046 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1048 // First check if we have any symbols with assignment expressions.
1049 // This is needed to get rid of the on the fly compilation warning about '_object_' not being used.
1050 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1051 TString expr = symbol->AssignExpression();
1052 if (expr == "") continue; // Skip entries that have no assignment expression.
1053 haveAssignments = true;
1056 if (haveAssignments or fDebugMode)
1058 code << " virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
1062 code << " virtual void Add(const TObject* /*_object_*/, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
1066 code << "#ifdef __CINT__" << endl;
1067 code << " gFunctionName = \"Add\";" << endl;
1068 code << "#endif" << endl;
1070 code << " AliHLTDomainEntry _type_spec_(_type_, _spec_);" << endl;
1073 code << " HLTDebug(Form(\"Adding TObject %p, with class name '%s' from data block"
1074 " '%s', to global trigger object %p\", _object_, _object_->ClassName(),"
1075 " _type_spec_.AsString().Data(), this));" << endl;
1076 code << " _object_->Print();" << endl;
1077 code << " bool _object_assigned_ = false;" << endl;
1079 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1081 // Write code to check if the block type, specification and class name is correct.
1082 // Then write code to assign the variable from the input object.
1083 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1084 TString expr = symbol->AssignExpression();
1085 if (expr == "") continue; // Skip entries that have no assignment expression.
1086 bool isTrigDecision = strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0;
1091 code << " HLTDebug(Form(\"Trying to match input object to class '"
1092 << symbol->ObjectClass() << "', trigger name '" << symbol->RealName()
1093 << "' and block type '%s'\", " << symbol->Name()
1094 << "DomainEntry.AsString().Data()));" << endl;
1098 code << " HLTDebug(Form(\"Trying to match input object to class '"
1099 << symbol->ObjectClass() << "' and block type '%s'\", "
1100 << symbol->Name() << "DomainEntry.AsString().Data()));" << endl;
1103 // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
1104 // Have to use the TClass system for extra protection.
1105 code << " const " << symbol->ObjectClass() << "* " << symbol->Name() << "_object_ = NULL;" << endl;
1106 code << " if (_object_->InheritsFrom(" << symbol->ObjectClass() << "::Class())) " << symbol->Name()
1107 << "_object_ = dynamic_cast<const " << symbol->ObjectClass()
1108 << "*>(_object_);" << endl;
1109 code << " if (" << symbol->Name() << "_object_ != NULL && ";
1112 code << "strcmp(" << symbol->Name() << "_object_->Name(), \""
1113 << symbol->RealName() << "\") == 0 && ";
1115 code << symbol->Name() << "DomainEntry == _type_spec_) {" << endl;
1116 TString fullname = symbol->Name();
1117 fullname += "_object_";
1118 expr.ReplaceAll("this", fullname);
1119 code << " this->" << symbol->Name() << " = " << expr.Data() << ";" << endl;
1122 code << " this->" << symbol->Name() << "TriggerDomain = "
1123 << fullname.Data() << "->TriggerDomain();" << endl;
1127 code << " HLTDebug(Form(\"Added TObject %p with class name '%s' to variable "
1128 << symbol->Name() << "\", _object_, _object_->ClassName()));" << endl;
1129 code << " _object_assigned_ = true;" << endl;
1131 code << " }" << endl;
1135 code << " if (! _object_assigned_) {" << endl;
1136 code << " HLTDebug(Form(\"Did not assign TObject %p"
1137 " with class name '%s' to any variable.\", _object_, _object_->ClassName()));"
1139 code << " }" << endl;
1141 code << " }" << endl;
1143 // Generate the CalculateTriggerDecision method.
1144 // This requires code to be generated that checks which items in the trigger menu
1145 // have their conditions asserted and then the trigger domain is generated from
1146 // those fired items.
1147 // The processing will start from the highest priority trigger group and stop
1148 // after at least one trigger from the current priority group being processed
1149 // is positive. For each priority group all the trigger menu items are checked.
1150 // Their combined trigger condition expression must be true for the trigger priority
1151 // group to be triggered positive. The full condition expression is formed by
1152 // concatenating the individual condition expressions. If no trailing operators are
1153 // used in the individual expressions then the default condition operator is placed
1154 // between two concatenated condition expressions.
1155 // If a trigger priority group has at least one trigger fired then the trigger domain
1156 // is calculated such that it will give the same result as the concatenated trigger
1157 // domain merging expressions for all the individual trigger menu items with
1158 // positive results. Again, if no trailing operators are used in the individual
1159 // merging expressions then the default domain operator is placed between two
1160 // expression fragments.
1161 code << " virtual bool CalculateTriggerDecision(bool& _trigger_result_, AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl;
1164 code << "#ifdef __CINT__" << endl;
1165 code << " gFunctionName = \"CalculateTriggerDecision\";" << endl;
1166 code << "#endif" << endl;
1167 code << " HLTDebug(Form(\"Calculating global HLT trigger result with trigger object at %p.\", this));" << endl;
1170 // Build a list of priorities used in the trigger menu.
1171 std::vector<UInt_t> priorities;
1172 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1174 const AliHLTTriggerMenuItem* item = menu->Item(i);
1175 bool priorityNotInList = std::find(priorities.begin(), priorities.end(), item->Priority()) == priorities.end();
1176 if (priorityNotInList) priorities.push_back(item->Priority());
1178 std::sort(priorities.begin(), priorities.end(), AliHLTDescendingNumbers);
1179 // From the priority list, build the priority groups in the correct order,
1180 // i.e. highest priority first.
1181 // The priority group is a list of vectors of integers. The integers are the
1182 // index numbers into the trigger menu item list for the items which form part
1183 // of the priority group.
1184 std::vector<std::vector<Int_t> > priorityGroup;
1185 priorityGroup.insert(priorityGroup.begin(), priorities.size(), std::vector<Int_t>());
1186 for (size_t n = 0; n < priorities.size(); n++)
1188 UInt_t priority = priorities[n];
1189 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1191 const AliHLTTriggerMenuItem* item = menu->Item(i);
1192 if (item->Priority() == priority) priorityGroup[n].push_back(i);
1196 for (size_t n = 0; n < priorityGroup.size(); n++)
1200 code << " HLTDebug(Form(\"Processing trigger priority group " << priorities[n] << "\"));" << endl;
1203 if (n == 0) code << "UInt_t ";
1204 code << "_previous_match_ = 0xFFFFFFFF;" << endl;
1206 if (n == 0) code << "bool ";
1207 code << "_trigger_matched_ = false;" << endl;
1209 if (n == 0) code << "bool ";
1210 code << "_group_result_ = false;" << endl;
1211 std::vector<TString> conditionOperator;
1212 conditionOperator.insert(conditionOperator.begin(), priorityGroup[n].size(), TString(""));
1213 std::vector<TString> domainOperator;
1214 domainOperator.insert(domainOperator.begin(), priorityGroup[n].size(), TString(""));
1215 for (size_t m = 0; m < priorityGroup[n].size(); m++)
1217 UInt_t i = priorityGroup[n][m];
1218 const AliHLTTriggerMenuItem* item = menu->Item(i);
1219 TString triggerCondition = item->TriggerCondition();
1220 TString mergeExpr = item->MergeExpression();
1221 // Replace the symbols found in the trigger condition and merging expressions
1222 // with appropriate compilable versions.
1223 for (Int_t j = 0; j < symbols.GetEntriesFast(); j++)
1225 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(j) );
1226 bool symbolNamesDifferent = strcmp(symbol->RealName(), symbol->Name()) != 0;
1227 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
1229 TString newname = symbol->Name();
1230 newname += "TriggerDomain";
1231 mergeExpr.ReplaceAll(symbol->RealName(), newname);
1235 if (symbolNamesDifferent) mergeExpr.ReplaceAll(symbol->RealName(), symbol->Name());
1237 if (symbolNamesDifferent) triggerCondition.ReplaceAll(symbol->RealName(), symbol->Name());
1239 // We allow the trigger conditions and merging expressions to have trailing operators.
1240 // Thus, we need to extract the operators and cleanup the expressions so that they will
1241 // compile. This means that we silently ignore the trailing operator if not needed.
1242 if (ExtractedOperator(triggerCondition, conditionOperator[m]))
1244 // If the trailing operator is the same as the default operator then reset
1245 // the value in the operator list so that the default is used in the generated
1246 // code. This creates more compact code.
1247 if (conditionOperator[m] == menu->DefaultConditionOperator()) conditionOperator[m] = "";
1249 if (ExtractedOperator(mergeExpr, domainOperator[m]))
1251 if (domainOperator[m] == menu->DefaultDomainOperator()) domainOperator[m] = "";
1255 code << " HLTDebug(Form(\"Trying trigger condition " << i
1256 << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));"
1260 if (n == 0 and m == 0) code << "bool ";
1261 code << "_item_result_ = false;" << endl;
1262 code << " if (" << triggerCondition << ") {" << endl;
1263 code << " ++fCounter[" << i << "];" << endl;
1264 const char* indentation = "";
1265 // Generate the code to handle the prescalar and scale-down
1266 bool havePrescalar = item->PreScalar() != 0;
1267 bool haveScaledown = item->ScaleDown() < 1;
1268 if (havePrescalar or haveScaledown)
1272 if (havePrescalar) code << "(fCounter[" << i << "] % " << item->PreScalar() << ") == 1";
1273 if (havePrescalar and haveScaledown) code << " && ";
1276 std::streamsize oldprecision = code.precision(17);
1277 code << "gRandom->Rndm() < " << item->ScaleDown();
1278 code.precision(oldprecision);
1280 code << ") {" << endl;
1282 code << indentation << " _item_result_ = true;" << endl;
1285 code << indentation << " HLTDebug(Form(\"Matched trigger condition " << i
1286 << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));" << endl;
1288 if (havePrescalar or haveScaledown)
1290 code << " }" << endl;
1292 code << " }" << endl;
1295 // Since this is the first item of the trigger group,
1296 // the generated trigger logic can be simplified a little.
1297 code << " _group_result_ = _item_result_;" << endl;
1298 code << " if (_item_result_) {" << endl;
1299 code << " _domain_ = " << mergeExpr.Data() << ";" << endl;
1300 code << " _description_ = fMenuItemDescription" << i << ";" << endl;
1301 code << " _previous_match_ = " << i << ";" << endl;
1302 code << " _trigger_matched_ = true;" << endl;
1303 code << " }" << endl;
1307 if (conditionOperator[m-1] == "")
1309 code << " _group_result_ = _group_result_ "
1310 << menu->DefaultConditionOperator() << " _item_result_;" << endl;
1314 code << " _group_result_ = _group_result_ "
1315 << conditionOperator[m-1] << " _item_result_;" << endl;
1317 code << " if (_item_result_) {" << endl;
1318 code << " if (_trigger_matched_) {" << endl;
1319 bool switchWillBeEmpty = true;
1320 for (size_t k = 0; k < m; k++)
1322 if (domainOperator[k] == "") continue;
1323 switchWillBeEmpty = false;
1325 if (switchWillBeEmpty)
1327 code << " _domain_ = _domain_ " << menu->DefaultDomainOperator() << " "
1328 << mergeExpr.Data() << ";" << endl;
1332 code << " switch(_previous_match_) {" << endl;
1333 for (size_t k = 0; k < m; k++)
1335 if (domainOperator[k] == "") continue;
1336 code << " case " << k << ": _domain_ = _domain_ "
1337 << domainOperator[k] << " " << mergeExpr.Data() << "; break;" << endl;
1339 code << " default: _domain_ = _domain_ "
1340 << menu->DefaultDomainOperator() << " " << mergeExpr.Data() << ";" << endl;
1341 code << " }" << endl;
1343 code << " _description_ += \",\";" << endl;
1344 code << " _description_ += fMenuItemDescription" << i << ";" << endl;
1345 code << " } else {" << endl;
1346 code << " _domain_ = " << mergeExpr.Data() << ";" << endl;
1347 code << " _description_ = fMenuItemDescription" << i << ";" << endl;
1348 code << " }" << endl;
1349 code << " _previous_match_ = " << i << ";" << endl;
1350 code << " _trigger_matched_ = true;" << endl;
1351 code << " }" << endl;
1354 code << " if (_group_result_) {" << endl;
1357 if (n < priorities.size() - 1)
1359 code << " HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n]
1360 << ". Stopping processing here because all other trigger groups have lower priority.\"));" << endl;
1364 code << " HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n] << ".\"));" << endl;
1367 bool methodReturnResult = true;
1368 if (priorityGroup[n].size() > 0)
1370 const AliHLTTriggerMenuItem* item = menu->Item(priorityGroup[n][0]);
1371 methodReturnResult = item->DefaultResult();
1373 // Check to see if the items of the group all have the same default result.
1374 // If not then warn the user since only the first item's value will be used.
1375 for (size_t m = 1; m < priorityGroup[n].size(); m++)
1377 const AliHLTTriggerMenuItem* item = menu->Item(priorityGroup[n][m]);
1378 if (item->DefaultResult() != methodReturnResult)
1380 HLTWarning("Found items with different default results set for priority group %d."
1381 "Will only use the value from the first item.",
1387 code << " _trigger_result_ = " << (methodReturnResult ? "true" : "false") << ";" << endl;
1388 code << " return true;" << endl;
1389 code << " }" << endl;
1391 code << " _domain_.Clear();" << endl;
1392 code << " _description_ = \"\";" << endl;
1393 code << " _trigger_result_ = " << (menu->DefaultResult() ? "true" : "false") << ";" << endl;
1394 code << " return false;" << endl;
1395 code << " }" << endl;
1397 // Generate getter and setter methods for the counters.
1398 code << " const TArrayL64& GetCounters() const { return fCounter; }" << endl;
1399 code << " void SetCounters(const TArrayL64& counters) { fCounter = counters; }" << endl;
1401 code << "private:" << endl;
1402 // Add the symbols in the trigger menu to the list of private variables.
1403 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1405 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1406 code << " " << symbol->Type() << " " << symbol->Name() << ";" << endl;
1407 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
1409 code << " AliHLTTriggerDomain " << symbol->Name() << "TriggerDomain;" << endl;
1411 code << " AliHLTDomainEntry " << symbol->Name() << "DomainEntry;" << endl;
1413 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1415 code << " TString fMenuItemDescription" << i << ";" << endl;
1417 code << " TArrayL64 fCounter;" << endl;
1418 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
1419 code << " ClassDef(" << name.Data() << ", 0)" << endl;
1420 code << "#else" << endl;
1421 code << " virtual const char* Class_Name() const { return \"" << name.Data() << "\"; }" << endl;
1422 code << "#endif" << endl;
1423 code << "};" << endl;
1424 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
1425 code << "ClassImp(" << name.Data() << ")" << endl;
1426 code << "#endif" << endl;
1430 // Now we need to compile and load the new class.
1431 result = LoadTriggerClass(filename, includePaths);
1436 int AliHLTGlobalTriggerComponent::LoadTriggerClass(
1437 const char* filename, const TClonesArray& includePaths
1440 // Loads the code for a custom global trigger class implementation on the fly.
1442 HLTDebug("Loading HLT trigger class from file '%s'.", filename);
1444 TString compiler = gSystem->GetBuildCompilerVersion();
1445 if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc")))
1447 TString includePath;
1448 #if defined(PKGINCLUDEDIR)
1449 // this is especially for the HLT build system where the package is installed
1450 // in a specific directory including proper treatment of include files
1451 includePath.Form("-I%s", PKGINCLUDEDIR);
1453 // the default AliRoot behavior, all include files can be found in the
1454 // $ALICE_ROOT subfolders
1455 includePath = "-I${ALICE_ROOT}/include -I${ALICE_ROOT}/HLT/BASE -I${ALICE_ROOT}/HLT/trigger";
1457 // Add any include paths that were specified on the command line.
1458 for (Int_t i = 0; i < includePaths.GetEntriesFast(); i++)
1460 TString path = static_cast<TObjString*>(includePaths.UncheckedAt(i))->String();
1461 includePath += " -I";
1462 includePath += path;
1464 HLTDebug("using include settings: %s", includePath.Data());
1465 gSystem->SetIncludePath(includePath);
1466 gSystem->SetFlagsOpt("-O3 -DNDEBUG");
1467 gSystem->SetFlagsDebug("-g3 -DDEBUG -D__DEBUG");
1472 result = gSystem->CompileMacro(filename, "g");
1476 result = gSystem->CompileMacro(filename, "O");
1478 if (result != kTRUE)
1480 HLTFatal("Could not compile and load global trigger menu implementation.");
1486 // Store the library state to be checked later in UnloadTriggerClass.
1487 fLibStateAtLoad = gSystem->GetLibraries();
1489 // If we do not support the compiler then try interpret the class instead.
1490 TString cmd = ".L ";
1492 Int_t errorcode = TInterpreter::kNoError;
1493 gROOT->ProcessLine(cmd, &errorcode);
1494 if (errorcode != TInterpreter::kNoError)
1496 HLTFatal("Could not load interpreted global trigger menu implementation"
1497 " (Interpreter error code = %d).",
1508 int AliHLTGlobalTriggerComponent::UnloadTriggerClass(const char* filename)
1510 // Unloads the code previously loaded by LoadTriggerClass.
1512 HLTDebug("Unloading HLT trigger class in file '%s'.", filename);
1514 TString compiler = gSystem->GetBuildCompilerVersion();
1515 if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc")))
1517 // Generate the library name.
1518 TString libname = filename;
1519 Ssiz_t dotpos = libname.Last('.');
1520 if (0 <= dotpos and dotpos < libname.Length()) libname[dotpos] = '_';
1522 libname += gSystem->GetSoExt();
1524 // This is a workaround for a problem with unloading shared libraries in ROOT.
1525 // If the trigger logic library is loaded before the libAliHLTHOMER.so library
1526 // or any other library is loaded afterwards, then during the gInterpreter->UnloadFile
1527 // call all the subsequent libraries get unloded. This means that any objects created
1528 // from classes implemented in the libAliHLTHOMER.so library will generate segfaults
1529 // since the executable code has been unloaded.
1530 // We need to check if there are any more libraries loaded after the class we
1531 // are unloading and in that case don't unload the class.
1532 TString libstring = gSystem->GetLibraries();
1533 TString token, lastlib;
1535 Int_t numOfLibs = 0, posOfLib = -1;
1536 while (libstring.Tokenize(token, from, " "))
1540 if (token.Contains(libname)) posOfLib = numOfLibs;
1542 if (numOfLibs != posOfLib)
1544 HLTWarning(Form("ROOT limitation! Cannot properly cleanup and unload the shared"
1545 " library '%s' since another library '%s' was loaded afterwards. Trying to"
1546 " unload this library will remove the others and lead to serious memory faults.",
1547 libname.Data(), lastlib.Data()
1554 if ((path = gSystem->DynamicPathName(libname)) != NULL)
1556 result = gInterpreter->UnloadFile(path);
1559 if (result != TInterpreter::kNoError) return -ENOENT;
1563 // This is again a workaround for the problem with unloading files in ROOT.
1564 // If the trigger logic class is loaded before the libAliHLTHOMER.so library
1565 // or any other library is loaded afterwards, then during the gInterpreter->UnloadFile
1566 // call all the subsequent libraries get unloded.
1567 // We need to check if the list of loaded libraries has changed since the last
1568 // call to LoadTriggerClass. If it has then don't unload the class.
1569 if (fLibStateAtLoad != gSystem->GetLibraries())
1571 TString libstring = gSystem->GetLibraries();
1574 while (libstring.Tokenize(token, from, " "))
1576 if (not fLibStateAtLoad.Contains(token)) break;
1578 HLTWarning(Form("ROOT limitation! Cannot properly cleanup and unload the file"
1579 " '%s' since another library '%s' was loaded afterwards. Trying to unload"
1580 " this file will remove the other library and lead to serious memory faults.",
1581 filename, token.Data()
1586 // If we did not compile the trigger logic then remove the interpreted class.
1587 TString cmd = ".U ";
1589 Int_t errorcode = TInterpreter::kNoError;
1590 gROOT->ProcessLine(cmd, &errorcode);
1591 if (errorcode != TInterpreter::kNoError)
1593 HLTFatal("Could not unload interpreted global trigger menu implementation"
1594 " (Interpreter error code = %d).",
1605 int AliHLTGlobalTriggerComponent::FindSymbol(const char* name, const TClonesArray& list)
1607 // Searches for the named symbol in the given list.
1608 // See header for more details.
1610 for (int i = 0; i < list.GetEntriesFast(); i++)
1612 const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(i) );
1613 if (symbol == NULL) continue;
1614 if (strcmp(symbol->Name(), name) == 0) return i;
1623 * Helper routine to compare two trigger menu symbols to see if b is a subset of a.
1624 * \returns true if b is a subset of a or they are unrelated.
1626 bool AliHLTCheckForContainment(const AliHLTTriggerMenuSymbol* a, const AliHLTTriggerMenuSymbol* b)
1628 TString bstr = b->Name();
1629 return bstr.Contains(a->Name());
1632 } // end of namespace
1635 int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, TClonesArray& list)
1637 // Builds the list of symbols to use in the custom global trigger menu
1638 // implementation class.
1639 // See header for more details.
1641 // Note: when we build the symbol list we must use the symbol name as returned
1642 // by the Name() method and not the RealName() method when using FindSymbol.
1643 // This is so that we avoid problems with the generated code not compiling
1644 // because names like "abc-xyz" and "abc_xyz" are synonymous.
1645 // Name() returns the converted C++ symbol name as used in the generated code.
1647 for (UInt_t i = 0; i < menu->NumberOfSymbols(); i++)
1649 const AliHLTTriggerMenuSymbol* symbol = menu->Symbol(i);
1650 if (FindSymbol(symbol->Name(), list) != -1)
1652 HLTError("Multiple symbols with the name '%s' defined in the trigger menu.", symbol->Name());
1657 new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
1659 catch (const std::bad_alloc&)
1661 HLTError("Could not allocate more memory for the symbols list when adding a trigger menu symbol.");
1665 Int_t initialEntryCount = list.GetEntriesFast();
1667 // Note: the \\. must not be the first element in the character class, otherwise
1668 // it is interpreted as an "any character" dot symbol.
1669 TRegexp exp("[_a-zA-Z][-\\._a-zA-Z0-9]*");
1670 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1672 const AliHLTTriggerMenuItem* item = menu->Item(i);
1673 TString str = item->TriggerCondition();
1678 Ssiz_t pos = exp.Index(str, &length, start);
1679 if (pos == kNPOS) break;
1682 // Check if there is a numerical character before the found
1683 // regular expression. If so, then the symbol is not a valid one
1684 // and should be skipped.
1687 bool notValid = false;
1690 case '0': case '1': case '2': case '3': case '4':
1691 case '5': case '6': case '7': case '8': case '9':
1698 if (notValid) continue;
1700 TString s = str(pos, length);
1702 if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
1703 s == "compl" or s == "not" or s == "not_eq" or s == "or" or
1704 s == "or_eq" or s == "xor" or s == "xor_eq" or s == "true" or
1708 // Ignore iso646.h and other keywords.
1712 // We need to handle the special case where the symbol contains a dot.
1713 // In C++ this is a dereferencing operator. So we need to check if the
1714 // current symbol we are handling starts with the same string as any of
1715 // the existing symbols defined manually in the symbols table.
1716 // If we do find such a case then revert to treating the dot as an operator
1717 // rather than part of the symbol name. i.e. skip adding the automatic symbol.
1718 bool dereferencedSymbol = false;
1719 for (int j = 0; j < initialEntryCount; j++)
1721 const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(j) );
1722 if (symbol == NULL) continue;
1723 TString symstr = symbol->Name();
1725 if (s.BeginsWith(symstr))
1727 dereferencedSymbol = true;
1731 if (dereferencedSymbol) continue;
1733 // Need to create the symbols first and check if its name is in the list
1734 // before actually adding it to the symbols list.
1735 AliHLTTriggerMenuSymbol newSymbol;
1736 newSymbol.Name(s.Data());
1737 newSymbol.Type("bool");
1738 newSymbol.ObjectClass("AliHLTTriggerDecision");
1739 newSymbol.AssignExpression("this->Result()");
1740 newSymbol.DefaultValue("false");
1741 if (FindSymbol(newSymbol.Name(), list) == -1)
1745 new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
1747 catch (const std::bad_alloc&)
1749 HLTError("Could not allocate more memory for the symbols list when adding a trigger name symbol.");
1754 while (start < str.Length());
1757 // This last part is necessary to make sure that symbols are replaced in the
1758 // trigger condition and domain merging expressions in a greedy manner.
1759 // I.e. we need to make sure that if one symbol's string representation is
1760 // contained inside another (string subset) that the longer symbol name is
1761 // always first in the symbols list.
1762 // This will work because the symbol table is traversed from first to last
1763 // element and TString::ReplaceAll is used to replace the substrings inside
1764 // the AliHLTGlobalTriggerComponent::GenerateTrigger method.
1765 std::vector<AliHLTTriggerMenuSymbol*> orderedList;
1766 for (Int_t i = 0; i < list.GetEntriesFast(); i++)
1768 orderedList.push_back( static_cast<AliHLTTriggerMenuSymbol*>(list.UncheckedAt(i)) );
1770 std::sort(orderedList.begin(), orderedList.end(), AliHLTCheckForContainment);
1771 //std::sort(orderedList.begin(), orderedList.end());
1772 // Now swap values around according to the orderedList.
1773 for (Int_t i = 0; i < list.GetEntriesFast(); i++)
1775 AliHLTTriggerMenuSymbol* target = static_cast<AliHLTTriggerMenuSymbol*>(list.UncheckedAt(i));
1776 AliHLTTriggerMenuSymbol tmp = *target;
1777 *target = *orderedList[i];
1778 *orderedList[i] = tmp;
1785 bool AliHLTGlobalTriggerComponent::ExtractedOperator(TString& expr, TString& op)
1787 // Extracts the trailing operator from the expression.
1790 // First skip the trailing whitespace.
1791 bool whitespace = true;
1792 for (i = expr.Length()-1; i >= 0 and whitespace; i--)
1796 case ' ': case '\t': case '\r': case '\n':
1803 if (i < 0 or whitespace) return false;
1805 // Now find the first whitespace character before the trailing symbol.
1806 bool nonwhitespace = true;
1807 for (; i >= 0 and nonwhitespace; i--)
1811 case ' ': case '\t': case '\r': case '\n':
1812 nonwhitespace = false;
1815 nonwhitespace = true;
1818 if (i < 0 or nonwhitespace) return false;
1820 // Extract the last symbols and check if it is a valid operator.
1823 if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
1824 s == "compl" or s == "not" or s == "not_eq" or s == "or" or
1825 s == "or_eq" or s == "xor" or s == "xor_eq" or s == "&&" or
1826 s == "&=" or s == "&" or s == "|" or s == "~" or s == "!" or
1827 s == "!=" or s == "||" or s == "|=" or s == "^" or s == "^=" or
1828 s == "==" or s == "+" or s == "-" or s == "*" or s == "/" or
1829 s == "%" or s == ">" or s == "<" or s == ">=" or s == "<="
1841 bool AliHLTGlobalTriggerComponent::FillSoftwareTrigger()
1843 // Fills the fSoftwareTrigger structure.
1845 if (fCDH == NULL) return false;
1846 UChar_t l1msg = fCDH->GetL1TriggerMessage();
1847 if ((l1msg & 0x1) == 0x0) return false; // skip physics events.
1848 // From here on everything must be a software trigger.
1849 if (((l1msg >> 2) & 0xF) == 0xE)
1851 fSoftwareTrigger.Name("START_OF_DATA");
1852 fSoftwareTrigger.Description("Generated internal start of data trigger.");
1854 else if (((l1msg >> 2) & 0xF) == 0xF)
1856 fSoftwareTrigger.Name("END_OF_DATA");
1857 fSoftwareTrigger.Description("Generated internal end of data trigger.");
1859 else if (((l1msg >> 6) & 0x1) == 0x1)
1861 fSoftwareTrigger.Name("CALIBRATION");
1862 fSoftwareTrigger.Description("Generated internal calibration trigger.");
1866 fSoftwareTrigger.Name("SOFTWARE");
1867 fSoftwareTrigger.Description("Generated internal software trigger.");
1869 UInt_t detectors = fCDH->GetSubDetectors();
1870 fSoftwareTrigger.ReadoutList( AliHLTReadoutList(Int_t(detectors)) );
1875 int AliHLTGlobalTriggerComponent::PrintStatistics(const AliHLTGlobalTrigger* pTrigger, AliHLTComponentLogSeverity level, int offset) const
1877 // print some statistics
1878 int totalEvents=fTotalEventCounter+offset;
1879 const TArrayL64& counters = pTrigger->GetCounters();
1880 if (pTrigger->CallFailed()) return -EPROTO;
1881 for (int i = 0; i < counters.GetSize(); i++) {
1882 ULong64_t count = counters[i];
1884 if (totalEvents>0) ratio=100*(float)count/totalEvents;
1885 HLTLog(level, "Item %d: total events: %d - counted events: %llu (%.1f%%)", i, totalEvents, count, ratio);
1890 int AliHLTGlobalTriggerComponent::AddCTPDecisions(AliHLTGlobalTrigger* pTrigger, const AliHLTCTPData* pCTPData, const AliHLTComponentTriggerData* trigData)
1892 // add trigger decisions for the valid CTP classes
1893 if (!pCTPData || !pTrigger) return 0;
1895 AliHLTUInt64_t triggerMask=pCTPData->Mask();
1896 AliHLTUInt64_t bit0=0x1;
1897 if (!fCTPDecisions) {
1900 fCTPDecisions=new TClonesArray(AliHLTTriggerDecision::Class(), gkNCTPTriggerClasses);
1902 catch (const std::bad_alloc&)
1904 HLTError("Could not allocate memory for the CTP decisions array.");
1907 if (!fCTPDecisions) return -ENOMEM;
1911 fCTPDecisions->ExpandCreate(gkNCTPTriggerClasses);
1913 catch (const std::bad_alloc&)
1915 HLTError("Could not allocate more memory for the CTP decisions array.");
1918 for (int i=0; i<gkNCTPTriggerClasses; i++) {
1919 const char* name=pCTPData->Name(i);
1920 if (triggerMask&(bit0<<i) && name) {
1921 AliHLTTriggerDecision* pDecision=dynamic_cast<AliHLTTriggerDecision*>(fCTPDecisions->At(i));
1924 delete fCTPDecisions;
1928 pDecision->Name(name);
1933 for (int i=0; i<gkNCTPTriggerClasses; i++) {
1934 const char* name=pCTPData->Name(i);
1935 if ((triggerMask&(bit0<<i))==0 || name==NULL) continue;
1936 AliHLTTriggerDecision* pDecision=dynamic_cast<AliHLTTriggerDecision*>(fCTPDecisions->At(i));
1937 HLTDebug("updating CTP trigger decision %d %s (%p casted %p)", i, name, fCTPDecisions->At(i), pDecision);
1938 if (!pDecision) return -ENOENT;
1941 // 13 March 2010 - Optimisation:
1942 // Dont use the EvaluateCTPTriggerClass method, which uses slow TFormula objects.
1943 AliHLTUInt64_t triggers = 0;
1944 if (trigData) triggers = pCTPData->ActiveTriggers(*trigData);
1945 else triggers = pCTPData->Triggers();
1946 result = (triggers&((AliHLTUInt64_t)0x1<<i)) ? true : false;
1947 //if (trigData) result=pCTPData->EvaluateCTPTriggerClass(name, *trigData);
1948 //else result=pCTPData->EvaluateCTPTriggerClass(name);
1949 pDecision->Result(result);
1950 pDecision->TriggerDomain().Clear();
1951 if (trigData) pDecision->TriggerDomain().Add(pCTPData->ReadoutList(*trigData));
1952 else pDecision->TriggerDomain().Add(pCTPData->ReadoutList());
1954 pTrigger->Add(fCTPDecisions->At(i), kAliHLTDataTypeTriggerDecision, kAliHLTVoidDataSpec);
1955 if (pTrigger->CallFailed()) return -EPROTO;