1/* 2 * Copyright (c) 2022 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 <ctime> 17#include <cinttypes> 18 19#include "sync_fence_tracker.h" 20#include "frame_sched.h" 21#include "hilog/log.h" 22#include "parameters.h" 23#include "hisysevent.h" 24#include "file_ex.h" 25 26#ifndef ROSEN_TRACE_DISABLE 27#include "hitrace_meter.h" 28#define RS_TRACE_NAME_FMT(fmt, ...) HITRACE_METER_FMT(HITRACE_TAG_GRAPHIC_AGP, fmt, ##__VA_ARGS__) 29#else 30#define RS_TRACE_NAME_FMT(fmt, ...) 31#endif //ROSEN_TRACE_DISABLE 32 33#ifdef FENCE_SCHED_ENABLE 34#include <fcntl.h> 35#include <stdio.h> 36#include <sys/ioctl.h> 37#include <unistd.h> 38#endif 39 40namespace OHOS { 41using namespace OHOS::HiviewDFX; 42namespace { 43#undef LOG_DOMAIN 44#define LOG_DOMAIN 0xD001400 45#undef LOG_TAG 46#define LOG_TAG "SyncFence" 47 48constexpr int FRAME_SET_BLUR_SIZE_ID = 100007; 49constexpr int FRAME_SET_CONTAINER_NODE_ID = 100008; 50 51#ifdef FENCE_SCHED_ENABLE 52constexpr unsigned int QOS_CTRL_IPC_MAGIC = 0xCC; 53 54#define QOS_CTRL_BASIC_OPERATION \ 55 _IOWR(QOS_CTRL_IPC_MAGIC, 1, struct QosCtrlData) 56 57#define QOS_APPLY 1 58 59typedef enum { 60 QOS_BACKGROUND = 0, 61 QOS_UTILITY, 62 QOS_DEFAULT, 63 QOS_USER_INITIATED, 64 QOS_DEADLINE_REQUEST, 65 QOS_USER_INTERACTIVE, 66 QOS_KEY_BACKGROUND, 67} QosLevel; 68 69struct QosCtrlData { 70 int pid; 71 unsigned int type; 72 unsigned int level; 73 int qos; 74 int staticQos; 75 int dynamicQos; 76 bool tagSchedEnable = false; 77}; 78 79static int TrivalOpenQosCtrlNode(void) 80{ 81 char fileName[] = "/proc/thread-self/sched_qos_ctrl"; 82 int fd = open(fileName, O_RDWR); 83 if (fd < 0) { 84 HILOG_WARN(LOG_CORE, "open qos node failed"); 85 } 86 return fd; 87} 88 89void QosApply(unsigned int level) 90{ 91 int fd = TrivalOpenQosCtrlNode(); 92 if (fd < 0) { 93 return; 94 } 95 96 int tid = gettid(); 97 struct QosCtrlData data; 98 data.level = level; 99 data.type = QOS_APPLY; 100 data.pid = tid; 101 int ret = ioctl(fd, QOS_CTRL_BASIC_OPERATION, &data); 102 if (ret < 0) { 103 HILOG_WARN(LOG_CORE, "qos apply failed"); 104 } 105 close(fd); 106} 107#endif 108} 109 110SyncFenceTracker::SyncFenceTracker(const std::string threadName) 111 : threadName_(threadName), 112 fencesQueued_(0), 113 fencesSignaled_(0) 114{ 115 runner_ = OHOS::AppExecFwk::EventRunner::Create(threadName_); 116 handler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner_); 117 118#ifdef FENCE_SCHED_ENABLE 119 if (handler_) { 120 handler_->PostTask([]() { 121 QosApply(QosLevel::QOS_USER_INTERACTIVE); 122 }); 123 } 124#endif 125 if (threadName_.compare("Acquire Fence") == 0) { 126 isGpuFence_ = true; 127 } 128 if (isGpuFence_) { 129 isGpuEnable_ = OHOS::system::GetBoolParameter("persist.deadline.gpu_enable", false); 130 } 131} 132 133void SyncFenceTracker::TrackFence(const sptr<SyncFence>& fence, bool traceTag) 134{ 135 if (fence == nullptr) { 136 HILOG_DEBUG(LOG_CORE, "Trace fence failed, fence is null"); 137 return; 138 } 139 if (isGpuFence_) { 140 if (!traceTag && !isGpuEnable_) { 141 return; 142 } 143 } 144 if (fence->SyncFileReadTimestamp() != SyncFence::FENCE_PENDING_TIMESTAMP) { 145 RS_TRACE_NAME_FMT("%s %d has signaled", threadName_.c_str(), fencesQueued_.load()); 146 fencesQueued_.fetch_add(1); 147 fencesSignaled_.fetch_add(1); 148 return; 149 } 150 151 RS_TRACE_NAME_FMT("%s %d", threadName_.c_str(), fencesQueued_.load()); 152 if (handler_) { 153 handler_->PostTask([this, fence, traceTag]() { 154 if (isGpuFence_ && isGpuEnable_) { 155 Rosen::FrameSched::GetInstance().SetFrameParam(FRAME_SET_CONTAINER_NODE_ID, 0, 0, processedNodeNum_); 156 processedNodeNum_ = 0; 157 } 158 Loop(fence, traceTag); 159 }); 160 fencesQueued_.fetch_add(1); 161 } 162} 163 164bool SyncFenceTracker::CheckGpuSubhealthEventLimit() 165{ 166 auto now = std::chrono::system_clock::now(); 167 std::time_t t = std::chrono::system_clock::to_time_t(now); 168 std::tm *tm = std::localtime(&t); 169 if (tm != nullptr && (gpuSubhealthEventNum_ == 0 || tm->tm_yday > gpuSubhealthEventDay_)) { 170 gpuSubhealthEventDay_ = tm->tm_yday; 171 gpuSubhealthEventNum_ = 0; 172 HILOG_DEBUG(LOG_CORE, "first event of %{public}" PRId32, gpuSubhealthEventDay_); 173 gpuSubhealthEventNum_++; 174 return true; 175 } else if (gpuSubhealthEventNum_ < GPU_SUBHEALTH_EVENT_LIMIT) { 176 gpuSubhealthEventNum_++; 177 HILOG_DEBUG(LOG_CORE, "%{public}" PRId32 "event of %{public}" PRId32 "day", 178 gpuSubhealthEventNum_, gpuSubhealthEventDay_); 179 return true; 180 } 181 HILOG_DEBUG(LOG_CORE, "%{public}" PRId32 "event exceed %{public}" PRId32 "day", 182 gpuSubhealthEventNum_, gpuSubhealthEventDay_); 183 return false; 184} 185 186inline void SyncFenceTracker::UpdateFrameQueue(int32_t startTime) 187{ 188 if (frameStartTimes_->size() >= FRAME_QUEUE_SIZE_LIMIT) { 189 frameStartTimes_->pop(); 190 } 191 frameStartTimes_->push(startTime); 192} 193 194int32_t SyncFenceTracker::GetFrameRate() 195{ 196 int32_t frameRate = 0; 197 int32_t frameNum = static_cast<int32_t>(frameStartTimes_->size()); 198 if (frameNum > 1) { 199 int32_t interval = frameStartTimes_->back() - frameStartTimes_->front(); 200 if (interval > 0) { 201 frameRate = FRAME_PERIOD * (frameNum - 1) / interval; 202 } 203 } 204 return frameRate; 205} 206 207void SyncFenceTracker::ReportEventGpuSubhealth(int32_t duration) 208{ 209 if (handler_) { 210 handler_->PostTask([this, duration]() { 211 RS_TRACE_NAME_FMT("report GPU_SUBHEALTH_MONITORING"); 212 auto reportName = "GPU_SUBHEALTH_MONITORING"; 213 HILOG_DEBUG(LOG_CORE, "report GPU_SUBHEALTH_MONITORING. duration : %{public}" 214 PRId32, duration); 215 HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::GRAPHIC, reportName, 216 OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, "WAIT_ACQUIRE_FENCE_TIME", 217 duration, "FRAME_RATE", GetFrameRate()); 218 }); 219 } 220} 221 222void SyncFenceTracker::Loop(const sptr<SyncFence>& fence, bool traceTag) 223{ 224 uint32_t fenceIndex = 0; 225 fenceIndex = fencesSignaled_.load(); 226 { 227 RS_TRACE_NAME_FMT("Waiting for %s %d", threadName_.c_str(), fenceIndex); 228 int32_t result = 0; 229 if (isGpuFence_ && traceTag) { 230 int32_t startTimestamp = static_cast<int32_t>( 231 std::chrono::duration_cast<std::chrono::milliseconds>( 232 std::chrono::steady_clock::now().time_since_epoch()).count()); 233 UpdateFrameQueue(startTimestamp); 234 result = WaitFence(fence); 235 int32_t endTimestamp = static_cast<int32_t>( 236 std::chrono::duration_cast<std::chrono::milliseconds>( 237 std::chrono::steady_clock::now().time_since_epoch()).count()); 238 int32_t duration = endTimestamp - startTimestamp; 239 HILOG_DEBUG(LOG_CORE, "Waiting for Acquire Fence: %{public}" PRId32 "ms", duration); 240 if (duration > GPU_SUBHEALTH_EVENT_THRESHOLD && CheckGpuSubhealthEventLimit()) { 241 ReportEventGpuSubhealth(duration); 242 } 243 } else { 244 result = WaitFence(fence); 245 } 246 247 if (result < 0) { 248 HILOG_DEBUG(LOG_CORE, "Error waiting for SyncFence: %s", strerror(result)); 249 } 250 } 251 fencesSignaled_.fetch_add(1); 252} 253 254int32_t SyncFenceTracker::WaitFence(const sptr<SyncFence>& fence) 255{ 256 if (isGpuFence_ && isGpuEnable_) { 257 Rosen::FrameSched::GetInstance().MonitorGpuStart(); 258 } 259 int32_t result = fence->Wait(SYNC_TIME_OUT); 260 if (isGpuFence_ && isGpuEnable_) { 261 Rosen::FrameSched::GetInstance().MonitorGpuEnd(); 262 } 263 return result; 264} 265 266void SyncFenceTracker::SetBlurSize(int32_t blurSize) 267{ 268 if (handler_) { 269 handler_->PostTask([blurSize]() { 270 Rosen::FrameSched::GetInstance().SetFrameParam(FRAME_SET_BLUR_SIZE_ID, 0, 0, blurSize); 271 }); 272 } 273} 274 275void SyncFenceTracker::SetContainerNodeNum(int containerNodeNum) 276{ 277 if (isGpuEnable_) { 278 processedNodeNum_ += containerNodeNum; 279 } 280} 281} // namespace OHOS