ALIROOT-5433 Transition to CDHv3 in HLT
[u/mrichter/AliRoot.git] / HLT / trigger / AliHLTGlobalTriggerComponent.cxx
CommitLineData
3da1c6d7 1// $Id$
1b9a175e 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///
def2ec97 23/// The AliHLTGlobalTriggerComponent class applies the global HLT trigger to all
1b9a175e 24/// trigger information produced by components deriving from AliHLTTrigger.
25
26#include "AliHLTGlobalTriggerComponent.h"
e2bb8ddd 27#include "AliHLTGlobalTriggerDecision.h"
28#include "AliHLTGlobalTrigger.h"
52f67e50 29#include "AliHLTGlobalTriggerConfig.h"
30#include "AliHLTTriggerMenu.h"
474952b2 31#include "AliHLTCTPData.h"
3da1c6d7 32#include "AliCDBManager.h"
33#include "AliCDBStorage.h"
34#include "AliCDBEntry.h"
e2bb8ddd 35#include "TUUID.h"
36#include "TROOT.h"
72bc5ab0 37#include "TSystem.h"
52f67e50 38#include "TRegexp.h"
39#include "TClonesArray.h"
40#include "TObjString.h"
1b820a65 41#include "TString.h"
52f67e50 42#include "TInterpreter.h"
d4ed5215 43#include "TDatime.h"
81d62bb4 44#include "TClass.h"
d543303d 45#include "TNamed.h"
f925a066 46#include "TRandom3.h"
e2bb8ddd 47#include <fstream>
48#include <cerrno>
566a01d0 49#include <cassert>
81d62bb4 50#include <vector>
51#include <algorithm>
1b9a175e 52
53ClassImp(AliHLTGlobalTriggerComponent)
54
3da1c6d7 55const char* AliHLTGlobalTriggerComponent::fgkTriggerMenuCDBPath = "HLT/ConfigHLT/HLTGlobalTrigger";
56
1b9a175e 57
81d62bb4 58namespace
59{
60 /**
61 * This method is used as a comparison functor with the STL sort routines.
62 */
63 bool AliHLTDescendingNumbers(UInt_t a, UInt_t b)
64 {
65 return a > b;
66 }
67} // end of namespace
68
69
1b9a175e 70AliHLTGlobalTriggerComponent::AliHLTGlobalTriggerComponent() :
e2bb8ddd 71 AliHLTTrigger(),
52f67e50 72 fTrigger(NULL),
72bc5ab0 73 fDebugMode(false),
566a01d0 74 fRuntimeCompile(true),
81d62bb4 75 fDeleteCodeFile(false),
9e14734f 76 fMakeSoftwareTriggers(true),
566a01d0 77 fCodeFileName(),
81d62bb4 78 fClassName(),
79 fCTPDecisions(NULL),
80 fBufferSizeConst(2*(sizeof(AliHLTGlobalTriggerDecision) + sizeof(AliHLTReadoutList))),
81 fBufferSizeMultiplier(1.),
82 fIncludePaths(TObjString::Class()),
1b820a65 83 fIncludeFiles(TObjString::Class()),
6598c82b 84 fLibStateAtLoad(),
3d6ea577 85 fBits(0),
cc095616 86 fDataEventsOnly(true),
87 fMonitorPeriod(-1),
9e14734f 88 fUniqueID(0),
89 fSoftwareTrigger(true, "SOFTWARE"),
16517abe 90 fTotalEventCounter(0),
91 fCDH(NULL)
1b9a175e 92{
93 // Default constructor.
acc7214e 94
95 ClearInfoForNewEvent(false);
1b9a175e 96}
97
98
99AliHLTGlobalTriggerComponent::~AliHLTGlobalTriggerComponent()
100{
101 // Default destructor.
e2bb8ddd 102
103 if (fTrigger != NULL) delete fTrigger;
566a01d0 104
105 if (fCTPDecisions) {
106 fCTPDecisions->Delete();
107 delete fCTPDecisions;
108 }
1b9a175e 109}
110
111
025443e0 112void AliHLTGlobalTriggerComponent::GetOutputDataTypes(AliHLTComponentDataTypeList& list) const
113{
114 // Returns the kAliHLTDataTypeGlobalTrigger type as output.
115 list.push_back(kAliHLTDataTypeGlobalTrigger);
116}
117
118
1b9a175e 119void AliHLTGlobalTriggerComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
120{
121 // Returns the output data size estimate.
122
81d62bb4 123 constBase = fBufferSizeConst;
124 inputMultiplier = fBufferSizeMultiplier;
1b9a175e 125}
126
127
52f67e50 128Int_t AliHLTGlobalTriggerComponent::DoInit(int argc, const char** argv)
1b9a175e 129{
e2bb8ddd 130 // Initialises the global trigger component.
131
52f67e50 132 fDebugMode = false;
81d62bb4 133 fClassName = "";
134 fCodeFileName = "";
135 fDeleteCodeFile = false;
9e14734f 136 fMakeSoftwareTriggers = true;
52f67e50 137 const char* configFileName = NULL;
138 const char* codeFileName = NULL;
81d62bb4 139 fIncludePaths.Clear();
140 fIncludeFiles.Clear();
6598c82b 141 SetBit(kIncludeInput);
3d6ea577 142 fDataEventsOnly = true;
f925a066 143 UInt_t randomSeed = 0;
144 bool randomSeedSet = false;
16517abe 145 fCDH = NULL;
52f67e50 146
147 for (int i = 0; i < argc; i++)
148 {
149 if (strcmp(argv[i], "-config") == 0)
150 {
151 if (configFileName != NULL)
152 {
153 HLTWarning("Trigger configuration macro was already specified."
154 " Will replace previous value given by -config."
155 );
156 }
157 if (argc <= i+1)
158 {
159 HLTError("The trigger configuration macro filename was not specified." );
160 return -EINVAL;
161 }
162 configFileName = argv[i+1];
163 i++;
164 continue;
165 }
166
167 if (strcmp(argv[i], "-includepath") == 0)
168 {
169 if (argc <= i+1)
170 {
171 HLTError("The include path was not specified." );
172 return -EINVAL;
173 }
dda123c3 174 try
175 {
176 new (fIncludePaths[fIncludePaths.GetEntriesFast()]) TObjString(argv[i+1]);
177 }
178 catch (const std::bad_alloc&)
179 {
180 HLTError("Could not allocate more memory for the fIncludePaths array.");
181 return -ENOMEM;
182 }
52f67e50 183 i++;
184 continue;
185 }
186
187 if (strcmp(argv[i], "-include") == 0)
188 {
189 if (argc <= i+1)
190 {
191 HLTError("The include file name was not specified." );
192 return -EINVAL;
193 }
dda123c3 194 try
195 {
196 new (fIncludeFiles[fIncludeFiles.GetEntriesFast()]) TObjString(argv[i+1]);
197 }
198 catch (const std::bad_alloc&)
199 {
200 HLTError("Could not allocate more memory for the fIncludeFiles array.");
201 return -ENOMEM;
202 }
52f67e50 203 i++;
204 continue;
205 }
206
207 if (strcmp(argv[i], "-debug") == 0)
208 {
209 if (fDebugMode == true)
210 {
211 HLTWarning("The debug flag was already specified. Ignoring this instance.");
212 }
213 fDebugMode = true;
566a01d0 214 continue;
215 }
216
217 if (strcmp(argv[i], "-cint") == 0)
218 {
219 fRuntimeCompile = false;
52f67e50 220 continue;
221 }
222
223 if (strcmp(argv[i], "-usecode") == 0)
224 {
225 if (codeFileName != NULL)
226 {
227 HLTWarning("Custom trigger code file was already specified."
228 " Will replace previous value given by -usecode."
229 );
230 }
231 if (argc <= i+1)
232 {
233 HLTError("The custom trigger code filename was not specified." );
234 return -EINVAL;
235 }
236 codeFileName = argv[i+1];
237 if (argc <= i+2)
238 {
239 HLTError("The custom trigger class name was not specified." );
240 return -EINVAL;
241 }
81d62bb4 242 fClassName = argv[i+2];
52f67e50 243 i += 2;
244 continue;
245 }
474952b2 246
247 if (strcmp(argv[i], "-skipctp") == 0)
248 {
249 HLTInfo("Skipping CTP counters in trigger decision");
6598c82b 250 SetBit(kSkipCTP);
251 continue;
252 }
253
254 if (strcmp(argv[i], "-forward-input") == 0)
255 {
256 HLTInfo("Forwarding input objects and trigger decisions");
257 SetBit(kForwardInput);
258 SetBit(kIncludeShort);
259 SetBit(kIncludeInput, false);
260 continue;
261 }
262
d543303d 263 if (strstr(argv[i], "-include-input") == argv[i])
6598c82b 264 {
265 SetBit(kForwardInput,false);
266 TString param=argv[i];
267 param.ReplaceAll("-include-input", "");
268 if (param.CompareTo("=none")==0)
269 {
270 HLTInfo("skipping objects and trigger decisions");
271 SetBit(kIncludeShort, false);
272 SetBit(kIncludeInput, false);
273 }
274 else if (param.CompareTo("=short")==0)
275 {
d543303d 276 HLTInfo("including short info on objects and trigger decisions");
6598c82b 277 SetBit(kIncludeShort);
278 SetBit(kIncludeInput, false);
279 }
d543303d 280 else if (param.CompareTo("=both")==0)
281 {
282 HLTInfo("including input objects, trigger decisions and short info");
283 SetBit(kIncludeShort);
284 SetBit(kIncludeInput);
285 }
6598c82b 286 else if (param.CompareTo("=objects")==0 || param.IsNull())
287 {
288 HLTInfo("including input objects and trigger decisions");
289 SetBit(kIncludeShort, false);
290 SetBit(kIncludeInput);
291 }
292 else
293 {
294 HLTError("unknown parameter '%s' for argument '-include-input'", param.Data());
295 }
474952b2 296 continue;
297 }
3d6ea577 298
299 if (strcmp(argv[i], "-process-all-events") == 0)
300 {
301 fDataEventsOnly = false;
302 continue;
303 }
b375374f 304
305 if (strstr(argv[i], "-monitoring") == argv[i])
306 {
307 TString param=argv[i];
308 param.ReplaceAll("-monitoring", "");
309 if (param.IsNull())
310 {
311 // -monitoring
312 // enable monitoring trigger for all events
313 fMonitorPeriod=0;
314 } else {
315 // -monitoring=n
316 // enable monitoring trigger once every n seconds
317 param.ReplaceAll("=", "");
318 if (param.IsDigit()) {
319 fMonitorPeriod=param.Atoi();
320 } else {
321 HLTError("expecting number as parameter for argument '-monitoring=', got %s, skipping monitoring trigger", param.Data());
322 }
323 }
324 continue;
325 }
9e14734f 326
327 if (strcmp(argv[i], "-dont-make-software-triggers") == 0)
328 {
329 fMakeSoftwareTriggers = false;
330 continue;
331 }
f925a066 332 if (strcmp(argv[i], "-randomseed") == 0)
333 {
334 if (randomSeedSet)
335 {
336 HLTWarning("The random seed was already specified previously with the option -randomseed."
337 "Will replace the previous value of %d with the new one.",
338 randomSeed
339 );
340 }
341 if (argc <= i+1)
342 {
343 HLTError("The number to use as the seed was not specified for the -randomseed option." );
344 return -EINVAL;
345 }
346 TString numstr = argv[i+1];
347 if (not numstr.IsDigit())
348 {
349 HLTError("The number specified in the -randomseed option is not a valid decimal integer." );
350 return -EINVAL;
351 }
352 randomSeed = numstr.Atoi();
353 randomSeedSet = true;
354 i++;
355 continue;
356 }
3d6ea577 357
52f67e50 358 HLTError("Unknown option '%s'.", argv[i]);
359 return -EINVAL;
360 } // for loop
361
362 const AliHLTTriggerMenu* menu = NULL;
363 if (configFileName != NULL)
364 {
365 TString cmd = ".x ";
366 cmd += configFileName;
367 gROOT->ProcessLine(cmd);
368 menu = AliHLTGlobalTriggerConfig::Menu();
369 }
370
3da1c6d7 371 // Try load the trigger menu from the CDB if it is not loaded yet with the
372 // -config option
81d62bb4 373 int result = -ENOENT;
374 if (menu == NULL)
3da1c6d7 375 {
81d62bb4 376 result = LoadTriggerMenu(fgkTriggerMenuCDBPath, menu);
3da1c6d7 377 }
52f67e50 378 if (menu == NULL)
379 {
380 HLTError("No trigger menu configuration found or specified.");
81d62bb4 381 return result;
52f67e50 382 }
383
52f67e50 384 if (codeFileName == NULL)
385 {
81d62bb4 386 result = GenerateTrigger(menu, fClassName, fCodeFileName, fIncludePaths, fIncludeFiles);
387 if (result == 0) fDeleteCodeFile = true;
52f67e50 388 }
389 else
390 {
81d62bb4 391 result = LoadTriggerClass(codeFileName, fIncludePaths);
392 if (result == 0) fCodeFileName = codeFileName;
52f67e50 393 }
e2bb8ddd 394 if (result != 0) return result;
395
dda123c3 396 try
397 {
398 fTrigger = AliHLTGlobalTrigger::CreateNew(fClassName.Data());
399 }
400 catch (const std::bad_alloc&)
401 {
402 HLTError("Could not allocate memory for the AliHLTGlobalTrigger instance.");
403 return -ENOMEM;
404 }
e2bb8ddd 405 if (fTrigger == NULL)
406 {
81d62bb4 407 HLTError("Could not create a new instance of '%s'.", fClassName.Data());
e2bb8ddd 408 return -EIO;
409 }
410
52f67e50 411 fTrigger->FillFromMenu(*menu);
325e5e42 412 if (fTrigger->CallFailed()) return -EPROTO;
474952b2 413
414 // setup the CTP accounting in AliHLTComponent
566a01d0 415 SetupCTPData();
474952b2 416
acc7214e 417 // Set the default values from the trigger menu.
418 SetDescription(menu->DefaultDescription());
419 SetTriggerDomain(menu->DefaultTriggerDomain());
420
f925a066 421 // Initialise the random number generator seed value.
422 // NOTE: The GenerateTrigger method called above will set the fUniqueID value
423 // with a random value based on a GUID that should be unique across the system.
424 // This is then used as the seed to the random number generator if the -randomseed
425 // option is not used.
426 if (not randomSeedSet) randomSeed = fUniqueID;
427 gRandom->SetSeed(randomSeed);
428
9e14734f 429 fTotalEventCounter = 0;
e2bb8ddd 430 return 0;
431}
432
1b9a175e 433
e2bb8ddd 434Int_t AliHLTGlobalTriggerComponent::DoDeinit()
435{
436 // Cleans up the global trigger component.
437
438 if (fTrigger != NULL)
439 {
440 delete fTrigger;
441 fTrigger = NULL;
442 }
443
566a01d0 444 if (fCTPDecisions) {
445 fCTPDecisions->Delete();
446 delete fCTPDecisions;
447 }
448 fCTPDecisions=NULL;
16517abe 449 fCDH = NULL;
81d62bb4 450
451 Int_t result = UnloadTriggerClass(fCodeFileName);
452 if (result != 0) return result;
453
454 if (fDeleteCodeFile and !fCodeFileName.IsNull() && gSystem->AccessPathName(fCodeFileName)==0 && !fDebugMode) {
bb9f4a0c 455 TString command="rm -f ";
456 command+=fCodeFileName + " " + TString(fCodeFileName).ReplaceAll(".cxx", "_cxx.d");
81d62bb4 457 gSystem->Exec(command);
458 }
459 fCodeFileName="";
460 fDeleteCodeFile=false;
566a01d0 461
1b9a175e 462 return 0;
463}
4f1d6b68 464
465
466AliHLTComponent* AliHLTGlobalTriggerComponent::Spawn()
467{
468 // Creates a new object instance.
dda123c3 469 AliHLTComponent* comp = NULL;
470 try
471 {
472 comp = new AliHLTGlobalTriggerComponent;
473 }
474 catch (const std::bad_alloc&)
475 {
476 HLTError("Could not allocate memory for a new instance of AliHLTGlobalTriggerComponent.");
477 return NULL;
478 }
479 return comp;
4f1d6b68 480}
481
e2bb8ddd 482
483int AliHLTGlobalTriggerComponent::DoTrigger()
484{
485 // This method will apply the global trigger decision.
486
487 if (fTrigger == NULL)
488 {
489 HLTFatal("Global trigger implementation object is NULL!");
490 return -EIO;
491 }
2974f8dc 492
493 AliHLTUInt32_t eventType=0;
494 if (!IsDataEvent(&eventType)) {
3d6ea577 495 if (fDataEventsOnly)
496 {
169c8b34 497 if (eventType == gkAliEventTypeEndOfRun) PrintStatistics(fTrigger, kHLTLogImportant);
2f251ae6 498 IgnoreEvent(); // dont generate any trigger decision.
3d6ea577 499 return 0;
500 }
2974f8dc 501 }
16517abe 502
503 fCDH = NULL; // have to reset this in case ExtractTriggerData fails.
16e6f752 504 int triggerSuccess=ExtractTriggerData(*GetTriggerData(), NULL, NULL, &fCDH, NULL, true);
505 if(triggerSuccess<0){
506 HLTError("Couldn't extract CDH from trigger data: %s", strerror(-triggerSuccess));
507 return -EPROTO;
508 }
81d62bb4 509 // Copy the trigger counters in case we need to set them back to their original
510 // value because the PushBack method fails with ENOSPC.
511 TArrayL64 originalCounters = fTrigger->GetCounters();
325e5e42 512 if (fTrigger->CallFailed()) return -EPROTO;
81d62bb4 513
e2bb8ddd 514 fTrigger->NewEvent();
325e5e42 515 if (fTrigger->CallFailed()) return -EPROTO;
e2bb8ddd 516
517 // Fill in the input data.
518 const TObject* obj = GetFirstInputObject();
519 while (obj != NULL)
520 {
52f67e50 521 fTrigger->Add(obj, GetDataType(), GetSpecification());
325e5e42 522 if (fTrigger->CallFailed()) return -EPROTO;
52f67e50 523 obj = GetNextInputObject();
524 }
525
a489a8dd 526 // add trigger decisions for every CTP class
527 const AliHLTCTPData* pCTPData=CTPData();
528 if (pCTPData) {
566a01d0 529 AddCTPDecisions(fTrigger, pCTPData, GetTriggerData());
a489a8dd 530 }
9e14734f 531
532 bool softwareTriggerIsValid = FillSoftwareTrigger();
533 if (softwareTriggerIsValid)
534 {
535 fTrigger->Add(&fSoftwareTrigger, kAliHLTDataTypeTriggerDecision, kAliHLTVoidDataSpec);
536 }
537
52f67e50 538 // Calculate the global trigger result and trigger domain, then create and push
539 // back the new global trigger decision object.
540 TString description;
acc7214e 541 AliHLTTriggerDomain triggerDomain;
f925a066 542 bool triggerResult = false;
543 bool matchedItems = fTrigger->CalculateTriggerDecision(triggerResult, triggerDomain, description);
325e5e42 544 if (fTrigger->CallFailed()) return -EPROTO;
acc7214e 545 AliHLTGlobalTriggerDecision decision(
546 triggerResult,
547 // The following will cause the decision to be generated with default values
548 // (set in fTriggerDomain and fDescription) if the trigger result is false.
f925a066 549 (matchedItems == true) ? triggerDomain : GetTriggerDomain(),
550 (matchedItems == true) ? description.Data() : GetDescription()
acc7214e 551 );
48d98db9 552
cc095616 553 decision.SetUniqueID(fUniqueID);
9e14734f 554 decision.SetCounters(fTrigger->GetCounters(), fTotalEventCounter+1);
325e5e42 555 if (fTrigger->CallFailed()) return -EPROTO;
556
2f251ae6 557 TClonesArray shortInfo(TNamed::Class(), GetNumberOfInputBlocks());
52f67e50 558
2f251ae6 559 // Add the input objects used to make the global decision.
52f67e50 560 obj = GetFirstInputObject();
561 while (obj != NULL)
562 {
2f251ae6 563 const AliHLTTriggerDecision* intrig = dynamic_cast<const AliHLTTriggerDecision*>(obj);
564
565 if (TestBit(kForwardInput)) Forward(obj);
566
567 if (TestBit(kIncludeInput))
e2bb8ddd 568 {
2f251ae6 569 if (intrig != NULL)
570 {
571 decision.AddTriggerInput(*intrig);
572 }
573 else
574 {
575 // The const_cast should be safe in this case because the list of inputObjects
576 // will be added to the global decision with AddInputObjectRef, which only
577 // modifies the kCanDelete bit and nothing else.
578 // This is necessary since GetFirstInputObject only returns const objects.
579 decision.AddInputObjectRef( const_cast<TObject*>(obj) );
580 }
e2bb8ddd 581 }
2f251ae6 582
583 if (TestBit(kIncludeShort))
e2bb8ddd 584 {
2f251ae6 585 int entries = shortInfo.GetEntriesFast();
dda123c3 586 try
587 {
2f251ae6 588 new (shortInfo[entries]) TNamed(obj->GetName(), obj->GetTitle());
dda123c3 589 }
590 catch (const std::bad_alloc&)
591 {
592 HLTError("Could not allocate more memory for the short list of input objects.");
dda123c3 593 return -ENOMEM;
594 }
2f251ae6 595 if (intrig != NULL)
596 {
597 shortInfo[entries]->SetBit(BIT(16)); // indicate that this is a trigger decision
598 shortInfo[entries]->SetBit(BIT(15), intrig->Result());
d543303d 599 }
600 }
601
e2bb8ddd 602 obj = GetNextInputObject();
603 }
2f251ae6 604 if (TestBit(kIncludeShort)) decision.AddInputObjectRef(&shortInfo);
605
606 // The const_cast should be safe in this case because AddInputObjectRef just
607 // modifies the kCanDelete bit and nothing else.
608 if (!TestBit(kSkipCTP) && CTPData()) decision.AddInputObjectRef(const_cast<AliHLTCTPData*>(CTPData()));
609
9e14734f 610 if (softwareTriggerIsValid and TestBit(kIncludeInput)) decision.AddTriggerInput(fSoftwareTrigger);
611
2f251ae6 612 static UInt_t lastTime=0;
613 TDatime time;
1d94e64a 614 if (time.Get()-lastTime>60)
615 {
2f251ae6 616 lastTime=time.Get();
617 PrintStatistics(fTrigger, kHLTLogImportant);
d543303d 618 }
169c8b34 619 else if (eventType==gkAliEventTypeEndOfRun)
620 {
621 PrintStatistics(fTrigger, kHLTLogImportant);
622 }
1d94e64a 623
0744f75d 624 // add readout filter to event done data
2974f8dc 625 CreateEventDoneReadoutFilter(decision.TriggerDomain(), 3);
b375374f 626
627 // add monitoring filter to event done data if enabled by setting
628 // a monitoring period >=0: -1 means off, 0 means for every event
629 // configured by argument '-monitoring[=n]'
630 if (fMonitorPeriod>=0) {
631 static UInt_t lastMonitorEvent=0;
632
633 AliHLTTriggerDomain monitoringFilter(decision.TriggerDomain());
634 if (decision.Result() &&
dd2e5959 635 int(time.Get()-lastMonitorEvent)>fMonitorPeriod) {
b375374f 636 lastMonitorEvent=time.Get();
637 // add monitoring event command for triggered events
638 CreateEventDoneReadoutFilter(decision.TriggerDomain(), 5);
639 } else {
640 // empty filter list if events are not triggered
641 // or within the monitoring interval
642 monitoringFilter.Clear();
643 }
644 // add monitoring filter list
645 CreateEventDoneReadoutFilter(monitoringFilter, 4);
0744f75d 646 }
16517abe 647
648 // Mask the readout list according to the CTP trigger
649 // if the classes have been initialized (mask non-zero).
650 // If we are dealing with a software trigger on the other hand then
651 // mask with the participating detector list.
652 // In both cases we must make sure that HLT is part of the readout mask.
08105f74 653 AliHLTReadoutList readoutlist = decision.ReadoutList();
654 AliHLTReadoutList readoutMask;
16517abe 655 if (CTPData() != NULL and CTPData()->Mask() != 0x0)
656 {
08105f74 657 readoutMask = CTPData()->ReadoutList(*GetTriggerData());
658 readoutMask.Enable(AliHLTReadoutList::kHLT);
16517abe 659 }
660 else if (softwareTriggerIsValid)
661 {
16e6f752 662 UInt_t detectors = fCDH.GetSubDetectors();
08105f74 663 readoutMask = AliHLTReadoutList(Int_t(detectors | AliHLTReadoutList::kHLT));
16517abe 664 }
08105f74 665 readoutlist.AndEq(readoutMask);
666 decision.ReadoutList(readoutlist); // override the readout list with the masked one.
667
668 // Also check whether the final readout list equals a full readout of detectors
669 // irrespective of HLT.
670 // Calculate the difference between the input and output list (xor)
671 // and check if any bits are set (ignoring HLT).
672 AliHLTReadoutList::EDetectorId minDetector = ( readoutlist ^ readoutMask ).GetFirstUsedDetector();
673 // Create the readout list specification word:
674 // Bit 0: Original Data Present (bit 15 of CDH status & error bit to be set)
675 // Bit 1-31: Reserved for future use
676 AliHLTUInt32_t spec = 0x0;
677 if ( AliHLTReadoutList::kNoDetector == minDetector || AliHLTReadoutList::kHLT == minDetector ) // Any bits set after XOR?
678 {
679 spec |= (AliHLTUInt32_t) 0x1;
680 }
681 else
682 {
683 spec &= ~((AliHLTUInt32_t) 0x1);
684 }
685 SetReadoutListSpecBits(spec);
b375374f 686
52fec07c 687 if (TriggerEvent(&decision, kAliHLTDataTypeGlobalTrigger) == -ENOSPC)
81d62bb4 688 {
689 // Increase the estimated buffer space required if the PushBack methods in TriggerEvent
690 // returned the "no buffer space" error code. Also remember to set the trigger counters
691 // back to what they were, otherwise triggers will be double counted when we try to reprocess
692 // this event with larger buffers.
693 fBufferSizeConst += 1024*1024;
694 fBufferSizeMultiplier *= 2.;
695 fTrigger->SetCounters(originalCounters);
325e5e42 696 if (fTrigger->CallFailed()) return -EPROTO;
81d62bb4 697 return -ENOSPC;
698 }
9e14734f 699
700 ++fTotalEventCounter;
81d62bb4 701 return 0;
702}
703
704
705int AliHLTGlobalTriggerComponent::Reconfigure(const char* cdbEntry, const char* chainId)
706{
707 // Reconfigure the component by loading the trigger menu and recreating the
708 // trigger logic class.
709
710 const char* path = fgkTriggerMenuCDBPath;
711 const char* id = "(unknown)";
712 if (cdbEntry != NULL) path = cdbEntry;
713 if (chainId != NULL and chainId[0] != '\0') id = chainId;
714 HLTInfo("Reconfiguring from '%s' for chain component '%s'.", path, id);
715
716 const AliHLTTriggerMenu* menu = NULL;
717 int result = LoadTriggerMenu(path, menu);
718 if (result != 0) return result;
719
720 TString className;
721 TString codeFileName;
722 result = GenerateTrigger(menu, className, codeFileName, fIncludePaths, fIncludeFiles);
723 if (result != 0) return result;
724
dda123c3 725 AliHLTGlobalTrigger* trigger = NULL;
726 try
727 {
728 trigger = AliHLTGlobalTrigger::CreateNew(className.Data());
729 }
730 catch (const std::bad_alloc&)
731 {
732 HLTError("Could not allocate memory for the AliHLTGlobalTrigger instance.");
733 return -ENOMEM;
734 }
81d62bb4 735 if (trigger == NULL)
736 {
737 HLTError("Could not create a new instance of '%s'.", className.Data());
738 // Make sure to cleanup after the new code file.
739 UnloadTriggerClass(codeFileName);
740 if (not codeFileName.IsNull() and gSystem->AccessPathName(codeFileName)==0 and not fDebugMode)
741 {
bb9f4a0c 742 TString command="rm -f ";
743 command+=codeFileName + " " + TString(codeFileName).ReplaceAll(".cxx", "_cxx.d");
81d62bb4 744 gSystem->Exec(command);
745 }
746 return -EIO;
747 }
748
749 if (fTrigger != NULL)
750 {
751 delete fTrigger;
752 fTrigger = NULL;
753 }
754
755 fTrigger = trigger;
756 fTrigger->FillFromMenu(*menu);
325e5e42 757 if (fTrigger->CallFailed()) return -EPROTO;
81d62bb4 758
759 // Set the default values from the trigger menu.
760 SetDescription(menu->DefaultDescription());
761 SetTriggerDomain(menu->DefaultTriggerDomain());
762
763 // Cleanup the old class code.
764 UnloadTriggerClass(fCodeFileName);
765 if (fDeleteCodeFile and not fCodeFileName.IsNull() and gSystem->AccessPathName(fCodeFileName)==0 and not fDebugMode)
766 {
bb9f4a0c 767 TString command="rm -f ";
768 command+=fCodeFileName + " " + TString(fCodeFileName).ReplaceAll(".cxx", "_cxx.d");
81d62bb4 769 gSystem->Exec(command);
770 }
771 fCodeFileName = codeFileName;
772 fDeleteCodeFile = true; // Since we generated a new class.
773
774 return 0;
775}
776
777
778int AliHLTGlobalTriggerComponent::LoadTriggerMenu(const char* cdbPath, const AliHLTTriggerMenu*& menu)
779{
780 // Loads the trigger menu object from the CDB path.
781
782 HLTDebug("Trying to load trigger menu from '%s'.", cdbPath);
74cbb05a 783 TObject* obj = LoadAndExtractOCDBObject(cdbPath);
81d62bb4 784 if (obj == NULL)
785 {
786 HLTError("Configuration object for \"%s\" is missing.", cdbPath);
787 return -ENOENT;
788 }
789 if (obj->IsA() != AliHLTTriggerMenu::Class())
790 {
791 HLTError("Wrong type for configuration object in \"%s\". Found a %s but we expect a AliHLTTriggerMenu.",
792 cdbPath, obj->ClassName()
793 );
794 return -EPROTO;
795 }
796 menu = static_cast<AliHLTTriggerMenu*>(obj);
e2bb8ddd 797 return 0;
798}
799
800
cc095616 801void AliHLTGlobalTriggerComponent::GenerateFileName(TString& name, TString& filename)
579a2996 802{
803 // Creates a unique file name for the generated code.
804
cc095616 805 TUUID guid = GenerateGUID();
85b88cd8 806 union
807 {
808 UChar_t buf[16];
809 UInt_t bufAsInt[4];
810 };
cc095616 811 guid.GetUUID(buf);
85b88cd8 812 fUniqueID = bufAsInt[0];
cc095616 813 TString guidstr = guid.AsString();
814 // Replace '-' with '_' in string.
815 for (int i = 0; i < guidstr.Length(); ++i)
579a2996 816 {
cc095616 817 if (guidstr[i] == '-') guidstr[i] = '_';
818 }
579a2996 819 name = "AliHLTGlobalTriggerImpl_";
cc095616 820 name += guidstr;
579a2996 821 filename = name + ".cxx";
822
823 // For good measure, check that the file names are not used. If they are then regenerate.
824 fstream file(filename.Data(), ios_base::in);
825 if (file.good())
826 {
827 file.close();
828 GenerateFileName(name, filename);
829 }
830}
831
832
52f67e50 833int AliHLTGlobalTriggerComponent::GenerateTrigger(
81d62bb4 834 const AliHLTTriggerMenu* menu, TString& name, TString& filename,
52f67e50 835 const TClonesArray& includePaths, const TClonesArray& includeFiles
836 )
e2bb8ddd 837{
838 // Generates the global trigger class that will implement the specified trigger menu.
52f67e50 839 // See header for more details.
e2bb8ddd 840
579a2996 841 GenerateFileName(name, filename);
842 HLTDebug("Generating custom HLT trigger class named %s, in file %s, using trigger menu %p.",
843 name.Data(), filename.Data(), ((void*)menu)
844 );
e2bb8ddd 845
52f67e50 846 // Open a text file to write the code and generate the new class.
81d62bb4 847 fstream code(filename.Data(), ios_base::out | ios_base::trunc);
e2bb8ddd 848 if (not code.good())
849 {
81d62bb4 850 HLTError("Could not open file '%s' for writing.", filename.Data());
e2bb8ddd 851 return -EIO;
852 }
853
52f67e50 854 TClonesArray symbols(AliHLTTriggerMenuSymbol::Class());
855 int result = BuildSymbolList(menu, symbols);
856 if (result != 0) return result;
857
81d62bb4 858 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
52f67e50 859 code << "#include <cstring>" << endl;
2f251ae6 860 code << "#include \"TClass.h\"" << endl;
52f67e50 861 code << "#include \"TString.h\"" << endl;
862 code << "#include \"TClonesArray.h\"" << endl;
f925a066 863 code << "#include \"TRandom3.h\"" << endl;
81d62bb4 864 code << "#include \"AliHLTLogging.h\"" << endl;
e2bb8ddd 865 code << "#include \"AliHLTGlobalTrigger.h\"" << endl;
866 code << "#include \"AliHLTGlobalTriggerDecision.h\"" << endl;
52f67e50 867 code << "#include \"AliHLTDomainEntry.h\"" << endl;
868 code << "#include \"AliHLTTriggerDomain.h\"" << endl;
869 code << "#include \"AliHLTReadoutList.h\"" << endl;
870 code << "#include \"AliHLTTriggerMenu.h\"" << endl;
871 code << "#include \"AliHLTTriggerMenuItem.h\"" << endl;
872 code << "#include \"AliHLTTriggerMenuSymbol.h\"" << endl;
873
874 // Add any include files that were specified on the command line.
875 for (Int_t i = 0; i < includeFiles.GetEntriesFast(); i++)
876 {
7da191b6 877 TString file = static_cast<TObjString*>(includeFiles.UncheckedAt(i))->String();
52f67e50 878 code << "#include \"" << file.Data() << "\"" << endl;
879 }
880
81d62bb4 881 if (fDebugMode)
882 {
883 code << "#else" << endl;
884 code << "const char* gFunctionName = \"???\";" << endl;
885 code << "#define HLTDebug(msg) if (CheckFilter(kHLTLogDebug) && CheckGroup(Class_Name())) SendMessage(kHLTLogDebug, Class_Name(), ::gFunctionName, __FILE__, __LINE__, msg)" << endl;
886 }
887 code << "#endif" << endl;
888
889 code << "class " << name << " :" << endl;
890 // Add appropriate #ifdef sections since we need to prevent inheritance from
891 // AliHLTGlobalTrigger. CINT does not seem to support multiple inheritance nor
892 // multiple levels of inheritance. Neither of the following schemes worked:
893 //
894 // 1) class AliHLTGlobalTrigger : public AliHLTLogging {};
895 // class AliHLTGlobalTriggerImpl_xyz : public AliHLTGlobalTrigger {};
896 //
897 // 2) class AliHLTGlobalTrigger {};
898 // class AliHLTGlobalTriggerImpl_xyz : public AliHLTGlobalTrigger, public AliHLTLogging {};
899 //
900 // Thus, we are forced to just inherit from AliHLTLogging when running in the CINT
901 // interpreter. But we anyway have to call the global trigger implementation class
902 // through the AliHLTGlobalTriggerWrapper so this is not such a problem.
903 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
904 code << " public AliHLTGlobalTrigger," << endl;
905 code << "#endif" << endl;
906 code << " public AliHLTLogging" << endl;
e2bb8ddd 907 code << "{" << endl;
908 code << "public:" << endl;
52f67e50 909
81d62bb4 910 // Generate constructor method.
911 code << " " << name << "() :" << endl;
912 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
913 code << " AliHLTGlobalTrigger()," << endl;
914 code << "#endif" << endl;
915 code << " AliHLTLogging()";
52f67e50 916 // Write the symbols in the trigger menu in the initialisation list.
917 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
918 {
919 code << "," << endl;
920 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
921 code << " " << symbol->Name() << "()," << endl;
922 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
923 {
924 code << " " << symbol->Name() << "TriggerDomain()," << endl;
925 }
926 code << " " << symbol->Name() << "DomainEntry(kAliHLTAnyDataType)";
927 }
928 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
929 {
930 code << "," << endl << " fMenuItemDescription" << i << "()";
931 }
932 code << endl << " {" << endl;
933 if (fDebugMode)
934 {
81d62bb4 935 code << "#ifdef __CINT__" << endl;
936 code << " gFunctionName = \"" << name.Data() <<"\";" << endl;
937 code << "#endif" << endl;
52f67e50 938 code << " SetLocalLoggingLevel(kHLTLogAll);" << endl;
81d62bb4 939 code << " HLTDebug(Form(\"Creating new instance at %p.\", this));" << endl;
52f67e50 940 }
e2bb8ddd 941 code << " }" << endl;
52f67e50 942
e2bb8ddd 943 code << " virtual ~" << name << "() {" << endl;
52f67e50 944 if (fDebugMode)
945 {
81d62bb4 946 code << "#ifdef __CINT__" << endl;
947 code << " gFunctionName = \"~" << name.Data() << "\";" << endl;
948 code << "#endif" << endl;
949 code << " HLTDebug(Form(\"Deleting instance at %p.\", this));" << endl;
52f67e50 950 }
e2bb8ddd 951 code << " }" << endl;
52f67e50 952
953 // Generate the FillFromMenu method.
954 code << " virtual void FillFromMenu(const AliHLTTriggerMenu& menu) {" << endl;
955 if (fDebugMode)
956 {
81d62bb4 957 code << "#ifdef __CINT__" << endl;
958 code << " gFunctionName = \"FillFromMenu\";" << endl;
959 code << "#endif" << endl;
960 code << " HLTDebug(Form(\"Filling description entries from trigger menu for global trigger %p.\", this));" << endl;
52f67e50 961 }
81d62bb4 962 code << " fCounter.Set(menu.NumberOfItems());" << endl;
52f67e50 963 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
964 {
965 code << " fMenuItemDescription" << i << " = (menu.Item(" << i
966 << ") != NULL) ? menu.Item(" << i << ")->Description() : \"\";" << endl;
967 }
968 if (fDebugMode)
969 {
81d62bb4 970 code << " HLTDebug(Form(\"Finished filling description entries from trigger menu.\"));" << endl;
971 code << " HLTDebug(Form(\"Filling domain entries from trigger menu symbols for global trigger %p.\", this));" << endl;
52f67e50 972 }
973 code << " for (Int_t i = 0; i < menu.SymbolArray().GetEntriesFast(); i++) {" << endl;
325e5e42 974 // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
975 // Have to use the TClass system for extra protection.
976 code << " if (menu.SymbolArray().UncheckedAt(i) == NULL) continue;" << endl;
977 code << " if (menu.SymbolArray().UncheckedAt(i)->IsA() != AliHLTTriggerMenuSymbol::Class()) continue;" << endl;
52f67e50 978 code << " const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const"
979 " AliHLTTriggerMenuSymbol*>(menu.SymbolArray().UncheckedAt(i));" << endl;
980 code << " if (symbol == NULL) continue;" << endl;
981 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
982 {
983 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
025443e0 984 code << " if (strcmp(symbol->RealName(), \"" << symbol->RealName() << "\") == 0) {" << endl;
52f67e50 985 if (fDebugMode)
986 {
81d62bb4 987 code << " HLTDebug(Form(\"Assinging domain entry value corresponding with symbol '%s' to '%s'.\","
025443e0 988 " symbol->RealName(), symbol->BlockType().AsString().Data()));" << endl;
52f67e50 989 }
990 code << " " << symbol->Name() << "DomainEntry = symbol->BlockType();" << endl;
991 code << " continue;" << endl;
992 code << " }" << endl;
993 }
994 code << " }" << endl;
2f251ae6 995 // The following is an optimisation where symbols without any assignment operators
996 // are treated as constant and only initialised in FillFromMenu rather than reseting
997 // them in the NewEvent method.
998 // Note: we putting this initialisation into the constructor can lead to seg faults
999 // under CINT interpretation. Thus we must put it into the FillFromMenu method instead.
1000 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1001 {
1002 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1003 if (TString(symbol->AssignExpression()) != "") continue;
1004 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0) continue;
1005 // CINT has problems with the implicit equals operator for complex types, so if
1006 // the type has an equals operater we need to write the operator call explicitly.
1007 TClass* clas = TClass::GetClass(symbol->Type());
1008 if (clas != NULL and clas->GetMethodAny("operator=") != NULL)
1009 {
1010 code << " " << symbol->Name() << ".operator = (" << symbol->DefaultValue() << ");" << endl;
1011 }
1012 else
1013 {
1014 code << " " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
1015 }
1016 }
52f67e50 1017 if (fDebugMode)
1018 {
81d62bb4 1019 code << " HLTDebug(Form(\"Finished filling domain entries from trigger menu symbols.\"));" << endl;
52f67e50 1020 }
e2bb8ddd 1021 code << " }" << endl;
52f67e50 1022
1023 // Generate the NewEvent method.
1024 code << " virtual void NewEvent() {" << endl;
1025 if (fDebugMode)
1026 {
81d62bb4 1027 code << "#ifdef __CINT__" << endl;
1028 code << " gFunctionName = \"NewEvent\";" << endl;
1029 code << "#endif" << endl;
1030 code << " HLTDebug(Form(\"New event for global trigger object %p, initialising variables to default values.\", this));" << endl;
52f67e50 1031 }
1032 // Write code to initialise the symbols in the trigger menu to their default values.
1033 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1034 {
1035 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
2f251ae6 1036 // The following is an optimisation. If the symbol does not have an assignment expression
1037 // then it is effectively a constant symbol and can be initialised earlier and only once.
1038 // In this case we initialise it in the FillFromMenu method instead.
1039 if (TString(symbol->AssignExpression()) == "") continue;
81d62bb4 1040 // CINT has problems with the implicit equals operator for complex types, so if
2f251ae6 1041 // the type has an equals operater we need to write the operator call explicitly.
81d62bb4 1042 TClass* clas = TClass::GetClass(symbol->Type());
1043 if (clas != NULL and clas->GetMethodAny("operator=") != NULL)
1044 {
1045 code << " " << symbol->Name() << ".operator = (" << symbol->DefaultValue() << ");" << endl;
1046 }
1047 else
1048 {
1049 code << " " << symbol->Name() << " = " << symbol->DefaultValue() << ";" << endl;
1050 }
52f67e50 1051 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
1052 {
1053 code << " " << symbol->Name() << "TriggerDomain.Clear();" << endl;
1054 }
1055 }
1056 if (fDebugMode)
1057 {
81d62bb4 1058 code << " HLTDebug(Form(\"Finished initialising variables.\"));" << endl;
52f67e50 1059 }
e2bb8ddd 1060 code << " }" << endl;
52f67e50 1061
1062 // Generate the Add method.
8066c87b 1063 bool haveAssignments = false;
1064 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1065 {
1066 // First check if we have any symbols with assignment expressions.
1067 // This is needed to get rid of the on the fly compilation warning about '_object_' not being used.
1068 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1069 TString expr = symbol->AssignExpression();
1070 if (expr == "") continue; // Skip entries that have no assignment expression.
1071 haveAssignments = true;
1072 break;
1073 }
1074 if (haveAssignments or fDebugMode)
1075 {
1076 code << " virtual void Add(const TObject* _object_, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
1077 }
1078 else
1079 {
1080 code << " virtual void Add(const TObject* /*_object_*/, const AliHLTComponentDataType& _type_, AliHLTUInt32_t _spec_) {" << endl;
1081 }
81d62bb4 1082 if (fDebugMode)
1083 {
1084 code << "#ifdef __CINT__" << endl;
1085 code << " gFunctionName = \"Add\";" << endl;
1086 code << "#endif" << endl;
1087 }
52f67e50 1088 code << " AliHLTDomainEntry _type_spec_(_type_, _spec_);" << endl;
1089 if (fDebugMode)
1090 {
81d62bb4 1091 code << " HLTDebug(Form(\"Adding TObject %p, with class name '%s' from data block"
52f67e50 1092 " '%s', to global trigger object %p\", _object_, _object_->ClassName(),"
81d62bb4 1093 " _type_spec_.AsString().Data(), this));" << endl;
52f67e50 1094 code << " _object_->Print();" << endl;
1095 code << " bool _object_assigned_ = false;" << endl;
1096 }
1097 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1098 {
1099 // Write code to check if the block type, specification and class name is correct.
1100 // Then write code to assign the variable from the input object.
1101 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1102 TString expr = symbol->AssignExpression();
1103 if (expr == "") continue; // Skip entries that have no assignment expression.
1104 bool isTrigDecision = strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0;
1105 if (fDebugMode)
1106 {
1107 if (isTrigDecision)
1108 {
81d62bb4 1109 code << " HLTDebug(Form(\"Trying to match input object to class '"
f48dcb4e 1110 << symbol->ObjectClass() << "', trigger name '" << symbol->RealName()
52f67e50 1111 << "' and block type '%s'\", " << symbol->Name()
81d62bb4 1112 << "DomainEntry.AsString().Data()));" << endl;
52f67e50 1113 }
1114 else
1115 {
81d62bb4 1116 code << " HLTDebug(Form(\"Trying to match input object to class '"
52f67e50 1117 << symbol->ObjectClass() << "' and block type '%s'\", "
81d62bb4 1118 << symbol->Name() << "DomainEntry.AsString().Data()));" << endl;
52f67e50 1119 }
1120 }
325e5e42 1121 // 30 Oct 2009 - CINT sometimes evaluates the dynamic_cast incorrectly.
1122 // Have to use the TClass system for extra protection.
1123 code << " const " << symbol->ObjectClass() << "* " << symbol->Name() << "_object_ = NULL;" << endl;
f1cac1f9 1124 code << " if (_object_->InheritsFrom(" << symbol->ObjectClass() << "::Class())) " << symbol->Name()
52f67e50 1125 << "_object_ = dynamic_cast<const " << symbol->ObjectClass()
1126 << "*>(_object_);" << endl;
81d62bb4 1127 code << " if (" << symbol->Name() << "_object_ != NULL && ";
52f67e50 1128 if (isTrigDecision)
1129 {
1130 code << "strcmp(" << symbol->Name() << "_object_->Name(), \""
e9f09f57 1131 << symbol->RealName() << "\") == 0 && ";
52f67e50 1132 }
1133 code << symbol->Name() << "DomainEntry == _type_spec_) {" << endl;
1134 TString fullname = symbol->Name();
1135 fullname += "_object_";
1136 expr.ReplaceAll("this", fullname);
1137 code << " this->" << symbol->Name() << " = " << expr.Data() << ";" << endl;
1138 if (isTrigDecision)
1139 {
1140 code << " this->" << symbol->Name() << "TriggerDomain = "
1141 << fullname.Data() << "->TriggerDomain();" << endl;
1142 }
1143 if (fDebugMode)
1144 {
81d62bb4 1145 code << " HLTDebug(Form(\"Added TObject %p with class name '%s' to variable "
1146 << symbol->Name() << "\", _object_, _object_->ClassName()));" << endl;
52f67e50 1147 code << " _object_assigned_ = true;" << endl;
1148 }
1149 code << " }" << endl;
1150 }
1151 if (fDebugMode)
1152 {
81d62bb4 1153 code << " if (! _object_assigned_) {" << endl;
1154 code << " HLTDebug(Form(\"Did not assign TObject %p"
1155 " with class name '%s' to any variable.\", _object_, _object_->ClassName()));"
52f67e50 1156 << endl;
81d62bb4 1157 code << " }" << endl;
52f67e50 1158 }
e2bb8ddd 1159 code << " }" << endl;
52f67e50 1160
1161 // Generate the CalculateTriggerDecision method.
81d62bb4 1162 // This requires code to be generated that checks which items in the trigger menu
1163 // have their conditions asserted and then the trigger domain is generated from
1164 // those fired items.
1165 // The processing will start from the highest priority trigger group and stop
1166 // after at least one trigger from the current priority group being processed
1167 // is positive. For each priority group all the trigger menu items are checked.
1168 // Their combined trigger condition expression must be true for the trigger priority
1169 // group to be triggered positive. The full condition expression is formed by
1170 // concatenating the individual condition expressions. If no trailing operators are
1171 // used in the individual expressions then the default condition operator is placed
1172 // between two concatenated condition expressions.
1173 // If a trigger priority group has at least one trigger fired then the trigger domain
1174 // is calculated such that it will give the same result as the concatenated trigger
1175 // domain merging expressions for all the individual trigger menu items with
1176 // positive results. Again, if no trailing operators are used in the individual
1177 // merging expressions then the default domain operator is placed between two
1178 // expression fragments.
f925a066 1179 code << " virtual bool CalculateTriggerDecision(bool& _trigger_result_, AliHLTTriggerDomain& _domain_, TString& _description_) {" << endl;
52f67e50 1180 if (fDebugMode)
1181 {
81d62bb4 1182 code << "#ifdef __CINT__" << endl;
1183 code << " gFunctionName = \"CalculateTriggerDecision\";" << endl;
1184 code << "#endif" << endl;
1185 code << " HLTDebug(Form(\"Calculating global HLT trigger result with trigger object at %p.\", this));" << endl;
52f67e50 1186 }
81d62bb4 1187
1188 // Build a list of priorities used in the trigger menu.
1189 std::vector<UInt_t> priorities;
52f67e50 1190 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1191 {
1192 const AliHLTTriggerMenuItem* item = menu->Item(i);
81d62bb4 1193 bool priorityNotInList = std::find(priorities.begin(), priorities.end(), item->Priority()) == priorities.end();
1194 if (priorityNotInList) priorities.push_back(item->Priority());
1195 }
1196 std::sort(priorities.begin(), priorities.end(), AliHLTDescendingNumbers);
1197 // From the priority list, build the priority groups in the correct order,
1198 // i.e. highest priority first.
1199 // The priority group is a list of vectors of integers. The integers are the
1200 // index numbers into the trigger menu item list for the items which form part
1201 // of the priority group.
1202 std::vector<std::vector<Int_t> > priorityGroup;
1203 priorityGroup.insert(priorityGroup.begin(), priorities.size(), std::vector<Int_t>());
1204 for (size_t n = 0; n < priorities.size(); n++)
1205 {
1206 UInt_t priority = priorities[n];
1207 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
52f67e50 1208 {
81d62bb4 1209 const AliHLTTriggerMenuItem* item = menu->Item(i);
1210 if (item->Priority() == priority) priorityGroup[n].push_back(i);
52f67e50 1211 }
81d62bb4 1212 }
1213
1214 for (size_t n = 0; n < priorityGroup.size(); n++)
1215 {
52f67e50 1216 if (fDebugMode)
1217 {
81d62bb4 1218 code << " HLTDebug(Form(\"Processing trigger priority group " << priorities[n] << "\"));" << endl;
52f67e50 1219 }
81d62bb4 1220 code << " ";
1221 if (n == 0) code << "UInt_t ";
1222 code << "_previous_match_ = 0xFFFFFFFF;" << endl;
1223 code << " ";
1224 if (n == 0) code << "bool ";
1225 code << "_trigger_matched_ = false;" << endl;
1226 code << " ";
1227 if (n == 0) code << "bool ";
1228 code << "_group_result_ = false;" << endl;
1229 std::vector<TString> conditionOperator;
1230 conditionOperator.insert(conditionOperator.begin(), priorityGroup[n].size(), TString(""));
1231 std::vector<TString> domainOperator;
1232 domainOperator.insert(domainOperator.begin(), priorityGroup[n].size(), TString(""));
1233 for (size_t m = 0; m < priorityGroup[n].size(); m++)
52f67e50 1234 {
81d62bb4 1235 UInt_t i = priorityGroup[n][m];
1236 const AliHLTTriggerMenuItem* item = menu->Item(i);
1237 TString triggerCondition = item->TriggerCondition();
1238 TString mergeExpr = item->MergeExpression();
1239 // Replace the symbols found in the trigger condition and merging expressions
1240 // with appropriate compilable versions.
1241 for (Int_t j = 0; j < symbols.GetEntriesFast(); j++)
1242 {
1243 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(j) );
1244 bool symbolNamesDifferent = strcmp(symbol->RealName(), symbol->Name()) != 0;
1245 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
1246 {
1247 TString newname = symbol->Name();
1248 newname += "TriggerDomain";
1249 mergeExpr.ReplaceAll(symbol->RealName(), newname);
1250 }
1251 else
1252 {
1253 if (symbolNamesDifferent) mergeExpr.ReplaceAll(symbol->RealName(), symbol->Name());
1254 }
1255 if (symbolNamesDifferent) triggerCondition.ReplaceAll(symbol->RealName(), symbol->Name());
1256 }
1257 // We allow the trigger conditions and merging expressions to have trailing operators.
1258 // Thus, we need to extract the operators and cleanup the expressions so that they will
1259 // compile. This means that we silently ignore the trailing operator if not needed.
1260 if (ExtractedOperator(triggerCondition, conditionOperator[m]))
1261 {
1262 // If the trailing operator is the same as the default operator then reset
1263 // the value in the operator list so that the default is used in the generated
1264 // code. This creates more compact code.
1265 if (conditionOperator[m] == menu->DefaultConditionOperator()) conditionOperator[m] = "";
1266 }
1267 if (ExtractedOperator(mergeExpr, domainOperator[m]))
1268 {
1269 if (domainOperator[m] == menu->DefaultDomainOperator()) domainOperator[m] = "";
1270 }
1271 if (fDebugMode)
1272 {
1273 code << " HLTDebug(Form(\"Trying trigger condition " << i
1274 << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));"
1275 << endl;
1276 }
1277 code << " ";
1278 if (n == 0 and m == 0) code << "bool ";
1279 code << "_item_result_ = false;" << endl;
1280 code << " if (" << triggerCondition << ") {" << endl;
1281 code << " ++fCounter[" << i << "];" << endl;
1282 const char* indentation = "";
f925a066 1283 // Generate the code to handle the prescalar and scale-down
1284 bool havePrescalar = item->PreScalar() != 0;
1285 bool haveScaledown = item->ScaleDown() < 1;
1286 if (havePrescalar or haveScaledown)
81d62bb4 1287 {
1288 indentation = " ";
f925a066 1289 code << " if (";
1290 if (havePrescalar) code << "(fCounter[" << i << "] % " << item->PreScalar() << ") == 1";
1291 if (havePrescalar and haveScaledown) code << " && ";
1292 if (haveScaledown)
1293 {
1294 std::streamsize oldprecision = code.precision(17);
1295 code << "gRandom->Rndm() < " << item->ScaleDown();
1296 code.precision(oldprecision);
1297 }
1298 code << ") {" << endl;
81d62bb4 1299 }
1300 code << indentation << " _item_result_ = true;" << endl;
1301 if (fDebugMode)
1302 {
1303 code << indentation << " HLTDebug(Form(\"Matched trigger condition " << i
1304 << " (Description = '%s').\", fMenuItemDescription" << i << ".Data()));" << endl;
1305 }
f925a066 1306 if (havePrescalar or haveScaledown)
81d62bb4 1307 {
1308 code << " }" << endl;
1309 }
1310 code << " }" << endl;
1311 if (m == 0)
1312 {
1313 // Since this is the first item of the trigger group,
1314 // the generated trigger logic can be simplified a little.
1315 code << " _group_result_ = _item_result_;" << endl;
1316 code << " if (_item_result_) {" << endl;
1317 code << " _domain_ = " << mergeExpr.Data() << ";" << endl;
1318 code << " _description_ = fMenuItemDescription" << i << ";" << endl;
1319 code << " _previous_match_ = " << i << ";" << endl;
1320 code << " _trigger_matched_ = true;" << endl;
1321 code << " }" << endl;
1322 }
1323 else
1324 {
325e5e42 1325 if (conditionOperator[m-1] == "")
81d62bb4 1326 {
1327 code << " _group_result_ = _group_result_ "
1328 << menu->DefaultConditionOperator() << " _item_result_;" << endl;
1329 }
1330 else
1331 {
325e5e42 1332 code << " _group_result_ = _group_result_ "
1333 << conditionOperator[m-1] << " _item_result_;" << endl;
81d62bb4 1334 }
1335 code << " if (_item_result_) {" << endl;
1336 code << " if (_trigger_matched_) {" << endl;
325e5e42 1337 bool switchWillBeEmpty = true;
81d62bb4 1338 for (size_t k = 0; k < m; k++)
1339 {
1340 if (domainOperator[k] == "") continue;
1341 switchWillBeEmpty = false;
1342 }
1343 if (switchWillBeEmpty)
1344 {
1345 code << " _domain_ = _domain_ " << menu->DefaultDomainOperator() << " "
1346 << mergeExpr.Data() << ";" << endl;
1347 }
1348 else
1349 {
1350 code << " switch(_previous_match_) {" << endl;
1351 for (size_t k = 0; k < m; k++)
1352 {
1353 if (domainOperator[k] == "") continue;
1354 code << " case " << k << ": _domain_ = _domain_ "
1355 << domainOperator[k] << " " << mergeExpr.Data() << "; break;" << endl;
1356 }
1357 code << " default: _domain_ = _domain_ "
1358 << menu->DefaultDomainOperator() << " " << mergeExpr.Data() << ";" << endl;
1359 code << " }" << endl;
1360 }
1361 code << " _description_ += \",\";" << endl;
1362 code << " _description_ += fMenuItemDescription" << i << ";" << endl;
1363 code << " } else {" << endl;
1364 code << " _domain_ = " << mergeExpr.Data() << ";" << endl;
1365 code << " _description_ = fMenuItemDescription" << i << ";" << endl;
1366 code << " }" << endl;
1367 code << " _previous_match_ = " << i << ";" << endl;
1368 code << " _trigger_matched_ = true;" << endl;
1369 code << " }" << endl;
1370 }
52f67e50 1371 }
81d62bb4 1372 code << " if (_group_result_) {" << endl;
52f67e50 1373 if (fDebugMode)
1374 {
81d62bb4 1375 if (n < priorities.size() - 1)
1376 {
1377 code << " HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n]
1378 << ". Stopping processing here because all other trigger groups have lower priority.\"));" << endl;
1379 }
1380 else
1381 {
1382 code << " HLTDebug(Form(\"Matched triggers in trigger priority group " << priorities[n] << ".\"));" << endl;
1383 }
52f67e50 1384 }
f925a066 1385 bool methodReturnResult = true;
1386 if (priorityGroup[n].size() > 0)
1387 {
1388 const AliHLTTriggerMenuItem* item = menu->Item(priorityGroup[n][0]);
1389 methodReturnResult = item->DefaultResult();
1390 }
1391 // Check to see if the items of the group all have the same default result.
1392 // If not then warn the user since only the first item's value will be used.
1393 for (size_t m = 1; m < priorityGroup[n].size(); m++)
1394 {
1395 const AliHLTTriggerMenuItem* item = menu->Item(priorityGroup[n][m]);
1396 if (item->DefaultResult() != methodReturnResult)
1397 {
1398 HLTWarning("Found items with different default results set for priority group %d."
1399 "Will only use the value from the first item.",
1400 item->Priority()
1401 );
1402 break;
1403 }
1404 }
1405 code << " _trigger_result_ = " << (methodReturnResult ? "true" : "false") << ";" << endl;
81d62bb4 1406 code << " return true;" << endl;
52f67e50 1407 code << " }" << endl;
1408 }
81d62bb4 1409 code << " _domain_.Clear();" << endl;
1410 code << " _description_ = \"\";" << endl;
f925a066 1411 code << " _trigger_result_ = " << (menu->DefaultResult() ? "true" : "false") << ";" << endl;
81d62bb4 1412 code << " return false;" << endl;
e2bb8ddd 1413 code << " }" << endl;
52f67e50 1414
81d62bb4 1415 // Generate getter and setter methods for the counters.
1416 code << " const TArrayL64& GetCounters() const { return fCounter; }" << endl;
1417 code << " void SetCounters(const TArrayL64& counters) { fCounter = counters; }" << endl;
52f67e50 1418
e2bb8ddd 1419 code << "private:" << endl;
52f67e50 1420 // Add the symbols in the trigger menu to the list of private variables.
1421 for (Int_t i = 0; i < symbols.GetEntriesFast(); i++)
1422 {
1423 AliHLTTriggerMenuSymbol* symbol = static_cast<AliHLTTriggerMenuSymbol*>( symbols.UncheckedAt(i) );
1424 code << " " << symbol->Type() << " " << symbol->Name() << ";" << endl;
1425 if (strcmp(symbol->ObjectClass(), "AliHLTTriggerDecision") == 0)
1426 {
1427 code << " AliHLTTriggerDomain " << symbol->Name() << "TriggerDomain;" << endl;
1428 }
1429 code << " AliHLTDomainEntry " << symbol->Name() << "DomainEntry;" << endl;
1430 }
1431 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1432 {
1433 code << " TString fMenuItemDescription" << i << ";" << endl;
1434 }
81d62bb4 1435 code << " TArrayL64 fCounter;" << endl;
1436 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
1437 code << " ClassDef(" << name.Data() << ", 0)" << endl;
1438 code << "#else" << endl;
1439 code << " virtual const char* Class_Name() const { return \"" << name.Data() << "\"; }" << endl;
1440 code << "#endif" << endl;
e2bb8ddd 1441 code << "};" << endl;
81d62bb4 1442 code << "#if !defined(__CINT__) || defined(__MAKECINT__)" << endl;
1443 code << "ClassImp(" << name.Data() << ")" << endl;
1444 code << "#endif" << endl;
e2bb8ddd 1445
1446 code.close();
1447
52f67e50 1448 // Now we need to compile and load the new class.
81d62bb4 1449 result = LoadTriggerClass(filename, includePaths);
52f67e50 1450 return result;
1451}
1452
1453
1454int AliHLTGlobalTriggerComponent::LoadTriggerClass(
1455 const char* filename, const TClonesArray& includePaths
1456 )
1457{
1458 // Loads the code for a custom global trigger class implementation on the fly.
1459
81d62bb4 1460 HLTDebug("Loading HLT trigger class from file '%s'.", filename);
1461
52f67e50 1462 TString compiler = gSystem->GetBuildCompilerVersion();
11689766 1463 if (fRuntimeCompile && (compiler.Contains("gcc") || compiler.Contains("icc") || compiler.Contains("clang")))
566a01d0 1464 {
1465 TString includePath;
1466#if defined(PKGINCLUDEDIR)
1467 // this is especially for the HLT build system where the package is installed
1468 // in a specific directory including proper treatment of include files
1469 includePath.Form("-I%s", PKGINCLUDEDIR);
1470#else
1471 // the default AliRoot behavior, all include files can be found in the
1472 // $ALICE_ROOT subfolders
1473 includePath = "-I${ALICE_ROOT}/include -I${ALICE_ROOT}/HLT/BASE -I${ALICE_ROOT}/HLT/trigger";
1474#endif
52f67e50 1475 // Add any include paths that were specified on the command line.
1476 for (Int_t i = 0; i < includePaths.GetEntriesFast(); i++)
1477 {
7da191b6 1478 TString path = static_cast<TObjString*>(includePaths.UncheckedAt(i))->String();
81d62bb4 1479 includePath += " -I";
52f67e50 1480 includePath += path;
1481 }
81d62bb4 1482 HLTDebug("using include settings: %s", includePath.Data());
52f67e50 1483 gSystem->SetIncludePath(includePath);
1484 gSystem->SetFlagsOpt("-O3 -DNDEBUG");
1485 gSystem->SetFlagsDebug("-g3 -DDEBUG -D__DEBUG");
1486
1487 int result = kTRUE;
1488 if (fDebugMode)
1489 {
1490 result = gSystem->CompileMacro(filename, "g");
1491 }
1492 else
1493 {
1494 result = gSystem->CompileMacro(filename, "O");
1495 }
1496 if (result != kTRUE)
1497 {
1498 HLTFatal("Could not compile and load global trigger menu implementation.");
1499 return -ENOENT;
1500 }
1501 }
1502 else
1503 {
1b820a65 1504 // Store the library state to be checked later in UnloadTriggerClass.
1505 fLibStateAtLoad = gSystem->GetLibraries();
1506
52f67e50 1507 // If we do not support the compiler then try interpret the class instead.
81d62bb4 1508 TString cmd = ".L ";
52f67e50 1509 cmd += filename;
1510 Int_t errorcode = TInterpreter::kNoError;
1511 gROOT->ProcessLine(cmd, &errorcode);
1512 if (errorcode != TInterpreter::kNoError)
1513 {
1514 HLTFatal("Could not load interpreted global trigger menu implementation"
1515 " (Interpreter error code = %d).",
1516 errorcode
1517 );
1518 return -ENOENT;
1519 }
1520 }
1521
1522 return 0;
1523}
1524
1525
81d62bb4 1526int AliHLTGlobalTriggerComponent::UnloadTriggerClass(const char* filename)
1527{
1528 // Unloads the code previously loaded by LoadTriggerClass.
1529
1530 HLTDebug("Unloading HLT trigger class in file '%s'.", filename);
1531
1532 TString compiler = gSystem->GetBuildCompilerVersion();
1533 if (fRuntimeCompile && (compiler.Contains("gcc") or compiler.Contains("icc")))
1534 {
1b820a65 1535 // Generate the library name.
81d62bb4 1536 TString libname = filename;
1537 Ssiz_t dotpos = libname.Last('.');
1538 if (0 <= dotpos and dotpos < libname.Length()) libname[dotpos] = '_';
1539 libname += ".";
1540 libname += gSystem->GetSoExt();
1541
1b820a65 1542 // This is a workaround for a problem with unloading shared libraries in ROOT.
1543 // If the trigger logic library is loaded before the libAliHLTHOMER.so library
1544 // or any other library is loaded afterwards, then during the gInterpreter->UnloadFile
1545 // call all the subsequent libraries get unloded. This means that any objects created
1546 // from classes implemented in the libAliHLTHOMER.so library will generate segfaults
1547 // since the executable code has been unloaded.
1548 // We need to check if there are any more libraries loaded after the class we
1549 // are unloading and in that case don't unload the class.
1550 TString libstring = gSystem->GetLibraries();
1551 TString token, lastlib;
1552 Ssiz_t from = 0;
1553 Int_t numOfLibs = 0, posOfLib = -1;
1554 while (libstring.Tokenize(token, from, " "))
1555 {
1556 ++numOfLibs;
1557 lastlib = token;
1558 if (token.Contains(libname)) posOfLib = numOfLibs;
1559 }
1560 if (numOfLibs != posOfLib)
1561 {
1562 HLTWarning(Form("ROOT limitation! Cannot properly cleanup and unload the shared"
1563 " library '%s' since another library '%s' was loaded afterwards. Trying to"
1564 " unload this library will remove the others and lead to serious memory faults.",
1565 libname.Data(), lastlib.Data()
1566 ));
1567 return 0;
1568 }
1569
81d62bb4 1570 char* path = NULL;
1571 int result = 0;
1572 if ((path = gSystem->DynamicPathName(libname)) != NULL)
1573 {
1574 result = gInterpreter->UnloadFile(path);
1575 delete [] path;
1576 }
1577 if (result != TInterpreter::kNoError) return -ENOENT;
1578 }
1579 else
1580 {
1b820a65 1581 // This is again a workaround for the problem with unloading files in ROOT.
1582 // If the trigger logic class is loaded before the libAliHLTHOMER.so library
1583 // or any other library is loaded afterwards, then during the gInterpreter->UnloadFile
1584 // call all the subsequent libraries get unloded.
1585 // We need to check if the list of loaded libraries has changed since the last
1586 // call to LoadTriggerClass. If it has then don't unload the class.
1587 if (fLibStateAtLoad != gSystem->GetLibraries())
1588 {
1589 TString libstring = gSystem->GetLibraries();
1590 TString token;
1591 Ssiz_t from = 0;
1592 while (libstring.Tokenize(token, from, " "))
1593 {
1594 if (not fLibStateAtLoad.Contains(token)) break;
1595 }
1596 HLTWarning(Form("ROOT limitation! Cannot properly cleanup and unload the file"
1597 " '%s' since another library '%s' was loaded afterwards. Trying to unload"
1598 " this file will remove the other library and lead to serious memory faults.",
1599 filename, token.Data()
1600 ));
1601 return 0;
1602 }
1603
1604 // If we did not compile the trigger logic then remove the interpreted class.
81d62bb4 1605 TString cmd = ".U ";
1606 cmd += filename;
1607 Int_t errorcode = TInterpreter::kNoError;
1608 gROOT->ProcessLine(cmd, &errorcode);
1609 if (errorcode != TInterpreter::kNoError)
1610 {
1611 HLTFatal("Could not unload interpreted global trigger menu implementation"
1612 " (Interpreter error code = %d).",
1613 errorcode
1614 );
1615 return -ENOENT;
1616 }
1617 }
1618
1619 return 0;
1620}
1621
1622
52f67e50 1623int AliHLTGlobalTriggerComponent::FindSymbol(const char* name, const TClonesArray& list)
1624{
1625 // Searches for the named symbol in the given list.
1626 // See header for more details.
1627
1628 for (int i = 0; i < list.GetEntriesFast(); i++)
1629 {
1630 const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(i) );
1631 if (symbol == NULL) continue;
1632 if (strcmp(symbol->Name(), name) == 0) return i;
1633 }
1634 return -1;
1635}
1636
1637
1788d826 1638namespace
1639{
1640 /**
1641 * Helper routine to compare two trigger menu symbols to see if b is a subset of a.
1642 * \returns true if b is a subset of a or they are unrelated.
1643 */
1644 bool AliHLTCheckForContainment(const AliHLTTriggerMenuSymbol* a, const AliHLTTriggerMenuSymbol* b)
1645 {
1646 TString bstr = b->Name();
1647 return bstr.Contains(a->Name());
1648 }
1649
1650} // end of namespace
1651
1652
52f67e50 1653int AliHLTGlobalTriggerComponent::BuildSymbolList(const AliHLTTriggerMenu* menu, TClonesArray& list)
1654{
1655 // Builds the list of symbols to use in the custom global trigger menu
1656 // implementation class.
1657 // See header for more details.
1658
025443e0 1659 // Note: when we build the symbol list we must use the symbol name as returned
1660 // by the Name() method and not the RealName() method when using FindSymbol.
1661 // This is so that we avoid problems with the generated code not compiling
1662 // because names like "abc-xyz" and "abc_xyz" are synonymous.
1663 // Name() returns the converted C++ symbol name as used in the generated code.
1664
52f67e50 1665 for (UInt_t i = 0; i < menu->NumberOfSymbols(); i++)
1666 {
1667 const AliHLTTriggerMenuSymbol* symbol = menu->Symbol(i);
1668 if (FindSymbol(symbol->Name(), list) != -1)
1669 {
1670 HLTError("Multiple symbols with the name '%s' defined in the trigger menu.", symbol->Name());
1671 return -EIO;
1672 }
dda123c3 1673 try
1674 {
1675 new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(*symbol);
1676 }
1677 catch (const std::bad_alloc&)
1678 {
1679 HLTError("Could not allocate more memory for the symbols list when adding a trigger menu symbol.");
1680 return -ENOMEM;
1681 }
52f67e50 1682 }
1788d826 1683 Int_t initialEntryCount = list.GetEntriesFast();
52f67e50 1684
1788d826 1685 // Note: the \\. must not be the first element in the character class, otherwise
1686 // it is interpreted as an "any character" dot symbol.
1687 TRegexp exp("[_a-zA-Z][-\\._a-zA-Z0-9]*");
52f67e50 1688 for (UInt_t i = 0; i < menu->NumberOfItems(); i++)
1689 {
1690 const AliHLTTriggerMenuItem* item = menu->Item(i);
81d62bb4 1691 TString str = item->TriggerCondition();
52f67e50 1692 Ssiz_t start = 0;
1693 do
1694 {
1695 Ssiz_t length = 0;
1696 Ssiz_t pos = exp.Index(str, &length, start);
1697 if (pos == kNPOS) break;
52f67e50 1698 start = pos+length;
1699
3da1c6d7 1700 // Check if there is a numerical character before the found
1701 // regular expression. If so, then the symbol is not a valid one
1702 // and should be skipped.
1703 if (pos > 0)
1704 {
1705 bool notValid = false;
1706 switch (str[pos-1])
1707 {
1708 case '0': case '1': case '2': case '3': case '4':
1709 case '5': case '6': case '7': case '8': case '9':
1710 notValid = true;
1711 break;
1712 default:
1713 notValid = false;
1714 break;
1715 }
1716 if (notValid) continue;
1717 }
1718 TString s = str(pos, length);
1719
52f67e50 1720 if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
1721 s == "compl" or s == "not" or s == "not_eq" or s == "or" or
1722 s == "or_eq" or s == "xor" or s == "xor_eq" or s == "true" or
1723 s == "false"
1724 )
1725 {
1726 // Ignore iso646.h and other keywords.
1727 continue;
1728 }
1788d826 1729
1730 // We need to handle the special case where the symbol contains a dot.
1731 // In C++ this is a dereferencing operator. So we need to check if the
1732 // current symbol we are handling starts with the same string as any of
1733 // the existing symbols defined manually in the symbols table.
1734 // If we do find such a case then revert to treating the dot as an operator
1735 // rather than part of the symbol name. i.e. skip adding the automatic symbol.
1736 bool dereferencedSymbol = false;
1737 for (int j = 0; j < initialEntryCount; j++)
1738 {
1739 const AliHLTTriggerMenuSymbol* symbol = dynamic_cast<const AliHLTTriggerMenuSymbol*>( list.UncheckedAt(j) );
1740 if (symbol == NULL) continue;
1741 TString symstr = symbol->Name();
1742 symstr += ".";
1743 if (s.BeginsWith(symstr))
1744 {
1745 dereferencedSymbol = true;
1746 break;
1747 }
1748 }
1749 if (dereferencedSymbol) continue;
3da1c6d7 1750
025443e0 1751 // Need to create the symbols first and check if its name is in the list
1752 // before actually adding it to the symbols list.
1753 AliHLTTriggerMenuSymbol newSymbol;
1754 newSymbol.Name(s.Data());
1755 newSymbol.Type("bool");
1756 newSymbol.ObjectClass("AliHLTTriggerDecision");
1757 newSymbol.AssignExpression("this->Result()");
1758 newSymbol.DefaultValue("false");
1759 if (FindSymbol(newSymbol.Name(), list) == -1)
52f67e50 1760 {
dda123c3 1761 try
1762 {
1763 new (list[list.GetEntriesFast()]) AliHLTTriggerMenuSymbol(newSymbol);
1764 }
1765 catch (const std::bad_alloc&)
1766 {
1767 HLTError("Could not allocate more memory for the symbols list when adding a trigger name symbol.");
1768 return -ENOMEM;
1769 }
52f67e50 1770 }
1771 }
1772 while (start < str.Length());
1773 }
1774
1788d826 1775 // This last part is necessary to make sure that symbols are replaced in the
1776 // trigger condition and domain merging expressions in a greedy manner.
1777 // I.e. we need to make sure that if one symbol's string representation is
1778 // contained inside another (string subset) that the longer symbol name is
1779 // always first in the symbols list.
1780 // This will work because the symbol table is traversed from first to last
1781 // element and TString::ReplaceAll is used to replace the substrings inside
1782 // the AliHLTGlobalTriggerComponent::GenerateTrigger method.
1783 std::vector<AliHLTTriggerMenuSymbol*> orderedList;
1784 for (Int_t i = 0; i < list.GetEntriesFast(); i++)
1785 {
1786 orderedList.push_back( static_cast<AliHLTTriggerMenuSymbol*>(list.UncheckedAt(i)) );
1787 }
1788 std::sort(orderedList.begin(), orderedList.end(), AliHLTCheckForContainment);
1789 //std::sort(orderedList.begin(), orderedList.end());
1790 // Now swap values around according to the orderedList.
1791 for (Int_t i = 0; i < list.GetEntriesFast(); i++)
1792 {
1793 AliHLTTriggerMenuSymbol* target = static_cast<AliHLTTriggerMenuSymbol*>(list.UncheckedAt(i));
1794 AliHLTTriggerMenuSymbol tmp = *target;
1795 *target = *orderedList[i];
1796 *orderedList[i] = tmp;
1797 }
1798
e2bb8ddd 1799 return 0;
1800}
1801
81d62bb4 1802
1803bool AliHLTGlobalTriggerComponent::ExtractedOperator(TString& expr, TString& op)
1804{
1805 // Extracts the trailing operator from the expression.
1806
1807 Ssiz_t i = 0;
1808 // First skip the trailing whitespace.
1809 bool whitespace = true;
1810 for (i = expr.Length()-1; i >= 0 and whitespace; i--)
1811 {
1812 switch (expr[i])
1813 {
1814 case ' ': case '\t': case '\r': case '\n':
1815 whitespace = true;
1816 break;
1817 default:
1818 whitespace = false;
1819 }
1820 }
1821 if (i < 0 or whitespace) return false;
1822
1823 // Now find the first whitespace character before the trailing symbol.
1824 bool nonwhitespace = true;
1825 for (; i >= 0 and nonwhitespace; i--)
1826 {
1827 switch (expr[i])
1828 {
1829 case ' ': case '\t': case '\r': case '\n':
1830 nonwhitespace = false;
1831 break;
1832 default:
1833 nonwhitespace = true;
1834 }
1835 }
1836 if (i < 0 or nonwhitespace) return false;
1837
1838 // Extract the last symbols and check if it is a valid operator.
1839 TString s = expr;
1840 s.Remove(0, i+2);
1841 if (s == "and" or s == "and_eq" or s == "bitand" or s == "bitor" or
1842 s == "compl" or s == "not" or s == "not_eq" or s == "or" or
1843 s == "or_eq" or s == "xor" or s == "xor_eq" or s == "&&" or
1844 s == "&=" or s == "&" or s == "|" or s == "~" or s == "!" or
1845 s == "!=" or s == "||" or s == "|=" or s == "^" or s == "^=" or
1846 s == "==" or s == "+" or s == "-" or s == "*" or s == "/" or
1847 s == "%" or s == ">" or s == "<" or s == ">=" or s == "<="
1848 )
1849 {
1850 expr.Remove(i+1);
1851 op = s;
1852 return true;
1853 }
1854
1855 return false;
1856}
1857
1858
9e14734f 1859bool AliHLTGlobalTriggerComponent::FillSoftwareTrigger()
1860{
1861 // Fills the fSoftwareTrigger structure.
16517abe 1862
16e6f752 1863 UChar_t l1msg = fCDH.GetL1TriggerMessage();
9e14734f 1864 if ((l1msg & 0x1) == 0x0) return false; // skip physics events.
1865 // From here on everything must be a software trigger.
1866 if (((l1msg >> 2) & 0xF) == 0xE)
1867 {
1868 fSoftwareTrigger.Name("START_OF_DATA");
1869 fSoftwareTrigger.Description("Generated internal start of data trigger.");
1870 }
1871 else if (((l1msg >> 2) & 0xF) == 0xF)
1872 {
1873 fSoftwareTrigger.Name("END_OF_DATA");
1874 fSoftwareTrigger.Description("Generated internal end of data trigger.");
1875 }
1876 else if (((l1msg >> 6) & 0x1) == 0x1)
1877 {
1878 fSoftwareTrigger.Name("CALIBRATION");
1879 fSoftwareTrigger.Description("Generated internal calibration trigger.");
1880 }
1881 else
1882 {
1883 fSoftwareTrigger.Name("SOFTWARE");
1884 fSoftwareTrigger.Description("Generated internal software trigger.");
1885 }
16e6f752 1886 UInt_t detectors = fCDH.GetSubDetectors();
9e14734f 1887 fSoftwareTrigger.ReadoutList( AliHLTReadoutList(Int_t(detectors)) );
1888 return true;
1889}
1890
1891
2974f8dc 1892int AliHLTGlobalTriggerComponent::PrintStatistics(const AliHLTGlobalTrigger* pTrigger, AliHLTComponentLogSeverity level, int offset) const
1893{
1894 // print some statistics
228a8993 1895 int totalEvents=fTotalEventCounter+offset;
325e5e42 1896 const TArrayL64& counters = pTrigger->GetCounters();
1897 if (pTrigger->CallFailed()) return -EPROTO;
1898 for (int i = 0; i < counters.GetSize(); i++) {
1899 ULong64_t count = counters[i];
8b29f84f 1900 float ratio=0;
1901 if (totalEvents>0) ratio=100*(float)count/totalEvents;
7923396e 1902 HLTLog(level, "Item %d: total events: %d - counted events: %llu (%.1f%%)", i, totalEvents, count, ratio);
2974f8dc 1903 }
2974f8dc 1904 return 0;
1905}
566a01d0 1906
1907int AliHLTGlobalTriggerComponent::AddCTPDecisions(AliHLTGlobalTrigger* pTrigger, const AliHLTCTPData* pCTPData, const AliHLTComponentTriggerData* trigData)
1908{
1909 // add trigger decisions for the valid CTP classes
1910 if (!pCTPData || !pTrigger) return 0;
1911
16e6f752 1912 AliHLTTriggerMask_t triggerMask=pCTPData->Mask();
1913 AliHLTTriggerMask_t bit0(0x1);
566a01d0 1914 if (!fCTPDecisions) {
dda123c3 1915 try
1916 {
1917 fCTPDecisions=new TClonesArray(AliHLTTriggerDecision::Class(), gkNCTPTriggerClasses);
1918 }
1919 catch (const std::bad_alloc&)
1920 {
1921 HLTError("Could not allocate memory for the CTP decisions array.");
1922 return -ENOMEM;
1923 }
566a01d0 1924 if (!fCTPDecisions) return -ENOMEM;
1925
dda123c3 1926 try
1927 {
1928 fCTPDecisions->ExpandCreate(gkNCTPTriggerClasses);
1929 }
1930 catch (const std::bad_alloc&)
1931 {
1932 HLTError("Could not allocate more memory for the CTP decisions array.");
1933 return -ENOMEM;
1934 }
566a01d0 1935 for (int i=0; i<gkNCTPTriggerClasses; i++) {
1936 const char* name=pCTPData->Name(i);
16e6f752 1937 if ( (triggerMask&(bit0<<i)).any() && name) {
566a01d0 1938 AliHLTTriggerDecision* pDecision=dynamic_cast<AliHLTTriggerDecision*>(fCTPDecisions->At(i));
1939 assert(pDecision);
1940 if (!pDecision) {
1941 delete fCTPDecisions;
1942 fCTPDecisions=NULL;
1943 return -ENOENT;
1944 }
1945 pDecision->Name(name);
1946 }
1947 }
1948 }
1949
1950 for (int i=0; i<gkNCTPTriggerClasses; i++) {
1951 const char* name=pCTPData->Name(i);
16e6f752 1952 if ((triggerMask&(bit0<<i)).none() || name==NULL) continue;
566a01d0 1953 AliHLTTriggerDecision* pDecision=dynamic_cast<AliHLTTriggerDecision*>(fCTPDecisions->At(i));
1954 HLTDebug("updating CTP trigger decision %d %s (%p casted %p)", i, name, fCTPDecisions->At(i), pDecision);
1955 if (!pDecision) return -ENOENT;
1956
1957 bool result=false;
2f251ae6 1958 // 13 March 2010 - Optimisation:
1959 // Dont use the EvaluateCTPTriggerClass method, which uses slow TFormula objects.
16e6f752 1960 AliHLTTriggerMask_t triggers = 0;
2f251ae6 1961 if (trigData) triggers = pCTPData->ActiveTriggers(*trigData);
1962 else triggers = pCTPData->Triggers();
16e6f752 1963 result = (triggers&(bit0<<i)).any() ? true : false;
2f251ae6 1964 //if (trigData) result=pCTPData->EvaluateCTPTriggerClass(name, *trigData);
1965 //else result=pCTPData->EvaluateCTPTriggerClass(name);
566a01d0 1966 pDecision->Result(result);
1967 pDecision->TriggerDomain().Clear();
1968 if (trigData) pDecision->TriggerDomain().Add(pCTPData->ReadoutList(*trigData));
1969 else pDecision->TriggerDomain().Add(pCTPData->ReadoutList());
1970
1971 pTrigger->Add(fCTPDecisions->At(i), kAliHLTDataTypeTriggerDecision, kAliHLTVoidDataSpec);
325e5e42 1972 if (pTrigger->CallFailed()) return -EPROTO;
566a01d0 1973 }
1974
1975 return 0;
1976}