• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "gfx/performance/rs_perfmonitor_reporter.h"
16 #include "common/rs_background_thread.h"
17 #ifdef ROSEN_OHOS
18 #include "hisysevent.h"
19 #endif
20 #include "rs_trace.h"
21 
22 namespace OHOS {
23 namespace Rosen {
24 #ifdef ROSEN_OHOS
25 const int32_t COUNTER_SIZE = 4;
26 const int32_t REASON_SIZE = 7;
27 const char* CPU_ONDRAW = "CPU_ONDRAW";
28 const char* CPU_FLUSH = "CPU_FLUSH";
29 //for rendergroup subhealth
30 constexpr int32_t DRAWING_CACHE_UPDATE_TIME_THRESHOLD = 3;
31 constexpr int32_t INTERVAL_THRESHOLD = 1000000;
32 constexpr int32_t DRAWING_CACHE_DURATION_TIMEOUT_THRESHOLD = 1000;
33 constexpr int32_t REPORT_INTERVAL = 120000000;
34 constexpr int32_t DRAWING_CACHE_MAX_CONTINUOUS_UPDATE_TIME = 7;
35 constexpr int32_t STORED_TIMESTAMP_COUNT = DRAWING_CACHE_UPDATE_TIME_THRESHOLD - 1;
36 constexpr int32_t PRINT_SUBHEALTH_TRACE_INTERVAL = 5000;
37 #endif
38 
GetInstance()39 RSPerfMonitorReporter& RSPerfMonitorReporter::GetInstance()
40 {
41     static RSPerfMonitorReporter instance;
42     return instance;
43 }
44 
SetFocusAppInfo(const char * bundleName)45 void RSPerfMonitorReporter::SetFocusAppInfo(const char* bundleName)
46 {
47 #ifdef ROSEN_OHOS
48     SetCurrentBundleName(bundleName);
49     if (!IsOpenPerf()) {
50         return;
51     }
52     auto task = [this]() {
53         this->ReportBlurStatEvent();
54         this->ReportTextureStatEvent();
55         this->ReportCacheReasonEvent();
56         Drawing::PerfmonitorReporter::ResetStatsData();
57     };
58     RSBackgroundThread::Instance().PostTask(task);
59 #endif
60 }
61 
ReportAtRsFrameEnd()62 void RSPerfMonitorReporter::ReportAtRsFrameEnd()
63 {
64 #ifdef ROSEN_OHOS
65     if (!IsOpenPerf()) {
66         return;
67     }
68     auto task = [this]() {
69         this->ReportBlurPerfEvent();
70         this->ReportTexturePerfEvent();
71         Drawing::PerfmonitorReporter::ResetPerfEventData();
72     };
73     RSBackgroundThread::Instance().PostTask(task);
74 #endif
75 }
76 
ReportBlurStatEvent()77 void RSPerfMonitorReporter::ReportBlurStatEvent()
78 {
79 #ifdef ROSEN_OHOS
80     std::string bundleName = GetCurrentBundleName();
81     std::map<std::string, std::vector<uint16_t>> uploadBlur;
82     {
83         std::lock_guard<std::mutex> guard(mtx_);
84         uploadBlur = statsBlur_;
85         statsBlur_.clear();
86     }
87     for (const auto& node : uploadBlur) {
88         RS_TRACE_NAME_FMT("SubHealthEvent RS_STATS_BLUR [%s], [%s]", bundleName.c_str(),
89             node.first.c_str());
90         HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::GRAPHIC, "RS_STATS_BLUR",
91             HiviewDFX::HiSysEvent::EventType::STATISTIC, "BUNDLE_NAME", bundleName,
92             "NODE_NAME", node.first, "BLUR_TIME", node.second, "BLUR_STATUS", CPU_ONDRAW);
93     }
94     uploadBlur.clear();
95 
96     uploadBlur = Drawing::PerfmonitorReporter::GetBlurStatsData();
97     for (const auto& node : uploadBlur) {
98         RS_TRACE_NAME_FMT("SubHealthEvent RS_STATS_BLUR [%s], [%s]", bundleName.c_str(),
99             node.first.c_str());
100         HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::GRAPHIC, "RS_STATS_BLUR",
101             HiviewDFX::HiSysEvent::EventType::STATISTIC, "BUNDLE_NAME", bundleName,
102             "NODE_NAME", node.first, "BLUR_TIME", node.second, "BLUR_STATUS", CPU_FLUSH);
103     }
104     uploadBlur.clear();
105 #endif
106 }
107 
ReportBlurPerfEvent()108 void RSPerfMonitorReporter::ReportBlurPerfEvent()
109 {
110 #ifdef ROSEN_OHOS
111     std::map<std::string, Drawing::RsBlurEvent> uploadEvents;
112     {
113         std::lock_guard<std::mutex> guard(mtx_);
114         uploadEvents = eventBlur_;
115         eventBlur_.clear();
116     }
117 
118     std::string bundleName = GetCurrentBundleName();
119     for (const auto& [nodeName, node] : uploadEvents) {
120         RS_TRACE_NAME_FMT("SubHealthEvent RS_NODE_BLUR [%s], [%s], [%lld]", bundleName.c_str(),
121             nodeName.c_str(), node.fBlurTime);
122         HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::GRAPHIC, "RS_NODE_BLUR",
123             HiviewDFX::HiSysEvent::EventType::FAULT, "PID", node.fPid, "NODE_NAME", nodeName,
124             "BUNDLE_NAME", bundleName, "FILTER_TYPE", node.fFilterType, "BLUR_RADIUS", node.fBlurRadius,
125             "BLUR_WIDTH", node.fWidth, "BLUR_HEIGHT", node.fHeight, "BLUR_TIME", node.fBlurTime,
126             "BLUR_STATUS", CPU_ONDRAW);
127     }
128     uploadEvents.clear();
129 
130     uploadEvents = Drawing::PerfmonitorReporter::GetBlurPerfEventData();
131     for (const auto& [nodeName, node] : uploadEvents) {
132         RS_TRACE_NAME_FMT("SubHealthEvent RS_NODE_BLUR [%s], [%s], [%lld]", bundleName.c_str(),
133             nodeName.c_str(), node.fBlurTime);
134         HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::GRAPHIC, "RS_NODE_BLUR",
135             HiviewDFX::HiSysEvent::EventType::FAULT, "PID", node.fPid, "NODE_NAME", nodeName,
136             "BUNDLE_NAME", bundleName, "FILTER_TYPE", node.fFilterType, "BLUR_RADIUS", node.fBlurRadius,
137             "BLUR_WIDTH", node.fWidth, "BLUR_HEIGHT", node.fHeight, "BLUR_TIME", node.fBlurTime,
138             "BLUR_STATUS", CPU_FLUSH);
139     }
140     uploadEvents.clear();
141 #endif
142 }
143 
ReportCacheReasonEvent()144 void RSPerfMonitorReporter::ReportCacheReasonEvent()
145 {
146 #ifdef ROSEN_OHOS
147     std::string bundleName = GetCurrentBundleName();
148     std::map<std::string, std::vector<uint16_t>> uploadReason;
149     {
150         std::lock_guard<std::mutex> guard(mtx_);
151         uploadReason = statsReason_;
152         statsReason_.clear();
153     }
154     for (const auto& node : uploadReason) {
155         RS_TRACE_NAME_FMT("SubHealthEvent RS_STATS_CAHCHE [%s], [%s]", bundleName.c_str(),
156             node.first.c_str());
157         HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::GRAPHIC, "RS_STATS_CAHCHE",
158             HiviewDFX::HiSysEvent::EventType::STATISTIC, "BUNDLE_NAME", bundleName,
159             "NODE_NAME", node.first, "CACHE_REASON", node.second);
160     }
161     uploadReason.clear();
162 #endif
163 }
164 
ReportTextureStatEvent()165 void RSPerfMonitorReporter::ReportTextureStatEvent()
166 {
167 #ifdef ROSEN_OHOS
168     std::string bundleName = GetCurrentBundleName();
169     std::map<std::string, std::vector<uint16_t>> uploadTexture =
170         Drawing::PerfmonitorReporter::GetTextureStatsData();
171     for (const auto& node : uploadTexture) {
172         RS_TRACE_NAME_FMT("SubHealthEvent RS_STATS_TEXTURE [%s], [%s]",
173             bundleName.c_str(), node.first.c_str());
174         HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::GRAPHIC, "RS_STATS_TEXTURE",
175             OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, "BUNDLE_NAME", bundleName,
176             "NODE_NAME", node.first, "TEXTURE_TIME", node.second, "TEXTURE_STATUS", CPU_FLUSH);
177     }
178 #endif
179 }
180 
ReportTexturePerfEvent()181 void RSPerfMonitorReporter::ReportTexturePerfEvent()
182 {
183 #ifdef ROSEN_OHOS
184     std::string bundleName = GetCurrentBundleName();
185     std::map<std::string, Drawing::RsTextureEvent> uploadEvents =
186         Drawing::PerfmonitorReporter::GetTexturePerfEventData();
187     for (const auto& [nodeName, node] : uploadEvents) {
188         RS_TRACE_NAME_FMT("SubHealthEvent RS_NODE_TEXTURE [%s], [%s], [%lld]",
189             bundleName.c_str(), nodeName.c_str(), node.fAllocTime);
190         HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::GRAPHIC, "RS_NODE_TEXTURE",
191             OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, "PID", node.fPid, "NODE_NAME", nodeName,
192             "BUNDLE_NAME", bundleName, "TEXTURE_TIME", node.fAllocTime, "FMAX_BYTES", node.fMaxBytes,
193             "FBUDGETED_BYTES", node.fBudgetedBytes, "CLEAR_CACHE", node.fClearCache,
194             "TEXTURE_STATUS", CPU_FLUSH);
195     }
196 #endif
197 }
198 
RecordBlurPerfEvent(NodeId nodeId,const std::string & nodeName,uint16_t filterType,float blurRadius,int32_t width,int32_t height,int64_t blurTime,bool isBlurType)199 void RSPerfMonitorReporter::RecordBlurPerfEvent(NodeId nodeId, const std::string& nodeName,
200     uint16_t filterType, float blurRadius, int32_t width, int32_t height, int64_t blurTime,
201     bool isBlurType)
202 {
203 #ifdef ROSEN_OHOS
204     if (!IsOpenPerf() || !isBlurType || nodeName.empty() ||
205         blurTime < Drawing::COUNTER_MS_THIRD_TYPE) {
206         return;
207     }
208     int32_t pid = ExtractPid(nodeId);
209     Drawing::RsBlurEvent bEvent;
210     bEvent.initEvent(pid, filterType, blurRadius, width, height, blurTime);
211     std::lock_guard<std::mutex> guard(mtx_);
212     eventBlur_[nodeName] = bEvent;
213 #endif
214 }
215 
RecordBlurNode(const std::string & nodeName,int64_t duration,bool isBlurType)216 void RSPerfMonitorReporter::RecordBlurNode(const std::string& nodeName, int64_t duration,
217     bool isBlurType)
218 {
219 #ifdef ROSEN_OHOS
220     int16_t cType = Drawing::PerfmonitorReporter::GetSplitRange(duration);
221     if (!IsOpenPerf() || !isBlurType || nodeName.empty() ||
222         cType <= Drawing::COUNTER_INVALID_TYPE) {
223         return;
224     }
225     std::lock_guard<std::mutex> guard(mtx_);
226     if (statsBlur_.find(nodeName) == statsBlur_.end()) {
227         statsBlur_[nodeName] = std::vector<uint16_t>(COUNTER_SIZE, 0);
228     }
229     statsBlur_[nodeName][cType]++;
230 #endif
231 }
232 
RecordBlurCacheReason(const std::string & nodeName,BLUR_CLEAR_CACHE_REASON reason,bool isBlurType)233 void RSPerfMonitorReporter::RecordBlurCacheReason(const std::string& nodeName, BLUR_CLEAR_CACHE_REASON reason,
234     bool isBlurType)
235 {
236 #ifdef ROSEN_OHOS
237     if (!IsOpenPerf() || !isBlurType || nodeName.empty()) {
238         return;
239     }
240     std::lock_guard<std::mutex> guard(mtx_);
241     if (statsReason_.find(nodeName) == statsReason_.end()) {
242         statsReason_[nodeName] = std::vector<uint16_t>(REASON_SIZE, 0);
243     }
244     statsReason_[nodeName][reason]++;
245 #endif
246 }
247 
SetCurrentBundleName(const char * bundleName)248 void RSPerfMonitorReporter::SetCurrentBundleName(const char* bundleName)
249 {
250     std::lock_guard<std::mutex> guard(mtx_);
251     currentBundleName_ = bundleName;
252 }
253 
GetCurrentBundleName()254 std::string RSPerfMonitorReporter::GetCurrentBundleName()
255 {
256     std::lock_guard<std::mutex> guard(mtx_);
257     return currentBundleName_;
258 }
259 
IsOpenPerf()260 bool RSPerfMonitorReporter::IsOpenPerf()
261 {
262 #ifdef ROSEN_OHOS
263     static bool isOpenPerf = Drawing::PerfmonitorReporter::IsOpenPerf();
264     return isOpenPerf;
265 #else
266     return false;
267 #endif
268 }
269 
StartRendergroupMonitor()270 std::chrono::time_point<high_resolution_clock> RSPerfMonitorReporter::StartRendergroupMonitor()
271 {
272     return high_resolution_clock::now();
273 }
274 
EndRendergroupMonitor(std::chrono::time_point<high_resolution_clock> & startTime,NodeId & nodeId,int updateTimes)275 void RSPerfMonitorReporter::EndRendergroupMonitor(std::chrono::time_point<high_resolution_clock>& startTime,
276     NodeId& nodeId, int updateTimes)
277 {
278 #ifdef ROSEN_OHOS
279     auto endTime = high_resolution_clock::now();
280     auto interval = std::chrono::duration_cast<microseconds>(endTime - startTime);
281     bool needTrace = interval.count() > PRINT_SUBHEALTH_TRACE_INTERVAL;
282     if (needTrace) {
283         RS_TRACE_BEGIN("SubHealthEvent Rendergroup, updateCache interval:" + std::to_string(interval.count()));
284     }
285     ProcessRendergroupSubhealth(nodeId, updateTimes, interval.count(), startTime);
286     if (needTrace) {
287         RS_TRACE_END();
288     }
289 #endif
290 }
291 
ClearRendergroupDataMap(NodeId & nodeId)292 void RSPerfMonitorReporter::ClearRendergroupDataMap(NodeId& nodeId)
293 {
294 #ifdef ROSEN_OHOS
295     {
296         std::lock_guard<std::mutex> lock(drawingCacheTimeTakenMapMutex_);
297         drawingCacheTimeTakenMap_.erase(nodeId);
298     }
299     {
300         std::lock_guard<std::mutex> lock(drawingCacheLastTwoTimestampMapMutex_);
301         drawingCacheLastTwoTimestampMap_.erase(nodeId);
302     }
303 #endif
304 }
305 
ProcessRendergroupSubhealth(NodeId & nodeId,int updateTimes,int interval,std::chrono::time_point<high_resolution_clock> & startTime)306 void RSPerfMonitorReporter::ProcessRendergroupSubhealth(NodeId& nodeId, int updateTimes, int interval,
307     std::chrono::time_point<high_resolution_clock>& startTime)
308 {
309 #ifdef ROSEN_OHOS
310     {
311         std::lock_guard<std::mutex> lock(drawingCacheTimeTakenMapMutex_);
312         drawingCacheTimeTakenMap_[nodeId].emplace_back(interval);
313         if (drawingCacheTimeTakenMap_[nodeId].size() > DRAWING_CACHE_UPDATE_TIME_THRESHOLD) {
314             drawingCacheTimeTakenMap_[nodeId].erase(drawingCacheTimeTakenMap_[nodeId].begin());
315         }
316     }
317     // check if need hisysevent report
318     if (NeedReportSubHealth(nodeId, updateTimes, startTime)) {
319         auto reportTime = high_resolution_clock::now();
320         std::string bundleName = GetCurrentBundleName();
321         std::string timeTaken = GetUpdateCacheTimeTaken(nodeId);
322         RSBackgroundThread::Instance().PostTask([nodeId, bundleName, updateTimes, timeTaken]() {
323             RS_TRACE_NAME("RSPerfMonitorReporter::ProcessRendergroupSubhealth HiSysEventWrite in RSBackgroundThread");
324             HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::GRAPHIC, RENDERGROUP_SUBHEALTH_EVENT_NAME,
325                 OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
326                 "NODE_ID", nodeId,
327                 "BUNDLE_NAME", bundleName,
328                 "CONTINUOUS_UPDATE_CACHE_TIMES", updateTimes,
329                 "UPDATE_CACHE_TIME_TAKEN", timeTaken);
330         });
331         {
332             std::lock_guard<std::mutex> lock(drawingCacheLastReportTimeMapMutex_);
333             drawingCacheLastReportTimeMap_[nodeId] = reportTime;
334         }
335     }
336     {
337         std::lock_guard<std::mutex> lock(drawingCacheLastTwoTimestampMapMutex_);
338         drawingCacheLastTwoTimestampMap_[nodeId].push(startTime);
339         if (drawingCacheLastTwoTimestampMap_[nodeId].size() > STORED_TIMESTAMP_COUNT) {
340             drawingCacheLastTwoTimestampMap_[nodeId].pop();
341         }
342     }
343 #endif
344 }
345 
NeedReportSubHealth(NodeId & nodeId,int updateTimes,std::chrono::time_point<high_resolution_clock> & startTime)346 bool RSPerfMonitorReporter::NeedReportSubHealth(NodeId& nodeId, int updateTimes,
347     std::chrono::time_point<high_resolution_clock>& startTime)
348 {
349 #ifdef ROSEN_OHOS
350     if (!MeetReportFrequencyControl(nodeId, startTime)) {
351         return false;
352     }
353     {
354         std::lock_guard<std::mutex> lock(drawingCacheLastTwoTimestampMapMutex_);
355         size_t timestampCounts = drawingCacheLastTwoTimestampMap_[nodeId].size();
356         if (timestampCounts != STORED_TIMESTAMP_COUNT) {
357             return false;
358         }
359         auto firstTimestamp = drawingCacheLastTwoTimestampMap_[nodeId].front();
360         auto interval = std::chrono::duration_cast<microseconds>(startTime - firstTimestamp);
361         if (interval.count() > INTERVAL_THRESHOLD) {
362             return false;
363         }
364     }
365     if (CheckAllDrawingCacheDurationTimeout(nodeId)) {
366         return true;
367     }
368     if (updateTimes >= DRAWING_CACHE_MAX_CONTINUOUS_UPDATE_TIME) {
369         return true;
370     }
371     return false;
372 #else
373     return false;
374 #endif
375 }
376 
CheckAllDrawingCacheDurationTimeout(NodeId & nodeId)377 bool RSPerfMonitorReporter::CheckAllDrawingCacheDurationTimeout(NodeId& nodeId)
378 {
379 #ifdef ROSEN_OHOS
380     std::lock_guard<std::mutex> lock(drawingCacheTimeTakenMapMutex_);
381     for (auto& it: drawingCacheTimeTakenMap_[nodeId]) {
382         if (it < DRAWING_CACHE_DURATION_TIMEOUT_THRESHOLD) {
383             return false;
384         }
385     }
386     return true;
387 #else
388     return false;
389 #endif
390 }
391 
MeetReportFrequencyControl(NodeId & nodeId,std::chrono::time_point<high_resolution_clock> & startTime)392 bool RSPerfMonitorReporter::MeetReportFrequencyControl(NodeId& nodeId,
393     std::chrono::time_point<high_resolution_clock>& startTime)
394 {
395 #ifdef ROSEN_OHOS
396     std::lock_guard<std::mutex> lock(drawingCacheLastReportTimeMapMutex_);
397     if (drawingCacheLastReportTimeMap_.find(nodeId) == drawingCacheLastReportTimeMap_.end()) {
398         return true;
399     } else {
400         auto lastTime = drawingCacheLastReportTimeMap_[nodeId];
401         if (std::chrono::duration_cast<microseconds>(startTime - lastTime).count() > REPORT_INTERVAL) {
402             return true;
403         }
404     }
405     return false;
406 #else
407     return false;
408 #endif
409 }
410 
GetUpdateCacheTimeTaken(NodeId & nodeId)411 std::string RSPerfMonitorReporter::GetUpdateCacheTimeTaken(NodeId& nodeId)
412 {
413     std::string result;
414 #ifdef ROSEN_OHOS
415     std::lock_guard<std::mutex> lock(drawingCacheTimeTakenMapMutex_);
416     if (drawingCacheTimeTakenMap_.find(nodeId) != drawingCacheTimeTakenMap_.end()) {
417         for (auto& it: drawingCacheTimeTakenMap_[nodeId]) {
418             result += std::to_string(it) + ",";
419         }
420     }
421     if (result.size() > 0 && result.back() == ',') {
422         result.pop_back();
423     }
424     return result;
425 #else
426     return result;
427 #endif
428 }
429 
430 } // namespace Rosen
431 } // namespace OHOS
432