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 <filesystem>
17 #include <numeric>
18
19 #include "foundation/graphic/graphic_2d/utils/log/rs_trace.h"
20 #include "rs_profiler.h"
21 #include "rs_profiler_archive.h"
22 #include "rs_profiler_cache.h"
23 #include "rs_profiler_capture_recorder.h"
24 #include "rs_profiler_capturedata.h"
25 #include "rs_profiler_file.h"
26 #include "rs_profiler_json.h"
27 #include "rs_profiler_network.h"
28 #include "rs_profiler_settings.h"
29 #include "rs_profiler_telemetry.h"
30 #include "rs_profiler_utils.h"
31 #include "rs_profiler_packet.h"
32
33 #include "params/rs_display_render_params.h"
34 #include "pipeline/rs_main_thread.h"
35 #include "pipeline/rs_render_service_connection.h"
36 #include "pipeline/rs_uni_render_util.h"
37
38 namespace OHOS::Rosen {
39
40 // (user): Move to RSProfiler
41 static RSRenderService* g_renderService = nullptr;
42 static std::atomic<int32_t> g_renderServiceCpuId = 0;
43 static std::atomic<int32_t> g_renderServiceRenderCpuId = 0;
44 static RSMainThread* g_mainThread = nullptr;
45 static RSContext* g_context = nullptr;
46 static uint64_t g_frameBeginTimestamp = 0u;
47 static uint64_t g_frameRenderBeginTimestamp = 0u;
48 static double g_dirtyRegionPercentage = 0.0;
49 static bool g_rdcSent = true;
50
51 static std::atomic<uint32_t> g_lastCacheImageCount = 0;
52
53 static RSFile g_recordFile {};
54 static double g_recordStartTime = 0.0;
55 static uint32_t g_frameNumber = 0;
56
57 static RSFile g_playbackFile {};
58 static double g_playbackStartTime = 0.0;
59 static NodeId g_playbackParentNodeId = 0;
60 static int g_playbackPid = 0;
61 static bool g_playbackShouldBeTerminated = true;
62 static double g_playbackPauseTime = 0;
63 static int g_playbackWaitFrames = 0;
64
65 static std::unordered_set<NodeId> g_nodeSetPerf;
66 static std::unordered_map<NodeId, int> g_mapNode2Count;
67 static NodeId g_calcPerfNode = 0;
68 static int g_calcPerfNodeTry = 0;
69 static bool g_calcPerfNodeExcludeDown = false;
70
71 constexpr int CALC_PERF_NODE_TIME_COUNT = 64; // increased to improve reliability of perfomance measurement
72 static uint64_t g_calcPerfNodeTime[CALC_PERF_NODE_TIME_COUNT];
73 static NodeId g_calcPerfNodeParent = 0;
74 static int g_calcPerfNodeIndex = 0;
75 static int g_nodeSetPerfCalcIndex = -1;
76 static std::string g_testDataFrame;
77 static std::vector<RSRenderNode::SharedPtr> g_childOfDisplayNodes;
78
79 #pragma pack(push, 1)
80 struct AlignedMessageParcel {
81 uint8_t pad = 0u;
82 MessageParcel parcel;
83 };
84 #pragma pack(pop)
85
DeviceInfoToCaptureData(double time,const DeviceInfo & in,RSCaptureData & out)86 void DeviceInfoToCaptureData(double time, const DeviceInfo& in, RSCaptureData& out)
87 {
88 std::string frequency;
89 std::string load;
90 for (uint32_t i = 0; i < in.cpu.cores; i++) {
91 frequency += std::to_string(in.cpu.coreFrequencyLoad[i].current);
92 load += std::to_string(in.cpu.coreFrequencyLoad[i].load);
93 if (i + 1 < in.cpu.cores) {
94 frequency += ";";
95 load += ";";
96 }
97 }
98
99 out.SetTime(static_cast<float>(time));
100 out.SetProperty(RSCaptureData::KEY_CPU_TEMP, in.cpu.temperature);
101 out.SetProperty(RSCaptureData::KEY_CPU_CURRENT, in.cpu.current);
102 out.SetProperty(RSCaptureData::KEY_CPU_LOAD, load);
103 out.SetProperty(RSCaptureData::KEY_CPU_FREQ, frequency);
104 out.SetProperty(RSCaptureData::KEY_GPU_LOAD, in.gpu.frequencyLoad.load);
105 out.SetProperty(RSCaptureData::KEY_GPU_FREQ, in.gpu.frequencyLoad.current);
106 }
107
GetPid(const std::shared_ptr<RSRenderNode> & node)108 static pid_t GetPid(const std::shared_ptr<RSRenderNode>& node)
109 {
110 return node ? Utils::ExtractPid(node->GetId()) : 0;
111 }
112
GetNodeId(const std::shared_ptr<RSRenderNode> & node)113 static NodeId GetNodeId(const std::shared_ptr<RSRenderNode>& node)
114 {
115 return node ? Utils::ExtractNodeId(node->GetId()) : 0;
116 }
117
SendTelemetry(double time)118 static void SendTelemetry(double time)
119 {
120 if (time >= 0.0) {
121 RSCaptureData captureData;
122 DeviceInfoToCaptureData(time, RSTelemetry::GetDeviceInfo(), captureData);
123 Network::SendCaptureData(captureData);
124 }
125 }
126
127 /*
128 To visualize the damage region (as it's set for KHR_partial_update), you can set the following variable:
129 'hdc shell param set rosen.dirtyregiondebug.enabled 6'
130 */
SetDirtyRegion(const Occlusion::Region & dirtyRegion)131 void RSProfiler::SetDirtyRegion(const Occlusion::Region& dirtyRegion)
132 {
133 if (!IsRecording()) {
134 return;
135 }
136
137 const double maxPercentValue = 100.0;
138 g_dirtyRegionPercentage = maxPercentValue;
139
140 if (!g_context) {
141 return;
142 }
143 std::shared_ptr<RSDisplayRenderNode> displayNode = GetDisplayNode(*g_context);
144 if (!displayNode) {
145 return;
146 }
147 auto params = static_cast<RSDisplayRenderParams*>(displayNode->GetRenderParams().get());
148 if (!params) {
149 return;
150 }
151
152 auto screenInfo = params->GetScreenInfo();
153 const uint64_t displayWidth = screenInfo.width;
154 const uint64_t displayHeight = screenInfo.height;
155 const uint64_t displayArea = displayWidth * displayHeight;
156
157 auto rects = RSUniRenderUtil::ScreenIntersectDirtyRects(dirtyRegion, screenInfo);
158 uint64_t dirtyRegionArea = 0;
159 for (const auto& rect : rects) {
160 dirtyRegionArea += static_cast<uint64_t>(rect.GetWidth() * rect.GetHeight());
161 }
162
163 if (displayArea > 0) {
164 g_dirtyRegionPercentage =
165 maxPercentValue * static_cast<double>(dirtyRegionArea) / static_cast<double>(displayArea);
166 }
167 if (g_dirtyRegionPercentage > maxPercentValue) {
168 g_dirtyRegionPercentage = maxPercentValue;
169 }
170 }
171
Init(RSRenderService * renderService)172 void RSProfiler::Init(RSRenderService* renderService)
173 {
174 if (!IsEnabled()) {
175 return;
176 }
177
178 g_renderService = renderService;
179 g_mainThread = g_renderService ? g_renderService->mainThread_ : nullptr;
180 g_context = g_mainThread ? g_mainThread->context_.get() : nullptr;
181
182 if (!IsBetaRecordEnabled()) {
183 static auto const networkRunLambda = []() {
184 Network::Run();
185 };
186 static std::thread const thread(networkRunLambda);
187 }
188 }
189
OnCreateConnection(pid_t pid)190 void RSProfiler::OnCreateConnection(pid_t pid)
191 {
192 if (!IsEnabled()) {
193 return;
194 }
195
196 if (IsRecording()) {
197 g_recordFile.AddHeaderPid(pid);
198 }
199 }
200
OnRemoteRequest(RSIRenderServiceConnection * connection,uint32_t code,MessageParcel & parcel,MessageParcel &,MessageOption & option)201 void RSProfiler::OnRemoteRequest(RSIRenderServiceConnection* connection, uint32_t code, MessageParcel& parcel,
202 MessageParcel& /*reply*/, MessageOption& option)
203 {
204 if (!IsEnabled()) {
205 return;
206 }
207
208 if (IsRecording() && (g_recordStartTime > 0.0)) {
209 const pid_t pid = GetConnectionPid(connection);
210 const auto& pids = g_recordFile.GetHeaderPids();
211 if (std::find(std::begin(pids), std::end(pids), pid) != std::end(pids)) {
212 const double deltaTime = Now() - g_recordStartTime;
213
214 std::stringstream stream(std::ios::in | std::ios::out | std::ios::binary);
215
216 char headerType = 1; // parcel data
217 stream.write(reinterpret_cast<const char*>(&headerType), sizeof(headerType));
218 stream.write(reinterpret_cast<const char*>(&deltaTime), sizeof(deltaTime));
219
220 // set sending pid
221 stream.write(reinterpret_cast<const char*>(&pid), sizeof(pid));
222 stream.write(reinterpret_cast<const char*>(&code), sizeof(code));
223
224 const size_t dataSize = parcel.GetDataSize();
225 stream.write(reinterpret_cast<const char*>(&dataSize), sizeof(dataSize));
226 stream.write(reinterpret_cast<const char*>(parcel.GetData()), dataSize);
227
228 const int32_t flags = option.GetFlags();
229 stream.write(reinterpret_cast<const char*>(&flags), sizeof(flags));
230 const int32_t waitTime = option.GetWaitTime();
231 stream.write(reinterpret_cast<const char*>(&waitTime), sizeof(waitTime));
232
233 const std::string out = stream.str();
234 constexpr size_t headerOffset = 8 + 1;
235 if (out.size() >= headerOffset) {
236 g_recordFile.WriteRSData(deltaTime, out.data() + headerOffset, out.size() - headerOffset);
237 }
238 Network::SendBinary(out.data(), out.size());
239 }
240 }
241
242 if (IsLoadSaveFirstScreenInProgress()) {
243 // saving screen right now
244 }
245 if (IsPlaying()) {
246 SetTransactionTimeCorrection(g_playbackStartTime, g_playbackFile.GetWriteTime());
247 SetSubstitutingPid(g_playbackFile.GetHeaderPids(), g_playbackPid, g_playbackParentNodeId);
248 SetMode(Mode::READ);
249 } else if (IsRecording()) {
250 SetMode(Mode::WRITE);
251 } else {
252 SetMode(Mode::NONE);
253 }
254 }
255
OnRecvParcel(const MessageParcel * parcel,RSTransactionData * data)256 void RSProfiler::OnRecvParcel(const MessageParcel* parcel, RSTransactionData* data)
257 {
258 if (!IsEnabled()) {
259 return;
260 }
261
262 if (parcel && IsParcelMock(*parcel)) {
263 data->SetSendingPid(Utils::GetMockPid(data->GetSendingPid()));
264 }
265 }
266
CreateMockConnection(pid_t pid)267 void RSProfiler::CreateMockConnection(pid_t pid)
268 {
269 if (!IsEnabled() || !g_renderService) {
270 return;
271 }
272
273 auto tokenObj = new IRemoteStub<RSIConnectionToken>();
274
275 sptr<RSIRenderServiceConnection> newConn(new RSRenderServiceConnection(pid, g_renderService, g_mainThread,
276 g_renderService->screenManager_, tokenObj, g_renderService->appVSyncDistributor_));
277
278 sptr<RSIRenderServiceConnection> tmp;
279
280 std::unique_lock<std::mutex> lock(g_renderService->mutex_);
281 // if connections_ has the same token one, replace it.
282 if (g_renderService->connections_.count(tokenObj) > 0) {
283 tmp = g_renderService->connections_.at(tokenObj);
284 }
285 g_renderService->connections_[tokenObj] = newConn;
286 lock.unlock();
287 g_mainThread->AddTransactionDataPidInfo(pid);
288 }
289
GetConnection(pid_t pid)290 RSRenderServiceConnection* RSProfiler::GetConnection(pid_t pid)
291 {
292 if (!g_renderService) {
293 return nullptr;
294 }
295
296 for (const auto& pair : g_renderService->connections_) {
297 auto connection = static_cast<RSRenderServiceConnection*>(pair.second.GetRefPtr());
298 if (connection->remotePid_ == pid) {
299 return connection;
300 }
301 }
302
303 return nullptr;
304 }
305
GetConnectionPid(RSIRenderServiceConnection * connection)306 pid_t RSProfiler::GetConnectionPid(RSIRenderServiceConnection* connection)
307 {
308 if (!g_renderService || !connection) {
309 return 0;
310 }
311
312 for (const auto& pair : g_renderService->connections_) {
313 auto renderServiceConnection = static_cast<RSRenderServiceConnection*>(pair.second.GetRefPtr());
314 if (renderServiceConnection == connection) {
315 return renderServiceConnection->remotePid_;
316 }
317 }
318
319 return 0;
320 }
321
GetConnectionsPids()322 std::vector<pid_t> RSProfiler::GetConnectionsPids()
323 {
324 if (!g_renderService) {
325 return {};
326 }
327
328 std::vector<pid_t> pids;
329 pids.reserve(g_renderService->connections_.size());
330 for (const auto& pair : g_renderService->connections_) {
331 pids.push_back(static_cast<RSRenderServiceConnection*>(pair.second.GetRefPtr())->remotePid_);
332 }
333 return pids;
334 }
335
OnProcessCommand()336 void RSProfiler::OnProcessCommand()
337 {
338 if (!IsEnabled()) {
339 return;
340 }
341
342 if (IsPlaying()) {
343 ResetAnimationStamp();
344 }
345 }
346
OnRenderBegin()347 void RSProfiler::OnRenderBegin()
348 {
349 if (!IsEnabled()) {
350 return;
351 }
352 RS_LOGD("RSProfiler::OnRenderBegin(): enabled"); // NOLINT
353 g_renderServiceCpuId = Utils::GetCpuId();
354 }
355
OnRenderEnd()356 void RSProfiler::OnRenderEnd()
357 {
358 if (!IsEnabled()) {
359 return;
360 }
361
362 g_renderServiceCpuId = Utils::GetCpuId();
363 }
364
OnParallelRenderBegin()365 void RSProfiler::OnParallelRenderBegin()
366 {
367 if (!IsEnabled()) {
368 return;
369 }
370
371 if (g_calcPerfNode > 0) {
372 // force render thread to be on fastest CPU
373 constexpr uint32_t spamCount = 10'000;
374 std::vector<int> data;
375 data.resize(spamCount);
376 for (uint32_t i = 0; i < spamCount; i++) {
377 for (uint32_t j = i + 1; j < spamCount; j++) {
378 std::swap(data[i], data[j]);
379 }
380 }
381
382 constexpr uint32_t trashCashStep = 64;
383 constexpr uint32_t newCount = spamCount * trashCashStep;
384 constexpr int trashNum = 0x7F;
385 data.resize(newCount);
386 for (uint32_t i = 0; i < spamCount; i++) {
387 data[i * trashCashStep] = trashNum;
388 }
389 }
390
391 g_frameRenderBeginTimestamp = RawNowNano();
392 }
393
OnParallelRenderEnd(uint32_t frameNumber)394 void RSProfiler::OnParallelRenderEnd(uint32_t frameNumber)
395 {
396 const uint64_t frameLengthNanosecs = RawNowNano() - g_frameRenderBeginTimestamp;
397 CalcNodeWeigthOnFrameEnd(frameLengthNanosecs);
398
399 if (!IsRecording() || (g_recordStartTime <= 0.0)) {
400 return;
401 }
402
403 const double currentTime = static_cast<double>(g_frameRenderBeginTimestamp) * 1e-9;
404 const double timeSinceRecordStart = currentTime - g_recordStartTime;
405
406 if (timeSinceRecordStart > 0.0) {
407 RSCaptureData captureData;
408 captureData.SetTime(timeSinceRecordStart);
409 captureData.SetProperty(RSCaptureData::KEY_RENDER_FRAME_NUMBER, frameNumber);
410 captureData.SetProperty(RSCaptureData::KEY_RENDER_FRAME_LEN, frameLengthNanosecs);
411
412 std::vector<char> out;
413 DataWriter archive(out);
414 char headerType = static_cast<char>(PackageID::RS_PROFILER_RENDER_METRICS);
415 archive.Serialize(headerType);
416 captureData.Serialize(archive);
417
418 Network::SendBinary(out.data(), out.size());
419 g_recordFile.WriteRSMetrics(0, timeSinceRecordStart, out.data(), out.size());
420 }
421 }
422
ShouldBlockHWCNode()423 bool RSProfiler::ShouldBlockHWCNode()
424 {
425 if (!IsEnabled()) {
426 return false;
427 }
428
429 return GetMode() == Mode::READ;
430 }
431
OnFrameBegin()432 void RSProfiler::OnFrameBegin()
433 {
434 if (!IsEnabled()) {
435 return;
436 }
437
438 g_frameBeginTimestamp = RawNowNano();
439 g_renderServiceCpuId = Utils::GetCpuId();
440 g_frameNumber++;
441
442 StartBetaRecord();
443 }
444
OnFrameEnd()445 void RSProfiler::OnFrameEnd()
446 {
447 if (!IsEnabled()) {
448 return;
449 }
450
451 g_renderServiceCpuId = Utils::GetCpuId();
452 ProcessCommands();
453 ProcessSendingRdc();
454 RecordUpdate();
455
456 UpdateDirtyRegionBetaRecord(g_dirtyRegionPercentage);
457 UpdateBetaRecord();
458
459 g_renderServiceCpuId = Utils::GetCpuId();
460 }
461
CalcNodeWeigthOnFrameEnd(uint64_t frameLength)462 void RSProfiler::CalcNodeWeigthOnFrameEnd(uint64_t frameLength)
463 {
464 g_renderServiceRenderCpuId = Utils::GetCpuId();
465
466 if (g_calcPerfNode == 0 || g_calcPerfNodeTry < 0 || g_calcPerfNodeTry > CALC_PERF_NODE_TIME_COUNT) {
467 return;
468 }
469
470 g_calcPerfNodeTime[g_calcPerfNodeTry] = frameLength;
471 g_calcPerfNodeTry++;
472 if (g_calcPerfNodeTry < CALC_PERF_NODE_TIME_COUNT) {
473 AwakeRenderServiceThreadResetCaches();
474 return;
475 }
476
477 constexpr NodeId renderEntireFrame = 1;
478
479 std::sort(std::begin(g_calcPerfNodeTime), std::end(g_calcPerfNodeTime));
480 constexpr int32_t middle = CALC_PERF_NODE_TIME_COUNT / 2;
481 Respond("CALC_PERF_NODE_RESULT: " + std::to_string(g_calcPerfNode) + " " + "cnt=" +
482 std::to_string(g_mapNode2Count[g_calcPerfNode]) + " " + std::to_string(g_calcPerfNodeTime[middle]));
483 Network::SendRSTreeSingleNodePerf(g_calcPerfNode, g_calcPerfNodeTime[middle]);
484
485 if (g_calcPerfNode != renderEntireFrame) {
486 auto parent = GetRenderNode(g_calcPerfNodeParent);
487 auto child = parent ? GetRenderNode(g_calcPerfNode) : nullptr;
488 if (child) {
489 parent->AddChild(child, g_calcPerfNodeIndex);
490 }
491 }
492
493 g_calcPerfNode = 0;
494 g_calcPerfNodeParent = 0;
495 g_calcPerfNodeIndex = 0;
496 g_calcPerfNodeTry = 0;
497
498 if (g_nodeSetPerfCalcIndex >= 0) {
499 g_nodeSetPerfCalcIndex++;
500 CalcPerfNodeAllStep();
501 }
502
503 AwakeRenderServiceThread();
504 g_renderServiceCpuId = Utils::GetCpuId();
505 }
506
RenderServiceTreeDump(JsonWriter & out)507 void RSProfiler::RenderServiceTreeDump(JsonWriter& out)
508 {
509 RS_TRACE_NAME("GetDumpTreeJSON");
510
511 if (!g_context) {
512 return;
513 }
514
515 auto& animation = out["Animation Node"];
516 animation.PushArray();
517 for (auto& [nodeId, _] : g_context->animatingNodeList_) {
518 animation.Append(nodeId);
519 }
520 animation.PopArray();
521
522 auto& root = out["Root node"];
523 const auto rootNode = g_context->GetGlobalRootRenderNode();
524 if (rootNode) {
525 DumpNode(*rootNode, root);
526 } else {
527 root.PushObject();
528 root.PopObject();
529 }
530 }
531
RawNowNano()532 uint64_t RSProfiler::RawNowNano()
533 {
534 return Utils::Now();
535 }
536
NowNano()537 uint64_t RSProfiler::NowNano()
538 {
539 return PatchTime(RawNowNano());
540 }
541
Now()542 double RSProfiler::Now()
543 {
544 return Utils::ToSeconds(NowNano());
545 }
546
IsRecording()547 bool RSProfiler::IsRecording()
548 {
549 return IsEnabled() && g_recordFile.IsOpen();
550 }
551
IsPlaying()552 bool RSProfiler::IsPlaying()
553 {
554 return IsEnabled() && g_playbackFile.IsOpen();
555 }
556
ScheduleTask(std::function<void ()> && task)557 void RSProfiler::ScheduleTask(std::function<void()> && task)
558 {
559 if (g_mainThread) {
560 g_mainThread->PostTask(std::move(task));
561 }
562 }
563
RequestNextVSync()564 void RSProfiler::RequestNextVSync()
565 {
566 if (g_mainThread) {
567 g_mainThread->RequestNextVSync();
568 }
569 ScheduleTask([]() { g_mainThread->RequestNextVSync(); });
570 }
571
AwakeRenderServiceThread()572 void RSProfiler::AwakeRenderServiceThread()
573 {
574 if (g_mainThread) {
575 g_mainThread->RequestNextVSync();
576 g_mainThread->SetAccessibilityConfigChanged();
577 g_mainThread->SetDirtyFlag();
578 }
579 ScheduleTask([]() {
580 g_mainThread->SetAccessibilityConfigChanged();
581 g_mainThread->SetDirtyFlag();
582 g_mainThread->RequestNextVSync();
583 });
584 }
585
AwakeRenderServiceThreadResetCaches()586 void RSProfiler::AwakeRenderServiceThreadResetCaches()
587 {
588 RSMainThread::Instance()->PostTask([]() {
589 RSMainThread::Instance()->SetAccessibilityConfigChanged();
590
591 auto& nodeMap = RSMainThread::Instance()->GetContext().GetMutableNodeMap();
592 nodeMap.TraversalNodes([](const std::shared_ptr<RSBaseRenderNode>& node) {
593 if (node == nullptr) {
594 return;
595 }
596 node->SetSubTreeDirty(true);
597 node->SetContentDirty();
598 node->SetDirty();
599 });
600
601 nodeMap.TraverseSurfaceNodes([](const std::shared_ptr<RSSurfaceRenderNode>& surfaceNode) mutable {
602 if (surfaceNode == nullptr) {
603 return;
604 }
605 surfaceNode->NeedClearBufferCache();
606 surfaceNode->GetRSSurfaceHandler()->ResetBufferAvailableCount();
607 surfaceNode->GetRSSurfaceHandler()->CleanCache();
608 surfaceNode->UpdateBufferInfo(nullptr, {}, nullptr, nullptr);
609 surfaceNode->SetNotifyRTBufferAvailable(false);
610 surfaceNode->SetContentDirty();
611 surfaceNode->ResetHardwareEnabledStates();
612 });
613
614 RSMainThread::Instance()->RequestNextVSync();
615 });
616 }
617
618
ResetAnimationStamp()619 void RSProfiler::ResetAnimationStamp()
620 {
621 if (g_mainThread && g_context) {
622 g_mainThread->lastAnimateTimestamp_ = g_context->GetCurrentTimestamp();
623 }
624 }
625
GetRenderNode(uint64_t id)626 std::shared_ptr<RSRenderNode> RSProfiler::GetRenderNode(uint64_t id)
627 {
628 return g_context ? g_context->GetMutableNodeMap().GetRenderNode(id) : nullptr;
629 }
630
IsLoadSaveFirstScreenInProgress()631 bool RSProfiler::IsLoadSaveFirstScreenInProgress()
632 {
633 return (GetMode() == Mode::WRITE_EMUL || GetMode() == Mode::READ_EMUL);
634 }
635
HiddenSpaceTurnOn()636 void RSProfiler::HiddenSpaceTurnOn()
637 {
638 if (!g_childOfDisplayNodes.empty()) {
639 HiddenSpaceTurnOff();
640 }
641
642 const auto& rootRenderNode = g_context->GetGlobalRootRenderNode();
643 auto& children = *rootRenderNode->GetChildren();
644 if (children.empty()) {
645 return;
646 }
647 if (auto& displayNode = children.front()) {
648 if (auto rootNode = GetRenderNode(Utils::PatchNodeId(0))) {
649 g_childOfDisplayNodes = *displayNode->GetChildren();
650
651 displayNode->ClearChildren();
652 displayNode->AddChild(rootNode);
653 }
654 }
655
656 g_mainThread->SetDirtyFlag();
657 AwakeRenderServiceThread();
658 }
659
HiddenSpaceTurnOff()660 void RSProfiler::HiddenSpaceTurnOff()
661 {
662 const auto& rootRenderNode = g_context->GetGlobalRootRenderNode();
663 const auto& children = *rootRenderNode->GetChildren();
664 if (children.empty()) {
665 return;
666 }
667 if (auto& displayNode = children.front()) {
668 displayNode->ClearChildren();
669 for (const auto& child : g_childOfDisplayNodes) {
670 displayNode->AddChild(child);
671 }
672 FilterMockNode(*g_context);
673 g_childOfDisplayNodes.clear();
674 }
675
676 g_mainThread->SetDirtyFlag();
677
678 AwakeRenderServiceThread();
679 }
680
FirstFrameMarshalling()681 std::string RSProfiler::FirstFrameMarshalling()
682 {
683 std::stringstream stream;
684 SetMode(Mode::WRITE_EMUL);
685 DisableSharedMemory();
686 MarshalNodes(*g_context, stream);
687 EnableSharedMemory();
688 SetMode(Mode::NONE);
689
690 const int32_t focusPid = g_mainThread->focusAppPid_;
691 stream.write(reinterpret_cast<const char*>(&focusPid), sizeof(focusPid));
692
693 const int32_t focusUid = g_mainThread->focusAppUid_;
694 stream.write(reinterpret_cast<const char*>(&focusUid), sizeof(focusUid));
695
696 const uint64_t focusNodeId = g_mainThread->focusNodeId_;
697 stream.write(reinterpret_cast<const char*>(&focusNodeId), sizeof(focusNodeId));
698
699 const std::string bundleName = g_mainThread->focusAppBundleName_;
700 size_t size = bundleName.size();
701 stream.write(reinterpret_cast<const char*>(&size), sizeof(size));
702 stream.write(reinterpret_cast<const char*>(bundleName.data()), size);
703
704 const std::string abilityName = g_mainThread->focusAppAbilityName_;
705 size = abilityName.size();
706 stream.write(reinterpret_cast<const char*>(&size), sizeof(size));
707 stream.write(reinterpret_cast<const char*>(abilityName.data()), size);
708
709 return stream.str();
710 }
711
FirstFrameUnmarshalling(const std::string & data,uint32_t fileVersion)712 void RSProfiler::FirstFrameUnmarshalling(const std::string& data, uint32_t fileVersion)
713 {
714 std::stringstream stream;
715 stream.str(data);
716
717 SetMode(Mode::READ_EMUL);
718
719 DisableSharedMemory();
720 UnmarshalNodes(*g_context, stream, fileVersion);
721 EnableSharedMemory();
722
723 SetMode(Mode::NONE);
724
725 int32_t focusPid = 0;
726 stream.read(reinterpret_cast<char*>(&focusPid), sizeof(focusPid));
727
728 int32_t focusUid = 0;
729 stream.read(reinterpret_cast<char*>(&focusUid), sizeof(focusUid));
730
731 uint64_t focusNodeId = 0;
732 stream.read(reinterpret_cast<char*>(&focusNodeId), sizeof(focusNodeId));
733
734 size_t size = 0;
735 stream.read(reinterpret_cast<char*>(&size), sizeof(size));
736 std::string bundleName;
737 bundleName.resize(size, ' ');
738 stream.read(reinterpret_cast<char*>(bundleName.data()), size);
739
740 stream.read(reinterpret_cast<char*>(&size), sizeof(size));
741 std::string abilityName;
742 abilityName.resize(size, ' ');
743 stream.read(reinterpret_cast<char*>(abilityName.data()), size);
744
745 focusPid = Utils::GetMockPid(focusPid);
746 focusNodeId = Utils::PatchNodeId(focusNodeId);
747
748 CreateMockConnection(focusPid);
749 g_mainThread->SetFocusAppInfo(focusPid, focusUid, bundleName, abilityName, focusNodeId);
750 }
751
SaveRdc(const ArgList & args)752 void RSProfiler::SaveRdc(const ArgList& args)
753 {
754 g_rdcSent = false;
755 RSSystemProperties::SetSaveRDC(true);
756 RSSystemProperties::SetInstantRecording(true);
757
758 AwakeRenderServiceThread();
759 Respond("Recording current frame cmds (for .rdc) into : /data/default.drawing");
760 }
761
SaveSkp(const ArgList & args)762 void RSProfiler::SaveSkp(const ArgList& args)
763 {
764 RSSystemProperties::SetInstantRecording(true);
765 AwakeRenderServiceThread();
766 Respond("Recording current frame cmds into : /data/default.skp");
767 }
768
ProcessSendingRdc()769 void RSProfiler::ProcessSendingRdc()
770 {
771 if (!RSSystemProperties::GetSaveRDC() || g_rdcSent) {
772 return;
773 }
774 AwakeRenderServiceThread();
775
776 if (!RSCaptureRecorder::PullAndSendRdc()) {
777 return;
778 }
779 RSSystemProperties::SetSaveRDC(false);
780 g_rdcSent = true;
781 }
782
GetImagesAdded()783 static uint32_t GetImagesAdded()
784 {
785 const size_t count = ImageCache::Size();
786 const uint32_t added = count - g_lastCacheImageCount;
787 g_lastCacheImageCount = count;
788 return added;
789 }
790
RecordUpdate()791 void RSProfiler::RecordUpdate()
792 {
793 if (!IsRecording() || (g_recordStartTime <= 0.0)) {
794 return;
795 }
796
797 const uint64_t frameLengthNanosecs = RawNowNano() - g_frameBeginTimestamp;
798
799 const double currentTime = g_frameBeginTimestamp * 1e-9; // Now();
800 const double timeSinceRecordStart = currentTime - g_recordStartTime;
801
802 if (timeSinceRecordStart > 0.0) {
803 RSCaptureData captureData;
804 captureData.SetTime(timeSinceRecordStart);
805 captureData.SetProperty(RSCaptureData::KEY_RS_FRAME_NUMBER, g_frameNumber);
806 captureData.SetProperty(RSCaptureData::KEY_RS_FRAME_LEN, frameLengthNanosecs);
807 captureData.SetProperty(RSCaptureData::KEY_RS_CMD_COUNT, GetCommandCount());
808 captureData.SetProperty(RSCaptureData::KEY_RS_CMD_EXECUTE_COUNT, GetCommandExecuteCount());
809 captureData.SetProperty(RSCaptureData::KEY_RS_CMD_PARCEL_LIST, GetCommandParcelList(g_recordStartTime));
810 captureData.SetProperty(RSCaptureData::KEY_RS_PIXEL_IMAGE_ADDED, GetImagesAdded());
811 captureData.SetProperty(RSCaptureData::KEY_RS_DIRTY_REGION, floor(g_dirtyRegionPercentage));
812 captureData.SetProperty(RSCaptureData::KEY_RS_CPU_ID, g_renderServiceCpuId.load());
813
814 std::vector<char> out;
815 DataWriter archive(out);
816 char headerType = static_cast<char>(PackageID::RS_PROFILER_RS_METRICS);
817 archive.Serialize(headerType);
818 captureData.Serialize(archive);
819
820 Network::SendBinary(out.data(), out.size());
821 g_recordFile.WriteRSMetrics(0, timeSinceRecordStart, out.data(), out.size());
822 }
823
824 WriteBetaRecordMetrics(g_recordFile, timeSinceRecordStart);
825 }
826
Respond(const std::string & message)827 void RSProfiler::Respond(const std::string& message)
828 {
829 Network::SendMessage(message);
830 }
831
SetSystemParameter(const ArgList & args)832 void RSProfiler::SetSystemParameter(const ArgList& args)
833 {
834 if (!SystemParameter::Set(args.String(0), args.String(1))) {
835 Respond("There is no such a system parameter");
836 }
837 }
838
GetSystemParameter(const ArgList & args)839 void RSProfiler::GetSystemParameter(const ArgList& args)
840 {
841 const auto parameter = SystemParameter::Find(args.String());
842 Respond(parameter ? parameter->ToString() : "There is no such a system parameter");
843 }
844
DumpSystemParameters(const ArgList & args)845 void RSProfiler::DumpSystemParameters(const ArgList& args)
846 {
847 Respond(SystemParameter::Dump());
848 }
849
DumpConnections(const ArgList & args)850 void RSProfiler::DumpConnections(const ArgList& args)
851 {
852 if (!g_renderService) {
853 return;
854 }
855
856 std::string out;
857 for (const auto& pid : GetConnectionsPids()) {
858 out += "pid=" + std::to_string(pid);
859
860 const std::string path = "/proc/" + std::to_string(pid) + "/cmdline";
861 FILE* file = Utils::FileOpen(path, "r");
862 if (const size_t size = Utils::FileSize(file)) {
863 std::string content;
864 content.resize(size);
865 Utils::FileRead(file, content.data(), content.size());
866 Utils::FileClose(file);
867 out += " ";
868 out += content;
869 }
870 if (Utils::IsFileValid(file)) {
871 Utils::FileClose(file);
872 }
873 out += "\n";
874 }
875 Respond(out);
876 }
877
DumpNodeModifiers(const ArgList & args)878 void RSProfiler::DumpNodeModifiers(const ArgList& args)
879 {
880 if (const auto node = GetRenderNode(args.Node())) {
881 Respond("Modifiers=" + DumpModifiers(*node));
882 }
883 }
884
DumpNodeProperties(const ArgList & args)885 void RSProfiler::DumpNodeProperties(const ArgList& args)
886 {
887 if (const auto node = GetRenderNode(args.Node())) {
888 Respond("RenderProperties=" + DumpRenderProperties(*node));
889 }
890 }
891
DumpTree(const ArgList & args)892 void RSProfiler::DumpTree(const ArgList& args)
893 {
894 if (!g_context) {
895 return;
896 }
897
898 std::map<std::string, std::tuple<NodeId, std::string>> list;
899 GetSurfacesTrees(*g_context, list);
900
901 std::string out = "Tree: count=" + std::to_string(static_cast<int>(GetRenderNodeCount(*g_context))) +
902 " time=" + std::to_string(Now()) + "\n";
903
904 const std::string& node = args.String();
905 for (const auto& item : list) {
906 if (std::strstr(item.first.data(), node.data())) {
907 out += "*** " + item.first + " pid=" + std::to_string(ExtractPid(std::get<0>(item.second))) +
908 " lowId=" + std::to_string(Utils::ExtractNodeId(std::get<0>(item.second))) + "\n" +
909 std::get<1>(item.second) + "\n";
910 }
911 }
912
913 Respond(out);
914 }
915
DumpTreeToJson(const ArgList & args)916 void RSProfiler::DumpTreeToJson(const ArgList& args)
917 {
918 if (!g_context) {
919 return;
920 }
921
922 JsonWriter json;
923 json.PushObject();
924 RenderServiceTreeDump(json);
925
926 auto& display = json["Display"];
927 auto displayNode = GetDisplayNode(*g_context);
928 auto dirtyManager = displayNode ? displayNode->GetDirtyManager() : nullptr;
929 if (dirtyManager) {
930 const auto displayRect = dirtyManager->GetSurfaceRect();
931 display = { displayRect.GetLeft(), displayRect.GetTop(), displayRect.GetRight(), displayRect.GetBottom() };
932 } else {
933 display = { 0.0f, 0.0f, 0.0f, 0.0f };
934 }
935
936 json.PopObject();
937 Network::SendRSTreeDumpJSON(json.GetDumpString());
938 }
939
DumpSurfaces(const ArgList & args)940 void RSProfiler::DumpSurfaces(const ArgList& args)
941 {
942 if (!g_context) {
943 return;
944 }
945
946 std::map<NodeId, std::string> surfaces;
947 GetSurfacesTrees(*g_context, args.Pid(), surfaces);
948
949 std::string out;
950 for (const auto& item : surfaces) {
951 out += "*** " + std::to_string(item.first) + " pid=" + std::to_string(ExtractPid(item.first)) +
952 " lowId=" + std::to_string(Utils::ExtractNodeId(item.first)) + "\n" + item.second + "\n";
953 }
954
955 out += "TREE: count=" + std::to_string(static_cast<int32_t>(GetRenderNodeCount(*g_context))) +
956 " time=" + std::to_string(Now()) + "\n";
957
958 Respond(out);
959 }
960
DumpNodeSurface(const ArgList & args)961 void RSProfiler::DumpNodeSurface(const ArgList& args)
962 {
963 if (g_renderService) {
964 std::string out;
965 g_renderService->DumpSurfaceNode(out, Utils::GetRootNodeId(args.Node()));
966 Respond(out);
967 }
968 }
969
PatchNode(const ArgList & args)970 void RSProfiler::PatchNode(const ArgList& args)
971 {
972 const auto node = GetRenderNode(args.Node());
973 if (!node) {
974 return;
975 }
976
977 const Vector4f screenRect = GetScreenRect(*g_context);
978
979 auto surfaceNode = static_cast<RSSurfaceRenderNode*>(node.get());
980 {
981 auto& region = const_cast<Occlusion::Region&>(surfaceNode->GetVisibleRegion());
982 region = Occlusion::Region({ screenRect[0], screenRect[1], screenRect[2], screenRect[3] }); // NOLINT
983 }
984
985 RSProperties& properties = node->GetMutableRenderProperties();
986 properties.SetBounds(screenRect);
987 properties.SetFrame(screenRect);
988 properties.SetDrawRegion(std::make_shared<RectF>(screenRect));
989
990 AwakeRenderServiceThread();
991 }
992
KillNode(const ArgList & args)993 void RSProfiler::KillNode(const ArgList& args)
994 {
995 if (const auto node = GetRenderNode(args.Node())) {
996 node->RemoveFromTree(false);
997 AwakeRenderServiceThread();
998 Respond("OK");
999 }
1000 }
1001
AttachChild(const ArgList & args)1002 void RSProfiler::AttachChild(const ArgList& args)
1003 {
1004 constexpr size_t parentIndex = 0;
1005 constexpr size_t childIndex = parentIndex + 2;
1006
1007 auto parent = GetRenderNode(Utils::ComposeNodeId(args.Pid(parentIndex), args.Node(parentIndex + 1)));
1008 auto child = GetRenderNode(Utils::ComposeNodeId(args.Pid(childIndex), args.Node(childIndex + 1)));
1009 if (parent && child) {
1010 parent->AddChild(child);
1011 AwakeRenderServiceThread();
1012 Respond("OK");
1013 }
1014 }
1015
KillPid(const ArgList & args)1016 void RSProfiler::KillPid(const ArgList& args)
1017 {
1018 const pid_t pid = args.Pid();
1019 if (const auto node = GetRenderNode(Utils::GetRootNodeId(static_cast<uint64_t>(pid)))) {
1020 const auto parent = node->GetParent().lock();
1021 const std::string out =
1022 "parentPid=" + std::to_string(GetPid(parent)) + " parentNode=" + std::to_string(GetNodeId(parent));
1023
1024 g_context->GetMutableNodeMap().FilterNodeByPid(pid);
1025 AwakeRenderServiceThread();
1026 Respond(out);
1027 }
1028 }
1029
GetRoot(const ArgList & args)1030 void RSProfiler::GetRoot(const ArgList& args)
1031 {
1032 if (!g_context) {
1033 return;
1034 }
1035
1036 std::string out;
1037
1038 const RSRenderNodeMap& map = g_context->GetMutableNodeMap();
1039 std::shared_ptr<RSRenderNode> node = map.GetRenderNode<RSRenderNode>(GetRandomSurfaceNode(*g_context));
1040 while (node && (node->GetId() != 0)) {
1041 std::string type;
1042 const RSRenderNodeType nodeType = node->GetType();
1043 if (nodeType == RSRenderNodeType::UNKNOW) {
1044 type = "UNKNOWN";
1045 } else if (nodeType == RSRenderNodeType::RS_NODE) {
1046 type = "NONE";
1047 } else if (nodeType == RSRenderNodeType::DISPLAY_NODE) {
1048 type = "DISPLAY_NODE";
1049 } else if (nodeType == RSRenderNodeType::EFFECT_NODE) {
1050 type = "EFFECT_NODE";
1051 } else if (nodeType == RSRenderNodeType::ROOT_NODE) {
1052 type = "ROOT_NODE";
1053 } else if (nodeType == RSRenderNodeType::CANVAS_DRAWING_NODE) {
1054 type = "CANVAS_DRAWING_NODE";
1055 }
1056
1057 if (!type.empty()) {
1058 out += "pid=" + std::to_string(GetPid(node)) + " node_id=" + std::to_string(GetNodeId(node)) + "|" + type +
1059 ";\n";
1060 }
1061
1062 node = node->GetParent().lock();
1063 };
1064
1065 if (node) {
1066 out += "ROOT_ID=" + std::to_string(node->GetId()); // DISPLAY_NODE;ohos.sceneboard
1067 }
1068
1069 Respond(out);
1070 }
1071
GetDeviceInfo(const ArgList & args)1072 void RSProfiler::GetDeviceInfo(const ArgList& args)
1073 {
1074 Respond(RSTelemetry::GetDeviceInfoString());
1075 }
1076
GetDeviceFrequency(const ArgList & args)1077 void RSProfiler::GetDeviceFrequency(const ArgList& args)
1078 {
1079 Respond(RSTelemetry::GetDeviceFrequencyString());
1080 Respond(RSTelemetry::GetCpuAffinityString());
1081 }
1082
FixDeviceEnv(const ArgList & args)1083 void RSProfiler::FixDeviceEnv(const ArgList& args)
1084 {
1085 constexpr int32_t cpu = 8;
1086 Utils::SetCpuAffinity(cpu);
1087 Respond("OK");
1088 }
1089
GetPerfTree(const ArgList & args)1090 void RSProfiler::GetPerfTree(const ArgList& args)
1091 {
1092 if (!g_context) {
1093 return;
1094 }
1095
1096 g_nodeSetPerf.clear();
1097 g_mapNode2Count.clear();
1098
1099 auto& rootNode = g_context->GetGlobalRootRenderNode();
1100 auto rootNodeChildren = rootNode ? rootNode->GetSortedChildren() : nullptr;
1101 if (!rootNodeChildren) {
1102 Respond("ERROR");
1103 return;
1104 }
1105
1106 for (const auto& child : *rootNodeChildren) {
1107 auto displayNode = RSBaseRenderNode::ReinterpretCast<RSDisplayRenderNode>(child);
1108 if (!displayNode) {
1109 continue;
1110 }
1111 std::vector<RSBaseRenderNode::SharedPtr> curAllSurfaces;
1112 displayNode->CollectSurface(displayNode, curAllSurfaces, true, false);
1113 for (auto& node : curAllSurfaces) {
1114 if (node) {
1115 PerfTreeFlatten(*node, g_nodeSetPerf, g_mapNode2Count);
1116 }
1117 }
1118 }
1119
1120 std::string outString;
1121 auto& nodeMap = g_context->GetMutableNodeMap();
1122 for (auto it = g_nodeSetPerf.begin(); it != g_nodeSetPerf.end(); it++) {
1123 auto node = nodeMap.GetRenderNode(*it);
1124 if (!node) {
1125 continue;
1126 }
1127 std::string sNodeType;
1128 RSRenderNode::DumpNodeType(node->GetType(), sNodeType);
1129 outString += (it != g_nodeSetPerf.begin() ? ", " : "") + std::to_string(*it) + ":" +
1130 std::to_string(g_mapNode2Count[*it]) + " [" + sNodeType + "]";
1131 }
1132
1133 Network::SendRSTreePerfNodeList(g_nodeSetPerf);
1134 Respond("OK: Count=" + std::to_string(g_nodeSetPerf.size()) + " LIST=[" + outString + "]");
1135 }
1136
CalcPerfNode(const ArgList & args)1137 void RSProfiler::CalcPerfNode(const ArgList& args)
1138 {
1139 g_calcPerfNode = args.Uint64();
1140 auto node = GetRenderNode(g_calcPerfNode);
1141 const auto parent = node ? node->GetParent().lock() : nullptr;
1142 auto parentChildren = parent ? parent->GetChildren() : nullptr;
1143 if (!parentChildren) {
1144 return;
1145 }
1146
1147 int index = 0;
1148 g_calcPerfNodeParent = parent->GetId();
1149 for (const auto& child : *parentChildren) {
1150 if (child && child->GetId() == node->GetId()) {
1151 g_calcPerfNodeIndex = index;
1152 }
1153 }
1154
1155 parent->RemoveChild(node);
1156 Respond("CalcPerfNode: NodeRemoved index=" + std::to_string(index));
1157 AwakeRenderServiceThread();
1158 }
1159
SocketShutdown(const ArgList & args)1160 void RSProfiler::SocketShutdown(const ArgList& args)
1161 {
1162 Network::ForceShutdown();
1163 }
1164
Version(const ArgList & args)1165 void RSProfiler::Version(const ArgList& args)
1166 {
1167 Respond("Version: " + std::to_string(RSFILE_VERSION_LATEST));
1168 }
1169
FileVersion(const ArgList & args)1170 void RSProfiler::FileVersion(const ArgList& args)
1171 {
1172 Respond("File version: " + std::to_string(RSFILE_VERSION_LATEST));
1173 }
1174
CalcPerfNodeAll(const ArgList & args)1175 void RSProfiler::CalcPerfNodeAll(const ArgList& args)
1176 {
1177 if (g_nodeSetPerf.empty()) {
1178 Respond("ERROR");
1179 return;
1180 }
1181
1182 g_nodeSetPerfCalcIndex = 0;
1183 CalcPerfNodeAllStep();
1184
1185 AwakeRenderServiceThread();
1186 }
1187
CalcPerfNodeAllStep()1188 void RSProfiler::CalcPerfNodeAllStep()
1189 {
1190 if (g_nodeSetPerfCalcIndex < 0) {
1191 return;
1192 }
1193
1194 if (g_nodeSetPerfCalcIndex == 0) {
1195 g_calcPerfNode = 1;
1196 AwakeRenderServiceThread();
1197 return;
1198 }
1199
1200 if (g_nodeSetPerfCalcIndex - 1 < static_cast<int32_t>(g_nodeSetPerf.size())) {
1201 auto it = g_nodeSetPerf.begin();
1202 std::advance(it, g_nodeSetPerfCalcIndex - 1);
1203 g_calcPerfNode = *it;
1204 } else {
1205 g_nodeSetPerfCalcIndex = -1;
1206 return;
1207 }
1208
1209 auto node = GetRenderNode(g_calcPerfNode);
1210 const auto parent = node ? node->GetParent().lock() : nullptr;
1211 auto parentChildren = parent ? parent->GetChildren() : nullptr;
1212 if (!parentChildren) {
1213 g_nodeSetPerfCalcIndex = -1;
1214 return;
1215 }
1216
1217 int index = 0;
1218 g_calcPerfNodeParent = parent->GetId();
1219 for (const auto& child : *parentChildren) {
1220 if (child && child->GetId() == node->GetId()) {
1221 g_calcPerfNodeIndex = index;
1222 }
1223 }
1224
1225 parent->RemoveChild(node);
1226 AwakeRenderServiceThread();
1227 }
1228
TestSaveFrame(const ArgList & args)1229 void RSProfiler::TestSaveFrame(const ArgList& args)
1230 {
1231 g_testDataFrame = FirstFrameMarshalling();
1232 Respond("Save Frame Size: " + std::to_string(g_testDataFrame.size()));
1233 }
1234
TestLoadFrame(const ArgList & args)1235 void RSProfiler::TestLoadFrame(const ArgList& args)
1236 {
1237 FirstFrameUnmarshalling(g_testDataFrame, RSFILE_VERSION_LATEST);
1238 Respond("Load Frame Size: " + std::to_string(g_testDataFrame.size()));
1239 }
1240
TestSwitch(const ArgList & args)1241 void RSProfiler::TestSwitch(const ArgList& args)
1242 {
1243 if (g_childOfDisplayNodes.empty()) {
1244 HiddenSpaceTurnOn();
1245 Respond("OK: HiddenSpaceTurnOn");
1246 } else {
1247 HiddenSpaceTurnOff();
1248 Respond("OK: HiddenSpaceTurnOff");
1249 }
1250 }
1251
RecordStart(const ArgList & args)1252 void RSProfiler::RecordStart(const ArgList& args)
1253 {
1254 g_recordStartTime = 0.0;
1255
1256 ImageCache::Reset();
1257 g_lastCacheImageCount = 0;
1258
1259 if (!OpenBetaRecordFile(g_recordFile)) {
1260 g_recordFile.Create(RSFile::GetDefaultPath());
1261 }
1262
1263 g_recordFile.AddLayer(); // add 0 layer
1264
1265 FilterMockNode(*g_context);
1266
1267 g_recordFile.AddHeaderFirstFrame(FirstFrameMarshalling());
1268
1269 const std::vector<pid_t> pids = GetConnectionsPids();
1270 for (pid_t pid : pids) {
1271 g_recordFile.AddHeaderPid(pid);
1272 }
1273
1274 SetMode(Mode::WRITE);
1275
1276 g_recordStartTime = Now();
1277 g_frameNumber = 0;
1278
1279 if (IsBetaRecordStarted()) {
1280 return;
1281 }
1282
1283 std::thread thread([]() {
1284 while (IsRecording()) {
1285 if (g_recordStartTime >= 0) {
1286 SendTelemetry(Now() - g_recordStartTime);
1287 }
1288 static constexpr int32_t GFX_METRICS_SEND_INTERVAL = 8;
1289 std::this_thread::sleep_for(std::chrono::milliseconds(GFX_METRICS_SEND_INTERVAL));
1290 }
1291 });
1292 thread.detach();
1293
1294 Respond("Network: Record start");
1295 }
1296
RecordStop(const ArgList & args)1297 void RSProfiler::RecordStop(const ArgList& args)
1298 {
1299 if (!IsRecording()) {
1300 return;
1301 }
1302
1303 g_recordFile.SetWriteTime(g_recordStartTime);
1304
1305 std::stringstream stream(std::ios::in | std::ios::out | std::ios::binary);
1306
1307 if (!IsBetaRecordStarted()) {
1308 // DOUBLE WORK - send header of file
1309 const char headerType = 0;
1310 stream.write(reinterpret_cast<const char*>(&headerType), sizeof(headerType));
1311 stream.write(reinterpret_cast<const char*>(&g_recordStartTime), sizeof(g_recordStartTime));
1312
1313 const uint32_t pidCount = g_recordFile.GetHeaderPids().size();
1314 stream.write(reinterpret_cast<const char*>(&pidCount), sizeof(pidCount));
1315 for (auto item : g_recordFile.GetHeaderPids()) {
1316 stream.write(reinterpret_cast<const char*>(&item), sizeof(item));
1317 }
1318
1319 uint32_t sizeFirstFrame = static_cast<uint32_t>(g_recordFile.GetHeaderFirstFrame().size());
1320 stream.write(reinterpret_cast<const char*>(&sizeFirstFrame), sizeof(sizeFirstFrame));
1321 stream.write(reinterpret_cast<const char*>(&g_recordFile.GetHeaderFirstFrame()[0]), sizeFirstFrame);
1322
1323 ImageCache::Serialize(stream);
1324 Network::SendBinary(stream.str().data(), stream.str().size());
1325 }
1326 SaveBetaRecordFile(g_recordFile);
1327 g_recordFile.Close();
1328 g_recordStartTime = 0.0;
1329
1330 ImageCache::Reset();
1331 g_lastCacheImageCount = 0;
1332
1333 Respond("Network: Record stop (" + std::to_string(stream.str().size()) + ")");
1334 }
1335
PlaybackPrepareFirstFrame(const ArgList & args)1336 void RSProfiler::PlaybackPrepareFirstFrame(const ArgList& args)
1337 {
1338 g_playbackPid = args.Pid();
1339 g_playbackStartTime = 0.0;
1340 g_playbackPauseTime = args.Fp64(1);
1341 std::string path = args.String(2);
1342 if (!Utils::FileExists(path)) {
1343 Respond("Can't playback non existing file '" + path + "'");
1344 path = RSFile::GetDefaultPath();
1345 }
1346
1347 ImageCache::Reset();
1348
1349 Respond("Opening file " + path);
1350 g_playbackFile.Open(path);
1351 if (!g_playbackFile.IsOpen()) {
1352 Respond("Can't open file.");
1353 return;
1354 }
1355 std::string dataFirstFrame = g_playbackFile.GetHeaderFirstFrame();
1356
1357 // get first frame data
1358 FirstFrameUnmarshalling(dataFirstFrame, g_playbackFile.GetVersion());
1359 // The number of frames loaded before command processing
1360 constexpr int defaultWaitFrames = 5;
1361 g_playbackWaitFrames = defaultWaitFrames;
1362 Respond("awake_frame " + std::to_string(g_playbackWaitFrames));
1363 AwakeRenderServiceThread();
1364 }
1365
PlaybackStart(const ArgList & args)1366 void RSProfiler::PlaybackStart(const ArgList& args)
1367 {
1368 HiddenSpaceTurnOn();
1369
1370 for (size_t pid : g_playbackFile.GetHeaderPids()) {
1371 CreateMockConnection(Utils::GetMockPid(pid));
1372 }
1373
1374 g_playbackStartTime = Now();
1375
1376 const double pauseTime = g_playbackPauseTime;
1377 if (pauseTime > 0.0) {
1378 const uint64_t currentTime = RawNowNano();
1379 const uint64_t pauseTimeStart = currentTime + Utils::ToNanoseconds(pauseTime);
1380 TimePauseAt(currentTime, pauseTimeStart);
1381 }
1382
1383 AwakeRenderServiceThread();
1384
1385 g_playbackShouldBeTerminated = false;
1386
1387 const auto timeoutLimit = args.Int64();
1388 std::thread thread([timeoutLimit]() {
1389 while (IsPlaying()) {
1390 const int64_t timestamp = static_cast<int64_t>(RawNowNano());
1391
1392 PlaybackUpdate();
1393 if (g_playbackStartTime >= 0) {
1394 SendTelemetry(Now() - g_playbackStartTime);
1395 }
1396
1397 const int64_t timeout = timeoutLimit - static_cast<int64_t>(RawNowNano()) + timestamp;
1398 if (timeout > 0) {
1399 std::this_thread::sleep_for(std::chrono::nanoseconds(timeout));
1400 }
1401 }
1402 });
1403 thread.detach();
1404
1405 Respond("Playback start");
1406 }
1407
PlaybackStop(const ArgList & args)1408 void RSProfiler::PlaybackStop(const ArgList& args)
1409 {
1410 if (g_childOfDisplayNodes.empty()) {
1411 return;
1412 }
1413 HiddenSpaceTurnOff();
1414 FilterMockNode(*g_context);
1415 g_playbackShouldBeTerminated = true;
1416
1417 Respond("Playback stop");
1418 }
1419
PlaybackUpdate()1420 void RSProfiler::PlaybackUpdate()
1421 {
1422 if (!IsPlaying()) {
1423 return;
1424 }
1425
1426 const double deltaTime = Now() - g_playbackStartTime;
1427
1428 std::vector<uint8_t> data;
1429 double readTime = 0.0;
1430 if (!g_playbackShouldBeTerminated && g_playbackFile.ReadRSData(deltaTime, data, readTime)) {
1431 std::stringstream stream(std::ios::in | std::ios::out | std::ios::binary);
1432 stream.write(reinterpret_cast<const char*>(data.data()), data.size());
1433 stream.seekg(0);
1434
1435 pid_t pid = 0;
1436 stream.read(reinterpret_cast<char*>(&pid), sizeof(pid));
1437
1438 RSRenderServiceConnection* connection = GetConnection(Utils::GetMockPid(pid));
1439 if (!connection) {
1440 const std::vector<pid_t>& pids = g_playbackFile.GetHeaderPids();
1441 if (!pids.empty()) {
1442 connection = GetConnection(Utils::GetMockPid(pids[0]));
1443 }
1444 }
1445
1446 if (connection) {
1447 uint32_t code = 0;
1448 stream.read(reinterpret_cast<char*>(&code), sizeof(code));
1449
1450 size_t dataSize = 0;
1451 stream.read(reinterpret_cast<char*>(&dataSize), sizeof(dataSize));
1452
1453 auto* data = new uint8_t[dataSize];
1454 stream.read(reinterpret_cast<char*>(data), dataSize);
1455
1456 int32_t flags = 0;
1457 stream.read(reinterpret_cast<char*>(&flags), sizeof(flags));
1458
1459 int32_t waitTime = 0;
1460 stream.read(reinterpret_cast<char*>(&waitTime), sizeof(waitTime));
1461
1462 AlignedMessageParcel parcel;
1463 parcel.parcel.SetMaxCapacity(dataSize + 1);
1464 parcel.parcel.WriteBuffer(data, dataSize);
1465
1466 delete[] data;
1467
1468 MessageOption option;
1469 option.SetFlags(flags);
1470 option.SetWaitTime(waitTime);
1471
1472 MessageParcel reply;
1473 connection->OnRemoteRequest(code, parcel.parcel, reply, option);
1474 }
1475 }
1476
1477 if (g_playbackShouldBeTerminated || g_playbackFile.RSDataEOF()) {
1478 g_playbackStartTime = 0.0;
1479 g_playbackFile.Close();
1480 g_playbackPid = 0;
1481 TimePauseClear();
1482 g_playbackShouldBeTerminated = false;
1483 }
1484 }
1485
PlaybackPrepare(const ArgList & args)1486 void RSProfiler::PlaybackPrepare(const ArgList& args)
1487 {
1488 const pid_t pid = args.Pid();
1489 if (!g_context || (pid == 0)) {
1490 return;
1491 }
1492
1493 FilterForPlayback(*g_context, pid);
1494 AwakeRenderServiceThread();
1495 Respond("OK");
1496 }
1497
PlaybackPause(const ArgList & args)1498 void RSProfiler::PlaybackPause(const ArgList& args)
1499 {
1500 if (!IsPlaying()) {
1501 return;
1502 }
1503
1504 const uint64_t currentTime = RawNowNano();
1505 const double recordPlayTime = Now() - g_playbackStartTime;
1506 TimePauseAt(currentTime, currentTime);
1507 Respond("OK: " + std::to_string(recordPlayTime));
1508 }
1509
PlaybackPauseAt(const ArgList & args)1510 void RSProfiler::PlaybackPauseAt(const ArgList& args)
1511 {
1512 if (!IsPlaying()) {
1513 return;
1514 }
1515
1516 const double pauseTime = args.Fp64();
1517 const double recordPlayTime = Now() - g_playbackStartTime;
1518 if (recordPlayTime > pauseTime) {
1519 return;
1520 }
1521
1522 const uint64_t currentTime = RawNowNano();
1523 const uint64_t pauseTimeStart = currentTime + Utils::ToNanoseconds(pauseTime - recordPlayTime);
1524
1525 TimePauseAt(currentTime, pauseTimeStart);
1526 ResetAnimationStamp();
1527 Respond("OK");
1528 }
1529
PlaybackPauseClear(const ArgList & args)1530 void RSProfiler::PlaybackPauseClear(const ArgList& args)
1531 {
1532 TimePauseClear();
1533 Respond("OK");
1534 }
1535
PlaybackResume(const ArgList & args)1536 void RSProfiler::PlaybackResume(const ArgList& args)
1537 {
1538 if (!IsPlaying()) {
1539 return;
1540 }
1541
1542 TimePauseResume(Utils::Now());
1543 ResetAnimationStamp();
1544 Respond("OK");
1545 }
1546
GetCommand(const std::string & command)1547 RSProfiler::Command RSProfiler::GetCommand(const std::string& command)
1548 {
1549 static const std::map<std::string, Command> COMMANDS = {
1550 { "rstree_contains", DumpTree },
1551 { "rstree_fix", PatchNode },
1552 { "rstree_kill_node", KillNode },
1553 { "rstree_setparent", AttachChild },
1554 { "rstree_getroot", GetRoot },
1555 { "rstree_node_mod", DumpNodeModifiers },
1556 { "rstree_node_prop", DumpNodeProperties },
1557 { "rstree_pid", DumpSurfaces },
1558 { "rstree_kill_pid", KillPid },
1559 { "rstree_prepare_replay", PlaybackPrepare },
1560 { "rstree_save_frame", TestSaveFrame },
1561 { "rstree_load_frame", TestLoadFrame },
1562 { "rstree_switch", TestSwitch },
1563 { "rstree_dump_json", DumpTreeToJson },
1564 { "rsrecord_start", RecordStart },
1565 { "rsrecord_stop", RecordStop },
1566 { "rsrecord_replay_prepare", PlaybackPrepareFirstFrame },
1567 { "rsrecord_replay", PlaybackStart },
1568 { "rsrecord_replay_stop", PlaybackStop },
1569 { "rsrecord_pause_now", PlaybackPause },
1570 { "rsrecord_pause_at", PlaybackPauseAt },
1571 { "rsrecord_pause_resume", PlaybackResume },
1572 { "rsrecord_pause_clear", PlaybackPauseClear },
1573 { "rssurface_pid", DumpNodeSurface },
1574 { "rscon_print", DumpConnections },
1575 { "save_rdc", SaveRdc },
1576 { "save_skp", SaveSkp },
1577 { "info", GetDeviceInfo },
1578 { "freq", GetDeviceFrequency },
1579 { "fixenv", FixDeviceEnv },
1580 { "set", SetSystemParameter },
1581 { "get", GetSystemParameter },
1582 { "params", DumpSystemParameters },
1583 { "get_perf_tree", GetPerfTree },
1584 { "calc_perf_node", CalcPerfNode },
1585 { "calc_perf_node_all", CalcPerfNodeAll },
1586 { "socket_shutdown", SocketShutdown },
1587 { "version", Version },
1588 { "file_version", FileVersion },
1589 };
1590
1591 if (command.empty()) {
1592 return nullptr;
1593 }
1594
1595 const auto delegate = COMMANDS.find(command);
1596 return (delegate != COMMANDS.end()) ? delegate->second : nullptr;
1597 }
1598
ProcessCommands()1599 void RSProfiler::ProcessCommands()
1600 {
1601 if (g_playbackWaitFrames > 0) {
1602 g_playbackWaitFrames--;
1603 Respond("awake_frame " + std::to_string(g_playbackWaitFrames));
1604 AwakeRenderServiceThread();
1605 return;
1606 }
1607
1608 std::vector<std::string> commandData;
1609 if (!Network::PopCommand(commandData)) {
1610 return;
1611 }
1612
1613 const std::string& command = commandData[0];
1614 if (const Command delegate = GetCommand(command)) {
1615 const ArgList args =
1616 (commandData.size() > 1) ? ArgList({ commandData.begin() + 1, commandData.end() }) : ArgList();
1617 delegate(args);
1618 } else if (!command.empty()) {
1619 Respond("Command has not been found: " + command);
1620 }
1621 }
1622
GetFrameNumber()1623 uint32_t RSProfiler::GetFrameNumber()
1624 {
1625 return g_frameNumber;
1626 }
1627
1628 } // namespace OHOS::Rosen