multicolor.C: Use a THStack to show a 2-D hist with cells with different colors | Histograms | transpad.C: Example of a canvas showing two histograms with different scales. |
//********************************************************************* //+ Evaluate the performance of THnSparse vs THnF (or Float_t arrays) // for different numbers of dimensions and bins per dimension. // // 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, THnF/Float_t*, 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. THnF/Float_t. // // 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. // // tutorials/tree/drawsparse.C shows an example for visualizing a // THnSparse. It creates a TTree which is then drawn using // TParallelCoord. // // This macro should be run in compiled mode due to the many nested // loops that force CINT to disable its optimization. If run // interpreted one would not benchmark THnSparse but CINT. // // Run as // .L $ROOTSYS/tutorials/hist/sparsehist.C+ // // Axel.Naumann@cern.ch (2007-09-14) // ********************************************************************* #include "TH1.h" #include "TH2.h" #include "TH3.h" #include "THnSparse.h" #include "TStopwatch.h" #include "TRandom.h" #include "TCanvas.h" #include "TFile.h" #include "TStyle.h" #include "TSystem.h" class TTimeHists { public: enum EHist { kHist, kSparse, kNumHist }; enum ETime { kReal, kCPU, kNumTime }; TTimeHists(Int_t dim, Int_t bins, Long_t num): fValue(0), fDim(dim), fBins(bins), fNum(num), fSparse(0), fHist(0), fArray(0) {} ~TTimeHists(); bool Run(); Double_t GetTime(EHist hist, ETime time) const { if (time == kReal) return fTime[hist][0]; return fTime[hist][1]; } static void SetDebug(Int_t lvl) { fgDebug = lvl; } THnSparse* GetSparse() const { return fSparse; } protected: void Fill(EHist hist); Double_t Check(EHist hist); void SetupHist(EHist hist); void NextValues(); void SetupValues(); private: Double_t* fValue; Int_t fDim; Int_t fBins; Long_t fNum; Double_t fTime[2][2]; THnSparse* fSparse; TH1* fHist; Float_t* fArray; static Int_t fgDebug; }; Int_t TTimeHists::fgDebug = 0; TTimeHists::~TTimeHists() { delete [] fValue; delete fSparse; delete fHist; delete [] fArray; } bool TTimeHists::Run() { // run all tests with current settings, and check for identity of content. Double_t check[2]; Long64_t rep[2]; for (int h = 0; h < 2; ++h) { rep[h] = 0; SetupValues(); try { TStopwatch w; w.Start(); SetupHist((EHist) h); w.Stop(); do { w.Start(kFALSE); Fill((EHist) h); check[h] = Check((EHist) h); w.Stop(); ++rep[h]; } while (!h && w.RealTime() < 0.1 || h && rep[0] > 0 && rep[1] < rep[0]); fTime[h][0] = (1.* fNum * rep[h]) / w.RealTime() / 1E6; fTime[h][1] = (1.* fNum * rep[h]) / w.CpuTime() / 1E6; if (h == 1 && (fTime[h][0] > 1E20 || fTime[h][1] > 1E20)) { do { // some more cycles: w.Start(kFALSE); Fill((EHist) h); Check((EHist) h); w.Stop(); ++rep[h]; } while (w.RealTime() < 0.1); fTime[h][0] = (1.* fNum * rep[h]) / w.RealTime() / 1E6; fTime[h][1] = (1.* fNum * rep[h]) / w.CpuTime() / 1E6; } if (fTime[h][0] > 1E20) fTime[h][0] = 1E20; if (fTime[h][1] > 1E20) fTime[h][1] = 1E20; } catch (std::exception&) { fTime[h][0] = fTime[h][1] = -1.; check[h] = -1.; // can never be < 1 without exception rep[h] = -1; } } if (check[0] != check[1]) if (check[0] != -1.) printf("ERROR: mismatch of histogram / array (%g) and sparse histogram (%g) for dim=%d, bins=%d!\n", check[0], check[1], fDim, fBins); // else // printf("ERROR: cannot allocate histogram / array for dim=%d, bins=%d - out of memory!\n", // fDim, fBins); return (check[0] == check[1]); } void TTimeHists::NextValues() { for (Int_t d = 0; d < fDim; ++d) fValue[d] = gRandom->Gaus() / 4.; } void TTimeHists::SetupValues() { // define fValue if (!fValue) fValue = new Double_t[fDim]; gRandom->SetSeed(42); } void TTimeHists::Fill(EHist hist) { for (Long_t n = 0; n < fNum; ++n) { NextValues(); if (fgDebug > 1) { printf("%ld: fill %s", n, hist == kHist? (fDim < 4 ? "hist" : "arr") : "sparse"); for (Int_t d = 0; d < fDim; ++d) printf("[%g]", fValue[d]); printf("\n"); } if (hist == kHist) { 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: { Long_t pos = 0; for (Int_t d = 0; d < fDim; ++d) { pos *= (fBins + 2); Int_t ibin = (Int_t)((fValue[d] + 1.) / 2. * fBins + 1); if (ibin > fBins) ibin = fBins + 1; if (ibin < 0) ibin = 0; pos += ibin; } ++fArray[pos]; } } } else { fSparse->Fill(fValue); } } } void TTimeHists::SetupHist(EHist hist) { if (hist == kHist) { 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: { MemInfo_t meminfo; gSystem->GetMemInfo(&meminfo); Int_t size = 1; for (Int_t d = 0; d < fDim; ++d) { if ((Int_t)(size * sizeof(Float_t)) > INT_MAX / (fBins + 2) || meminfo.fMemFree > 0 && meminfo.fMemFree / 2 < (Int_t) (size * sizeof(Float_t)/1000/1000)) throw std::bad_alloc(); size *= (fBins + 2); } if (meminfo.fMemFree > 0 && meminfo.fMemFree / 2 < (Int_t) (size * sizeof(Float_t)/1000/1000)) throw std::bad_alloc(); fArray = new Float_t[size]; memset(fArray, 0, sizeof(Float_t)*size); } } } else { Int_t* bins = new Int_t[fDim]; Double_t *xmin = new Double_t[fDim]; Double_t *xmax = new Double_t[fDim]; for (Int_t d = 0; d < fDim; ++d) { bins[d] = fBins; xmin[d] = -1.; xmax[d] = 1.; } fSparse = new THnSparseF("hs", "hs", fDim, bins, xmin, xmax); } } Double_t TTimeHists::Check(EHist hist) { // Check bin content of all bins Double_t check = 0.; Int_t* x = new Int_t[fDim]; memset(x, 0, sizeof(Int_t) * fDim); if (hist == kHist) { Long_t idx = 0; Long_t size = 1; for (Int_t d = 0; d < fDim; ++d) size *= (fBins + 2); while (x[0] <= fBins + 1) { Double_t v = -1.; if (fDim < 4) { Long_t histidx = x[0]; if (fDim == 2) histidx = fHist->GetBin(x[0], x[1]); else if (fDim == 3) histidx = fHist->GetBin(x[0], x[1], x[2]); v = fHist->GetBinContent(histidx); } else v = fArray[idx]; Double_t checkx = 0.; if (v) for (Int_t d = 0; d < fDim; ++d) checkx += x[d]; check += checkx * v; if (fgDebug > 2 || fgDebug > 1 && v) { printf("%s%d", fDim < 4 ? "hist" : "arr", fDim); for (Int_t d = 0; d < fDim; ++d) printf("[%d]", x[d]); printf(" = %g\n", v); } ++x[fDim - 1]; // Adjust the bin idx // no wrapping for dim 0 - it's what we break on! for (Int_t d = fDim - 1; d > 0; --d) { if (x[d] > fBins + 1) { x[d] = 0; ++x[d - 1]; } } ++idx; } // while next bin } else { for (Long64_t i = 0; i < fSparse->GetNbins(); ++i) { Double_t v = fSparse->GetBinContent(i, x); Double_t checkx = 0.; for (Int_t d = 0; d < fDim; ++d) checkx += x[d]; check += checkx * v; if (fgDebug > 1) { printf("sparse%d", fDim); for (Int_t d = 0; d < fDim; ++d) printf("[%d]", x[d]); printf(" = %g\n", v); } } } check /= fNum; if (fgDebug > 0) printf("check %s%d = %g\n", hist == kHist ? (fDim < 4 ? "hist" : "arr") : "sparse", fDim, check); return check; } void sparsehist() { #ifdef __CINT__ 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) { TString name("htime_"); if (h == 0) name += "arr"; else name += "sp"; if (t == 0) name += "_r"; TString title; title.Form("Throughput (fill,get) %s (%s, 1M entries/sec);dim;bins;1M entries/sec", h == 0 ? "THnF/Float_t[n]" : "THnSparseF", t == 0 ? "real" : "CPU"); htime[h][t] = new TH2F(name, title, 6, 0.5, 6.5, 10, 5, 105); } 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); // TTimeHists::SetDebug(2); Double_t max = -1.; for (Int_t dim = 1; dim < 7; ++dim) { printf("Processing dimension %d", dim); for (Int_t bins = 10; bins <= 100; bins += 10) { TTimeHists timer(dim, bins, /*num*/ 1000); timer.Run(); 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); } hsparse_mem->Fill(dim, bins, timer.GetSparse()->GetSparseFractionMem()); hsparse_bins->Fill(dim, bins, timer.GetSparse()->GetSparseFractionBins()); if (max < timer.GetTime(TTimeHists::kSparse, TTimeHists::kReal)) max = timer.GetTime(TTimeHists::kSparse, TTimeHists::kReal); printf("."); fflush(stdout); } printf(" done\n"); } Double_t markersize = 2.5; hsparse_mem->SetMarkerSize(markersize); hsparse_bins->SetMarkerSize(markersize); TH2F* htime_ratio[TTimeHists::kNumTime]; for (int t = 0; t < TTimeHists::kNumTime; ++t) { const char* name = t ? "htime_ratio" : "htime_ratio_r"; htime_ratio[t] = (TH2F*) htime[TTimeHists::kSparse][t]->Clone(name); TString title; title.Form("Relative speed improvement (%s, 1M entries/sec): sparse/hist;dim;bins;#Delta 1M entries/sec", t == 0 ? "real" : "CPU"); htime_ratio[t]->SetTitle(title); htime_ratio[t]->Divide(htime[TTimeHists::kHist][t]); htime_ratio[t]->SetMinimum(0.1); htime_ratio[t]->SetMarkerSize(markersize); } TFile* f = new TFile("sparsehist.root","RECREATE"); TCanvas* canv= new TCanvas("c","c"); canv->Divide(3,3); gStyle->SetPalette(8,0); gStyle->SetPaintTextFormat(".2g"); gStyle->SetOptStat(0); const char* opt = "TEXT COL"; for (int t = 0; t < TTimeHists::kNumTime; ++t) { for (int h = 0; h < TTimeHists::kNumHist; ++h) { htime[h][t]->SetMaximum(max); htime[h][t]->SetMarkerSize(markersize); canv->cd(1 + h + 3 * t); htime[h][t]->Draw(opt); htime[h][t]->Write(); } canv->cd(3 + t * 3); htime_ratio[t]->Draw(opt); gPad->SetLogz(); htime_ratio[t]->Write(); } canv->cd(7); hsparse_mem->Draw(opt); canv->cd(8); hsparse_bins->Draw(opt); hsparse_mem->Write(); hsparse_bins->Write(); canv->Write(); delete f; } sparsehist.C:1 sparsehist.C:2 sparsehist.C:3 sparsehist.C:4 sparsehist.C:5 sparsehist.C:6 sparsehist.C:7 sparsehist.C:8 sparsehist.C:9 sparsehist.C:10 sparsehist.C:11 sparsehist.C:12 sparsehist.C:13 sparsehist.C:14 sparsehist.C:15 sparsehist.C:16 sparsehist.C:17 sparsehist.C:18 sparsehist.C:19 sparsehist.C:20 sparsehist.C:21 sparsehist.C:22 sparsehist.C:23 sparsehist.C:24 sparsehist.C:25 sparsehist.C:26 sparsehist.C:27 sparsehist.C:28 sparsehist.C:29 sparsehist.C:30 sparsehist.C:31 sparsehist.C:32 sparsehist.C:33 sparsehist.C:34 sparsehist.C:35 sparsehist.C:36 sparsehist.C:37 sparsehist.C:38 sparsehist.C:39 sparsehist.C:40 sparsehist.C:41 sparsehist.C:42 sparsehist.C:43 sparsehist.C:44 sparsehist.C:45 sparsehist.C:46 sparsehist.C:47 sparsehist.C:48 sparsehist.C:49 sparsehist.C:50 sparsehist.C:51 sparsehist.C:52 sparsehist.C:53 sparsehist.C:54 sparsehist.C:55 sparsehist.C:56 sparsehist.C:57 sparsehist.C:58 sparsehist.C:59 sparsehist.C:60 sparsehist.C:61 sparsehist.C:62 sparsehist.C:63 sparsehist.C:64 sparsehist.C:65 sparsehist.C:66 sparsehist.C:67 sparsehist.C:68 sparsehist.C:69 sparsehist.C:70 sparsehist.C:71 sparsehist.C:72 sparsehist.C:73 sparsehist.C:74 sparsehist.C:75 sparsehist.C:76 sparsehist.C:77 sparsehist.C:78 sparsehist.C:79 sparsehist.C:80 sparsehist.C:81 sparsehist.C:82 sparsehist.C:83 sparsehist.C:84 sparsehist.C:85 sparsehist.C:86 sparsehist.C:87 sparsehist.C:88 sparsehist.C:89 sparsehist.C:90 sparsehist.C:91 sparsehist.C:92 sparsehist.C:93 sparsehist.C:94 sparsehist.C:95 sparsehist.C:96 sparsehist.C:97 sparsehist.C:98 sparsehist.C:99 sparsehist.C:100 sparsehist.C:101 sparsehist.C:102 sparsehist.C:103 sparsehist.C:104 sparsehist.C:105 sparsehist.C:106 sparsehist.C:107 sparsehist.C:108 sparsehist.C:109 sparsehist.C:110 sparsehist.C:111 sparsehist.C:112 sparsehist.C:113 sparsehist.C:114 sparsehist.C:115 sparsehist.C:116 sparsehist.C:117 sparsehist.C:118 sparsehist.C:119 sparsehist.C:120 sparsehist.C:121 sparsehist.C:122 sparsehist.C:123 sparsehist.C:124 sparsehist.C:125 sparsehist.C:126 sparsehist.C:127 sparsehist.C:128 sparsehist.C:129 sparsehist.C:130 sparsehist.C:131 sparsehist.C:132 sparsehist.C:133 sparsehist.C:134 sparsehist.C:135 sparsehist.C:136 sparsehist.C:137 sparsehist.C:138 sparsehist.C:139 sparsehist.C:140 sparsehist.C:141 sparsehist.C:142 sparsehist.C:143 sparsehist.C:144 sparsehist.C:145 sparsehist.C:146 sparsehist.C:147 sparsehist.C:148 sparsehist.C:149 sparsehist.C:150 sparsehist.C:151 sparsehist.C:152 sparsehist.C:153 sparsehist.C:154 sparsehist.C:155 sparsehist.C:156 sparsehist.C:157 sparsehist.C:158 sparsehist.C:159 sparsehist.C:160 sparsehist.C:161 sparsehist.C:162 sparsehist.C:163 sparsehist.C:164 sparsehist.C:165 sparsehist.C:166 sparsehist.C:167 sparsehist.C:168 sparsehist.C:169 sparsehist.C:170 sparsehist.C:171 sparsehist.C:172 sparsehist.C:173 sparsehist.C:174 sparsehist.C:175 sparsehist.C:176 sparsehist.C:177 sparsehist.C:178 sparsehist.C:179 sparsehist.C:180 sparsehist.C:181 sparsehist.C:182 sparsehist.C:183 sparsehist.C:184 sparsehist.C:185 sparsehist.C:186 sparsehist.C:187 sparsehist.C:188 sparsehist.C:189 sparsehist.C:190 sparsehist.C:191 sparsehist.C:192 sparsehist.C:193 sparsehist.C:194 sparsehist.C:195 sparsehist.C:196 sparsehist.C:197 sparsehist.C:198 sparsehist.C:199 sparsehist.C:200 sparsehist.C:201 sparsehist.C:202 sparsehist.C:203 sparsehist.C:204 sparsehist.C:205 sparsehist.C:206 sparsehist.C:207 sparsehist.C:208 sparsehist.C:209 sparsehist.C:210 sparsehist.C:211 sparsehist.C:212 sparsehist.C:213 sparsehist.C:214 sparsehist.C:215 sparsehist.C:216 sparsehist.C:217 sparsehist.C:218 sparsehist.C:219 sparsehist.C:220 sparsehist.C:221 sparsehist.C:222 sparsehist.C:223 sparsehist.C:224 sparsehist.C:225 sparsehist.C:226 sparsehist.C:227 sparsehist.C:228 sparsehist.C:229 sparsehist.C:230 sparsehist.C:231 sparsehist.C:232 sparsehist.C:233 sparsehist.C:234 sparsehist.C:235 sparsehist.C:236 sparsehist.C:237 sparsehist.C:238 sparsehist.C:239 sparsehist.C:240 sparsehist.C:241 sparsehist.C:242 sparsehist.C:243 sparsehist.C:244 sparsehist.C:245 sparsehist.C:246 sparsehist.C:247 sparsehist.C:248 sparsehist.C:249 sparsehist.C:250 sparsehist.C:251 sparsehist.C:252 sparsehist.C:253 sparsehist.C:254 sparsehist.C:255 sparsehist.C:256 sparsehist.C:257 sparsehist.C:258 sparsehist.C:259 sparsehist.C:260 sparsehist.C:261 sparsehist.C:262 sparsehist.C:263 sparsehist.C:264 sparsehist.C:265 sparsehist.C:266 sparsehist.C:267 sparsehist.C:268 sparsehist.C:269 sparsehist.C:270 sparsehist.C:271 sparsehist.C:272 sparsehist.C:273 sparsehist.C:274 sparsehist.C:275 sparsehist.C:276 sparsehist.C:277 sparsehist.C:278 sparsehist.C:279 sparsehist.C:280 sparsehist.C:281 sparsehist.C:282 sparsehist.C:283 sparsehist.C:284 sparsehist.C:285 sparsehist.C:286 sparsehist.C:287 sparsehist.C:288 sparsehist.C:289 sparsehist.C:290 sparsehist.C:291 sparsehist.C:292 sparsehist.C:293 sparsehist.C:294 sparsehist.C:295 sparsehist.C:296 sparsehist.C:297 sparsehist.C:298 sparsehist.C:299 sparsehist.C:300 sparsehist.C:301 sparsehist.C:302 sparsehist.C:303 sparsehist.C:304 sparsehist.C:305 sparsehist.C:306 sparsehist.C:307 sparsehist.C:308 sparsehist.C:309 sparsehist.C:310 sparsehist.C:311 sparsehist.C:312 sparsehist.C:313 sparsehist.C:314 sparsehist.C:315 sparsehist.C:316 sparsehist.C:317 sparsehist.C:318 sparsehist.C:319 sparsehist.C:320 sparsehist.C:321 sparsehist.C:322 sparsehist.C:323 sparsehist.C:324 sparsehist.C:325 sparsehist.C:326 sparsehist.C:327 sparsehist.C:328 sparsehist.C:329 sparsehist.C:330 sparsehist.C:331 sparsehist.C:332 sparsehist.C:333 sparsehist.C:334 sparsehist.C:335 sparsehist.C:336 sparsehist.C:337 sparsehist.C:338 sparsehist.C:339 sparsehist.C:340 sparsehist.C:341 sparsehist.C:342 sparsehist.C:343 sparsehist.C:344 sparsehist.C:345 sparsehist.C:346 sparsehist.C:347 sparsehist.C:348 sparsehist.C:349 sparsehist.C:350 sparsehist.C:351 sparsehist.C:352 sparsehist.C:353 sparsehist.C:354 sparsehist.C:355 sparsehist.C:356 sparsehist.C:357 sparsehist.C:358 sparsehist.C:359 sparsehist.C:360 sparsehist.C:361 sparsehist.C:362 sparsehist.C:363 sparsehist.C:364 sparsehist.C:365 sparsehist.C:366 sparsehist.C:367 sparsehist.C:368 sparsehist.C:369 sparsehist.C:370 sparsehist.C:371 sparsehist.C:372 sparsehist.C:373 sparsehist.C:374 sparsehist.C:375 sparsehist.C:376 sparsehist.C:377 sparsehist.C:378 sparsehist.C:379 sparsehist.C:380 sparsehist.C:381 sparsehist.C:382 sparsehist.C:383 sparsehist.C:384 sparsehist.C:385 sparsehist.C:386 sparsehist.C:387 sparsehist.C:388 sparsehist.C:389 sparsehist.C:390 sparsehist.C:391 sparsehist.C:392 sparsehist.C:393 sparsehist.C:394 sparsehist.C:395 sparsehist.C:396 sparsehist.C:397 |
|