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