From 81d62bb496cb308f0efd28da3ff8165a2144feff Mon Sep 17 00:00:00 2001 From: aszostak Date: Thu, 29 Oct 2009 22:26:51 +0000 Subject: [PATCH] * Adding explicit priority settings for the global trigger menu items. This allows one to form priority groups which allows trigger menus to be operated in 3 modes: 1) The trigger menu is evaluated until the first entry matches the trigger condition and further evaluation is stopped. 2) All entries in the trigger menu are evaluated. 3) A mixture of the above two extremes. A default merging operator for the trigger condition and domain merging expressions can now be specified in the trigger menu. In addition, one can add trailing operators to the trigger condition and domain merging expressions, which are used implicitly to concatenate sub-expressions from each trigger menu for case 2 and 3 above. This gives more flexibility than just having a default merging operator. * Had to significantly change how the generated trigger logic is loaded, in particular to be able to use CINT to interpret the code. Got rid of the class factory concept in AliHLTGlobalTrigger and simplified the class. This was necessary because the factory concept did not want to work with CINT. Had to add the AliHLTGlobalTriggerWrapper class which interfaces between compiled code and an interpreted AliHLTGlobalTrigger class. * Interpreting of trigger menu logic rather than on the fly compilation now works (however compilation is default for speed). * Adding proper unit tests for the global trigger component in testGlobalTriggerComponent.C * Added a comparison operator to the AliHLTTriggerDomain that can be used to compare if two domains are equivalent. * Also improved the class documentation. --- HLT/BASE/AliHLTDomainEntry.h | 2 + HLT/BASE/AliHLTGlobalTriggerDecision.cxx | 2 +- HLT/BASE/AliHLTGlobalTriggerDecision.h | 67 +- HLT/BASE/AliHLTTriggerDecision.cxx | 10 + HLT/BASE/AliHLTTriggerDecision.h | 6 +- HLT/BASE/AliHLTTriggerDomain.cxx | 116 ++- HLT/BASE/AliHLTTriggerDomain.h | 10 + HLT/BASE/AliHLTTriggerMenu.cxx | 40 +- HLT/BASE/AliHLTTriggerMenu.h | 105 ++- HLT/BASE/AliHLTTriggerMenuItem.cxx | 7 +- HLT/BASE/AliHLTTriggerMenuItem.h | 43 +- HLT/BASE/AliHLTTriggerMenuSymbol.cxx | 2 +- HLT/BASE/AliHLTTriggerMenuSymbol.h | 39 +- HLT/libAliHLTTrigger.pkg | 2 + HLT/trigger/AliHLTGlobalTrigger.cxx | 95 +-- HLT/trigger/AliHLTGlobalTrigger.h | 118 +-- HLT/trigger/AliHLTGlobalTriggerComponent.cxx | 756 ++++++++++++++---- HLT/trigger/AliHLTGlobalTriggerComponent.h | 55 +- HLT/trigger/AliHLTGlobalTriggerConfig.cxx | 61 +- HLT/trigger/AliHLTGlobalTriggerConfig.h | 64 +- HLT/trigger/AliHLTGlobalTriggerWrapper.cxx | 282 +++++++ HLT/trigger/AliHLTGlobalTriggerWrapper.h | 111 +++ HLT/trigger/AliHLTTriggerLinkDef.h | 2 +- HLT/trigger/test/Makefile.am | 8 +- HLT/trigger/test/TriggerConfig.C | 110 ++- HLT/trigger/test/testGlobalTriggerComponent.C | 395 ++++++++- 26 files changed, 2089 insertions(+), 419 deletions(-) create mode 100644 HLT/trigger/AliHLTGlobalTriggerWrapper.cxx create mode 100644 HLT/trigger/AliHLTGlobalTriggerWrapper.h diff --git a/HLT/BASE/AliHLTDomainEntry.h b/HLT/BASE/AliHLTDomainEntry.h index 54daddff667..62adc02141f 100644 --- a/HLT/BASE/AliHLTDomainEntry.h +++ b/HLT/BASE/AliHLTDomainEntry.h @@ -205,6 +205,7 @@ class AliHLTDomainEntry : public TObject * \return true if the domain entries are identical or if they overlap (match) * due to wild card values. False is returned if there is absolutely no * overlap between this and the right hand side domain entries. + * \note No comparison is done for the exclude flag. */ bool operator == (const AliHLTDomainEntry& rhs) const { @@ -217,6 +218,7 @@ class AliHLTDomainEntry : public TObject * \return true if the domain entries do not overlap (match) in any way, also * after considering any wild card values. False is returned if the entries * are identical or if they overlap due to wild card values. + * \note No comparison is done for the exclude flag. */ bool operator != (const AliHLTDomainEntry& rhs) const { diff --git a/HLT/BASE/AliHLTGlobalTriggerDecision.cxx b/HLT/BASE/AliHLTGlobalTriggerDecision.cxx index d9a06e0ced9..03189061b86 100644 --- a/HLT/BASE/AliHLTGlobalTriggerDecision.cxx +++ b/HLT/BASE/AliHLTGlobalTriggerDecision.cxx @@ -201,7 +201,7 @@ void AliHLTGlobalTriggerDecision::SetCounters(const TArrayL64& counters, Long64_ // Sets the counter array. // If the number of events is specified, an additional counter is added at the end. fCounters = counters; - if (eventCount>0) { + if (eventCount>=0) { int size=fCounters.GetSize(); fCounters.Set(size+1); fCounters[size]=eventCount; diff --git a/HLT/BASE/AliHLTGlobalTriggerDecision.h b/HLT/BASE/AliHLTGlobalTriggerDecision.h index d96f3e46034..183d522d5aa 100644 --- a/HLT/BASE/AliHLTGlobalTriggerDecision.h +++ b/HLT/BASE/AliHLTGlobalTriggerDecision.h @@ -15,6 +15,47 @@ #include "TArrayL64.h" #include "TObjArray.h" +/** + * \class AliHLTGlobalTriggerDecision + * The global trigger decision object is generated by the AliHLTGlobalTriggerComponent + * class during processing of input triggers. + * + * Multiple input trigger components deriving from AliHLTTrigger will generate + * AliHLTTriggerDecision objects and possibly additional summary objects. All these + * objects are input for the global trigger component AliHLTGlobalTriggerComponent. + * After processing the input objects based on the trigger menu encoded in AliHLTTriggerMenu, + * the global trigger will generate and fill an AliHLTGlobalTriggerDecision object + * based on its decision. The new object will contain all the information a normal + * AliHLTTriggerDecision object generated by AliHLTTrigger contains. But in addition + * all the input objects that contributed to the global decision are also stored + * inside AliHLTGlobalTriggerDecision. The contributing trigger decisions are filled + * in fContributingTriggers and contributing summary TObjects are filled into fInputObjects. + * These can be accessed with the following methods: + * NumberOfTriggerInputs TriggerInput TriggerInputs for the + * trigger inputs; + * and NumberOfInputObjects InputObject InputObjects for the + * input summary objects. + * + * There is also an array of counters stored in the global decision. These are + * a copy of the internal counters of the global trigger component. There is one + * counter for every item in the trigger menu, plus a possible additional counter + * at the end which indicated the total number of events processed by the global + * trigger component. + * + * \note The counters do not necessarily correspond to the actual number of triggers + * that are recorded in the HLT output data stream. For most simple trigger menu + * configurations the counters will indeed correspond the the actual number of triggers + * recorded. But for more complex menus that use non zero prescalar values this may not + * be the case. The reason is that the counters array returned is the internal counter + * values (state) of the global trigger component. The counters are used to make the + * prescalars work. Thus, every time a corresponding trigger condition matches + * (evaluates to true) the counter is incremented, but the trigger decision might + * anyway skip the corresponding trigger in the menu since the prescalar is downscaling + * the trigger rate for that particular trigger menu item. This means that the counter + * values will be an upper bound. + * The real count and rate of particular triggers should always be taken by actually + * counting the trigger decision result. + */ class AliHLTGlobalTriggerDecision : public AliHLTTriggerDecision { public: @@ -124,12 +165,34 @@ class AliHLTGlobalTriggerDecision : public AliHLTTriggerDecision /** * Sets the counter array. - * If the number of events is specified, an additional counter is added at the end. + * If the number of events is specified, an additional counter is added at the end + * and filled with eventCount which indicates the number of events that have been counted. + * \param counters The array of new counter values that the internal counters should be set to. + * \param eventCount This should be the total number of events processed. If it is + * a positive number >= 0 then the extra counter is added to the array and filled + * with the value of eventCount. */ - void SetCounters(const TArrayL64& counters, Long64_t eventCount=0); + void SetCounters(const TArrayL64& counters, Long64_t eventCount = -1); /** * Returns the event trigger counters associated with the global trigger classes. + * There is one counter for every trigger menu item that the global trigger component + * was configured with. Thus the first counter will correspond to the first menu item + * added to the trigger menu, the second counter for the second item added and so on. + * If the total number of events processed counter is pressent it will be at the + * end of the array in position N-1 where N is the number of items in the counter + * array (also this will correspond to N-1 trigger menu items in the global trigger menu). + * + * \note The counters do not necessarily correspond to the actual number of trigger + * that are recorded in the HLT output data stream. For most simple trigger menu + * configurations the counters will indeed correspond the the actual number of triggers + * recorded. But for more complex menus which use prescalar values this may not be + * the case. The reason is that the counters array returned is the internal counter + * values (state) of the global trigger component. The counters are used to make the + * prescalars work. Thus every time a corresponding trigger condition matches + * (evaluates to true) the counter is incremented, but the trigger decision might + * anyhow skip the corresponding trigger in the menu since the prescalar is downscaling + * the trigger rate for that particular trigger menu item. */ const TArrayL64& Counters() const { return fCounters; } diff --git a/HLT/BASE/AliHLTTriggerDecision.cxx b/HLT/BASE/AliHLTTriggerDecision.cxx index 03daaec1c1c..9af4ba37d2e 100644 --- a/HLT/BASE/AliHLTTriggerDecision.cxx +++ b/HLT/BASE/AliHLTTriggerDecision.cxx @@ -72,6 +72,16 @@ AliHLTTriggerDecision::~AliHLTTriggerDecision() } +void AliHLTTriggerDecision::ReadoutList(const AliHLTReadoutList& value) +{ + // Replaces the readout list in the trigger domain with the new value. + + AliHLTReadoutList fullReadout = ~ AliHLTReadoutList(0x0); + fTriggerDomain.Remove(fullReadout); + fTriggerDomain.Add(value); +} + + void AliHLTTriggerDecision::Print(Option_t* option) const { // Prints the contents of the trigger decision. diff --git a/HLT/BASE/AliHLTTriggerDecision.h b/HLT/BASE/AliHLTTriggerDecision.h index 73db6630bbd..cb35a64e50c 100644 --- a/HLT/BASE/AliHLTTriggerDecision.h +++ b/HLT/BASE/AliHLTTriggerDecision.h @@ -138,11 +138,7 @@ class AliHLTTriggerDecision : public TObject /** * Sets the DDL readout list associated with this trigger decision. */ - void ReadoutList(const AliHLTReadoutList& value) - { - fTriggerDomain.Remove(kAliHLTDAQRDOUTDataTypeID, kAliHLTDataOriginAny); - fTriggerDomain.Add(value); - } + void ReadoutList(const AliHLTReadoutList& value); /** * Returns the trigger domain associated with this trigger decision. diff --git a/HLT/BASE/AliHLTTriggerDomain.cxx b/HLT/BASE/AliHLTTriggerDomain.cxx index 9489e3865c5..6de22cbf14f 100644 --- a/HLT/BASE/AliHLTTriggerDomain.cxx +++ b/HLT/BASE/AliHLTTriggerDomain.cxx @@ -147,7 +147,7 @@ AliHLTTriggerDomain::AliHLTTriggerDomain(const AliHLTTriggerDomain& domain) : for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++) { - const AliHLTDomainEntry* entry = static_cast( domain.fEntries[i] ); + const AliHLTDomainEntry* entry = static_cast( domain.fEntries.UncheckedAt(i) ); new (fEntries[fEntries.GetEntriesFast()]) AliHLTDomainEntry(*entry); } } @@ -209,7 +209,7 @@ void AliHLTTriggerDomain::Add(const AliHLTDomainEntry& entry) // because it is already part of the trigger domain. for (Int_t i = 0; i < count; i++) { - AliHLTDomainEntry* ientry = static_cast(fEntries[i]); + AliHLTDomainEntry* ientry = static_cast(fEntries.UncheckedAt(i)); if (ientry->Inclusive()) { if (entry.SubsetOf(*ientry)) @@ -342,7 +342,7 @@ void AliHLTTriggerDomain::Remove(const AliHLTDomainEntry& entry) // inclusive trigger domain entries (rules / patterns). for (Int_t i = 0; i < count; i++) { - AliHLTDomainEntry* ientry = static_cast(fEntries[i]); + AliHLTDomainEntry* ientry = static_cast(fEntries.UncheckedAt(i)); if (ientry->Inclusive()) { if (ientry->SubsetOf(entry)) @@ -432,7 +432,7 @@ bool AliHLTTriggerDomain::Contains(const AliHLTDomainEntry& entry) const bool result = false; for (Int_t i = 0; i < fEntries.GetEntriesFast(); i++) { - const AliHLTDomainEntry* ientry = static_cast(fEntries[i]); + const AliHLTDomainEntry* ientry = static_cast(fEntries.UncheckedAt(i)); if (ientry->Inclusive()) { if (*ientry == entry) result = true; @@ -458,7 +458,7 @@ bool AliHLTTriggerDomain::IncludeInReadout(const AliHLTComponentBlockData* block bool result = false; for (Int_t i = 0; i < fEntries.GetEntriesFast(); i++) { - const AliHLTDomainEntry* entry = static_cast(fEntries[i]); + const AliHLTDomainEntry* entry = static_cast(fEntries.UncheckedAt(i)); if (entry->Inclusive()) { if (*entry == block) result = true; @@ -488,7 +488,7 @@ void AliHLTTriggerDomain::Print(Option_t* /*option*/) const cout << "Trigger domain rules (applied in order of first to last):" << endl; for (Int_t i = 0; i < fEntries.GetEntriesFast(); i++) { - const AliHLTDomainEntry* entry = static_cast( fEntries[i] ); + const AliHLTDomainEntry* entry = static_cast( fEntries.UncheckedAt(i) ); if (entry->Inclusive()) { cout << "Include "; @@ -516,7 +516,7 @@ AliHLTTriggerDomain& AliHLTTriggerDomain::operator = (const AliHLTTriggerDomain& fEntries.Clear(); for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++) { - const AliHLTDomainEntry* entry = static_cast( domain.fEntries[i] ); + const AliHLTDomainEntry* entry = static_cast( domain.fEntries.UncheckedAt(i) ); new (fEntries[fEntries.GetEntriesFast()]) AliHLTDomainEntry(*entry); } return *this; @@ -555,10 +555,10 @@ AliHLTTriggerDomain& AliHLTTriggerDomain::operator |= (const AliHLTTriggerDomain // intersections to the end of fEntries. for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++) { - const AliHLTDomainEntry* newEntry = static_cast( domain.fEntries[i] ); + const AliHLTDomainEntry* newEntry = static_cast( domain.fEntries.UncheckedAt(i) ); for (Int_t j = 0; j < count; j++) { - const AliHLTDomainEntry* currentEntry = static_cast( fEntries[j] ); + const AliHLTDomainEntry* currentEntry = static_cast( fEntries.UncheckedAt(j) ); if (currentEntry->Inclusive() and newEntry->Inclusive()) { // If either entry is a subset of the other then we do not need to add @@ -637,10 +637,10 @@ AliHLTTriggerDomain& AliHLTTriggerDomain::operator ^= (const AliHLTTriggerDomain // IncludeInReadout() or Contains(). for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++) { - const AliHLTDomainEntry* newEntry = static_cast( domain.fEntries[i] ); + const AliHLTDomainEntry* newEntry = static_cast( domain.fEntries.UncheckedAt(i) ); for (Int_t j = 0; j < count; j++) { - const AliHLTDomainEntry* currentEntry = static_cast( fEntries[j] ); + const AliHLTDomainEntry* currentEntry = static_cast( fEntries.UncheckedAt(j) ); if (newEntry->IntersectWith(*currentEntry, intersect)) { // We can remove all intersections that were already added that will @@ -688,7 +688,7 @@ AliHLTTriggerDomain& AliHLTTriggerDomain::operator -= (const AliHLTTriggerDomain // parts of the two trigger domains. for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++) { - const AliHLTDomainEntry* checkEntry = static_cast( domain.fEntries[i] ); + const AliHLTDomainEntry* checkEntry = static_cast( domain.fEntries.UncheckedAt(i) ); if (checkEntry->Inclusive()) { // For inclusive entries we need to find the overlaps with the inclusive @@ -696,7 +696,7 @@ AliHLTTriggerDomain& AliHLTTriggerDomain::operator -= (const AliHLTTriggerDomain // part of the trigger domain set. for (Int_t j = 0; j < startOfIntersects; j++) { - AliHLTDomainEntry* currentEntry = static_cast( fEntries[j] ); + AliHLTDomainEntry* currentEntry = static_cast( fEntries.UncheckedAt(j) ); // We only need to consider the case where both entries are inclusive, // since an exclusion in fEntries already eliminates those data blocks @@ -723,7 +723,7 @@ AliHLTTriggerDomain& AliHLTTriggerDomain::operator -= (const AliHLTTriggerDomain // all of fEntries and re-apply these with the same exclude flags. for (Int_t j = 0; j < startOfIntersects; j++) { - AliHLTDomainEntry* currentEntry = static_cast( fEntries[j] ); + AliHLTDomainEntry* currentEntry = static_cast( fEntries.UncheckedAt(j) ); if (checkEntry->IntersectWith(*currentEntry, intersect)) { // We can remove all intersections that were already added that will @@ -756,7 +756,7 @@ AliHLTTriggerDomain AliHLTTriggerDomain::operator ~ () const result.Add(kAliHLTAnyDataType); for (Int_t i = 0; i < fEntries.GetEntriesFast(); i++) { - const AliHLTDomainEntry* entry = static_cast( fEntries[i] ); + const AliHLTDomainEntry* entry = static_cast( fEntries.UncheckedAt(i) ); if (entry->Inclusive()) { result.Remove(*entry); @@ -792,12 +792,12 @@ AliHLTTriggerDomain AliHLTTriggerDomain::operator & (const AliHLTTriggerDomain& // makes sure that all exclusion entries are always subsets of inclusion entries. for (Int_t i = 0; i < domain.fEntries.GetEntriesFast(); i++) { - const AliHLTDomainEntry* checkEntry = static_cast( domain.fEntries[i] ); + const AliHLTDomainEntry* checkEntry = static_cast( domain.fEntries.UncheckedAt(i) ); if (checkEntry->Inclusive()) { for (Int_t j = 0; j < fEntries.GetEntriesFast(); j++) { - AliHLTDomainEntry* currentEntry = static_cast( fEntries[j] ); + AliHLTDomainEntry* currentEntry = static_cast( fEntries.UncheckedAt(j) ); if (checkEntry->IntersectWith(*currentEntry, intersect)) { // We can remove all entries that were already added to the result that @@ -812,7 +812,7 @@ AliHLTTriggerDomain AliHLTTriggerDomain::operator & (const AliHLTTriggerDomain& { for (Int_t j = 0; j < fEntries.GetEntriesFast(); j++) { - AliHLTDomainEntry* currentEntry = static_cast( fEntries[j] ); + AliHLTDomainEntry* currentEntry = static_cast( fEntries.UncheckedAt(j) ); if (checkEntry->IntersectWith(*currentEntry, intersect)) { // We can remove all entries that were already added to the result that @@ -831,6 +831,72 @@ AliHLTTriggerDomain AliHLTTriggerDomain::operator & (const AliHLTTriggerDomain& } +bool AliHLTTriggerDomain::operator == (const AliHLTTriggerDomain& domain) const +{ + // Checks if two domains are the same. + + if (fEntries.GetEntriesFast() != domain.fEntries.GetEntriesFast()) return false; + + // We need to find for each entry in this domain an identical entry in the domain + // that we are comparing to. Both entries cannot have subset entries further down + // in the entries lists. i.e. for fEntries[n], there cannot be any entry fEntries[m] + // that is a subset of fEntries[n] where m > n. Similarly for domain.fEntries. + // If two such entries are matched and they respect the subset rule mentioned, + // then they are marked. We keep finding matching pairs until no more pairs are + // found and check if there are any unmarked entries in either list. If there are + // any unmatched pairs then the two domains do not match. + // + // Note: We use bit 14 in fBits to mark the entries. + // 2) We traverse fEntries from back to front (i.e. from N-1 down to 0) so that + // we are guaranteed that fEntries[n] has no subset entries above it that are + // not marked. + for (Int_t i = fEntries.GetEntriesFast() - 1; i >= 0; --i) + { + AliHLTDomainEntry* entry1 = static_cast( fEntries.UncheckedAt(i) ); + // Find identical domain entry in domain.fEntries. + AliHLTDomainEntry* entry2 = NULL; + Int_t entry2index = -1; + for (Int_t j = fEntries.GetEntriesFast() - 1; j >= 0; --j) + { + AliHLTDomainEntry* current = static_cast( domain.fEntries.UncheckedAt(j) ); + if (current->TestBit(BIT(14))) continue; // skip marked entries. + if (entry1->IdenticalTo(*current) and entry1->Exclusive() == current->Exclusive()) + { + entry2 = current; + entry2index = j; + break; + } + } + if (entry2 == NULL) + { + // Could not find identical entry in domain.fEntries for fEntries[i] so we + // will have at least one unmatched entry and thus the domains do not match. + return false; + } + // Now check if entry2 has any subset entries below it. If it does then + // it fails our ordering requirements and the domains cannot match. + for (Int_t j = entry2index + 1; j < fEntries.GetEntriesFast(); ++j) + { + AliHLTDomainEntry* current = static_cast( domain.fEntries.UncheckedAt(j) ); + if (current->TestBit(BIT(14))) continue; // skip marked entries. + if (entry1->SubsetOf(*current)) return false; + } + // If we got to this point then entry1 and entry2 are a match and obey the + // ordering rules, so mark them. + entry1->SetBit(BIT(14), true); + entry2->SetBit(BIT(14), true); + } + // At this point we could find all pairs so the domains match. + // We now just need to clear the bits that we set. + for (Int_t i = 0; i < fEntries.GetEntriesFast() - 1; ++i) + { + fEntries[i]->SetBit(BIT(14), false); + domain.fEntries[i]->SetBit(BIT(14), false); + } + return true; +} + + AliHLTTriggerDomain::operator AliHLTReadoutList () const { // Typecast operator which constructs a readout list from the trigger domain. @@ -892,7 +958,7 @@ void AliHLTTriggerDomain::MergeEntries( } else { - const AliHLTDomainEntry* newEntry = static_cast( domain.fEntries[i] ); + const AliHLTDomainEntry* newEntry = static_cast( domain.fEntries.UncheckedAt(i) ); new (fEntries[entriesCount+i]) AliHLTDomainEntry(*newEntry); } } @@ -901,7 +967,7 @@ void AliHLTTriggerDomain::MergeEntries( // the MarkForDeletionSubsetsOf method. for (Int_t i = startOfIntersects; i < fEntries.GetEntriesFast(); i++) { - const AliHLTDomainEntry* ientry = static_cast( fEntries[i] ); + const AliHLTDomainEntry* ientry = static_cast( fEntries.UncheckedAt(i) ); if (ientry->TestBit(BIT(14))) { fEntries.RemoveAt(i); @@ -921,7 +987,7 @@ void AliHLTTriggerDomain::MarkForDeletionSubsetsOf(const AliHLTDomainEntry& entr AliHLTDomainEntry intersect; for (Int_t i = min; i < fEntries.GetEntriesFast(); i++) { - AliHLTDomainEntry* ientry = static_cast( fEntries[i] ); + AliHLTDomainEntry* ientry = static_cast( fEntries.UncheckedAt(i) ); if (ientry->TestBit(BIT(14))) continue; if (ientry->SubsetOf(entry)) { @@ -939,7 +1005,7 @@ void AliHLTTriggerDomain::RemoveMarkedEntries() bool anythingRemoved = false; for (Int_t i = 0; i < fEntries.GetEntriesFast(); i++) { - const AliHLTDomainEntry* ientry = static_cast( fEntries[i] ); + const AliHLTDomainEntry* ientry = static_cast( fEntries.UncheckedAt(i) ); if (ientry->TestBit(BIT(14))) { fEntries.RemoveAt(i); @@ -964,14 +1030,14 @@ void AliHLTTriggerDomain::Optimise() for (Int_t i = 1; i < fEntries.GetEntriesFast(); i++) { - AliHLTDomainEntry* ientry = static_cast( fEntries[i] ); + AliHLTDomainEntry* ientry = static_cast( fEntries.UncheckedAt(i) ); // For the i'th entry in fEntries, compare it in reverse order with all other // entries that are before it and look for redundant ones, i.e. that are subsets // of the i'th entry. for (Int_t j = i-1; j >= 0; j--) { - AliHLTDomainEntry* jentry = static_cast( fEntries[j] ); + AliHLTDomainEntry* jentry = static_cast( fEntries.UncheckedAt(j) ); if (jentry->TestBit(BIT(14))) continue; // Find entries that intersect if (jentry->SubsetOf(*ientry)) @@ -1009,5 +1075,5 @@ void AliHLTTriggerDomain::Optimise() const AliHLTDomainEntry& AliHLTTriggerDomain::operator[](int index) const { // Access individual entry of the domain - return dynamic_cast(*fEntries[index]); + return static_cast(*fEntries[index]); } diff --git a/HLT/BASE/AliHLTTriggerDomain.h b/HLT/BASE/AliHLTTriggerDomain.h index 7c786dad406..1203ab75801 100644 --- a/HLT/BASE/AliHLTTriggerDomain.h +++ b/HLT/BASE/AliHLTTriggerDomain.h @@ -374,6 +374,16 @@ class AliHLTTriggerDomain : public TObject return result.operator -= (domain); } + /** + * Checks if two domains are equal, i.e. have the same domain rules. + */ + bool operator == (const AliHLTTriggerDomain& domain) const; + + /** + * Checks if two domains are not equal, i.e. have different domain rules. + */ + bool operator != (const AliHLTTriggerDomain& domain) const { return not this->operator==(domain); } + /** * Typecase operator to create a DDL readout list object from the trigger domain. */ diff --git a/HLT/BASE/AliHLTTriggerMenu.cxx b/HLT/BASE/AliHLTTriggerMenu.cxx index edb3105d52c..7e6900a054b 100644 --- a/HLT/BASE/AliHLTTriggerMenu.cxx +++ b/HLT/BASE/AliHLTTriggerMenu.cxx @@ -1,4 +1,4 @@ -// $Id:$ +// $Id$ /************************************************************************** * This file is property of and copyright by the ALICE HLT Project * * ALICE Experiment at CERN, All rights reserved. * @@ -35,7 +35,9 @@ AliHLTTriggerMenu::AliHLTTriggerMenu() : fSymbols(AliHLTTriggerMenuSymbol::Class(), 100), fItems(AliHLTTriggerMenuItem::Class(), 100), fDefaultDescription(), - fDefaultDomain() + fDefaultDomain(), + fDefaultConditionOperator("||"), + fDefaultDomainOperator("|") { // Default constructor. } @@ -53,7 +55,9 @@ AliHLTTriggerMenu::AliHLTTriggerMenu(const AliHLTTriggerMenu& obj) : fSymbols(AliHLTTriggerMenuSymbol::Class(), obj.fSymbols.GetEntriesFast()), fItems(AliHLTTriggerMenuItem::Class(), obj.fItems.GetEntriesFast()), fDefaultDescription(obj.fDefaultDescription), - fDefaultDomain(obj.fDefaultDomain) + fDefaultDomain(obj.fDefaultDomain), + fDefaultConditionOperator(obj.fDefaultConditionOperator), + fDefaultDomainOperator(obj.fDefaultDomainOperator) { // Copy constructor performs a deep copy. @@ -88,6 +92,8 @@ AliHLTTriggerMenu& AliHLTTriggerMenu::operator = (const AliHLTTriggerMenu& obj) } fDefaultDescription = obj.fDefaultDescription; fDefaultDomain = obj.fDefaultDomain; + fDefaultConditionOperator = obj.fDefaultConditionOperator; + fDefaultDomainOperator = obj.fDefaultDomainOperator; } return *this; } @@ -106,9 +112,10 @@ void AliHLTTriggerMenu::Print(Option_t* option) const } cout << endl; cout << setw(10) << "Prescalar" << " | " + << setw(10) << "Priority" << " | " << setw(60) << "Trigger condition" << " | " << setw(60) << "Domain merge expression" << setw(0) << endl; - cout << setfill('-') << setw(10) << "-" << "-+-" + cout << setfill('-') << setw(10) << "-" << "-+-" << setw(10) << "-" << "-+-" << setw(60) << "-" << "-+-" << setw(60) << "-" << setw(0) << setfill(' ') << endl; for (UInt_t i = 0; i < NumberOfItems(); i++) @@ -136,7 +143,9 @@ void AliHLTTriggerMenu::Print(Option_t* option) const Symbol(i)->Print("compact"); } if (NumberOfSymbols() == 0) cout << "(none)" << endl; - cout << "Default trigger description: \"" << fDefaultDescription << "\"" << endl; + cout << "Default trigger condition operator: " << fDefaultConditionOperator << endl; + cout << " Default trigger domain operator: " << fDefaultDomainOperator << endl; + cout << " Default trigger description: \"" << fDefaultDescription << "\"" << endl; cout << "Default "; fDefaultDomain.Print(); } @@ -148,3 +157,24 @@ void AliHLTTriggerMenu::Clear(Option_t* option) fSymbols.Clear(option); fItems.Clear(option); } + + +void AliHLTTriggerMenu::AddSymbol(const AliHLTTriggerMenuSymbol& entry) +{ + // Adds a new symbol to the trigger menu. + + for (Int_t i = 0; i < fSymbols.GetEntriesFast(); i++) + { + const char* symbolname = static_cast(fSymbols.UncheckedAt(i))->Name(); + if ( strcmp(symbolname, entry.Name()) == 0 ) + { + Warning("AliHLTTriggerMenu::AddSymbol", + "The symbol '%s' already exists in the trigger menu. Will not add the new entry.", + entry.RealName() + ); + return; + } + } + new (fSymbols[fSymbols.GetEntriesFast()]) AliHLTTriggerMenuSymbol(entry); +} + diff --git a/HLT/BASE/AliHLTTriggerMenu.h b/HLT/BASE/AliHLTTriggerMenu.h index 656a7d9cac5..ac2899f1975 100644 --- a/HLT/BASE/AliHLTTriggerMenu.h +++ b/HLT/BASE/AliHLTTriggerMenu.h @@ -1,5 +1,5 @@ //-*- Mode: C++ -*- -// $Id:$ +// $Id$ #ifndef ALIHLTTRIGGERMENU_H #define ALIHLTTRIGGERMENU_H /* This file is property of and copyright by the ALICE HLT Project * @@ -20,10 +20,70 @@ /** * \class AliHLTTriggerMenu - * This class is an abstract class. Classes which derive from this class should - * implement the logic for a particular trigger menu. The AliHLTTriggerMenu class - * creates a class deriving from AliHLTTriggerMenu on the fly to implement the - * trigger logic for that particular trigger menu. + * The trigger menu specifies the HLT global trigger component configuration. + * The global trigger has a list of individual input trigger components deriving + * from AliHLTTrigger. Each one of these triggers is named. Thus, the trigger menu + * is a list of trigger condition expressions, where the variables inside the + * expressions are the names of the input triggers. In this way the global trigger + * can be configured in a powerful manner using C++ expressions. + * Attached to each trigger condition expression is a trigger domain merging + * expression, which indicates how the final global trigger domain should be + * calculated from the fragments coming from each individual trigger component. + * Each entry in the trigger menu has a priority. These are set explicitly and + * set to zero by default. The higher the priority number for a menu item the + * higher its priority. Multiple items can have the same priority values. + * + * An important concept is the trigger priority group. This is a number of menu + * items that all have the same priority. If all trigger menu items have the + * same priority value then there is only one priority group with all the items + * being members of the same group. Otherwise there can be any number of priority + * groups with any number of one or more trigger menu items in a group. + * A trigger menu item belongs to priority group N if it has a priority number equal + * to N. The trigger menu is then evaluated by the global trigger component, such + * that the highest priority trigger groups (largest N) are evaluated first. + * Trigger items within a priority group are then evaluated in the order they + * were added to the trigger menu. Thus, the first item added to the menu in group + * N is evaluated first, and the last added to group N is evaluated last. + * Inside a priority group all trigger menu items have their trigger condition + * expressions evaluated. This is equivalent to evaluating the group's trigger + * condition expression, where the group's expression is a concatenation of the + * individual trigger condition expressions of the items in priority group N. + * This means that the trigger conditions expressions (indeed, also the trigger + * domain merging expressions) are allowed to have a dangling trailing operator. + * The trailing operator will then make sense in the full concatenated expression. + * If no such trailing operator is found then the default trigger conditions operator + * is used implicitly, as defined in the trigger menu. + * If the full concatenated condition expression evaluates to true then the priority + * group's result is also true and the output trigger domain can be calculated. + * This is done by taking all the merging expressions from only those trigger menu + * items whose trigger condition expression fragments were true, and concatenating + * those merging expression fragments together to arrive at the full merging expression. + * The final trigger domain is calculated by evaluating the merging expression. + * Note that the concatenation of the merging expression fragments working in the + * same manner as the trigger condition expressions. So a trailing operator is + * allowed in each trigger menu item's merging expression, and is implicitly removed + * if not needed, but used to concatenate with the next expression required. + * The default domain merging operator is used if no trailing operator is present + * but a concatenation is required. + * The evaluation of trigger menu items stops at the first priority group whose + * trigger condition expression evaluated to true. This is important to force + * mutually exclusive precedence of a higher priority trigger or triggers. + * The two extremes of this model are: + * - All trigger menu entries have the same priority so they are all part of the + * same priority group, and thus every trigger menu item is evaluated. + * - Every trigger menu entry has a different priority, so each forms its own priority + * group, and the trigger evaluation stops at the first highest priority item + * that matches the trigger condition. + * Another way to look at the model is that priority groups are mutually exclusive. + * Trigger menu items from two different priority groups cannot be active at the same + * time. While more than one trigger menu item can be active at the same time if they + * are from the same priority group. + * Yet another view at the model is that a priority group forms an explicit trigger + * condition and trigger domain merging expression, while trigger menu items specify + * the expression fragments that are concatenated together implicitly. If there is + * just one trigger menu item in a priority group then the groups expressions are + * explicit. On the other hand, for multiple items in a group they form implicit + * expression fragments. */ class AliHLTTriggerMenu : public TObject { @@ -106,12 +166,11 @@ class AliHLTTriggerMenu : public TObject } /** - * Adds a new symbol to the trigger menu. + * Adds a new symbol to the trigger menu. If the symbol being added already + * exists in the trigger menu then the new symbol will not be added. + * \param entry The new trigger menu symbol being added. */ - void AddSymbol(const AliHLTTriggerMenuSymbol& entry) - { - new (fSymbols[fSymbols.GetEntriesFast()]) AliHLTTriggerMenuSymbol(entry); - } + void AddSymbol(const AliHLTTriggerMenuSymbol& entry); /** * Returns the array of symbols. @@ -183,6 +242,30 @@ class AliHLTTriggerMenu : public TObject */ AliHLTTriggerDomain& DefaultTriggerDomain() { return fDefaultDomain; } + /** + * Sets the default operator used to merge trigger conditions that are matched from + * the same trigger menu priority group. + */ + void DefaultConditionOperator(const char* value) { fDefaultConditionOperator = value; } + + /** + * Returns the default operator used to merge trigger conditions that are matched from + * the same trigger menu priority group. + */ + const char* DefaultConditionOperator() const { return fDefaultConditionOperator.Data(); } + + /** + * Sets the default operator used to merge trigger domains that are matched from + * the same trigger menu priority group. + */ + void DefaultDomainOperator(const char* value) { fDefaultDomainOperator = value; } + + /** + * Returns the default operator used to merge trigger domains that are matched from + * the same trigger menu priority group. + */ + const char* DefaultDomainOperator() const { return fDefaultDomainOperator.Data(); } + private: TString fName; /// Name of the trigger menu. @@ -190,6 +273,8 @@ class AliHLTTriggerMenu : public TObject TClonesArray fItems; /// List of trigger menu items. TString fDefaultDescription; /// The default trigger description to use for negative global triggers. AliHLTTriggerDomain fDefaultDomain; /// The default trigger domain to use for negative global triggers. + TString fDefaultConditionOperator; /// The default operator to use to merge trigger conditions from the same priority group. + TString fDefaultDomainOperator; /// The default operator to use to merge trigger domains from the same priority group. ClassDef(AliHLTTriggerMenu, 2) // Trigger menu for the global HLT trigger. }; diff --git a/HLT/BASE/AliHLTTriggerMenuItem.cxx b/HLT/BASE/AliHLTTriggerMenuItem.cxx index a41fdabf77a..73d0bda1ddf 100644 --- a/HLT/BASE/AliHLTTriggerMenuItem.cxx +++ b/HLT/BASE/AliHLTTriggerMenuItem.cxx @@ -1,4 +1,4 @@ -// $Id:$ +// $Id$ /************************************************************************** * This file is property of and copyright by the ALICE HLT Project * * ALICE Experiment at CERN, All rights reserved. * @@ -34,7 +34,8 @@ AliHLTTriggerMenuItem::AliHLTTriggerMenuItem() : fDescription(), fConditionExpr(), fDomainExpr(), - fPrescalar(0) + fPrescalar(0), + fPriority(0) { // Default constructor. } @@ -54,6 +55,7 @@ void AliHLTTriggerMenuItem::Print(Option_t* option) const if (opt.Contains("compact")) { cout << setw(10) << fPrescalar << " | " + << setw(10) << fPriority << " | " << setw(60) << fConditionExpr.Data() << " | " << setw(60) << fDomainExpr.Data() << setw(0) << endl; } @@ -63,6 +65,7 @@ void AliHLTTriggerMenuItem::Print(Option_t* option) const cout << " Trigger condition expression = " << fConditionExpr.Data() << endl; cout << "Trigger domain merge expression = " << fDomainExpr.Data() << endl; cout << " Pre-scalar = " << fPrescalar << endl; + cout << " Priority = " << fPriority << endl; } } diff --git a/HLT/BASE/AliHLTTriggerMenuItem.h b/HLT/BASE/AliHLTTriggerMenuItem.h index 8815810ab7f..5859caf56ed 100644 --- a/HLT/BASE/AliHLTTriggerMenuItem.h +++ b/HLT/BASE/AliHLTTriggerMenuItem.h @@ -1,5 +1,5 @@ //-*- Mode: C++ -*- -// $Id:$ +// $Id$ #ifndef ALIHLTTRIGGERMENUITEM_H #define ALIHLTTRIGGERMENUITEM_H /* This file is property of and copyright by the ALICE HLT Project * @@ -17,7 +17,29 @@ /** * \class AliHLTTriggerMenuItem - * TODO + * A trigger menu item is used to store the information for a single entry in the + * HLT global trigger menu AliHLTTriggerMenu. + * It stores information about the trigger condition, trigger domain merging + * expression, trigger priority and the prescalar to apply. + * The trigger condition is an expression which indicates that must be true + * for the trigger menu entry to be fired. A fired item will then use the trigger + * domain merging expression for the computation of the final global trigger domain. + * + * \note The following symbol names are reserved and should not be used in either + * the trigger condition or merging expressions: + * _domain_ + * _description_ + * _item_result_ + * _group_result_ + * _previous_match_ + * _trigger_matched_ + * FillFromMenu + * NewEvent + * Add + * CalculateTriggerDecision + * GetCounters + * SetCounters + * CreateNew */ class AliHLTTriggerMenuItem : public TObject { @@ -52,12 +74,12 @@ class AliHLTTriggerMenuItem : public TObject /** * Returns the trigger condition expression. */ - const char* TriggerCondision() const { return fConditionExpr.Data(); } + const char* TriggerCondition() const { return fConditionExpr.Data(); } /** * Set the trigger condition expression. */ - void TriggerCondision(const char* value) { fConditionExpr = value; } + void TriggerCondition(const char* value) { fConditionExpr = value; } /** * Returns the trigger domain merging expression. @@ -78,6 +100,16 @@ class AliHLTTriggerMenuItem : public TObject * Set the pre-scalar value. A value of zero turns off the prescalar. */ void PreScalar(UInt_t value) { fPrescalar = value; } + + /** + * Returns the priority value. + */ + UInt_t Priority() const { return fPriority; } + + /** + * Set the priority value. Higher values give a higher priority. + */ + void Priority(UInt_t value) { fPriority = value; } private: @@ -85,8 +117,9 @@ class AliHLTTriggerMenuItem : public TObject TString fConditionExpr; /// The trigger condition expression. TString fDomainExpr; /// Trigger domain merging expression. UInt_t fPrescalar; /// Pre-scalar value used to optionally reduce the trigger rate. Every modulus n'th event is triggered, where n equals the pre-scalar value. + UInt_t fPriority; /// Priority of the trigger menu item. Higher values have higher priority. - ClassDef(AliHLTTriggerMenuItem, 2) // Trigger menu item for global HLT trigger. + ClassDef(AliHLTTriggerMenuItem, 3) // Trigger menu item for global HLT trigger. }; #endif // ALIHLTTRIGGERMENUITEM_H diff --git a/HLT/BASE/AliHLTTriggerMenuSymbol.cxx b/HLT/BASE/AliHLTTriggerMenuSymbol.cxx index 923b0547c61..8c27204b01d 100644 --- a/HLT/BASE/AliHLTTriggerMenuSymbol.cxx +++ b/HLT/BASE/AliHLTTriggerMenuSymbol.cxx @@ -56,7 +56,7 @@ void AliHLTTriggerMenuSymbol::Print(Option_t* option) const TString opt = option; if (opt.Contains("compact")) { - cout << setw(15) << fName << " | " + cout << setw(15) << fRealName << " | " << setw(20) << fType << " | "; fBlockType.Print("noendl"); cout << " | " << setw(20) << ObjectClass() diff --git a/HLT/BASE/AliHLTTriggerMenuSymbol.h b/HLT/BASE/AliHLTTriggerMenuSymbol.h index 3577332fc75..420fa1f85ba 100644 --- a/HLT/BASE/AliHLTTriggerMenuSymbol.h +++ b/HLT/BASE/AliHLTTriggerMenuSymbol.h @@ -18,7 +18,42 @@ /** * \class AliHLTTriggerMenuSymbol - * TODO + * The trigger menu symbol is used to either label a TObject variable found in + * one of the input data blocks or create a constant object that can be used in + * various trigger menu expressions. + * It essentially represents a C++ variable with a name and type. This is filled + * with the information found in an input TObject, as specified by the + * AssignExpression() method. If nothing can be assigned because an + * appropriate TObject cannot be found, then a default value is used. + * The correct TObject is found by searching for a TObject with a matching class + * type as given by ObjectClass() from the input data blocks. The input + * data block must also have the data block type and specification match those + * given in the BlockType() method. + * + * The symbol name should normally be a valid C++ symbol name. This normally + * excludes the minus sign from being used in the name. However, since CTP trigger + * names use the minus sign extensively, the minus sign is also allowed in HLT + * trigger menu symbol names. This is implicitly converted to an underscore in the + * name. However, the original name with minus signs is retained and available + * with the RealName() method. In addition, the RealName is used + * for display purposes. + * \note Trigger menu symbols names that use minus signs are synonymous to those + * that use understores in the same locations. For this reason it is better to use + * one or the other form, but not both at the same time. + * \note The following symbol names are reserved and should not be used: + * _domain_ + * _description_ + * _item_result_ + * _group_result_ + * _previous_match_ + * _trigger_matched_ + * FillFromMenu + * NewEvent + * Add + * CalculateTriggerDecision + * GetCounters + * SetCounters + * CreateNew */ class AliHLTTriggerMenuSymbol : public TObject { @@ -161,7 +196,7 @@ class AliHLTTriggerMenuSymbol : public TObject TString fDefaultValue; /// The default value this symbol is set to (this must be a valid C++ expression). TString fRealName; /// The name of the symbol, differs from fName by replaced '-' chars. - ClassDef(AliHLTTriggerMenuSymbol, 3) // Trigger menu item for global HLT trigger. + ClassDef(AliHLTTriggerMenuSymbol, 4) // Trigger menu item for global HLT trigger. }; #endif // ALIHLTTRIGGERMENUSYMBOL_H diff --git a/HLT/libAliHLTTrigger.pkg b/HLT/libAliHLTTrigger.pkg index f424e8df168..bd2840f83c6 100644 --- a/HLT/libAliHLTTrigger.pkg +++ b/HLT/libAliHLTTrigger.pkg @@ -11,6 +11,7 @@ CLASS_HDRS:= \ AliHLTTrigger.h \ AliHLTGlobalTrigger.h \ + AliHLTGlobalTriggerWrapper.h \ AliHLTGlobalTriggerConfig.h \ AliHLTGlobalTriggerComponent.h \ AliHLTTriggerBarrelMultiplicity.h \ @@ -62,6 +63,7 @@ include $(MODDIR)/hlt.conf SRCS:=$(patsubst %,trigger/%,$(MODULE_SRCS)) CINTHDRS:=$(patsubst %,trigger/%,$(CLASS_HDRS)) +CINTSTUBS:=$(patsubst %,trigger/%,$(STUB_HDRS)) HDRS:=$(patsubst %,trigger/%,$(MODULE_HDRS)) DHDR:=$(patsubst %,trigger/%,$(MODULE_DHDR)) CINTAUTOLINK:= $(shell test "x$(MODULE_DHDR)" = "x" && echo 1) diff --git a/HLT/trigger/AliHLTGlobalTrigger.cxx b/HLT/trigger/AliHLTGlobalTrigger.cxx index 08914ef3030..5cfee2802f3 100644 --- a/HLT/trigger/AliHLTGlobalTrigger.cxx +++ b/HLT/trigger/AliHLTGlobalTrigger.cxx @@ -20,96 +20,35 @@ /// @date 19 Dec 2008 /// @brief Implementation of the AliHLTGlobalTrigger base class. /// -/// The AliHLTGlobalTriggerComponent class is an abstract class from which a -/// derived class is constructed by AliHLTTriggerMenu on the fly. The derived +/// The AliHLTGlobalTrigger base class is an abstract class from which a +/// derived class is constructed from AliHLTTriggerMenu on the fly. The derived /// class then implements triggering based on the particular trigger menu. #include "AliHLTGlobalTrigger.h" -#include "AliHLTGlobalTriggerDecision.h" -#include +#include "AliHLTGlobalTriggerWrapper.h" +#include "TClass.h" ClassImp(AliHLTGlobalTrigger) -// Static factory array. -AliHLTGlobalTrigger::Factory* -AliHLTGlobalTrigger::Factory::fFactory[AliHLTGlobalTrigger::Factory::kMaxFactories] - = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; - -AliHLTGlobalTrigger::AliHLTGlobalTrigger() : - AliHLTLogging(), - fCounters() -{ - // Default constructor. -} - - -AliHLTGlobalTrigger::~AliHLTGlobalTrigger() -{ - // Default destructor. -} - - -AliHLTGlobalTrigger* AliHLTGlobalTrigger::Factory::CreateNew(const char* name) -{ - // Creates a new instance of the named trigger class. - - for (int i = 0; i < kMaxFactories; i++) - { - if (fFactory[i] != NULL) - { - if (strcmp(fFactory[i]->ClassName(), name) == 0) - { - return fFactory[i]->New(); - } - } - } - return NULL; -} - - -AliHLTGlobalTrigger::Factory::Factory() : AliHLTLogging() +AliHLTGlobalTrigger* AliHLTGlobalTrigger::CreateNew(const char* name) { - // Default constructor resisters the class factory. + // Creates a new instance of the named global trigger class. - for (int i = 0; i < kMaxFactories; i++) + TClass* c = TClass::GetClass(name); + if (c == NULL) return NULL; + if (c->GetDeclFileLine() == -1 and c->GetImplFileLine() == -1) { - if (fFactory[i] == NULL) - { - fFactory[i] = this; - return; - } + // Could not find the implementation lines which should be there if the code + // was compiled. So assuming that this is an interpreted class. In this case + // we need to use a interface wrapper class to make things work properly. + AliHLTGlobalTriggerWrapper* trigger = new AliHLTGlobalTriggerWrapper(name); + if (not trigger->IsValid()) return NULL; + return trigger; } - - HLTFatal("Trying to register too many global trigger factories."); -} - - -AliHLTGlobalTrigger::Factory::~Factory() -{ - // The default destructor deregisters the factory. - - for (int i = 0; i < kMaxFactories; i++) - { - if (fFactory[i] == this) - { - fFactory[i] = NULL; - return; - } - } - - HLTFatal("Could not find factory to deregister."); -} - - -void AliHLTGlobalTrigger::ResetCounters(UInt_t number) -{ - // Resets the trigger counters. - - fCounters.Set(number); - for (UInt_t i = 0; i < number; i++) + else { - fCounters[i] = 0; + return static_cast(c->New()); } } diff --git a/HLT/trigger/AliHLTGlobalTrigger.h b/HLT/trigger/AliHLTGlobalTrigger.h index ee26b4556fb..1d228a5be08 100644 --- a/HLT/trigger/AliHLTGlobalTrigger.h +++ b/HLT/trigger/AliHLTGlobalTrigger.h @@ -12,36 +12,26 @@ /// @brief Declaration of the AliHLTGlobalTrigger base class. #include "TObject.h" -#include "TArrayL64.h" #include "AliHLTDataTypes.h" -#include "AliHLTLogging.h" class AliHLTTriggerDomain; -class AliHLTTriggerDecision; -class AliHLTGlobalTriggerDecision; class AliHLTTriggerMenu; -class TClonesArray; +class TString; +class TArrayL64; /** * \class AliHLTGlobalTrigger * This class is an abstract class. Classes which derive from this class should - * implement the logic for a particular trigger menu. The AliHLTTriggerMenu class - * creates a class deriving from AliHLTGlobalTrigger on the fly to implement the - * trigger logic for that particular trigger menu. + * implement the logic for a particular trigger menu. The AliHLTGlobalTriggerComponent + * takes the AliHLTTriggerMenu class and creates a class deriving from AliHLTGlobalTrigger + * on the fly to implement the trigger logic for that particular trigger menu. */ -class AliHLTGlobalTrigger : public AliHLTLogging +class AliHLTGlobalTrigger { public: - /** - * Default constructor. - */ - AliHLTGlobalTrigger(); - - /** - * Default destructor. - */ - virtual ~AliHLTGlobalTrigger(); + /// Default destructor. + virtual ~AliHLTGlobalTrigger() {} /** * Abstract method to fill values from a trigger menu. Specifically, the description @@ -78,97 +68,25 @@ class AliHLTGlobalTrigger : public AliHLTLogging virtual bool CalculateTriggerDecision(AliHLTTriggerDomain& domain, TString& description) = 0; /** - * Creates a new instance of a particular trigger class. - * \param name The name of the class to create. - * \returns the new trigger class instance which needs to be deleted by the - * caller with the delete operator. - */ - static AliHLTGlobalTrigger* CreateNew(const char* name) { return Factory::CreateNew(name); } - - /** - * Sets the number of trigger counters and resets them all to zero. - * \param number The number of counters to use. + * Returns the array of internal trigger counters. */ - void ResetCounters(UInt_t number = 0); + virtual const TArrayL64& GetCounters() const = 0; /** - * Returns the array of trigger counters. + * Sets the internal trigger counter values. + * \param counters The array of trigger counters to use. */ - const TArrayL64& Counters() const { return fCounters; } - - protected: + virtual void SetCounters(const TArrayL64& counters) = 0; /** - * The factory object is used to create new instances of classes via the - * AliHLTGlobalTrigger::CreateNew method. - * A single static instance of a factory must be created by classes deriving - * from AliHLTGlobalTrigger so that AliHLTGlobalTrigger::CreateNew will work - * properly. - */ - class Factory : public AliHLTLogging - { - public: - - /** - * Default constructor registers a class factory for the creation of new - * instances of classes deriving from AliHLTGlobalTrigger. - */ - Factory(); - - /** - * The default destructor deregisters the factory from the class factory list. - */ - ~Factory(); - - /** - * Creates a new instance of a particular trigger class. - * \param name The name of the class to create. - * \returns the new trigger class instance which needs to be deleted by the - * caller with the delete operator. - */ - static AliHLTGlobalTrigger* CreateNew(const char* name); - - /** - * Returns the class name of the object returned by the New() method. - */ - virtual const char* ClassName() const = 0; - - /** - * Creates and returns a new instance of a trigger class. - * The returned object should be deleted via the delete operator. - */ - virtual AliHLTGlobalTrigger* New() const = 0; - - private: - - enum {kMaxFactories = 8}; /// The maximum number of factories that can be registered. - - static Factory* fFactory[kMaxFactories]; - }; - - /// Not implemented. Do not allow copying of this object. - AliHLTGlobalTrigger(const AliHLTGlobalTrigger& obj); - /// Not implemented. Do not allow copying of this object. - AliHLTGlobalTrigger& operator = (const AliHLTGlobalTrigger& obj); - - /** - * Increments a trigger counter by one. - * \param i The counter to increment. - */ - void IncrementCounter(UInt_t i) { ++fCounters[i]; }; - - /** - * Returns a trigger counter's value. - * \param i The counter number to return. + * Creates a new instance of a particular global trigger class. + * \param name The name of the class to create. + * \returns the new trigger class instance which needs to be deleted by the + * caller with the delete operator. */ - Long64_t GetCounter(UInt_t i) const { return fCounters[i]; }; - - private: - - TArrayL64 fCounters; //! Event trigger counters. One counter for each trigger class. + static AliHLTGlobalTrigger* CreateNew(const char* name); ClassDef(AliHLTGlobalTrigger, 0) // Global HLT trigger base class which implements logic for a particular trigger menu. }; #endif // ALIHLTGLOBALTRIGGER_H - diff --git a/HLT/trigger/AliHLTGlobalTriggerComponent.cxx b/HLT/trigger/AliHLTGlobalTriggerComponent.cxx index 2f4c27958ce..698b08f2598 100644 --- a/HLT/trigger/AliHLTGlobalTriggerComponent.cxx +++ b/HLT/trigger/AliHLTGlobalTriggerComponent.cxx @@ -41,23 +41,44 @@ #include "TSystem.h" #include "TInterpreter.h" #include "TDatime.h" +#include "TClass.h" #include #include #include +#include +#include ClassImp(AliHLTGlobalTriggerComponent) const char* AliHLTGlobalTriggerComponent::fgkTriggerMenuCDBPath = "HLT/ConfigHLT/HLTGlobalTrigger"; +namespace +{ + /** + * This method is used as a comparison functor with the STL sort routines. + */ + bool AliHLTDescendingNumbers(UInt_t a, UInt_t b) + { + return a > b; + } +} // end of namespace + + AliHLTGlobalTriggerComponent::AliHLTGlobalTriggerComponent() : AliHLTTrigger(), fTrigger(NULL), fDebugMode(false), fRuntimeCompile(true), fSkipCTPCounters(false), + fDeleteCodeFile(false), fCodeFileName(), - fCTPDecisions(NULL) + fClassName(), + fCTPDecisions(NULL), + fBufferSizeConst(2*(sizeof(AliHLTGlobalTriggerDecision) + sizeof(AliHLTReadoutList))), + fBufferSizeMultiplier(1.), + fIncludePaths(TObjString::Class()), + fIncludeFiles(TObjString::Class()) { // Default constructor. @@ -82,14 +103,8 @@ void AliHLTGlobalTriggerComponent::GetOutputDataSize(unsigned long& constBase, d { // Returns the output data size estimate. - // the real size can actually not be determined here since an arbitrary - // number of objects can be part of the decision - // collect the known ones and add a margin - constBase = 0; - constBase += 2*sizeof(AliHLTGlobalTriggerDecision); - constBase += sizeof(AliHLTCTPData); - constBase += 5*sizeof(AliHLTTriggerDecision); - inputMultiplier = 2; + constBase = fBufferSizeConst; + inputMultiplier = fBufferSizeMultiplier; } @@ -98,11 +113,13 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv) // Initialises the global trigger component. fDebugMode = false; + fClassName = ""; + fCodeFileName = ""; + fDeleteCodeFile = false; const char* configFileName = NULL; const char* codeFileName = NULL; - TString classname; - TClonesArray includePaths(TObjString::Class()); - TClonesArray includeFiles(TObjString::Class()); + fIncludePaths.Clear(); + fIncludeFiles.Clear(); for (int i = 0; i < argc; i++) { @@ -131,7 +148,7 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv) HLTError("The include path was not specified." ); return -EINVAL; } - new (includePaths[includePaths.GetEntriesFast()]) TObjString(argv[i+1]); + new (fIncludePaths[fIncludePaths.GetEntriesFast()]) TObjString(argv[i+1]); i++; continue; } @@ -143,7 +160,7 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv) HLTError("The include file name was not specified." ); return -EINVAL; } - new (includeFiles[includeFiles.GetEntriesFast()]) TObjString(argv[i+1]); + new (fIncludeFiles[fIncludeFiles.GetEntriesFast()]) TObjString(argv[i+1]); i++; continue; } @@ -183,7 +200,7 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv) HLTError("The custom trigger class name was not specified." ); return -EINVAL; } - classname = argv[i+2]; + fClassName = argv[i+2]; i += 2; continue; } @@ -210,66 +227,37 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv) // Try load the trigger menu from the CDB if it is not loaded yet with the // -config option - if (menu == NULL and AliCDBManager::Instance() != NULL) + int result = -ENOENT; + if (menu == NULL) { - AliCDBStorage* store = AliCDBManager::Instance()->GetDefaultStorage(); - if (store == NULL) - { - HLTError("Could not get the the default storage for the CDB."); - return -EIO; - } - Int_t version = store->GetLatestVersion(fgkTriggerMenuCDBPath, GetRunNo()); - Int_t subVersion = store->GetLatestSubVersion(fgkTriggerMenuCDBPath, GetRunNo(), version); - AliCDBEntry* entry = AliCDBManager::Instance()->Get(fgkTriggerMenuCDBPath, GetRunNo(), version, subVersion); - if (entry == NULL) - { - HLTError("Could not get the CDB entry for \"%s\".", fgkTriggerMenuCDBPath); - return -EIO; - } - TObject* obj = entry->GetObject(); - if (obj == NULL) - { - HLTError("Configuration object for \"%s\" is missing.", fgkTriggerMenuCDBPath); - return -ENOENT; - } - if (obj->IsA() != AliHLTTriggerMenu::Class()) - { - HLTError("Wrong type for configuration object in \"%s\". Found a %s but we expect a AliHLTTriggerMenu.", - fgkTriggerMenuCDBPath, obj->ClassName() - ); - return -EPROTO; - } - menu = dynamic_cast(obj); + result = LoadTriggerMenu(fgkTriggerMenuCDBPath, menu); } - if (menu == NULL) { HLTError("No trigger menu configuration found or specified."); - return -ENOENT; + return result; } - int result = 0; if (codeFileName == NULL) { - HLTDebug("Generating custom HLT trigger class."); - result = GenerateTrigger(menu, classname, includePaths, includeFiles); + result = GenerateTrigger(menu, fClassName, fCodeFileName, fIncludePaths, fIncludeFiles); + if (result == 0) fDeleteCodeFile = true; } else { - HLTDebug("Loading HLT trigger class from file '%s'.", codeFileName); - result = LoadTriggerClass(codeFileName, includePaths); + result = LoadTriggerClass(codeFileName, fIncludePaths); + if (result == 0) fCodeFileName = codeFileName; } if (result != 0) return result; - fTrigger = AliHLTGlobalTrigger::CreateNew(classname.Data()); + fTrigger = AliHLTGlobalTrigger::CreateNew(fClassName.Data()); if (fTrigger == NULL) { - HLTError("Could not create a new instance of '%s'.", classname.Data()); + HLTError("Could not create a new instance of '%s'.", fClassName.Data()); return -EIO; } fTrigger->FillFromMenu(*menu); - fTrigger->ResetCounters(menu->NumberOfItems()); // setup the CTP accounting in AliHLTComponent SetupCTPData(); @@ -291,19 +279,23 @@ Int_t AliHLTGlobalTriggerComponent::DoDeinit() delete fTrigger; fTrigger = NULL; } - - if (!fCodeFileName.IsNull() && gSystem->AccessPathName(fCodeFileName)==0 && !fDebugMode) { - fCodeFileName.ReplaceAll(".cxx", "*"); - TString command="rm "; command+=fCodeFileName; - gSystem->Exec(command); - } - fCodeFileName=""; if (fCTPDecisions) { fCTPDecisions->Delete(); delete fCTPDecisions; } fCTPDecisions=NULL; + + Int_t result = UnloadTriggerClass(fCodeFileName); + if (result != 0) return result; + + if (fDeleteCodeFile and !fCodeFileName.IsNull() && gSystem->AccessPathName(fCodeFileName)==0 && !fDebugMode) { + fCodeFileName.ReplaceAll(".cxx", "*"); + TString command="rm "; command+=fCodeFileName; + gSystem->Exec(command); + } + fCodeFileName=""; + fDeleteCodeFile=false; return 0; } @@ -333,6 +325,10 @@ int AliHLTGlobalTriggerComponent::DoTrigger() return 0; } + // Copy the trigger counters in case we need to set them back to their original + // value because the PushBack method fails with ENOSPC. + TArrayL64 originalCounters = fTrigger->GetCounters(); + fTrigger->NewEvent(); // Fill in the input data. @@ -354,7 +350,6 @@ int AliHLTGlobalTriggerComponent::DoTrigger() TString description; AliHLTTriggerDomain triggerDomain; bool triggerResult = fTrigger->CalculateTriggerDecision(triggerDomain, description); - AliHLTGlobalTriggerDecision decision( triggerResult, // The following will cause the decision to be generated with default values @@ -374,7 +369,7 @@ int AliHLTGlobalTriggerComponent::DoTrigger() decision.ReadoutList(maskedList); } - decision.SetCounters(fTrigger->Counters(), GetEventCount()+1); + decision.SetCounters(fTrigger->GetCounters(), GetEventCount()+1); static UInt_t lastTime=0; TDatime time; if (time.Get()-lastTime>5) { @@ -401,19 +396,136 @@ int AliHLTGlobalTriggerComponent::DoTrigger() CreateEventDoneReadoutFilter(decision.TriggerDomain(), 3); CreateEventDoneReadoutFilter(decision.TriggerDomain(), 4); - TriggerEvent(&decision); + if (TriggerEvent(&decision) == -ENOSPC) + { + // Increase the estimated buffer space required if the PushBack methods in TriggerEvent + // returned the "no buffer space" error code. Also remember to set the trigger counters + // back to what they were, otherwise triggers will be double counted when we try to reprocess + // this event with larger buffers. + fBufferSizeConst += 1024*1024; + fBufferSizeMultiplier *= 2.; + fTrigger->SetCounters(originalCounters); + return -ENOSPC; + } + return 0; +} + + +int AliHLTGlobalTriggerComponent::Reconfigure(const char* cdbEntry, const char* chainId) +{ + // Reconfigure the component by loading the trigger menu and recreating the + // trigger logic class. + + const char* path = fgkTriggerMenuCDBPath; + const char* id = "(unknown)"; + if (cdbEntry != NULL) path = cdbEntry; + if (chainId != NULL and chainId[0] != '\0') id = chainId; + HLTInfo("Reconfiguring from '%s' for chain component '%s'.", path, id); + + const AliHLTTriggerMenu* menu = NULL; + int result = LoadTriggerMenu(path, menu); + if (result != 0) return result; + + TString className; + TString codeFileName; + result = GenerateTrigger(menu, className, codeFileName, fIncludePaths, fIncludeFiles); + if (result != 0) return result; + + AliHLTGlobalTrigger* trigger = AliHLTGlobalTrigger::CreateNew(className.Data()); + if (trigger == NULL) + { + HLTError("Could not create a new instance of '%s'.", className.Data()); + // Make sure to cleanup after the new code file. + UnloadTriggerClass(codeFileName); + if (not codeFileName.IsNull() and gSystem->AccessPathName(codeFileName)==0 and not fDebugMode) + { + codeFileName.ReplaceAll(".cxx", "*"); + TString command="rm "; command+=codeFileName; + gSystem->Exec(command); + } + return -EIO; + } + + if (fTrigger != NULL) + { + delete fTrigger; + fTrigger = NULL; + } + + fTrigger = trigger; + fTrigger->FillFromMenu(*menu); + + // Set the default values from the trigger menu. + SetDescription(menu->DefaultDescription()); + SetTriggerDomain(menu->DefaultTriggerDomain()); + + // Cleanup the old class code. + UnloadTriggerClass(fCodeFileName); + if (fDeleteCodeFile and not fCodeFileName.IsNull() and gSystem->AccessPathName(fCodeFileName)==0 and not fDebugMode) + { + fCodeFileName.ReplaceAll(".cxx", "*"); + TString command="rm "; command+=fCodeFileName; + gSystem->Exec(command); + } + fCodeFileName = codeFileName; + fDeleteCodeFile = true; // Since we generated a new class. + + return 0; +} + + +int AliHLTGlobalTriggerComponent::LoadTriggerMenu(const char* cdbPath, const AliHLTTriggerMenu*& menu) +{ + // Loads the trigger menu object from the CDB path. + + HLTDebug("Trying to load trigger menu from '%s'.", cdbPath); + if (AliCDBManager::Instance() == NULL) + { + HLTError("CDB manager object not found."); + return -EIO; + } + AliCDBStorage* store = AliCDBManager::Instance()->GetDefaultStorage(); + if (store == NULL) + { + HLTError("Could not get the the default storage for the CDB."); + return -EIO; + } + Int_t version = store->GetLatestVersion(cdbPath, GetRunNo()); + Int_t subVersion = store->GetLatestSubVersion(cdbPath, GetRunNo(), version); + AliCDBEntry* entry = AliCDBManager::Instance()->Get(cdbPath, GetRunNo(), version, subVersion); + if (entry == NULL) + { + HLTError("Could not get the CDB entry for \"%s\".", cdbPath); + return -EIO; + } + TObject* obj = entry->GetObject(); + if (obj == NULL) + { + HLTError("Configuration object for \"%s\" is missing.", cdbPath); + return -ENOENT; + } + if (obj->IsA() != AliHLTTriggerMenu::Class()) + { + HLTError("Wrong type for configuration object in \"%s\". Found a %s but we expect a AliHLTTriggerMenu.", + cdbPath, obj->ClassName() + ); + return -EPROTO; + } + menu = static_cast(obj); return 0; } int AliHLTGlobalTriggerComponent::GenerateTrigger( - const AliHLTTriggerMenu* menu, TString& name, + const AliHLTTriggerMenu* menu, TString& name, TString& filename, const TClonesArray& includePaths, const TClonesArray& includeFiles ) { // Generates the global trigger class that will implement the specified trigger menu. // See header for more details. + HLTDebug("Generating custom HLT trigger class named %s using trigger menu %p.", ((void*)menu), name.Data()); + // Create a new UUID and replace the '-' characters with '_' to make it a valid // C++ symbol name. TUUID uuid; @@ -426,13 +538,13 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( // Create the name of the new class. name = "AliHLTGlobalTriggerImpl_"; name += uuidstr; - fCodeFileName = name + ".cxx"; + filename = name + ".cxx"; // Open a text file to write the code and generate the new class. - fstream code(fCodeFileName.Data(), ios_base::out | ios_base::trunc); + fstream code(filename.Data(), ios_base::out | ios_base::trunc); if (not code.good()) { - HLTError("Could not open file '%s' for writing.", fCodeFileName.Data()); + HLTError("Could not open file '%s' for writing.", filename.Data()); return -EIO; } @@ -440,10 +552,11 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( int result = BuildSymbolList(menu, symbols); if (result != 0) return result; - //code << "#ifndef __CINT__" << endl; + code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl; code << "#include " << endl; code << "#include \"TString.h\"" << endl; code << "#include \"TClonesArray.h\"" << endl; + code << "#include \"AliHLTLogging.h\"" << endl; code << "#include \"AliHLTGlobalTrigger.h\"" << endl; code << "#include \"AliHLTGlobalTriggerDecision.h\"" << endl; code << "#include \"AliHLTDomainEntry.h\"" << endl; @@ -452,7 +565,6 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( code << "#include \"AliHLTTriggerMenu.h\"" << endl; code << "#include \"AliHLTTriggerMenuItem.h\"" << endl; code << "#include \"AliHLTTriggerMenuSymbol.h\"" << endl; - //code << "#endif //__CINT__" << endl; // Add any include files that were specified on the command line. for (Int_t i = 0; i < includeFiles.GetEntriesFast(); i++) @@ -461,11 +573,41 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( code << "#include \"" << file.Data() << "\"" << endl; } - code << "class " << name << " : public AliHLTGlobalTrigger" << endl; + if (fDebugMode) + { + code << "#else" << endl; + code << "const char* gFunctionName = \"???\";" << endl; + code << "#define HLTDebug(msg) if (CheckFilter(kHLTLogDebug) && CheckGroup(Class_Name())) SendMessage(kHLTLogDebug, Class_Name(), ::gFunctionName, __FILE__, __LINE__, msg)" << endl; + } + code << "#endif" << endl; + + code << "class " << name << " :" << endl; + // Add appropriate #ifdef sections since we need to prevent inheritance from + // AliHLTGlobalTrigger. CINT does not seem to support multiple inheritance nor + // multiple levels of inheritance. Neither of the following schemes worked: + // + // 1) class AliHLTGlobalTrigger : public AliHLTLogging {}; + // class AliHLTGlobalTriggerImpl_xyz : public AliHLTGlobalTrigger {}; + // + // 2) class AliHLTGlobalTrigger {}; + // class AliHLTGlobalTriggerImpl_xyz : public AliHLTGlobalTrigger, public AliHLTLogging {}; + // + // Thus, we are forced to just inherit from AliHLTLogging when running in the CINT + // interpreter. But we anyway have to call the global trigger implementation class + // through the AliHLTGlobalTriggerWrapper so this is not such a problem. + code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl; + code << " public AliHLTGlobalTrigger," << endl; + code << "#endif" << endl; + code << " public AliHLTLogging" << endl; code << "{" << endl; code << "public:" << endl; - code << " " << name << "() : AliHLTGlobalTrigger()"; + // Generate constructor method. + code << " " << name << "() :" << endl; + code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl; + code << " AliHLTGlobalTrigger()," << endl; + code << "#endif" << endl; + code << " AliHLTLogging()"; // Write the symbols in the trigger menu in the initialisation list. for (Int_t i = 0; i < symbols.GetEntriesFast(); i++) { @@ -485,15 +627,21 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( code << endl << " {" << endl; if (fDebugMode) { + code << "#ifdef __CINT__" << endl; + code << " gFunctionName = \"" << name.Data() <<"\";" << endl; + code << "#endif" << endl; code << " SetLocalLoggingLevel(kHLTLogAll);" << endl; - code << " HLTInfo(\"Creating new instance at %p.\", this);" << endl; + code << " HLTDebug(Form(\"Creating new instance at %p.\", this));" << endl; } code << " }" << endl; code << " virtual ~" << name << "() {" << endl; if (fDebugMode) { - code << " HLTInfo(\"Deleting instance at %p.\", this);" << endl; + code << "#ifdef __CINT__" << endl; + code << " gFunctionName = \"~" << name.Data() << "\";" << endl; + code << "#endif" << endl; + code << " HLTDebug(Form(\"Deleting instance at %p.\", this));" << endl; } code << " }" << endl; @@ -501,8 +649,12 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( code << " virtual void FillFromMenu(const AliHLTTriggerMenu& menu) {" << endl; if (fDebugMode) { - code << " HLTDebug(\"Filling description entries from trigger menu for global trigger %p.\", this);" << endl; + code << "#ifdef __CINT__" << endl; + code << " gFunctionName = \"FillFromMenu\";" << endl; + code << "#endif" << endl; + code << " HLTDebug(Form(\"Filling description entries from trigger menu for global trigger %p.\", this));" << endl; } + code << " fCounter.Set(menu.NumberOfItems());" << endl; for (UInt_t i = 0; i < menu->NumberOfItems(); i++) { code << " fMenuItemDescription" << i << " = (menu.Item(" << i @@ -510,8 +662,8 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( } if (fDebugMode) { - code << " HLTDebug(\"Finished filling description entries from trigger menu.\");" << endl; - code << " HLTDebug(\"Filling domain entries from trigger menu symbols for global trigger %p.\", this);" << endl; + code << " HLTDebug(Form(\"Finished filling description entries from trigger menu.\"));" << endl; + code << " HLTDebug(Form(\"Filling domain entries from trigger menu symbols for global trigger %p.\", this));" << endl; } code << " for (Int_t i = 0; i < menu.SymbolArray().GetEntriesFast(); i++) {" << endl; code << " const AliHLTTriggerMenuSymbol* symbol = dynamic_cast( symbols.UncheckedAt(i) ); - code << " if (strcmp(symbol->Name(), \"" << symbol->RealName() << "\") == 0) {" << endl; + code << " if (strcmp(symbol->Name(), \"" << symbol->Name() << "\") == 0) {" << endl; if (fDebugMode) { - code << " HLTDebug(\"Assinging domain entry value to match for symbol '%s' to '%s'.\"," - " symbol->Name(), symbol->BlockType().AsString().Data());" << endl; + code << " HLTDebug(Form(\"Assinging domain entry value corresponding with symbol '%s' to '%s'.\"," + " symbol->Name(), symbol->BlockType().AsString().Data()));" << endl; } code << " " << symbol->Name() << "DomainEntry = symbol->BlockType();" << endl; code << " continue;" << endl; @@ -533,7 +685,7 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( code << " }" << endl; if (fDebugMode) { - code << " HLTDebug(\"Finished filling domain entries from trigger menu symbols.\");" << endl; + code << " HLTDebug(Form(\"Finished filling domain entries from trigger menu symbols.\"));" << endl; } code << " }" << endl; @@ -541,13 +693,26 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( code << " virtual void NewEvent() {" << endl; if (fDebugMode) { - code << " HLTDebug(\"New event for global trigger object %p, initialising variables to default values.\", this);" << endl; + code << "#ifdef __CINT__" << endl; + code << " gFunctionName = \"NewEvent\";" << endl; + code << "#endif" << endl; + code << " HLTDebug(Form(\"New event for global trigger object %p, initialising variables to default values.\", this));" << endl; } // Write code to initialise the symbols in the trigger menu to their default values. for (Int_t i = 0; i < symbols.GetEntriesFast(); i++) { AliHLTTriggerMenuSymbol* symbol = static_cast( symbols.UncheckedAt(i) ); - code << " " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl; + // CINT has problems with the implicit equals operator for complex types, so if + // the type has a equals operater we need to write the operator call explicitly. + TClass* clas = TClass::GetClass(symbol->Type()); + if (clas != NULL and clas->GetMethodAny("operator=") != NULL) + { + code << " " << symbol->Name() << ".operator = (" << symbol->DefaultValue() << ");" << endl; + } + else + { + code << " " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl; + } if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0) { code << " " << symbol->Name() << "TriggerDomain.Clear();" << endl; @@ -555,18 +720,24 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( } if (fDebugMode) { - code << " HLTDebug(\"Finished initialising variables.\");" << endl; + code << " HLTDebug(Form(\"Finished initialising variables.\"));" << endl; } code << " }" << endl; // Generate the Add method. code << " virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl; + if (fDebugMode) + { + code << "#ifdef __CINT__" << endl; + code << " gFunctionName = \"Add\";" << endl; + code << "#endif" << endl; + } code << " AliHLTDomainEntry _type_spec_(_type_, _spec_);" << endl; if (fDebugMode) { - code << " HLTDebug(\"Adding TObject %p, with class name '%s' from data block" + code << " HLTDebug(Form(\"Adding TObject %p, with class name '%s' from data block" " '%s', to global trigger object %p\", _object_, _object_->ClassName()," - " _type_spec_.AsString().Data(), this);" << endl; + " _type_spec_.AsString().Data(), this));" << endl; code << " _object_->Print();" << endl; code << " bool _object_assigned_ = false;" << endl; } @@ -582,26 +753,26 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( { if (isTrigDecision) { - code << " HLTDebug(\"Trying to match input object to class '" + code << " HLTDebug(Form(\"Trying to match input object to class '" << symbol->ObjectClass() << "', trigger name '" << symbol->RealName() << "' and block type '%s'\", " << symbol->Name() - << "DomainEntry.AsString().Data());" << endl; + << "DomainEntry.AsString().Data()));" << endl; } else { - code << " HLTDebug(\"Trying to match input object to class '" + code << " HLTDebug(Form(\"Trying to match input object to class '" << symbol->ObjectClass() << "' and block type '%s'\", " - << symbol->Name() << "DomainEntry.AsString().Data());" << endl; + << symbol->Name() << "DomainEntry.AsString().Data()));" << endl; } } code << " const " << symbol->ObjectClass() << "* " << symbol->Name() << "_object_ = dynamic_castObjectClass() << "*>(_object_);" << endl; - code << " if (" << symbol->Name() << "_object_ != NULL and "; + code << " if (" << symbol->Name() << "_object_ != NULL && "; if (isTrigDecision) { code << "strcmp(" << symbol->Name() << "_object_->Name(), \"" - << symbol->RealName() << "\") == 0 and "; + << symbol->Name() << "\") == 0 && "; } code << symbol->Name() << "DomainEntry == _type_spec_) {" << endl; TString fullname = symbol->Name(); @@ -615,84 +786,259 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( } if (fDebugMode) { - code << " HLTDebug(\"Added TObject %p with class name '%s' to variable " - << symbol->Name() << "\", _object_, _object_->ClassName());" << endl; + code << " HLTDebug(Form(\"Added TObject %p with class name '%s' to variable " + << symbol->Name() << "\", _object_, _object_->ClassName()));" << endl; code << " _object_assigned_ = true;" << endl; } code << " }" << endl; } if (fDebugMode) { - code << " if (not _object_assigned_) HLTDebug(\"Did not assign TObject %p" - " with class name '%s' to any variable.\", _object_, _object_->ClassName());" + code << " if (! _object_assigned_) {" << endl; + code << " HLTDebug(Form(\"Did not assign TObject %p" + " with class name '%s' to any variable.\", _object_, _object_->ClassName()));" << endl; + code << " }" << endl; } code << " }" << endl; // Generate the CalculateTriggerDecision method. + // This requires code to be generated that checks which items in the trigger menu + // have their conditions asserted and then the trigger domain is generated from + // those fired items. + // The processing will start from the highest priority trigger group and stop + // after at least one trigger from the current priority group being processed + // is positive. For each priority group all the trigger menu items are checked. + // Their combined trigger condition expression must be true for the trigger priority + // group to be triggered positive. The full condition expression is formed by + // concatenating the individual condition expressions. If no trailing operators are + // used in the individual expressions then the default condition operator is placed + // between two concatenated condition expressions. + // If a trigger priority group has at least one trigger fired then the trigger domain + // is calculated such that it will give the same result as the concatenated trigger + // domain merging expressions for all the individual trigger menu items with + // positive results. Again, if no trailing operators are used in the individual + // merging expressions then the default domain operator is placed between two + // expression fragments. code << " virtual bool CalculateTriggerDecision(AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl; if (fDebugMode) { - code << " HLTDebug(\"Calculating global HLT trigger result with trigger object at %p.\", this);" << endl; + code << "#ifdef __CINT__" << endl; + code << " gFunctionName = \"CalculateTriggerDecision\";" << endl; + code << "#endif" << endl; + code << " HLTDebug(Form(\"Calculating global HLT trigger result with trigger object at %p.\", this));" << endl; } - code << " bool result=false;" << endl; + + // Build a list of priorities used in the trigger menu. + std::vector priorities; for (UInt_t i = 0; i < menu->NumberOfItems(); i++) { const AliHLTTriggerMenuItem* item = menu->Item(i); - TString triggerCondision = item->TriggerCondision(); - TString mergeExpr = item->MergeExpression(); - for (Int_t j = 0; j < symbols.GetEntriesFast(); j++) + bool priorityNotInList = std::find(priorities.begin(), priorities.end(), item->Priority()) == priorities.end(); + if (priorityNotInList) priorities.push_back(item->Priority()); + } + std::sort(priorities.begin(), priorities.end(), AliHLTDescendingNumbers); + // From the priority list, build the priority groups in the correct order, + // i.e. highest priority first. + // The priority group is a list of vectors of integers. The integers are the + // index numbers into the trigger menu item list for the items which form part + // of the priority group. + std::vector > priorityGroup; + priorityGroup.insert(priorityGroup.begin(), priorities.size(), std::vector()); + for (size_t n = 0; n < priorities.size(); n++) + { + UInt_t priority = priorities[n]; + for (UInt_t i = 0; i < menu->NumberOfItems(); i++) { - AliHLTTriggerMenuSymbol* symbol = static_cast( symbols.UncheckedAt(j) ); - if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") != 0) continue; - TString newname = symbol->Name(); - newname += "TriggerDomain"; - mergeExpr.ReplaceAll(symbol->RealName(), newname); - triggerCondision.ReplaceAll(symbol->RealName(), symbol->Name()); + const AliHLTTriggerMenuItem* item = menu->Item(i); + if (item->Priority() == priority) priorityGroup[n].push_back(i); } + } + + for (size_t n = 0; n < priorityGroup.size(); n++) + { if (fDebugMode) { - code << " HLTDebug(\"Trying trigger condition " << i - << " (Description = '%s').\", fMenuItemDescription" << i << ".Data());" - << endl; + code << " HLTDebug(Form(\"Processing trigger priority group " << priorities[n] << "\"));" << endl; } - code << " if (" << triggerCondision << ") {" << endl; - code << " IncrementCounter(" << i << ");" << endl; - const char* indentation = ""; - if (item->PreScalar() != 0) + code << " "; + if (n == 0) code << "UInt_t "; + code << "_previous_match_ = 0xFFFFFFFF;" << endl; + code << " "; + if (n == 0) code << "bool "; + code << "_trigger_matched_ = false;" << endl; + code << " "; + if (n == 0) code << "bool "; + code << "_group_result_ = false;" << endl; + std::vector conditionOperator; + conditionOperator.insert(conditionOperator.begin(), priorityGroup[n].size(), TString("")); + std::vector domainOperator; + domainOperator.insert(domainOperator.begin(), priorityGroup[n].size(), TString("")); + for (size_t m = 0; m < priorityGroup[n].size(); m++) { - indentation = " "; - code << " if ((GetCounter(" << i << ") % " << item->PreScalar() << ") == 1) {" << endl; + UInt_t i = priorityGroup[n][m]; + const AliHLTTriggerMenuItem* item = menu->Item(i); + TString triggerCondition = item->TriggerCondition(); + TString mergeExpr = item->MergeExpression(); + // Replace the symbols found in the trigger condition and merging expressions + // with appropriate compilable versions. + for (Int_t j = 0; j < symbols.GetEntriesFast(); j++) + { + AliHLTTriggerMenuSymbol* symbol = static_cast( symbols.UncheckedAt(j) ); + bool symbolNamesDifferent = strcmp(symbol->RealName(), symbol->Name()) != 0; + if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0) + { + TString newname = symbol->Name(); + newname += "TriggerDomain"; + mergeExpr.ReplaceAll(symbol->RealName(), newname); + } + else + { + if (symbolNamesDifferent) mergeExpr.ReplaceAll(symbol->RealName(), symbol->Name()); + } + if (symbolNamesDifferent) triggerCondition.ReplaceAll(symbol->RealName(), symbol->Name()); + } + // We allow the trigger conditions and merging expressions to have trailing operators. + // Thus, we need to extract the operators and cleanup the expressions so that they will + // compile. This means that we silently ignore the trailing operator if not needed. + if (ExtractedOperator(triggerCondition, conditionOperator[m])) + { + // If the trailing operator is the same as the default operator then reset + // the value in the operator list so that the default is used in the generated + // code. This creates more compact code. + if (conditionOperator[m] == menu->DefaultConditionOperator()) conditionOperator[m] = ""; + } + if (ExtractedOperator(mergeExpr, domainOperator[m])) + { + if (domainOperator[m] == menu->DefaultDomainOperator()) domainOperator[m] = ""; + } + if (fDebugMode) + { + code << " HLTDebug(Form(\"Trying trigger condition " << i + << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));" + << endl; + } + code << " "; + if (n == 0 and m == 0) code << "bool "; + code << "_item_result_ = false;" << endl; + code << " if (" << triggerCondition << ") {" << endl; + code << " ++fCounter[" << i << "];" << endl; + const char* indentation = ""; + if (item->PreScalar() != 0) + { + indentation = " "; + code << " if ((fCounter[" << i << "] % " << item->PreScalar() << ") == 1) {" << endl; + } + code << indentation << " _item_result_ = true;" << endl; + if (fDebugMode) + { + code << indentation << " HLTDebug(Form(\"Matched trigger condition " << i + << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));" << endl; + } + if (item->PreScalar() != 0) + { + code << " }" << endl; + } + code << " }" << endl; + if (m == 0) + { + // Since this is the first item of the trigger group, + // the generated trigger logic can be simplified a little. + code << " _group_result_ = _item_result_;" << endl; + code << " if (_item_result_) {" << endl; + code << " _domain_ = " << mergeExpr.Data() << ";" << endl; + code << " _description_ = fMenuItemDescription" << i << ";" << endl; + code << " _previous_match_ = " << i << ";" << endl; + code << " _trigger_matched_ = true;" << endl; + code << " }" << endl; + } + else + { + bool switchWillBeEmpty = true; + for (size_t k = 0; k < m; k++) + { + if (conditionOperator[k] == "") continue; + switchWillBeEmpty = false; + } + if (switchWillBeEmpty) + { + code << " _group_result_ = _group_result_ " + << menu->DefaultConditionOperator() << " _item_result_;" << endl; + } + else + { + code << " switch(_previous_match_) {" << endl; + for (size_t k = 0; k < m; k++) + { + if (conditionOperator[k] == "") continue; + code << " case " << k << ": _group_result_ = _group_result_ " + << conditionOperator[k] << " _item_result_; break;" << endl; + } + code << " default: _group_result_ = _group_result_ " + << menu->DefaultConditionOperator() << " _item_result_;" << endl; + code << " }" << endl; + } + code << " if (_item_result_) {" << endl; + code << " if (_trigger_matched_) {" << endl; + switchWillBeEmpty = true; + for (size_t k = 0; k < m; k++) + { + if (domainOperator[k] == "") continue; + switchWillBeEmpty = false; + } + if (switchWillBeEmpty) + { + code << " _domain_ = _domain_ " << menu->DefaultDomainOperator() << " " + << mergeExpr.Data() << ";" << endl; + } + else + { + code << " switch(_previous_match_) {" << endl; + for (size_t k = 0; k < m; k++) + { + if (domainOperator[k] == "") continue; + code << " case " << k << ": _domain_ = _domain_ " + << domainOperator[k] << " " << mergeExpr.Data() << "; break;" << endl; + } + code << " default: _domain_ = _domain_ " + << menu->DefaultDomainOperator() << " " << mergeExpr.Data() << ";" << endl; + code << " }" << endl; + } + code << " _description_ += \",\";" << endl; + code << " _description_ += fMenuItemDescription" << i << ";" << endl; + code << " } else {" << endl; + code << " _domain_ = " << mergeExpr.Data() << ";" << endl; + code << " _description_ = fMenuItemDescription" << i << ";" << endl; + code << " }" << endl; + code << " _previous_match_ = " << i << ";" << endl; + code << " _trigger_matched_ = true;" << endl; + code << " }" << endl; + } } - code << indentation << " _domain_ |= " << mergeExpr.Data() << ";" << endl; - code << indentation << " if (!_description_.IsNull()) _description_+= \",\";" << endl; - code << indentation << " _description_ += fMenuItemDescription" << i << ";" << endl; + code << " if (_group_result_) {" << endl; if (fDebugMode) { - code << indentation << " HLTDebug(\"Matched trigger condition " << i - << " (Description = '%s').\", fMenuItemDescription" << i << ".Data());" << endl; - } - code << indentation << " result=true;" << endl; - if (item->PreScalar() != 0) - { - code << " }" << endl; + if (n < priorities.size() - 1) + { + code << " HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n] + << ". Stopping processing here because all other trigger groups have lower priority.\"));" << endl; + } + else + { + code << " HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n] << ".\"));" << endl; + } } + code << " return true;" << endl; code << " }" << endl; } - code << " return result;" << endl; + code << " _domain_.Clear();" << endl; + code << " _description_ = \"\";" << endl; + code << " return false;" << endl; code << " }" << endl; - // Generate the custom Factory class. - code << " class FactoryImpl : public AliHLTGlobalTrigger::Factory" << endl; - code << " {" << endl; - code << " public:" << endl; - code << " virtual const char* ClassName() const {" << endl; - code << " return \"" << name << "\";" << endl; - code << " }" << endl; - code << " virtual AliHLTGlobalTrigger* New() const {" << endl; - code << " return new " << name << "();" << endl; - code << " }" << endl; - code << " };" << endl; + // Generate getter and setter methods for the counters. + code << " const TArrayL64& GetCounters() const { return fCounter; }" << endl; + code << " void SetCounters(const TArrayL64& counters) { fCounter = counters; }" << endl; code << "private:" << endl; // Add the symbols in the trigger menu to the list of private variables. @@ -710,17 +1056,21 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger( { code << " TString fMenuItemDescription" << i << ";" << endl; } + code << " TArrayL64 fCounter;" << endl; + code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl; + code << " ClassDef(" << name.Data() << ", 0)" << endl; + code << "#else" << endl; + code << " virtual const char* Class_Name() const { return \"" << name.Data() << "\"; }" << endl; + code << "#endif" << endl; code << "};" << endl; - - // Write a global object for the Factory class for automatic registration. - code << "namespace {" << endl; - code << " const " << name << "::FactoryImpl gkFactoryImpl;" << endl; - code << "};" << endl; + code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl; + code << "ClassImp(" << name.Data() << ")" << endl; + code << "#endif" << endl; code.close(); // Now we need to compile and load the new class. - result = LoadTriggerClass(fCodeFileName, includePaths); + result = LoadTriggerClass(filename, includePaths); return result; } @@ -731,6 +1081,8 @@ int AliHLTGlobalTriggerComponent::LoadTriggerClass( { // Loads the code for a custom global trigger class implementation on the fly. + HLTDebug("Loading HLT trigger class from file '%s'.", filename); + TString compiler = gSystem->GetBuildCompilerVersion(); if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc"))) { @@ -744,14 +1096,14 @@ int AliHLTGlobalTriggerComponent::LoadTriggerClass( // $ALICE_ROOT subfolders includePath = "-I${ALICE_ROOT}/include -I${ALICE_ROOT}/HLT/BASE -I${ALICE_ROOT}/HLT/trigger"; #endif - HLTDebug("using include settings: %s", includePath.Data()); // Add any include paths that were specified on the command line. for (Int_t i = 0; i < includePaths.GetEntriesFast(); i++) { TString path = static_cast(includePaths.UncheckedAt(i))->String(); - includePath += " "; + includePath += " -I"; includePath += path; } + HLTDebug("using include settings: %s", includePath.Data()); gSystem->SetIncludePath(includePath); gSystem->SetFlagsOpt("-O3 -DNDEBUG"); gSystem->SetFlagsDebug("-g3 -DDEBUG -D__DEBUG"); @@ -774,7 +1126,7 @@ int AliHLTGlobalTriggerComponent::LoadTriggerClass( else { // If we do not support the compiler then try interpret the class instead. - TString cmd = ".x "; + TString cmd = ".L "; cmd += filename; Int_t errorcode = TInterpreter::kNoError; gROOT->ProcessLine(cmd, &errorcode); @@ -792,6 +1144,51 @@ int AliHLTGlobalTriggerComponent::LoadTriggerClass( } +int AliHLTGlobalTriggerComponent::UnloadTriggerClass(const char* filename) +{ + // Unloads the code previously loaded by LoadTriggerClass. + + HLTDebug("Unloading HLT trigger class in file '%s'.", filename); + + TString compiler = gSystem->GetBuildCompilerVersion(); + if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc"))) + { + TString libname = filename; + Ssiz_t dotpos = libname.Last('.'); + if (0 <= dotpos and dotpos < libname.Length()) libname[dotpos] = '_'; + libname += "."; + libname += gSystem->GetSoExt(); + + char* path = NULL; + int result = 0; + if ((path = gSystem->DynamicPathName(libname)) != NULL) + { + result = gInterpreter->UnloadFile(path); + delete [] path; + } + if (result != TInterpreter::kNoError) return -ENOENT; + } + else + { + // If we do not support the compiler then try interpret the class instead. + TString cmd = ".U "; + cmd += filename; + Int_t errorcode = TInterpreter::kNoError; + gROOT->ProcessLine(cmd, &errorcode); + if (errorcode != TInterpreter::kNoError) + { + HLTFatal("Could not unload interpreted global trigger menu implementation" + " (Interpreter error code = %d).", + errorcode + ); + return -ENOENT; + } + } + + return 0; +} + + int AliHLTGlobalTriggerComponent::FindSymbol(const char* name, const TClonesArray& list) { // Searches for the named symbol in the given list. @@ -829,7 +1226,7 @@ int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, for (UInt_t i = 0; i < menu->NumberOfItems(); i++) { const AliHLTTriggerMenuItem* item = menu->Item(i); - TString str = item->TriggerCondision(); + TString str = item->TriggerCondition(); Ssiz_t start = 0; do { @@ -885,15 +1282,72 @@ int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, return 0; } + +bool AliHLTGlobalTriggerComponent::ExtractedOperator(TString& expr, TString& op) +{ + // Extracts the trailing operator from the expression. + + Ssiz_t i = 0; + // First skip the trailing whitespace. + bool whitespace = true; + for (i = expr.Length()-1; i >= 0 and whitespace; i--) + { + switch (expr[i]) + { + case ' ': case '\t': case '\r': case '\n': + whitespace = true; + break; + default: + whitespace = false; + } + } + if (i < 0 or whitespace) return false; + + // Now find the first whitespace character before the trailing symbol. + bool nonwhitespace = true; + for (; i >= 0 and nonwhitespace; i--) + { + switch (expr[i]) + { + case ' ': case '\t': case '\r': case '\n': + nonwhitespace = false; + break; + default: + nonwhitespace = true; + } + } + if (i < 0 or nonwhitespace) return false; + + // Extract the last symbols and check if it is a valid operator. + TString s = expr; + s.Remove(0, i+2); + if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or + s == "compl" or s == "not" or s == "not_eq" or s == "or" or + s == "or_eq" or s == "xor" or s == "xor_eq" or s == "&&" or + s == "&=" or s == "&" or s == "|" or s == "~" or s == "!" or + s == "!=" or s == "||" or s == "|=" or s == "^" or s == "^=" or + s == "==" or s == "+" or s == "-" or s == "*" or s == "/" or + s == "%" or s == ">" or s == "<" or s == ">=" or s == "<=" + ) + { + expr.Remove(i+1); + op = s; + return true; + } + + return false; +} + + int AliHLTGlobalTriggerComponent::PrintStatistics(const AliHLTGlobalTrigger* pTrigger, AliHLTComponentLogSeverity level, int offset) const { // print some statistics int totalEvents=GetEventCount()+offset; - for (int i=0; iCounters().GetSize(); i++) { - ULong64_t count=pTrigger->Counters()[i]; + for (int i=0; iGetCounters().GetSize(); i++) { + ULong64_t count=pTrigger->GetCounters()[i]; float ratio=0; if (totalEvents>0) ratio=100*(float)count/totalEvents; - HLTLog(level, "Item %d: total events: %d - triggered events: %llu (%.1f%%)", i, totalEvents, count, ratio); + HLTLog(level, "Item %d: total events: %d - counted events: %llu (%.1f%%)", i, totalEvents, count, ratio); } return 0; } diff --git a/HLT/trigger/AliHLTGlobalTriggerComponent.h b/HLT/trigger/AliHLTGlobalTriggerComponent.h index 201e92fe20f..f5fd852f906 100644 --- a/HLT/trigger/AliHLTGlobalTriggerComponent.h +++ b/HLT/trigger/AliHLTGlobalTriggerComponent.h @@ -12,10 +12,10 @@ /// @brief Declaration of the AliHLTGlobalTriggerComponent component class. #include "AliHLTTrigger.h" +#include "TClonesArray.h" class AliHLTTriggerMenu; class AliHLTGlobalTrigger; -class TClonesArray; /** * \class AliHLTGlobalTriggerComponent @@ -55,6 +55,8 @@ class TClonesArray; * Used to force the component to use an existing class for the global HLT trigger * class implementation, with the name of classname and found in the file * filename. + * \li -skipctp
+ * Indicates that the CTP data should not be added to the global HLT trigger decision. * *

Configuration:

* @@ -135,6 +137,15 @@ class AliHLTGlobalTriggerComponent : public AliHLTTrigger */ virtual int DoTrigger(); + /** + * Reconfigures the component by loading the trigger menu from the given + * CDB entry. + * \param cdbEntry The CDB path to the trigger menu to load. + * \param chainId The ID of the component in the chain. + * \returns Zero on success and non-zero values otherwise. + */ + virtual int Reconfigure(const char* cdbEntry, const char* chainId); + private: /// Not implemented. Do not allow copying of this object. @@ -142,6 +153,16 @@ class AliHLTGlobalTriggerComponent : public AliHLTTrigger /// Not implemented. Do not allow copying of this object. AliHLTGlobalTriggerComponent& operator = (const AliHLTGlobalTriggerComponent& obj); + /** + * Loads a trigger menu object from the CDB. + * \param cdbPath in The path in the CDB to load the trigger menu object from. + * \param menu out A pointer that gets filled with the new trigger menu object. + * \returns Zero if the trigger menu object was found and the pointer to it + * set in the menu variable. If a non-zero error code is returned then + * the menu variable is not changed at all. + */ + int LoadTriggerMenu(const char* cdbPath, const AliHLTTriggerMenu*& menu); + /** * Generates the code for the global trigger to apply the given trigger menu. * The code will then be compiled on the fly and loaded. The name of the new @@ -150,14 +171,19 @@ class AliHLTGlobalTriggerComponent : public AliHLTTrigger * AliHLTGlobalTrigger::CreateNew(name) * \endcode * where name is the name of the generated class as returned by this method. + * + * The name of the generated code file is stored in the variable fCodeFileName + * and the fDeleteCodeFile is set to true. + * * \param menu in The trigger menu to create the global trigger class from. * \param name out The name of the generated class. + * \param filename out The name of the generated file containing the code. * \param includePaths in The list of include path strings. * \param includeFiles in The list of include file strings. * \returns The error code suitable to return in DoInit. Zero on success. */ int GenerateTrigger( - const AliHLTTriggerMenu* menu, TString& name, + const AliHLTTriggerMenu* menu, TString& name, TString& filename, const TClonesArray& includePaths, const TClonesArray& includeFiles ); @@ -171,6 +197,13 @@ class AliHLTGlobalTriggerComponent : public AliHLTTrigger */ int LoadTriggerClass(const char* filename, const TClonesArray& includePaths); + /** + * Unloads the code that was previously loaded by LoadTriggerClass. + * \param filename The name of the file containing the global trigger class logic to be unloaded. + * \returns The error code suitable to return in DoInit. Zero on success. + */ + int UnloadTriggerClass(const char* filename); + /** * Searches for the specified symbol name in the given list. * \param name The name of the symbol to find. @@ -187,6 +220,18 @@ class AliHLTGlobalTriggerComponent : public AliHLTTrigger * \returns The error code suitable to return in DoInit. Zero on success. */ int BuildSymbolList(const AliHLTTriggerMenu* menu, TClonesArray& list); + + /** + * Extracts the trailing operator in a C++ expression and returns the found + * operator in a separate output string. + * [in/out] \param expr The C++ expression to check. The trailing operator + * is removed from the expression if found. + * [out] \param op The output variable which will be filled with the + * operator found in the expression. + * \return true if the trailing operator was found in the expression and + * false otherwise. + */ + bool ExtractedOperator(TString& expr, TString& op); /** * Add trigger decisions according to the active CTP trigger classes @@ -207,8 +252,14 @@ class AliHLTGlobalTriggerComponent : public AliHLTTrigger bool fDebugMode; //! Indicates if the generated global trigger class should be in debug mode. bool fRuntimeCompile; //! Indicates if the generated global trigger class should be compiled bool fSkipCTPCounters; //! Indicates whether to ship CTP info with the trigger decision + bool fDeleteCodeFile; //! If true then the code file indicated by fCodeFileName should be deleted during DoDeinit. TString fCodeFileName; //! base file name of the generated code for the global trigger + TString fClassName; //! The generated/loaded trigger class name. TClonesArray* fCTPDecisions; //! AliHLTTriggerDecision objects for the CTP classes + unsigned long fBufferSizeConst; //! Constant size estimate for GetOutputDataSize. + double fBufferSizeMultiplier; //! Buffer size multiplier estimate for GetOutputDataSize. + TClonesArray fIncludePaths; //! Paths specified by the -includepath command line option. + TClonesArray fIncludeFiles; //! Files specified by the -include command line option. static const char* fgkTriggerMenuCDBPath; //! The path string to read the trigger menu from the CDB. diff --git a/HLT/trigger/AliHLTGlobalTriggerConfig.cxx b/HLT/trigger/AliHLTGlobalTriggerConfig.cxx index 091c537a23d..6e0e74cfac8 100644 --- a/HLT/trigger/AliHLTGlobalTriggerConfig.cxx +++ b/HLT/trigger/AliHLTGlobalTriggerConfig.cxx @@ -1,4 +1,4 @@ -// $Id:$ +// $Id$ /************************************************************************** * This file is property of and copyright by the ALICE HLT Project * * ALICE Experiment at CERN, All rights reserved. * @@ -193,6 +193,25 @@ void AliHLTGlobalTriggerConfig::AddSymbol( } +void AliHLTGlobalTriggerConfig::AddItem( + UInt_t priority, const char* conditionExpr, const char* domainExpr, + UInt_t prescalar, const char* description + ) +{ + // Adds a new entry to the trigger menu with a particular priority. + + if (fgMenu == NULL) NewMenu(""); + + AliHLTTriggerMenuItem entry; + entry.TriggerCondition(conditionExpr); + entry.MergeExpression(domainExpr); + entry.PreScalar(prescalar); + entry.Priority(priority); + if (description != NULL) entry.Description(description); + fgMenu->AddItem(entry); +} + + void AliHLTGlobalTriggerConfig::AddItem( const char* conditionExpr, const char* domainExpr, UInt_t prescalar, const char* description @@ -203,7 +222,7 @@ void AliHLTGlobalTriggerConfig::AddItem( if (fgMenu == NULL) NewMenu(""); AliHLTTriggerMenuItem entry; - entry.TriggerCondision(conditionExpr); + entry.TriggerCondition(conditionExpr); entry.MergeExpression(domainExpr); entry.PreScalar(prescalar); if (description != NULL) entry.Description(description); @@ -211,6 +230,24 @@ void AliHLTGlobalTriggerConfig::AddItem( } +void AliHLTGlobalTriggerConfig::AddItem( + UInt_t priority, const char* conditionExpr, const char* domainExpr, + const char* description + ) +{ + // Adds a new entry to the trigger menu with a particular priority. + + if (fgMenu == NULL) NewMenu(""); + + AliHLTTriggerMenuItem entry; + entry.TriggerCondition(conditionExpr); + entry.MergeExpression(domainExpr); + entry.Priority(priority); + if (description != NULL) entry.Description(description); + fgMenu->AddItem(entry); +} + + void AliHLTGlobalTriggerConfig::AddItem( const char* conditionExpr, const char* domainExpr, const char* description ) @@ -220,7 +257,7 @@ void AliHLTGlobalTriggerConfig::AddItem( if (fgMenu == NULL) NewMenu(""); AliHLTTriggerMenuItem entry; - entry.TriggerCondision(conditionExpr); + entry.TriggerCondition(conditionExpr); entry.MergeExpression(domainExpr); if (description != NULL) entry.Description(description); fgMenu->AddItem(entry); @@ -254,6 +291,24 @@ AliHLTTriggerDomain& AliHLTGlobalTriggerConfig::DefaultTriggerDomain() } +void AliHLTGlobalTriggerConfig::SetDefaultConditionOperator(const char* op) +{ + // Sets the default operator for trigger condition merging. + + if (fgMenu == NULL) NewMenu(""); + fgMenu->DefaultConditionOperator(op); +} + + +void AliHLTGlobalTriggerConfig::SetDefaultDomainOperator(const char* op) +{ + // Sets the default operator for trigger domain merging. + + if (fgMenu == NULL) NewMenu(""); + fgMenu->DefaultDomainOperator(op); +} + + void AliHLTGlobalTriggerConfig::Print(Option_t* option) const { // Prints the contents of the current trigger menu being manipulated. diff --git a/HLT/trigger/AliHLTGlobalTriggerConfig.h b/HLT/trigger/AliHLTGlobalTriggerConfig.h index 153a9bc1218..84daf48a63a 100644 --- a/HLT/trigger/AliHLTGlobalTriggerConfig.h +++ b/HLT/trigger/AliHLTGlobalTriggerConfig.h @@ -1,5 +1,5 @@ //-*- Mode: C++ -*- -// $Id:$ +// $Id$ #ifndef ALIHLTGLOBALTRIGGERCONFIG_H #define ALIHLTGLOBALTRIGGERCONFIG_H /* This file is property of and copyright by the ALICE HLT Project * @@ -21,6 +21,15 @@ class AliHLTTriggerDomain; * \class AliHLTGlobalTriggerConfig * This class is a user interface class used to make it easy to create HLT global * trigger configurations (trigger menus). + * + * \note The following symbol names are reserved and should not be used in any + * of the trigger conditions, merging expressions or trigger menu symbols: + * _domain_ + * _description_ + * _item_result_ + * _group_result_ + * _previous_match_ + * _trigger_matched_ */ class AliHLTGlobalTriggerConfig { @@ -178,6 +187,25 @@ class AliHLTGlobalTriggerConfig const char* blockType, const char* origin, UInt_t spec ); + /** + * Adds a new trigger menu item to the current trigger menu with a particular priority. + * \param priority The priority group this entry should be part of. Higher numbers + * indicate higher priorities. + * \param conditionExpr The trigger condition expression. It must be a valid + * C++ expression, where the symbol names must be either defined in the + * menu or the names of AliHLTTrigger components. + * \param domainExpr The trigger domain merging expression. It must be a + * valid C++ expression, where the symbol names must be either defined in + * the menu or the names of AliHLTTrigger components. + * \param prescalar The prescalar value to use (Zero if not used). + * \param description Optional description string which will be used in the + * global result. + */ + static void AddItem( + UInt_t priority, const char* conditionExpr, const char* domainExpr, + UInt_t prescalar, const char* description = NULL + ); + /** * Adds a new trigger menu item to the current trigger menu. * \param conditionExpr The trigger condition expression. It must be a valid @@ -195,6 +223,24 @@ class AliHLTGlobalTriggerConfig const char* description = NULL ); + /** + * Adds a new trigger menu item to the current trigger menu with a particular priority. + * \param priority The priority group this entry should be part of. Higher numbers + * indicate higher priorities. + * \param conditionExpr The trigger condition expression. It must be a valid + * C++ expression, where the symbol names must be either defined in the + * menu or the names of AliHLTTrigger components. + * \param domainExpr The trigger domain merging expression. It must be a + * valid C++ expression, where the symbol names must be either defined in + * the menu or the names of AliHLTTrigger components. + * \param description Optional description string which will be used in the + * global result. + */ + static void AddItem( + UInt_t priority, const char* conditionExpr, const char* domainExpr, + const char* description = NULL + ); + /** * Adds a new trigger menu item to the current trigger menu. * \param conditionExpr The trigger condition expression. It must be a valid @@ -233,6 +279,22 @@ class AliHLTGlobalTriggerConfig */ static AliHLTTriggerDomain& DefaultTriggerDomain(); + /** + * This method sets the default operator used to merge trigger conditions from + * the same trigger menu priority group. + * The trigger menu normally uses the 'or' operator. + * \param op The new default operator to use. + */ + static void SetDefaultConditionOperator(const char* op); + + /** + * This method sets the default operator used to merge trigger domains from + * the same trigger menu priority group that get matched. + * The trigger menu normally uses the '|' operator. + * \param op The new default operator to use. + */ + static void SetDefaultDomainOperator(const char* op); + private: /// Not implemented. Do not allow copying of this object. diff --git a/HLT/trigger/AliHLTGlobalTriggerWrapper.cxx b/HLT/trigger/AliHLTGlobalTriggerWrapper.cxx new file mode 100644 index 00000000000..22eae904581 --- /dev/null +++ b/HLT/trigger/AliHLTGlobalTriggerWrapper.cxx @@ -0,0 +1,282 @@ +// $Id: $ +/************************************************************************** + * This file is property of and copyright by the ALICE HLT Project * + * ALICE Experiment at CERN, All rights reserved. * + * * + * Primary Authors: Artur Szostak * + * for The ALICE HLT Project. * + * * + * Permission to use, copy, modify and distribute this software and its * + * documentation strictly for non-commercial purposes is hereby granted * + * without fee, provided that the above copyright notice appears in all * + * copies and that both the copyright notice and this permission notice * + * appear in the supporting documentation. The authors make no claims * + * about the suitability of this software for any purpose. It is * + * provided "as is" without express or implied warranty. * + **************************************************************************/ + +/// @file AliHLTGlobalTriggerWrapper.cxx +/// @author Artur Szostak +/// @date 28 Oct 2009 +/// @brief Implementation of the AliHLTGlobalTriggerWrapper interface class. +/// +/// The AliHLTGlobalTriggerWrapper class is used to interface with an interpreted +/// class deriving from AliHLTGlobalTrigger. This is used when the global trigger +/// component is using CINT to interpret the trigger logic. The wrapper is necessary +/// to be able to call interpreted code from compiled code. + +#include "AliHLTGlobalTriggerWrapper.h" +#include "TArrayL64.h" +#include "TClass.h" +#include "TInterpreter.h" + +#ifdef R__BUILDING_CINT7 +#include "cint7/Api.h" +#else +#include "Api.h" +#endif + +ClassImp(AliHLTGlobalTriggerWrapper) + + +AliHLTGlobalTriggerWrapper::AliHLTGlobalTriggerWrapper(const char* classname) : + AliHLTGlobalTrigger(), + AliHLTLogging(), + fClass(NULL), + fObject(NULL), + fFillFromMenuCall(), + fNewEventCall(), + fAddCall(), + fCalculateTriggerDecisionCall(), + fGetCountersCall(), + fSetCountersCall() +{ + // The default constructor. + + fClass = TClass::GetClass(classname); + if (fClass == NULL) + { + HLTError("Could not find class information for '%s'.", classname); + return; + } + fFillFromMenuCall.InitWithPrototype(fClass, "FillFromMenu", "const AliHLTTriggerMenu&"); + if (not fFillFromMenuCall.IsValid()) + { + HLTError("Could not initialise method call object for class '%s' and method FillFromMenu.", classname); + return; + } + fNewEventCall.InitWithPrototype(fClass, "NewEvent", " "); // Must have single whitespace in last parameter or we get a segfault in G__interpret_func. + if (not fNewEventCall.IsValid()) + { + HLTError("Could not initialise method call object for class '%s' and method NewEvent.", classname); + return; + } + fAddCall.InitWithPrototype(fClass, "Add", "const TObject*, const AliHLTComponentDataType&, AliHLTUInt32_t"); + if (not fAddCall.IsValid()) + { + HLTError("Could not initialise method call object for class '%s' and method Add.", classname); + return; + } + fCalculateTriggerDecisionCall.InitWithPrototype(fClass, "CalculateTriggerDecision", "AliHLTTriggerDomain&, TString&"); + if (not fCalculateTriggerDecisionCall.IsValid()) + { + HLTError("Could not initialise method call object for class '%s' and method CalculateTriggerDecision.", classname); + return; + } + fGetCountersCall.InitWithPrototype(fClass, "GetCounters", " "); // Must have single whitespace in last parameter or we get a segfault in G__interpret_func. + if (not fGetCountersCall.IsValid()) + { + HLTError("Could not initialise method call object for class '%s' and method GetCounters.", classname); + return; + } + fSetCountersCall.InitWithPrototype(fClass, "SetCounters", "TArrayL64&"); + if (not fSetCountersCall.IsValid()) + { + HLTError("Could not initialise method call object for class '%s' and method SetCounters.", classname); + return; + } + fObject = fClass->New(); + if (fObject == NULL) + { + HLTError("Could not create a new object of type '%s'.", classname); + } +} + + +AliHLTGlobalTriggerWrapper::~AliHLTGlobalTriggerWrapper() +{ + // Default destructor. + + fClass->Destructor(fObject); +} + + +void AliHLTGlobalTriggerWrapper::FillFromMenu(const AliHLTTriggerMenu& menu) +{ + // Fills internal values from the trigger menu. + + struct Params + { + const void* fMenu; + } params; + params.fMenu = &menu; + fFillFromMenuCall.SetParamPtrs(¶ms, 1); + fFillFromMenuCall.Execute(fObject); + int error = G__lasterror(); + if (error != TInterpreter::kNoError) + { + if (error == TInterpreter::kFatal) + { + HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); + } + else + { + HLTError("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); + } + } +} + + +void AliHLTGlobalTriggerWrapper::NewEvent() +{ + // Clears the internal buffers for a new event. + + fNewEventCall.Execute(fObject); + int error = G__lasterror(); + if (error != TInterpreter::kNoError) + { + if (error == TInterpreter::kFatal) + { + HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); + } + else + { + HLTError("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); + } + } +} + + +void AliHLTGlobalTriggerWrapper::Add( + const TObject* object, const AliHLTComponentDataType& type, + AliHLTUInt32_t spec + ) +{ + // Adds parameters from the object to the internal buffers and variables. + + struct Params + { + const void* fObj; + const void* fType; + long fSpec; + } params; + params.fObj = object; + params.fType = &type; + params.fSpec = spec; + fAddCall.SetParamPtrs(¶ms, 3); + fAddCall.Execute(fObject); + int error = G__lasterror(); + if (error != TInterpreter::kNoError) + { + if (error == TInterpreter::kFatal) + { + HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); + } + else + { + HLTError("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); + } + } +} + + +bool AliHLTGlobalTriggerWrapper::CalculateTriggerDecision(AliHLTTriggerDomain& domain, TString& description) +{ + // Calculates the global trigger decision. + + struct Params + { + const void* fDomain; + const void* fDesc; + } params; + params.fDomain = &domain; + params.fDesc = &description; + fCalculateTriggerDecisionCall.SetParamPtrs(¶ms, 2); + Long_t retval; + fCalculateTriggerDecisionCall.Execute(fObject, retval); + int error = G__lasterror(); + if (error != TInterpreter::kNoError) + { + if (error == TInterpreter::kFatal) + { + HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); + } + else + { + HLTError("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); + } + } + return bool(retval); +} + + +const TArrayL64& AliHLTGlobalTriggerWrapper::GetCounters() const +{ + // Returns the internal counter array. + + Long_t retval = 0x0; + fGetCountersCall.Execute(fObject, retval); + int error = G__lasterror(); + if (error != TInterpreter::kNoError) + { + if (error == TInterpreter::kFatal) + { + HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); + } + else + { + HLTError("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); + } + } + static const TArrayL64 emptyArray; + const TArrayL64* ptr = &emptyArray; // Make sure we do not return a NULL pointer. + if (retval != 0x0) ptr = reinterpret_cast(retval); + return *ptr; +} + + +void AliHLTGlobalTriggerWrapper::SetCounters(const TArrayL64& counters) +{ + // Fills the internal counter array with new values. + + struct Params + { + const void* fCounters; + } params; + params.fCounters = &counters; + fSetCountersCall.SetParamPtrs(¶ms, 1); + fSetCountersCall.Execute(fObject); + int error = G__lasterror(); + if (error != TInterpreter::kNoError) + { + if (error == TInterpreter::kFatal) + { + HLTFatal("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); + } + else + { + HLTError("Error interpreting the code for class '%s' at line %d.", fClass->GetName(), G__lasterror_linenum()); + } + } +} + + +bool AliHLTGlobalTriggerWrapper::IsValid() const +{ + // Checks if the wrapper class was initialised correctly. + + return fClass != NULL and fObject != NULL and fFillFromMenuCall.IsValid() + and fNewEventCall.IsValid() and fAddCall.IsValid() + and fCalculateTriggerDecisionCall.IsValid(); +} + diff --git a/HLT/trigger/AliHLTGlobalTriggerWrapper.h b/HLT/trigger/AliHLTGlobalTriggerWrapper.h new file mode 100644 index 00000000000..a3ee287b63d --- /dev/null +++ b/HLT/trigger/AliHLTGlobalTriggerWrapper.h @@ -0,0 +1,111 @@ +//-*- Mode: C++ -*- +// $Id: $ +#ifndef ALIHLTGLOBALTRIGGERWRAPPER_H +#define ALIHLTGLOBALTRIGGERWRAPPER_H +/* This file is property of and copyright by the ALICE HLT Project * + * ALICE Experiment at CERN, All rights reserved. * + * See cxx source for full Copyright notice */ + +/// @file AliHLTGlobalTriggerWrapper.h +/// @author Artur Szostak +/// @date 28 Oct 2009 +/// @brief Declaration of the AliHLTGlobalTriggerWrapper interface class. + +#include "AliHLTGlobalTrigger.h" +#include "AliHLTLogging.h" +#include "TMethodCall.h" + +class TClass; + +/** + * \class AliHLTGlobalTriggerWrapper + * This class is used to interface with an interpreted class deriving from + * AliHLTGlobalTrigger. Technically the interpreted class just need to provide + * the same interface, i.e. the same methods set of methods as AliHLTGlobalTrigger. + * Direct inheritance from AliHLTGlobalTrigger and AliHLTLogging does not seam to + * work so providing the same set of methods is enough. + * The underlying class with which the wrapper interfaces is created and deleted + * when the wrapper is created and deleted. Thus, the underlying object has the + * same lifetime as the wrapper object. + */ +class AliHLTGlobalTriggerWrapper : public AliHLTGlobalTrigger, public AliHLTLogging +{ + public: + + /** + * The default constructor constructs the named underlying class and interfaces with it. + * \param classname The name of the underlying class to interface with. + */ + AliHLTGlobalTriggerWrapper(const char* classname); + + /// Default destructor will delete the underlying class. + virtual ~AliHLTGlobalTriggerWrapper(); + + /** + * Fill values from a trigger menu. Specifically, the description + * strings and domain entry values will be copied over. + * \param menu The trigger menu to fill from. + */ + virtual void FillFromMenu(const AliHLTTriggerMenu& menu); + + /** + * Method to indicate that a new event is being processed and the + * internal buffers should be reset. + */ + virtual void NewEvent(); + + /** + * This method is used to fill in the internal attributes from the given object + * which is found in the input data block list. + * \param object The object to fill from. + * \param type The data block type the object was found in. + * \param spec The data block specification the object was found in. + */ + virtual void Add( + const TObject* object, + const AliHLTComponentDataType& type, + AliHLTUInt32_t spec + ); + + /** + * Calculates the trigger decision and returns the resulting domain and description. + * \param domain The resultant trigger domain for the global HLT result. + * \param description The resultant description for the global HLT result. + * \returns The global HLT trigger decision result. + */ + virtual bool CalculateTriggerDecision(AliHLTTriggerDomain& domain, TString& description); + + /** + * Returns the array of internal trigger counters. + */ + virtual const TArrayL64& GetCounters() const; + + /** + * Sets the internal trigger counter values. + * \param counters The array of trigger counters to use. + */ + virtual void SetCounters(const TArrayL64& counters); + + /// Returns true if the wrapper object has setup the underlying object class properly. + bool IsValid() const; + + private: + + /// Not implemented. Do not allow copying of this object. + AliHLTGlobalTriggerWrapper(const AliHLTGlobalTriggerWrapper& obj); + /// Not implemented. Do not allow copying of this object. + AliHLTGlobalTriggerWrapper& operator = (const AliHLTGlobalTriggerWrapper& obj); + + TClass* fClass; /// Pointer to the object class. + void* fObject; /// Pointer to the object being interfaced. + TMethodCall fFillFromMenuCall; /// Method call object for FillFromMenu method. + TMethodCall fNewEventCall; /// Method call object for NewEvent method. + TMethodCall fAddCall; /// Method call object for Add method. + TMethodCall fCalculateTriggerDecisionCall; /// Method call object for CalculateTriggerDecision method. + mutable TMethodCall fGetCountersCall; /// Method call object for GetCounters method. + TMethodCall fSetCountersCall; /// Method call object for SetCounters method. + + ClassDef(AliHLTGlobalTriggerWrapper, 0) // Wrapper class to interface with an interpreted global trigger class. +}; + +#endif // ALIHLTGLOBALTRIGGERWRAPPER_H diff --git a/HLT/trigger/AliHLTTriggerLinkDef.h b/HLT/trigger/AliHLTTriggerLinkDef.h index bd5f8b6da83..0a5cd359486 100644 --- a/HLT/trigger/AliHLTTriggerLinkDef.h +++ b/HLT/trigger/AliHLTTriggerLinkDef.h @@ -5,7 +5,7 @@ #pragma link off all functions; #pragma link C++ class AliHLTTrigger+; #pragma link C++ class AliHLTGlobalTrigger+; -#pragma link C++ class AliHLTGlobalTrigger::Factory+; +#pragma link C++ class AliHLTGlobalTriggerWrapper+; #pragma link C++ class AliHLTGlobalTriggerConfig+; #pragma link C++ class AliHLTGlobalTriggerComponent+; #pragma link C++ class AliHLTTriggerBarrelMultiplicity+; diff --git a/HLT/trigger/test/Makefile.am b/HLT/trigger/test/Makefile.am index bef6e7a37e5..8b9bec1508a 100644 --- a/HLT/trigger/test/Makefile.am +++ b/HLT/trigger/test/Makefile.am @@ -6,10 +6,12 @@ AM_CPPFLAGS = -I$(top_srcdir)/BASE \ EXTRA_DIST = -check_PROGRAMS = testTriggerDomain +check_PROGRAMS = testTriggerDomain testGlobalTriggerComponent testTriggerDomain_SOURCES = testTriggerDomain.C +testGlobalTriggerComponent_SOURCES = testGlobalTriggerComponent.C + # linker flags LDADD_COMMON = $(top_builddir)/BASE/libHLTbase.la \ @@ -23,5 +25,9 @@ testTriggerDomain_LDADD = $(LDADD_COMMON) testTriggerDomain_LDFLAGS = $(LDFLAGS_COMMON) +testGlobalTriggerComponent_LDADD = $(LDADD_COMMON) + +testGlobalTriggerComponent_LDFLAGS = $(LDFLAGS_COMMON) + TESTS = $(check_PROGRAMS) diff --git a/HLT/trigger/test/TriggerConfig.C b/HLT/trigger/test/TriggerConfig.C index 9818060f5c9..0d45d05c539 100644 --- a/HLT/trigger/test/TriggerConfig.C +++ b/HLT/trigger/test/TriggerConfig.C @@ -1,11 +1,107 @@ +// $Id: $ +/************************************************************************** + * This file is property of and copyright by the ALICE HLT Project * + * ALICE Experiment at CERN, All rights reserved. * + * * + * Primary Authors: Artur Szostak * + * for The ALICE HLT Project. * + * * + * Permission to use, copy, modify and distribute this software and its * + * documentation strictly for non-commercial purposes is hereby granted * + * without fee, provided that the above copyright notice appears in all * + * copies and that both the copyright notice and this permission notice * + * appear in the supporting documentation. The authors make no claims * + * about the suitability of this software for any purpose. It is * + * provided "as is" without express or implied warranty. * + **************************************************************************/ -void TriggerConfig() +/// @file TriggerConfig.C +/// @author Artur Szostak +/// @date 28 Oct 2009 +/// @brief Implementation of the global trigger menu configuration routines. +/// +/// The TriggerConfig routine generates a global trigger menu configuration used +/// to test the AliHLTGlobalTriggerComponent class. + +/** + * Initialise a trigger menu to test a configuration where all trigger menu entries + * have different priority values. Thus only the first trigger menu item that + * matches is activated. + */ +void PriorityGroupTestConfig() +{ + AliHLTGlobalTriggerConfig config("Priority group test config"); + config.AddItem(3, "triggerTPC && triggerSSD", "triggerSSD", "Fast SSD trigger"); + config.AddItem(2, "triggerMUON || triggerSSD", "triggerMUON | triggerSSD", "MUON trigger"); + config.AddItem(1, "triggerTPC", "triggerTPC | triggerMUON | triggerSSD", "TPC trigger"); + config.SetDefaultTriggerDescription("No trigger"); +} + +/** + * Initialise a trigger menu to test a configuration where all trigger menu entries + * have the same priority values. Thus all entries form a single priority group and + * multiple items can be matched with the trigger input. + */ +void SingleGroupTestConfig() { - AliHLTGlobalTriggerConfig config("test Config"); - config.AddSymbol("domainAll", "AliHLTTriggerDomain", "", "AliHLTTriggerDomain(\"*******:***,-DAQRDOUT:TST\")"); - config.AddItem("true", "domainAll", 5, "Trigger Type: pass through"); - config.AddItem("Trigger1", "Trigger1 | Trigger2", 3, "Trigger Type: 1"); - config.AddItem("Trigger2", "Trigger2", 0, "Trigger Type: 2"); - config.Print(); + AliHLTGlobalTriggerConfig config("Single group test config"); + config.AddItem("triggerTPC", "triggerTPC", "TPC trigger"); + config.AddItem("triggerMUON", "triggerMUON", "MUON trigger"); + config.AddItem("triggerSSD", "triggerSSD", "SSD trigger"); + config.SetDefaultConditionOperator("||"); + config.SetDefaultDomainOperator("|"); } +/** + * Create a trigger menu configuration to test the prescalar mechanism. + */ +void PrescalarTestConfig() +{ + AliHLTGlobalTriggerConfig config("Prescalar test config"); + config.AddItem(2, "triggerTPC", "triggerTPC", 2, "TPC trigger"); + config.AddItem(1, "triggerMUON", "triggerMUON", "MUON trigger"); + config.SetDefaultConditionOperator("||"); +} + +/** + * Create a trigger menu configuration to test the trigger menu symbol mechanism. + */ +void SymbolTestConfig() +{ + AliHLTGlobalTriggerConfig config("Symbol test config"); + config.AddSymbol("domain-All", "AliHLTTriggerDomain", "", "AliHLTTriggerDomain(\"*******:***,-DAQRDOUT:TST\")"); + config.AddSymbol("trigClasses", "AliHLTUInt64_t", "this->GetTriggerClasses()", "0x0", "AliHLTEventSummary"); + config.AddItem(2, "true", "domain-All", 5, "Pass through"); + config.AddItem(1, "trigClasses == 0x2", "domain-All", "Trigger class 2"); +} + +/** + * This will make a complex configuration that uses multiple features of the + * trigger menu configuration system. + */ +void ComplexTestConfig() +{ + AliHLTGlobalTriggerConfig config("Complex test config"); + config.AddSymbol("domain-All", "AliHLTTriggerDomain", "", "AliHLTTriggerDomain(\"*******:***,-DAQRDOUT:TST\")"); + config.AddItem(3, "true", "domain-All", 5, "Pass through"); + config.AddItem(2, "triggerSSD", "triggerSSD", "SSD trigger"); + config.AddItem(2, "triggerMUON", "triggerMUON", "MUON trigger"); + config.AddItem(1, "triggerTPC", "triggerTPC | triggerSSD | triggerMUON", "Slow trigger"); + config.SetDefaultDomain(AliHLTTriggerDomain("*******:MUON")); +} + +/** + * Top level configuration routine for the global trigger component tests. + */ +void TriggerConfig(int version = 0) +{ + switch (version) + { + case 0: PriorityGroupTestConfig(); break; + case 1: SingleGroupTestConfig(); break; + case 2: PrescalarTestConfig(); break; + case 3: SymbolTestConfig(); break; + case 4: ComplexTestConfig(); break; + default: AliHLTGlobalTriggerConfig config("Empty test config"); + } +} diff --git a/HLT/trigger/test/testGlobalTriggerComponent.C b/HLT/trigger/test/testGlobalTriggerComponent.C index be2ed85a611..290928c7364 100644 --- a/HLT/trigger/test/testGlobalTriggerComponent.C +++ b/HLT/trigger/test/testGlobalTriggerComponent.C @@ -20,46 +20,407 @@ * @date 19 Dec 2008 * * This macro is used to test the AliHLTGlobalTriggerComponent class. + * A number of tests are run with the AliHLTSystem framework to check that + * the automatically generated global trigger logic is generated correctly. */ - -void testGlobalTriggerComponent(bool debug = false) + +#if defined(__CINT__) && (! defined(__MAKECINT__)) +#error This macro must be compiled. Try running as testGlobalTriggerComponent.C++ +#endif + +#if !defined(__CINT__) || defined(__MAKECINT__) +#include "TSystem.h" +#include "TClassTable.h" +#include "TFile.h" +#include "AliLog.h" +#include "AliHLTReadoutList.h" +#include "AliHLTTriggerDomain.h" +#include "AliHLTTriggerDecision.h" +#include "AliHLTGlobalTriggerDecision.h" +#include "AliHLTSystem.h" +#include "AliHLTConfiguration.h" +#include "AliHLTConfigurationHandler.h" +#include "Riostream.h" +#endif + +/** + * Generates some sample input data and writes it into 8 files named + * testInputFile1.root ... testInputFile8.root + */ +void GenerateInputData() { - gSystem->Load("libAliHLTTrigger.so"); + if (gClassTable->GetID("AliHLTGlobalTriggerComponent") < 0) + { + gSystem->Load("libAliHLTUtil.so"); + gSystem->Load("libAliHLTTRD.so"); + gSystem->Load("libAliHLTTrigger.so"); + } - TFile* file = new TFile("testInputFile.root", "RECREATE"); - AliHLTReadoutList readoutList1("TPC"); AliHLTTriggerDomain triggerDomain1; triggerDomain1.Add("CLUSTERS", "TPC "); + triggerDomain1.Add("TRACKS", "TPC "); triggerDomain1.Add(readoutList1); - AliHLTTriggerDecision decision1(true, "Trigger1", triggerDomain1, "Example trigger 1"); + AliHLTTriggerDecision decision1(true, "triggerTPC", triggerDomain1, "TPC has data"); - AliHLTReadoutList readoutList2("MUONTRK"); + AliHLTReadoutList readoutList2a("MUONTRK"); + AliHLTReadoutList readoutList2b("MUONTRG"); AliHLTTriggerDomain triggerDomain2; - triggerDomain2.Add("aaaaaaaa", "bbbb"); - triggerDomain2.Add(readoutList2); - AliHLTTriggerDecision decision2(true, "Trigger2", triggerDomain2, "Another example trigger 2"); + triggerDomain2.Add("TRACKS", "MUON"); + triggerDomain2.Add(readoutList2a); + triggerDomain2.Add(readoutList2b); + AliHLTTriggerDecision decision2(true, "triggerMUON", triggerDomain2, "MUON has data"); + + AliHLTReadoutList readoutList3("ITSSSD"); + AliHLTTriggerDomain triggerDomain3; + triggerDomain3.Add("*******", "SSD "); + triggerDomain3.Add(readoutList3); + AliHLTTriggerDecision decision3(true, "triggerSSD", triggerDomain3, "SSD has data"); + + TFile* file = new TFile("testInputFile1.root", "RECREATE"); + decision1.Write("triggerTPC"); + decision2.Write("triggerMUON"); + decision3.Write("triggerSSD"); + delete file; + + file = new TFile("testInputFile2.root", "RECREATE"); + decision1.Write("triggerTPC"); + delete file; + + file = new TFile("testInputFile3.root", "RECREATE"); + decision2.Write("triggerMUON"); + delete file; + + file = new TFile("testInputFile4.root", "RECREATE"); + decision3.Write("triggerSSD"); + delete file; + + file = new TFile("testInputFile5.root", "RECREATE"); + decision1.Write("triggerTPC"); + decision2.Write("triggerMUON"); + delete file; + + file = new TFile("testInputFile6.root", "RECREATE"); + decision1.Write("triggerTPC"); + decision3.Write("triggerSSD"); + delete file; - decision1.Write("Trigger1"); - decision2.Write("Trigger2"); + file = new TFile("testInputFile7.root", "RECREATE"); + decision2.Write("triggerMUON"); + decision3.Write("triggerSSD"); delete file; + + file = new TFile("testInputFile8.root", "RECREATE"); + delete file; +} +/** + * Runs a small global trigger test chain with the different configuration as specified + * in TriggerConfig.C. + * \param config The configuration version to pass to TriggerConfig.C + * \param usecint If true then the global trigger component uses CINT to interpret + * the code rather than compiling it. + * \param debug If true then the global trigger component generates extra debug + * statements in the on the fly AliHLTGlobalTriggerImp_*.cxx file. + * \param numOfEvents The number of events to run the chain for. + * \param customClass Names the custom class that should be loaded from the file + * \.cxx. This is useful for debugging only. i.e. you can + * edit a generated logic file and test it by hand. + */ +void RunTrigger(int config = 0, bool usecint = false, bool debug = false, int numOfEvents = 8, const char* customClass = NULL) +{ AliHLTSystem sys; + sys.fpConfigurationHandler->SetLocalLoggingLevel(kHLTLogAll); sys.LoadComponentLibraries("libAliHLTUtil.so"); + sys.LoadComponentLibraries("libAliHLTTRD.so"); sys.LoadComponentLibraries("libAliHLTTrigger.so"); if (debug) { AliLog::SetGlobalLogLevel(AliLog::kMaxType); - sys.SetGlobalLoggingLevel(0x7F); + sys.SetGlobalLoggingLevel(kHLTLogAll); + } + + TString cmdline = "-datatype ROOTTOBJ 'HLT ' "; + for (int i = 1; i <= 8; i++) + { + if (i > 1) cmdline += " -nextevent"; + cmdline += Form(" -datafile testInputFile%d.root", i); } + AliHLTConfiguration pub("pub", "ROOTFilePublisher", NULL, cmdline.Data()); - AliHLTConfiguration pub("pub", "ROOTFilePublisher", NULL, " -datatype ROOTTOBJ 'HLT ' -datafile testInputFile.root"); - TString cmdline = "-config TriggerConfig.C -include AliHLTRunSummary.h"; + cmdline = Form("-config TriggerConfig.C(%d) -includepath $ALICE_ROOT/include -includepath $ALICE_ROOT/HLT/BASE" + " -includepath $ALICE_ROOT/HLT/trigger -include AliHLTEventSummary.h", + config + ); + if (customClass != NULL) cmdline += Form(" -usecode %s.cxx %s", customClass, customClass); + if (usecint) cmdline += " -cint"; if (debug) cmdline += " -debug"; AliHLTConfiguration proc("proc", "HLTGlobalTrigger", "pub", cmdline.Data()); - AliHLTConfiguration sink("sink", "ROOTFileWriter", "proc", "-datafile testOutput.root -concatenate-events"); + + AliHLTConfiguration sink("sink", "ROOTFileWriter", "proc", "-datafile testOutputFile.root -concatenate-events"); sys.BuildTaskList("sink"); - sys.Run(10); + sys.Run(numOfEvents); +} + +/** + * Checks that a particular decision is as expected and prints error messages + * if it is not. + * \param testName The name of the test being run. + * \param eventNum The number of the event being checked. + * \param decision The global trigger decision being checked. + * \param expectedResult The expected global trigger result. + * \param expectedDomain The expected resulting global trigger domain. + * \param expectedDescription The expected resulting trigger description. + * \returns true if the decision is as expected. + */ +bool Check( + const char* testName, + int eventNum, + AliHLTGlobalTriggerDecision* decision, + bool expectedResult, + AliHLTTriggerDomain expectedDomain, + TString expectedDescription + ) +{ + if (decision == NULL) + { + cerr << "ERROR (Test: " << testName + << "): No decision found where expected for event " + << eventNum << "." << endl; + return false; + } + if (decision->Result() != expectedResult) + { + cerr << "ERROR (Test: " << testName + << "): The result does not match the expected value for event " + << eventNum << ". Got " << decision->Result() << " but expected " + << expectedResult << "." << endl; + return false; + } + if (decision->TriggerDomain() != expectedDomain) + { + cerr << "ERROR (Test: " << testName + << "): The domain does not match the expected value for event " + << eventNum << ". Got:" << endl; + decision->TriggerDomain().Print(); + cout << "but expected:" << endl; + expectedDomain.Print(); + return false; + } + if (decision->Description() != expectedDescription) + { + cerr << "ERROR (Test: " << testName + << "): The description does not match the expected value for event " + << eventNum << ". Got '" << decision->Description() << "' but expected '" + << expectedDescription << "'." << endl; + return false; + } + return true; +} + + +/// Routine for checking the result of the PriorityGroupTestConfig() config in TriggerConfig.C +bool CheckPriorityGroupTestConfig(const char* testName = "Priority group config") +{ + AliHLTGlobalTriggerDecision* decision = NULL; + bool result = false; + + AliHLTTriggerDomain domainTPC("CLUSTERS:TPC ,TRACKS:TPC "); + domainTPC.Add(AliHLTReadoutList("TPC")); + AliHLTTriggerDomain domainMUON("TRACKS:MUON"); + domainMUON.Add(AliHLTReadoutList("MUONTRK")); + domainMUON.Add(AliHLTReadoutList("MUONTRG")); + AliHLTTriggerDomain domainSSD("*******:SSD "); + domainSSD.Add(AliHLTReadoutList("ITSSSD")); + + TFile* file = new TFile("testOutputFile.root", "READ"); + + // Triggers in events (i.e. input triggers): + // event 1: TPC MUON SSD + // event 2: TPC + // event 3: MUON + // event 4: SSD + // event 5: TPC MUON + // event 6: TPC SSD + // event 7: MUON SSD + // event 8: (empty) + decision = dynamic_cast(file->Get("HLTGlobalTrigger;1")); + result = Check(testName, 1, decision, true, domainSSD, "Fast SSD trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;2")); + result = Check(testName, 2, decision, true, domainTPC, "TPC trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;3")); + result = Check(testName, 3, decision, true, domainMUON, "MUON trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;4")); + result = Check(testName, 4, decision, true, domainSSD, "MUON trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;5")); + result = Check(testName, 5, decision, true, domainMUON, "MUON trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;6")); + result = Check(testName, 6, decision, true, domainSSD, "Fast SSD trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;7")); + result = Check(testName, 7, decision, true, domainMUON | domainSSD, "MUON trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;8")); + result = Check(testName, 8, decision, false, AliHLTTriggerDomain(), "No trigger"); + if (! result) goto cleanup; + + delete file; + return true; + +cleanup: + if (decision != NULL) + { + cout << "========== Dumping incorrect decision ========== " << endl; + decision->Print(); + } + delete file; + return false; +} + + +/// Routine for checking the result of the SingleGroupTestConfig() config in TriggerConfig.C +bool CheckSingleGroupTestConfig(const char* testName = "Single group config") +{ + AliHLTGlobalTriggerDecision* decision = NULL; + bool result = false; + + AliHLTTriggerDomain domainTPC("CLUSTERS:TPC ,TRACKS:TPC "); + domainTPC.Add(AliHLTReadoutList("TPC")); + AliHLTTriggerDomain domainMUON("TRACKS:MUON"); + domainMUON.Add(AliHLTReadoutList("MUONTRK")); + domainMUON.Add(AliHLTReadoutList("MUONTRG")); + AliHLTTriggerDomain domainSSD("*******:SSD "); + domainSSD.Add(AliHLTReadoutList("ITSSSD")); + + TFile* file = new TFile("testOutputFile.root", "READ"); + + // Triggers in events (i.e. input triggers): + // event 1: TPC MUON SSD + // event 2: TPC + // event 3: MUON + // event 4: SSD + // event 5: TPC MUON + // event 6: TPC SSD + // event 7: MUON SSD + // event 8: (empty) + decision = dynamic_cast(file->Get("HLTGlobalTrigger;1")); + result = Check(testName, 1, decision, true, domainTPC | domainMUON | domainSSD, "TPC trigger,MUON trigger,SSD trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;2")); + result = Check(testName, 2, decision, true, domainTPC, "TPC trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;3")); + result = Check(testName, 3, decision, true, domainMUON, "MUON trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;4")); + result = Check(testName, 4, decision, true, domainSSD, "SSD trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;5")); + result = Check(testName, 5, decision, true, domainTPC | domainMUON, "TPC trigger,MUON trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;6")); + result = Check(testName, 6, decision, true, domainTPC | domainSSD, "TPC trigger,SSD trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;7")); + result = Check(testName, 7, decision, true, domainMUON | domainSSD, "MUON trigger,SSD trigger"); + if (! result) goto cleanup; + decision = dynamic_cast(file->Get("HLTGlobalTrigger;8")); + result = Check(testName, 8, decision, false, AliHLTTriggerDomain(), ""); + if (! result) goto cleanup; + + delete file; + return true; + +cleanup: + if (decision != NULL) + { + cout << "========== Dumping incorrect decision ========== " << endl; + decision->Print(); + } + delete file; + return false; +} + + +typedef bool (*CheckFunctionType)(const char* testName); + +/** + * This will check the results of a global trigger run with a particular checking + * routine and for different combinations of -cint and -debug flags passed to the + * global trigger component. + * It is important to check these flag combinations to make sure that everything + * is functioning the same under all the different combinations as it should. + * \param function The checking routine to use. + * \param version The trigger menu configuration version to use in RunTrigger. + * \param testName The name of the test being run. + * \param numOfEvents The number of events to run the chain for. + * \param customClass Name of the custom class as passed to RunTrigger. + * \returns true if the different checks succeeded and false otherwise. + */ +bool CheckDifferentModes(CheckFunctionType function, int version, const char* testName, int numOfEvents = 8, const char* customClass = NULL) +{ + TString name = testName; + RunTrigger(version, false, false, numOfEvents, customClass); + if (! function(testName)) return false; + gSystem->Exec("rm -f testOutputFile.root"); // Cleanup output file for next test. + + name = testName; + name += " interpreted with CINT"; + RunTrigger(version, true, false, numOfEvents, customClass); + if (! function(testName)) return false; + gSystem->Exec("rm -f testOutputFile.root"); // Cleanup output file for next test. + + name = testName; + name += " in debug mode"; + RunTrigger(version, false, true, numOfEvents, customClass); + if (! function(testName)) return false; + gSystem->Exec("rm -f testOutputFile.root"); // Cleanup output file for next test. + + name = testName; + name += " interpreted with CINT in debug mode"; + RunTrigger(version, true, true, numOfEvents, customClass); + if (! function(testName)) return false; + gSystem->Exec("rm -f testOutputFile.root"); // Cleanup output file for next test. + + return true; +} + +/** + * Runs several tests for the AliHLTGlobalTriggerComponent class. + * We specifically test if the global trigger menu configuration is interpreted + * correctly and the trigger logic generated correctly on the fly. + * \param numOfEvents The number of events to run the chain for. + * \param customClass Name of the custom class as passed to CheckDifferentModes. + * \returns true if the different checks succeeded and false otherwise. + */ +bool testGlobalTriggerComponent(int numOfEvents = 8, const char* customClass = NULL) +{ + GenerateInputData(); + + if (! CheckDifferentModes(CheckPriorityGroupTestConfig, 0, "Priority group config", numOfEvents, customClass)) return false; + if (! CheckDifferentModes(CheckSingleGroupTestConfig, 1, "Single group config", numOfEvents, customClass)) return false; + + // Cleanup all temporary files generated. + gSystem->Exec("rm -f testOutputFile.root testInputFile*.root AliHLTGlobalTriggerImpl*"); + return true; +} + + + +#ifndef __MAKECINT__ + +int main(int /*argc*/, const char** /*argv*/) +{ + gSystem->Exec("if test ! -f TriggerConfig.C ; then cp $ALICE_ROOT/HLT/trigger/test/TriggerConfig.C ./; fi"); + bool resultOk = testGlobalTriggerComponent(); + if (not resultOk) return 1; + return 0; } +#endif // __MAKECINT__ -- 2.43.0