• 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 <thread>
17 
18 #include "rs_profiler.h"
19 #include "rs_profiler_archive.h"
20 #include "rs_profiler_command.h"
21 #include "rs_profiler_file.h"
22 #include "rs_profiler_network.h"
23 #include "rs_profiler_packet.h"
24 #include "rs_profiler_telemetry.h"
25 #include "pipeline/main_thread/rs_main_thread.h"
26 
27 namespace OHOS::Rosen {
28 
29 static constexpr uint32_t INACTIVITY_THRESHOLD_SECONDS = 5u;
30 static DeviceInfo g_deviceInfo;
31 static std::mutex g_deviceInfoMutex;
32 static bool g_started = false;
33 static double g_inactiveTimestamp = 0.0;
34 static double g_recordsTimestamp = 0.0;
35 static double g_currentFrameDirtyRegion = 0.0;
36 static uint64_t g_lastParcelTime = 0;
37 static int g_animationCount = 0;
38 static std::mutex g_mutexBetaRecording;
39 static bool g_mutexBetaRecordingLocked = false;
40 
41 // implemented in rs_profiler.cpp
42 void DeviceInfoToCaptureData(double time, const DeviceInfo& in, RSCaptureData& out);
43 
HasInitializationFinished()44 static bool HasInitializationFinished()
45 {
46     constexpr uint32_t maxAttempts = 600u;
47     static uint32_t attempt = 0u;
48     if (attempt < maxAttempts) {
49         attempt++;
50     }
51     return attempt == maxAttempts;
52 }
53 
GetBetaRecordFileName(uint32_t index)54 static std::string GetBetaRecordFileName(uint32_t index)
55 {
56     constexpr uint32_t ten = 10u;
57     const std::string cacheFile("/data/service/el0/render_service/file");
58     return cacheFile + ((index < ten) ? "0" : "") + std::to_string(index) + ".ohr";
59 }
60 
IsBetaRecordInactive()61 bool RSProfiler::IsBetaRecordInactive()
62 {
63     return (Now() - g_inactiveTimestamp) > INACTIVITY_THRESHOLD_SECONDS;
64 }
65 
RequestVSyncOnBetaRecordInactivity()66 void RSProfiler::RequestVSyncOnBetaRecordInactivity()
67 {
68     if (IsBetaRecordInactive()) {
69         RequestNextVSync();
70     }
71 }
72 
LaunchBetaRecordNotificationThread()73 void RSProfiler::LaunchBetaRecordNotificationThread()
74 {
75     std::thread thread([]() {
76         while (IsBetaRecordStarted()) {
77             RequestVSyncOnBetaRecordInactivity();
78             std::this_thread::sleep_for(std::chrono::seconds(INACTIVITY_THRESHOLD_SECONDS));
79         }
80     });
81     thread.detach();
82 }
83 
LaunchBetaRecordFileSplitThread()84 void RSProfiler::LaunchBetaRecordFileSplitThread()
85 {
86     std::thread thread([]() {
87         while (IsBetaRecordStarted() && IsBetaRecordEnabled()) {
88             SaveBetaRecord();
89 
90             constexpr int32_t splitCheckTime = 100;
91             std::this_thread::sleep_for(std::chrono::milliseconds(splitCheckTime));
92         }
93     });
94     thread.detach();
95 }
96 
LaunchBetaRecordMetricsUpdateThread()97 void RSProfiler::LaunchBetaRecordMetricsUpdateThread()
98 {
99     if (!IsBetaRecordEnabledWithMetrics()) {
100         return;
101     }
102     std::thread thread([]() {
103         while (IsBetaRecordStarted()) {
104             const DeviceInfo deviceInfo = RSTelemetry::GetDeviceInfo();
105 
106             g_deviceInfoMutex.lock();
107             g_deviceInfo = deviceInfo;
108             g_deviceInfoMutex.unlock();
109 
110             constexpr int32_t sendInterval = 8;
111             std::this_thread::sleep_for(std::chrono::milliseconds(sendInterval));
112         }
113     });
114     thread.detach();
115 }
116 
BetaRecordOnFrameBegin()117 void RSProfiler::BetaRecordOnFrameBegin()
118 {
119     if (IsBetaRecordStarted() && IsBetaRecordEnabled()) {
120         g_mutexBetaRecording.lock();
121         g_mutexBetaRecordingLocked = true;
122     } else {
123         g_mutexBetaRecordingLocked = false;
124     }
125 }
126 
BetaRecordOnFrameEnd()127 void RSProfiler::BetaRecordOnFrameEnd()
128 {
129     if (g_mutexBetaRecordingLocked) {
130         g_mutexBetaRecording.unlock();
131         g_mutexBetaRecordingLocked = false;
132     }
133 }
134 
StartBetaRecord()135 void RSProfiler::StartBetaRecord()
136 {
137     if (HasInitializationFinished() && !IsBetaRecordStarted() && IsBetaRecordEnabled()) {
138         g_inactiveTimestamp = Now();
139         g_recordsTimestamp = Now();
140 
141         LaunchBetaRecordNotificationThread();
142         LaunchBetaRecordMetricsUpdateThread();
143 
144         // Start recording for the first file
145         RecordStart(ArgList());
146 
147         g_started = true;
148 
149         LaunchBetaRecordFileSplitThread();
150     }
151 }
152 
StopBetaRecord()153 void RSProfiler::StopBetaRecord()
154 {
155     if (IsBetaRecordStarted()) {
156         RecordStop(ArgList());
157         g_started = false;
158         g_inactiveTimestamp = 0;
159     }
160 }
161 
IsBetaRecordStarted()162 bool RSProfiler::IsBetaRecordStarted()
163 {
164     return g_started;
165 }
166 
BetaRecordSetLastParcelTime()167 void RSProfiler::BetaRecordSetLastParcelTime()
168 {
169     g_lastParcelTime = Utils::Now();
170 }
171 
SaveBetaRecord()172 void RSProfiler::SaveBetaRecord()
173 {
174     if (g_animationCount) {
175         // doesn't start beta record during animations
176         return;
177     }
178     constexpr double inactivityThreshold = 0.5;
179     if (g_lastParcelTime + Utils::ToNanoseconds(inactivityThreshold) > Utils::Now()) {
180         // doesn't start beta record if parcels were sent less then 0.5 second ago
181         return;
182     }
183 
184     if (IsNoneMode()) {
185         std::unique_lock<std::mutex> lock(g_mutexBetaRecording);
186         RecordStart(ArgList());
187         return;
188     }
189 
190     constexpr double recordMaxLengthSeconds = 30.0;
191     const auto recordLength = Now() - g_recordsTimestamp;
192     if (!IsBetaRecordSavingTriggered() && (recordLength <= recordMaxLengthSeconds)) {
193         // start new beta-record file every recordMaxLengthSeconds
194         return;
195     }
196 
197     std::unique_lock<std::mutex> lock(g_mutexBetaRecording);
198     RecordStop(ArgList());
199     EnableBetaRecord();
200 }
201 
UpdateBetaRecord(const RSContext & context)202 void RSProfiler::UpdateBetaRecord(const RSContext& context)
203 {
204     // the last time any rendering is done
205     if (g_currentFrameDirtyRegion > 0) {
206         g_inactiveTimestamp = Now();
207     }
208     g_animationCount = static_cast<int>(context.animatingNodeList_.size());
209 }
210 
OpenBetaRecordFile(RSFile & file)211 bool RSProfiler::OpenBetaRecordFile(RSFile& file)
212 {
213     if (!IsBetaRecordStarted()) {
214         return false;
215     }
216 
217     const auto path = "RECORD_IN_MEMORY";
218     file.SetVersion(RSFILE_VERSION_LATEST);
219     file.Create(path);
220 
221     g_recordsTimestamp = Now();
222     return true;
223 }
224 
SaveBetaRecordFile(RSFile & file)225 bool RSProfiler::SaveBetaRecordFile(RSFile& file)
226 {
227     if (!IsBetaRecordStarted()) {
228         return false;
229     }
230 
231     constexpr uint32_t maxCacheFiles = 10u;
232     static uint32_t index = 0u;
233 
234     std::vector<uint8_t> data;
235     if (!file.GetDataCopy(data)) {
236         return false;
237     }
238 
239     auto out = Utils::FileOpen(GetBetaRecordFileName(index), "wbe");
240     if (Utils::IsFileValid(out)) {
241         Utils::FileWrite(out, data.data(), data.size());
242         Utils::FileClose(out);
243     }
244 
245     index++;
246     if (index >= maxCacheFiles) {
247         index = 0u;
248     }
249 
250     return true;
251 }
252 
WriteBetaRecordMetrics(RSFile & file,double time)253 void RSProfiler::WriteBetaRecordMetrics(RSFile& file, double time)
254 {
255     if (!IsBetaRecordStarted() || (time < 0.0) || !IsBetaRecordEnabledWithMetrics()) {
256         return;
257     }
258 
259     g_deviceInfoMutex.lock();
260     const DeviceInfo deviceInfo = g_deviceInfo;
261     g_deviceInfoMutex.unlock();
262 
263     RSCaptureData captureData;
264     DeviceInfoToCaptureData(time, deviceInfo, captureData);
265 
266     std::vector<char> out;
267     DataWriter archive(out);
268     char headerType = static_cast<char>(PackageID::RS_PROFILER_GFX_METRICS);
269     archive.Serialize(headerType);
270     captureData.Serialize(archive);
271 
272     file.WriteGFXMetrics(0, time, 0, out.data(), out.size());
273 }
274 
UpdateDirtyRegionBetaRecord(double currentFrameDirtyRegion)275 void RSProfiler::UpdateDirtyRegionBetaRecord(double currentFrameDirtyRegion)
276 {
277     g_currentFrameDirtyRegion = currentFrameDirtyRegion;
278 }
279 
280 } // namespace OHOS::Rosen