• 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 "animation_filter.h"
17 
18 namespace SysTuning {
19 namespace TraceStreamer {
20 constexpr uint8_t ANIMATION_INFO_NUM_MIN = 2;
21 constexpr uint8_t GENERATE_VSYNC_EVENT_MAX = 5;
22 constexpr uint8_t DYNAMIC_STACK_DEPTH_MIN = 2;
23 constexpr uint16_t FPS_60 = 60;
24 constexpr uint16_t FPS_70 = 70;
25 constexpr uint16_t FPS_90 = 90;
26 constexpr uint16_t FPS_100 = 100;
27 constexpr uint16_t FPS_120 = 120;
28 
AnimationFilter(TraceDataCache * dataCache,const TraceStreamerFilters * filter)29 AnimationFilter::AnimationFilter(TraceDataCache *dataCache, const TraceStreamerFilters *filter)
30     : FilterBase(dataCache, filter)
31 {
32     dynamicFrame_ = traceDataCache_->GetDynamicFrame();
33     callStackSlice_ = traceDataCache_->GetInternalSlicesData();
34     if (dynamicFrame_ == nullptr || callStackSlice_ == nullptr) {
35         TS_LOGE("dynamicFrame_ or callStackSlice_ is nullptr.");
36     }
37 }
~AnimationFilter()38 AnimationFilter::~AnimationFilter() {}
InitAnimationStartEvents()39 void AnimationFilter::InitAnimationStartEvents()
40 {
41     auto res = streamFilters_->configFilter_->GetAnimationConfig().GetOnAnimationStartEvents();
42     for (auto &eventName : res) {
43         onAnimationStartEvents_.insert(traceDataCache_->GetDataIndex(eventName));
44     }
45 }
UpdateDeviceFps(const BytraceLine & line)46 bool AnimationFilter::UpdateDeviceFps(const BytraceLine &line)
47 {
48     generateVsyncCnt_++;
49     if (generateFirstTime_ == INVALID_UINT64) {
50         generateFirstTime_ = line.ts;
51     }
52     if (generateVsyncCnt_ <= GENERATE_VSYNC_EVENT_MAX) {
53         return true;
54     }
55     // calculate the average frame rate
56     uint64_t generateTimePeriod = (line.ts - generateFirstTime_) / GENERATE_VSYNC_EVENT_MAX;
57     uint32_t fps = BILLION_NANOSECONDS / generateTimePeriod;
58     if (fps < FPS_70) {
59         traceDataCache_->GetDeviceInfo()->UpdateFrameRate(FPS_60);
60     } else if (fps < FPS_100) {
61         traceDataCache_->GetDeviceInfo()->UpdateFrameRate(FPS_90);
62     } else {
63         traceDataCache_->GetDeviceInfo()->UpdateFrameRate(FPS_120);
64     }
65     TS_LOGI("physical frame rate is %u", fps);
66     return true;
67 }
UpdateDeviceScreenSize(const TracePoint & point)68 bool AnimationFilter::UpdateDeviceScreenSize(const TracePoint &point)
69 {
70     // get width and height, eg:funcArgs=(0, 0, 1344, 2772) Alpha: 1.00
71     std::smatch matcheLine;
72     std::regex screenSizePattern(R"(\(\d+,\s*\d+,\s*(\d+),\s*(\d+)\))");
73     if (!std::regex_search(point.funcArgs_, matcheLine, screenSizePattern)) {
74         TS_LOGE("Not support this event: %s\n", point.name_.data());
75         return false;
76     }
77     uint8_t index = 0;
78     uint32_t width = base::StrToInt<uint32_t>(matcheLine[++index].str()).value();
79     uint32_t height = base::StrToInt<uint32_t>(matcheLine[++index].str()).value();
80     traceDataCache_->GetDeviceInfo()->UpdateWidthAndHeight(matcheLine);
81     TS_LOGI("physical width is %u, height is %u", width, height);
82     return true;
83 }
UpdateDeviceInfoEvent(const TracePoint & point,const BytraceLine & line)84 bool AnimationFilter::UpdateDeviceInfoEvent(const TracePoint &point, const BytraceLine &line)
85 {
86     if (traceDataCache_->GetConstDeviceInfo().PhysicalFrameRate() == INVALID_UINT32 &&
87         streamFilters_->configFilter_->GetAnimationConfig().CheckIfFrameRateCmd(point.name_)) {
88         return UpdateDeviceFps(line);
89     } else if (traceDataCache_->GetConstDeviceInfo().PhysicalWidth() == INVALID_UINT32 &&
90                streamFilters_->configFilter_->GetAnimationConfig().CheckIfScreenSizeCmd(point.name_)) {
91         return UpdateDeviceScreenSize(point);
92     }
93     return false;
94 }
BeginDynamicFrameEvent(const TracePoint & point,size_t callStackRow)95 bool AnimationFilter::BeginDynamicFrameEvent(const TracePoint &point, size_t callStackRow)
96 {
97     if (streamFilters_->configFilter_->GetAnimationConfig().CheckIfParallelCmd(point.name_)) {
98         isNewAnimation_ = true;
99         return true;
100     }
101     if (streamFilters_->configFilter_->GetAnimationConfig().CheckIfFrameCountCmd(point.name_)) {
102         frameCountRows_.insert(callStackRow);
103         return true;
104     } else if (streamFilters_->configFilter_->GetAnimationConfig().CheckIfRealFrameRateCmd(point.name_)) {
105         // eg: `frame rate is 88.61: APP_LIST_FLING, com.taobao.taobao, pages/Index`
106         auto infos = SplitStringToVec(point.funcArgs_, ": ");
107         auto curRealFrameRateFlagInadex = traceDataCache_->GetDataIndex("H:" + infos.back());
108         auto iter = realFrameRateFlagsDict_.find(curRealFrameRateFlagInadex);
109         TS_CHECK_TRUE_RET(iter != realFrameRateFlagsDict_.end(), false);
110         auto animationRow = iter->second;
111         auto curRealFrameRate = SplitStringToVec(infos.front(), " ").back();
112         auto curFrameNum = "0:";
113         traceDataCache_->GetAnimation()->UpdateFrameInfo(animationRow,
114                                                          traceDataCache_->GetDataIndex(curFrameNum + curRealFrameRate));
115         return true;
116     } else if (streamFilters_->configFilter_->GetAnimationConfig().CheckIfFrameBeginCmd(point.name_)) {
117         // get the parent frame of data
118         const std::optional<uint64_t> &parentId = callStackSlice_->ParentIdData()[callStackRow];
119         uint8_t depth = callStackSlice_->Depths()[callStackRow];
120         TS_CHECK_TRUE_RET(depth >= DYNAMIC_STACK_DEPTH_MIN && parentId.has_value(), false);
121         callstackWithDynamicFrameRows_.emplace_back(callStackRow);
122         return true;
123     }
124     return false;
125 }
EndDynamicFrameEvent(uint64_t ts,size_t callStackRow)126 bool AnimationFilter::EndDynamicFrameEvent(uint64_t ts, size_t callStackRow)
127 {
128     auto iter = frameCountRows_.find(callStackRow);
129     if (iter == frameCountRows_.end()) {
130         return false;
131     }
132     frameCountEndTimes_.emplace_back(ts);
133     frameCountRows_.erase(iter);
134     return true;
135 }
StartAnimationEvent(const BytraceLine & line,const TracePoint & point,size_t callStackRow)136 bool AnimationFilter::StartAnimationEvent(const BytraceLine &line, const TracePoint &point, size_t callStackRow)
137 {
138     auto infos = SplitStringToVec(point.name_, ", ");
139     auto curAnimationIndex = traceDataCache_->GetDataIndex(infos.front());
140     auto startEventIter = onAnimationStartEvents_.find(curAnimationIndex);
141     TS_CHECK_TRUE_RET(startEventIter != onAnimationStartEvents_.end() && infos.size() >= ANIMATION_INFO_NUM_MIN, false);
142     auto nameIndex = traceDataCache_->GetDataIndex(infos[0] + ", " + infos[1]);
143     // pop for '.': '1693876195576.'
144     auto &inputTimeStr = infos[inputTimeIndex_];
145     if (inputTimeStr.back() == '.') {
146         inputTimeStr.pop_back();
147     }
148     uint64_t inputTime = base::StrToInt<uint64_t>(inputTimeStr).value();
149     inputTime =
150         streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, inputTime * ONE_MILLION_NANOSECONDS);
151     auto startPoint = line.ts;
152     auto animationRow = traceDataCache_->GetAnimation()->AppendAnimation(inputTime, startPoint, nameIndex);
153     animationCallIds_.emplace(callStackRow, animationRow);
154     realFrameRateFlagsDict_[traceDataCache_->GetDataIndex(point.name_)] = animationRow;
155     return true;
156 }
FinishAnimationEvent(const BytraceLine & line,size_t callStackRow)157 bool AnimationFilter::FinishAnimationEvent(const BytraceLine &line, size_t callStackRow)
158 {
159     auto iter = animationCallIds_.find(callStackRow);
160     if (iter == animationCallIds_.end()) {
161         return false;
162     }
163     auto animationRow = iter->second;
164     traceDataCache_->GetAnimation()->UpdateEndPoint(animationRow, line.ts);
165     animationCallIds_.erase(iter);
166     return true;
167 }
UpdateDynamicEndTime(const uint64_t curFrameRow,uint64_t curStackRow)168 bool AnimationFilter::UpdateDynamicEndTime(const uint64_t curFrameRow, uint64_t curStackRow)
169 {
170     // update dynamicFrame endTime, filter up from the curStackRow, until reach the top
171     for (uint8_t stackCurDepth = callStackSlice_->Depths()[curStackRow]; stackCurDepth > 0; stackCurDepth--) {
172         if (!callStackSlice_->ParentIdData()[curStackRow].has_value()) {
173             return false;
174         }
175         curStackRow = callStackSlice_->ParentIdData()[curStackRow].value();
176         // use frameEndTimeCmd_'s endTime as dynamicFrame endTime
177         auto nameIndex = callStackSlice_->NamesData()[curStackRow];
178         if ((!isNewAnimation_ && StartWith(traceDataCache_->GetDataFromDict(nameIndex), frameEndTimeCmd_)) ||
179             streamFilters_->configFilter_->GetAnimationConfig().CheckIfFrameEndTimeCmd(
180                 traceDataCache_->GetDataFromDict(nameIndex))) {
181             auto endTime = callStackSlice_->TimeStampData()[curStackRow] + callStackSlice_->DursData()[curStackRow];
182             dynamicFrame_->UpdateEndTime(curFrameRow, endTime);
183             return true;
184         }
185     }
186     return false;
187 }
UpdateFrameInfo()188 void AnimationFilter::UpdateFrameInfo()
189 {
190     auto animation = traceDataCache_->GetAnimation();
191     for (size_t row = 0; row < animation->Size(); row++) {
192         if (animation->FrameInfos()[row] != INVALID_UINT64) {
193             continue;
194         }
195         auto firstFrameTimeIter =
196             std::lower_bound(frameCountEndTimes_.begin(), frameCountEndTimes_.end(), animation->StartPoints()[row]);
197         uint64_t frameNum = 0;
198         while (firstFrameTimeIter != frameCountEndTimes_.end() && *firstFrameTimeIter <= animation->EndPoints()[row]) {
199             ++frameNum;
200             ++firstFrameTimeIter;
201         }
202         auto curRealFrameRate = ":0";
203         animation->UpdateFrameInfo(row, traceDataCache_->GetDataIndex(std::to_string(frameNum) + curRealFrameRate));
204     }
205     frameCountRows_.clear();
206     frameCountEndTimes_.clear();
207     realFrameRateFlagsDict_.clear();
208 }
UpdateDynamicFrameInfo()209 void AnimationFilter::UpdateDynamicFrameInfo()
210 {
211     std::smatch matcheLine;
212     for (auto it = callstackWithDynamicFrameRows_.begin(); it != callstackWithDynamicFrameRows_.end(); ++it) {
213         // update dynamicFrame pix, eg:H:RSUniRender::Process:[xxx] (0, 0, 1344, 2772) Alpha: 1.00
214         auto nameDataIndex = callStackSlice_->NamesData()[*it];
215         const std::string &curStackName = traceDataCache_->GetDataFromDict(nameDataIndex);
216         if (!std::regex_search(curStackName, matcheLine, framePixPattern_)) {
217             TS_LOGE("Not support this event: %s\n", curStackName.data());
218             continue;
219         }
220         int32_t index = dynamicFrame_->AppendDynamicFrame(
221             traceDataCache_->GetDataIndex(matcheLine[1].str()), matcheLine,
222             traceDataCache_->GetDataIndex((matcheLine[DYNAMICFRAME_MATCH_LAST].str())));
223         if (index == INVALID_INT32) {
224             TS_LOGE("Failed to append dynamic frame: %s\n", curStackName.data());
225             continue;
226         }
227         UpdateDynamicEndTime(index, *it);
228     }
229     TS_LOGI("UpdateDynamicFrame (%zu) endTime and pos finish", callstackWithDynamicFrameRows_.size());
230     // this can only be cleared by the UpdateDynamicFrameInfo function
231     callstackWithDynamicFrameRows_.clear();
232 }
Clear()233 void AnimationFilter::Clear()
234 {
235     generateFirstTime_ = INVALID_UINT64;
236     generateVsyncCnt_ = 0;
237     animationCallIds_.clear();
238 }
239 } // namespace TraceStreamer
240 } // namespace SysTuning
241