]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/trigger/AliHLTGlobalTriggerComponent.cxx
Applying the proper fix to cope with setups with multiple trigger clusters.
[u/mrichter/AliRoot.git] / HLT / trigger / AliHLTGlobalTriggerComponent.cxx
1 // $Id$
2 /**************************************************************************
3  * This file is property of and copyright by the ALICE HLT Project        *
4  * ALICE Experiment at CERN, All rights reserved.                         *
5  *                                                                        *
6  * Primary Authors: Artur Szostak <artursz@iafrica.com>                   *
7  *                  for The ALICE HLT Project.                            *
8  *                                                                        *
9  * Permission to use, copy, modify and distribute this software and its   *
10  * documentation strictly for non-commercial purposes is hereby granted   *
11  * without fee, provided that the above copyright notice appears in all   *
12  * copies and that both the copyright notice and this permission notice   *
13  * appear in the supporting documentation. The authors make no claims     *
14  * about the suitability of this software for any purpose. It is          *
15  * provided "as is" without express or implied warranty.                  *
16  **************************************************************************/
17
18 /// @file   AliHLTGlobalTriggerComponent.cxx
19 /// @author Artur Szostak <artursz@iafrica.com>
20 /// @date   26 Nov 2008
21 /// @brief  Implementation of the AliHLTGlobalTriggerComponent component class.
22 ///
23 /// The AliHLTGlobalTriggerComponentComponent class applies the global HLT trigger to all
24 /// trigger information produced by components deriving from AliHLTTrigger.
25
26 #include "AliHLTGlobalTriggerComponent.h"
27 #include "AliHLTGlobalTriggerDecision.h"
28 #include "AliHLTGlobalTrigger.h"
29 #include "AliHLTGlobalTriggerConfig.h"
30 #include "AliHLTTriggerMenu.h"
31 #include "AliHLTCTPData.h"
32 #include "AliCDBManager.h"
33 #include "AliCDBStorage.h"
34 #include "AliCDBEntry.h"
35 #include "TUUID.h"
36 #include "TROOT.h"
37 #include "TSystem.h"
38 #include "TRegexp.h"
39 #include "TClonesArray.h"
40 #include "TObjString.h"
41 #include "TSystem.h"
42 #include "TInterpreter.h"
43 #include "TDatime.h"
44 #include <fstream>
45 #include <cerrno>
46
47 ClassImp(AliHLTGlobalTriggerComponent)
48
49 const char* AliHLTGlobalTriggerComponent::fgkTriggerMenuCDBPath = "HLT/ConfigHLT/HLTGlobalTrigger";
50
51
52 AliHLTGlobalTriggerComponent::AliHLTGlobalTriggerComponent() :
53         AliHLTTrigger(),
54         fTrigger(NULL),
55         fDebugMode(false),
56         fCodeFileName()
57 {
58   // Default constructor.
59   
60   ClearInfoForNewEvent(false);
61 }
62
63
64 AliHLTGlobalTriggerComponent::~AliHLTGlobalTriggerComponent()
65 {
66   // Default destructor.
67   
68   if (fTrigger != NULL) delete fTrigger;
69 }
70
71
72 void AliHLTGlobalTriggerComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
73 {
74   // Returns the output data size estimate.
75
76   constBase = sizeof(AliHLTGlobalTriggerDecision);
77   inputMultiplier = 1;
78 }
79
80
81 Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
82 {
83   // Initialises the global trigger component.
84   
85   fDebugMode = false;
86   bool bSkipCTPCounters=false;
87   const char* configFileName = NULL;
88   const char* codeFileName = NULL;
89   TString classname;
90   TClonesArray includePaths(TObjString::Class());
91   TClonesArray includeFiles(TObjString::Class());
92   
93   for (int i = 0; i < argc; i++)
94   {
95     if (strcmp(argv[i], "-config") == 0)
96     {
97       if (configFileName != NULL)
98       {
99         HLTWarning("Trigger configuration macro was already specified."
100                    " Will replace previous value given by -config."
101         );
102       }
103       if (argc <= i+1)
104       {
105         HLTError("The trigger configuration macro filename was not specified." );
106         return -EINVAL;
107       }
108       configFileName = argv[i+1];
109       i++;
110       continue;
111     }
112     
113     if (strcmp(argv[i], "-includepath") == 0)
114     {
115       if (argc <= i+1)
116       {
117         HLTError("The include path was not specified." );
118         return -EINVAL;
119       }
120       new (includePaths[includePaths.GetEntriesFast()]) TObjString(argv[i+1]);
121       i++;
122       continue;
123     }
124     
125     if (strcmp(argv[i], "-include") == 0)
126     {
127       if (argc <= i+1)
128       {
129         HLTError("The include file name was not specified." );
130         return -EINVAL;
131       }
132       new (includeFiles[includeFiles.GetEntriesFast()]) TObjString(argv[i+1]);
133       i++;
134       continue;
135     }
136     
137     if (strcmp(argv[i], "-debug") == 0)
138     {
139       if (fDebugMode == true)
140       {
141         HLTWarning("The debug flag was already specified. Ignoring this instance.");
142       }
143       fDebugMode = true;
144       i++;
145       continue;
146     }
147     
148     if (strcmp(argv[i], "-usecode") == 0)
149     {
150       if (codeFileName != NULL)
151       {
152         HLTWarning("Custom trigger code file was already specified."
153                    " Will replace previous value given by -usecode."
154         );
155       }
156       if (argc <= i+1)
157       {
158         HLTError("The custom trigger code filename was not specified." );
159         return -EINVAL;
160       }
161       codeFileName = argv[i+1];
162       if (argc <= i+2)
163       {
164         HLTError("The custom trigger class name was not specified." );
165         return -EINVAL;
166       }
167       classname = argv[i+2];
168       i += 2;
169       continue;
170     }
171
172     if (strcmp(argv[i], "-skipctp") == 0)
173     {
174       HLTInfo("Skipping CTP counters in trigger decision");
175       bSkipCTPCounters=true;
176       continue;
177     }
178         
179     HLTError("Unknown option '%s'.", argv[i]);
180     return -EINVAL;
181   } // for loop
182   
183   const AliHLTTriggerMenu* menu = NULL;
184   if (configFileName != NULL)
185   {
186     TString cmd = ".x ";
187     cmd += configFileName;
188     gROOT->ProcessLine(cmd);
189     menu = AliHLTGlobalTriggerConfig::Menu();
190   }
191   
192   // Try load the trigger menu from the CDB if it is not loaded yet with the
193   // -config option
194   if (menu == NULL and AliCDBManager::Instance() != NULL)
195   {
196     AliCDBStorage* store = AliCDBManager::Instance()->GetDefaultStorage();
197     if (store == NULL)
198     {
199       HLTError("Could not get the the default storage for the CDB.");
200       return -EIO;
201     }
202     Int_t version = store->GetLatestVersion(fgkTriggerMenuCDBPath, GetRunNo());
203     Int_t subVersion = store->GetLatestSubVersion(fgkTriggerMenuCDBPath, GetRunNo(), version);
204     AliCDBEntry* entry = AliCDBManager::Instance()->Get(fgkTriggerMenuCDBPath, GetRunNo(), version, subVersion);
205     if (entry == NULL)
206     {
207       HLTError("Could not get the CDB entry for \"%s\".", fgkTriggerMenuCDBPath);
208       return -EIO;
209     }
210     TObject* obj = entry->GetObject();
211     if (obj == NULL)
212     {
213       HLTError("Configuration object for \"%s\" is missing.", fgkTriggerMenuCDBPath);
214       return -ENOENT;
215     }
216     if (obj->IsA() != AliHLTTriggerMenu::Class())
217     {
218       HLTError("Wrong type for configuration object in \"%s\". Found a %s but we expect a AliHLTTriggerMenu.",
219                fgkTriggerMenuCDBPath, obj->ClassName()
220       );
221       return -EPROTO;
222     }
223     menu = dynamic_cast<AliHLTTriggerMenu*>(obj);
224   }
225   
226   if (menu == NULL)
227   {
228     HLTError("No trigger menu configuration found or specified.");
229     return -ENOENT;
230   }
231   
232   int result = 0;
233   if (codeFileName == NULL)
234   {
235     HLTDebug("Generating custom HLT trigger class.");
236     result = GenerateTrigger(menu, classname, includePaths, includeFiles);
237   }
238   else
239   {
240     HLTDebug("Loading HLT trigger class from file '%s'.", codeFileName);
241     result = LoadTriggerClass(codeFileName, includePaths);
242   }
243   if (result != 0) return result;
244   
245   fTrigger = AliHLTGlobalTrigger::CreateNew(classname.Data());
246   if (fTrigger == NULL)
247   {
248     HLTError("Could not create a new instance of '%s'.", classname.Data());
249     return -EIO;
250   }
251   
252   fTrigger->FillFromMenu(*menu);
253   fTrigger->ResetCounters(menu->NumberOfItems());
254
255   // setup the CTP accounting in AliHLTComponent
256   if (!bSkipCTPCounters) SetupCTPData();
257
258   // Set the default values from the trigger menu.
259   SetDescription(menu->DefaultDescription());
260   SetTriggerDomain(menu->DefaultTriggerDomain());
261   
262   return 0;
263 }
264
265
266 Int_t AliHLTGlobalTriggerComponent::DoDeinit()
267 {
268   // Cleans up the global trigger component.
269   
270   if (fTrigger != NULL)
271   {
272     delete fTrigger;
273     fTrigger = NULL;
274   }
275
276   if (!fCodeFileName.IsNull() && gSystem->AccessPathName(fCodeFileName)==0 && !fDebugMode) {
277     fCodeFileName.ReplaceAll(".cxx", "*");
278     TString command="rm "; command+=fCodeFileName;
279     gSystem->Exec(command);
280   }
281   fCodeFileName="";
282   
283   return 0;
284 }
285
286
287 AliHLTComponent* AliHLTGlobalTriggerComponent::Spawn()
288 {
289   // Creates a new object instance.
290   
291   return new AliHLTGlobalTriggerComponent;
292 }
293
294
295 int AliHLTGlobalTriggerComponent::DoTrigger()
296 {
297   // This method will apply the global trigger decision.
298
299   if (fTrigger == NULL)
300   {
301     HLTFatal("Global trigger implementation object is NULL!");
302     return -EIO;
303   }
304
305   AliHLTUInt32_t eventType=0;
306   if (!IsDataEvent(&eventType)) {
307     if (eventType==gkAliEventTypeEndOfRun) PrintStatistics(fTrigger, kHLTLogImportant, 0);
308     return 0;
309   }
310
311   fTrigger->NewEvent();
312   
313   // Fill in the input data.
314   const TObject* obj = GetFirstInputObject();
315   while (obj != NULL)
316   {
317     fTrigger->Add(obj, GetDataType(), GetSpecification());
318     obj = GetNextInputObject();
319   }
320
321   // Calculate the global trigger result and trigger domain, then create and push
322   // back the new global trigger decision object.
323   TString description;
324   AliHLTTriggerDomain triggerDomain;
325   bool triggerResult = fTrigger->CalculateTriggerDecision(triggerDomain, description);
326   
327   AliHLTGlobalTriggerDecision decision(
328       triggerResult,
329       // The following will cause the decision to be generated with default values
330       // (set in fTriggerDomain and fDescription) if the trigger result is false.
331       (triggerResult == true) ? triggerDomain : GetTriggerDomain(),
332       (triggerResult == true) ? description.Data() : GetDescription()
333     );
334
335   // mask the readout list according to the CTP trigger
336   // if the classes have been initialized (mask non-zero)
337   const AliHLTCTPData* pCTPData=CTPData();
338   if (pCTPData && pCTPData->Mask()) {
339     AliHLTEventDDL eventDDL=pCTPData->ReadoutList(*GetTriggerData());
340     AliHLTReadoutList ctpreadout(eventDDL);
341     ctpreadout.Enable(AliHLTReadoutList::kHLT);
342     AliHLTReadoutList maskedList=decision.ReadoutList();
343     maskedList.AndEq(ctpreadout);
344     decision.ReadoutList(maskedList);
345   }
346
347   decision.SetCounters(fTrigger->Counters(), GetEventCount()+1);
348   static UInt_t lastTime=0;
349   TDatime time;
350   if (time.Get()-lastTime>5) {
351     lastTime=time.Get();
352     PrintStatistics(fTrigger);
353   }
354   
355   // Add the input objects used to the global decision.
356   obj = GetFirstInputObject();
357   while (obj != NULL)
358   {
359     if (obj->IsA() == AliHLTTriggerDecision::Class())
360     {
361       decision.AddTriggerInput( *static_cast<const AliHLTTriggerDecision*>(obj) );
362     }
363     else
364     {
365       decision.AddInputObject(obj);
366     }
367     obj = GetNextInputObject();
368   }
369
370   if (CTPData()) decision.AddInputObject(CTPData());
371
372   CreateEventDoneReadoutFilter(decision.TriggerDomain(), 3);
373   CreateEventDoneReadoutFilter(decision.TriggerDomain(), 4);
374   TriggerEvent(&decision);
375   return 0;
376 }
377
378
379 int AliHLTGlobalTriggerComponent::GenerateTrigger(
380     const AliHLTTriggerMenu* menu, TString& name,
381     const TClonesArray& includePaths, const TClonesArray& includeFiles
382   )
383 {
384   // Generates the global trigger class that will implement the specified trigger menu.
385   // See header for more details.
386   
387   // Create a new UUID and replace the '-' characters with '_' to make it a valid
388   // C++ symbol name.
389   TUUID uuid;
390   TString uuidstr = uuid.AsString();
391   for (Int_t i = 0; i < uuidstr.Length(); i++)
392   {
393     if (uuidstr[i] == '-') uuidstr[i] = '_';
394   }
395   
396   // Create the name of the new class.
397   name = "AliHLTGlobalTriggerImpl_";
398   name += uuidstr;
399   fCodeFileName = name + ".cxx";
400   
401   // Open a text file to write the code and generate the new class.
402   fstream code(fCodeFileName.Data(), ios_base::out | ios_base::trunc);
403   if (not code.good())
404   {
405     HLTError("Could not open file '%s' for writing.", fCodeFileName.Data());
406     return -EIO;
407   }
408   
409   TClonesArray symbols(AliHLTTriggerMenuSymbol::Class());
410   int result = BuildSymbolList(menu, symbols);
411   if (result != 0) return result;
412   
413   code << "#include <cstring>" << endl;
414   code << "#include \"TString.h\"" << endl;
415   code << "#include \"TClonesArray.h\"" << endl;
416   code << "#include \"AliHLTGlobalTrigger.h\"" << endl;
417   code << "#include \"AliHLTGlobalTriggerDecision.h\"" << endl;
418   code << "#include \"AliHLTDomainEntry.h\"" << endl;
419   code << "#include \"AliHLTTriggerDomain.h\"" << endl;
420   code << "#include \"AliHLTReadoutList.h\"" << endl;
421   code << "#include \"AliHLTTriggerMenu.h\"" << endl;
422   code << "#include \"AliHLTTriggerMenuItem.h\"" << endl;
423   code << "#include \"AliHLTTriggerMenuSymbol.h\"" << endl;
424   
425   // Add any include files that were specified on the command line.
426   for (Int_t i = 0; i < includeFiles.GetEntriesFast(); i++)
427   {
428     TString file = static_cast<TObjString*>(includeFiles.UncheckedAt(i))->String();
429     code << "#include \"" << file.Data() << "\"" << endl;
430   }
431   
432   code << "class " << name << " : public AliHLTGlobalTrigger" << endl;
433   code << "{" << endl;
434   code << "public:" << endl;
435   
436   code << "  " << name << "() : AliHLTGlobalTrigger()";
437   // Write the symbols in the trigger menu in the initialisation list.
438   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
439   {
440     code << "," << endl;
441     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
442     code << "    " << symbol->Name() << "()," << endl;
443     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
444     {
445       code << "    " << symbol->Name() << "TriggerDomain()," << endl;
446     }
447     code << "    " << symbol->Name() << "DomainEntry(kAliHLTAnyDataType)";
448   }
449   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
450   {
451     code << "," << endl << "    fMenuItemDescription" << i << "()";
452   }
453   code << endl << "  {" << endl;
454   if (fDebugMode)
455   {
456     code << "    SetLocalLoggingLevel(kHLTLogAll);" << endl;
457     code << "    HLTInfo(\"Creating new instance at %p.\", this);" << endl;
458   }
459   code << "  }" << endl;
460   
461   code << "  virtual ~" << name << "() {" << endl;
462   if (fDebugMode)
463   {
464     code << "    HLTInfo(\"Deleting instance at %p.\", this);" << endl;
465   }
466   code << "  }" << endl;
467   
468   // Generate the FillFromMenu method.
469   code << "  virtual void FillFromMenu(const AliHLTTriggerMenu& menu) {" << endl;
470   if (fDebugMode)
471   {
472     code << "    HLTDebug(\"Filling description entries from trigger menu for global trigger %p.\", this);" << endl;
473   }
474   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
475   {
476     code << "    fMenuItemDescription" << i << " = (menu.Item(" << i
477          << ") != NULL) ? menu.Item(" << i << ")->Description() : \"\";" << endl;
478   }
479   if (fDebugMode)
480   {
481     code << "    HLTDebug(\"Finished filling description entries from trigger menu.\");" << endl;
482     code << "    HLTDebug(\"Filling domain entries from trigger menu symbols for global trigger %p.\", this);" << endl;
483   }
484   code << "    for (Int_t i = 0; i < menu.SymbolArray().GetEntriesFast(); i++) {" << endl;
485   code << "      const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const"
486            " AliHLTTriggerMenuSymbol*>(menu.SymbolArray().UncheckedAt(i));" << endl;
487   code << "      if (symbol == NULL) continue;" << endl;
488   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
489   {
490     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
491     code << "      if (strcmp(symbol->Name(), \"" << symbol->Name() << "\") == 0) {" << endl;
492     if (fDebugMode)
493     {
494       code << "        HLTDebug(\"Assinging domain entry value to match for symbol '%s' to '%s'.\","
495               " symbol->Name(), symbol->BlockType().AsString().Data());" << endl;
496     }
497     code << "        " << symbol->Name() << "DomainEntry = symbol->BlockType();" << endl;
498     code << "        continue;" << endl;
499     code << "      }" << endl;
500   }
501   code << "    }" << endl;
502   if (fDebugMode)
503   {
504     code << "    HLTDebug(\"Finished filling domain entries from trigger menu symbols.\");" << endl;
505   }
506   code << "  }" << endl;
507   
508   // Generate the NewEvent method.
509   code << "  virtual void NewEvent() {" << endl;
510   if (fDebugMode)
511   {
512     code << "    HLTDebug(\"New event for global trigger object %p, initialising variables to default values.\", this);" << endl;
513   }
514   // Write code to initialise the symbols in the trigger menu to their default values.
515   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
516   {
517     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
518     code << "    " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
519     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
520     {
521       code << "    " << symbol->Name() << "TriggerDomain.Clear();" << endl;
522     }
523   }
524   if (fDebugMode)
525   {
526     code << "    HLTDebug(\"Finished initialising variables.\");" << endl;
527   }
528   code << "  }" << endl;
529   
530   // Generate the Add method.
531   code << "  virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
532   code << "    AliHLTDomainEntry _type_spec_(_type_, _spec_);" << endl;
533   if (fDebugMode)
534   {
535     code << "    HLTDebug(\"Adding TObject %p, with class name '%s' from data block"
536             " '%s', to global trigger object %p\", _object_, _object_->ClassName(),"
537             " _type_spec_.AsString().Data(), this);" << endl;
538     code << "    _object_->Print();" << endl;
539     code << "    bool _object_assigned_ = false;" << endl;
540   }
541   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
542   {
543     // Write code to check if the block type, specification and class name is correct.
544     // Then write code to assign the variable from the input object.
545     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
546     TString expr = symbol->AssignExpression();
547     if (expr == "") continue; // Skip entries that have no assignment expression.
548     bool isTrigDecision = strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0;
549     if (fDebugMode)
550     {
551       if (isTrigDecision)
552       {
553         code << "    HLTDebug(\"Trying to match input object to class '"
554              << symbol->ObjectClass() << "', trigger name '" << symbol->Name()
555              << "' and block type '%s'\", " << symbol->Name()
556              << "DomainEntry.AsString().Data());" << endl;
557       }
558       else
559       {
560         code << "    HLTDebug(\"Trying to match input object to class '"
561              << symbol->ObjectClass() << "' and block type '%s'\", "
562              << symbol->Name() << "DomainEntry.AsString().Data());" << endl;
563       }
564     }
565     code << "    const " << symbol->ObjectClass() << "* " << symbol->Name()
566          << "_object_ = dynamic_cast<const " << symbol->ObjectClass()
567          << "*>(_object_);" << endl;
568     code << "    if (" << symbol->Name() << "_object_ != NULL and ";
569     if (isTrigDecision)
570     {
571       code << "strcmp(" << symbol->Name() << "_object_->Name(), \""
572            << symbol->Name() << "\") == 0 and ";
573     }
574     code << symbol->Name() << "DomainEntry == _type_spec_) {" << endl;
575     TString fullname = symbol->Name();
576     fullname += "_object_";
577     expr.ReplaceAll("this", fullname);
578     code << "      this->" << symbol->Name() << " = " << expr.Data() << ";" << endl;
579     if (isTrigDecision)
580     {
581       code << "      this->" << symbol->Name() << "TriggerDomain = "
582            << fullname.Data() << "->TriggerDomain();" << endl;
583     }
584     if (fDebugMode)
585     {
586       code << "      HLTDebug(\"Added TObject %p with class name '%s' to variable "
587            << symbol->Name() << "\", _object_, _object_->ClassName());" << endl;
588       code << "      _object_assigned_ = true;" << endl;
589     }
590     code << "    }" << endl;
591   }
592   if (fDebugMode)
593   {
594     code << "    if (not _object_assigned_) HLTDebug(\"Did not assign TObject %p"
595             " with class name '%s' to any variable.\", _object_, _object_->ClassName());"
596          << endl;
597   }
598   code << "  }" << endl;
599   
600   // Generate the CalculateTriggerDecision method.
601   code << "  virtual bool CalculateTriggerDecision(AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl;
602   if (fDebugMode)
603   {
604     code << "    HLTDebug(\"Calculating global HLT trigger result with trigger object at %p.\", this);" << endl;
605   }
606   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
607   {
608     const AliHLTTriggerMenuItem* item = menu->Item(i);
609     TString mergeExpr = item->MergeExpression();
610     for (Int_t j = 0; j < symbols.GetEntriesFast(); j++)
611     {
612       AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(j) );
613       if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") != 0) continue;
614       TString newname = symbol->Name();
615       newname += "TriggerDomain";
616       mergeExpr.ReplaceAll(symbol->Name(), newname);
617     }
618     if (fDebugMode)
619     {
620       code << "    HLTDebug(\"Trying trigger condition " << i
621            << " (Description = '%s').\", fMenuItemDescription" << i << ".Data());"
622            << endl;
623     }
624     code << "    if (" << item->TriggerCondision() << ") {" << endl;
625     code << "      IncrementCounter(" << i << ");" << endl;
626     const char* indentation = "";
627     if (item->PreScalar() != 0)
628     {
629       indentation = "  ";
630       code << "      if ((GetCounter(" << i << ") % " << item->PreScalar() << ") == 1) {" << endl;
631     }
632     code << indentation << "      _domain_ = " << mergeExpr.Data() << ";" << endl;
633     code << indentation << "      _description_ = fMenuItemDescription" << i << ";" << endl;
634     if (fDebugMode)
635     {
636       code << indentation << "      HLTDebug(\"Matched trigger condition " << i
637            << " (Description = '%s').\", fMenuItemDescription" << i << ".Data());" << endl;
638     }
639     code << indentation << "      return true;" << endl;
640     if (item->PreScalar() != 0)
641     {
642       code << "      }" << endl;
643     }
644     code << "    }" << endl;
645   }
646   code << "    return false;" << endl;
647   code << "  }" << endl;
648   
649   // Generate the custom Factory class.
650   code << "  class FactoryImpl : public AliHLTGlobalTrigger::Factory" << endl;
651   code << "  {" << endl;
652   code << "  public:" << endl;
653   code << "    virtual const char* ClassName() const {" << endl;
654   code << "      return \"" << name << "\";" << endl;
655   code << "    }" << endl;
656   code << "    virtual AliHLTGlobalTrigger* New() const {" << endl;
657   code << "      return new " << name << "();" << endl;
658   code << "    }" << endl;
659   code << "  };" << endl;
660   
661   code << "private:" << endl;
662   // Add the symbols in the trigger menu to the list of private variables.
663   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
664   {
665     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
666     code << "  " << symbol->Type() << " " << symbol->Name() << ";" << endl;
667     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
668     {
669       code << "  AliHLTTriggerDomain " << symbol->Name() << "TriggerDomain;" << endl;
670     }
671     code << "  AliHLTDomainEntry " << symbol->Name() << "DomainEntry;" << endl;
672   }
673   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
674   {
675     code << "  TString fMenuItemDescription" << i << ";" << endl;
676   }
677   code << "};" << endl;
678   
679   // Write a global object for the Factory class for automatic registration.
680   code << "namespace {" << endl;
681   code << "  const " << name << "::FactoryImpl gkFactoryImpl;" << endl;
682   code << "};" << endl;
683   
684   code.close();
685   
686   // Now we need to compile and load the new class.
687   result = LoadTriggerClass(fCodeFileName, includePaths);
688   return result;
689 }
690
691
692 int AliHLTGlobalTriggerComponent::LoadTriggerClass(
693     const char* filename, const TClonesArray& includePaths
694   )
695 {
696   // Loads the code for a custom global trigger class implementation on the fly.
697   
698   TString compiler = gSystem->GetBuildCompilerVersion();
699   if (compiler.Contains("gcc") or compiler.Contains("icc"))
700   {
701     TString includePath = "-I${ALICE_ROOT}/include -I${ALICE_ROOT}/HLT/BASE -I${ALICE_ROOT}/HLT/trigger";
702     // Add any include paths that were specified on the command line.
703     for (Int_t i = 0; i < includePaths.GetEntriesFast(); i++)
704     {
705       TString path = static_cast<TObjString*>(includePaths.UncheckedAt(i))->String();
706       includePath += " ";
707       includePath += path;
708     }
709     gSystem->SetIncludePath(includePath);
710     gSystem->SetFlagsOpt("-O3 -DNDEBUG");
711     gSystem->SetFlagsDebug("-g3 -DDEBUG -D__DEBUG");
712     
713     int result = kTRUE;
714     if (fDebugMode)
715     {
716       result = gSystem->CompileMacro(filename, "g");
717     }
718     else
719     {
720       result = gSystem->CompileMacro(filename, "O");
721     }
722     if (result != kTRUE)
723     {
724       HLTFatal("Could not compile and load global trigger menu implementation.");
725       return -ENOENT;
726     }
727   }
728   else
729   {
730     // If we do not support the compiler then try interpret the class instead.
731     TString cmd = ".L ";
732     cmd += filename;
733     Int_t errorcode = TInterpreter::kNoError;
734     gROOT->ProcessLine(cmd, &errorcode);
735     if (errorcode != TInterpreter::kNoError)
736     {
737       HLTFatal("Could not load interpreted global trigger menu implementation"
738                " (Interpreter error code = %d).",
739                errorcode
740       );
741       return -ENOENT;
742     }
743   }
744   
745   return 0;
746 }
747
748
749 int AliHLTGlobalTriggerComponent::FindSymbol(const char* name, const TClonesArray& list)
750 {
751   // Searches for the named symbol in the given list.
752   // See header for more details.
753   
754   for (int i = 0; i < list.GetEntriesFast(); i++)
755   {
756     const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(i) );
757     if (symbol == NULL) continue;
758     if (strcmp(symbol->Name(), name) == 0) return i;
759   }
760   return -1;
761 }
762
763
764 int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, TClonesArray& list)
765 {
766   // Builds the list of symbols to use in the custom global trigger menu
767   // implementation class.
768   // See header for more details.
769   
770   for (UInt_t i = 0; i < menu->NumberOfSymbols(); i++)
771   {
772     const AliHLTTriggerMenuSymbol* symbol = menu->Symbol(i);
773     if (FindSymbol(symbol->Name(), list) != -1)
774     {
775       HLTError("Multiple symbols with the name '%s' defined in the trigger menu.", symbol->Name());
776       return -EIO;
777     }
778     new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
779   }
780   
781   TRegexp exp("[_a-zA-Z][_a-zA-Z0-9]*");
782   TRegexp hexexp("x[a-fA-F0-9]+");
783   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
784   {
785     const AliHLTTriggerMenuItem* item = menu->Item(i);
786     TString str = item->TriggerCondision();
787     Ssiz_t start = 0;
788     do
789     {
790       Ssiz_t length = 0;
791       Ssiz_t pos = exp.Index(str, &length, start);
792       if (pos == kNPOS) break;
793       start = pos+length;
794       
795       // Check if there is a numerical character before the found
796       // regular expression. If so, then the symbol is not a valid one
797       // and should be skipped.
798       if (pos > 0)
799       {
800         bool notValid = false;
801         switch (str[pos-1])
802         {
803         case '0': case '1': case '2': case '3': case '4':
804         case '5': case '6': case '7': case '8': case '9':
805           notValid = true;
806           break;
807         default:
808           notValid = false;
809           break;
810         }
811         if (notValid) continue;
812       }
813       TString s = str(pos, length);
814       
815       if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
816           s == "compl" or s == "not" or s == "not_eq" or s == "or" or
817           s == "or_eq" or s == "xor" or s == "xor_eq" or s == "true" or
818           s == "false"
819          )
820       {
821         // Ignore iso646.h and other keywords.
822         continue;
823       }
824
825       if (FindSymbol(s.Data(), list) == -1)
826       {
827         AliHLTTriggerMenuSymbol newSymbol;
828         newSymbol.Name(s.Data());
829         newSymbol.Type("bool");
830         newSymbol.ObjectClass("AliHLTTriggerDecision");
831         newSymbol.AssignExpression("this->Result()");
832         newSymbol.DefaultValue("false");
833         new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
834       }
835     }
836     while (start < str.Length());
837   }
838   
839   return 0;
840 }
841
842 int AliHLTGlobalTriggerComponent::PrintStatistics(const AliHLTGlobalTrigger* pTrigger, AliHLTComponentLogSeverity level, int offset) const
843 {
844   // print some statistics
845   ULong64_t count=0;
846   for (int i=0; i<pTrigger->Counters().GetSize(); i++) {
847     count+=pTrigger->Counters()[i];
848   }
849   int totalEvents=GetEventCount()+offset;
850   float ratio=0;
851   if (totalEvents>0) ratio=100*(float)count/totalEvents;
852   HLTLog(level, "total events: %d - triggered events: %llu (%.1f%%)", totalEvents, count, ratio);
853   return 0;
854 }