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