• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #ifndef HIPERF_VIRTUAL_RUNTIME_H
16 #define HIPERF_VIRTUAL_RUNTIME_H
17 
18 #include <functional>
19 #include <fstream>
20 #if defined(is_ohos) && is_ohos
21 #include "callstack.h"
22 #endif
23 #include "hashlist.h"
24 #include "perf_event_record.h"
25 #include "symbols_file.h"
26 #include "virtual_thread.h"
27 
28 namespace OHOS {
29 namespace Developtools {
30 namespace HiPerf {
31 /*
32 This Class contains userspace thread objects. and kernel space objects
33 It represents a virtual operating environment, mainly referring to the relationship between pid,
34 mmaps, and symbols.
35 
36 It mainly receives data is ip pointer (virtual address), pid
37 According to these data, it will find the corresponding mmap and its corresponding elf (also called
38 DSO)
39 
40 Then find the corresponding symbol in the corresponding elf symbol file according to the offset
41 recorded in the corresponding mmap.
42 */
43 using kSymbolsHits = std::unordered_set<uint64_t>;
44 using uSymbolsHits = std::unordered_map<pid_t, std::unordered_set<uint64_t>>;
45 
46 class VirtualRuntime {
47 public:
48     explicit VirtualRuntime(const bool onDevice = true);
49     ~VirtualRuntime();
50     // thread need hook the record
51     // from the record , it will call back to write some Simulated Record
52     // case 1. some mmap will be create when it read mmaps for each new process (from record sample)
53 
54     using RecordCallBack = std::function<bool(PerfEventRecord&)>;
55     using CollectSymbolCallBack = std::function<void(PerfRecordSample*)>;
56 
57     void SetRecordMode(const RecordCallBack &recordCallBack);
58     void SetCollectSymbolCallBack(const CollectSymbolCallBack &collectSymbolCallBack);
59 
60     // this both used in report and record follow
61     // it process the record, and rebuild the trhread maps
62     // It internally determines whether to go to the Record process (which will generate virtual
63     // events) or the Report process by judging whether SetRecordMode has been passed.
64     void UpdateFromRecord(PerfEventRecord &record);
65     void NeedDropKernelCallChain(PerfRecordSample &sample);
66     // in reocrd mode
67     // we make a kernel symbols from some proc file
68     void UpdateKernelSpaceMaps();
69     void UpdateKernelModulesSpaceMaps();
70     void UpdateServiceSpaceMaps();
71     void UpdateDevhostSpaceMaps();
72     // load vdso
73     void LoadVdso();
74 
75     void UpdateKernelSymbols();
76     void UpdateKernelModulesSymbols();
77     void UpdateServiceSymbols();
78     void UpdateDevhostSymbols();
79 
80     pid_t devhostPid_ = -1;
81     void SetDevhostPid(const pid_t devhost);
82     void FixHMBundleMmap(char *filename, const int pid, u16 &headerSize);
83 
84     // set symbols path , it will send to every symobile file for search
85     bool SetSymbolsPaths(const std::vector<std::string> &symbolsPaths);
86 
87     // any mode
88     static_assert(sizeof(pid_t) == sizeof(int));
89 
GetSymbolsFiles()90     const std::vector<std::unique_ptr<SymbolsFile>> &GetSymbolsFiles() const
91     {
92         return symbolsFiles_;
93     }
94 
GetUniStackTable()95     const ProcessStackMap* GetUniStackTable()
96     {
97         return &processStackMap_;
98     }
99 
100     void SetCallStackExpend(const size_t mergeLevel = 0)
101     {
102         callstackMergeLevel_ = mergeLevel;
103     }
104 
SetDisableUnwind(const bool disableUnwind)105     void SetDisableUnwind(const bool disableUnwind)
106     {
107         HLOGV("disableUnwind change to %d", disableUnwind);
108         disableUnwind_ = disableUnwind;
109     }
110 
EnableDebugInfoSymbolic(const bool enable)111     void EnableDebugInfoSymbolic(const bool enable)
112     {
113         enableDebugInfoSymbolic_ = enable;
114     }
SetDedupStack()115     void SetDedupStack()
116     {
117         dedupStack_ = true;
118     }
119 
120     void ImportUniqueStackNodes(const std::vector<UniStackTableInfo>&);
121 
122     bool isHM_ = false;
SetHM(bool isHM)123     void SetHM(bool isHM)
124     {
125         isHM_ = isHM;
126     }
127 
SetNeedKernelCallChain(const bool kernelCallChain)128     void SetNeedKernelCallChain(const bool kernelCallChain)
129     {
130         needkernelCallChain_ = kernelCallChain;
131     }
132     DfxSymbol GetSymbol(const uint64_t ip, const pid_t pid, const pid_t tid,
133                            const perf_callchain_context &context = PERF_CONTEXT_MAX);
134     void ClearSymbolCache();
135 
136     VirtualThread &GetThread(const pid_t pid, const pid_t tid, const std::string name = "");
GetThreads()137     const std::map<pid_t, VirtualThread> &GetThreads() const
138     {
139         return userSpaceThreadMap_;
140     }
141     void SymbolicRecord(PerfRecordSample &recordSample);
142     void SymbolSpeRecord(PerfRecordAuxtrace &recordAuxTrace);
143 
144     // report use
145     void UpdateFromPerfData(const std::vector<SymbolFileStruct> &);
146     void UnwindFromRecord(PerfRecordSample &recordSample);
147     std::string ReadThreadName(const pid_t tid, const bool isThread);
148     std::string ReadFromSavedCmdLines(const pid_t tid);
149     bool IsKernelThread(const pid_t pid);
150     void CollectDedupSymbol(kSymbolsHits &kernelSymbolsHits,
151                             uSymbolsHits &userSymbolsHits);
152     // debug time
153 #ifdef HIPERF_DEBUG_TIME
154     std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero();
155     std::chrono::microseconds unwindFromRecordTimes_ = std::chrono::microseconds::zero();
156     std::chrono::microseconds unwindCallStackTimes_ = std::chrono::microseconds::zero();
157     std::chrono::microseconds symbolicRecordTimes_ = std::chrono::microseconds::zero();
158     std::chrono::microseconds updateThreadTimes_ = std::chrono::microseconds::zero();
159     std::chrono::microseconds processSampleRecordTimes_ = std::chrono::microseconds::zero();
160     std::chrono::microseconds processMmapRecordTimes_ = std::chrono::microseconds::zero();
161     std::chrono::microseconds processMmap2RecordTimes_ = std::chrono::microseconds::zero();
162     std::chrono::microseconds processCommRecordTimes_ = std::chrono::microseconds::zero();
163     std::chrono::microseconds threadParseMapsTimes_ = std::chrono::microseconds::zero();
164     std::chrono::microseconds threadCreateMmapTimes_ = std::chrono::microseconds::zero();
165 #endif
166     const bool loadSymboleWhenNeeded_ = true; // this is a feature config
167 
168 private:
169     bool needkernelCallChain_ = false;
170     bool disableUnwind_ = true;
171     bool enableDebugInfoSymbolic_ = false;
172     bool dedupStack_ = false;
173     const bool isRoot_ = IsRoot();
174     size_t callstackMergeLevel_ = 1;
175     std::ifstream savedCmdLines_;
176 #if defined(is_ohos) && is_ohos
177     CallStack callstack_;
178 #endif
179     // pid map with user space thread
180     std::map<pid_t, VirtualThread> userSpaceThreadMap_;
181     // not pid , just memmap
182     std::vector<DfxMap> kernelSpaceMemMaps_;
183     ProcessStackMap processStackMap_;
184     RecordCallBack recordCallBack_;
185     CollectSymbolCallBack collectSymbolCallBack_;
186     std::vector<std::unique_ptr<SymbolsFile>> symbolsFiles_;
187     enum SymbolCacheLimit : std::size_t {
188         KERNEL_SYMBOL_CACHE_LIMIT = 4000,
189         USER_SYMBOL_CACHE_LIMIT = 4000,
190     };
191     HashList<uint64_t, DfxSymbol> userSymbolCache_;
192     HashList<uint64_t, DfxSymbol> kernelSymbolCache_ {KERNEL_SYMBOL_CACHE_LIMIT};
193     HashList<uint64_t, DfxSymbol> kThreadSymbolCache_ {KERNEL_SYMBOL_CACHE_LIMIT};
194     bool GetSymbolCache(const uint64_t fileVaddr, DfxSymbol &symbol,
195                         const perf_callchain_context &context);
196     // find synbols function name
197     void MakeCallFrame(DfxSymbol &symbol, DfxFrame &callFrame);
198     void UpdateSymbols(std::shared_ptr<DfxMap> map, const pid_t pid);
199     // we don't know whether hap vma mapping is stand for a so
200     // thus we need try to parse it first
201     bool UpdateHapSymbols(std::shared_ptr<DfxMap> map);
202     void UpdateFromRecord(PerfRecordSample &recordSample);
203     void UpdateFromRecord(PerfRecordMmap &recordMmap);
204     void UpdateFromRecord(PerfRecordMmap2 &recordMmap2);
205     void UpdateFromRecord(PerfRecordComm &recordComm);
206     void DedupFromRecord(PerfRecordSample *recordSample);
207     void UpdateFromRecord(PerfRecordAuxtrace &recordAuxTrace);
208     // threads
209     VirtualThread &UpdateThread(const pid_t pid, const pid_t tid, const std::string name = "");
210     VirtualThread &CreateThread(const pid_t pid, const pid_t tid, const std::string name = "");
211 
212     // maps
213     std::shared_ptr<DfxMap> UpdateThreadMaps(const pid_t pid, const pid_t tid, const std::string filename,
214                                              const uint64_t begin, const uint64_t len, const uint64_t offset,
215                                              const uint32_t prot = 0);
216     void UpdatekernelMap(const uint64_t begin, const uint64_t end, const uint64_t offset, const std::string &filename);
217 
218     const DfxSymbol GetKernelSymbol(const uint64_t ip, const std::vector<DfxMap> &memMaps,
219                                     const VirtualThread &thread);
220     const DfxSymbol GetUserSymbol(const uint64_t ip, const VirtualThread &thread);
221     const DfxSymbol GetKernelThreadSymbol(const uint64_t ip, const VirtualThread &thread);
222 #ifdef HIPERF_DEBUG
223     std::unordered_set<uint64_t> missedRuntimeVaddr_;
224 #endif
225     void SymbolicCallFrame(PerfRecordSample &recordSample, const uint64_t ip,
226                            const pid_t serverPid, const perf_callchain_context context);
227     bool RecoverCallStack(PerfRecordSample &recordSample);
228     std::vector<std::string> symbolsPaths_;
229 
230     // kernel thread
231     void UpdateKernelThreadMap(const pid_t pid, const uint64_t begin, const uint64_t len,
232                                const uint64_t offset, const std::string &filename);
233     bool CheckValidSandBoxMmap(PerfRecordMmap2 &recordMmap2);
234     void ProcessKernelCallChain(PerfRecordSample &sample);
235     void AdjustCallChain(PerfRecordSample &sample);
236 };
237 } // namespace HiPerf
238 } // namespace Developtools
239 } // namespace OHOS
240 #endif // HIPERF_VIRTUAL_RUNTIME_H
241