• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <atomic>
35 #include <cstddef>
36 #include <cstdint>
37 
38 
39 // Must be included last.
40 #include <google/protobuf/port_def.inc>
41 
42 namespace google {
43 namespace protobuf {
44 namespace internal {
45 
46 #if defined(PROTOBUF_ARENAZ_SAMPLE)
47 struct ThreadSafeArenaStats;
48 void RecordResetSlow(ThreadSafeArenaStats* info);
49 void RecordAllocateSlow(ThreadSafeArenaStats* info, size_t requested,
50                         size_t allocated, size_t wasted);
51 // Stores information about a sampled thread safe arena.  All mutations to this
52 // *must* be made through `Record*` functions below.  All reads from this *must*
53 // only occur in the callback to `ThreadSafeArenazSampler::Iterate`.
54 struct ThreadSafeArenaStats
55     : public absl::profiling_internal::Sample<ThreadSafeArenaStats> {
56   // Constructs the object but does not fill in any fields.
57   ThreadSafeArenaStats();
58   ~ThreadSafeArenaStats();
59 
60   // Puts the object into a clean state, fills in the logically `const` members,
61   // blocking for any readers that are currently sampling the object.
62   void PrepareForSampling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu);
63 
64   // These fields are mutated by the various Record* APIs and need to be
65   // thread-safe.
66   std::atomic<int> num_allocations;
67   std::atomic<int> num_resets;
68   std::atomic<size_t> bytes_requested;
69   std::atomic<size_t> bytes_allocated;
70   std::atomic<size_t> bytes_wasted;
71   // Records the largest size an arena ever had.  Maintained across resets.
72   std::atomic<size_t> max_bytes_allocated;
73   // Bit i when set to 1 indicates that a thread with tid % 63 = i accessed the
74   // underlying arena.  The field is maintained across resets.
75   std::atomic<uint64_t> thread_ids;
76 
77   // All of the fields below are set by `PrepareForSampling`, they must not
78   // be mutated in `Record*` functions.  They are logically `const` in that
79   // sense. These are guarded by init_mu, but that is not externalized to
80   // clients, who can only read them during
81   // `ThreadSafeArenazSampler::Iterate` which will hold the lock.
82   static constexpr int kMaxStackDepth = 64;
83   int32_t depth;
84   void* stack[kMaxStackDepth];
RecordAllocateStatsThreadSafeArenaStats85   static void RecordAllocateStats(ThreadSafeArenaStats* info, size_t requested,
86                                   size_t allocated, size_t wasted) {
87     if (PROTOBUF_PREDICT_TRUE(info == nullptr)) return;
88     RecordAllocateSlow(info, requested, allocated, wasted);
89   }
90 };
91 
92 ThreadSafeArenaStats* SampleSlow(int64_t* next_sample);
93 void UnsampleSlow(ThreadSafeArenaStats* info);
94 
95 class ThreadSafeArenaStatsHandle {
96  public:
97   explicit ThreadSafeArenaStatsHandle() = default;
ThreadSafeArenaStatsHandle(ThreadSafeArenaStats * info)98   explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats* info)
99       : info_(info) {}
100 
~ThreadSafeArenaStatsHandle()101   ~ThreadSafeArenaStatsHandle() {
102     if (PROTOBUF_PREDICT_TRUE(info_ == nullptr)) return;
103     UnsampleSlow(info_);
104   }
105 
ThreadSafeArenaStatsHandle(ThreadSafeArenaStatsHandle && other)106   ThreadSafeArenaStatsHandle(ThreadSafeArenaStatsHandle&& other) noexcept
107       : info_(absl::exchange(other.info_, nullptr)) {}
108 
109   ThreadSafeArenaStatsHandle& operator=(
110       ThreadSafeArenaStatsHandle&& other) noexcept {
111     if (PROTOBUF_PREDICT_FALSE(info_ != nullptr)) {
112       UnsampleSlow(info_);
113     }
114     info_ = absl::exchange(other.info_, nullptr);
115     return *this;
116   }
117 
RecordReset()118   void RecordReset() {
119     if (PROTOBUF_PREDICT_TRUE(info_ == nullptr)) return;
120     RecordResetSlow(info_);
121   }
122 
MutableStats()123   ThreadSafeArenaStats* MutableStats() { return info_; }
124 
swap(ThreadSafeArenaStatsHandle & lhs,ThreadSafeArenaStatsHandle & rhs)125   friend void swap(ThreadSafeArenaStatsHandle& lhs,
126                    ThreadSafeArenaStatsHandle& rhs) {
127     std::swap(lhs.info_, rhs.info_);
128   }
129 
130   friend class ThreadSafeArenaStatsHandlePeer;
131 
132  private:
133   ThreadSafeArenaStats* info_ = nullptr;
134 };
135 
136 using ThreadSafeArenazSampler =
137     ::absl::profiling_internal::SampleRecorder<ThreadSafeArenaStats>;
138 
139 extern PROTOBUF_THREAD_LOCAL int64_t global_next_sample;
140 
141 // Returns an RAII sampling handle that manages registration and unregistation
142 // with the global sampler.
Sample()143 inline ThreadSafeArenaStatsHandle Sample() {
144   if (PROTOBUF_PREDICT_TRUE(--global_next_sample > 0)) {
145     return ThreadSafeArenaStatsHandle(nullptr);
146   }
147   return ThreadSafeArenaStatsHandle(SampleSlow(&global_next_sample));
148 }
149 
150 #else
151 struct ThreadSafeArenaStats {
152   static void RecordAllocateStats(ThreadSafeArenaStats*, size_t /*requested*/,
153                                   size_t /*allocated*/, size_t /*wasted*/) {}
154 };
155 
156 ThreadSafeArenaStats* SampleSlow(int64_t* next_sample);
157 void UnsampleSlow(ThreadSafeArenaStats* info);
158 
159 class ThreadSafeArenaStatsHandle {
160  public:
161   explicit ThreadSafeArenaStatsHandle() = default;
162   explicit ThreadSafeArenaStatsHandle(ThreadSafeArenaStats*) {}
163 
164   void RecordReset() {}
165 
166   ThreadSafeArenaStats* MutableStats() { return nullptr; }
167 
168   friend void swap(ThreadSafeArenaStatsHandle&, ThreadSafeArenaStatsHandle&) {}
169 
170  private:
171   friend class ThreadSafeArenaStatsHandlePeer;
172 };
173 
174 class ThreadSafeArenazSampler {
175  public:
176   void Unregister(ThreadSafeArenaStats*) {}
177   void SetMaxSamples(int32_t) {}
178 };
179 
180 // Returns an RAII sampling handle that manages registration and unregistation
181 // with the global sampler.
182 inline ThreadSafeArenaStatsHandle Sample() {
183   return ThreadSafeArenaStatsHandle(nullptr);
184 }
185 #endif  // defined(PROTOBUF_ARENAZ_SAMPLE)
186 
187 // Returns a global Sampler.
188 ThreadSafeArenazSampler& GlobalThreadSafeArenazSampler();
189 
190 // Enables or disables sampling for thread safe arenas.
191 void SetThreadSafeArenazEnabled(bool enabled);
192 
193 // Sets the rate at which thread safe arena will be sampled.
194 void SetThreadSafeArenazSampleParameter(int32_t rate);
195 
196 // Sets a soft max for the number of samples that will be kept.
197 void SetThreadSafeArenazMaxSamples(int32_t max);
198 
199 // Sets the current value for when arenas should be next sampled.
200 void SetThreadSafeArenazGlobalNextSample(int64_t next_sample);
201 
202 }  // namespace internal
203 }  // namespace protobuf
204 }  // namespace google
205 
206 #include <google/protobuf/port_undef.inc>
207 #endif  // GOOGLE_PROTOBUF_SRC_PROTOBUF_ARENAZ_SAMPLER_H__
208