1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
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 <thread>
25 #include <unistd.h>
26 #include <sys/time.h>
27 #include "include/profiler_fps.h"
28 #include "include/sp_log.h"
29 #include "include/sp_utils.h"
30 #include "include/ByTrace.h"
31
32
33 namespace OHOS {
34 namespace SmartPerf {
ItemData()35 std::map<std::string, std::string> ProfilerFPS::ItemData()
36 {
37 std::map<std::string, std::string> result;
38 FpsInfoProfiler finalResult = GetFpsInfo();
39 lastFpsInfoResult = finalResult;
40 result["fps"] = std::to_string(finalResult.fps);
41 LOGI("ProfilerFPS.result.fps====: %s", std::to_string(finalResult.fps).c_str());
42 LOGI("ProfilerFPS.result.curTime====: %s", std::to_string(finalResult.curTime).c_str());
43 std::string jitterStr = "";
44 std::string split = "";
45 for (size_t i = 0; i < finalResult.jitters.size(); i++) {
46 if (i > 0) {
47 split = ";;";
48 }
49 jitterStr += split + std::to_string(finalResult.jitters[i]);
50 }
51 result["fpsJitters"] = jitterStr;
52 LOGI("ProfilerFPS.result.jitters====: %s", jitterStr.c_str());
53 if (isCatchTrace > 0) {
54 ByTrace::GetInstance().CheckFpsJitters(finalResult.jitters, finalResult.fps);
55 }
56 return result;
57 }
58
SetTraceCatch()59 void ProfilerFPS::SetTraceCatch()
60 {
61 isCatchTrace = 1;
62 }
63
SetPackageName(std::string pName)64 void ProfilerFPS::SetPackageName(std::string pName)
65 {
66 pkgName = std::move(pName);
67 }
68
GetResultFPS(int sectionsNum)69 void ProfilerFPS::GetResultFPS(int sectionsNum)
70 {
71 struct timeval start;
72 struct timeval end;
73 gettimeofday(&start, nullptr);
74 FpsInfoProfiler fpsInfoResult;
75 unsigned long runTime;
76 fpsInfoResult = GetFpsInfo();
77 if (fpsInfoResult.fps == 0) {
78 if (lastCurrTime == 0) {
79 long long currTime = (fpsInfoResult.currTimeDump / msClear) * msClear + fpsInfoResult.currTimeDiff;
80 lastCurrTime = currTime / oneSec;
81 printf("fps:%d|%lld\n", fpsInfoResult.fps, currTime / oneSec);
82 } else {
83 printf("fps:%d|%lld\n", fpsInfoResult.fps, lastCurrTime + oneThousand);
84 lastCurrTime = lastCurrTime + oneThousand;
85 }
86 } else {
87 long long currTime = (fpsInfoResult.currTimeStamps[0] / msClear) * msClear + fpsInfoResult.currTimeDiff;
88 lastCurrTime = currTime / oneSec;
89 printf("fps:%d|%lld\n", fpsInfoResult.fps, lastCurrTime);
90 }
91 lastFpsInfoResult = fpsInfoResult;
92 if (sectionsNum == ten && fpsInfoResult.fps != 0) {
93 GetSectionsFps(fpsInfoResult);
94 }
95 time_t now = time(nullptr);
96 if (now == -1) {
97 LOGI("Failed to get current time.");
98 return;
99 }
100 char *dt = ctime(&now);
101 LOGI("printf time is: %s", dt);
102 fflush(stdout);
103 gettimeofday(&end, nullptr);
104 runTime = end.tv_sec * 1e6 - start.tv_sec * 1e6 + end.tv_usec - start.tv_usec;
105 LOGI("printf time is---runTime: %s", std::to_string(runTime).c_str());
106 if (runTime < sleepTime) {
107 usleep(sleepTime - runTime);
108 }
109 GetCurrentTime(ten);
110 }
111
GetCurrentTime(int sleepNum)112 void ProfilerFPS::GetCurrentTime(int sleepNum)
113 {
114 for (int i = 0; i < sleepNum; i++) {
115 struct timespec time1 = { 0 };
116 clock_gettime(CLOCK_MONOTONIC, &time1);
117 int curTimeNow = static_cast<int>(time1.tv_sec - 1);
118 if (curTimeNow == lastFpsInfoResult.curTime) {
119 usleep(sleepNowTime);
120 } else {
121 break;
122 }
123 }
124 }
125
GetTimeDiff()126 void ProfilerFPS::GetTimeDiff()
127 {
128 long long clockRealTime = 0;
129 long long clockMonotonicRaw = 0;
130 int two = 2;
131 std::string strRealTime;
132 std::string cmd = "timestamps";
133 FILE *fd = popen(cmd.c_str(), "r");
134 if (fd == nullptr) {
135 return;
136 }
137 char buf[1024] = {'\0'};
138 while ((fgets(buf, sizeof(buf), fd)) != nullptr) {
139 std::string line = buf;
140 std::vector<std::string> params;
141 SPUtils::StrSplit(line, " ", params);
142 if (params[0].find("CLOCK_REALTIME") != std::string::npos && clockRealTime == 0) {
143 strRealTime = params[two];
144 strRealTime.erase(strRealTime.find('.'), 1);
145 clockRealTime = std::stoll(strRealTime);
146 currRealTime = clockRealTime;
147 } else if (params[0].find("CLOCK_MONOTONIC_RAW") != std::string::npos && clockMonotonicRaw == 0) {
148 strRealTime = params[two];
149 strRealTime.erase(strRealTime.find('.'), 1);
150 clockMonotonicRaw = std::stoll(strRealTime);
151 }
152 }
153 pclose(fd);
154 fpsInfo.currTimeDiff = clockRealTime - clockMonotonicRaw;
155 }
156
GetSectionsPrint(int printCount,long long msStartTime) const157 void ProfilerFPS::GetSectionsPrint(int printCount, long long msStartTime) const
158 {
159 if (printCount < ten) {
160 for (int i = 0; i < ten - printCount; i++) {
161 long long msJiange = 100;
162 msStartTime += msJiange;
163 printf("sectionsFps:%d|%lld\n", 0, msStartTime);
164 }
165 }
166 }
167
GetSectionsFps(FpsInfoProfiler & fpsInfoResult) const168 void ProfilerFPS::GetSectionsFps(FpsInfoProfiler &fpsInfoResult) const
169 {
170 int msCount = 0;
171 long long msJiange = 100000000;
172 long long msStartTime = (fpsInfoResult.currTimeStamps[0] / msClear) * msClear + msJiange;
173 long long currLastTime = lastCurrTime;
174 long long harTime = 100;
175 int printCount = 0;
176 uint32_t count = 0;
177 for (uint32_t i = 0; i < fpsInfoResult.currTimeStamps.size(); i++) {
178 long long currTime = fpsInfoResult.currTimeStamps[i];
179 if (currTime <= msStartTime) {
180 msCount++;
181 } else if (currTime > msStartTime && currTime <= (msStartTime + msJiange)) {
182 printf("sectionsFps:%d|%lld\n", msCount * ten, currLastTime);
183 msCount = 1;
184 msStartTime += msJiange;
185 currLastTime += harTime;
186 printCount++;
187 } else {
188 printf("sectionsFps:%d|%lld\n", msCount * ten, currLastTime);
189 printCount++;
190 msCount = 0;
191 msStartTime += msJiange;
192 currLastTime += harTime;
193 count--;
194 }
195 long long size = fpsInfoResult.currTimeStamps.size();
196 if (size <= 1) {
197 return;
198 }
199 if (i == (size - 1)) {
200 printf("sectionsFps:%d|%lld\n", msCount * ten, currLastTime);
201 printCount++;
202 GetSectionsPrint(printCount, currLastTime);
203 }
204 count++;
205 }
206 }
207
GetFPS(std::vector<std::string> v)208 void ProfilerFPS::GetFPS(std::vector<std::string> v)
209 {
210 if (v[number] == "") {
211 printf("the args of num must be not-null!\n");
212 } else {
213 this->num = atoi(v[number].c_str());
214 if (this->num < 0) {
215 printf("set num:%d not valid arg\n", this->num);
216 }
217 printf("set num:%d success\n", this->num);
218 int sectionsNum = atoi(v[four].c_str());
219 for (int i = 0; i < this->num; i++) {
220 GetResultFPS(sectionsNum);
221 }
222 }
223 printf("SP_daemon exec finished!\n");
224 }
225
226
GetFpsInfo()227 FpsInfoProfiler ProfilerFPS::GetFpsInfo()
228 {
229 fpsInfoMax.fps = 0;
230 std::string uniteLayer = "UniRender";
231 if (pkgName.empty()) {
232 GetCurrentTime(fifty);
233 fpsInfoMax = GetSurfaceFrame(uniteLayer);
234 } else {
235 bool onTop = IsForeGround();
236 if (onTop) {
237 LOGI("ProfilerFPS.onTop===========");
238 GetCurrentTime(fifty);
239 fpsInfoMax = GetSurfaceFrame(uniteLayer);
240 } else {
241 fpsInfoMax.Clear();
242 }
243 }
244 return fpsInfoMax;
245 }
246
GetSurfaceFrame(std::string name)247 FpsInfoProfiler ProfilerFPS::GetSurfaceFrame(std::string name)
248 {
249 if (name == "") {
250 return FpsInfoProfiler();
251 }
252 static std::map<std::string, FpsInfoProfiler> fpsMap;
253 if (fpsMap.count(name) == 0) {
254 FpsInfoProfiler tmp;
255 tmp.fps = 0;
256 fpsMap[name] = tmp;
257 }
258 fpsInfo = fpsMap[name];
259 fpsInfo.fps = 0;
260 FILE *fp;
261 static char tmp[1024];
262 GetTimeDiff();
263 std::string cmd = "hidumper -s 10 -a \"fps " + name + "\"";
264 fp = popen(cmd.c_str(), "r");
265 if (fp == nullptr) {
266 return fpsInfo;
267 }
268 fpsNum = 0;
269 refresh = true;
270 lastTime = -1;
271 LOGI("ProfilerFPS dump time: start!");
272 struct timespec time1 = { 0 };
273 clock_gettime(CLOCK_MONOTONIC, &time1);
274 fpsInfo.curTime = static_cast<int>(time1.tv_sec - 1);
275 fpsInfo.currTimeDump = (time1.tv_sec - 1) * mod + time1.tv_nsec;
276 LOGI("ProfilerFPS Time-------fpsInfo.curTime: %s", std::to_string(fpsInfo.curTime).c_str());
277 while (fgets(tmp, sizeof(tmp), fp) != nullptr) {
278 std::string str(tmp);
279 LOGD("ProfilerFPS dump time: %s", str.c_str());
280 frameReadyTime = 0;
281 std::stringstream sstream;
282 sstream << tmp;
283 sstream >> frameReadyTime;
284 if (frameReadyTime == 0) {
285 continue;
286 }
287 if (lastReadyTime >= frameReadyTime) {
288 lastReadyTime = -1;
289 continue;
290 }
291 GetSameTimeNums();
292 }
293 pclose(fp);
294 LOGI("ProfilerFPS Time-------fpsNum: %s", std::to_string(fpsNum).c_str());
295 return fpsInfo;
296 }
297
GetSameTimeNums()298 void ProfilerFPS::GetSameTimeNums()
299 {
300 std::string onScreenTime = std::to_string(frameReadyTime / mod);
301 std::string fpsCurTime = std::to_string(fpsInfo.curTime);
302 if (onScreenTime.find(fpsCurTime) != std::string::npos) {
303 fpsNum++;
304 fpsInfo.currTimeStamps.push_back(frameReadyTime);
305 }
306 fpsInfo.fps = fpsNum;
307 if (onScreenTime == fpsCurTime) {
308 long long jitter;
309 if (lastTime != -1) {
310 jitter = frameReadyTime - lastTime;
311 fpsInfo.jitters.push_back(jitter);
312 } else {
313 if (lastFrameReadyTime != 0) {
314 jitter = frameReadyTime - lastFrameReadyTime;
315 fpsInfo.jitters.push_back(jitter);
316 }
317 }
318 lastTime = frameReadyTime;
319 lastFrameReadyTime = frameReadyTime;
320 }
321 }
IsForeGround()322 bool ProfilerFPS::IsForeGround()
323 {
324 const std::string cmd = "hidumper -s WindowManagerService -a -a";
325 char buf[1024] = {'\0'};
326 std::string appLine = "app name [" + pkgName;
327 std::string bundleLine = "bundle name [" + pkgName;
328 isFoundAppName = false;
329 isFoundBundleName = false;
330 FILE *fd = popen(cmd.c_str(), "r");
331 if (fd == nullptr) {
332 return false;
333 }
334 while (fgets(buf, sizeof(buf), fd) != nullptr) {
335 std::string line = buf;
336 if (line.find(appLine) != std::string::npos) {
337 isFoundAppName = true;
338 }
339 if (line.find(bundleLine) != std::string::npos) {
340 isFoundBundleName = true;
341 }
342 if (isFoundAppName || isFoundBundleName) {
343 if (line.find("app state") != std::string::npos) {
344 bool tag = IsFindForeGround(line);
345 pclose(fd);
346 return tag;
347 }
348 }
349 }
350 pclose(fd);
351 return false;
352 }
353
IsFindForeGround(std::string line) const354 bool ProfilerFPS::IsFindForeGround(std::string line) const
355 {
356 std::string foreGroundTag = line.substr(line.find("#") + 1);
357 if (foreGroundTag.find("FOREGROUND") != std::string::npos) {
358 return true;
359 } else {
360 return false;
361 }
362 }
363 }
364 }