1 /*
2  * Copyright (C) 2021 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 #include <cstdio>
16 #include <algorithm>
17 #include <iostream>
18 #include <sstream>
19 #include <queue>
20 #include <string>
21 #include <thread>
22 #include <unistd.h>
23 #include <ctime>
24 #include <sys/time.h>
25 #include "include/sp_utils.h"
26 #include "include/ByTrace.h"
27 #include "include/Capture.h"
28 #include "include/FPS.h"
29 #include "include/startup_delay.h"
30 #include "include/profiler_fps.h"
31 #include "include/sp_log.h"
32 #include "include/common.h"
33 #include <sys/wait.h>
34 #include <sys/types.h>
35 namespace OHOS {
36 namespace SmartPerf {
ItemData()37 std::map<std::string, std::string> FPS::ItemData()
38 {
39     std::map<std::string, std::string> result;
40     FpsInfo fpsInfoResult;
41     if (surfaceViewName.length() > 0) {
42         fpsInfoResult = GetDiffLayersFpsInfo(surfaceViewName);
43     } else {
44         fpsInfoResult = GetFpsInfo();
45     }
46     prevResultFpsInfo = fpsInfoResult;
47     std::string value = FindFpsRefreshrate();
48     result["refreshrate"] = value;
49     if (processFlag) {
50         result["fps"] = "NA";
51         result["fpsJitters"] = "NA";
52     } else {
53         int fullFrame = 120;
54         if (fpsInfoResult.fps > fullFrame) {
55             fpsInfoResult.fps = fullFrame;
56         }
57         result["fps"] = std::to_string(fpsInfoResult.fps);
58         LOGI("result.fps: %s", std::to_string(fpsInfoResult.fps).c_str());
59         LOGI("result.curTime: %s", std::to_string(fpsInfoResult.curTime).c_str());
60         std::string jitterStr = "";
61         std::string split = "";
62         for (size_t i = 0; i < fpsInfoResult.jitters.size(); i++) {
63             if (i > 0) {
64                 split = ";;";
65             }
66             jitterStr += split + std::to_string(fpsInfoResult.jitters[i]);
67         }
68         result["fpsJitters"] = jitterStr;
69         LOGI("result.jitters: %s", jitterStr.c_str());
70         SetFpsCurrentFpsTime(fpsInfoResult);
71     }
72     return result;
73 }
74 
SetFpsCurrentFpsTime(FpsInfo fpsInfoResult)75 void FPS::SetFpsCurrentFpsTime(FpsInfo fpsInfoResult)
76 {
77     ffTime.fps = fpsInfoResult.fps;
78     if (!fpsInfoResult.jitters.empty()) {
79         auto maxElement = std::max_element(fpsInfoResult.jitters.begin(), fpsInfoResult.jitters.end());
80         ffTime.currentFpsTime = *maxElement;
81     }
82 }
83 
GetFpsCurrentFpsTime()84 FpsCurrentFpsTime FPS::GetFpsCurrentFpsTime()
85 {
86     return ffTime;
87 }
88 
SetPackageName(std::string pName)89 void FPS::SetPackageName(std::string pName)
90 {
91     pkgName = std::move(pName);
92 }
93 
SetProcessId(const std::string &pid)94 void FPS::SetProcessId(const std::string &pid)
95 {
96     processId = pid;
97 }
98 
SetLayerName(std::string sName)99 void FPS::SetLayerName(std::string sName)
100 {
101     surfaceViewName = std::move(sName);
102 }
GetDiffLayersFpsInfo(const std::string &sName)103 FpsInfo FPS::GetDiffLayersFpsInfo(const std::string &sName)
104 {
105     OHOS::SmartPerf::SPUtils::GetCurrentTime(fifty, prevResultFpsInfo.curTime);
106     fpsInfoMax = GetSurfaceFrame(sName);
107     return fpsInfoMax;
108 }
109 
GetFpsInfo()110 FpsInfo FPS::GetFpsInfo()
111 {
112     processFlag = false;
113     fpsInfoMax.fps = 0;
114     if (pkgName.empty()) {
115         return fpsInfoMax;
116     }
117     bool onTop = OHOS::SmartPerf::SPUtils::IsForeGround(pkgName);
118     if (onTop) {
119         std::string uniteLayer;
120         if (!rkFlag) {
121             uniteLayer = "UniRender";
122         } else {
123             ProfilerFPS &profilerFps = ProfilerFPS::GetInstance();
124             uniteLayer = profilerFps.GetSurface();
125         }
126         OHOS::SmartPerf::SPUtils::GetCurrentTime(fifty, prevResultFpsInfo.curTime);
127         fpsInfoMax = GetSurfaceFrame(uniteLayer);
128     } else {
129         LOGI("FPS:app is in the background");
130         if (processId.empty()) {
131             processFlag = true;
132             fpsInfoMax.Clear();
133         } else {
134             fpsInfoMax.Clear();
135         }
136     }
137     return fpsInfoMax;
138 }
139 
GetSurfaceFrame(std::string name)140 FpsInfo FPS::GetSurfaceFrame(std::string name)
141 {
142     if (name == "") {
143         return FpsInfo();
144     }
145     static std::map<std::string, FpsInfo> fpsMap;
146     if (fpsMap.count(name) == 0) {
147         FpsInfo tmp;
148         tmp.fps = 0;
149         fpsMap[name] = tmp;
150     }
151     fpsInfo = fpsMap[name];
152     fpsInfo.fps = 0;
153     std::string command = "fps " + name;
154     const char* args[] = { "hidumper", "-s", "10", "-a", command.c_str(), nullptr };
155     int pipefd[2];
156     pid_t pid;
157     if (pipe(pipefd) == -1) {
158         LOGE("FPS::Failed to create pipe");
159         return fpsInfo;
160     }
161     pid = fork();
162     if (pid == -1) {
163         LOGE("FPS::Failed to fork");
164         return fpsInfo;
165     } else if (pid == 0) {
166         close(pipefd[0]);
167         dup2(pipefd[1], STDOUT_FILENO);
168         close(pipefd[1]);
169         if (execvp(args[0], const_cast<char *const*>(args)) == -1) {
170             LOGE("FPS::Failed to execute hidumper");
171             return fpsInfo;
172         }
173     } else {
174         close(pipefd[1]);
175         ReadDataFromPipe(pipefd[0]);
176         close(pipefd[0]);
177         waitpid(pid, nullptr, 0);
178     }
179     return fpsInfo;
180 }
181 
ReadDataFromPipe(int fd)182 void FPS::ReadDataFromPipe(int fd)
183 {
184     char tmp[1024];
185     fpsNum = 0;
186     prevScreenTimestamp = -1;
187     LOGI("FPS::dump time: start!");
188     struct timespec time1 = { 0 };
189     clock_gettime(CLOCK_MONOTONIC, &time1);
190     fpsInfo.curTime = static_cast<int>(time1.tv_sec - 1);
191     fpsInfo.currTimeDump = (time1.tv_sec - 1) * mod + time1.tv_nsec;
192     LOGI("FPS:fpsInfo.curTime: %d", fpsInfo.curTime);
193     LOGI("FPS:psInfo.currTimeDump: %lld", fpsInfo.currTimeDump);
194     FILE *fp = fdopen(fd, "r");
195     if (!fp) {
196         LOGE("FPS::Failed to open file descriptor");
197         return;
198     }
199     while (fgets(tmp, sizeof(tmp), fp) != nullptr) {
200         std::string str(tmp);
201         LOGD("FPS::dump time: %s", str.c_str());
202         curScreenTimestamp = 0;
203         std::stringstream sstream;
204         sstream << tmp;
205         sstream >> curScreenTimestamp;
206         if (curScreenTimestamp == 0) {
207             continue;
208         }
209         CalcFpsAndJitters();
210     }
211     if (fclose(fp) == EOF) {
212         LOGE("FPS::Failed to close file descriptor");
213     }
214 }
215 
CalcFpsAndJitters()216 void FPS::CalcFpsAndJitters()
217 {
218     std::string onScreenTime = std::to_string(curScreenTimestamp / mod);
219     std::string fpsCurTime = std::to_string(fpsInfo.curTime);
220     if (onScreenTime.find(fpsCurTime) != std::string::npos) {
221         fpsNum++;
222         fpsInfo.currTimeStamps.push_back(curScreenTimestamp);
223     }
224     fpsInfo.fps = fpsNum;
225     if (onScreenTime == fpsCurTime) {
226         long long jitter;
227         if (prevScreenTimestamp != -1) {
228             jitter = curScreenTimestamp - prevScreenTimestamp;
229             fpsInfo.jitters.push_back(jitter);
230         } else {
231             if (prevlastScreenTimestamp != 0 && (curScreenTimestamp - prevlastScreenTimestamp) < mod) {
232                 jitter = curScreenTimestamp - prevlastScreenTimestamp;
233                 fpsInfo.jitters.push_back(jitter);
234             } else {
235                 jitter = curScreenTimestamp - curScreenTimestamp / mod * mod;
236                 fpsInfo.jitters.push_back(jitter);
237             }
238         }
239         prevScreenTimestamp = curScreenTimestamp;
240         prevlastScreenTimestamp = curScreenTimestamp;
241     }
242 }
243 
SetRkFlag()244 void FPS::SetRkFlag()
245 {
246     rkFlag = true;
247 }
248 
FindFpsRefreshrate()249 std::string FPS::FindFpsRefreshrate()
250 {
251     std::string screenInfo;
252     SPUtils::LoadFile(screenPath, screenInfo);
253     size_t pos = 0;
254     std::string token;
255     std::string value;
256     if (!rkFlag) {
257         while ((pos = screenInfo.find(";")) != std::string::npos) {
258             token = screenInfo.substr(0, pos);
259             screenInfo.erase(0, pos + 1);
260             if (token.find("current_fps:") != std::string::npos) {
261                 value = token.substr(token.find(":") + 1);
262                 break;
263             }
264         }
265     } else {
266             std::string screen = OHOS::SmartPerf::SPUtils::GetScreen();
267             std::string start = "refreshrate=";
268             size_t startPos = screen.find(start) + start.length();
269             size_t endPos = screen.length();
270             value = screen.substr(startPos, endPos - startPos);
271         }
272     return value;
273 }
274 }
275 }
276 
277