• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "base/log/jank_frame_report.h"
17 
18 #include <chrono>
19 
20 #include "render_service_client/core/transaction/rs_interfaces.h"
21 
22 #include "base/log/ace_trace.h"
23 #include "base/perfmonitor/perf_monitor.h"
24 #include "base/log/event_report.h"
25 
26 namespace OHOS::Ace {
27 namespace {
28 constexpr uint32_t JANK_FRAME_6_FREQ = 0;
29 constexpr uint32_t JANK_FRAME_15_FREQ = 1;
30 constexpr uint32_t JANK_FRAME_20_FREQ = 2;
31 constexpr uint32_t JANK_FRAME_36_FREQ = 3;
32 constexpr uint32_t JANK_FRAME_48_FREQ = 4;
33 constexpr uint32_t JANK_FRAME_60_FREQ = 5;
34 constexpr uint32_t JANK_FRAME_120_FREQ = 6;
35 constexpr uint32_t JANK_FRAME_180_FREQ = 7;
36 constexpr uint32_t JANK_SIZE = 8;
37 
38 using namespace std;
39 using namespace std::chrono;
40 
41 template<class T>
GetSystemTimestamp()42 int64_t GetSystemTimestamp()
43 {
44     return duration_cast<T>(system_clock::now().time_since_epoch()).count();
45 }
46 
47 template<class T>
GetSteadyTimestamp()48 int64_t GetSteadyTimestamp()
49 {
50     return duration_cast<T>(steady_clock::now().time_since_epoch()).count();
51 }
52 
GetJankRange(double jank)53 uint32_t GetJankRange(double jank)
54 {
55     if (jank < 6.0f) {
56         return JANK_FRAME_6_FREQ;
57     }
58     if (jank < 15.0f) {
59         return JANK_FRAME_15_FREQ;
60     }
61     if (jank < 20.0f) {
62         return JANK_FRAME_20_FREQ;
63     }
64     if (jank < 36.0f) {
65         return JANK_FRAME_36_FREQ;
66     }
67     if (jank < 48.0f) {
68         return JANK_FRAME_48_FREQ;
69     }
70     if (jank < 60.0f) {
71         return JANK_FRAME_60_FREQ;
72     }
73     if (jank < 120.0f) {
74         return JANK_FRAME_120_FREQ;
75     }
76     return JANK_FRAME_180_FREQ;
77 }
78 
79 class SteadyTimeRecorder {
80 public:
81     static steady_clock::time_point begin;
Begin()82     static void Begin()
83     {
84         begin = steady_clock::now();
85     }
End()86     static int64_t End()
87     {
88         auto end = steady_clock::now();
89         return duration_cast<milliseconds>(end - begin).count();
90     }
91 };
92 
93 steady_clock::time_point SteadyTimeRecorder::begin {};
94 } // namespace
95 
96 std::vector<uint16_t> JankFrameReport::frameJankRecord_(JANK_SIZE, 0);
97 int32_t JankFrameReport::jankFrameCount_ = 0;
98 int32_t JankFrameReport::prevFrameUpdateCount_ = 0;
99 int32_t JankFrameReport::currentFrameUpdateCount_ = 0;
100 JankFrameFlag JankFrameReport::recordStatus_ = JANK_IDLE;
101 int64_t JankFrameReport::startTime_ = 0;
102 int64_t JankFrameReport::prevEndTimeStamp_ = 0;
103 int64_t JankFrameReport::refreshPeriod_ = 16666666;
104 std::string JankFrameReport::pageUrl_;
105 bool JankFrameReport::needReport_ = false;
106 bool JankFrameReport::hasJsAnimation_ = false;
107 int64_t JankFrameReport::animatorEndTime_ = 0;
108 double JankFrameReport::jsAnimationDelayJank_ = 0;
109 
JankFrameRecord(int64_t timeStampNanos)110 void JankFrameReport::JankFrameRecord(int64_t timeStampNanos)
111 {
112     if (refreshPeriod_ <= 0) {
113         return;
114     }
115     int64_t now = GetSteadyTimestamp<std::chrono::nanoseconds>();
116     int64_t duration = now - std::max(timeStampNanos, prevEndTimeStamp_);
117     double jank = double(duration) / refreshPeriod_;
118     // perf monitor jank frame
119     PerfMonitor::GetPerfMonitor()->SetFrameTime(timeStampNanos, duration, jank);
120     RecordJankStatus(jank);
121     prevFrameUpdateCount_ = currentFrameUpdateCount_;
122     RecordPreviousEnd();
123 }
124 
JsAnimationToRsRecord()125 void JankFrameReport::JsAnimationToRsRecord()
126 {
127     int64_t now = GetSteadyTimestamp<std::chrono::nanoseconds>();
128     if (hasJsAnimation_ && animatorEndTime_ != 0) {
129         int64_t jsAnimationDuration = now - animatorEndTime_;
130         jsAnimationDelayJank_ = double(jsAnimationDuration) / refreshPeriod_;
131     }
132 }
133 
RecordJankStatus(double jank)134 void JankFrameReport::RecordJankStatus(double jank)
135 {
136     if (recordStatus_ == JANK_IDLE && animatorEndTime_ == 0) {
137         return;
138     }
139     if (jsAnimationDelayJank_ > 1.0f) {
140         jank += jsAnimationDelayJank_;
141     }
142     if (animatorEndTime_ != 0) {
143         hasJsAnimation_ = false;
144         animatorEndTime_ = 0;
145         jsAnimationDelayJank_ = 0;
146     }
147     // on need to record
148     if (jank <= 1.0f) {
149         return;
150     }
151     // skip first frame
152     if (prevFrameUpdateCount_ == 0 && (currentFrameUpdateCount_ >= 0)) {
153         return;
154     };
155     needReport_ = true;
156     frameJankRecord_[GetJankRange(jank)]++;
157     if (jank >= 6.0f) {
158         jankFrameCount_++;
159         ACE_COUNT_TRACE(jankFrameCount_, "JANK FRAME %s", pageUrl_.c_str());
160     }
161 }
162 
RecordPreviousEnd()163 void JankFrameReport::RecordPreviousEnd()
164 {
165     prevEndTimeStamp_ = GetSteadyTimestamp<std::chrono::nanoseconds>();
166 }
167 
ClearFrameJankRecord()168 void JankFrameReport::ClearFrameJankRecord()
169 {
170     std::fill(frameJankRecord_.begin(), frameJankRecord_.end(), 0);
171     jankFrameCount_ = 0;
172     recordStatus_ = JANK_IDLE;
173     prevEndTimeStamp_ = 0;
174     currentFrameUpdateCount_ = 0;
175     needReport_ = false;
176     hasJsAnimation_ = false;
177     jsAnimationDelayJank_ = 0;
178     animatorEndTime_ = 0;
179 }
180 
SetFrameJankFlag(JankFrameFlag flag)181 void JankFrameReport::SetFrameJankFlag(JankFrameFlag flag)
182 {
183     recordStatus_++;
184     if (recordStatus_ == 1) {
185         animatorEndTime_ = 0;
186         hasJsAnimation_ = false;
187     }
188 }
189 
ClearFrameJankFlag(JankFrameFlag flag)190 void JankFrameReport::ClearFrameJankFlag(JankFrameFlag flag)
191 {
192     if (recordStatus_ > 0) {
193         if (recordStatus_ == 1) {
194             animatorEndTime_ = GetSteadyTimestamp<std::chrono::nanoseconds>();
195         }
196         recordStatus_--;
197     }
198     if (recordStatus_ == JANK_IDLE) {
199         prevEndTimeStamp_ = 0;
200         currentFrameUpdateCount_ = 0;
201     }
202 }
203 
RecordFrameUpdate()204 void JankFrameReport::RecordFrameUpdate()
205 {
206     currentFrameUpdateCount_++;
207 }
208 
ResetFrameJankClock()209 void JankFrameReport::ResetFrameJankClock()
210 {
211     startTime_ = GetSystemTimestamp<std::chrono::milliseconds>();
212     SteadyTimeRecorder::Begin();
213 }
214 
StartRecord(const std::string & pageUrl)215 void JankFrameReport::StartRecord(const std::string& pageUrl)
216 {
217     ResetFrameJankClock();
218     pageUrl_ = pageUrl;
219 }
220 
FlushRecord()221 void JankFrameReport::FlushRecord()
222 {
223     Rosen::RSInterfaces::GetInstance().ReportJankStats();
224     if (needReport_) {
225         EventReport::JankFrameReport(startTime_, SteadyTimeRecorder::End(), frameJankRecord_, pageUrl_);
226     }
227     ClearFrameJankRecord();
228 }
229 
ReportJSAnimation()230 void JankFrameReport::ReportJSAnimation()
231 {
232     if (animatorEndTime_ != 0) {
233         hasJsAnimation_ = true;
234     }
235 }
236 } // namespace OHOS::Ace
237