• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 
16 #include "frame_report.h"
17 
18 #include <dlfcn.h>
19 #include <cstdio>
20 #include <securec.h>
21 #include <unistd.h>
22 #include <hilog/log.h>
23 
24 #include "parameter.h"
25 #include "parameters.h"
26 
27 namespace OHOS {
28 namespace Rosen {
29 
30 static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, 0xD001404, "FrameReport" };
31 #define LOGF(...) (void)OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, __VA_ARGS__)
32 #define LOGE(...) (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, __VA_ARGS__)
33 #define LOGW(...) (void)OHOS::HiviewDFX::HiLog::Warn(LOG_LABEL, __VA_ARGS__)
34 #define LOGI(...) (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, __VA_ARGS__)
35 #define LOGD(...) (void)OHOS::HiviewDFX::HiLog::Debug(LOG_LABEL, __VA_ARGS__)
36 
37 #if (defined(__aarch64__) || defined(__x86_64__))
38     const std::string FRAME_AWARE_SO_PATH = "/system/lib64/libframe_ui_intf.z.so";
39 #else
40     const std::string FRAME_AWARE_SO_PATH = "/system/lib/libframe_ui_intf.z.so";
41 #endif
42 
43 constexpr int SCHEDULE_MSG_BUFFER_SIZE = 48;
44 constexpr int REPORT_BUFFER_SIZE = 256;
45 
46 constexpr int THOUSAND_COUNT = 1000;
47 constexpr int MIN_GAME_FPS = 10;
48 constexpr int SEND_FPS_FRAME_NUM = 100;
49 constexpr int64_t VALID_TIME_INTERVAL = 800000000;
50 constexpr int MIN_FRAME_NUM = 40;
51 constexpr int64_t ONE_SECOND = 1000000000;
52 const std::vector<int> LEVEL_TO_TARGET_FPS({ 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 90, 120, 144 });
53 const int MAX_FRAME_LEVEL(LEVEL_TO_TARGET_FPS.size() - 1);
54 const std::vector<int> REAL_FPS_TO_LEVEL({ 0, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 90, 120 });
55 constexpr const char *SWITCH_TEXT = "debug.graphic.framereport";
56 
GetInstance()57 FrameReport& FrameReport::GetInstance()
58 {
59     static FrameReport instance;
60     return instance;
61 }
62 
FrameReport()63 FrameReport::FrameReport()
64 {
65     int ret = WatchParameter(SWITCH_TEXT, SwitchFunction, this);
66     if (ret) {
67         LOGW("WatchParameter failed");
68     }
69     ret = LoadLibrary();
70     if (!ret) {
71         LOGE("dlopen libframe_ui_intf.so failed");
72         return;
73     }
74 }
75 
~FrameReport()76 FrameReport::~FrameReport()
77 {
78     CloseLibrary();
79 }
80 
SwitchFunction(const char * key,const char * value,void * context)81 void FrameReport::SwitchFunction(const char *key, const char *value, void *context)
82 {
83     auto &that = *reinterpret_cast<FrameReport *>(context);
84     that.gameScene_ = std::atoi(value) != 0;
85     LOGI("SwitchFunction value %{public}s  that.gameScene_ %{public}d ",
86         value, that.gameScene_);
87 }
88 
IsReportBySurfaceName(std::string & name)89 bool FrameReport::IsReportBySurfaceName(std::string& name)
90 {
91     bool isSurface = name.find("Surface") != std::string::npos;
92     return isSurface;
93 }
94 
IsGameScene() const95 bool FrameReport::IsGameScene() const
96 {
97     return gameScene_;
98 }
99 
SetGameScene(bool gameScene)100 void FrameReport::SetGameScene(bool gameScene)
101 {
102     gameScene_ = gameScene;
103     LOGI("SetGameScene gameScene_ %{public}d ", gameScene_);
104 }
105 
CalculateGameFps(int64_t timestamp)106 void FrameReport::CalculateGameFps(int64_t timestamp)
107 {
108     DeleteInvalidTimes(timestamp);
109     gameTimeStamps_.PushElement(timestamp);
110     gameLastTimeStamp_ = timestamp;
111     GetTargetGameFps();
112 
113     if ((targetFps_ > 0 && targetFps_ != lastTargetFps_) || (frameNumCnt_ > SEND_FPS_FRAME_NUM)) {
114         SendGameTargetFps(targetFps_);
115         lastTargetFps_ = targetFps_;
116         frameNumCnt_ = 0;
117     }
118     frameNumCnt_++;
119 }
120 
DeleteInvalidTimes(int64_t timestamp)121 void FrameReport::DeleteInvalidTimes(int64_t timestamp)
122 {
123     int64_t headTimestamp = std::get<int64_t>(gameTimeStamps_.GetTailElement());
124     if ((timestamp - headTimestamp) > VALID_TIME_INTERVAL) {
125         gameTimeStamps_.ClearArray();
126     }
127     return;
128 }
129 
GetTargetGameFps()130 void FrameReport::GetTargetGameFps()
131 {
132     targetFps_ = 0;
133     FpsCalculator curFps;
134     curFps.frameNum = gameTimeStamps_.ArraySize();
135 
136     if (curFps.frameNum < MIN_FRAME_NUM) {
137         return;
138     }
139     curFps.duration =
140         std::get<int64_t>(gameTimeStamps_.GetTailElement()) - std::get<int64_t>(gameTimeStamps_.GetHeadElement());
141     curFps.realFps =
142         static_cast<float>(ONE_SECOND) * static_cast<float>(curFps.frameNum - 1) / static_cast<float>(curFps.duration);
143     curFps.fps = static_cast<int>(curFps.realFps) + 1;
144 
145     targetFps_ = FindStage(curFps.fps);
146 
147     LOGD("GetTargetGameFps targetFps_ %{public}d  curFps.fps %{public}d  curFps.realFps %{public}f", targetFps_,
148         curFps.fps, curFps.realFps);
149 }
150 
FindStage(const int fps) const151 int FrameReport::FindStage(const int fps) const
152 {
153     int validFps = (fps <= MIN_GAME_FPS) ? MIN_GAME_FPS : fps;
154     auto it = lower_bound(REAL_FPS_TO_LEVEL.begin(), REAL_FPS_TO_LEVEL.end(), validFps);
155     int level = it - REAL_FPS_TO_LEVEL.begin() - 1;
156     level = (level < 0) ? 0 : level;
157     level = (level > MAX_FRAME_LEVEL) ? MAX_FRAME_LEVEL : level;
158     return LEVEL_TO_TARGET_FPS[level];
159 }
160 
SetLastSwapBufferTime(int64_t lastSwapBufferTime)161 void FrameReport::SetLastSwapBufferTime(int64_t lastSwapBufferTime)
162 {
163     if (!IsReportBySurfaceName(name_)) {
164         return;
165     }
166     lastSwapBufferTime_ = lastSwapBufferTime;
167 
168     int64_t time = std::chrono::duration_cast<std::chrono::nanoseconds>(
169         std::chrono::steady_clock::now().time_since_epoch()).count();
170     CalculateGameFps(time);
171 }
172 
SetDequeueBufferTime(std::string & name,int64_t dequeueBufferTime)173 void FrameReport::SetDequeueBufferTime(std::string& name, int64_t dequeueBufferTime)
174 {
175     if (!IsReportBySurfaceName(name)) {
176         return;
177     }
178     name_ = name;
179     dequeueBufferTime_ = dequeueBufferTime;
180 }
181 
SetQueueBufferTime(std::string & name,int64_t queueBufferTime)182 void FrameReport::SetQueueBufferTime(std::string& name, int64_t queueBufferTime)
183 {
184     if (!IsReportBySurfaceName(name)) {
185         return;
186     }
187     queueBufferTime_ = queueBufferTime;
188 }
189 
SetPendingBufferNum(std::string & name,int32_t pendingBufferNum)190 void FrameReport::SetPendingBufferNum(std::string& name, int32_t pendingBufferNum)
191 {
192     if (!IsReportBySurfaceName(name)) {
193         return;
194     }
195     pendingBufferNum_ = pendingBufferNum;
196 }
197 
LoadLibrary()198 bool FrameReport::LoadLibrary()
199 {
200     if (!schedSoLoaded_) {
201         schedHandle_ = dlopen(FRAME_AWARE_SO_PATH.c_str(), RTLD_LAZY);
202         if (schedHandle_ == nullptr) {
203             LOGE("dlopen libframe_ui_intf.so failed! error = %{public}s", dlerror());
204             return false;
205         }
206         schedSoLoaded_ = true;
207     }
208     LOGI("load library success!");
209     return true;
210 }
211 
CloseLibrary()212 void FrameReport::CloseLibrary()
213 {
214     if (schedHandle_ != nullptr) {
215         if (dlclose(schedHandle_) != 0) {
216             LOGE("libframe_ui_intf.so close failed!\n");
217             return;
218         }
219     }
220     schedHandle_ = nullptr;
221     schedSoLoaded_ = false;
222     LOGI("libframe_ui_intf.so close success!\n");
223 }
224 
LoadSymbol(const char * symName)225 void* FrameReport::LoadSymbol(const char* symName)
226 {
227     if (!schedSoLoaded_) {
228         LOGE("libframe_ui_intf.so not loaded.\n");
229         return nullptr;
230     }
231 
232     void *funcSym = dlsym(schedHandle_, symName);
233     if (funcSym == nullptr) {
234         LOGE("Get %{public}s symbol failed: %{public}s\n", symName, dlerror());
235         return nullptr;
236     }
237     return funcSym;
238 }
239 
CurTime(int type,const std::string & message,int length)240 int FrameReport::CurTime(int type, const std::string& message, int length)
241 {
242     int ret = -1;
243     if (curTimeFunc_ == nullptr) {
244         curTimeFunc_ = LoadSymbol("CurTime");
245     }
246     if (curTimeFunc_ != nullptr) {
247         auto curTimeFunc = reinterpret_cast<int (*)(int, const std::string&, int)>(curTimeFunc_);
248         ret = curTimeFunc(type, message, length);
249     } else {
250         LOGE("load CurTime function failed!");
251     }
252     return ret;
253 }
254 
SchedMsg(int type,const std::string & message,int length)255 int FrameReport::SchedMsg(int type, const std::string& message, int length)
256 {
257     int ret = -1;
258     if (schedMsgFunc_ == nullptr) {
259         schedMsgFunc_ = LoadSymbol("SchedMsg");
260     }
261     if (schedMsgFunc_ != nullptr) {
262         auto schedMsgFunc = reinterpret_cast<int (*)(int, const std::string&, int)>(schedMsgFunc_);
263         ret = schedMsgFunc(type, message, length);
264     } else {
265         LOGE("load SchedMsg function failed!");
266     }
267     return ret;
268 }
269 
Report(std::string & name)270 void FrameReport::Report(std::string& name)
271 {
272     if (!IsReportBySurfaceName(name)) {
273         return;
274     }
275 
276     char msg[REPORT_BUFFER_SIZE] = { 0 };
277 
278     int ret = sprintf_s(msg, sizeof(msg),
279         "{\"swapBufferTime\":\"%d\",\"pendingBufferNum\":\"%d\",\"dequeueBufferTime\":\"%d\","
280         "\"queueBufferTime\":\"%d\", \"skipHint\":\"%d\"}",
281         static_cast<int>(lastSwapBufferTime_ / THOUSAND_COUNT), pendingBufferNum_,
282         static_cast<int>(dequeueBufferTime_ / THOUSAND_COUNT), static_cast<int>(queueBufferTime_ / THOUSAND_COUNT),
283         skipHintStatus_);
284     if (ret == -1) {
285         return;
286     }
287     std::string bfMsg(msg);
288     LOGD("Report bfMsg %{public}s ", bfMsg.c_str());
289 #ifdef AI_SCHED_ENABLE
290     ret = CurTime(1, bfMsg, bfMsg.size());
291     if (ret) {
292         LOGW("hwsched sf time failed");
293     } else {
294         LOGD("hwsched sf time succ");
295     }
296 #endif
297 }
298 
SendGameTargetFps(int32_t fps)299 void FrameReport::SendGameTargetFps(int32_t fps)
300 {
301     char msg[SCHEDULE_MSG_BUFFER_SIZE] = { 0 };
302     int ret = sprintf_s(msg, sizeof(msg), "{\"agpFPS\":\"%d\"}", fps);
303     if (ret == -1) {
304         return;
305     }
306 
307     std::string bfMsg(msg);
308     LOGD("SendGameTargetFps bfMsg %{public}s ", bfMsg.c_str());
309 #ifdef AI_SCHED_ENABLE
310     ret = SchedMsg(1, bfMsg, bfMsg.size());
311     if (ret) {
312         LOGW("hwsched game fps failed");
313     } else {
314         LOGD("hwsched game fps succ");
315     }
316 #endif
317 }
318 
319 } // namespace Rosen
320 } // namespace OHOS