Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-12-17 02:43:54

0001 #ifndef PerfTools_AllocMonitor_ThreadTracker_h
0002 #define PerfTools_AllocMonitor_ThreadTracker_h
0003 // -*- C++ -*-
0004 //
0005 // Package:     PerfTools/AllocMonitor
0006 // Class  :     ThreadTracker
0007 //
0008 /**\class ThreadTracker ThreadTracker.h "ThreadTracker.h"
0009 
0010  Description: [one line class summary]
0011 
0012  Usage:
0013     <usage>
0014 
0015 */
0016 //
0017 // Original Author:  Christopher Jones
0018 //         Created:  Mon, 11 Nov 2024 22:54:21 GMT
0019 //
0020 
0021 // system include files
0022 #if defined(ALLOC_USE_PTHREADS)
0023 #include <pthread.h>
0024 #else
0025 #include <unistd.h>
0026 #include <sys/syscall.h>
0027 #endif
0028 
0029 #include <array>
0030 #include <atomic>
0031 #include <cstdlib>
0032 // user include files
0033 
0034 // forward declarations
0035 
0036 namespace cms::perftools::allocMon {
0037   inline auto thread_id() {
0038 #if defined(ALLOC_USE_PTHREADS)
0039     /*NOTE: if use pthread_self, the values returned by linux had
0040      lots of hash collisions when using a simple % hash. Worked
0041      better if first divided value by 0x700 and then did %. 
0042      [test done on el8]
0043  */
0044     return pthread_self();
0045 #else
0046     return syscall(SYS_gettid);
0047 #endif
0048   }
0049 
0050   struct ThreadTracker {
0051     static constexpr unsigned int kHashedEntries = 128;
0052     static constexpr unsigned int kExtraEntries = 128;
0053     static constexpr unsigned int kTotalEntries = kHashedEntries + kExtraEntries;
0054     using entry_type = decltype(thread_id());
0055     static constexpr entry_type kUnusedEntry = ~entry_type(0);
0056     std::array<std::atomic<entry_type>, kHashedEntries> hashed_threads_;
0057     std::array<std::atomic<entry_type>, kExtraEntries> extra_threads_;
0058 
0059     std::size_t thread_index() {
0060       auto id = thread_id();
0061       auto index = thread_index_guess(id);
0062       auto used_id = hashed_threads_[index].load();
0063 
0064       if (id == used_id) {
0065         return index;
0066       }
0067       //try to be first thread to grab the index
0068       auto expected = entry_type(index + 1);
0069       if (used_id == expected) {
0070         if (hashed_threads_[index].compare_exchange_strong(expected, id)) {
0071           return index;
0072         } else {
0073           //another thread just beat us so have to go to non-hash storage
0074           return find_new_index(id);
0075         }
0076       }
0077       //search in non-hash storage
0078       return find_index(id);
0079     }
0080 
0081     static ThreadTracker& instance();
0082 
0083   private:
0084     ThreadTracker() {
0085       //put a value which will not match the % used when looking up the entry
0086       entry_type entry = 0;
0087       for (auto& v : hashed_threads_) {
0088         v = ++entry;
0089       }
0090       //assume kUsedEntry is not a valid thread-id
0091       for (auto& v : extra_threads_) {
0092         v = kUnusedEntry;
0093       }
0094     }
0095 
0096     std::size_t thread_index_guess(entry_type id) const {
0097 #if defined(ALLOC_USE_PTHREADS)
0098       return (id / 0x700) % kHashedEntries;
0099 #else
0100       return id % kHashedEntries;
0101 #endif
0102     }
0103 
0104     std::size_t find_new_index(entry_type id) {
0105       std::size_t index = 0;
0106       for (auto& v : extra_threads_) {
0107         entry_type expected = kUnusedEntry;
0108         if (v == expected) {
0109           if (v.compare_exchange_strong(expected, id)) {
0110             return index + kHashedEntries;
0111           }
0112         }
0113         ++index;
0114       }
0115       //failed to find an open entry
0116       abort();
0117       return 0;
0118     }
0119 
0120     std::size_t find_index(entry_type id) {
0121       std::size_t index = 0;
0122       for (auto const& v : extra_threads_) {
0123         if (v == id) {
0124           return index + kHashedEntries;
0125         }
0126         ++index;
0127       }
0128       return find_new_index(id);
0129     }
0130   };
0131 }  // namespace cms::perftools::allocMon
0132 #endif