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