• 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(fifty, 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.Clear();
126                 return fpsInfoMax;
127             } else {
128                 firstDump = false;
129             }
130         }
131         OHOS::SmartPerf::SPUtils::GetCurrentTime(fifty, prevResultFpsInfo.curTime);
132         fpsInfoMax = GetSurfaceFrame(gameLayerName);
133         if (fpsInfoMax.fps == 0) {
134             return GetChangedLayerFps();
135         } else {
136             return fpsInfoMax;
137         }
138     } else {
139         bool onTop = OHOS::SmartPerf::SPUtils::IsForeGround(pkgName);
140         if (onTop) {
141             std::string uniteLayer;
142             if (!rkFlag && !isOtherDevice) {
143                 uniteLayer = "UniRender";
144             } else if (isOtherDevice) {
145                 uniteLayer = profilerFps.GetSurface();
146             } else {
147                 uniteLayer = profilerFps.GetSurface();
148             }
149             OHOS::SmartPerf::SPUtils::GetCurrentTime(fifty, prevResultFpsInfo.curTime);
150             fpsInfoMax = GetSurfaceFrame(uniteLayer);
151         } else {
152             LOGE("FPS:app is in the background");
153             if (processId.empty()) {
154                 processFlag = true;
155                 fpsInfoMax.Clear();
156             } else {
157                 fpsInfoMax.Clear();
158             }
159         }
160     }
161     return fpsInfoMax;
162 }
163 
SetOtherDeviceFlag()164 bool FPS::SetOtherDeviceFlag()
165 {
166     isOtherDevice = true;
167     return isOtherDevice;
168 }
169 
GetChangedLayerFps()170 FpsInfo FPS::GetChangedLayerFps()
171 {
172     ProfilerFPS &profilerFps = ProfilerFPS::GetInstance();
173     gameLayerName = profilerFps.GetGameLayer();
174     if (gameLayerName.empty()) {
175         if (processId.empty()) {
176             processFlag = true;
177         }
178         fpsInfoMax.Clear();
179     } else {
180         fpsInfoMax = GetSurfaceFrame(gameLayerName);
181     }
182     return fpsInfoMax;
183 }
184 
GetSurfaceFrame(std::string name)185 FpsInfo FPS::GetSurfaceFrame(std::string name)
186 {
187     if (name == "") {
188         return FpsInfo();
189     }
190     static std::map<std::string, FpsInfo> fpsMap;
191     if (fpsMap.count(name) == 0) {
192         FpsInfo tmp;
193         tmp.fps = 0;
194         fpsMap[name] = tmp;
195     }
196     fpsInfo = fpsMap[name];
197     fpsInfo.fps = 0;
198     std::string command = "fps " + name;
199     const std::vector<const char*> args = { "hidumper", "-s", "10", "-a", command.c_str(), nullptr };
200     int pipefd[2];
201     pid_t pid;
202     if (pipe(pipefd) == -1) {
203         LOGE("FPS::Failed to create pipe");
204         return fpsInfo;
205     }
206     pid = fork();
207     if (pid == -1) {
208         LOGE("FPS::Failed to fork");
209         return fpsInfo;
210     }
211     if (pid == 0) {
212         close(pipefd[0]);
213         dup2(pipefd[1], STDOUT_FILENO);
214         close(pipefd[1]);
215         execvp(args[0], const_cast<char *const*>(args.data()));
216         LOGE("FPS::Failed to execute hidumper");
217         _exit(EXIT_FAILURE);
218     }
219     close(pipefd[1]);
220     ReadDataFromPipe(pipefd[0]);
221     close(pipefd[0]);
222     waitpid(pid, nullptr, 0);
223     return fpsInfo;
224 }
225 
ReadDataFromPipe(int fd)226 void FPS::ReadDataFromPipe(int fd)
227 {
228     fpsInfo.currTimeStamps.clear();
229     char tmp[1024];
230     fpsNum = 0;
231     prevScreenTimestamp = -1;
232     bool isBreak = false;
233     struct timespec time1 = { 0 };
234     clock_gettime(CLOCK_MONOTONIC, &time1);
235     fpsInfo.curTime = static_cast<int>(time1.tv_sec - 1);
236     fpsInfo.currTimeDump = (time1.tv_sec - 1) * mod + time1.tv_nsec;
237     LOGD("FPS:fpsInfo.curTime: %d, FPS:psInfo.currTimeDump: %lld",
238         fpsInfo.curTime, fpsInfo.currTimeDump);
239     FILE *fp = fdopen(fd, "r");
240     if (!fp) {
241         LOGE("FPS::Failed to open file descriptor");
242         return;
243     }
244     std::stringstream sstream;
245     while (fgets(tmp, sizeof(tmp), fp) != nullptr) {
246         LOGD("FPS::ReadDataFromPipe::dump time: %s", tmp);
247         curScreenTimestamp = 0;
248         sstream.clear();
249         sstream.str(tmp);
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