52 #define INT_MAX std::numeric_limits<int>::max()
57 enum EHist { kHist, kSparse, kNumHist };
58 enum ETime { kReal, kCPU, kNumTime };
59 TTimeHists(Int_t dim, Int_t bins, Long_t num):
60 fValue(0), fDim(dim), fBins(bins), fNum(num),
61 fSparse(0), fHist(0), fHn(0) {}
64 Double_t GetTime(EHist hist, ETime time)
const {
65 if (time == kReal)
return fTime[hist][0];
66 return fTime[hist][1]; }
67 static void SetDebug(Int_t lvl) { fgDebug = lvl; }
68 THnSparse* GetSparse()
const {
return fSparse; }
71 void Fill(EHist hist);
72 Double_t Check(EHist hist);
73 void SetupHist(EHist hist);
89 Int_t TTimeHists::fgDebug = 0;
91 TTimeHists::~TTimeHists()
99 bool TTimeHists::Run()
105 for (
int h = 0; h < 2; ++h) {
111 SetupHist((EHist) h);
116 check[h] = Check((EHist) h);
119 }
while ((!h && w.RealTime() < 0.1)
120 || (h && rep[0] > 0 && rep[1] < rep[0]));
122 fTime[h][0] = (1.* fNum * rep[h]) / w.RealTime() / 1E6;
123 fTime[h][1] = (1.* fNum * rep[h]) / w.CpuTime() / 1E6;
125 if (h == 1 && (fTime[h][0] > 1E20 || fTime[h][1] > 1E20)) {
133 }
while (w.RealTime() < 0.1);
135 fTime[h][0] = (1.* fNum * rep[h]) / w.RealTime() / 1E6;
136 fTime[h][1] = (1.* fNum * rep[h]) / w.CpuTime() / 1E6;
139 if (fTime[h][0] > 1E20) fTime[h][0] = 1E20;
140 if (fTime[h][1] > 1E20) fTime[h][1] = 1E20;
142 catch (std::exception&) {
143 fTime[h][0] = fTime[h][1] = -1.;
148 if (check[0] != check[1])
150 printf(
"ERROR: mismatch of histogram (%g) and sparse histogram (%g) for dim=%d, bins=%d!\n",
151 check[0], check[1], fDim, fBins);
155 return (check[0] == check[1]);
158 void TTimeHists::NextValues()
160 for (Int_t d = 0; d < fDim; ++d)
161 fValue[d] = gRandom->Gaus() / 4.;
164 void TTimeHists::SetupValues()
167 if (!fValue) fValue =
new Double_t[fDim];
168 gRandom->SetSeed(42);
171 void TTimeHists::Fill(EHist hist)
173 for (Long_t n = 0; n < fNum; ++n) {
176 printf(
"%ld: fill %s", n, hist == kHist? (fDim < 4 ?
"hist" :
"arr") :
"sparse");
177 for (Int_t d = 0; d < fDim; ++d)
178 printf(
"[%g]", fValue[d]);
183 case 1: fHist->Fill(fValue[0]);
break;
184 case 2: ((TH2F*)fHist)->Fill(fValue[0], fValue[1]);
break;
185 case 3: ((TH3F*)fHist)->Fill(fValue[0], fValue[1], fValue[2]);
break;
186 default: fHn->Fill(fValue);
break;
189 fSparse->Fill(fValue);
194 void TTimeHists::SetupHist(EHist hist)
198 case 1: fHist =
new TH1F(
"h1",
"h1", fBins, -1., 1.);
break;
199 case 2: fHist =
new TH2F(
"h2",
"h2", fBins, -1., 1., fBins, -1., 1.);
break;
200 case 3: fHist =
new TH3F(
"h3",
"h3", fBins, -1., 1., fBins, -1., 1., fBins, -1., 1.);
break;
204 gSystem->GetMemInfo(&meminfo);
206 for (Int_t d = 0; d < fDim; ++d) {
207 if ((Int_t)(size *
sizeof(Float_t)) > INT_MAX / (fBins + 2)
208 || (meminfo.fMemFree > 0
209 && meminfo.fMemFree / 2 < (Int_t) (size *
sizeof(Float_t)/1000/1000)))
210 throw std::bad_alloc();
213 if (meminfo.fMemFree > 0
214 && meminfo.fMemFree / 2 < (Int_t) (size *
sizeof(Float_t)/1000/1000))
215 throw std::bad_alloc();
216 Int_t* bins =
new Int_t[fDim];
217 Double_t *xmin =
new Double_t[fDim];
218 Double_t *xmax =
new Double_t[fDim];
219 for (Int_t d = 0; d < fDim; ++d) {
224 fHn =
new THnF(
"hn",
"hn", fDim, bins, xmin, xmax);
228 Int_t* bins =
new Int_t[fDim];
229 Double_t *xmin =
new Double_t[fDim];
230 Double_t *xmax =
new Double_t[fDim];
231 for (Int_t d = 0; d < fDim; ++d) {
236 fSparse =
new THnSparseF(
"hs",
"hs", fDim, bins, xmin, xmax);
240 Double_t TTimeHists::Check(EHist hist)
244 Int_t* x =
new Int_t[fDim];
245 memset(x, 0,
sizeof(Int_t) * fDim);
250 for (Int_t d = 0; d < fDim; ++d)
252 while (x[0] <= fBins + 1) {
255 Long_t histidx = x[0];
256 if (fDim == 2) histidx = fHist->GetBin(x[0], x[1]);
257 else if (fDim == 3) histidx = fHist->GetBin(x[0], x[1], x[2]);
258 v = fHist->GetBinContent(histidx);
260 else v = fHn->GetBinContent(x);
261 Double_t checkx = 0.;
263 for (Int_t d = 0; d < fDim; ++d)
267 if (fgDebug > 2 || (fgDebug > 1 && v)) {
268 printf(
"%s%d", fDim < 4 ?
"hist" :
"arr", fDim);
269 for (Int_t d = 0; d < fDim; ++d)
270 printf(
"[%d]", x[d]);
271 printf(
" = %g\n", v);
277 for (Int_t d = fDim - 1; d > 0; --d) {
278 if (x[d] > fBins + 1) {
286 for (Long64_t i = 0; i < fSparse->GetNbins(); ++i) {
287 Double_t v = fSparse->GetBinContent(i, x);
288 Double_t checkx = 0.;
289 for (Int_t d = 0; d < fDim; ++d)
294 printf(
"sparse%d", fDim);
295 for (Int_t d = 0; d < fDim; ++d)
296 printf(
"[%d]", x[d]);
297 printf(
" = %g\n", v);
303 printf(
"check %s%d = %g\n", hist == kHist ? (fDim < 4 ?
"hist" :
"arr") :
"sparse", fDim, check);
311 #if defined (__CLING__)
312 printf(
"Please run this script in compiled mode by running \".x sparsehist.C+\"\n");
316 TH2F* htime[TTimeHists::kNumHist][TTimeHists::kNumTime];
317 for (
int h = 0; h < TTimeHists::kNumHist; ++h)
318 for (
int t = 0; t < TTimeHists::kNumTime; ++t) {
319 TString name(
"htime_");
320 if (h == 0) name +=
"arr";
322 if (t == 0) name +=
"_r";
325 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");
326 htime[h][t] =
new TH2F(name, title, 6, 0.5, 6.5, 10, 5, 105);
329 TH2F* hsparse_mem =
new TH2F(
"hsparse_mem",
"Fractional memory usage;dim;bins;fraction of memory used", 6, 0.5, 6.5, 10, 5, 105);
330 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);
334 for (Int_t dim = 1; dim < 7; ++dim) {
335 printf(
"Processing dimension %d", dim);
336 for (Int_t bins = 10; bins <= 100; bins += 10) {
337 TTimeHists timer(dim, bins, 1000);
339 for (
int h = 0; h < TTimeHists::kNumHist; ++h) {
340 for (
int t = 0; t < TTimeHists::kNumTime; ++t) {
341 Double_t time = timer.GetTime((TTimeHists::EHist)h, (TTimeHists::ETime)t);
343 htime[h][t]->Fill(dim, bins, time);
346 hsparse_mem->Fill(dim, bins, timer.GetSparse()->GetSparseFractionMem());
347 hsparse_bins->Fill(dim, bins, timer.GetSparse()->GetSparseFractionBins());
349 if (max < timer.GetTime(TTimeHists::kSparse, TTimeHists::kReal))
350 max = timer.GetTime(TTimeHists::kSparse, TTimeHists::kReal);
357 Double_t markersize = 2.5;
358 hsparse_mem->SetMarkerSize(markersize);
359 hsparse_bins->SetMarkerSize(markersize);
361 TH2F* htime_ratio[TTimeHists::kNumTime];
362 for (
int t = 0; t < TTimeHists::kNumTime; ++t) {
363 const char* name = t ?
"htime_ratio" :
"htime_ratio_r";
364 htime_ratio[t] = (TH2F*) htime[TTimeHists::kSparse][t]->Clone(name);
366 title.Form(
"Relative speed improvement (%s, 1M entries/sec): sparse/hist;dim;bins;#Delta 1M entries/sec", t == 0 ?
"real" :
"CPU");
367 htime_ratio[t]->SetTitle(title);
368 htime_ratio[t]->Divide(htime[TTimeHists::kHist][t]);
369 htime_ratio[t]->SetMinimum(0.1);
370 htime_ratio[t]->SetMarkerSize(markersize);
373 TFile* f =
new TFile(
"sparsehist.root",
"RECREATE");
375 TCanvas* canv=
new TCanvas(
"c",
"c");
378 gStyle->SetPalette(8,0);
379 gStyle->SetPaintTextFormat(
".2g");
380 gStyle->SetOptStat(0);
381 const char* opt =
"TEXT COL";
383 for (
int t = 0; t < TTimeHists::kNumTime; ++t) {
384 for (
int h = 0; h < TTimeHists::kNumHist; ++h) {
385 htime[h][t]->SetMaximum(max);
386 htime[h][t]->SetMarkerSize(markersize);
387 canv->cd(1 + h + 3 * t);
388 htime[h][t]->Draw(opt);
389 htime[h][t]->Write();
392 htime_ratio[t]->Draw(opt); gPad->SetLogz();
393 htime_ratio[t]->Write();
396 canv->cd(7); hsparse_mem->Draw(opt);
397 canv->cd(8); hsparse_bins->Draw(opt);
398 hsparse_mem->Write();
399 hsparse_bins->Write();