• 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 
104     // debug time
105 #ifdef HIPERF_DEBUG_TIME
106     std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero();
107     std::chrono::microseconds unwindFromRecordTimes_ = std::chrono::microseconds::zero();
108     std::chrono::microseconds unwindCallStackTimes_ = std::chrono::microseconds::zero();
109     std::chrono::microseconds symbolicRecordTimes_ = std::chrono::microseconds::zero();
110     std::chrono::microseconds updateThreadTimes_ = std::chrono::microseconds::zero();
111     std::chrono::microseconds prcessSampleRecordTimes_ = std::chrono::microseconds::zero();
112     std::chrono::microseconds prcessMmapRecordTimes_ = std::chrono::microseconds::zero();
113     std::chrono::microseconds prcessMmap2RecordTimes_ = std::chrono::microseconds::zero();
114     std::chrono::microseconds prcessCommRecordTimes_ = std::chrono::microseconds::zero();
115     std::chrono::microseconds threadParseMapsTimes_ = std::chrono::microseconds::zero();
116     std::chrono::microseconds threadCreateMmapTimes_ = std::chrono::microseconds::zero();
117 #endif
118     const bool loadSymboleWhenNeeded_ = true; // this is a feature config
119 
120 private:
121     bool disableUnwind_ = true;
122     size_t callstackMergeLevel_ = 1;
123     CallStack callstack_;
124     // pid map with user space thread
125     std::map<pid_t, VirtualThread> userSpaceThreadMap_;
126     // not pid , just memmap
127     std::vector<MemMapItem> kernelSpaceMemMaps_;
128     RecordCallBack recordCallBack_;
129     std::vector<std::unique_ptr<SymbolsFile>> symbolsFiles_;
130     enum SymbolCacheLimit : std::size_t {
131         KERNEL_SYMBOL_CACHE_LIMIT = 4000,
132         THREAD_SYMBOL_CACHE_LIMIT = 2000,
133     };
134     std::unordered_map<pid_t, HashList<uint64_t, Symbol>> threadSymbolCache_;
135     HashList<uint64_t, Symbol> kernelSymbolCache_ {KERNEL_SYMBOL_CACHE_LIMIT};
136     bool GetSymbolCache(uint64_t ip, pid_t pid, pid_t tid, Symbol &symbol,
137                         const perf_callchain_context &context);
138     // find synbols function name
139     void MakeCallFrame(Symbol &symbol, CallFrame &callFrame);
140     // records
141     void UpdateSymbols(std::string filename);
142     void UpdateFromRecord(PerfRecordSample &recordSample);
143     void UpdateFromRecord(PerfRecordMmap &recordMmap);
144     void UpdateFromRecord(PerfRecordMmap2 &recordMmap2);
145     void UpdateFromRecord(PerfRecordComm &recordComm);
146 
147     // threads
148     VirtualThread &UpdateThread(pid_t pid, pid_t tid, const std::string name = "");
149     std::string ReadThreadName(pid_t tid);
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