]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - HLT/trigger/AliHLTGlobalTriggerComponent.cxx
putting back the lost statistics message at EOR
[u/mrichter/AliRoot.git] / HLT / trigger / AliHLTGlobalTriggerComponent.cxx
index 8fcc9defe564d4fc2526444fa4096376e272a00f..aa9b11f21ab6929f3a4c33ca390f5e564d152288 100644 (file)
@@ -20,7 +20,7 @@
 /// @date   26 Nov 2008
 /// @brief  Implementation of the AliHLTGlobalTriggerComponent component class.
 ///
-/// The AliHLTGlobalTriggerComponentComponent class applies the global HLT trigger to all
+/// The AliHLTGlobalTriggerComponent class applies the global HLT trigger to all
 /// trigger information produced by components deriving from AliHLTTrigger.
 
 #include "AliHLTGlobalTriggerComponent.h"
@@ -32,6 +32,7 @@
 #include "AliCDBManager.h"
 #include "AliCDBStorage.h"
 #include "AliCDBEntry.h"
+#include "AliRawDataHeader.h"
 #include "TUUID.h"
 #include "TROOT.h"
 #include "TSystem.h"
@@ -43,6 +44,7 @@
 #include "TDatime.h"
 #include "TClass.h"
 #include "TNamed.h"
+#include "TRandom3.h"
 #include <fstream>
 #include <cerrno>
 #include <cassert>
@@ -72,6 +74,7 @@ AliHLTGlobalTriggerComponent::AliHLTGlobalTriggerComponent() :
        fDebugMode(false),
        fRuntimeCompile(true),
        fDeleteCodeFile(false),
+       fMakeSoftwareTriggers(true),
        fCodeFileName(),
        fClassName(),
        fCTPDecisions(NULL),
@@ -81,7 +84,12 @@ AliHLTGlobalTriggerComponent::AliHLTGlobalTriggerComponent() :
        fIncludeFiles(TObjString::Class()),
        fLibStateAtLoad(),
        fBits(0),
-       fDataEventsOnly(true)
+       fDataEventsOnly(true),
+       fMonitorPeriod(-1),
+       fUniqueID(0),
+       fSoftwareTrigger(true, "SOFTWARE"),
+       fTotalEventCounter(0),
+       fCDH(NULL)
 {
   // Default constructor.
   
@@ -126,12 +134,16 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
   fClassName = "";
   fCodeFileName = "";
   fDeleteCodeFile = false;
+  fMakeSoftwareTriggers = true;
   const char* configFileName = NULL;
   const char* codeFileName = NULL;
   fIncludePaths.Clear();
   fIncludeFiles.Clear();
   SetBit(kIncludeInput);
   fDataEventsOnly = true;
+  UInt_t randomSeed = 0;
+  bool randomSeedSet = false;
+  fCDH = NULL;
   
   for (int i = 0; i < argc; i++)
   {
@@ -160,7 +172,15 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
         HLTError("The include path was not specified." );
         return -EINVAL;
       }
-      new (fIncludePaths[fIncludePaths.GetEntriesFast()]) TObjString(argv[i+1]);
+      try
+      {
+        new (fIncludePaths[fIncludePaths.GetEntriesFast()]) TObjString(argv[i+1]);
+      }
+      catch (const std::bad_alloc&)
+      {
+        HLTError("Could not allocate more memory for the fIncludePaths array.");
+        return -ENOMEM;
+      }
       i++;
       continue;
     }
@@ -172,7 +192,15 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
         HLTError("The include file name was not specified." );
         return -EINVAL;
       }
-      new (fIncludeFiles[fIncludeFiles.GetEntriesFast()]) TObjString(argv[i+1]);
+      try
+      {
+        new (fIncludeFiles[fIncludeFiles.GetEntriesFast()]) TObjString(argv[i+1]);
+      }
+      catch (const std::bad_alloc&)
+      {
+        HLTError("Could not allocate more memory for the fIncludeFiles array.");
+        return -ENOMEM;
+      }
       i++;
       continue;
     }
@@ -274,6 +302,59 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
       fDataEventsOnly = false;
       continue;
     }
+
+    if (strstr(argv[i], "-monitoring") == argv[i])
+    {
+      TString param=argv[i];
+      param.ReplaceAll("-monitoring", "");
+      if (param.IsNull()) 
+      {
+       // -monitoring
+       // enable monitoring trigger for all events
+       fMonitorPeriod=0;
+      } else {
+       // -monitoring=n
+       // enable monitoring trigger once every n seconds
+       param.ReplaceAll("=", "");
+       if (param.IsDigit()) {
+         fMonitorPeriod=param.Atoi();
+       } else {
+         HLTError("expecting number as parameter for argument '-monitoring=', got %s, skipping monitoring trigger", param.Data());
+       }
+      }
+      continue;
+    }
+
+    if (strcmp(argv[i], "-dont-make-software-triggers") == 0)
+    {
+      fMakeSoftwareTriggers = false;
+      continue;
+    }
+    if (strcmp(argv[i], "-randomseed") == 0)
+    {
+      if (randomSeedSet)
+      {
+        HLTWarning("The random seed was already specified previously with the option -randomseed."
+                   "Will replace the previous value of %d with the new one.",
+                   randomSeed
+        );
+      }
+      if (argc <= i+1)
+      {
+        HLTError("The number to use as the seed was not specified for the -randomseed option." );
+        return -EINVAL;
+      }
+      TString numstr = argv[i+1];
+      if (not numstr.IsDigit())
+      {
+        HLTError("The number specified in the -randomseed option is not a valid decimal integer." );
+        return -EINVAL;
+      }
+      randomSeed = numstr.Atoi();
+      randomSeedSet = true;
+      i++;
+      continue;
+    }
     
     HLTError("Unknown option '%s'.", argv[i]);
     return -EINVAL;
@@ -313,7 +394,15 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
   }
   if (result != 0) return result;
   
-  fTrigger = AliHLTGlobalTrigger::CreateNew(fClassName.Data());
+  try
+  {
+    fTrigger = AliHLTGlobalTrigger::CreateNew(fClassName.Data());
+  }
+  catch (const std::bad_alloc&)
+  {
+    HLTError("Could not allocate memory for the AliHLTGlobalTrigger instance.");
+    return -ENOMEM;
+  }
   if (fTrigger == NULL)
   {
     HLTError("Could not create a new instance of '%s'.", fClassName.Data());
@@ -330,6 +419,15 @@ Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
   SetDescription(menu->DefaultDescription());
   SetTriggerDomain(menu->DefaultTriggerDomain());
   
+  // Initialise the random number generator seed value.
+  // NOTE: The GenerateTrigger method called above will set the fUniqueID value
+  // with a random value based on a GUID that should be unique across the system.
+  // This is then used as the seed to the random number generator if the -randomseed
+  // option is not used.
+  if (not randomSeedSet) randomSeed = fUniqueID;
+  gRandom->SetSeed(randomSeed);
+  
+  fTotalEventCounter = 0;
   return 0;
 }
 
@@ -349,6 +447,7 @@ Int_t AliHLTGlobalTriggerComponent::DoDeinit()
     delete fCTPDecisions;
   }
   fCTPDecisions=NULL;
+  fCDH = NULL;
   
   Int_t result = UnloadTriggerClass(fCodeFileName);
   if (result != 0) return result;
@@ -368,8 +467,17 @@ Int_t AliHLTGlobalTriggerComponent::DoDeinit()
 AliHLTComponent* AliHLTGlobalTriggerComponent::Spawn()
 {
   // Creates a new object instance.
-  
-  return new AliHLTGlobalTriggerComponent;
+  AliHLTComponent* comp = NULL;
+  try
+  {
+    comp = new AliHLTGlobalTriggerComponent;
+  }
+  catch (const std::bad_alloc&)
+  {
+    HLTError("Could not allocate memory for a new instance of AliHLTGlobalTriggerComponent.");
+    return NULL;
+  }
+  return comp;
 }
 
 
@@ -385,13 +493,19 @@ int AliHLTGlobalTriggerComponent::DoTrigger()
 
   AliHLTUInt32_t eventType=0;
   if (!IsDataEvent(&eventType)) {
-    if (eventType==gkAliEventTypeEndOfRun) PrintStatistics(fTrigger, kHLTLogImportant, 0);
+    if (eventType==gkAliEventTypeEndOfRun)
+    {
+      PrintStatistics(fTrigger, kHLTLogImportant);
+    }
     if (fDataEventsOnly)
     {
-      IgnoreEvent();
+      IgnoreEvent();  // dont generate any trigger decision.
       return 0;
     }
   }
+  
+  fCDH = NULL;  // have to reset this in case ExtractTriggerData fails.
+  ExtractTriggerData(*GetTriggerData(), NULL, NULL, &fCDH, NULL);
 
   // Copy the trigger counters in case we need to set them back to their original
   // value because the PushBack method fails with ENOSPC.
@@ -415,87 +529,143 @@ int AliHLTGlobalTriggerComponent::DoTrigger()
   if (pCTPData) {
     AddCTPDecisions(fTrigger, pCTPData, GetTriggerData());
   }
-
+  
+  bool softwareTriggerIsValid = FillSoftwareTrigger();
+  if (softwareTriggerIsValid)
+  {
+    fTrigger->Add(&fSoftwareTrigger, kAliHLTDataTypeTriggerDecision, kAliHLTVoidDataSpec);
+  }
+  
   // Calculate the global trigger result and trigger domain, then create and push
   // back the new global trigger decision object.
   TString description;
   AliHLTTriggerDomain triggerDomain;
-  bool triggerResult = fTrigger->CalculateTriggerDecision(triggerDomain, description);
+  bool triggerResult = false;
+  bool matchedItems = fTrigger->CalculateTriggerDecision(triggerResult, triggerDomain, description);
   if (fTrigger->CallFailed()) return -EPROTO;
   AliHLTGlobalTriggerDecision decision(
       triggerResult,
       // The following will cause the decision to be generated with default values
       // (set in fTriggerDomain and fDescription) if the trigger result is false.
-      (triggerResult == true) ? triggerDomain : GetTriggerDomain(),
-      (triggerResult == true) ? description.Data() : GetDescription()
+      (matchedItems == true) ? triggerDomain : GetTriggerDomain(),
+      (matchedItems == true) ? description.Data() : GetDescription()
     );
 
-  // mask the readout list according to the CTP trigger
-  // if the classes have been initialized (mask non-zero)
-  if (pCTPData && pCTPData->Mask()) {
-    AliHLTEventDDL eventDDL=pCTPData->ReadoutList(*GetTriggerData());
-    AliHLTReadoutList ctpreadout(eventDDL);
-    ctpreadout.Enable(AliHLTReadoutList::kHLT);
-    AliHLTReadoutList maskedList=decision.ReadoutList();
-    maskedList.AndEq(ctpreadout);
-    decision.ReadoutList(maskedList);
-  }
-
-  decision.SetCounters(fTrigger->GetCounters(), GetEventCount()+1);
+  decision.SetUniqueID(fUniqueID);
+  decision.SetCounters(fTrigger->GetCounters(), fTotalEventCounter+1);
   if (fTrigger->CallFailed()) return -EPROTO;
   
-  static UInt_t lastTime=0;
-  TDatime time;
-  if (time.Get()-lastTime>60) {
-    lastTime=time.Get();
-    PrintStatistics(fTrigger, kHLTLogImportant);
-  }
+  TClonesArray shortInfo(TNamed::Class(), GetNumberOfInputBlocks());
   
-  // Add the input objects used to the global decision.
-  TClonesArray* pShortInfo=NULL;
-  if (TestBit(kIncludeShort)) {
-    pShortInfo=new TClonesArray(TNamed::Class(), GetNumberOfInputBlocks());
-  }
+  // Add the input objects used to make the global decision.
   obj = GetFirstInputObject();
   while (obj != NULL)
   {
-    if (TestBit(kForwardInput)) {
-      Forward(obj);
-    }
-    if (TestBit(kIncludeInput)) {
-    if (obj->IsA() == AliHLTTriggerDecision::Class())
+    const AliHLTTriggerDecision* intrig = dynamic_cast<const AliHLTTriggerDecision*>(obj);
+    
+    if (TestBit(kForwardInput)) Forward(obj);
+    
+    if (TestBit(kIncludeInput))
     {
-      decision.AddTriggerInput( *static_cast<const AliHLTTriggerDecision*>(obj) );
+      if (intrig != NULL)
+      {
+         decision.AddTriggerInput(*intrig);
+      }
+      else
+      {
+        // The const_cast should be safe in this case because the list of inputObjects
+        // will be added to the global decision with AddInputObjectRef, which only
+        // modifies the kCanDelete bit and nothing else.
+        // This is necessary since GetFirstInputObject only returns const objects.
+        decision.AddInputObjectRef( const_cast<TObject*>(obj) );
+      }
     }
-    else
+    
+    if (TestBit(kIncludeShort))
     {
-      decision.AddInputObject(obj);
-    }
-    }
-
-    if (TestBit(kIncludeShort)) {
-      int entries=pShortInfo->GetEntriesFast();
-      new ((*pShortInfo)[entries]) TNamed(obj->GetName(), obj->GetTitle());
-      if (obj->IsA() == AliHLTTriggerDecision::Class()) {
-       (*pShortInfo)[entries]->SetBit(BIT(16)); // indicate that this is a trigger decision
-       (*pShortInfo)[entries]->SetBit(BIT(15), ((AliHLTTriggerDecision*)obj)->Result());
+      int entries = shortInfo.GetEntriesFast();
+      try
+      {
+        new (shortInfo[entries]) TNamed(obj->GetName(), obj->GetTitle());
+      }
+      catch (const std::bad_alloc&)
+      {
+        HLTError("Could not allocate more memory for the short list of input objects.");
+        return -ENOMEM;
+      }
+      if (intrig != NULL)
+      {
+        shortInfo[entries]->SetBit(BIT(16)); // indicate that this is a trigger decision
+        shortInfo[entries]->SetBit(BIT(15), intrig->Result());
       }
     }
 
     obj = GetNextInputObject();
   }
-  if (pShortInfo) {
-    decision.AddInputObject(pShortInfo);
-    pShortInfo->Delete();
-    delete pShortInfo;
-    pShortInfo=NULL;
+  if (TestBit(kIncludeShort)) decision.AddInputObjectRef(&shortInfo);
+  
+  // The const_cast should be safe in this case because AddInputObjectRef just
+  // modifies the kCanDelete bit and nothing else.
+  if (!TestBit(kSkipCTP) && CTPData()) decision.AddInputObjectRef(const_cast<AliHLTCTPData*>(CTPData()));
+  
+  if (softwareTriggerIsValid and TestBit(kIncludeInput)) decision.AddTriggerInput(fSoftwareTrigger);
+  
+  static UInt_t lastTime=0;
+  TDatime time;
+  if (time.Get()-lastTime>60)
+  {
+    lastTime=time.Get();
+    PrintStatistics(fTrigger, kHLTLogImportant);
   }
+  
+  // add readout filter to event done data
+  CreateEventDoneReadoutFilter(decision.TriggerDomain(), 3);
 
-  if (!TestBit(kSkipCTP) && CTPData()) decision.AddInputObject(CTPData());
+  // add monitoring filter to event done data if enabled by setting
+  // a monitoring period >=0: -1 means off, 0 means for every event
+  // configured by argument '-monitoring[=n]'
+  if (fMonitorPeriod>=0) {
+    static UInt_t lastMonitorEvent=0;
+
+    AliHLTTriggerDomain monitoringFilter(decision.TriggerDomain());
+    if (decision.Result() &&
+       int(time.Get()-lastMonitorEvent)>fMonitorPeriod) {
+      lastMonitorEvent=time.Get();
+      // add monitoring event command for triggered events
+      CreateEventDoneReadoutFilter(decision.TriggerDomain(), 5);
+    } else {
+      // empty filter list if events are not triggered
+      // or within the monitoring interval
+      monitoringFilter.Clear();
+    }
+    // add monitoring filter list
+    CreateEventDoneReadoutFilter(monitoringFilter, 4);
+  }
+  
+  // Mask the readout list according to the CTP trigger
+  // if the classes have been initialized (mask non-zero).
+  // If we are dealing with a software trigger on the other hand then
+  // mask with the participating detector list.
+  // In both cases we must make sure that HLT is part of the readout mask.
+  if (CTPData() != NULL and CTPData()->Mask() != 0x0)
+  {
+    AliHLTReadoutList readoutlist = decision.ReadoutList();
+    AliHLTReadoutList ctpreadout = CTPData()->ReadoutList(*GetTriggerData());
+    ctpreadout.Enable(AliHLTReadoutList::kHLT);
+    readoutlist.AndEq(ctpreadout);
+    decision.ReadoutList(readoutlist); // override the readout list with the masked one.
+  }
+  else if (softwareTriggerIsValid)
+  {
+    assert(fCDH != NULL);
+    AliHLTReadoutList readoutlist = decision.ReadoutList();
+    UInt_t detectors = fCDH->GetSubDetectors();
+    AliHLTReadoutList softwareReadout(Int_t(detectors | AliHLTReadoutList::kHLT));
+    readoutlist.AndEq(softwareReadout);
+    decision.ReadoutList(readoutlist); // override the readout list with the masked one.
+  }
 
-  CreateEventDoneReadoutFilter(decision.TriggerDomain(), 3);
-  CreateEventDoneReadoutFilter(decision.TriggerDomain(), 4);
-  if (TriggerEvent(&decision) == -ENOSPC)
+  if (TriggerEvent(&decision, kAliHLTDataTypeGlobalTrigger) == -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
@@ -507,6 +677,8 @@ int AliHLTGlobalTriggerComponent::DoTrigger()
     if (fTrigger->CallFailed()) return -EPROTO;
     return -ENOSPC;
   }
+  
+  ++fTotalEventCounter;
   return 0;
 }
 
@@ -531,7 +703,16 @@ int AliHLTGlobalTriggerComponent::Reconfigure(const char* cdbEntry, const char*
   result = GenerateTrigger(menu, className, codeFileName, fIncludePaths, fIncludeFiles);
   if (result != 0) return result;
   
-  AliHLTGlobalTrigger* trigger = AliHLTGlobalTrigger::CreateNew(className.Data());
+  AliHLTGlobalTrigger* trigger = NULL;
+  try
+  {
+    trigger = AliHLTGlobalTrigger::CreateNew(className.Data());
+  }
+  catch (const std::bad_alloc&)
+  {
+    HLTError("Could not allocate memory for the AliHLTGlobalTrigger instance.");
+    return -ENOMEM;
+  }
   if (trigger == NULL)
   {
     HLTError("Could not create a new instance of '%s'.", className.Data());
@@ -592,6 +773,11 @@ int AliHLTGlobalTriggerComponent::LoadTriggerMenu(const char* cdbPath, const Ali
     return -EIO;
   }
   Int_t version = store->GetLatestVersion(cdbPath, GetRunNo());
+  if (version < 0)
+  {
+    HLTError("Could not find an entry in the CDB for \"%s\".", cdbPath);
+    return -EIO;
+  }
   Int_t subVersion = store->GetLatestSubVersion(cdbPath, GetRunNo(), version);
   AliCDBEntry* entry = AliCDBManager::Instance()->Get(cdbPath, GetRunNo(), version, subVersion);
   if (entry == NULL)
@@ -617,6 +803,38 @@ int AliHLTGlobalTriggerComponent::LoadTriggerMenu(const char* cdbPath, const Ali
 }
 
 
+void AliHLTGlobalTriggerComponent::GenerateFileName(TString& name, TString& filename)
+{
+  // Creates a unique file name for the generated code.
+  
+  TUUID guid = GenerateGUID();
+  union
+  {
+    UChar_t buf[16];
+    UInt_t bufAsInt[4];
+  };
+  guid.GetUUID(buf);
+  fUniqueID = bufAsInt[0];
+  TString guidstr = guid.AsString();
+  // Replace '-' with '_' in string.
+  for (int i = 0; i < guidstr.Length(); ++i)
+  {
+    if (guidstr[i] == '-') guidstr[i] = '_';
+  }
+  name = "AliHLTGlobalTriggerImpl_";
+  name += guidstr;
+  filename = name + ".cxx";
+
+  // For good measure, check that the file names are not used. If they are then regenerate.
+  fstream file(filename.Data(), ios_base::in);
+  if (file.good())
+  {
+    file.close();
+    GenerateFileName(name, filename);
+  }
+}
+
+
 int AliHLTGlobalTriggerComponent::GenerateTrigger(
     const AliHLTTriggerMenu* menu, TString& name, TString& filename,
     const TClonesArray& includePaths, const TClonesArray& includeFiles
@@ -625,21 +843,10 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
   // 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;
-  TString uuidstr = uuid.AsString();
-  for (Int_t i = 0; i < uuidstr.Length(); i++)
-  {
-    if (uuidstr[i] == '-') uuidstr[i] = '_';
-  }
-  
-  // Create the name of the new class.
-  name = "AliHLTGlobalTriggerImpl_";
-  name += uuidstr;
-  filename = name + ".cxx";
+  GenerateFileName(name, filename);
+  HLTDebug("Generating custom HLT trigger class named %s, in file %s, using trigger menu %p.",
+    name.Data(), filename.Data(), ((void*)menu)
+  );
   
   // Open a text file to write the code and generate the new class.
   fstream code(filename.Data(), ios_base::out | ios_base::trunc);
@@ -655,8 +862,10 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
   
   code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
   code << "#include <cstring>" << endl;
+  code << "#include \"TClass.h\"" << endl;
   code << "#include \"TString.h\"" << endl;
   code << "#include \"TClonesArray.h\"" << endl;
+  code << "#include \"TRandom3.h\"" << endl;
   code << "#include \"AliHLTLogging.h\"" << endl;
   code << "#include \"AliHLTGlobalTrigger.h\"" << endl;
   code << "#include \"AliHLTGlobalTriggerDecision.h\"" << endl;
@@ -788,6 +997,28 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
     code << "      }" << endl;
   }
   code << "    }" << endl;
+  // The following is an optimisation where symbols without any assignment operators
+  // are treated as constant and only initialised in FillFromMenu rather than reseting
+  // them in the NewEvent method.
+  // Note: we putting this initialisation into the constructor can lead to seg faults
+  // under CINT interpretation. Thus we must put it into the FillFromMenu method instead.
+  for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
+  {
+    AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
+    if (TString(symbol->AssignExpression()) != "") continue;
+    if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0) continue;
+    // CINT has problems with the implicit equals operator for complex types, so if
+    // the type has an 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 (fDebugMode)
   {
     code << "    HLTDebug(Form(\"Finished filling domain entries from trigger menu symbols.\"));" << endl;
@@ -807,8 +1038,12 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
   {
     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
+    // The following is an optimisation. If the symbol does not have an assignment expression
+    // then it is effectively a constant symbol and can be initialised earlier and only once.
+    // In this case we initialise it in the FillFromMenu method instead.
+    if (TString(symbol->AssignExpression()) == "") continue;
     // 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.
+    // the type has an equals operater we need to write the operator call explicitly.
     TClass* clas = TClass::GetClass(symbol->Type());
     if (clas != NULL and clas->GetMethodAny("operator=") != NULL)
     {
@@ -830,7 +1065,25 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
   code << "  }" << endl;
   
   // Generate the Add method.
-  code << "  virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
+  bool haveAssignments = false;
+  for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
+  {
+    // First check if we have any symbols with assignment expressions.
+    // This is needed to get rid of the on the fly compilation warning about '_object_' not being used.
+    AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
+    TString expr = symbol->AssignExpression();
+    if (expr == "") continue; // Skip entries that have no assignment expression.
+    haveAssignments = true;
+    break;
+  }
+  if (haveAssignments or fDebugMode)
+  {
+    code << "  virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
+  }
+  else
+  {
+    code << "  virtual void Add(const TObject* /*_object_*/, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
+  }
   if (fDebugMode)
   {
     code << "#ifdef __CINT__" << endl;
@@ -873,7 +1126,7 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
     // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
     // Have to use the TClass system for extra protection.
     code << "    const " << symbol->ObjectClass() << "* " << symbol->Name() << "_object_ = NULL;" << endl;
-    code << "    if (_object_->IsA() == " << symbol->ObjectClass() << "::Class()) " << symbol->Name()
+    code << "    if (_object_->InheritsFrom(" << symbol->ObjectClass() << "::Class())) " << symbol->Name()
          << "_object_ = dynamic_cast<const " << symbol->ObjectClass()
          << "*>(_object_);" << endl;
     code << "    if (" << symbol->Name() << "_object_ != NULL && ";
@@ -928,7 +1181,7 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
   // 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;
+  code << "  virtual bool CalculateTriggerDecision(bool& _trigger_result_, AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl;
   if (fDebugMode)
   {
     code << "#ifdef __CINT__" << endl;
@@ -1032,10 +1285,22 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
       code << "    if (" << triggerCondition << ") {" << endl;
       code << "      ++fCounter[" << i << "];" << endl;
       const char* indentation = "";
-      if (item->PreScalar() != 0)
+      // Generate the code to handle the prescalar and scale-down
+      bool havePrescalar = item->PreScalar() != 0;
+      bool haveScaledown = item->ScaleDown() < 1;
+      if (havePrescalar or haveScaledown) 
       {
         indentation = "  ";
-        code << "      if ((fCounter[" << i << "] % " << item->PreScalar() << ") == 1) {" << endl;
+        code << "      if (";
+        if (havePrescalar) code << "(fCounter[" << i << "] % " << item->PreScalar() << ") == 1";
+        if (havePrescalar and haveScaledown) code << " && ";
+        if (haveScaledown)
+        {
+          std::streamsize oldprecision = code.precision(17);
+          code << "gRandom->Rndm() < " << item->ScaleDown();
+          code.precision(oldprecision);
+        }
+        code << ") {" << endl;
       }
       code << indentation << "      _item_result_ = true;" << endl;
       if (fDebugMode)
@@ -1043,7 +1308,7 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
         code << indentation << "      HLTDebug(Form(\"Matched trigger condition " << i
              << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));" << endl;
       }
-      if (item->PreScalar() != 0)
+      if (havePrescalar or haveScaledown)
       {
         code << "      }" << endl;
       }
@@ -1122,11 +1387,33 @@ int AliHLTGlobalTriggerComponent::GenerateTrigger(
         code << "      HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n] << ".\"));" << endl;
       }
     }
+    bool methodReturnResult = true;
+    if (priorityGroup[n].size() > 0)
+    {
+      const AliHLTTriggerMenuItem* item = menu->Item(priorityGroup[n][0]);
+      methodReturnResult = item->DefaultResult();
+    }
+    // Check to see if the items of the group all have the same default result.
+    // If not then warn the user since only the first item's value will be used.
+    for (size_t m = 1; m < priorityGroup[n].size(); m++)
+    {
+      const AliHLTTriggerMenuItem* item = menu->Item(priorityGroup[n][m]);
+      if (item->DefaultResult() != methodReturnResult)
+      {
+        HLTWarning("Found items with different default results set for priority group %d."
+                   "Will only use the value from the first item.",
+                   item->Priority()
+                  );
+        break;
+      }
+    }
+    code << "      _trigger_result_ = " << (methodReturnResult ? "true" : "false") << ";" << endl;
     code << "      return true;" << endl;
     code << "    }" << endl;
   }
   code << "    _domain_.Clear();" << endl;
   code << "    _description_ = \"\";" << endl;
+  code << "    _trigger_result_ = " << (menu->DefaultResult() ? "true" : "false") << ";" << endl;
   code << "    return false;" << endl;
   code << "  }" << endl;
   
@@ -1353,6 +1640,21 @@ int AliHLTGlobalTriggerComponent::FindSymbol(const char* name, const TClonesArra
 }
 
 
+namespace
+{
+  /**
+   * Helper routine to compare two trigger menu symbols to see if b is a subset of a.
+   * \returns true if b is a subset of a or they are unrelated.
+   */
+  bool AliHLTCheckForContainment(const AliHLTTriggerMenuSymbol* a, const AliHLTTriggerMenuSymbol* b)
+  {
+    TString bstr = b->Name();
+    return bstr.Contains(a->Name());
+  }
+
+} // end of namespace
+
+
 int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, TClonesArray& list)
 {
   // Builds the list of symbols to use in the custom global trigger menu
@@ -1373,11 +1675,21 @@ int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu,
       HLTError("Multiple symbols with the name '%s' defined in the trigger menu.", symbol->Name());
       return -EIO;
     }
-    new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
+    try
+    {
+      new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
+    }
+    catch (const std::bad_alloc&)
+    {
+      HLTError("Could not allocate more memory for the symbols list when adding a trigger menu symbol.");
+      return -ENOMEM;
+    }
   }
+  Int_t initialEntryCount = list.GetEntriesFast();
   
-  TRegexp exp("[_a-zA-Z][-_a-zA-Z0-9]*");
-  TRegexp hexexp("x[a-fA-F0-9]+");
+  // Note: the \\. must not be the first element in the character class, otherwise
+  // it is interpreted as an "any character" dot symbol.
+  TRegexp exp("[_a-zA-Z][-\\._a-zA-Z0-9]*");
   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
   {
     const AliHLTTriggerMenuItem* item = menu->Item(i);
@@ -1419,6 +1731,27 @@ int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu,
         // Ignore iso646.h and other keywords.
         continue;
       }
+      
+      // We need to handle the special case where the symbol contains a dot.
+      // In C++ this is a dereferencing operator. So we need to check if the
+      // current symbol we are handling starts with the same string as any of
+      // the existing symbols defined manually in the symbols table.
+      // If we do find such a case then revert to treating the dot as an operator
+      // rather than part of the symbol name. i.e. skip adding the automatic symbol.
+      bool dereferencedSymbol = false;
+      for (int j = 0; j < initialEntryCount; j++)
+      {
+        const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(j) );
+        if (symbol == NULL) continue;
+        TString symstr = symbol->Name();
+        symstr += ".";
+        if (s.BeginsWith(symstr))
+        {
+          dereferencedSymbol = true;
+          break;
+        }
+      }
+      if (dereferencedSymbol) continue;
 
       // Need to create the symbols first and check if its name is in the list
       // before actually adding it to the symbols list.
@@ -1430,12 +1763,44 @@ int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu,
       newSymbol.DefaultValue("false");
       if (FindSymbol(newSymbol.Name(), list) == -1)
       {
-        new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
+        try
+        {
+          new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
+        }
+        catch (const std::bad_alloc&)
+        {
+          HLTError("Could not allocate more memory for the symbols list when adding a trigger name symbol.");
+          return -ENOMEM;
+        }
       }
     }
     while (start < str.Length());
   }
   
+  // This last part is necessary to make sure that symbols are replaced in the
+  // trigger condition and domain merging expressions in a greedy manner.
+  // I.e. we need to make sure that if one symbol's string representation is
+  // contained inside another (string subset) that the longer symbol name is
+  // always first in the symbols list.
+  // This will work because the symbol table is traversed from first to last
+  // element and TString::ReplaceAll is used to replace the substrings inside
+  // the AliHLTGlobalTriggerComponent::GenerateTrigger method.
+  std::vector<AliHLTTriggerMenuSymbol*> orderedList;
+  for (Int_t i = 0; i < list.GetEntriesFast(); i++)
+  {
+    orderedList.push_back( static_cast<AliHLTTriggerMenuSymbol*>(list.UncheckedAt(i)) );
+  }
+  std::sort(orderedList.begin(), orderedList.end(), AliHLTCheckForContainment);
+  //std::sort(orderedList.begin(), orderedList.end());
+  // Now swap values around according to the orderedList.
+  for (Int_t i = 0; i < list.GetEntriesFast(); i++)
+  {
+    AliHLTTriggerMenuSymbol* target = static_cast<AliHLTTriggerMenuSymbol*>(list.UncheckedAt(i));
+    AliHLTTriggerMenuSymbol tmp = *target;
+    *target = *orderedList[i];
+    *orderedList[i] = tmp;
+  }
+  
   return 0;
 }
 
@@ -1496,10 +1861,44 @@ bool AliHLTGlobalTriggerComponent::ExtractedOperator(TString& expr, TString& op)
 }
 
 
+bool AliHLTGlobalTriggerComponent::FillSoftwareTrigger()
+{
+  // Fills the fSoftwareTrigger structure.
+  
+  if (fCDH == NULL) return false;
+  UChar_t l1msg = fCDH->GetL1TriggerMessage();
+  if ((l1msg & 0x1) == 0x0) return false;  // skip physics events.
+  // From here on everything must be a software trigger.
+  if (((l1msg >> 2) & 0xF) == 0xE)
+  {
+    fSoftwareTrigger.Name("START_OF_DATA");
+    fSoftwareTrigger.Description("Generated internal start of data trigger.");
+  }
+  else if (((l1msg >> 2) & 0xF) == 0xF)
+  {
+    fSoftwareTrigger.Name("END_OF_DATA");
+    fSoftwareTrigger.Description("Generated internal end of data trigger.");
+  }
+  else if (((l1msg >> 6) & 0x1) == 0x1)
+  {
+    fSoftwareTrigger.Name("CALIBRATION");
+    fSoftwareTrigger.Description("Generated internal calibration trigger.");
+  }
+  else
+  {
+    fSoftwareTrigger.Name("SOFTWARE");
+    fSoftwareTrigger.Description("Generated internal software trigger.");
+  }
+  UInt_t detectors = fCDH->GetSubDetectors();
+  fSoftwareTrigger.ReadoutList( AliHLTReadoutList(Int_t(detectors)) );
+  return true;
+}
+
+
 int AliHLTGlobalTriggerComponent::PrintStatistics(const AliHLTGlobalTrigger* pTrigger, AliHLTComponentLogSeverity level, int offset) const
 {
   // print some statistics
-  int totalEvents=GetEventCount()+offset;
+  int totalEvents=fTotalEventCounter+offset;
   const TArrayL64& counters = pTrigger->GetCounters();
   if (pTrigger->CallFailed()) return -EPROTO;
   for (int i = 0; i < counters.GetSize(); i++) {
@@ -1519,10 +1918,26 @@ int AliHLTGlobalTriggerComponent::AddCTPDecisions(AliHLTGlobalTrigger* pTrigger,
   AliHLTUInt64_t triggerMask=pCTPData->Mask();
   AliHLTUInt64_t bit0=0x1;
   if (!fCTPDecisions) {
-    fCTPDecisions=new TClonesArray(AliHLTTriggerDecision::Class(), gkNCTPTriggerClasses);
+    try
+    {
+      fCTPDecisions=new TClonesArray(AliHLTTriggerDecision::Class(), gkNCTPTriggerClasses);
+    }
+    catch (const std::bad_alloc&)
+    {
+      HLTError("Could not allocate memory for the CTP decisions array.");
+      return -ENOMEM;
+    }
     if (!fCTPDecisions) return -ENOMEM;
 
-    fCTPDecisions->ExpandCreate(gkNCTPTriggerClasses);
+    try
+    {
+      fCTPDecisions->ExpandCreate(gkNCTPTriggerClasses);
+    }
+    catch (const std::bad_alloc&)
+    {
+      HLTError("Could not allocate more memory for the CTP decisions array.");
+      return -ENOMEM;
+    }
     for (int i=0; i<gkNCTPTriggerClasses; i++) {
       const char* name=pCTPData->Name(i);
       if (triggerMask&(bit0<<i) && name) {
@@ -1546,8 +1961,14 @@ int AliHLTGlobalTriggerComponent::AddCTPDecisions(AliHLTGlobalTrigger* pTrigger,
     if (!pDecision) return -ENOENT;
 
     bool result=false;
-    if (trigData) result=pCTPData->EvaluateCTPTriggerClass(name, *trigData);
-    else result=pCTPData->EvaluateCTPTriggerClass(name);
+    // 13 March 2010 - Optimisation:
+    // Dont use the EvaluateCTPTriggerClass method, which uses slow TFormula objects.
+    AliHLTUInt64_t triggers = 0;
+    if (trigData) triggers = pCTPData->ActiveTriggers(*trigData);
+    else triggers = pCTPData->Triggers();
+    result = (triggers&((AliHLTUInt64_t)0x1<<i)) ? true : false;
+    //if (trigData) result=pCTPData->EvaluateCTPTriggerClass(name, *trigData);
+    //else result=pCTPData->EvaluateCTPTriggerClass(name);
     pDecision->Result(result);
     pDecision->TriggerDomain().Clear();
     if (trigData) pDecision->TriggerDomain().Add(pCTPData->ReadoutList(*trigData));