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