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