File indexing completed on 2025-01-31 10:12:06
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef GOOGLE_PROTOBUF_SRC_GOOGLE_PROTOBUF_ARENAZ_SAMPLER_H__
0009 #define GOOGLE_PROTOBUF_SRC_GOOGLE_PROTOBUF_ARENAZ_SAMPLER_H__
0010
0011 #include <array>
0012 #include <atomic>
0013 #include <cstddef>
0014 #include <cstdint>
0015 #include <utility>
0016
0017
0018
0019 #include "google/protobuf/port_def.inc"
0020
0021 namespace google {
0022 namespace protobuf {
0023 namespace internal {
0024
0025 #if defined(PROTOBUF_ARENAZ_SAMPLE)
0026 struct ThreadSafeArenaStats;
0027 void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t used,
0028 size_t allocated, size_t wasted);
0029
0030
0031
0032 struct ThreadSafeArenaStats
0033 : public absl::profiling_internal::Sample<ThreadSafeArenaStats> {
0034
0035 ThreadSafeArenaStats();
0036 ~ThreadSafeArenaStats();
0037
0038
0039
0040
0041
0042 void PrepareForSampling(int64_t stride)
0043 ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu);
0044
0045
0046
0047 struct BlockStats {
0048 std::atomic<int> num_allocations;
0049 std::atomic<size_t> bytes_allocated;
0050 std::atomic<size_t> bytes_used;
0051 std::atomic<size_t> bytes_wasted;
0052
0053 void PrepareForSampling();
0054 };
0055
0056
0057
0058
0059
0060
0061
0062 static constexpr size_t kBlockHistogramBins = 15;
0063 static constexpr size_t kLogMaxSizeForBinZero = 7;
0064 static constexpr size_t kMaxSizeForBinZero = (1 << kLogMaxSizeForBinZero);
0065 static constexpr size_t kMaxSizeForPenultimateBin =
0066 1 << (kLogMaxSizeForBinZero + kBlockHistogramBins - 2);
0067 std::array<BlockStats, kBlockHistogramBins> block_histogram;
0068
0069
0070 std::atomic<size_t> max_block_size;
0071
0072
0073
0074
0075 std::atomic<uint64_t> thread_ids;
0076
0077
0078
0079
0080
0081
0082 static constexpr int kMaxStackDepth = 64;
0083 int32_t depth;
0084 void* stack[kMaxStackDepth];
0085 static void RecordAllocateStats(ThreadSafeArenaStats* info, size_t used,
0086 size_t allocated, size_t wasted) {
0087 if (PROTOBUF_PREDICT_TRUE(info == nullptr)) return;
0088 RecordAllocateSlow(info, used, allocated, wasted);
0089 }
0090
0091
0092 static size_t FindBin(size_t bytes);
0093
0094
0095
0096 static std::pair<size_t, size_t> MinMaxBlockSizeForBin(size_t bin);
0097 };
0098
0099 struct SamplingState {
0100
0101
0102
0103 int64_t next_sample;
0104
0105
0106
0107 int64_t sample_stride;
0108 };
0109
0110 ThreadSafeArenaStats* SampleSlow(SamplingState& sampling_state);
0111 void UnsampleSlow(ThreadSafeArenaStats* info);
0112
0113 class ThreadSafeArenaStatsHandle {
0114 public:
0115 explicit ThreadSafeArenaStatsHandle() = default;
0116 explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats* info)
0117 : info_(info) {}
0118
0119 ~ThreadSafeArenaStatsHandle() {
0120 if (PROTOBUF_PREDICT_TRUE(info_ == nullptr)) return;
0121 UnsampleSlow(info_);
0122 }
0123
0124 ThreadSafeArenaStatsHandle(ThreadSafeArenaStatsHandle&& other) noexcept
0125 : info_(std::exchange(other.info_, nullptr)) {}
0126
0127 ThreadSafeArenaStatsHandle& operator=(
0128 ThreadSafeArenaStatsHandle&& other) noexcept {
0129 if (PROTOBUF_PREDICT_FALSE(info_ != nullptr)) {
0130 UnsampleSlow(info_);
0131 }
0132 info_ = std::exchange(other.info_, nullptr);
0133 return *this;
0134 }
0135
0136 ThreadSafeArenaStats* MutableStats() { return info_; }
0137
0138 friend void swap(ThreadSafeArenaStatsHandle& lhs,
0139 ThreadSafeArenaStatsHandle& rhs) {
0140 std::swap(lhs.info_, rhs.info_);
0141 }
0142
0143 friend class ThreadSafeArenaStatsHandlePeer;
0144
0145 private:
0146 ThreadSafeArenaStats* info_ = nullptr;
0147 };
0148
0149 using ThreadSafeArenazSampler =
0150 ::absl::profiling_internal::SampleRecorder<ThreadSafeArenaStats>;
0151
0152 extern PROTOBUF_THREAD_LOCAL SamplingState global_sampling_state;
0153
0154
0155
0156 inline ThreadSafeArenaStatsHandle Sample() {
0157 if (PROTOBUF_PREDICT_TRUE(--global_sampling_state.next_sample > 0)) {
0158 return ThreadSafeArenaStatsHandle(nullptr);
0159 }
0160 return ThreadSafeArenaStatsHandle(SampleSlow(global_sampling_state));
0161 }
0162
0163 #else
0164
0165 using SamplingState = int64_t;
0166
0167 struct ThreadSafeArenaStats {
0168 static void RecordAllocateStats(ThreadSafeArenaStats*, size_t ,
0169 size_t , size_t ) {}
0170 };
0171
0172 ThreadSafeArenaStats* SampleSlow(SamplingState& next_sample);
0173 void UnsampleSlow(ThreadSafeArenaStats* info);
0174
0175 class ThreadSafeArenaStatsHandle {
0176 public:
0177 explicit ThreadSafeArenaStatsHandle() = default;
0178 explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats*) {}
0179
0180 void RecordReset() {}
0181
0182 ThreadSafeArenaStats* MutableStats() { return nullptr; }
0183
0184 friend void swap(ThreadSafeArenaStatsHandle&, ThreadSafeArenaStatsHandle&) {}
0185
0186 private:
0187 friend class ThreadSafeArenaStatsHandlePeer;
0188 };
0189
0190 class ThreadSafeArenazSampler {
0191 public:
0192 void Unregister(ThreadSafeArenaStats*) {}
0193 void SetMaxSamples(int32_t) {}
0194 };
0195
0196
0197
0198 inline ThreadSafeArenaStatsHandle Sample() {
0199 return ThreadSafeArenaStatsHandle(nullptr);
0200 }
0201 #endif
0202
0203
0204 ThreadSafeArenazSampler& GlobalThreadSafeArenazSampler();
0205
0206 using ThreadSafeArenazConfigListener = void (*)();
0207 void SetThreadSafeArenazConfigListener(ThreadSafeArenazConfigListener l);
0208
0209
0210 void SetThreadSafeArenazEnabled(bool enabled);
0211 void SetThreadSafeArenazEnabledInternal(bool enabled);
0212
0213
0214 bool IsThreadSafeArenazEnabled();
0215
0216
0217 void SetThreadSafeArenazSampleParameter(int32_t rate);
0218 void SetThreadSafeArenazSampleParameterInternal(int32_t rate);
0219
0220
0221 int32_t ThreadSafeArenazSampleParameter();
0222
0223
0224 void SetThreadSafeArenazMaxSamples(int32_t max);
0225 void SetThreadSafeArenazMaxSamplesInternal(int32_t max);
0226
0227
0228 size_t ThreadSafeArenazMaxSamples();
0229
0230
0231 void SetThreadSafeArenazGlobalNextSample(int64_t next_sample);
0232
0233 }
0234 }
0235 }
0236
0237 #include "google/protobuf/port_undef.inc"
0238 #endif