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 reason)112 void SetGCReason(GCReason reason) 113 { 114 reason_ = reason; 115 } 116 GetGCReason()117 GCReason GetGCReason() const 118 { 119 return reason_; 120 } 121 GetLongGCStats()122 LongGCStats *GetLongGCStats() 123 { 124 return longGCStats_; 125 } 126 127 bool IsLongGC(GCReason gcReason, bool gcIsSensitive, bool gcIsInBackground, float gcTotalTime); 128 GetGCTypeName()129 const char *GetGCTypeName() 130 { 131 switch (gcType_) { 132 case GCType::PARTIAL_YOUNG_GC: 133 return "HPP YoungGC"; 134 case GCType::PARTIAL_OLD_GC: 135 return "HPP OldGC"; 136 case GCType::COMPRESS_GC: 137 return "CompressGC"; 138 case GCType::SHARED_GC: 139 return "SharedGC"; 140 case GCType::SHARED_PARTIAL_GC: 141 return "SharedPartialGC"; 142 case GCType::SHARED_FULL_GC: 143 return "SharedCompressGC"; 144 default: 145 return "UnknownType"; 146 } 147 } 148 149 static const char *GCReasonToString(GCReason reason); 150 const char *GCReasonToString(); 151 GetAvgSurvivalRate()152 double GetAvgSurvivalRate() 153 { 154 double copiedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_ALIVE)) / 155 GetRecordData(RecordData::YOUNG_TOTAL_COMMIT); 156 double promotedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_PROMOTE)) / 157 GetRecordData(RecordData::YOUNG_TOTAL_COMMIT); 158 return std::min(copiedRate + promotedRate, 1.0); 159 } 160 161 virtual void RecordGCSpeed(); 162 virtual void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason); 163 virtual void RecordStatisticAfterGC(); 164 165 class Scope : public ClockScope { 166 public: 167 enum ScopeId : uint8_t { 168 #define DEFINE_SCOPE(scope) scope, 169 SCOPE_LIST(DEFINE_SCOPE) 170 #undef DEFINE_SCOPE 171 SCOPE_NUM, 172 }; 173 Scope(ScopeId id,GCStats * stats)174 Scope(ScopeId id, GCStats* stats) : id_(id), stats_(stats) 175 { 176 if (id_ == ScopeId::ConcurrentMark) { 177 stats_->NotifyConcurrentMark(); 178 } 179 } ~Scope()180 ~Scope() 181 { 182 float duration = stats_->PrintTimeMilliseconds(stats_->TimeToMicroseconds(GetPauseTime())); 183 stats_->SetScopeId(id_, duration); 184 } 185 186 private: 187 ScopeId id_; 188 GCStats* stats_; 189 }; 190 GetScopeDuration(int pos)191 float GetScopeDuration(int pos) const 192 { 193 return scopeDuration_[pos]; 194 } 195 IncreaseTotalDuration(float duration)196 void IncreaseTotalDuration(float duration) 197 { 198 gcDuration_ += duration; 199 } 200 GetGCCount()201 size_t GetGCCount() 202 { 203 return GetRecordData(RecordData::SEMI_COUNT) + GetRecordData(RecordData::YOUNG_COUNT) + 204 GetRecordData(RecordData::OLD_COUNT) + GetRecordData(RecordData::COMPRESS_COUNT) + 205 GetRecordData(RecordData::SHARED_COUNT); 206 } 207 GetGCDuration()208 size_t GetGCDuration() const 209 { 210 return static_cast<size_t>(gcDuration_); 211 } 212 213 virtual size_t GetAccumulatedAllocateSize(); GetAccumulatedFreeSize()214 size_t GetAccumulatedFreeSize() const 215 { 216 return accumulatedFreeSize_; 217 } 218 IncreaseFullGCLongTimeCount()219 void IncreaseFullGCLongTimeCount() 220 { 221 fullGCLongTimeCount_ += 1; 222 } 223 GetFullGCLongTimeCount()224 size_t GetFullGCLongTimeCount() const 225 { 226 return fullGCLongTimeCount_; 227 } 228 229 protected: 230 bool CheckIfNeedPrint(GCType type); 231 void PrintVerboseGCStatistic(); 232 void PrintGCDurationStatistic(); 233 void PrintGCSummaryStatistic(GCType type = GCType::START); 234 void InitializeRecordList(); 235 float GetConcurrrentMarkDuration(); 236 void GCFinishTrace(); 237 virtual void ProcessBeforeLongGCStats(); 238 virtual void ProcessAfterLongGCStats(); GetRecordDurationIndex(RecordDuration durationIdx)239 int GetRecordDurationIndex(RecordDuration durationIdx) 240 { 241 return (int)durationIdx - (int)RecordDuration::FIRST_DATA; 242 } 243 GetRecordDuration(RecordDuration durationIdx)244 float GetRecordDuration(RecordDuration durationIdx) 245 { 246 return recordDuration_[GetRecordDurationIndex(durationIdx)]; 247 } 248 SetRecordDuration(RecordDuration durationIdx,float value)249 void SetRecordDuration(RecordDuration durationIdx, float value) 250 { 251 recordDuration_[GetRecordDurationIndex(durationIdx)] = value; 252 } 253 IncreaseRecordDuration(RecordDuration durationIdx,float value)254 void IncreaseRecordDuration(RecordDuration durationIdx, float value) 255 { 256 recordDuration_[GetRecordDurationIndex(durationIdx)] += value; 257 } 258 GetRecordDataIndex(RecordData dataIdx)259 int GetRecordDataIndex(RecordData dataIdx) 260 { 261 return (int)dataIdx - (int)RecordData::FIRST_DATA; 262 } 263 264 void IncreaseRecordData(RecordData dataIdx, size_t value = 1) 265 { 266 recordData_[GetRecordDataIndex(dataIdx)] += value; 267 } 268 SetScopeId(int pos,float duration)269 void SetScopeId(int pos, float duration) 270 { 271 scopeDuration_[pos] = duration; 272 } 273 NotifyConcurrentMark()274 void NotifyConcurrentMark() 275 { 276 concurrentMark_ = true; 277 } 278 IncreaseAccumulatedFreeSize(size_t size)279 void IncreaseAccumulatedFreeSize(size_t size) 280 { 281 accumulatedFreeSize_ += size; 282 } 283 TimeToMicroseconds(Duration time)284 size_t TimeToMicroseconds(Duration time) 285 { 286 return std::chrono::duration_cast<std::chrono::microseconds>(time).count(); 287 } 288 PrintTimeMilliseconds(uint64_t ms)289 float PrintTimeMilliseconds(uint64_t ms) 290 { 291 return (float)ms / THOUSAND; 292 } 293 sizeToMB(size_t size)294 float sizeToMB(size_t size) 295 { 296 return (float)size / 1_MB; 297 } 298 sizeToKB(size_t size)299 float sizeToKB(size_t size) 300 { 301 return (float)size / 1_KB; 302 } 303 304 const Heap *heap_ {nullptr}; 305 float gcDuration_ = 0.0f; 306 size_t longPauseTime_ = 0; 307 size_t fullGCLongTimeCount_ = 0; 308 size_t accumulatedFreeSize_ = 0; 309 310 static constexpr size_t DEFAULT_UPDATE_REFERENCE_SPEED = 10_MB; 311 static constexpr size_t DEFAULT_OLD_CLEAR_NATIVE_OBJ_SPEED = 1_KB; 312 static constexpr size_t DEFAULT_OLD_EVACUATE_SPACE_SPEED = 600_KB; 313 static constexpr size_t DEFAULT_YOUNG_CLEAR_NATIVE_OBJ_SPEED = 3_KB; 314 315 GCType gcType_ {GCType::START}; 316 GCReason reason_ {GCReason::OTHER}; 317 float scopeDuration_[Scope::ScopeId::SCOPE_NUM] {0.0f}; 318 size_t recordData_[(uint8_t)RecordData::NUM_OF_DATA] {0}; 319 size_t gcSpeed_ [(uint8_t)SpeedData::NUM_OF_SPEED] = { 320 DEFAULT_UPDATE_REFERENCE_SPEED, DEFAULT_OLD_CLEAR_NATIVE_OBJ_SPEED, 321 DEFAULT_OLD_EVACUATE_SPACE_SPEED, DEFAULT_YOUNG_CLEAR_NATIVE_OBJ_SPEED}; 322 float recordDuration_[(uint8_t)RecordDuration::NUM_OF_DURATION] {0.0f}; 323 bool concurrentMark_ {false}; 324 325 static constexpr uint32_t THOUSAND = 1000; 326 327 NO_COPY_SEMANTIC(GCStats); 328 NO_MOVE_SEMANTIC(GCStats); 329 private: 330 LongGCStats *longGCStats_; 331 }; 332 333 class SharedGCStats : public GCStats { 334 public: SharedGCStats(const SharedHeap * sHeap,bool enableGCTracer)335 SharedGCStats(const SharedHeap *sHeap, bool enableGCTracer) 336 : GCStats(nullptr), sHeap_(sHeap), enableGCTracer_(enableGCTracer) 337 { 338 SetRecordData(RecordData::SHARED_COUNT, 0); 339 } 340 ~SharedGCStats() = default; 341 342 void PrintStatisticResult() override; 343 void PrintGCMemoryStatistic() override; 344 void PrintGCStatistic() override; 345 346 void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason) override; 347 void RecordStatisticAfterGC() override; 348 size_t GetAccumulatedAllocateSize() override; 349 private: 350 void PrintSharedGCDuration(); 351 void PrintSharedGCSummaryStatistic(); 352 void SharedGCFinishTrace(); 353 void ProcessAfterLongGCStats() override; 354 void ProcessBeforeLongGCStats() override; 355 356 const SharedHeap *sHeap_ {nullptr}; 357 bool enableGCTracer_ {false}; 358 }; 359 } // namespace panda::ecmascript 360 361 #endif // ECMASCRIPT_MEM_GC_STATS_H 362