• 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(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     void ClearSymbolCache();
135 
136     VirtualThread &GetThread(pid_t pid, 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(pid_t tid, bool isThread);
148     std::string ReadFromSavedCmdLines(pid_t tid);
149     bool IsKernelThread(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(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, 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(pid_t pid, pid_t tid, const std::string name = "");
210     VirtualThread &CreateThread(pid_t pid, pid_t tid, const std::string name = "");
211 
212     // maps
213     std::shared_ptr<DfxMap> UpdateThreadMaps(pid_t pid, pid_t tid, const std::string filename, uint64_t begin,
214                           uint64_t len, uint64_t offset, uint32_t prot = 0);
215     void UpdatekernelMap(uint64_t begin, uint64_t end, uint64_t offset, std::string filename);
216 
217     const DfxSymbol GetKernelSymbol(uint64_t ip, const std::vector<DfxMap> &memMaps,
218                                  const VirtualThread &thread);
219     const DfxSymbol GetUserSymbol(uint64_t ip, const VirtualThread &thread);
220     const DfxSymbol GetKernelThreadSymbol(uint64_t ip, const VirtualThread &thread);
221 #ifdef HIPERF_DEBUG
222     std::unordered_set<uint64_t> missedRuntimeVaddr_;
223 #endif
224     void SymbolicCallFrame(PerfRecordSample &recordSample, uint64_t ip,
225                            pid_t serverPid, perf_callchain_context context);
226     bool RecoverCallStack(PerfRecordSample &recordSample);
227     std::vector<std::string> symbolsPaths_;
228 
229     // kernel thread
230     void UpdateKernelThreadMap(pid_t pid, uint64_t begin, uint64_t len, uint64_t offset, std::string filename);
231     bool CheckValidSandBoxMmap(PerfRecordMmap2 &recordMmap2);
232     void ProcessKernelCallChain(PerfRecordSample &sample);
233     void AdjustCallChain(PerfRecordSample &sample);
234 };
235 } // namespace HiPerf
236 } // namespace Developtools
237 } // namespace OHOS
238 #endif // HIPERF_VIRTUAL_RUNTIME_H
239