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