• 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/js_tagged_value.h"
25 #include "ecmascript/jspandafile/method_literal.h"
26 #include "ecmascript/mem/c_containers.h"
27 #include "ecmascript/mem/native_area_allocator.h"
28 #include "ecmascript/mem/region.h"
29 #include "ecmascript/mem/visitor.h"
30 #include "ecmascript/pgo_profiler/types/pgo_profiler_type.h"
31 #include "ecmascript/pgo_profiler/types/pgo_type_generator.h"
32 #include "ecmascript/platform/mutex.h"
33 #include "ecmascript/taskpool/task.h"
34 #include "ecmascript/pgo_profiler/pgo_utils.h"
35 #include "ecmascript/pgo_profiler/types/pgo_profile_type.h"
36 
37 namespace panda::ecmascript {
38 class ProfileTypeInfo;
39 class JSFunction;
40 
41 namespace pgo {
42 class PGORecordDetailInfos;
43 
44 enum class SampleMode : uint8_t {
45     HOTNESS_MODE,
46     CALL_MODE,
47 };
48 
49 class PGOProfiler {
50 public:
51     NO_COPY_SEMANTIC(PGOProfiler);
52     NO_MOVE_SEMANTIC(PGOProfiler);
53 
54     PGOProfiler(EcmaVM *vm, bool isEnable);
55 
56     virtual ~PGOProfiler();
57 
58     static ProfileType CreateRecordProfileType(ApEntityId abcId, ApEntityId classId);
59     void ProfileCreateObject(JSTaggedType object, ApEntityId abcId, int32_t traceId);
60     void ProfileDefineClass(JSTaggedType ctor);
61     void ProfileDefineGetterSetter(
62         JSHClass *receverHClass, JSHClass *holderHClass, const JSHandle<JSTaggedValue> &func, int32_t pcOffset);
63     void ProfileClassRootHClass(JSTaggedType ctor, JSTaggedType rootHcValue,
64                                 ProfileType::Kind kind = ProfileType::Kind::ClassId);
65     void UpdateRootProfileType(JSHClass *oldHClass, JSHClass *newHClass);
66 
SetSaveTimestamp(std::chrono::system_clock::time_point timestamp)67     void SetSaveTimestamp(std::chrono::system_clock::time_point timestamp)
68     {
69         saveTimestamp_ = timestamp;
70     }
71 
72     void PGOPreDump(JSTaggedType func);
73     void PGODump(JSTaggedType func);
74 
75     void WaitPGODumpPause();
76     void WaitPGODumpResume();
77     void WaitPGODumpFinish();
78 
79     void HandlePGOPreDump();
80     void HandlePGODump(bool force);
81 
82     void ProcessReferences(const WeakRootVisitor &visitor);
83     void Iterate(const RootVisitor &visitor);
84 
85     void UpdateTrackArrayLength(JSTaggedValue trackInfoVal, uint32_t newSize);
86     void UpdateTrackSpaceFlag(TaggedObject *object, RegionSpaceFlag spaceFlag);
87     void UpdateTrackElementsKind(JSTaggedValue trackInfoVal, ElementsKind newKind);
88     void UpdateTrackInfo(JSTaggedValue trackInfoVal);
89 
90     JSTaggedValue TryFindKeyInPrototypeChain(TaggedObject *currObj, JSHClass *currHC, JSTaggedValue key);
91 
92 private:
93     static constexpr uint32_t MERGED_EVERY_COUNT = 50;
94     static constexpr uint32_t MS_PRE_SECOND = 1000;
95     enum class BCType : uint8_t {
96         STORE,
97         LOAD,
98     };
99 
100     enum class State : uint8_t {
101         STOP,
102         PAUSE,
103         START,
104         FORCE_SAVE,
105         FORCE_SAVE_PAUSE,
106     };
107 
108     void ProfileBytecode(ApEntityId abcId, const CString &recordName, JSTaggedValue value);
109     bool PausePGODump();
110 
111     void DumpICByName(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
112                       ProfileTypeInfo *profileTypeInfo, BCType type);
113     void DumpICByValue(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
114                        uint32_t slotId, ProfileTypeInfo *profileTypeInfo, BCType type);
115 
116     void DumpICByNameWithPoly(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
117                               JSTaggedValue cacheValue, BCType type);
118     void DumpICByValueWithPoly(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
119                                JSTaggedValue cacheValue, BCType type);
120 
121     void DumpICByNameWithHandler(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
122                                  JSHClass *hclass, JSTaggedValue secondValue, BCType type);
123     void DumpICByValueWithHandler(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
124                                   JSHClass *hclass, JSTaggedValue secondValue, BCType type);
125     void DumpByForce();
126 
127     void DumpOpType(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
128                     ProfileTypeInfo *profileTypeInfo);
129     void DumpDefineClass(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
130                          uint32_t slotId, ProfileTypeInfo *profileTypeInfo);
131     bool FunctionKindVerify(const JSFunction *ctorFunction);
132     void DumpCreateObject(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
133                           uint32_t slotId, ProfileTypeInfo *profileTypeInfo, int32_t traceId);
134     void DumpCall(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, uint32_t slotId,
135                   ProfileTypeInfo *profileTypeInfo);
136     void DumpNewObjRange(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
137                          uint32_t slotId, ProfileTypeInfo *profileTypeInfo);
138     void DumpGetIterator(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
139                          uint32_t slotId, ProfileTypeInfo *profileTypeInfo);
140     void DumpInstanceof(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
141                          uint32_t slotId, ProfileTypeInfo *profileTypeInfo);
142 
143     void UpdateLayout(JSHClass *hclass);
144     void UpdateTranstionLayout(JSHClass *parent, JSHClass *child);
145     void AddTranstionObjectInfo(ProfileType recordType, EntityId methodId, int32_t bcOffset, JSHClass *receiver,
146         JSHClass *hold, JSHClass *holdTra);
147     void UpdatePrototypeChainInfo(JSHClass *receiver, JSHClass *holder, PGOObjectInfo &info);
148 
149     void AddObjectInfo(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
150                        JSHClass *receiver, JSHClass *hold, JSHClass *holdTra);
151     void AddObjectInfoWithMega(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset);
152     void AddBuiltinsInfo(
153         ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, JSHClass *receiver,
154         JSHClass *transitionHClass, OnHeapMode onHeap = OnHeapMode::NONE);
155 
156     ProfileType GetProfileType(JSTaggedType root, JSTaggedType child);
157     ProfileType GetOrInsertProfileType(JSTaggedType root, JSTaggedType child);
158     void InsertProfileType(JSTaggedType root, JSTaggedType child, ProfileType traceType);
159 
160     class WorkNode;
161     void UpdateExtraProfileTypeInfo(ApEntityId abcId, const CString& recordName, EntityId methodId, WorkNode* current);
162     WorkNode* PopFromProfileQueue();
163     void SaveProfiler(bool force);
164 
165     class PGOProfilerTask : public Task {
166     public:
PGOProfilerTask(PGOProfiler * profiler,int32_t id)167         explicit PGOProfilerTask(PGOProfiler *profiler, int32_t id)
168             : Task(id), profiler_(profiler){};
169         virtual ~PGOProfilerTask() override = default;
170 
Run(uint32_t threadIndex)171         bool Run([[maybe_unused]] uint32_t threadIndex) override
172         {
173             profiler_->HandlePGODump(profiler_->isForce_);
174             return true;
175         }
176 
177         NO_COPY_SEMANTIC(PGOProfilerTask);
178         NO_MOVE_SEMANTIC(PGOProfilerTask);
179     private:
180         PGOProfiler *profiler_;
181     };
182 
183     using PcOffset = int32_t;
184     class ExtraProfileTypeInfo {
185     public:
GetReceiverAddr()186         uintptr_t GetReceiverAddr() const
187         {
188             return reinterpret_cast<uintptr_t>(&receiver);
189         }
190 
GetHolderAddr()191         uintptr_t GetHolderAddr() const
192         {
193             return reinterpret_cast<uintptr_t>(&holder);
194         }
195 
GetReceiverHClass()196         JSHClass* GetReceiverHClass() const
197         {
198             return receiver.GetTaggedObject()->GetClass();
199         }
200 
GetHolderHClass()201         JSHClass* GetHolderHClass() const
202         {
203             return holder.GetTaggedObject()->GetClass();
204         }
205 
SetReceiver(JSHClass * hclass)206         void SetReceiver(JSHClass* hclass)
207         {
208             receiver = JSTaggedValue::Cast(hclass);
209         }
210 
SetHolder(JSHClass * hclass)211         void SetHolder(JSHClass* hclass)
212         {
213             holder = JSTaggedValue::Cast(hclass);
214         }
215 
SetReceiver(JSTaggedValue value)216         void SetReceiver(JSTaggedValue value)
217         {
218             receiver = value;
219         }
220 
SetHolder(JSTaggedValue value)221         void SetHolder(JSTaggedValue value)
222         {
223             holder = value;
224         }
225 
SetReceiver(TaggedObject * value)226         void SetReceiver(TaggedObject* value)
227         {
228             receiver = JSTaggedValue::Cast(value);
229         }
230 
SetHolder(TaggedObject * value)231         void SetHolder(TaggedObject* value)
232         {
233             holder = JSTaggedValue::Cast(value);
234         }
235 
GetReceiver()236         JSTaggedValue GetReceiver() const
237         {
238             return receiver;
239         }
240 
GetHolder()241         JSTaggedValue GetHolder() const
242         {
243             return holder;
244         }
245 
Clear()246         void Clear()
247         {
248             receiver = JSTaggedValue::Hole();
249             holder = JSTaggedValue::Hole();
250         }
251 
ClearReceiver()252         void ClearReceiver()
253         {
254             receiver = JSTaggedValue::Hole();
255         }
256 
ClearHolder()257         void ClearHolder()
258         {
259             holder = JSTaggedValue::Hole();
260         }
261 
262         bool operator==(const ExtraProfileTypeInfo& other) const
263         {
264             return receiver == other.receiver && holder == other.holder;
265         }
266 
IsHole()267         bool IsHole() const
268         {
269             return receiver.IsHole() && holder.IsHole();
270         }
271 
ProcessReceiver(const WeakRootVisitor & visitor)272         void ProcessReceiver(const WeakRootVisitor& visitor)
273         {
274             if (!receiver.IsHeapObject()) {
275                 return;
276             }
277             auto obj = receiver.GetTaggedObject();
278             auto fwd = visitor(obj);
279             if (fwd == nullptr) {
280                 ClearReceiver();
281             } else if (fwd != obj) {
282                 SetReceiver(fwd);
283             }
284         }
285 
ProcessHolder(const WeakRootVisitor & visitor)286         void ProcessHolder(const WeakRootVisitor& visitor)
287         {
288             if (!holder.IsHeapObject()) {
289                 return;
290             }
291             auto obj = holder.GetTaggedObject();
292             auto fwd = visitor(obj);
293             if (fwd == nullptr) {
294                 ClearHolder();
295             } else if (fwd != obj) {
296                 SetHolder(fwd);
297             }
298         }
299 
300     private:
301         JSTaggedValue receiver {JSTaggedValue::Hole()};
302         JSTaggedValue holder {JSTaggedValue::Hole()};
303     };
304 
305     class WorkList;
306     class WorkNode {
307     public:
WorkNode(JSTaggedType value)308         WorkNode(JSTaggedType value) : value_(value) {}
SetPrev(WorkNode * prev)309         void SetPrev(WorkNode *prev)
310         {
311             prev_ = prev;
312         }
313 
SetNext(WorkNode * next)314         void SetNext(WorkNode *next)
315         {
316             next_ = next;
317         }
318 
SetValue(JSTaggedType value)319         void SetValue(JSTaggedType value)
320         {
321             value_ = value;
322         }
323 
SetWorkList(WorkList * workList)324         void SetWorkList(WorkList *workList)
325         {
326             workList_ = workList;
327         }
328 
GetPrev()329         WorkNode *GetPrev() const
330         {
331             return prev_;
332         }
333 
GetNext()334         WorkNode *GetNext() const
335         {
336             return next_;
337         }
338 
GetValue()339         JSTaggedType GetValue() const
340         {
341             return value_;
342         }
343 
GetValueAddr()344         uintptr_t GetValueAddr() const
345         {
346             return reinterpret_cast<uintptr_t>(&value_);
347         }
348 
GetWorkList()349         WorkList *GetWorkList() const
350         {
351             return workList_;
352         }
353 
SetExtraProfileTypeInfo(int32_t pcOffset,JSHClass * receiverHClass,JSHClass * holderHClass)354         void SetExtraProfileTypeInfo(int32_t pcOffset, JSHClass* receiverHClass, JSHClass* holderHClass)
355         {
356             auto it = map_.find(pcOffset);
357 
358             ExtraProfileTypeInfo info;
359             info.SetReceiver(receiverHClass);
360             info.SetHolder(holderHClass);
361 
362             if (it == map_.end()) {
363                 map_.insert(std::make_pair(pcOffset, info));
364                 return;
365             }
366 
367             if (it->second == info) {
368                 return;
369             }
370 
371             it->second.Clear();
372         }
373 
HasExtraProfileTypeInfo()374         bool HasExtraProfileTypeInfo()
375         {
376             return !map_.empty();
377         }
378 
ProcessExtraProfileTypeInfo(const WeakRootVisitor & visitor)379         void ProcessExtraProfileTypeInfo(const WeakRootVisitor& visitor)
380         {
381             for (auto& iter: map_) {
382                 auto& info = iter.second;
383                 info.ProcessReceiver(visitor);
384                 info.ProcessHolder(visitor);
385             }
386         }
387 
IterateExtraProfileTypeInfo(const RootVisitor & visitor)388         void IterateExtraProfileTypeInfo(const RootVisitor& visitor)
389         {
390             if (HasExtraProfileTypeInfo()) {
391                 for (auto& iter: map_) {
392                     auto& info = iter.second;
393                     visitor(Root::ROOT_VM, ObjectSlot(info.GetReceiverAddr()));
394                     visitor(Root::ROOT_VM, ObjectSlot(info.GetHolderAddr()));
395                 }
396             }
397         }
398 
GetExtraProfileTypeInfo()399         std::unordered_map<PcOffset, ExtraProfileTypeInfo>& GetExtraProfileTypeInfo()
400         {
401             return map_;
402         }
403 
404     private:
405         WorkList *workList_ { nullptr };
406         WorkNode *prev_ { nullptr };
407         WorkNode *next_ { nullptr };
408         JSTaggedType value_ { JSTaggedValue::Undefined().GetRawData() };
409         std::unordered_map<PcOffset, ExtraProfileTypeInfo> map_;
410     };
411 
412     class WorkList {
413     public:
414         using Callback = std::function<void(WorkNode *node)>;
IsEmpty()415         bool IsEmpty() const
416         {
417             return first_ == nullptr;
418         }
419         void PushBack(WorkNode *node);
420         WorkNode *PopFront();
421         void Remove(WorkNode *node);
422         void Iterate(Callback callback) const;
423     private:
424         WorkNode *first_ { nullptr };
425         WorkNode *last_ { nullptr };
426     };
427 
428     static ApEntityId GetMethodAbcId(JSFunction *jsFunction);
429     ProfileType GetRecordProfileType(JSFunction *jsFunction, const CString &recordName);
430     ProfileType GetRecordProfileType(ApEntityId abcId, const CString &recordName);
431     ProfileType GetRecordProfileType(const std::shared_ptr<JSPandaFile> &pf, ApEntityId abcId,
432                                      const CString &recordName);
433 
434     void Reset(bool isEnable);
435 
436     EcmaVM *vm_ { nullptr };
437     bool isEnable_ { false };
438     bool isForce_ {false};
439     State state_ { State::STOP };
440     uint32_t methodCount_ { 0 };
441     std::chrono::system_clock::time_point saveTimestamp_;
442     Mutex mutex_;
443     ConditionVariable condition_;
444     WorkList dumpWorkList_;
445     WorkList preDumpWorkList_;
446     CMap<JSTaggedType, PGOTypeGenerator *> tracedProfiles_;
447     std::unique_ptr<PGORecordDetailInfos> recordInfos_;
448     friend class PGOProfilerManager;
449 };
450 } // namespace pgo
451 } // namespace panda::ecmascript
452 #endif // ECMASCRIPT_PGO_PROFILER_H
453