// @(#)root/test:$Id$ // Author: Nikolay Root 05/07/98 #include #include "Riostream.h" #include "TCollection.h" #include "TSortedList.h" #include "TObjArray.h" #include "TClonesArray.h" #include "TOrdCollection.h" #include "THashList.h" #include "THashTable.h" #include "TBtree.h" #include "TStopwatch.h" #include "TRandom.h" // // This program benchmarks access time to objects by name or index // for TObjArray,TOrdCollection,TList,TSortedList,THashList,TBtree, // TClonesArray and THashTable collections. // // Usage: tcollbm -h - to print a usage info // tcollbm [-n|-i|-m] [nobjects] [ntimes] - to run tests // // switches: // -n - benchmark access by name (default) // -i - benchmark access by index // -m - benchmark of objects allocation // // parameters: // nobjects - number of objects to be inserted into collections // ntimes - number of random lookups in the collection // // default values ( adjusted in 'main' according 'moda' value ) int nobjects = 100; // Number of objects to be inserted. int ntimes = 100000; // Number of random lookups. int moda = 0; // Default - access by name //_____________________________________________________________ class HitNames { // Utility class to handle the table of names Int_t fSize; // Array size char** fNames; // Array for objects names public: void InitNames(); void DeleteNames(); void Resize(Int_t s) { if(s <= fSize) return; DeleteNames(); fSize=s; InitNames(); } HitNames() : fSize(0), fNames(0) {}; HitNames(Int_t s) : fSize(s), fNames(0) { InitNames(); }; virtual ~HitNames() { DeleteNames(); }; const char *operator[](Int_t i) { return fNames[i]; }; }; void HitNames::InitNames() { // Create and fill names // cout << "HitNames::InitNames() are called" << endl; fNames = new char* [fSize]; for (int i=0;iDelete(); } void Dump() const { fColl->Dump(); } virtual const char* GetName() const { return fColl->ClassName(); } Tester() : fWhat(Other),fNobj(10),fNtimes(100000),fModa(0),fColl(0) {} Tester(Int_t no,Int_t nt,Int_t m,TCollection *p) : fWhat(Other),fNobj(no),fNtimes(nt),fModa(m),fColl(p) { if(!strcmp(GetName(),"TClonesArray")) fWhat = Clones; if(!strcmp(GetName(),"TObjArray")) fWhat = Array; if(!strcmp(GetName(),"TBtree")) fWhat = BTree; } virtual ~Tester() { if(fColl) delete fColl; } }; void Tester::Fill() { if (fWhat == Clones) { TClonesArray &base = *((TClonesArray*)fColl); for (Int_t i=0;iAdd(new TNamed(names[i],GetName())); } } Double_t Tester::TestAllocation() { // benchmark memory allocation TStopwatch timer; timer.Start(); for (Int_t i=0;iRndm(1)); if(!((*o)[i])) Printf("Object %d not found !!!",i); } timer.Stop(); } else if(fWhat == Array) { TObjArray *o = (TObjArray*)fColl; timer.Start(); for (Int_t j=0;jRndm(1)); if(!((*o)[i])) Printf("Object %d not found !!!",i); } timer.Stop(); } else if(fWhat == BTree) { TBtree *o = (TBtree*)fColl; timer.Start(); for (Int_t j=0;jRndm(1)); if(!((*o)[i])) Printf("Object %d not found !!!",i); } timer.Stop(); } else { cout << "Class " << GetName() << " doesn't support access by index" << endl; } CleanUp(); return timer.CpuTime(); }; Double_t Tester::TestByName() { // benchmark access by name Fill(); TStopwatch timer; Int_t i; timer.Start(); for (Int_t j=0;jRndm(1)); if(!((*fColl)(names[i]))) Printf("Object %5s not found !!!",names[i]); } timer.Stop(); CleanUp(); return timer.CpuTime(); }; Double_t Tester::DoTest() { // Return the average time in msec. Double_t v; if(fModa==2) { printf("Memory allocation test for %-20s", GetName()); v=TestAllocation(); } else if(fModa==1) { printf("Random lookups by Index for %-20s", GetName()); v=TestByIndex(); } else { printf("Random lookups by Name for %-20s", GetName()); v=TestByName(); } Printf(" CpuTime=%7.2f seconds", v); return 1000*v/fNtimes; }; //_______________________________________________________________ const int ntests = 8; // Number of classes to be tested Double_t deltas[ntests]; // benchmark results int main(int argc,char **argv) { // Initialize the ROOT framework if(argc == 2 && !strcmp(argv[1],"-h")) { Printf("Usage: tcollbm [-n|-i] [nobjects] [ntimes]"); Printf(" -n - benchmark access by name"); Printf(" -i - benchmark access by index"); Printf(" -m - benchmark memory allocation"); Printf(" nobjects - number of objects to be inserted into collections"); Printf(" ntimes - number of random lookups in the collection"); return 1; } if(argc > 1 && !strcmp(argv[1],"-n")) { moda = 0; argc--; argv++; }; if(argc > 1 && !strcmp(argv[1],"-i")) { moda = 1; argc--; argv++; }; if(argc > 1 && !strcmp(argv[1],"-m")) { moda = 2; argc--; argv++; }; // // Set defaults values for selected test // if(moda == 0) { nobjects = 100; ntimes = 10000; } if(moda == 1) { nobjects = 100; ntimes = 1000000; } if(moda == 2) { nobjects = 1000; ntimes = 100; } Int_t no = nobjects; Int_t nt = ntimes; if(argc > 1) { no = atoi(argv[1]); } if(argc > 2) { nt = atoi(argv[2]); } if(no > 1) { nobjects = no; } else { nobjects = 2; Printf("Reset nobjects to %d",nobjects); } if(nt > 99) { ntimes = nt; } else { ntimes = 100; Printf("Reset ntimes to %d",ntimes); } Printf("Nobjects = %d , Ntimes = %d",nobjects,ntimes); if(ntimes > 5000000 || (moda==2 && nobjects*ntimes > 500000)) { Printf("This test takes some time. Be partient ..."); } names.Resize(nobjects); Double_t smin = 10000000; int j=-1,idx=-1; TObjArray array(ntests); // Array of collections array.Add(new Tester(nobjects,ntimes,moda, new TObjArray())); // Add TObjArray j++; deltas[j] = ((Tester*)(array[j]))->DoTest(); if(deltas[j] < smin) { idx=j; smin=deltas[j]; } array.Add(new Tester(nobjects,ntimes,moda, new TClonesArray("TNamed",nobjects))); // Add TClonesArray j++; deltas[j] = ((Tester*)(array[j]))->DoTest(); if(deltas[j] < smin) { idx=j; smin=deltas[j]; } array.Add(new Tester(nobjects,ntimes,moda, new TBtree())); // Add TBTree j++; deltas[j] = ((Tester*)(array[j]))->DoTest(); if(deltas[j] < smin) { idx=j; smin=deltas[j]; } if(moda != 1) { // Skip classes without operator[] from index test array.Add(new Tester(nobjects,ntimes,moda, new TOrdCollection())); // Add TOrdCollection j++; deltas[j] = ((Tester*)(array[j]))->DoTest(); if(deltas[j] < smin) { idx=j; smin=deltas[j]; } array.Add(new Tester(nobjects,ntimes,moda, new TList())); // Add TList j++; deltas[j] = ((Tester*)(array[j]))->DoTest(); if(deltas[j] < smin) { idx=j; smin=deltas[j]; } array.Add(new Tester(nobjects,ntimes,moda, new TSortedList())); // Add TSortedList j++; deltas[j] = ((Tester*)(array[j]))->DoTest(); if(deltas[j] < smin) { idx=j; smin=deltas[j]; } array.Add(new Tester(nobjects,ntimes,moda, new THashList())); // Add THashList j++; deltas[j] = ((Tester*)(array[j]))->DoTest(); if(deltas[j] < smin) { idx=j; smin=deltas[j]; } array.Add(new Tester(nobjects,ntimes,moda, new THashTable())); // Add THashTable j++; deltas[j] = ((Tester*)(array[j]))->DoTest(); if(deltas[j] < smin) { idx=j; smin=deltas[j]; } } // Results info ... j++; if(idx<0) { Printf("Can not find the winner. Sorry...\n"); array.Delete(); return 1; } if(smin==0) { Printf( "Input parameters nobjects=%d and ntimes=%d too small for Your computer.", nobjects,ntimes); Printf("Please, increase its and try again..."); array.Delete(); return 1; } Printf("\n\t\tBenchmark results\n"); Printf("\tAbsolute winner - %s",array[idx]->GetName()); Printf("\tAverage (msec)\tRatio\t\tClassName"); for (int i=0;iGetName()); } array.Delete(); return 0; }