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