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