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 <thread>
20 #include "include/sp_utils.h"
21 #include "include/ByTrace.h"
22 #include "include/Capture.h"
23 #include "include/FPS.h"
24 namespace OHOS {
25 namespace SmartPerf {
ItemData()26 std::map<std::string, std::string> FPS::ItemData()
27 {
28 std::map<std::string, std::string> result;
29 FpsInfo fpsInfo = GetFpsInfo();
30 result["fps"] = std::to_string(fpsInfo.fps);
31 std::string jitterStr = "";
32 std::string split = "";
33 for (size_t i = 0; i < fpsInfo.jitters.size(); i++) {
34 if (i > 0) {
35 split = ";;";
36 }
37 jitterStr += split + std::to_string(fpsInfo.jitters[i]);
38 }
39 result["fpsJitters"] = jitterStr;
40 if (isCatchTrace > 0) {
41 ByTrace::GetInstance().CheckFpsJitters(fpsInfo.jitters);
42 }
43 if (isCapture > 0) {
44 Capture::GetInstance().TriggerGetCatch(SPUtils::GetCurTime());
45 }
46 return result;
47 }
48
SetTraceCatch()49 void FPS::SetTraceCatch()
50 {
51 isCatchTrace = 1;
52 }
53
SetCaptureOn()54 void FPS::SetCaptureOn()
55 {
56 isCapture = 1;
57 }
58
SetPackageName(std::string pName)59 void FPS::SetPackageName(std::string pName)
60 {
61 pkgName = std::move(pName);
62 }
GetSurface()63 std::string FPS::GetSurface()
64 {
65 std::string cmdResult;
66 std::string cmdString1 = "hidumper -s 10 -a sur";
67 std::string cmdString2 = "face | grep sur";
68 std::string cmdString3 = "face";
69 SPUtils::LoadCmd(cmdString1 + cmdString2 + cmdString3, cmdResult);
70 size_t position1 = cmdResult.find("[");
71 size_t position2 = cmdResult.find("]");
72 return cmdResult.substr(position1 + 1, position2 - position1 - 1);
73 }
74
GetFpsInfo()75 FpsInfo FPS::GetFpsInfo()
76 {
77 FpsInfo fpsInfoMax;
78 fpsInfoMax.fps = 0;
79 int fpsValue = 0;
80
81 if (pkgName.empty()) {
82 return fpsInfoMax;
83 }
84
85 std::string layerName;
86 std::vector<std::string> sps;
87 SPUtils::StrSplit(this->pkgName, ".", sps);
88 std::string addEndChar = "0";
89 const uint64_t pNameLastPos = sps.size();
90 std::string pkgSuffix = sps[pNameLastPos - 1];
91 layerName = std::string(pkgSuffix.c_str() + addEndChar);
92 std::string uniteLayer = "DisplayNode";
93 uniteLayer = GetSurface();
94 std::string spSurfacePrefix = "sp_";
95 std::string line = GetLayer(layerName);
96 std::vector<std::string> params;
97 SPUtils::StrSplit(line, ":", params);
98 std::string pkgZOrd = params[1];
99 std::string zOrd = "-1";
100 std::string focusSurface = params[0];
101 FpsInfo uniteFpsInfo;
102 if (focusSurface.find(layerName) != std::string::npos) {
103 uniteFpsInfo = GetSurfaceFrame(uniteLayer);
104 }
105 if ((focusSurface.find(spSurfacePrefix) != std::string::npos) && (strcmp(pkgZOrd.c_str(), zOrd.c_str()) != 0)) {
106 if (uniteFpsInfo.fps <= fpsValue) {
107 uniteFpsInfo = GetSurfaceFrame(uniteLayer);
108 }
109 }
110 FpsInfo fpsInfo = GetSurfaceFrame(layerName);
111 if (fpsInfo.fps > uniteFpsInfo.fps) {
112 fpsInfoMax = fpsInfo;
113 } else {
114 fpsInfoMax = uniteFpsInfo;
115 }
116 if (fpsInfoMax.fps < fpsValue) {
117 fpsInfoMax.fps = fpsValue;
118 }
119 return fpsInfoMax;
120 }
121
GetSurfaceFrame(std::string name)122 FpsInfo FPS::GetSurfaceFrame(std::string name)
123 {
124 if (name == "") {
125 return FpsInfo();
126 }
127 static std::map<std::string, FpsInfo> fpsMap;
128 if (fpsMap.count(name) == 0) {
129 FpsInfo tmp;
130 tmp.fps = 0;
131 tmp.preFps = 0;
132 fpsMap[name] = tmp;
133 }
134 FpsInfo &fpsInfo = fpsMap[name];
135 fpsInfo.fps = 0;
136 FILE *fp;
137 static char tmp[1024];
138 std::string cmd = "hidumper -s 10 -a \"fps " + name + "\"";
139 fp = popen(cmd.c_str(), "r");
140 if (fp == nullptr) {
141 return fpsInfo;
142 }
143 long long mod = 1e9;
144 long long lastReadyTime = -1;
145 int fpsGb = 0;
146 static long long lastLineTime;
147 if (!(fpsInfo.timeStampQ).empty()) {
148 lastReadyTime = (fpsInfo.timeStampQ).back();
149 lastLineTime = (fpsInfo.timeStampQ).back();
150 }
151 bool jump = false;
152 bool refresh = false;
153
154 int cnt = 0;
155 int zeroNum = 0;
156 while (fgets(tmp, sizeof(tmp), fp) != nullptr) {
157 long long frameReadyTime = 0;
158 std::stringstream sstream;
159 sstream << tmp;
160 sstream >> frameReadyTime;
161 cnt++;
162 if (frameReadyTime == 0) {
163 zeroNum++;
164 continue;
165 }
166 if (lastReadyTime >= frameReadyTime) {
167 lastReadyTime = -1;
168 continue;
169 }
170 refresh = true;
171 long long tFrameReadyTime = frameReadyTime / mod;
172 long long tLastReadyTime = lastReadyTime / mod;
173 long long lastFrame = -1;
174 if (tFrameReadyTime == tLastReadyTime) {
175 (fpsInfo.timeStampQ).push(frameReadyTime);
176 } else if (tFrameReadyTime == tLastReadyTime + 1) {
177 jump = true;
178 lastReadyTime = frameReadyTime;
179 int fpsTmp = 0;
180 fpsInfo.jitters.clear();
181 while (!(fpsInfo.timeStampQ).empty()) {
182 fpsTmp++;
183 long long currFrame = (fpsInfo.timeStampQ.front());
184 if (lastFrame != -1) {
185 long long jitter = currFrame - lastFrame;
186 fpsInfo.jitters.push_back(jitter);
187 }
188 lastFrame = currFrame;
189 (fpsInfo.timeStampQ).pop();
190 }
191
192 fpsGb = fpsTmp;
193
194 (fpsInfo.timeStampQ).push(frameReadyTime);
195
196 fpsInfo.lastFrameReadyTime = lastFrame;
197 } else if (tFrameReadyTime > tLastReadyTime + 1) {
198 jump = true;
199 lastReadyTime = frameReadyTime;
200
201 while (!(fpsInfo.timeStampQ).empty()) {
202 (fpsInfo.timeStampQ).pop();
203 }
204
205 (fpsInfo.timeStampQ).push(frameReadyTime);
206 }
207 }
208
209 pclose(fp);
210 const int maxZeroNum = 120;
211 if (zeroNum >= maxZeroNum) {
212 while (!(fpsInfo.timeStampQ.empty())) {
213 fpsInfo.timeStampQ.pop();
214 }
215 fpsInfo.fps = 0;
216 return fpsInfo;
217 }
218 const int minPrintLine = 5;
219 if (cnt < minPrintLine) {
220 fpsInfo.fps = fpsInfo.preFps;
221 return fpsInfo;
222 }
223 if (!fpsInfo.timeStampQ.empty() && fpsInfo.timeStampQ.back() == lastLineTime) {
224 fpsInfo.fps = fpsGb;
225 return fpsInfo;
226 }
227 if (fpsGb > 0) {
228 fpsInfo.fps = fpsGb;
229 fpsInfo.preFps = fpsGb;
230 return fpsInfo;
231 } else if (refresh && !jump) {
232 fpsInfo.fps = fpsInfo.preFps;
233 return fpsInfo;
234 } else {
235 fpsInfo.fps = 0;
236 return fpsInfo;
237 }
238 }
239
GetLayer(std::string pkgSurface)240 std::string FPS::GetLayer(std::string pkgSurface)
241 {
242 std::vector<DumpEntity> dumpEntityList;
243 std::string curFocusId = "-1";
244 const std::string cmd = "hidumper -s WindowManagerService -a -a";
245 FILE *fd = popen(cmd.c_str(), "r");
246 if (fd != nullptr) {
247 int lineNum = 0;
248 char buf[1024] = {'\0'};
249
250 const int paramFifteen = 15;
251 const int paramThree = 3;
252 const int windowNameIndex = 0;
253 const int windowIdIndex = 3;
254 const int focusNameIndex = 2;
255
256 while ((fgets(buf, sizeof(buf), fd)) != nullptr) {
257 std::string line = buf;
258 if (line[0] == '-' || line[0] == ' ') {
259 continue;
260 }
261 std::vector<std::string> params;
262 SPUtils::StrSplit(line, " ", params);
263 if (params[windowNameIndex].find("WindowName") != std::string::npos &&
264 params[windowIdIndex].find("WinId") != std::string::npos) {
265 continue;
266 }
267 if (params.size() == paramFifteen) {
268 DumpEntity dumpEntity { params[0], params[1], params[2], params[3], params[7]};
269 dumpEntityList.push_back(dumpEntity);
270 }
271 if (params.size() == paramThree) {
272 curFocusId = params[focusNameIndex];
273 break;
274 }
275 lineNum++;
276 }
277 pclose(fd);
278 }
279
280 std::string focusWindowName = "NA";
281 std::string pkgZOrd = "-1";
282 int curId = std::stoi(curFocusId);
283 for (size_t i = 0; i < dumpEntityList.size(); i++) {
284 DumpEntity dumpItem = dumpEntityList[i];
285 int curWinId = std::stoi(dumpItem.windId);
286 if (curId == curWinId) {
287 focusWindowName = dumpItem.windowName;
288 }
289 if (dumpItem.windowName.find(pkgSurface) != std::string::npos)
290 {
291 pkgZOrd = dumpItem.zOrd;
292 }
293 }
294 return focusWindowName + ":" + pkgZOrd;
295 }
296 }
297 }
298