1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
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 "cpu_filter.h"
17 #include "args_filter.h"
18 #include "process_filter.h"
19 #include "trace_streamer_filters.h"
20
21 namespace SysTuning {
22 namespace TraceStreamer {
CpuFilter(TraceDataCache * dataCache,const TraceStreamerFilters * filter)23 CpuFilter::CpuFilter(TraceDataCache *dataCache, const TraceStreamerFilters *filter) : FilterBase(dataCache, filter) {}
24 CpuFilter::~CpuFilter() = default;
ProcNextPidSwitchEvent(uint64_t ts,uint64_t cpu,uint32_t prevPid,uint32_t nextPid,DataIndex nextInfo)25 void CpuFilter::ProcNextPidSwitchEvent(uint64_t ts,
26 uint64_t cpu,
27 uint32_t prevPid,
28 uint32_t nextPid,
29 DataIndex nextInfo)
30 {
31 CheckWakeupEvent(nextPid);
32 auto lastRow = RowOfInternalTidInStateTable(nextPid);
33 if (lastRow != INVALID_UINT64) {
34 // check if there are wakeup or waking events before
35 traceDataCache_->GetThreadStateData()->UpdateDuration(static_cast<TableRowId>(lastRow), ts);
36 }
37 auto index = traceDataCache_->GetThreadStateData()->AppendThreadState(ts, INVALID_TIME, cpu, nextPid, TASK_RUNNING);
38 if (nextInfo != INVALID_DATAINDEX) {
39 ArgsSet args;
40 args.AppendArg(nextInfo_, BASE_DATA_TYPE_STRING, nextInfo);
41 auto argSetId = streamFilters_->argsFilter_->NewArgs(args);
42 traceDataCache_->GetThreadStateData()->SetArgSetId(index, argSetId);
43 }
44 (void)RemberInternalTidInStateTable(nextPid, index, TASK_RUNNING);
45 if (cpuToRowThreadState_.find(cpu) == cpuToRowThreadState_.end()) {
46 cpuToRowThreadState_.insert(std::make_pair(cpu, index));
47 } else {
48 // only one thread on run on a cpu at a certain time
49 if (traceDataCache_->GetThreadStateData()->ItidsData()[cpuToRowThreadState_.at(cpu)] != prevPid) {
50 if (!traceDataCache_->GetThreadStateData()->End(static_cast<TableRowId>(cpuToRowThreadState_.at(cpu)),
51 ts)) {
52 ClearInternalTidInStateTable(
53 traceDataCache_->GetThreadStateData()->ItidsData()[cpuToRowThreadState_.at(cpu)]);
54 }
55 }
56 cpuToRowThreadState_.at(cpu) = index;
57 }
58 }
ProcPrevPidSwitchEvent(uint64_t ts,uint64_t cpu,uint32_t prevPid,uint64_t prevState,BinderTransactionInfo & btInfo)59 void CpuFilter::ProcPrevPidSwitchEvent(uint64_t ts,
60 uint64_t cpu,
61 uint32_t prevPid,
62 uint64_t prevState,
63 BinderTransactionInfo &btInfo)
64 {
65 bool isChangeCpu = false;
66 auto lastRow = RowOfInternalTidInStateTable(prevPid);
67 if (lastRow != INVALID_UINT64) {
68 auto lastCpu = traceDataCache_->GetConstThreadStateData().CpusData()[lastRow];
69 auto lastState = traceDataCache_->GetConstThreadStateData().StatesData()[lastRow];
70 auto lastStartTs = traceDataCache_->GetConstThreadStateData().TimeStampData()[lastRow];
71 if ((cpu != lastCpu) && (lastState == TASK_RUNNING)) {
72 if (traceDataCache_->HMKernelTraceEnabled() || (ts == lastStartTs)) {
73 isChangeCpu = true;
74 }
75 }
76 if (!isChangeCpu) {
77 CheckWakeupEvent(prevPid);
78 traceDataCache_->GetThreadStateData()->UpdateDuration(static_cast<TableRowId>(lastRow), ts);
79 streamFilters_->processFilter_->AddCpuStateCount(prevPid);
80 auto thread = traceDataCache_->GetThreadData(prevPid);
81 if (thread && !thread->switchCount_) {
82 thread->switchCount_ = 1;
83 }
84 }
85 }
86
87 if (!isChangeCpu) {
88 auto threadStateRow =
89 traceDataCache_->GetThreadStateData()->AppendThreadState(ts, INVALID_TIME, INVALID_CPU, prevPid, prevState);
90 btInfo.threadStateRow = threadStateRow;
91 if (prevState == TASK_UNINTERRUPTIBLE || prevState == TASK_DK) {
92 if (!pidToThreadSliceRow_.count(prevPid)) {
93 pidToThreadSliceRow_.emplace(std::make_pair(prevPid, threadStateRow));
94 } else {
95 pidToThreadSliceRow_.at(prevPid) = threadStateRow;
96 }
97 } else {
98 if (pidToThreadSliceRow_.count(prevPid)) {
99 pidToThreadSliceRow_.erase(prevPid);
100 }
101 }
102 (void)RemberInternalTidInStateTable(prevPid, threadStateRow, prevState);
103 }
104 }
InsertSwitchEvent(uint64_t ts,uint64_t cpu,uint32_t prevPid,int32_t prevPrio,uint64_t prevState,uint32_t nextPid,int32_t nextPrio,DataIndex nextInfo)105 void CpuFilter::InsertSwitchEvent(uint64_t ts,
106 uint64_t cpu,
107 uint32_t prevPid,
108 int32_t prevPrio,
109 uint64_t prevState,
110 uint32_t nextPid,
111 int32_t nextPrio,
112 DataIndex nextInfo)
113 {
114 BinderTransactionInfo btInfo = {prevPid, nextPid, INVALID_UINT64, INVALID_UINT64};
115 SchedSliceRow schedSliceRow = {ts, INVALID_UINT64, cpu, nextPid, 0, nextPrio};
116 auto index = traceDataCache_->GetSchedSliceData()->AppendSchedSlice(schedSliceRow);
117 auto prevTidOnCpu = cpuToRowSched_.find(cpu);
118 if (prevTidOnCpu != cpuToRowSched_.end()) {
119 traceDataCache_->GetSchedSliceData()->Update(prevTidOnCpu->second.row, ts, prevState);
120 btInfo.schedSliceRow = prevTidOnCpu->second.row;
121 cpuToRowSched_.at(cpu).row = index;
122 } else {
123 cpuToRowSched_.insert(std::make_pair(cpu, RowPos{nextPid, index}));
124 }
125 if (nextPid) {
126 ProcNextPidSwitchEvent(ts, cpu, prevPid, nextPid, nextInfo);
127 }
128 if (prevPid) {
129 ProcPrevPidSwitchEvent(ts, cpu, prevPid, prevState, btInfo);
130 }
131 if (traceDataCache_->BinderRunnableTraceEnabled() && iTidToTransaction_.find(prevPid) != iTidToTransaction_.end()) {
132 uint64_t transactionId = iTidToTransaction_.at(prevPid);
133 auto iter = transactionIdToInfo_.find(transactionId);
134 if (prevState != TASK_NEW || iter == transactionIdToInfo_.end() || iter->second.iTidFrom != prevPid ||
135 btInfo.schedSliceRow == INVALID_UINT64 || btInfo.threadStateRow == INVALID_UINT64) {
136 TransactionClear(prevState, transactionId);
137 return;
138 }
139 transactionIdToInfo_[transactionId] = btInfo;
140 }
141 }
142
InsertBlockedReasonEvent(uint64_t cpu,uint32_t iTid,bool iowait,DataIndex caller,uint32_t delay)143 bool CpuFilter::InsertBlockedReasonEvent(uint64_t cpu, uint32_t iTid, bool iowait, DataIndex caller, uint32_t delay)
144 {
145 if (pidToThreadSliceRow_.count(iTid) == 0) {
146 return false;
147 }
148
149 // ArgSet
150 ArgsSet args;
151 args.AppendArg(ioWait_, BASE_DATA_TYPE_INT, iowait);
152 args.AppendArg(caller_, BASE_DATA_TYPE_STRING, caller);
153 if (delay != INVALID_UINT32) {
154 args.AppendArg(delay_, BASE_DATA_TYPE_INT, delay);
155 }
156 auto argSetId = streamFilters_->argsFilter_->NewArgs(args);
157 auto row = pidToThreadSliceRow_.at(iTid);
158 traceDataCache_->GetThreadStateData()->SetArgSetId(row, argSetId);
159 if (iowait) {
160 auto state = traceDataCache_->GetThreadStateData()->StatesData()[row];
161 if (state == TASK_UNINTERRUPTIBLE) {
162 traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_UNINTERRUPTIBLE_IO);
163 } else if (state == TASK_DK) { // state == TASK_DK
164 traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_DK_IO);
165 }
166 } else {
167 auto state = traceDataCache_->GetThreadStateData()->StatesData()[row];
168 if (state == TASK_UNINTERRUPTIBLE) {
169 traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_UNINTERRUPTIBLE_NIO);
170 } else if (state == TASK_DK) { // state == TASK_DK
171 traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_DK_NIO);
172 }
173 }
174 pidToThreadSliceRow_.erase(iTid);
175 return true;
176 }
InsertProcessExitEvent(uint64_t ts,uint64_t cpu,uint32_t pid)177 bool CpuFilter::InsertProcessExitEvent(uint64_t ts, uint64_t cpu, uint32_t pid)
178 {
179 Unused(cpu);
180 auto thread = traceDataCache_->GetThreadData(static_cast<InternalTid>(pid));
181 if (thread) {
182 thread->endT_ = ts;
183 return true;
184 }
185 return false;
186 }
187
InsertProcessFreeEvent(uint64_t ts,uint32_t pid)188 bool CpuFilter::InsertProcessFreeEvent(uint64_t ts, uint32_t pid)
189 {
190 auto thread = traceDataCache_->GetThreadData(static_cast<InternalTid>(pid));
191 if (thread) {
192 thread->endT_ = ts;
193 return true;
194 }
195 return false;
196 }
197
Finish() const198 void CpuFilter::Finish() const
199 {
200 UpdateProcessData(true);
201 auto threadState = traceDataCache_->GetConstThreadStateData();
202 auto size = threadState.Size();
203 auto rowData = threadState.ItidsData();
204 for (auto i = 0; i < size; i++) {
205 auto thread = traceDataCache_->GetThreadData(rowData[i]);
206 if (thread->internalPid_ == INVALID_UINT32) {
207 continue;
208 }
209 auto process = traceDataCache_->GetProcessData(thread->internalPid_);
210 traceDataCache_->GetThreadStateData()->UpdateTidAndPid(i, thread->tid_, process->pid_);
211 }
212 auto slice = traceDataCache_->GetConstSchedSliceData();
213 size = slice.Size();
214 for (auto i = 0; i < size; i++) {
215 traceDataCache_->GetSchedSliceData()->ReviseInternalPid(
216 i, traceDataCache_->GetThreadData(slice.InternalTidsData()[i])->internalPid_);
217 }
218 }
Clear()219 void CpuFilter::Clear()
220 {
221 cpuToRowThreadState_.clear();
222 cpuToRowSched_.clear();
223 lastWakeUpMsg_.clear();
224 internalTidToRowThreadState_.clear();
225 iTidToTransaction_.clear();
226 transactionIdToInfo_.clear();
227 pidToThreadSliceRow_.clear();
228 }
InsertWakeupEvent(uint64_t ts,uint32_t internalTid,bool isWaking)229 void CpuFilter::InsertWakeupEvent(uint64_t ts, uint32_t internalTid, bool isWaking)
230 {
231 if (!isWaking && !toRunnableTid_.count(internalTid)) {
232 toRunnableTid_[internalTid] = ts;
233 }
234 }
RemberInternalTidInStateTable(uint32_t uid,uint64_t row,uint64_t state)235 uint64_t CpuFilter::RemberInternalTidInStateTable(uint32_t uid, uint64_t row, uint64_t state)
236 {
237 if (internalTidToRowThreadState_.find(uid) != internalTidToRowThreadState_.end()) {
238 internalTidToRowThreadState_.at(uid) = TPthread{row, state};
239 } else {
240 internalTidToRowThreadState_.insert(std::make_pair(uid, TPthread{row, state}));
241 }
242 return 0;
243 }
RowOfInternalTidInStateTable(uint32_t uid) const244 uint64_t CpuFilter::RowOfInternalTidInStateTable(uint32_t uid) const
245 {
246 auto itor = internalTidToRowThreadState_.find(uid);
247 if (itor != internalTidToRowThreadState_.end()) {
248 return (*itor).second.row_;
249 }
250 return INVALID_UINT64;
251 }
ClearInternalTidInStateTable(uint32_t uid)252 void CpuFilter::ClearInternalTidInStateTable(uint32_t uid)
253 {
254 auto itor = internalTidToRowThreadState_.find(uid);
255 if (itor != internalTidToRowThreadState_.end()) {
256 internalTidToRowThreadState_.erase(itor);
257 }
258 }
StateOfInternalTidInStateTable(uint32_t uid) const259 uint64_t CpuFilter::StateOfInternalTidInStateTable(uint32_t uid) const
260 {
261 auto itor = internalTidToRowThreadState_.find(uid);
262 if (itor != internalTidToRowThreadState_.end()) {
263 return (*itor).second.state_;
264 }
265 return TASK_INVALID;
266 }
267
CheckWakeupEvent(uint32_t internalTid)268 void CpuFilter::CheckWakeupEvent(uint32_t internalTid)
269 {
270 if (toRunnableTid_.count(internalTid)) {
271 uint64_t lastrow = RowOfInternalTidInStateTable(internalTid);
272 auto lastState = StateOfInternalTidInStateTable(internalTid);
273 if (lastState == TASK_RUNNING) {
274 toRunnableTid_.erase(internalTid);
275 return;
276 }
277 if (lastrow != INVALID_UINT64) {
278 traceDataCache_->GetThreadStateData()->UpdateDuration(static_cast<TableRowId>(lastrow),
279 toRunnableTid_.at(internalTid));
280 }
281 auto index = traceDataCache_->GetThreadStateData()->AppendThreadState(
282 toRunnableTid_.at(internalTid), INVALID_TIME, INVALID_CPU, internalTid, TASK_RUNNABLE);
283 (void)RemberInternalTidInStateTable(internalTid, index, TASK_RUNNABLE);
284 toRunnableTid_.erase(internalTid);
285 }
286 return;
287 }
288
InsertRunnableBinderEvent(uint32_t transactionId,uint32_t iTid)289 void CpuFilter::InsertRunnableBinderEvent(uint32_t transactionId, uint32_t iTid)
290 {
291 if (iTidToTransaction_.find(iTid) != iTidToTransaction_.end()) {
292 iTidToTransaction_.erase(iTid);
293 }
294 iTidToTransaction_.emplace(iTid, transactionId);
295 if (transactionIdToInfo_.find(transactionId) != transactionIdToInfo_.end()) {
296 transactionIdToInfo_.erase(transactionId);
297 }
298 transactionIdToInfo_.emplace(transactionId,
299 BinderTransactionInfo{iTid, INVALID_UINT32, INVALID_UINT64, INVALID_UINT64});
300 }
301
InsertRunnableBinderRecvEvent(uint32_t transactionId,uint32_t iTid)302 void CpuFilter::InsertRunnableBinderRecvEvent(uint32_t transactionId, uint32_t iTid)
303 {
304 auto iter = transactionIdToInfo_.find(transactionId);
305 if (iter == transactionIdToInfo_.end()) {
306 return;
307 }
308 if (iter->second.iTidTo == iTid && iter->second.schedSliceRow != INVALID_UINT64 &&
309 iter->second.threadStateRow != INVALID_UINT64) {
310 traceDataCache_->GetSchedSliceData()->UpdateEndState(iter->second.schedSliceRow, TASK_RUNNABLE_BINDER);
311 traceDataCache_->GetThreadStateData()->UpdateState(iter->second.threadStateRow, TASK_RUNNABLE_BINDER);
312 }
313 TransactionClear(INVALID_UINT32, transactionId);
314 }
315
TransactionClear(uint32_t iTidFrom,uint32_t transactionId)316 void CpuFilter::TransactionClear(uint32_t iTidFrom, uint32_t transactionId)
317 {
318 if (iTidToTransaction_.find(iTidFrom) != iTidToTransaction_.end()) {
319 iTidToTransaction_.erase(iTidFrom);
320 }
321 auto iter = transactionIdToInfo_.find(transactionId);
322 if (iter != transactionIdToInfo_.end()) {
323 if (iTidToTransaction_.find(iter->second.iTidFrom) != iTidToTransaction_.end()) {
324 iTidToTransaction_.erase(iter->second.iTidFrom);
325 }
326 transactionIdToInfo_.erase(transactionId);
327 }
328 }
329
UpdateProcessData(bool isFinish) const330 void CpuFilter::UpdateProcessData(bool isFinish) const
331 {
332 for (auto i = 0; i < traceDataCache_->ThreadSize(); i++) {
333 auto thread = traceDataCache_->GetThreadData(i);
334 if (thread->internalPid_ != INVALID_UINT32) {
335 if (!isFinish) {
336 continue;
337 }
338 traceDataCache_->GetProcessData(thread->internalPid_)->threadCount_++;
339 traceDataCache_->GetProcessData(thread->internalPid_)->cpuStatesCount_ += thread->cpuStatesCount_;
340 traceDataCache_->GetProcessData(thread->internalPid_)->sliceSize_ += thread->sliceSize_;
341 traceDataCache_->GetProcessData(thread->internalPid_)->switchCount_ += thread->switchCount_;
342 continue;
343 }
344 auto ipid = traceDataCache_->AppendNewProcessData(
345 thread->tid_, traceDataCache_->GetDataFromDict(thread->nameIndex_), thread->startT_);
346 thread->internalPid_ = ipid;
347 traceDataCache_->GetProcessData(thread->internalPid_)->threadCount_++;
348 traceDataCache_->GetProcessData(thread->internalPid_)->cpuStatesCount_ += thread->cpuStatesCount_;
349 traceDataCache_->GetProcessData(thread->internalPid_)->sliceSize_ += thread->sliceSize_;
350 traceDataCache_->GetProcessData(thread->internalPid_)->switchCount_ += thread->switchCount_;
351 }
352 }
353
UpdateSchedSliceReadySize(uint64_t minSchedSliceRowToBeUpdated)354 bool CpuFilter::UpdateSchedSliceReadySize(uint64_t minSchedSliceRowToBeUpdated)
355 {
356 auto schedSlice = traceDataCache_->GetSchedSliceData();
357 for (auto i = 0; i < schedSlice->Size(); i++) {
358 traceDataCache_->GetSchedSliceData()->ReviseInternalPid(
359 i, traceDataCache_->GetThreadData(schedSlice->InternalTidsData()[i])->internalPid_);
360 }
361 schedSlice->UpdateReadySize(schedSlice->Size());
362 for (const auto &[_, schedSliceInfo] : cpuToRowSched_) {
363 if (minSchedSliceRowToBeUpdated > schedSliceInfo.row) {
364 minSchedSliceRowToBeUpdated = schedSliceInfo.row;
365 }
366 }
367 // the ready size isn't all
368 TS_CHECK_TRUE_RET(minSchedSliceRowToBeUpdated != INVALID_UINT64, true);
369 schedSlice->UpdateReadySize(minSchedSliceRowToBeUpdated);
370 TS_LOGI("minSchedSliceRowToBeUpdated=%" PRIu64 ", size=%zu, ready.size=%zu\n", minSchedSliceRowToBeUpdated,
371 schedSlice->Size(), schedSlice->readySize_);
372 for (auto &[_, schedSliceInfo] : cpuToRowSched_) {
373 schedSliceInfo.row -= schedSlice->readySize_;
374 }
375 for (auto &[_, binderTransactionInfo] : transactionIdToInfo_) {
376 binderTransactionInfo.schedSliceRow -= schedSlice->readySize_;
377 }
378 return true;
379 }
380 } // namespace TraceStreamer
381 } // namespace SysTuning
382