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 <vector>
21 #include <map>
22 #include <string>
23 #include <unistd.h>
24 #include <sys/time.h>
25
26 namespace {
27 struct DumpEntity {
28 const std::string windowName;
29 const std::string displayId;
30 const std::string pid;
31 const std::string windId;
32 };
33 struct FpsInfo {
34 int fps;
35 int preFps;
36 std::vector<long long> jitters;
37 std::queue<long long> timeStampQ;
38 long long lastFrameReadyTime;
39 long long currentFpsTime;
FpsInfo__anonfcf673520111::FpsInfo40 FpsInfo()
41 {
42 fps = 0;
43 preFps = 0;
44 lastFrameReadyTime = 0;
45 currentFpsTime = 0;
46 }
47 };
48 struct FpsConfig {
49 const long long mod = 1e9;
50 long long lastReadyTime;
51 int fpsGb;
52 bool jump;
53 bool refresh;
54 int cnt;
55 int zeroNum;
FpsConfig__anonfcf673520111::FpsConfig56 FpsConfig()
57 {
58 lastReadyTime = -1;
59 fpsGb = 0;
60 jump = false;
61 refresh = false;
62 cnt = 0;
63 zeroNum = 0;
64 }
65 };
66 }
67
StrSplit(const std::string & content,const std::string & sp,std::vector<std::string> & out)68 static void StrSplit(const std::string &content, const std::string &sp, std::vector<std::string> &out)
69 {
70 size_t index = 0;
71 while (index != std::string::npos) {
72 size_t tEnd = content.find_first_of(sp, index);
73 std::string tmp = content.substr(index, tEnd - index);
74 if (tmp != "" && tmp != " ") {
75 out.push_back(tmp);
76 }
77 if (tEnd == std::string::npos) {
78 break;
79 }
80 index = tEnd + 1;
81 }
82 }
83
GetLayer()84 static std::string GetLayer()
85 {
86 std::vector<DumpEntity> dumpEntityList;
87 std::string curFocusId = "-1";
88 const std::string cmd = "hidumper -s WindowManagerService -a -a";
89 std::string cmdExc = cmd;
90 FILE *fd = popen(cmdExc.c_str(), "r");
91 if (fd != nullptr) {
92 int lineNum = 0;
93 std::string line;
94 char buf[1024] = {'\0'};
95
96 const int paramFifteen = 15;
97 const int paramThree = 3;
98 const int windowNameIndex = 0;
99 const int windowIdIndex = 3;
100 const int focusNameIndex = 2;
101
102 while ((fgets(buf, sizeof(buf), fd)) != nullptr) {
103 line = buf;
104 if (line[0] == '-' || line[0] == ' ') {
105 continue;
106 }
107 std::vector<std::string> params;
108 StrSplit(line, " ", params);
109 if (params[windowNameIndex].find("WindowName")!= std::string::npos &&
110 params[windowIdIndex].find("WinId")!= std::string::npos) {
111 continue;
112 }
113 if (params.size() == paramFifteen) {
114 DumpEntity dumpEntity { params[0], params[1], params[2], params[3] };
115 dumpEntityList.push_back(dumpEntity);
116 }
117 if (params.size() == paramThree) {
118 curFocusId = params[focusNameIndex];
119 break;
120 }
121 lineNum++;
122 }
123 pclose(fd);
124 }
125
126 std::string resultWindowName = "NA";
127 int curId = std::stoi(curFocusId);
128 for (size_t i = 0; i < dumpEntityList.size(); i++) {
129 DumpEntity dumpItem = dumpEntityList[i];
130 int curWinId = std::stoi(dumpItem.windId);
131 if (curId == curWinId) {
132 resultWindowName = dumpItem.windowName;
133 }
134 }
135 return resultWindowName;
136 }
137
ProcessResult(FILE * fp,FpsConfig & fpsConfig,FpsInfo & fpsInfo)138 static void ProcessResult(FILE *fp, FpsConfig &fpsConfig, FpsInfo &fpsInfo)
139 {
140 char tmp[1024];
141 while (fgets(tmp, sizeof(tmp), fp) != nullptr) {
142 long long frameReadyTime = 0;
143 std::stringstream sstream;
144 sstream << tmp;
145 sstream >> frameReadyTime;
146 fpsConfig.cnt++;
147 if (frameReadyTime == 0) {
148 fpsConfig.zeroNum++;
149 continue;
150 }
151
152 if (fpsConfig.lastReadyTime >= frameReadyTime) {
153 fpsConfig.lastReadyTime = -1;
154 continue;
155 }
156 fpsConfig.refresh = true;
157 long long tFrameReadyTime = frameReadyTime / fpsConfig.mod;
158 long long tLastReadyTime = fpsConfig.lastReadyTime / fpsConfig.mod;
159 long long lastFrame = -1;
160 if (tFrameReadyTime == tLastReadyTime) {
161 (fpsInfo.timeStampQ).push(frameReadyTime);
162 } else if (tFrameReadyTime == tLastReadyTime + 1) {
163 fpsConfig.jump = true;
164 lastFrame = fpsInfo.lastFrameReadyTime;
165 fpsConfig.lastReadyTime = frameReadyTime;
166 int fpsTmp = 0;
167 fpsInfo.jitters.clear();
168 while (!(fpsInfo.timeStampQ).empty()) {
169 fpsTmp++;
170 long long currFrame = (fpsInfo.timeStampQ.front());
171 if (lastFrame != -1) {
172 long long jitter = currFrame - lastFrame;
173 fpsInfo.jitters.push_back(jitter);
174 }
175 lastFrame = currFrame;
176 (fpsInfo.timeStampQ).pop();
177 }
178 fpsConfig.fpsGb = fpsTmp;
179 (fpsInfo.timeStampQ).push(frameReadyTime);
180 fpsInfo.lastFrameReadyTime = lastFrame;
181 } else if (tFrameReadyTime > tLastReadyTime + 1) {
182 fpsConfig.jump = true;
183 fpsConfig.lastReadyTime = frameReadyTime;
184 while (!(fpsInfo.timeStampQ).empty()) {
185 (fpsInfo.timeStampQ).pop();
186 }
187 (fpsInfo.timeStampQ).push(frameReadyTime);
188 }
189 }
190 }
191
GetSurfaceFrame(std::string name,FpsConfig & fpsConfig)192 static FpsInfo GetSurfaceFrame(std::string name, FpsConfig &fpsConfig)
193 {
194 static std::map<std::string, FpsInfo> fpsMap;
195 if (fpsMap.count(name) == 0) {
196 FpsInfo tmp;
197 tmp.fps = 0;
198 tmp.preFps = 0;
199 fpsMap[name] = tmp;
200 }
201 FpsInfo &fpsInfo = fpsMap[name];
202 fpsInfo.fps = 0;
203
204 struct timeval tv;
205 gettimeofday(&tv, nullptr);
206 fpsInfo.currentFpsTime = tv.tv_sec * 1e3 + tv.tv_usec / 1e3;
207
208 std::string cmd = "hidumper -s 10 -a \"fps " + name + "\"";
209 std::string cmdExc = cmd;
210 FILE *fp = popen(cmdExc.c_str(), "r");
211 if (fp == nullptr) {
212 return fpsInfo;
213 }
214 static long long lastLineTime;
215 if (!(fpsInfo.timeStampQ).empty()) {
216 fpsConfig.lastReadyTime = (fpsInfo.timeStampQ).back();
217 lastLineTime = (fpsInfo.timeStampQ).back();
218 }
219 ProcessResult(fp, fpsConfig, fpsInfo);
220 pclose(fp);
221 const int maxZeroNum = 120;
222 const int minPrintLine = 5;
223 if (fpsConfig.zeroNum >= maxZeroNum) {
224 while (!(fpsInfo.timeStampQ.empty())) {
225 fpsInfo.timeStampQ.pop();
226 }
227 fpsInfo.fps = 0;
228 return fpsInfo;
229 }
230
231 if (fpsConfig.cnt < minPrintLine) {
232 fpsInfo.fps = fpsInfo.preFps;
233 return fpsInfo;
234 }
235
236 if (!fpsInfo.timeStampQ.empty() && fpsInfo.timeStampQ.back() == lastLineTime) {
237 fpsInfo.fps = 0;
238 return fpsInfo;
239 }
240
241 if (fpsConfig.fpsGb > 0) {
242 fpsInfo.fps = fpsConfig.fpsGb;
243 fpsInfo.preFps = fpsConfig.fpsGb;
244 return fpsInfo;
245 } else if (fpsConfig.refresh && !fpsConfig.jump) {
246 fpsInfo.fps = fpsInfo.preFps;
247 return fpsInfo;
248 } else {
249 fpsInfo.fps = 0;
250 return fpsInfo;
251 }
252 }
253
ReplaceString(std::string & res)254 static void ReplaceString(std::string &res)
255 {
256 std::string flagOne = "\r";
257 std::string flagTwo = "\n";
258 std::string::size_type ret = res.find(flagOne);
259 while (ret != res.npos) {
260 res.replace(ret, 1, "");
261 ret = res.find(flagOne);
262 }
263 ret = res.find(flagTwo);
264 while (ret != res.npos) {
265 res.replace(ret, 1, "");
266 ret = res.find(flagTwo);
267 }
268 }
269
LoadCmd(const std::string & cmd,std::string & result)270 static bool LoadCmd(const std::string &cmd, std::string &result)
271 {
272 std::string cmdExc = cmd;
273 FILE *fd = popen(cmdExc.c_str(), "r");
274 if (fd == nullptr) {
275 return false;
276 }
277 char buf[1024] = {'\0'};
278 int ret = fread(buf, sizeof(buf), 1, fd);
279 if (ret >= 0) {
280 result = buf;
281 }
282 if (pclose(fd) == -1) {
283 std::cout << "" << std::endl;
284 }
285 ReplaceString(result);
286 return ret >= 0 ? true : false;
287 }
288
main(int argc,char * argv[])289 int main(int argc, char *argv[])
290 {
291 if (argc < 2) {
292 printf("exec failed, require one param | example: GP_daemon_fps 10");
293 return 0;
294 }
295 int num = 1;
296 if (!strcmp(argv[1], "")) {
297 printf("the args of num must be not-null!\n");
298 } else {
299 num = atoi(argv[1]);
300 if (num < 0) {
301 printf("set num:%d not valid arg\n", num);
302 }
303 printf("set num:%d success\n", num);
304 FpsInfo gfpsInfo;
305 FpsInfo gfpsUniteInfo;
306 std::string layerName;
307 std::string tempLayerName;
308 struct timeval start;
309 struct timeval end;
310 std::string uniteLayer = "DisplayNode";
311 unsigned long oneSec = 1000000;
312 std::string cmdResult;
313 for (int i = 0; i < num; i++) {
314 unsigned long runTime;
315 gettimeofday(&start, nullptr);
316 tempLayerName = GetLayer();
317 if (i == 0) {
318 layerName = tempLayerName;
319 LoadCmd("hidumper -s 10 -a \"fpsClear DisplayNode\"", cmdResult);
320 LoadCmd("hidumper -s 10 -a \"fpsClear" + layerName + "\"", cmdResult);
321 } else {
322 if (layerName.compare(tempLayerName) != 0) {
323 layerName = tempLayerName;
324 LoadCmd("hidumper -s 10 -a \"fpsClear" + layerName + "\"", cmdResult);
325 }
326 }
327 FpsConfig fpsConfig;
328 FpsConfig fpsUniteConfig;
329 gfpsInfo = GetSurfaceFrame(layerName, fpsConfig);
330 gfpsUniteInfo = GetSurfaceFrame(uniteLayer, fpsUniteConfig);
331 if (gfpsUniteInfo.fps > gfpsInfo.fps)
332 {
333 printf("fps:%d|%lld\n", gfpsUniteInfo.fps, gfpsUniteInfo.currentFpsTime);
334 } else {
335 printf("fps:%d|%lld\n", gfpsInfo.fps, gfpsInfo.currentFpsTime);
336 }
337 fflush(stdout);
338 gettimeofday(&end, nullptr);
339 runTime = end.tv_sec * 1e6 - start.tv_sec * 1e6 + end.tv_usec - start.tv_usec;
340 if (runTime < oneSec) {
341 usleep(oneSec - runTime);
342 }
343 }
344 }
345 printf("GP_daemon_fps exec finished!\n");
346 return 0;
347 }
348