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 GetAvgSurvivalRate()106 double GetAvgSurvivalRate() 107 { 108 double copiedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_ALIVE)) / 109 GetRecordData(RecordData::YOUNG_TOTAL_COMMIT); 110 double promotedRate = double(GetRecordData(RecordData::YOUNG_TOTAL_PROMOTE)) / 111 GetRecordData(RecordData::YOUNG_TOTAL_COMMIT); 112 return std::min(copiedRate + promotedRate, 1.0); 113 } 114 115 void RecordGCSpeed(); 116 void RecordStatisticBeforeGC(TriggerGCType gcType, GCReason reason); 117 void RecordStatisticAfterGC(); 118 119 class Scope : public ClockScope { 120 public: 121 enum ScopeId : uint8_t { 122 #define DEFINE_SCOPE(scope) scope, 123 SCOPE_LIST(DEFINE_SCOPE) 124 #undef DEFINE_SCOPE 125 SCOPE_NUM, 126 }; 127 Scope(ScopeId id,GCStats * stats)128 Scope(ScopeId id, GCStats* stats) : id_(id), stats_(stats) 129 { 130 if (id_ == ScopeId::ConcurrentMark) { 131 stats_->NotifyConcurrentMark(); 132 } 133 } ~Scope()134 ~Scope() 135 { 136 float duration = stats_->PrintTimeMilliseconds(stats_->TimeToMicroseconds(GetPauseTime())); 137 stats_->SetScopeId(id_, duration); 138 } 139 140 private: 141 ScopeId id_; 142 GCStats* stats_; 143 }; 144 145 private: 146 bool CheckIfNeedPrint(GCType type); 147 void PrintVerboseGCStatistic(); 148 void PrintGCDurationStatistic(); 149 void PrintGCSummaryStatistic(GCType type = GCType::START); 150 GCType GetGCType(TriggerGCType gcType); 151 const char *GCReasonToString(); 152 void InitializeRecordList(); 153 const char *GetGCTypeName(); 154 float GetConcurrrentMarkDuration(); 155 GetRecordDurationIndex(RecordDuration durationIdx)156 int GetRecordDurationIndex(RecordDuration durationIdx) 157 { 158 return (int)durationIdx - (int)RecordDuration::FIRST_DATA; 159 } 160 GetRecordDuration(RecordDuration durationIdx)161 float GetRecordDuration(RecordDuration durationIdx) 162 { 163 return recordDuration_[GetRecordDurationIndex(durationIdx)]; 164 } 165 SetRecordDuration(RecordDuration durationIdx,float value)166 void SetRecordDuration(RecordDuration durationIdx, float value) 167 { 168 recordDuration_[GetRecordDurationIndex(durationIdx)] = value; 169 } 170 IncreaseRecordDuration(RecordDuration durationIdx,float value)171 void IncreaseRecordDuration(RecordDuration durationIdx, float value) 172 { 173 recordDuration_[GetRecordDurationIndex(durationIdx)] += value; 174 } 175 GetRecordDataIndex(RecordData dataIdx)176 int GetRecordDataIndex(RecordData dataIdx) 177 { 178 return (int)dataIdx - (int)RecordData::FIRST_DATA; 179 } 180 181 void IncreaseRecordData(RecordData dataIdx, size_t value = 1) 182 { 183 recordData_[GetRecordDataIndex(dataIdx)] += value; 184 } 185 SetScopeId(int pos,float duration)186 void SetScopeId(int pos, float duration) 187 { 188 scopeDuration_[pos] = duration; 189 } 190 NotifyConcurrentMark()191 void NotifyConcurrentMark() 192 { 193 concurrentMark_ = true; 194 } 195 TimeToMicroseconds(Duration time)196 size_t TimeToMicroseconds(Duration time) 197 { 198 return std::chrono::duration_cast<std::chrono::microseconds>(time).count(); 199 } 200 PrintTimeMilliseconds(uint64_t ms)201 float PrintTimeMilliseconds(uint64_t ms) 202 { 203 return (float)ms / THOUSAND; 204 } 205 sizeToMB(size_t size)206 float sizeToMB(size_t size) 207 { 208 return (float)size / 1_MB; 209 } 210 sizeToKB(size_t size)211 float sizeToKB(size_t size) 212 { 213 return (float)size / 1_KB; 214 } 215 216 const Heap *heap_ {nullptr}; 217 size_t longPauseTime_ = 0; 218 219 static constexpr size_t DEFAULT_UPDATE_REFERENCE_SPEED = 10_MB; 220 static constexpr size_t DEFAULT_OLD_CLEAR_NATIVE_OBJ_SPEED = 1_KB; 221 static constexpr size_t DEFAULT_OLD_EVACUATE_SPACE_SPEED = 600_KB; 222 static constexpr size_t DEFAULT_YOUNG_CLEAR_NATIVE_OBJ_SPEED = 3_KB; 223 224 GCType gcType_ {GCType::START}; 225 GCReason reason_ {GCReason::OTHER}; 226 float scopeDuration_[Scope::ScopeId::SCOPE_NUM] {0.0f}; 227 size_t recordData_[(uint8_t)RecordData::NUM_OF_DATA]; 228 size_t gcSpeed_ [(uint8_t)SpeedData::NUM_OF_SPEED] = { 229 DEFAULT_UPDATE_REFERENCE_SPEED, DEFAULT_OLD_CLEAR_NATIVE_OBJ_SPEED, 230 DEFAULT_OLD_EVACUATE_SPACE_SPEED, DEFAULT_YOUNG_CLEAR_NATIVE_OBJ_SPEED}; 231 float recordDuration_[(uint8_t)RecordDuration::NUM_OF_DURATION] {0.0f}; 232 bool concurrentMark_ {false}; 233 234 static constexpr uint32_t THOUSAND = 1000; 235 236 NO_COPY_SEMANTIC(GCStats); 237 NO_MOVE_SEMANTIC(GCStats); 238 }; 239 } // namespace panda::ecmascript 240 241 #endif // ECMASCRIPT_MEM_GC_STATS_H 242