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