• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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