File indexing completed on 2024-12-17 02:43:54
0001 #ifndef PerfTools_AllocMonitor_ThreadTracker_h
0002 #define PerfTools_AllocMonitor_ThreadTracker_h
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
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
0033
0034
0035
0036 namespace cms::perftools::allocMon {
0037 inline auto thread_id() {
0038 #if defined(ALLOC_USE_PTHREADS)
0039
0040
0041
0042
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
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
0074 return find_new_index(id);
0075 }
0076 }
0077
0078 return find_index(id);
0079 }
0080
0081 static ThreadTracker& instance();
0082
0083 private:
0084 ThreadTracker() {
0085
0086 entry_type entry = 0;
0087 for (auto& v : hashed_threads_) {
0088 v = ++entry;
0089 }
0090
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
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 }
0132 #endif