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 33 class EntryIdMap { 34 public: 35 EntryIdMap() = default; 36 ~EntryIdMap() = default; 37 NO_COPY_SEMANTIC(EntryIdMap); 38 NO_MOVE_SEMANTIC(EntryIdMap); 39 40 static constexpr uint32_t SEQ_STEP = 2; 41 std::pair<bool, uint32_t> FindId(JSTaggedType addr); 42 bool InsertId(JSTaggedType addr, uint32_t id); 43 bool EraseId(JSTaggedType addr); 44 bool Move(JSTaggedType oldAddr, JSTaggedType forwardAddr); 45 void UpdateEntryIdMap(HeapSnapshot *snapshot); GetNextId()46 uint32_t GetNextId() 47 { 48 nextId_ += SEQ_STEP; 49 return nextId_ - SEQ_STEP; 50 } GetLastId()51 uint32_t GetLastId() 52 { 53 return nextId_ - SEQ_STEP; 54 } GetIdCount()55 size_t GetIdCount() 56 { 57 return idMap_.size(); 58 } 59 60 private: 61 uint32_t nextId_ {3U}; // 1 Reversed for SyntheticRoot 62 CUnorderedMap<JSTaggedType, uint32_t> idMap_ {}; 63 }; 64 65 class HeapProfiler : public HeapProfilerInterface { 66 public: 67 NO_MOVE_SEMANTIC(HeapProfiler); 68 NO_COPY_SEMANTIC(HeapProfiler); 69 explicit HeapProfiler(const EcmaVM *vm); 70 ~HeapProfiler() override; 71 72 enum class SampleType { ONE_SHOT, REAL_TIME }; 73 74 void AllocationEvent(TaggedObject *address, size_t size) override; 75 void MoveEvent(uintptr_t address, TaggedObject *forwardAddress, size_t size) override; 76 /** 77 * dump the specific snapshot in target format 78 */ 79 bool DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progress *progress = nullptr, 80 bool isVmMode = true, bool isPrivate = false, bool captureNumericValue = false, 81 bool isFullGC = true) override; 82 void DumpHeapSnapshot(DumpFormat dumpFormat, bool isVmMode = true, bool isPrivate = false, 83 bool captureNumericValue = false, bool isFullGC = true) override; 84 void AddSnapshot(HeapSnapshot *snapshot); 85 86 bool StartHeapTracking(double timeInterval, bool isVmMode = true, Stream *stream = nullptr, 87 bool traceAllocation = false, bool newThread = true) override; 88 bool StopHeapTracking(Stream *stream, Progress *progress = nullptr, bool newThread = true) override; 89 bool UpdateHeapTracking(Stream *stream) override; 90 bool StartHeapSampling(uint64_t samplingInterval, int stackDepth = 128) override; 91 void StopHeapSampling() override; 92 const struct SamplingInfo *GetAllocationProfile() override; GetIdCount()93 size_t GetIdCount() override 94 { 95 return entryIdMap_->GetIdCount(); 96 } GetEntryIdMap()97 EntryIdMap *GetEntryIdMap() const 98 { 99 return const_cast<EntryIdMap *>(entryIdMap_); 100 } GetChunk()101 Chunk *GetChunk() const 102 { 103 return const_cast<Chunk *>(&chunk_); 104 } GetEcmaStringTable()105 StringHashMap *GetEcmaStringTable() const 106 { 107 return const_cast<StringHashMap *>(&stringTable_); 108 } 109 110 private: 111 /** 112 * trigger full gc to make sure no unreachable objects in heap 113 */ 114 bool ForceFullGC(const EcmaVM *vm); 115 116 /** 117 * make a new heap snapshot and put it into a container eg, vector 118 */ 119 HeapSnapshot *MakeHeapSnapshot(SampleType sampleType, bool isVmMode = true, 120 bool isPrivate = false, bool captureNumericValue = false, 121 bool traceAllocation = false, bool isFullGC = true); 122 std::string GenDumpFileName(DumpFormat dumpFormat); 123 CString GetTimeStamp(); 124 void UpdateHeapObjects(HeapSnapshot *snapshot); 125 void ClearSnapshot(); 126 127 const size_t MAX_NUM_HPROF = 5; // ~10MB 128 const EcmaVM *vm_; 129 CVector<HeapSnapshot *> hprofs_; 130 StringHashMap stringTable_; 131 bool isProfiling_ {false}; 132 EntryIdMap* entryIdMap_; 133 std::unique_ptr<HeapTracker> heapTracker_; 134 Chunk chunk_; 135 std::unique_ptr<HeapSampling> heapSampling_ {nullptr}; 136 Mutex mutex_; 137 }; 138 } // namespace panda::ecmascript 139 #endif // ECMASCRIPT_DFX_HPROF_HEAP_PROFILER_H 140