abseil-cpp/absl/container/internal/hashtablez_sampler.h
Go to the documentation of this file.
1 // Copyright 2018 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // -----------------------------------------------------------------------------
16 // File: hashtablez_sampler.h
17 // -----------------------------------------------------------------------------
18 //
19 // This header file defines the API for a low level library to sample hashtables
20 // and collect runtime statistics about them.
21 //
22 // `HashtablezSampler` controls the lifecycle of `HashtablezInfo` objects which
23 // store information about a single sample.
24 //
25 // `Record*` methods store information into samples.
26 // `Sample()` and `Unsample()` make use of a single global sampler with
27 // properties controlled by the flags hashtablez_enabled,
28 // hashtablez_sample_rate, and hashtablez_max_samples.
29 //
30 // WARNING
31 //
32 // Using this sampling API may cause sampled Swiss tables to use the global
33 // allocator (operator `new`) in addition to any custom allocator. If you
34 // are using a table in an unusual circumstance where allocation or calling a
35 // linux syscall is unacceptable, this could interfere.
36 //
37 // This utility is internal-only. Use at your own risk.
38 
39 #ifndef ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
40 #define ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
41 
42 #include <atomic>
43 #include <functional>
44 #include <memory>
45 #include <vector>
46 
47 #include "absl/base/config.h"
48 #include "absl/base/internal/per_thread_tls.h"
49 #include "absl/base/optimization.h"
51 #include "absl/synchronization/mutex.h"
52 #include "absl/utility/utility.h"
53 
54 namespace absl {
56 namespace container_internal {
57 
58 // Stores information about a sampled hashtable. All mutations to this *must*
59 // be made through `Record*` functions below. All reads from this *must* only
60 // occur in the callback to `HashtablezSampler::Iterate`.
61 struct HashtablezInfo : public profiling_internal::Sample<HashtablezInfo> {
62  // Constructs the object but does not fill in any fields.
65  HashtablezInfo(const HashtablezInfo&) = delete;
66  HashtablezInfo& operator=(const HashtablezInfo&) = delete;
67 
68  // Puts the object into a clean state, fills in the logically `const` members,
69  // blocking for any readers that are currently sampling the object.
70  void PrepareForSampling(int64_t stride, size_t inline_element_size_value)
72 
73  // These fields are mutated by the various Record* APIs and need to be
74  // thread-safe.
75  std::atomic<size_t> capacity;
76  std::atomic<size_t> size;
77  std::atomic<size_t> num_erases;
78  std::atomic<size_t> num_rehashes;
79  std::atomic<size_t> max_probe_length;
80  std::atomic<size_t> total_probe_length;
81  std::atomic<size_t> hashes_bitwise_or;
82  std::atomic<size_t> hashes_bitwise_and;
83  std::atomic<size_t> hashes_bitwise_xor;
84  std::atomic<size_t> max_reserve;
85 
86  // All of the fields below are set by `PrepareForSampling`, they must not be
87  // mutated in `Record*` functions. They are logically `const` in that sense.
88  // These are guarded by init_mu, but that is not externalized to clients,
89  // which can read them only during `SampleRecorder::Iterate` which will hold
90  // the lock.
91  static constexpr int kMaxStackDepth = 64;
95  size_t inline_element_size; // How big is the slot?
96 };
97 
98 inline void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length) {
99 #ifdef ABSL_INTERNAL_HAVE_SSE2
100  total_probe_length /= 16;
101 #else
102  total_probe_length /= 8;
103 #endif
104  info->total_probe_length.store(total_probe_length, std::memory_order_relaxed);
105  info->num_erases.store(0, std::memory_order_relaxed);
106  // There is only one concurrent writer, so `load` then `store` is sufficient
107  // instead of using `fetch_add`.
108  info->num_rehashes.store(
109  1 + info->num_rehashes.load(std::memory_order_relaxed),
110  std::memory_order_relaxed);
111 }
112 
114  size_t target_capacity) {
115  info->max_reserve.store(
116  (std::max)(info->max_reserve.load(std::memory_order_relaxed),
117  target_capacity),
118  std::memory_order_relaxed);
119 }
120 
122  info->max_reserve.store(0, std::memory_order_relaxed);
123 }
124 
125 inline void RecordStorageChangedSlow(HashtablezInfo* info, size_t size,
126  size_t capacity) {
127  info->size.store(size, std::memory_order_relaxed);
128  info->capacity.store(capacity, std::memory_order_relaxed);
129  if (size == 0) {
130  // This is a clear, reset the total/num_erases too.
131  info->total_probe_length.store(0, std::memory_order_relaxed);
132  info->num_erases.store(0, std::memory_order_relaxed);
133  }
134 }
135 
136 void RecordInsertSlow(HashtablezInfo* info, size_t hash,
137  size_t distance_from_desired);
138 
139 inline void RecordEraseSlow(HashtablezInfo* info) {
140  info->size.fetch_sub(1, std::memory_order_relaxed);
141  // There is only one concurrent writer, so `load` then `store` is sufficient
142  // instead of using `fetch_add`.
143  info->num_erases.store(
144  1 + info->num_erases.load(std::memory_order_relaxed),
145  std::memory_order_relaxed);
146 }
147 
150  // When we make a sampling decision, we record that distance so we can weight
151  // each sample.
153 };
154 
156  size_t inline_element_size);
157 void UnsampleSlow(HashtablezInfo* info);
158 
159 #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
160 #error ABSL_INTERNAL_HASHTABLEZ_SAMPLE cannot be directly set
161 #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
162 
163 #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
164 class HashtablezInfoHandle {
165  public:
166  explicit HashtablezInfoHandle() : info_(nullptr) {}
167  explicit HashtablezInfoHandle(HashtablezInfo* info) : info_(info) {}
169  if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
171  }
172 
174  HashtablezInfoHandle& operator=(const HashtablezInfoHandle&) = delete;
175 
177  : info_(absl::exchange(o.info_, nullptr)) {}
178  HashtablezInfoHandle& operator=(HashtablezInfoHandle&& o) noexcept {
179  if (ABSL_PREDICT_FALSE(info_ != nullptr)) {
181  }
182  info_ = absl::exchange(o.info_, nullptr);
183  return *this;
184  }
185 
186  inline void RecordStorageChanged(size_t size, size_t capacity) {
187  if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
189  }
190 
191  inline void RecordRehash(size_t total_probe_length) {
192  if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
193  RecordRehashSlow(info_, total_probe_length);
194  }
195 
196  inline void RecordReservation(size_t target_capacity) {
197  if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
198  RecordReservationSlow(info_, target_capacity);
199  }
200 
201  inline void RecordClearedReservation() {
202  if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
204  }
205 
206  inline void RecordInsert(size_t hash, size_t distance_from_desired) {
207  if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
208  RecordInsertSlow(info_, hash, distance_from_desired);
209  }
210 
211  inline void RecordErase() {
212  if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
214  }
215 
216  friend inline void swap(HashtablezInfoHandle& lhs,
217  HashtablezInfoHandle& rhs) {
218  std::swap(lhs.info_, rhs.info_);
219  }
220 
221  private:
222  friend class HashtablezInfoHandlePeer;
223  HashtablezInfo* info_;
224 };
225 #else
226 // Ensure that when Hashtablez is turned off at compile time, HashtablezInfo can
227 // be removed by the linker, in order to reduce the binary size.
229  public:
230  explicit HashtablezInfoHandle() = default;
231  explicit HashtablezInfoHandle(std::nullptr_t) {}
232 
233  inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/) {}
234  inline void RecordRehash(size_t /*total_probe_length*/) {}
235  inline void RecordReservation(size_t /*target_capacity*/) {}
236  inline void RecordClearedReservation() {}
237  inline void RecordInsert(size_t /*hash*/, size_t /*distance_from_desired*/) {}
238  inline void RecordErase() {}
239 
240  friend inline void swap(HashtablezInfoHandle& /*lhs*/,
241  HashtablezInfoHandle& /*rhs*/) {}
242 };
243 #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
244 
245 #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
246 extern ABSL_PER_THREAD_TLS_KEYWORD SamplingState global_next_sample;
247 #endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
248 
249 // Returns an RAII sampling handle that manages registration and unregistation
250 // with the global sampler.
252  size_t inline_element_size ABSL_ATTRIBUTE_UNUSED) {
253 #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
254  if (ABSL_PREDICT_TRUE(--global_next_sample.next_sample > 0)) {
255  return HashtablezInfoHandle(nullptr);
256  }
257  return HashtablezInfoHandle(
258  SampleSlow(global_next_sample, inline_element_size));
259 #else
260  return HashtablezInfoHandle(nullptr);
261 #endif // !ABSL_PER_THREAD_TLS
262 }
263 
264 using HashtablezSampler =
266 
267 // Returns a global Sampler.
269 
270 using HashtablezConfigListener = void (*)();
272 
273 // Enables or disables sampling for Swiss tables.
274 bool IsHashtablezEnabled();
275 void SetHashtablezEnabled(bool enabled);
276 void SetHashtablezEnabledInternal(bool enabled);
277 
278 // Sets the rate at which Swiss tables will be sampled.
282 
283 // Sets a soft max for the number of samples that will be kept.
287 
288 // Configuration override.
289 // This allows process-wide sampling without depending on order of
290 // initialization of static storage duration objects.
291 // The definition of this constant is weak, which allows us to inject a
292 // different value for it at link time.
294 
295 } // namespace container_internal
297 } // namespace absl
298 
299 #endif // ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
ABSL_PREDICT_FALSE
#define ABSL_PREDICT_FALSE(x)
Definition: abseil-cpp/absl/base/optimization.h:180
absl::container_internal::SetHashtablezMaxSamples
void SetHashtablezMaxSamples(int32_t max)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:222
absl::container_internal::HashtablezInfo::stack
void * stack[kMaxStackDepth]
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:94
absl::container_internal::HashtablezInfo::HashtablezInfo
HashtablezInfo()
Definition: bloaty/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc:63
absl::container_internal::GetHashtablezMaxSamples
int32_t GetHashtablezMaxSamples()
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:218
absl::profiling_internal::Sample
Definition: sample_recorder.h:43
absl::container_internal::HashtablezInfo::init_mu
absl::Mutex init_mu
Definition: bloaty/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h:87
absl::container_internal::HashtablezInfo::num_erases
std::atomic< size_t > num_erases
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:77
absl::Time
Definition: third_party/abseil-cpp/absl/time/time.h:642
absl::container_internal::SetHashtablezEnabled
void SetHashtablezEnabled(bool enabled)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:191
absl::container_internal::HashtablezSampler
::absl::profiling_internal::SampleRecorder< HashtablezInfo > HashtablezSampler
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:265
capacity
uint16_t capacity
Definition: protobuf/src/google/protobuf/descriptor.cc:948
ABSL_ATTRIBUTE_UNUSED
#define ABSL_ATTRIBUTE_UNUSED
Definition: abseil-cpp/absl/base/attributes.h:550
absl::container_internal::HashtablezInfo::kMaxStackDepth
static constexpr int kMaxStackDepth
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:91
absl::container_internal::HashtablezInfoHandle::RecordClearedReservation
void RecordClearedReservation()
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:236
absl::container_internal::RecordRehashSlow
void RecordRehashSlow(HashtablezInfo *info, size_t total_probe_length)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:98
absl::container_internal::HashtablezInfo::max_reserve
std::atomic< size_t > max_reserve
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:84
absl::container_internal::HashtablezInfo::depth
int32_t depth
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:93
absl::container_internal::IsHashtablezEnabled
bool IsHashtablezEnabled()
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:187
absl::container_internal::RecordClearedReservationSlow
void RecordClearedReservationSlow(HashtablezInfo *info)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:121
absl::container_internal::HashtablezInfoHandle::RecordReservation
void RecordReservation(size_t)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:235
absl::container_internal::HashtablezInfoHandle
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:228
absl::container_internal::HashtablezInfoHandle::swap
friend void swap(HashtablezInfoHandle &, HashtablezInfoHandle &)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:240
absl::container_internal::HashtablezSampler
Definition: bloaty/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.h:238
absl::container_internal::SampleSlow
HashtablezInfo * SampleSlow(SamplingState &next_sample, size_t inline_element_size)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:114
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::container_internal::RecordStorageChangedSlow
void RecordStorageChangedSlow(HashtablezInfo *info, size_t size, size_t capacity)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:125
absl::container_internal::HashtablezInfo::hashes_bitwise_or
std::atomic< size_t > hashes_bitwise_or
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:81
info_
experimental::ClientRpcInfo * info_
Definition: client_interceptors_end2end_test.cc:169
absl::container_internal::SamplingState
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:148
o
UnboundConversion o
Definition: third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc:97
hash
uint64_t hash
Definition: ring_hash.cc:284
sample_recorder.h
absl::container_internal::AbslContainerInternalSampleEverything
bool ABSL_INTERNAL_C_SYMBOL() AbslContainerInternalSampleEverything()
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler_force_weak_definition.cc:25
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::container_internal::HashtablezInfo::hashes_bitwise_and
std::atomic< size_t > hashes_bitwise_and
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:82
absl::container_internal::HashtablezInfo::capacity
std::atomic< size_t > capacity
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:75
int64_t
signed __int64 int64_t
Definition: stdint-msvc2008.h:89
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
absl::container_internal::SamplingState::next_sample
int64_t next_sample
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:149
ABSL_EXCLUSIVE_LOCKS_REQUIRED
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: abseil-cpp/absl/base/thread_annotations.h:145
absl::container_internal::HashtablezInfo::inline_element_size
size_t inline_element_size
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:95
absl::container_internal::HashtablezInfo::num_rehashes
std::atomic< size_t > num_rehashes
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:78
absl::container_internal::HashtablezInfo::create_time
absl::Time create_time
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:92
absl::container_internal::HashtablezInfo::size
std::atomic< size_t > size
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:76
absl::container_internal::HashtablezInfo::~HashtablezInfo
~HashtablezInfo()
std::swap
void swap(Json::Value &a, Json::Value &b)
Specialize std::swap() for Json::Value.
Definition: third_party/bloaty/third_party/protobuf/conformance/third_party/jsoncpp/json.h:1226
absl::container_internal::HashtablezInfoHandle::HashtablezInfoHandle
HashtablezInfoHandle()=default
ABSL_PER_THREAD_TLS_KEYWORD
#define ABSL_PER_THREAD_TLS_KEYWORD
Definition: abseil-cpp/absl/base/internal/per_thread_tls.h:48
absl::container_internal::HashtablezInfo::max_probe_length
std::atomic< size_t > max_probe_length
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:79
ABSL_INTERNAL_C_SYMBOL
#define ABSL_INTERNAL_C_SYMBOL(x)
Definition: third_party/abseil-cpp/absl/base/config.h:172
absl::container_internal::SetHashtablezMaxSamplesInternal
void SetHashtablezMaxSamplesInternal(int32_t max)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:227
absl::container_internal::SetHashtablezSampleParameter
void SetHashtablezSampleParameter(int32_t rate)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:204
ABSL_PREDICT_TRUE
#define ABSL_PREDICT_TRUE(x)
Definition: abseil-cpp/absl/base/optimization.h:181
absl::container_internal::GetHashtablezSampleParameter
int32_t GetHashtablezSampleParameter()
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:200
absl::container_internal::SetHashtablezEnabledInternal
void SetHashtablezEnabledInternal(bool enabled)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:196
absl::container_internal::SetHashtablezConfigListener
void SetHashtablezConfigListener(HashtablezConfigListener l)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:183
absl::container_internal::HashtablezInfoHandle::RecordInsert
void RecordInsert(size_t, size_t)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:237
absl::container_internal::HashtablezInfo
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:61
absl::container_internal::GlobalHashtablezSampler
HashtablezSampler & GlobalHashtablezSampler()
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:63
absl::container_internal::HashtablezInfo::hashes_bitwise_xor
std::atomic< size_t > hashes_bitwise_xor
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:83
absl::container_internal::HashtablezInfoHandle::RecordRehash
void RecordRehash(size_t)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:234
absl::container_internal::Sample
HashtablezInfoHandle Sample(size_t inline_element_size ABSL_ATTRIBUTE_UNUSED)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:251
absl::container_internal::SamplingState::sample_stride
int64_t sample_stride
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:152
absl::container_internal::RecordReservationSlow
void RecordReservationSlow(HashtablezInfo *info, size_t target_capacity)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:113
absl::container_internal::RecordInsertSlow
void RecordInsertSlow(HashtablezInfo *info, size_t hash, size_t distance_from_desired)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:161
absl::container_internal::HashtablezInfoHandle::HashtablezInfoHandle
HashtablezInfoHandle(std::nullptr_t)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:231
absl::container_internal::HashtablezInfo::operator=
HashtablezInfo & operator=(const HashtablezInfo &)=delete
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::container_internal::HashtablezInfoHandle::RecordErase
void RecordErase()
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:238
absl::container_internal::RecordEraseSlow
void RecordEraseSlow(HashtablezInfo *info)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:139
absl::container_internal::HashtablezConfigListener
void(*)() HashtablezConfigListener
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:270
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
absl::container_internal::SetHashtablezSampleParameterInternal
void SetHashtablezSampleParameterInternal(int32_t rate)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:209
int32_t
signed int int32_t
Definition: stdint-msvc2008.h:77
absl::container_internal::HashtablezInfo::PrepareForSampling
void PrepareForSampling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu)
Definition: bloaty/third_party/abseil-cpp/absl/container/internal/hashtablez_sampler.cc:66
absl::profiling_internal::SampleRecorder
Definition: sample_recorder.h:57
absl::exchange
T exchange(T &obj, U &&new_value)
Definition: abseil-cpp/absl/utility/utility.h:314
absl::container_internal::UnsampleSlow
void UnsampleSlow(HashtablezInfo *info)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.cc:157
absl::container_internal::HashtablezInfo::total_probe_length
std::atomic< size_t > total_probe_length
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:80
absl::container_internal::HashtablezInfoHandle::RecordStorageChanged
void RecordStorageChanged(size_t, size_t)
Definition: abseil-cpp/absl/container/internal/hashtablez_sampler.h:233


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:01