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 "slice_filter.h"
17 #include <cstdint>
18 #include <limits>
19 #include <optional>
20
21 #include "args_filter.h"
22 #include "log.h"
23 #include "measure_filter.h"
24 #include "process_filter.h"
25 #include "stat_filter.h"
26 #include "string_to_numerical.h"
27 #include "ts_common.h"
28
29 namespace SysTuning {
30 namespace TraceStreamer {
31 using namespace SysTuning::base;
SliceFilter(TraceDataCache * dataCache,const TraceStreamerFilters * filter)32 SliceFilter::SliceFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter)
33 : FilterBase(dataCache, filter), asyncEventMap_(INVALID_UINT64)
34 {
35 }
36
37 SliceFilter::~SliceFilter() = default;
38
BeginSlice(const std::string & comm,uint64_t timestamp,uint32_t pid,uint32_t threadGroupId,DataIndex cat,DataIndex nameIndex)39 size_t SliceFilter::BeginSlice(const std::string& comm,
40 uint64_t timestamp,
41 uint32_t pid,
42 uint32_t threadGroupId,
43 DataIndex cat,
44 DataIndex nameIndex)
45 {
46 InternalTid internalTid = INVALID_UTID;
47 if (threadGroupId > 0) {
48 internalTid = streamFilters_->processFilter_->UpdateOrCreateThreadWithPidAndName(pid, threadGroupId, comm);
49 pidTothreadGroupId_[pid] = threadGroupId;
50 } else {
51 internalTid = streamFilters_->processFilter_->UpdateOrCreateThreadWithName(timestamp, pid, comm);
52 }
53 // make a SliceData DataItem, {timestamp, dur, internalTid, cat, nameIndex}
54 struct SliceData sliceData = {timestamp, -1, internalTid, cat, nameIndex};
55 ArgsSet args;
56 return StartSlice(timestamp, pid, cat, nameIndex, args, sliceData);
57 }
58
IrqHandlerEntry(uint64_t timestamp,uint32_t cpu,DataIndex catalog,DataIndex nameIndex)59 void SliceFilter::IrqHandlerEntry(uint64_t timestamp, uint32_t cpu, DataIndex catalog, DataIndex nameIndex)
60 {
61 struct SliceData sliceData = {timestamp, 0, cpu, catalog, nameIndex};
62 auto slices = traceDataCache_->GetIrqData();
63 size_t index = slices->AppendInternalSlice(
64 sliceData.timestamp, sliceData.duration, sliceData.internalTid, sliceData.cat,
65 GetNameASCIISumNoNum(traceDataCache_->GetDataFromDict(sliceData.name)), sliceData.name, 0, std::nullopt);
66 if (irqEventMap_.count(cpu)) {
67 // not match
68 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_DATA_LOST);
69 irqEventMap_.at(cpu) = {timestamp, index};
70 } else {
71 irqEventMap_[cpu] = {timestamp, index};
72 }
73 return;
74 }
75
IrqHandlerExit(uint64_t timestamp,uint32_t cpu,ArgsSet args)76 void SliceFilter::IrqHandlerExit(uint64_t timestamp, uint32_t cpu, ArgsSet args)
77 {
78 if (!irqEventMap_.count(cpu)) {
79 // not match
80 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_NOTMATCH);
81 return;
82 }
83 uint32_t argSetId = INVALID_UINT32;
84 auto slices = traceDataCache_->GetIrqData();
85 argSetId = streamFilters_->argsFilter_->NewArgs(args);
86 slices->SetIrqDurAndArg(irqEventMap_.at(cpu).row, timestamp, argSetId);
87 irqEventMap_.erase(cpu);
88 return;
89 }
90
SoftIrqEntry(uint64_t timestamp,uint32_t cpu,DataIndex catalog,DataIndex nameIndex)91 void SliceFilter::SoftIrqEntry(uint64_t timestamp, uint32_t cpu, DataIndex catalog, DataIndex nameIndex)
92 {
93 struct SliceData sliceData = {timestamp, 0, cpu, catalog, nameIndex};
94 auto slices = traceDataCache_->GetIrqData();
95 size_t index = slices->AppendInternalSlice(
96 sliceData.timestamp, sliceData.duration, sliceData.internalTid, sliceData.cat,
97 GetNameASCIISumNoNum(traceDataCache_->GetDataFromDict(sliceData.name)), sliceData.name, 0, std::nullopt);
98 if (softIrqEventMap_.count(cpu)) {
99 // not match
100 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SOFTIRQ_ENTRY, STAT_EVENT_DATA_LOST);
101 softIrqEventMap_.at(cpu) = {timestamp, index};
102 } else {
103 softIrqEventMap_[cpu] = {timestamp, index};
104 }
105 return;
106 }
107
SoftIrqExit(uint64_t timestamp,uint32_t cpu,ArgsSet args)108 void SliceFilter::SoftIrqExit(uint64_t timestamp, uint32_t cpu, ArgsSet args)
109 {
110 if (!softIrqEventMap_.count(cpu)) {
111 // not match
112 streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_LOST);
113 return;
114 }
115 uint32_t argSetId = INVALID_UINT32;
116 auto slices = traceDataCache_->GetIrqData();
117 argSetId = streamFilters_->argsFilter_->NewArgs(args);
118 slices->SetIrqDurAndArg(softIrqEventMap_.at(cpu).row, timestamp, argSetId);
119 softIrqEventMap_.erase(cpu);
120 return;
121 }
122
RememberSliceData(InternalTid internalTid,std::unordered_map<InternalTid,StackOfSlices> & stackMap,SliceData & slice,uint32_t depth,uint64_t index)123 void SliceFilter::RememberSliceData(InternalTid internalTid,
124 std::unordered_map<InternalTid, StackOfSlices>& stackMap,
125 SliceData& slice,
126 uint32_t depth,
127 uint64_t index)
128 {
129 if (stackMap.find(internalTid) == stackMap.end()) {
130 auto& sliceStack = stackMap[internalTid].sliceStack; // this can be a empty call, but it does not matter
131 slice.depth = depth;
132 slice.index = index;
133 sliceStack.push_back(slice);
134 } else {
135 auto& sliceStack = stackMap.at(internalTid).sliceStack; // this can be a empty call, but it does not matter
136 slice.depth = depth;
137 slice.index = index;
138 sliceStack.push_back(slice);
139 }
140 }
AsyncBinder(uint64_t timestamp,uint32_t pid,DataIndex cat,DataIndex nameIndex,ArgsSet & args)141 size_t SliceFilter::AsyncBinder(uint64_t timestamp, uint32_t pid, DataIndex cat, DataIndex nameIndex, ArgsSet& args)
142 {
143 InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timestamp, pid);
144 struct SliceData sliceData = {timestamp, 0, internalTid, cat, nameIndex};
145 return StartSlice(timestamp, pid, cat, nameIndex, args, std::move(sliceData));
146 }
CurrentDepth(InternalTid internalTid)147 uint8_t SliceFilter::CurrentDepth(InternalTid internalTid)
148 {
149 if (depthHolder_.find(internalTid) == depthHolder_.end()) {
150 return 0;
151 }
152 auto& depthMap = depthHolder_.at(internalTid);
153 auto depthSize = depthMap.size();
154 auto lastIndex = 0;
155 for (int32_t i = depthSize - 1; i >= 0; i--) {
156 if (depthMap.at(i)) {
157 return i;
158 }
159 }
160 return 0;
161 }
UpdateDepth(bool increase,InternalTid internalTid,int32_t depth)162 uint8_t SliceFilter::UpdateDepth(bool increase, InternalTid internalTid, int32_t depth)
163 {
164 if (increase) {
165 if (depthHolder_.find(internalTid) == depthHolder_.end()) {
166 StackOnDepth tmp;
167 tmp.insert(std::make_pair(0, true));
168 depthHolder_.insert(std::make_pair(internalTid, tmp));
169 return 0;
170 }
171 auto& depthMap = depthHolder_.at(internalTid);
172 auto depthSize = depthMap.size();
173 auto lastIndex = 0;
174 for (int32_t i = depthSize - 1; i >= 0; i--) {
175 if (depthMap.at(i) && (i == depthSize - 1)) {
176 depthMap.insert(std::make_pair(depthSize, true));
177 return depthSize;
178 }
179 if (depthMap.at(i)) {
180 break;
181 }
182 lastIndex = i;
183 }
184
185 if (!depthMap.at(lastIndex)) {
186 depthMap.at(lastIndex) = true;
187 return lastIndex;
188 }
189 } else {
190 if (depthHolder_.find(internalTid) == depthHolder_.end()) {
191 TS_LOGE("internalTid not found");
192 return 0;
193 }
194 auto& depthMap = depthHolder_.at(internalTid);
195 if (depthMap.find(depth) == depthMap.end()) {
196 return 0;
197 }
198 depthMap.at(depth) = false;
199 }
200 return depth;
201 }
202
CloseUnMatchedSlice(int64_t ts,SlicesStack & stack,InternalTid itid)203 void SliceFilter::CloseUnMatchedSlice(int64_t ts, SlicesStack& stack, InternalTid itid)
204 {
205 auto slices = traceDataCache_->GetInternalSlicesData();
206 bool incomplete = false;
207 for (int i = stack.size() - 1; i >= 0; i--) {
208 uint32_t sliceIdx = stack[i].index;
209 int64_t startTs = slices->TimeStamData()[sliceIdx];
210 int64_t dur = slices->DursData()[sliceIdx];
211 int64_t endTs = startTs + dur;
212 if (dur == -1) {
213 incomplete = true;
214 continue;
215 }
216 if (incomplete) {
217 if (ts <= endTs) {
218 continue;
219 }
220 for (int j = stack.size() - 1; j > i; --j) {
221 uint32_t childIdx = stack[i].index;
222 slices->SetDur(childIdx, endTs - slices->TimeStamData()[childIdx]);
223 stack.pop_back();
224 }
225 stack.pop_back();
226 incomplete = false;
227 continue;
228 }
229 if (endTs <= ts) {
230 stack.pop_back();
231 }
232 }
233 }
234
MatchingIncompleteSliceIndex(const SlicesStack & stack,DataIndex category,DataIndex name)235 int32_t SliceFilter::MatchingIncompleteSliceIndex(const SlicesStack& stack, DataIndex category, DataIndex name)
236 {
237 auto slices = traceDataCache_->GetInternalSlicesData();
238 for (int i = stack.size() - 1; i >= 0; i--) {
239 uint32_t sliceIdx = stack[i].index;
240 if (slices->DursData()[sliceIdx] != -1) {
241 continue;
242 }
243 const DataIndex& categoryLast = slices->CatsData()[sliceIdx];
244 if (category != INVALID_UINT64 && (categoryLast != INVALID_UINT64 && category != categoryLast)) {
245 continue;
246 }
247 const DataIndex& nameLast = slices->NamesData()[sliceIdx];
248 if (name != INVALID_UINT64 && nameLast != INVALID_UINT64 && name != nameLast) {
249 continue;
250 }
251 return static_cast<int32_t>(i);
252 }
253 return -1;
254 }
StartSlice(uint64_t timestamp,uint32_t pid,DataIndex cat,DataIndex nameIndex,ArgsSet & args,SliceData sliceData)255 size_t SliceFilter::StartSlice(
256 uint64_t timestamp, uint32_t pid, DataIndex cat, DataIndex nameIndex, ArgsSet& args, SliceData sliceData)
257 {
258 InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timestamp, pid);
259 auto& sliceStack = binderStackMap_[internalTid];
260 auto& stack = sliceStack.sliceStack;
261 if (sliceStack.isAsyncEvent) {
262 sliceStack.asyncEventCount++;
263 sliceStack.asyncEventLastBeginTs = timestamp;
264 if (!stack.empty()) {
265 return INVALID_UINT32;
266 }
267 }
268 // keep slice of thread
269 CloseUnMatchedSlice(timestamp, stack, internalTid);
270 uint32_t depth = stack.size();
271 auto slices = traceDataCache_->GetInternalSlicesData();
272 uint32_t parentId = depth == 0 ? INVALID_UINT32 : slices->IdsData()[stack.back().index];
273
274 size_t index = slices->AppendInternalSlice(
275 sliceData.timestamp, sliceData.duration, sliceData.internalTid, sliceData.cat,
276 GetNameASCIISumNoNum(traceDataCache_->GetDataFromDict(sliceData.name)), sliceData.name, 0, parentId);
277 if (depth >= std::numeric_limits<uint8_t>::max()) {
278 return INVALID_UINT32;
279 }
280 slices->SetDepth(index, depth);
281
282 uint32_t argSetId = INVALID_UINT32;
283 if (args.valuesMap_.size()) {
284 if (args.inserted_) {
285 argSetId = args.argSetId_;
286 } else {
287 argSetId = streamFilters_->argsFilter_->NewArgs(args);
288 sliceRowToArgsSetId_[index] = argSetId;
289 argsSetIdToSliceRow_[argSetId] = static_cast<uint32_t>(index);
290 args.argSetId_ = argSetId;
291 args.inserted_ = true;
292 }
293 // set ArgSetId here
294 slices->SetArgSetId(index, argSetId);
295 }
296 sliceData.argSetId = argSetId;
297 RememberSliceData(sliceData.internalTid, binderStackMap_, sliceData, depth, index);
298 return index;
299 }
BeginBinder(uint64_t timestamp,uint32_t pid,DataIndex cat,DataIndex nameIndex,ArgsSet args)300 size_t SliceFilter::BeginBinder(uint64_t timestamp, uint32_t pid, DataIndex cat, DataIndex nameIndex, ArgsSet args)
301 {
302 InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timestamp, pid);
303 struct SliceData sliceData = {timestamp, -1, internalTid, cat, nameIndex};
304 return StartSlice(timestamp, pid, cat, nameIndex, args, std::move(sliceData));
305 }
306
CompleteSlice(uint64_t timestamp,uint32_t pid,DataIndex category,DataIndex name,ArgsSet args)307 size_t SliceFilter::CompleteSlice(uint64_t timestamp, uint32_t pid, DataIndex category, DataIndex name, ArgsSet args)
308 {
309 InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timestamp, pid);
310 if (binderStackMap_.find(internalTid) == binderStackMap_.end()) {
311 return INVALID_INT32;
312 }
313 auto& stackInfo = binderStackMap_[internalTid];
314 SlicesStack& stack = stackInfo.sliceStack;
315 CloseUnMatchedSlice(timestamp, stack, internalTid);
316 if (stack.empty()) {
317 TS_LOGE("a slice end do not match a slice start event");
318 callEventDisMatchCount++;
319 return INVALID_INT32;
320 }
321 auto stackIdx = MatchingIncompleteSliceIndex(stack, category, name);
322 if (stackIdx < 0) {
323 TS_LOGE("MatchingIncompleteSliceIndex failed");
324 return INVALID_INT32;
325 }
326 auto lastRow = stack[stackIdx].index;
327 auto slices = traceDataCache_->GetInternalSlicesData();
328 slices->SetDuration(lastRow, timestamp);
329
330 auto argSize = sliceRowToArgsSetId_.count(lastRow);
331 size_t argSetId = 0;
332 if (args.valuesMap_.size()) {
333 if (!argSize) {
334 argSetId = streamFilters_->argsFilter_->NewArgs(args);
335 sliceRowToArgsSetId_[lastRow] = argSetId;
336 slices->SetArgSetId(lastRow, argSetId);
337 } else {
338 argSetId = sliceRowToArgsSetId_.at(lastRow);
339 }
340 streamFilters_->argsFilter_->AppendArgs(args, argSetId);
341 }
342 if (stackInfo.isAsyncEvent) {
343 ArgsSet args;
344 args.AppendArg(asyncBeginCountId_, BASE_DATA_TYPE_INT, stackInfo.asyncEventCount);
345 args.AppendArg(asyncBeginTsId_, BASE_DATA_TYPE_INT, stackInfo.asyncEventLastBeginTs);
346 if (!argSetId) {
347 argSetId = streamFilters_->argsFilter_->NewArgs(args);
348 sliceRowToArgsSetId_[lastRow] = argSetId;
349 slices->SetArgSetId(lastRow, argSetId);
350 } else {
351 streamFilters_->argsFilter_->AppendArgs(args, argSetId);
352 }
353 }
354 if (stackIdx == stack.size() - 1) {
355 stack.pop_back();
356 }
357 streamFilters_->processFilter_->AddThreadSliceNum(internalTid);
358 return lastRow;
359 }
EndBinder(uint64_t timestamp,uint32_t pid,DataIndex category,DataIndex name,ArgsSet args)360 size_t SliceFilter::EndBinder(uint64_t timestamp, uint32_t pid, DataIndex category, DataIndex name, ArgsSet args)
361 {
362 return CompleteSlice(timestamp, pid, category, name, args);
363 }
AddArgs(uint32_t tid,DataIndex key1,DataIndex key2,ArgsSet & args)364 std::tuple<uint64_t, uint32_t> SliceFilter::AddArgs(uint32_t tid, DataIndex key1, DataIndex key2, ArgsSet& args)
365 {
366 InternalTid internalTid = streamFilters_->processFilter_->GetInternalTid(tid);
367 if (binderStackMap_.find(internalTid) == binderStackMap_.end()) {
368 return std::make_tuple(INVALID_UINT32, INVALID_UINT32);
369 }
370 auto& stack = binderStackMap_[internalTid];
371 auto idx = MatchingIncompleteSliceIndex(stack.sliceStack, key1, key2);
372 if (idx < 0) {
373 return std::make_tuple(INVALID_UINT32, INVALID_UINT32);
374 }
375 uint32_t argSetId = stack.sliceStack[idx].argSetId;
376 if (argSetId == INVALID_UINT32) {
377 argSetId = streamFilters_->argsFilter_->NewArgs(args);
378 sliceRowToArgsSetId_[stack.sliceStack[idx].index] = argSetId;
379 stack.sliceStack[idx].argSetId = argSetId;
380 } else {
381 streamFilters_->argsFilter_->AppendArgs(args, argSetId);
382 }
383 return std::make_tuple(stack.sliceStack[idx].index, argSetId);
384 }
StartAsyncSlice(uint64_t timestamp,uint32_t pid,uint32_t threadGroupId,uint64_t cookie,DataIndex nameIndex)385 void SliceFilter::StartAsyncSlice(uint64_t timestamp,
386 uint32_t pid,
387 uint32_t threadGroupId,
388 uint64_t cookie,
389 DataIndex nameIndex)
390 {
391 UNUSED(pid);
392 InternalPid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timestamp, threadGroupId);
393
394 auto lastFilterId = asyncEventMap_.Find(internalTid, cookie, nameIndex);
395 auto slices = traceDataCache_->GetInternalSlicesData();
396 if (lastFilterId != INVALID_UINT64) {
397 asyncEventDisMatchCount++;
398 return;
399 }
400 asyncEventSize_++;
401 // a pid, cookie and function name determain a callstack
402 asyncEventMap_.Insert(internalTid, cookie, nameIndex, asyncEventSize_);
403 // the IDE need a depth to paint call slice in different position of the canvas, the depth of async call
404 // do not mean the parent-to-child relationship, it is different from no-async call
405 uint8_t depth = 0;
406 size_t index = slices->AppendInternalAsyncSlice(timestamp, -1, internalTid, INVALID_UINT64,
407 GetNameASCIISumNoNum(traceDataCache_->GetDataFromDict(nameIndex)),
408 nameIndex, depth, cookie, std::nullopt);
409 asyncEventFilterMap_.insert(std::make_pair(asyncEventSize_, AsyncEvent{timestamp, index}));
410 }
411
FinishAsyncSlice(uint64_t timestamp,uint32_t pid,uint32_t threadGroupId,uint64_t cookie,DataIndex nameIndex)412 void SliceFilter::FinishAsyncSlice(uint64_t timestamp,
413 uint32_t pid,
414 uint32_t threadGroupId,
415 uint64_t cookie,
416 DataIndex nameIndex)
417 {
418 UNUSED(pid);
419 InternalPid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timestamp, threadGroupId);
420 auto lastFilterId = asyncEventMap_.Find(internalTid, cookie, nameIndex);
421 auto slices = traceDataCache_->GetInternalSlicesData();
422 if (lastFilterId == INVALID_UINT64) { // if failed
423 asyncEventDisMatchCount++;
424 return;
425 }
426 if (asyncEventFilterMap_.find(lastFilterId) == asyncEventFilterMap_.end()) {
427 TS_LOGE("logic error");
428 asyncEventDisMatchCount++;
429 return;
430 }
431 // update timestamp
432 asyncEventFilterMap_.at(lastFilterId).timestamp = timestamp;
433 slices->SetDuration(asyncEventFilterMap_.at(lastFilterId).row, timestamp);
434 asyncEventFilterMap_.erase(lastFilterId);
435 asyncEventMap_.Erase(internalTid, cookie, nameIndex);
436 streamFilters_->processFilter_->AddThreadSliceNum(internalTid);
437 }
438
439
EndSlice(uint64_t timestamp,uint32_t pid,uint32_t threadGroupId,DataIndex category,DataIndex name)440 size_t SliceFilter::EndSlice(
441 uint64_t timestamp, uint32_t pid, uint32_t threadGroupId, DataIndex category, DataIndex name)
442 {
443 return CompleteSlice(timestamp, pid, category, name);
444 }
445
Clear()446 void SliceFilter::Clear()
447 {
448 asyncEventMap_.Clear();
449 asyncNoEndingEventMap_.clear();
450 irqEventMap_.clear();
451 softIrqEventMap_.clear();
452 asyncEventFilterMap_.clear();
453 sliceStackMap_.clear();
454 depthHolder_.clear();
455 sliceRowToArgsSetId_.clear();
456 argsSetIdToSliceRow_.clear();
457 argsSetIdToSliceRow_.clear();
458 argsSet_.clear();
459 }
460 } // namespace TraceStreamer
461 } // namespace SysTuning
462