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