• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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_DFX_HPROF_HEAP_PROFILER_H
17 #define ECMASCRIPT_DFX_HPROF_HEAP_PROFILER_H
18 
19 #include "common_components/heap/heap.h"
20 #include "ecmascript/ecma_macros.h"
21 #include "ecmascript/dfx/hprof/file_stream.h"
22 #include "ecmascript/dfx/hprof/heap_profiler_interface.h"
23 #include "ecmascript/dfx/hprof/heap_snapshot_json_serializer.h"
24 #include "ecmascript/dfx/hprof/heap_tracker.h"
25 #include "ecmascript/dfx/hprof/heap_sampling.h"
26 #include "ecmascript/dfx/hprof/progress.h"
27 #include "ecmascript/dfx/hprof/string_hashmap.h"
28 #include "ecmascript/dfx/hprof/heap_marker.h"
29 #include "ecmascript/mem/c_containers.h"
30 #include "ecmascript/mem/clock_scope.h"
31 
32 namespace panda::ecmascript {
33 class HeapSnapshot;
34 class EcmaVM;
35 using NodeId = uint64_t;
36 
37 class EntryIdMap {
38 public:
39     EntryIdMap() = default;
40     ~EntryIdMap() = default;
41     NO_COPY_SEMANTIC(EntryIdMap);
42     NO_MOVE_SEMANTIC(EntryIdMap);
43 
44     static constexpr uint64_t SEQ_STEP = 2;
45     std::pair<bool, NodeId> FindId(JSTaggedType addr);
46     NodeId FindOrInsertNodeId(JSTaggedType addr);
47     bool InsertId(JSTaggedType addr, NodeId id);
48     bool EraseId(JSTaggedType addr);
49     bool Move(JSTaggedType oldAddr, JSTaggedType forwardAddr);
50     void UpdateEntryIdMap(HeapSnapshot *snapshot);
51     void RemoveUnmarkedObjects(HeapMarker &marker);
GetNextId()52     NodeId GetNextId()
53     {
54         nextId_ += SEQ_STEP;
55         return nextId_ - SEQ_STEP;
56     }
GetLastId()57     NodeId GetLastId()
58     {
59         return nextId_ - SEQ_STEP;
60     }
GetIdCount()61     size_t GetIdCount()
62     {
63         return idMap_.size();
64     }
GetIdMap()65     CUnorderedMap<JSTaggedType, NodeId>* GetIdMap()
66     {
67         return &idMap_;
68     }
GetId()69     NodeId GetId()
70     {
71         return nextId_;
72     }
SetId(NodeId id)73     void SetId(NodeId id)
74     {
75         nextId_ = id;
76     }
77 
78 private:
79     NodeId nextId_ {3U};  // 1 Reversed for SyntheticRoot
80     CUnorderedMap<JSTaggedType, NodeId> idMap_ {};
81 };
82 
83 struct ScopeWrapper {
84     LocalScope *localScope_ {nullptr};
85     EcmaHandleScope *ecmaHandleScope_ {nullptr};
86     ClockScope clockScope_;
87 
ScopeWrapperScopeWrapper88     ScopeWrapper(LocalScope *localScope, EcmaHandleScope *ecmaHandleScope)
89         : localScope_(localScope), ecmaHandleScope_(ecmaHandleScope) {}
90 };
91 
92 enum class DumpHeapSnapshotStatus : uint8_t {
93     SUCCESS,
94     FORK_FAILED,
95     FAILED_TO_WAIT,
96     WAIT_FORK_PROCESS_TIMEOUT,
97 };
98 
99 class HeapProfiler : public HeapProfilerInterface {
100 public:
101     NO_MOVE_SEMANTIC(HeapProfiler);
102     NO_COPY_SEMANTIC(HeapProfiler);
103     explicit HeapProfiler(const EcmaVM *vm);
104     ~HeapProfiler() override;
105 
106     enum class SampleType { ONE_SHOT, REAL_TIME };
107 
108     void AllocationEvent(TaggedObject *address, size_t size) override;
109     void MoveEvent(uintptr_t address, TaggedObject *forwardAddress, size_t size) override;
110     /**
111      * dump the specific snapshot in target format
112      */
113     bool DumpHeapSnapshot(Stream *stream, const DumpSnapShotOption &dumpOption, Progress *progress = nullptr,
114                           std::function<void(uint8_t)> callback = [] (uint8_t) {}) override;
115     void DumpHeapSnapshotForOOM(const DumpSnapShotOption &dumpOption, bool fromSharedGC = false) override;
116     void AddSnapshot(HeapSnapshot *snapshot);
117 
118     bool StartHeapTracking(double timeInterval, bool isVmMode = true, Stream *stream = nullptr,
119                            bool traceAllocation = false, bool newThread = true) override;
120     bool StopHeapTracking(Stream *stream, Progress *progress = nullptr, bool newThread = true) override;
121     bool UpdateHeapTracking(Stream *stream) override;
122     bool StartHeapSampling(uint64_t samplingInterval, int stackDepth = 128) override;
123     void StopHeapSampling() override;
124     const struct SamplingInfo *GetAllocationProfile() override;
GetIdCount()125     size_t GetIdCount() override
126     {
127         return entryIdMap_->GetIdCount();
128     }
GetEntryIdMap()129     EntryIdMap *GetEntryIdMap() const
130     {
131         return const_cast<EntryIdMap *>(entryIdMap_);
132     }
GetChunk()133     Chunk *GetChunk() const
134     {
135         return const_cast<Chunk *>(&chunk_);
136     }
GetEcmaStringTable()137     StringHashMap *GetEcmaStringTable() const
138     {
139         return const_cast<StringHashMap *>(&stringTable_);
140     }
141 
142     bool IsStartLocalHandleLeakDetect() const;
143     void SwitchStartLocalHandleLeakDetect();
144     void IncreaseScopeCount();
145     void DecreaseScopeCount();
146     void PushToActiveScopeStack(LocalScope *localScope, EcmaHandleScope *ecmaHandleScope);
147     void PopFromActiveScopeStack();
148     void ClearHandleBackTrace();
149     std::string_view GetBackTraceOfHandle(uintptr_t handle) const;
150     void WriteToLeakStackTraceFd(std::ostringstream &buffer) const;
151     void SetLeakStackTraceFd(int32_t fd);
152     int32_t GetLeakStackTraceFd() const;
153     void CloseLeakStackTraceFd();
154     void StorePotentiallyLeakHandles(uintptr_t handle);
155 
156 private:
157     /**
158      * trigger full gc to make sure no unreachable objects in heap
159      */
160     bool ForceFullGC(const EcmaVM *vm);
161     void ForceSharedGC();
162     void DumpHeapSnapshotFromSharedGC(Stream *stream, const DumpSnapShotOption &dumpOption);
163 
164     /**
165      * make a new heap snapshot and put it into a container eg, vector
166      */
167     HeapSnapshot *MakeHeapSnapshot(SampleType sampleType, const DumpSnapShotOption &dumpOption,
168                                    bool traceAllocation = false);
169     bool DoDump(Stream *stream, Progress *progress, const DumpSnapShotOption &dumpOption);
170     std::string GenDumpFileName(DumpFormat dumpFormat);
171     CString GetTimeStamp();
172     void UpdateHeapObjects(HeapSnapshot *snapshot);
173     void ClearSnapshot();
174     void FillIdMap();
175     bool BinaryDump(Stream *stream, const DumpSnapShotOption &dumpOption);
176 
177     uint32_t GetScopeCount() const;
178     std::shared_ptr<ScopeWrapper> GetLastActiveScope() const;
179     bool InsertHandleBackTrace(uintptr_t handle, const std::string &backTrace);
180     const std::string RAWHEAP_FILE_NAME = "/data/log/faultlog/temp/jsheap.rawheap";
181 
182     const size_t MAX_NUM_HPROF = 5;  // ~10MB
183     const EcmaVM *vm_;
184     CVector<HeapSnapshot *> hprofs_;
185     StringHashMap stringTable_;
186     bool isProfiling_ {false};
187     EntryIdMap *entryIdMap_;
188     std::unique_ptr<HeapTracker> heapTracker_;
189     Chunk chunk_;
190     std::unique_ptr<HeapSampling> heapSampling_ {nullptr};
191     Mutex mutex_;
192 
193     static const long LOCAL_HANDLE_LEAK_TIME_MS {5000};
194     bool startLocalHandleLeakDetect_ {false};
195     uint32_t scopeCount_ {0};
196     std::stack<std::shared_ptr<ScopeWrapper>> activeScopeStack_;
197     std::map<uintptr_t, std::string> handleBackTrace_;
198     int32_t leakStackTraceFd_ {-1};
199     uint32_t moveEventCbId_ {0};
200 
201     friend class HeapProfilerFriendTest;
202 };
203 }  // namespace panda::ecmascript
204 #endif  // ECMASCRIPT_DFX_HPROF_HEAP_PROFILER_H
205