Skip to content

Commit

Permalink
Use bit manipulation with the UniqueIDGenSvc and add a check for repe…
Browse files Browse the repository at this point in the history
…ated numbers (#247)

Co-authored-by: Thomas Madlener <[email protected]>
  • Loading branch information
jmcarcell and tmadlener authored Oct 15, 2024
1 parent 117bbce commit d3f8562
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 34 deletions.
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

0 comments on commit d3f8562

Please sign in to comment.