Skip to content

Commit 8b00c13

Browse files
DPL Analysis: make sure each name hash in histogram registry is unique (#5068)
1 parent 90f87c4 commit 8b00c13

File tree

3 files changed

+42
-8
lines changed

3 files changed

+42
-8
lines changed

Framework/Core/include/Framework/HistogramRegistry.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ class HistogramRegistry
615615
template <typename T>
616616
void insertClone(const HistName& histName, const std::shared_ptr<T>& originalHist)
617617
{
618+
validateHash(histName.hash, histName.str);
618619
for (auto i = 0u; i < MAX_REGISTRY_SIZE; ++i) {
619620
TObject* rawPtr = nullptr;
620621
std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mRegistryValue[imask(histName.idx + i)]);
@@ -629,6 +630,8 @@ class HistogramRegistry
629630
LOGF(FATAL, "Internal array of HistogramRegistry %s is full.", mName);
630631
}
631632

633+
void validateHash(const uint32_t hash, const char* name);
634+
632635
// helper function to find the histogram position in the registry
633636
template <typename T>
634637
uint32_t getHistIndex(const T& histName)

Framework/Core/src/HistogramRegistry.cxx

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,33 @@ const std::map<HistType, std::function<HistPtr(const HistogramSpec&)>> HistFacto
3737
// create histogram from specification and insert it into the registry
3838
void HistogramRegistry::insert(const HistogramSpec& histSpec)
3939
{
40-
const uint32_t i = imask(histSpec.hash);
41-
for (auto j = 0u; j < MAX_REGISTRY_SIZE; ++j) {
40+
validateHash(histSpec.hash, histSpec.name.data());
41+
const uint32_t idx = imask(histSpec.hash);
42+
for (auto i = 0u; i < MAX_REGISTRY_SIZE; ++i) {
4243
TObject* rawPtr = nullptr;
43-
std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mRegistryValue[imask(j + i)]);
44+
std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mRegistryValue[imask(idx + i)]);
4445
if (!rawPtr) {
4546
registerName(histSpec.name);
46-
mRegistryKey[imask(j + i)] = histSpec.hash;
47-
mRegistryValue[imask(j + i)] = HistFactory::createHistVariant(histSpec);
48-
lookup += j;
47+
mRegistryKey[imask(idx + i)] = histSpec.hash;
48+
mRegistryValue[imask(idx + i)] = HistFactory::createHistVariant(histSpec);
49+
lookup += i;
4950
return;
5051
}
5152
}
5253
LOGF(FATAL, R"(Internal array of HistogramRegistry "%s" is full.)", mName);
5354
}
5455

56+
void HistogramRegistry::validateHash(const uint32_t hash, const char* name)
57+
{
58+
auto it = std::find(mRegistryKey.begin(), mRegistryKey.end(), hash);
59+
if (it != mRegistryKey.end()) {
60+
auto idx = it - mRegistryKey.begin();
61+
std::string collidingName{};
62+
std::visit([&](const auto& hist) { collidingName = hist->GetName(); }, mRegistryValue[idx]);
63+
LOGF(FATAL, R"(Hash collision in HistogramRegistry "%s"! Please rename histogram "%s" or "%s".)", mName, name, collidingName);
64+
}
65+
}
66+
5567
void HistogramRegistry::add(const HistogramSpec& histSpec)
5668
{
5769
insert(histSpec);
@@ -201,6 +213,9 @@ void HistogramRegistry::print(bool showAxisDetails)
201213
}
202214
LOGF(INFO, "%s", std::string(titleString.size(), '='), titleString);
203215
LOGF(INFO, "Total: %d histograms, ca. %s", nHistos, totalSizeInfo);
216+
if (lookup) {
217+
LOGF(INFO, "Due to index collisions, histograms were shifted by %d registry slots in total.", lookup);
218+
}
204219
LOGF(INFO, "%s", std::string(titleString.size(), '='), titleString);
205220
LOGF(INFO, "");
206221
}
@@ -211,9 +226,9 @@ TList* HistogramRegistry::operator*()
211226
TList* list = new TList();
212227
list->SetName(mName.data());
213228

214-
for (auto j = 0u; j < MAX_REGISTRY_SIZE; ++j) {
229+
for (auto i = 0u; i < MAX_REGISTRY_SIZE; ++i) {
215230
TNamed* rawPtr = nullptr;
216-
std::visit([&](const auto& sharedPtr) { rawPtr = (TNamed*)sharedPtr.get(); }, mRegistryValue[j]);
231+
std::visit([&](const auto& sharedPtr) { rawPtr = (TNamed*)sharedPtr.get(); }, mRegistryValue[i]);
217232
if (rawPtr) {
218233
std::deque<std::string> path = splitPath(rawPtr->GetName());
219234
std::string name = path.back();

Framework/Core/test/test_HistogramRegistry.cxx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "Framework/HistogramRegistry.h"
1515
#include <boost/test/unit_test.hpp>
16+
#include <iostream>
1617

1718
using namespace o2;
1819
using namespace o2::framework;
@@ -55,6 +56,21 @@ BOOST_AUTO_TEST_CASE(HistogramRegistryLookup)
5556
auto r = foo();
5657
auto histo2 = r.get<TH1>(HIST("histo")).get();
5758
BOOST_REQUIRE_EQUAL(histo2->GetNbinsX(), 100);
59+
60+
registry.print();
61+
62+
// check that registry behaves correctly when two different names have equal hash:
63+
/*
64+
auto str1 = "Maria has nine red beds.";
65+
auto str2 = "Steven has fifteen white tables.";
66+
BOOST_REQUIRE_EQUAL(compile_time_hash(str1), compile_time_hash(str2));
67+
try {
68+
registry.add(str1, "", kTH1F, {{20, 0.0f, 10.01f}});
69+
registry.add(str2, "", kTH1F, {{20, 0.0f, 10.01f}});
70+
} catch (...) {
71+
std::cout << "Hash collision was detected correctly!" << std::endl;
72+
}
73+
*/
5874
}
5975

6076
BOOST_AUTO_TEST_CASE(HistogramRegistryExpressionFill)

0 commit comments

Comments
 (0)