• 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 
20 #include "callstack.h"
21 #include "perf_event_record.h"
22 #include "symbols_file.h"
23 #include "virtual_thread.h"
24 
25 namespace OHOS {
26 namespace Developtools {
27 namespace HiPerf {
28 /*
29 This Class contains userspace thread objects. and kernel space objects
30 It represents a virtual operating environment, mainly referring to the relationship between pid,
31 mmaps, and symbols.
32 
33 It mainly receives data is ip pointer (virtual address), pid
34 According to these data, it will find the corresponding mmap and its corresponding elf (also called
35 DSO)
36 
37 Then find the corresponding symbol in the corresponding elf symbol file according to the offset
38 recorded in the corresponding mmap.
39 */
40 
41 class VirtualRuntime {
42 public:
43     VirtualRuntime(bool onDevice = true);
44 
45     // thread need hook the record
46     // from the record , it will call back to write some Simulated Record
47     // case 1. some mmap will be create when it read mmaps for each new process (from record sample)
48 
49     using RecordCallBack = std::function<bool(std::unique_ptr<PerfEventRecord>)>;
50     void SetRecordMode(RecordCallBack recordCallBack);
51 
52     // this both used in report and record follow
53     // it process the record, and rebuild the trhread maps
54     // It internally determines whether to go to the Record process (which will generate virtual
55     // events) or the Report process by judging whether SetRecordMode has been passed.
56     void UpdateFromRecord(PerfEventRecord &reocrd);
57 
58     // in reocrd mode
59     // we make a kernel symbols from some proc file
60     void UpdateKernelSpaceMaps();
61     void UpdateKernelModulesSpaceMaps();
62     // load vdso
63     void LoadVdso();
64 
65     void UpdateKernelSymbols();
66     void UpdateKernelModulesSymbols();
67 
68     // set symbols path , it will send to every symobile file for search
69     bool SetSymbolsPaths(const std::vector<std::string> &symbolsPaths);
70 
71     // any mode
72     static_assert(sizeof(pid_t) == sizeof(int));
73 
GetSymbolsFiles()74     const std::vector<std::unique_ptr<SymbolsFile>> &GetSymbolsFiles() const
75     {
76         return symbolsFiles_;
77     }
78 
79     void SetCallStackExpend(size_t mergeLevel = 0)
80     {
81         callstackMergeLevel_ = mergeLevel;
82     }
83 
SetDisableUnwind(bool disableUnwind)84     void SetDisableUnwind(bool disableUnwind)
85     {
86         HLOGV("disableUnwind change to %d", disableUnwind);
87         disableUnwind_ = disableUnwind;
88     }
89 
90     const Symbol GetSymbol(uint64_t ip, pid_t pid, pid_t tid,
91                            const perf_callchain_context &context = PERF_CONTEXT_MAX);
92 
93     VirtualThread &GetThread(pid_t pid, pid_t tid);
GetThreads()94     const std::map<pid_t, VirtualThread> &GetThreads() const
95     {
96         return userSpaceThreadMap_;
97     }
98     void SymbolicRecord(PerfRecordSample &recordSample);
99 
100     // report use
101     void UpdateFromPerfData(const std::vector<SymbolFileStruct> &);
102     void UnwindFromRecord(PerfRecordSample &recordSample);
103     std::string ReadThreadName(pid_t tid);
104 
105     // debug time
106 #ifdef HIPERF_DEBUG_TIME
107     std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero();
108     std::chrono::microseconds unwindFromRecordTimes_ = std::chrono::microseconds::zero();
109     std::chrono::microseconds unwindCallStackTimes_ = std::chrono::microseconds::zero();
110     std::chrono::microseconds symbolicRecordTimes_ = std::chrono::microseconds::zero();
111     std::chrono::microseconds updateThreadTimes_ = std::chrono::microseconds::zero();
112     std::chrono::microseconds prcessSampleRecordTimes_ = std::chrono::microseconds::zero();
113     std::chrono::microseconds prcessMmapRecordTimes_ = std::chrono::microseconds::zero();
114     std::chrono::microseconds prcessMmap2RecordTimes_ = std::chrono::microseconds::zero();
115     std::chrono::microseconds prcessCommRecordTimes_ = std::chrono::microseconds::zero();
116     std::chrono::microseconds threadParseMapsTimes_ = std::chrono::microseconds::zero();
117     std::chrono::microseconds threadCreateMmapTimes_ = std::chrono::microseconds::zero();
118 #endif
119     const bool loadSymboleWhenNeeded_ = true; // this is a feature config
120 
121 private:
122     bool disableUnwind_ = true;
123     size_t callstackMergeLevel_ = 1;
124     CallStack callstack_;
125     // pid map with user space thread
126     std::map<pid_t, VirtualThread> userSpaceThreadMap_;
127     // not pid , just memmap
128     std::vector<MemMapItem> kernelSpaceMemMaps_;
129     RecordCallBack recordCallBack_;
130     std::vector<std::unique_ptr<SymbolsFile>> symbolsFiles_;
131     enum SymbolCacheLimit : std::size_t {
132         KERNEL_SYMBOL_CACHE_LIMIT = 4000,
133         THREAD_SYMBOL_CACHE_LIMIT = 2000,
134     };
135     std::unordered_map<pid_t, HashList<uint64_t, Symbol>> threadSymbolCache_;
136     HashList<uint64_t, Symbol> kernelSymbolCache_ {KERNEL_SYMBOL_CACHE_LIMIT};
137     bool GetSymbolCache(uint64_t ip, pid_t pid, pid_t tid, Symbol &symbol,
138                         const perf_callchain_context &context);
139     // find synbols function name
140     void MakeCallFrame(Symbol &symbol, CallFrame &callFrame);
141     // records
142     void UpdateSymbols(std::string filename);
143     void UpdateFromRecord(PerfRecordSample &recordSample);
144     void UpdateFromRecord(PerfRecordMmap &recordMmap);
145     void UpdateFromRecord(PerfRecordMmap2 &recordMmap2);
146     void UpdateFromRecord(PerfRecordComm &recordComm);
147 
148     // threads
149     VirtualThread &UpdateThread(pid_t pid, pid_t tid, const std::string name = "");
150     VirtualThread &CreateThread(pid_t pid, pid_t tid);
151 
152     // maps
153     void UpdateThreadMaps(pid_t pid, pid_t tid, const std::string filename, uint64_t begin,
154                           uint64_t len, uint64_t offset);
155     void UpdatekernelMap(uint64_t begin, uint64_t end, uint64_t offset, std::string filename);
156 
157     const Symbol GetKernelSymbol(uint64_t ip, const std::vector<MemMapItem> &memMaps,
158                                  const VirtualThread &thread);
159     const Symbol GetUserSymbol(uint64_t ip, const VirtualThread &thread);
160 #ifdef HIPERF_DEBUG
161     std::unordered_set<uint64_t> missedRuntimeVaddr_;
162 #endif
163     void SymbolicCallFrame(PerfRecordSample &recordSample, uint64_t ip,
164                            perf_callchain_context context);
165 
166     std::vector<std::string> symbolsPaths_;
167 
168     FRIEND_TEST(VirtualRuntimeTest, SetRecordMode);
169     FRIEND_TEST(VirtualRuntimeTest, UpdateKernelSymbols);
170     FRIEND_TEST(VirtualRuntimeTest, UpdateKernelModulesSymbols);
171     FRIEND_TEST(VirtualRuntimeTest, SetCallStackExpend);
172     FRIEND_TEST(VirtualRuntimeTest, SetDisableUnwind);
173     FRIEND_TEST(VirtualRuntimeTest, UnwindFromRecord);
174     friend class VirtualRuntimeTest;
175 };
176 } // namespace HiPerf
177 } // namespace Developtools
178 } // namespace OHOS
179 #endif // HIPERF_VIRTUAL_RUNTIME_H
180