3 //**************************************************************************
4 //* This file is property of and copyright by the ALICE HLT Project *
5 //* ALICE Experiment at CERN, All rights reserved. *
7 //* Primary Authors: Timur Pocheptsov <Timur.Pocheptsov@cern.ch> *
8 //* Matthias Richter <Matthias.Richter@cern.ch>
9 //* for The ALICE HLT Project. *
11 //* Permission to use, copy, modify and distribute this software and its *
12 //* documentation strictly for non-commercial purposes is hereby granted *
13 //* without fee, provided that the above copyright notice appears in all *
14 //* copies and that both the copyright notice and this permission notice *
15 //* appear in the supporting documentation. The authors make no claims *
16 //* about the suitability of this software for any purpose. It is *
17 //* provided "as is" without express or implied warranty. *
18 //**************************************************************************
20 /// @file AliHLTTTreeProcessor.cxx
21 /// @author Timur Pocheptsov, Matthias Richter
23 /// @brief Generic component for data collection in a TTree
28 #include "AliHLTTTreeProcessor.h"
29 #include "TDirectory.h"
34 #include "TStopwatch.h"
36 /** ROOT macro for the implementation of ROOT specific class methods */
37 ClassImp(AliHLTTTreeProcessor)
39 AliHLTTTreeProcessor::AliHLTTTreeProcessor()
43 fMaxEntries(kMaxEntries),
44 fPublishInterval(kInterval),
50 fForcedEventsCount(0),
51 fSkippedEventsCount(0),
54 // see header file for class documentation
56 // refer to README to build package
58 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
61 const AliHLTUInt32_t AliHLTTTreeProcessor::fgkTimeScale=1000000; // ticks per second
63 AliHLTTTreeProcessor::~AliHLTTTreeProcessor()
65 // see header file for class documentation
68 AliHLTComponentDataType AliHLTTTreeProcessor::GetOutputDataType()
70 // get the component output data type
71 return kAliHLTDataTypeHistogram;
74 void AliHLTTTreeProcessor::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
76 // get the output size estimator
78 if (!fDefinitions.size()) {
79 HLTError("Can not calculate output data size, no histogram definitions were provided");
84 for (list_const_iterator i = fDefinitions.begin(); i != fDefinitions.end(); ++i)
85 constBase += i->GetSize();
90 int AliHLTTTreeProcessor::DoInit(int argc, const char** argv)
93 // ask child to create the tree.
97 std::auto_ptr<TTree> ptr(CreateTree(argc, argv));
99 //Stage 1: default initialization.
100 ptr->SetDirectory(0);
101 //"Default" (for derived component) histograms.
102 FillHistogramDefinitions();
104 fMaxEntries = kMaxEntries;
105 fPublishInterval = kInterval;
108 TString cdbPath("HLT/ConfigHLT/");
109 cdbPath += GetComponentID();
111 iResult = ConfigureFromCDBTObjString(cdbPath);
115 //Stage 3: command line arguments.
116 if (argc && (iResult = ConfigureFromArgumentString(argc, argv)) < 0)
119 ptr->SetCircular(fMaxEntries);
120 fTree = ptr.release();
121 } else //No way to process error correctly - error is unknown here.
124 HLTError("fTree pointer must be null before DoInit call");
128 if (iResult>=0 && fMaxEventTime>0) {
129 fpEventTimer=new TStopwatch;
131 fpEventTimer->Reset();
133 fpCycleTimer=new TStopwatch;
135 fpCycleTimer->Reset();
138 fSkippedEventsCount=0;
143 int AliHLTTTreeProcessor::DoDeinit()
148 fDefinitions.clear();
150 if (fpEventTimer) delete fpEventTimer;
152 if (fpCycleTimer) delete fpCycleTimer;
158 int AliHLTTTreeProcessor::DoEvent(const AliHLTComponentEventData& evtData, AliHLTComponentTriggerData& trigData)
160 //Process event and publish histograms.
161 AliHLTUInt32_t eventType=0;
162 if (!IsDataEvent(&eventType) && eventType!=gkAliEventTypeEndOfRun) return 0;
164 //I'm pretty sure, that if fTree == 0 (DoInit failed) DoEvent is not called.
165 //But interface itself does not force you to call DoInit before DoEvent, so,
166 //I make this check explicit.
168 HLTError("fTree is a null pointer, try to call AliHLTTTreeProcessor::DoInit first.");
169 return -EINVAL;//-ENULLTREE? :)
172 AliHLTUInt32_t averageEventTime=0;
173 AliHLTUInt32_t averageCycleTime=0;
177 bool bDoFilling=true;
178 bool bDoPublishing=false;
179 const int cycleResetInterval=1000;
180 if (fpEventTimer && fpCycleTimer) {
181 averageEventTime=(fpEventTimer->RealTime()*fgkTimeScale)/(GetEventCount()+1);
182 fillingtime=fpEventTimer->RealTime()*fgkTimeScale;
183 publishtime=fillingtime;
184 fpEventTimer->Start(kFALSE);
185 fpCycleTimer->Stop();
186 averageCycleTime=(fpCycleTimer->RealTime()*fgkTimeScale)/((GetEventCount()%cycleResetInterval)+1);
187 // adapt processing to 3/4 of the max time
188 bDoFilling=4*averageEventTime<3*fMaxEventTime || averageEventTime<averageCycleTime;
189 if (fNofEventsForce>0 && fForcedEventsCount<fNofEventsForce) {
190 fForcedEventsCount++;
195 // process input data blocks and fill the tree
197 if (eventType!=gkAliEventTypeEndOfRun) {
198 if (bDoFilling) {iResult=FillTree(fTree, evtData, trigData); fNewEventsCount++;}
199 else fSkippedEventsCount++;
202 fpEventTimer->Stop();
203 fillingtime=fpEventTimer->RealTime()*fgkTimeScale-fillingtime;
204 fpEventTimer->Start(kFALSE);
212 if (( time.Get() - fLastTime > fPublishInterval && fNewEventsCount>0) ||
213 eventType==gkAliEventTypeEndOfRun) {
215 for (list_const_iterator i = fDefinitions.begin(); i != fDefinitions.end(); ++i) {
216 if (TH1* h = CreateHistogram(*i)) {
217 //I do not care about errors here - since I'm not able
218 //to rollback changes.
219 // TODO: in case of -ENOSPC et the size of the last object by calling
220 // GetLastObjectSize() and accumulate the necessary output buffer size
221 PushBack(h, GetOriginDataType(), GetDataSpec());
224 unsigned eventcount=GetEventCount()+1;
225 HLTBenchmark("publishing %d histograms, %d entries in tree, %d new events since last publishing, accumulated %d of %d events (%.1f%%)", fDefinitions.size(), fTree->GetEntriesFast(), fNewEventsCount, eventcount-fSkippedEventsCount, eventcount, eventcount>0?(100*float(eventcount-fSkippedEventsCount)/eventcount):0);
228 fLastTime = time.Get();
232 fpEventTimer->Stop();
233 publishtime=fpEventTimer->RealTime()*fgkTimeScale-publishtime;
234 if (publishtime>fillingtime) publishtime-=fillingtime;
237 averageEventTime=(fpEventTimer->RealTime()*fgkTimeScale)/(GetEventCount()+1);
239 // info output once every 5 seconds
240 static UInt_t lastTime=0;
241 if (time.Get()-lastTime>5 ||
242 eventType==gkAliEventTypeEndOfRun ||
245 unsigned eventcount=GetEventCount()+1;
246 HLTBenchmark("filling time %d us, publishing time %d, average total processing time %d us, cycle time %d us, accumulated %d of %d events (%.1f%%)", fillingtime, publishtime, averageEventTime, averageCycleTime, eventcount-fSkippedEventsCount, eventcount, eventcount>0?(100*float(eventcount-fSkippedEventsCount)/eventcount):0);
250 bool bReset=(GetEventCount()%cycleResetInterval)==0;
251 fpCycleTimer->Start(bReset);
257 int AliHLTTTreeProcessor::ScanConfigurationArgument(int argc, const char** argv)
259 // scan one argument and its parameters from the list
260 // return number of processed entries.
261 // possible arguments:
262 // -maxentries number
264 // -histogram name -size number -expression expression [-cut expression ][-opt option]
265 // As soon as "-histogram" found, -size and -expression and -outtype are required,
266 // cut and option can be omitted.
270 std::list<AliHLTHistogramDefinition> newDefs;
271 AliHLTHistogramDefinition def;
277 const TString argument(argv[i]);
279 if (argument.CompareTo("-maxentries") == 0) { //1. Max entries argument for TTree.
281 HLTError("Numeric value for '-maxentries' is expected");
284 //Next must be a number.
285 //TString returns 0 (number) even if string contains non-numeric symbols.
286 maxEntries = TString(argv[i + 1]).Atoi();
287 if (maxEntries <= 0) {
288 HLTError("Bad value for '-maxentries': %d", maxEntries);
293 } else if (argument.CompareTo("-interval") == 0) { //2. Interval argument for publishing.
295 HLTError("Numeric value for '-interval' is expected");
299 const Int_t interval = TString(argv[i + 1]).Atoi();
301 HLTError("Bad value for '-interval' argument: %d", interval);
305 fPublishInterval = interval;
308 } else if (argument.CompareTo("-maxeventtime") == 0) { // max average processing time in us
310 HLTError("Numeric value for '-maxeventtime' is expected");
314 const Int_t time = TString(argv[i + 1]).Atoi();
316 HLTError("Bad value for '-maxeventtime' argument: %d", time);
320 fMaxEventTime = time;
323 } else if (argument.CompareTo("-forced-events") == 0) { // number of forced events
325 HLTError("Numeric value for '-forced-events' is expected");
329 const Int_t count = TString(argv[i + 1]).Atoi();
331 HLTError("Bad value for '-forced-events' argument: %d", count);
335 fNofEventsForce = count;
336 fForcedEventsCount=0;
339 } else if (argument.CompareTo("-histogram") == 0) { //3. Histogramm definition.
340 const int nParsed = ParseHistogramDefinition(argc, argv, i, def);
344 newDefs.push_back(def);
348 HLTError("Unknown argument %s", argument.Data());
353 if (maxEntries != fMaxEntries) {
354 fMaxEntries = maxEntries;
357 fTree->SetCircular(fMaxEntries);
362 fDefinitions.swap(newDefs);
367 TH1* AliHLTTTreeProcessor::CreateHistogram(const AliHLTHistogramDefinition& d)
370 // create a histogram from the tree
372 HLTError("fTree is a null pointer, try to call AliHLTTTreeProcessor::DoInit first.");
376 TString histName(d.GetName());
377 if (!histName.Contains("(")) {
378 //Without number of bins, the histogram will be "fixed"
379 //and most of values can go to underflow/overflow bins,
380 //since kCanRebin will be false.
381 histName += TString::Format("(%d)", Int_t(kDefaultNBins));
384 const Long64_t rez = fTree->Project(histName.Data(), d.GetExpression().Data(), d.GetCut().Data(), d.GetDrawOption().Data());
387 HLTError("TTree::Project failed");
391 //Now, cut off the binning part of a name
392 histName = histName(0, histName.Index("("));
393 TH1 * hist = dynamic_cast<TH1*>(gDirectory->Get(histName.Data()));
395 const TString msg(Form("Hist %s is a null pointer, selection was %s, strange name or hist's type\n", histName.Data(), d.GetExpression().Data()));
396 HLTError(msg.Data());
397 }else if (d.GetDrawOption().Length()) {
398 hist->SetOption(d.GetDrawOption().Data());
404 int AliHLTTTreeProcessor::ParseHistogramDefinition(int argc, const char** argv, int pos, AliHLTHistogramDefinition& dst)const
406 //Histogram-definition:
407 // -histogram name -size number -expression expression [-cut expression][-opt option]
409 //at pos we have '-histogram', at pos + 1 must be the name.
410 if (pos + 1 == argc) {
411 HLTError("Bad histogram definition, histogram name is expected");
415 dst.SetName(argv[pos + 1]);
418 //At pos must be '-size', and number at pos + 1.
419 if (pos == argc || TString(argv[pos]).CompareTo("-size")) {
420 HLTError("Bad histogram definition, '-size' is expected");
424 if (pos + 1 == argc) {
425 HLTError("Bad histogram definition, size is expected");
429 dst.SetSize(TString(argv[pos + 1]).Atoi());
430 if (dst.GetSize() <= 0) {
431 HLTError("Bad histogram definition, positive size is required");
436 //At pos must be '-expression', and expression at pos + 1.
437 if (pos == argc || TString(argv[pos]).CompareTo("-expression")) {
438 HLTError("Bad histogram definition, '-expression' is expected");
442 if (pos + 1 == argc) {
443 HLTError("Bad histogram definition, expression is expected");
447 dst.SetExpression(argv[pos + 1]);
452 dst.SetDrawOption("");
454 //remaining options can be the cut and Draw option.
459 if (TString(argv[pos]).CompareTo("-cut") == 0) {
460 dst.SetCut(argv[pos + 1]);
468 if (TString(argv[pos]).CompareTo("-opt") == 0) {
469 dst.SetDrawOption(argv[pos + 1]);