132a6e48fSopenharmony_ci/* 232a6e48fSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd. 332a6e48fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 432a6e48fSopenharmony_ci * you may not use this file except in compliance with the License. 532a6e48fSopenharmony_ci * You may obtain a copy of the License at 632a6e48fSopenharmony_ci * 732a6e48fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 832a6e48fSopenharmony_ci * 932a6e48fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1032a6e48fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1132a6e48fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1232a6e48fSopenharmony_ci * See the License for the specific language governing permissions and 1332a6e48fSopenharmony_ci * limitations under the License. 1432a6e48fSopenharmony_ci */ 1532a6e48fSopenharmony_ci 1632a6e48fSopenharmony_ci#include <ctime> 1732a6e48fSopenharmony_ci#include <cinttypes> 1832a6e48fSopenharmony_ci 1932a6e48fSopenharmony_ci#include "sync_fence_tracker.h" 2032a6e48fSopenharmony_ci#include "frame_sched.h" 2132a6e48fSopenharmony_ci#include "hilog/log.h" 2232a6e48fSopenharmony_ci#include "parameters.h" 2332a6e48fSopenharmony_ci#include "hisysevent.h" 2432a6e48fSopenharmony_ci#include "file_ex.h" 2532a6e48fSopenharmony_ci 2632a6e48fSopenharmony_ci#ifndef ROSEN_TRACE_DISABLE 2732a6e48fSopenharmony_ci#include "hitrace_meter.h" 2832a6e48fSopenharmony_ci#define RS_TRACE_NAME_FMT(fmt, ...) HITRACE_METER_FMT(HITRACE_TAG_GRAPHIC_AGP, fmt, ##__VA_ARGS__) 2932a6e48fSopenharmony_ci#else 3032a6e48fSopenharmony_ci#define RS_TRACE_NAME_FMT(fmt, ...) 3132a6e48fSopenharmony_ci#endif //ROSEN_TRACE_DISABLE 3232a6e48fSopenharmony_ci 3332a6e48fSopenharmony_ci#ifdef FENCE_SCHED_ENABLE 3432a6e48fSopenharmony_ci#include <fcntl.h> 3532a6e48fSopenharmony_ci#include <stdio.h> 3632a6e48fSopenharmony_ci#include <sys/ioctl.h> 3732a6e48fSopenharmony_ci#include <unistd.h> 3832a6e48fSopenharmony_ci#endif 3932a6e48fSopenharmony_ci 4032a6e48fSopenharmony_cinamespace OHOS { 4132a6e48fSopenharmony_ciusing namespace OHOS::HiviewDFX; 4232a6e48fSopenharmony_cinamespace { 4332a6e48fSopenharmony_ci#undef LOG_DOMAIN 4432a6e48fSopenharmony_ci#define LOG_DOMAIN 0xD001400 4532a6e48fSopenharmony_ci#undef LOG_TAG 4632a6e48fSopenharmony_ci#define LOG_TAG "SyncFence" 4732a6e48fSopenharmony_ci 4832a6e48fSopenharmony_ciconstexpr int FRAME_SET_BLUR_SIZE_ID = 100007; 4932a6e48fSopenharmony_ciconstexpr int FRAME_SET_CONTAINER_NODE_ID = 100008; 5032a6e48fSopenharmony_ci 5132a6e48fSopenharmony_ci#ifdef FENCE_SCHED_ENABLE 5232a6e48fSopenharmony_ciconstexpr unsigned int QOS_CTRL_IPC_MAGIC = 0xCC; 5332a6e48fSopenharmony_ci 5432a6e48fSopenharmony_ci#define QOS_CTRL_BASIC_OPERATION \ 5532a6e48fSopenharmony_ci _IOWR(QOS_CTRL_IPC_MAGIC, 1, struct QosCtrlData) 5632a6e48fSopenharmony_ci 5732a6e48fSopenharmony_ci#define QOS_APPLY 1 5832a6e48fSopenharmony_ci 5932a6e48fSopenharmony_citypedef enum { 6032a6e48fSopenharmony_ci QOS_BACKGROUND = 0, 6132a6e48fSopenharmony_ci QOS_UTILITY, 6232a6e48fSopenharmony_ci QOS_DEFAULT, 6332a6e48fSopenharmony_ci QOS_USER_INITIATED, 6432a6e48fSopenharmony_ci QOS_DEADLINE_REQUEST, 6532a6e48fSopenharmony_ci QOS_USER_INTERACTIVE, 6632a6e48fSopenharmony_ci QOS_KEY_BACKGROUND, 6732a6e48fSopenharmony_ci} QosLevel; 6832a6e48fSopenharmony_ci 6932a6e48fSopenharmony_cistruct QosCtrlData { 7032a6e48fSopenharmony_ci int pid; 7132a6e48fSopenharmony_ci unsigned int type; 7232a6e48fSopenharmony_ci unsigned int level; 7332a6e48fSopenharmony_ci int qos; 7432a6e48fSopenharmony_ci int staticQos; 7532a6e48fSopenharmony_ci int dynamicQos; 7632a6e48fSopenharmony_ci bool tagSchedEnable = false; 7732a6e48fSopenharmony_ci}; 7832a6e48fSopenharmony_ci 7932a6e48fSopenharmony_cistatic int TrivalOpenQosCtrlNode(void) 8032a6e48fSopenharmony_ci{ 8132a6e48fSopenharmony_ci char fileName[] = "/proc/thread-self/sched_qos_ctrl"; 8232a6e48fSopenharmony_ci int fd = open(fileName, O_RDWR); 8332a6e48fSopenharmony_ci if (fd < 0) { 8432a6e48fSopenharmony_ci HILOG_WARN(LOG_CORE, "open qos node failed"); 8532a6e48fSopenharmony_ci } 8632a6e48fSopenharmony_ci return fd; 8732a6e48fSopenharmony_ci} 8832a6e48fSopenharmony_ci 8932a6e48fSopenharmony_civoid QosApply(unsigned int level) 9032a6e48fSopenharmony_ci{ 9132a6e48fSopenharmony_ci int fd = TrivalOpenQosCtrlNode(); 9232a6e48fSopenharmony_ci if (fd < 0) { 9332a6e48fSopenharmony_ci return; 9432a6e48fSopenharmony_ci } 9532a6e48fSopenharmony_ci 9632a6e48fSopenharmony_ci int tid = gettid(); 9732a6e48fSopenharmony_ci struct QosCtrlData data; 9832a6e48fSopenharmony_ci data.level = level; 9932a6e48fSopenharmony_ci data.type = QOS_APPLY; 10032a6e48fSopenharmony_ci data.pid = tid; 10132a6e48fSopenharmony_ci int ret = ioctl(fd, QOS_CTRL_BASIC_OPERATION, &data); 10232a6e48fSopenharmony_ci if (ret < 0) { 10332a6e48fSopenharmony_ci HILOG_WARN(LOG_CORE, "qos apply failed"); 10432a6e48fSopenharmony_ci } 10532a6e48fSopenharmony_ci close(fd); 10632a6e48fSopenharmony_ci} 10732a6e48fSopenharmony_ci#endif 10832a6e48fSopenharmony_ci} 10932a6e48fSopenharmony_ci 11032a6e48fSopenharmony_ciSyncFenceTracker::SyncFenceTracker(const std::string threadName) 11132a6e48fSopenharmony_ci : threadName_(threadName), 11232a6e48fSopenharmony_ci fencesQueued_(0), 11332a6e48fSopenharmony_ci fencesSignaled_(0) 11432a6e48fSopenharmony_ci{ 11532a6e48fSopenharmony_ci runner_ = OHOS::AppExecFwk::EventRunner::Create(threadName_); 11632a6e48fSopenharmony_ci handler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner_); 11732a6e48fSopenharmony_ci 11832a6e48fSopenharmony_ci#ifdef FENCE_SCHED_ENABLE 11932a6e48fSopenharmony_ci if (handler_) { 12032a6e48fSopenharmony_ci handler_->PostTask([]() { 12132a6e48fSopenharmony_ci QosApply(QosLevel::QOS_USER_INTERACTIVE); 12232a6e48fSopenharmony_ci }); 12332a6e48fSopenharmony_ci } 12432a6e48fSopenharmony_ci#endif 12532a6e48fSopenharmony_ci if (threadName_.compare("Acquire Fence") == 0) { 12632a6e48fSopenharmony_ci isGpuFence_ = true; 12732a6e48fSopenharmony_ci } 12832a6e48fSopenharmony_ci if (isGpuFence_) { 12932a6e48fSopenharmony_ci isGpuEnable_ = OHOS::system::GetBoolParameter("persist.deadline.gpu_enable", false); 13032a6e48fSopenharmony_ci } 13132a6e48fSopenharmony_ci} 13232a6e48fSopenharmony_ci 13332a6e48fSopenharmony_civoid SyncFenceTracker::TrackFence(const sptr<SyncFence>& fence, bool traceTag) 13432a6e48fSopenharmony_ci{ 13532a6e48fSopenharmony_ci if (fence == nullptr) { 13632a6e48fSopenharmony_ci HILOG_DEBUG(LOG_CORE, "Trace fence failed, fence is null"); 13732a6e48fSopenharmony_ci return; 13832a6e48fSopenharmony_ci } 13932a6e48fSopenharmony_ci if (isGpuFence_) { 14032a6e48fSopenharmony_ci if (!traceTag && !isGpuEnable_) { 14132a6e48fSopenharmony_ci return; 14232a6e48fSopenharmony_ci } 14332a6e48fSopenharmony_ci } 14432a6e48fSopenharmony_ci if (fence->SyncFileReadTimestamp() != SyncFence::FENCE_PENDING_TIMESTAMP) { 14532a6e48fSopenharmony_ci RS_TRACE_NAME_FMT("%s %d has signaled", threadName_.c_str(), fencesQueued_.load()); 14632a6e48fSopenharmony_ci fencesQueued_.fetch_add(1); 14732a6e48fSopenharmony_ci fencesSignaled_.fetch_add(1); 14832a6e48fSopenharmony_ci return; 14932a6e48fSopenharmony_ci } 15032a6e48fSopenharmony_ci 15132a6e48fSopenharmony_ci RS_TRACE_NAME_FMT("%s %d", threadName_.c_str(), fencesQueued_.load()); 15232a6e48fSopenharmony_ci if (handler_) { 15332a6e48fSopenharmony_ci handler_->PostTask([this, fence, traceTag]() { 15432a6e48fSopenharmony_ci if (isGpuFence_ && isGpuEnable_) { 15532a6e48fSopenharmony_ci Rosen::FrameSched::GetInstance().SetFrameParam(FRAME_SET_CONTAINER_NODE_ID, 0, 0, processedNodeNum_); 15632a6e48fSopenharmony_ci processedNodeNum_ = 0; 15732a6e48fSopenharmony_ci } 15832a6e48fSopenharmony_ci Loop(fence, traceTag); 15932a6e48fSopenharmony_ci }); 16032a6e48fSopenharmony_ci fencesQueued_.fetch_add(1); 16132a6e48fSopenharmony_ci } 16232a6e48fSopenharmony_ci} 16332a6e48fSopenharmony_ci 16432a6e48fSopenharmony_cibool SyncFenceTracker::CheckGpuSubhealthEventLimit() 16532a6e48fSopenharmony_ci{ 16632a6e48fSopenharmony_ci auto now = std::chrono::system_clock::now(); 16732a6e48fSopenharmony_ci std::time_t t = std::chrono::system_clock::to_time_t(now); 16832a6e48fSopenharmony_ci std::tm *tm = std::localtime(&t); 16932a6e48fSopenharmony_ci if (tm != nullptr && (gpuSubhealthEventNum_ == 0 || tm->tm_yday > gpuSubhealthEventDay_)) { 17032a6e48fSopenharmony_ci gpuSubhealthEventDay_ = tm->tm_yday; 17132a6e48fSopenharmony_ci gpuSubhealthEventNum_ = 0; 17232a6e48fSopenharmony_ci HILOG_DEBUG(LOG_CORE, "first event of %{public}" PRId32, gpuSubhealthEventDay_); 17332a6e48fSopenharmony_ci gpuSubhealthEventNum_++; 17432a6e48fSopenharmony_ci return true; 17532a6e48fSopenharmony_ci } else if (gpuSubhealthEventNum_ < GPU_SUBHEALTH_EVENT_LIMIT) { 17632a6e48fSopenharmony_ci gpuSubhealthEventNum_++; 17732a6e48fSopenharmony_ci HILOG_DEBUG(LOG_CORE, "%{public}" PRId32 "event of %{public}" PRId32 "day", 17832a6e48fSopenharmony_ci gpuSubhealthEventNum_, gpuSubhealthEventDay_); 17932a6e48fSopenharmony_ci return true; 18032a6e48fSopenharmony_ci } 18132a6e48fSopenharmony_ci HILOG_DEBUG(LOG_CORE, "%{public}" PRId32 "event exceed %{public}" PRId32 "day", 18232a6e48fSopenharmony_ci gpuSubhealthEventNum_, gpuSubhealthEventDay_); 18332a6e48fSopenharmony_ci return false; 18432a6e48fSopenharmony_ci} 18532a6e48fSopenharmony_ci 18632a6e48fSopenharmony_ciinline void SyncFenceTracker::UpdateFrameQueue(int32_t startTime) 18732a6e48fSopenharmony_ci{ 18832a6e48fSopenharmony_ci if (frameStartTimes_->size() >= FRAME_QUEUE_SIZE_LIMIT) { 18932a6e48fSopenharmony_ci frameStartTimes_->pop(); 19032a6e48fSopenharmony_ci } 19132a6e48fSopenharmony_ci frameStartTimes_->push(startTime); 19232a6e48fSopenharmony_ci} 19332a6e48fSopenharmony_ci 19432a6e48fSopenharmony_ciint32_t SyncFenceTracker::GetFrameRate() 19532a6e48fSopenharmony_ci{ 19632a6e48fSopenharmony_ci int32_t frameRate = 0; 19732a6e48fSopenharmony_ci int32_t frameNum = static_cast<int32_t>(frameStartTimes_->size()); 19832a6e48fSopenharmony_ci if (frameNum > 1) { 19932a6e48fSopenharmony_ci int32_t interval = frameStartTimes_->back() - frameStartTimes_->front(); 20032a6e48fSopenharmony_ci if (interval > 0) { 20132a6e48fSopenharmony_ci frameRate = FRAME_PERIOD * (frameNum - 1) / interval; 20232a6e48fSopenharmony_ci } 20332a6e48fSopenharmony_ci } 20432a6e48fSopenharmony_ci return frameRate; 20532a6e48fSopenharmony_ci} 20632a6e48fSopenharmony_ci 20732a6e48fSopenharmony_civoid SyncFenceTracker::ReportEventGpuSubhealth(int32_t duration) 20832a6e48fSopenharmony_ci{ 20932a6e48fSopenharmony_ci if (handler_) { 21032a6e48fSopenharmony_ci handler_->PostTask([this, duration]() { 21132a6e48fSopenharmony_ci RS_TRACE_NAME_FMT("report GPU_SUBHEALTH_MONITORING"); 21232a6e48fSopenharmony_ci auto reportName = "GPU_SUBHEALTH_MONITORING"; 21332a6e48fSopenharmony_ci HILOG_DEBUG(LOG_CORE, "report GPU_SUBHEALTH_MONITORING. duration : %{public}" 21432a6e48fSopenharmony_ci PRId32, duration); 21532a6e48fSopenharmony_ci HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::GRAPHIC, reportName, 21632a6e48fSopenharmony_ci OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, "WAIT_ACQUIRE_FENCE_TIME", 21732a6e48fSopenharmony_ci duration, "FRAME_RATE", GetFrameRate()); 21832a6e48fSopenharmony_ci }); 21932a6e48fSopenharmony_ci } 22032a6e48fSopenharmony_ci} 22132a6e48fSopenharmony_ci 22232a6e48fSopenharmony_civoid SyncFenceTracker::Loop(const sptr<SyncFence>& fence, bool traceTag) 22332a6e48fSopenharmony_ci{ 22432a6e48fSopenharmony_ci uint32_t fenceIndex = 0; 22532a6e48fSopenharmony_ci fenceIndex = fencesSignaled_.load(); 22632a6e48fSopenharmony_ci { 22732a6e48fSopenharmony_ci RS_TRACE_NAME_FMT("Waiting for %s %d", threadName_.c_str(), fenceIndex); 22832a6e48fSopenharmony_ci int32_t result = 0; 22932a6e48fSopenharmony_ci if (isGpuFence_ && traceTag) { 23032a6e48fSopenharmony_ci int32_t startTimestamp = static_cast<int32_t>( 23132a6e48fSopenharmony_ci std::chrono::duration_cast<std::chrono::milliseconds>( 23232a6e48fSopenharmony_ci std::chrono::steady_clock::now().time_since_epoch()).count()); 23332a6e48fSopenharmony_ci UpdateFrameQueue(startTimestamp); 23432a6e48fSopenharmony_ci result = WaitFence(fence); 23532a6e48fSopenharmony_ci int32_t endTimestamp = static_cast<int32_t>( 23632a6e48fSopenharmony_ci std::chrono::duration_cast<std::chrono::milliseconds>( 23732a6e48fSopenharmony_ci std::chrono::steady_clock::now().time_since_epoch()).count()); 23832a6e48fSopenharmony_ci int32_t duration = endTimestamp - startTimestamp; 23932a6e48fSopenharmony_ci HILOG_DEBUG(LOG_CORE, "Waiting for Acquire Fence: %{public}" PRId32 "ms", duration); 24032a6e48fSopenharmony_ci if (duration > GPU_SUBHEALTH_EVENT_THRESHOLD && CheckGpuSubhealthEventLimit()) { 24132a6e48fSopenharmony_ci ReportEventGpuSubhealth(duration); 24232a6e48fSopenharmony_ci } 24332a6e48fSopenharmony_ci } else { 24432a6e48fSopenharmony_ci result = WaitFence(fence); 24532a6e48fSopenharmony_ci } 24632a6e48fSopenharmony_ci 24732a6e48fSopenharmony_ci if (result < 0) { 24832a6e48fSopenharmony_ci HILOG_DEBUG(LOG_CORE, "Error waiting for SyncFence: %s", strerror(result)); 24932a6e48fSopenharmony_ci } 25032a6e48fSopenharmony_ci } 25132a6e48fSopenharmony_ci fencesSignaled_.fetch_add(1); 25232a6e48fSopenharmony_ci} 25332a6e48fSopenharmony_ci 25432a6e48fSopenharmony_ciint32_t SyncFenceTracker::WaitFence(const sptr<SyncFence>& fence) 25532a6e48fSopenharmony_ci{ 25632a6e48fSopenharmony_ci if (isGpuFence_ && isGpuEnable_) { 25732a6e48fSopenharmony_ci Rosen::FrameSched::GetInstance().MonitorGpuStart(); 25832a6e48fSopenharmony_ci } 25932a6e48fSopenharmony_ci int32_t result = fence->Wait(SYNC_TIME_OUT); 26032a6e48fSopenharmony_ci if (isGpuFence_ && isGpuEnable_) { 26132a6e48fSopenharmony_ci Rosen::FrameSched::GetInstance().MonitorGpuEnd(); 26232a6e48fSopenharmony_ci } 26332a6e48fSopenharmony_ci return result; 26432a6e48fSopenharmony_ci} 26532a6e48fSopenharmony_ci 26632a6e48fSopenharmony_civoid SyncFenceTracker::SetBlurSize(int32_t blurSize) 26732a6e48fSopenharmony_ci{ 26832a6e48fSopenharmony_ci if (handler_) { 26932a6e48fSopenharmony_ci handler_->PostTask([blurSize]() { 27032a6e48fSopenharmony_ci Rosen::FrameSched::GetInstance().SetFrameParam(FRAME_SET_BLUR_SIZE_ID, 0, 0, blurSize); 27132a6e48fSopenharmony_ci }); 27232a6e48fSopenharmony_ci } 27332a6e48fSopenharmony_ci} 27432a6e48fSopenharmony_ci 27532a6e48fSopenharmony_civoid SyncFenceTracker::SetContainerNodeNum(int containerNodeNum) 27632a6e48fSopenharmony_ci{ 27732a6e48fSopenharmony_ci if (isGpuEnable_) { 27832a6e48fSopenharmony_ci processedNodeNum_ += containerNodeNum; 27932a6e48fSopenharmony_ci } 28032a6e48fSopenharmony_ci} 28132a6e48fSopenharmony_ci} // namespace OHOS