2525#include " absl/container/internal/have_sse.h"
2626#include " absl/debugging/stacktrace.h"
2727#include " absl/memory/memory.h"
28+ #include " absl/profiling/internal/sample_recorder.h"
2829#include " absl/synchronization/mutex.h"
2930
3031namespace absl {
@@ -37,7 +38,6 @@ ABSL_CONST_INIT std::atomic<bool> g_hashtablez_enabled{
3738 false
3839};
3940ABSL_CONST_INIT std::atomic<int32_t > g_hashtablez_sample_parameter{1 << 10 };
40- ABSL_CONST_INIT std::atomic<int32_t > g_hashtablez_max_samples{1 << 20 };
4141
4242#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
4343ABSL_PER_THREAD_TLS_KEYWORD absl::base_internal::ExponentialBiased
@@ -50,16 +50,11 @@ ABSL_PER_THREAD_TLS_KEYWORD absl::base_internal::ExponentialBiased
5050ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0 ;
5151#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
5252
53- HashtablezSampler& HashtablezSampler::Global () {
53+ HashtablezSampler& GlobalHashtablezSampler () {
5454 static auto * sampler = new HashtablezSampler ();
5555 return *sampler;
5656}
5757
58- HashtablezSampler::DisposeCallback HashtablezSampler::SetDisposeCallback (
59- DisposeCallback f) {
60- return dispose_.exchange (f, std::memory_order_relaxed);
61- }
62-
6358HashtablezInfo::HashtablezInfo () { PrepareForSampling (); }
6459HashtablezInfo::~HashtablezInfo () = default ;
6560
@@ -80,93 +75,6 @@ void HashtablezInfo::PrepareForSampling() {
8075 // instead.
8176 depth = absl::GetStackTrace (stack, HashtablezInfo::kMaxStackDepth ,
8277 /* skip_count= */ 0 );
83- dead = nullptr ;
84- }
85-
86- HashtablezSampler::HashtablezSampler ()
87- : dropped_samples_(0 ), size_estimate_(0 ), all_(nullptr ), dispose_(nullptr ) {
88- absl::MutexLock l (&graveyard_.init_mu );
89- graveyard_.dead = &graveyard_;
90- }
91-
92- HashtablezSampler::~HashtablezSampler () {
93- HashtablezInfo* s = all_.load (std::memory_order_acquire);
94- while (s != nullptr ) {
95- HashtablezInfo* next = s->next ;
96- delete s;
97- s = next;
98- }
99- }
100-
101- void HashtablezSampler::PushNew (HashtablezInfo* sample) {
102- sample->next = all_.load (std::memory_order_relaxed);
103- while (!all_.compare_exchange_weak (sample->next , sample,
104- std::memory_order_release,
105- std::memory_order_relaxed)) {
106- }
107- }
108-
109- void HashtablezSampler::PushDead (HashtablezInfo* sample) {
110- if (auto * dispose = dispose_.load (std::memory_order_relaxed)) {
111- dispose (*sample);
112- }
113-
114- absl::MutexLock graveyard_lock (&graveyard_.init_mu );
115- absl::MutexLock sample_lock (&sample->init_mu );
116- sample->dead = graveyard_.dead ;
117- graveyard_.dead = sample;
118- }
119-
120- HashtablezInfo* HashtablezSampler::PopDead () {
121- absl::MutexLock graveyard_lock (&graveyard_.init_mu );
122-
123- // The list is circular, so eventually it collapses down to
124- // graveyard_.dead == &graveyard_
125- // when it is empty.
126- HashtablezInfo* sample = graveyard_.dead ;
127- if (sample == &graveyard_) return nullptr ;
128-
129- absl::MutexLock sample_lock (&sample->init_mu );
130- graveyard_.dead = sample->dead ;
131- sample->PrepareForSampling ();
132- return sample;
133- }
134-
135- HashtablezInfo* HashtablezSampler::Register () {
136- int64_t size = size_estimate_.fetch_add (1 , std::memory_order_relaxed);
137- if (size > g_hashtablez_max_samples.load (std::memory_order_relaxed)) {
138- size_estimate_.fetch_sub (1 , std::memory_order_relaxed);
139- dropped_samples_.fetch_add (1 , std::memory_order_relaxed);
140- return nullptr ;
141- }
142-
143- HashtablezInfo* sample = PopDead ();
144- if (sample == nullptr ) {
145- // Resurrection failed. Hire a new warlock.
146- sample = new HashtablezInfo ();
147- PushNew (sample);
148- }
149-
150- return sample;
151- }
152-
153- void HashtablezSampler::Unregister (HashtablezInfo* sample) {
154- PushDead (sample);
155- size_estimate_.fetch_sub (1 , std::memory_order_relaxed);
156- }
157-
158- int64_t HashtablezSampler::Iterate (
159- const std::function<void (const HashtablezInfo& stack)>& f) {
160- HashtablezInfo* s = all_.load (std::memory_order_acquire);
161- while (s != nullptr ) {
162- absl::MutexLock l (&s->init_mu );
163- if (s->dead == nullptr ) {
164- f (*s);
165- }
166- s = s->next ;
167- }
168-
169- return dropped_samples_.load (std::memory_order_relaxed);
17078}
17179
17280static bool ShouldForceSampling () {
@@ -192,7 +100,7 @@ static bool ShouldForceSampling() {
192100HashtablezInfo* SampleSlow (int64_t * next_sample) {
193101 if (ABSL_PREDICT_FALSE (ShouldForceSampling ())) {
194102 *next_sample = 1 ;
195- return HashtablezSampler::Global ().Register ();
103+ return GlobalHashtablezSampler ().Register ();
196104 }
197105
198106#if !defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
@@ -217,12 +125,12 @@ HashtablezInfo* SampleSlow(int64_t* next_sample) {
217125 return SampleSlow (next_sample);
218126 }
219127
220- return HashtablezSampler::Global ().Register ();
128+ return GlobalHashtablezSampler ().Register ();
221129#endif
222130}
223131
224132void UnsampleSlow (HashtablezInfo* info) {
225- HashtablezSampler::Global ().Unregister (info);
133+ GlobalHashtablezSampler ().Unregister (info);
226134}
227135
228136void RecordInsertSlow (HashtablezInfo* info, size_t hash,
@@ -262,7 +170,7 @@ void SetHashtablezSampleParameter(int32_t rate) {
262170
263171void SetHashtablezMaxSamples (int32_t max) {
264172 if (max > 0 ) {
265- g_hashtablez_max_samples. store (max, std::memory_order_release );
173+ GlobalHashtablezSampler (). SetMaxSamples (max);
266174 } else {
267175 ABSL_RAW_LOG (ERROR, " Invalid hashtablez max samples: %lld" ,
268176 static_cast <long long >(max)); // NOLINT(runtime/int)
0 commit comments