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 uint32_t objSize; 82 uint32_t offset; // offset to the file 83 }; 84 85 #define PER_GROUP_MEM_SIZE (128 * 1024 * 1024) // 128 MB 86 #define HEAD_NUM_PER_GROUP (PER_GROUP_MEM_SIZE / sizeof(AddrTableItem)) 87 #define VERSION_ID_SIZE 8 88 #define MAX_FILE_SIZE (4 * 1024 * 1024 * 1024ULL) // 4 * 1024 * 1024 * 1024 : file size bigger than 4GB 89 #define MAX_OBJ_SIZE (MAX_FILE_SIZE >> 1) 90 91 struct NewAddr { 92 char *data; 93 uint32_t objSize; 94 NewAddrNewAddr95 NewAddr(uint32_t actSize, uint32_t objSize) : objSize(objSize) 96 { 97 if (actSize == 0 || actSize > MAX_OBJ_SIZE) { 98 LOG_ECMA(ERROR) << "ark raw heap decode abnormal obj size=" << actSize; 99 data = nullptr; 100 return; 101 } 102 data = new char[actSize]; 103 } ~NewAddrNewAddr104 ~NewAddr() 105 { 106 delete[] data; 107 } DataNewAddr108 char *Data() 109 { 110 return data; 111 } 112 }; 113 114 class HeapProfiler : public HeapProfilerInterface { 115 public: 116 NO_MOVE_SEMANTIC(HeapProfiler); 117 NO_COPY_SEMANTIC(HeapProfiler); 118 explicit HeapProfiler(const EcmaVM *vm); 119 ~HeapProfiler() override; 120 121 enum class SampleType { ONE_SHOT, REAL_TIME }; 122 123 void AllocationEvent(TaggedObject *address, size_t size) override; 124 void MoveEvent(uintptr_t address, TaggedObject *forwardAddress, size_t size) override; 125 /** 126 * dump the specific snapshot in target format 127 */ 128 bool DumpHeapSnapshot(Stream *stream, const DumpSnapShotOption &dumpOption, Progress *progress = nullptr) override; 129 void DumpHeapSnapshot(const DumpSnapShotOption &dumpOption) override; 130 void AddSnapshot(HeapSnapshot *snapshot); 131 132 bool StartHeapTracking(double timeInterval, bool isVmMode = true, Stream *stream = nullptr, 133 bool traceAllocation = false, bool newThread = true) override; 134 bool StopHeapTracking(Stream *stream, Progress *progress = nullptr, bool newThread = true) override; 135 bool UpdateHeapTracking(Stream *stream) override; 136 bool StartHeapSampling(uint64_t samplingInterval, int stackDepth = 128) override; 137 void StopHeapSampling() override; 138 const struct SamplingInfo *GetAllocationProfile() override; GetIdCount()139 size_t GetIdCount() override 140 { 141 return entryIdMap_->GetIdCount(); 142 } GetEntryIdMap()143 EntryIdMap *GetEntryIdMap() const 144 { 145 return const_cast<EntryIdMap *>(entryIdMap_); 146 } GetChunk()147 Chunk *GetChunk() const 148 { 149 return const_cast<Chunk *>(&chunk_); 150 } GetEcmaStringTable()151 StringHashMap *GetEcmaStringTable() const 152 { 153 return const_cast<StringHashMap *>(&stringTable_); 154 } 155 bool GenerateHeapSnapshot(std::string &inputFilePath, std::string &outputPath) override; 156 157 private: 158 /** 159 * trigger full gc to make sure no unreachable objects in heap 160 */ 161 bool ForceFullGC(const EcmaVM *vm); 162 void ForceSharedGC(); 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 uint32_t WriteToBinFile(Stream *stream, char *objTab, uint32_t objNum, 177 CVector<std::pair<char *, uint32_t>> &memBuf); 178 uint32_t CopyObjectMem2Buf(char *objTable, uint32_t objNum, CVector<std::pair<char *, uint32_t>> &memBufVec); 179 uint32_t GenObjTable(CUnorderedMap<char *, uint32_t> &headerMap, HeapSnapshot *snapshot, 180 CUnorderedMap<uint64_t, CVector<uint64_t>> &strIdMapObjVec); 181 uint32_t GenRootTable(Stream *stream); 182 bool DumpRawHeap(Stream *stream, uint32_t &fileOffset, CVector<uint32_t> &secIndexVec); 183 184 const size_t MAX_NUM_HPROF = 5; // ~10MB 185 const EcmaVM *vm_; 186 CVector<HeapSnapshot *> hprofs_; 187 StringHashMap stringTable_; 188 bool isProfiling_ {false}; 189 EntryIdMap* entryIdMap_; 190 std::unique_ptr<HeapTracker> heapTracker_; 191 Chunk chunk_; 192 std::unique_ptr<HeapSampling> heapSampling_ {nullptr}; 193 Mutex mutex_; 194 friend class HeapProfilerFriendTest; 195 }; 196 } // namespace panda::ecmascript 197 #endif // ECMASCRIPT_DFX_HPROF_HEAP_PROFILER_H 198