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