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 "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_, 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_, frameCountCmd_)) {
101 frameCountRows_.insert(callStackRow);
102 return true;
103 } else if (StartWith(point.name_, realFrameRateCmd_)) {
104 // eg: `frame rate is 88.61: APP_LIST_FLING, com.taobao.taobao, pages/Index`
105 auto infos = SplitStringToVec(point.funcArgs_, ": ");
106 auto curRealFrameRateFlagInadex = traceDataCache_->GetDataIndex("H:" + infos.back());
107 auto iter = realFrameRateFlagsDict_.find(curRealFrameRateFlagInadex);
108 TS_CHECK_TRUE_RET(iter != realFrameRateFlagsDict_.end(), false);
109 auto animationRow = iter->second;
110 auto curRealFrameRate = SplitStringToVec(infos.front(), " ").back();
111 auto curFrameNum = "0:";
112 traceDataCache_->GetAnimation()->UpdateFrameInfo(animationRow,
113 traceDataCache_->GetDataIndex(curFrameNum + curRealFrameRate));
114 return true;
115 } else if (!StartWith(point.name_, frameBeginCmd_)) {
116 return false;
117 }
118 // get the parent frame of data
119 const std::optional<uint64_t>& parentId = callStackSlice_->ParentIdData()[callStackRow];
120 uint8_t depth = callStackSlice_->Depths()[callStackRow];
121 TS_CHECK_TRUE_RET(depth >= DYNAMIC_STACK_DEPTH_MIN && parentId.has_value(), false);
122 // get name 'xxx' from [xxx], eg:H:RSUniRender::Process:[xxx]
123 auto nameSize = point.funcPrefix_.size() - frameBeginPrefix_.size() - 1;
124 TS_CHECK_TRUE_RET(nameSize > 0, false);
125 auto nameIndex = traceDataCache_->GetDataIndex(point.funcPrefix_.substr(frameBeginPrefix_.size(), nameSize));
126 auto dynamicFramRow = dynamicFrame_->AppendDynamicFrame(nameIndex);
127 callStackRowMap_.emplace(callStackRow, dynamicFramRow);
128 return true;
129 }
EndDynamicFrameEvent(uint64_t ts,size_t callStackRow)130 bool AnimationFilter::EndDynamicFrameEvent(uint64_t ts, size_t callStackRow)
131 {
132 auto iter = frameCountRows_.find(callStackRow);
133 if (iter == frameCountRows_.end()) {
134 return false;
135 }
136 frameCountEndTimes_.emplace_back(ts);
137 frameCountRows_.erase(iter);
138 return true;
139 }
StartAnimationEvent(const BytraceLine & line,const TracePoint & point,size_t callStackRow)140 bool AnimationFilter::StartAnimationEvent(const BytraceLine& line, const TracePoint& point, size_t callStackRow)
141 {
142 auto infos = SplitStringToVec(point.name_, ", ");
143 auto curAnimationIndex = traceDataCache_->GetDataIndex(infos.front());
144 auto startEventIter = onAnimationStartEvents_.find(curAnimationIndex);
145 TS_CHECK_TRUE_RET(startEventIter != onAnimationStartEvents_.end() && infos.size() >= ANIMATION_INFO_NUM_MIN, false);
146 auto nameIndex = traceDataCache_->GetDataIndex(infos[0] + ", " + infos[1]);
147 // pop for '.': '1693876195576.'
148 auto& inputTimeStr = infos[inputTimeIndex_];
149 if (inputTimeStr.back() == '.') {
150 inputTimeStr.pop_back();
151 }
152 uint64_t inputTime = base::StrToInt<uint64_t>(inputTimeStr).value();
153 inputTime =
154 streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, inputTime * ONE_MILLION_NANOSECONDS);
155 auto startPoint = line.ts;
156 auto animationRow = traceDataCache_->GetAnimation()->AppendAnimation(inputTime, startPoint, nameIndex);
157 animationCallIds_.emplace(callStackRow, animationRow);
158 realFrameRateFlagsDict_[traceDataCache_->GetDataIndex(point.name_)] = animationRow;
159 return true;
160 }
FinishAnimationEvent(const BytraceLine & line,size_t callStackRow)161 bool AnimationFilter::FinishAnimationEvent(const BytraceLine& line, size_t callStackRow)
162 {
163 auto iter = animationCallIds_.find(callStackRow);
164 if (iter == animationCallIds_.end()) {
165 return false;
166 }
167 auto animationRow = iter->second;
168 traceDataCache_->GetAnimation()->UpdateEndPoint(animationRow, line.ts);
169 animationCallIds_.erase(iter);
170 return true;
171 }
UpdateDynamicEndTime(const uint64_t curFrameRow,uint64_t curStackRow)172 bool AnimationFilter::UpdateDynamicEndTime(const uint64_t curFrameRow, uint64_t curStackRow)
173 {
174 // update dynamicFrame endTime, filter up from the curStackRow, until reach the top
175 for (uint8_t stackCurDepth = callStackSlice_->Depths()[curStackRow]; stackCurDepth > 0; stackCurDepth--) {
176 if (!callStackSlice_->ParentIdData()[curStackRow].has_value()) {
177 return false;
178 }
179 curStackRow = callStackSlice_->ParentIdData()[curStackRow].value();
180 // use frameEndTimeCmd_'s endTime as dynamicFrame endTime
181 if (frameEndTimeCmd_ == callStackSlice_->NamesData()[curStackRow]) {
182 auto endTime = callStackSlice_->TimeStampData()[curStackRow] + callStackSlice_->DursData()[curStackRow];
183 dynamicFrame_->UpdateEndTime(curFrameRow, endTime);
184 return true;
185 }
186 }
187 return false;
188 }
UpdateFrameInfo()189 void AnimationFilter::UpdateFrameInfo()
190 {
191 auto animation = traceDataCache_->GetAnimation();
192 for (size_t row = 0; row < animation->Size(); row++) {
193 if (animation->FrameInfos()[row] != INVALID_UINT64) {
194 continue;
195 }
196 auto firstFrameTimeIter =
197 std::lower_bound(frameCountEndTimes_.begin(), frameCountEndTimes_.end(), animation->StartPoints()[row]);
198 uint64_t frameNum = 0;
199 while (firstFrameTimeIter != frameCountEndTimes_.end() && *firstFrameTimeIter <= animation->EndPoints()[row]) {
200 ++frameNum;
201 ++firstFrameTimeIter;
202 }
203 auto curRealFrameRate = ":0";
204 animation->UpdateFrameInfo(row, traceDataCache_->GetDataIndex(std::to_string(frameNum) + curRealFrameRate));
205 }
206 frameCountRows_.clear();
207 frameCountEndTimes_.clear();
208 realFrameRateFlagsDict_.clear();
209 }
UpdateDynamicFrameInfo()210 void AnimationFilter::UpdateDynamicFrameInfo()
211 {
212 std::smatch matcheLine;
213 std::regex framePixPattern(R"((\d+),\s*(\d+),\s*(\d+),\s*(\d+)\)\s+Alpha:\s+-*(\d+\.\d+))");
214 for (const auto& it : callStackRowMap_) {
215 // update dynamicFrame pix, eg:H:RSUniRender::Process:[xxx] (0, 0, 1344, 2772) Alpha: 1.00
216 auto nameDataIndex = callStackSlice_->NamesData()[it.first];
217 const std::string& curStackName = traceDataCache_->GetDataFromDict(nameDataIndex);
218 const std::string& funcArgs = curStackName.substr(frameBeginCmd_.size());
219 if (!std::regex_search(funcArgs, matcheLine, framePixPattern)) {
220 TS_LOGE("Not support this event: %s\n", funcArgs.data());
221 continue;
222 }
223 dynamicFrame_->UpdatePosition(
224 it.second, matcheLine,
225 traceDataCache_->GetDataIndex((matcheLine[DYNAMICFRAME_MATCH_LAST].str()))); // alpha
226 UpdateDynamicEndTime(it.second, it.first);
227 }
228 TS_LOGI("UpdateDynamicFrame (%zu) endTime and pos finish", callStackRowMap_.size());
229 // this can only be cleared by the UpdateDynamicFrameInfo function
230 callStackRowMap_.clear();
231 }
Clear()232 void AnimationFilter::Clear()
233 {
234 generateFirstTime_ = INVALID_UINT64;
235 generateVsyncCnt_ = 0;
236 animationCallIds_.clear();
237 }
238 } // namespace TraceStreamer
239 } // namespace SysTuning
240