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