From 42fcc760a605eb762b929a7d09d0109b300c9717 Mon Sep 17 00:00:00 2001 From: albfsg Date: Wed, 17 Jun 2026 13:12:16 +0200 Subject: [PATCH 1/4] [ntuple] Add flamegraph visualizator backend supporting Speedscope --- tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx | 13 +++ tree/ntupleutil/src/RNTupleInspector.cxx | 110 ++++++++++++++++++ tree/ntupleutil/test/ntuple_inspector.cxx | 57 +++++++++ 3 files changed, 180 insertions(+) diff --git a/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx b/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx index 4f679532c1c87..c721bb120a18c 100644 --- a/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx +++ b/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx @@ -50,6 +50,10 @@ enum class ENTupleInspectorHist { kUncompressedSize }; +enum class EFlamegraphSpecificationFormat { + kSpeedscopeJSON +}; + // clang-format off /** \class ROOT::Experimental::RNTupleInspector @@ -493,6 +497,15 @@ public: { PrintFieldTreeAsDot(GetDescriptor().GetFieldZero(), output); } + + ///////////////////////////////////////////////////////////////////////////// + /// \brief Print a string that represents the tree of the (sub)fields and columns of an RNTuple in a format which a + /// flamegraph visualizer can render + /// + /// \param[in] format The output format for the flamegraph specification (right now only supports Speedscope's JSON) + /// + void PrintFieldTreeAsFlamegraphSpecification(EFlamegraphSpecificationFormat format, + std::ostream &output = std::cout) const; }; } // namespace Experimental } // namespace ROOT diff --git a/tree/ntupleutil/src/RNTupleInspector.cxx b/tree/ntupleutil/src/RNTupleInspector.cxx index 1a5b192f6ad53..7cdef248476e9 100644 --- a/tree/ntupleutil/src/RNTupleInspector.cxx +++ b/tree/ntupleutil/src/RNTupleInspector.cxx @@ -565,3 +565,113 @@ void ROOT::Experimental::RNTupleInspector::PrintFieldTreeAsDot(const ROOT::RFiel if (isZeroField) output << "}"; } + +void ROOT::Experimental::RNTupleInspector::PrintFieldTreeAsFlamegraphSpecification( + EFlamegraphSpecificationFormat format, std::ostream &output) const +{ + (void)format; // There is only one format at the moment + + const auto &tupleDescriptor = GetDescriptor(); + ROOT::DescriptorId_t rootId = tupleDescriptor.GetFieldZeroId(); + const auto &rootFieldDescriptor = tupleDescriptor.GetFieldDescriptor(rootId); + + struct FrameDescription { + std::string name; + std::string type; + size_t byteSize = 0; + char kind; // 'F' or 'C' for field or column + }; + + struct TimelineOcurrence { + size_t frameDescriptionIndex; + unsigned int timestamp; + char type; // 'O' or 'C' for open or close + }; + + std::vector frameDescriptions; + std::vector timelineOcurrences; + unsigned int currentTime = 0; + + auto visitFieldsDFS = [&](auto &self, const ROOT::RFieldDescriptor &fieldDescriptor) -> size_t { + FrameDescription fieldFrame; + fieldFrame.name = tupleDescriptor.GetQualifiedFieldName(fieldDescriptor.GetId()); + fieldFrame.type = fieldDescriptor.GetTypeName(); + fieldFrame.kind = 'F'; + frameDescriptions.push_back(fieldFrame); + + size_t frameDescriptionIndex = frameDescriptions.size() - 1; + + timelineOcurrences.push_back({frameDescriptionIndex, currentTime, 'O'}); + + size_t subTreeSize = 0; + const auto &childIds = fieldDescriptor.GetLinkIds(); + + for (const auto &childFieldId : childIds) { + const auto &childFieldDescriptor = tupleDescriptor.GetFieldDescriptor(childFieldId); + subTreeSize += self(self, childFieldDescriptor); + } + + for (const auto &columnDescriptor : tupleDescriptor.GetColumnIterable(fieldDescriptor.GetId())) { + const auto &columnInfo = GetColumnInspector(columnDescriptor.GetPhysicalId()); + size_t columnSize = columnInfo.GetCompressedSize(); + + FrameDescription columnFrame; + + columnFrame.name = tupleDescriptor.GetQualifiedFieldName(fieldDescriptor.GetId()) + " [col#" + + std::to_string(columnDescriptor.GetPhysicalId()) + "]"; + columnFrame.type = ROOT::Internal::RColumnElementBase::GetColumnTypeName(columnDescriptor.GetType()); + columnFrame.byteSize = columnSize; + columnFrame.kind = 'C'; + frameDescriptions.push_back(columnFrame); + + size_t columnFrameIdx = frameDescriptions.size() - 1; + + timelineOcurrences.push_back({columnFrameIdx, currentTime, 'O'}); + currentTime += columnSize; + timelineOcurrences.push_back({columnFrameIdx, currentTime, 'C'}); + + subTreeSize += columnSize; + } + + frameDescriptions[frameDescriptionIndex].byteSize = subTreeSize; + + timelineOcurrences.push_back({frameDescriptionIndex, currentTime, 'C'}); + + return subTreeSize; + }; + + visitFieldsDFS(visitFieldsDFS, rootFieldDescriptor); + + output << "{\n"; + output << " \"$schema\":\"https://www.speedscope.app/file-format-schema.json\",\n"; + output << " \"shared\":{\n"; + output << " \"frames\":[\n"; + + for (size_t i = 0; i < frameDescriptions.size(); ++i) { + output << " { \"name\":\"" << frameDescriptions[i].name + << "\", \"file\":\"Type: " << frameDescriptions[i].type << ", Size: " << frameDescriptions[i].byteSize + << "B\" }" << (i + 1 < frameDescriptions.size() ? ",\n" : "\n"); + } + + output << " ]\n"; + output << " },\n"; + output << " \"profiles\":[\n"; + output << " {\n"; + output << " \"type\":\"evented\",\n"; + output << " \"name\":\"Flattened Timeline\",\n"; + output << " \"unit\":\"bytes\",\n"; + output << " \"startValue\":0,\n"; + output << " \"endValue\":" << currentTime << ",\n"; + output << " \"events\":[\n"; + + for (size_t i = 0; i < timelineOcurrences.size(); ++i) { + const auto &e = timelineOcurrences[i]; + output << " {\"type\":\"" << e.type << "\",\"frame\":" << e.frameDescriptionIndex + << ",\"at\":" << e.timestamp << "}" << (i + 1 < timelineOcurrences.size() ? ",\n" : "\n"); + } + + output << " ]\n"; + output << " }\n"; + output << " ]\n"; + output << "}\n"; +} diff --git a/tree/ntupleutil/test/ntuple_inspector.cxx b/tree/ntupleutil/test/ntuple_inspector.cxx index 5812a926eb9ee..6364f1c78d497 100644 --- a/tree/ntupleutil/test/ntuple_inspector.cxx +++ b/tree/ntupleutil/test/ntuple_inspector.cxx @@ -862,3 +862,60 @@ TEST(RNTupleInspector, FieldTreeAsDot) "int

Type: std::int32_t

ID: 1

>]\n}"; EXPECT_EQ(dot, expected); } + +TEST(RNTupleInspector, FieldTreeAsFlamegraphSpecification) +{ + FileRaii fileGuard("test_ntuple_inspector_field_tree_as_flamegraph_specification"); + { + auto model = RNTupleModel::Create(); + auto fieldFloat1 = model->MakeField("float1"); + auto fieldInt = model->MakeField("int"); + auto writer = RNTupleWriter::Recreate(std::move(model), "ntuple", fileGuard.GetPath()); + + for (int i = 0; i < 10; ++i) { + *fieldFloat1 = 3.14f * i; + *fieldInt = 42 * i; + writer->Fill(); + } + } + auto inspector = RNTupleInspector::Create("ntuple", fileGuard.GetPath()); + std::ostringstream flamegraphSpecificationStream; + inspector->PrintFieldTreeAsFlamegraphSpecification( + ROOT::Experimental::EFlamegraphSpecificationFormat::kSpeedscopeJSON, flamegraphSpecificationStream); + const std::string flamegraphSpecification = flamegraphSpecificationStream.str(); + const std::string &expected = R"({ + "$schema":"https://www.speedscope.app/file-format-schema.json", + "shared":{ + "frames":[ + { "name":"", "file":"Type: , Size: 80B" }, + { "name":"float1", "file":"Type: float, Size: 40B" }, + { "name":"float1 [col#0]", "file":"Type: SplitReal32, Size: 40B" }, + { "name":"int", "file":"Type: std::int32_t, Size: 40B" }, + { "name":"int [col#1]", "file":"Type: SplitInt32, Size: 40B" } + ] + }, + "profiles":[ + { + "type":"evented", + "name":"Flattened Timeline", + "unit":"bytes", + "startValue":0, + "endValue":80, + "events":[ + {"type":"O","frame":0,"at":0}, + {"type":"O","frame":1,"at":0}, + {"type":"O","frame":2,"at":0}, + {"type":"C","frame":2,"at":40}, + {"type":"C","frame":1,"at":40}, + {"type":"O","frame":3,"at":40}, + {"type":"O","frame":4,"at":40}, + {"type":"C","frame":4,"at":80}, + {"type":"C","frame":3,"at":80}, + {"type":"C","frame":0,"at":80} + ] + } + ] +} +)"; + EXPECT_EQ(flamegraphSpecification, expected); +} From fa47fb9f1f4254462c74b2c42df59b35dfbccc7d Mon Sep 17 00:00:00 2001 From: albfsg Date: Thu, 18 Jun 2026 13:03:06 +0200 Subject: [PATCH 2/4] Apply to the feature and test in commit 42fcc76 changes proposed in comments --- tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx | 10 +- tree/ntupleutil/src/RNTupleInspector.cxx | 176 ++++++++++-------- tree/ntupleutil/test/ntuple_inspector.cxx | 15 +- 3 files changed, 107 insertions(+), 94 deletions(-) diff --git a/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx b/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx index c721bb120a18c..ac10afcdf95df 100644 --- a/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx +++ b/tree/ntupleutil/inc/ROOT/RNTupleInspector.hxx @@ -50,7 +50,8 @@ enum class ENTupleInspectorHist { kUncompressedSize }; -enum class EFlamegraphSpecificationFormat { +enum class ESchemaProfileFormat { + /// https://www.speedscope.app/file-format-schema.json kSpeedscopeJSON }; @@ -500,12 +501,11 @@ public: ///////////////////////////////////////////////////////////////////////////// /// \brief Print a string that represents the tree of the (sub)fields and columns of an RNTuple in a format which a - /// flamegraph visualizer can render + /// performance profile visualizer can render /// - /// \param[in] format The output format for the flamegraph specification (right now only supports Speedscope's JSON) + /// \param[in] format The output format for the flamegraph specification /// - void PrintFieldTreeAsFlamegraphSpecification(EFlamegraphSpecificationFormat format, - std::ostream &output = std::cout) const; + void PrintSchemaProfile(ESchemaProfileFormat format, std::ostream &output = std::cout) const; }; } // namespace Experimental } // namespace ROOT diff --git a/tree/ntupleutil/src/RNTupleInspector.cxx b/tree/ntupleutil/src/RNTupleInspector.cxx index 7cdef248476e9..aa7468522599f 100644 --- a/tree/ntupleutil/src/RNTupleInspector.cxx +++ b/tree/ntupleutil/src/RNTupleInspector.cxx @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -566,44 +567,96 @@ void ROOT::Experimental::RNTupleInspector::PrintFieldTreeAsDot(const ROOT::RFiel output << "}"; } -void ROOT::Experimental::RNTupleInspector::PrintFieldTreeAsFlamegraphSpecification( - EFlamegraphSpecificationFormat format, std::ostream &output) const +struct SpeedscopeFrame { + std::string primaryString; + std::string secondaryString; + std::uint64_t openingPosition = 0; + std::uint64_t closingPosition = 0; +}; + +static void PrintSchemaProfileAsSpeedscope(const std::vector &frames, std::ostream &output) { - (void)format; // There is only one format at the moment + output << "{\n"; + output << " \"$schema\":\"https://www.speedscope.app/file-format-schema.json\",\n"; + output << " \"shared\":{\n"; + output << " \"frames\":[\n"; - const auto &tupleDescriptor = GetDescriptor(); - ROOT::DescriptorId_t rootId = tupleDescriptor.GetFieldZeroId(); - const auto &rootFieldDescriptor = tupleDescriptor.GetFieldDescriptor(rootId); + for (std::size_t i = 0; i < frames.size(); ++i) { + output << " { \"name\":\"" << frames[i].primaryString + << "\", \"file\":\"Type: " << frames[i].secondaryString + << ", Size: " << frames[i].closingPosition - frames[i].openingPosition << "B\" }" + << (i + 1 < frames.size() ? ",\n" : "\n"); + } - struct FrameDescription { - std::string name; - std::string type; - size_t byteSize = 0; - char kind; // 'F' or 'C' for field or column - }; + output << " ]\n"; + output << " },\n"; + output << " \"profiles\":[\n"; + output << " {\n"; + output << " \"type\":\"evented\",\n"; + output << " \"name\":\"Flattened Timeline\",\n"; + output << " \"unit\":\"bytes\",\n"; + output << " \"startValue\":0,\n"; + output << " \"endValue\":" << frames.back().closingPosition << ",\n"; + output << " \"events\":[\n"; + + bool first = true; + + // Parameter idx Index of the frame being processed + // Parameter limit + // - If the frame is not root: Closing Position of it's father + // - If the frame is root: Closing Position of the last element of frames + // Returns index of the processed frame in the vector frames + std::function processRecursive = [&](std::size_t idx, + std::uint32_t limit) -> std::size_t { + while (idx < frames.size() && frames[idx].openingPosition < limit) { + std::size_t currentIdx = idx; + + if (!first) + output << ",\n"; + + output << " {\"type\":\"O\",\"frame\":" << currentIdx + << ",\"at\":" << frames[currentIdx].openingPosition << "}"; + first = false; + + idx = processRecursive(idx + 1, frames[currentIdx].closingPosition); - struct TimelineOcurrence { - size_t frameDescriptionIndex; - unsigned int timestamp; - char type; // 'O' or 'C' for open or close + output << ",\n {\"type\":\"C\",\"frame\":" << currentIdx + << ",\"at\":" << frames[currentIdx].closingPosition << "}"; + } + return idx; }; - std::vector frameDescriptions; - std::vector timelineOcurrences; - unsigned int currentTime = 0; + processRecursive(0, frames.back().closingPosition); + + output << "\n ]\n"; + output << " }\n"; + output << " ]\n"; + output << "}\n"; +} + +void ROOT::Experimental::RNTupleInspector::PrintSchemaProfile(ESchemaProfileFormat format, std::ostream &output) const +{ + // There is only one format at the moment + assert(format == ESchemaProfileFormat::kSpeedscopeJSON); + + const auto &tupleDescriptor = GetDescriptor(); + ROOT::DescriptorId_t rootId = tupleDescriptor.GetFieldZeroId(); + const auto &rootFieldDescriptor = tupleDescriptor.GetFieldDescriptor(rootId); - auto visitFieldsDFS = [&](auto &self, const ROOT::RFieldDescriptor &fieldDescriptor) -> size_t { - FrameDescription fieldFrame; - fieldFrame.name = tupleDescriptor.GetQualifiedFieldName(fieldDescriptor.GetId()); - fieldFrame.type = fieldDescriptor.GetTypeName(); - fieldFrame.kind = 'F'; - frameDescriptions.push_back(fieldFrame); + std::vector frames; + std::uint32_t positionCursor = 0; - size_t frameDescriptionIndex = frameDescriptions.size() - 1; + // Returns size of the visited field + auto visitFieldsRecursive = [&](auto &self, const ROOT::RFieldDescriptor &fieldDescriptor) -> std::size_t { + SpeedscopeFrame fieldSpeedscopeFrame; + fieldSpeedscopeFrame.primaryString = tupleDescriptor.GetQualifiedFieldName(fieldDescriptor.GetId()); + fieldSpeedscopeFrame.secondaryString = fieldDescriptor.GetTypeName(); + fieldSpeedscopeFrame.openingPosition = positionCursor; + frames.push_back(fieldSpeedscopeFrame); - timelineOcurrences.push_back({frameDescriptionIndex, currentTime, 'O'}); + std::size_t fieldSpeedscopeFrameIndex = frames.size() - 1; - size_t subTreeSize = 0; + std::size_t subTreeSize = 0; const auto &childIds = fieldDescriptor.GetLinkIds(); for (const auto &childFieldId : childIds) { @@ -613,65 +666,26 @@ void ROOT::Experimental::RNTupleInspector::PrintFieldTreeAsFlamegraphSpecificati for (const auto &columnDescriptor : tupleDescriptor.GetColumnIterable(fieldDescriptor.GetId())) { const auto &columnInfo = GetColumnInspector(columnDescriptor.GetPhysicalId()); - size_t columnSize = columnInfo.GetCompressedSize(); - - FrameDescription columnFrame; - - columnFrame.name = tupleDescriptor.GetQualifiedFieldName(fieldDescriptor.GetId()) + " [col#" + - std::to_string(columnDescriptor.GetPhysicalId()) + "]"; - columnFrame.type = ROOT::Internal::RColumnElementBase::GetColumnTypeName(columnDescriptor.GetType()); - columnFrame.byteSize = columnSize; - columnFrame.kind = 'C'; - frameDescriptions.push_back(columnFrame); - - size_t columnFrameIdx = frameDescriptions.size() - 1; - - timelineOcurrences.push_back({columnFrameIdx, currentTime, 'O'}); - currentTime += columnSize; - timelineOcurrences.push_back({columnFrameIdx, currentTime, 'C'}); - + std::size_t columnSize = columnInfo.GetCompressedSize(); + + SpeedscopeFrame columnSpeedscopeFrame; + columnSpeedscopeFrame.primaryString = tupleDescriptor.GetQualifiedFieldName(fieldDescriptor.GetId()) + + " [col#" + std::to_string(columnDescriptor.GetPhysicalId()) + "]"; + columnSpeedscopeFrame.secondaryString = + ROOT::Internal::RColumnElementBase::GetColumnTypeName(columnDescriptor.GetType()); + columnSpeedscopeFrame.openingPosition = positionCursor; + positionCursor += columnSize; + columnSpeedscopeFrame.closingPosition = positionCursor; + frames.push_back(columnSpeedscopeFrame); subTreeSize += columnSize; } - frameDescriptions[frameDescriptionIndex].byteSize = subTreeSize; - - timelineOcurrences.push_back({frameDescriptionIndex, currentTime, 'C'}); + frames[fieldSpeedscopeFrameIndex].closingPosition = positionCursor; return subTreeSize; }; - visitFieldsDFS(visitFieldsDFS, rootFieldDescriptor); - - output << "{\n"; - output << " \"$schema\":\"https://www.speedscope.app/file-format-schema.json\",\n"; - output << " \"shared\":{\n"; - output << " \"frames\":[\n"; - - for (size_t i = 0; i < frameDescriptions.size(); ++i) { - output << " { \"name\":\"" << frameDescriptions[i].name - << "\", \"file\":\"Type: " << frameDescriptions[i].type << ", Size: " << frameDescriptions[i].byteSize - << "B\" }" << (i + 1 < frameDescriptions.size() ? ",\n" : "\n"); - } - - output << " ]\n"; - output << " },\n"; - output << " \"profiles\":[\n"; - output << " {\n"; - output << " \"type\":\"evented\",\n"; - output << " \"name\":\"Flattened Timeline\",\n"; - output << " \"unit\":\"bytes\",\n"; - output << " \"startValue\":0,\n"; - output << " \"endValue\":" << currentTime << ",\n"; - output << " \"events\":[\n"; - - for (size_t i = 0; i < timelineOcurrences.size(); ++i) { - const auto &e = timelineOcurrences[i]; - output << " {\"type\":\"" << e.type << "\",\"frame\":" << e.frameDescriptionIndex - << ",\"at\":" << e.timestamp << "}" << (i + 1 < timelineOcurrences.size() ? ",\n" : "\n"); - } + visitFieldsRecursive(visitFieldsRecursive, rootFieldDescriptor); - output << " ]\n"; - output << " }\n"; - output << " ]\n"; - output << "}\n"; + PrintSchemaProfileAsSpeedscope(frames, output); } diff --git a/tree/ntupleutil/test/ntuple_inspector.cxx b/tree/ntupleutil/test/ntuple_inspector.cxx index 6364f1c78d497..44231fb9b9ea5 100644 --- a/tree/ntupleutil/test/ntuple_inspector.cxx +++ b/tree/ntupleutil/test/ntuple_inspector.cxx @@ -863,9 +863,9 @@ TEST(RNTupleInspector, FieldTreeAsDot) EXPECT_EQ(dot, expected); } -TEST(RNTupleInspector, FieldTreeAsFlamegraphSpecification) +TEST(RNTupleInspector, SchemaProfileSpecification) { - FileRaii fileGuard("test_ntuple_inspector_field_tree_as_flamegraph_specification"); + FileRaii fileGuard("test_schema_profile_specification.root"); { auto model = RNTupleModel::Create(); auto fieldFloat1 = model->MakeField("float1"); @@ -879,11 +879,10 @@ TEST(RNTupleInspector, FieldTreeAsFlamegraphSpecification) } } auto inspector = RNTupleInspector::Create("ntuple", fileGuard.GetPath()); - std::ostringstream flamegraphSpecificationStream; - inspector->PrintFieldTreeAsFlamegraphSpecification( - ROOT::Experimental::EFlamegraphSpecificationFormat::kSpeedscopeJSON, flamegraphSpecificationStream); - const std::string flamegraphSpecification = flamegraphSpecificationStream.str(); - const std::string &expected = R"({ + std::ostringstream schemaProfileStream; + inspector->PrintSchemaProfile(ROOT::Experimental::ESchemaProfileFormat::kSpeedscopeJSON, schemaProfileStream); + const std::string schemaProfileSpecificaiton = schemaProfileStream.str(); + const std::string expected = R"({ "$schema":"https://www.speedscope.app/file-format-schema.json", "shared":{ "frames":[ @@ -917,5 +916,5 @@ TEST(RNTupleInspector, FieldTreeAsFlamegraphSpecification) ] } )"; - EXPECT_EQ(flamegraphSpecification, expected); + EXPECT_EQ(schemaProfileSpecificaiton, expected); } From bd688738c2b9dfc98674b383c1a08202e2730841 Mon Sep 17 00:00:00 2001 From: albfsg Date: Thu, 18 Jun 2026 13:23:24 +0200 Subject: [PATCH 3/4] Fix return value description in processRecursive comment --- tree/ntupleutil/src/RNTupleInspector.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tree/ntupleutil/src/RNTupleInspector.cxx b/tree/ntupleutil/src/RNTupleInspector.cxx index aa7468522599f..5c584604afab5 100644 --- a/tree/ntupleutil/src/RNTupleInspector.cxx +++ b/tree/ntupleutil/src/RNTupleInspector.cxx @@ -605,7 +605,7 @@ static void PrintSchemaProfileAsSpeedscope(const std::vector &f // Parameter limit // - If the frame is not root: Closing Position of it's father // - If the frame is root: Closing Position of the last element of frames - // Returns index of the processed frame in the vector frames + // Returns index of the next index to be processed std::function processRecursive = [&](std::size_t idx, std::uint32_t limit) -> std::size_t { while (idx < frames.size() && frames[idx].openingPosition < limit) { From 6dafd69082b5749d3a93cfe912eea5fdb332ce71 Mon Sep 17 00:00:00 2001 From: albfsg Date: Thu, 18 Jun 2026 14:23:26 +0200 Subject: [PATCH 4/4] Change static function name to better reflect it's purpose --- tree/ntupleutil/src/RNTupleInspector.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tree/ntupleutil/src/RNTupleInspector.cxx b/tree/ntupleutil/src/RNTupleInspector.cxx index 5c584604afab5..1e9c9e62e2c3a 100644 --- a/tree/ntupleutil/src/RNTupleInspector.cxx +++ b/tree/ntupleutil/src/RNTupleInspector.cxx @@ -574,7 +574,7 @@ struct SpeedscopeFrame { std::uint64_t closingPosition = 0; }; -static void PrintSchemaProfileAsSpeedscope(const std::vector &frames, std::ostream &output) +static void PrintSpeedscopeFrames(const std::vector &frames, std::ostream &output) { output << "{\n"; output << " \"$schema\":\"https://www.speedscope.app/file-format-schema.json\",\n"; @@ -687,5 +687,5 @@ void ROOT::Experimental::RNTupleInspector::PrintSchemaProfile(ESchemaProfileForm visitFieldsRecursive(visitFieldsRecursive, rootFieldDescriptor); - PrintSchemaProfileAsSpeedscope(frames, output); + PrintSpeedscopeFrames(frames, output); }