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 <ctime>
24 #include <unistd.h>
25 #include <sys/time.h>
26 #include "include/profiler_fps.h"
27 #include "include/sp_log.h"
28 #include "include/sp_utils.h"
29
30
31 namespace OHOS {
32 namespace SmartPerf {
33
GetResultFPS(int sectionsNum)34 void ProfilerFPS::GetResultFPS(int sectionsNum)
35 {
36 struct timeval start;
37 struct timeval end;
38 gettimeofday(&start, nullptr);
39 FpsInfoProfiler fpsInfoResult;
40 unsigned long runTime;
41 fpsInfoResult = GetFpsInfo();
42 LOGI("result.fps====: %s", std::to_string(fpsInfoResult.fps).c_str());
43 if (fpsInfoResult.fps == 0) {
44 if (lastCurrTime == 0) {
45 long long msStartTime = ((currRealTime / msClear) * msClear) - msClear;
46 printf("fps:%d|%lld\n", fpsInfoResult.fps, msStartTime / oneSec);
47 } else {
48 printf("fps:%d|%lld\n", fpsInfoResult.fps, lastCurrTime + oneThousand);
49 lastCurrTime = lastCurrTime + oneThousand;
50 }
51 } else {
52 long long two = 2;
53 long long currTime = (fpsInfoResult.currTimeStamps[0] / msClear) * msClear + currTimeDiff;
54 if ((lastCurrTime + two) == (currTime / oneSec)) {
55 fpsInfoResult.fps = 0;
56 printf("fps:%d|%lld\n", fpsInfoResult.fps, lastCurrTime + oneThousand);
57 lastCurrTime = lastCurrTime + oneThousand;
58 } else {
59 if (lastCurrTime < (currTime / oneSec)) {
60 printf("fps:%d|%lld\n", fpsInfoResult.fps, currTime / oneSec);
61 lastCurrTime = currTime / oneSec;
62 } else {
63 printf("fps:%d|%lld\n", fpsInfoResult.fps, lastCurrTime + oneThousand);
64 lastCurrTime = lastCurrTime + oneThousand;
65 }
66 }
67 }
68 time_t now = time(0);
69 if (now == -1) {
70 LOGI("Failed to get current time.");
71 return;
72 }
73 char* dt = ctime(&now);
74 LOGI("printf time is: %s", dt);
75 if (sectionsNum == ten && fpsInfoResult.fps != 0) {
76 GetSectionsFps(fpsInfoResult);
77 }
78 fflush(stdout);
79 gettimeofday(&end, nullptr);
80 runTime = end.tv_sec * 1e6 - start.tv_sec * 1e6 + end.tv_usec - start.tv_usec;
81 if (runTime < oneSec) {
82 usleep(oneSec - runTime);
83 }
84 }
85
GetFPS(int argc,std::vector<std::string> v)86 void ProfilerFPS::GetFPS(int argc, std::vector<std::string> v)
87 {
88 int sectionsNum = 0;
89 if (v[number] == "") {
90 printf("the args of num must be not-null!\n");
91 } else {
92 num = atoi(v[number].c_str());
93 if (num < 0) {
94 printf("set num:%d not valid arg\n", num);
95 }
96 printf("set num:%d success\n", num);
97 sectionsNum = atoi(v[four].c_str());
98 for (int i = 0; i < num; i++) {
99 GetResultFPS(sectionsNum);
100 }
101 }
102 printf("SP_daemon exec finished!\n");
103 }
104
GetSectionsPrint(int printCount,long long msStartTime)105 void ProfilerFPS::GetSectionsPrint(int printCount, long long msStartTime)
106 {
107 long long msJiange = 100;
108 if (printCount < ten) {
109 for (int i = 0; i < ten - printCount; i++) {
110 msStartTime += msJiange;
111 printf("sectionsFps:%d|%lld\n", 0, msStartTime);
112 }
113 }
114 }
115
GetSectionsFps(FpsInfoProfiler & fpsInfo)116 void ProfilerFPS::GetSectionsFps(FpsInfoProfiler &fpsInfo)
117 {
118 int msCount = 0;
119 long long msJiange = 100000000;
120 long long msStartTime = (fpsInfo.currTimeStamps[0] / msClear) * msClear + msJiange;
121 long long currTime = 0;
122 long long currLastTime = lastCurrTime;
123 long long harTime = 100;
124 int printCount = 0;
125 for (int i = 0; i < fpsInfo.currTimeStamps.size(); i++) {
126 currTime = fpsInfo.currTimeStamps[i];
127 if (currTime <= msStartTime) {
128 msCount++;
129 } else if (currTime > msStartTime && currTime <= (msStartTime + msJiange)) {
130 printf("sectionsFps:%d|%lld\n", msCount * ten, currLastTime);
131 msCount = 1;
132 msStartTime += msJiange;
133 currLastTime += harTime;
134 printCount++;
135 } else {
136 printf("sectionsFps:%d|%lld\n", msCount * ten, currLastTime);
137 printCount++;
138 msCount = 0;
139 msStartTime += msJiange;
140 currLastTime += harTime;
141 i--;
142 }
143 if (i == (fpsInfo.currTimeStamps.size() - 1)) {
144 printf("sectionsFps:%d|%lld\n", msCount * ten, currLastTime);
145 printCount++;
146 GetSectionsPrint(printCount, currLastTime);
147 }
148 }
149 }
150
GetTimeDiff()151 void ProfilerFPS::GetTimeDiff()
152 {
153 long long clockRealTime = 0;
154 long long clockMonotonicRaw = 0;
155 int two = 2;
156 std::string strRealTime;
157 std::string cmd = "timestamps";
158 FILE *fd = popen(cmd.c_str(), "r");
159 if (fd == nullptr) {
160 return;
161 }
162 char buf[1024] = {'\0'};
163 while ((fgets(buf, sizeof(buf), fd)) != nullptr) {
164 std::string line = buf;
165 std::vector<std::string> params;
166 SPUtils::StrSplit(line, " ", params);
167 if (params[0].find("CLOCK_REALTIME") != std::string::npos && clockRealTime == 0) {
168 strRealTime = params[two];
169 strRealTime.erase(strRealTime.find('.'), 1);
170 clockRealTime = std::stoll(strRealTime);
171 currRealTime = clockRealTime;
172 } else if (params[0].find("CLOCK_MONOTONIC_RAW") != std::string::npos && clockMonotonicRaw == 0) {
173 strRealTime = params[two];
174 strRealTime.erase(strRealTime.find('.'), 1);
175 clockMonotonicRaw = std::stoll(strRealTime);
176 }
177 }
178 pclose(fd);
179 currTimeDiff = clockRealTime - clockMonotonicRaw;
180 }
181
GetSurface()182 std::string ProfilerFPS::GetSurface()
183 {
184 std::string cmdResult;
185 std::string cmdString1 = "hidumper -s 10 -a sur";
186 std::string cmdString2 = "face | grep sur";
187 std::string cmdString3 = "face";
188 SPUtils::LoadCmd(cmdString1 + cmdString2 + cmdString3, cmdResult);
189 size_t position1 = cmdResult.find("[");
190 size_t position2 = cmdResult.find("]");
191 LOGI("cmdResult==: %s", (cmdResult.substr(position1 + 1, position2 - position1 - 1)).c_str());
192 return cmdResult.substr(position1 + 1, position2 - position1 - 1);
193 }
194
CutLayerName(std::string layerName)195 std::string ProfilerFPS::CutLayerName(std::string layerName)
196 {
197 std::string subLayerName;
198 size_t twenty = 20;
199 if (layerName.size() > twenty) {
200 subLayerName = layerName.substr(0, twenty);
201 } else {
202 subLayerName = layerName;
203 }
204 return subLayerName;
205 }
206
GetFpsInfoMax()207 FpsInfoProfiler ProfilerFPS::GetFpsInfoMax()
208 {
209 int fpsValue = 0;
210 if (fpsInfo.fps > uniteFpsInfo.fps) {
211 fpsInfoMax = fpsInfo;
212 } else {
213 fpsInfoMax = uniteFpsInfo;
214 }
215 if (fpsInfoMax.fps < fpsValue) {
216 fpsInfoMax.fps = fpsValue;
217 }
218 if (fpsInfoMax == prevFlagFpsInfo) {
219 LOGI("fpsInfoMax == prevFlagFpsInfo");
220 if (cntFpsInfo == lastFlagFpsInfo) {
221 LOGI("cntFpsInfo == lastFlagFpsInfo");
222 fpsInfoMax.fps = 0;
223 fpsInfoMax.Clear();
224 return fpsInfoMax;
225 } else {
226 LOGI("cntFpsInfo != lastFlagFpsInfo");
227 if ((cntFpsInfo.currTimeStamps.size() > 0 && lastFlagFpsInfo.currTimeStamps.size() > 0) &&
228 cntFpsInfo.currTimeStamps[0] == lastFlagFpsInfo.currTimeStamps[0]) {
229 cntFpsInfo.fps = 0;
230 cntFpsInfo.Clear();
231 } else {
232 lastFlagFpsInfo = cntFpsInfo;
233 }
234 return cntFpsInfo;
235 }
236 } else {
237 LOGI("fpsInfoMax != prevFlagFpsInfo");
238 if ((fpsInfoMax.currTimeStamps.size() > 0 && lastFlagFpsInfo.currTimeStamps.size() > 0) &&
239 fpsInfoMax.currTimeStamps[0] == lastFlagFpsInfo.currTimeStamps[0]) {
240 LOGI("fpsInfoMax == lastFlagFpsInfo");
241 lastFlagFpsInfo = cntFpsInfo;
242 prevFlagFpsInfo = fpsInfoMax;
243 return cntFpsInfo;
244 } else if ((fpsInfoMax.currTimeStamps.size() > 0 && prevFlagFpsInfo.currTimeStamps.size() > 0) &&
245 fpsInfoMax.currTimeStamps[0] == prevFlagFpsInfo.currTimeStamps[0]) {
246 prevFlagFpsInfo = fpsInfoMax;
247 fpsInfoMax.fps = 0;
248 fpsInfoMax.Clear();
249 return fpsInfoMax;
250 } else {
251 LOGI("fpsInfoMax != lastFlagFpsInfo");
252 prevFlagFpsInfo = fpsInfoMax;
253 return fpsInfoMax;
254 }
255 }
256 }
GetFpsInfo()257 FpsInfoProfiler ProfilerFPS::GetFpsInfo()
258 {
259 fpsInfoMax.fps = 0;
260 std::string tempLayerName;
261 std::string uniteLayer = "DisplayNode";
262 uniteLayer = GetSurface();
263 tempLayerName = GetLayer();
264 GetTimeDiff();
265 uniteFpsInfo = GetSurfaceFrame(uniteLayer);
266 fpsInfo = GetSurfaceFrame(tempLayerName);
267 return GetFpsInfoMax();
268 }
269
GetFpsInfoResult(FpsInfoProfiler & fpsInfo,long long & lastLineTime)270 FpsInfoProfiler ProfilerFPS::GetFpsInfoResult(FpsInfoProfiler &fpsInfo, long long &lastLineTime)
271 {
272 const int maxZeroNum = 266;
273 if (zeroNum >= maxZeroNum) {
274 LOGI("zeroNum====: %s", std::to_string(zeroNum).c_str());
275 while (!(fpsInfo.timeStampQ.empty())) {
276 fpsInfo.timeStampQ.pop();
277 }
278 fpsInfo.fps = 0;
279 fpsInfo.jitters.clear();
280 LOGI("fpsInfo.fps0: %s", std::to_string(fpsInfo.fps).c_str());
281 return fpsInfo;
282 }
283 const int minPrintLine = 5;
284 if (cnt < minPrintLine) {
285 fpsInfo.fps = fpsInfo.preFps;
286 LOGI("fpsInfo.fps1: %s", std::to_string(fpsInfo.fps).c_str());
287 return fpsInfo;
288 }
289 if (!fpsInfo.timeStampQ.empty() && fpsInfo.timeStampQ.back() == lastLineTime) {
290 fpsInfo.fps = fpsGb;
291 if (fpsGb == 0) {
292 fpsInfo.jitters.clear();
293 }
294 LOGI("fpsInfo.fps2: %s", std::to_string(fpsInfo.fps).c_str());
295 LOGI("lastLineTime: %s", std::to_string(lastLineTime).c_str());
296 return fpsInfo;
297 }
298 if (fpsGb > 0) {
299 fpsInfo.fps = fpsGb;
300 fpsInfo.preFps = fpsGb;
301 LOGI("fpsInfo.fps3: %s", std::to_string(fpsInfo.fps).c_str());
302 LOGI("fpsInfo.preFps3: %s", std::to_string(fpsInfo.preFps).c_str());
303 return fpsInfo;
304 } else if (refresh && !jump) {
305 fpsInfo.fps = fpsInfo.preFps;
306 LOGI("fpsInfo.fps4: %s", std::to_string(fpsInfo.fps).c_str());
307 return fpsInfo;
308 } else {
309 fpsInfo.fps = 0;
310 fpsInfo.jitters.clear();
311 LOGI("fpsInfo.fps5: %s", std::to_string(fpsInfo.fps).c_str());
312 return fpsInfo;
313 }
314 }
315
GetLastFpsInfo(FpsInfoProfiler & fpsInfo)316 void ProfilerFPS::GetLastFpsInfo(FpsInfoProfiler &fpsInfo)
317 {
318 int total = 266;
319 if (cnt == total) {
320 LOGI("cnt == total && fpsGb != 0");
321 lastReadyTime = frameReadyTime;
322 int fpsTmp = 0;
323 cntFpsInfo.jitters.clear();
324 cntFpsInfo.currTimeStamps.clear();
325 while (!(fpsInfo.timeStampQ).empty()) {
326 fpsTmp++;
327 long long currFrame = (fpsInfo.timeStampQ.front());
328 cntFpsInfo.currTimeStamps.push_back(currFrame);
329 if (lastFrame != -1) {
330 long long jitter = currFrame - lastFrame;
331 cntFpsInfo.jitters.push_back(jitter);
332 } else {
333 long long jitter = currFrame - currFrame / mod * mod;
334 cntFpsInfo.jitters.push_back(jitter);
335 }
336 lastFrame = currFrame;
337 (fpsInfo.timeStampQ).pop();
338 }
339 cntFpsInfo.fps = fpsTmp;
340 LOGI("cntFpsInfo.fps====: %s", std::to_string(cntFpsInfo.fps).c_str());
341 }
342 }
343
GetPrevFpsInfo(FpsInfoProfiler & fpsInfo)344 void ProfilerFPS::GetPrevFpsInfo(FpsInfoProfiler &fpsInfo)
345 {
346 refresh = true;
347 long long tFrameReadyTime = frameReadyTime / mod;
348 long long tLastReadyTime = lastReadyTime / mod;
349 lastFrame = -1;
350 if (tFrameReadyTime == tLastReadyTime) {
351 (fpsInfo.timeStampQ).push(frameReadyTime);
352 } else if (tFrameReadyTime >= tLastReadyTime + 1) {
353 jump = true;
354 lastReadyTime = frameReadyTime;
355 int fpsTmp = 0;
356 fpsInfo.jitters.clear();
357 fpsInfo.currTimeStamps.clear();
358 while (!(fpsInfo.timeStampQ).empty()) {
359 fpsTmp++;
360 long long currFrame = (fpsInfo.timeStampQ.front());
361 fpsInfo.currTimeStamps.push_back(currFrame);
362 if (lastFrame != -1) {
363 long long jitter = currFrame - lastFrame;
364 fpsInfo.jitters.push_back(jitter);
365 } else {
366 long long jitter = currFrame - currFrame / mod * mod;
367 fpsInfo.jitters.push_back(jitter);
368 }
369 lastFrame = currFrame;
370 (fpsInfo.timeStampQ).pop();
371 }
372 fpsGb = fpsTmp;
373 LOGI("fpsGb====: %s", std::to_string(fpsGb).c_str());
374 (fpsInfo.timeStampQ).push(frameReadyTime);
375 fpsInfo.lastFrameReadyTime = lastFrame;
376 }
377 }
378
InitParams(FpsInfoProfiler & fpsInfo,long long & lastLineTime)379 void ProfilerFPS::InitParams(FpsInfoProfiler &fpsInfo, long long &lastLineTime)
380 {
381 lastReadyTime = -1;
382 fpsGb = 0;
383 if (!(fpsInfo.timeStampQ).empty()) {
384 lastReadyTime = (fpsInfo.timeStampQ).back();
385 lastLineTime = (fpsInfo.timeStampQ).back();
386 }
387 jump = false;
388 refresh = false;
389 cnt = 0;
390 zeroNum = 0;
391 }
392
GetSurfaceFrame(std::string name)393 FpsInfoProfiler ProfilerFPS::GetSurfaceFrame(std::string name)
394 {
395 if (name == "") {
396 return FpsInfoProfiler();
397 }
398 static std::map<std::string, FpsInfoProfiler> fpsMap;
399 if (fpsMap.count(name) == 0) {
400 FpsInfoProfiler tmp;
401 tmp.fps = 0;
402 tmp.preFps = 0;
403 fpsMap[name] = tmp;
404 }
405 fpsInfo = fpsMap[name];
406 fpsInfo.fps = 0;
407 FILE *fp;
408 static char tmp[1024];
409 std::string cmd = "hidumper -s 10 -a \"fps " + name + "\"";
410 LOGI("cmd=====: %s", cmd.c_str());
411 fp = popen(cmd.c_str(), "r");
412 if (fp == nullptr) {
413 return fpsInfo;
414 }
415 static long long lastLineTime;
416 InitParams(fpsInfo, lastLineTime);
417 LOGI("dump time: start!");
418 while (fgets(tmp, sizeof(tmp), fp) != nullptr) {
419 std::string str(tmp);
420 LOGD("dump time: %s", str.c_str());
421 frameReadyTime = 0;
422 std::stringstream sstream;
423 sstream << tmp;
424 sstream >> frameReadyTime;
425 cnt++;
426 if (frameReadyTime == 0) {
427 zeroNum++;
428 continue;
429 }
430 if (lastReadyTime >= frameReadyTime) {
431 lastReadyTime = -1;
432 continue;
433 }
434 GetPrevFpsInfo(fpsInfo);
435 GetLastFpsInfo(fpsInfo);
436 }
437 pclose(fp);
438 return GetFpsInfoResult(fpsInfo, lastLineTime);
439 }
440
GetLayer()441 std::string ProfilerFPS::GetLayer()
442 {
443 std::vector<DumpEntityProfiler> dumpEntityList;
444 std::string curFocusId = "-1";
445 const std::string cmd = "hidumper -s WindowManagerService -a -a";
446 std::string focusWindowName = "NA";
447 FILE *fd = popen(cmd.c_str(), "r");
448 if (fd == nullptr) {
449 return focusWindowName;
450 }
451 int lineNum = 0;
452 char buf[1024] = {'\0'};
453 while ((fgets(buf, sizeof(buf), fd)) != nullptr) {
454 std::string line = buf;
455 if (line[0] == '-' || line[0] == ' ') {
456 continue;
457 }
458 std::vector<std::string> params;
459 SPUtils::StrSplit(line, " ", params);
460 if (params[windowNameIndex].find("WindowName") != std::string::npos &&
461 params[windowIdIndex].find("WinId") != std::string::npos) {
462 continue;
463 }
464 if (params.size() > paramFourteen) {
465 DumpEntityProfiler dumpEntity { params[0], params[1], params[2], params[3], params[7]};
466 dumpEntityList.push_back(dumpEntity);
467 }
468 if (params.size() == paramFourteen || params.size() == paramTwentyFour) {
469 DumpEntityProfiler dumpEntity { params[0], params[2], params[2], params[3], params[6]};
470 dumpEntityList.push_back(dumpEntity);
471 }
472 if (params.size() == paramThree) {
473 curFocusId = params[focusNameIndex];
474 break;
475 }
476 lineNum++;
477 }
478 pclose(fd);
479 int curId = std::stoi(curFocusId);
480 for (size_t i = 0; i < dumpEntityList.size(); i++) {
481 DumpEntityProfiler dumpItem = dumpEntityList[i];
482 int curWinId = std::stoi(dumpItem.windId);
483 if (curId == curWinId) {
484 focusWindowName = dumpItem.windowName;
485 }
486 }
487 return focusWindowName;
488 }
489 }
490 }