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
16 #include "runtime/mem/mem_stats.h"
17
18 #include "libpandabase/utils/utf.h"
19 #include "runtime/include/class.h"
20 #include "runtime/include/runtime.h"
21 #include "runtime/mem/mem_stats_additional_info.h"
22 #include "runtime/mem/mem_stats_default.h"
23 #include "runtime/mem/object_helpers.h"
24
25 namespace panda::mem {
26
27 template <typename T>
RecordAllocateObject(size_t size,SpaceType type_mem)28 void MemStats<T>::RecordAllocateObject(size_t size, SpaceType type_mem)
29 {
30 RecordAllocateObjects(1, size, type_mem);
31 }
32
33 template <typename T>
RecordAllocateObjects(size_t total_object_num,size_t total_object_size,SpaceType type_mem)34 void MemStats<T>::RecordAllocateObjects(size_t total_object_num, size_t total_object_size, SpaceType type_mem)
35 {
36 ASSERT(IsHeapSpace(type_mem));
37 RecordAllocate(total_object_size, type_mem);
38 if (type_mem == SpaceType::SPACE_TYPE_HUMONGOUS_OBJECT) {
39 // Atomic with acq_rel order reason: data race with humongous_objects_allocated_ with dependecies on reads after
40 // the load and on writes before the store
41 humongous_objects_allocated_.fetch_add(total_object_num, std::memory_order_acq_rel);
42 } else {
43 // Atomic with acq_rel order reason: data race with objects_allocated_ with dependecies on reads after the load
44 // and on writes before the store
45 objects_allocated_.fetch_add(total_object_num, std::memory_order_acq_rel);
46 }
47 }
48
49 template <typename T>
RecordYoungMovedObjects(size_t young_object_num,size_t size,SpaceType type_mem)50 void MemStats<T>::RecordYoungMovedObjects(size_t young_object_num, size_t size, SpaceType type_mem)
51 {
52 ASSERT(IsHeapSpace(type_mem));
53 RecordMoved(size, type_mem);
54 // We can't move SPACE_TYPE_HUMONGOUS_OBJECT
55 ASSERT(type_mem != SpaceType::SPACE_TYPE_HUMONGOUS_OBJECT);
56 // Atomic with acq_rel order reason: data race with last_young_objects_moved_bytes_ with dependecies on reads after
57 // the load and on writes before the store
58 last_young_objects_moved_bytes_.fetch_add(size, std::memory_order_acq_rel);
59 // Atomic with acq_rel order reason: data race with objects_allocated_ with dependecies on reads after the load and
60 // on writes before the store
61 [[maybe_unused]] uint64_t old_val = objects_allocated_.fetch_sub(young_object_num, std::memory_order_acq_rel);
62 ASSERT(old_val >= young_object_num);
63 }
64
65 template <typename T>
RecordTenuredMovedObjects(size_t tenured_object_num,size_t size,SpaceType type_mem)66 void MemStats<T>::RecordTenuredMovedObjects(size_t tenured_object_num, size_t size, SpaceType type_mem)
67 {
68 ASSERT(IsHeapSpace(type_mem));
69 RecordMoved(size, type_mem);
70 // We can't move SPACE_TYPE_HUMONGOUS_OBJECT
71 ASSERT(type_mem != SpaceType::SPACE_TYPE_HUMONGOUS_OBJECT);
72 // Atomic with acq_rel order reason: data race with objects_allocated_ with dependecies on reads after the load and
73 // on writes before the store
74 [[maybe_unused]] uint64_t old_val = objects_allocated_.fetch_sub(tenured_object_num, std::memory_order_acq_rel);
75 ASSERT(old_val >= tenured_object_num);
76 }
77
78 template <typename T>
RecordFreeObject(size_t object_size,SpaceType type_mem)79 void MemStats<T>::RecordFreeObject(size_t object_size, SpaceType type_mem)
80 {
81 RecordFreeObjects(1, object_size, type_mem);
82 }
83
84 template <typename T>
RecordFreeObjects(size_t total_object_num,size_t total_object_size,SpaceType type_mem)85 void MemStats<T>::RecordFreeObjects(size_t total_object_num, size_t total_object_size, SpaceType type_mem)
86 {
87 ASSERT(IsHeapSpace(type_mem));
88 RecordFree(total_object_size, type_mem);
89 if (type_mem == SpaceType::SPACE_TYPE_HUMONGOUS_OBJECT) {
90 // Atomic with acq_rel order reason: data race with humongous_objects_freed_ with dependecies on reads after the
91 // load and on writes before the store
92 humongous_objects_freed_.fetch_add(total_object_num, std::memory_order_acq_rel);
93 } else {
94 // Atomic with acq_rel order reason: data race with objects_freed_ with dependecies on reads after the load and
95 // on writes before the store
96 objects_freed_.fetch_add(total_object_num, std::memory_order_acq_rel);
97 }
98 }
99
100 template <typename T>
GetStatistics(HeapManager * heap_manager)101 PandaString MemStats<T>::GetStatistics(HeapManager *heap_manager)
102 {
103 PandaStringStream statistic;
104 statistic << "memory statistics:" << std::endl;
105 statistic << "heap: allocated - " << GetAllocatedHeap() << ", freed - " << GetFreedHeap() << std::endl;
106 statistic << "raw memory: allocated - " << GetAllocated(SpaceType::SPACE_TYPE_INTERNAL) << ", freed - "
107 << GetFreed(SpaceType::SPACE_TYPE_INTERNAL) << std::endl;
108 statistic << "compiler: allocated - " << GetAllocated(SpaceType::SPACE_TYPE_CODE) << std::endl;
109 statistic << "ArenaAllocator: allocated - " << GetAllocated(SpaceType::SPACE_TYPE_COMPILER) << std::endl;
110 statistic << "total footprint now - " << GetTotalFootprint() << std::endl;
111 statistic << "total allocated object - " << GetTotalObjectsAllocated() << std::endl;
112 statistic << "min GC pause time - " << GetMinGCPause() << std::endl;
113 statistic << "max GC pause time - " << GetMaxGCPause() << std::endl;
114 statistic << "average GC pause time - " << GetAverageGCPause() << std::endl;
115 statistic << "total GC pause time - " << GetTotalGCPause() << std::endl;
116 auto additional_statistics = static_cast<T *>(this)->GetAdditionalStatistics(heap_manager);
117 return statistic.str() + additional_statistics;
118 }
119
120 template <typename T>
GetTotalObjectsAllocated() const121 [[nodiscard]] uint64_t MemStats<T>::GetTotalObjectsAllocated() const
122 {
123 // Atomic with acquire order reason: data race with objects_allocated_ with dependecies on reads after the load
124 // which should become visible
125 return objects_allocated_.load(std::memory_order_acquire);
126 }
127
128 template <typename T>
GetTotalObjectsFreed() const129 [[nodiscard]] uint64_t MemStats<T>::GetTotalObjectsFreed() const
130 {
131 // Atomic with acquire order reason: data race with objects_freed_ with dependecies on reads after the load which
132 // should become visible
133 return objects_freed_.load(std::memory_order_acquire);
134 }
135
136 template <typename T>
GetTotalRegularObjectsAllocated() const137 [[nodiscard]] uint64_t MemStats<T>::GetTotalRegularObjectsAllocated() const
138 {
139 return GetTotalObjectsAllocated() - GetTotalHumongousObjectsAllocated();
140 }
141
142 template <typename T>
GetTotalRegularObjectsFreed() const143 [[nodiscard]] uint64_t MemStats<T>::GetTotalRegularObjectsFreed() const
144 {
145 return GetTotalObjectsFreed() - GetTotalHumongousObjectsFreed();
146 }
147
148 template <typename T>
GetTotalHumongousObjectsAllocated() const149 [[nodiscard]] uint64_t MemStats<T>::GetTotalHumongousObjectsAllocated() const
150 {
151 // Atomic with acquire order reason: data race with humongous_objects_allocated_ with dependecies on reads after the
152 // load which should become visible
153 return humongous_objects_allocated_.load(std::memory_order_acquire);
154 }
155
156 template <typename T>
GetTotalHumongousObjectsFreed() const157 [[nodiscard]] uint64_t MemStats<T>::GetTotalHumongousObjectsFreed() const
158 {
159 // Atomic with acquire order reason: data race with humongous_objects_freed_ with dependecies on reads after the
160 // load which should become visible
161 return humongous_objects_freed_.load(std::memory_order_acquire);
162 }
163
164 template <typename T>
GetObjectsCountAlive() const165 [[nodiscard]] uint64_t MemStats<T>::GetObjectsCountAlive() const
166 {
167 return GetTotalObjectsAllocated() - GetTotalObjectsFreed();
168 }
169
170 template <typename T>
GetRegularObjectsCountAlive() const171 [[nodiscard]] uint64_t MemStats<T>::GetRegularObjectsCountAlive() const
172 {
173 return GetTotalRegularObjectsAllocated() - GetTotalRegularObjectsFreed();
174 }
175
176 template <typename T>
GetHumonguousObjectsCountAlive() const177 [[nodiscard]] uint64_t MemStats<T>::GetHumonguousObjectsCountAlive() const
178 {
179 return GetTotalHumongousObjectsAllocated() - GetTotalHumongousObjectsFreed();
180 }
181
182 template <typename T>
GetLastYoungObjectsMovedBytes() const183 [[nodiscard]] uint64_t MemStats<T>::GetLastYoungObjectsMovedBytes() const
184 {
185 // Atomic with acquire order reason: data race with last_young_objects_moved_bytes_ with dependecies on reads after
186 // the load which should become visible
187 return last_young_objects_moved_bytes_.load(std::memory_order_acquire);
188 }
189
190 template <typename T>
RecordGCPauseStart()191 void MemStats<T>::RecordGCPauseStart()
192 {
193 pause_start_time_ = clock::now();
194 }
195
196 template <typename T>
RecordGCPauseEnd()197 void MemStats<T>::RecordGCPauseEnd()
198 {
199 duration pause_time = clock::now() - pause_start_time_;
200 if (pause_count_) {
201 min_pause_ = std::min(min_pause_, pause_time);
202 max_pause_ = std::max(max_pause_, pause_time);
203 } else {
204 min_pause_ = pause_time;
205 max_pause_ = pause_time;
206 }
207 pause_count_++;
208 sum_pause_ += pause_time;
209 }
210
211 template <typename T>
GetMinGCPause() const212 uint64_t MemStats<T>::GetMinGCPause() const
213 {
214 return std::chrono::duration_cast<std::chrono::milliseconds>(min_pause_).count();
215 }
216
217 template <typename T>
GetMaxGCPause() const218 uint64_t MemStats<T>::GetMaxGCPause() const
219 {
220 return std::chrono::duration_cast<std::chrono::milliseconds>(max_pause_).count();
221 }
222
223 template <typename T>
GetAverageGCPause() const224 uint64_t MemStats<T>::GetAverageGCPause() const
225 {
226 return pause_count_ ? std::chrono::duration_cast<std::chrono::milliseconds>(sum_pause_).count() / pause_count_ : 0;
227 }
228
229 template <typename T>
GetTotalGCPause() const230 uint64_t MemStats<T>::GetTotalGCPause() const
231 {
232 return std::chrono::duration_cast<std::chrono::milliseconds>(sum_pause_).count();
233 }
234
235 template class MemStats<MemStatsDefault>;
236 template class MemStats<MemStatsAdditionalInfo>;
237 } // namespace panda::mem
238