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 29namespace panda::ecmascript { 30class HeapSnapshot; 31class EcmaVM; 32using NodeId = uint64_t; 33 34class EntryIdMap { 35public: 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); 47 NodeId GetNextId() 48 { 49 nextId_ += SEQ_STEP; 50 return nextId_ - SEQ_STEP; 51 } 52 NodeId GetLastId() 53 { 54 return nextId_ - SEQ_STEP; 55 } 56 size_t GetIdCount() 57 { 58 return idMap_.size(); 59 } 60 CUnorderedMap<JSTaggedType, NodeId>* GetIdMap() 61 { 62 return &idMap_; 63 } 64 NodeId GetId() 65 { 66 return nextId_; 67 } 68 void SetId(NodeId id) 69 { 70 nextId_ = id; 71 } 72 73private: 74 NodeId nextId_ {3U}; // 1 Reversed for SyntheticRoot 75 CUnorderedMap<JSTaggedType, NodeId> idMap_ {}; 76}; 77 78struct 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 86struct RawHeapObjInfo { 87 AddrTableItem *tInfo; 88 char *newAddr; 89 bool isRoot; 90 CUnorderedSet<uint64_t> refSet; 91}; 92 93struct RawHeapInfoArgs { 94 CVector<RawHeapObjInfo *> rawObjInfoVec; 95 CUnorderedMap<uint64_t, RawHeapObjInfo *> oldAddrMapObjInfo; 96 CUnorderedMap<uint64_t, const char *> strTableIdMapNewStr; 97}; 98 99class ChunkDecoder { 100public: 101 explicit ChunkDecoder(char *mAddr, uint64_t fSize); 102 103 ~ChunkDecoder() 104 { 105 auto &objInfoVec = rawHeapArgs.rawObjInfoVec; 106 for (auto obj : objInfoVec) { 107 delete obj; 108 } 109 } 110 111 RawHeapInfoArgs &GetRawHeapInfoArgs() 112 { 113 return rawHeapArgs; 114 } 115 116private: 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 128class HeapProfiler : public HeapProfilerInterface { 129public: 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 } 157 EntryIdMap *GetEntryIdMap() const 158 { 159 return const_cast<EntryIdMap *>(entryIdMap_); 160 } 161 Chunk *GetChunk() const 162 { 163 return const_cast<Chunk *>(&chunk_); 164 } 165 StringHashMap *GetEcmaStringTable() const 166 { 167 return const_cast<StringHashMap *>(&stringTable_); 168 } 169 bool GenerateHeapSnapshot(std::string &inputFilePath, std::string &outputPath) override; 170 171private: 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