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 "ecmascript/ecma_macros.h" 20 #include "ecmascript/dfx/hprof/file_stream.h" 21 #include "ecmascript/dfx/hprof/heap_profiler_interface.h" 22 #include "ecmascript/dfx/hprof/heap_snapshot_json_serializer.h" 23 #include "ecmascript/dfx/hprof/heap_tracker.h" 24 #include "ecmascript/dfx/hprof/heap_sampling.h" 25 #include "ecmascript/dfx/hprof/progress.h" 26 #include "ecmascript/dfx/hprof/string_hashmap.h" 27 #include "ecmascript/mem/c_containers.h" 28 29 namespace panda::ecmascript { 30 class HeapSnapshot; 31 class EcmaVM; 32 using NodeId = uint64_t; 33 34 class EntryIdMap { 35 public: 36 EntryIdMap() = default; 37 ~EntryIdMap() = default; 38 NO_COPY_SEMANTIC(EntryIdMap); 39 NO_MOVE_SEMANTIC(EntryIdMap); 40 41 static constexpr uint64_t SEQ_STEP = 2; 42 std::pair<bool, NodeId> FindId(JSTaggedType addr); 43 bool InsertId(JSTaggedType addr, NodeId id); 44 bool EraseId(JSTaggedType addr); 45 bool Move(JSTaggedType oldAddr, JSTaggedType forwardAddr); 46 void UpdateEntryIdMap(HeapSnapshot *snapshot); GetNextId()47 NodeId GetNextId() 48 { 49 nextId_ += SEQ_STEP; 50 return nextId_ - SEQ_STEP; 51 } GetLastId()52 NodeId GetLastId() 53 { 54 return nextId_ - SEQ_STEP; 55 } GetIdCount()56 size_t GetIdCount() 57 { 58 return idMap_.size(); 59 } GetIdMap()60 CUnorderedMap<JSTaggedType, NodeId>* GetIdMap() 61 { 62 return &idMap_; 63 } GetId()64 NodeId GetId() 65 { 66 return nextId_; 67 } SetId(NodeId id)68 void SetId(NodeId id) 69 { 70 nextId_ = id; 71 } 72 73 private: 74 NodeId nextId_ {3U}; // 1 Reversed for SyntheticRoot 75 CUnorderedMap<JSTaggedType, NodeId> idMap_ {}; 76 }; 77 78 struct AddrTableItem { 79 uint64_t addr; 80 uint64_t id; 81 uint64_t objSize; 82 uint64_t offset; // offset to the file 83 uint64_t stringId; 84 }; 85 86 struct RawHeapObjInfo { 87 AddrTableItem *tInfo; 88 char *newAddr; 89 bool isRoot; 90 CUnorderedSet<uint64_t> refSet; 91 }; 92 93 struct RawHeapInfoArgs { 94 CVector<RawHeapObjInfo *> rawObjInfoVec; 95 CUnorderedMap<uint64_t, RawHeapObjInfo *> oldAddrMapObjInfo; 96 CUnorderedMap<uint64_t, const char *> strTableIdMapNewStr; 97 }; 98 99 class ChunkDecoder { 100 public: 101 explicit ChunkDecoder(char *mAddr, uint64_t fSize); 102 ~ChunkDecoder()103 ~ChunkDecoder() 104 { 105 auto &objInfoVec = rawHeapArgs.rawObjInfoVec; 106 for (auto obj : objInfoVec) { 107 delete obj; 108 } 109 } 110 GetRawHeapInfoArgs()111 RawHeapInfoArgs &GetRawHeapInfoArgs() 112 { 113 return rawHeapArgs; 114 } 115 116 private: 117 void DecodeStrTable(const char *charPtr); 118 119 uint64_t heapObjCnt; 120 uint64_t rootObjCnt; 121 uint64_t shareObjCnt; 122 uint64_t strTableOffset; 123 RawHeapInfoArgs rawHeapArgs; 124 char *mapAddr; 125 uint64_t fileSize; 126 }; 127 128 class HeapProfiler : public HeapProfilerInterface { 129 public: 130 NO_MOVE_SEMANTIC(HeapProfiler); 131 NO_COPY_SEMANTIC(HeapProfiler); 132 explicit HeapProfiler(const EcmaVM *vm); 133 ~HeapProfiler() override; 134 135 enum class SampleType { ONE_SHOT, REAL_TIME }; 136 137 void AllocationEvent(TaggedObject *address, size_t size) override; 138 void MoveEvent(uintptr_t address, TaggedObject *forwardAddress, size_t size) override; 139 /** 140 * dump the specific snapshot in target format 141 */ 142 bool DumpHeapSnapshot(Stream *stream, const DumpSnapShotOption &dumpOption, Progress *progress = nullptr) override; 143 void DumpHeapSnapshot(const DumpSnapShotOption &dumpOption) override; 144 void AddSnapshot(HeapSnapshot *snapshot); 145 146 bool StartHeapTracking(double timeInterval, bool isVmMode = true, Stream *stream = nullptr, 147 bool traceAllocation = false, bool newThread = true) override; 148 bool StopHeapTracking(Stream *stream, Progress *progress = nullptr, bool newThread = true) override; 149 bool UpdateHeapTracking(Stream *stream) override; 150 bool StartHeapSampling(uint64_t samplingInterval, int stackDepth = 128) override; 151 void StopHeapSampling() override; 152 const struct SamplingInfo *GetAllocationProfile() override; 153 size_t GetIdCount() override 154 { 155 return entryIdMap_->GetIdCount(); 156 } GetEntryIdMap() const157 EntryIdMap *GetEntryIdMap() const 158 { 159 return const_cast<EntryIdMap *>(entryIdMap_); 160 } GetChunk() const161 Chunk *GetChunk() const 162 { 163 return const_cast<Chunk *>(&chunk_); 164 } GetEcmaStringTable() const165 StringHashMap *GetEcmaStringTable() const 166 { 167 return const_cast<StringHashMap *>(&stringTable_); 168 } 169 bool GenerateHeapSnapshot(std::string &inputFilePath, std::string &outputPath) override; 170 171 private: 172 /** 173 * trigger full gc to make sure no unreachable objects in heap 174 */ 175 bool ForceFullGC(const EcmaVM *vm); 176 void ForceSharedGC(); 177 178 /** 179 * make a new heap snapshot and put it into a container eg, vector 180 */ 181 HeapSnapshot *MakeHeapSnapshot(SampleType sampleType, const DumpSnapShotOption &dumpOption, 182 bool traceAllocation = false); 183 bool DoDump(Stream *stream, Progress *progress, const DumpSnapShotOption &dumpOption); 184 std::string GenDumpFileName(DumpFormat dumpFormat); 185 CString GetTimeStamp(); 186 void UpdateHeapObjects(HeapSnapshot *snapshot); 187 void ClearSnapshot(); 188 void FillIdMap(); 189 bool BinaryDump(Stream *stream, const DumpSnapShotOption &dumpOption); 190 191 const size_t MAX_NUM_HPROF = 5; // ~10MB 192 const EcmaVM *vm_; 193 CVector<HeapSnapshot *> hprofs_; 194 StringHashMap stringTable_; 195 bool isProfiling_ {false}; 196 EntryIdMap* entryIdMap_; 197 std::unique_ptr<HeapTracker> heapTracker_; 198 Chunk chunk_; 199 std::unique_ptr<HeapSampling> heapSampling_ {nullptr}; 200 Mutex mutex_; 201 }; 202 } // namespace panda::ecmascript 203 #endif // ECMASCRIPT_DFX_HPROF_HEAP_PROFILER_H 204