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