Coverage Report

Created: 2023-06-07 07:09

/src/LPM/external.protobuf/include/google/protobuf/arenaz_sampler.h
Line
Count
Source (jump to first uncovered line)
1
// Protocol Buffers - Google's data interchange format
2
// Copyright 2008 Google Inc.  All rights reserved.
3
// https://developers.google.com/protocol-buffers/
4
//
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions are
7
// met:
8
//
9
//     * Redistributions of source code must retain the above copyright
10
// notice, this list of conditions and the following disclaimer.
11
//     * Redistributions in binary form must reproduce the above
12
// copyright notice, this list of conditions and the following disclaimer
13
// in the documentation and/or other materials provided with the
14
// distribution.
15
//     * Neither the name of Google Inc. nor the names of its
16
// contributors may be used to endorse or promote products derived from
17
// this software without specific prior written permission.
18
//
19
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31
#ifndef GOOGLE_PROTOBUF_SRC_GOOGLE_PROTOBUF_ARENAZ_SAMPLER_H__
32
#define GOOGLE_PROTOBUF_SRC_GOOGLE_PROTOBUF_ARENAZ_SAMPLER_H__
33
34
#include <array>
35
#include <atomic>
36
#include <cstddef>
37
#include <cstdint>
38
#include <utility>
39
40
41
// Must be included last.
42
#include "google/protobuf/port_def.inc"
43
44
namespace google {
45
namespace protobuf {
46
namespace internal {
47
48
#if defined(PROTOBUF_ARENAZ_SAMPLE)
49
struct ThreadSafeArenaStats;
50
void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t used,
51
                        size_t allocated, size_t wasted);
52
// Stores information about a sampled thread safe arena.  All mutations to this
53
// *must* be made through `Record*` functions below.  All reads from this *must*
54
// only occur in the callback to `ThreadSafeArenazSampler::Iterate`.
55
struct ThreadSafeArenaStats
56
    : public absl::profiling_internal::Sample<ThreadSafeArenaStats> {
57
  // Constructs the object but does not fill in any fields.
58
  ThreadSafeArenaStats();
59
  ~ThreadSafeArenaStats();
60
61
  // Puts the object into a clean state, fills in the logically `const` members,
62
  // blocking for any readers that are currently sampling the object.  The
63
  // 'stride' parameter is the number of ThreadSafeArenas that were instantiated
64
  // between this sample and the previous one.
65
  void PrepareForSampling(int64_t stride)
66
      ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu);
67
68
  // These fields are mutated by the various Record* APIs and need to be
69
  // thread-safe.
70
  struct BlockStats {
71
    std::atomic<int> num_allocations;
72
    std::atomic<size_t> bytes_allocated;
73
    std::atomic<size_t> bytes_used;
74
    std::atomic<size_t> bytes_wasted;
75
76
    void PrepareForSampling();
77
  };
78
79
  // block_histogram is a kBlockHistogramBins sized histogram.  The zeroth bin
80
  // stores info about blocks of size \in [1, 1 << kLogMaxSizeForBinZero]. Bin
81
  // i, where i > 0, stores info for blocks of size \in (max_size_bin (i-1),
82
  // 1 << (kLogMaxSizeForBinZero + i)].  The final bin stores info about blocks
83
  // of size \in [kMaxSizeForPenultimateBin + 1,
84
  // std::numeric_limits<size_t>::max()].
85
  static constexpr size_t kBlockHistogramBins = 15;
86
  static constexpr size_t kLogMaxSizeForBinZero = 7;
87
  static constexpr size_t kMaxSizeForBinZero = (1 << kLogMaxSizeForBinZero);
88
  static constexpr size_t kMaxSizeForPenultimateBin =
89
      1 << (kLogMaxSizeForBinZero + kBlockHistogramBins - 2);
90
  std::array<BlockStats, kBlockHistogramBins> block_histogram;
91
92
  // Records the largest block allocated for the arena.
93
  std::atomic<size_t> max_block_size;
94
  // Bit `i` is set to 1 indicates that a thread with `tid % 63 = i` accessed
95
  // the underlying arena.  We use `% 63` as a rudimentary hash to ensure some
96
  // bit mixing for thread-ids; `% 64` would only grab the low bits and might
97
  // create sampling artifacts.
98
  std::atomic<uint64_t> thread_ids;
99
100
  // All of the fields below are set by `PrepareForSampling`, they must not
101
  // be mutated in `Record*` functions.  They are logically `const` in that
102
  // sense. These are guarded by init_mu, but that is not externalized to
103
  // clients, who can only read them during
104
  // `ThreadSafeArenazSampler::Iterate` which will hold the lock.
105
  static constexpr int kMaxStackDepth = 64;
106
  int32_t depth;
107
  void* stack[kMaxStackDepth];
108
  static void RecordAllocateStats(ThreadSafeArenaStats* info, size_t used,
109
                                  size_t allocated, size_t wasted) {
110
    if (PROTOBUF_PREDICT_TRUE(info == nullptr)) return;
111
    RecordAllocateSlow(info, used, allocated, wasted);
112
  }
113
114
  // Returns the bin for the provided size.
115
  static size_t FindBin(size_t bytes);
116
117
  // Returns the min and max bytes that can be stored in the histogram for
118
  // blocks in the provided bin.
119
  static std::pair<size_t, size_t> MinMaxBlockSizeForBin(size_t bin);
120
};
121
122
struct SamplingState {
123
  // Number of ThreadSafeArenas that should be instantiated before the next
124
  // ThreadSafeArena is sampled.  This variable is decremented with each
125
  // instantiation.
126
  int64_t next_sample;
127
  // When we make a sampling decision, we record that distance between from the
128
  // previous sample so we can weight each sample.  'distance' here is the
129
  // number of instantiations of ThreadSafeArena.
130
  int64_t sample_stride;
131
};
132
133
ThreadSafeArenaStats* SampleSlow(SamplingState& sampling_state);
134
void UnsampleSlow(ThreadSafeArenaStats* info);
135
136
class ThreadSafeArenaStatsHandle {
137
 public:
138
  explicit ThreadSafeArenaStatsHandle() = default;
139
  explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats* info)
140
      : info_(info) {}
141
142
  ~ThreadSafeArenaStatsHandle() {
143
    if (PROTOBUF_PREDICT_TRUE(info_ == nullptr)) return;
144
    UnsampleSlow(info_);
145
  }
146
147
  ThreadSafeArenaStatsHandle(ThreadSafeArenaStatsHandle&& other) noexcept
148
      : info_(absl::exchange(other.info_, nullptr)) {}
149
150
  ThreadSafeArenaStatsHandle& operator=(
151
      ThreadSafeArenaStatsHandle&& other) noexcept {
152
    if (PROTOBUF_PREDICT_FALSE(info_ != nullptr)) {
153
      UnsampleSlow(info_);
154
    }
155
    info_ = absl::exchange(other.info_, nullptr);
156
    return *this;
157
  }
158
159
  ThreadSafeArenaStats* MutableStats() { return info_; }
160
161
  friend void swap(ThreadSafeArenaStatsHandle& lhs,
162
                   ThreadSafeArenaStatsHandle& rhs) {
163
    std::swap(lhs.info_, rhs.info_);
164
  }
165
166
  friend class ThreadSafeArenaStatsHandlePeer;
167
168
 private:
169
  ThreadSafeArenaStats* info_ = nullptr;
170
};
171
172
using ThreadSafeArenazSampler =
173
    ::absl::profiling_internal::SampleRecorder<ThreadSafeArenaStats>;
174
175
extern PROTOBUF_THREAD_LOCAL SamplingState global_sampling_state;
176
177
// Returns an RAII sampling handle that manages registration and unregistation
178
// with the global sampler.
179
inline ThreadSafeArenaStatsHandle Sample() {
180
  if (PROTOBUF_PREDICT_TRUE(--global_sampling_state.next_sample > 0)) {
181
    return ThreadSafeArenaStatsHandle(nullptr);
182
  }
183
  return ThreadSafeArenaStatsHandle(SampleSlow(global_sampling_state));
184
}
185
186
#else
187
188
using SamplingState = int64_t;
189
190
struct ThreadSafeArenaStats {
191
  static void RecordAllocateStats(ThreadSafeArenaStats*, size_t /*requested*/,
192
0
                                  size_t /*allocated*/, size_t /*wasted*/) {}
193
};
194
195
ThreadSafeArenaStats* SampleSlow(SamplingState& next_sample);
196
void UnsampleSlow(ThreadSafeArenaStats* info);
197
198
class ThreadSafeArenaStatsHandle {
199
 public:
200
  explicit ThreadSafeArenaStatsHandle() = default;
201
0
  explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats*) {}
202
203
0
  void RecordReset() {}
204
205
0
  ThreadSafeArenaStats* MutableStats() { return nullptr; }
206
207
0
  friend void swap(ThreadSafeArenaStatsHandle&, ThreadSafeArenaStatsHandle&) {}
208
209
 private:
210
  friend class ThreadSafeArenaStatsHandlePeer;
211
};
212
213
class ThreadSafeArenazSampler {
214
 public:
215
0
  void Unregister(ThreadSafeArenaStats*) {}
216
0
  void SetMaxSamples(int32_t) {}
217
};
218
219
// Returns an RAII sampling handle that manages registration and unregistation
220
// with the global sampler.
221
0
inline ThreadSafeArenaStatsHandle Sample() {
222
0
  return ThreadSafeArenaStatsHandle(nullptr);
223
0
}
224
#endif  // defined(PROTOBUF_ARENAZ_SAMPLE)
225
226
// Returns a global Sampler.
227
ThreadSafeArenazSampler& GlobalThreadSafeArenazSampler();
228
229
using ThreadSafeArenazConfigListener = void (*)();
230
void SetThreadSafeArenazConfigListener(ThreadSafeArenazConfigListener l);
231
232
// Enables or disables sampling for thread safe arenas.
233
void SetThreadSafeArenazEnabled(bool enabled);
234
void SetThreadSafeArenazEnabledInternal(bool enabled);
235
236
// Returns true if sampling is on, false otherwise.
237
bool IsThreadSafeArenazEnabled();
238
239
// Sets the rate at which thread safe arena will be sampled.
240
void SetThreadSafeArenazSampleParameter(int32_t rate);
241
void SetThreadSafeArenazSampleParameterInternal(int32_t rate);
242
243
// Returns the rate at which thread safe arena will be sampled.
244
int32_t ThreadSafeArenazSampleParameter();
245
246
// Sets a soft max for the number of samples that will be kept.
247
void SetThreadSafeArenazMaxSamples(int32_t max);
248
void SetThreadSafeArenazMaxSamplesInternal(int32_t max);
249
250
// Returns the max number of samples that will be kept.
251
size_t ThreadSafeArenazMaxSamples();
252
253
// Sets the current value for when arenas should be next sampled.
254
void SetThreadSafeArenazGlobalNextSample(int64_t next_sample);
255
256
}  // namespace internal
257
}  // namespace protobuf
258
}  // namespace google
259
260
#include "google/protobuf/port_undef.inc"
261
#endif  // GOOGLE_PROTOBUF_SRC_PROTOBUF_ARENAZ_SAMPLER_H__