• 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     (void)fclose(fp);
259     CalcJitters();
260 }
261 
CalcFpsAndJitters(bool isBreak)262 bool FPS::CalcFpsAndJitters(bool isBreak)
263 {
264     long long onScreenTime = curScreenTimestamp / mod;
265     bool findFpsCurTime = (onScreenTime == fpsInfo.curTime);
266     if (findFpsCurTime) {
267         isBreak = true;
268         fpsNum++;
269         fpsInfo.fps = fpsNum;
270         fpsInfo.currTimeStamps.push_back(curScreenTimestamp);
271     } else {
272         findFpsCurTime = false;
273     }
274     return isBreak && !findFpsCurTime;
275 }
276 
CalcJitters()277 void FPS::CalcJitters()
278 {
279     bool isOrder = true;
280     if (fpsInfo.currTimeStamps.size() > 1) {
281         isOrder = fpsInfo.currTimeStamps[1] - fpsInfo.currTimeStamps[0] > 0;
282     }
283     if (isOrder) {
284         for (size_t i = 0; i < fpsInfo.currTimeStamps.size(); i++) {
285             curScreenTimestamp = fpsInfo.currTimeStamps[i];
286             long long jitter = CalculateJitter();
287             fpsInfo.jitters.push_back(jitter);
288             prevlastScreenTimestamp = curScreenTimestamp;
289             prevScreenTimestamp = curScreenTimestamp;
290         }
291     } else {
292         for (size_t i = fpsInfo.currTimeStamps.size(); i > 0 ; i--) {
293             curScreenTimestamp = fpsInfo.currTimeStamps[i - 1];
294             long long jitter = CalculateJitter();
295             fpsInfo.jitters.push_back(jitter);
296             prevlastScreenTimestamp = curScreenTimestamp;
297             prevScreenTimestamp = curScreenTimestamp;
298         }
299     }
300 }
301 
CalculateJitter() const302 long long FPS::CalculateJitter() const
303 {
304     long long jitter;
305     if (prevScreenTimestamp == -1) {
306         if (prevlastScreenTimestamp != 0 && (curScreenTimestamp - prevlastScreenTimestamp) < mod) {
307             jitter = curScreenTimestamp - prevlastScreenTimestamp;
308         } else {
309             jitter = curScreenTimestamp % mod;
310         }
311     } else {
312         jitter = curScreenTimestamp - prevScreenTimestamp;
313     }
314     return jitter;
315 }
316 
SetRkFlag()317 void FPS::SetRkFlag()
318 {
319     rkFlag = true;
320 }
321 
FindFpsRefreshrate()322 std::string FPS::FindFpsRefreshrate()
323 {
324     std::string value;
325     std::string screenInfo;
326     SPUtils::LoadFile(screenPath, screenInfo);
327     value = GetHardenRefreshrate(screenInfo);
328     size_t pos = 0;
329     std::string token;
330     if (!rkFlag) {
331         while ((pos = screenInfo.find(";")) != std::string::npos) {
332             token = screenInfo.substr(0, pos);
333             screenInfo.erase(0, pos + 1);
334             if (token.find("current_fps:") != std::string::npos) {
335                 value = token.substr(token.find(":") + 1);
336                 break;
337             }
338         }
339     } else {
340             std::string screen = OHOS::SmartPerf::SPUtils::GetScreen();
341             std::string start = "refreshrate=";
342             size_t startPos = screen.find(start) + start.length();
343             size_t endPos = screen.length();
344             value = screen.substr(startPos, endPos - startPos);
345         }
346     return value;
347 }
348 
GetHardenRefreshrate(std::string & screenInfo) const349 std::string FPS::GetHardenRefreshrate(std::string &screenInfo) const
350 {
351     if (screenInfo.empty()) {
352         SPUtils::LoadCmd(HIDUMPER_CMD_MAP.at(HidumperCmd::DUMPER_SCREEN), screenInfo);
353     }
354     std::string value = "";
355     std::string refreshrate = "refreshrate=";
356     size_t activeModePos = screenInfo.find("activeMode:");
357     if (activeModePos != std::string::npos) {
358         size_t refreshRatePos = screenInfo.find(refreshrate, activeModePos);
359         if (refreshRatePos != std::string::npos) {
360             size_t endPos = screenInfo.find(" ", refreshRatePos);
361             if (endPos != std::string::npos) {
362                 value = screenInfo.substr(refreshRatePos + refreshrate.length(),
363                 endPos - refreshRatePos - refreshrate.length());
364             }
365         }
366     }
367     return value;
368 }
369 }
370 }
371 
372