TTreeCache.cxx

Go to the documentation of this file.
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 }

Generated on Tue Jul 5 15:34:10 2011 for ROOT_528-00b_version by  doxygen 1.5.1