xref: /aosp_15_r20/system/extras/simpleperf/thread_tree.h (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #ifndef SIMPLE_PERF_THREAD_TREE_H_
18*288bf522SAndroid Build Coastguard Worker #define SIMPLE_PERF_THREAD_TREE_H_
19*288bf522SAndroid Build Coastguard Worker 
20*288bf522SAndroid Build Coastguard Worker #include <stdint.h>
21*288bf522SAndroid Build Coastguard Worker 
22*288bf522SAndroid Build Coastguard Worker #include <limits>
23*288bf522SAndroid Build Coastguard Worker #include <map>
24*288bf522SAndroid Build Coastguard Worker #include <memory>
25*288bf522SAndroid Build Coastguard Worker #include <unordered_map>
26*288bf522SAndroid Build Coastguard Worker 
27*288bf522SAndroid Build Coastguard Worker #include "dso.h"
28*288bf522SAndroid Build Coastguard Worker 
29*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
30*288bf522SAndroid Build Coastguard Worker 
31*288bf522SAndroid Build Coastguard Worker struct Record;
32*288bf522SAndroid Build Coastguard Worker 
33*288bf522SAndroid Build Coastguard Worker constexpr char DEFAULT_KERNEL_MMAP_NAME[] = "[kernel.kallsyms]";
34*288bf522SAndroid Build Coastguard Worker constexpr char DEFAULT_KERNEL_BPF_MMAP_NAME[] = "[bpf]";
35*288bf522SAndroid Build Coastguard Worker constexpr char DEFAULT_EXECNAME_FOR_THREAD_MMAP[] = "//anon";
36*288bf522SAndroid Build Coastguard Worker 
37*288bf522SAndroid Build Coastguard Worker namespace map_flags {
38*288bf522SAndroid Build Coastguard Worker constexpr uint32_t PROT_JIT_SYMFILE_MAP = 0x4000;
39*288bf522SAndroid Build Coastguard Worker }  // namespace map_flags
40*288bf522SAndroid Build Coastguard Worker 
41*288bf522SAndroid Build Coastguard Worker struct MapEntry {
42*288bf522SAndroid Build Coastguard Worker   uint64_t start_addr;
43*288bf522SAndroid Build Coastguard Worker   uint64_t len;
44*288bf522SAndroid Build Coastguard Worker   uint64_t pgoff;
45*288bf522SAndroid Build Coastguard Worker   Dso* dso;
46*288bf522SAndroid Build Coastguard Worker   bool in_kernel;
47*288bf522SAndroid Build Coastguard Worker   uint32_t flags;
48*288bf522SAndroid Build Coastguard Worker 
49*288bf522SAndroid Build Coastguard Worker   MapEntry(uint64_t start_addr, uint64_t len, uint64_t pgoff, Dso* dso, bool in_kernel,
50*288bf522SAndroid Build Coastguard Worker            uint32_t flags = 0)
start_addrMapEntry51*288bf522SAndroid Build Coastguard Worker       : start_addr(start_addr),
52*288bf522SAndroid Build Coastguard Worker         len(len),
53*288bf522SAndroid Build Coastguard Worker         pgoff(pgoff),
54*288bf522SAndroid Build Coastguard Worker         dso(dso),
55*288bf522SAndroid Build Coastguard Worker         in_kernel(in_kernel),
56*288bf522SAndroid Build Coastguard Worker         flags(flags) {}
MapEntryMapEntry57*288bf522SAndroid Build Coastguard Worker   MapEntry() {}
58*288bf522SAndroid Build Coastguard Worker 
get_end_addrMapEntry59*288bf522SAndroid Build Coastguard Worker   uint64_t get_end_addr() const { return start_addr + len; }
60*288bf522SAndroid Build Coastguard Worker 
ContainsMapEntry61*288bf522SAndroid Build Coastguard Worker   uint64_t Contains(uint64_t addr) const { return addr >= start_addr && addr < get_end_addr(); }
62*288bf522SAndroid Build Coastguard Worker 
GetVaddrInFileMapEntry63*288bf522SAndroid Build Coastguard Worker   uint64_t GetVaddrInFile(uint64_t addr) const {
64*288bf522SAndroid Build Coastguard Worker     if (Contains(addr)) {
65*288bf522SAndroid Build Coastguard Worker       return dso->IpToVaddrInFile(addr, start_addr, pgoff);
66*288bf522SAndroid Build Coastguard Worker     }
67*288bf522SAndroid Build Coastguard Worker     return 0;
68*288bf522SAndroid Build Coastguard Worker   }
69*288bf522SAndroid Build Coastguard Worker };
70*288bf522SAndroid Build Coastguard Worker 
71*288bf522SAndroid Build Coastguard Worker struct MapSet {
72*288bf522SAndroid Build Coastguard Worker   std::map<uint64_t, const MapEntry*> maps;  // Map from start_addr to a MapEntry.
73*288bf522SAndroid Build Coastguard Worker   uint64_t version = 0u;                     // incremented each time changing maps
74*288bf522SAndroid Build Coastguard Worker 
75*288bf522SAndroid Build Coastguard Worker   const MapEntry* FindMapByAddr(uint64_t addr) const;
76*288bf522SAndroid Build Coastguard Worker };
77*288bf522SAndroid Build Coastguard Worker 
78*288bf522SAndroid Build Coastguard Worker struct ThreadEntry {
79*288bf522SAndroid Build Coastguard Worker   int pid;
80*288bf522SAndroid Build Coastguard Worker   int tid;
81*288bf522SAndroid Build Coastguard Worker   const char* comm;              // It always refers to the latest comm.
82*288bf522SAndroid Build Coastguard Worker   std::shared_ptr<MapSet> maps;  // maps is shared by threads in the same process.
83*288bf522SAndroid Build Coastguard Worker };
84*288bf522SAndroid Build Coastguard Worker 
85*288bf522SAndroid Build Coastguard Worker struct FileFeature;
86*288bf522SAndroid Build Coastguard Worker 
87*288bf522SAndroid Build Coastguard Worker // ThreadTree contains thread information (in ThreadEntry) and mmap information
88*288bf522SAndroid Build Coastguard Worker // (in MapEntry) of the monitored threads. It also has interface to access
89*288bf522SAndroid Build Coastguard Worker // symbols in executable binaries mapped in the monitored threads.
90*288bf522SAndroid Build Coastguard Worker class ThreadTree {
91*288bf522SAndroid Build Coastguard Worker  public:
ThreadTree()92*288bf522SAndroid Build Coastguard Worker   ThreadTree()
93*288bf522SAndroid Build Coastguard Worker       : show_ip_for_unknown_symbol_(false),
94*288bf522SAndroid Build Coastguard Worker         show_mark_for_unknown_symbol_(false),
95*288bf522SAndroid Build Coastguard Worker         unknown_symbol_("unknown", 0, std::numeric_limits<unsigned long long>::max()) {
96*288bf522SAndroid Build Coastguard Worker     unknown_dso_ = Dso::CreateDso(DSO_UNKNOWN_FILE, "unknown");
97*288bf522SAndroid Build Coastguard Worker     unknown_map_ =
98*288bf522SAndroid Build Coastguard Worker         MapEntry(0, std::numeric_limits<unsigned long long>::max(), 0, unknown_dso_.get(), false);
99*288bf522SAndroid Build Coastguard Worker     // We can't dump comm for pid 0 from /proc, so add it's name here.
100*288bf522SAndroid Build Coastguard Worker     SetThreadName(0, 0, "swapper");
101*288bf522SAndroid Build Coastguard Worker   }
~ThreadTree()102*288bf522SAndroid Build Coastguard Worker   virtual ~ThreadTree() {}
103*288bf522SAndroid Build Coastguard Worker 
DisableThreadExitRecords()104*288bf522SAndroid Build Coastguard Worker   void DisableThreadExitRecords() { disable_thread_exit_records_ = true; }
105*288bf522SAndroid Build Coastguard Worker   void SetThreadName(int pid, int tid, const std::string& comm);
106*288bf522SAndroid Build Coastguard Worker   bool ForkThread(int pid, int tid, int ppid, int ptid);
107*288bf522SAndroid Build Coastguard Worker   virtual ThreadEntry* FindThread(int tid) const;
108*288bf522SAndroid Build Coastguard Worker   ThreadEntry* FindThreadOrNew(int pid, int tid);
109*288bf522SAndroid Build Coastguard Worker   void ExitThread(int pid, int tid);
110*288bf522SAndroid Build Coastguard Worker   void AddKernelMap(uint64_t start_addr, uint64_t len, uint64_t pgoff, const std::string& filename);
GetKernelMaps()111*288bf522SAndroid Build Coastguard Worker   const MapSet& GetKernelMaps() { return kernel_maps_; }
112*288bf522SAndroid Build Coastguard Worker   void AddThreadMap(int pid, int tid, uint64_t start_addr, uint64_t len, uint64_t pgoff,
113*288bf522SAndroid Build Coastguard Worker                     const std::string& filename, uint32_t flags = 0);
114*288bf522SAndroid Build Coastguard Worker 
115*288bf522SAndroid Build Coastguard Worker   // Add process symbols that do not correspond to any real dso.
116*288bf522SAndroid Build Coastguard Worker   // For example, these might be symbols generated by a JIT.
117*288bf522SAndroid Build Coastguard Worker   void AddSymbolsForProcess(int pid, std::vector<Symbol>* symbols);
118*288bf522SAndroid Build Coastguard Worker 
119*288bf522SAndroid Build Coastguard Worker   const MapEntry* FindMap(const ThreadEntry* thread, uint64_t ip, bool in_kernel);
120*288bf522SAndroid Build Coastguard Worker   // Find map for an ip address when we don't know whether it is in kernel.
121*288bf522SAndroid Build Coastguard Worker   const MapEntry* FindMap(const ThreadEntry* thread, uint64_t ip);
122*288bf522SAndroid Build Coastguard Worker   const Symbol* FindSymbol(const MapEntry* map, uint64_t ip, uint64_t* pvaddr_in_file,
123*288bf522SAndroid Build Coastguard Worker                            Dso** pdso = nullptr);
124*288bf522SAndroid Build Coastguard Worker   const Symbol* FindKernelSymbol(uint64_t ip);
IsUnknownDso(const Dso * dso)125*288bf522SAndroid Build Coastguard Worker   bool IsUnknownDso(const Dso* dso) const { return dso == unknown_dso_.get(); }
UnknownSymbol()126*288bf522SAndroid Build Coastguard Worker   const Symbol* UnknownSymbol() const { return &unknown_symbol_; }
127*288bf522SAndroid Build Coastguard Worker 
ShowIpForUnknownSymbol()128*288bf522SAndroid Build Coastguard Worker   void ShowIpForUnknownSymbol() { show_ip_for_unknown_symbol_ = true; }
ShowMarkForUnknownSymbol()129*288bf522SAndroid Build Coastguard Worker   void ShowMarkForUnknownSymbol() {
130*288bf522SAndroid Build Coastguard Worker     show_mark_for_unknown_symbol_ = true;
131*288bf522SAndroid Build Coastguard Worker     unknown_symbol_ = Symbol("*unknown", 0, ULLONG_MAX);
132*288bf522SAndroid Build Coastguard Worker   }
133*288bf522SAndroid Build Coastguard Worker   // Clear thread and map information, but keep loaded dso information. It saves
134*288bf522SAndroid Build Coastguard Worker   // the time to reload dso information.
135*288bf522SAndroid Build Coastguard Worker   void ClearThreadAndMap();
136*288bf522SAndroid Build Coastguard Worker   bool AddDsoInfo(FileFeature& file);
137*288bf522SAndroid Build Coastguard Worker   void AddDexFileOffset(const std::string& file_path, uint64_t dex_file_offset);
138*288bf522SAndroid Build Coastguard Worker 
139*288bf522SAndroid Build Coastguard Worker   // Update thread tree with information provided by record.
140*288bf522SAndroid Build Coastguard Worker   void Update(const Record& record);
141*288bf522SAndroid Build Coastguard Worker 
142*288bf522SAndroid Build Coastguard Worker   std::vector<Dso*> GetAllDsos() const;
143*288bf522SAndroid Build Coastguard Worker   Dso* FindUserDsoOrNew(const std::string& filename, uint64_t start_addr = 0,
144*288bf522SAndroid Build Coastguard Worker                         DsoType dso_type = DSO_ELF_FILE);
145*288bf522SAndroid Build Coastguard Worker 
146*288bf522SAndroid Build Coastguard Worker  private:
147*288bf522SAndroid Build Coastguard Worker   ThreadEntry* CreateThread(int pid, int tid);
148*288bf522SAndroid Build Coastguard Worker   Dso* FindKernelDsoOrNew();
149*288bf522SAndroid Build Coastguard Worker   Dso* FindKernelModuleDsoOrNew(const std::string& filename, uint64_t memory_start,
150*288bf522SAndroid Build Coastguard Worker                                 uint64_t memory_end);
151*288bf522SAndroid Build Coastguard Worker 
152*288bf522SAndroid Build Coastguard Worker   const MapEntry* AllocateMap(const MapEntry& entry);
153*288bf522SAndroid Build Coastguard Worker   void InsertMap(MapSet& maps, const MapEntry& entry);
154*288bf522SAndroid Build Coastguard Worker 
155*288bf522SAndroid Build Coastguard Worker   // Add thread maps to cover symbols in dso.
156*288bf522SAndroid Build Coastguard Worker   void AddThreadMapsForDsoSymbols(ThreadEntry* thread, Dso* dso);
157*288bf522SAndroid Build Coastguard Worker 
158*288bf522SAndroid Build Coastguard Worker   std::unordered_map<int, std::unique_ptr<ThreadEntry>> thread_tree_;
159*288bf522SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<std::string>> thread_comm_storage_;
160*288bf522SAndroid Build Coastguard Worker 
161*288bf522SAndroid Build Coastguard Worker   MapSet kernel_maps_;
162*288bf522SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<MapEntry>> map_storage_;
163*288bf522SAndroid Build Coastguard Worker   MapEntry unknown_map_;
164*288bf522SAndroid Build Coastguard Worker 
165*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<Dso> kernel_dso_;
166*288bf522SAndroid Build Coastguard Worker   std::unordered_map<std::string, std::unique_ptr<Dso>> module_dso_tree_;
167*288bf522SAndroid Build Coastguard Worker   std::unordered_map<std::string, std::unique_ptr<Dso>> user_dso_tree_;
168*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<Dso> unknown_dso_;
169*288bf522SAndroid Build Coastguard Worker   bool show_ip_for_unknown_symbol_;
170*288bf522SAndroid Build Coastguard Worker   bool show_mark_for_unknown_symbol_;
171*288bf522SAndroid Build Coastguard Worker   Symbol unknown_symbol_;
172*288bf522SAndroid Build Coastguard Worker   bool disable_thread_exit_records_ = false;
173*288bf522SAndroid Build Coastguard Worker };
174*288bf522SAndroid Build Coastguard Worker 
175*288bf522SAndroid Build Coastguard Worker }  // namespace simpleperf
176*288bf522SAndroid Build Coastguard Worker 
177*288bf522SAndroid Build Coastguard Worker #endif  // SIMPLE_PERF_THREAD_TREE_H_
178