148f512ceSopenharmony_ci/* 248f512ceSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 348f512ceSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 448f512ceSopenharmony_ci * you may not use this file except in compliance with the License. 548f512ceSopenharmony_ci * You may obtain a copy of the License at 648f512ceSopenharmony_ci * 748f512ceSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 848f512ceSopenharmony_ci * 948f512ceSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1048f512ceSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1148f512ceSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1248f512ceSopenharmony_ci * See the License for the specific language governing permissions and 1348f512ceSopenharmony_ci * limitations under the License. 1448f512ceSopenharmony_ci */ 1548f512ceSopenharmony_ci#ifndef HIPERF_VIRTUAL_RUNTIME_H 1648f512ceSopenharmony_ci#define HIPERF_VIRTUAL_RUNTIME_H 1748f512ceSopenharmony_ci 1848f512ceSopenharmony_ci#include <functional> 1948f512ceSopenharmony_ci#include <fstream> 2048f512ceSopenharmony_ci#if defined(is_ohos) && is_ohos 2148f512ceSopenharmony_ci#include "callstack.h" 2248f512ceSopenharmony_ci#endif 2348f512ceSopenharmony_ci#include "hashlist.h" 2448f512ceSopenharmony_ci#include "perf_event_record.h" 2548f512ceSopenharmony_ci#include "symbols_file.h" 2648f512ceSopenharmony_ci#include "virtual_thread.h" 2748f512ceSopenharmony_ci 2848f512ceSopenharmony_cinamespace OHOS { 2948f512ceSopenharmony_cinamespace Developtools { 3048f512ceSopenharmony_cinamespace HiPerf { 3148f512ceSopenharmony_ci/* 3248f512ceSopenharmony_ciThis Class contains userspace thread objects. and kernel space objects 3348f512ceSopenharmony_ciIt represents a virtual operating environment, mainly referring to the relationship between pid, 3448f512ceSopenharmony_cimmaps, and symbols. 3548f512ceSopenharmony_ci 3648f512ceSopenharmony_ciIt mainly receives data is ip pointer (virtual address), pid 3748f512ceSopenharmony_ciAccording to these data, it will find the corresponding mmap and its corresponding elf (also called 3848f512ceSopenharmony_ciDSO) 3948f512ceSopenharmony_ci 4048f512ceSopenharmony_ciThen find the corresponding symbol in the corresponding elf symbol file according to the offset 4148f512ceSopenharmony_cirecorded in the corresponding mmap. 4248f512ceSopenharmony_ci*/ 4348f512ceSopenharmony_ciusing kSymbolsHits = std::unordered_set<uint64_t>; 4448f512ceSopenharmony_ciusing uSymbolsHits = std::unordered_map<pid_t, std::unordered_set<uint64_t>>; 4548f512ceSopenharmony_ci 4648f512ceSopenharmony_ciclass VirtualRuntime { 4748f512ceSopenharmony_cipublic: 4848f512ceSopenharmony_ci explicit VirtualRuntime(bool onDevice = true); 4948f512ceSopenharmony_ci ~VirtualRuntime(); 5048f512ceSopenharmony_ci // thread need hook the record 5148f512ceSopenharmony_ci // from the record , it will call back to write some Simulated Record 5248f512ceSopenharmony_ci // case 1. some mmap will be create when it read mmaps for each new process (from record sample) 5348f512ceSopenharmony_ci 5448f512ceSopenharmony_ci using RecordCallBack = std::function<bool(std::unique_ptr<PerfEventRecord>)>; 5548f512ceSopenharmony_ci using CollectSymbolCallBack = std::function<void(PerfRecordSample*)>; 5648f512ceSopenharmony_ci 5748f512ceSopenharmony_ci void SetRecordMode(RecordCallBack recordCallBack); 5848f512ceSopenharmony_ci void SetCollectSymbolCallBack(CollectSymbolCallBack collectSymbolCallBack); 5948f512ceSopenharmony_ci 6048f512ceSopenharmony_ci // this both used in report and record follow 6148f512ceSopenharmony_ci // it process the record, and rebuild the trhread maps 6248f512ceSopenharmony_ci // It internally determines whether to go to the Record process (which will generate virtual 6348f512ceSopenharmony_ci // events) or the Report process by judging whether SetRecordMode has been passed. 6448f512ceSopenharmony_ci void UpdateFromRecord(PerfEventRecord &record); 6548f512ceSopenharmony_ci void NeedDropKernelCallChain(PerfRecordSample &sample); 6648f512ceSopenharmony_ci // in reocrd mode 6748f512ceSopenharmony_ci // we make a kernel symbols from some proc file 6848f512ceSopenharmony_ci void UpdateKernelSpaceMaps(); 6948f512ceSopenharmony_ci void UpdateKernelModulesSpaceMaps(); 7048f512ceSopenharmony_ci void UpdateServiceSpaceMaps(); 7148f512ceSopenharmony_ci void UpdateDevhostSpaceMaps(); 7248f512ceSopenharmony_ci // load vdso 7348f512ceSopenharmony_ci void LoadVdso(); 7448f512ceSopenharmony_ci 7548f512ceSopenharmony_ci void UpdateKernelSymbols(); 7648f512ceSopenharmony_ci void UpdateKernelModulesSymbols(); 7748f512ceSopenharmony_ci void UpdateServiceSymbols(); 7848f512ceSopenharmony_ci void UpdateDevhostSymbols(); 7948f512ceSopenharmony_ci 8048f512ceSopenharmony_ci pid_t devhostPid_ = -1; 8148f512ceSopenharmony_ci void SetDevhostPid(pid_t devhost); 8248f512ceSopenharmony_ci void FixHMBundleMmap(char *filename, int pid, u16 &headerSize); 8348f512ceSopenharmony_ci 8448f512ceSopenharmony_ci // set symbols path , it will send to every symobile file for search 8548f512ceSopenharmony_ci bool SetSymbolsPaths(const std::vector<std::string> &symbolsPaths); 8648f512ceSopenharmony_ci 8748f512ceSopenharmony_ci // any mode 8848f512ceSopenharmony_ci static_assert(sizeof(pid_t) == sizeof(int)); 8948f512ceSopenharmony_ci 9048f512ceSopenharmony_ci const std::vector<std::unique_ptr<SymbolsFile>> &GetSymbolsFiles() const 9148f512ceSopenharmony_ci { 9248f512ceSopenharmony_ci return symbolsFiles_; 9348f512ceSopenharmony_ci } 9448f512ceSopenharmony_ci 9548f512ceSopenharmony_ci const ProcessStackMap* GetUniStackTable() 9648f512ceSopenharmony_ci { 9748f512ceSopenharmony_ci return &processStackMap_; 9848f512ceSopenharmony_ci } 9948f512ceSopenharmony_ci 10048f512ceSopenharmony_ci void SetCallStackExpend(size_t mergeLevel = 0) 10148f512ceSopenharmony_ci { 10248f512ceSopenharmony_ci callstackMergeLevel_ = mergeLevel; 10348f512ceSopenharmony_ci } 10448f512ceSopenharmony_ci 10548f512ceSopenharmony_ci void SetDisableUnwind(bool disableUnwind) 10648f512ceSopenharmony_ci { 10748f512ceSopenharmony_ci HLOGV("disableUnwind change to %d", disableUnwind); 10848f512ceSopenharmony_ci disableUnwind_ = disableUnwind; 10948f512ceSopenharmony_ci } 11048f512ceSopenharmony_ci 11148f512ceSopenharmony_ci void EnableDebugInfoSymbolic(bool enable) 11248f512ceSopenharmony_ci { 11348f512ceSopenharmony_ci enableDebugInfoSymbolic_ = enable; 11448f512ceSopenharmony_ci } 11548f512ceSopenharmony_ci void SetDedupStack() 11648f512ceSopenharmony_ci { 11748f512ceSopenharmony_ci dedupStack_ = true; 11848f512ceSopenharmony_ci } 11948f512ceSopenharmony_ci 12048f512ceSopenharmony_ci void ImportUniqueStackNodes(const std::vector<UniStackTableInfo>&); 12148f512ceSopenharmony_ci 12248f512ceSopenharmony_ci bool isHM_ = false; 12348f512ceSopenharmony_ci void SetHM(bool isHM) 12448f512ceSopenharmony_ci { 12548f512ceSopenharmony_ci isHM_ = isHM; 12648f512ceSopenharmony_ci } 12748f512ceSopenharmony_ci 12848f512ceSopenharmony_ci void SetNeedKernelCallChain(bool kernelCallChain) 12948f512ceSopenharmony_ci { 13048f512ceSopenharmony_ci needkernelCallChain_ = kernelCallChain; 13148f512ceSopenharmony_ci } 13248f512ceSopenharmony_ci DfxSymbol GetSymbol(uint64_t ip, pid_t pid, pid_t tid, 13348f512ceSopenharmony_ci const perf_callchain_context &context = PERF_CONTEXT_MAX); 13448f512ceSopenharmony_ci 13548f512ceSopenharmony_ci VirtualThread &GetThread(pid_t pid, pid_t tid, const std::string name = ""); 13648f512ceSopenharmony_ci const std::map<pid_t, VirtualThread> &GetThreads() const 13748f512ceSopenharmony_ci { 13848f512ceSopenharmony_ci return userSpaceThreadMap_; 13948f512ceSopenharmony_ci } 14048f512ceSopenharmony_ci void SymbolicRecord(PerfRecordSample &recordSample); 14148f512ceSopenharmony_ci void SymbolSpeRecord(PerfRecordAuxtrace &recordAuxTrace); 14248f512ceSopenharmony_ci 14348f512ceSopenharmony_ci // report use 14448f512ceSopenharmony_ci void UpdateFromPerfData(const std::vector<SymbolFileStruct> &); 14548f512ceSopenharmony_ci void UnwindFromRecord(PerfRecordSample &recordSample); 14648f512ceSopenharmony_ci std::string ReadThreadName(pid_t tid, bool isThread); 14748f512ceSopenharmony_ci std::string ReadFromSavedCmdLines(pid_t tid); 14848f512ceSopenharmony_ci bool IsKernelThread(pid_t pid); 14948f512ceSopenharmony_ci void CollectDedupSymbol(kSymbolsHits &kernelSymbolsHits, 15048f512ceSopenharmony_ci uSymbolsHits &userSymbolsHits); 15148f512ceSopenharmony_ci // debug time 15248f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME 15348f512ceSopenharmony_ci std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero(); 15448f512ceSopenharmony_ci std::chrono::microseconds unwindFromRecordTimes_ = std::chrono::microseconds::zero(); 15548f512ceSopenharmony_ci std::chrono::microseconds unwindCallStackTimes_ = std::chrono::microseconds::zero(); 15648f512ceSopenharmony_ci std::chrono::microseconds symbolicRecordTimes_ = std::chrono::microseconds::zero(); 15748f512ceSopenharmony_ci std::chrono::microseconds updateThreadTimes_ = std::chrono::microseconds::zero(); 15848f512ceSopenharmony_ci std::chrono::microseconds processSampleRecordTimes_ = std::chrono::microseconds::zero(); 15948f512ceSopenharmony_ci std::chrono::microseconds processMmapRecordTimes_ = std::chrono::microseconds::zero(); 16048f512ceSopenharmony_ci std::chrono::microseconds processMmap2RecordTimes_ = std::chrono::microseconds::zero(); 16148f512ceSopenharmony_ci std::chrono::microseconds processCommRecordTimes_ = std::chrono::microseconds::zero(); 16248f512ceSopenharmony_ci std::chrono::microseconds threadParseMapsTimes_ = std::chrono::microseconds::zero(); 16348f512ceSopenharmony_ci std::chrono::microseconds threadCreateMmapTimes_ = std::chrono::microseconds::zero(); 16448f512ceSopenharmony_ci#endif 16548f512ceSopenharmony_ci const bool loadSymboleWhenNeeded_ = true; // this is a feature config 16648f512ceSopenharmony_ci 16748f512ceSopenharmony_ciprivate: 16848f512ceSopenharmony_ci bool needkernelCallChain_ = false; 16948f512ceSopenharmony_ci bool disableUnwind_ = true; 17048f512ceSopenharmony_ci bool enableDebugInfoSymbolic_ = false; 17148f512ceSopenharmony_ci bool dedupStack_ = false; 17248f512ceSopenharmony_ci size_t callstackMergeLevel_ = 1; 17348f512ceSopenharmony_ci std::ifstream savedCmdLines_; 17448f512ceSopenharmony_ci#if defined(is_ohos) && is_ohos 17548f512ceSopenharmony_ci CallStack callstack_; 17648f512ceSopenharmony_ci#endif 17748f512ceSopenharmony_ci // pid map with user space thread 17848f512ceSopenharmony_ci std::map<pid_t, VirtualThread> userSpaceThreadMap_; 17948f512ceSopenharmony_ci // not pid , just memmap 18048f512ceSopenharmony_ci std::vector<DfxMap> kernelSpaceMemMaps_; 18148f512ceSopenharmony_ci ProcessStackMap processStackMap_; 18248f512ceSopenharmony_ci RecordCallBack recordCallBack_; 18348f512ceSopenharmony_ci CollectSymbolCallBack collectSymbolCallBack_; 18448f512ceSopenharmony_ci std::vector<std::unique_ptr<SymbolsFile>> symbolsFiles_; 18548f512ceSopenharmony_ci enum SymbolCacheLimit : std::size_t { 18648f512ceSopenharmony_ci KERNEL_SYMBOL_CACHE_LIMIT = 4000, 18748f512ceSopenharmony_ci USER_SYMBOL_CACHE_LIMIT = 4000, 18848f512ceSopenharmony_ci }; 18948f512ceSopenharmony_ci HashList<uint64_t, DfxSymbol> userSymbolCache_; 19048f512ceSopenharmony_ci HashList<uint64_t, DfxSymbol> kernelSymbolCache_ {KERNEL_SYMBOL_CACHE_LIMIT}; 19148f512ceSopenharmony_ci HashList<uint64_t, DfxSymbol> kThreadSymbolCache_ {KERNEL_SYMBOL_CACHE_LIMIT}; 19248f512ceSopenharmony_ci bool GetSymbolCache(uint64_t fileVaddr, DfxSymbol &symbol, 19348f512ceSopenharmony_ci const perf_callchain_context &context); 19448f512ceSopenharmony_ci // find synbols function name 19548f512ceSopenharmony_ci void MakeCallFrame(DfxSymbol &symbol, DfxFrame &callFrame); 19648f512ceSopenharmony_ci void UpdateSymbols(std::shared_ptr<DfxMap> map, pid_t pid); 19748f512ceSopenharmony_ci // we don't know whether hap vma mapping is stand for a so 19848f512ceSopenharmony_ci // thus we need try to parse it first 19948f512ceSopenharmony_ci bool UpdateHapSymbols(std::shared_ptr<DfxMap> map); 20048f512ceSopenharmony_ci void UpdateFromRecord(PerfRecordSample &recordSample); 20148f512ceSopenharmony_ci void UpdateFromRecord(PerfRecordMmap &recordMmap); 20248f512ceSopenharmony_ci void UpdateFromRecord(PerfRecordMmap2 &recordMmap2); 20348f512ceSopenharmony_ci void UpdateFromRecord(PerfRecordComm &recordComm); 20448f512ceSopenharmony_ci void DedupFromRecord(PerfRecordSample *recordSample); 20548f512ceSopenharmony_ci void UpdateFromRecord(PerfRecordAuxtrace &recordAuxTrace); 20648f512ceSopenharmony_ci // threads 20748f512ceSopenharmony_ci VirtualThread &UpdateThread(pid_t pid, pid_t tid, const std::string name = ""); 20848f512ceSopenharmony_ci VirtualThread &CreateThread(pid_t pid, pid_t tid, const std::string name = ""); 20948f512ceSopenharmony_ci 21048f512ceSopenharmony_ci // maps 21148f512ceSopenharmony_ci std::shared_ptr<DfxMap> UpdateThreadMaps(pid_t pid, pid_t tid, const std::string filename, uint64_t begin, 21248f512ceSopenharmony_ci uint64_t len, uint64_t offset, uint32_t prot = 0); 21348f512ceSopenharmony_ci void UpdatekernelMap(uint64_t begin, uint64_t end, uint64_t offset, std::string filename); 21448f512ceSopenharmony_ci 21548f512ceSopenharmony_ci const DfxSymbol GetKernelSymbol(uint64_t ip, const std::vector<DfxMap> &memMaps, 21648f512ceSopenharmony_ci const VirtualThread &thread); 21748f512ceSopenharmony_ci const DfxSymbol GetUserSymbol(uint64_t ip, const VirtualThread &thread); 21848f512ceSopenharmony_ci const DfxSymbol GetKernelThreadSymbol(uint64_t ip, const VirtualThread &thread); 21948f512ceSopenharmony_ci#ifdef HIPERF_DEBUG 22048f512ceSopenharmony_ci std::unordered_set<uint64_t> missedRuntimeVaddr_; 22148f512ceSopenharmony_ci#endif 22248f512ceSopenharmony_ci void SymbolicCallFrame(PerfRecordSample &recordSample, uint64_t ip, 22348f512ceSopenharmony_ci pid_t serverPid, perf_callchain_context context); 22448f512ceSopenharmony_ci bool RecoverCallStack(PerfRecordSample &recordSample); 22548f512ceSopenharmony_ci std::vector<std::string> symbolsPaths_; 22648f512ceSopenharmony_ci 22748f512ceSopenharmony_ci // kernel thread 22848f512ceSopenharmony_ci void UpdateKernelThreadMap(pid_t pid, uint64_t begin, uint64_t len, std::string filename); 22948f512ceSopenharmony_ci 23048f512ceSopenharmony_ci FRIEND_TEST(VirtualRuntimeTest, SetRecordMode); 23148f512ceSopenharmony_ci FRIEND_TEST(VirtualRuntimeTest, UpdateKernelSymbols); 23248f512ceSopenharmony_ci FRIEND_TEST(VirtualRuntimeTest, UpdateKernelModulesSymbols); 23348f512ceSopenharmony_ci FRIEND_TEST(VirtualRuntimeTest, SetCallStackExpend); 23448f512ceSopenharmony_ci FRIEND_TEST(VirtualRuntimeTest, SetDisableUnwind); 23548f512ceSopenharmony_ci FRIEND_TEST(VirtualRuntimeTest, UnwindFromRecord); 23648f512ceSopenharmony_ci friend class VirtualRuntimeTest; 23748f512ceSopenharmony_ci 23848f512ceSopenharmony_ci bool CheckValidSandBoxMmap(PerfRecordMmap2 &recordMmap2); 23948f512ceSopenharmony_ci}; 24048f512ceSopenharmony_ci} // namespace HiPerf 24148f512ceSopenharmony_ci} // namespace Developtools 24248f512ceSopenharmony_ci} // namespace OHOS 24348f512ceSopenharmony_ci#endif // HIPERF_VIRTUAL_RUNTIME_H 244