The script calculates the bandwidth for filling and retrieving bin contents (in million entries per second) for these two histogramming techniques, where "seconds" is CPU and real time.
The first line of the plots contains the bandwidth based on the CPU time (THnSpase, TH1/2/3/nF*, ratio), the second line shows the plots for real time, and the third line shows the fraction of filled bins and memory used by THnSparse vs. TH1/2/3/nF.
The timing depends on the distribution and the amount of entries in the histograms; here, a Gaussian distribution (center is contained in the histograms) is used to fill each histogram with 1000 entries. The filling and reading is repeated until enough statistics have been collected.
This macro should be run in compiled mode due to the many nested loops that force CLING to disable its optimization. If run interpreted one would not benchmark THnSparse but CLING.
#ifndef INT_MAX
#define INT_MAX std::numeric_limits<int>::max()
#endif
public:
fValue(nullptr), fDim(dim), fBins(bins), fNum(num),
bool Run();
if (time == kReal) return fTime[hist][0];
return fTime[hist][1]; }
protected:
private:
};
Int_t TTimeHists::fgDebug = 0;
TTimeHists::~TTimeHists()
{
delete [] fValue;
delete fHist;
}
bool TTimeHists::Run()
{
for (
int h = 0;
h < 2; ++
h) {
try {
do {
}
while ((!
h &&
w.RealTime() < 0.1)
fTime[
h][0] = (1.* fNum *
rep[
h]) /
w.RealTime() / 1
E6;
fTime[
h][1] = (1.* fNum *
rep[
h]) /
w.CpuTime() / 1
E6;
if (
h == 1 && (fTime[
h][0] > 1
E20 || fTime[
h][1] > 1
E20)) {
do {
}
while (
w.RealTime() < 0.1);
fTime[
h][0] = (1.* fNum *
rep[
h]) /
w.RealTime() / 1
E6;
fTime[
h][1] = (1.* fNum *
rep[
h]) /
w.CpuTime() / 1
E6;
}
if (fTime[
h][0] > 1
E20) fTime[
h][0] = 1
E20;
if (fTime[
h][1] > 1
E20) fTime[
h][1] = 1
E20;
}
catch (std::exception&) {
fTime[
h][0] = fTime[
h][1] = -1.;
}
}
printf(
"ERROR: mismatch of histogram (%g) and sparse histogram (%g) for dim=%d, bins=%d!\n",
}
void TTimeHists::NextValues()
{
}
void TTimeHists::SetupValues()
{
if (!fValue) fValue =
new Double_t[fDim];
}
void TTimeHists::Fill(
EHist hist)
{
if (fgDebug > 1) {
printf(
"%ld: fill %s",
n, hist ==
kHist? (fDim < 4 ?
"hist" :
"arr") :
"sparse");
}
switch (fDim) {
case 1: fHist->Fill(fValue[0]); break;
case 2: ((
TH2F*)fHist)->Fill(fValue[0], fValue[1]);
break;
case 3: ((
TH3F*)fHist)->Fill(fValue[0], fValue[1], fValue[2]);
break;
default:
fHn->Fill(fValue);
break;
}
} else {
}
}
}
void TTimeHists::SetupHist(
EHist hist)
{
switch (fDim) {
case 1: fHist =
new TH1F(
"h1",
"h1", fBins, -1., 1.);
break;
case 2: fHist =
new TH2F(
"h2",
"h2", fBins, -1., 1., fBins, -1., 1.);
break;
case 3: fHist =
new TH3F(
"h3",
"h3", fBins, -1., 1., fBins, -1., 1., fBins, -1., 1.);
break;
default:
{
throw std::bad_alloc();
}
throw std::bad_alloc();
}
}
}
} else {
}
}
}
{
while (
x[0] <= fBins + 1) {
if (fDim < 4) {
if (fDim == 2)
histidx = fHist->GetBin(
x[0],
x[1]);
else if (fDim == 3)
histidx = fHist->GetBin(
x[0],
x[1],
x[2]);
}
else v =
fHn->GetBinContent(
x);
if (fgDebug > 2 || (fgDebug > 1 &&
v)) {
printf(
"%s%d", fDim < 4 ?
"hist" :
"arr", fDim);
}
}
}
++idx;
}
} else {
if (fgDebug > 1) {
}
}
}
if (fgDebug > 0)
printf(
"check %s%d = %g\n", hist ==
kHist ? (fDim < 4 ?
"hist" :
"arr") :
"sparse", fDim,
check);
}
#if defined (__CLING__)
printf(
"Please run this script in compiled mode by running \".x sparsehist.C+\"\n");
return;
#endif
TH2F*
htime[TTimeHists::kNumHist][TTimeHists::kNumTime];
for (
int h = 0;
h < TTimeHists::kNumHist; ++
h)
for (int t = 0; t < TTimeHists::kNumTime; ++t) {
if (
h == 0)
name +=
"arr";
if (t == 0)
name +=
"_r";
title.
Form(
"Throughput (fill,get) %s (%s, 1M entries/sec);dim;bins;1M entries/sec",
h == 0 ?
"TH1/2/3/nF" :
"THnSparseF", t == 0 ?
"real" :
"CPU");
}
TH2F*
hsparse_mem =
new TH2F(
"hsparse_mem",
"Fractional memory usage;dim;bins;fraction of memory used", 6, 0.5, 6.5, 10, 5, 105);
TH2F*
hsparse_bins =
new TH2F(
"hsparse_bins",
"Fractional number of used bins;dim;bins;fraction of filled bins", 6, 0.5, 6.5, 10, 5, 105);
for (
Int_t dim = 1; dim < 7; ++dim) {
printf(
"Processing dimension %d", dim);
for (
Int_t bins = 10; bins <= 100; bins += 10) {
for (
int h = 0;
h < TTimeHists::kNumHist; ++
h) {
for (int t = 0; t < TTimeHists::kNumTime; ++t) {
Double_t time =
timer.GetTime((TTimeHists::EHist)
h, (TTimeHists::ETime)t);
if (time >= 0.)
htime[
h][t]->Fill(dim, bins, time);
}
}
if (max <
timer.GetTime(TTimeHists::kSparse, TTimeHists::kReal))
max =
timer.GetTime(TTimeHists::kSparse, TTimeHists::kReal);
}
}
for (int t = 0; t < TTimeHists::kNumTime; ++t) {
const char*
name = t ?
"htime_ratio" :
"htime_ratio_r";
title.
Form(
"Relative speed improvement (%s, 1M entries/sec): sparse/hist;dim;bins;#Delta 1M entries/sec", t == 0 ?
"real" :
"CPU");
}
const char* opt = "TEXT COL";
for (int t = 0; t < TTimeHists::kNumTime; ++t) {
for (
int h = 0;
h < TTimeHists::kNumHist; ++
h) {
}
}
}
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
THnSparseT< TArrayF > THnSparseF
R__EXTERN TRandom * gRandom
R__EXTERN TStyle * gStyle
R__EXTERN TSystem * gSystem
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
1-D histogram with a float per channel (see TH1 documentation)
TH1 is the base class of all histogram classes in ROOT.
2-D histogram with a float per channel (see TH1 documentation)
3-D histogram with a float per channel (see TH1 documentation)
Efficient multidimensional histogram.
Multidimensional histogram.
virtual Double_t Gaus(Double_t mean=0, Double_t sigma=1)
Samples a random number from the standard Normal (Gaussian) Distribution with the given mean and sigm...
virtual void SetSeed(ULong_t seed=0)
Set the random generator seed.
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
void SetOptStat(Int_t stat=1)
The type of information printed in the histogram statistics box can be selected via the parameter mod...
void SetPaintTextFormat(const char *format="g")
void SetPalette(Int_t ncolors=kBird, Int_t *colors=nullptr, Float_t alpha=1.)
See TColor::SetPalette.
virtual int GetMemInfo(MemInfo_t *info) const
Returns ram and swap memory usage info into the MemInfo_t structure.