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