00001 // @(#)root/tree:$Id: TTreeCache.cxx 38394 2011-03-11 21:59:11Z pcanal $ 00002 // Author: Rene Brun 04/06/2006 00003 00004 /************************************************************************* 00005 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * 00006 * All rights reserved. * 00007 * * 00008 * For the licensing terms see $ROOTSYS/LICENSE. * 00009 * For the list of contributors see $ROOTSYS/README/CREDITS. * 00010 *************************************************************************/ 00011 00012 ////////////////////////////////////////////////////////////////////////// 00013 // // 00014 // TTreeCache // 00015 // // 00016 // A specialized TFileCacheRead object for a TTree // 00017 // This class acts as a file cache, registering automatically the // 00018 // baskets from the branches being processed (TTree::Draw or // 00019 // TTree::Process and TSelectors) when in the learning phase. // 00020 // The learning phase is by default 100 entries. // 00021 // It can be changed via TTreeCache::SetLearnEntries. // 00022 // // 00023 // This cache speeds-up considerably the performance, in particular // 00024 // when the Tree is accessed remotely via a high latency network. // 00025 // // 00026 // The default cache size (10 Mbytes) may be changed via the function // 00027 // TTreeCache::SetCacheSize // 00028 // // 00029 // Only the baskets for the requested entry range are put in the cache // 00030 // // 00031 // For each Tree being processed a TTreeCache object is created. // 00032 // This object is automatically deleted when the Tree is deleted or // 00033 // when the file is deleted. // 00034 // // 00035 // -Special case of a TChain // 00036 // Once the training is done on the first Tree, the list of branches // 00037 // in the cache is kept for the following files. // 00038 // // 00039 // -Special case of a TEventlist // 00040 // if the Tree or TChain has a TEventlist, only the buffers // 00041 // referenced by the list are put in the cache. // 00042 // // 00043 // The learning period is started or restarted when: 00044 // - TTree::SetCacheSize is called for the first time. 00045 // - TTree::SetCacheSize is called a second time with a different size. 00046 // - TTreeCache::StartLearningPhase is called. 00047 // - TTree[Cache]::SetEntryRange is called 00048 // * and the learning is not yet finished 00049 // * and has not been set to manual 00050 // * and the new minimun entry is different. 00051 // 00052 // The learning period is stopped (and prefetching is actually started) when: 00053 // - TTree[Cache]::StopLearningPhase is called. 00054 // - An entry outside the 'learning' range is requested 00055 // The 'learning range is from fEntryMin (default to 0) to 00056 // fEntryMin + fgLearnEntries (default to 100). 00057 // - A 'cached' TChain switches over to a new file. 00058 // 00059 // WHY DO WE NEED the TreeCache when doing data analysis? 00060 // ====================================================== 00061 // 00062 // When writing a TTree, the branch buffers are kept in memory. 00063 // A typical branch buffersize (before compression) is typically 32 KBytes. 00064 // After compression, the zipped buffer may be just a few Kbytes. 00065 // The branch buffers cannot be much larger in case of Trees with several 00066 // hundred or thousand branches. 00067 // When writing, this does not generate a performance problem because branch 00068 // buffers are always written sequentially and the OS is in general clever enough 00069 // to flush the data to the output file when a few MBytes of data have to be written. 00070 // When reading at the contrary, one may hit a performance problem when reading 00071 // across a network (LAN or WAN) and the network latency is high. 00072 // For example in a WAN with 10ms latency, reading 1000 buffers of 10 KBytes each 00073 // with no cache will imply 10s penalty where a local read of the 10 MBytes would 00074 // take about 1 second. 00075 // The TreeCache will try to prefetch all the buffers for the selected branches 00076 // such that instead of transfering 1000 buffers of 10 Kbytes, it will be able 00077 // to transfer one single large buffer of 10 Mbytes in one single transaction. 00078 // Not only the TreeCache minimizes the number of transfers, but in addition 00079 // it can sort the blocks to be read in increasing order such that the file 00080 // is read sequentially. 00081 // Systems like xrootd, dCache or httpd take advantage of the TreeCache in 00082 // reading ahead as much data as they can and return to the application 00083 // the maximum data specified in the cache and have the next chunk of data ready 00084 // when the next request comes. 00085 // 00086 // 00087 // HOW TO USE the TreeCache 00088 // ========================= 00089 // 00090 // A few use cases are discussed below. It is not simple to activate the cache 00091 // by default (except case1 below) because there are many possible configurations. 00092 // In some applications you know a priori the list of branches to read. 00093 // In other applications the analysis loop calls several layers of user functions 00094 // where it is impossible to predict a priori which branches will be used. This 00095 // is probably the most frequent case. In this case ROOT I/O will flag used 00096 // branches automatically when a branch buffer is read during the learning phase. 00097 // The TreeCache interface provides functions to instruct the cache about the used 00098 // branches if they are known a priori. In the examples below, portions of analysis 00099 // code are shown. The few statements involving the TreeCache are marked with //<<< 00100 // 00101 // ------------------- 00102 // 1- with TTree::Draw 00103 // ------------------- 00104 // the TreeCache is automatically used by TTree::Draw. The function knows 00105 // which branches are used in the query and it puts automatically these branches 00106 // in the cache. The entry range is also known automatically. 00107 // 00108 // ------------------------------------- 00109 // 2- with TTree::Process and TSelectors 00110 // ------------------------------------- 00111 // You must enable the cache and tell the system which branches to cache 00112 // and also specify the entry range. It is important to specify the entry range 00113 // in case you process only a subset of the events, otherwise you run the risk 00114 // to store in the cache entries that you do not need. 00115 // 00116 // --example 2a 00117 //-- 00118 // TTree *T = (TTree*)f->Get("mytree"); 00119 // Long64_t nentries = T->GetEntries(); 00120 // Int_t cachesize = 10000000; //10 MBytes 00121 // T->SetCacheSize(cachesize); //<<< 00122 // T->AddBranch("*",kTRUE); //<<< add all branches to the cache 00123 // T->Process('myselector.C+"); 00124 // //in the TSelector::Process function we read all branches 00125 // T->GetEntry(i); 00126 //-- ... here you process your entry 00127 // 00128 // 00129 // --example 2b 00130 // in the Process function we read a subset of the branches. 00131 // Only the branches used in the first entry will be put in the cache 00132 //-- 00133 // TTree *T = (TTree*)f->Get("mytree"); 00134 // //we want to process only the 200 first entries 00135 // Long64_t nentries=200; 00136 // int efirst= 0; 00137 // int elast = efirst+nentries; 00138 // Int_t cachesize = 10000000; //10 MBytes 00139 // TTreeCache::SetLearnEntries(1); //<<< we can take the decision after 1 entry 00140 // T->SetCacheSize(cachesize); //<<< 00141 // T->SetCacheEntryRange(efirst,elast); //<<< 00142 // T->Process('myselector.C+","",nentries,efirst); 00143 // // in the TSelector::Process we read only 2 branches 00144 // TBranch *b1 = T->GetBranch("branch1"); 00145 // b1->GetEntry(i); 00146 // if (somecondition) return; 00147 // TBranch *b2 = T->GetBranch("branch2"); 00148 // b2->GetEntry(i); 00149 // ... here you process your entry 00150 //-- 00151 // ---------------------------- 00152 // 3- with your own event loop 00153 // ---------------------------- 00154 // --example 3a 00155 // in your analysis loop, you always use 2 branches. You want to prefetch 00156 // the branch buffers for these 2 branches only. 00157 //-- 00158 // TTree *T = (TTree*)f->Get("mytree"); 00159 // TBranch *b1 = T->GetBranch("branch1"); 00160 // TBranch *b2 = T->GetBranch("branch2"); 00161 // Long64_t nentries = T->GetEntries(); 00162 // Int_t cachesize = 10000000; //10 MBytes 00163 // T->SetCacheSize(cachesize); //<<< 00164 // T->AddBranchToCache(b1,kTRUE); //<<<add branch1 and branch2 to the cache 00165 // T->AddBranchToCache(b2,kTRUE); //<<< 00166 // T->StopCacheLearningPhase(); //<<< 00167 // for (Long64_t i=0;i<nentries;i++) { 00168 // T->LoadTree(i); //<<< important call when calling TBranch::GetEntry after 00169 // b1->GetEntry(i); 00170 // if (some condition not met) continue; 00171 // b2->GetEntry(i); 00172 // if (some condition not met) continue; 00173 // //here we read the full event only in some rare cases. 00174 // //there is no point in caching the other branches as it might be 00175 // //more economical to read only the branch buffers really used. 00176 // T->GetEntry(i); 00177 // .. process the rare but interesting cases. 00178 // ... here you process your entry 00179 // } 00180 //-- 00181 // --example 3b 00182 // in your analysis loop, you always use 2 branches in the main loop. 00183 // you also call some analysis functions where a few more branches will be read. 00184 // but you do not know a priori which ones. There is no point in prefetching 00185 // branches that will be used very rarely. 00186 //-- 00187 // TTree *T = (TTree*)f->Get("mytree"); 00188 // Long64_t nentries = T->GetEntries(); 00189 // Int_t cachesize = 10000000; //10 MBytes 00190 // T->SetCacheSize(cachesize); //<<< 00191 // T->SetCacheLearnEntries(5); //<<< we can take the decision after 5 entries 00192 // TBranch *b1 = T->GetBranch("branch1"); 00193 // TBranch *b2 = T->GetBranch("branch2"); 00194 // for (Long64_t i=0;i<nentries;i++) { 00195 // T->LoadTree(i); 00196 // b1->GetEntry(i); 00197 // if (some condition not met) continue; 00198 // b2->GetEntry(i); 00199 // //at this point we may call a user function where a few more branches 00200 // //will be read conditionally. These branches will be put in the cache 00201 // //if they have been used in the first 10 entries 00202 // if (some condition not met) continue; 00203 // //here we read the full event only in some rare cases. 00204 // //there is no point in caching the other branches as it might be 00205 // //more economical to read only the branch buffers really used. 00206 // T->GetEntry(i); 00207 // .. process the rare but interesting cases. 00208 // ... here you process your entry 00209 // } 00210 //-- 00211 // 00212 // 00213 // SPECIAL CASES WHERE TreeCache should not be activated 00214 // ===================================================== 00215 // 00216 // When reading only a small fraction of all entries such that not all branch 00217 // buffers are read, it might be faster to run without a cache. 00218 // 00219 // 00220 // HOW TO VERIFY That the TreeCache has been used and check its performance 00221 // ======================================================================== 00222 // 00223 // Once your analysis loop has terminated, you can access/print the number 00224 // of effective system reads for a given file with a code like 00225 // (where TFile* f is a pointer to your file) 00226 // 00227 // printf("Reading %lld bytes in %d transactions\n",f->GetBytesRead(), f->GetReadCalls()); 00228 // 00229 ////////////////////////////////////////////////////////////////////////// 00230 00231 #include "TTreeCache.h" 00232 #include "TChain.h" 00233 #include "TList.h" 00234 #include "TBranch.h" 00235 #include "TEventList.h" 00236 #include "TObjString.h" 00237 #include "TRegexp.h" 00238 #include "TLeaf.h" 00239 #include "TFriendElement.h" 00240 #include "TFile.h" 00241 00242 Int_t TTreeCache::fgLearnEntries = 100; 00243 00244 ClassImp(TTreeCache) 00245 00246 //______________________________________________________________________________ 00247 TTreeCache::TTreeCache() : TFileCacheRead(), 00248 fEntryMin(0), 00249 fEntryMax(1), 00250 fEntryCurrent(-1), 00251 fEntryNext(-1), 00252 fZipBytes(0), 00253 fNbranches(0), 00254 fNReadOk(0), 00255 fNReadMiss(0), 00256 fNReadPref(0), 00257 fBranches(0), 00258 fBrNames(0), 00259 fOwner(0), 00260 fTree(0), 00261 fIsLearning(kTRUE), 00262 fIsManual(kFALSE) 00263 { 00264 // Default Constructor. 00265 } 00266 00267 //______________________________________________________________________________ 00268 TTreeCache::TTreeCache(TTree *tree, Int_t buffersize) : TFileCacheRead(tree->GetCurrentFile(),buffersize), 00269 fEntryMin(0), 00270 fEntryMax(tree->GetEntriesFast()), 00271 fEntryCurrent(-1), 00272 fEntryNext(0), 00273 fZipBytes(0), 00274 fNbranches(0), 00275 fNReadOk(0), 00276 fNReadMiss(0), 00277 fNReadPref(0), 00278 fBranches(0), 00279 fBrNames(new TList), 00280 fOwner(tree), 00281 fTree(0), 00282 fIsLearning(kTRUE), 00283 fIsManual(kFALSE) 00284 { 00285 // Constructor. 00286 00287 fEntryNext = fEntryMin + fgLearnEntries; 00288 Int_t nleaves = tree->GetListOfLeaves()->GetEntries(); 00289 fBranches = new TObjArray(nleaves); 00290 } 00291 00292 //______________________________________________________________________________ 00293 TTreeCache::~TTreeCache() 00294 { 00295 // destructor. (in general called by the TFile destructor 00296 00297 delete fBranches; 00298 if (fBrNames) {fBrNames->Delete(); delete fBrNames; fBrNames=0;} 00299 } 00300 00301 //_____________________________________________________________________________ 00302 void TTreeCache::AddBranch(TBranch *b, Bool_t subbranches /*= kFALSE*/) 00303 { 00304 //add a branch to the list of branches to be stored in the cache 00305 //this function is called by TBranch::GetBasket 00306 00307 if (!fIsLearning) return; 00308 00309 // Reject branch that are not from the cached tree. 00310 if (!b || fOwner->GetTree() != b->GetTree()) return; 00311 00312 //Is branch already in the cache? 00313 Bool_t isNew = kTRUE; 00314 for (int i=0;i<fNbranches;i++) { 00315 if (fBranches->UncheckedAt(i) == b) {isNew = kFALSE; break;} 00316 } 00317 if (isNew) { 00318 fTree = b->GetTree(); 00319 fBranches->AddAtAndExpand(b, fNbranches); 00320 fBrNames->Add(new TObjString(b->GetName())); 00321 fZipBytes += b->GetZipBytes(); 00322 fNbranches++; 00323 if (gDebug > 0) printf("Entry: %lld, registering branch: %s\n",b->GetTree()->GetReadEntry(),b->GetName()); 00324 } 00325 00326 // process subbranches 00327 if (subbranches) { 00328 TObjArray *lb = b->GetListOfBranches(); 00329 Int_t nb = lb->GetEntriesFast(); 00330 for (Int_t j = 0; j < nb; j++) { 00331 TBranch* branch = (TBranch*) lb->UncheckedAt(j); 00332 if (!branch) continue; 00333 AddBranch(branch, subbranches); 00334 } 00335 } 00336 } 00337 00338 00339 //_____________________________________________________________________________ 00340 void TTreeCache::AddBranch(const char *bname, Bool_t subbranches /*= kFALSE*/) 00341 { 00342 // Add a branch to the list of branches to be stored in the cache 00343 // this is to be used by user (thats why we pass the name of the branch). 00344 // It works in exactly the same way as TTree::SetBranchStatus so you 00345 // probably want to look over ther for details about the use of bname 00346 // with regular expresions. 00347 // The branches are taken with respect to the Owner of this TTreeCache 00348 // (i.e. the original Tree) 00349 // NB: if bname="*" all branches are put in the cache and the learning phase stopped 00350 00351 TBranch *branch, *bcount; 00352 TLeaf *leaf, *leafcount; 00353 00354 Int_t i; 00355 Int_t nleaves = (fOwner->GetListOfLeaves())->GetEntriesFast(); 00356 TRegexp re(bname,kTRUE); 00357 Int_t nb = 0; 00358 00359 // first pass, loop on all branches 00360 // for leafcount branches activate/deactivate in function of status 00361 Bool_t all = kFALSE; 00362 if (!strcmp(bname,"*")) all = kTRUE; 00363 for (i=0;i<nleaves;i++) { 00364 leaf = (TLeaf*)(fOwner->GetListOfLeaves())->UncheckedAt(i); 00365 branch = (TBranch*)leaf->GetBranch(); 00366 TString s = branch->GetName(); 00367 if (!all) { //Regexp gives wrong result for [] in name 00368 TString longname; 00369 longname.Form("%s.%s",fOwner->GetName(),branch->GetName()); 00370 if (strcmp(bname,branch->GetName()) 00371 && longname != bname 00372 && s.Index(re) == kNPOS) continue; 00373 } 00374 nb++; 00375 AddBranch(branch, subbranches); 00376 leafcount = leaf->GetLeafCount(); 00377 if (leafcount && !all) { 00378 bcount = leafcount->GetBranch(); 00379 AddBranch(bcount, subbranches); 00380 } 00381 } 00382 if (nb==0 && strchr(bname,'*')==0) { 00383 branch = fOwner->GetBranch(bname); 00384 if (branch) { 00385 AddBranch(branch, subbranches); 00386 ++nb; 00387 } 00388 } 00389 00390 //search in list of friends 00391 UInt_t foundInFriend = 0; 00392 if (fOwner->GetListOfFriends()) { 00393 TIter nextf(fOwner->GetListOfFriends()); 00394 TFriendElement *fe; 00395 TString name; 00396 while ((fe = (TFriendElement*)nextf())) { 00397 TTree *t = fe->GetTree(); 00398 if (t==0) continue; 00399 00400 // If the alias is present replace it with the real name. 00401 char *subbranch = (char*)strstr(bname,fe->GetName()); 00402 if (subbranch!=bname) subbranch = 0; 00403 if (subbranch) { 00404 subbranch += strlen(fe->GetName()); 00405 if ( *subbranch != '.' ) subbranch = 0; 00406 else subbranch ++; 00407 } 00408 if (subbranch) { 00409 name.Form("%s.%s",t->GetName(),subbranch); 00410 AddBranch(name, subbranches); 00411 } 00412 } 00413 } 00414 if (!nb && !foundInFriend) { 00415 if (gDebug > 0) printf("AddBranch: unknown branch -> %s \n", bname); 00416 return; 00417 } 00418 //if all branches are selected stop the learning phase 00419 if (*bname == '*') { 00420 fEntryNext = -1; // We are likely to have change the set of branches, so for the [re-]reading of the cluster. 00421 StopLearningPhase(); 00422 } 00423 } 00424 00425 //_____________________________________________________________________________ 00426 Bool_t TTreeCache::FillBuffer() 00427 { 00428 // Fill the cache buffer with the branches in the cache. 00429 00430 00431 if (fNbranches <= 0) return kFALSE; 00432 TTree *tree = ((TBranch*)fBranches->UncheckedAt(0))->GetTree(); 00433 Long64_t entry = tree->GetReadEntry(); 00434 00435 // If the entry is in the range we previously prefetched, there is 00436 // no point in retrying. Note that this will also return false 00437 // during the training phase (fEntryNext is then set intentional to 00438 // the end of the training phase). 00439 if (fEntryCurrent <= entry && entry < fEntryNext) return kFALSE; 00440 00441 // Triggered by the user, not the learning phase 00442 if (entry == -1) entry = 0; 00443 00444 // Estimate number of entries that can fit in the cache compare it 00445 // to the original value of fBufferSize not to the real one 00446 Long64_t autoFlush = tree->GetAutoFlush(); 00447 if (autoFlush > 0) { 00448 //case when the tree autoflush has been set 00449 Int_t averageEntrySize = tree->GetZipBytes()/tree->GetEntries(); 00450 if (averageEntrySize < 1) averageEntrySize = 1; 00451 Int_t nauto = fBufferSizeMin/(averageEntrySize*autoFlush); 00452 if (nauto < 1) nauto = 1; 00453 fEntryCurrent = entry - entry%autoFlush; 00454 fEntryNext = entry - entry%autoFlush + nauto*autoFlush; 00455 } else { 00456 // Below we increment by "autoFlush" events each iteration. 00457 // Thus, autoFlush cannot be negative. 00458 autoFlush = 0; 00459 00460 //case of old files before November 9 2009 00461 fEntryCurrent = entry; 00462 if (fZipBytes==0) { 00463 fEntryNext = entry + tree->GetEntries(); 00464 } else { 00465 Long64_t clusterEstimate = tree->GetEntries()*fBufferSizeMin/fZipBytes; 00466 if (clusterEstimate == 0) 00467 clusterEstimate = 1; 00468 fEntryNext = entry + clusterEstimate; 00469 } 00470 } 00471 if (fEntryCurrent < fEntryMin) fEntryCurrent = fEntryMin; 00472 if (fEntryMax <= 0) fEntryMax = tree->GetEntries(); 00473 if (fEntryNext > fEntryMax) fEntryNext = fEntryMax+1; 00474 00475 00476 // Check if owner has a TEventList set. If yes we optimize for this 00477 // Special case reading only the baskets containing entries in the 00478 // list. 00479 TEventList *elist = fOwner->GetEventList(); 00480 Long64_t chainOffset = 0; 00481 if (elist) { 00482 if (fOwner->IsA() ==TChain::Class()) { 00483 TChain *chain = (TChain*)fOwner; 00484 Int_t t = chain->GetTreeNumber(); 00485 chainOffset = chain->GetTreeOffset()[t]; 00486 } 00487 } 00488 00489 //clear cache buffer 00490 TFileCacheRead::Prefetch(0,0); 00491 //store baskets 00492 Int_t flushIntervals = 0; 00493 Long64_t minEntry = fEntryCurrent; 00494 Long64_t prevNtot; 00495 do { 00496 prevNtot = fNtot; 00497 for (Int_t i=0;i<fNbranches;i++) { 00498 TBranch *b = (TBranch*)fBranches->UncheckedAt(i); 00499 if (b->GetDirectory()==0) continue; 00500 if (b->GetDirectory()->GetFile() != fFile) continue; 00501 Int_t nb = b->GetMaxBaskets(); 00502 Int_t *lbaskets = b->GetBasketBytes(); 00503 Long64_t *entries = b->GetBasketEntry(); 00504 if (!lbaskets || !entries) continue; 00505 //we have found the branch. We now register all its baskets 00506 //from the requested offset to the basket below fEntrymax 00507 Int_t blistsize = b->GetListOfBaskets()->GetSize(); 00508 for (Int_t j=0;j<nb;j++) { 00509 // This basket has already been read, skip it 00510 if (j<blistsize && b->GetListOfBaskets()->UncheckedAt(j)) continue; 00511 00512 Long64_t pos = b->GetBasketSeek(j); 00513 Int_t len = lbaskets[j]; 00514 if (pos <= 0 || len <= 0) continue; 00515 //important: do not try to read fEntryNext, otherwise you jump to the next autoflush 00516 if (entries[j] >= fEntryNext) continue; 00517 if (entries[j] < minEntry && (j<nb-1 && entries[j+1] <= minEntry)) continue; 00518 if (elist) { 00519 Long64_t emax = fEntryMax; 00520 if (j<nb-1) emax = entries[j+1]-1; 00521 if (!elist->ContainsRange(entries[j]+chainOffset,emax+chainOffset)) continue; 00522 } 00523 fNReadPref++; 00524 00525 TFileCacheRead::Prefetch(pos,len); 00526 } 00527 if (gDebug > 0) printf("Entry: %lld, registering baskets branch %s, fEntryNext=%lld, fNseek=%d, fNtot=%d\n",minEntry,((TBranch*)fBranches->UncheckedAt(i))->GetName(),fEntryNext,fNseek,fNtot); 00528 } 00529 flushIntervals++; 00530 minEntry += autoFlush; 00531 00532 if (!((autoFlush > 0) && (fBufferSizeMin > (fNtot*(flushIntervals+1))/flushIntervals) && (prevNtot < fNtot) && (minEntry < fEntryMax))) 00533 break; 00534 00535 fEntryNext += autoFlush; 00536 if (fEntryNext > fEntryMax) fEntryNext = fEntryMax+1; 00537 } while (kTRUE); 00538 fIsLearning = kFALSE; 00539 return kTRUE; 00540 } 00541 00542 //_____________________________________________________________________________ 00543 Double_t TTreeCache::GetEfficiency() const 00544 { 00545 // Give the total efficiency of the cache... defined as the ratio 00546 // of blocks found in the cache vs. the number of blocks prefetched 00547 // ( it could be more than 1 if we read the same block from the cache more 00548 // than once ) 00549 // Note: This should eb used at the end of the processing or we will 00550 // get uncomplete stats 00551 00552 if ( !fNReadPref ) 00553 return 0; 00554 00555 return ((Double_t)fNReadOk / (Double_t)fNReadPref); 00556 } 00557 00558 //_____________________________________________________________________________ 00559 Double_t TTreeCache::GetEfficiencyRel() const 00560 { 00561 // This will indicate a sort of relative efficiency... a ratio of the 00562 // reads found in the cache to the number of reads so far 00563 00564 if ( !fNReadOk && !fNReadMiss ) 00565 return 0; 00566 00567 return ((Double_t)fNReadOk / (Double_t)(fNReadOk + fNReadMiss)); 00568 } 00569 00570 //_____________________________________________________________________________ 00571 Int_t TTreeCache::GetLearnEntries() 00572 { 00573 //static function returning the number of entries used to train the cache 00574 //see SetLearnEntries 00575 00576 return fgLearnEntries; 00577 } 00578 00579 //_____________________________________________________________________________ 00580 TTree *TTreeCache::GetOwner() const 00581 { 00582 //return the owner of this cache. 00583 00584 return fOwner; 00585 } 00586 00587 //_____________________________________________________________________________ 00588 TTree *TTreeCache::GetTree() const 00589 { 00590 //return Tree in the cache 00591 if (fNbranches <= 0) return 0; 00592 return ((TBranch*)(fBranches->UncheckedAt(0)))->GetTree(); 00593 } 00594 00595 //_____________________________________________________________________________ 00596 void TTreeCache::Print(Option_t *option) const 00597 { 00598 // Print cache statistics, like 00599 // ******TreeCache statistics for file: cms2.root ****** 00600 // Number of branches in the cache ...: 1093 00601 // Cache Efficiency ..................: 0.997372 00602 // Cache Efficiency Rel...............: 1.000000 00603 // Learn entries......................: 100 00604 // Reading............................: 72761843 bytes in 7 transactions 00605 // Readahead..........................: 256000 bytes with overhead = 0 bytes 00606 // Average transaction................: 10394.549000 Kbytes 00607 // Number of blocks in current cache..: 210, total size: 6280352 00608 // 00609 // if option = "a" the list of blocks in the cache is printed 00610 // see also class TTreePerfStats 00611 00612 TString opt = option; 00613 opt.ToLower(); 00614 printf("******TreeCache statistics for file: %s ******\n",fFile->GetName()); 00615 if (fNbranches <= 0) return; 00616 printf("Number of branches in the cache ...: %d\n",fNbranches); 00617 printf("Cache Efficiency ..................: %f\n",GetEfficiency()); 00618 printf("Cache Efficiency Rel...............: %f\n",GetEfficiencyRel()); 00619 printf("Learn entries......................: %d\n",TTreeCache::GetLearnEntries()); 00620 TFileCacheRead::Print(option); 00621 } 00622 00623 //_____________________________________________________________________________ 00624 Int_t TTreeCache::ReadBuffer(char *buf, Long64_t pos, Int_t len) 00625 { 00626 // Read buffer at position pos. 00627 // If pos is in the list of prefetched blocks read from fBuffer. 00628 // Otherwise try to fill the cache from the list of selected branches, 00629 // and recheck if pos is now in the list. 00630 // Returns 00631 // -1 in case of read failure, 00632 // 0 in case not in cache, 00633 // 1 in case read from cache. 00634 // This function overloads TFileCacheRead::ReadBuffer. 00635 00636 //Is request already in the cache? 00637 if (TFileCacheRead::ReadBuffer(buf,pos,len) == 1){ 00638 fNReadOk++; 00639 return 1; 00640 } 00641 00642 //not found in cache. Do we need to fill the cache? 00643 Bool_t bufferFilled = FillBuffer(); 00644 if (bufferFilled) { 00645 Int_t res = TFileCacheRead::ReadBuffer(buf,pos,len); 00646 00647 if (res == 1) 00648 fNReadOk++; 00649 else if (res == 0) 00650 fNReadMiss++; 00651 00652 return res; 00653 } 00654 fNReadMiss++; 00655 00656 return 0; 00657 } 00658 00659 //_____________________________________________________________________________ 00660 void TTreeCache::ResetCache() 00661 { 00662 // This will simply clear the cache 00663 TFileCacheRead::Prefetch(0,0); 00664 00665 } 00666 00667 //_____________________________________________________________________________ 00668 void TTreeCache::SetEntryRange(Long64_t emin, Long64_t emax) 00669 { 00670 // Set the minimum and maximum entry number to be processed 00671 // this information helps to optimize the number of baskets to read 00672 // when prefetching the branch buffers. 00673 00674 // This is called by TTreePlayer::Process in an automatic way... 00675 // don't restart it if the user has specified the branches. 00676 Bool_t needLearningStart = (fEntryMin != emin) && fIsLearning && !fIsManual; 00677 00678 fEntryMin = emin; 00679 fEntryMax = emax; 00680 fEntryNext = fEntryMin + fgLearnEntries; 00681 if (gDebug > 0) 00682 Info("SetEntryRange", "fEntryMin=%lld, fEntryMax=%lld, fEntryNext=%lld", 00683 fEntryMin, fEntryMax, fEntryNext); 00684 00685 if (needLearningStart) { 00686 // Restart learning 00687 fIsLearning = kTRUE; 00688 fIsManual = kFALSE; 00689 fNbranches = 0; 00690 fZipBytes = 0; 00691 if (fBrNames) fBrNames->Delete(); 00692 fEntryCurrent = -1; 00693 } 00694 } 00695 00696 //_____________________________________________________________________________ 00697 void TTreeCache::SetLearnEntries(Int_t n) 00698 { 00699 // Static function to set the number of entries to be used in learning mode 00700 // The default value for n is 10. n must be >= 1 00701 00702 if (n < 1) n = 1; 00703 fgLearnEntries = n; 00704 } 00705 00706 //_____________________________________________________________________________ 00707 void TTreeCache::StartLearningPhase() 00708 { 00709 // The name should be enough to explain the method. 00710 // The only additional comments is that the cache is cleaned before 00711 // the new learning phase. 00712 00713 fIsLearning = kTRUE; 00714 fIsManual = kFALSE; 00715 fNbranches = 0; 00716 fZipBytes = 0; 00717 if (fBrNames) fBrNames->Delete(); 00718 fIsTransferred = kFALSE; 00719 fEntryCurrent = -1; 00720 } 00721 00722 //_____________________________________________________________________________ 00723 void TTreeCache::StopLearningPhase() 00724 { 00725 // This is the counterpart of StartLearningPhase() and can be used to stop 00726 // the learning phase. It's useful when the user knows exactly what branches 00727 // he is going to use. 00728 // For the moment it's just a call to FillBuffer() since that method 00729 // will create the buffer lists from the specified branches. 00730 00731 if (fIsLearning) { 00732 // This will force FillBuffer to read the buffers. 00733 fEntryNext = -1; 00734 fIsLearning = kFALSE; 00735 } 00736 fIsManual = kTRUE; 00737 FillBuffer(); 00738 00739 } 00740 00741 //_____________________________________________________________________________ 00742 void TTreeCache::UpdateBranches(TTree *tree, Bool_t owner) 00743 { 00744 // Update pointer to current Tree and recompute pointers to the branches in the cache. 00745 00746 if (owner) { 00747 fOwner = tree; 00748 SetFile(tree->GetCurrentFile()); 00749 } 00750 fTree = tree; 00751 00752 fEntryMin = 0; 00753 fEntryMax = fTree->GetEntries(); 00754 00755 fEntryCurrent = -1; 00756 00757 if (fBrNames->GetEntries() == 0 && fIsLearning) { 00758 // We still need to learn. 00759 fEntryNext = fEntryMin + fgLearnEntries; 00760 } else { 00761 // We learnt from a previous file. 00762 fIsLearning = kFALSE; 00763 fEntryNext = -1; 00764 } 00765 fZipBytes = 0; 00766 fNbranches = 0; 00767 00768 TIter next(fBrNames); 00769 TObjString *os; 00770 while ((os = (TObjString*)next())) { 00771 TBranch *b = fTree->GetBranch(os->GetName()); 00772 if (!b) { 00773 continue; 00774 } 00775 fBranches->AddAt(b, fNbranches); 00776 fZipBytes += b->GetZipBytes(); 00777 fNbranches++; 00778 } 00779 }