1 /* 2 * Copyright (c) 2023 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_PGO_PROFILER_H 17 #define ECMASCRIPT_PGO_PROFILER_H 18 19 #include <chrono> 20 #include <memory> 21 22 #include "ecmascript/common.h" 23 #include "ecmascript/elements.h" 24 #include "ecmascript/global_index.h" 25 #include "ecmascript/js_handle.h" 26 #include "ecmascript/js_tagged_value.h" 27 #include "ecmascript/jspandafile/method_literal.h" 28 #include "ecmascript/mem/c_containers.h" 29 #include "ecmascript/mem/native_area_allocator.h" 30 #include "ecmascript/mem/region.h" 31 #include "ecmascript/mem/visitor.h" 32 #include "ecmascript/pgo_profiler/pgo_extra_profiler.h" 33 #include "ecmascript/pgo_profiler/pgo_state.h" 34 #include "ecmascript/pgo_profiler/pgo_utils.h" 35 #include "ecmascript/pgo_profiler/types/pgo_profile_type.h" 36 #include "ecmascript/pgo_profiler/types/pgo_profiler_type.h" 37 #include "ecmascript/pgo_profiler/types/pgo_type_generator.h" 38 #include "ecmascript/platform/mutex.h" 39 #include "ecmascript/taskpool/task.h" 40 41 namespace panda::ecmascript { 42 class ProfileTypeInfo; 43 class JSFunction; 44 class GlobalIndex; 45 class JITProfiler; 46 47 namespace pgo { 48 class PGORecordDetailInfos; 49 class PGOProfilerManager; 50 using State = pgo::PGOState::State; 51 52 enum class SampleMode : uint8_t { 53 HOTNESS_MODE, 54 CALL_MODE, 55 }; 56 57 class PGOProfiler { 58 public: 59 PGOProfiler(EcmaVM* vm, bool isEnable); 60 virtual ~PGOProfiler(); 61 NO_COPY_SEMANTIC(PGOProfiler); 62 NO_MOVE_SEMANTIC(PGOProfiler); 63 void PUBLIC_API RecordProfileType(JSHClass* hclass, JSPandaFile* pandaFile, int32_t traceId); 64 static ProfileType CreateRecordProfileType(ApEntityId abcId, ApEntityId classId); 65 void ProfileDefineClass(JSTaggedType ctor); 66 void ProfileProtoTransitionClass(JSHandle<JSFunction> func, 67 JSHandle<JSHClass> hclass, 68 JSHandle<JSTaggedValue> proto); 69 void ProfileProtoTransitionPrototype(JSHandle<JSFunction> func, 70 JSHandle<JSTaggedValue> prototype, 71 JSHandle<JSTaggedValue> oldPrototype, 72 JSHandle<JSTaggedValue> baseIhc); 73 void ProfileDefineGetterSetter(JSHClass* receverHClass, 74 JSHClass* holderHClass, 75 const JSHandle<JSTaggedValue>& func, 76 int32_t pcOffset); 77 void ProfileClassRootHClass(JSTaggedType ctor, 78 JSTaggedType rootHcValue, 79 ProfileType::Kind kind = ProfileType::Kind::ClassId); 80 void PUBLIC_API ProfileNapiRootHClass(JSTaggedType ctor, 81 JSTaggedType rootHcValue, 82 ProfileType::Kind kind = ProfileType::Kind::NapiId); 83 void UpdateRootProfileTypeSafe(JSHClass* oldHClass, JSHClass* newHClass); 84 void InitJITProfiler(); 85 void PGOPreDump(JSTaggedType func); 86 void PGODump(JSTaggedType func); 87 void SuspendByGC(); 88 void ResumeByGC(); 89 void HandlePGOPreDump(); 90 void HandlePGODumpByDumpThread(); 91 void ProcessReferences(const WeakRootVisitor& visitor); 92 void Iterate(RootVisitor& visitor); 93 void UpdateTrackArrayLength(JSTaggedValue trackInfoVal, uint32_t newSize); 94 void UpdateTrackSpaceFlag(TaggedObject* object, RegionSpaceFlag spaceFlag); 95 void UpdateTrackInfo(JSTaggedValue trackInfoVal); 96 JSTaggedValue TryFindKeyInPrototypeChain(TaggedObject* currObj, JSHClass* currHC, JSTaggedValue key); 97 static ApEntityId PUBLIC_API GetMethodAbcId(JSFunction* jsFunction); 98 static ApEntityId PUBLIC_API GetMethodAbcId(JSTaggedValue jsMethod); 99 void Reset(bool isEnable); 100 void InsertSkipCtorMethodIdSafe(EntityId ctorMethodId); 101 void SetSaveTimestamp(std::chrono::system_clock::time_point timestamp); 102 JITProfiler* PUBLIC_API GetJITProfile(); 103 void SetStopAndNotify(); 104 bool SetStartIfStop(); 105 void TrySaveByDumpThread(); 106 void DumpBeforeDestroy(); 107 108 private: 109 class WorkNode; 110 class WorkList; 111 112 enum class BCType : uint8_t { 113 STORE, 114 LOAD, 115 }; 116 117 void ProfileBytecode(ApEntityId abcId, const CString& recordName, JSTaggedValue funcValue); 118 void DumpICByName(ApEntityId abcId, 119 const CString& recordName, 120 EntityId methodId, 121 int32_t bcOffset, 122 uint32_t slotId, 123 ProfileTypeInfo* profileTypeInfo, 124 BCType type); 125 void DumpICByValue(ApEntityId abcId, 126 const CString& recordName, 127 EntityId methodId, 128 int32_t bcOffset, 129 uint32_t slotId, 130 ProfileTypeInfo* profileTypeInfo, 131 BCType type); 132 void DumpICByNameWithPoly(ApEntityId abcId, 133 const CString& recordName, 134 EntityId methodId, 135 int32_t bcOffset, 136 JSTaggedValue cacheValue, 137 BCType type); 138 void DumpICByValueWithPoly(ApEntityId abcId, 139 const CString& recordName, 140 EntityId methodId, 141 int32_t bcOffset, 142 JSTaggedValue cacheValue, 143 BCType type); 144 bool DumpICByNameWithHandler(ApEntityId abcId, 145 const CString& recordName, 146 EntityId methodId, 147 int32_t bcOffset, 148 JSHClass* hclass, 149 JSTaggedValue secondValue, 150 BCType type); 151 bool DumpICLoadByNameWithHandler(ApEntityId abcId, 152 const CString& recordName, 153 EntityId methodId, 154 int32_t bcOffset, 155 JSHClass* hclass, 156 JSTaggedValue secondValue); 157 void DumpICByValueWithHandler(ApEntityId abcId, 158 const CString& recordName, 159 EntityId methodId, 160 int32_t bcOffset, 161 JSHClass* hclass, 162 JSTaggedValue secondValue, 163 BCType type); 164 void TryDumpProtoTransitionType(JSHClass* hclass); 165 void DumpOpType(ApEntityId abcId, 166 const CString& recordName, 167 EntityId methodId, 168 int32_t bcOffset, 169 uint32_t slotId, 170 ProfileTypeInfo* profileTypeInfo); 171 void DumpDefineClass(ApEntityId abcId, 172 const CString& recordName, 173 EntityId methodId, 174 int32_t bcOffset, 175 uint32_t slotId, 176 ProfileTypeInfo* profileTypeInfo); 177 bool FunctionKindVerify(const JSFunction* ctorFunction); 178 void DumpCreateObject(ApEntityId abcId, 179 const CString& recordName, 180 EntityId methodId, 181 int32_t bcOffset, 182 uint32_t slotId, 183 ProfileTypeInfo* profileTypeInfo, 184 int32_t traceId); 185 void DumpCall(ApEntityId abcId, 186 const CString& recordName, 187 EntityId methodId, 188 int32_t bcOffset, 189 uint32_t slotId, 190 ProfileTypeInfo* profileTypeInfo); 191 void DumpNewObjRange(ApEntityId abcId, 192 const CString& recordName, 193 EntityId methodId, 194 int32_t bcOffset, 195 uint32_t slotId, 196 ProfileTypeInfo* profileTypeInfo); 197 void DumpGetIterator(ApEntityId abcId, 198 const CString& recordName, 199 EntityId methodId, 200 int32_t bcOffset, 201 uint32_t slotId, 202 ProfileTypeInfo* profileTypeInfo); 203 void DumpInstanceof(ApEntityId abcId, 204 const CString& recordName, 205 EntityId methodId, 206 int32_t bcOffset, 207 uint32_t slotId, 208 ProfileTypeInfo* profileTypeInfo); 209 void UpdateLayout(JSHClass* hclass); 210 void UpdateTransitionLayout(JSHClass* parent, JSHClass* child); 211 bool AddTransitionObjectInfo(ProfileType recordType, 212 EntityId methodId, 213 int32_t bcOffset, 214 JSHClass* receiver, 215 JSHClass* hold, 216 JSHClass* holdTra, 217 PGOSampleType accessorMethod); 218 void UpdatePrototypeChainInfo(JSHClass* receiver, JSHClass* holder, PGOObjectInfo& info); 219 bool AddObjectInfo(ApEntityId abcId, 220 const CString& recordName, 221 EntityId methodId, 222 int32_t bcOffset, 223 JSHClass* receiver, 224 JSHClass* hold, 225 JSHClass* holdTra, 226 uint32_t accessorMethodId = 0); 227 void AddObjectInfoWithMega(ApEntityId abcId, const CString& recordName, EntityId methodId, int32_t bcOffset); 228 bool AddBuiltinsInfoByNameInInstance( 229 ApEntityId abcId, const CString& recordName, EntityId methodId, int32_t bcOffset, JSHClass* receiver); 230 bool AddBuiltinsInfoByNameInProt(ApEntityId abcId, 231 const CString& recordName, 232 EntityId methodId, 233 int32_t bcOffset, 234 JSHClass* receiver, 235 JSHClass* hold); 236 bool AddBuiltinsInfo(ApEntityId abcId, 237 const CString& recordName, 238 EntityId methodId, 239 int32_t bcOffset, 240 JSHClass* receiver, 241 JSHClass* transitionHClass, 242 OnHeapMode onHeap = OnHeapMode::NONE, 243 bool everOutOfBounds = false); 244 void AddBuiltinsGlobalInfo( 245 ApEntityId abcId, const CString& recordName, EntityId methodId, int32_t bcOffset, GlobalIndex globalId); 246 void SetRootProfileType(JSHClass* root, ApEntityId abcId, uint32_t type, ProfileType::Kind kind); 247 ProfileType FindRootProfileType(JSHClass* hclass); 248 ProfileType GetOrInsertProfileType(JSHClass* child, ProfileType rootType); 249 ProfileType GetProfileType(JSHClass* hclass, bool check = false); 250 bool IsRecoredTransRootType(ProfileType type); 251 bool HasValidExtraProfileTypeInfo(JSFunction* func); 252 void ProcessExtraProfileTypeInfo(JSFunction* func, 253 ApEntityId abcId, 254 const CString& recordName, 255 JSTaggedValue methodValue, 256 WorkNode* current); 257 void UpdateExtraProfileTypeInfo(ApEntityId abcId, 258 const CString& recordName, 259 EntityId methodId, 260 WorkNode* current); 261 WorkNode* PopFromProfileQueue(); 262 bool IsJSHClassNotEqual(JSHClass* receiver, 263 JSHClass* hold, 264 JSHClass* exceptRecvHClass, 265 JSHClass* exceptRecvHClassOnHeap, 266 JSHClass* exceptHoldHClass, 267 JSHClass* exceptPrototypeOfPrototypeHClass); 268 bool CheckProtoChangeMarker(JSTaggedValue cellValue) const; 269 ProfileType GetRecordProfileType(JSFunction* jsFunction, const CString& recordName); 270 ProfileType GetRecordProfileType(ApEntityId abcId, const CString& recordName); 271 ProfileType GetRecordProfileType(const std::shared_ptr<JSPandaFile>& pf, 272 ApEntityId abcId, 273 const CString& recordName); 274 bool IsSkippableObjectTypeSafe(ProfileType type); 275 bool IsSkippableCtor(uint32_t entityId); 276 bool InsertDefinedCtor(uint32_t entityId); 277 278 class WorkNode { 279 public: WorkNode(JSTaggedType value)280 WorkNode(JSTaggedType value): value_(value) {} SetPrev(WorkNode * prev)281 void SetPrev(WorkNode* prev) 282 { 283 prev_ = prev; 284 } 285 SetNext(WorkNode * next)286 void SetNext(WorkNode* next) 287 { 288 next_ = next; 289 } 290 SetValue(JSTaggedType value)291 void SetValue(JSTaggedType value) 292 { 293 value_ = value; 294 } 295 SetWorkList(WorkList * workList)296 void SetWorkList(WorkList* workList) 297 { 298 workList_ = workList; 299 } 300 GetPrev()301 WorkNode* GetPrev() const 302 { 303 return prev_; 304 } 305 GetNext()306 WorkNode* GetNext() const 307 { 308 return next_; 309 } 310 GetValue()311 JSTaggedType GetValue() const 312 { 313 return value_; 314 } 315 GetValueAddr()316 uintptr_t GetValueAddr() const 317 { 318 return reinterpret_cast<uintptr_t>(&value_); 319 } 320 GetWorkList()321 WorkList* GetWorkList() const 322 { 323 return workList_; 324 } 325 326 private: 327 WorkList* workList_ {nullptr}; 328 WorkNode* prev_ {nullptr}; 329 WorkNode* next_ {nullptr}; 330 JSTaggedType value_ {JSTaggedValue::Undefined().GetRawData()}; 331 }; 332 333 class WorkList { 334 public: 335 using Callback = std::function<void(WorkNode* node)>; 336 bool IsEmpty(); 337 void PushBack(WorkNode* node); 338 WorkNode* PopFront(); 339 void Remove(WorkNode* node); 340 void Iterate(Callback callback) const; 341 void Reset(); 342 343 private: 344 WorkNode* first_ {nullptr}; 345 WorkNode* last_ {nullptr}; 346 Mutex workListMutex_; 347 }; 348 349 private: 350 static constexpr uint32_t MERGED_EVERY_COUNT = 50; 351 static constexpr uint32_t MS_PRE_SECOND = 1000; 352 std::unique_ptr<NativeAreaAllocator> nativeAreaAllocator_; 353 EcmaVM* vm_ {nullptr}; 354 bool isEnable_ {false}; 355 uint32_t methodCount_ {0}; 356 std::chrono::system_clock::time_point saveTimestamp_; 357 WorkList dumpWorkList_; 358 WorkList preDumpWorkList_; 359 std::shared_ptr<PGORecordDetailInfos> recordInfos_; 360 std::unique_ptr<PGOState> state_; 361 PGOProfilerManager* manager_ {nullptr}; 362 // AOT only supports executing Defineclass bc once currently. 363 // If defineclass executed multiple times, It will gives up collection. 364 CUnorderedSet<uint32_t> definedCtorMethodId_; 365 CUnorderedSet<uint32_t> skipCtorMethodId_; 366 Mutex skipCtorMethodIdMutex_; 367 JITProfiler* jitProfiler_ {nullptr}; 368 CVector<ProfileType> recordedTransRootType_; 369 friend class PGOProfilerManager; 370 }; 371 372 class PGODumpPauseScope { 373 public: PGODumpPauseScope(std::shared_ptr<PGOProfiler> profiler)374 explicit PGODumpPauseScope(std::shared_ptr<PGOProfiler> profiler): profiler_(profiler) 375 { 376 profiler_->SuspendByGC(); 377 } 378 ~PGODumpPauseScope()379 ~PGODumpPauseScope() 380 { 381 profiler_->ResumeByGC(); 382 } 383 384 NO_COPY_SEMANTIC(PGODumpPauseScope); 385 NO_MOVE_SEMANTIC(PGODumpPauseScope); 386 387 private: 388 std::shared_ptr<PGOProfiler> profiler_; 389 }; 390 } // namespace pgo 391 } // namespace panda::ecmascript 392 #endif // ECMASCRIPT_PGO_PROFILER_H 393