Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use bit manipulation with the UniqueIDGenSvc and add a check for repeated numbers #247

Merged
merged 11 commits into from
Oct 15, 2024
58 changes: 42 additions & 16 deletions k4FWCore/components/UniqueIDGenSvc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,53 @@
*/
#include "UniqueIDGenSvc.h"

DECLARE_COMPONENT(UniqueIDGenSvc)
#include <cstdint>
#include <stdexcept>
#include <string>

UniqueIDGenSvc::UniqueIDGenSvc(const std::string& name, ISvcLocator* svcLoc) : base_class(name, svcLoc) {}

StatusCode UniqueIDGenSvc::initialize() {
StatusCode sc = Service::initialize();
return sc;
}

const size_t bits32 = std::numeric_limits<uint32_t>::digits;
const size_t bits64 = std::numeric_limits<uint64_t>::digits;
const size_t bitsSizeT = std::numeric_limits<size_t>::digits;
constexpr size_t bits32 = std::numeric_limits<uint32_t>::digits;
constexpr size_t bits64 = std::numeric_limits<uint64_t>::digits;
constexpr size_t bitsSizeT = std::numeric_limits<size_t>::digits;

size_t UniqueIDGenSvc::getUniqueID(uint32_t evt_num, uint32_t run_num, const std::string& name) const {
std::bitset<bits64> seed_bits(this->m_seed);
std::bitset<bits32> event_num_bits(evt_num), run_num_bits(run_num);
size_t str_hash = std::hash<std::string>{}(name);
std::bitset<bitsSizeT> name_bits(str_hash);
std::bitset<bits64> seed_bits = this->m_seed.value();
std::bitset<bits32> event_num_bits = evt_num, run_num_bits = run_num;
size_t str_hash = std::hash<std::string>{}(name);
std::bitset<bitsSizeT> name_bits = str_hash;

std::bitset<bits64 + bits32 + bits32 + bitsSizeT> combined_bits;

std::bitset<bits64 + bits32 + bits32 + bitsSizeT> combined_bits(seed_bits.to_string() + event_num_bits.to_string() +
run_num_bits.to_string() + name_bits.to_string());
for (size_t i = 0; i < bitsSizeT; i++) {
combined_bits[i] = name_bits[i];
}
for (size_t i = 0; i < bits32; i++) {
combined_bits[i + bitsSizeT] = run_num_bits[i];
}
for (size_t i = 0; i < bits32; i++) {
combined_bits[i + bits32 + bitsSizeT] = event_num_bits[i];
}
for (size_t i = 0; i < bits64; i++) {
combined_bits[i + bits32 + bits32 + bitsSizeT] = seed_bits[i];
}

return std::hash<std::bitset<bits64 + bits32 + bits32 + bitsSizeT>>{}(combined_bits);
auto hash = std::hash<std::bitset<bits64 + bits32 + bits32 + bitsSizeT>>{}(combined_bits);
bool inserted = false;
{
std::lock_guard<std::mutex> lock(m_mutex);
std::tie(std::ignore, inserted) = m_uniqueIDs.insert(hash);
}
if (!inserted) {
error() << "Event number " << evt_num << ", run number " << run_num << " and algorithm name \"" << name
<< "\" have already been used. Please check the uniqueness of the event number, run number and name."
<< endmsg;
if (m_throwIfDuplicate) {
throw std::runtime_error("Duplicate event number, run number and algorithm name");
}
}

return hash;
}

DECLARE_COMPONENT(UniqueIDGenSvc)
16 changes: 10 additions & 6 deletions k4FWCore/components/UniqueIDGenSvc.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
#ifndef FWCORE_UNIQUEIDGENSVC_H
#define FWCORE_UNIQUEIDGENSVC_H

#include "GaudiKernel/Service.h"
#include "k4Interface/IUniqueIDGenSvc.h"

#include <cstdint>
#include <functional>
#include <string>

#include <GaudiKernel/Service.h>
#include "k4Interface/IUniqueIDGenSvc.h"
#include <unordered_set>

/** @class UniqueIDGenSvc
* Generate unique, reproducible numbers using
Expand All @@ -34,11 +36,13 @@
class UniqueIDGenSvc : public extends<Service, IUniqueIDGenSvc> {
public:
UniqueIDGenSvc(const std::string& name, ISvcLocator* svcLoc);
StatusCode initialize() override;
size_t getUniqueID(uint32_t evt_num, uint32_t run_num, const std::string& name) const override;
size_t getUniqueID(uint32_t evt_num, uint32_t run_num, const std::string& name) const override;

private:
Gaudi::Property<int64_t> m_seed{this, "Seed", {123456789}};
Gaudi::Property<uint64_t> m_seed{this, "Seed", {123456789}};
mutable std::unordered_set<size_t, std::identity> m_uniqueIDs;
mutable std::mutex m_mutex;
Gaudi::Property<bool> m_throwIfDuplicate{this, "ThrowIfDuplicate", {true}};
};

#endif
3 changes: 0 additions & 3 deletions k4Interface/include/k4Interface/IUniqueIDGenSvc.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@
#ifndef FWCORE_IUNIQUEIDGENSVC_H
#define FWCORE_IUNIQUEIDGENSVC_H

#include <bitset>
#include <cstdint>
#include <functional>
#include <limits>
#include <string>

#include <GaudiKernel/IInterface.h>
Expand Down
3 changes: 2 additions & 1 deletion test/k4FWCoreTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ add_test(NAME checkKeepDropSwitch
COMMAND python scripts/check_KeepDropSwitch.py ${PROJECT_BINARY_DIR}/test/k4FWCoreTest/output_k4test_exampledata_2.root)
set_test_env(checkKeepDropSwitch)
set_property(TEST checkKeepDropSwitch APPEND PROPERTY DEPENDS ReadExampleEventData)
add_test_with_env(TestUniqueIDGenSvc options/TestUniqueIDGenSvc.py)
add_test_with_env(TestUniqueIDGenSvc options/TestUniqueIDGenSvc.py -n 1)
add_test_with_env(TestUniqueIDGenSvcRepeated options/TestUniqueIDGenSvc.py -n 2 PROPERTIES PASS_REGULAR_EXPRESSION "Duplicate event number, run number and algorithm name")
add_test_with_env(TestEventHeaderFiller options/createEventHeader.py)
add_test_with_env(EventHeaderCheck options/runEventHeaderCheck.py PROPERTIES DEPENDS TestEventHeaderFiller)
add_test(NAME TestExec WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} COMMAND python options/TestExec.py)
Expand Down
17 changes: 11 additions & 6 deletions test/k4FWCoreTest/src/components/TestUniqueIDGenSvc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/
#include "TestUniqueIDGenSvc.h"

#include <cstdint>

DECLARE_COMPONENT(TestUniqueIDGenSvc)

TestUniqueIDGenSvc::TestUniqueIDGenSvc(const std::string& aName, ISvcLocator* aSvcLoc)
Expand All @@ -33,16 +35,19 @@ StatusCode TestUniqueIDGenSvc::initialize() {
return StatusCode::SUCCESS;
}

// This is meant to run up to two times
// For the first event, check that when giving two different event numbers, the unique IDs are different
// For the second event, the service throws when trying to get the same ID twice
StatusCode TestUniqueIDGenSvc::execute(const EventContext&) const {
uint evt_num = 4;
uint run_num = 3;
++m_counter;
uint32_t evt_num = 4;
uint32_t run_num = 3 + m_counter.sum();
std::string name = "Some algorithm name";

auto uid = m_service->getUniqueID(evt_num, run_num, name);
auto uid_again = m_service->getUniqueID(evt_num, run_num, name);

if (uid != uid_again) {
return StatusCode::FAILURE;
auto uid_again = m_service->getUniqueID(evt_num + (m_counter.sum() % 2), run_num, name);
if (uid == uid_again) {
throw std::runtime_error("Unique IDs are the same");
}

return StatusCode::SUCCESS;
Expand Down
6 changes: 4 additions & 2 deletions test/k4FWCoreTest/src/components/TestUniqueIDGenSvc.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
#define TEST_UNIQUEIDGENSVC_H

// GAUDI
#include <Gaudi/Algorithm.h>
#include "Gaudi/Accumulators.h"
#include "Gaudi/Algorithm.h"

#include "k4Interface/IUniqueIDGenSvc.h"

Expand All @@ -37,7 +38,8 @@ class TestUniqueIDGenSvc : public Gaudi::Algorithm {
StatusCode execute(const EventContext&) const final;

private:
SmartIF<IUniqueIDGenSvc> m_service;
SmartIF<IUniqueIDGenSvc> m_service;
mutable Gaudi::Accumulators::Counter<> m_counter{this, "EventCounter"};
};

#endif // TEST_UNIQUEIDGENSVC_H
Loading