21#include <TRandomGen.h>
34#include <boost/archive/binary_iarchive.hpp>
35#include <boost/archive/binary_oarchive.hpp>
36#include <boost/histogram.hpp>
37#include <boost/histogram/serialization.hpp>
40namespace bh = boost::histogram;
82 const double scale = 1.0;
84 if (
o->InheritsFrom(TH1::Class())) {
87 return reinterpret_cast<TH1*
>(
o)->GetNcells() *
sizeof(Int_t) / scale;
88 }
else if (
o->InheritsFrom(THnSparse::Class())) {
89 auto* sparse =
reinterpret_cast<THnSparse*
>(
o);
91 return sparse->GetNChunks() * sparse->GetChunkSize() / scale;
92 }
else if (
o->InheritsFrom(THnBase::Class())) {
94 return reinterpret_cast<THnBase*
>(
o)->GetNbins() *
sizeof(Int_t) / scale;
95 }
else if (
o->InheritsFrom(TTree::Class())) {
97 auto tree =
reinterpret_cast<TTree*
>(
o);
98 auto branchList =
tree->GetListOfBranches();
99 for (
const auto* branch : *branchList) {
100 totalSize +=
dynamic_cast<const TBranch*
>(branch)->GetTotalSize();
102 return totalSize / scale;
104 throw std::runtime_error(
"Object with type '" + std::string(
o->ClassName()) +
"' is not one of the mergeable types.");
108 return o->size() *
sizeof(
int);
112 auto end = std::chrono::high_resolution_clock::now();
113 auto start = std::chrono::high_resolution_clock::now();
115 if (
o->InheritsFrom(TH1::Class())) {
117 start = std::chrono::high_resolution_clock::now();
118 reinterpret_cast<TH1*
>(
o)->Merge(
i,
"-NOCHECK");
119 }
else if (
o->InheritsFrom(THnBase::Class())) {
121 start = std::chrono::high_resolution_clock::now();
122 reinterpret_cast<THnBase*
>(
o)->Merge(
i);
123 }
else if (
o->InheritsFrom(TTree::Class())) {
124 start = std::chrono::high_resolution_clock::now();
125 reinterpret_cast<TTree*
>(
o)->Merge(
i);
127 throw std::runtime_error(
"Object with type '" + std::string(
o->ClassName()) +
"' is not one of the mergeable types.");
129 end = std::chrono::high_resolution_clock::now();
133 end = std::chrono::high_resolution_clock::now();
136 auto elapsed_seconds = std::chrono::duration_cast<std::chrono::duration<double>>(
end -
start);
137 return elapsed_seconds.count();
140 auto end = std::chrono::high_resolution_clock::now();
141 auto start = std::chrono::high_resolution_clock::now();
145 end = std::chrono::high_resolution_clock::now();
150 std::ostringstream os;
152 boost::archive::binary_oarchive oa(os);
154 end = std::chrono::high_resolution_clock::now();
157 auto elapsed_seconds = std::chrono::duration_cast<std::chrono::duration<double>>(
end -
start);
158 return elapsed_seconds.count();
161 auto start = std::chrono::high_resolution_clock::now();
162 auto end = std::chrono::high_resolution_clock::now();
166 start = std::chrono::high_resolution_clock::now();
172 auto* storedClass = ftm.ReadClass();
173 if (storedClass ==
nullptr) {
174 throw std::runtime_error(
"Unknown stored class");
176 ftm.SetBufferOffset(0);
178 auto* tObjectClass = TClass::GetClass(
typeid(
TObject));
180 if (!storedClass->InheritsFrom(tObjectClass)) {
181 throw std::runtime_error(
"Class '" + std::string(storedClass->GetName()) +
"'does not inherit from TObject");
184 auto*
object = ftm.ReadObjectAny(storedClass);
185 if (
object ==
nullptr) {
186 throw std::runtime_error(
"Failed to read object with name '" + std::string(storedClass->GetName()) +
"' from message using ROOT serialization.");
190 end = std::chrono::high_resolution_clock::now();
195 std::ostringstream os;
197 boost::archive::binary_oarchive oa(os);
201 start = std::chrono::high_resolution_clock::now();
202 auto deserialisedHistogram =
typename std::remove_pointer<
decltype(
o)>
::type();
203 std::istringstream is(
buf);
204 boost::archive::binary_iarchive ia(is);
205 ia >> deserialisedHistogram;
206 end = std::chrono::high_resolution_clock::now();
207 assert(deserialisedHistogram == *
o);
209 auto elapsed_seconds = std::chrono::duration_cast<std::chrono::duration<double>>(
end -
start);
210 return elapsed_seconds.count();
213 const double scale = 1.0;
217 auto serialisedSize = tm->BufferSize();
219 return serialisedSize / scale;
221 std::ostringstream os;
223 boost::archive::binary_oarchive oa(os);
226 return buf.size() / scale;
233static std::vector<Results> BM_TH1I(
size_t repetitions,
const Parameters p)
236 const size_t entries = p.
entries;
237 const size_t bins = objSize /
sizeof(Int_t);
239 auto m = std::make_unique<TH1I>(
"merged",
"merged",
bins, 0, 1000000);
241 for (
size_t i = 0;
i <
bins;
i++) {
242 m->SetBinContent(
i, 1);
245 std::unique_ptr<TCollection> collection = std::make_unique<TObjArray>();
246 collection->SetOwner(
true);
247 auto uni = std::make_unique<TF1>(
"uni",
"1", 0, 1000000);
248 TH1I*
h =
new TH1I(
"test",
"test",
bins, 0, 1000000);
251 std::vector<Results> allResults;
252 for (
size_t r = 0;
r < repetitions;
r++) {
254 h->FillRandom(
"uni", entries);
261 allResults.push_back(iterationResults);
266static std::vector<Results> BM_TH2I(
size_t repetitions,
const Parameters p)
269 const size_t entries = p.
entries;
270 const size_t bins = std::sqrt(objSize /
sizeof(Int_t));
272 auto m = std::make_unique<TH2I>(
"merged",
"merged",
bins, 0, 1000000,
bins, 0, 1000000);
275 m->SetBinContent(
i, 1);
278 std::unique_ptr<TCollection> collection = std::make_unique<TObjArray>();
279 collection->SetOwner(
true);
280 auto uni = std::make_unique<TF2>(
"uni",
"1", 0, 1000000, 0, 1000000);
281 auto*
h =
new TH2I(
"test",
"test",
bins, 0, 1000000,
bins, 0, 1000000);
284 std::vector<Results> allResults;
285 for (
size_t r = 0;
r < repetitions;
r++) {
287 h->FillRandom(
"uni", entries);
294 allResults.push_back(iterationResults);
299static std::vector<Results> BM_TH3I(
size_t repetitions,
const Parameters p)
302 const size_t entries = p.
entries;
303 const size_t bins = std::pow(objSize /
sizeof(Int_t), 1 / 3.0);
305 auto m = std::make_unique<TH3I>(
"merged",
"merged",
bins, 0, 1000000,
bins, 0, 1000000,
bins, 0, 1000000);
308 m->SetBinContent(
i, 1);
311 std::unique_ptr<TCollection> collection = std::make_unique<TObjArray>();
312 collection->SetOwner(
true);
313 auto uni = std::make_unique<TF3>(
"uni",
"1", 0, 1000000, 0, 1000000, 0, 1000000);
314 auto*
h =
new TH3I(
"test",
"test",
bins, 0, 1000000,
bins, 0, 1000000,
bins, 0, 1000000);
317 std::vector<Results> allResults;
318 for (
size_t r = 0;
r < repetitions;
r++) {
320 h->FillRandom(
"uni", entries);
327 allResults.push_back(iterationResults);
332template <
typename storageT>
333static std::vector<Results> BM_BoostRegular1D(
size_t repetitions,
const Parameters p)
335 const size_t entries = p.
entries;
337 const double min = 0.0;
338 const double max = 1000000.0;
340 auto merged = bh::make_histogram_with(storageT(), bh::axis::regular<>(
bins,
min,
max,
"x"));
342 using HistoType =
decltype(merged);
345 gen.SetSeed(std::random_device()());
346 Double_t randomArray[entries];
348 std::vector<Results> allResults;
349 for (
size_t r = 0;
r < repetitions;
r++) {
350 auto h = bh::make_histogram_with(storageT(), bh::axis::regular<>(
bins,
min,
max,
"x"));
351 gen.RndmArray(entries, randomArray);
352 for (
double rnd : randomArray) {
361 allResults.push_back(iterationResults);
366template <
typename storageT>
367static std::vector<Results> BM_BoostRegular2D(
size_t repetitions,
const Parameters p)
369 const size_t entries = p.
entries;
371 const double min = 0.0;
372 const double max = 1000000.0;
374 auto merged = bh::make_histogram_with(storageT(), bh::axis::regular<>(
bins,
min,
max,
"x"), bh::axis::regular<>(
bins,
min,
max,
"y"));
378 gen.SetSeed(std::random_device()());
379 Double_t randomArrayX[entries];
380 Double_t randomArrayY[entries];
382 std::vector<Results> allResults;
383 for (
size_t r = 0;
r < repetitions;
r++) {
384 auto h = bh::make_histogram_with(storageT(), bh::axis::regular<>(
bins,
min,
max,
"x"), bh::axis::regular<>(
bins,
min,
max,
"y"));
385 gen.RndmArray(entries, randomArrayX);
386 gen.RndmArray(entries, randomArrayY);
387 for (
size_t rnd = 0; rnd < entries; rnd++) {
388 h(randomArrayX[rnd] *
max, randomArrayY[rnd] *
max);
397 allResults.push_back(iterationResults);
402static std::vector<Results> BM_THNSparseI(
size_t repetitions,
const Parameters p)
406 const size_t entries = p.
entries;
408 const Double_t
min = 0.0;
409 const Double_t
max = 1000000.0;
410 const std::vector<Int_t> binsDims(dim,
bins);
411 const std::vector<Double_t> mins(dim,
min);
412 const std::vector<Double_t> maxs(dim,
max);
415 gen.SetSeed(std::random_device()());
416 Double_t randomArray[dim];
418 std::vector<Results> allResults;
419 for (
size_t rep = 0; rep < repetitions; rep++) {
421 std::unique_ptr<TCollection> collection = std::make_unique<TObjArray>();
422 collection->SetOwner(
true);
423 auto*
h =
new THnSparseI(
"test",
"test", dim, binsDims.data(), mins.data(), maxs.data());
426 auto m = std::make_unique<THnSparseI>(
"merged",
"merged", dim, binsDims.data(), mins.data(), maxs.data());
429 gen.RndmArray(dim, randomArray);
430 for (
double&
r : randomArray) {
433 h->Fill(randomArray);
437 gen.RndmArray(dim, randomArray);
438 for (
double&
r : randomArray) {
441 m->Fill(randomArray);
450 allResults.push_back(iterationResults);
455static std::vector<Results> BM_TTree(
size_t repetitions,
const Parameters p)
459 const size_t entries = p.
entries;
461 using branch_t = std::vector<uint64_t>;
462 std::vector<branch_t> branchCollection;
463 for (
size_t i = 0;
i < branches;
i++) {
464 branchCollection.emplace_back(branchSize, 0);
466 auto createTree = [&](std::string
name) -> TTree* {
467 TTree*
tree =
new TTree();
468 for (
size_t i = 0;
i < branchCollection.size();
i++) {
470 &branchCollection[
i],
477 auto fillTree = [&](TTree* t) {
479 gen.SetSeed(std::random_device()());
480 Float_t randomArray[branchSize];
483 for (
auto& branch : branchCollection) {
484 gen.RndmArray(branchSize, randomArray);
485 for (
size_t i = 0;
i < branchSize;
i++) {
486 branch[
i] =
static_cast<uint64_t
>(randomArray[
i]);
493 std::vector<Results> allResults;
494 for (
size_t r = 0;
r < repetitions;
r++) {
495 std::unique_ptr<TCollection> collection = std::make_unique<TObjArray>();
496 collection->SetOwner(
true);
497 TTree* t = createTree(
"input");
501 TTree*
m = createTree(
"merged");
510 allResults.push_back(iterationResults);
520 "objectSize,bins,dimensions,entries,branches,branchSize,"
521 "sizeBytes,sizeSerialisedBytes,deserialisationSeconds,mergingSeconds,serialisationSeconds"
527 for (
const auto r : results) {
530 <<
r.sizeBytes <<
"," <<
r.sizeSerialisedBytes <<
"," <<
r.deserialisationSeconds <<
"," <<
r.mergingSeconds <<
"," <<
r.serialisationSeconds
535int main(
int argc,
const char* argv[])
538 throw std::runtime_error(
"Output file name expected");
546 size_t repetitions = argc < 3 ? 1 : std::atoll(argv[2]);
550 std::vector<Parameters> parameters{
559 for (
const auto& p : parameters) {
560 auto results = BM_TH1I(repetitions, p);
568 std::vector<Parameters> parameters{
577 for (
const auto& p : parameters) {
578 auto results = BM_TH2I(repetitions, p);
586 std::vector<Parameters> parameters{
595 for (
const auto& p : parameters) {
596 auto results = BM_TH3I(repetitions, p);
604 std::vector<Parameters> parameters{
634 for (
const auto& p : parameters) {
635 auto results = BM_THNSparseI(repetitions, p);
643 std::vector<Parameters> parameters{
661 for (
const auto& p : parameters) {
662 auto results = BM_TTree(repetitions, p);
670#define BM_BOOST1DARRAY_FOR(objSize, entries) \
672 constexpr auto p = Parameters::forHistograms(objSize, entries); \
673 auto results = BM_BoostRegular1D<std::array<int32_t, p.objectSize / sizeof(int32_t) + 2>>(repetitions, p); \
674 printResultsCSV(file, "BoostRegular1DArray", p, results); \
675 printResultsCSV(std::cout, "BoostRegular1DArray", p, results); \
688#define BM_BOOST1DVECTOR_FOR(objSize, entries) \
690 constexpr auto p = Parameters::forHistograms(objSize, entries); \
691 auto results = BM_BoostRegular1D<std::vector<int32_t>>(repetitions, p); \
692 printResultsCSV(file, "BoostRegular1DVector", p, results); \
693 printResultsCSV(std::cout, "BoostRegular1DVector", p, results); \
708#define BM_BOOST2DARRAY_FOR(objSize, arrSize, entries) \
710 constexpr auto p = Parameters::forHistograms(objSize, entries); \
711 auto results = BM_BoostRegular2D<std::array<int32_t, arrSize>>(repetitions, p); \
712 printResultsCSV(file, "BoostRegular2DArray", p, results); \
713 printResultsCSV(std::cout, "BoostRegular2DArray", p, results); \
726#define BM_BOOST2DVECTOR_FOR(objSize, entries) \
728 constexpr auto p = Parameters::forHistograms(objSize, entries); \
729 auto results = BM_BoostRegular2D<std::vector<int32_t>>(repetitions, p); \
730 printResultsCSV(file, "BoostRegular2DVector", p, results); \
731 printResultsCSV(std::cout, "BoostRegular2DVector", p, results); \
default_random_engine gen(dev())
#define BM_BOOST1DARRAY_FOR(objSize, entries)
void printResultsCSV(std::ostream &out, std::string name, const Parameters &p, const std::vector< Results > &results)
#define BM_BOOST2DARRAY_FOR(objSize, arrSize, entries)
void printHeaderCSV(std::ostream &out)
#define BM_BOOST1DVECTOR_FOR(objSize, entries)
#define BM_BOOST2DVECTOR_FOR(objSize, entries)
Class for time synchronization of RawReader instances.
GLuint const GLchar * name
GLsizei const GLfloat * value
GLint GLint GLsizei GLint GLenum GLenum type
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLenum GLuint GLenum GLsizei const GLchar * buf
std::string to_string(gsl::span< T, Size > span)
static constexpr Parameters forHistograms(size_t objectSize, size_t entries)
static constexpr Parameters forSparse(size_t bins, size_t dimensions, size_t entries)
static constexpr Parameters forTrees(size_t branches, size_t branchSize, size_t entries)
size_t sizeSerialisedBytes
double serialisationSeconds
double deserialisationSeconds
std::unique_ptr< TTree > tree((TTree *) flIn.Get(std::string(o2::base::NameConf::CTFTREENAME).c_str()))