• 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.hpp"
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     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 collectSymboolCallBack);
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 &reocrd);
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 ip, DfxSymbol &symbol,
192                         const perf_callchain_context &context);
193     // find synbols function name
194     void MakeCallFrame(DfxSymbol &symbol, CallFrame &callFrame);
195     // records
196     void UpdateSymbols(std::string filename);
197     // we don't know whether hap vma mapping is stand for a so
198     // thus we need try to parse it first
199     bool UpdateHapSymbols(std::shared_ptr<DfxMap> map);
200     void UpdateFromRecord(PerfRecordSample &recordSample);
201     void UpdateFromRecord(PerfRecordMmap &recordMmap);
202     void UpdateFromRecord(PerfRecordMmap2 &recordMmap2);
203     void UpdateFromRecord(PerfRecordComm &recordComm);
204     void DedupFromRecord(PerfRecordSample *recordSample);
205     // threads
206     VirtualThread &UpdateThread(pid_t pid, pid_t tid, const std::string name = "");
207     VirtualThread &CreateThread(pid_t pid, pid_t tid, const std::string name = "");
208 
209     // maps
210     void UpdateThreadMaps(pid_t pid, pid_t tid, const std::string filename, uint64_t begin,
211                           uint64_t len, uint64_t offset);
212     void UpdatekernelMap(uint64_t begin, uint64_t end, uint64_t offset, std::string filename);
213 
214     const DfxSymbol GetKernelSymbol(uint64_t ip, const std::vector<DfxMap> &memMaps,
215                                  const VirtualThread &thread);
216     const DfxSymbol GetUserSymbol(uint64_t ip, const VirtualThread &thread);
217     const DfxSymbol GetKernelThreadSymbol(uint64_t ip, const VirtualThread &thread);
218 #ifdef HIPERF_DEBUG
219     std::unordered_set<uint64_t> missedRuntimeVaddr_;
220 #endif
221     void SymbolicCallFrame(PerfRecordSample &recordSample, uint64_t ip,
222                            pid_t server_pid, perf_callchain_context context);
223     bool RecoverCallStack(PerfRecordSample &recordSample);
224     std::vector<std::string> symbolsPaths_;
225 
226     // kernel thread
227     void UpdateKernelThreadMap(pid_t pid, uint64_t begin, uint64_t len, std::string filename);
228 
229     FRIEND_TEST(VirtualRuntimeTest, SetRecordMode);
230     FRIEND_TEST(VirtualRuntimeTest, UpdateKernelSymbols);
231     FRIEND_TEST(VirtualRuntimeTest, UpdateKernelModulesSymbols);
232     FRIEND_TEST(VirtualRuntimeTest, SetCallStackExpend);
233     FRIEND_TEST(VirtualRuntimeTest, SetDisableUnwind);
234     FRIEND_TEST(VirtualRuntimeTest, UnwindFromRecord);
235     friend class VirtualRuntimeTest;
236 
237     bool CheckValidSandBoxMmap(PerfRecordMmap2 &recordMmap2);
238 };
239 } // namespace HiPerf
240 } // namespace Developtools
241 } // namespace OHOS
242 #endif // HIPERF_VIRTUAL_RUNTIME_H
243