• 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(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(std::unique_ptr<PerfEventRecord>)>;
55     using CollectSymbolCallBack = std::function<void(PerfRecordSample*)>;
56 
57     void SetRecordMode(RecordCallBack recordCallBack);
58     void SetCollectSymbolCallBack(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(pid_t devhost);
82     void FixHMBundleMmap(char *filename, 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(size_t mergeLevel = 0)
101     {
102         callstackMergeLevel_ = mergeLevel;
103     }
104 
SetDisableUnwind(bool disableUnwind)105     void SetDisableUnwind(bool disableUnwind)
106     {
107         HLOGV("disableUnwind change to %d", disableUnwind);
108         disableUnwind_ = disableUnwind;
109     }
110 
EnableDebugInfoSymbolic(bool enable)111     void EnableDebugInfoSymbolic(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(bool kernelCallChain)128     void SetNeedKernelCallChain(bool kernelCallChain)
129     {
130         needkernelCallChain_ = kernelCallChain;
131     }
132     DfxSymbol GetSymbol(uint64_t ip, pid_t pid, pid_t tid,
133                            const perf_callchain_context &context = PERF_CONTEXT_MAX);
134 
135     VirtualThread &GetThread(pid_t pid, pid_t tid, const std::string name = "");
GetThreads()136     const std::map<pid_t, VirtualThread> &GetThreads() const
137     {
138         return userSpaceThreadMap_;
139     }
140     void SymbolicRecord(PerfRecordSample &recordSample);
141 
142     // report use
143     void UpdateFromPerfData(const std::vector<SymbolFileStruct> &);
144     void UnwindFromRecord(PerfRecordSample &recordSample);
145     std::string ReadThreadName(pid_t tid, bool isThread);
146     std::string ReadFromSavedCmdLines(pid_t tid);
147     bool IsKernelThread(pid_t pid);
148     void CollectDedupSymbol(kSymbolsHits &kernelSymbolsHits,
149                             uSymbolsHits &userSymbolsHits);
150     // debug time
151 #ifdef HIPERF_DEBUG_TIME
152     std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero();
153     std::chrono::microseconds unwindFromRecordTimes_ = std::chrono::microseconds::zero();
154     std::chrono::microseconds unwindCallStackTimes_ = std::chrono::microseconds::zero();
155     std::chrono::microseconds symbolicRecordTimes_ = std::chrono::microseconds::zero();
156     std::chrono::microseconds updateThreadTimes_ = std::chrono::microseconds::zero();
157     std::chrono::microseconds processSampleRecordTimes_ = std::chrono::microseconds::zero();
158     std::chrono::microseconds processMmapRecordTimes_ = std::chrono::microseconds::zero();
159     std::chrono::microseconds processMmap2RecordTimes_ = std::chrono::microseconds::zero();
160     std::chrono::microseconds processCommRecordTimes_ = std::chrono::microseconds::zero();
161     std::chrono::microseconds threadParseMapsTimes_ = std::chrono::microseconds::zero();
162     std::chrono::microseconds threadCreateMmapTimes_ = std::chrono::microseconds::zero();
163 #endif
164     const bool loadSymboleWhenNeeded_ = true; // this is a feature config
165 
166 private:
167     bool needkernelCallChain_ = false;
168     bool disableUnwind_ = true;
169     bool enableDebugInfoSymbolic_ = false;
170     bool dedupStack_ = false;
171     size_t callstackMergeLevel_ = 1;
172     std::ifstream savedCmdLines_;
173 #if defined(is_ohos) && is_ohos
174     CallStack callstack_;
175 #endif
176     // pid map with user space thread
177     std::map<pid_t, VirtualThread> userSpaceThreadMap_;
178     // not pid , just memmap
179     std::vector<DfxMap> kernelSpaceMemMaps_;
180     ProcessStackMap processStackMap_;
181     RecordCallBack recordCallBack_;
182     CollectSymbolCallBack collectSymbolCallBack_;
183     std::vector<std::unique_ptr<SymbolsFile>> symbolsFiles_;
184     enum SymbolCacheLimit : std::size_t {
185         KERNEL_SYMBOL_CACHE_LIMIT = 4000,
186         USER_SYMBOL_CACHE_LIMIT = 4000,
187     };
188     HashList<uint64_t, DfxSymbol> userSymbolCache_;
189     HashList<uint64_t, DfxSymbol> kernelSymbolCache_ {KERNEL_SYMBOL_CACHE_LIMIT};
190     HashList<uint64_t, DfxSymbol> kThreadSymbolCache_ {KERNEL_SYMBOL_CACHE_LIMIT};
191     bool GetSymbolCache(uint64_t fileVaddr, DfxSymbol &symbol,
192                         const perf_callchain_context &context);
193     // find synbols function name
194     void MakeCallFrame(DfxSymbol &symbol, DfxFrame &callFrame);
195     void UpdateSymbols(std::shared_ptr<DfxMap> map, pid_t pid);
196     // we don't know whether hap vma mapping is stand for a so
197     // thus we need try to parse it first
198     bool UpdateHapSymbols(std::shared_ptr<DfxMap> map);
199     void UpdateFromRecord(PerfRecordSample &recordSample);
200     void UpdateFromRecord(PerfRecordMmap &recordMmap);
201     void UpdateFromRecord(PerfRecordMmap2 &recordMmap2);
202     void UpdateFromRecord(PerfRecordComm &recordComm);
203     void DedupFromRecord(PerfRecordSample *recordSample);
204     // threads
205     VirtualThread &UpdateThread(pid_t pid, pid_t tid, const std::string name = "");
206     VirtualThread &CreateThread(pid_t pid, pid_t tid, const std::string name = "");
207 
208     // maps
209     std::shared_ptr<DfxMap> UpdateThreadMaps(pid_t pid, pid_t tid, const std::string filename, uint64_t begin,
210                           uint64_t len, uint64_t offset, uint32_t prot = 0);
211     void UpdatekernelMap(uint64_t begin, uint64_t end, uint64_t offset, std::string filename);
212 
213     const DfxSymbol GetKernelSymbol(uint64_t ip, const std::vector<DfxMap> &memMaps,
214                                  const VirtualThread &thread);
215     const DfxSymbol GetUserSymbol(uint64_t ip, const VirtualThread &thread);
216     const DfxSymbol GetKernelThreadSymbol(uint64_t ip, const VirtualThread &thread);
217 #ifdef HIPERF_DEBUG
218     std::unordered_set<uint64_t> missedRuntimeVaddr_;
219 #endif
220     void SymbolicCallFrame(PerfRecordSample &recordSample, uint64_t ip,
221                            pid_t serverPid, perf_callchain_context context);
222     bool RecoverCallStack(PerfRecordSample &recordSample);
223     std::vector<std::string> symbolsPaths_;
224 
225     // kernel thread
226     void UpdateKernelThreadMap(pid_t pid, uint64_t begin, uint64_t len, std::string filename);
227 
228     FRIEND_TEST(VirtualRuntimeTest, SetRecordMode);
229     FRIEND_TEST(VirtualRuntimeTest, UpdateKernelSymbols);
230     FRIEND_TEST(VirtualRuntimeTest, UpdateKernelModulesSymbols);
231     FRIEND_TEST(VirtualRuntimeTest, SetCallStackExpend);
232     FRIEND_TEST(VirtualRuntimeTest, SetDisableUnwind);
233     FRIEND_TEST(VirtualRuntimeTest, UnwindFromRecord);
234     friend class VirtualRuntimeTest;
235 
236     bool CheckValidSandBoxMmap(PerfRecordMmap2 &recordMmap2);
237 };
238 } // namespace HiPerf
239 } // namespace Developtools
240 } // namespace OHOS
241 #endif // HIPERF_VIRTUAL_RUNTIME_H
242