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