From bea36a8bc76b6088324f8c1751a81b6fb550e76a Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 3 Sep 2026 21:40:35 +0000 Subject: [PATCH] Parametrize RDataFrame snapshot benchmarks over compression levels Each compression algorithm is now benchmarked at levels 1, 6 and 9 instead of a single hardcoded level, and the benchmarks report the compressed file size and the throughput of uncompressed input bytes. The benchmarked dataset is also made big enough for the compression to dominate over the fixed snapshot overheads (10 million doubles instead of 100 thousand). The input data is generated only once, so that unlike before, the random number generation does not contribute to the measured time. The output file is now written to RB_TEMP_FS and removed afterwards. This implements the improvements proposed for these benchmarks in PR #225 on top of the current state of the repository. --- root/io/io/TFile_RDFSnapshot.cxx | 109 +++++++++++++++++-------------- 1 file changed, 60 insertions(+), 49 deletions(-) diff --git a/root/io/io/TFile_RDFSnapshot.cxx b/root/io/io/TFile_RDFSnapshot.cxx index f646c71b..6ea6ceba 100644 --- a/root/io/io/TFile_RDFSnapshot.cxx +++ b/root/io/io/TFile_RDFSnapshot.cxx @@ -1,68 +1,79 @@ #include "ROOT/RDataFrame.hxx" #include "ROOT/RSnapshotOptions.hxx" +#include "TFile.h" #include "TRandom3.h" +#include "TSystem.h" #include "benchmark/benchmark.h" #include "rootbench/RBConfig.h" +#include +#include +#include -auto SetupRDF() { - // We create an empty data frame - ROOT::RDataFrame tdf(100000); - // We now fill it with random numbers - gRandom->SetSeed(1); - auto tdf_1 = tdf.Define("rnd", []() { return gRandom->Gaus(); }); - return tdf_1; -} +// Number of doubles written per snapshot: large enough that the compression +// dominates over the fixed overheads of the snapshot, small enough to keep +// the total runtime of the benchmarks reasonable. +constexpr ULong64_t kNEntries = 10000000; -auto SetupRDFOptions(ROOT::RCompressionSetting::EAlgorithm::EValues alg, int level) { - ROOT::RDF::RSnapshotOptions options; - options.fCompressionAlgorithm = alg; - options.fCompressionLevel = level; - return options; +// The input data is generated only once, so that the random number generation +// does not contribute to the benchmarked snapshot time. +static const std::vector &GetInputData() +{ + static const std::vector data = [] { + std::vector v(kNEntries); + TRandom3 rng(1); + for (auto &x : v) + x = rng.Gaus(); + return v; + }(); + return data; } +static void BM_TFile_RDFSnapshot(benchmark::State &state, ROOT::RCompressionSetting::EAlgorithm::EValues algo, + const std::string &algoName) +{ + const auto &data = GetInputData(); -static void BM_TFile_RDFSnapshot_ZLIB(benchmark::State &state) { - auto tdf = SetupRDF(); - auto options = SetupRDFOptions(ROOT::RCompressionSetting::EAlgorithm::kZLIB, 1); - for (auto _ : state) { - //And we write out the dataset on disk - tdf.Snapshot("randomNumbers", "bench_data.root", {"rnd"}, options); - } -} -BENCHMARK(BM_TFile_RDFSnapshot_ZLIB)->Unit(benchmark::kMicrosecond); + ROOT::RDataFrame df(kNEntries); + auto dfWithCol = df.Define("rnd", [&data](ULong64_t entry) { return data[entry]; }, {"rdfentry_"}); + ROOT::RDF::RSnapshotOptions options; + options.fCompressionAlgorithm = algo; + options.fCompressionLevel = state.range(0); -static void BM_TFile_RDFSnapshot_LZ4(benchmark::State &state) { - auto tdf = SetupRDF(); - auto options = SetupRDFOptions(ROOT::RCompressionSetting::EAlgorithm::kLZ4, 4); - for (auto _ : state) { - //And we write out the dataset on disk - tdf.Snapshot("randomNumbers", "bench_data.root", {"rnd"}, options); - } -} -BENCHMARK(BM_TFile_RDFSnapshot_LZ4)->Unit(benchmark::kMicrosecond); + const std::string fileName = + RB::GetTempFs() + "/rdfsnapshot_" + algoName + "_" + std::to_string(state.range(0)) + ".root"; + for (auto _ : state) { + // And we write out the dataset on disk + dfWithCol.Snapshot("randomNumbers", fileName, {"rnd"}, options); + } -static void BM_TFile_RDFSnapshot_LZMA (benchmark::State &state) { - auto tdf = SetupRDF(); - auto options = SetupRDFOptions(ROOT::RCompressionSetting::EAlgorithm::kLZMA, 8); - for (auto _ : state) { - //And we write out the dataset on disk - tdf.Snapshot("randomNumbers", "bench_data.root", {"rnd"}, options); - } -} -BENCHMARK(BM_TFile_RDFSnapshot_LZMA)->Unit(benchmark::kMicrosecond); - -static void BM_TFile_RDFSnapshot_ZSTD (benchmark::State &state) { - auto tdf = SetupRDF(); - auto options = SetupRDFOptions(ROOT::RCompressionSetting::EAlgorithm::kZSTD, 6); - for (auto _ : state) { - //And we write out the dataset on disk - tdf.Snapshot("randomNumbers", "bench_data.root", {"rnd"}, options); - } + { + std::unique_ptr file{TFile::Open(fileName.c_str())}; + state.counters["comp_size"] = file->GetSize(); + } + // Reports the throughput of uncompressed input bytes as bytes_per_second. + state.SetBytesProcessed(state.iterations() * kNEntries * sizeof(double)); + + gSystem->Unlink(fileName.c_str()); } -BENCHMARK(BM_TFile_RDFSnapshot_ZSTD)->Unit(benchmark::kMicrosecond); + +BENCHMARK_CAPTURE(BM_TFile_RDFSnapshot, ZLIB, ROOT::RCompressionSetting::EAlgorithm::kZLIB, "zlib") +->Arg(1)->Arg(6)->Arg(9) +->Unit(benchmark::kMillisecond); + +BENCHMARK_CAPTURE(BM_TFile_RDFSnapshot, LZMA, ROOT::RCompressionSetting::EAlgorithm::kLZMA, "lzma") +->Arg(1)->Arg(6)->Arg(9) +->Unit(benchmark::kMillisecond); + +BENCHMARK_CAPTURE(BM_TFile_RDFSnapshot, LZ4, ROOT::RCompressionSetting::EAlgorithm::kLZ4, "lz4") +->Arg(1)->Arg(6)->Arg(9) +->Unit(benchmark::kMillisecond); + +BENCHMARK_CAPTURE(BM_TFile_RDFSnapshot, ZSTD, ROOT::RCompressionSetting::EAlgorithm::kZSTD, "zstd") +->Arg(1)->Arg(6)->Arg(9) +->Unit(benchmark::kMillisecond); BENCHMARK_MAIN();