]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/trigger/AliHLTGlobalTriggerComponent.cxx
Making the TArrayL64 member variable of the AliHLTGlobalTrigger base class a dynamic...
[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   const TArrayL64* counters=fTrigger->Counters();
348   if (counters) {
349     decision.SetCounters(*counters, GetEventCount()+1);
350   }
351   static UInt_t lastTime=0;
352   TDatime time;
353   if (time.Get()-lastTime>5) {
354     lastTime=time.Get();
355     PrintStatistics(fTrigger);
356   }
357   
358   // Add the input objects used to the global decision.
359   obj = GetFirstInputObject();
360   while (obj != NULL)
361   {
362     if (obj->IsA() == AliHLTTriggerDecision::Class())
363     {
364       decision.AddTriggerInput( *static_cast<const AliHLTTriggerDecision*>(obj) );
365     }
366     else
367     {
368       decision.AddInputObject(obj);
369     }
370     obj = GetNextInputObject();
371   }
372
373   if (CTPData()) decision.AddInputObject(CTPData());
374
375   CreateEventDoneReadoutFilter(decision.TriggerDomain(), 3);
376   CreateEventDoneReadoutFilter(decision.TriggerDomain(), 4);
377   TriggerEvent(&decision);
378   return 0;
379 }
380
381
382 int AliHLTGlobalTriggerComponent::GenerateTrigger(
383     const AliHLTTriggerMenu* menu, TString& name,
384     const TClonesArray& includePaths, const TClonesArray& includeFiles
385   )
386 {
387   // Generates the global trigger class that will implement the specified trigger menu.
388   // See header for more details.
389   
390   // Create a new UUID and replace the '-' characters with '_' to make it a valid
391   // C++ symbol name.
392   TUUID uuid;
393   TString uuidstr = uuid.AsString();
394   for (Int_t i = 0; i < uuidstr.Length(); i++)
395   {
396     if (uuidstr[i] == '-') uuidstr[i] = '_';
397   }
398   
399   // Create the name of the new class.
400   name = "AliHLTGlobalTriggerImpl_";
401   name += uuidstr;
402   fCodeFileName = name + ".cxx";
403   
404   // Open a text file to write the code and generate the new class.
405   fstream code(fCodeFileName.Data(), ios_base::out | ios_base::trunc);
406   if (not code.good())
407   {
408     HLTError("Could not open file '%s' for writing.", fCodeFileName.Data());
409     return -EIO;
410   }
411   
412   TClonesArray symbols(AliHLTTriggerMenuSymbol::Class());
413   int result = BuildSymbolList(menu, symbols);
414   if (result != 0) return result;
415   
416   code << "#include <cstring>" << endl;
417   code << "#include \"TString.h\"" << endl;
418   code << "#include \"TClonesArray.h\"" << endl;
419   code << "#include \"AliHLTGlobalTrigger.h\"" << endl;
420   code << "#include \"AliHLTGlobalTriggerDecision.h\"" << endl;
421   code << "#include \"AliHLTDomainEntry.h\"" << endl;
422   code << "#include \"AliHLTTriggerDomain.h\"" << endl;
423   code << "#include \"AliHLTReadoutList.h\"" << endl;
424   code << "#include \"AliHLTTriggerMenu.h\"" << endl;
425   code << "#include \"AliHLTTriggerMenuItem.h\"" << endl;
426   code << "#include \"AliHLTTriggerMenuSymbol.h\"" << endl;
427   
428   // Add any include files that were specified on the command line.
429   for (Int_t i = 0; i < includeFiles.GetEntriesFast(); i++)
430   {
431     TString file = static_cast<TObjString*>(includeFiles.UncheckedAt(i))->String();
432     code << "#include \"" << file.Data() << "\"" << endl;
433   }
434   
435   code << "class " << name << " : public AliHLTGlobalTrigger" << endl;
436   code << "{" << endl;
437   code << "public:" << endl;
438   
439   code << "  " << name << "() : AliHLTGlobalTrigger()";
440   // Write the symbols in the trigger menu in the initialisation list.
441   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
442   {
443     code << "," << endl;
444     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
445     code << "    " << symbol->Name() << "()," << endl;
446     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
447     {
448       code << "    " << symbol->Name() << "TriggerDomain()," << endl;
449     }
450     code << "    " << symbol->Name() << "DomainEntry(kAliHLTAnyDataType)";
451   }
452   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
453   {
454     code << "," << endl << "    fMenuItemDescription" << i << "()";
455   }
456   code << endl << "  {" << endl;
457   if (fDebugMode)
458   {
459     code << "    SetLocalLoggingLevel(kHLTLogAll);" << endl;
460     code << "    HLTInfo(\"Creating new instance at %p.\", this);" << endl;
461   }
462   code << "  }" << endl;
463   
464   code << "  virtual ~" << name << "() {" << endl;
465   if (fDebugMode)
466   {
467     code << "    HLTInfo(\"Deleting instance at %p.\", this);" << endl;
468   }
469   code << "  }" << endl;
470   
471   // Generate the FillFromMenu method.
472   code << "  virtual void FillFromMenu(const AliHLTTriggerMenu& menu) {" << endl;
473   if (fDebugMode)
474   {
475     code << "    HLTDebug(\"Filling description entries from trigger menu for global trigger %p.\", this);" << endl;
476   }
477   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
478   {
479     code << "    fMenuItemDescription" << i << " = (menu.Item(" << i
480          << ") != NULL) ? menu.Item(" << i << ")->Description() : \"\";" << endl;
481   }
482   if (fDebugMode)
483   {
484     code << "    HLTDebug(\"Finished filling description entries from trigger menu.\");" << endl;
485     code << "    HLTDebug(\"Filling domain entries from trigger menu symbols for global trigger %p.\", this);" << endl;
486   }
487   code << "    for (Int_t i = 0; i < menu.SymbolArray().GetEntriesFast(); i++) {" << endl;
488   code << "      const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const"
489            " AliHLTTriggerMenuSymbol*>(menu.SymbolArray().UncheckedAt(i));" << endl;
490   code << "      if (symbol == NULL) continue;" << endl;
491   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
492   {
493     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
494     code << "      if (strcmp(symbol->Name(), \"" << symbol->Name() << "\") == 0) {" << endl;
495     if (fDebugMode)
496     {
497       code << "        HLTDebug(\"Assinging domain entry value to match for symbol '%s' to '%s'.\","
498               " symbol->Name(), symbol->BlockType().AsString().Data());" << endl;
499     }
500     code << "        " << symbol->Name() << "DomainEntry = symbol->BlockType();" << endl;
501     code << "        continue;" << endl;
502     code << "      }" << endl;
503   }
504   code << "    }" << endl;
505   if (fDebugMode)
506   {
507     code << "    HLTDebug(\"Finished filling domain entries from trigger menu symbols.\");" << endl;
508   }
509   code << "  }" << endl;
510   
511   // Generate the NewEvent method.
512   code << "  virtual void NewEvent() {" << endl;
513   if (fDebugMode)
514   {
515     code << "    HLTDebug(\"New event for global trigger object %p, initialising variables to default values.\", this);" << endl;
516   }
517   // Write code to initialise the symbols in the trigger menu to their default values.
518   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
519   {
520     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
521     code << "    " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
522     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
523     {
524       code << "    " << symbol->Name() << "TriggerDomain.Clear();" << endl;
525     }
526   }
527   if (fDebugMode)
528   {
529     code << "    HLTDebug(\"Finished initialising variables.\");" << endl;
530   }
531   code << "  }" << endl;
532   
533   // Generate the Add method.
534   code << "  virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
535   code << "    AliHLTDomainEntry _type_spec_(_type_, _spec_);" << endl;
536   if (fDebugMode)
537   {
538     code << "    HLTDebug(\"Adding TObject %p, with class name '%s' from data block"
539             " '%s', to global trigger object %p\", _object_, _object_->ClassName(),"
540             " _type_spec_.AsString().Data(), this);" << endl;
541     code << "    _object_->Print();" << endl;
542     code << "    bool _object_assigned_ = false;" << endl;
543   }
544   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
545   {
546     // Write code to check if the block type, specification and class name is correct.
547     // Then write code to assign the variable from the input object.
548     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
549     TString expr = symbol->AssignExpression();
550     if (expr == "") continue; // Skip entries that have no assignment expression.
551     bool isTrigDecision = strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0;
552     if (fDebugMode)
553     {
554       if (isTrigDecision)
555       {
556         code << "    HLTDebug(\"Trying to match input object to class '"
557              << symbol->ObjectClass() << "', trigger name '" << symbol->Name()
558              << "' and block type '%s'\", " << symbol->Name()
559              << "DomainEntry.AsString().Data());" << endl;
560       }
561       else
562       {
563         code << "    HLTDebug(\"Trying to match input object to class '"
564              << symbol->ObjectClass() << "' and block type '%s'\", "
565              << symbol->Name() << "DomainEntry.AsString().Data());" << endl;
566       }
567     }
568     code << "    const " << symbol->ObjectClass() << "* " << symbol->Name()
569          << "_object_ = dynamic_cast<const " << symbol->ObjectClass()
570          << "*>(_object_);" << endl;
571     code << "    if (" << symbol->Name() << "_object_ != NULL and ";
572     if (isTrigDecision)
573     {
574       code << "strcmp(" << symbol->Name() << "_object_->Name(), \""
575            << symbol->Name() << "\") == 0 and ";
576     }
577     code << symbol->Name() << "DomainEntry == _type_spec_) {" << endl;
578     TString fullname = symbol->Name();
579     fullname += "_object_";
580     expr.ReplaceAll("this", fullname);
581     code << "      this->" << symbol->Name() << " = " << expr.Data() << ";" << endl;
582     if (isTrigDecision)
583     {
584       code << "      this->" << symbol->Name() << "TriggerDomain = "
585            << fullname.Data() << "->TriggerDomain();" << endl;
586     }
587     if (fDebugMode)
588     {
589       code << "      HLTDebug(\"Added TObject %p with class name '%s' to variable "
590            << symbol->Name() << "\", _object_, _object_->ClassName());" << endl;
591       code << "      _object_assigned_ = true;" << endl;
592     }
593     code << "    }" << endl;
594   }
595   if (fDebugMode)
596   {
597     code << "    if (not _object_assigned_) HLTDebug(\"Did not assign TObject %p"
598             " with class name '%s' to any variable.\", _object_, _object_->ClassName());"
599          << endl;
600   }
601   code << "  }" << endl;
602   
603   // Generate the CalculateTriggerDecision method.
604   code << "  virtual bool CalculateTriggerDecision(AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl;
605   if (fDebugMode)
606   {
607     code << "    HLTDebug(\"Calculating global HLT trigger result with trigger object at %p.\", this);" << endl;
608   }
609   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
610   {
611     const AliHLTTriggerMenuItem* item = menu->Item(i);
612     TString mergeExpr = item->MergeExpression();
613     for (Int_t j = 0; j < symbols.GetEntriesFast(); j++)
614     {
615       AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(j) );
616       if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") != 0) continue;
617       TString newname = symbol->Name();
618       newname += "TriggerDomain";
619       mergeExpr.ReplaceAll(symbol->Name(), newname);
620     }
621     if (fDebugMode)
622     {
623       code << "    HLTDebug(\"Trying trigger condition " << i
624            << " (Description = '%s').\", fMenuItemDescription" << i << ".Data());"
625            << endl;
626     }
627     code << "    if (" << item->TriggerCondision() << ") {" << endl;
628     code << "      IncrementCounter(" << i << ");" << endl;
629     const char* indentation = "";
630     if (item->PreScalar() != 0)
631     {
632       indentation = "  ";
633       code << "      if ((GetCounter(" << i << ") % " << item->PreScalar() << ") == 1) {" << endl;
634     }
635     code << indentation << "      _domain_ = " << mergeExpr.Data() << ";" << endl;
636     code << indentation << "      _description_ = fMenuItemDescription" << i << ";" << endl;
637     if (fDebugMode)
638     {
639       code << indentation << "      HLTDebug(\"Matched trigger condition " << i
640            << " (Description = '%s').\", fMenuItemDescription" << i << ".Data());" << endl;
641     }
642     code << indentation << "      return true;" << endl;
643     if (item->PreScalar() != 0)
644     {
645       code << "      }" << endl;
646     }
647     code << "    }" << endl;
648   }
649   code << "    return false;" << endl;
650   code << "  }" << endl;
651   
652   // Generate the custom Factory class.
653   code << "  class FactoryImpl : public AliHLTGlobalTrigger::Factory" << endl;
654   code << "  {" << endl;
655   code << "  public:" << endl;
656   code << "    virtual const char* ClassName() const {" << endl;
657   code << "      return \"" << name << "\";" << endl;
658   code << "    }" << endl;
659   code << "    virtual AliHLTGlobalTrigger* New() const {" << endl;
660   code << "      return new " << name << "();" << endl;
661   code << "    }" << endl;
662   code << "  };" << endl;
663   
664   code << "private:" << endl;
665   // Add the symbols in the trigger menu to the list of private variables.
666   for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
667   {
668     AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
669     code << "  " << symbol->Type() << " " << symbol->Name() << ";" << endl;
670     if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
671     {
672       code << "  AliHLTTriggerDomain " << symbol->Name() << "TriggerDomain;" << endl;
673     }
674     code << "  AliHLTDomainEntry " << symbol->Name() << "DomainEntry;" << endl;
675   }
676   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
677   {
678     code << "  TString fMenuItemDescription" << i << ";" << endl;
679   }
680   code << "};" << endl;
681   
682   // Write a global object for the Factory class for automatic registration.
683   code << "namespace {" << endl;
684   code << "  const " << name << "::FactoryImpl gkFactoryImpl;" << endl;
685   code << "};" << endl;
686   
687   code.close();
688   
689   // Now we need to compile and load the new class.
690   result = LoadTriggerClass(fCodeFileName, includePaths);
691   return result;
692 }
693
694
695 int AliHLTGlobalTriggerComponent::LoadTriggerClass(
696     const char* filename, const TClonesArray& includePaths
697   )
698 {
699   // Loads the code for a custom global trigger class implementation on the fly.
700   
701   TString compiler = gSystem->GetBuildCompilerVersion();
702   if (compiler.Contains("gcc") or compiler.Contains("icc"))
703   {
704     TString includePath = "-I${ALICE_ROOT}/include -I${ALICE_ROOT}/HLT/BASE -I${ALICE_ROOT}/HLT/trigger";
705     // Add any include paths that were specified on the command line.
706     for (Int_t i = 0; i < includePaths.GetEntriesFast(); i++)
707     {
708       TString path = static_cast<TObjString*>(includePaths.UncheckedAt(i))->String();
709       includePath += " ";
710       includePath += path;
711     }
712     gSystem->SetIncludePath(includePath);
713     gSystem->SetFlagsOpt("-O3 -DNDEBUG");
714     gSystem->SetFlagsDebug("-g3 -DDEBUG -D__DEBUG");
715     
716     int result = kTRUE;
717     if (fDebugMode)
718     {
719       result = gSystem->CompileMacro(filename, "g");
720     }
721     else
722     {
723       result = gSystem->CompileMacro(filename, "O");
724     }
725     if (result != kTRUE)
726     {
727       HLTFatal("Could not compile and load global trigger menu implementation.");
728       return -ENOENT;
729     }
730   }
731   else
732   {
733     // If we do not support the compiler then try interpret the class instead.
734     TString cmd = ".L ";
735     cmd += filename;
736     Int_t errorcode = TInterpreter::kNoError;
737     gROOT->ProcessLine(cmd, &errorcode);
738     if (errorcode != TInterpreter::kNoError)
739     {
740       HLTFatal("Could not load interpreted global trigger menu implementation"
741                " (Interpreter error code = %d).",
742                errorcode
743       );
744       return -ENOENT;
745     }
746   }
747   
748   return 0;
749 }
750
751
752 int AliHLTGlobalTriggerComponent::FindSymbol(const char* name, const TClonesArray& list)
753 {
754   // Searches for the named symbol in the given list.
755   // See header for more details.
756   
757   for (int i = 0; i < list.GetEntriesFast(); i++)
758   {
759     const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(i) );
760     if (symbol == NULL) continue;
761     if (strcmp(symbol->Name(), name) == 0) return i;
762   }
763   return -1;
764 }
765
766
767 int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, TClonesArray& list)
768 {
769   // Builds the list of symbols to use in the custom global trigger menu
770   // implementation class.
771   // See header for more details.
772   
773   for (UInt_t i = 0; i < menu->NumberOfSymbols(); i++)
774   {
775     const AliHLTTriggerMenuSymbol* symbol = menu->Symbol(i);
776     if (FindSymbol(symbol->Name(), list) != -1)
777     {
778       HLTError("Multiple symbols with the name '%s' defined in the trigger menu.", symbol->Name());
779       return -EIO;
780     }
781     new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
782   }
783   
784   TRegexp exp("[_a-zA-Z][_a-zA-Z0-9]*");
785   TRegexp hexexp("x[a-fA-F0-9]+");
786   for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
787   {
788     const AliHLTTriggerMenuItem* item = menu->Item(i);
789     TString str = item->TriggerCondision();
790     Ssiz_t start = 0;
791     do
792     {
793       Ssiz_t length = 0;
794       Ssiz_t pos = exp.Index(str, &length, start);
795       if (pos == kNPOS) break;
796       start = pos+length;
797       
798       // Check if there is a numerical character before the found
799       // regular expression. If so, then the symbol is not a valid one
800       // and should be skipped.
801       if (pos > 0)
802       {
803         bool notValid = false;
804         switch (str[pos-1])
805         {
806         case '0': case '1': case '2': case '3': case '4':
807         case '5': case '6': case '7': case '8': case '9':
808           notValid = true;
809           break;
810         default:
811           notValid = false;
812           break;
813         }
814         if (notValid) continue;
815       }
816       TString s = str(pos, length);
817       
818       if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
819           s == "compl" or s == "not" or s == "not_eq" or s == "or" or
820           s == "or_eq" or s == "xor" or s == "xor_eq" or s == "true" or
821           s == "false"
822          )
823       {
824         // Ignore iso646.h and other keywords.
825         continue;
826       }
827
828       if (FindSymbol(s.Data(), list) == -1)
829       {
830         AliHLTTriggerMenuSymbol newSymbol;
831         newSymbol.Name(s.Data());
832         newSymbol.Type("bool");
833         newSymbol.ObjectClass("AliHLTTriggerDecision");
834         newSymbol.AssignExpression("this->Result()");
835         newSymbol.DefaultValue("false");
836         new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
837       }
838     }
839     while (start < str.Length());
840   }
841   
842   return 0;
843 }
844
845 int AliHLTGlobalTriggerComponent::PrintStatistics(const AliHLTGlobalTrigger* pTrigger, AliHLTComponentLogSeverity level, int offset) const
846 {
847   // print some statistics
848   ULong64_t count=0;
849   const TArrayL64* counters=pTrigger->Counters();
850   for (int i=0; counters!=NULL && i<counters->GetSize(); i++) {
851     count+=(*counters)[i];
852   }
853   int totalEvents=GetEventCount()+offset;
854   float ratio=0;
855   if (totalEvents>0) ratio=100*(float)count/totalEvents;
856   HLTLog(level, "total events: %d - triggered events: %llu (%.1f%%)", totalEvents, count, ratio);
857   return 0;
858 }