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