• 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 "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