ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/MitAna/TreeMod/src/OutputMod.cc
Revision: 1.15
Committed: Fri Jul 17 20:47:43 2009 UTC (15 years, 9 months ago) by loizides
Content type: text/plain
Branch: MAIN
CVS Tags: Mit_011a, Mit_011, Mit_010a, Mit_010
Changes since 1.14: +16 -12 lines
Log Message:
Added support for arbitrary collections.

File Contents

# Content
1 // $Id: OutputMod.cc,v 1.14 2009/07/17 19:18:34 loizides Exp $
2
3 #include "MitAna/TreeMod/interface/OutputMod.h"
4 #include "MitAna/TreeMod/interface/HLTFwkMod.h"
5 #include "MitAna/DataUtil/interface/Debug.h"
6 #include "MitAna/DataTree/interface/BranchTable.h"
7 #include "MitAna/DataTree/interface/EventHeaderCol.h"
8 #include "MitAna/DataTree/interface/Names.h"
9 #include "MitAna/DataUtil/interface/TreeWriter.h"
10 #include "MitAna/TreeMod/interface/TreeBranchLoader.h"
11
12 using namespace mithep;
13 using namespace std;
14
15 ClassImp(mithep::OutputMod)
16
17 //--------------------------------------------------------------------------------------------------
18 OutputMod::OutputMod(const char *name, const char *title) :
19 BaseMod(name,title),
20 fTreeName(Names::gkEvtTreeName),
21 fPrefix("skimtest"),
22 fPathName("."),
23 fMaxSize(1024),
24 fCompLevel(9),
25 fSplitLevel(99),
26 fBranchSize(16*1024),
27 fDoReset(kFALSE),
28 fCheckBrDep(kTRUE),
29 fUseBrDep(kTRUE),
30 fCheckTamBr(kTRUE),
31 fKeepTamBr(kFALSE),
32 fTreeWriter(0),
33 fEventHeader(0),
34 fAllEventHeader(0),
35 fRunInfo(0),
36 fLaHeader(0),
37 fBranchTable(0),
38 fBranches(0),
39 fNBranchesMax(1024),
40 fRunTree(0),
41 fLATree(0),
42 fAllTree(0),
43 fSkimmedIn(0),
44 fHltTree(0),
45 fHLTTab(new vector<string>),
46 fHLTLab(new vector<string>),
47 fRunEntries(0),
48 fHltEntries(0),
49 fFileNum(-1),
50 fLastWrittenEvt(-1),
51 fLastSeenEvt(-1),
52 fCounter(0)
53 {
54 // Constructor.
55 }
56
57 //--------------------------------------------------------------------------------------------------
58 void OutputMod::BeginRun()
59 {
60 // Create HLT tree if HLTFwkMod is being run.
61
62 if (!HasHLTInfo())
63 return;
64
65 if (!fHltTree) {
66 HLTFwkMod *hm = const_cast<HLTFwkMod*>(GetHltFwkMod());
67 fTreeWriter->AddBranchToTree(hm->HLTTreeName(), hm->HLTTabName(),
68 TClass::GetClass(typeid(*fHLTTab))->GetName(),
69 &fHLTTab, 32000, 0);
70 fTreeWriter->AddBranchToTree(hm->HLTTreeName(), hm->HLTLabName(),
71 TClass::GetClass(typeid(*fHLTLab))->GetName(),
72 &fHLTLab, 32000, 0);
73 fTreeWriter->SetAutoFill(hm->HLTTreeName(), 0);
74 fHltTree = fTreeWriter->GetTree(hm->HLTTreeName());
75 }
76 }
77
78 //--------------------------------------------------------------------------------------------------
79 void OutputMod::CheckAndAddBranch(const char *bname, const char *cname)
80 {
81 // Check if the given branch should be kept or dropped.
82
83 if (IsAcceptedBranch(bname))
84 return;
85
86 // populate regular expression list if this was not yet done
87 if (fCmdReList.size() != fCmdList.size()) {
88 for (UInt_t i=0; i<fCmdList.size(); ++i) {
89 const char *ptr = fCmdList.at(i).c_str();
90 fCmdReList.push_back(TRegexp(ptr+5,kTRUE));
91 if (ptr[0]=='k')
92 fCmdDeList.push_back(kTRUE);
93 else
94 fCmdDeList.push_back(kFALSE);
95 }
96 }
97
98 // decide whether given branch name should be kept or dropped
99 TString brname(bname);
100 Bool_t decision = kFALSE;
101 Bool_t decision_found = kFALSE;
102
103 for (UInt_t i=0; i<fCmdList.size(); ++i) {
104 TRegexp &re(fCmdReList.at(i));
105 if (brname.Index(re) == kNPOS)
106 continue;
107 decision = fCmdDeList.at(i);
108 decision_found = kTRUE;
109 }
110
111 if (!decision_found) { // no decision found: still drop branch
112 Warning("CheckAndAddBranch",
113 "No decision found for branch '%s' and class '%s'. Branch therefore dropped!",
114 bname, cname);
115 return;
116 }
117
118 if (!decision) { // drop branch according to request
119 Info("CheckAndAddBranch",
120 "Dropped branch '%s' and class '%s'", bname, cname);
121 return;
122 }
123
124 // add branch to accepted branch list
125 Info("CheckAndAddBranch",
126 "Kept branch '%s' and class '%s'", bname, cname);
127
128 fBrNameList.push_back(string(bname));
129 fBrClassList.push_back(string(cname));
130 }
131
132 //--------------------------------------------------------------------------------------------------
133 Bool_t OutputMod::CheckAndResolveBranchDep()
134 {
135 // Checks dependency in BranchTable. Resolve dependency automatically if fUserBrDep is kTRUE.
136
137 TFile *cfile = const_cast<TFile*>(GetSel()->GetCurrentFile());
138 if (!cfile) {
139 SendError(kAbortAnalysis, "CheckAndResolveBranchDep", "Could not get pointer to current file!");
140 return kFALSE;
141 }
142
143 BranchTable *br = dynamic_cast<BranchTable*>(cfile->Get(Names::gkBranchTable));
144 if (!br) {
145 SendError(kAbortAnalysis, "CheckAndResolveBranchDep", "Could not get pointer to branch table!");
146 return kFALSE;
147 }
148
149 TList *blist = br->GetBranches();
150 if (!blist) {
151 SendError(kAbortAnalysis, "CheckAndResolveBranchDep", "Could not get list of branches!");
152 return kFALSE;
153 }
154
155 fBranchTable = new BranchTable;
156 fBranchTable->SetName(Names::gkBranchTable);
157 fBranchTable->SetOwner();
158
159 TList sht;
160 sht.SetOwner(kTRUE);
161 for (UInt_t i=0; i<fBrNameList.size(); ++i) {
162 sht.Add(new TObjString(fBrNameList.at(i).c_str()));
163 }
164
165 for (UInt_t i=0; i<fBrNameList.size(); ++i) {
166 TString brname(fBrNameList.at(i));
167 if (!blist->FindObject(brname))
168 continue;
169 TList *bdeps = br->GetDepBranches(brname);
170 if (!bdeps)
171 continue;
172
173 // check dependency
174 TIter iter(bdeps->MakeIterator());
175 const TObjString *n = dynamic_cast<const TObjString*>(iter.Next());
176 while (n) {
177 if (sht.FindObject(n->GetName())) {
178 // dependent branch is already accepted
179 fBranchTable->Add(new BranchName(brname,n->GetName()));
180 } else {
181 if (fUseBrDep) {
182 const TObjArray *arr = GetSel()->GetTree()->GetTree()->GetListOfBranches();
183 TBranch *br = dynamic_cast<TBranch*>(arr->FindObject(n->GetName()));
184 if (!br) {
185 Error("CheckAndResolveBranchDep",
186 "Could not get branch '%s' to resolve dependency for branch '%s'",
187 n->GetName(), brname.Data());
188 } else {
189 Info("CheckAndResolveBranchDep",
190 "Adding branch '%s' to resolve dependency for branch '%s'",
191 n->GetName(), brname.Data());
192 fBrNameList.push_back(string(n->GetName()));
193 fBrClassList.push_back(br->GetClassName());
194 sht.Add(new TObjString(n->GetName()));
195 fBranchTable->Add(new BranchName(brname,n->GetName()));
196 }
197 } else {
198 Warning("CheckAndResolveBranchDep",
199 "Unresolved dependency of branch '%s' and '%s' ",
200 n->GetName(), brname.Data());
201 }
202 }
203 n = dynamic_cast<const TObjString*>(iter.Next());
204 }
205 delete bdeps;
206 }
207 delete blist;
208 return kTRUE;
209 }
210
211 //--------------------------------------------------------------------------------------------------
212 void OutputMod::CheckAndResolveTAMDep(Bool_t solve)
213 {
214 // Check if TAM has loaded additional branches. If requested try to solve the the dependency
215 // by adding the branch to the list of branches.
216
217 const THashTable &ht = GetSel()->GetBranchTable();
218
219 TIter iter(ht.MakeIterator());
220 const TAMBranchInfo *next = dynamic_cast<const TAMBranchInfo*>(iter.Next());
221
222 while (next) {
223 const TAMBranchInfo *cur = next;
224 next = dynamic_cast<const TAMBranchInfo*>(iter.Next());
225 Bool_t isloaded = cur->IsLoaded();
226 if (!isloaded)
227 continue;
228
229 const char *bname = cur->GetName();
230 if (IsAcceptedBranch(bname))
231 continue;
232
233 TreeBranchLoader *loader = dynamic_cast<TreeBranchLoader*>(cur->GetLoader());
234 if (!loader)
235 continue;
236
237 TBranch *br = loader->GetBranch();
238 if (!br)
239 continue;
240
241 const char *cname = br->GetClassName();
242
243 if (solve) {
244 Info("CheckAndResolveTAMDep",
245 "Resolving dependency for loaded branch '%s' and class '%s'", bname,cname);
246
247 fBrNameList.push_back(string(bname));
248 fBrClassList.push_back(string(cname));
249 fBranches[GetNBranches()-1] = reinterpret_cast<TObject*>(loader->GetAddress());
250
251 } else {
252 Warning("CheckAndResolveTAMDep",
253 "Unresolved dependency for loaded branch '%s' and class '%s'",
254 bname,cname);
255 }
256 }
257 }
258
259 //--------------------------------------------------------------------------------------------------
260 void OutputMod::EndRun()
261 {
262 // Nothing to be done at this point.
263 }
264
265 //--------------------------------------------------------------------------------------------------
266 void OutputMod::FillAllEventHeader(Bool_t isremoved)
267 {
268 // Fill event header into the all-event-header tree.
269
270 if (!fTreeWriter->BeginEvent(kFALSE)) {
271 SendError(kAbortAnalysis, "FillAllEventHeader", "Begin event failed!");
272 return;
273 }
274
275 if (fSkimmedIn) { // copy alread skimmed headers if any there
276 for(UInt_t i=0; i<fSkimmedIn->Entries(); ++i) {
277 const EventHeader *eh = fSkimmedIn->At(i);
278 fAllEventHeader->SetEvtNum(eh->EvtNum());
279 fAllEventHeader->SetLumiSec(eh->LumiSec());
280 fAllEventHeader->SetRunNum(eh->RunNum());
281 fAllEventHeader->SetRunEntry(eh->RunEntry());
282 fAllEventHeader->SetSkimmed(eh->Skimmed()+1);
283 fAllTree->Fill();
284 }
285 }
286
287 const EventHeader *eh = GetEventHeader();
288 fAllEventHeader->SetEvtNum(eh->EvtNum());
289 fAllEventHeader->SetLumiSec(eh->LumiSec());
290 fAllEventHeader->SetRunNum(eh->RunNum());
291 if (isremoved) {
292 fAllEventHeader->SetRunEntry(-1);
293 fAllEventHeader->SetSkimmed(eh->Skimmed()+1);
294 } else {
295 fAllEventHeader->SetRunEntry(eh->RunEntry());
296 fAllEventHeader->SetSkimmed(eh->Skimmed());
297 }
298
299 fAllTree->Fill();
300 }
301
302 //--------------------------------------------------------------------------------------------------
303 void OutputMod::FillHltInfo()
304 {
305 // Write HLT trigger table if needed.
306
307 if (!fHltTree)
308 return;
309
310 HLTFwkMod *hm = const_cast<HLTFwkMod*>(GetHltFwkMod());
311 vector<string> *trigtable = hm->fHLTTab;
312 vector<string> *labels = hm->fHLTLab;
313
314 Bool_t doCopy = kFALSE;
315 if (fHLTTab->size()==0) {
316 doCopy = kTRUE;
317 } else {
318 // check if existing table contains all necessary paths:
319 // if so keep it, otherwise store the new one
320
321 if ((fHLTTab->size() != trigtable->size()) ||
322 (fHLTLab->size() != labels->size())) {
323 doCopy = kTRUE;
324 } else {
325 // need to check more thoroughly
326
327 for (UInt_t i=0; i<trigtable->size(); ++i) {
328 if (trigtable->at(i) != fHLTTab->at(i)) {
329 doCopy = kTRUE;
330 break;
331 }
332 }
333 if (!doCopy) {
334 for (UInt_t i=0; i<labels->size(); ++i) {
335 if (labels->at(i) != fHLTLab->at(i)) {
336 doCopy = kTRUE;
337 break;
338 }
339 }
340 }
341 }
342 }
343
344 if (!doCopy)
345 return;
346
347 fHLTTab->resize(trigtable->size());
348 copy(trigtable->begin(),trigtable->end(), fHLTTab->begin());
349 fHLTLab->resize(labels->size());
350 copy(labels->begin(),labels->end(), fHLTLab->begin());
351
352 ++fHltEntries;
353 fHltTree->Fill();
354 }
355
356 //--------------------------------------------------------------------------------------------------
357 Bool_t OutputMod::IsAcceptedBranch(const char *bname)
358 {
359 // Return true if given branch is already in branch list. Also return true if a special
360 // branch like the "EventHeader" branch is reqested.
361
362 // search in branch list
363 for (UInt_t i=0; i<GetNBranches(); ++i) {
364 if (fBrNameList.at(i).compare(bname) == 0)
365 return kTRUE;
366 }
367
368 // check if special branch that we take care of ourselves
369 string name(bname);
370 if (name.compare("EventHeader") == 0) {
371 return kTRUE;
372 }
373
374 return kFALSE;
375 }
376
377 //--------------------------------------------------------------------------------------------------
378 Bool_t OutputMod::Notify()
379 {
380 // On first notify, loop over list of branches to determine the list of kept branches.
381
382 if (GetNEventsProcessed() != 0)
383 return kTRUE;
384
385 const TTree *tree=GetSel()->GetTree();
386 if (!tree)
387 return kFALSE;
388
389 const TObjArray *arr = tree->GetTree()->GetListOfBranches();
390 if (!arr)
391 return kFALSE;
392
393 for (Int_t i=0; i<arr->GetEntries(); ++i) {
394 TBranch *br = dynamic_cast<TBranch*>(arr->At(i));
395 if (!br && !br->GetMother())
396 continue;
397 br = br->GetMother();
398 TClass *cls = TClass::GetClass(br->GetClassName());
399 if (!cls)
400 continue;
401
402 if (!cls->InheritsFrom("TObject")) {
403 Warning("Notify", "Found branch '%s' where class '%s' does not derive from TObject",
404 br->GetName(), br->GetClassName());
405 continue;
406 }
407
408 CheckAndAddBranch(br->GetName(), br->GetClassName());
409 }
410
411 if (fCheckBrDep && !CheckAndResolveBranchDep())
412 return kFALSE;
413
414 RequestBranches();
415 return kTRUE;
416 }
417
418 //--------------------------------------------------------------------------------------------------
419 void OutputMod::LoadBranches()
420 {
421 // Loop over requested branches and load them.
422
423 for (UInt_t i=0; i<GetNBranches(); ++i) {
424 LoadBranch(fBrNameList.at(i).c_str());
425 }
426 }
427
428 //--------------------------------------------------------------------------------------------------
429 void OutputMod::Process()
430 {
431 // Write out the kept branches of the current event. Make sure the meta information is
432 // correctly updated.
433
434 if (GetSel()->GetCurEvt() == fLastSeenEvt) {
435 Warning("Process", "Event with %ul already seen", fLastSeenEvt);
436 return;
437 }
438 fLastSeenEvt = GetSel()->GetCurEvt();
439
440 if (GetSel()->GetCurEvt() == fLastWrittenEvt) {
441 Warning("Process", "Event with %ul already written", fLastWrittenEvt);
442 return;
443 }
444 fLastWrittenEvt = GetSel()->GetCurEvt();
445 ++fCounter;
446
447 // prepare for tree filling
448 if (!fTreeWriter->BeginEvent(fDoReset)) {
449 SendError(kAbortAnalysis, "Process", "Begin event failed!");
450 return;
451 }
452
453 if (GetNEventsProcessed() == 0 && fCheckTamBr) {
454 CheckAndResolveTAMDep(fKeepTamBr);
455 }
456
457 // load all our branches
458 LoadBranches();
459
460 // pass our branches to tree writer if on first event
461 if (GetNEventsProcessed() == 0) {
462 SetupBranches();
463 }
464
465 // reset per file quantities if a new file was opened
466 if (fTreeWriter->GetFileNumber()!=fFileNum) {
467 fRunmap.clear();
468 fRunEntries = 0;
469 fHltEntries = 0;
470 fFileNum = fTreeWriter->GetFileNumber();
471 if (fBranchTable)
472 fTreeWriter->StoreObject(fBranchTable);
473 }
474
475 UInt_t runnum = GetEventHeader()->RunNum();
476
477 // store look ahead information
478 if (fRunEntries>0) {
479 fLaHeader->SetRunNum(runnum);
480 fLATree->Fill();
481 }
482
483 // fill event header
484 fEventHeader->SetEvtNum(GetEventHeader()->EvtNum());
485 fEventHeader->SetLumiSec(GetEventHeader()->LumiSec());
486 fEventHeader->SetRunNum(runnum);
487
488 // fill all event header
489 FillAllEventHeader(kFALSE);
490
491 // look-up if entry is in map
492 map<UInt_t,Int_t>::iterator riter = fRunmap.find(runnum);
493 if (riter != fRunmap.end()) { // found existing run info
494 Int_t runentry = riter->second;
495 fEventHeader->SetRunEntry(runentry);
496
497 IncNEventsProcessed();
498 fTreeWriter->EndEvent(fDoReset);
499 return;
500 }
501
502 // fill new run info
503 Int_t runentry = fRunEntries;
504 ++fRunEntries;
505 fEventHeader->SetRunEntry(runentry);
506 fRunmap.insert(pair<UInt_t,Int_t>(runnum,runentry));
507 fRunInfo->SetRunNum(runnum);
508
509 Int_t hltentry = fHltEntries;
510 FillHltInfo();
511 if (hltentry < fHltEntries)
512 fRunInfo->SetHltEntry(hltentry);
513 else
514 fRunInfo->SetHltEntry(hltentry-1);
515
516 fRunTree->Fill();
517
518 IncNEventsProcessed();
519
520 if (!fTreeWriter->EndEvent(fDoReset)) {
521 SendError(kAbortAnalysis, "Process", "End event failed!");
522 return;
523 }
524 }
525
526 //--------------------------------------------------------------------------------------------------
527 void OutputMod::ProcessAll()
528 {
529 // Called by the Selector class for events that were skipped.
530
531 if (GetSel()->GetCurEvt() == fLastSeenEvt)
532 return;
533
534 fLastSeenEvt = GetSel()->GetCurEvt();
535 ++fCounter;
536
537 // prepare for tree filling
538 FillAllEventHeader(kTRUE);
539 }
540
541 //--------------------------------------------------------------------------------------------------
542 void OutputMod::RequestBranches()
543 {
544 // Loop over requested branches and request them.
545
546 for (UInt_t i=0; i<GetNBranches(); ++i) {
547 if (i>=fNBranchesMax) {
548 SendError(kAbortAnalysis, "RequestBranches", "Cannot request branch '%s' "
549 "since maximum number of branches [%d] is reached",
550 fBrNameList.at(i).c_str(), fNBranchesMax);
551 return;
552 }
553 fBranches[i] = 0;
554 TAModule::ReqBranch(fBrNameList.at(i).c_str(), fBranches[i]);
555 }
556 }
557
558 //--------------------------------------------------------------------------------------------------
559 void OutputMod::SetupBranches()
560 {
561 // Setup branches in tree writer.
562
563 for (UInt_t i=0; i<GetNBranches(); ++i) {
564 const char *bname = fBrNameList.at(i).c_str();
565 const char *cname = fBrClassList.at(i).c_str();
566 if (!fBranches[i]) {
567 SendError(kWarning, "SetupBranches",
568 "Pointer for branch '%s' and class '%s' is NULL", bname, cname);
569 continue;
570 }
571 Int_t bsize = fBranchSize;
572 TString cnamestr(cname);
573 if ((bsize<128*1024) && (cnamestr.Contains("mithep::MCParticle"))) {
574 bsize=128*1024;
575 } else if ((bsize<32*1024) && (cnamestr.Contains("mithep::CaloTower"))) {
576 bsize=32*1024;
577 }
578
579 fTreeWriter->AddBranch(bname, cname, &fBranches[i], bsize);
580 }
581 }
582
583 //--------------------------------------------------------------------------------------------------
584 void OutputMod::SlaveBegin()
585 {
586 // Setup the tree writer and create branches that can already be created at this point.
587
588 // setup tree writer
589 fTreeWriter = new TreeWriter(fTreeName, kFALSE);
590 fTreeWriter->SetBaseURL(fPathName);
591 fTreeWriter->SetPrefix(fPrefix);
592 fTreeWriter->SetMaxSize(fMaxSize*1024*1024);
593 fTreeWriter->SetCompressLevel(fCompLevel);
594 fTreeWriter->SetDefaultSL(fSplitLevel);
595 fTreeWriter->SetDefaultBrSize(fBranchSize);
596 fTreeWriter->AddTree(fTreeName);
597 fTreeWriter->DoBranchRef(fTreeName);
598
599 // deal with my own tree objects
600 fEventHeader = new EventHeader;
601 fTreeWriter->AddBranch(GetSel()->GetEvtHdrName(), &fEventHeader);
602
603 // deal with other trees
604 const char *tname = 0;
605 fRunInfo = new RunInfo;
606 tname = GetSel()->GetRunTreeName();
607 fTreeWriter->AddBranchToTree(tname, GetSel()->GetRunInfoName(), &fRunInfo);
608 fTreeWriter->SetAutoFill(tname, 0);
609 fRunTree = fTreeWriter->GetTree(tname);
610 fLaHeader = new LAHeader;
611 tname = GetSel()->GetLATreeName();
612 fTreeWriter->AddBranchToTree(tname, GetSel()->GetLAHdrName(), &fLaHeader);
613 fTreeWriter->SetAutoFill(tname, 0);
614 fLATree = fTreeWriter->GetTree(tname);
615 fAllEventHeader = new EventHeader;
616 tname = GetSel()->GetAllEvtTreeName();
617 fTreeWriter->AddBranchToTree(tname, GetSel()->GetAllEvtHdrBrn(), &fAllEventHeader);
618 fAllTree = fTreeWriter->GetTree(tname);
619 fTreeWriter->SetAutoFill(tname, 0);
620
621 // get pointer to all event headers
622 fSkimmedIn = GetPublicObj<EventHeaderCol>(Names::gkSkimmedHeaders);
623
624 // create TObject space for TAM
625 fBranches = new TObject*[fNBranchesMax + fAddList.size()];
626
627 // deal here with additional published objects
628 for (UInt_t i=0; i<fAddList.size(); ++i) {
629 TString objname(fAddList.at(i));
630 TObject *obj = FindPublicObj(objname);
631 if (obj) {
632 fBranches[fNBranchesMax+i] = obj;
633 fTreeWriter->AddBranch(objname, &fBranches[fNBranchesMax+i]);
634 Info("SlaveBegin", "Adding additional branch named '%s' as requested", objname.Data());
635 } else {
636 SendError(kAbortAnalysis, "SlaveBegin",
637 "Object named '%s' for additional branch is NULL", objname.Data());
638 }
639 }
640
641 // adjust checks for TAM branches
642 if (fKeepTamBr)
643 fCheckTamBr = kTRUE;
644 }
645
646 //--------------------------------------------------------------------------------------------------
647 void OutputMod::SlaveTerminate()
648 {
649 // Terminate tree writing and do cleanup.
650
651 RetractObj(Names::gkSkimmedHeaders);
652
653 delete fTreeWriter;
654 fTreeWriter = 0;
655
656 delete fEventHeader;
657 delete fRunInfo;
658 delete fLaHeader;
659 delete fAllEventHeader;
660
661 delete[] fBranches;
662
663 Double_t frac = 100.*GetNEventsProcessed()/fCounter;
664 Info("SlaveTerminate", "Stored %.2f%% events (%ld out of %ld)",
665 frac, GetNEventsProcessed(), fCounter);
666 }