xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/common/process_tracker.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_PROCESS_TRACKER_H_
18 #define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_PROCESS_TRACKER_H_
19 
20 #include <cstdint>
21 #include <optional>
22 #include <unordered_map>
23 #include <unordered_set>
24 #include <utility>
25 #include <vector>
26 
27 #include "perfetto/ext/base/flat_hash_map.h"
28 #include "perfetto/ext/base/string_view.h"
29 #include "src/trace_processor/importers/common/args_tracker.h"
30 #include "src/trace_processor/storage/trace_storage.h"
31 #include "src/trace_processor/types/trace_processor_context.h"
32 
33 namespace perfetto {
34 namespace trace_processor {
35 
36 // Thread names can come from different sources, and we don't always want to
37 // overwrite the previously set name. This enum determines the priority of
38 // different sources.
39 enum class ThreadNamePriority {
40   kOther = 0,
41   kFtrace = 1,
42   kEtwTrace = 1,
43   kProcessTree = 2,
44   kTrackDescriptorThreadType = 3,
45   kTrackDescriptor = 4,
46 
47   // Priority when trace processor hardcodes a name for a process (e.g. calling
48   // the idle thread "swapper" when parsing ftrace).
49   // Keep this last.
50   kTraceProcessorConstant = 5,
51 };
52 
53 class ProcessTracker {
54  public:
55   explicit ProcessTracker(TraceProcessorContext*);
56   ProcessTracker(const ProcessTracker&) = delete;
57   ProcessTracker& operator=(const ProcessTracker&) = delete;
58   virtual ~ProcessTracker();
59 
60   using UniqueThreadIterator = std::vector<UniqueTid>::const_iterator;
61   using UniqueThreadBounds =
62       std::pair<UniqueThreadIterator, UniqueThreadIterator>;
63 
64   // TODO(b/110409911): Invalidation of process and threads is yet to be
65   // implemented. This will include passing timestamps into the below methods
66   // to ensure the correct upid/utid is found.
67 
68   // Called when a task_newtask is observed. This force the tracker to start
69   // a new UTID for the thread, which is needed for TID-recycling resolution.
70   UniqueTid StartNewThread(std::optional<int64_t> timestamp, uint32_t tid);
71 
72   // Returns whether a thread is considered alive by the process tracker.
73   bool IsThreadAlive(UniqueTid utid);
74 
75   // Called when sched_process_exit is observed. This forces the tracker to
76   // end the thread lifetime for the utid associated with the given tid.
77   void EndThread(int64_t timestamp, uint32_t tid);
78 
79   // Returns the thread utid or std::nullopt if it doesn't exist.
80   std::optional<UniqueTid> GetThreadOrNull(uint32_t tid);
81 
82   // Returns the thread utid (or creates a new entry if not present)
83   UniqueTid GetOrCreateThread(uint32_t tid);
84 
85   // Assigns the given name to the thread if the new name has a higher priority
86   // than the existing one. Returns the utid of the thread.
87   virtual UniqueTid UpdateThreadName(uint32_t tid,
88                                      StringId thread_name_id,
89                                      ThreadNamePriority priority);
90 
91   // Assigns the given name to the thread if the new name has a higher priority
92   // than the existing one. The thread is identified by utid.
93   virtual void UpdateThreadNameByUtid(UniqueTid utid,
94                                       StringId thread_name_id,
95                                       ThreadNamePriority priority);
96 
97   // Called when a thread is seen the process tree. Retrieves the matching utid
98   // for the tid and the matching upid for the tgid and stores both.
99   // Virtual for testing.
100   virtual UniqueTid UpdateThread(uint32_t tid, uint32_t pid);
101 
102   // Associates trusted_pid with track UUID.
103   void UpdateTrustedPid(uint32_t trusted_pid, uint64_t uuid);
104 
105   // Returns the trusted_pid associated with the track UUID, or std::nullopt if
106   // not found.
107   std::optional<uint32_t> GetTrustedPid(uint64_t uuid);
108 
109   // Performs namespace-local to root-level resolution of thread or process id,
110   // given tid (can be root-level or namespace-local, but we don't know
111   // beforehand) and root-level pid/tgid that the thread belongs to.
112   // Returns the root-level thread id for tid on successful resolution;
113   // otherwise, returns std::nullopt on resolution failure, or the thread of
114   // tid isn't running in a pid namespace.
115   std::optional<uint32_t> ResolveNamespacedTid(uint32_t root_level_pid,
116                                                uint32_t tid);
117 
118   // Called when a task_newtask without the CLONE_THREAD flag is observed.
119   // This force the tracker to start both a new UTID and a new UPID.
120   UniquePid StartNewProcess(std::optional<int64_t> timestamp,
121                             std::optional<uint32_t> parent_tid,
122                             uint32_t pid,
123                             StringId main_thread_name,
124                             ThreadNamePriority priority);
125 
126   // Called when a process is seen in a process tree. Retrieves the UniquePid
127   // for that pid or assigns a new one.
128   // Virtual for testing.
129   virtual UniquePid SetProcessMetadata(uint32_t pid,
130                                        std::optional<uint32_t> ppid,
131                                        base::StringView name,
132                                        base::StringView cmdline);
133 
134   // Sets the process user id.
135   void SetProcessUid(UniquePid upid, uint32_t uid);
136 
137   // Assigns the given name to the process identified by |upid| if it does not
138   // have a name yet.
139   virtual void SetProcessNameIfUnset(UniquePid upid, StringId process_name_id);
140 
141   // Sets the start timestamp to the process identified by |upid| if it doesn't
142   // have a timestamp yet.
143   void SetStartTsIfUnset(UniquePid upid, int64_t start_ts_nanoseconds);
144 
145   // Called on a task rename event to set the thread name and possibly process
146   // name (if the tid provided is the main thread of the process).
147   void UpdateThreadNameAndMaybeProcessName(uint32_t tid,
148                                            StringId thread_name,
149                                            ThreadNamePriority priority);
150 
151   // Called when a process is seen in a process tree. Retrieves the UniquePid
152   // for that pid or assigns a new one.
153   // Virtual for testing.
154   virtual UniquePid GetOrCreateProcess(uint32_t pid);
155 
156   // Returns the upid for a given pid.
UpidForPidForTesting(uint32_t pid)157   std::optional<UniquePid> UpidForPidForTesting(uint32_t pid) {
158     auto it = pids_.Find(pid);
159     return it ? std::make_optional(*it) : std::nullopt;
160   }
161 
162   // Returns the bounds of a range that includes all UniqueTids that have the
163   // requested tid.
UtidsForTidForTesting(uint32_t tid)164   UniqueThreadBounds UtidsForTidForTesting(uint32_t tid) {
165     const auto& deque = tids_[tid];
166     return std::make_pair(deque.begin(), deque.end());
167   }
168 
169   // Marks the two threads as belonging to the same process, even if we don't
170   // know which one yet. If one of the two threads is later mapped to a process,
171   // the other will be mapped to the same process. The order of the two threads
172   // is irrelevant, Associate(A, B) has the same effect of Associate(B, A).
173   void AssociateThreads(UniqueTid, UniqueTid);
174 
175   // Creates the mapping from tid 0 <-> utid 0 and pid 0 <-> upid 0. This is
176   // done for Linux-based system traces (proto or ftrace format) as for these
177   // traces, we always have the "swapper" (idle) process having tid/pid 0.
178   void SetPidZeroIsUpidZeroIdleProcess();
179 
180   // Returns a BoundInserter to add arguments to the arg set of a process.
181   // Arguments are flushed into trace storage only after the trace was loaded in
182   // its entirety.
183   ArgsTracker::BoundInserter AddArgsTo(UniquePid upid);
184 
185   // Called when the trace was fully loaded.
186   void NotifyEndOfFile();
187 
188   // Tracks the namespace-local pids for a process running in a pid namespace.
189   void UpdateNamespacedProcess(uint32_t pid, std::vector<uint32_t> nspid);
190 
191   // Tracks the namespace-local thread ids for a thread running in a pid
192   // namespace.
193   void UpdateNamespacedThread(uint32_t pid,
194                               uint32_t tid,
195                               std::vector<uint32_t> nstid);
196 
197   // The UniqueTid of the swapper thread, is 0 for the default machine and is
198   // > 0 for remote machines.
swapper_utid()199   UniqueTid swapper_utid() const { return swapper_utid_; }
200 
201  private:
202   // Returns the utid of a thread having |tid| and |pid| as the parent process.
203   // pid == std::nullopt matches all processes.
204   // Returns std::nullopt if such a thread doesn't exist.
205   std::optional<uint32_t> GetThreadOrNull(uint32_t tid,
206                                           std::optional<uint32_t> pid);
207 
208   // Called whenever we discover that the passed thread belongs to the passed
209   // process. The |pending_assocs_| vector is scanned to see if there are any
210   // other threads associated to the passed thread.
211   void ResolvePendingAssociations(UniqueTid, UniquePid);
212 
213   // Writes the association that the passed thread belongs to the passed
214   // process.
215   void AssociateThreadToProcess(UniqueTid, UniquePid);
216 
217   TraceProcessorContext* const context_;
218 
219   ArgsTracker args_tracker_;
220 
221   // Mapping for tid to the vector of possible UniqueTids.
222   // TODO(lalitm): this is a one-many mapping because this code was written
223   // before global sorting was a thing so multiple threads could be "active"
224   // simultaneously. This is no longer the case so this should be removed
225   // (though it seems like there are subtle things which break in Chrome if this
226   // changes).
227   base::FlatHashMap<uint32_t /* tid */, std::vector<UniqueTid>> tids_;
228 
229   // Mapping of the most recently seen pid to the associated upid.
230   base::FlatHashMap<uint32_t /* pid (aka tgid) */, UniquePid> pids_;
231 
232   // Pending thread associations. The meaning of a pair<ThreadA, ThreadB> in
233   // this vector is: we know that A and B belong to the same process, but we
234   // don't know yet which process. A and A are idempotent, as in, pair<A,B> is
235   // equivalent to pair<B,A>.
236   std::vector<std::pair<UniqueTid, UniqueTid>> pending_assocs_;
237 
238   // Pending parent process associations. The meaning of pair<ThreadA, ProcessB>
239   // in this vector is: we know that A created process B but we don't know the
240   // process of A. That is, we don't know the parent *process* of B.
241   std::vector<std::pair<UniqueTid, UniquePid>> pending_parent_assocs_;
242 
243   // A mapping from utid to the priority of a thread name source.
244   std::vector<ThreadNamePriority> thread_name_priorities_;
245 
246   // A mapping from track UUIDs to trusted pids.
247   std::unordered_map<uint64_t, uint32_t> trusted_pids_;
248 
249   struct NamespacedThread {
250     uint32_t pid;                 // Root-level pid.
251     uint32_t tid;                 // Root-level tid.
252     std::vector<uint32_t> nstid;  // Namespace-local tids.
253   };
254   // Keeps track of pid-namespaced threads, keyed by root-level thread ids.
255   std::unordered_map<uint32_t /* tid */, NamespacedThread> namespaced_threads_;
256 
257   struct NamespacedProcess {
258     uint32_t pid;                          // Root-level pid.
259     std::vector<uint32_t> nspid;           // Namespace-local pids.
260     std::unordered_set<uint32_t> threads;  // Root-level thread IDs.
261   };
262   // Keeps track pid-namespaced processes, keyed by root-level pids.
263   std::unordered_map<uint32_t /* pid (aka tgid) */, NamespacedProcess>
264       namespaced_processes_;
265 
266   UniquePid swapper_upid_ = 0;
267   UniqueTid swapper_utid_ = 0;
268 };
269 
270 }  // namespace trace_processor
271 }  // namespace perfetto
272 
273 #endif  // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_PROCESS_TRACKER_H_
274