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