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