• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (streamFilters_->configFilter_->GetSwitchConfig().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 (streamFilters_->configFilter_->GetSwitchConfig().BinderRunnableConfigEnabled() &&
132         iTidToTransaction_.find(prevPid) != iTidToTransaction_.end()) {
133         uint64_t transactionId = iTidToTransaction_.at(prevPid);
134         auto iter = transactionIdToInfo_.find(transactionId);
135         if (prevState != TASK_NEW || iter == transactionIdToInfo_.end() || iter->second.iTidFrom != prevPid ||
136             btInfo.schedSliceRow == INVALID_UINT64 || btInfo.threadStateRow == INVALID_UINT64) {
137             TransactionClear(prevState, transactionId);
138             return;
139         }
140         transactionIdToInfo_[transactionId] = btInfo;
141     }
142 }
143 
InsertBlockedReasonEvent(uint64_t cpu,uint32_t iTid,bool iowait,DataIndex caller,uint32_t delay)144 bool CpuFilter::InsertBlockedReasonEvent(uint64_t cpu, uint32_t iTid, bool iowait, DataIndex caller, uint32_t delay)
145 {
146     if (pidToThreadSliceRow_.count(iTid) == 0) {
147         return false;
148     }
149 
150     // ArgSet
151     ArgsSet args;
152     args.AppendArg(ioWait_, BASE_DATA_TYPE_INT, iowait);
153     args.AppendArg(caller_, BASE_DATA_TYPE_STRING, caller);
154     if (delay != INVALID_UINT32) {
155         args.AppendArg(delay_, BASE_DATA_TYPE_INT, delay);
156     }
157     auto argSetId = streamFilters_->argsFilter_->NewArgs(args);
158     auto row = pidToThreadSliceRow_.at(iTid);
159     traceDataCache_->GetThreadStateData()->SetArgSetId(row, argSetId);
160     if (iowait) {
161         auto state = traceDataCache_->GetThreadStateData()->StatesData()[row];
162         if (state == TASK_UNINTERRUPTIBLE) {
163             traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_UNINTERRUPTIBLE_IO);
164         } else if (state == TASK_DK) { // state == TASK_DK
165             traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_DK_IO);
166         }
167     } else {
168         auto state = traceDataCache_->GetThreadStateData()->StatesData()[row];
169         if (state == TASK_UNINTERRUPTIBLE) {
170             traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_UNINTERRUPTIBLE_NIO);
171         } else if (state == TASK_DK) { // state == TASK_DK
172             traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_DK_NIO);
173         }
174     }
175     pidToThreadSliceRow_.erase(iTid);
176     return true;
177 }
InsertProcessExitEvent(uint64_t ts,uint64_t cpu,uint32_t pid)178 bool CpuFilter::InsertProcessExitEvent(uint64_t ts, uint64_t cpu, uint32_t pid)
179 {
180     Unused(cpu);
181     auto thread = traceDataCache_->GetThreadData(static_cast<InternalTid>(pid));
182     if (thread) {
183         thread->endT_ = ts;
184         return true;
185     }
186     return false;
187 }
188 
InsertProcessFreeEvent(uint64_t ts,uint32_t pid)189 bool CpuFilter::InsertProcessFreeEvent(uint64_t ts, uint32_t pid)
190 {
191     auto thread = traceDataCache_->GetThreadData(static_cast<InternalTid>(pid));
192     if (thread) {
193         thread->endT_ = ts;
194         return true;
195     }
196     return false;
197 }
198 
Finish() const199 void CpuFilter::Finish() const
200 {
201     UpdateProcessData(true);
202     auto threadState = traceDataCache_->GetConstThreadStateData();
203     auto size = threadState.Size();
204     auto rowData = threadState.ItidsData();
205     for (auto i = 0; i < size; i++) {
206         auto thread = traceDataCache_->GetThreadData(rowData[i]);
207         if (thread->internalPid_ == INVALID_UINT32) {
208             continue;
209         }
210         auto process = traceDataCache_->GetProcessData(thread->internalPid_);
211         traceDataCache_->GetThreadStateData()->UpdateTidAndPid(i, thread->tid_, process->pid_);
212     }
213     auto slice = traceDataCache_->GetConstSchedSliceData();
214     size = slice.Size();
215     for (auto i = 0; i < size; i++) {
216         traceDataCache_->GetSchedSliceData()->ReviseInternalPid(
217             i, traceDataCache_->GetThreadData(slice.InternalTidsData()[i])->internalPid_);
218     }
219 }
Clear()220 void CpuFilter::Clear()
221 {
222     cpuToRowThreadState_.clear();
223     cpuToRowSched_.clear();
224     lastWakeUpMsg_.clear();
225     internalTidToRowThreadState_.clear();
226     iTidToTransaction_.clear();
227     transactionIdToInfo_.clear();
228     pidToThreadSliceRow_.clear();
229 }
InsertWakeupEvent(uint64_t ts,uint32_t internalTid,bool isWaking)230 void CpuFilter::InsertWakeupEvent(uint64_t ts, uint32_t internalTid, bool isWaking)
231 {
232     if (!isWaking && !toRunnableTid_.count(internalTid)) {
233         toRunnableTid_[internalTid] = ts;
234     }
235 }
RemberInternalTidInStateTable(uint32_t uid,uint64_t row,uint64_t state)236 uint64_t CpuFilter::RemberInternalTidInStateTable(uint32_t uid, uint64_t row, uint64_t state)
237 {
238     if (internalTidToRowThreadState_.find(uid) != internalTidToRowThreadState_.end()) {
239         internalTidToRowThreadState_.at(uid) = TPthread{row, state};
240     } else {
241         internalTidToRowThreadState_.insert(std::make_pair(uid, TPthread{row, state}));
242     }
243     return 0;
244 }
RowOfInternalTidInStateTable(uint32_t uid) const245 uint64_t CpuFilter::RowOfInternalTidInStateTable(uint32_t uid) const
246 {
247     auto itor = internalTidToRowThreadState_.find(uid);
248     if (itor != internalTidToRowThreadState_.end()) {
249         return (*itor).second.row_;
250     }
251     return INVALID_UINT64;
252 }
ClearInternalTidInStateTable(uint32_t uid)253 void CpuFilter::ClearInternalTidInStateTable(uint32_t uid)
254 {
255     auto itor = internalTidToRowThreadState_.find(uid);
256     if (itor != internalTidToRowThreadState_.end()) {
257         internalTidToRowThreadState_.erase(itor);
258     }
259 }
StateOfInternalTidInStateTable(uint32_t uid) const260 uint64_t CpuFilter::StateOfInternalTidInStateTable(uint32_t uid) const
261 {
262     auto itor = internalTidToRowThreadState_.find(uid);
263     if (itor != internalTidToRowThreadState_.end()) {
264         return (*itor).second.state_;
265     }
266     return TASK_INVALID;
267 }
268 
CheckWakeupEvent(uint32_t internalTid)269 void CpuFilter::CheckWakeupEvent(uint32_t internalTid)
270 {
271     if (toRunnableTid_.count(internalTid)) {
272         uint64_t lastrow = RowOfInternalTidInStateTable(internalTid);
273         auto lastState = StateOfInternalTidInStateTable(internalTid);
274         if (lastState == TASK_RUNNING) {
275             toRunnableTid_.erase(internalTid);
276             return;
277         }
278         if (lastrow != INVALID_UINT64) {
279             traceDataCache_->GetThreadStateData()->UpdateDuration(static_cast<TableRowId>(lastrow),
280                                                                   toRunnableTid_.at(internalTid));
281         }
282         auto index = traceDataCache_->GetThreadStateData()->AppendThreadState(
283             toRunnableTid_.at(internalTid), INVALID_TIME, INVALID_CPU, internalTid, TASK_RUNNABLE);
284         (void)RemberInternalTidInStateTable(internalTid, index, TASK_RUNNABLE);
285         toRunnableTid_.erase(internalTid);
286     }
287     return;
288 }
289 
InsertRunnableBinderEvent(uint32_t transactionId,uint32_t iTid)290 void CpuFilter::InsertRunnableBinderEvent(uint32_t transactionId, uint32_t iTid)
291 {
292     if (iTidToTransaction_.find(iTid) != iTidToTransaction_.end()) {
293         iTidToTransaction_.erase(iTid);
294     }
295     iTidToTransaction_.emplace(iTid, transactionId);
296     if (transactionIdToInfo_.find(transactionId) != transactionIdToInfo_.end()) {
297         transactionIdToInfo_.erase(transactionId);
298     }
299     transactionIdToInfo_.emplace(transactionId,
300                                  BinderTransactionInfo{iTid, INVALID_UINT32, INVALID_UINT64, INVALID_UINT64});
301 }
302 
InsertRunnableBinderRecvEvent(uint32_t transactionId,uint32_t iTid)303 void CpuFilter::InsertRunnableBinderRecvEvent(uint32_t transactionId, uint32_t iTid)
304 {
305     auto iter = transactionIdToInfo_.find(transactionId);
306     if (iter == transactionIdToInfo_.end()) {
307         return;
308     }
309     if (iter->second.iTidTo == iTid && iter->second.schedSliceRow != INVALID_UINT64 &&
310         iter->second.threadStateRow != INVALID_UINT64) {
311         traceDataCache_->GetSchedSliceData()->UpdateEndState(iter->second.schedSliceRow, TASK_RUNNABLE_BINDER);
312         traceDataCache_->GetThreadStateData()->UpdateState(iter->second.threadStateRow, TASK_RUNNABLE_BINDER);
313     }
314     TransactionClear(INVALID_UINT32, transactionId);
315 }
316 
TransactionClear(uint32_t iTidFrom,uint32_t transactionId)317 void CpuFilter::TransactionClear(uint32_t iTidFrom, uint32_t transactionId)
318 {
319     if (iTidToTransaction_.find(iTidFrom) != iTidToTransaction_.end()) {
320         iTidToTransaction_.erase(iTidFrom);
321     }
322     auto iter = transactionIdToInfo_.find(transactionId);
323     if (iter != transactionIdToInfo_.end()) {
324         if (iTidToTransaction_.find(iter->second.iTidFrom) != iTidToTransaction_.end()) {
325             iTidToTransaction_.erase(iter->second.iTidFrom);
326         }
327         transactionIdToInfo_.erase(transactionId);
328     }
329 }
330 
UpdateProcessData(bool isFinish) const331 void CpuFilter::UpdateProcessData(bool isFinish) const
332 {
333     for (auto i = 0; i < traceDataCache_->ThreadSize(); i++) {
334         auto thread = traceDataCache_->GetThreadData(i);
335         if (thread->internalPid_ != INVALID_UINT32) {
336             if (!isFinish) {
337                 continue;
338             }
339             traceDataCache_->GetProcessData(thread->internalPid_)->threadCount_++;
340             traceDataCache_->GetProcessData(thread->internalPid_)->cpuStatesCount_ += thread->cpuStatesCount_;
341             traceDataCache_->GetProcessData(thread->internalPid_)->sliceSize_ += thread->sliceSize_;
342             traceDataCache_->GetProcessData(thread->internalPid_)->switchCount_ += thread->switchCount_;
343             continue;
344         }
345         auto ipid = traceDataCache_->AppendNewProcessData(
346             thread->tid_, traceDataCache_->GetDataFromDict(thread->nameIndex_), thread->startT_);
347         thread->internalPid_ = ipid;
348         traceDataCache_->GetProcessData(thread->internalPid_)->threadCount_++;
349         traceDataCache_->GetProcessData(thread->internalPid_)->cpuStatesCount_ += thread->cpuStatesCount_;
350         traceDataCache_->GetProcessData(thread->internalPid_)->sliceSize_ += thread->sliceSize_;
351         traceDataCache_->GetProcessData(thread->internalPid_)->switchCount_ += thread->switchCount_;
352     }
353 }
354 
UpdateSchedSliceReadySize(uint64_t minSchedSliceRowToBeUpdated)355 bool CpuFilter::UpdateSchedSliceReadySize(uint64_t minSchedSliceRowToBeUpdated)
356 {
357     auto schedSlice = traceDataCache_->GetSchedSliceData();
358     for (auto i = 0; i < schedSlice->Size(); i++) {
359         traceDataCache_->GetSchedSliceData()->ReviseInternalPid(
360             i, traceDataCache_->GetThreadData(schedSlice->InternalTidsData()[i])->internalPid_);
361     }
362     schedSlice->UpdateReadySize(schedSlice->Size());
363     for (const auto &[_, schedSliceInfo] : cpuToRowSched_) {
364         if (minSchedSliceRowToBeUpdated > schedSliceInfo.row) {
365             minSchedSliceRowToBeUpdated = schedSliceInfo.row;
366         }
367     }
368     // the ready size isn't all
369     TS_CHECK_TRUE_RET(minSchedSliceRowToBeUpdated != INVALID_UINT64, true);
370     schedSlice->UpdateReadySize(minSchedSliceRowToBeUpdated);
371     TS_LOGI("minSchedSliceRowToBeUpdated=%" PRIu64 ", size=%zu, ready.size=%zu\n", minSchedSliceRowToBeUpdated,
372             schedSlice->Size(), schedSlice->readySize_);
373     for (auto &[_, schedSliceInfo] : cpuToRowSched_) {
374         schedSliceInfo.row -= schedSlice->readySize_;
375     }
376     for (auto &[_, binderTransactionInfo] : transactionIdToInfo_) {
377         binderTransactionInfo.schedSliceRow -= schedSlice->readySize_;
378     }
379     return true;
380 }
381 } // namespace TraceStreamer
382 } // namespace SysTuning
383