106f6ba60Sopenharmony_ci/*
206f6ba60Sopenharmony_ci * Copyright (C) 2021 Huawei Device Co., Ltd.
306f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
406f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License.
506f6ba60Sopenharmony_ci * You may obtain a copy of the License at
606f6ba60Sopenharmony_ci *
706f6ba60Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
806f6ba60Sopenharmony_ci *
906f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1006f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1106f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1206f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and
1306f6ba60Sopenharmony_ci * limitations under the License.
1406f6ba60Sopenharmony_ci */
1506f6ba60Sopenharmony_ci#include <cstdio>
1606f6ba60Sopenharmony_ci#include <algorithm>
1706f6ba60Sopenharmony_ci#include <iostream>
1806f6ba60Sopenharmony_ci#include <sstream>
1906f6ba60Sopenharmony_ci#include <queue>
2006f6ba60Sopenharmony_ci#include <string>
2106f6ba60Sopenharmony_ci#include <thread>
2206f6ba60Sopenharmony_ci#include <unistd.h>
2306f6ba60Sopenharmony_ci#include <ctime>
2406f6ba60Sopenharmony_ci#include <sys/time.h>
2506f6ba60Sopenharmony_ci#include "include/sp_utils.h"
2606f6ba60Sopenharmony_ci#include "include/ByTrace.h"
2706f6ba60Sopenharmony_ci#include "include/Capture.h"
2806f6ba60Sopenharmony_ci#include "include/FPS.h"
2906f6ba60Sopenharmony_ci#include "include/startup_delay.h"
3006f6ba60Sopenharmony_ci#include "include/profiler_fps.h"
3106f6ba60Sopenharmony_ci#include "include/sp_log.h"
3206f6ba60Sopenharmony_ci#include "include/common.h"
3306f6ba60Sopenharmony_ci#include <sys/wait.h>
3406f6ba60Sopenharmony_ci#include <sys/types.h>
3506f6ba60Sopenharmony_cinamespace OHOS {
3606f6ba60Sopenharmony_cinamespace SmartPerf {
3706f6ba60Sopenharmony_cistd::map<std::string, std::string> FPS::ItemData()
3806f6ba60Sopenharmony_ci{
3906f6ba60Sopenharmony_ci    std::map<std::string, std::string> result;
4006f6ba60Sopenharmony_ci    FpsInfo fpsInfoResult;
4106f6ba60Sopenharmony_ci    if (surfaceViewName.length() > 0) {
4206f6ba60Sopenharmony_ci        fpsInfoResult = GetDiffLayersFpsInfo(surfaceViewName);
4306f6ba60Sopenharmony_ci    } else {
4406f6ba60Sopenharmony_ci        fpsInfoResult = GetFpsInfo();
4506f6ba60Sopenharmony_ci    }
4606f6ba60Sopenharmony_ci    prevResultFpsInfo = fpsInfoResult;
4706f6ba60Sopenharmony_ci    std::string value = FindFpsRefreshrate();
4806f6ba60Sopenharmony_ci    result["refreshrate"] = value;
4906f6ba60Sopenharmony_ci    if (processFlag) {
5006f6ba60Sopenharmony_ci        result["fps"] = "NA";
5106f6ba60Sopenharmony_ci        result["fpsJitters"] = "NA";
5206f6ba60Sopenharmony_ci    } else {
5306f6ba60Sopenharmony_ci        int fullFrame = 120;
5406f6ba60Sopenharmony_ci        if (fpsInfoResult.fps > fullFrame) {
5506f6ba60Sopenharmony_ci            fpsInfoResult.fps = fullFrame;
5606f6ba60Sopenharmony_ci        }
5706f6ba60Sopenharmony_ci        result["fps"] = std::to_string(fpsInfoResult.fps);
5806f6ba60Sopenharmony_ci        LOGI("result.fps: %s", std::to_string(fpsInfoResult.fps).c_str());
5906f6ba60Sopenharmony_ci        LOGI("result.curTime: %s", std::to_string(fpsInfoResult.curTime).c_str());
6006f6ba60Sopenharmony_ci        std::string jitterStr = "";
6106f6ba60Sopenharmony_ci        std::string split = "";
6206f6ba60Sopenharmony_ci        for (size_t i = 0; i < fpsInfoResult.jitters.size(); i++) {
6306f6ba60Sopenharmony_ci            if (i > 0) {
6406f6ba60Sopenharmony_ci                split = ";;";
6506f6ba60Sopenharmony_ci            }
6606f6ba60Sopenharmony_ci            jitterStr += split + std::to_string(fpsInfoResult.jitters[i]);
6706f6ba60Sopenharmony_ci        }
6806f6ba60Sopenharmony_ci        result["fpsJitters"] = jitterStr;
6906f6ba60Sopenharmony_ci        LOGI("result.jitters: %s", jitterStr.c_str());
7006f6ba60Sopenharmony_ci        SetFpsCurrentFpsTime(fpsInfoResult);
7106f6ba60Sopenharmony_ci    }
7206f6ba60Sopenharmony_ci    return result;
7306f6ba60Sopenharmony_ci}
7406f6ba60Sopenharmony_ci
7506f6ba60Sopenharmony_civoid FPS::SetFpsCurrentFpsTime(FpsInfo fpsInfoResult)
7606f6ba60Sopenharmony_ci{
7706f6ba60Sopenharmony_ci    ffTime.fps = fpsInfoResult.fps;
7806f6ba60Sopenharmony_ci    if (!fpsInfoResult.jitters.empty()) {
7906f6ba60Sopenharmony_ci        auto maxElement = std::max_element(fpsInfoResult.jitters.begin(), fpsInfoResult.jitters.end());
8006f6ba60Sopenharmony_ci        ffTime.currentFpsTime = *maxElement;
8106f6ba60Sopenharmony_ci    }
8206f6ba60Sopenharmony_ci}
8306f6ba60Sopenharmony_ci
8406f6ba60Sopenharmony_ciFpsCurrentFpsTime FPS::GetFpsCurrentFpsTime()
8506f6ba60Sopenharmony_ci{
8606f6ba60Sopenharmony_ci    return ffTime;
8706f6ba60Sopenharmony_ci}
8806f6ba60Sopenharmony_ci
8906f6ba60Sopenharmony_civoid FPS::SetPackageName(std::string pName)
9006f6ba60Sopenharmony_ci{
9106f6ba60Sopenharmony_ci    pkgName = std::move(pName);
9206f6ba60Sopenharmony_ci}
9306f6ba60Sopenharmony_ci
9406f6ba60Sopenharmony_civoid FPS::SetProcessId(const std::string &pid)
9506f6ba60Sopenharmony_ci{
9606f6ba60Sopenharmony_ci    processId = pid;
9706f6ba60Sopenharmony_ci}
9806f6ba60Sopenharmony_ci
9906f6ba60Sopenharmony_civoid FPS::SetLayerName(std::string sName)
10006f6ba60Sopenharmony_ci{
10106f6ba60Sopenharmony_ci    surfaceViewName = std::move(sName);
10206f6ba60Sopenharmony_ci}
10306f6ba60Sopenharmony_ciFpsInfo FPS::GetDiffLayersFpsInfo(const std::string &sName)
10406f6ba60Sopenharmony_ci{
10506f6ba60Sopenharmony_ci    OHOS::SmartPerf::SPUtils::GetCurrentTime(fifty, prevResultFpsInfo.curTime);
10606f6ba60Sopenharmony_ci    fpsInfoMax = GetSurfaceFrame(sName);
10706f6ba60Sopenharmony_ci    return fpsInfoMax;
10806f6ba60Sopenharmony_ci}
10906f6ba60Sopenharmony_ci
11006f6ba60Sopenharmony_ciFpsInfo FPS::GetFpsInfo()
11106f6ba60Sopenharmony_ci{
11206f6ba60Sopenharmony_ci    processFlag = false;
11306f6ba60Sopenharmony_ci    fpsInfoMax.fps = 0;
11406f6ba60Sopenharmony_ci    if (pkgName.empty()) {
11506f6ba60Sopenharmony_ci        return fpsInfoMax;
11606f6ba60Sopenharmony_ci    }
11706f6ba60Sopenharmony_ci    bool onTop = OHOS::SmartPerf::SPUtils::IsForeGround(pkgName);
11806f6ba60Sopenharmony_ci    if (onTop) {
11906f6ba60Sopenharmony_ci        std::string uniteLayer;
12006f6ba60Sopenharmony_ci        if (!rkFlag) {
12106f6ba60Sopenharmony_ci            uniteLayer = "UniRender";
12206f6ba60Sopenharmony_ci        } else {
12306f6ba60Sopenharmony_ci            ProfilerFPS &profilerFps = ProfilerFPS::GetInstance();
12406f6ba60Sopenharmony_ci            uniteLayer = profilerFps.GetSurface();
12506f6ba60Sopenharmony_ci        }
12606f6ba60Sopenharmony_ci        OHOS::SmartPerf::SPUtils::GetCurrentTime(fifty, prevResultFpsInfo.curTime);
12706f6ba60Sopenharmony_ci        fpsInfoMax = GetSurfaceFrame(uniteLayer);
12806f6ba60Sopenharmony_ci    } else {
12906f6ba60Sopenharmony_ci        LOGI("FPS:app is in the background");
13006f6ba60Sopenharmony_ci        if (processId.empty()) {
13106f6ba60Sopenharmony_ci            processFlag = true;
13206f6ba60Sopenharmony_ci            fpsInfoMax.Clear();
13306f6ba60Sopenharmony_ci        } else {
13406f6ba60Sopenharmony_ci            fpsInfoMax.Clear();
13506f6ba60Sopenharmony_ci        }
13606f6ba60Sopenharmony_ci    }
13706f6ba60Sopenharmony_ci    return fpsInfoMax;
13806f6ba60Sopenharmony_ci}
13906f6ba60Sopenharmony_ci
14006f6ba60Sopenharmony_ciFpsInfo FPS::GetSurfaceFrame(std::string name)
14106f6ba60Sopenharmony_ci{
14206f6ba60Sopenharmony_ci    if (name == "") {
14306f6ba60Sopenharmony_ci        return FpsInfo();
14406f6ba60Sopenharmony_ci    }
14506f6ba60Sopenharmony_ci    static std::map<std::string, FpsInfo> fpsMap;
14606f6ba60Sopenharmony_ci    if (fpsMap.count(name) == 0) {
14706f6ba60Sopenharmony_ci        FpsInfo tmp;
14806f6ba60Sopenharmony_ci        tmp.fps = 0;
14906f6ba60Sopenharmony_ci        fpsMap[name] = tmp;
15006f6ba60Sopenharmony_ci    }
15106f6ba60Sopenharmony_ci    fpsInfo = fpsMap[name];
15206f6ba60Sopenharmony_ci    fpsInfo.fps = 0;
15306f6ba60Sopenharmony_ci    std::string command = "fps " + name;
15406f6ba60Sopenharmony_ci    const char* args[] = { "hidumper", "-s", "10", "-a", command.c_str(), nullptr };
15506f6ba60Sopenharmony_ci    int pipefd[2];
15606f6ba60Sopenharmony_ci    pid_t pid;
15706f6ba60Sopenharmony_ci    if (pipe(pipefd) == -1) {
15806f6ba60Sopenharmony_ci        LOGE("FPS::Failed to create pipe");
15906f6ba60Sopenharmony_ci        return fpsInfo;
16006f6ba60Sopenharmony_ci    }
16106f6ba60Sopenharmony_ci    pid = fork();
16206f6ba60Sopenharmony_ci    if (pid == -1) {
16306f6ba60Sopenharmony_ci        LOGE("FPS::Failed to fork");
16406f6ba60Sopenharmony_ci        return fpsInfo;
16506f6ba60Sopenharmony_ci    } else if (pid == 0) {
16606f6ba60Sopenharmony_ci        close(pipefd[0]);
16706f6ba60Sopenharmony_ci        dup2(pipefd[1], STDOUT_FILENO);
16806f6ba60Sopenharmony_ci        close(pipefd[1]);
16906f6ba60Sopenharmony_ci        if (execvp(args[0], const_cast<char *const*>(args)) == -1) {
17006f6ba60Sopenharmony_ci            LOGE("FPS::Failed to execute hidumper");
17106f6ba60Sopenharmony_ci            return fpsInfo;
17206f6ba60Sopenharmony_ci        }
17306f6ba60Sopenharmony_ci    } else {
17406f6ba60Sopenharmony_ci        close(pipefd[1]);
17506f6ba60Sopenharmony_ci        ReadDataFromPipe(pipefd[0]);
17606f6ba60Sopenharmony_ci        close(pipefd[0]);
17706f6ba60Sopenharmony_ci        waitpid(pid, nullptr, 0);
17806f6ba60Sopenharmony_ci    }
17906f6ba60Sopenharmony_ci    return fpsInfo;
18006f6ba60Sopenharmony_ci}
18106f6ba60Sopenharmony_ci
18206f6ba60Sopenharmony_civoid FPS::ReadDataFromPipe(int fd)
18306f6ba60Sopenharmony_ci{
18406f6ba60Sopenharmony_ci    char tmp[1024];
18506f6ba60Sopenharmony_ci    fpsNum = 0;
18606f6ba60Sopenharmony_ci    prevScreenTimestamp = -1;
18706f6ba60Sopenharmony_ci    LOGI("FPS::dump time: start!");
18806f6ba60Sopenharmony_ci    struct timespec time1 = { 0 };
18906f6ba60Sopenharmony_ci    clock_gettime(CLOCK_MONOTONIC, &time1);
19006f6ba60Sopenharmony_ci    fpsInfo.curTime = static_cast<int>(time1.tv_sec - 1);
19106f6ba60Sopenharmony_ci    fpsInfo.currTimeDump = (time1.tv_sec - 1) * mod + time1.tv_nsec;
19206f6ba60Sopenharmony_ci    LOGI("FPS:fpsInfo.curTime: %d", fpsInfo.curTime);
19306f6ba60Sopenharmony_ci    LOGI("FPS:psInfo.currTimeDump: %lld", fpsInfo.currTimeDump);
19406f6ba60Sopenharmony_ci    FILE *fp = fdopen(fd, "r");
19506f6ba60Sopenharmony_ci    if (!fp) {
19606f6ba60Sopenharmony_ci        LOGE("FPS::Failed to open file descriptor");
19706f6ba60Sopenharmony_ci        return;
19806f6ba60Sopenharmony_ci    }
19906f6ba60Sopenharmony_ci    while (fgets(tmp, sizeof(tmp), fp) != nullptr) {
20006f6ba60Sopenharmony_ci        std::string str(tmp);
20106f6ba60Sopenharmony_ci        LOGD("FPS::dump time: %s", str.c_str());
20206f6ba60Sopenharmony_ci        curScreenTimestamp = 0;
20306f6ba60Sopenharmony_ci        std::stringstream sstream;
20406f6ba60Sopenharmony_ci        sstream << tmp;
20506f6ba60Sopenharmony_ci        sstream >> curScreenTimestamp;
20606f6ba60Sopenharmony_ci        if (curScreenTimestamp == 0) {
20706f6ba60Sopenharmony_ci            continue;
20806f6ba60Sopenharmony_ci        }
20906f6ba60Sopenharmony_ci        CalcFpsAndJitters();
21006f6ba60Sopenharmony_ci    }
21106f6ba60Sopenharmony_ci    if (fclose(fp) == EOF) {
21206f6ba60Sopenharmony_ci        LOGE("FPS::Failed to close file descriptor");
21306f6ba60Sopenharmony_ci    }
21406f6ba60Sopenharmony_ci}
21506f6ba60Sopenharmony_ci
21606f6ba60Sopenharmony_civoid FPS::CalcFpsAndJitters()
21706f6ba60Sopenharmony_ci{
21806f6ba60Sopenharmony_ci    std::string onScreenTime = std::to_string(curScreenTimestamp / mod);
21906f6ba60Sopenharmony_ci    std::string fpsCurTime = std::to_string(fpsInfo.curTime);
22006f6ba60Sopenharmony_ci    if (onScreenTime.find(fpsCurTime) != std::string::npos) {
22106f6ba60Sopenharmony_ci        fpsNum++;
22206f6ba60Sopenharmony_ci        fpsInfo.currTimeStamps.push_back(curScreenTimestamp);
22306f6ba60Sopenharmony_ci    }
22406f6ba60Sopenharmony_ci    fpsInfo.fps = fpsNum;
22506f6ba60Sopenharmony_ci    if (onScreenTime == fpsCurTime) {
22606f6ba60Sopenharmony_ci        long long jitter;
22706f6ba60Sopenharmony_ci        if (prevScreenTimestamp != -1) {
22806f6ba60Sopenharmony_ci            jitter = curScreenTimestamp - prevScreenTimestamp;
22906f6ba60Sopenharmony_ci            fpsInfo.jitters.push_back(jitter);
23006f6ba60Sopenharmony_ci        } else {
23106f6ba60Sopenharmony_ci            if (prevlastScreenTimestamp != 0 && (curScreenTimestamp - prevlastScreenTimestamp) < mod) {
23206f6ba60Sopenharmony_ci                jitter = curScreenTimestamp - prevlastScreenTimestamp;
23306f6ba60Sopenharmony_ci                fpsInfo.jitters.push_back(jitter);
23406f6ba60Sopenharmony_ci            } else {
23506f6ba60Sopenharmony_ci                jitter = curScreenTimestamp - curScreenTimestamp / mod * mod;
23606f6ba60Sopenharmony_ci                fpsInfo.jitters.push_back(jitter);
23706f6ba60Sopenharmony_ci            }
23806f6ba60Sopenharmony_ci        }
23906f6ba60Sopenharmony_ci        prevScreenTimestamp = curScreenTimestamp;
24006f6ba60Sopenharmony_ci        prevlastScreenTimestamp = curScreenTimestamp;
24106f6ba60Sopenharmony_ci    }
24206f6ba60Sopenharmony_ci}
24306f6ba60Sopenharmony_ci
24406f6ba60Sopenharmony_civoid FPS::SetRkFlag()
24506f6ba60Sopenharmony_ci{
24606f6ba60Sopenharmony_ci    rkFlag = true;
24706f6ba60Sopenharmony_ci}
24806f6ba60Sopenharmony_ci
24906f6ba60Sopenharmony_cistd::string FPS::FindFpsRefreshrate()
25006f6ba60Sopenharmony_ci{
25106f6ba60Sopenharmony_ci    std::string screenInfo;
25206f6ba60Sopenharmony_ci    SPUtils::LoadFile(screenPath, screenInfo);
25306f6ba60Sopenharmony_ci    size_t pos = 0;
25406f6ba60Sopenharmony_ci    std::string token;
25506f6ba60Sopenharmony_ci    std::string value;
25606f6ba60Sopenharmony_ci    if (!rkFlag) {
25706f6ba60Sopenharmony_ci        while ((pos = screenInfo.find(";")) != std::string::npos) {
25806f6ba60Sopenharmony_ci            token = screenInfo.substr(0, pos);
25906f6ba60Sopenharmony_ci            screenInfo.erase(0, pos + 1);
26006f6ba60Sopenharmony_ci            if (token.find("current_fps:") != std::string::npos) {
26106f6ba60Sopenharmony_ci                value = token.substr(token.find(":") + 1);
26206f6ba60Sopenharmony_ci                break;
26306f6ba60Sopenharmony_ci            }
26406f6ba60Sopenharmony_ci        }
26506f6ba60Sopenharmony_ci    } else {
26606f6ba60Sopenharmony_ci            std::string screen = OHOS::SmartPerf::SPUtils::GetScreen();
26706f6ba60Sopenharmony_ci            std::string start = "refreshrate=";
26806f6ba60Sopenharmony_ci            size_t startPos = screen.find(start) + start.length();
26906f6ba60Sopenharmony_ci            size_t endPos = screen.length();
27006f6ba60Sopenharmony_ci            value = screen.substr(startPos, endPos - startPos);
27106f6ba60Sopenharmony_ci        }
27206f6ba60Sopenharmony_ci    return value;
27306f6ba60Sopenharmony_ci}
27406f6ba60Sopenharmony_ci}
27506f6ba60Sopenharmony_ci}
27606f6ba60Sopenharmony_ci
277