• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
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  * http://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 #ifndef PANDA_RUNTIME_MEM_GC_GC_STATS_H
16 #define PANDA_RUNTIME_MEM_GC_GC_STATS_H
17 
18 #include "libpandabase/os/mutex.h"
19 #include "runtime/include/histogram-inl.h"
20 #include "runtime/include/mem/panda_containers.h"
21 #include "runtime/include/mem/panda_string.h"
22 #include "runtime/include/time_utils.h"
23 #include "runtime/mem/gc/gc_types.h"
24 
25 #include <algorithm>
26 #include <atomic>
27 #include <ratio>
28 
29 namespace ark::mem {
30 
31 namespace test {
32 class MemStatsGenGCTest;
33 }  // namespace test
34 
35 class GCStats;
36 class HeapManager;
37 
38 enum class ObjectTypeStats : size_t {
39     YOUNG_FREED_OBJECTS = 0,
40     MOVED_OBJECTS,
41     ALL_FREED_OBJECTS,
42 
43     OBJECT_TYPE_STATS_LAST
44 };
45 
ToIndex(ObjectTypeStats type)46 constexpr size_t ToIndex(ObjectTypeStats type)
47 {
48     return static_cast<size_t>(type);
49 }
50 
51 constexpr size_t OBJECT_TYPE_STATS_SIZE = static_cast<size_t>(ObjectTypeStats::OBJECT_TYPE_STATS_LAST);
52 
53 enum class MemoryTypeStats : size_t {
54     YOUNG_FREED_BYTES = 0,
55     MOVED_BYTES,
56     ALL_FREED_BYTES,
57 
58     MEMORY_TYPE_STATS_LAST
59 };
60 
ToIndex(MemoryTypeStats type)61 constexpr size_t ToIndex(MemoryTypeStats type)
62 {
63     return static_cast<size_t>(type);
64 }
65 
66 constexpr size_t MEMORY_TYPE_STATS_SIZE = static_cast<size_t>(MemoryTypeStats::MEMORY_TYPE_STATS_LAST);
67 
68 enum class TimeTypeStats : size_t {
69     YOUNG_PAUSED_TIME = 0,
70     YOUNG_TOTAL_TIME,
71     ALL_PAUSED_TIME,
72     ALL_TOTAL_TIME,
73 
74     TIME_TYPE_STATS_LAST
75 };
76 
ToIndex(TimeTypeStats type)77 constexpr size_t ToIndex(TimeTypeStats type)
78 {
79     return static_cast<size_t>(type);
80 }
81 
82 constexpr size_t TIME_TYPE_STATS_SIZE = static_cast<size_t>(TimeTypeStats::TIME_TYPE_STATS_LAST);
83 
84 enum class PauseTypeStats : size_t {
85     COMMON_PAUSE = 0,
86     INITIAL_MARK_PAUSE,
87     REMARK_PAUSE,
88 
89     PAUSE_TYPE_STATS_LAST
90 };
91 
ToIndex(PauseTypeStats type)92 constexpr size_t ToIndex(PauseTypeStats type)
93 {
94     return static_cast<size_t>(type);
95 }
96 
ToPauseTypeStats(size_t type)97 constexpr PauseTypeStats ToPauseTypeStats(size_t type)
98 {
99     return static_cast<PauseTypeStats>(type);
100 }
101 
ToString(PauseTypeStats type)102 constexpr std::string_view ToString(PauseTypeStats type)
103 {
104     switch (type) {
105         case PauseTypeStats::COMMON_PAUSE:
106             return "COMMON_PAUSE";
107         case PauseTypeStats::INITIAL_MARK_PAUSE:
108             return "INITIAL_MARK_PAUSE";
109         case PauseTypeStats::REMARK_PAUSE:
110             return "REMARK_PAUSE";
111         default:
112             return "UnknownPauseType";
113     }
114 }
115 
116 constexpr size_t PAUSE_TYPE_STATS_SIZE = static_cast<size_t>(PauseTypeStats::PAUSE_TYPE_STATS_LAST);
117 
118 // scoped specific for GC Stats
119 class GCInstanceStats {
120 public:
GCInstanceStats()121     GCInstanceStats()
122     {
123         std::fill(begin(objectsStats_), end(objectsStats_),
124                   SimpleHistogram<uint64_t>(helpers::ValueType::VALUE_TYPE_OBJECT));
125         std::fill(begin(memoryStats_), end(memoryStats_),
126                   SimpleHistogram<uint64_t>(helpers::ValueType::VALUE_TYPE_MEMORY));
127         std::fill(begin(timeStats_), end(timeStats_), SimpleHistogram<uint64_t>(helpers::ValueType::VALUE_TYPE_TIME));
128     }
129 
AddObjectsValue(uint64_t value,ObjectTypeStats memoryType)130     void AddObjectsValue(uint64_t value, ObjectTypeStats memoryType)
131     {
132         auto index = static_cast<size_t>(memoryType);
133         objectsStats_[index].AddValue(value);
134     }
135 
AddMemoryValue(uint64_t value,MemoryTypeStats memoryType)136     void AddMemoryValue(uint64_t value, MemoryTypeStats memoryType)
137     {
138         auto index = static_cast<size_t>(memoryType);
139         memoryStats_[index].AddValue(value);
140     }
141 
AddTimeValue(uint64_t value,TimeTypeStats timeType)142     void AddTimeValue(uint64_t value, TimeTypeStats timeType)
143     {
144         auto index = static_cast<size_t>(timeType);
145         timeStats_[index].AddValue(value);
146     }
147 
AddReclaimRatioValue(double value)148     void AddReclaimRatioValue(double value)
149     {
150         reclaimBytes_.AddValue(value);
151     }
152 
AddCopiedRatioValue(double value)153     void AddCopiedRatioValue(double value)
154     {
155         copiedBytes_.AddValue(value);
156     }
157 
158     PandaString GetDump(GCType gcType);
159 
160     virtual ~GCInstanceStats() = default;
161 
162     NO_COPY_SEMANTIC(GCInstanceStats);
163     NO_MOVE_SEMANTIC(GCInstanceStats);
164 
165 private:
166     PandaString GetYoungSpaceDump(GCType gcType);
167     PandaString GetAllSpacesDump(GCType gcType);
168     std::array<SimpleHistogram<uint64_t>, OBJECT_TYPE_STATS_SIZE> objectsStats_;
169     std::array<SimpleHistogram<uint64_t>, MEMORY_TYPE_STATS_SIZE> memoryStats_;
170     std::array<SimpleHistogram<uint64_t>, TIME_TYPE_STATS_SIZE> timeStats_;
171     SimpleHistogram<double> reclaimBytes_;
172     SimpleHistogram<double> copiedBytes_;
173 };
174 
175 // scoped all field GCStats except pause_
176 class GCScopedStats {
177 public:
178     explicit GCScopedStats(GCStats *stats, GCInstanceStats *instanceStats = nullptr);
179 
180     NO_COPY_SEMANTIC(GCScopedStats);
181     NO_MOVE_SEMANTIC(GCScopedStats);
182 
183     ~GCScopedStats();
184 
185 private:
186     uint64_t startTime_;
187     GCInstanceStats *instanceStats_;
188     GCStats *stats_;
189 };
190 
191 // scoped field GCStats while GC in pause
192 class GCScopedPauseStats {
193 public:
194     explicit GCScopedPauseStats(GCStats *stats, GCInstanceStats *instanceStats = nullptr,
195                                 PauseTypeStats pauseType = PauseTypeStats::COMMON_PAUSE);
196 
197     NO_COPY_SEMANTIC(GCScopedPauseStats);
198     NO_MOVE_SEMANTIC(GCScopedPauseStats);
199 
200     ~GCScopedPauseStats();
201 
202 private:
203     uint64_t startTime_;
204     GCInstanceStats *instanceStats_;
205     GCStats *stats_;
206     PauseTypeStats pauseType_;
207 };
208 
209 class GCStats {
210 public:
211     explicit GCStats(MemStatsType *memStats, GCType gcTypeFromRuntime, InternalAllocatorPtr allocator);
212     ~GCStats();
213 
214     NO_COPY_SEMANTIC(GCStats);
215     NO_MOVE_SEMANTIC(GCStats);
216 
217     PandaString GetStatistics();
218 
219     PandaString GetFinalStatistics(HeapManager *heapManager);
220 
221     PandaString GetPhasePauseStat(PauseTypeStats pauseType);
222 
223     uint64_t GetPhasePause(PauseTypeStats pauseType);
224     void ResetLastPause();
225 
GetObjectsFreedBytes()226     size_t GetObjectsFreedBytes()
227     {
228 #ifdef PANDA_TARGET_64
229         static_assert(sizeof(objectsFreedBytes_) == sizeof(std::atomic_uint64_t));
230         // Atomic with seq_cst order reason: data race with objects_freed_bytes_ with requirement for sequentially
231         // consistent order where threads observe all modifications in the same order
232         return reinterpret_cast<std::atomic_uint64_t *>(&objectsFreedBytes_)->load(std::memory_order_seq_cst);
233 #endif
234 #ifdef PANDA_TARGET_32
235         static_assert(sizeof(objectsFreedBytes_) == sizeof(std::atomic_uint32_t));
236         // Atomic with seq_cst order reason: data race with objects_freed_bytes_ with requirement for sequentially
237         // consistent order where threads observe all modifications in the same order
238         return reinterpret_cast<std::atomic_uint32_t *>(&objectsFreedBytes_)->load(std::memory_order_seq_cst);
239 #endif
240         UNREACHABLE();
241     }
242 
GetObjectsFreedCount()243     uint64_t GetObjectsFreedCount()
244     {
245         return objectsFreed_;
246     }
247 
GetLargeObjectsFreedBytes()248     uint64_t GetLargeObjectsFreedBytes()
249     {
250         return largeObjectsFreedBytes_;
251     }
252 
GetLargeObjectsFreedCount()253     uint64_t GetLargeObjectsFreedCount()
254     {
255         return largeObjectsFreed_;
256     }
257 
258     void StartMutatorLock();
259     void StopMutatorLock();
260 
261 private:
262     // For convert from nano to 10 seconds
263     using PERIOD = std::deca;
264     GCType gcType_ {GCType::INVALID_GC};
265     size_t objectsFreed_ {0};
266     size_t objectsFreedBytes_ {0};
267     size_t largeObjectsFreed_ {0};
268     size_t largeObjectsFreedBytes_ {0};
269     uint64_t startTime_ {0};
270     // CC-OFFNXT(G.FMT.03) project code style
GUARDED_BY(mutatorStatsLock_)271     size_t countMutator_ GUARDED_BY(mutatorStatsLock_) {0};
272     // CC-OFFNXT(G.FMT.03) project code style
GUARDED_BY(mutatorStatsLock_)273     uint64_t mutatorStartTime_ GUARDED_BY(mutatorStatsLock_) {0};
274 
275     uint64_t lastDuration_ {0};
276     uint64_t totalDuration_ {0};
277     uint64_t totalPause_ {0};
278     // CC-OFFNXT(G.FMT.03) project code style
GUARDED_BY(mutatorStatsLock_)279     uint64_t totalMutatorPause_ GUARDED_BY(mutatorStatsLock_) {0};
280 
281     uint64_t lastStartDuration_ {0};
282     // GC in the last PERIOD
283     uint64_t countGcPeriod_ {0};
284     // GC number of times every PERIOD
285     PandaVector<uint64_t> *allNumberDurations_ {nullptr};
286 
287     std::array<uint64_t, PAUSE_TYPE_STATS_SIZE> lastPause_ {};
288 
289     os::memory::Mutex mutatorStatsLock_;
290     MemStatsType *memStats_;
291 
292     void StartCollectStats();
293     void StopCollectStats(GCInstanceStats *instanceStats);
294 
295     void AddPause(uint64_t pause, GCInstanceStats *instanceStats, PauseTypeStats pauseType);
296 
297     void RecordDuration(uint64_t duration, GCInstanceStats *instanceStats);
298 
299     uint64_t ConvertTimeToPeriod(uint64_t timeInNanos, bool ceil = false);
300 
301     InternalAllocatorPtr allocator_ {nullptr};
302 
303 #ifndef NDEBUG
304     PauseTypeStats prevPauseType_ {PauseTypeStats::COMMON_PAUSE};
305 #endif
306 
307     friend GCScopedPauseStats;
308     friend GCScopedStats;
309     friend test::MemStatsGenGCTest;
310 };
311 
312 }  // namespace ark::mem
313 
314 #endif  // PANDA_RUNTIME_MEM_GC_GC_STATS_H
315