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