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 "rs_profiler.h"
17
18 #include <cstddef>
19 #include <fstream>
20 #include <filesystem>
21 #include <numeric>
22 #include <system_error>
23
24 #include "rs_profiler_archive.h"
25 #include "rs_profiler_cache.h"
26 #include "rs_profiler_capture_recorder.h"
27 #include "rs_profiler_capturedata.h"
28 #include "rs_profiler_command.h"
29 #include "rs_profiler_file.h"
30 #include "rs_profiler_json.h"
31 #include "rs_profiler_log.h"
32 #include "rs_profiler_network.h"
33 #include "rs_profiler_packet.h"
34 #include "rs_profiler_settings.h"
35 #include "rs_profiler_telemetry.h"
36 #include "rs_profiler_test_tree.h"
37
38 #include "common/rs_common_def.h"
39 #include "feature/dirty/rs_uni_dirty_compute_util.h"
40 #include "pipeline/render_thread/rs_uni_render_util.h"
41 #include "params/rs_screen_render_params.h"
42 #include "pipeline/main_thread/rs_main_thread.h"
43 #include "pipeline/rs_logical_display_render_node.h"
44 #include "pipeline/rs_render_node_gc.h"
45 #include "pipeline/main_thread/rs_render_service_connection.h"
46 #include "render/rs_typeface_cache.h"
47
48 namespace OHOS::Rosen {
49
50 namespace {
51 // (user): Move to RSProfiler
52 static RSRenderService* g_renderService = nullptr;
53 static RSMainThread* g_mainThread = nullptr;
54 static std::atomic<int32_t> g_renderServiceCpuId = 0;
55 static std::atomic<int32_t> g_renderServiceRenderCpuId = 0;
56 static uint64_t g_frameSyncTimestamp = 0u;
57 static uint64_t g_frameBeginTimestamp = 0u;
58 static uint64_t g_frameRenderBeginTimestamp = 0u;
59 static double g_dirtyRegionPercentage = 0.0;
60 static std::stringstream g_dirtyRegionList;
61 static bool g_rdcSent = true;
62 static uint64_t g_recordMinVsync = 0;
63 static uint64_t g_recordMaxVsync = 0;
64
65 static std::atomic<uint32_t> g_lastCacheImageCount = 0;
66
67 static RSFile g_recordFile {};
68 static double g_recordStartTime = 0.0;
69 static uint32_t g_frameNumber = 0;
70
71 static RSFile g_playbackFile {};
72 static double g_playbackStartTime = 0.0;
73 static NodeId g_playbackParentNodeId = 0;
74 static int g_playbackPid = 0;
75 static bool g_playbackShouldBeTerminated = true;
76 static double g_playbackPauseTime = 0;
77 static int g_playbackWaitFrames = 0;
78 static double g_replayLastPauseTimeReported = 0;
79
80 static std::vector<std::pair<NodeId, uint32_t>> g_nodeListPerf;
81 static std::unordered_map<NodeId, uint32_t> g_mapNode2Count;
82 static std::unordered_map<NodeId, uint32_t> g_mapNode2UpTime;
83 static std::unordered_map<NodeId, uint32_t> g_mapNode2UpDownTime;
84 static NodeId g_calcPerfNode = 0;
85 static uint32_t g_calcPerfNodeTry = 0;
86 static bool g_calcPerfNodeExcludeDown = false;
87
88 static std::vector<std::pair<std::shared_ptr<RSRenderNode>, std::vector<std::shared_ptr<RSRenderNode>>>>
89 g_calcPerfSavedChildren;
90 static NodeId g_blinkNodeId = 0;
91 static uint32_t g_blinkNodeCount = 0;
92 static std::vector<std::shared_ptr<RSRenderNode>> g_blinkSavedParentChildren;
93
94 constexpr int CALC_PERF_NODE_TIME_COUNT_MIN = 128; // min render tries
95 constexpr int CALC_PERF_NODE_TIME_COUNT_MAX = 4096; // max render tries
96 static uint32_t g_effectiveNodeTimeCount = CALC_PERF_NODE_TIME_COUNT_MAX;
97 static uint64_t g_calcPerfNodeTime[CALC_PERF_NODE_TIME_COUNT_MAX];
98 static int g_nodeListPerfCalcIndex = -1;
99
100 static std::string g_testDataFrame;
101 static std::vector<RSRenderNode::SharedPtr> g_childOfDisplayNodes;
102 static uint32_t g_recordParcelNumber = 0;
103 static bool g_playbackImmediate = false;
104 static std::unordered_map<std::string, std::string> g_recordRsMetric;
105 } // namespace
106
107 RSContext* RSProfiler::context_ = nullptr;
108
109 #pragma pack(push, 1)
110 struct AlignedMessageParcel {
111 uint8_t pad = 0u;
112 MessageParcel parcel;
113 };
114 #pragma pack(pop)
115
DeviceInfoToCaptureData(double time,const DeviceInfo & in,RSCaptureData & out)116 void DeviceInfoToCaptureData(double time, const DeviceInfo& in, RSCaptureData& out)
117 {
118 std::string frequency;
119 std::string load;
120 for (uint32_t i = 0; i < in.cpu.cores; i++) {
121 frequency += std::to_string(in.cpu.coreFrequencyLoad[i].current);
122 load += std::to_string(in.cpu.coreFrequencyLoad[i].load);
123 if (i + 1 < in.cpu.cores) {
124 frequency += ";";
125 load += ";";
126 }
127 }
128
129 out.SetTime(static_cast<float>(time));
130 out.SetProperty(RSCaptureData::KEY_CPU_TEMP, in.cpu.temperature);
131 out.SetProperty(RSCaptureData::KEY_CPU_CURRENT, in.cpu.current);
132 out.SetProperty(RSCaptureData::KEY_CPU_LOAD, load);
133 out.SetProperty(RSCaptureData::KEY_CPU_FREQ, frequency);
134 out.SetProperty(RSCaptureData::KEY_GPU_LOAD, in.gpu.frequencyLoad.load);
135 out.SetProperty(RSCaptureData::KEY_GPU_FREQ, in.gpu.frequencyLoad.current);
136 out.SetProperty(RSCaptureData::KEY_CPU_ID, g_renderServiceRenderCpuId.load());
137 }
138
GetPid(const std::shared_ptr<RSRenderNode> & node)139 static pid_t GetPid(const std::shared_ptr<RSRenderNode>& node)
140 {
141 return node ? Utils::ExtractPid(node->GetId()) : 0;
142 }
143
GetNodeId(const std::shared_ptr<RSRenderNode> & node)144 static NodeId GetNodeId(const std::shared_ptr<RSRenderNode>& node)
145 {
146 return node ? Utils::ExtractNodeId(node->GetId()) : 0;
147 }
148
SendTelemetry(double time)149 static void SendTelemetry(double time)
150 {
151 if (time >= 0.0) {
152 RSCaptureData captureData;
153 DeviceInfoToCaptureData(time, RSTelemetry::GetDeviceInfo(), captureData);
154 Network::SendCaptureData(captureData);
155 }
156 }
157
158 /*
159 To visualize the damage region (as it's set for KHR_partial_update), you can set the following variable:
160 'hdc shell param set rosen.dirtyregiondebug.enabled 6'
161 */
SetDirtyRegion(const Occlusion::Region & dirtyRegion)162 void RSProfiler::SetDirtyRegion(const Occlusion::Region& dirtyRegion)
163 {
164 #ifdef RS_ENABLE_GPU
165 if (!IsRecording()) {
166 return;
167 }
168
169 const double maxPercentValue = 100.0;
170 g_dirtyRegionPercentage = maxPercentValue;
171
172 if (!context_) {
173 return;
174 }
175 std::shared_ptr<RSScreenRenderNode> displayNode = GetScreenNode(*context_);
176 if (!displayNode) {
177 return;
178 }
179 // the following logic calcuate the percentage of dirtyRegion
180 auto params = static_cast<RSScreenRenderParams*>(displayNode->GetRenderParams().get());
181 if (!params) {
182 return;
183 }
184
185 auto screenInfo = params->GetScreenInfo();
186 const uint64_t displayArea = static_cast<uint64_t>(screenInfo.width * screenInfo.height);
187
188 auto rects = RSUniDirtyComputeUtil::ScreenIntersectDirtyRects(dirtyRegion, screenInfo);
189 uint64_t dirtyRegionArea = 0;
190 g_dirtyRegionList.str("");
191 for (const auto& rect : rects) {
192 dirtyRegionArea += static_cast<uint64_t>(rect.GetWidth() * rect.GetHeight());
193 int32_t value = rect.GetLeft();
194 g_dirtyRegionList.write(reinterpret_cast<const char*>(&value), sizeof(value));
195 value = rect.GetTop();
196 g_dirtyRegionList.write(reinterpret_cast<const char*>(&value), sizeof(value));
197 value = rect.GetWidth();
198 g_dirtyRegionList.write(reinterpret_cast<const char*>(&value), sizeof(value));
199 value = rect.GetHeight();
200 g_dirtyRegionList.write(reinterpret_cast<const char*>(&value), sizeof(value));
201 }
202
203 if (displayArea > 0) {
204 g_dirtyRegionPercentage =
205 maxPercentValue * static_cast<double>(dirtyRegionArea) / static_cast<double>(displayArea);
206 }
207 if (g_dirtyRegionPercentage > maxPercentValue) {
208 g_dirtyRegionPercentage = maxPercentValue;
209 }
210 #endif
211 }
212
Init(RSRenderService * renderService)213 void RSProfiler::Init(RSRenderService* renderService)
214 {
215 g_renderService = renderService;
216 g_mainThread = g_renderService ? g_renderService->mainThread_ : nullptr;
217 context_ = g_mainThread ? g_mainThread->context_.get() : nullptr;
218
219 RSSystemProperties::SetProfilerDisabled();
220 RSSystemProperties::WatchSystemProperty(SYS_KEY_ENABLED, OnFlagChangedCallback, nullptr);
221 RSSystemProperties::WatchSystemProperty(SYS_KEY_BETARECORDING, OnFlagChangedCallback, nullptr);
222 bool isEnabled = RSSystemProperties::GetProfilerEnabled();
223 bool isBetaRecord = RSSystemProperties::GetBetaRecordingMode() != 0;
224 HRPI("Profiler flags changed enabled=%{public}d beta_record=%{public}d", isEnabled ? 1 : 0, isBetaRecord ? 1 : 0);
225
226 if (!IsEnabled()) {
227 return;
228 }
229 }
230
StartNetworkThread()231 void RSProfiler::StartNetworkThread()
232 {
233 if (Network::IsRunning()) {
234 return;
235 }
236 auto networkRunLambda = []() {
237 Network::Run();
238 };
239 std::thread thread(networkRunLambda);
240 thread.detach();
241 }
242
OnCreateConnection(pid_t pid)243 void RSProfiler::OnCreateConnection(pid_t pid)
244 {
245 if (!IsEnabled()) {
246 return;
247 }
248
249 if (IsRecording()) {
250 g_recordFile.AddHeaderPid(pid);
251 }
252 }
253
WriteRemoteRequest(pid_t pid,uint32_t code,MessageParcel & parcel,MessageOption & option)254 uint64_t RSProfiler::WriteRemoteRequest(pid_t pid, uint32_t code, MessageParcel& parcel, MessageOption& option)
255 {
256 const double deltaTime = Now() - g_recordStartTime;
257
258 std::stringstream stream(std::ios::in | std::ios::out | std::ios::binary);
259
260 char headerType = 1; // parcel data
261 stream.write(reinterpret_cast<const char*>(&headerType), sizeof(headerType));
262 stream.write(reinterpret_cast<const char*>(&deltaTime), sizeof(deltaTime));
263
264 // set sending pid
265 stream.write(reinterpret_cast<const char*>(&pid), sizeof(pid));
266 stream.write(reinterpret_cast<const char*>(&code), sizeof(code));
267
268 const size_t dataSize = parcel.GetDataSize();
269 stream.write(reinterpret_cast<const char*>(&dataSize), sizeof(dataSize));
270 stream.write(reinterpret_cast<const char*>(parcel.GetData()), dataSize);
271
272 const int32_t flags = option.GetFlags();
273 stream.write(reinterpret_cast<const char*>(&flags), sizeof(flags));
274 const int32_t waitTime = option.GetWaitTime();
275 stream.write(reinterpret_cast<const char*>(&waitTime), sizeof(waitTime));
276 g_recordParcelNumber++;
277 stream.write(reinterpret_cast<const char*>(&g_recordParcelNumber), sizeof(g_recordParcelNumber));
278
279 const std::string out = stream.str();
280 constexpr size_t headerOffset = 8 + 1;
281 if (out.size() >= headerOffset) {
282 g_recordFile.WriteRSData(deltaTime, out.data() + headerOffset, out.size() - headerOffset);
283 BetaRecordSetLastParcelTime();
284 }
285 Network::SendBinary(out.data(), out.size());
286 return g_recordParcelNumber;
287 }
288
OnRemoteRequest(RSIRenderServiceConnection * connection,uint32_t code,MessageParcel & parcel,MessageParcel &,MessageOption & option)289 uint64_t RSProfiler::OnRemoteRequest(RSIRenderServiceConnection* connection, uint32_t code,
290 MessageParcel& parcel, MessageParcel& /*reply*/, MessageOption& option)
291 {
292 if (!IsEnabled()) {
293 return 0;
294 }
295
296 if (IsRecording()) {
297 constexpr size_t BYTE_SIZE_FOR_ASHMEM = 4;
298 if (code == static_cast<uint32_t>(RSIRenderServiceConnectionInterfaceCode::COMMIT_TRANSACTION) &&
299 parcel.GetDataSize() >= BYTE_SIZE_FOR_ASHMEM) {
300 const uint32_t *data = reinterpret_cast<const uint32_t*>(parcel.GetData());
301 if (data && *data) {
302 // ashmem parcel - don't save
303 return 0;
304 }
305 }
306 const pid_t pid = GetConnectionPid(connection);
307 const auto& pids = g_recordFile.GetHeaderPids();
308 if (std::find(std::begin(pids), std::end(pids), pid) != std::end(pids)) {
309 return WriteRemoteRequest(pid, code, parcel, option);
310 }
311 } else {
312 g_recordParcelNumber = 0;
313 }
314
315 if (IsLoadSaveFirstScreenInProgress()) {
316 // saving screen right now
317 }
318 if (IsPlaying()) {
319 SetTransactionTimeCorrection(g_playbackStartTime, g_playbackFile.GetWriteTime());
320 SetSubstitutingPid(g_playbackFile.GetHeaderPids(), g_playbackPid, g_playbackParentNodeId);
321 SetMode(Mode::READ);
322 }
323 return 0;
324 }
325
OnRecvParcel(const MessageParcel * parcel,RSTransactionData * data)326 void RSProfiler::OnRecvParcel(const MessageParcel* parcel, RSTransactionData* data)
327 {
328 if (!IsEnabled()) {
329 return;
330 }
331
332 if (parcel && IsParcelMock(*parcel)) {
333 data->SetSendingPid(Utils::GetMockPid(data->GetSendingPid()));
334 }
335 }
336
CreateMockConnection(pid_t pid)337 void RSProfiler::CreateMockConnection(pid_t pid)
338 {
339 if (!IsEnabled() || !g_renderService) {
340 return;
341 }
342
343 auto tokenObj = new IRemoteStub<RSIConnectionToken>();
344
345 sptr<RSIRenderServiceConnection> newConn(new RSRenderServiceConnection(pid, g_renderService,
346 g_mainThread, g_renderService->screenManager_, tokenObj, g_renderService->appVSyncDistributor_));
347
348 sptr<RSIRenderServiceConnection> tmp;
349
350 std::unique_lock<std::mutex> lock(g_renderService->mutex_);
351 // if connections_ has the same token one, replace it.
352 if (g_renderService->connections_.count(tokenObj) > 0) {
353 tmp = g_renderService->connections_.at(tokenObj);
354 }
355 g_renderService->connections_[tokenObj] = newConn;
356 lock.unlock();
357 g_mainThread->AddTransactionDataPidInfo(pid);
358 }
359
GetConnection(pid_t pid)360 RSRenderServiceConnection* RSProfiler::GetConnection(pid_t pid)
361 {
362 if (!g_renderService) {
363 return nullptr;
364 }
365
366 for (const auto& pair : g_renderService->connections_) {
367 auto connection = static_cast<RSRenderServiceConnection*>(pair.second.GetRefPtr());
368 if (connection->remotePid_ == pid) {
369 return connection;
370 }
371 }
372
373 return nullptr;
374 }
375
GetConnectionPid(RSIRenderServiceConnection * connection)376 pid_t RSProfiler::GetConnectionPid(RSIRenderServiceConnection* connection)
377 {
378 if (!g_renderService || !connection) {
379 return 0;
380 }
381
382 for (const auto& pair : g_renderService->connections_) {
383 auto renderServiceConnection = static_cast<RSRenderServiceConnection*>(pair.second.GetRefPtr());
384 if (renderServiceConnection == connection) {
385 return renderServiceConnection->remotePid_;
386 }
387 }
388
389 return 0;
390 }
391
GetConnectionsPids()392 std::vector<pid_t> RSProfiler::GetConnectionsPids()
393 {
394 if (!g_renderService) {
395 return {};
396 }
397
398 std::vector<pid_t> pids;
399 pids.reserve(g_renderService->connections_.size());
400 for (const auto& pair : g_renderService->connections_) {
401 pids.push_back(static_cast<RSRenderServiceConnection*>(pair.second.GetRefPtr())->remotePid_);
402 }
403 return pids;
404 }
405
OnFlagChangedCallback(const char * key,const char * value,void * context)406 void RSProfiler::OnFlagChangedCallback(const char *key, const char *value, void *context)
407 {
408 constexpr int8_t two = 2;
409 if (!strcmp(key, SYS_KEY_ENABLED)) {
410 signalFlagChanged_ = two;
411 AwakeRenderServiceThread();
412 }
413 if (!strcmp(key, SYS_KEY_BETARECORDING)) {
414 signalFlagChanged_ = two;
415 AwakeRenderServiceThread();
416 }
417 }
418
OnWorkModeChanged()419 void RSProfiler::OnWorkModeChanged()
420 {
421 if (IsEnabled()) {
422 if (IsBetaRecordEnabled()) {
423 HRPD("RSProfiler: Stop network. Start beta-recording.");
424 Network::Stop();
425 StartBetaRecord();
426 } else {
427 StopBetaRecord();
428 StartNetworkThread();
429 HRPD("RSProfiler: Stop beta-recording (if running). Start network.");
430 }
431 } else {
432 HRPD("RSProfiler: Stop recording. Stop network.");
433 StopBetaRecord();
434 Network::Stop();
435 RecordStop(ArgList());
436 PlaybackStop(ArgList());
437
438 ImageCache::Reset();
439 g_recordFile.Close();
440 g_playbackFile.Close();
441 Utils::FileDelete(RSFile::GetDefaultPath());
442 }
443 }
444
ProcessSignalFlag()445 void RSProfiler::ProcessSignalFlag()
446 {
447 if (signalFlagChanged_ <= 0) {
448 return;
449 }
450
451 signalFlagChanged_--;
452 if (!signalFlagChanged_) {
453 bool newEnabled = RSSystemProperties::GetProfilerEnabled();
454 bool newBetaRecord = RSSystemProperties::GetBetaRecordingMode() != 0;
455 HRPD("Profiler flags changed enabled=%{public}d beta_record=%{public}d", newEnabled ? 1 : 0,
456 newBetaRecord ? 1 : 0);
457 if (enabled_ && !newEnabled) {
458 const ArgList dummy;
459 if (IsReadMode()) {
460 PlaybackStop(dummy);
461 }
462 if (IsWriteMode()) {
463 RecordStop(dummy);
464 }
465 }
466 if (enabled_ != newEnabled || IsBetaRecordEnabled() != newBetaRecord) {
467 enabled_ = newEnabled;
468 betaRecordingEnabled_ = newBetaRecord;
469 RSCaptureRecorder::GetInstance().SetProfilerEnabled(enabled_);
470 OnWorkModeChanged();
471 }
472 }
473 AwakeRenderServiceThread();
474 }
475
OnProcessCommand()476 void RSProfiler::OnProcessCommand()
477 {
478 RS_TRACE_NAME("Profiler OnProcessCommand");
479 ProcessSignalFlag();
480
481 if (!IsEnabled()) {
482 return;
483 }
484
485 if (IsPlaying()) {
486 ResetAnimationStamp();
487 }
488 }
489
IsSecureScreen()490 bool RSProfiler::IsSecureScreen()
491 {
492 std::shared_ptr<RSScreenRenderNode> screenNode = GetScreenNode(*context_);
493 if (!screenNode) {
494 return false;
495 }
496 for (auto& child : *screenNode->GetChildren()) {
497 auto displayNode = child->ReinterpretCastTo<RSLogicalDisplayRenderNode>();
498 if (!displayNode) {
499 continue;
500 }
501 if (displayNode->GetMultableSpecialLayerMgr().Find(SpecialLayerType::HAS_SECURITY)) {
502 return true;
503 }
504 }
505 return false;
506 }
507
OnRenderBegin()508 void RSProfiler::OnRenderBegin()
509 {
510 if (!IsEnabled()) {
511 return;
512 }
513
514 RS_TRACE_NAME("Profiler OnRenderBegin");
515 HRPD("OnRenderBegin()");
516 g_renderServiceCpuId = Utils::GetCpuId();
517
518 ProcessCommands();
519 ProcessSendingRdc();
520 }
521
OnRenderEnd()522 void RSProfiler::OnRenderEnd()
523 {
524 if (!IsEnabled()) {
525 return;
526 }
527
528 RS_TRACE_NAME("Profiler OnRenderEnd");
529 g_renderServiceCpuId = Utils::GetCpuId();
530 }
531
OnParallelRenderBegin()532 void RSProfiler::OnParallelRenderBegin()
533 {
534 if (!IsEnabled()) {
535 return;
536 }
537
538 if (g_calcPerfNode > 0) {
539 // force render thread to be on fastest CPU
540 constexpr uint32_t spamCount = 10'000;
541 std::vector<int> data;
542 data.resize(spamCount);
543 for (uint32_t i = 0; i < spamCount; i++) {
544 for (uint32_t j = i + 1; j < spamCount; j++) {
545 std::swap(data[i], data[j]);
546 }
547 }
548
549 constexpr uint32_t trashCashStep = 64;
550 constexpr uint32_t newCount = spamCount * trashCashStep;
551 constexpr int trashNum = 0x7F;
552 data.resize(newCount);
553 for (uint32_t i = 0; i < spamCount; i++) {
554 data[i * trashCashStep] = trashNum;
555 }
556 }
557
558 g_frameRenderBeginTimestamp = RawNowNano();
559 }
560
OnParallelRenderEnd(uint32_t frameNumber)561 void RSProfiler::OnParallelRenderEnd(uint32_t frameNumber)
562 {
563 g_renderServiceRenderCpuId = Utils::GetCpuId();
564 const uint64_t frameLengthNanosecs = RawNowNano() - g_frameRenderBeginTimestamp;
565 CalcNodeWeigthOnFrameEnd(frameLengthNanosecs);
566
567 if (!IsRecording()) {
568 return;
569 }
570
571 const double currentTime = Utils::ToSeconds(g_frameRenderBeginTimestamp);
572 const double timeSinceRecordStart = currentTime - g_recordStartTime;
573
574 if (timeSinceRecordStart > 0.0) {
575 RSCaptureData captureData;
576 captureData.SetTime(timeSinceRecordStart);
577 captureData.SetProperty(RSCaptureData::KEY_RENDER_FRAME_NUMBER, frameNumber);
578 captureData.SetProperty(RSCaptureData::KEY_RENDER_FRAME_LEN, frameLengthNanosecs);
579
580 std::vector<char> out;
581 DataWriter archive(out);
582 char headerType = static_cast<char>(PackageID::RS_PROFILER_RENDER_METRICS);
583 archive.Serialize(headerType);
584 captureData.Serialize(archive);
585
586 Network::SendBinary(out.data(), out.size());
587 g_recordFile.WriteRenderMetrics(0, timeSinceRecordStart, out.data(), out.size());
588 }
589 }
590
ShouldBlockHWCNode()591 bool RSProfiler::ShouldBlockHWCNode()
592 {
593 return IsEnabled() && IsReadMode();
594 }
595
OnFrameBegin(uint64_t syncTime)596 void RSProfiler::OnFrameBegin(uint64_t syncTime)
597 {
598 if (!IsEnabled()) {
599 return;
600 }
601
602 RS_TRACE_NAME("Profiler OnFrameBegin");
603 g_frameSyncTimestamp = syncTime;
604 g_frameBeginTimestamp = RawNowNano();
605 g_renderServiceCpuId = Utils::GetCpuId();
606 g_frameNumber++;
607
608 LogEventVSync(syncTime);
609
610 BetaRecordOnFrameBegin();
611 StartBetaRecord();
612 }
613
ProcessPauseMessage()614 void RSProfiler::ProcessPauseMessage()
615 {
616 if (!IsPlaying()) {
617 return;
618 }
619
620 uint64_t pauseAtTime = TimePauseGet();
621 uint64_t nowTime = RawNowNano();
622 if (pauseAtTime > 0 && nowTime > pauseAtTime) {
623 const double deltaTime = PlaybackDeltaTime();
624 if (deltaTime > g_replayLastPauseTimeReported) {
625 int64_t vsyncId = g_playbackFile.ConvertTime2VsyncId(deltaTime);
626 if (vsyncId) {
627 SendMessage("Replay timer paused vsyncId=%" PRId64, vsyncId); // DO NOT TOUCH!
628 }
629 g_replayLastPauseTimeReported = deltaTime;
630 }
631 }
632 }
633
OnFrameEnd()634 void RSProfiler::OnFrameEnd()
635 {
636 if (!IsEnabled()) {
637 return;
638 }
639
640 RS_TRACE_NAME("Profiler OnFrameEnd");
641 g_renderServiceCpuId = Utils::GetCpuId();
642 RecordUpdate();
643
644 UpdateDirtyRegionBetaRecord(g_dirtyRegionPercentage);
645 if (context_) {
646 UpdateBetaRecord(*context_);
647 }
648 BlinkNodeUpdate();
649 CalcPerfNodeUpdate();
650
651 ProcessPauseMessage();
652
653 g_renderServiceCpuId = Utils::GetCpuId();
654
655 constexpr int maxMsgPerFrame = 32;
656 std::string msg_value = ReceiveMessageBase();
657 for (int i = 0; msg_value != "" && i < maxMsgPerFrame; msg_value = ReceiveMessageBase(), i++) {
658 if (!msg_value.length()) {
659 break;
660 }
661 Network::SendMessage(msg_value);
662 }
663
664 if (IsRecordingMode()) {
665 RSProfilerLogMsg log_value = ReceiveRSLogBase();
666 for (int i = 0; log_value.time_ && i < maxMsgPerFrame; log_value = ReceiveRSLogBase(), i++) {
667 if (!log_value.msg_.length()) {
668 break;
669 }
670 LogEventMsg(log_value.time_, log_value.type_, log_value.msg_);
671 }
672 }
673
674 BetaRecordOnFrameEnd();
675 }
676
CalcNodeWeigthOnFrameEnd(uint64_t frameLength)677 void RSProfiler::CalcNodeWeigthOnFrameEnd(uint64_t frameLength)
678 {
679 if (g_calcPerfNode == 0) {
680 return;
681 }
682
683 g_calcPerfNodeTime[g_calcPerfNodeTry] = frameLength;
684 g_calcPerfNodeTry++;
685 if (g_calcPerfNodeTry < g_effectiveNodeTimeCount) {
686 AwakeRenderServiceThread();
687 return;
688 }
689
690 std::sort(g_calcPerfNodeTime, g_calcPerfNodeTime + g_effectiveNodeTimeCount);
691
692 const uint16_t startCnt = g_effectiveNodeTimeCount / 4;
693 const uint16_t endCnt = g_effectiveNodeTimeCount - startCnt;
694 uint64_t avgValue = 0;
695 for (auto i = startCnt; i < endCnt; i++) {
696 avgValue += g_calcPerfNodeTime[i];
697 }
698 avgValue /= endCnt - startCnt;
699
700 if (g_calcPerfNodeExcludeDown) {
701 g_mapNode2UpTime[g_calcPerfNode] = avgValue;
702 } else {
703 g_mapNode2UpDownTime[g_calcPerfNode] = avgValue;
704 }
705
706 constexpr float nanoToMs = 1000'000.0f;
707
708 if (g_calcPerfNodeExcludeDown) {
709 Respond("CALC_PERF_NODE_RESULT: U->" + std::to_string(g_calcPerfNode) + " " + std::to_string(avgValue) +
710 " inMS=" + std::to_string(avgValue / nanoToMs) + " tries=" + std::to_string(g_effectiveNodeTimeCount));
711 } else {
712 Respond("CALC_PERF_NODE_RESULT: UD->" + std::to_string(g_calcPerfNode) + " " + std::to_string(avgValue) +
713 " inMS=" + std::to_string(avgValue / nanoToMs) + " tries=" + std::to_string(g_effectiveNodeTimeCount));
714 }
715
716 g_calcPerfNode = 0;
717
718 AwakeRenderServiceThread();
719 g_renderServiceCpuId = Utils::GetCpuId();
720 }
721
RenderServiceTreeDump(JsonWriter & out,pid_t pid)722 void RSProfiler::RenderServiceTreeDump(JsonWriter& out, pid_t pid)
723 {
724 RS_TRACE_NAME("GetDumpTreeJSON");
725
726 if (!context_) {
727 return;
728 }
729
730 const bool useMockPid = (pid > 0) && IsReadMode();
731 if (useMockPid) {
732 pid = Utils::GetMockPid(pid);
733 }
734
735 auto& animation = out["Animation Node"];
736 animation.PushArray();
737 for (auto& [nodeId, _] : context_->animatingNodeList_) {
738 if (!pid) {
739 animation.Append(nodeId);
740 } else if (pid == Utils::ExtractPid(nodeId)) {
741 animation.Append(nodeId);
742 }
743 }
744 animation.PopArray();
745
746 auto rootNode = context_->GetGlobalRootRenderNode();
747 if (pid) {
748 rootNode = nullptr;
749 auto& nodeMap = RSMainThread::Instance()->GetContext().GetMutableNodeMap();
750 nodeMap.TraversalNodes([&rootNode, pid](const std::shared_ptr<RSBaseRenderNode>& node) {
751 if (!node || !node->GetSortedChildren()) {
752 return;
753 }
754 auto parentPtr = node->GetParent().lock();
755 if (parentPtr != nullptr && !rootNode &&
756 Utils::ExtractPid(node->GetId()) != Utils::ExtractPid(parentPtr->GetId()) &&
757 Utils::ExtractPid(node->GetId()) == pid && node->GetSortedChildren()->size() > 0) {
758 rootNode = node;
759 Respond("Root node found: " + std::to_string(rootNode->GetId()));
760 }
761 });
762 }
763
764 auto& root = out["Root node"];
765 if (rootNode) {
766 DumpNode(*rootNode, root, useMockPid, pid > 0);
767 } else {
768 Respond("rootNode not found");
769 root.PushObject();
770 root.PopObject();
771 }
772
773 if (context_) {
774 auto& rootOffscreen = out["Offscreen node"];
775 DumpOffscreen(*context_, rootOffscreen, useMockPid, pid);
776 }
777 }
778
RawNowNano()779 uint64_t RSProfiler::RawNowNano()
780 {
781 return Utils::Now();
782 }
783
NowNano()784 uint64_t RSProfiler::NowNano()
785 {
786 return PatchTime(RawNowNano());
787 }
788
Now()789 double RSProfiler::Now()
790 {
791 return Utils::ToSeconds(NowNano());
792 }
793
IsRecording()794 bool RSProfiler::IsRecording()
795 {
796 return IsEnabled() && IsWriteMode() && g_recordFile.IsOpen() && (g_recordStartTime > 0);
797 }
798
IsPlaying()799 bool RSProfiler::IsPlaying()
800 {
801 return IsEnabled() && IsReadMode() && g_playbackFile.IsOpen() && !g_playbackShouldBeTerminated;
802 }
803
ScheduleTask(std::function<void ()> && task)804 void RSProfiler::ScheduleTask(std::function<void()> && task)
805 {
806 if (g_mainThread) {
807 g_mainThread->PostTask(std::move(task));
808 }
809 }
810
RequestNextVSync()811 void RSProfiler::RequestNextVSync()
812 {
813 if (g_mainThread) {
814 g_mainThread->RequestNextVSync();
815 }
816 ScheduleTask([]() { g_mainThread->RequestNextVSync(); });
817 }
818
AwakeRenderServiceThread()819 void RSProfiler::AwakeRenderServiceThread()
820 {
821 if (g_mainThread) {
822 g_mainThread->RequestNextVSync();
823 g_mainThread->SetAccessibilityConfigChanged();
824 g_mainThread->SetDirtyFlag();
825 }
826 ScheduleTask([]() {
827 g_mainThread->SetAccessibilityConfigChanged();
828 g_mainThread->SetDirtyFlag();
829 g_mainThread->RequestNextVSync();
830 });
831 }
832
ResetAnimationStamp()833 void RSProfiler::ResetAnimationStamp()
834 {
835 if (g_mainThread && context_) {
836 g_mainThread->lastAnimateTimestamp_ = context_->GetCurrentTimestamp();
837 }
838 }
839
GetRenderNode(uint64_t id)840 std::shared_ptr<RSRenderNode> RSProfiler::GetRenderNode(uint64_t id)
841 {
842 return context_ ? context_->GetMutableNodeMap().GetRenderNode(id) : nullptr;
843 }
844
IsLoadSaveFirstScreenInProgress()845 bool RSProfiler::IsLoadSaveFirstScreenInProgress()
846 {
847 return IsWriteEmulationMode() || IsReadEmulationMode();
848 }
849
FirstFrameMarshalling(uint32_t fileVersion)850 std::string RSProfiler::FirstFrameMarshalling(uint32_t fileVersion)
851 {
852 if (!context_) {
853 return "";
854 }
855
856 RS_TRACE_NAME("Profiler FirstFrameMarshalling");
857 std::stringstream stream;
858 stream.exceptions(0); // 0: disable all exceptions for stringstream
859 TypefaceMarshalling(stream, fileVersion);
860 if (!stream.good()) {
861 HRPD("strstream error with typeface marshalling");
862 }
863
864 SetMode(Mode::WRITE_EMUL);
865 DisableSharedMemory();
866 MarshalNodes(*context_, stream, fileVersion);
867 if (!stream.good()) {
868 HRPD("strstream error with marshalling nodes");
869 }
870 EnableSharedMemory();
871 SetMode(Mode::NONE);
872
873 const int32_t focusPid = g_mainThread->focusAppPid_;
874 stream.write(reinterpret_cast<const char*>(&focusPid), sizeof(focusPid));
875
876 const int32_t focusUid = g_mainThread->focusAppUid_;
877 stream.write(reinterpret_cast<const char*>(&focusUid), sizeof(focusUid));
878
879 const uint64_t focusNodeId = g_mainThread->focusNodeId_;
880 stream.write(reinterpret_cast<const char*>(&focusNodeId), sizeof(focusNodeId));
881
882 const std::string bundleName = g_mainThread->focusAppBundleName_;
883 size_t size = bundleName.size();
884 stream.write(reinterpret_cast<const char*>(&size), sizeof(size));
885 stream.write(reinterpret_cast<const char*>(bundleName.data()), size);
886
887 const std::string abilityName = g_mainThread->focusAppAbilityName_;
888 size = abilityName.size();
889 stream.write(reinterpret_cast<const char*>(&size), sizeof(size));
890 stream.write(reinterpret_cast<const char*>(abilityName.data()), size);
891
892 if (!stream.good()) {
893 HRPE("error with stringstream in FirstFrameMarshalling");
894 }
895 return stream.str();
896 }
897
FirstFrameUnmarshalling(const std::string & data,uint32_t fileVersion)898 std::string RSProfiler::FirstFrameUnmarshalling(const std::string& data, uint32_t fileVersion)
899 {
900 std::stringstream stream;
901 std::string errReason;
902
903 stream.str(data);
904
905 errReason = TypefaceUnmarshalling(stream, fileVersion);
906 if (errReason.size()) {
907 return errReason;
908 }
909
910 SetMode(Mode::READ_EMUL);
911
912 DisableSharedMemory();
913 errReason = UnmarshalNodes(*context_, stream, fileVersion);
914 EnableSharedMemory();
915
916 SetMode(Mode::NONE);
917
918 if (errReason.size()) {
919 return errReason;
920 }
921
922 int32_t focusPid = 0;
923 stream.read(reinterpret_cast<char*>(&focusPid), sizeof(focusPid));
924
925 int32_t focusUid = 0;
926 stream.read(reinterpret_cast<char*>(&focusUid), sizeof(focusUid));
927
928 uint64_t focusNodeId = 0;
929 stream.read(reinterpret_cast<char*>(&focusNodeId), sizeof(focusNodeId));
930
931 constexpr size_t nameSizeMax = 4096;
932 size_t size = 0;
933 stream.read(reinterpret_cast<char*>(&size), sizeof(size));
934 if (size > nameSizeMax) {
935 return "FirstFrameUnmarshalling failed, file is damaged";
936 }
937 std::string bundleName;
938 bundleName.resize(size, ' ');
939 stream.read(reinterpret_cast<char*>(bundleName.data()), size);
940
941 stream.read(reinterpret_cast<char*>(&size), sizeof(size));
942 if (size > nameSizeMax) {
943 return "FirstFrameUnmarshalling failed, file is damaged";
944 }
945
946 std::string abilityName;
947 abilityName.resize(size, ' ');
948 stream.read(reinterpret_cast<char*>(abilityName.data()), size);
949
950 focusPid = Utils::GetMockPid(focusPid);
951 focusNodeId = Utils::PatchNodeId(focusNodeId);
952
953 CreateMockConnection(focusPid);
954 FocusAppInfo info = {
955 .pid = focusPid,
956 .uid = focusUid,
957 .bundleName = bundleName,
958 .abilityName = abilityName,
959 .focusNodeId = focusNodeId};
960 g_mainThread->SetFocusAppInfo(info);
961
962 return "";
963 }
964
TypefaceMarshalling(std::stringstream & stream,uint32_t fileVersion)965 void RSProfiler::TypefaceMarshalling(std::stringstream& stream, uint32_t fileVersion)
966 {
967 if (fileVersion >= RSFILE_VERSION_RENDER_TYPEFACE_FIX) {
968 std::stringstream fontStream;
969 RSTypefaceCache::Instance().ReplaySerialize(fontStream);
970 size_t fontStreamSize = fontStream.str().size();
971 stream.write(reinterpret_cast<const char*>(&fontStreamSize), sizeof(fontStreamSize));
972 stream.write(reinterpret_cast<const char*>(fontStream.str().c_str()), fontStreamSize);
973 }
974 }
975
TypefaceUnmarshalling(std::stringstream & stream,uint32_t fileVersion)976 std::string RSProfiler::TypefaceUnmarshalling(std::stringstream& stream, uint32_t fileVersion)
977 {
978 if (fileVersion >= RSFILE_VERSION_RENDER_TYPEFACE_FIX) {
979 std::vector<uint8_t> fontData;
980 std::stringstream fontStream;
981 size_t fontStreamSize;
982 constexpr size_t fontStreamSizeMax = 100'000'000;
983
984 stream.read(reinterpret_cast<char*>(&fontStreamSize), sizeof(fontStreamSize));
985 if (fontStreamSize > fontStreamSizeMax) {
986 return "Typeface track is damaged";
987 }
988 fontData.resize(fontStreamSize);
989 stream.read(reinterpret_cast<char*>(fontData.data()), fontData.size());
990 fontStream.write(reinterpret_cast<const char*>(fontData.data()), fontData.size());
991 return RSTypefaceCache::Instance().ReplayDeserialize(fontStream);
992 }
993 return "";
994 }
995
HiddenSpaceTurnOn()996 void RSProfiler::HiddenSpaceTurnOn()
997 {
998 if (!g_childOfDisplayNodes.empty()) {
999 HiddenSpaceTurnOff();
1000 }
1001
1002 auto logicalDisplayNode = GetLogicalDisplay();
1003 if (logicalDisplayNode == nullptr) {
1004 HRPE("RSProfiler::HiddenSpaceTurnOn Logical Display is nullptr");
1005 return;
1006 }
1007
1008 if (auto rootNode = GetRenderNode(Utils::PatchNodeId(0))) {
1009 g_childOfDisplayNodes = *logicalDisplayNode->GetChildren();
1010
1011 logicalDisplayNode->ClearChildren();
1012 logicalDisplayNode->AddChild(rootNode);
1013 }
1014
1015 g_mainThread->SetDirtyFlag();
1016 AwakeRenderServiceThread();
1017 }
1018
GetLogicalDisplay()1019 std::shared_ptr<RSRenderNode> RSProfiler::GetLogicalDisplay()
1020 {
1021 const auto& rootRenderNode = context_->GetGlobalRootRenderNode();
1022 if (rootRenderNode == nullptr) {
1023 return nullptr;
1024 }
1025
1026 const auto& children = *rootRenderNode->GetChildren();
1027 if (children.empty()) {
1028 return nullptr;
1029 }
1030 for (const auto& screenNode : children) { // apply multiple screen nodes
1031 if (!screenNode) {
1032 continue;
1033 }
1034 const auto& screenNodeChildren = screenNode->GetChildren();
1035 if (screenNodeChildren->empty()) {
1036 continue;
1037 }
1038 return screenNodeChildren->front(); // return display node
1039 }
1040 return nullptr;
1041 }
1042
HiddenSpaceTurnOff()1043 void RSProfiler::HiddenSpaceTurnOff()
1044 {
1045 auto logicalDisplayNode = GetLogicalDisplay();
1046 if (logicalDisplayNode == nullptr) {
1047 HRPE("RSProfiler::HiddenSpaceTurnOff Logical Display is nullptr");
1048 return;
1049 }
1050
1051 logicalDisplayNode->ClearChildren();
1052 for (const auto& child : g_childOfDisplayNodes) {
1053 logicalDisplayNode->AddChild(child);
1054 }
1055 auto& listPostponed = RSProfiler::GetChildOfDisplayNodesPostponed();
1056 for (const auto& childWeak : listPostponed) {
1057 if (auto child = childWeak.lock()) {
1058 logicalDisplayNode->AddChild(child);
1059 }
1060 }
1061 listPostponed.clear();
1062 FilterMockNode(*context_);
1063 RSTypefaceCache::Instance().ReplayClear();
1064 g_childOfDisplayNodes.clear();
1065
1066 g_mainThread->SetDirtyFlag();
1067
1068 AwakeRenderServiceThread();
1069 }
1070
SaveRdc(const ArgList & args)1071 void RSProfiler::SaveRdc(const ArgList& args)
1072 {
1073 g_rdcSent = false;
1074 RSSystemProperties::SetSaveRDC(true);
1075 RSSystemProperties::SetInstantRecording(true);
1076
1077 AwakeRenderServiceThread();
1078 Respond("Recording current frame cmds (for .rdc) into : /data/default.drawing");
1079 }
1080
ProcessSendingRdc()1081 void RSProfiler::ProcessSendingRdc()
1082 {
1083 if (!RSSystemProperties::GetSaveRDC() || g_rdcSent) {
1084 return;
1085 }
1086 AwakeRenderServiceThread();
1087
1088 if (!RSCaptureRecorder::PullAndSendRdc()) {
1089 return;
1090 }
1091 RSSystemProperties::SetSaveRDC(false);
1092 g_rdcSent = true;
1093 }
1094
GetImagesAdded()1095 static uint32_t GetImagesAdded()
1096 {
1097 const size_t count = ImageCache::Size();
1098 const uint32_t added = count - g_lastCacheImageCount;
1099 g_lastCacheImageCount = count;
1100 return added;
1101 }
1102
WriteRSMetricsToRecordFile(double timeSinceRecordStart,double syncTime,uint64_t frameLen)1103 void RSProfiler::WriteRSMetricsToRecordFile(double timeSinceRecordStart, double syncTime, uint64_t frameLen)
1104 {
1105 RSCaptureData captureData;
1106 captureData.SetTime(timeSinceRecordStart);
1107 captureData.SetProperty(RSCaptureData::KEY_RS_FRAME_NUMBER, g_frameNumber);
1108 captureData.SetProperty(RSCaptureData::KEY_RS_SYNC_TIME, syncTime);
1109 captureData.SetProperty(RSCaptureData::KEY_RS_FRAME_LEN, frameLen);
1110 captureData.SetProperty(RSCaptureData::KEY_RS_CMD_COUNT, GetCommandCount());
1111 captureData.SetProperty(RSCaptureData::KEY_RS_CMD_EXECUTE_COUNT, GetCommandExecuteCount());
1112 captureData.SetProperty(RSCaptureData::KEY_RS_PARCEL_CMD_LIST, GetParcelCommandList());
1113 captureData.SetProperty(RSCaptureData::KEY_RS_PIXEL_IMAGE_ADDED, GetImagesAdded());
1114 captureData.SetProperty(RSCaptureData::KEY_RS_DIRTY_REGION, floor(g_dirtyRegionPercentage));
1115 captureData.SetProperty(RSCaptureData::KEY_RS_DIRTY_REGION_LIST, g_dirtyRegionList.str());
1116 captureData.SetProperty(RSCaptureData::KEY_RS_CPU_ID, g_renderServiceCpuId.load());
1117 uint64_t vsyncId = g_mainThread ? g_mainThread->vsyncId_ : 0;
1118 captureData.SetProperty(RSCaptureData::KEY_RS_VSYNC_ID, vsyncId);
1119
1120 if (!g_recordMinVsync) {
1121 g_recordMinVsync = vsyncId;
1122 }
1123 if (g_recordMaxVsync < vsyncId) {
1124 g_recordMaxVsync = vsyncId;
1125 }
1126
1127 auto& customMetrics = GetCustomMetrics();
1128 float displayAreaToPercent = 100.f / static_cast<float>(GetDisplayArea());
1129 customMetrics.MultiplyFloat(RSPROFILER_METRIC_BLUR_AREA_OPERATIONS, displayAreaToPercent);
1130 customMetrics.MultiplyFloat(RSPROFILER_METRIC_BLUR_AREA_SHADER_CALLS, displayAreaToPercent);
1131 customMetrics.MultiplyFloat(RSPROFILER_METRIC_ANIMATION_NODE_SIZE, displayAreaToPercent);
1132
1133 for (size_t i = 0; i < customMetrics.GetCount(); i++) {
1134 RsMetricSet(std::to_string(i + 1) + "m", customMetrics.Get(i));
1135 }
1136
1137 ResetCustomMetrics();
1138
1139 // update general metrics
1140 for (const auto& metric : g_recordRsMetric) {
1141 captureData.SetProperty(metric.first, metric.second);
1142 }
1143 RsMetricClear();
1144
1145 std::vector<char> out;
1146 DataWriter archive(out);
1147 char headerType = static_cast<char>(PackageID::RS_PROFILER_RS_METRICS);
1148 archive.Serialize(headerType);
1149 captureData.Serialize(archive);
1150
1151 Network::SendBinary(out.data(), out.size());
1152 g_recordFile.WriteRSMetrics(0, timeSinceRecordStart, out.data(), out.size());
1153 }
1154
RecordUpdate()1155 void RSProfiler::RecordUpdate()
1156 {
1157 if (!IsRecording()) {
1158 return;
1159 }
1160
1161 if (IsRecordAbortRequested()) {
1162 recordAbortRequested_ = false;
1163 SendMessage("Record: Exceeded memory limit. Abort"); // DO NOT TOUCH!
1164 RecordStop(ArgList {});
1165 return;
1166 }
1167
1168 const uint64_t frameLengthNanosecs = RawNowNano() - g_frameBeginTimestamp;
1169
1170 const double currentTime = Utils::ToSeconds(g_frameBeginTimestamp);
1171 const double timeSinceRecordStart = currentTime - g_recordStartTime;
1172 const uint64_t recordStartTimeNano = Utils::ToNanoseconds(g_recordStartTime);
1173 double timeSinceRecordStartToSync = Utils::ToSeconds(g_frameSyncTimestamp - recordStartTimeNano);
1174 if (g_frameSyncTimestamp < recordStartTimeNano) {
1175 timeSinceRecordStartToSync = -Utils::ToSeconds(recordStartTimeNano - g_frameSyncTimestamp);
1176 }
1177
1178 if (timeSinceRecordStart > 0.0) {
1179 WriteRSMetricsToRecordFile(timeSinceRecordStart, timeSinceRecordStartToSync, frameLengthNanosecs);
1180 }
1181
1182 WriteBetaRecordMetrics(g_recordFile, timeSinceRecordStart);
1183 }
1184
RecordSave()1185 void RSProfiler::RecordSave()
1186 {
1187 SendMessage("Record: Prepping data for sending...");
1188
1189 std::stringstream stream(std::ios::in | std::ios::out | std::ios::binary);
1190 // DOUBLE WORK - send header of file
1191 const char headerType = 0;
1192 stream.write(reinterpret_cast<const char*>(&headerType), sizeof(headerType));
1193 stream.write(reinterpret_cast<const char*>(&g_recordStartTime), sizeof(g_recordStartTime));
1194
1195 const uint32_t pidCount = g_recordFile.GetHeaderPids().size();
1196 stream.write(reinterpret_cast<const char*>(&pidCount), sizeof(pidCount));
1197 for (auto item : g_recordFile.GetHeaderPids()) {
1198 stream.write(reinterpret_cast<const char*>(&item), sizeof(item));
1199 }
1200
1201 // FIRST FRAME HEADER
1202 const uint32_t sizeFirstFrame = static_cast<uint32_t>(g_recordFile.GetHeaderFirstFrame().size());
1203 stream.write(reinterpret_cast<const char*>(&sizeFirstFrame), sizeof(sizeFirstFrame));
1204 stream.write(reinterpret_cast<const char*>(&g_recordFile.GetHeaderFirstFrame()[0]), sizeFirstFrame);
1205
1206 // ANIME START TIMES
1207 const auto headerAnimeStartTimes = AnimeGetStartTimesFlattened(g_recordStartTime);
1208
1209 const uint32_t startTimesSize = headerAnimeStartTimes.size();
1210 stream.write(reinterpret_cast<const char*>(&startTimesSize), sizeof(startTimesSize));
1211 stream.write(reinterpret_cast<const char*>(headerAnimeStartTimes.data()),
1212 startTimesSize * sizeof(std::pair<uint64_t, int64_t>));
1213
1214 const auto imageCacheConsumption = ImageCache::Consumption();
1215 SendMessage("Record: Image cache memory usage: %.2fMB (%zu)", Utils::Megabytes(imageCacheConsumption),
1216 imageCacheConsumption);
1217 ImageCache::Serialize(stream);
1218
1219 const auto binary = stream.str();
1220 Network::SendBinary(binary);
1221
1222 SendMessage("Record: Sent: %.2fMB (%zu)", Utils::Megabytes(binary.size()), binary.size());
1223 }
1224
1225 // Deprecated: Use SendMessage instead
Respond(const std::string & message)1226 void RSProfiler::Respond(const std::string& message)
1227 {
1228 Network::SendMessage(message);
1229 }
1230
SendMessage(const char * format,...)1231 void RSProfiler::SendMessage(const char* format, ...)
1232 {
1233 if (!format) {
1234 return;
1235 }
1236
1237 va_list args;
1238 va_start(args, format);
1239 const auto out = Utils::Format(format, args);
1240 va_end(args);
1241
1242 Network::SendMessage(out);
1243 }
1244
DumpConnections(const ArgList & args)1245 void RSProfiler::DumpConnections(const ArgList& args)
1246 {
1247 if (!g_renderService) {
1248 return;
1249 }
1250
1251 std::string out;
1252 for (const auto& pid : GetConnectionsPids()) {
1253 out += "pid=" + std::to_string(pid);
1254
1255 const std::string path = "/proc/" + std::to_string(pid) + "/cmdline";
1256 FILE* file = Utils::FileOpen(path, "r");
1257 if (const size_t size = Utils::FileSize(file)) {
1258 std::string content;
1259 content.resize(size);
1260 Utils::FileRead(file, content.data(), content.size());
1261 Utils::FileClose(file);
1262 out += " ";
1263 out += content;
1264 }
1265 if (Utils::IsFileValid(file)) {
1266 Utils::FileClose(file);
1267 }
1268 out += "\n";
1269 }
1270 Respond(out);
1271 }
1272
DumpDrawingCanvasNodes(const ArgList & args)1273 void RSProfiler::DumpDrawingCanvasNodes(const ArgList& args)
1274 {
1275 if (!context_) {
1276 return;
1277 }
1278 const auto& map = const_cast<RSContext&>(*context_).GetMutableNodeMap();
1279 for (const auto& [_, subMap] : map.renderNodeMap_) {
1280 for (const auto& [_, node] : subMap) {
1281 if (node->GetType() == RSRenderNodeType::CANVAS_DRAWING_NODE) {
1282 Respond("CANVAS_DRAWING_NODE: " + std::to_string(node->GetId()));
1283 }
1284 }
1285 }
1286 }
1287
GetDisplayArea()1288 uint64_t RSProfiler::GetDisplayArea()
1289 {
1290 if (!context_) {
1291 return 1;
1292 }
1293 std::shared_ptr<RSScreenRenderNode> displayNode = GetScreenNode(*context_);
1294 if (!displayNode) {
1295 return 1;
1296 }
1297
1298 auto params = static_cast<RSScreenRenderParams*>(displayNode->GetRenderParams().get());
1299 if (!params) {
1300 return 1;
1301 }
1302 auto screenInfo = params->GetScreenInfo();
1303 return static_cast<uint64_t>(screenInfo.width * screenInfo.height);
1304 }
1305
PlaybackSetImmediate(const ArgList & args)1306 void RSProfiler::PlaybackSetImmediate(const ArgList& args)
1307 {
1308 g_playbackImmediate = args.Int64(0) ? true : false;
1309 Respond("Playback immediate mode: " + std::to_string(g_playbackImmediate));
1310 }
1311
DumpTree(const ArgList & args)1312 void RSProfiler::DumpTree(const ArgList& args)
1313 {
1314 if (!context_) {
1315 return;
1316 }
1317
1318 std::map<std::string, std::tuple<NodeId, std::string>> list;
1319 GetSurfacesTrees(*context_, list);
1320
1321 std::string out = "Tree: count=" + std::to_string(static_cast<int>(GetRenderNodeCount(*context_))) +
1322 " time=" + std::to_string(Now()) + "\n";
1323
1324 const std::string& node = args.String();
1325 for (const auto& item : list) {
1326 if (std::strstr(item.first.data(), node.data())) {
1327 out += "*** " + item.first + " pid=" + std::to_string(ExtractPid(std::get<0>(item.second))) +
1328 " lowId=" + std::to_string(Utils::ExtractNodeId(std::get<0>(item.second))) + "\n" +
1329 std::get<1>(item.second) + "\n";
1330 }
1331 }
1332
1333 Respond(out);
1334 }
1335
DumpTreeToJson(const ArgList & args)1336 void RSProfiler::DumpTreeToJson(const ArgList& args)
1337 {
1338 if (!context_ || !g_mainThread) {
1339 return;
1340 }
1341
1342 JsonWriter json;
1343 json.PushObject();
1344 pid_t pid = args.Pid();
1345 RenderServiceTreeDump(json, pid);
1346
1347 auto& display = json["Display"];
1348 auto screenNode = GetScreenNode(*context_);
1349 auto dirtyManager = screenNode ? screenNode->GetDirtyManager() : nullptr;
1350 if (dirtyManager) {
1351 const auto displayRect = dirtyManager->GetSurfaceRect();
1352 display = { displayRect.GetLeft(), displayRect.GetTop(), displayRect.GetRight(), displayRect.GetBottom() };
1353 } else {
1354 display = { 0.0f, 0.0f, 0.0f, 0.0f };
1355 }
1356
1357 json["transactionFlags"] = g_mainThread->transactionFlags_;
1358 json["timestamp"] = g_mainThread->timestamp_;
1359 json["vsyncID"] = g_mainThread->vsyncId_;
1360
1361 json.PopObject();
1362 Network::SendRSTreeDumpJSON(json.GetDumpString());
1363
1364 if (args.String() != "NOLOG") {
1365 Network::SendMessage(json.GetDumpString());
1366 }
1367 }
1368
1369
DumpNodeSurface(const ArgList & args)1370 void RSProfiler::DumpNodeSurface(const ArgList& args)
1371 {
1372 if (g_renderService) {
1373 std::string out;
1374 g_renderService->DumpSurfaceNode(out, Utils::GetRootNodeId(args.Node()));
1375 Respond(out);
1376 }
1377 }
1378
PatchNode(const ArgList & args)1379 void RSProfiler::PatchNode(const ArgList& args)
1380 {
1381 const auto node = GetRenderNode(args.Node());
1382 if (!node) {
1383 return;
1384 }
1385
1386 const Vector4f screenRect = GetScreenRect(*context_);
1387
1388 auto surfaceNode = static_cast<RSSurfaceRenderNode*>(node.get());
1389 {
1390 auto& region = const_cast<Occlusion::Region&>(surfaceNode->GetVisibleRegion());
1391 region = Occlusion::Region({ screenRect[0], screenRect[1], screenRect[2], screenRect[3] }); // NOLINT
1392 }
1393
1394 RSProperties& properties = node->GetMutableRenderProperties();
1395 properties.SetBounds(screenRect);
1396 properties.SetFrame(screenRect);
1397 properties.SetDrawRegion(std::make_shared<RectF>(screenRect));
1398
1399 AwakeRenderServiceThread();
1400 }
1401
1402
BlinkNode(const ArgList & args)1403 void RSProfiler::BlinkNode(const ArgList& args)
1404 {
1405 if (const auto node = GetRenderNode(args.Node())) {
1406 const auto parent = node->GetParent().lock();
1407 auto parentChildren = parent ? parent->GetChildren() : nullptr;
1408 if (!parentChildren) {
1409 return;
1410 }
1411
1412 g_blinkNodeId = args.Node();
1413 g_blinkNodeCount = 0;
1414
1415 g_blinkSavedParentChildren.clear();
1416 g_blinkSavedParentChildren.push_back(parent);
1417
1418 for (const auto& child : *parentChildren) {
1419 if (child != nullptr) {
1420 g_blinkSavedParentChildren.push_back(child);
1421 }
1422 }
1423
1424 AwakeRenderServiceThread();
1425 Respond("OK");
1426 }
1427 }
1428
KillPid(const ArgList & args)1429 void RSProfiler::KillPid(const ArgList& args)
1430 {
1431 const pid_t pid = args.Pid();
1432 if (const auto node = GetRenderNode(Utils::GetRootNodeId(static_cast<uint64_t>(pid)))) {
1433 const auto parent = node->GetParent().lock();
1434 const std::string out =
1435 "parentPid=" + std::to_string(GetPid(parent)) + " parentNode=" + std::to_string(GetNodeId(parent));
1436
1437 context_->GetMutableNodeMap().FilterNodeByPid(pid, true);
1438 AwakeRenderServiceThread();
1439 Respond(out);
1440 }
1441 }
1442
GetPerfTree(const ArgList & args)1443 void RSProfiler::GetPerfTree(const ArgList& args)
1444 {
1445 if (!context_) {
1446 return;
1447 }
1448
1449 g_nodeListPerf.clear();
1450 g_mapNode2Count.clear();
1451
1452 auto rootNode = GetRenderNode(Utils::PatchNodeId(0));
1453 if (!rootNode) {
1454 Respond("ERROR");
1455 return;
1456 }
1457
1458 PerfTreeFlatten(rootNode, g_nodeListPerf, g_mapNode2Count, 0);
1459
1460 std::string outString;
1461 auto& nodeMap = context_->GetMutableNodeMap();
1462 for (auto it = g_nodeListPerf.begin(); it != g_nodeListPerf.end(); it++) {
1463 auto node = nodeMap.GetRenderNode(it->first);
1464 if (!node) {
1465 continue;
1466 }
1467 std::string sNodeType;
1468 RSRenderNode::DumpNodeType(node->GetType(), sNodeType);
1469 outString += (it != g_nodeListPerf.begin() ? ", " : "") + std::to_string(it->first) + ":" +
1470 std::to_string(g_mapNode2Count[it->first]) + " [" + sNodeType + "]";
1471 }
1472
1473 std::unordered_set<uint64_t> perfNodesSet;
1474 for (const auto& item : g_nodeListPerf) {
1475 perfNodesSet.insert(item.first);
1476 }
1477
1478 Network::SendRSTreePerfNodeList(perfNodesSet);
1479 Respond("OK: Count=" + std::to_string(g_nodeListPerf.size()) + " LIST=[" + outString + "]");
1480 }
1481
CalcPerfNodePrepareLo(const std::shared_ptr<RSRenderNode> & node,bool forceExcludeNode)1482 void RSProfiler::CalcPerfNodePrepareLo(const std::shared_ptr<RSRenderNode>& node, bool forceExcludeNode)
1483 {
1484 if (!node || node->id_ == Utils::PatchNodeId(0)) {
1485 return;
1486 }
1487
1488 const auto parent = node->GetParent().lock();
1489 auto parentChildren = parent ? parent->GetChildren() : nullptr;
1490 if (!parentChildren) {
1491 return;
1492 }
1493
1494 std::vector<std::shared_ptr<RSRenderNode>> childList;
1495 for (const auto& child : *parentChildren) {
1496 if (child != nullptr) {
1497 childList.push_back(child);
1498 }
1499 }
1500
1501 if (forceExcludeNode) {
1502 g_calcPerfSavedChildren.emplace_back(parent, childList);
1503 parent->RemoveChild(node);
1504 node->ResetParent();
1505 } else {
1506 g_calcPerfSavedChildren.clear();
1507 }
1508 }
1509
CalcPerfNodePrepare(NodeId nodeId,uint32_t timeCount,bool excludeDown)1510 void RSProfiler::CalcPerfNodePrepare(NodeId nodeId, uint32_t timeCount, bool excludeDown)
1511 {
1512 g_calcPerfNode = nodeId;
1513 g_effectiveNodeTimeCount = timeCount;
1514 g_calcPerfNodeExcludeDown = excludeDown;
1515 g_calcPerfSavedChildren.clear();
1516
1517 auto node = GetRenderNode(g_calcPerfNode);
1518 CalcPerfNodePrepareLo(node, excludeDown);
1519 }
1520
DumpParameter(std::string & out,int & usual,const std::string & name,bool value)1521 static void DumpParameter(std::string& out, int& usual, const std::string& name, bool value)
1522 {
1523 out += " " + name + "=" + (value ? "true" : "false");
1524 usual += value ? 0 : 1;
1525 }
1526
PrintNodeCacheLo(const std::shared_ptr<RSRenderNode> & node)1527 void RSProfiler::PrintNodeCacheLo(const std::shared_ptr<RSRenderNode>& node)
1528 {
1529 std::string nodeStr = std::to_string(node->id_) + ": ";
1530 int usual = 0;
1531
1532 const std::string cacheTypes[] = { "CacheType::NONE", "CacheType::DISABLED_CACHE", "CacheType::CONTENT" };
1533 const auto cacheType = static_cast<int>(node->GetCacheType());
1534 nodeStr += "CacheType=" +
1535 (cacheType > static_cast<int>(CacheType::CONTENT) ? std::to_string(cacheType) : cacheTypes[cacheType]);
1536 usual += cacheType == static_cast<int>(CacheType::NONE) ? 1 : 0;
1537
1538 const std::string drawingCacheTypes[] = { "RSDrawingCacheType::DISABLED_CACHE", "RSDrawingCacheType::FORCED_CACHE",
1539 "RSDrawingCacheType::TARGETED_CACHE", "RSDrawingCacheType::FOREGROUND_FILTER_CACHE" };
1540 const int drawingCacheType = node->GetDrawingCacheType();
1541 nodeStr += "DrawingCacheType=" + (drawingCacheType > RSDrawingCacheType::FOREGROUND_FILTER_CACHE
1542 ? std::to_string(drawingCacheType)
1543 : drawingCacheTypes[drawingCacheType]);
1544 usual += (cacheType == RSDrawingCacheType::DISABLED_CACHE) ? 1 : 0;
1545
1546 DumpParameter(nodeStr, usual, "HasCachedTexture", node->HasCachedTexture());
1547 DumpParameter(nodeStr, usual, "DrawInGroup", node->IsSuggestedDrawInGroup());
1548 DumpParameter(nodeStr, usual, "CacheSurfaceValid", node->IsCacheSurfaceValid());
1549 DumpParameter(nodeStr, usual, "CacheCompletedSurfaceValid", node->IsCacheCompletedSurfaceValid());
1550 if (constexpr int usualParamCnt = 6; usual >= usualParamCnt) {
1551 return;
1552 }
1553 Respond(nodeStr);
1554 }
1555
CalcPerfNode(const ArgList & args)1556 void RSProfiler::CalcPerfNode(const ArgList& args)
1557 {
1558 NodeId nodeId = args.Uint64();
1559 uint32_t timeCount = args.Uint32(1);
1560 const bool excludeDown = args.Uint32(2) > 0;
1561
1562 if (timeCount < CALC_PERF_NODE_TIME_COUNT_MIN) {
1563 timeCount = CALC_PERF_NODE_TIME_COUNT_MAX;
1564 }
1565 if (timeCount > CALC_PERF_NODE_TIME_COUNT_MAX) {
1566 timeCount = CALC_PERF_NODE_TIME_COUNT_MAX;
1567 }
1568
1569 Respond("CalcPerfNode: calculating...");
1570
1571 g_nodeListPerf.clear();
1572 g_nodeListPerf.emplace_back(nodeId, 0);
1573 g_mapNode2UpTime.clear();
1574 g_mapNode2UpDownTime.clear();
1575 g_nodeListPerfCalcIndex = 0;
1576 g_effectiveNodeTimeCount = timeCount;
1577 CalcPerfNodeAllStep();
1578 AwakeRenderServiceThread();
1579 }
1580
CalcPerfNodeAll(const ArgList & args)1581 void RSProfiler::CalcPerfNodeAll(const ArgList& args)
1582 {
1583 if (g_nodeListPerf.empty()) {
1584 Respond("ERROR");
1585 return;
1586 }
1587
1588 g_mapNode2UpTime.clear();
1589 g_mapNode2UpDownTime.clear();
1590 g_nodeListPerfCalcIndex = 0;
1591 g_effectiveNodeTimeCount = CALC_PERF_NODE_TIME_COUNT_MIN;
1592 CalcPerfNodeAllStep();
1593 AwakeRenderServiceThread();
1594 }
1595
CalcPerfNodeAllStep()1596 void RSProfiler::CalcPerfNodeAllStep()
1597 {
1598 if (g_nodeListPerfCalcIndex < 0) {
1599 return;
1600 }
1601
1602 const auto doublePerfListSize = static_cast<int32_t>(g_nodeListPerf.size()) * 2;
1603 if (g_nodeListPerfCalcIndex >= doublePerfListSize) {
1604 g_nodeListPerfCalcIndex = -1;
1605
1606 for (auto it : g_nodeListPerf) {
1607 const auto node = GetRenderNode(it.first);
1608 if (!node) {
1609 continue;
1610 }
1611 const auto parent = node->GetParent().lock();
1612 if (!parent || !g_mapNode2UpTime.count(node->id_) || !g_mapNode2UpDownTime.count(node->id_)) {
1613 Respond("CALC_RESULT [" + std::to_string(node->id_) + "] error");
1614 Network::SendRSTreeSingleNodePerf(node->id_, 0);
1615 continue;
1616 }
1617
1618 int64_t ns = (int64_t)g_mapNode2UpDownTime[node->id_] - (int64_t)g_mapNode2UpTime[node->id_];
1619 constexpr float nsToMs = 1000.0f;
1620 double ms = static_cast<double>(ns) / nsToMs;
1621 ms /= nsToMs;
1622
1623 Respond("CALC_RESULT [" + std::to_string(node->id_) + "] time=" + std::to_string(ms));
1624 Network::SendRSTreeSingleNodePerf(node->id_, ms);
1625 }
1626
1627 return;
1628 }
1629
1630 const NodeId nodeId = g_nodeListPerf[g_nodeListPerfCalcIndex / 2].first;
1631 const bool excludeDown = g_nodeListPerfCalcIndex % 2;
1632 CalcPerfNodePrepare(nodeId, g_effectiveNodeTimeCount, excludeDown);
1633 AwakeRenderServiceThread();
1634 }
1635
TestSaveFrame(const ArgList & args)1636 void RSProfiler::TestSaveFrame(const ArgList& args)
1637 {
1638 g_testDataFrame = FirstFrameMarshalling(RSFILE_VERSION_LATEST);
1639 Respond("Save Frame Size: " + std::to_string(g_testDataFrame.size()));
1640 }
1641
TestLoadFrame(const ArgList & args)1642 void RSProfiler::TestLoadFrame(const ArgList& args)
1643 {
1644 FirstFrameUnmarshalling(g_testDataFrame, RSFILE_VERSION_LATEST);
1645 Respond("Load Frame Size: " + std::to_string(g_testDataFrame.size()));
1646 }
1647
TestSwitch(const ArgList & args)1648 void RSProfiler::TestSwitch(const ArgList& args)
1649 {
1650 if (g_childOfDisplayNodes.empty()) {
1651 HiddenSpaceTurnOn();
1652 Respond("OK: HiddenSpaceTurnOn");
1653 } else {
1654 HiddenSpaceTurnOff();
1655 Respond("OK: HiddenSpaceTurnOff");
1656 }
1657 }
1658
BuildTestTree(const ArgList & args)1659 void RSProfiler::BuildTestTree(const ArgList& args)
1660 {
1661 if (!context_ || !g_mainThread) {
1662 return;
1663 }
1664
1665 if (!RSProfiler::testTree_.empty()) {
1666 SendMessage("Test tree already build");
1667 return;
1668 }
1669
1670 const NodeId defaultTopId = 54321000;
1671 NodeId topId = args.Count() == 0 ? defaultTopId : args.Node();
1672 bool withDisplay = args.Count() > 1;
1673
1674 auto testTreeBuilder = TestTreeBuilder();
1675
1676 RSProfiler::testTree_ = testTreeBuilder.Build(*context_, topId, withDisplay);
1677
1678 SendMessage("Build test tree");
1679 }
1680
ClearTestTree(const ArgList & args)1681 void RSProfiler::ClearTestTree(const ArgList& args)
1682 {
1683 for (auto iter = RSProfiler::testTree_.rbegin(); iter != RSProfiler::testTree_.rend(); ++iter) {
1684 (*iter)->RemoveFromTree();
1685 (*iter)->RemoveAllModifiersNG();
1686 }
1687 RSProfiler::testTree_.clear();
1688 SendMessage("Test tree cleared");
1689 }
1690
RecordStart(const ArgList & args)1691 void RSProfiler::RecordStart(const ArgList& args)
1692 {
1693 if (!IsNoneMode() || !g_childOfDisplayNodes.empty()) {
1694 SendMessage("Record: Start failed. Playback/Saving is in progress");
1695 return;
1696 }
1697
1698 g_recordStartTime = 0.0;
1699 g_recordParcelNumber = 0;
1700
1701 MetricRenderNodeInit(context_);
1702 ResetCustomMetrics();
1703
1704 ImageCache::Reset();
1705 g_lastCacheImageCount = 0;
1706
1707 if (!OpenBetaRecordFile(g_recordFile)) {
1708 const auto overridePath = args.String(1);
1709 const auto path = (!overridePath.empty() && args.String(0) == "-f") ? overridePath : RSFile::GetDefaultPath();
1710 g_recordFile.SetVersion(RSFILE_VERSION_LATEST);
1711 g_recordFile.Create(path);
1712 }
1713
1714 g_recordMinVsync = 0;
1715 g_recordMaxVsync = 0;
1716
1717 g_recordFile.AddLayer(); // add 0 layer
1718
1719 FilterMockNode(*context_);
1720 RSTypefaceCache::Instance().ReplayClear();
1721
1722 g_recordFile.AddHeaderFirstFrame(FirstFrameMarshalling(g_recordFile.GetVersion()));
1723
1724 const std::vector<pid_t> pids = GetConnectionsPids();
1725 for (pid_t pid : pids) {
1726 g_recordFile.AddHeaderPid(pid);
1727 }
1728
1729 g_recordFile.LayerAddHeaderProperty(0, "MetricsList", RsMetricGetList());
1730
1731 g_recordStartTime = Now();
1732 g_frameNumber = 0;
1733 SetMode(Mode::WRITE);
1734
1735 SendMessage("Record: Started");
1736
1737 if (IsBetaRecordStarted()) {
1738 return;
1739 }
1740
1741 std::thread thread([]() {
1742 while (IsRecording()) {
1743 SendTelemetry(Now() - g_recordStartTime);
1744 static constexpr int32_t GFX_METRICS_SEND_INTERVAL = 8;
1745 std::this_thread::sleep_for(std::chrono::milliseconds(GFX_METRICS_SEND_INTERVAL));
1746 }
1747 });
1748 thread.detach();
1749
1750 SendMessage("Network: Record start"); // DO NOT TOUCH!
1751 }
1752
RecordStop(const ArgList & args)1753 void RSProfiler::RecordStop(const ArgList& args)
1754 {
1755 if (!IsRecording()) {
1756 SendMessage("Record: Stop failed. Record is not in progress");
1757 return;
1758 }
1759
1760 SetMode(Mode::SAVING);
1761 if (args.String() == "REMOVELAST") {
1762 g_recordFile.UnwriteRSData(); // remove last commands they may start animation with password depiction
1763 g_recordFile.UnwriteRSData();
1764 }
1765
1766 bool isBetaRecordingStarted = IsBetaRecordStarted();
1767 std::thread thread([isBetaRecordingStarted]() {
1768 g_recordFile.SetWriteTime(g_recordStartTime);
1769
1770 if (isBetaRecordingStarted) {
1771 SaveBetaRecordFile(g_recordFile);
1772 } else {
1773 RecordSave();
1774 }
1775
1776 g_recordFile.Close();
1777 g_recordStartTime = 0.0;
1778 g_lastCacheImageCount = 0;
1779
1780 ImageCache::Reset();
1781
1782 SendMessage("Record: Stopped");
1783 SendMessage("Network: record_vsync_range %" PRIu64 "%" PRIu64, g_recordMinVsync, g_recordMaxVsync); // DO NOT TOUCH!
1784
1785 SetMode(Mode::NONE);
1786 });
1787 thread.detach();
1788 }
1789
PlaybackPrepareFirstFrame(const ArgList & args)1790 void RSProfiler::PlaybackPrepareFirstFrame(const ArgList& args)
1791 {
1792 if (!IsNoneMode()) {
1793 SendMessage("Playback: PrepareFirstFrame failed. Record/Saving is in progress");
1794 return;
1795 }
1796
1797 if (g_playbackFile.IsOpen() || !g_childOfDisplayNodes.empty()) {
1798 Respond("FAILED: rsrecord_replay_prepare was already called");
1799 return;
1800 }
1801 g_playbackPid = args.Pid();
1802 g_playbackStartTime = 0.0;
1803 g_playbackPauseTime = args.Fp64(1);
1804 constexpr int pathArgPos = 2;
1805 std::string path = args.String(pathArgPos);
1806 if (!Utils::FileExists(path)) {
1807 Respond("Can't playback non existing file '" + path + "'");
1808 path = RSFile::GetDefaultPath();
1809 }
1810
1811 RSTypefaceCache::Instance().ReplayClear();
1812 ImageCache::Reset();
1813
1814 auto &animeMap = RSProfiler::AnimeGetStartTimes();
1815 animeMap.clear();
1816
1817 Respond("Opening file " + path);
1818 g_playbackFile.Open(path);
1819 if (!g_playbackFile.IsOpen()) {
1820 Respond("Can't open file: not found");
1821 return;
1822 }
1823
1824 if (args.String(0) == "VSYNC") {
1825 g_playbackFile.CacheVsyncId2Time(0);
1826 int64_t reqVSyncId = args.Int64(1);
1827 int64_t realVSyncId = g_playbackFile.GetClosestVsyncId(reqVSyncId);
1828 if (reqVSyncId != realVSyncId) {
1829 Respond("WARNING: vsyncId=" + std::to_string(reqVSyncId) +
1830 " absent chosen the closest vsyncId=" + std::to_string(realVSyncId));
1831 }
1832 g_playbackPauseTime = g_playbackFile.ConvertVsyncId2Time(realVSyncId);
1833 }
1834
1835 AnimeGetStartTimesFromFile(animeMap);
1836
1837 // get first frame data
1838 if (auto errReason = FirstFrameUnmarshalling(g_playbackFile.GetHeaderFirstFrame(), g_playbackFile.GetVersion());
1839 !errReason.empty()) {
1840 Respond("Can't open file: " + errReason);
1841 FilterMockNode(*context_);
1842 g_playbackFile.Close();
1843 return;
1844 }
1845 // The number of frames loaded before command processing
1846 constexpr int defaultWaitFrames = 5;
1847 g_playbackWaitFrames = defaultWaitFrames;
1848 SendMessage("awake_frame %d", g_playbackWaitFrames); // DO NOT TOUCH!
1849 AwakeRenderServiceThread();
1850 }
1851
AnimeGetStartTimesFromFile(std::unordered_map<AnimationId,std::vector<int64_t>> & animeMap)1852 void RSProfiler::AnimeGetStartTimesFromFile(std::unordered_map<AnimationId, std::vector<int64_t>>& animeMap)
1853 {
1854 const auto& fileAnimeStartTimes = g_playbackFile.GetAnimeStartTimes();
1855 for (const auto& item : fileAnimeStartTimes) {
1856 if (animeMap.count(item.first)) {
1857 animeMap[Utils::PatchNodeId(item.first)].push_back(item.second);
1858 } else {
1859 std::vector<int64_t> list;
1860 list.push_back(item.second);
1861 animeMap.insert({ Utils::PatchNodeId(item.first), list });
1862 }
1863 }
1864 }
1865
PlaybackStart(const ArgList & args)1866 void RSProfiler::PlaybackStart(const ArgList& args)
1867 {
1868 if (!IsNoneMode()) {
1869 SendMessage("Playback: Start failed. Record/Saving is in progress");
1870 return;
1871 }
1872
1873 if (!g_playbackFile.IsOpen() || !g_childOfDisplayNodes.empty()) {
1874 Respond("FAILED: rsrecord_replay was already called");
1875 return;
1876 }
1877
1878 HiddenSpaceTurnOn();
1879
1880 for (size_t pid : g_playbackFile.GetHeaderPids()) {
1881 CreateMockConnection(Utils::GetMockPid(pid));
1882 }
1883
1884 g_playbackStartTime = Now();
1885
1886 const double pauseTime = g_playbackPauseTime;
1887 if (pauseTime > 0.0) {
1888 const uint64_t currentTime = RawNowNano();
1889 const uint64_t pauseTimeStart = currentTime + Utils::ToNanoseconds(pauseTime) / BaseGetPlaybackSpeed();
1890 TimePauseAt(currentTime, pauseTimeStart, g_playbackImmediate);
1891 }
1892
1893 AwakeRenderServiceThread();
1894
1895 g_playbackShouldBeTerminated = false;
1896 g_replayLastPauseTimeReported = 0;
1897 SetMode(Mode::READ);
1898
1899 const auto timeoutLimit = args.Int64();
1900 std::thread thread([timeoutLimit]() {
1901 while (IsPlaying()) {
1902 const int64_t timestamp = static_cast<int64_t>(RawNowNano());
1903
1904 PlaybackUpdate(PlaybackDeltaTime());
1905
1906 const int64_t timeout = timeoutLimit - static_cast<int64_t>(RawNowNano()) + timestamp;
1907 if (timeout > 0) {
1908 std::this_thread::sleep_for(std::chrono::nanoseconds(timeout));
1909 }
1910 }
1911 if (g_playbackFile.IsOpen()) {
1912 if (auto vsyncId = g_playbackFile.ConvertTime2VsyncId(PlaybackDeltaTime())) {
1913 SendMessage("Replay timer paused vsyncId=%" PRId64 "", vsyncId); // DO NOT TOUCH!
1914 }
1915 g_playbackFile.Close();
1916 }
1917 g_playbackStartTime = 0.0;
1918 g_playbackPid = 0;
1919 TimePauseClear();
1920 g_playbackShouldBeTerminated = false;
1921 Respond("Playback thread terminated");
1922 });
1923 thread.detach();
1924
1925 Respond("Playback start");
1926 }
1927
PlaybackStop(const ArgList & args)1928 void RSProfiler::PlaybackStop(const ArgList& args)
1929 {
1930 if (!g_playbackFile.IsOpen() && g_childOfDisplayNodes.empty()) {
1931 Respond("FAILED: Playback stop - no rsrecord_replay_* was called previously");
1932 return;
1933 }
1934 SetMode(Mode::NONE);
1935 if (g_childOfDisplayNodes.empty()) {
1936 // rsrecord_replay_prepare was called but rsrecord_replay_start was not
1937 g_playbackFile.Close();
1938 g_childOfDisplayNodes.clear();
1939 } else {
1940 g_playbackShouldBeTerminated = true;
1941 HiddenSpaceTurnOff();
1942 }
1943 FilterMockNode(*context_);
1944 constexpr int maxCountForSecurity = 1000;
1945 for (int i = 0; !RSRenderNodeGC::Instance().IsBucketQueueEmpty() && i < maxCountForSecurity; i++) {
1946 RSRenderNodeGC::Instance().ReleaseNodeBucket();
1947 }
1948 RSTypefaceCache::Instance().ReplayClear();
1949 ImageCache::Reset();
1950 g_replayLastPauseTimeReported = 0;
1951
1952 SendMessage("Playback stop"); // DO NOT TOUCH!
1953 }
1954
PlaybackDeltaTime()1955 double RSProfiler::PlaybackDeltaTime()
1956 {
1957 return Now() - g_playbackStartTime;
1958 }
1959
PlaybackUpdate(double deltaTime)1960 double RSProfiler::PlaybackUpdate(double deltaTime)
1961 {
1962 std::vector<uint8_t> data;
1963 double readTime = 0.0;
1964 if (!g_playbackShouldBeTerminated && g_playbackFile.ReadRSData(deltaTime, data, readTime)) {
1965 std::stringstream stream(std::ios::in | std::ios::out | std::ios::binary);
1966 stream.write(reinterpret_cast<const char*>(data.data()), data.size());
1967 stream.seekg(0);
1968
1969 pid_t pid = 0;
1970 stream.read(reinterpret_cast<char*>(&pid), sizeof(pid));
1971
1972 RSRenderServiceConnection* connection = GetConnection(Utils::GetMockPid(pid));
1973 if (!connection) {
1974 const std::vector<pid_t>& pids = g_playbackFile.GetHeaderPids();
1975 if (!pids.empty()) {
1976 connection = GetConnection(Utils::GetMockPid(pids[0]));
1977 }
1978 }
1979
1980 if (connection) {
1981 uint32_t code = 0;
1982 stream.read(reinterpret_cast<char*>(&code), sizeof(code));
1983
1984 size_t dataSize = 0;
1985 stream.read(reinterpret_cast<char*>(&dataSize), sizeof(dataSize));
1986
1987 auto* data = new uint8_t[dataSize];
1988 stream.read(reinterpret_cast<char*>(data), dataSize);
1989
1990 int32_t flags = 0;
1991 stream.read(reinterpret_cast<char*>(&flags), sizeof(flags));
1992
1993 int32_t waitTime = 0;
1994 stream.read(reinterpret_cast<char*>(&waitTime), sizeof(waitTime));
1995
1996 AlignedMessageParcel parcel;
1997 parcel.parcel.SetMaxCapacity(dataSize + 1);
1998 parcel.parcel.WriteBuffer(data, dataSize);
1999
2000 delete[] data;
2001
2002 MessageOption option;
2003 option.SetFlags(flags);
2004 option.SetWaitTime(waitTime);
2005
2006 MessageParcel reply;
2007 connection->OnRemoteRequest(code, parcel.parcel, reply, option);
2008 }
2009 }
2010
2011 if (g_playbackFile.RSDataEOF()) {
2012 g_playbackShouldBeTerminated = true;
2013 }
2014 return readTime;
2015 }
2016
PlaybackPrepare(const ArgList & args)2017 void RSProfiler::PlaybackPrepare(const ArgList& args)
2018 {
2019 const pid_t pid = args.Pid();
2020 if (!context_ || (pid == 0)) {
2021 return;
2022 }
2023
2024 AwakeRenderServiceThread();
2025 Respond("OK");
2026 }
2027
PlaybackPause(const ArgList & args)2028 void RSProfiler::PlaybackPause(const ArgList& args)
2029 {
2030 if (!IsPlaying()) {
2031 return;
2032 }
2033
2034 const uint64_t currentTime = RawNowNano();
2035 const double recordPlayTime = Utils::ToSeconds(PatchTime(currentTime)) - g_playbackStartTime;
2036 TimePauseAt(g_frameBeginTimestamp, currentTime, g_playbackImmediate);
2037 Respond("OK: " + std::to_string(recordPlayTime));
2038
2039 int64_t vsyncId = g_playbackFile.ConvertTime2VsyncId(recordPlayTime);
2040 if (vsyncId) {
2041 SendMessage("Replay timer paused vsyncId=%" PRId64, vsyncId); // DO NOT TOUCH!
2042 }
2043 g_replayLastPauseTimeReported = recordPlayTime;
2044 }
2045
PlaybackPauseAt(const ArgList & args)2046 void RSProfiler::PlaybackPauseAt(const ArgList& args)
2047 {
2048 if (!IsPlaying()) {
2049 Respond("PlaybackPauseAt REJECT is_playing=false");
2050 return;
2051 }
2052
2053 double pauseAtTimeSec;
2054 if (args.String(0) == "VSYNC") {
2055 int64_t reqVSyncId = args.Int64(1);
2056 int64_t realVSyncId = g_playbackFile.GetClosestVsyncId(reqVSyncId);
2057 if (reqVSyncId != realVSyncId) {
2058 Respond("WARNING: vsyncId=" + std::to_string(reqVSyncId) +
2059 " absent chosen the closest vsyncId=" + std::to_string(realVSyncId));
2060 }
2061 pauseAtTimeSec = g_playbackFile.ConvertVsyncId2Time(realVSyncId);
2062 } else {
2063 pauseAtTimeSec = args.Fp64();
2064 }
2065
2066 const uint64_t currentTimeNano = RawNowNano();
2067 const double alreadyPlayedTimeSec = Utils::ToSeconds(PatchTime(currentTimeNano)) - g_playbackStartTime;
2068 if (alreadyPlayedTimeSec > pauseAtTimeSec) {
2069 return;
2070 }
2071
2072 // set 2nd pause
2073 const uint64_t pauseAfterTimeNano = currentTimeNano + Utils::ToNanoseconds(pauseAtTimeSec - alreadyPlayedTimeSec)
2074 / BaseGetPlaybackSpeed();
2075
2076 TimePauseAt(currentTimeNano, pauseAfterTimeNano, g_playbackImmediate);
2077 ResetAnimationStamp();
2078 Respond("PlaybackPauseAt OK");
2079 }
2080
2081
ProcessCommands()2082 void RSProfiler::ProcessCommands()
2083 {
2084 if (g_playbackWaitFrames > 0) {
2085 g_playbackWaitFrames--;
2086 SendMessage("awake_frame %d", g_playbackWaitFrames); // DO NOT TOUCH!
2087 if (context_) {
2088 MarkReplayNodesDirty(*context_);
2089 }
2090 AwakeRenderServiceThread();
2091 return;
2092 }
2093
2094 std::vector<std::string> line;
2095 if (Network::PopCommand(line)) {
2096 Invoke(line);
2097 }
2098 }
2099
GetFrameNumber()2100 uint32_t RSProfiler::GetFrameNumber()
2101 {
2102 return g_frameNumber;
2103 }
2104
BlinkNodeUpdate()2105 void RSProfiler::BlinkNodeUpdate()
2106 {
2107 if (g_blinkSavedParentChildren.empty()) {
2108 return;
2109 }
2110
2111 constexpr uint32_t blinkTotalCount = 20;
2112 constexpr uint32_t blinkFrameDelay = 5;
2113 const uint32_t blinkStage = g_blinkNodeCount / blinkFrameDelay;
2114 if (const bool isOdd = blinkStage % 2) {
2115 // restore node
2116 const auto parentNode = g_blinkSavedParentChildren[0];
2117 if (!parentNode) {
2118 return;
2119 }
2120 for (size_t i = 1; i < g_blinkSavedParentChildren.size(); i++) {
2121 const auto child = g_blinkSavedParentChildren[i];
2122 parentNode->RemoveChild(child);
2123 child->ResetParent();
2124 }
2125 for (size_t i = 1; i < g_blinkSavedParentChildren.size(); i++) {
2126 const auto child = g_blinkSavedParentChildren[i];
2127 parentNode->AddChild(child);
2128 }
2129 if (blinkStage > blinkTotalCount) {
2130 g_blinkNodeCount = 0;
2131 g_blinkSavedParentChildren.clear();
2132 }
2133 } else {
2134 // remove node
2135 auto blinkNode = GetRenderNode(g_blinkNodeId);
2136 if (const auto parentNode = g_blinkSavedParentChildren[0]) {
2137 parentNode->RemoveChild(blinkNode);
2138 }
2139 if (blinkNode) {
2140 blinkNode->ResetParent();
2141 }
2142 }
2143
2144 g_blinkNodeCount++;
2145 AwakeRenderServiceThread();
2146 }
2147
CalcPerfNodeUpdate()2148 void RSProfiler::CalcPerfNodeUpdate()
2149 {
2150 if (g_calcPerfNode != 0 || g_nodeListPerfCalcIndex < 0) {
2151 return;
2152 }
2153
2154 for (const auto& item : g_calcPerfSavedChildren) {
2155 const auto parentNode = item.first;
2156 if (!parentNode) {
2157 continue;
2158 }
2159 for (const auto& child : item.second) {
2160 parentNode->RemoveChild(child);
2161 child->ResetParent();
2162 }
2163 for (const auto& child : item.second) {
2164 parentNode->AddChild(child);
2165 }
2166 }
2167
2168 if (g_calcPerfNodeTry != 0) {
2169 g_calcPerfNodeTry = 0;
2170 g_nodeListPerfCalcIndex++;
2171 CalcPerfNodeAllStep();
2172 return;
2173 }
2174
2175 g_calcPerfSavedChildren.clear();
2176 g_calcPerfNodeTry++;
2177 AwakeRenderServiceThread();
2178 }
2179
AnimeGetStartTimesFlattened(double recordStartTime)2180 std::vector<std::pair<uint64_t, int64_t>> RSProfiler::AnimeGetStartTimesFlattened(double recordStartTime)
2181 {
2182 std::vector<std::pair<uint64_t, int64_t>> headerAnimeStartTimes;
2183 const std::unordered_map<AnimationId, std::vector<int64_t>> &headerAnimeStartTimesMap = AnimeGetStartTimes();
2184 for (const auto& item : headerAnimeStartTimesMap) {
2185 for (const auto time : item.second) {
2186 headerAnimeStartTimes.push_back({
2187 Utils::PatchNodeId(item.first),
2188 time - Utils::ToNanoseconds(recordStartTime)
2189 });
2190 }
2191 }
2192 return headerAnimeStartTimes;
2193 }
2194
LogEventStart(uint64_t curTime,RSCaptureData & captureData,double & timeSinceRecordStart)2195 bool RSProfiler::LogEventStart(uint64_t curTime, RSCaptureData& captureData, double& timeSinceRecordStart)
2196 {
2197 if (!IsEnabled() || !IsRecording()) {
2198 return false;
2199 }
2200
2201 uint64_t nanoRecordStartTime = Utils::ToNanoseconds(g_recordStartTime);
2202 if (curTime < nanoRecordStartTime) {
2203 curTime = nanoRecordStartTime;
2204 }
2205 timeSinceRecordStart = Utils::ToSeconds(curTime - nanoRecordStartTime);
2206
2207 captureData.SetTime(timeSinceRecordStart);
2208 captureData.SetProperty(RSCaptureData::KEY_EVENT_TYPE, RSCaptureData::VAL_EVENT_TYPE_VSYNC);
2209 return true;
2210 }
2211
LogEventFinish(RSCaptureData & captureData,double timeSinceRecordStart)2212 void RSProfiler::LogEventFinish(RSCaptureData& captureData, double timeSinceRecordStart)
2213 {
2214 std::vector<char> out;
2215 DataWriter archive(out);
2216 char headerType = static_cast<char>(PackageID::RS_PROFILER_RS_EVENT);
2217 archive.Serialize(headerType);
2218 captureData.Serialize(archive);
2219
2220 Network::SendBinary(out.data(), out.size());
2221 g_recordFile.WriteLogEvent(0, timeSinceRecordStart, out.data(), out.size());
2222 }
2223
LogEventVSync(uint64_t syncTime)2224 void RSProfiler::LogEventVSync(uint64_t syncTime)
2225 {
2226 RSCaptureData captureData;
2227 double timeSinceRecordStart;
2228 if (!LogEventStart(syncTime, captureData, timeSinceRecordStart)) {
2229 return;
2230 }
2231 captureData.SetProperty(RSCaptureData::KEY_EVENT_TYPE, RSCaptureData::VAL_EVENT_TYPE_VSYNC);
2232 LogEventFinish(captureData, timeSinceRecordStart);
2233 }
2234
LogEventMsg(uint64_t curTime,RSProfilerLogType type,const std::string & msg)2235 void RSProfiler::LogEventMsg(uint64_t curTime, RSProfilerLogType type, const std::string& msg)
2236 {
2237 RSCaptureData captureData;
2238 double timeSinceRecordStart;
2239 if (!LogEventStart(curTime, captureData, timeSinceRecordStart)) {
2240 return;
2241 }
2242
2243 if (type == RSProfilerLogType::ERROR) {
2244 captureData.SetProperty(RSCaptureData::KEY_EVENT_TYPE, RSCaptureData::VAL_EVENT_TYPE_MSGERR);
2245 } else if (type == RSProfilerLogType::WARNING) {
2246 captureData.SetProperty(RSCaptureData::KEY_EVENT_TYPE, RSCaptureData::VAL_EVENT_TYPE_MSGWARN);
2247 } else if (type == RSProfilerLogType::INFO) {
2248 captureData.SetProperty(RSCaptureData::KEY_EVENT_TYPE, RSCaptureData::VAL_EVENT_TYPE_INFO);
2249 } else if (type == RSProfilerLogType::PIXELMAP) {
2250 captureData.SetProperty(RSCaptureData::KEY_EVENT_TYPE, RSCaptureData::VAL_EVENT_TYPE_PIXELMAP);
2251 } else if (type == RSProfilerLogType::PARCEL_UNMARSHALLING_START) {
2252 captureData.SetProperty(
2253 RSCaptureData::KEY_EVENT_TYPE, RSCaptureData::VAL_EVENT_TYPE_PARCEL_UNMARSHALLING_START);
2254 } else if (type == RSProfilerLogType::PARCEL_UNMARSHALLING_END) {
2255 captureData.SetProperty(RSCaptureData::KEY_EVENT_TYPE, RSCaptureData::VAL_EVENT_TYPE_PARCEL_UNMARSHALLING_END);
2256 } else if (type == RSProfilerLogType::DEBUG) {
2257 captureData.SetProperty(RSCaptureData::KEY_EVENT_TYPE, RSCaptureData::VAL_EVENT_TYPE_DEBUG);
2258 } else if (type == RSProfilerLogType::PIXELMAP_YUV) {
2259 captureData.SetProperty(RSCaptureData::KEY_EVENT_TYPE, RSCaptureData::VAL_EVENT_TYPE_PIXELMAP_YUV);
2260 }
2261
2262 captureData.SetProperty(RSCaptureData::KEY_EVENT_MSG, msg);
2263 LogEventFinish(captureData, timeSinceRecordStart);
2264 }
2265
RsMetricClear()2266 void RSProfiler::RsMetricClear()
2267 {
2268 g_recordRsMetric.clear();
2269 }
2270
RsMetricSet(std::string name,std::string value)2271 void RSProfiler::RsMetricSet(std::string name, std::string value)
2272 {
2273 g_recordRsMetric[name] = value;
2274 }
2275
TestSaveSubTree(const ArgList & args)2276 void RSProfiler::TestSaveSubTree(const ArgList& args)
2277 {
2278 const auto nodeId = args.Node();
2279 auto node = GetRenderNode(nodeId);
2280 if (!node) {
2281 Respond("Error: node not found");
2282 return;
2283 }
2284
2285 RSSystemProperties::SetProfilerPixelCheckMode(true);
2286 std::stringstream stream;
2287
2288 // Save RSFILE_VERSION
2289 uint32_t fileVersion = RSFILE_VERSION_LATEST;
2290 stream.write(reinterpret_cast<const char*>(&fileVersion), sizeof(fileVersion));
2291
2292 MarshalSubTree(*context_, stream, *node, fileVersion);
2293 std::string testDataSubTree = stream.str();
2294
2295 Respond("Save SubTree Size: " + std::to_string(testDataSubTree.size()));
2296
2297 // save file need setenforce 0
2298 std::string rootPath = "/data";
2299 char realRootPath[PATH_MAX] = {0};
2300 if (!realpath(rootPath.c_str(), realRootPath)) {
2301 Respond("Error: data path is invalid");
2302 return;
2303 }
2304 std::string filePath = realRootPath;
2305 filePath = filePath + "/rssbtree_test_" + std::to_string(nodeId);
2306 std::ofstream file(filePath);
2307 if (file.is_open()) {
2308 file << testDataSubTree;
2309 file.close();
2310 Respond("Save subTree Success, file path:" + filePath);
2311 } else {
2312 Respond("Save subTree Failed: save file faild!");
2313 }
2314 RSSystemProperties::SetProfilerPixelCheckMode(false);
2315 }
2316
TestLoadSubTree(const ArgList & args)2317 void RSProfiler::TestLoadSubTree(const ArgList& args)
2318 {
2319 const auto nodeId = args.Node();
2320 auto node = GetRenderNode(nodeId);
2321 if (!node) {
2322 Respond("Error: node not found");
2323 return;
2324 }
2325
2326 const auto filePath = args.String(1);
2327 if (filePath.empty()) {
2328 Respond("Error: Path is empty");
2329 return;
2330 }
2331
2332 char realPath[PATH_MAX] = {0};
2333 if (!realpath(filePath.c_str(), realPath)) {
2334 Respond("Error: Path is invalid");
2335 return;
2336 }
2337
2338 std::ifstream file(realPath);
2339 if (!file.is_open()) {
2340 std::error_code ec(errno, std::system_category());
2341 RS_LOGE("RSProfiler::TestLoadSubTree read file failed: %{public}s", ec.message().c_str());
2342 Respond("RSProfiler::TestLoadSubTree read file failed: " + ec.message());
2343 return;
2344 }
2345 std::stringstream stream;
2346 stream << file.rdbuf();
2347 file.close();
2348
2349 // Load RSFILE_VERSION
2350 uint32_t fileVersion = 0u;
2351 stream.read(reinterpret_cast<char*>(&fileVersion), sizeof(fileVersion));
2352
2353 std::string errorReason = UnmarshalSubTree(*context_, stream, *node, fileVersion);
2354 if (errorReason.size()) {
2355 RS_LOGE("RSProfiler::TestLoadSubTree failed: %{public}s", errorReason.c_str());
2356 Respond("RSProfiler::TestLoadSubTree failed: " + errorReason);
2357 }
2358 Respond("Load subTree result: " + errorReason);
2359 }
2360
TestClearSubTree(const ArgList & args)2361 void RSProfiler::TestClearSubTree(const ArgList& args)
2362 {
2363 FilterMockNode(*context_);
2364 constexpr int maxCountForSecurity = 1000;
2365 for (int i = 0; !RSRenderNodeGC::Instance().IsBucketQueueEmpty() && i < maxCountForSecurity; i++) {
2366 RSRenderNodeGC::Instance().ReleaseNodeBucket();
2367 }
2368 RSTypefaceCache::Instance().ReplayClear();
2369 ImageCache::Reset();
2370 Respond("Clear SubTree Success");
2371 }
2372
MarshalSubTree(RSContext & context,std::stringstream & data,const RSRenderNode & node,uint32_t fileVersion,bool clearImageCache)2373 void RSProfiler::MarshalSubTree(RSContext& context, std::stringstream& data,
2374 const RSRenderNode& node, uint32_t fileVersion, bool clearImageCache)
2375 {
2376 if (clearImageCache) {
2377 ImageCache::Reset();
2378 }
2379
2380 SetMode(Mode::WRITE_EMUL);
2381 DisableSharedMemory();
2382
2383 std::stringstream dataNodes(std::ios::in | std::ios::out | std::ios::binary);
2384 MarshalSubTreeLo(context, dataNodes, node, fileVersion);
2385
2386 EnableSharedMemory();
2387 SetMode(Mode::NONE);
2388
2389 std::stringstream dataPixelMaps(std::ios::in | std::ios::out | std::ios::binary);
2390 ImageCache::Serialize(dataPixelMaps);
2391
2392 // SAVE TO STREAM
2393 TypefaceMarshalling(data, fileVersion);
2394
2395 uint32_t pixelMapSize = dataPixelMaps.str().size();
2396 data.write(reinterpret_cast<const char*>(&pixelMapSize), sizeof(pixelMapSize));
2397 data.write(dataPixelMaps.str().data(), dataPixelMaps.str().size());
2398
2399 uint32_t nodesSize = dataNodes.str().size();
2400 data.write(reinterpret_cast<const char*>(&nodesSize), sizeof(nodesSize));
2401 data.write(dataNodes.str().data(), dataNodes.str().size());
2402 }
2403
UnmarshalSubTree(RSContext & context,std::stringstream & data,RSRenderNode & attachNode,uint32_t fileVersion,bool clearImageCache)2404 std::string RSProfiler::UnmarshalSubTree(RSContext& context, std::stringstream& data,
2405 RSRenderNode& attachNode, uint32_t fileVersion, bool clearImageCache)
2406 {
2407 if (clearImageCache) {
2408 ImageCache::Reset();
2409 }
2410
2411 TypefaceUnmarshalling(data, fileVersion);
2412
2413 uint32_t pixelMapSize = 0u;
2414 data.read(reinterpret_cast<char*>(&pixelMapSize), sizeof(pixelMapSize));
2415
2416 // read Cache
2417 ImageCache::Deserialize(data);
2418
2419 uint32_t nodesSize = 0u;
2420 data.read(reinterpret_cast<char*>(&nodesSize), sizeof(nodesSize));
2421
2422 SetMode(Mode::READ_EMUL);
2423 DisableSharedMemory();
2424
2425 std::string errReason = UnmarshalSubTreeLo(context, data, attachNode, fileVersion);
2426
2427 EnableSharedMemory();
2428 SetMode(Mode::NONE);
2429
2430 auto& nodeMap = context.GetMutableNodeMap();
2431 nodeMap.TraversalNodes([](const std::shared_ptr<RSBaseRenderNode>& node) {
2432 if (node == nullptr) {
2433 return;
2434 }
2435 if (Utils::IsNodeIdPatched(node->GetId())) {
2436 node->SetContentDirty();
2437 node->SetDirty();
2438 }
2439 });
2440 g_mainThread->SetDirtyFlag();
2441 AwakeRenderServiceThread();
2442 return errReason;
2443 }
2444 } // namespace OHOS::Rosen