• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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