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