• 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 "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