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 31 enum class GCType : int { 32 STW_YOUNG_GC = 0, 33 PARTIAL_YOUNG_GC, 34 PARTIAL_OLD_GC, 35 COMPRESS_GC, 36 OTHER, 37 START, 38 }; 39 40 enum class RecordData : uint8_t { 41 #define DEFINE_SCOPE(scope) scope, 42 RECORD_DATA(DEFINE_SCOPE) 43 #undef DEFINE_SCOPE 44 NUM_OF_DATA, 45 FIRST_DATA = START_OBJ_SIZE, 46 END_RECORD_OVERWRITE = COLLECT_REGION_SET_SIZE, 47 }; 48 49 enum class SpeedData : uint8_t { 50 #define DEFINE_SCOPE(scope) scope, 51 TRACE_GC_SPEED(DEFINE_SCOPE) 52 #undef DEFINE_SCOPE 53 NUM_OF_SPEED, 54 }; 55 56 enum class RecordDuration : uint8_t { 57 #define DEFINE_SCOPE(scope) scope, 58 RECORD_DURATION(DEFINE_SCOPE) 59 #undef DEFINE_SCOPE 60 NUM_OF_DURATION, 61 FIRST_DATA = SEMI_MIN_PAUSE, 62 }; 63 64 #define TRACE_GC(scope_id, gc_stats) \ 65 [[maybe_unused]] GCStats::Scope sp(scope_id, gc_stats) 66 67 class GCStats { 68 using Duration = std::chrono::duration<uint64_t, std::nano>; 69 70 public: GCStats(const Heap * heap)71 explicit GCStats(const Heap *heap) : heap_(heap) {} GCStats(const Heap * heap,size_t longPuaseTime)72 GCStats(const Heap *heap, size_t longPuaseTime) : heap_(heap), 73 longPauseTime_(longPuaseTime) {} 74 ~GCStats() = default; 75 76 void PrintStatisticResult(); 77 void PrintGCMemoryStatistic(); 78 bool CheckIfLongTimePause(); 79 void PrintGCStatistic(); 80 GetGCSpeed(SpeedData data)81 float GetGCSpeed(SpeedData data) 82 { 83 return gcSpeed_[(uint8_t)data]; 84 } 85 SetRecordData(RecordData dataIdx,size_t value)86 void SetRecordData(RecordData dataIdx, size_t value) 87 { 88 recordData_[GetRecordDataIndex(dataIdx)] = value; 89 } 90 GetRecordData(RecordData dataIdx)91 size_t GetRecordData(RecordData dataIdx) 92 { 93 return recordData_[GetRecordDataIndex(dataIdx)]; 94 } 95 SetGCReason(GCReason reason)96 void SetGCReason(GCReason reason) 97 { 98 reason_ = reason; 99 } 100 GetGCReason()101 GCReason GetGCReason() const 102 { 103 return reason_; 104 } 105 GetGCTypeName()106 const char *GetGCTypeName() 107 { 108 switch (gcType_) { 109 case GCType::STW_YOUNG_GC: 110 return "STWYoungGC"; 111 case GCType::PARTIAL_YOUNG_GC: 112 return "HPP YoungGC"; 113 case GCType::PARTIAL_OLD_GC: 114 return "HPP OldGC"; 115 case GCType::COMPRESS_GC: 116 return "CompressGC"; 117 default: 118 return "UnknownType"; 119 } 120 } 121 122 const char *GCReasonToString(); 123 GetAvgSurvivalRate()124 double GetAvgSurvivalRate() 125 { 126 double copiedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_ALIVE)) / 127 GetRecordData(RecordData::YOUNG_TOTAL_COMMIT); 128 double promotedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_PROMOTE)) / 129 GetRecordData(RecordData::YOUNG_TOTAL_COMMIT); 130 return std::min(copiedRate + promotedRate, 1.0); 131 } 132 133 void RecordGCSpeed(); 134 void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason); 135 void RecordStatisticAfterGC(); 136 137 class Scope : public ClockScope { 138 public: 139 enum ScopeId : uint8_t { 140 #define DEFINE_SCOPE(scope) scope, 141 SCOPE_LIST(DEFINE_SCOPE) 142 #undef DEFINE_SCOPE 143 SCOPE_NUM, 144 }; 145 Scope(ScopeId id,GCStats * stats)146 Scope(ScopeId id, GCStats* stats) : id_(id), stats_(stats) 147 { 148 if (id_ == ScopeId::ConcurrentMark) { 149 stats_->NotifyConcurrentMark(); 150 } 151 } ~Scope()152 ~Scope() 153 { 154 float duration = stats_->PrintTimeMilliseconds(stats_->TimeToMicroseconds(GetPauseTime())); 155 stats_->SetScopeId(id_, duration); 156 } 157 158 private: 159 ScopeId id_; 160 GCStats* stats_; 161 }; 162 163 private: 164 bool CheckIfNeedPrint(GCType type); 165 void PrintVerboseGCStatistic(); 166 void PrintGCDurationStatistic(); 167 void PrintGCSummaryStatistic(GCType type = GCType::START); 168 GCType GetGCType(TriggerGCType gcType); 169 void InitializeRecordList(); 170 float GetConcurrrentMarkDuration(); 171 GetRecordDurationIndex(RecordDuration durationIdx)172 int GetRecordDurationIndex(RecordDuration durationIdx) 173 { 174 return (int)durationIdx - (int)RecordDuration::FIRST_DATA; 175 } 176 GetRecordDuration(RecordDuration durationIdx)177 float GetRecordDuration(RecordDuration durationIdx) 178 { 179 return recordDuration_[GetRecordDurationIndex(durationIdx)]; 180 } 181 SetRecordDuration(RecordDuration durationIdx,float value)182 void SetRecordDuration(RecordDuration durationIdx, float value) 183 { 184 recordDuration_[GetRecordDurationIndex(durationIdx)] = value; 185 } 186 IncreaseRecordDuration(RecordDuration durationIdx,float value)187 void IncreaseRecordDuration(RecordDuration durationIdx, float value) 188 { 189 recordDuration_[GetRecordDurationIndex(durationIdx)] += value; 190 } 191 GetRecordDataIndex(RecordData dataIdx)192 int GetRecordDataIndex(RecordData dataIdx) 193 { 194 return (int)dataIdx - (int)RecordData::FIRST_DATA; 195 } 196 197 void IncreaseRecordData(RecordData dataIdx, size_t value = 1) 198 { 199 recordData_[GetRecordDataIndex(dataIdx)] += value; 200 } 201 SetScopeId(int pos,float duration)202 void SetScopeId(int pos, float duration) 203 { 204 scopeDuration_[pos] = duration; 205 } 206 NotifyConcurrentMark()207 void NotifyConcurrentMark() 208 { 209 concurrentMark_ = true; 210 } 211 TimeToMicroseconds(Duration time)212 size_t TimeToMicroseconds(Duration time) 213 { 214 return std::chrono::duration_cast<std::chrono::microseconds>(time).count(); 215 } 216 PrintTimeMilliseconds(uint64_t ms)217 float PrintTimeMilliseconds(uint64_t ms) 218 { 219 return (float)ms / THOUSAND; 220 } 221 sizeToMB(size_t size)222 float sizeToMB(size_t size) 223 { 224 return (float)size / 1_MB; 225 } 226 sizeToKB(size_t size)227 float sizeToKB(size_t size) 228 { 229 return (float)size / 1_KB; 230 } 231 232 const Heap *heap_ {nullptr}; 233 size_t longPauseTime_ = 0; 234 235 static constexpr size_t DEFAULT_UPDATE_REFERENCE_SPEED = 10_MB; 236 static constexpr size_t DEFAULT_OLD_CLEAR_NATIVE_OBJ_SPEED = 1_KB; 237 static constexpr size_t DEFAULT_OLD_EVACUATE_SPACE_SPEED = 600_KB; 238 static constexpr size_t DEFAULT_YOUNG_CLEAR_NATIVE_OBJ_SPEED = 3_KB; 239 240 GCType gcType_ {GCType::START}; 241 GCReason reason_ {GCReason::OTHER}; 242 float scopeDuration_[Scope::ScopeId::SCOPE_NUM] {0.0f}; 243 size_t recordData_[(uint8_t)RecordData::NUM_OF_DATA]; 244 size_t gcSpeed_ [(uint8_t)SpeedData::NUM_OF_SPEED] = { 245 DEFAULT_UPDATE_REFERENCE_SPEED, DEFAULT_OLD_CLEAR_NATIVE_OBJ_SPEED, 246 DEFAULT_OLD_EVACUATE_SPACE_SPEED, DEFAULT_YOUNG_CLEAR_NATIVE_OBJ_SPEED}; 247 float recordDuration_[(uint8_t)RecordDuration::NUM_OF_DURATION] {0.0f}; 248 bool concurrentMark_ {false}; 249 250 static constexpr uint32_t THOUSAND = 1000; 251 252 NO_COPY_SEMANTIC(GCStats); 253 NO_MOVE_SEMANTIC(GCStats); 254 }; 255 } // namespace panda::ecmascript 256 257 #endif // ECMASCRIPT_MEM_GC_STATS_H 258