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