Hello @mdessole,
This demo may reproduce my problem. With [UniformFill], time cost by [CopyTH3ToHnSparse] is always resonable no matter how many entries it fills. But for [GausFill], time cost get exponential longer when entries get more than 500x500x500.
#include <TH3.h>
#include <TRandom3.h>
#include <iostream>
#include <cmath>
#include <string>
#include <fstream>
#include <THnSparse.h>
#include <ctime>
std::unique_ptr<THnSparse> CopyTH3ToHnSparse(const TH3* h3)
{
clock_t clkStart, clkStop;
//time_t tStart, tStop;
clkStart = clock();
//tStart = time(NULL);
int iBins[3];
double dMin[3];
double dMax[3];
std::vector<const TAxis*> vAxis = { h3->GetXaxis(), h3->GetYaxis(), h3->GetZaxis() };
for (int i = 0; i < 3; i++) {
iBins[i] = vAxis[i]->GetNbins();
dMin[i] = vAxis[i]->GetXmin();
dMax[i] = vAxis[i]->GetXmax();
//printf("Axis[%d]: Bin[%5d], Min[%.3f], Max[%.3f]\n", i, iBins[i], dMin[i], dMax[i]);
}
std::unique_ptr<THnSparse> hnsp(new THnSparseD(h3->GetName(), h3->GetTitle(), 3, iBins, dMin, dMax));
long nbins = h3->GetNcells();
int index[3] = { 0, 0, 0 };
for (int i = 0; i < nbins; i++)
{
double value = h3->GetBinContent(i);
double error = h3->GetBinError(i);
if (!value && !error)continue;
h3->GetBinXYZ(i, index[0], index[1], index[2]);
long linindex = hnsp->GetBin(index, true);
hnsp->SetBinContent(linindex, value);
hnsp->SetBinError(linindex, error);
//hnsp->SetBinContent(index, value);
//hnsp->SetBinError(index, error);
}
hnsp->SetEntries(h3->GetEntries());
clkStop = clock();
//tStop = time(NULL);
std::printf("[THnSparse]: Sparse Fraction of Bins: %.5f\n", hnsp->GetSparseFractionBins());
std::printf("[THnSparse]: Sparse Fraction of Mem: %.5f\n", hnsp->GetSparseFractionMem());
std::printf("[THnSparse]: CPU Time: %10.3f second(s). \n", double(clkStop - clkStart) / CLOCKS_PER_SEC);
//std::printf("----Real Time: %10.3f second(s). \n", double(tStop - tStart));
return hnsp;
}
void UniformFill(TH3D* h3, long nfill, TRandom3* random)
{
clock_t clkFillStart, clkFillStop;
clkFillStart = clock();
for (long i = 0; i<nfill; i++)
{
auto x = random->Uniform(100.0) - 50.0;
auto y = random->Uniform(100.0) - 50.0;
auto z = random->Uniform(100.0) - 50.0;
auto value = random->Uniform(10.0);
h3->Fill(x, y, z, value);
}
clkFillStop = clock();
std::printf("[Histogram Uniform Fill] Fill Count: %ld, CPU Time: %10.3f second(s). \n", nfill, double(clkFillStop - clkFillStart) / CLOCKS_PER_SEC);
return;
}
void GausFill(TH3D* h3, long nfill, TRandom3* random)
{
clock_t clkFillStart, clkFillStop;
clkFillStart = clock();
for (long i = 0; i < nfill; i++)
{
int icasex = random->Integer(10);
int icasey = random->Integer(10);
int icasez = random->Integer(10);
double dCenterx = (double(icasex) - 4.5) * 10.0;
double dCentery = (double(icasey) - 4.5) * 10.0;
double dCenterz = (double(icasez) - 4.5) * 10.0;
double x = random->Gaus(dCenterx, 2.0);
double y = random->Gaus(dCentery, 2.0);
double z = random->Gaus(dCenterz, 2.0);
double value = random->Uniform(10.0);
h3->Fill(x, y, z, value);
}
clkFillStop = clock();
std::printf("[Histogram Gaus Fill] Fill Count: %ld, CPU Time: %10.3f second(s). \n", nfill, double(clkFillStop - clkFillStart) / CLOCKS_PER_SEC);
return;
}
int main(int argc, char** argv)
{
int iBins[3] = { 500, 500, 500 };
double dMin[3] = { -50., -50., -50. };
double dMax[3] = { 50., 50., 50. };
TRandom3* random = new TRandom3();
TH3D* h3 = new TH3D("TH3", "TH3",
iBins[0], dMin[0], dMax[0],
iBins[1], dMin[1], dMax[1],
iBins[2], dMin[2], dMax[2]
);
long nfill1 = 100 * 100 * 100;
long nfill2 = 500 * 500 * 500;
printf("-->Uniform Fill: \n");
UniformFill(h3, nfill1, random);
std::unique_ptr<THnSparse> hnsp1 = CopyTH3ToHnSparse(h3);
UniformFill(h3, nfill2, random);
std::unique_ptr<THnSparse> hnsp2 = CopyTH3ToHnSparse(h3);
delete h3;
TH3D* h3g = new TH3D("TH3", "TH3",
iBins[0], dMin[0], dMax[0],
iBins[1], dMin[1], dMax[1],
iBins[2], dMin[2], dMax[2]
);
printf("-->Gaus Fill: \n");
GausFill(h3g, nfill1, random);
std::unique_ptr<THnSparse> hnsp3 = CopyTH3ToHnSparse(h3g);
GausFill(h3g, nfill2, random);
std::unique_ptr<THnSparse> hnsp4 = CopyTH3ToHnSparse(h3g);
delete h3g;
delete random;
return 0;
}
My local machine output:
This is the flame graph draw from perf record data
