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