1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "process_filter.h"
17 #include <cinttypes>
18 #include <limits>
19 #include <string_view>
20 #include <utility>
21
22 using CustomPair = std::pair<uint32_t, uint32_t>;
23 namespace SysTuning {
24 namespace TraceStreamer {
25 namespace {
26 const uint32_t INVALID_ID = std::numeric_limits<uint32_t>::max();
27 }
ProcessFilter(TraceDataCache * dataCache,const TraceStreamerFilters * filter)28 ProcessFilter::ProcessFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter)
29 : FilterBase(dataCache, filter)
30 {
31 tidMappingSet_.insert(CustomPair(0, 0));
32 pidToInternalPidMap_.insert(CustomPair(0, 0));
33 }
34
~ProcessFilter()35 ProcessFilter::~ProcessFilter() {}
36
UpdateOrCreateThreadWithName(uint64_t timeStamp,uint32_t tid,std::string_view name)37 uint32_t ProcessFilter::UpdateOrCreateThreadWithName(uint64_t timeStamp, uint32_t tid, std::string_view name)
38 {
39 DataIndex nameIndex = traceDataCache_->GetDataIndex(name);
40 return UpdateOrCreateThreadWithNameIndex(timeStamp, tid, nameIndex);
41 }
42
AddProcessMemory(uint32_t ipid)43 void ProcessFilter::AddProcessMemory(uint32_t ipid)
44 {
45 traceDataCache_->GetProcessData(ipid)->memSize_ = 1;
46 }
47
AddThreadSliceNum(uint32_t itid)48 void ProcessFilter::AddThreadSliceNum(uint32_t itid)
49 {
50 traceDataCache_->GetThreadData(itid)->sliceSize_ = 1;
51 }
AddProcessSliceNum(uint32_t ipid)52 void ProcessFilter::AddProcessSliceNum(uint32_t ipid)
53 {
54 traceDataCache_->GetProcessData(ipid)->sliceSize_ = 1;
55 }
56
AddCpuStateCount(uint32_t itid)57 void ProcessFilter::AddCpuStateCount(uint32_t itid)
58 {
59 auto thread = traceDataCache_->GetThreadData(itid);
60 if (thread) {
61 thread->cpuStatesCount_++;
62 }
63 }
UpdateOrCreateThread(uint64_t timeStamp,uint32_t tid)64 uint32_t ProcessFilter::UpdateOrCreateThread(uint64_t timeStamp, uint32_t tid)
65 {
66 return UpdateOrCreateThreadWithNameIndex(timeStamp, tid, 0);
67 }
UpdateOrCreateThreadWithPidAndName(uint32_t tid,uint32_t pid,std::string_view name)68 uint32_t ProcessFilter::UpdateOrCreateThreadWithPidAndName(uint32_t tid, uint32_t pid, std::string_view name)
69 {
70 uint32_t internalTid = GetOrCreateThreadWithPid(tid, pid);
71 auto thread = traceDataCache_->GetThreadData(internalTid);
72 auto nameIndex = traceDataCache_->GetDataIndex(name);
73 thread->nameIndex_ = nameIndex;
74 // When the process ID is equal to the thread ID, the process name is also equal to the thread name
75 if (tid == pid) {
76 UpdateOrCreateProcessWithName(pid, name);
77 }
78 return internalTid;
79 }
80
GetOrCreateThreadWithPid(uint32_t tid,uint32_t pid)81 uint32_t ProcessFilter::GetOrCreateThreadWithPid(uint32_t tid, uint32_t pid)
82 {
83 TraceStdtype::Thread* thread = nullptr;
84 uint32_t internalTid;
85 if (pid == 0) {
86 internalTid = GetInternalTid(tid);
87 } else {
88 internalTid = GetInternalTid(tid, pid);
89 }
90 if (internalTid != INVALID_ID) {
91 thread = traceDataCache_->GetThreadData(internalTid);
92 } else {
93 std::tie(internalTid, thread) = NewThread(tid);
94 }
95
96 if (thread->internalPid_ == INVALID_UINT32 && pid != 0) {
97 std::tie(thread->internalPid_, std::ignore) = CreateProcessMaybe(pid, thread->startT_);
98 }
99
100 return internalTid;
101 }
102
UpdateOrCreateProcessWithName(uint32_t pid,std::string_view name)103 uint32_t ProcessFilter::UpdateOrCreateProcessWithName(uint32_t pid, std::string_view name)
104 {
105 uint32_t internalPid = 0;
106 TraceStdtype::Process* process = nullptr;
107 std::tie(internalPid, process) = CreateProcessMaybe(pid, 0);
108 if (process && name != "" && process->cmdLine_ != name) {
109 process->cmdLine_ = std::string(name);
110 }
111 // update main thread name
112 auto internalTid = GetInternalTid(pid, pid);
113 if (internalTid != INVALID_ID) {
114 auto thread = traceDataCache_->GetThreadData(internalTid);
115 thread->nameIndex_ = traceDataCache_->GetDataIndex(process->cmdLine_);
116 }
117 return internalPid;
118 }
119
UpdateOrCreateThreadWithNameIndex(uint64_t timeStamp,uint32_t tid,DataIndex threadNameIndex)120 uint32_t ProcessFilter::UpdateOrCreateThreadWithNameIndex(uint64_t timeStamp, uint32_t tid, DataIndex threadNameIndex)
121 {
122 TraceStdtype::Thread* thread = nullptr;
123 auto& internalTids = GetInternalTids(tid);
124 if (internalTids.size()) {
125 if (!threadNameIndex) {
126 return internalTids.back();
127 }
128 for (auto i : internalTids) {
129 thread = traceDataCache_->GetThreadData(i);
130 if (thread && threadNameIndex != thread->nameIndex_) {
131 thread->nameIndex_ = threadNameIndex;
132 }
133 }
134 } else {
135 InternalTid internalTid = INVALID_ITID;
136 std::tie(internalTid, thread) = NewThread(tid);
137 if (!thread) {
138 return INVALID_ID;
139 }
140 if (threadNameIndex != thread->nameIndex_) {
141 thread->nameIndex_ = threadNameIndex;
142 }
143 if (timeStamp < thread->startT_) {
144 thread->startT_ = timeStamp;
145 }
146 return internalTid;
147 }
148 return internalTids.back();
149 }
GetInternalTid(uint32_t tid,uint32_t pid) const150 uint32_t ProcessFilter::GetInternalTid(uint32_t tid, uint32_t pid) const
151 {
152 uint32_t internalTid = INVALID_ID;
153 auto tidsPair = tidMappingSet_.equal_range(tid);
154 for (auto it = tidsPair.first; it != tidsPair.second; it++) {
155 uint32_t iterItid = it->second;
156 auto iterThread = traceDataCache_->GetThreadData(iterItid);
157 if (iterThread->internalPid_ == INVALID_UINT32) {
158 internalTid = iterItid;
159 continue;
160 }
161
162 const auto& iterProcess = traceDataCache_->GetConstProcessData(iterThread->internalPid_);
163 if (iterProcess.pid_ == pid) {
164 internalTid = iterItid;
165 break;
166 }
167 }
168
169 return internalTid;
170 }
171
GetInternalTid(uint32_t tid) const172 uint32_t ProcessFilter::GetInternalTid(uint32_t tid) const
173 {
174 auto itRange = tidMappingSet_.equal_range(tid);
175 if (itRange.first != itRange.second) {
176 auto internalTid = std::prev(itRange.second)->second;
177 return internalTid;
178 }
179 return INVALID_ID;
180 }
181
GetInternalTids(uint32_t tid)182 std::vector<InternalTid>& ProcessFilter::GetInternalTids(uint32_t tid)
183 {
184 tmpTids_.clear();
185 auto itRange = tidMappingSet_.equal_range(tid);
186 auto it = itRange.first;
187 while (it != itRange.second) {
188 tmpTids_.push_back(it->second);
189 it++;
190 }
191 return tmpTids_;
192 }
193
IsThreadNameEmpty(uint32_t tid) const194 bool ProcessFilter::IsThreadNameEmpty(uint32_t tid) const
195 {
196 auto internalTid = GetInternalTid(tid);
197 if (internalTid != INVALID_ID) {
198 auto thread = traceDataCache_->GetThreadData(internalTid);
199 if (thread->nameIndex_) {
200 return false;
201 }
202 }
203 return true;
204 }
205
GetInternalPid(uint32_t pid) const206 InternalPid ProcessFilter::GetInternalPid(uint32_t pid) const
207 {
208 auto it = pidToInternalPidMap_.find(pid);
209 if (it != pidToInternalPidMap_.end()) {
210 return it->second;
211 }
212 return INVALID_ID;
213 }
214
GetOrCreateInternalPid(uint64_t timeStamp,uint32_t pid)215 InternalPid ProcessFilter::GetOrCreateInternalPid(uint64_t timeStamp, uint32_t pid)
216 {
217 auto ipid = GetInternalPid(pid);
218 if (ipid != INVALID_ID) {
219 return ipid;
220 }
221
222 uint32_t internalPid = 0;
223 TraceStdtype::Process* process = nullptr;
224 std::tie(internalPid, process) = CreateProcessMaybe(pid, timeStamp);
225 return internalPid;
226 }
NewThread(uint32_t tid)227 std::tuple<uint32_t, TraceStdtype::Thread*> ProcessFilter::NewThread(uint32_t tid)
228 {
229 uint32_t internalTid = traceDataCache_->NewInternalThread(tid);
230 tidMappingSet_.emplace(tid, internalTid);
231 auto thread = traceDataCache_->GetThreadData(internalTid);
232
233 return std::make_tuple(internalTid, thread);
234 }
235
NewProcess(uint32_t pid)236 std::tuple<uint32_t, TraceStdtype::Process*> ProcessFilter::NewProcess(uint32_t pid)
237 {
238 uint32_t internalPid = traceDataCache_->GetProcessInternalPid(pid);
239 pidToInternalPidMap_.emplace(pid, internalPid);
240 auto process = traceDataCache_->GetProcessData(internalPid);
241
242 return std::make_tuple(internalPid, process);
243 }
244
CreateProcessMaybe(uint32_t pid,uint64_t startT)245 std::tuple<uint32_t, TraceStdtype::Process*> ProcessFilter::CreateProcessMaybe(uint32_t pid, uint64_t startT)
246 {
247 uint32_t internalPid = INVALID_ID;
248 TraceStdtype::Process* process = nullptr;
249 auto it = pidToInternalPidMap_.find(pid);
250 if (it != pidToInternalPidMap_.end()) {
251 internalPid = it->second;
252 process = traceDataCache_->GetProcessData(internalPid);
253 } else {
254 std::tie(internalPid, process) = NewProcess(pid);
255 void(GetOrCreateThreadWithPid(pid, pid));
256 }
257
258 if (process->startT_ == 0) {
259 process->startT_ = startT;
260 }
261
262 return std::make_tuple(internalPid, process);
263 }
Clear()264 void ProcessFilter::Clear()
265 {
266 tidMappingSet_.clear();
267 pidToInternalPidMap_.clear();
268 }
269 } // namespace TraceStreamer
270 } // namespace SysTuning
271