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 #include "string_help.h"
18 #include "string_to_numerical.h"
19
20 namespace SysTuning {
21 namespace TraceStreamer {
22 constexpr uint8_t GENERATE_VSYNC_EVENT_MAX = 5;
23 constexpr uint8_t DYNAMIC_STACK_DEPTH_MIN = 4;
24 constexpr uint16_t FPS_60 = 60;
25 constexpr uint16_t FPS_70 = 70;
26 constexpr uint16_t FPS_90 = 90;
27 constexpr uint16_t FPS_100 = 100;
28 constexpr uint16_t FPS_120 = 120;
29
AnimationFilter(TraceDataCache * dataCache,const TraceStreamerFilters * filter)30 AnimationFilter::AnimationFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter)
31 : FilterBase(dataCache, filter)
32 {
33 dynamicFrame_ = traceDataCache_->GetDynamicFrame();
34 callStackSlice_ = traceDataCache_->GetInternalSlicesData();
35 if (dynamicFrame_ == nullptr || callStackSlice_ == nullptr) {
36 TS_LOGE("dynamicFrame_ or callStackSlice_ is nullptr.");
37 }
38 }
~AnimationFilter()39 AnimationFilter::~AnimationFilter() {}
UpdateDeviceFps(const BytraceLine & line)40 bool AnimationFilter::UpdateDeviceFps(const BytraceLine& line)
41 {
42 generateVsyncCnt_++;
43 if (generateFirstTime_ == INVALID_UINT64) {
44 generateFirstTime_ = line.ts;
45 }
46 if (generateVsyncCnt_ <= GENERATE_VSYNC_EVENT_MAX) {
47 return true;
48 }
49 // calculate the average frame rate
50 uint64_t generateTimePeriod = (line.ts - generateFirstTime_) / GENERATE_VSYNC_EVENT_MAX;
51 uint32_t fps = BILLION_NANOSECONDS / generateTimePeriod;
52 if (fps < FPS_70) {
53 traceDataCache_->GetDeviceInfo()->UpdateFrameRate(FPS_60);
54 } else if (fps < FPS_100) {
55 traceDataCache_->GetDeviceInfo()->UpdateFrameRate(FPS_90);
56 } else {
57 traceDataCache_->GetDeviceInfo()->UpdateFrameRate(FPS_120);
58 }
59 TS_LOGI("physical frame rate is %u", fps);
60 return true;
61 }
UpdateDeviceScreenSize(const TracePoint & point)62 bool AnimationFilter::UpdateDeviceScreenSize(const TracePoint& point)
63 {
64 // get width and height, eg:funcArgs=(0, 0, 1344, 2772) Alpha: 1.00
65 std::smatch matcheLine;
66 std::regex entryViewArgsPattern(R"(\(\d+,\s*\d+,\s*(\d+),\s*(\d+)\))");
67 if (!std::regex_search(point.funcArgs_, matcheLine, entryViewArgsPattern)) {
68 TS_LOGE("Not support this event: %s\n", point.name_.data());
69 return false;
70 }
71 uint8_t index = 0;
72 uint32_t width = base::StrToInt<uint32_t>(matcheLine[++index].str()).value();
73 uint32_t height = base::StrToInt<uint32_t>(matcheLine[++index].str()).value();
74 traceDataCache_->GetDeviceInfo()->UpdateWidthAndHeight(matcheLine);
75 TS_LOGI("physical width is %u, height is %u", width, height);
76 return true;
77 }
UpdateDeviceInfoEvent(const TracePoint & point,const BytraceLine & line)78 bool AnimationFilter::UpdateDeviceInfoEvent(const TracePoint& point, const BytraceLine& line)
79 {
80 if (traceDataCache_->GetConstDeviceInfo().PhysicalFrameRate() == INVALID_UINT32 &&
81 StartWith(point.name_, generateVsyncCmd_)) {
82 return UpdateDeviceFps(line);
83 } else if (traceDataCache_->GetConstDeviceInfo().PhysicalWidth() == INVALID_UINT32 &&
84 point.funcPrefixId_ == entryViewCmd_) {
85 return UpdateDeviceScreenSize(point);
86 }
87 return false;
88 }
BeginDynamicFrameEvent(const TracePoint & point,size_t callStackRow)89 bool AnimationFilter::BeginDynamicFrameEvent(const TracePoint& point, size_t callStackRow)
90 {
91 // get the parent frame of data
92 const std::optional<uint64_t>& parentId = callStackSlice_->ParentIdData()[callStackRow];
93 uint8_t depth = callStackSlice_->Depths()[callStackRow];
94 if (depth < DYNAMIC_STACK_DEPTH_MIN || !parentId.has_value()) {
95 return false;
96 }
97 const std::string& curStackName = traceDataCache_->GetDataFromDict(callStackSlice_->NamesData()[callStackRow]);
98 if (!StartWith(curStackName, leashWindowCmd_)) {
99 return false;
100 }
101 // get name 'xxx' from [xxx], eg:H:RSUniRender::Process:[xxx]
102 auto nameSize = point.funcPrefix_.size() - rsUniProcessCmd_.size() - 1;
103 if (nameSize <= 0) {
104 return false;
105 }
106 auto nameIndex = traceDataCache_->GetDataIndex(point.funcPrefix_.substr(rsUniProcessCmd_.size(), nameSize));
107 auto dynamicFramRow = dynamicFrame_->AppendDynamicFrame(nameIndex);
108 callStackRowMap_.emplace(callStackRow, dynamicFramRow);
109 return true;
110 }
StartAnimationEvent(const BytraceLine & line,size_t callStackRow)111 void AnimationFilter::StartAnimationEvent(const BytraceLine& line, size_t callStackRow)
112 {
113 auto animationRow = traceDataCache_->GetAnimation()->AppendAnimation(line.ts);
114 animationCallIds_.emplace(callStackRow, animationRow);
115 }
FinishAnimationEvent(const BytraceLine & line,size_t callStackRow)116 bool AnimationFilter::FinishAnimationEvent(const BytraceLine& line, size_t callStackRow)
117 {
118 auto iter = animationCallIds_.find(callStackRow);
119 if (iter == animationCallIds_.end()) {
120 return false;
121 }
122 auto animationRow = iter->second;
123 traceDataCache_->GetAnimation()->UpdateEndPoint(animationRow, line.ts);
124 animationCallIds_.erase(iter);
125 return true;
126 }
UpdateDynamicEndTime(const uint64_t curFrameRow,uint64_t curStackRow)127 bool AnimationFilter::UpdateDynamicEndTime(const uint64_t curFrameRow, uint64_t curStackRow)
128 {
129 // update dynamicFrame endTime, filter up from the curStackRow, until reach the top
130 for (uint8_t stackCurDepth = callStackSlice_->Depths()[curStackRow]; stackCurDepth > 0; stackCurDepth--) {
131 if (!callStackSlice_->ParentIdData()[curStackRow].has_value()) {
132 return false;
133 }
134 curStackRow = callStackSlice_->ParentIdData()[curStackRow].value();
135 // use 'H:RSMainThread::DoComposition' endTime as dynamicFrame endTime
136 if (rsDoCompCmd_ == callStackSlice_->NamesData()[curStackRow]) {
137 auto endTime = callStackSlice_->TimeStampData()[curStackRow] + callStackSlice_->DursData()[curStackRow];
138 dynamicFrame_->UpdateEndTime(curFrameRow, endTime);
139 return true;
140 }
141 }
142 return false;
143 }
UpdateDynamicFrameInfo()144 void AnimationFilter::UpdateDynamicFrameInfo()
145 {
146 std::smatch matcheLine;
147 std::regex leashWindowPattern(R"((\d+),\s*(\d+),\s*(\d+),\s*(\d+)\)\s+Alpha:\s+-*(\d+\.\d+))");
148 uint64_t curStackRow = INVALID_UINT64;
149 uint64_t curFrameRow = INVALID_UINT64;
150 for (const auto& it : callStackRowMap_) {
151 curStackRow = it.first;
152 curFrameRow = it.second;
153 // update dynamicFrame pos, eg:H:RSUniRender::Process:[leashWindow25] (0, 0, 1344, 2772) Alpha: 1.00
154 auto nameDataIndex = callStackSlice_->NamesData()[curStackRow];
155 const std::string& curStackName = traceDataCache_->GetDataFromDict(nameDataIndex);
156 const std::string& funcArgs = curStackName.substr(leashWindowCmd_.size());
157 if (!std::regex_search(funcArgs, matcheLine, leashWindowPattern)) {
158 TS_LOGE("Not support this event: %s\n", funcArgs.data());
159 continue;
160 }
161 dynamicFrame_->UpdatePosition(
162 curFrameRow, matcheLine,
163 traceDataCache_->GetDataIndex((matcheLine[DYNAMICFRAME_MATCH_LAST].str()))); // alpha
164 UpdateDynamicEndTime(curFrameRow, curStackRow);
165 }
166 TS_LOGI("UpdateDynamicFrame (%zu) endTime and pos finish", callStackRowMap_.size());
167 // this can only be cleared by the UpdateDynamicFrameInfo function
168 callStackRowMap_.clear();
169 }
Clear()170 void AnimationFilter::Clear()
171 {
172 generateFirstTime_ = INVALID_UINT64;
173 generateVsyncCnt_ = 0;
174 animationCallIds_.clear();
175 }
176 } // namespace TraceStreamer
177 } // namespace SysTuning
178