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