From 6470738260c9f55ca7fe5ad5e74c1a1b9ad79ccc Mon Sep 17 00:00:00 2001 From: silverweed Date: Thu, 3 Sep 2026 14:45:09 +0200 Subject: [PATCH 1/2] [ntupleutil] clang-format RNTupleInspector.hxx --- tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx b/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx index 957b1550b9c88..30bc3ce254f96 100644 --- a/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx +++ b/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx @@ -105,7 +105,9 @@ public: : fColumnDescriptor(colDesc), fCompressedPageSizes(compressedPageSizes), fElementSize(elemSize), - fNElements(nElems){}; + fNElements(nElems) + { + } ~RColumnInspector() = default; const ROOT::RColumnDescriptor &GetDescriptor() const { return fColumnDescriptor; } @@ -136,7 +138,9 @@ public: public: RFieldTreeInspector(const ROOT::RFieldDescriptor &fieldDesc, std::uint64_t onDiskSize, std::uint64_t inMemSize) - : fRootFieldDescriptor(fieldDesc), fCompressedSize(onDiskSize), fUncompressedSize(inMemSize){}; + : fRootFieldDescriptor(fieldDesc), fCompressedSize(onDiskSize), fUncompressedSize(inMemSize) + { + } ~RFieldTreeInspector() = default; const ROOT::RFieldDescriptor &GetDescriptor() const { return fRootFieldDescriptor; } From 363ba670134159a78e7eebbe8d719c04f33baead Mon Sep 17 00:00:00 2001 From: silverweed Date: Thu, 3 Sep 2026 14:39:21 +0200 Subject: [PATCH 2/2] [ntupleutil] add RNTupleInspector::GetPagesPerClusterDistribution --- tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx | 4 ++ tree/ntupleutil/src/RNTupleInspector.cxx | 64 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx b/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx index 30bc3ce254f96..407c58c408bfa 100644 --- a/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx +++ b/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx @@ -430,6 +430,10 @@ public: std::string histName = "", std::string histTitle = "", size_t nBins = 64); + std::unique_ptr GetPagesPerClusterDistribution(std::initializer_list colTypes = {}, + std::string_view histName = "", + std::string_view histTitle = "", size_t nBins = 32); + ///////////////////////////////////////////////////////////////////////////// /// \brief Get storage information for a given (sub)field by ID. /// diff --git a/tree/ntupleutil/src/RNTupleInspector.cxx b/tree/ntupleutil/src/RNTupleInspector.cxx index a3287a1d4d2ff..5b0bf5154e0d4 100644 --- a/tree/ntupleutil/src/RNTupleInspector.cxx +++ b/tree/ntupleutil/src/RNTupleInspector.cxx @@ -455,6 +455,70 @@ ROOT::Experimental::RNTupleInspector::GetPageSizeDistribution(std::initializer_l return stackedHist; } +std::unique_ptr ROOT::Experimental::RNTupleInspector::GetPagesPerClusterDistribution( + std::initializer_list colTypes, std::string_view histName, std::string_view histTitle, + size_t nBins) +{ + if (histName.empty()) + histName = "pagesPerClusterHist"; + if (histTitle.empty()) + histTitle = "#pages per cluster"; + + auto stackedHist = std::make_unique(std::string(histName).c_str(), std::string(histTitle).c_str()); + // Each element of the vector contains the sum of all pages of all columns of each type. + std::vector> pagesPerClusterPerColumnType; + + std::vector colTypeVec = colTypes; + if (std::empty(colTypes)) { + colTypeVec = GetColumnTypes(); + } + + for (const auto &clDesc : fDescriptor.GetClusterIterable()) { + auto &pagesPerColumnTypeInThisCluster = pagesPerClusterPerColumnType.emplace_back(); + for (const auto &colRange : clDesc.GetColumnRangeIterable()) { + const auto colId = colRange.GetPhysicalColumnId(); + const auto &colDesc = fDescriptor.GetColumnDescriptor(colId); + const auto nPages = clDesc.GetPageRange(colId).GetPageInfos().size(); + auto &nPagesForThisType = pagesPerColumnTypeInThisCluster[colDesc.GetType()]; + nPagesForThisType += nPages; + } + } + + double histMin = std::numeric_limits::max(); + double histMax = 0; + for (const auto &pagesPerType : pagesPerClusterPerColumnType) { + auto [min, max] = std::minmax_element(pagesPerType.begin(), pagesPerType.end(), + [](const auto &a, const auto &b) { return a.second < b.second; }); + histMin = std::min(histMin, min->second); + histMax = std::max(histMax, max->second); + } + + std::cout << "histMin = " << histMin << ", histMax = " << histMax << "\n"; + + std::array, static_cast(ENTupleColumnType::kMax)> histsPerType; + for (const auto &pagesPerType : pagesPerClusterPerColumnType) { + for (const auto &[colType, nPages] : pagesPerType) { + auto &hist = histsPerType[static_cast(colType)]; + if (!hist) { + hist = + std::make_unique(ROOT::Internal::RColumnElementBase::GetColumnTypeName(colType), + TString::Format("%s_%s", std::string(histTitle).c_str(), + ROOT::Internal::RColumnElementBase::GetColumnTypeName(colType)), + nBins, histMin, histMax + ((histMax - histMin) / static_cast(nBins))); + } + hist->Fill(nPages); + } + } + + for (auto &hist : histsPerType) { + if (hist) { + stackedHist->Add(hist.release()); + } + } + + return stackedHist; +} + //------------------------------------------------------------------------------ const ROOT::Experimental::RNTupleInspector::RFieldTreeInspector &