• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "src/trace_processor/importers/common/process_tracker.h"
18 #include "src/trace_processor/storage/stats.h"
19 
20 #include <utility>
21 
22 #include <inttypes.h>
23 
24 namespace perfetto {
25 namespace trace_processor {
26 
ProcessTracker(TraceProcessorContext * context)27 ProcessTracker::ProcessTracker(TraceProcessorContext* context)
28     : context_(context) {}
29 
30 ProcessTracker::~ProcessTracker() = default;
31 
StartNewThread(base::Optional<int64_t> timestamp,uint32_t tid,StringId thread_name_id)32 UniqueTid ProcessTracker::StartNewThread(base::Optional<int64_t> timestamp,
33                                          uint32_t tid,
34                                          StringId thread_name_id) {
35   tables::ThreadTable::Row row;
36   row.tid = tid;
37   row.name = thread_name_id;
38   row.start_ts = timestamp;
39 
40   auto* thread_table = context_->storage->mutable_thread_table();
41   UniqueTid new_utid = thread_table->Insert(row).row;
42   tids_[tid].emplace_back(new_utid);
43   return new_utid;
44 }
45 
EndThread(int64_t timestamp,uint32_t tid)46 void ProcessTracker::EndThread(int64_t timestamp, uint32_t tid) {
47   auto* thread_table = context_->storage->mutable_thread_table();
48   auto* process_table = context_->storage->mutable_process_table();
49 
50   UniqueTid utid = GetOrCreateThread(tid);
51   thread_table->mutable_end_ts()->Set(utid, timestamp);
52 
53   // Remove the thread from the list of threads being tracked as any event after
54   // this one should be ignored.
55   auto& vector = tids_[tid];
56   vector.erase(std::remove(vector.begin(), vector.end(), utid));
57 
58   auto opt_upid = thread_table->upid()[utid];
59   if (opt_upid.has_value()) {
60     // If the process pid and thread tid are equal, then this is the main thread
61     // of the process.
62     if (process_table->pid()[*opt_upid] == thread_table->tid()[utid]) {
63       process_table->mutable_end_ts()->Set(*opt_upid, timestamp);
64     }
65   }
66 }
67 
GetThreadOrNull(uint32_t tid)68 base::Optional<UniqueTid> ProcessTracker::GetThreadOrNull(uint32_t tid) {
69   auto opt_utid = GetThreadOrNull(tid, base::nullopt);
70   if (!opt_utid)
71     return base::nullopt;
72 
73   auto* threads = context_->storage->mutable_thread_table();
74   UniqueTid utid = *opt_utid;
75 
76   // Ensure that the tid matches the tid we were looking for.
77   PERFETTO_DCHECK(threads->tid()[utid] == tid);
78 
79   // If the thread is being tracked by the process tracker, it should not be
80   // known to have ended.
81   PERFETTO_DCHECK(!threads->end_ts()[utid].has_value());
82 
83   return utid;
84 }
85 
GetOrCreateThread(uint32_t tid)86 UniqueTid ProcessTracker::GetOrCreateThread(uint32_t tid) {
87   auto utid = GetThreadOrNull(tid);
88   return utid ? *utid : StartNewThread(base::nullopt, tid, kNullStringId);
89 }
90 
UpdateThreadName(uint32_t tid,StringId thread_name_id)91 UniqueTid ProcessTracker::UpdateThreadName(uint32_t tid,
92                                            StringId thread_name_id) {
93   auto* thread_table = context_->storage->mutable_thread_table();
94   auto utid = GetOrCreateThread(tid);
95   if (!thread_name_id.is_null())
96     thread_table->mutable_name()->Set(utid, thread_name_id);
97   return utid;
98 }
99 
SetThreadNameIfUnset(UniqueTid utid,StringId thread_name_id)100 void ProcessTracker::SetThreadNameIfUnset(UniqueTid utid,
101                                           StringId thread_name_id) {
102   auto* thread_table = context_->storage->mutable_thread_table();
103   if (thread_table->name()[utid].is_null())
104     thread_table->mutable_name()->Set(utid, thread_name_id);
105 }
106 
IsThreadAlive(UniqueTid utid)107 bool ProcessTracker::IsThreadAlive(UniqueTid utid) {
108   auto* threads = context_->storage->mutable_thread_table();
109   auto* processes = context_->storage->mutable_process_table();
110 
111   // If the thread has an end ts, it's certainly dead.
112   if (threads->end_ts()[utid].has_value())
113     return false;
114 
115   // If we don't know the parent process, we have to consider this thread alive.
116   auto opt_current_upid = threads->upid()[utid];
117   if (!opt_current_upid)
118     return true;
119 
120   // If the process is already dead, the thread can't be alive.
121   UniquePid current_upid = *opt_current_upid;
122   if (processes->end_ts()[current_upid].has_value())
123     return false;
124 
125   // If the process has been replaced in |pids_|, this thread is dead.
126   uint32_t current_pid = processes->pid()[current_upid];
127   auto pid_it = pids_.find(current_pid);
128   if (pid_it != pids_.end() && pid_it->second != current_upid)
129     return false;
130 
131   return true;
132 }
133 
GetThreadOrNull(uint32_t tid,base::Optional<uint32_t> pid)134 base::Optional<UniqueTid> ProcessTracker::GetThreadOrNull(
135     uint32_t tid,
136     base::Optional<uint32_t> pid) {
137   auto* threads = context_->storage->mutable_thread_table();
138   auto* processes = context_->storage->mutable_process_table();
139 
140   auto vector_it = tids_.find(tid);
141   if (vector_it == tids_.end())
142     return base::nullopt;
143 
144   // Iterate backwards through the threads so ones later in the trace are more
145   // likely to be picked.
146   const auto& vector = vector_it->second;
147   for (auto it = vector.rbegin(); it != vector.rend(); it++) {
148     UniqueTid current_utid = *it;
149 
150     // If we finished this thread, we should have removed it from the vector
151     // entirely.
152     PERFETTO_DCHECK(!threads->end_ts()[current_utid].has_value());
153 
154     // If the thread is dead, ignore it.
155     if (!IsThreadAlive(current_utid))
156       continue;
157 
158     // If we don't know the parent process, we have to choose this thread.
159     auto opt_current_upid = threads->upid()[current_utid];
160     if (!opt_current_upid)
161       return current_utid;
162 
163     // We found a thread that matches both the tid and its parent pid.
164     uint32_t current_pid = processes->pid()[*opt_current_upid];
165     if (!pid || current_pid == *pid)
166       return current_utid;
167   }
168   return base::nullopt;
169 }
170 
UpdateThread(uint32_t tid,uint32_t pid)171 UniqueTid ProcessTracker::UpdateThread(uint32_t tid, uint32_t pid) {
172   auto* thread_table = context_->storage->mutable_thread_table();
173 
174   // Try looking for a thread that matches both tid and thread group id (pid).
175   base::Optional<UniqueTid> opt_utid = GetThreadOrNull(tid, pid);
176 
177   // If no matching thread was found, create a new one.
178   UniqueTid utid =
179       opt_utid ? *opt_utid : StartNewThread(base::nullopt, tid, kNullStringId);
180   PERFETTO_DCHECK(thread_table->tid()[utid] == tid);
181 
182   // Find matching process or create new one.
183   if (!thread_table->upid()[utid].has_value()) {
184     AssociateThreadToProcess(utid, GetOrCreateProcess(pid));
185   }
186 
187   ResolvePendingAssociations(utid, *thread_table->upid()[utid]);
188 
189   return utid;
190 }
191 
StartNewProcess(base::Optional<int64_t> timestamp,base::Optional<uint32_t> parent_tid,uint32_t pid,StringId main_thread_name)192 UniquePid ProcessTracker::StartNewProcess(base::Optional<int64_t> timestamp,
193                                           base::Optional<uint32_t> parent_tid,
194                                           uint32_t pid,
195                                           StringId main_thread_name) {
196   pids_.erase(pid);
197   // TODO(eseckler): Consider erasing all old entries in |tids_| that match the
198   // |pid| (those would be for an older process with the same pid). Right now,
199   // we keep them in |tids_| (if they weren't erased by EndThread()), but ignore
200   // them in GetThreadOrNull().
201 
202   // Create a new UTID for the main thread, so we don't end up reusing an old
203   // entry in case of TID recycling.
204   StartNewThread(timestamp, /*tid=*/pid, kNullStringId);
205 
206   // Note that we erased the pid above so this should always return a new
207   // process.
208   UniquePid upid = GetOrCreateProcess(pid);
209 
210   auto* process_table = context_->storage->mutable_process_table();
211   auto* thread_table = context_->storage->mutable_thread_table();
212 
213   PERFETTO_DCHECK(process_table->name()[upid].is_null());
214   PERFETTO_DCHECK(!process_table->start_ts()[upid].has_value());
215 
216   if (timestamp) {
217     process_table->mutable_start_ts()->Set(upid, *timestamp);
218   }
219   process_table->mutable_name()->Set(upid, main_thread_name);
220 
221   if (parent_tid) {
222     UniqueTid parent_utid = GetOrCreateThread(*parent_tid);
223     auto opt_parent_upid = thread_table->upid()[parent_utid];
224     if (opt_parent_upid.has_value()) {
225       process_table->mutable_parent_upid()->Set(upid, *opt_parent_upid);
226     } else {
227       pending_parent_assocs_.emplace_back(parent_utid, upid);
228     }
229   }
230   return upid;
231 }
232 
SetProcessMetadata(uint32_t pid,base::Optional<uint32_t> ppid,base::StringView name)233 UniquePid ProcessTracker::SetProcessMetadata(uint32_t pid,
234                                              base::Optional<uint32_t> ppid,
235                                              base::StringView name) {
236   auto proc_name_id = context_->storage->InternString(name);
237 
238   base::Optional<UniquePid> pupid;
239   if (ppid.has_value()) {
240     pupid = GetOrCreateProcess(ppid.value());
241   }
242 
243   UniquePid upid = GetOrCreateProcess(pid);
244 
245   auto* process_table = context_->storage->mutable_process_table();
246   process_table->mutable_name()->Set(upid, proc_name_id);
247 
248   if (pupid)
249     process_table->mutable_parent_upid()->Set(upid, *pupid);
250 
251   return upid;
252 }
253 
SetProcessUid(UniquePid upid,uint32_t uid)254 void ProcessTracker::SetProcessUid(UniquePid upid, uint32_t uid) {
255   auto* process_table = context_->storage->mutable_process_table();
256   process_table->mutable_uid()->Set(upid, uid);
257 
258   // The notion of the app ID (as derived from the uid) is defined in
259   // frameworks/base/core/java/android/os/UserHandle.java
260   process_table->mutable_android_appid()->Set(upid, uid % 100000);
261 }
262 
SetProcessNameIfUnset(UniquePid upid,StringId process_name_id)263 void ProcessTracker::SetProcessNameIfUnset(UniquePid upid,
264                                            StringId process_name_id) {
265   auto* process_table = context_->storage->mutable_process_table();
266   if (process_table->name()[upid].is_null())
267     process_table->mutable_name()->Set(upid, process_name_id);
268 }
269 
UpdateProcessNameFromThreadName(uint32_t tid,StringId thread_name)270 void ProcessTracker::UpdateProcessNameFromThreadName(uint32_t tid,
271                                                      StringId thread_name) {
272   auto* thread_table = context_->storage->mutable_thread_table();
273   auto* process_table = context_->storage->mutable_process_table();
274 
275   auto utid = GetOrCreateThread(tid);
276   auto opt_upid = thread_table->upid()[utid];
277   if (opt_upid.has_value()) {
278     if (process_table->pid()[*opt_upid] == tid) {
279       process_table->mutable_name()->Set(*opt_upid, thread_name);
280     }
281   }
282 }
283 
GetOrCreateProcess(uint32_t pid)284 UniquePid ProcessTracker::GetOrCreateProcess(uint32_t pid) {
285   UniquePid upid;
286   auto it = pids_.find(pid);
287   if (it != pids_.end()) {
288     upid = it->second;
289   } else {
290     tables::ProcessTable::Row row;
291     row.pid = pid;
292     upid = context_->storage->mutable_process_table()->Insert(row).row;
293 
294     pids_.emplace(pid, upid);
295 
296     // Create an entry for the main thread.
297     // We cannot call StartNewThread() here, because threads for this process
298     // (including the main thread) might have been seen already prior to this
299     // call. This call usually comes from the ProcessTree dump which is delayed.
300     UpdateThread(/*tid=*/pid, pid);
301   }
302   return upid;
303 }
304 
AssociateThreads(UniqueTid utid1,UniqueTid utid2)305 void ProcessTracker::AssociateThreads(UniqueTid utid1, UniqueTid utid2) {
306   auto* tt = context_->storage->mutable_thread_table();
307 
308   // First of all check if one of the two threads is already bound to a process.
309   // If that is the case, map the other thread to the same process and resolve
310   // recursively any associations pending on the other thread.
311 
312   auto opt_upid1 = tt->upid()[utid1];
313   auto opt_upid2 = tt->upid()[utid2];
314 
315   if (opt_upid1.has_value() && !opt_upid2.has_value()) {
316     AssociateThreadToProcess(utid2, *opt_upid1);
317     ResolvePendingAssociations(utid2, *opt_upid1);
318     return;
319   }
320 
321   if (opt_upid2.has_value() && !opt_upid1.has_value()) {
322     AssociateThreadToProcess(utid1, *opt_upid2);
323     ResolvePendingAssociations(utid1, *opt_upid2);
324     return;
325   }
326 
327   if (opt_upid1.has_value() && opt_upid1 != opt_upid2) {
328     // Cannot associate two threads that belong to two different processes.
329     PERFETTO_ELOG("Process tracker failure. Cannot associate threads %u, %u",
330                   tt->tid()[utid1], tt->tid()[utid2]);
331     context_->storage->IncrementStats(stats::process_tracker_errors);
332     return;
333   }
334 
335   pending_assocs_.emplace_back(utid1, utid2);
336 }
337 
ResolvePendingAssociations(UniqueTid utid_arg,UniquePid upid)338 void ProcessTracker::ResolvePendingAssociations(UniqueTid utid_arg,
339                                                 UniquePid upid) {
340   auto* tt = context_->storage->mutable_thread_table();
341   auto* pt = context_->storage->mutable_process_table();
342   PERFETTO_DCHECK(tt->upid()[utid_arg] == upid);
343 
344   std::vector<UniqueTid> resolved_utids;
345   resolved_utids.emplace_back(utid_arg);
346 
347   while (!resolved_utids.empty()) {
348     UniqueTid utid = resolved_utids.back();
349     resolved_utids.pop_back();
350     for (auto it = pending_parent_assocs_.begin();
351          it != pending_parent_assocs_.end();) {
352       UniqueTid parent_utid = it->first;
353       UniquePid child_upid = it->second;
354 
355       if (parent_utid != utid) {
356         ++it;
357         continue;
358       }
359       PERFETTO_DCHECK(child_upid != upid);
360 
361       // Set the parent pid of the other process
362       PERFETTO_DCHECK(!pt->parent_upid()[child_upid] ||
363                       pt->parent_upid()[child_upid] == upid);
364       pt->mutable_parent_upid()->Set(child_upid, upid);
365 
366       // Erase the pair. The |pending_parent_assocs_| vector is not sorted and
367       // swapping a std::pair<uint32_t, uint32_t> is cheap.
368       std::swap(*it, pending_parent_assocs_.back());
369       pending_parent_assocs_.pop_back();
370     }
371 
372     for (auto it = pending_assocs_.begin(); it != pending_assocs_.end();) {
373       UniqueTid other_utid;
374       if (it->first == utid) {
375         other_utid = it->second;
376       } else if (it->second == utid) {
377         other_utid = it->first;
378       } else {
379         ++it;
380         continue;
381       }
382 
383       PERFETTO_DCHECK(other_utid != utid);
384 
385       // Update the other thread and associated it to the same process.
386       PERFETTO_DCHECK(!tt->upid()[other_utid] ||
387                       tt->upid()[other_utid] == upid);
388       AssociateThreadToProcess(other_utid, upid);
389 
390       // Erase the pair. The |pending_assocs_| vector is not sorted and swapping
391       // a std::pair<uint32_t, uint32_t> is cheap.
392       std::swap(*it, pending_assocs_.back());
393       pending_assocs_.pop_back();
394 
395       // Recurse into the newly resolved thread. Some other threads might have
396       // been bound to that.
397       resolved_utids.emplace_back(other_utid);
398     }
399   }  // while (!resolved_utids.empty())
400 }
401 
AssociateThreadToProcess(UniqueTid utid,UniquePid upid)402 void ProcessTracker::AssociateThreadToProcess(UniqueTid utid, UniquePid upid) {
403   auto* thread_table = context_->storage->mutable_thread_table();
404   thread_table->mutable_upid()->Set(utid, upid);
405   auto* process_table = context_->storage->mutable_process_table();
406   bool main_thread = thread_table->tid()[utid] == process_table->pid()[upid];
407   thread_table->mutable_is_main_thread()->Set(utid, main_thread);
408 }
409 
SetPidZeroIgnoredForIdleProcess()410 void ProcessTracker::SetPidZeroIgnoredForIdleProcess() {
411   // Create a mapping from (t|p)id 0 -> u(t|p)id 0 for the idle process.
412   tids_.emplace(0, std::vector<UniqueTid>{0});
413   pids_.emplace(0, 0);
414 }
415 
416 }  // namespace trace_processor
417 }  // namespace perfetto
418