• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "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().TimeStamsData()[lastRow];
71         if ((cpu != lastCpu) && (lastState == TASK_RUNNING) && (ts == lastStartTs)) {
72             isChangeCpu = true;
73         }
74         if (!isChangeCpu) {
75             CheckWakeupEvent(prevPid);
76             traceDataCache_->GetThreadStateData()->UpdateDuration(static_cast<TableRowId>(lastRow), ts);
77             streamFilters_->processFilter_->AddCpuStateCount(prevPid);
78             auto thread = traceDataCache_->GetThreadData(prevPid);
79             if (thread && !thread->switchCount_) {
80                 thread->switchCount_ = 1;
81             }
82         }
83     }
84 
85     if (!isChangeCpu) {
86         auto threadStateRow =
87             traceDataCache_->GetThreadStateData()->AppendThreadState(ts, INVALID_TIME, INVALID_CPU, prevPid, prevState);
88         btInfo.threadStateRow = threadStateRow;
89         if (prevState == TASK_UNINTERRUPTIBLE || prevState == TASK_DK) {
90             if (!pidToThreadSliceRow_.count(prevPid)) {
91                 pidToThreadSliceRow_.emplace(std::make_pair(prevPid, threadStateRow));
92             } else {
93                 pidToThreadSliceRow_.at(prevPid) = threadStateRow;
94             }
95         }
96         (void)RemberInternalTidInStateTable(prevPid, threadStateRow, prevState);
97     }
98 }
InsertSwitchEvent(uint64_t ts,uint64_t cpu,uint32_t prevPid,uint64_t prevPior,uint64_t prevState,uint32_t nextPid,uint64_t nextPior,DataIndex nextInfo)99 void CpuFilter::InsertSwitchEvent(uint64_t ts,
100                                   uint64_t cpu,
101                                   uint32_t prevPid,
102                                   uint64_t prevPior,
103                                   uint64_t prevState,
104                                   uint32_t nextPid,
105                                   uint64_t nextPior,
106                                   DataIndex nextInfo)
107 {
108     BinderTransactionInfo btInfo = {prevPid, nextPid, INVALID_UINT64, INVALID_UINT64};
109     auto index = traceDataCache_->GetSchedSliceData()->AppendSchedSlice(ts, INVALID_UINT64, cpu, nextPid, 0, nextPior);
110     auto prevTidOnCpu = cpuToRowSched_.find(cpu);
111     if (prevTidOnCpu != cpuToRowSched_.end()) {
112         traceDataCache_->GetSchedSliceData()->Update(prevTidOnCpu->second.row, ts, prevState);
113         btInfo.schedSliceRow = prevTidOnCpu->second.row;
114         cpuToRowSched_.at(cpu).row = index;
115     } else {
116         cpuToRowSched_.insert(std::make_pair(cpu, RowPos{nextPid, index}));
117     }
118     if (nextPid) {
119         ProcNextPidSwitchEvent(ts, cpu, prevPid, nextPid, nextInfo);
120     }
121     if (prevPid) {
122         ProcPrevPidSwitchEvent(ts, cpu, prevPid, prevState, btInfo);
123     }
124     if (traceDataCache_->BinderRunnableTraceEnabled() && iTidToTransaction_.find(prevPid) != iTidToTransaction_.end()) {
125         uint64_t transactionId = iTidToTransaction_.at(prevPid);
126         auto iter = transactionIdToInfo_.find(transactionId);
127         if (prevState != TASK_NEW || iter == transactionIdToInfo_.end() || iter->second.iTidFrom != prevPid ||
128             btInfo.schedSliceRow == INVALID_UINT64 || btInfo.threadStateRow == INVALID_UINT64) {
129             TransactionClear(prevState, transactionId);
130             return;
131         }
132         transactionIdToInfo_[transactionId] = btInfo;
133     }
134 }
135 
InsertBlockedReasonEvent(uint64_t ts,uint64_t cpu,uint32_t iTid,bool iowait,DataIndex caller,uint32_t delay)136 bool CpuFilter::InsertBlockedReasonEvent(uint64_t ts,
137                                          uint64_t cpu,
138                                          uint32_t iTid,
139                                          bool iowait,
140                                          DataIndex caller,
141                                          uint32_t delay)
142 {
143     if (pidToThreadSliceRow_.count(iTid)) {
144         // ArgSet
145         ArgsSet args;
146         args.AppendArg(ioWait_, BASE_DATA_TYPE_INT, iowait);
147         args.AppendArg(caller_, BASE_DATA_TYPE_STRING, caller);
148         if (delay != INVALID_UINT32) {
149             args.AppendArg(delay_, BASE_DATA_TYPE_INT, delay);
150         }
151         auto argSetId = streamFilters_->argsFilter_->NewArgs(args);
152         auto row = pidToThreadSliceRow_.at(iTid);
153         traceDataCache_->GetThreadStateData()->SetArgSetId(row, argSetId);
154         if (iowait) {
155             auto state = traceDataCache_->GetThreadStateData()->StatesData()[row];
156             if (state == TASK_UNINTERRUPTIBLE) {
157                 traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_UNINTERRUPTIBLE_IO);
158             } else if (state == TASK_DK) { // state == TASK_DK
159                 traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_DK_IO);
160             }
161         } else {
162             auto state = traceDataCache_->GetThreadStateData()->StatesData()[row];
163             if (state == TASK_UNINTERRUPTIBLE) {
164                 traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_UNINTERRUPTIBLE_NIO);
165             } else if (state == TASK_DK) { // state == TASK_DK
166                 traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_DK_NIO);
167             }
168         }
169         pidToThreadSliceRow_.erase(iTid);
170     }
171     return true;
172 }
InsertProcessExitEvent(uint64_t ts,uint64_t cpu,uint32_t pid)173 bool CpuFilter::InsertProcessExitEvent(uint64_t ts, uint64_t cpu, uint32_t pid)
174 {
175     Unused(cpu);
176     auto thread = traceDataCache_->GetThreadData(static_cast<InternalTid>(pid));
177     if (thread) {
178         thread->endT_ = ts;
179         return true;
180     }
181     return false;
182 }
183 
InsertProcessFreeEvent(uint64_t ts,uint32_t pid)184 bool CpuFilter::InsertProcessFreeEvent(uint64_t ts, uint32_t pid)
185 {
186     auto thread = traceDataCache_->GetThreadData(static_cast<InternalTid>(pid));
187     if (thread) {
188         thread->endT_ = ts;
189         return true;
190     }
191     return false;
192 }
193 
Finish() const194 void CpuFilter::Finish() const
195 {
196     auto size = traceDataCache_->ThreadSize();
197     for (auto i = 0; i < size; i++) {
198         auto thread = traceDataCache_->GetThreadData(i);
199         if (thread->internalPid_ != INVALID_UINT32) {
200             traceDataCache_->GetProcessData(thread->internalPid_)->threadCount_++;
201             traceDataCache_->GetProcessData(thread->internalPid_)->cpuStatesCount_ += thread->cpuStatesCount_;
202             traceDataCache_->GetProcessData(thread->internalPid_)->sliceSize_ += thread->sliceSize_;
203             traceDataCache_->GetProcessData(thread->internalPid_)->switchCount_ += thread->switchCount_;
204             continue;
205         }
206         auto ipid = traceDataCache_->AppendNewProcessData(
207             thread->tid_, traceDataCache_->GetDataFromDict(thread->nameIndex_), thread->startT_);
208         thread->internalPid_ = ipid;
209         traceDataCache_->GetProcessData(thread->internalPid_)->threadCount_++;
210         traceDataCache_->GetProcessData(thread->internalPid_)->cpuStatesCount_ += thread->cpuStatesCount_;
211         traceDataCache_->GetProcessData(thread->internalPid_)->sliceSize_ += thread->sliceSize_;
212         traceDataCache_->GetProcessData(thread->internalPid_)->switchCount_ += thread->switchCount_;
213     }
214     auto threadState = traceDataCache_->GetConstThreadStateData();
215     size = threadState.Size();
216     auto rowData = threadState.ItidsData();
217     for (auto i = 0; i < size; i++) {
218         auto thread = traceDataCache_->GetThreadData(rowData[i]);
219         if (thread->internalPid_ == INVALID_UINT32) {
220             continue;
221         }
222         auto process = traceDataCache_->GetProcessData(thread->internalPid_);
223         traceDataCache_->GetThreadStateData()->UpdateTidAndPid(i, thread->tid_, process->pid_);
224     }
225     auto slice = traceDataCache_->GetConstSchedSliceData();
226     size = slice.Size();
227     for (auto i = 0; i < size; i++) {
228         traceDataCache_->GetSchedSliceData()->ReviseInternalPid(
229             i, traceDataCache_->GetThreadData(slice.InternalTidsData()[i])->internalPid_);
230     }
231 }
Clear()232 void CpuFilter::Clear()
233 {
234     cpuToRowThreadState_.clear();
235     cpuToRowSched_.clear();
236     lastWakeUpMsg_.clear();
237     internalTidToRowThreadState_.clear();
238     iTidToTransaction_.clear();
239     transactionIdToInfo_.clear();
240     pidToThreadSliceRow_.clear();
241 }
InsertWakeupEvent(uint64_t ts,uint32_t internalTid,bool isWaking)242 void CpuFilter::InsertWakeupEvent(uint64_t ts, uint32_t internalTid, bool isWaking)
243 {
244     if (!isWaking && !toRunnableTid_.count(internalTid)) {
245         toRunnableTid_[internalTid] = ts;
246     }
247 }
RemberInternalTidInStateTable(uint32_t uid,uint64_t row,uint64_t state)248 uint64_t CpuFilter::RemberInternalTidInStateTable(uint32_t uid, uint64_t row, uint64_t state)
249 {
250     if (internalTidToRowThreadState_.find(uid) != internalTidToRowThreadState_.end()) {
251         internalTidToRowThreadState_.at(uid) = TPthread{row, state};
252     } else {
253         internalTidToRowThreadState_.insert(std::make_pair(uid, TPthread{row, state}));
254     }
255     return 0;
256 }
RowOfInternalTidInStateTable(uint32_t uid) const257 uint64_t CpuFilter::RowOfInternalTidInStateTable(uint32_t uid) const
258 {
259     auto itor = internalTidToRowThreadState_.find(uid);
260     if (itor != internalTidToRowThreadState_.end()) {
261         return (*itor).second.row_;
262     }
263     return INVALID_UINT64;
264 }
ClearInternalTidInStateTable(uint32_t uid)265 void CpuFilter::ClearInternalTidInStateTable(uint32_t uid)
266 {
267     auto itor = internalTidToRowThreadState_.find(uid);
268     if (itor != internalTidToRowThreadState_.end()) {
269         internalTidToRowThreadState_.erase(itor);
270     }
271 }
StateOfInternalTidInStateTable(uint32_t uid) const272 uint64_t CpuFilter::StateOfInternalTidInStateTable(uint32_t uid) const
273 {
274     auto itor = internalTidToRowThreadState_.find(uid);
275     if (itor != internalTidToRowThreadState_.end()) {
276         return (*itor).second.state_;
277     }
278     return TASK_INVALID;
279 }
280 
CheckWakeupEvent(uint32_t internalTid)281 void CpuFilter::CheckWakeupEvent(uint32_t internalTid)
282 {
283     if (toRunnableTid_.count(internalTid)) {
284         uint64_t lastrow = RowOfInternalTidInStateTable(internalTid);
285         auto lastState = StateOfInternalTidInStateTable(internalTid);
286         if (lastState == TASK_RUNNING) {
287             toRunnableTid_.erase(internalTid);
288             return;
289         }
290         if (lastrow != INVALID_UINT64) {
291             traceDataCache_->GetThreadStateData()->UpdateDuration(static_cast<TableRowId>(lastrow),
292                                                                   toRunnableTid_.at(internalTid));
293         }
294         auto index = traceDataCache_->GetThreadStateData()->AppendThreadState(
295             toRunnableTid_.at(internalTid), INVALID_TIME, INVALID_CPU, internalTid, TASK_RUNNABLE);
296         (void)RemberInternalTidInStateTable(internalTid, index, TASK_RUNNABLE);
297         toRunnableTid_.erase(internalTid);
298     }
299     return;
300 }
301 
InsertRunnableBinderEvent(uint32_t transactionId,uint32_t iTid)302 void CpuFilter::InsertRunnableBinderEvent(uint32_t transactionId, uint32_t iTid)
303 {
304     if (iTidToTransaction_.find(iTid) != iTidToTransaction_.end()) {
305         iTidToTransaction_.erase(iTid);
306     }
307     iTidToTransaction_.emplace(iTid, transactionId);
308     if (transactionIdToInfo_.find(transactionId) != transactionIdToInfo_.end()) {
309         transactionIdToInfo_.erase(transactionId);
310     }
311     transactionIdToInfo_.emplace(transactionId,
312                                  BinderTransactionInfo{iTid, INVALID_UINT32, INVALID_UINT64, INVALID_UINT64});
313 }
314 
InsertRunnableBinderRecvEvent(uint32_t transactionId,uint32_t iTid)315 void CpuFilter::InsertRunnableBinderRecvEvent(uint32_t transactionId, uint32_t iTid)
316 {
317     auto iter = transactionIdToInfo_.find(transactionId);
318     if (iter == transactionIdToInfo_.end()) {
319         return;
320     }
321     if (iter->second.iTidTo == iTid && iter->second.schedSliceRow != INVALID_UINT64 &&
322         iter->second.threadStateRow != INVALID_UINT64) {
323         traceDataCache_->GetSchedSliceData()->UpdateEndState(iter->second.schedSliceRow, TASK_RUNNABLE_BINDER);
324         traceDataCache_->GetThreadStateData()->UpdateState(iter->second.threadStateRow, TASK_RUNNABLE_BINDER);
325     }
326     TransactionClear(INVALID_UINT32, transactionId);
327 }
328 
TransactionClear(uint32_t iTidFrom,uint32_t transactionId)329 void CpuFilter::TransactionClear(uint32_t iTidFrom, uint32_t transactionId)
330 {
331     if (iTidToTransaction_.find(iTidFrom) != iTidToTransaction_.end()) {
332         iTidToTransaction_.erase(iTidFrom);
333     }
334     auto iter = transactionIdToInfo_.find(transactionId);
335     if (iter != transactionIdToInfo_.end()) {
336         if (iTidToTransaction_.find(iter->second.iTidFrom) != iTidToTransaction_.end()) {
337             iTidToTransaction_.erase(iter->second.iTidFrom);
338         }
339         transactionIdToInfo_.erase(transactionId);
340     }
341 }
342 } // namespace TraceStreamer
343 } // namespace SysTuning
344