2323#include " FWCore/ServiceRegistry/interface/ModuleCallingContext.h"
2424#include " DataFormats/Provenance/interface/ModuleDescription.h"
2525
26+ #if defined(ALLOC_USE_PTHREADS)
27+ #include < pthread.h>
28+ #else
29+ #include < unistd.h>
30+ #include < sys/syscall.h>
31+ #endif
32+
2633#include " moduleAlloc_setupFile.h"
2734#include " ThreadAllocInfo.h"
2835
2936namespace {
37+ inline auto thread_id () {
38+ #if defined(ALLOC_USE_PTHREADS)
39+ /* NOTE: if use pthread_self, the values returned by linux had
40+ lots of hash collisions when using a simple % hash. Worked
41+ better if first divided value by 0x700 and then did %.
42+ [test done on el8]
43+ */
44+ return pthread_self ();
45+ #else
46+ return syscall (SYS_gettid);
47+ #endif
48+ }
49+
50+ struct ThreadTracker {
51+ static constexpr unsigned int kHashedEntries = 128 ;
52+ static constexpr unsigned int kExtraEntries = 128 ;
53+ static constexpr unsigned int kTotalEntries = kHashedEntries + kExtraEntries ;
54+ using entry_type = decltype (thread_id());
55+ static constexpr entry_type kUnusedEntry = ~entry_type (0 );
56+ std::array<std::atomic<entry_type>, kHashedEntries > hashed_threads_;
57+ std::array<std::atomic<entry_type>, kExtraEntries > extra_threads_;
58+
59+ ThreadTracker () {
60+ // put a value which will not match the % used when looking up the entry
61+ entry_type entry = 0 ;
62+ for (auto & v : extra_threads_) {
63+ v = kUnusedEntry ;
64+ }
65+ for (auto & v : hashed_threads_) {
66+ v = ++entry;
67+ }
68+ }
69+
70+ std::size_t thread_index () {
71+ auto id = thread_id ();
72+ auto index = thread_index_guess (id);
73+ auto used_id = hashed_threads_[index].load ();
74+
75+ if (id == used_id) {
76+ return index;
77+ }
78+ // try to be first thread to grab the index
79+ auto expected = entry_type (index + 1 );
80+ if (used_id == expected) {
81+ if (hashed_threads_[index].compare_exchange_strong (expected, id)) {
82+ return index;
83+ } else {
84+ // another thread just beat us so have to go to non-hash storage
85+ return find_new_index (id);
86+ }
87+ }
88+ // search in non-hash storage
89+ return find_index (id);
90+ }
91+
92+ private:
93+ std::size_t thread_index_guess (entry_type id) const {
94+ #if defined(ALLOC_USE_PTHREADS)
95+ return (id / 0x700 ) % kHashedEntries ;
96+ #else
97+ return id % kHashedEntries ;
98+ #endif
99+ }
100+
101+ std::size_t find_new_index (entry_type id) {
102+ std::size_t index = 0 ;
103+ for (auto & v : extra_threads_) {
104+ entry_type expected = kUnusedEntry ;
105+ if (v == expected) {
106+ if (v.compare_exchange_strong (expected, id)) {
107+ return index + kHashedEntries ;
108+ }
109+ }
110+ ++index;
111+ }
112+ // failed to find an open entry
113+ abort ();
114+ return 0 ;
115+ }
116+
117+ std::size_t find_index (entry_type id) {
118+ std::size_t index = 0 ;
119+ for (auto const & v : extra_threads_) {
120+ if (v == id) {
121+ return index + kHashedEntries ;
122+ }
123+ ++index;
124+ }
125+ return find_new_index (id);
126+ }
127+ };
128+
129+ static ThreadTracker& getTracker () {
130+ static ThreadTracker s_tracker;
131+ return s_tracker;
132+ }
133+
30134 using namespace edm ::service::moduleAlloc;
31135 class MonitorAdaptor : public cms ::perftools::AllocMonitorBase {
32136 public:
@@ -43,8 +147,8 @@ namespace {
43147
44148 private:
45149 static ThreadAllocInfo& threadAllocInfo () {
46- thread_local ThreadAllocInfo s_info;
47- return s_info;
150+ static ThreadAllocInfo s_info[ThreadTracker:: kTotalEntries ] ;
151+ return s_info[ getTracker (). thread_index ()] ;
48152 }
49153 void allocCalled (size_t iRequested, size_t iActual, void const *) final {
50154 auto & allocInfo = threadAllocInfo ();
0 commit comments