https://github.com/root-project/root
Tip revision: 2c5707e9b4f78ee1b8691c35855575cd5b00925a authored by Unknown Author on 31 March 2006, 13:09:23 UTC
This commit was manufactured by cvs2svn to create tag 'v5-10-00c'.
This commit was manufactured by cvs2svn to create tag 'v5-10-00c'.
Tip revision: 2c5707e
tcollbm.cxx
// @(#)root/test:$Name: $:$Id: tcollbm.cxx,v 1.5 2002/01/23 17:52:51 rdm Exp $
// Author: Nikolay Root 05/07/98
#include <stdlib.h>
#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 Text_t *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;i<fSize;i++) {
fNames[i] = new char [20];
sprintf(fNames[i],"W%d",i+1);
}
}
void HitNames::DeleteNames() { // Clean up
if(!fNames) return;
// cout << "HitNames::DeleteNames() are called" << endl;
for (int i=0;i<fSize;i++) {
delete fNames[i];
}
delete fNames;
fNames = 0;
}
HitNames names; // We needs only one static object of this class
//_______________________________________________________________
//
// Just for fun, I introduce the class 'Tester' to collect
// a 'TNamed' objects. I use a objects of this class to perform a real
// tests.
class Tester : public TObject {
enum EClass { Clones, Array, BTree, Other };
EClass fWhat;
Int_t fNobj; // Number of objects to be stored in collection
Int_t fNtimes; // How many times to perform a test
Int_t fModa; // What we need to test
TCollection *fColl; // Collection under test
public:
void Fill(); // Fill the collection
Double_t TestAllocation(); // Memory allocation test
Double_t TestByName(); // benchmark by name
Double_t TestByIndex(); // benchmark by index
Double_t DoTest(); // Tests multiplexsor
void CleanUp() { fColl->Delete(); }
void Dump() const { fColl->Dump(); }
virtual const Text_t* 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;i<fNobj;i++) new (base[i]) TNamed(names[i],GetName());
} else {
for (Int_t i=0;i<fNobj;i++) fColl->Add(new TNamed(names[i],GetName()));
}
}
Double_t Tester::TestAllocation() { // benchmark memory allocation
TStopwatch timer;
timer.Start();
for (Int_t i=0;i<fNtimes;i++) {
Fill();
CleanUp();
}
timer.Stop();
return timer.CpuTime();
}
Double_t Tester::TestByIndex() { // benchmark access by index
Fill();
TStopwatch timer;
Int_t i;
if (fWhat == Clones) {
TClonesArray *o = (TClonesArray*)fColl;
timer.Start();
for (Int_t j=0;j<fNtimes;j++) {
i=Int_t(fNobj*gRandom->Rndm(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;j<fNtimes;j++) {
i=Int_t(fNobj*gRandom->Rndm(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;j<fNtimes;j++) {
i=Int_t(fNobj*gRandom->Rndm(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;j<fNtimes;j++) {
i=Int_t(fNobj*gRandom->Rndm(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;i<j;i++) {
Printf("\t%f\t%f\t%s",
deltas[i],deltas[i]/smin,array[i]->GetName());
}
array.Delete();
return 0;
}