1 /* 2 * Copyright (c) 2021 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 #ifndef ECMASCRIPT_MEM_GC_STATS_H 17 #define ECMASCRIPT_MEM_GC_STATS_H 18 19 #include <chrono> 20 #include <cstring> 21 #include <ctime> 22 23 #include "ecmascript/common.h" 24 #include "ecmascript/mem/clock_scope.h" 25 #include "ecmascript/mem/mem_common.h" 26 #include "libpandabase/macros.h" 27 28 namespace panda::ecmascript { 29 class Heap; 30 class SharedHeap; 31 32 enum class GCType : int { 33 STW_YOUNG_GC = 0, 34 PARTIAL_EDEN_GC, 35 PARTIAL_YOUNG_GC, 36 PARTIAL_OLD_GC, 37 COMPRESS_GC, 38 SHARED_GC, 39 OTHER, 40 START, 41 }; 42 43 enum class RecordData : uint8_t { 44 #define DEFINE_SCOPE(scope) scope, 45 RECORD_DATA(DEFINE_SCOPE) 46 #undef DEFINE_SCOPE 47 NUM_OF_DATA, 48 FIRST_DATA = START_OBJ_SIZE, 49 END_RECORD_OVERWRITE = COLLECT_REGION_SET_SIZE, 50 }; 51 52 enum class SpeedData : uint8_t { 53 #define DEFINE_SCOPE(scope) scope, 54 TRACE_GC_SPEED(DEFINE_SCOPE) 55 #undef DEFINE_SCOPE 56 NUM_OF_SPEED, 57 }; 58 59 enum class RecordDuration : uint8_t { 60 #define DEFINE_SCOPE(scope) scope, 61 RECORD_DURATION(DEFINE_SCOPE) 62 #undef DEFINE_SCOPE 63 NUM_OF_DURATION, 64 FIRST_DATA = SEMI_MIN_PAUSE, 65 }; 66 67 #define TRACE_GC(scope_id, gc_stats) \ 68 [[maybe_unused]] GCStats::Scope sp(scope_id, gc_stats) 69 70 class GCStats { 71 using Duration = std::chrono::duration<uint64_t, std::nano>; 72 73 public: GCStats(const Heap * heap)74 explicit GCStats(const Heap *heap) : heap_(heap) {} GCStats(const Heap * heap,size_t longPuaseTime)75 GCStats(const Heap *heap, size_t longPuaseTime) : heap_(heap), 76 longPauseTime_(longPuaseTime) {} 77 virtual ~GCStats() = default; 78 79 virtual void PrintStatisticResult(); 80 virtual void PrintGCMemoryStatistic(); 81 bool CheckIfLongTimePause(); 82 virtual void PrintGCStatistic(); 83 GetGCSpeed(SpeedData data)84 float GetGCSpeed(SpeedData data) 85 { 86 return gcSpeed_[(uint8_t)data]; 87 } 88 SetRecordData(RecordData dataIdx,size_t value)89 void SetRecordData(RecordData dataIdx, size_t value) 90 { 91 recordData_[GetRecordDataIndex(dataIdx)] = value; 92 } 93 GetRecordData(RecordData dataIdx)94 size_t GetRecordData(RecordData dataIdx) 95 { 96 return recordData_[GetRecordDataIndex(dataIdx)]; 97 } 98 SetGCReason(GCReason reason)99 void SetGCReason(GCReason reason) 100 { 101 reason_ = reason; 102 } 103 GetGCReason()104 GCReason GetGCReason() const 105 { 106 return reason_; 107 } 108 GetGCTypeName()109 const char *GetGCTypeName() 110 { 111 switch (gcType_) { 112 case GCType::STW_YOUNG_GC: 113 return "STWYoungGC"; 114 case GCType::PARTIAL_EDEN_GC: 115 return "HPP EdenGC"; 116 case GCType::PARTIAL_YOUNG_GC: 117 return "HPP YoungGC"; 118 case GCType::PARTIAL_OLD_GC: 119 return "HPP OldGC"; 120 case GCType::COMPRESS_GC: 121 return "CompressGC"; 122 case GCType::SHARED_GC: 123 return "SharedGC"; 124 default: 125 return "UnknownType"; 126 } 127 } 128 129 const char *GCReasonToString(); 130 GetAvgSurvivalRate()131 double GetAvgSurvivalRate() 132 { 133 if (gcType_ == GCType::PARTIAL_EDEN_GC) { 134 size_t commitSize = GetRecordData(RecordData::EDEN_TOTAL_COMMIT); 135 if (commitSize == 0) { 136 return 0; 137 } 138 double copiedRate = double(GetRecordData(RecordData::EDEN_TOTAL_ALIVE)) / commitSize; 139 double promotedRate = double(GetRecordData(RecordData::EDEN_TOTAL_PROMOTE)) / commitSize; 140 return std::min(copiedRate + promotedRate, 1.0); 141 } 142 double copiedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_ALIVE)) / 143 GetRecordData(RecordData::YOUNG_TOTAL_COMMIT); 144 double promotedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_PROMOTE)) / 145 GetRecordData(RecordData::YOUNG_TOTAL_COMMIT); 146 return std::min(copiedRate + promotedRate, 1.0); 147 } 148 149 virtual void RecordGCSpeed(); 150 virtual void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason); 151 virtual void RecordStatisticAfterGC(); 152 153 class Scope : public ClockScope { 154 public: 155 enum ScopeId : uint8_t { 156 #define DEFINE_SCOPE(scope) scope, 157 SCOPE_LIST(DEFINE_SCOPE) 158 #undef DEFINE_SCOPE 159 SCOPE_NUM, 160 }; 161 Scope(ScopeId id,GCStats * stats)162 Scope(ScopeId id, GCStats* stats) : id_(id), stats_(stats) 163 { 164 if (id_ == ScopeId::ConcurrentMark) { 165 stats_->NotifyConcurrentMark(); 166 } 167 } ~Scope()168 ~Scope() 169 { 170 float duration = stats_->PrintTimeMilliseconds(stats_->TimeToMicroseconds(GetPauseTime())); 171 stats_->SetScopeId(id_, duration); 172 } 173 174 private: 175 ScopeId id_; 176 GCStats* stats_; 177 }; 178 GetScopeDuration(int pos)179 float GetScopeDuration(int pos) const 180 { 181 return scopeDuration_[pos]; 182 } 183 IncreaseTotalDuration(float duration)184 void IncreaseTotalDuration(float duration) 185 { 186 gcDuration_ += duration; 187 } 188 GetGCCount()189 size_t GetGCCount() 190 { 191 return GetRecordData(RecordData::SEMI_COUNT) + GetRecordData(RecordData::YOUNG_COUNT) + 192 GetRecordData(RecordData::OLD_COUNT) + GetRecordData(RecordData::COMPRESS_COUNT) + 193 GetRecordData(RecordData::SHARED_COUNT); 194 } 195 GetGCDuration()196 size_t GetGCDuration() const 197 { 198 return static_cast<size_t>(gcDuration_); 199 } 200 201 virtual size_t GetAccumulatedAllocateSize(); GetAccumulatedFreeSize()202 size_t GetAccumulatedFreeSize() const 203 { 204 return accumulatedFreeSize_; 205 } 206 IncreaseFullGCLongTimeCount()207 void IncreaseFullGCLongTimeCount() 208 { 209 fullGCLongTimeCount_ += 1; 210 } 211 GetFullGCLongTimeCount()212 size_t GetFullGCLongTimeCount() const 213 { 214 return fullGCLongTimeCount_; 215 } 216 217 protected: 218 bool CheckIfNeedPrint(GCType type); 219 void PrintVerboseGCStatistic(); 220 void PrintGCDurationStatistic(); 221 void PrintGCSummaryStatistic(GCType type = GCType::START); 222 GCType GetGCType(TriggerGCType gcType); 223 void InitializeRecordList(); 224 float GetConcurrrentMarkDuration(); 225 GetRecordDurationIndex(RecordDuration durationIdx)226 int GetRecordDurationIndex(RecordDuration durationIdx) 227 { 228 return (int)durationIdx - (int)RecordDuration::FIRST_DATA; 229 } 230 GetRecordDuration(RecordDuration durationIdx)231 float GetRecordDuration(RecordDuration durationIdx) 232 { 233 return recordDuration_[GetRecordDurationIndex(durationIdx)]; 234 } 235 SetRecordDuration(RecordDuration durationIdx,float value)236 void SetRecordDuration(RecordDuration durationIdx, float value) 237 { 238 recordDuration_[GetRecordDurationIndex(durationIdx)] = value; 239 } 240 IncreaseRecordDuration(RecordDuration durationIdx,float value)241 void IncreaseRecordDuration(RecordDuration durationIdx, float value) 242 { 243 recordDuration_[GetRecordDurationIndex(durationIdx)] += value; 244 } 245 GetRecordDataIndex(RecordData dataIdx)246 int GetRecordDataIndex(RecordData dataIdx) 247 { 248 return (int)dataIdx - (int)RecordData::FIRST_DATA; 249 } 250 251 void IncreaseRecordData(RecordData dataIdx, size_t value = 1) 252 { 253 recordData_[GetRecordDataIndex(dataIdx)] += value; 254 } 255 SetScopeId(int pos,float duration)256 void SetScopeId(int pos, float duration) 257 { 258 scopeDuration_[pos] = duration; 259 } 260 NotifyConcurrentMark()261 void NotifyConcurrentMark() 262 { 263 concurrentMark_ = true; 264 } 265 IncreaseAccumulatedFreeSize(size_t size)266 void IncreaseAccumulatedFreeSize(size_t size) 267 { 268 accumulatedFreeSize_ += size; 269 } 270 TimeToMicroseconds(Duration time)271 size_t TimeToMicroseconds(Duration time) 272 { 273 return std::chrono::duration_cast<std::chrono::microseconds>(time).count(); 274 } 275 PrintTimeMilliseconds(uint64_t ms)276 float PrintTimeMilliseconds(uint64_t ms) 277 { 278 return (float)ms / THOUSAND; 279 } 280 sizeToMB(size_t size)281 float sizeToMB(size_t size) 282 { 283 return (float)size / 1_MB; 284 } 285 sizeToKB(size_t size)286 float sizeToKB(size_t size) 287 { 288 return (float)size / 1_KB; 289 } 290 291 const Heap *heap_ {nullptr}; 292 float gcDuration_ = 0.0f; 293 size_t longPauseTime_ = 0; 294 size_t fullGCLongTimeCount_ = 0; 295 size_t accumulatedFreeSize_ = 0; 296 297 static constexpr size_t DEFAULT_UPDATE_REFERENCE_SPEED = 10_MB; 298 static constexpr size_t DEFAULT_OLD_CLEAR_NATIVE_OBJ_SPEED = 1_KB; 299 static constexpr size_t DEFAULT_OLD_EVACUATE_SPACE_SPEED = 600_KB; 300 static constexpr size_t DEFAULT_YOUNG_CLEAR_NATIVE_OBJ_SPEED = 3_KB; 301 302 GCType gcType_ {GCType::START}; 303 GCReason reason_ {GCReason::OTHER}; 304 float scopeDuration_[Scope::ScopeId::SCOPE_NUM] {0.0f}; 305 size_t recordData_[(uint8_t)RecordData::NUM_OF_DATA] {0}; 306 size_t gcSpeed_ [(uint8_t)SpeedData::NUM_OF_SPEED] = { 307 DEFAULT_UPDATE_REFERENCE_SPEED, DEFAULT_OLD_CLEAR_NATIVE_OBJ_SPEED, 308 DEFAULT_OLD_EVACUATE_SPACE_SPEED, DEFAULT_YOUNG_CLEAR_NATIVE_OBJ_SPEED}; 309 float recordDuration_[(uint8_t)RecordDuration::NUM_OF_DURATION] {0.0f}; 310 bool concurrentMark_ {false}; 311 312 static constexpr uint32_t THOUSAND = 1000; 313 314 NO_COPY_SEMANTIC(GCStats); 315 NO_MOVE_SEMANTIC(GCStats); 316 }; 317 318 class SharedGCStats : public GCStats { 319 public: SharedGCStats(const SharedHeap * sHeap,bool enableGCTracer)320 SharedGCStats(const SharedHeap *sHeap, bool enableGCTracer) 321 : GCStats(nullptr), sHeap_(sHeap), enableGCTracer_(enableGCTracer) 322 { 323 SetRecordData(RecordData::SHARED_COUNT, 0); 324 } 325 ~SharedGCStats() = default; 326 327 void PrintStatisticResult() override; 328 void PrintGCMemoryStatistic() override; 329 void PrintGCStatistic() override; 330 331 void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason) override; 332 void RecordStatisticAfterGC() override; 333 size_t GetAccumulatedAllocateSize() override; 334 private: 335 void PrintSharedGCDuration(); 336 void PrintSharedGCSummaryStatistic(); 337 338 const SharedHeap *sHeap_ {nullptr}; 339 bool enableGCTracer_ {false}; 340 }; 341 } // namespace panda::ecmascript 342 343 #endif // ECMASCRIPT_MEM_GC_STATS_H 344