40#ifndef XAOD_STANDALONE
48#include <boost/core/demangle.hpp>
56#include <gtest/gtest.h>
73 static const std::unordered_map<std::string,SG::sgkey_t>
knownKeys =
75 {
"AnalysisMuons", 0x3a6b126f},
76 {
"AnalysisElectrons", 0x3902fec0},
77 {
"AnalysisPhotons", 0x35d1472f},
78 {
"AnalysisJets", 0x1afd1919},
79 {
"egammaClusters", 0x15788d1f},
80 {
"GSFConversionVertices", 0x1f3e85c9},
81 {
"InDetTrackParticles", 0x1d3890db},
82 {
"CombinedMuonTrackParticles", 0x340d9196},
83 {
"ExtrapolatedMuonTrackParticles", 0x14e35e9f},
84 {
"GSFTrackParticles", 0x2e42db0b},
85 {
"InDetForwardTrackParticles", 0x143c6846},
86 {
"MuonSpectrometerTrackParticles", 0x3993c8f3},
130 else if (
columnName.find (
".") != std::string::npos)
131 throw std::runtime_error (
"branch name does not contain AuxDyn or Aux: " +
m_branchName);
144 throw std::runtime_error (
"branch name does not contain AuxDyn or Aux: " +
m_branchName);
151 throw std::runtime_error (
"failed to get branch: " +
m_branchName);
162 throw std::runtime_error (
"branch not connected: " +
m_branchName);
163 if (
m_branch->GetEntry (entry) <= 0)
164 throw std::runtime_error (
"failed to get entry " + std::to_string (entry) +
" for branch: " +
m_branchName);
166 throw std::runtime_error (
"got nullptr reading data for branch: " +
m_branchName);
179 return static_cast<float>(
m_branch->GetZipBytes()) /
m_branch->GetEntries();
186 return static_cast<float>(
m_branch->GetTotBytes()) /
m_branch->GetEntries();
195 return m_branch->GetListOfBaskets()->GetSize();
222 else if (
columnName.find (
".") != std::string::npos)
223 throw std::runtime_error (
"branch name does not contain AuxDyn or Aux: " +
m_branchName);
236 throw std::runtime_error (
"branch name does not contain AuxDyn or Aux: " +
m_branchName);
243 throw std::runtime_error (
"failed to get branch: " +
m_branchName);
252 std::span<const T>
getEntry (Long64_t entry, std::size_t size)
255 throw std::runtime_error (
"branch not connected: " +
m_branchName);
267 throw std::runtime_error (
"requested size exceeds buffer size for branch: " +
m_branchName);
271 if (size > 0 &&
m_branch->GetEntry (entry) <= 0)
272 throw std::runtime_error (
"failed to get entry " + std::to_string (entry) +
" for branch: " +
m_branchName);
273 return std::span<const T>(
m_dataVec.data(), size);
280 return static_cast<float>(
m_branch->GetZipBytes()) /
m_branch->GetEntries();
287 return static_cast<float>(
m_branch->GetTotBytes()) /
m_branch->GetEntries();
296 return m_branch->GetListOfBaskets()->GetSize();
330 std::array<ColumnarOffsetType, 2>
data = {0, 0};
337 virtual bool connect (TTree * , std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>& , std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
368 result.name =
"EventCount(auto)";
391 virtual bool connect (TTree *
tree, std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>& , std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
393 auto iter = requestedColumns.find (
outputColumns.at(0).name);
394 if (iter == requestedColumns.end())
397 requestedColumns.erase (iter);
415 outData.push_back (branchData);
451 std::vector<ColumnarOffsetType>
offsets = {0};
464 virtual bool connect (TTree *
tree, std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
466 auto iter = requestedColumns.find (
outputColumns.at(0).name);
467 if (iter == requestedColumns.end())
474 throw std::runtime_error (
"offset name mismatch: " + iter->second.offsetName +
" != " +
outputColumns.at(1).name);
476 requestedColumns.erase (iter);
478 if (
auto offsetIter = offsetColumns.find (
outputColumns.at(1).name); offsetIter != offsetColumns.end())
484 if (iter != requestedColumns.end())
486 requestedColumns.erase (iter);
506 outData.insert (
outData.end(), branchData.begin(), branchData.end());
520 throw std::runtime_error (
"offset column not filled yet: " +
outputColumns.at(1).name);
522 throw std::runtime_error (
"offset column does not match: " +
outputColumns.at(1).name);
561 virtual bool connect (TTree * , std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
563 auto iter = requestedColumns.find (
outputColumns.at(0).name);
564 if (iter == requestedColumns.end())
570 const auto offsetName = iter->second.offsetName;
571 if (offsetName.empty())
572 throw std::runtime_error (
"missing offset column for: " +
outputColumns.at(0).name);
574 requestedColumns.erase (iter);
576 if (
auto offsetIter = offsetColumns.find (offsetName); offsetIter != offsetColumns.end())
579 throw std::runtime_error (
"missing offset column for: " +
outputColumns.at(0).name);
617 std::vector<ColumnarOffsetType>
offsets = {0};
630 virtual bool connect (TTree *
tree, std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>& , std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
632 auto iter = requestedColumns.find (
outputColumns.at(0).name);
633 if (iter == requestedColumns.end())
640 throw std::runtime_error (
"offset name mismatch: " + iter->second.offsetName +
" != " +
outputColumns.at(1).name);
642 requestedColumns.erase (iter);
645 if (iter == requestedColumns.end())
647 requestedColumns.erase (iter);
665 for (
auto&
data : branchData)
707 std::vector<ColumnarOffsetType>
offsets = {0};
724 virtual bool connect (TTree *
tree, std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
726 auto iter = requestedColumns.find (
outputColumns.at(0).name);
727 if (iter == requestedColumns.end())
734 throw std::runtime_error (
"offset name mismatch: " + iter->second.offsetName +
" != " +
outputColumns.at(1).name);
736 if (iter->second.linkTargetNames.size() != 1)
737 throw std::runtime_error (
"expected exactly one link target name for: " +
outputColumns.at(0).name);
741 if (
auto offsetIter = offsetColumns.find (iter->second.linkTargetNames.at(0)); offsetIter != offsetColumns.end())
744 throw std::runtime_error (
"missing offset column: " + iter->second.linkTargetNames.at(0));
746 requestedColumns.erase (iter);
749 if (iter == requestedColumns.end())
751 requestedColumns.erase (iter);
770 throw std::runtime_error (
"target offset column not yet filled for: " +
outputColumns.at(0).name);
771 for (
auto&
data : branchData)
773 for (
auto& element :
data)
775 if (element.isDefault() || (element.key() == 0 && element.index() == 0))
788 throw std::runtime_error(
789 std::format(
"target key mismatch: {:x} != {:x} for {} with element index {}",
856 virtual bool connect (TTree *
tree, std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>& , std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
858 auto iter = requestedColumns.find (
outputColumns.at(0).name);
859 if (iter == requestedColumns.end())
866 throw std::runtime_error (
"offset name mismatch: " + iter->second.offsetName +
" != " +
outputColumns.at(1).name);
868 requestedColumns.erase (iter);
871 if (iter == requestedColumns.end())
876 throw std::runtime_error (
"offset name mismatch: " + iter->second.offsetName +
" != " +
outputColumns.at(2).name);
878 requestedColumns.erase (iter);
881 if (iter == requestedColumns.end())
884 requestedColumns.erase (iter);
903 for (
auto& outerData : branchData)
905 for (
auto& innerData : outerData)
952 std::vector<ColumnarOffsetType>
offsets = {0};
969 virtual bool connect (TTree *
tree, std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
971 auto iter = requestedColumns.find (
outputColumns.at(0).name);
972 if (iter == requestedColumns.end())
979 throw std::runtime_error (
"offset name mismatch: " + iter->second.offsetName +
" != " +
outputColumns.at(1).name);
981 if (iter->second.linkTargetNames.size() != 1)
982 throw std::runtime_error (
"expected exactly one link target name for: " +
outputColumns.at(0).name);
986 if (
auto targetOffsetIter = offsetColumns.find (iter->second.linkTargetNames.at(0)); targetOffsetIter != offsetColumns.end())
989 throw std::runtime_error (
"missing offset column(vector-link): " + iter->second.linkTargetNames.at(0));
991 requestedColumns.erase (iter);
993 if (
auto offsetIter = offsetColumns.find (
outputColumns.at(1).name); offsetIter != offsetColumns.end())
999 if (iter != requestedColumns.end())
1002 requestedColumns.erase (iter);
1018 const auto& branchData =
branchReader.getEntry (entry);
1022 throw std::runtime_error (
"target offset column not yet filled for: " +
outputColumns.at(0).name);
1023 for (
auto& element : branchData)
1025 if (element.isDefault() || (element.key() == 0 && element.index() == 0))
1038 throw std::runtime_error (
"target key mismatch: " + std::to_string (element.key()) +
" != " + std::to_string (
targetKey) +
" for " +
outputColumns.at(0).name);
1047 throw std::runtime_error (
"offset column not filled yet: " +
outputColumns.at(1).name);
1049 throw std::runtime_error (
"offset column does not match: " +
outputColumns.at(1).name);
1089 template<
typename T>
1115 virtual bool connect (TTree *
tree, std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
1117 auto iter = requestedColumns.find (
outputColumns.at(0).name);
1118 if (iter == requestedColumns.end())
1127 throw std::runtime_error (
"offset name mismatch: " + iter->second.offsetName +
" != " +
outputColumns.at(1).name);
1129 const auto& linkContainers = iter->second.linkTargetNames;
1130 for (
const auto&
container : linkContainers)
1135 throw std::runtime_error (
"no key known for link container: " +
container);
1136 if (
auto targetOffsetIter = offsetColumns.find (
container); targetOffsetIter != offsetColumns.end())
1139 throw std::runtime_error (
"missing offset column: " +
container);
1142 requestedColumns.erase (iter);
1144 if (
auto offsetIter = offsetColumns.find (
outputColumns.at(1).name); offsetIter != offsetColumns.end())
1150 if (iter != requestedColumns.end())
1153 requestedColumns.erase (iter);
1157 if (iter != requestedColumns.end())
1160 requestedColumns.erase (iter);
1177 auto branchDataKey =
branchReaderKey.getEntry (entry, branchDataSize);
1183 if (targetOffsetColumn->size() <=
offsets.size())
1184 throw std::runtime_error (
"target offset column not yet filled for: " +
outputColumns.at(0).name);
1188 if (branchDataIndex[
index] ==
static_cast<UInt_t
>(-1))
1195 keyIndex = std::distance(
targetKeys.begin(), keyIter);
1200 std::cout <<
"assume target key for " <<
outputColumns.at(0).name <<
" is " << std::hex << branchDataKey[
index] << std::dec << std::endl;
1201 }
else if (branchDataKey[
index] != 0)
1203 std::ostringstream
error;
1204 error <<
"target key mismatch: read " << std::hex << branchDataKey[
index];
1205 error <<
", expected one of";
1207 error <<
" " << key;
1209 throw std::runtime_error (std::move (
error).
str());
1217 auto targetOffset = targetOffsetColumn.at (
offsets.size()-1);
1219 linkIndex += targetOffset;
1220 if (linkIndex >= targetOffsetColumn.at(
offsets.size()))
1221 throw std::runtime_error (std::format (
"index out of range for link: {} >= {} (base index {})",
outputColumns.at(0).name, linkIndex, targetOffsetColumn.at(
offsets.size()), targetOffset));
1230 throw std::runtime_error (
"offset column not filled yet: " +
outputColumns.at(1).name);
1232 throw std::runtime_error (
"offset column does not match: " +
outputColumns.at(1).name);
1274 template<
typename T>
1291 std::unordered_map<SG::sgkey_t,std::unordered_set<std::string>>
unknownKeys;
1306 for (
auto& [key, forbiddenContainer] :
unknownKeys)
1308 std::cout <<
"unknown key: " << std::hex << key << std::dec <<
", allowed containers:";
1311 if (forbiddenContainer.find (
container) == forbiddenContainer.end())
1314 std::cout << std::endl;
1318 virtual bool connect (TTree *
tree, std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>& offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
1320 auto iter = requestedColumns.find (
outputColumns.at(0).name);
1321 if (iter == requestedColumns.end())
1328 throw std::runtime_error (
"offset name mismatch: " + iter->second.offsetName +
" != " +
outputColumns.at(1).name);
1330 if (
containers.empty() || iter->second.variantLinkKeyColumn.empty())
1331 throw std::runtime_error (
"no variant link containers for: " +
outputColumns.at(0).name);
1332 if (iter->second.variantLinkKeyColumn !=
outputColumns.at(2).name)
1333 throw std::runtime_error (
"variant link key column mismatch: " + iter->second.variantLinkKeyColumn +
" != " +
outputColumns.at(2).name);
1338 if (!offsetColumns.contains (
container))
1339 throw std::runtime_error (
"missing offset column(variant-link): " +
container);
1351 requestedColumns.erase (iter);
1354 if (iter != requestedColumns.end())
1357 requestedColumns.erase (iter);
1361 if (iter != requestedColumns.end())
1364 requestedColumns.erase (iter);
1379 const auto& branchData =
branchReader.getEntry (entry);
1382 for (
auto&
data : branchData)
1384 for (
auto& element :
data)
1386 if (element.isDefault() || (element.key() == 0 && element.index() == 0))
1392 for (std::size_t i = 0; i <
containers.size(); ++i)
1397 throw std::runtime_error (
"invalid index: " + std::to_string (element.index()) +
" in container: " +
containers[i] +
" with size: " + std::to_string (
containerOffsets[i]->back()));
1400 throw std::runtime_error (
"container offset not yet filled for: " +
containers[i]);
1410 auto& forbiddenContainers =
unknownKeys[element.key()];
1411 for (std::size_t i = 0; i <
containers.size(); ++i)
1479 virtual bool connect (TTree *
tree, std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>& , std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
1481 auto iter = requestedColumns.find (
outputColumns.at(0).name);
1482 if (iter == requestedColumns.end())
1489 throw std::runtime_error (
"offset name mismatch: " + iter->second.offsetName +
" != " +
outputColumns.at(1).name);
1491 requestedColumns.erase (iter);
1494 if (iter == requestedColumns.end())
1499 requestedColumns.erase (iter);
1502 if (iter != requestedColumns.end())
1505 requestedColumns.erase (iter);
1521 const auto& branchData =
branchReader.getEntry (entry);
1524 for (
auto&
data : branchData)
1573 outputColumns.push_back ({.name = val_columnName, .isOffset =
true});
1574 outputColumns.push_back ({.name = val_columnName +
".name.data"});
1575 outputColumns.push_back ({.name = val_columnName +
".name.offset", .isOffset =
true});
1576 outputColumns.push_back ({.name = val_columnName +
".nameHash"});
1579 virtual bool connect (TTree * , std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>&
offsetColumns, std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
1581 if (
auto iter = requestedColumns.find (
outputColumns.at(0).name);
1582 iter != requestedColumns.end())
1583 requestedColumns.erase (iter);
1588 if (
auto iter = requestedColumns.find (
outputColumns.at(1).name);
1589 iter != requestedColumns.end())
1592 requestedColumns.erase (iter);
1595 if (
auto iter = requestedColumns.find (
outputColumns.at(2).name);
1596 iter != requestedColumns.end())
1599 requestedColumns.erase (iter);
1602 if (
auto iter = requestedColumns.find (
outputColumns.at(3).name);
1603 iter != requestedColumns.end())
1606 requestedColumns.erase (iter);
1610 throw std::runtime_error (
"duplicate size column: " +
outputColumns.at(0).name);
1632 namesHash.push_back (std::hash<std::string> () (termName));
1676 virtual bool connect (TTree *
tree, std::unordered_map<std::string,
const std::vector<ColumnarOffsetType>*>& , std::unordered_map<std::string,ColumnInfo>& requestedColumns)
override
1678 auto iter = requestedColumns.find (
outputColumns.at(0).name);
1679 if (iter == requestedColumns.end())
1686 throw std::runtime_error (
"offset name mismatch: " + iter->second.offsetName +
" != " +
outputColumns.at(1).name);
1688 requestedColumns.erase (iter);
1691 if (iter == requestedColumns.end())
1696 requestedColumns.erase (iter);
1710 const auto& branchData =
branchReader.getEntry (entry);
1713 for (
auto data : branchData)
1752 ColumnarPhysLiteTest ::
1753 ColumnarPhysLiteTest ()
1755 static std::once_flag flag;
1756 std::call_once (flag, [] ()
1758#ifdef XAOD_STANDALONE
1765 auto *fileName = getenv (
"ASG_TEST_FILE_LITE_MC");
1766 if (fileName ==
nullptr)
1767 throw std::runtime_error (
"missing ASG_TEST_FILE_LITE_MC");
1768 file.reset (TFile::Open (fileName,
"READ"));
1770 throw std::runtime_error (
"failed to open file");
1771 tree =
dynamic_cast<TTree*
> (
file->Get (
"CollectionTree"));
1773 throw std::runtime_error (
"failed to open tree");
1776 ColumnarPhysLiteTest :: ~ColumnarPhysLiteTest () =
default;
1778 std::string ColumnarPhysLiteTest :: makeUniqueName ()
1780 static std::atomic<unsigned>
index = 0;
1781 return "UniquePhysliteTestTool" + std::to_string(++
index);
1784 bool ColumnarPhysLiteTest ::
1790 void ColumnarPhysLiteTest :: setupKnownColumns (
const TestDefinition& testDefinition)
1794 knownColumns.push_back (std::make_shared<ColumnDataEventCount> ());
1796 tree->SetMakeClass (1);
1798 std::unordered_map<std::string,TBranch*> branches;
1800 TIter branchIter (
tree->GetListOfBranches());
1801 TObject *obj =
nullptr;
1802 while ((obj = branchIter()))
1804 TBranch *branch =
nullptr;
1805 if ((branch =
dynamic_cast<TBranch*
>(obj)))
1807 branches.emplace (branch->GetName(), branch);
1808 TIter subBranchIter (branch->GetListOfBranches());
1809 while ((obj = subBranchIter()))
1811 if (
auto subBranch =
dynamic_cast<TBranch*
>(obj))
1812 branches.emplace (subBranch->GetName(), subBranch);
1818 for (
const auto& [name, branch] : branches)
1820 if (name.find (
"AuxDyn.") != std::string::npos ||
1821 name.find (
"Aux.") != std::string::npos)
1823 TClass *branchClass =
nullptr;
1824 EDataType branchType {};
1825 branch->GetExpectedType (branchClass, branchType);
1826 if (branchClass ==
nullptr)
1851 if (*branchClass->GetTypeInfo() ==
typeid(std::vector<float>))
1854 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<char>))
1857 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::int8_t>))
1860 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::uint8_t>))
1863 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::int16_t>))
1866 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::uint16_t>))
1869 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::int32_t>))
1872 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::uint32_t>))
1875 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::int64_t>))
1878 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::uint64_t>))
1881 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::vector<float>>))
1884 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::vector<std::int32_t>>))
1887 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::vector<std::uint64_t>>))
1890 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::vector<std::vector<std::size_t>>>))
1893 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::vector<std::vector<unsigned char>>>))
1896 }
else if (*branchClass->GetTypeInfo() ==
typeid(std::vector<std::string>))
1898 knownColumns.push_back (std::make_shared<ColumnDataMetNames> (branch->GetName()));
1910 knownColumns.push_back (std::make_shared<ColumnDataSamplingPattern> (
"egammaClusters"));
1950 using namespace asg::msgUserCode;
1952 std::unordered_map<std::string,ColumnInfo> requestedColumns;
1954 requestedColumns[column.name] = std::move (column);
1957 std::cout <<
"requested columns: " << name << std::endl;
1965 std::set<std::string> unclaimedColumns;
1966 for (
auto& column : requestedColumns)
1968 if (!column.second.isOptional)
1969 unclaimedColumns.insert (column.first);
1971 std::cout <<
"optional column not claimed: " << column.first << std::endl;
1975 const auto& info = requestedColumns.at (columnName);
1978 auto offsetIter = std::find_if (
usedColumns.begin(),
usedColumns.end(), [&] (
const std::shared_ptr<TestUtils::IColumnData>& column)
1980 for (auto& output : column->outputColumns)
1982 if (output.name == info.offsetName)
1989 std::shared_ptr<TestUtils::IColumnData> myColumn;
1990 if (*info.type ==
typeid(
float))
1991 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<float>> (info.name, 0);
1992 else if (*info.type ==
typeid(
char))
1993 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<char>> (info.name, 0);
1994 else if (*info.type ==
typeid(std::uint16_t))
1995 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<std::uint16_t>> (info.name, 0);
1996 else if (*info.type ==
typeid(std::uint64_t))
1997 myColumn = std::make_shared<TestUtils::ColumnDataOutVector<std::uint64_t>> (info.name, 0);
2000 ANA_MSG_WARNING (
"unhandled column type: " << info.name <<
" " << info.type->name());
2006 ANA_MSG_WARNING (
"failed to connect dynamic output column: " << info.name);
2012 if (!unclaimedColumns.empty())
2014 std::string message =
"columns not claimed:";
2015 for (
auto& column : unclaimedColumns)
2016 message +=
" " + column;
2017 throw std::runtime_error (message);
2023 using namespace asg::msgUserCode;
2026 if (!testDefinition.
sysName.empty())
2030 throw std::runtime_error (
"tool does not support systematics");
2031 std::cout <<
"applying systematic variation: " << testDefinition.
sysName << std::endl;
2033 throw std::runtime_error (
"failed to apply systematic variation: " + testDefinition.
sysName);
2046 Benchmark benchmarkCall (testDefinition.
name, userConfiguration.batchSize);
2047 Benchmark benchmarkCall2 (testDefinition.
name +
"(call2)", userConfiguration.batchSize);
2048 Benchmark benchmarkCheck (testDefinition.
name +
"(column check)", userConfiguration.batchSize);
2053 const auto startTime = std::chrono::high_resolution_clock::now();
2054 bool endLoop =
false;
2055 for (; !endLoop; ++entry)
2066 if ((entry + 1) % userConfiguration.batchSize == 0)
2071 column->collectColumnData ();
2074 column->setData (toolColumnData);
2081 if (userConfiguration.runToolTwice)
2088 column->clearColumns ();
2089 if ((std::chrono::high_resolution_clock::now() - startTime) > userConfiguration.targetTime)
2094 column->collectColumnData ();
2098 std::cout <<
"Total entries read: " << entry << std::endl;
2099 const float emptyTime = benchmarkEmpty.
getEntryTime(0).value();
2100 std::cout <<
"Empty benchmark time: " << emptyTime <<
"ns" << std::endl;
2103 std::vector<TestUtils::BranchPerfData> branchPerfData;
2105 summary.name =
"total";
2106 summary.timeRead = 0;
2107 summary.timeUnpack = 0;
2108 summary.timeShallowCopy = 0;
2109 summary.entries = std::nullopt;
2110 summary.nullEntries = std::nullopt;
2113 branchPerfData.push_back (column->getPerfData (emptyTime));
2114 summary.timeRead.value() += branchPerfData.back().timeRead.value_or(0);
2115 summary.timeUnpack.value() += branchPerfData.back().timeUnpack.value_or(0);
2116 summary.timeShallowCopy.value() += branchPerfData.back().timeShallowCopy.value_or(0);
2118 std::sort (branchPerfData.begin(), branchPerfData.end(), [] (
const auto&
a,
const auto& b) {return a.name < b.name;});
2119 branchPerfData.insert (branchPerfData.end(), summary);
2120 const std::size_t nameWidth = std::max_element (branchPerfData.begin(), branchPerfData.end(), [] (
const auto&
a,
const auto& b) {return a.name.size() < b.name.size();})->name.size();
2121 std::string
header = std::format (
"{:{}} | read(ns) | unpack(ns) | size(B) | rate(MB/s) | compression | baskets | entries | null",
"branch name", nameWidth);
2122 std::cout <<
"\n" <<
header << std::endl;
2123 std::cout << std::string (
header.size(),
'-') << std::endl;
2124 for (
auto&
data : branchPerfData)
2126 if (
data.name ==
"total")
2127 std::cout << std::string (
header.size(),
'-') << std::endl;
2128 std::cout << std::format (
"{:{}} |",
data.name, nameWidth);
2130 std::cout << std::format (
"{:>9.0f} |",
data.timeRead.value());
2133 if (
data.timeUnpack)
2134 std::cout << std::format (
"{:>11.1f} |",
data.timeUnpack.value());
2138 std::cout << std::format (
"{:>8.1f} |",
data.entrySize.value());
2141 if (
data.timeRead &&
data.entrySize)
2142 std::cout << std::format (
"{:>11.1f} |", (
data.entrySize.value() / (
data.timeRead.value() * 1e-3 * 1.024 * 1.024)));
2145 if (
data.entrySize &&
data.uncompressedSize)
2146 std::cout << std::format (
"{:>12.2f} |",
float (
data.uncompressedSize.value()) /
data.entrySize.value());
2149 if (
data.numBaskets)
2150 std::cout << std::format (
"{:>8} |",
data.numBaskets.value());
2154 std::cout << std::format (
"{:>8.2f} |",
static_cast<float>(
data.entries.value())/
numberOfEvents);
2157 if (
data.nullEntries &&
data.entries)
2158 std::cout << std::format (
"{:>4.0f}%",
static_cast<float>(
data.nullEntries.value()) /
data.entries.value() * 100.0f);
2159 std::cout << std::endl;
2163 std::vector<TestUtils::ToolPerfData> toolPerfData;
2164 toolPerfData.emplace_back ();
2165 toolPerfData.back().name = testDefinition.
name;
2166 toolPerfData.back().timeCall = benchmarkCall.
getEntryTime(emptyTime);
2167 if (userConfiguration.runToolTwice)
2168 toolPerfData.back().timeCall2 = benchmarkCall2.
getEntryTime(emptyTime);
2169 toolPerfData.back().timeCheck = benchmarkCheck.
getEntryTime(emptyTime);
2173 const std::size_t nameWidth = std::max_element (toolPerfData.begin(), toolPerfData.end(), [] (
const auto&
a,
const auto& b) {return a.name.size() < b.name.size();})->name.size();
2174 std::string
header = std::format (
"{:{}} | call(ns) | call2(ns) | check(ns)",
"tool name", nameWidth);
2175 std::cout <<
"\n" <<
header << std::endl;
2176 std::cout << std::string (
header.size(),
'-') << std::endl;
2177 for (
auto&
data : toolPerfData)
2179 std::cout << std::format (
"{:{}} |",
data.name, nameWidth);
2181 std::cout << std::format (
"{:>9.0f} |",
data.timeCall.value());
2185 std::cout << std::format (
"{:>10.0f} |",
data.timeCall2.value());
2189 std::cout << std::format (
"{:>10.1f}",
data.timeCheck.value());
2190 std::cout << std::endl;
2196#ifdef XAOD_STANDALONE
2204#ifdef XAOD_STANDALONE
2205 Benchmark benchmarkEmptyClear (testDefinition.
name +
" empty clear");
2206 Benchmark benchmarkCallClear (testDefinition.
name +
" call clear");
2207 Benchmark benchmarkPrepClear (testDefinition.
name +
" prep clear");
2209 Benchmark benchmarkRepeatCall (testDefinition.
name +
" repeat-call");
2211 Benchmark benchmarkCallCopyRecord (testDefinition.
name +
" call copy-record");
2212 Benchmark benchmarkCallRetrieve (testDefinition.
name +
" call retrieve");
2214 Benchmark benchmarkPrepCopyRecord (testDefinition.
name +
" prep copy-record");
2215 Benchmark benchmarkPrepRetrieve (testDefinition.
name +
" prep retrieve");
2216 Benchmark benchmarkGetEntry (testDefinition.
name +
" getEntry");
2219#ifdef XAOD_STANDALONE
2220 std::cout <<
"known container keys:" << std::endl;
2223 std::cout << std::format (
" {} -> 0x{:x}, 0x{:x} -> {}",
container, event.getHash (
container), key, event.getName (key)) << std::endl;
2227 throw std::runtime_error (
"ColumnarPhysLiteTest: numberOfEvents == 0");
2236 const auto startTime = std::chrono::high_resolution_clock::now();
2237 for (; (std::chrono::high_resolution_clock::now() - startTime) < userConfiguration.targetTime; ++entry)
2246 static const std::string prepPostfix =
"Prep";
2252#ifdef XAOD_STANDALONE
2261 static const std::string callPostfix =
"Call";
2267 if (userConfiguration.runToolTwice)
2273#ifdef XAOD_STANDALONE
2282 std::cout <<
"Total entries read: " << entry << std::endl;
char data[hepevt_bytes_allocation_ATLAS]
A number of constexpr particle constants to avoid hardcoding them directly in various places.
ServiceHandle< StoreGateSvc > & evtStore()
The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
Class to wrap a set of SystematicVariations.
a class that holds the columnar data for a single call
void checkData() const
do a basic check of the data vector
void callNoCheck(const IColumnarTool &tool)
call the tool with the assembled data, without performing any checks on the data
the header information for the entire columnar data vector
this is a simple benchmarking helper class wrapping timers from std::chrono
std::optional< float > getEntryTime(float emptyTime) const
std::string columnName() const
BranchReaderArray(const std::string &val_branchName)
std::string containerName() const
void connectTree(TTree *tree)
std::vector< T > m_dataVec
std::span< const T > getEntry(Long64_t entry, std::size_t size)
std::optional< unsigned > numBaskets()
BranchReaderArray(const BranchReaderArray &)=delete
std::optional< float > uncompressedSize() const
std::optional< float > entrySize() const
BranchReaderArray & operator=(const BranchReaderArray &)=delete
void setIsStatic(bool isStatic)
const std::string & branchName() const
std::optional< float > entrySize() const
std::string columnName() const
BranchReader(const BranchReader &)=delete
BranchReader(const std::string &val_branchName)
std::string containerName() const
std::optional< unsigned > numBaskets()
BranchReader & operator=(const BranchReader &)=delete
void connectTree(TTree *tree)
const T & getEntry(Long64_t entry)
std::optional< float > uncompressedSize() const
const T & getCachedEntry() const
virtual void collectColumnData()=0
std::vector< OutputColumnInfo > outputColumns
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns)=0
virtual void clearColumns()=0
virtual ~IColumnData() noexcept=default
virtual void getEntry(Long64_t entry)=0
virtual void setData(TestUtils::ToolWrapperData &tool)=0
virtual BranchPerfData getPerfData(float emptyTime)=0
Tool for accessing xAOD files outside of Athena.
A relatively simple transient store for objects created in analysis.
IAppMgrUI * Init(const char *options="POOLRootAccess/basic.opts")
Bootstraps (creates and configures) the Gaudi Application with the provided options file.
constexpr double muonMassInMeV
the mass of the muon (in MeV)
uint32_t sgkey_t
Type used for hashed StoreGate key+CLID pairs.
void runXaodArrayTest(const UserConfiguration &userConfiguration, const TestDefinition &testDefinition, TFile *file)
static const std::unordered_map< std::string, SG::sgkey_t > knownKeys
constexpr unsigned columnarAccessMode
const std::string numberOfEventsName
the name used for the column containing the number of events
void renameContainers(IColumnarTool &tool, const std::vector< std::pair< std::string, std::string > > &renames)
rename containers in the columnar tool
std::size_t ColumnarOffsetType
the type used for the size and offsets in the columnar data
constexpr ColumnarOffsetType invalidObjectIndex
the value for an invalid element index
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
std::size_t erase_if(T_container &container, T_Func pred)
@ Jet
The object is a jet.
@ Muon
The object is a muon.
StatusCode Init(const char *appname)
Function initialising ROOT/PyROOT for using the ATLAS EDM.
a struct that contains meta-information about each column that's needed to interface the column with ...
std::size_t LinkIndexType
the type used for columns that represent element links
static constexpr LinkIndexType invalidLinkValue
the value used for an invalid link (a.k.a. empty/null link)
static LinkIndexType mergeLinkKeyIndex(LinkIndexType key, LinkIndexType index)
merge a key and index value into a link value
std::vector< std::shared_ptr< TestUtils::IColumnData > > knownColumns
std::vector< std::shared_ptr< TestUtils::IColumnData > > usedColumns
void setupColumns(ToolColumnVectorMap &toolWrapper)
std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > offsetColumns
void setupKnownColumns(const TestUtils::TestDefinition &testDefinition)
std::unique_ptr< TFile > file
the performance data for reading a single branch/column
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual void getEntry(Long64_t) override
virtual void clearColumns() override
virtual bool connect(TTree *, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
std::array< ColumnarOffsetType, 2 > data
virtual BranchPerfData getPerfData(float) override
virtual void collectColumnData() override
std::vector< char > columnData
virtual void collectColumnData() override
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
std::vector< ColumnarOffsetType > offsets
virtual BranchPerfData getPerfData(float emptyTime) override
virtual void getEntry(Long64_t entry) override
Benchmark benchmarkUnpack
virtual void setData(TestUtils::ToolWrapperData &tool) override
ColumnDataMetNames(const std::string &val_branchName)
std::vector< std::size_t > columnHashData
BranchReader< std::vector< std::string > > branchReader
virtual void clearColumns() override
ColumnDataOutVector(const std::string &val_columnName, const T &val_defaultValue)
virtual void collectColumnData() override
virtual BranchPerfData getPerfData(float) override
virtual void setData(TestUtils::ToolWrapperData &tool) override
const std::vector< ColumnarOffsetType > * offsetColumn
virtual void clearColumns() override
virtual void getEntry(Long64_t) override
virtual bool connect(TTree *, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
std::vector< std::size_t > namesHash
virtual void clearColumns() override
virtual void getEntry(Long64_t) override
virtual void collectColumnData() override
const std::vector< ColumnarOffsetType > * offsetColumns
virtual BranchPerfData getPerfData(float) override
virtual bool connect(TTree *, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
std::vector< char > namesData
std::vector< std::string > termNames
ColumnDataOutputMet(const std::string &val_columnName, std::vector< std::string > val_termNames)
std::vector< ColumnarOffsetType > namesOffsets
std::vector< ColumnarOffsetType > offsets
virtual void setData(TestUtils::ToolWrapperData &tool) override
BranchReader< xAOD::CaloClusterContainer > branchReader
virtual void clearColumns() override
virtual void getEntry(Long64_t entry) override
std::vector< std::uint32_t > columnData
Benchmark benchmarkUnpack
virtual BranchPerfData getPerfData(float emptyTime) override
ColumnDataSamplingPattern(const std::string &val_branchName)
std::vector< ColumnarOffsetType > offsets
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual void collectColumnData() override
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
virtual void clearColumns() override
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual void collectColumnData() override
virtual BranchPerfData getPerfData(float emptyTime) override
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
ColumnDataScalar(const std::string &val_branchName)
BranchReader< T > branchReader
virtual void getEntry(Long64_t entry) override
Benchmark benchmarkUnpack
virtual void getEntry(Long64_t entry) override
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual void collectColumnData() override
BranchReader< std::vector< ElementLink< T > > > branchReader
ColumnDataVectorLink(const std::string &val_branchName)
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
virtual BranchPerfData getPerfData(float emptyTime) override
Benchmark benchmarkUnpack
const std::vector< ColumnarOffsetType > * offsetColumn
std::string targetContainerName
std::vector< typename CM::LinkIndexType > columnData
const std::vector< ColumnarOffsetType > * targetOffsetColumn
std::vector< ColumnarOffsetType > offsets
virtual void clearColumns() override
BranchReader< Int_t > branchReaderSize
const std::vector< ColumnarOffsetType > * offsetColumn
std::vector< typename CM::LinkKeyType > keyColumnData
BranchReaderArray< UInt_t > branchReaderIndex
std::vector< typename CM::LinkIndexType > columnData
virtual void setData(TestUtils::ToolWrapperData &tool) override
std::vector< ColumnarOffsetType > offsets
std::vector< SG::sgkey_t > targetKeys
std::vector< const std::vector< ColumnarOffsetType > * > targetOffsetColumns
virtual BranchPerfData getPerfData(float emptyTime) override
virtual void collectColumnData() override
BranchReaderArray< UInt_t > branchReaderKey
ColumnDataVectorSplitLink(const std::string &val_branchName)
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
virtual void getEntry(Long64_t entry) override
virtual void clearColumns() override
Benchmark benchmarkUnpack
Benchmark benchmarkUnpack
std::vector< ColumnarOffsetType > offsets
virtual void getEntry(Long64_t entry) override
std::string targetContainerName
ColumnDataVectorVectorLink(const std::string &val_branchName)
BranchReader< std::vector< std::vector< ElementLink< T > > > > branchReader
virtual BranchPerfData getPerfData(float emptyTime) override
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual void collectColumnData() override
std::vector< typename CM::LinkIndexType > columnData
virtual void clearColumns() override
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
const std::vector< ColumnarOffsetType > * targetOffsetColumn
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
std::vector< std::string > containers
std::vector< const std::vector< ColumnarOffsetType > * > containerOffsets
ColumnDataVectorVectorVariantLink(const std::string &val_branchName)
std::vector< SG::sgkey_t > containerKeys
virtual void clearColumns() override
virtual void getEntry(Long64_t entry) override
Benchmark benchmarkUnpack
virtual BranchPerfData getPerfData(float emptyTime) override
std::vector< ColumnarOffsetType > offsets
std::vector< typename CM::LinkIndexType > columnData
virtual void collectColumnData() override
virtual void setData(TestUtils::ToolWrapperData &tool) override
BranchReader< std::vector< std::vector< ElementLink< T > > > > branchReader
~ColumnDataVectorVectorVariantLink()
std::vector< typename CM::LinkKeyType > keysColumn
std::unordered_map< SG::sgkey_t, std::unordered_set< std::string > > unknownKeys
std::vector< ColumnarOffsetType > outerOffsets
virtual void clearColumns() override
std::vector< T > columnData
std::vector< ColumnarOffsetType > innerOffsets
virtual void collectColumnData() override
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual BranchPerfData getPerfData(float emptyTime) override
Benchmark benchmarkUnpack
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
BranchReader< std::vector< std::vector< std::vector< T > > > > branchReader
virtual void getEntry(Long64_t entry) override
ColumnDataVectorVectorVector(const std::string &val_branchName)
std::vector< T > columnData
virtual BranchPerfData getPerfData(float emptyTime) override
virtual void clearColumns() override
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual void collectColumnData() override
std::vector< ColumnarOffsetType > offsets
BranchReader< std::vector< std::vector< T > > > branchReader
Benchmark benchmarkUnpack
ColumnDataVectorVector(const std::string &val_branchName)
virtual void getEntry(Long64_t entry) override
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
std::vector< ColumnarOffsetType > offsets
BranchReader< std::vector< T > > branchReader
virtual void setData(TestUtils::ToolWrapperData &tool) override
virtual bool connect(TTree *tree, std::unordered_map< std::string, const std::vector< ColumnarOffsetType > * > &offsetColumns, std::unordered_map< std::string, ColumnInfo > &requestedColumns) override
virtual BranchPerfData getPerfData(float emptyTime) override
virtual void getEntry(Long64_t entry) override
Benchmark benchmarkUnpack
ColumnDataVector(const std::string &val_branchName)
virtual void collectColumnData() override
const std::vector< ColumnarOffsetType > * offsetColumn
virtual void clearColumns() override
the general configuration for a single test
std::string sysName
the systematic variation to apply (empty for nominal)
IXAODToolCaller * xAODToolCaller
the callback for calling the tool in xAOD mode
std::vector< std::string > metTermNames
the MET output term names (if empty, MET output columns are omitted)
std::string name
the name identifier for the test
std::vector< std::pair< std::string, std::string > > containerRenames
the container name remappings to apply
asg::AsgTool * tool
the tool being tested
static UserConfiguration fromEnvironment()
create a UserConfiguration, loading from the file pointed to by the COLUMNAR_TEST_CONFIG environment ...