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