]> git.uio.no Git - u/mrichter/AliRoot.git/blame - HLT/BASE/util/AliHLTRootSchemaEvolutionComponent.cxx
add multiplicity dependence
[u/mrichter/AliRoot.git] / HLT / BASE / util / AliHLTRootSchemaEvolutionComponent.cxx
CommitLineData
65106d07 1// $Id$
2
3//**************************************************************************
4//* This file is property of and copyright by the ALICE HLT Project *
5//* ALICE Experiment at CERN, All rights reserved. *
6//* *
7//* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no> *
8//* for The ALICE HLT Project. *
9//* *
10//* Permission to use, copy, modify and distribute this software and its *
11//* documentation strictly for non-commercial purposes is hereby granted *
12//* without fee, provided that the above copyright notice appears in all *
13//* copies and that both the copyright notice and this permission notice *
14//* appear in the supporting documentation. The authors make no claims *
15//* about the suitability of this software for any purpose. It is *
16//* provided "as is" without express or implied warranty. *
17//**************************************************************************
18
19/** @file AliHLTRootSchemaEvolutionComponent.cxx
20 @author Matthias Richter
21 @date 2009-10-18
22 @brief Handler component for ROOT schema evolution of streamed objects
23*/
24
25#include "AliHLTRootSchemaEvolutionComponent.h"
26#include "AliHLTMessage.h"
b64e4d93 27#include "AliHLTReadoutList.h"
65106d07 28#include "TObjArray.h"
29#include "TStreamerInfo.h"
30#include "TList.h"
05948425 31#include "TFile.h"
a22cde70 32#include "TStopwatch.h"
33#include "TTimeStamp.h"
34#include "TDatime.h"
05948425 35
36#include "AliCDBStorage.h"
37#include "AliCDBManager.h"
38#include "AliCDBPath.h"
39#include "AliCDBId.h"
40#include "AliCDBMetaData.h"
41#include "AliCDBEntry.h"
65106d07 42
a22cde70 43#include <numeric>
44using std::accumulate;
45
65106d07 46/** ROOT macro for the implementation of ROOT specific class methods */
47ClassImp(AliHLTRootSchemaEvolutionComponent)
48
49AliHLTRootSchemaEvolutionComponent::AliHLTRootSchemaEvolutionComponent()
b64e4d93 50 : AliHLTCalibrationProcessor()
a22cde70 51 , fList()
b64e4d93 52 , fFlags(kFXS)
65106d07 53 , fpStreamerInfos(NULL)
a22cde70 54 , fpEventTimer(NULL)
55 , fpCycleTimer(NULL)
56 , fMaxEventTime(500)
65106d07 57 , fFXSPrescaler(0)
05948425 58 , fFileName()
65106d07 59{
60 // see header file for class documentation
61 // or
62 // refer to README to build package
63 // or
64 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
65
66}
b64e4d93 67
68// FIXME: read below when defining an OCDB object here
65106d07 69const char* AliHLTRootSchemaEvolutionComponent::fgkConfigurationObject=NULL;
a22cde70 70const AliHLTUInt32_t AliHLTRootSchemaEvolutionComponent::fgkTimeScale=1000000;
65106d07 71
72AliHLTRootSchemaEvolutionComponent::~AliHLTRootSchemaEvolutionComponent()
73{
74 // see header file for class documentation
75 if (fpStreamerInfos) {
76 fpStreamerInfos->Clear();
77 delete fpStreamerInfos;
78 }
79 fpStreamerInfos=NULL;
80}
81
82void AliHLTRootSchemaEvolutionComponent::GetInputDataTypes(AliHLTComponentDataTypeList& list)
83{
84 // see header file for class documentation
85 list.push_back(kAliHLTAnyDataType);
86}
87
88AliHLTComponentDataType AliHLTRootSchemaEvolutionComponent::GetOutputDataType()
89{
90 // see header file for class documentation
91 return kAliHLTDataTypeStreamerInfo;
92}
93
94void AliHLTRootSchemaEvolutionComponent::GetOutputDataSize(unsigned long& constBase, double& inputMultiplier)
95{
96 // see header file for class documentation
97
98 // this is nothing more than an assumption, in fact it's very difficult to predict how
99 // much output the component produces
100 constBase=100*1024;
101 inputMultiplier=3;
102}
103
b64e4d93 104int AliHLTRootSchemaEvolutionComponent::InitCalibration()
65106d07 105{
106 // see header file for class documentation
107
108 int iResult=0;
109
110 // default configuration from CDB
b64e4d93 111 // FIXME: has to be called from AliHLTCalibrationProcessor::DoInit in order to set
112 // the default parameters from OCDB before the custom argument scan
113 // not valid at the moment because fgkConfigurationObject==NULL
65106d07 114 if (iResult>=0 && fgkConfigurationObject!=NULL) iResult=ConfigureFromCDBTObjString(fgkConfigurationObject);
115
65106d07 116 if (iResult>=0) {
117 fpStreamerInfos=new TObjArray();
118 if (!fpStreamerInfos) iResult=-ENOMEM;
a22cde70 119
120 fpEventTimer=new TStopwatch;
121 if (fpEventTimer) {
122 fpEventTimer->Reset();
123 }
124 fpCycleTimer=new TStopwatch;
125 if (fpCycleTimer) {
126 fpCycleTimer->Reset();
127 }
65106d07 128 }
a22cde70 129
65106d07 130 return 0;
131}
132
b64e4d93 133int AliHLTRootSchemaEvolutionComponent::DeinitCalibration()
65106d07 134{
135 // see header file for class documentation
05948425 136 if (fFileName.IsNull()==0) {
137 WriteToFile(fFileName, fpStreamerInfos);
138 fFileName.Clear();
139 }
140
65106d07 141 if (fpStreamerInfos) {
142 fpStreamerInfos->Clear();
143 delete fpStreamerInfos;
144 }
145 fpStreamerInfos=NULL;
146
a22cde70 147 if (fpEventTimer) {
148 delete fpEventTimer;
149 fpEventTimer=NULL;
150 }
151 if (fpCycleTimer) {
152 delete fpCycleTimer;
153 fpCycleTimer=NULL;
154 }
65106d07 155 return 0;
156}
157
b64e4d93 158int AliHLTRootSchemaEvolutionComponent::ProcessCalibration( const AliHLTComponentEventData& /*evtData*/,
159 AliHLTComponentTriggerData& /*trigData*/ )
65106d07 160{
161 // see header file for class documentation
162 int iResult=0;
163 AliHLTUInt32_t eventType=gkAliEventTypeUnknown;
164 if (!IsDataEvent(&eventType) &&
165 eventType==gkAliEventTypeStartOfRun) {
166 return 0;
167 }
168
a22cde70 169 AliHLTUInt32_t listtime=accumulate(fList.begin(), fList.end(), int(0), AliHLTDataBlockItem::TimeSum());
170 AliHLTUInt32_t averageEventTime=0;
171 AliHLTUInt32_t averageCycleTime=0;
172
173 AliHLTUInt32_t proctime=0;
174 if (fpEventTimer) {
175 averageEventTime=(fpEventTimer->RealTime()*fgkTimeScale)/(GetEventCount()+1);
176 proctime=fpEventTimer->RealTime()*fgkTimeScale;
177 fpEventTimer->Start(kFALSE);
178 }
179 if (fpCycleTimer) {
180 fpCycleTimer->Stop();
181 averageCycleTime=(fpCycleTimer->RealTime()*fgkTimeScale)/(GetEventCount()+1);
182 }
183
184 // scale down the event processing according to the required rate
185 // and average processing time.
a22cde70 186 for (const AliHLTComponentBlockData* pBlock=GetFirstInputBlock();
187 pBlock && iResult>=0;
188 pBlock=GetNextInputBlock()) {
189 bool processBlock=true;
190 AliHLTDataBlockItem* item=FindItem(pBlock->fDataType, pBlock->fSpecification);
191 if (item) {
192 // TODO: do a selection of blocks on basis of the time spent in its processing
193 // for now only the global processing time is checked
194 // process if the average event time is smaller then the cycle time, i.e.
195 // the time is spent outside the component
196 // apply a factor 4 margin
197 processBlock=4*averageEventTime<fMaxEventTime || 2*averageEventTime<averageCycleTime;
198 } else {
199 // always process new incoming blocks
200 processBlock=true;
201 fList.push_back(AliHLTDataBlockItem(pBlock->fDataType, pBlock->fSpecification));
202 item=&fList[fList.size()-1];
203 }
204 if (processBlock) {
205 TObject* pObj=item->Extract(pBlock);
206 if (pObj) {
9ddb0769 207 AliHLTMessage msg(kMESS_OBJECT);
208 msg.EnableSchemaEvolution();
209 if ((iResult=item->Stream(pObj, msg))>=0) {
a22cde70 210 iResult=UpdateStreamerInfos(msg.GetStreamerInfos(), fpStreamerInfos);
9ddb0769 211 } else {
212 HLTError("failed to stream object %s of type %s", pObj->GetName(), pObj->ClassName());
213 }
a22cde70 214 delete pObj;
215 pObj=NULL;
216 }
217 }
218 }
219
220 if (fpEventTimer) {
221 fpEventTimer->Stop();
222 proctime=fpEventTimer->RealTime()*fgkTimeScale-proctime;
223 averageEventTime=(fpEventTimer->RealTime()*fgkTimeScale)/(GetEventCount()+1);
224
225 // info output once every 2 seconds
226 static UInt_t lastTime=0;
227 TDatime time;
228 if (time.Get()-lastTime>2) {
229 lastTime=time.Get();
230 HLTInfo("event time %d, average time %d, list time %d, cycle time %d", proctime, averageEventTime, listtime, averageCycleTime);
231 }
232 }
233 if (fpCycleTimer) {
234 fpCycleTimer->Start(kFALSE);
65106d07 235 }
236
237 if (iResult>=0) {
238 if ((TestBits(kHLTOUTatFirstEvent) && GetEventCount()==0) ||
b64e4d93 239 (TestBits(kHLTOUTatAllEvents))) {
65106d07 240 PushBack(fpStreamerInfos, kAliHLTDataTypeStreamerInfo);
241 }
05948425 242 }
65106d07 243
b64e4d93 244 if (TestBits(kFXS) && fFXSPrescaler>0 && (GetEventCount()%fFXSPrescaler)==0) {
245 // push to FXS
246 AliHLTReadoutList rdList(AliHLTReadoutList::kHLT);
247 PushToFXS((TObject*)fpStreamerInfos, "HLT", "StreamerInfo", &rdList );
248 }
249
250 return iResult;
251}
252
253int AliHLTRootSchemaEvolutionComponent::ShipDataToFXS( const AliHLTComponentEventData& /*evtData*/,
254 AliHLTComponentTriggerData& /*trigData*/)
255{
256 // see header file for class documentation
257 if (TestBits(kFXS)) {
258 // push to FXS
259 AliHLTReadoutList rdList(AliHLTReadoutList::kHLT);
260 PushToFXS((TObject*)fpStreamerInfos, "HLT", "StreamerInfo", &rdList );
05948425 261 }
262
b64e4d93 263 if (fFileName.IsNull()==0) {
05948425 264 WriteToFile(fFileName, fpStreamerInfos);
265 fFileName.Clear();
65106d07 266 }
267
b64e4d93 268 if (TestBits(kHLTOUTatEOR)) {
269 PushBack(fpStreamerInfos, kAliHLTDataTypeStreamerInfo);
270 }
271
a22cde70 272 for (unsigned i=0; i<fList.size(); i++) {
273 if (CheckFilter(kHLTLogDebug)) fList[i].Print("short");
274 else if (fList[i].IsObject()) {
275 HLTInfo("AliHLTDataBlockItem %s %08x\n"
276 " average extraction time: %d usec\n"
277 " average streaming time: %d usec"
278 , AliHLTComponent::DataType2Text(fList[i]).c_str()
279 , fList[i].GetSpecification()
280 , fList[i].GetExtractionTime()
281 , fList[i].GetStreamingTime());
282 }
283 }
a22cde70 284
b64e4d93 285 return 0;
65106d07 286}
287
288int AliHLTRootSchemaEvolutionComponent::UpdateStreamerInfos(const TList* list, TObjArray* infos) const
289{
290 // see header file for class documentation
291 int iResult=0;
292 if (!list || !infos) {
293 return -EINVAL;
294 }
295
296 TObject* element=NULL;
297 TIter next((TList*)list);
298 while ((element = next())) {
299 TStreamerInfo* pInfo=dynamic_cast<TStreamerInfo*>(element);
300 if (!pInfo) continue;
301 TString name=pInfo->GetName();
302 int i=0;
c067b272 303 if (pInfo->GetClassVersion()==0) continue; // skip classes which are not for storage
65106d07 304 for (; i<infos->GetEntriesFast(); i++) {
305 if (name.CompareTo(infos->At(i)->GetName())==0 &&
306 pInfo->GetClassVersion() == ((TStreamerInfo*)infos->At(i))->GetClassVersion()) {
307 // have it already
308 break;
309 }
310 }
311
c067b272 312 // Add streamer info if not yet there
313 if (i>=infos->GetEntriesFast()) {
314 infos->Add(pInfo);
315 }
65106d07 316 }
317
318 return iResult;
319}
320
321int AliHLTRootSchemaEvolutionComponent::ScanConfigurationArgument(int argc, const char** argv)
322{
323 // see header file for class documentation
324 int iResult=0;
325 if (argc<=0) return 0;
326 int i=0;
327 TString argument=argv[i];
328
329 // -hltout=[all,first,eor,off]
330 if (argument.Contains("-hltout")) {
331 argument.ReplaceAll("-hltout", "");
332 argument.ReplaceAll("=", "");
b64e4d93 333 if (argument.IsNull() || argument.CompareTo("all")==0) {
334 SetBits(kHLTOUTatAllEvents|kHLTOUTatEOR);
335 } else if (argument.CompareTo("first")==0) {
65106d07 336 SetBits(kHLTOUTatFirstEvent);
b64e4d93 337 } else if (argument.CompareTo("eor")==0) {
65106d07 338 SetBits(kHLTOUTatEOR);
b64e4d93 339 } else if (argument.CompareTo("off")==0) {
65106d07 340 ClearBits(kHLTOUTatAllEvents | kHLTOUTatFirstEvent | kHLTOUTatEOR);
341 } else {
342 HLTError("invalid parameter for argument -hltout= : %s", argument.Data());
343 return -EINVAL;
344 }
345 return 1;
346 }
347
348 // -fxs=[n,off]
349 if (argument.Contains("-fxs")) {
350 argument.ReplaceAll("-fxs", "");
351 argument.ReplaceAll("=", "");
c067b272 352 SetBits(kFXS);
65106d07 353 if (argument.IsNull()) {
b64e4d93 354 } else if (argument.CompareTo("off")==0) {
65106d07 355 ClearBits(kFXS);
356 } else if (argument.IsDigit()) {
357 fFXSPrescaler=argument.Atoi();
358 } else {
359 HLTError("invalid parameter for argument -fxs= : %s", argument.Data());
360 return -EINVAL;
361 }
362 return 1;
363 }
05948425 364
365 // -file=<filename>
366 if (argument.Contains("-file=")) {
367 argument.ReplaceAll("-file=", "");
368 if (!argument.IsNull()) {
369 fFileName=argument;
370 } else {
371 HLTError("argument -file= expects file name");
372 return -EINVAL;
373 }
374 return 1;
375 }
a22cde70 376
377 if (argument.Contains("-rate=")) {
378 argument.ReplaceAll("-rate=", "");
379 AliHLTUInt32_t rate=argument.Atoi();
380 if (rate>0 && rate<fgkTimeScale) {
381 fMaxEventTime=fgkTimeScale/rate;
382 } else {
383 HLTError("argument -file= expects number [Hz]");
384 return -EINVAL;
385 }
386 return 1;
387 }
b64e4d93 388
65106d07 389 return iResult;
390}
05948425 391
392int AliHLTRootSchemaEvolutionComponent::WriteToFile(const char* filename, const TObjArray* infos) const
393{
394 // write aray of streamer infos to file
395 if (!filename || !infos) return -EINVAL;
396
397 TFile out(filename, "RECREATE");
398 if (out.IsZombie()) {
399 HLTError("failed to open file %s", filename);
400 return -EBADF;
401 }
402
403 const char* entrypath="HLT/Calib/StreamerInfo";
404 int version = -1;
9ddb0769 405 AliCDBStorage* store = NULL;
406 // TODO: to be activated later, first some methods need to be made
407 // public in AliCDBManager. Or some new methods to be added
408 //if (AliCDBManager::Instance()->SelectSpecificStorage(entrypath))
409 // store = AliCDBManager::Instance()->GetSpecificStorage(entrypath);
410 if (!store)
411 store = AliCDBManager::Instance()->GetDefaultStorage();
412 AliCDBEntry* existingEntry=NULL;
413 if (store && store->GetLatestVersion(entrypath, GetRunNo())>=0 &&
414 (existingEntry=AliCDBManager::Instance()->Get(entrypath))!=NULL) {
415 version=existingEntry->GetId().GetVersion();
05948425 416 }
417 version++;
418
9ddb0769 419 TObjArray* clone=NULL;
420
421 if (existingEntry && existingEntry->GetObject()) {
422 TObject* cloneObj=existingEntry->GetObject()->Clone();
423 if (cloneObj) clone=dynamic_cast<TObjArray*>(cloneObj);
424 if (MergeStreamerInfo(clone, infos)==0) {
425 // no change, store with identical version
426 version=existingEntry->GetId().GetVersion();
427 }
428 } else {
429 TObject* cloneObj=infos->Clone();
430 if (cloneObj) clone=dynamic_cast<TObjArray*>(cloneObj);
431 }
432 if (!clone) {
433 HLTError("failed to clone streamer info object array");
434 return -ENOMEM;
435 }
436
05948425 437 AliCDBPath cdbPath(entrypath);
c067b272 438 AliCDBId cdbId(cdbPath, AliCDBManager::Instance()->GetRun(), AliCDBRunRange::Infinity(), version, 0);
05948425 439 AliCDBMetaData* cdbMetaData=new AliCDBMetaData;
c067b272 440 cdbMetaData->SetResponsible("ALICE HLT Matthias.Richter@cern.ch");
05948425 441 cdbMetaData->SetComment("Streamer info for HLTOUT payload");
9ddb0769 442 AliCDBEntry* entry=new AliCDBEntry(clone, cdbId, cdbMetaData, kTRUE);
05948425 443
444 out.cd();
445 entry->Write();
446 // this is a small memory leak
447 // seg fault in ROOT object handling if the two objects are deleted
448 // investigate later
449 //delete entry;
450 //delete cdbMetaData;
451 out.Close();
452
453 return 0;
454}
a22cde70 455
9ddb0769 456int AliHLTRootSchemaEvolutionComponent::MergeStreamerInfo(TObjArray* tgt, const TObjArray* src)
457{
458 /// merge streamer info entries from source array to target array
459 /// return 1 if target array has been changed
460
461 // add all existing infos if not existing in the current one, or having
462 // different class version
463 int iResult=0;
464 if (!tgt || !src) return -EINVAL;
465
466 {
467 // check if all infos from the existing entry are in the new entry and with
468 // identical class version
469 TIter next(src);
470 TObject* nextobj=NULL;
471 while ((nextobj=next())) {
472 TStreamerInfo* srcInfo=dynamic_cast<TStreamerInfo*>(nextobj);
473 if (!srcInfo) continue;
474 TString srcInfoName=srcInfo->GetName();
475
476 int i=0;
477 for (; i<tgt->GetEntriesFast(); i++) {
478 if (tgt->At(i)==NULL) continue;
479 if (srcInfoName.CompareTo(tgt->At(i)->GetName())!=0) continue;
480 // TODO: 2010-08-23 some more detailed investigation is needed.
481 // Structures used for data exchange, e.g. AliHLTComponentDataType
482 // or AliHLTEventDDLV1 do not have a class version, but need to be stored in the
483 // streamer info. Strictly speaking not, because those structures are not supposed
484 // to be changed at all, so they should be the same in all versions in the future.
485 // There has been a problem with detecting whether the streamer info is already in
486 // the target array if the srcInfo has class version -1. As it just concerns
487 // structures not going to be changed we can safely skip checking the class version,
488 // as long as the entry is already in the target streamer infos it does not need
489 // to be copied again.
490 if (srcInfo->GetClassVersion()<0) break;
491 TStreamerInfo* tgtInfo=dynamic_cast<TStreamerInfo*>(tgt->At(i));
492 if (tgtInfo && tgtInfo->GetClassVersion()==srcInfo->GetClassVersion()) break;
493 }
494 if (i<tgt->GetEntriesFast()) continue;
495
496 iResult=1;
497 tgt->Add(srcInfo);
498 }
499 }
500
501 return iResult;
502}
503
a22cde70 504AliHLTRootSchemaEvolutionComponent::AliHLTDataBlockItem*
505AliHLTRootSchemaEvolutionComponent::FindItem(AliHLTComponentDataType dt,
506 AliHLTUInt32_t spec)
507{
508 /// find item in the list
509 // vector<AliHLTDataBlockItem>::iterator element=std::find(fList.begin(), fList.end(), AliHLTDataBlockItem(dt,spec));
510 // if (element!=fList.end()) return &(*element);
511 for (unsigned i=0; i<fList.size(); i++) {
512 if (fList[i]==dt && fList[i]==spec) return &fList[i];
513 }
514 return NULL;
515}
516
517AliHLTRootSchemaEvolutionComponent::AliHLTDataBlockItem::AliHLTDataBlockItem(AliHLTComponentDataType dt,
518 AliHLTUInt32_t spec)
519 : fDt(dt)
520 , fSpecification(spec)
521 , fIsObject(false)
522 , fNofExtractions(0)
523 , fExtractionTimeUsec(0)
524 , fLastExtraction(0)
525 , fNofStreamings(0)
526 , fStreamingTimeUsec(0)
527 , fLastStreaming(0)
528{
529 // helper class to keep track of input data blocks
530 // in the AliHLTRootSchemaEvolutionComponent
531 //
532}
533
534AliHLTRootSchemaEvolutionComponent::AliHLTDataBlockItem::~AliHLTDataBlockItem()
535{
536 // destructor
537}
538
539TObject* AliHLTRootSchemaEvolutionComponent::AliHLTDataBlockItem::Extract(const AliHLTComponentBlockData* bd)
540{
541 /// extract data block to root object, and update performance parameters
542 /// object needs to be deleted externally
543 if (!bd || !bd->fPtr || bd->fSize<8) return NULL;
544
545 AliHLTUInt32_t firstWord=*((AliHLTUInt32_t*)bd->fPtr);
546 if (!(fIsObject=(firstWord==bd->fSize-sizeof(AliHLTUInt32_t)))) return NULL;
547
548 TStopwatch sw;
549 sw.Start();
550 AliHLTMessage msg(bd->fPtr, bd->fSize);
551 TClass* objclass=msg.GetClass();
552 if (!(fIsObject=(objclass!=NULL))) return NULL;
553 TObject* pObj=msg.ReadObject(objclass);
554 if (!(fIsObject=(pObj!=NULL))) return NULL;
555 sw.Stop();
556 AliHLTUInt32_t usec=sw.RealTime()*fgkTimeScale;
557 fNofExtractions++;
558 fExtractionTimeUsec+=usec;
559 TTimeStamp ts;
560 fLastExtraction=(ts.GetSec()%1000)*fgkTimeScale + ts.GetNanoSec()/1000;
561 return pObj;
562}
563
564int AliHLTRootSchemaEvolutionComponent::AliHLTDataBlockItem::Stream(TObject* obj, AliHLTMessage& msg)
565{
566 /// stream object and update performance parameters
567 if (!obj) return -EINVAL;
568 TStopwatch sw;
569 sw.Start();
570 msg.WriteObject(obj);
571
572 AliHLTUInt32_t usec=sw.RealTime()*fgkTimeScale;
573 fNofStreamings++;
574 fStreamingTimeUsec+=usec;
575 TTimeStamp ts;
576 fLastStreaming=(ts.GetSec()%1000)*fgkTimeScale + ts.GetNanoSec()/1000;
577 return 0;
578}
579
580void AliHLTRootSchemaEvolutionComponent::AliHLTDataBlockItem::Print(const char* option) const
581{
582 /// print status
583 if (fIsObject || !(strcmp(option, "short")==0))
584 cout << "AliHLTDataBlockItem: " << AliHLTComponent::DataType2Text(fDt).c_str() << " " << hex << fSpecification << dec << endl;
585 if (fIsObject) {
586 if (fNofExtractions>0) cout << " average extraction time: " << fExtractionTimeUsec/fNofExtractions << " usec" << endl;
587 else cout << " never extracted" << endl;
588 if (fNofStreamings>0) cout << " average streaming time: " << fStreamingTimeUsec/fNofStreamings << " usec" << endl;
589 else cout << " never streamed" << endl;
590 }
591}