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/process_tracker.h"
18 #include "src/trace_processor/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 // Create a mapping from (t|p)id 0 -> u(t|p)id 0 for the idle process.
30 tids_.emplace(0, 0);
31 pids_.emplace(0, 0);
32 }
33
34 ProcessTracker::~ProcessTracker() = default;
35
StartNewThread(int64_t timestamp,uint32_t tid,StringId thread_name_id)36 UniqueTid ProcessTracker::StartNewThread(int64_t timestamp,
37 uint32_t tid,
38 StringId thread_name_id) {
39 UniqueTid new_utid = context_->storage->AddEmptyThread(tid);
40 TraceStorage::Thread* thread = context_->storage->GetMutableThread(new_utid);
41 thread->name_id = thread_name_id;
42 thread->start_ns = timestamp;
43 tids_.emplace(tid, new_utid);
44 return new_utid;
45 }
46
GetOrCreateThread(uint32_t tid)47 UniqueTid ProcessTracker::GetOrCreateThread(uint32_t tid) {
48 auto pair_it = tids_.equal_range(tid);
49 if (pair_it.first != pair_it.second) {
50 return std::prev(pair_it.second)->second;
51 }
52 return StartNewThread(0, tid, 0);
53 }
54
UpdateThreadName(uint32_t tid,StringId thread_name_id)55 UniqueTid ProcessTracker::UpdateThreadName(uint32_t tid,
56 StringId thread_name_id) {
57 auto pair_it = tids_.equal_range(tid);
58
59 // If a utid exists for the tid, find it and update the name.
60 if (pair_it.first != pair_it.second) {
61 auto prev_utid = std::prev(pair_it.second)->second;
62 TraceStorage::Thread* thread =
63 context_->storage->GetMutableThread(prev_utid);
64 if (thread_name_id)
65 thread->name_id = thread_name_id;
66 return prev_utid;
67 }
68
69 // If none exist, assign a new utid and store it.
70 return StartNewThread(0, tid, thread_name_id);
71 }
72
UpdateThread(uint32_t tid,uint32_t pid)73 UniqueTid ProcessTracker::UpdateThread(uint32_t tid, uint32_t pid) {
74 auto tids_pair = tids_.equal_range(tid);
75
76 // Try looking for a thread that matches both tid and thread group id (pid).
77 TraceStorage::Thread* thread = nullptr;
78 UniqueTid utid = 0;
79 for (auto it = tids_pair.first; it != tids_pair.second; it++) {
80 UniqueTid iter_utid = it->second;
81 auto* iter_thread = context_->storage->GetMutableThread(iter_utid);
82 if (!iter_thread->upid.has_value()) {
83 // We haven't discovered the parent process for the thread. Assign it
84 // now and use this thread.
85 thread = iter_thread;
86 utid = iter_utid;
87 break;
88 }
89 const auto& iter_process =
90 context_->storage->GetProcess(iter_thread->upid.value());
91 if (iter_process.pid == pid) {
92 // We found a thread that matches both the tid and its parent pid.
93 thread = iter_thread;
94 utid = iter_utid;
95 break;
96 }
97 } // for(tids).
98
99 // If no matching thread was found, create a new one.
100 if (thread == nullptr) {
101 utid = context_->storage->AddEmptyThread(tid);
102 tids_.emplace(tid, utid);
103 thread = context_->storage->GetMutableThread(utid);
104 }
105
106 // Find matching process or create new one.
107 if (!thread->upid.has_value()) {
108 thread->upid = GetOrCreateProcess(pid);
109 }
110
111 ResolvePendingAssociations(utid, *thread->upid);
112
113 return utid;
114 }
115
StartNewProcess(int64_t timestamp,uint32_t pid)116 UniquePid ProcessTracker::StartNewProcess(int64_t timestamp, uint32_t pid) {
117 pids_.erase(pid);
118
119 // Create a new UTID for the main thread, so we don't end up reusing an old
120 // entry in case of TID recycling.
121 StartNewThread(timestamp, /*tid=*/pid, 0);
122
123 std::pair<UniquePid, TraceStorage::Process*> process =
124 GetOrCreateProcessPtr(pid);
125 process.second->start_ns = timestamp;
126 return process.first;
127 }
128
UpdateProcess(uint32_t pid,base::Optional<uint32_t> ppid,base::StringView name)129 UniquePid ProcessTracker::UpdateProcess(uint32_t pid,
130 base::Optional<uint32_t> ppid,
131 base::StringView name) {
132 auto proc_name_id = context_->storage->InternString(name);
133
134 base::Optional<UniquePid> pupid;
135 if (ppid.has_value()) {
136 pupid = GetOrCreateProcess(ppid.value());
137 }
138 UniquePid upid;
139 TraceStorage::Process* process;
140 std::tie(upid, process) = GetOrCreateProcessPtr(pid);
141 process->name_id = proc_name_id;
142 process->pupid = pupid;
143 return upid;
144 }
145
GetOrCreateProcess(uint32_t pid)146 UniquePid ProcessTracker::GetOrCreateProcess(uint32_t pid) {
147 return GetOrCreateProcessPtr(pid).first;
148 }
149
150 std::pair<UniquePid, TraceStorage::Process*>
GetOrCreateProcessPtr(uint32_t pid)151 ProcessTracker::GetOrCreateProcessPtr(uint32_t pid) {
152 UniquePid upid;
153 auto it = pids_.find(pid);
154 if (it != pids_.end()) {
155 upid = it->second;
156 } else {
157 upid = context_->storage->AddEmptyProcess(pid);
158 pids_.emplace(pid, upid);
159
160 // Create an entry for the main thread.
161 // We cannot call StartNewThread() here, because threads for this process
162 // (including the main thread) might have been seen already prior to this
163 // call. This call usually comes from the ProcessTree dump which is delayed.
164 UpdateThread(/*tid=*/pid, pid);
165 }
166 return std::make_pair(upid, context_->storage->GetMutableProcess(upid));
167 }
168
AssociateThreads(UniqueTid utid1,UniqueTid utid2)169 void ProcessTracker::AssociateThreads(UniqueTid utid1, UniqueTid utid2) {
170 TraceStorage::Thread* thd1 = context_->storage->GetMutableThread(utid1);
171 TraceStorage::Thread* thd2 = context_->storage->GetMutableThread(utid2);
172
173 // First of all check if one of the two threads is already bound to a process.
174 // If that is the case, map the other thread to the same process and resolve
175 // recursively any associations pending on the other thread.
176
177 if (thd1->upid.has_value() && !thd2->upid.has_value()) {
178 thd2->upid = *thd1->upid;
179 ResolvePendingAssociations(utid2, *thd1->upid);
180 return;
181 }
182
183 if (thd2->upid.has_value() && !thd1->upid.has_value()) {
184 thd1->upid = *thd2->upid;
185 ResolvePendingAssociations(utid1, *thd2->upid);
186 return;
187 }
188
189 if (thd1->upid.has_value() && thd1->upid != thd2->upid) {
190 // Cannot associate two threads that belong to two different processes.
191 PERFETTO_ELOG("Process tracker failure. Cannot associate threads %u, %u",
192 thd1->tid, thd2->tid);
193 context_->storage->IncrementStats(stats::process_tracker_errors);
194 return;
195 }
196
197 pending_assocs_.emplace_back(utid1, utid2);
198 }
199
ResolvePendingAssociations(UniqueTid utid_arg,UniquePid upid)200 void ProcessTracker::ResolvePendingAssociations(UniqueTid utid_arg,
201 UniquePid upid) {
202 PERFETTO_DCHECK(context_->storage->GetMutableThread(utid_arg)->upid == upid);
203 std::vector<UniqueTid> resolved_utids;
204 resolved_utids.emplace_back(utid_arg);
205
206 while (!resolved_utids.empty()) {
207 UniqueTid utid = resolved_utids.back();
208 resolved_utids.pop_back();
209 for (auto it = pending_assocs_.begin(); it != pending_assocs_.end();) {
210 UniqueTid other_utid;
211 if (it->first == utid) {
212 other_utid = it->second;
213 } else if (it->second == utid) {
214 other_utid = it->first;
215 } else {
216 ++it;
217 continue;
218 }
219
220 PERFETTO_DCHECK(other_utid != utid);
221
222 // Update the other thread and associated it to the same process.
223 auto* other_thd = context_->storage->GetMutableThread(other_utid);
224 PERFETTO_DCHECK(!other_thd->upid || other_thd->upid == upid);
225 other_thd->upid = upid;
226
227 // Erase the pair. The |pending_assocs_| vector is not sorted and swapping
228 // a std::pair<uint32_t, uint32_t> is cheap.
229 std::swap(*it, pending_assocs_.back());
230 pending_assocs_.pop_back();
231
232 // Recurse into the newly resolved thread. Some other threads might have
233 // been bound to that.
234 resolved_utids.emplace_back(other_utid);
235 }
236 } // while (!resolved_utids.empty())
237 }
238
239 } // namespace trace_processor
240 } // namespace perfetto
241