1 /**
2 * Copyright (c) 2021-2022 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 panda::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 // scoped specific for GC Stats
85 class GCInstanceStats {
86 public:
GCInstanceStats()87 GCInstanceStats()
88 {
89 std::fill(begin(objects_stats_), end(objects_stats_),
90 SimpleHistogram<uint64_t>(helpers::ValueType::VALUE_TYPE_OBJECT));
91 std::fill(begin(memory_stats_), end(memory_stats_),
92 SimpleHistogram<uint64_t>(helpers::ValueType::VALUE_TYPE_MEMORY));
93 std::fill(begin(time_stats_), end(time_stats_), SimpleHistogram<uint64_t>(helpers::ValueType::VALUE_TYPE_TIME));
94 }
95
AddObjectsValue(uint64_t value,ObjectTypeStats memory_type)96 void AddObjectsValue(uint64_t value, ObjectTypeStats memory_type)
97 {
98 auto index = static_cast<size_t>(memory_type);
99 objects_stats_[index].AddValue(value);
100 }
101
AddMemoryValue(uint64_t value,MemoryTypeStats memory_type)102 void AddMemoryValue(uint64_t value, MemoryTypeStats memory_type)
103 {
104 auto index = static_cast<size_t>(memory_type);
105 memory_stats_[index].AddValue(value);
106 }
107
AddTimeValue(uint64_t value,TimeTypeStats time_type)108 void AddTimeValue(uint64_t value, TimeTypeStats time_type)
109 {
110 auto index = static_cast<size_t>(time_type);
111 time_stats_[index].AddValue(value);
112 }
113
AddReclaimRatioValue(double value)114 void AddReclaimRatioValue(double value)
115 {
116 reclaim_bytes_.AddValue(value);
117 }
118
AddCopiedRatioValue(double value)119 void AddCopiedRatioValue(double value)
120 {
121 copied_bytes_.AddValue(value);
122 }
123
124 PandaString GetDump(GCType gc_type);
125
126 virtual ~GCInstanceStats() = default;
127
128 NO_COPY_SEMANTIC(GCInstanceStats);
129 NO_MOVE_SEMANTIC(GCInstanceStats);
130
131 private:
132 PandaString GetYoungSpaceDump(GCType gc_type);
133 PandaString GetAllSpacesDump(GCType gc_type);
134 std::array<SimpleHistogram<uint64_t>, OBJECT_TYPE_STATS_SIZE> objects_stats_;
135 std::array<SimpleHistogram<uint64_t>, MEMORY_TYPE_STATS_SIZE> memory_stats_;
136 std::array<SimpleHistogram<uint64_t>, TIME_TYPE_STATS_SIZE> time_stats_;
137 SimpleHistogram<double> reclaim_bytes_;
138 SimpleHistogram<double> copied_bytes_;
139 };
140
141 // scoped all field GCStats except pause_
142 class GCScopedStats {
143 public:
144 explicit GCScopedStats(GCStats *stats, GCInstanceStats *instance_stats = nullptr);
145
146 NO_COPY_SEMANTIC(GCScopedStats);
147 NO_MOVE_SEMANTIC(GCScopedStats);
148
149 ~GCScopedStats();
150
151 private:
152 uint64_t start_time_;
153 GCInstanceStats *instance_stats_;
154 GCStats *stats_;
155 };
156
157 // scoped field GCStats while GC in pause
158 class GCScopedPauseStats {
159 public:
160 explicit GCScopedPauseStats(GCStats *stats, GCInstanceStats *instance_stats = nullptr);
161
162 NO_COPY_SEMANTIC(GCScopedPauseStats);
163 NO_MOVE_SEMANTIC(GCScopedPauseStats);
164
165 ~GCScopedPauseStats();
166
167 private:
168 uint64_t start_time_;
169 GCInstanceStats *instance_stats_;
170 GCStats *stats_;
171 };
172
173 class GCStats {
174 public:
175 explicit GCStats(MemStatsType *mem_stats, GCType gc_type_from_runtime, InternalAllocatorPtr allocator);
176 ~GCStats();
177
178 NO_COPY_SEMANTIC(GCStats);
179 NO_MOVE_SEMANTIC(GCStats);
180
181 PandaString GetStatistics();
182
183 PandaString GetFinalStatistics(HeapManager *heap_manager);
184
GetObjectsFreedBytes()185 size_t GetObjectsFreedBytes()
186 {
187 #ifdef PANDA_TARGET_64
188 static_assert(sizeof(objects_freed_bytes_) == sizeof(std::atomic_uint64_t));
189 // Atomic with seq_cst order reason: data race with objects_freed_bytes_ with requirement for sequentially
190 // consistent order where threads observe all modifications in the same order
191 return reinterpret_cast<std::atomic_uint64_t *>(&objects_freed_bytes_)->load(std::memory_order_seq_cst);
192 #endif
193 #ifdef PANDA_TARGET_32
194 static_assert(sizeof(objects_freed_bytes_) == sizeof(std::atomic_uint32_t));
195 // Atomic with seq_cst order reason: data race with objects_freed_bytes_ with requirement for sequentially
196 // consistent order where threads observe all modifications in the same order
197 return reinterpret_cast<std::atomic_uint32_t *>(&objects_freed_bytes_)->load(std::memory_order_seq_cst);
198 #endif
199 UNREACHABLE();
200 }
201
GetObjectsFreedCount()202 uint64_t GetObjectsFreedCount()
203 {
204 return objects_freed_;
205 }
206
GetLargeObjectsFreedBytes()207 uint64_t GetLargeObjectsFreedBytes()
208 {
209 return large_objects_freed_bytes_;
210 }
211
GetLargeObjectsFreedCount()212 uint64_t GetLargeObjectsFreedCount()
213 {
214 return large_objects_freed_;
215 }
216
217 void StartMutatorLock();
218 void StopMutatorLock();
219
220 private:
221 // For convert from nano to 10 seconds
222 using PERIOD = std::deca;
223 GCType gc_type_ {GCType::INVALID_GC};
224 size_t objects_freed_ {0};
225 size_t objects_freed_bytes_ {0};
226 size_t large_objects_freed_ {0};
227 size_t large_objects_freed_bytes_ {0};
228 uint64_t start_time_ {0};
GUARDED_BY(mutator_stats_lock_)229 size_t count_mutator_ GUARDED_BY(mutator_stats_lock_) {0};
GUARDED_BY(mutator_stats_lock_)230 uint64_t mutator_start_time_ GUARDED_BY(mutator_stats_lock_) {0};
231
232 uint64_t last_duration_ {0};
233 uint64_t total_duration_ {0};
234 uint64_t last_pause_ {0};
235 uint64_t total_pause_ {0};
GUARDED_BY(mutator_stats_lock_)236 uint64_t total_mutator_pause_ GUARDED_BY(mutator_stats_lock_) {0};
237
238 uint64_t last_start_duration_ {0};
239 // GC in the last PERIOD
240 uint64_t count_gc_period_ {0};
241 // GC number of times every PERIOD
242 PandaVector<uint64_t> *all_number_durations_ {nullptr};
243
244 os::memory::Mutex mutator_stats_lock_;
245 MemStatsType *mem_stats_;
246
247 void StartCollectStats();
248 void StopCollectStats(GCInstanceStats *instance_stats);
249
250 void RecordPause(uint64_t pause, GCInstanceStats *instance_stats);
251 void RecordDuration(uint64_t duration, GCInstanceStats *instance_stats);
252
253 uint64_t ConvertTimeToPeriod(uint64_t time_in_nanos, bool ceil = false);
254
255 InternalAllocatorPtr allocator_ {nullptr};
256
257 friend GCScopedPauseStats;
258 friend GCScopedStats;
259 friend test::MemStatsGenGCTest;
260 };
261
262 } // namespace panda::mem
263
264 #endif // PANDA_RUNTIME_MEM_GC_GC_STATS_H
265