* Copyright (c) 2022-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "base/ohos/dynamic_frame_loss_monitor.h"
#include <chrono>
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/task/thread_pool.h"
#include "ohos_nweb/src/sysevent/event_reporter.h"
#include "base/trace_event/trace_event.h"
namespace {
const int kSuccessiveFrameLossThreshold = 1;
const int kMicrosecondsPerMillisecond = 1000;
}
namespace base {
namespace ohos {
DynamicFrameLossMonitor& DynamicFrameLossMonitor::GetInstance() {
static base::NoDestructor<DynamicFrameLossMonitor> instance;
return *instance.get();
}
void DynamicFrameLossMonitor::StartMonitor() {
std::unique_lock<std::mutex> lock(monitor_mutex_);
if (is_monitoring_) {
return;
}
is_monitoring_ = true;
start_time_ = GetCurrentTimestampMS();
}
void DynamicFrameLossMonitor::StopMonitor() {
std::unique_lock<std::mutex> lock(monitor_mutex_);
if (!is_monitoring_) {
return;
}
stop_time_ = GetCurrentTimestampMS();
Report();
ResetStatus();
}
void DynamicFrameLossMonitor::OnVsync() {
std::unique_lock<std::mutex> lock(monitor_mutex_);
if (!is_monitoring_) {
return;
}
++total_app_frames_;
if (!received_first_frame_) {
return;
}
if (cached_buffer_number_ <= 0) {
++total_app_missed_frames_;
++app_seq_missed_frames_;
if (app_seq_frames_ <= kSuccessiveFrameLossThreshold) {
app_seq_frames_ = 0;
}
TRACE_EVENT0("base", "WEBVIEW::DYNAMIC_FRAME_DROP_STATISTICS");
} else {
++app_seq_frames_;
if (app_seq_frames_ > kSuccessiveFrameLossThreshold) {
app_seq_missed_frames_ = 0;
}
--cached_buffer_number_;
}
max_app_seq_missed_frames_ = std::max(max_app_seq_missed_frames_, app_seq_missed_frames_);
}
void DynamicFrameLossMonitor::OnSwapBuffer() {
std::unique_lock<std::mutex> lock(monitor_mutex_);
if (!is_monitoring_) {
return;
}
received_first_frame_ = true;
++cached_buffer_number_;
if (prev_swap_buffer_time_ == 0) {
prev_swap_buffer_time_ = GetCurrentTimestampMS();
return;
}
auto current = GetCurrentTimestampMS();
max_app_frametime_ = std::max(max_app_frametime_, current - prev_swap_buffer_time_);
prev_swap_buffer_time_ = current;
}
int64_t DynamicFrameLossMonitor::GetCurrentTimestampMS() {
auto currentTime = std::chrono::system_clock::now().time_since_epoch();
return std::chrono::duration_cast<std::chrono::microseconds>(currentTime)
.count() / kMicrosecondsPerMillisecond;
}
void DynamicFrameLossMonitor::Report() {
if(total_app_missed_frames_ == 0) {
return;
}
#if defined(REPORT_SYS_EVENT)
base::ThreadPool::PostTask(
FROM_HERE,
{base::TaskPriority::LOWEST},
base::BindOnce(&ReportSlideJankStats, start_time_, stop_time_ - start_time_, total_app_frames_,
total_app_missed_frames_, max_app_frametime_, max_app_seq_missed_frames_)
);
TRACE_EVENT1("base", "WEBVIEW::DYNAMIC_FRAME_DROP_STATISTICS", "info",
"StartTime: " + std::to_string(start_time_) + ", Duration: " + std::to_string(stop_time_ - start_time_) +
", MaxAppFrametime: " + std::to_string(max_app_frametime_));
#endif
}
void DynamicFrameLossMonitor::ResetStatus() {
is_monitoring_ = false;
received_first_frame_ = false;
start_time_ = 0;
stop_time_ = 0;
total_app_frames_ = 0;
total_app_missed_frames_ = 0;
max_app_seq_missed_frames_=0;
app_seq_missed_frames_ = 0;
app_seq_frames_ = 0;
prev_swap_buffer_time_ = 0;
max_app_frametime_ = 0;
cached_buffer_number_ = 0;
}
}
}