• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         const int fullFrame = 120;
54         const int maxFullFrame = 123;
55         if (fpsInfoResult.fps > fullFrame && fpsInfoResult.fps < maxFullFrame) {
56             fpsInfoResult.fps = fullFrame;
57         }
58         result["fps"] = std::to_string(fpsInfoResult.fps);
59         std::string jitterStr = "";
60         std::string split = "";
61         for (size_t i = 0; i < fpsInfoResult.jitters.size(); i++) {
62             if (i > 0) {
63                 split = ";;";
64             }
65             jitterStr += split + std::to_string(fpsInfoResult.jitters[i]);
66         }
67         result["fpsJitters"] = jitterStr;
68         LOGD("result.fps: %s, result.curTime: %s, result.jitters: %s",
69             std::to_string(fpsInfoResult.fps).c_str(),
70             std::to_string(fpsInfoResult.curTime).c_str(),
71             jitterStr.c_str());
72         SetFpsCurrentFpsTime(fpsInfoResult);
73     }
74     return result;
75 }
76 
SetFpsCurrentFpsTime(FpsInfo fpsInfoResult)77 void FPS::SetFpsCurrentFpsTime(FpsInfo fpsInfoResult)
78 {
79     ffTime.fps = fpsInfoResult.fps;
80     if (!fpsInfoResult.jitters.empty()) {
81         auto maxElement = std::max_element(fpsInfoResult.jitters.begin(), fpsInfoResult.jitters.end());
82         ffTime.currentFpsTime = *maxElement;
83     }
84 }
85 
GetFpsCurrentFpsTime()86 FpsCurrentFpsTime FPS::GetFpsCurrentFpsTime()
87 {
88     return ffTime;
89 }
90 
SetPackageName(std::string pName)91 void FPS::SetPackageName(std::string pName)
92 {
93     pkgName = std::move(pName);
94 }
95 
SetProcessId(const std::string & pid)96 void FPS::SetProcessId(const std::string &pid)
97 {
98     processId = pid;
99 }
100 
SetLayerName(std::string sName)101 void FPS::SetLayerName(std::string sName)
102 {
103     surfaceViewName = std::move(sName);
104 }
GetDiffLayersFpsInfo(const std::string & sName)105 FpsInfo FPS::GetDiffLayersFpsInfo(const std::string &sName)
106 {
107     OHOS::SmartPerf::SPUtils::GetCurrentTime(prevResultFpsInfo.curTime);
108     fpsInfoMax = GetSurfaceFrame(sName);
109     return fpsInfoMax;
110 }
111 
GetFpsInfo()112 FpsInfo FPS::GetFpsInfo()
113 {
114     processFlag = false;
115     fpsInfoMax.fps = 0;
116     if (pkgName.empty()) {
117         return fpsInfoMax;
118     }
119     ProfilerFPS &profilerFps = ProfilerFPS::GetInstance();
120     if (isGameApp) {
121         if (firstDump) {
122             gameLayerName = profilerFps.GetGameLayer();
123             if (gameLayerName.empty()) {
124                 firstDump = true;
125                 fpsInfoMax.fps = 0;
126                 fpsInfoMax.jitters.clear();
127                 return fpsInfoMax;
128             } else {
129                 firstDump = false;
130             }
131         }
132         OHOS::SmartPerf::SPUtils::GetCurrentTime(prevResultFpsInfo.curTime);
133         fpsInfoMax = GetSurfaceFrame(gameLayerName);
134         if (fpsInfoMax.fps == 0) {
135             return GetChangedLayerFps();
136         } else {
137             return fpsInfoMax;
138         }
139     } else {
140         bool onTop = OHOS::SmartPerf::SPUtils::IsForeGround(pkgName);
141         if (onTop) {
142             std::string uniteLayer;
143             if (!rkFlag && !isOtherDevice) {
144                 uniteLayer = "UniRender";
145             } else {
146                 uniteLayer = profilerFps.GetSurface();
147             }
148             OHOS::SmartPerf::SPUtils::GetCurrentTime(prevResultFpsInfo.curTime);
149             fpsInfoMax = GetSurfaceFrame(uniteLayer);
150         } else {
151             LOGE("FPS:app is in the background");
152             if (processId.empty()) {
153                 processFlag = true;
154             }
155             fpsInfoMax.fps = 0;
156             fpsInfoMax.jitters.clear();
157         }
158     }
159     return fpsInfoMax;
160 }
161 
SetOtherDeviceFlag()162 bool FPS::SetOtherDeviceFlag()
163 {
164     isOtherDevice = true;
165     return isOtherDevice;
166 }
167 
GetChangedLayerFps()168 FpsInfo FPS::GetChangedLayerFps()
169 {
170     ProfilerFPS &profilerFps = ProfilerFPS::GetInstance();
171     gameLayerName = profilerFps.GetGameLayer();
172     if (gameLayerName.empty()) {
173         if (processId.empty()) {
174             processFlag = true;
175         }
176         fpsInfoMax.fps = 0;
177         fpsInfoMax.jitters.clear();
178     } else {
179         fpsInfoMax = GetSurfaceFrame(gameLayerName);
180     }
181     return fpsInfoMax;
182 }
183 
GetSurfaceFrame(std::string name)184 FpsInfo FPS::GetSurfaceFrame(std::string name)
185 {
186     if (name == "") {
187         return FpsInfo();
188     }
189     static std::map<std::string, FpsInfo> fpsMap;
190     if (fpsMap.count(name) == 0) {
191         FpsInfo tmp;
192         tmp.fps = 0;
193         fpsMap[name] = tmp;
194     }
195     fpsInfo = fpsMap[name];
196     fpsInfo.fps = 0;
197     std::string command = "fps " + name;
198     const std::vector<const char*> args = { "hidumper", "-s", "10", "-a", command.c_str(), nullptr };
199     int pipefd[2];
200     pid_t pid;
201     if (pipe(pipefd) == -1) {
202         LOGE("FPS::Failed to create pipe");
203         return fpsInfo;
204     }
205     pid = fork();
206     if (pid == -1) {
207         LOGE("FPS::Failed to fork");
208         return fpsInfo;
209     }
210     if (pid == 0) {
211         close(pipefd[0]);
212         dup2(pipefd[1], STDOUT_FILENO);
213         close(pipefd[1]);
214         execvp(args[0], const_cast<char *const*>(args.data()));
215         LOGE("FPS::Failed to execute hidumper");
216         _exit(EXIT_FAILURE);
217     }
218     close(pipefd[1]);
219     ReadDataFromPipe(pipefd[0]);
220     close(pipefd[0]);
221     waitpid(pid, nullptr, 0);
222     return fpsInfo;
223 }
224 
ReadDataFromPipe(int fd)225 void FPS::ReadDataFromPipe(int fd)
226 {
227     fpsInfo.currTimeStamps.clear();
228     char tmp[1024];
229     fpsNum = 0;
230     prevScreenTimestamp = -1;
231     bool isBreak = false;
232     struct timespec time1 = { 0 };
233     clock_gettime(CLOCK_MONOTONIC, &time1);
234     fpsInfo.curTime = static_cast<int>(time1.tv_sec - 1);
235     fpsInfo.currTimeDump = (time1.tv_sec - 1) * mod + time1.tv_nsec;
236     LOGD("FPS:fpsInfo.curTime: %d, FPS:psInfo.currTimeDump: %lld",
237         fpsInfo.curTime, fpsInfo.currTimeDump);
238     FILE *fp = fdopen(fd, "r");
239     if (!fp) {
240         LOGE("FPS::Failed to open file descriptor");
241         return;
242     }
243     std::stringstream sstream;
244     while (fgets(tmp, sizeof(tmp), fp) != nullptr) {
245         LOGD("FPS::ReadDataFromPipe::dump time: %s", tmp);
246         std::string tmpStr(tmp);
247         curScreenTimestamp = 0;
248         sstream.clear();
249         sstream.str(tmpStr);
250         sstream >> curScreenTimestamp;
251         if (curScreenTimestamp == 0) {
252             continue;
253         }
254         if (CalcFpsAndJitters(isBreak)) {
255             break;
256         }
257     }
258     CalcJitters();
259 }
260 
CalcFpsAndJitters(bool isBreak)261 bool FPS::CalcFpsAndJitters(bool isBreak)
262 {
263     long long onScreenTime = curScreenTimestamp / mod;
264     bool findFpsCurTime = (onScreenTime == fpsInfo.curTime);
265     if (findFpsCurTime) {
266         isBreak = true;
267         fpsNum++;
268         fpsInfo.fps = fpsNum;
269         fpsInfo.currTimeStamps.push_back(curScreenTimestamp);
270     } else {
271         findFpsCurTime = false;
272     }
273     return isBreak && !findFpsCurTime;
274 }
275 
CalcJitters()276 void FPS::CalcJitters()
277 {
278     bool isOrder = true;
279     if (fpsInfo.currTimeStamps.size() > 1) {
280         isOrder = fpsInfo.currTimeStamps[1] - fpsInfo.currTimeStamps[0] > 0;
281     }
282     if (isOrder) {
283         for (size_t i = 0; i < fpsInfo.currTimeStamps.size(); i++) {
284             curScreenTimestamp = fpsInfo.currTimeStamps[i];
285             long long jitter = CalculateJitter();
286             fpsInfo.jitters.push_back(jitter);
287             prevlastScreenTimestamp = curScreenTimestamp;
288             prevScreenTimestamp = curScreenTimestamp;
289         }
290     } else {
291         for (size_t i = fpsInfo.currTimeStamps.size(); i > 0; i--) {
292             curScreenTimestamp = fpsInfo.currTimeStamps[i - 1];
293             long long jitter = CalculateJitter();
294             fpsInfo.jitters.push_back(jitter);
295             prevlastScreenTimestamp = curScreenTimestamp;
296             prevScreenTimestamp = curScreenTimestamp;
297         }
298     }
299 }
300 
CalculateJitter() const301 long long FPS::CalculateJitter() const
302 {
303     long long jitter;
304     if (prevScreenTimestamp == -1) {
305         if (prevlastScreenTimestamp != 0 && (curScreenTimestamp - prevlastScreenTimestamp) < mod) {
306             jitter = curScreenTimestamp - prevlastScreenTimestamp;
307         } else {
308             jitter = curScreenTimestamp % mod;
309         }
310     } else {
311         jitter = curScreenTimestamp - prevScreenTimestamp;
312     }
313     return jitter;
314 }
315 
SetRkFlag()316 void FPS::SetRkFlag()
317 {
318     rkFlag = true;
319 }
320 
FindFpsRefreshrate()321 std::string FPS::FindFpsRefreshrate()
322 {
323     std::string value;
324     std::string screenInfo;
325     SPUtils::LoadFile(screenPath, screenInfo);
326     value = GetHardenRefreshrate(screenInfo);
327     size_t pos = 0;
328     std::string token;
329     if (!rkFlag) {
330         while ((pos = screenInfo.find(";")) != std::string::npos) {
331             token = screenInfo.substr(0, pos);
332             screenInfo.erase(0, pos + 1);
333             if (token.find("current_fps:") != std::string::npos) {
334                 value = token.substr(token.find(":") + 1);
335                 break;
336             }
337         }
338     } else {
339             std::string screen = OHOS::SmartPerf::SPUtils::GetScreen();
340             std::string start = "refreshrate=";
341             size_t startPos = screen.find(start) + start.length();
342             size_t endPos = screen.length();
343             value = screen.substr(startPos, endPos - startPos);
344         }
345     return value;
346 }
347 
GetHardenRefreshrate(std::string & screenInfo) const348 std::string FPS::GetHardenRefreshrate(std::string &screenInfo) const
349 {
350     if (screenInfo.empty()) {
351         SPUtils::LoadCmd(HIDUMPER_CMD_MAP.at(HidumperCmd::DUMPER_SCREEN), screenInfo);
352     }
353     std::string value = "";
354     std::string refreshrate = "refreshrate=";
355     size_t activeModePos = screenInfo.find("activeMode:");
356     if (activeModePos != std::string::npos) {
357         size_t refreshRatePos = screenInfo.find(refreshrate, activeModePos);
358         if (refreshRatePos != std::string::npos) {
359             size_t endPos = screenInfo.find(" ", refreshRatePos);
360             if (endPos != std::string::npos) {
361                 value = screenInfo.substr(refreshRatePos + refreshrate.length(),
362                 endPos - refreshRatePos - refreshrate.length());
363             }
364         }
365     }
366     return value;
367 }
368 }
369 }
370 
371