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 "foundation/graphic/graphic_2d/utils/log/rs_trace.h"
17 #include "rs_profiler.h"
18 #include "rs_profiler_json.h"
19 #include "rs_profiler_network.h"
20 
21 #include "common/rs_obj_geometry.h"
22 #include "pipeline/rs_context.h"
23 #include "pipeline/rs_display_render_node.h"
24 #include "pipeline/rs_root_render_node.h"
25 #include "pipeline/rs_surface_handler.h"
26 #include "pipeline/rs_surface_render_node.h"
27 
28 namespace OHOS::Rosen {
29 
DumpNode(const RSRenderNode & node,JsonWriter & out)30 void RSProfiler::DumpNode(const RSRenderNode& node, JsonWriter& out)
31 {
32     out.PushObject();
33     DumpNodeBaseInfo(node, out);
34     DumpNodeProperties(node.GetRenderProperties(), out);
35     DumpNodeOptionalFlags(node, out);
36     DumpNodeDrawCmdModifiers(node, out);
37     DumpNodeAnimations(node.animationManager_, out);
38     DumpNodeChildrenListUpdate(node, out);
39 
40     auto& children = out["children"];
41     children.PushArray();
42     if (node.GetSortedChildren()) {
43         for (auto& child : *node.GetSortedChildren()) {
44             if (child) {
45                 DumpNode(*child, children);
46             }
47         }
48     }
49     children.PopArray();
50     out.PopObject();
51 }
52 
DumpNodeBaseInfo(const RSRenderNode & node,JsonWriter & out)53 void RSProfiler::DumpNodeBaseInfo(const RSRenderNode& node, JsonWriter& out)
54 {
55     std::string type;
56     node.DumpNodeType(node.GetType(), type);
57     out["type"] = type;
58     out["id"] = node.GetId();
59     out["instanceRootNodeId"] = node.GetInstanceRootNodeId();
60     DumpNodeSubsurfaces(node, out);
61     auto sharedTrans = node.GetSharedTransitionParam();
62     if (sharedTrans) {
63         out["SharedTransitionParam"] =
64             std::to_string(sharedTrans->inNodeId_) + " -> " + std::to_string(sharedTrans->outNodeId_);
65     }
66     if (node.IsSuggestedDrawInGroup()) {
67         out["nodeGroup"] = static_cast<int>(node.nodeGroupType_);
68     }
69     if (node.GetUifirstRootNodeId() != INVALID_NODEID) {
70         out["uifirstRootNodeId"] = node.GetUifirstRootNodeId();
71     }
72     DumpNodeSubClassNode(node, out);
73 }
74 
DumpNodeSubsurfaces(const RSRenderNode & node,JsonWriter & out)75 void RSProfiler::DumpNodeSubsurfaces(const RSRenderNode& node, JsonWriter& out)
76 {
77     if (auto surface = node.ReinterpretCastTo<RSSurfaceRenderNode>(); surface && surface->HasSubSurfaceNodes()) {
78         auto& subsurface = out["subsurface"];
79         subsurface.PushArray();
80         for (auto [id, _] : surface->GetChildSubSurfaceNodes()) {
81             subsurface.Append(id);
82         }
83         subsurface.PopArray();
84     }
85 }
86 
DumpNodeSubClassNode(const RSRenderNode & node,JsonWriter & out)87 void RSProfiler::DumpNodeSubClassNode(const RSRenderNode& node, JsonWriter& out)
88 {
89     auto& subclass = out["subclass"];
90     subclass.PushObject();
91     if (node.GetType() == RSRenderNodeType::SURFACE_NODE) {
92         auto& surfaceNode = static_cast<const RSSurfaceRenderNode&>(node);
93         auto p = node.parent_.lock();
94         subclass["Parent"] = p ? p->GetId() : uint64_t(0);
95         subclass["Name"] = surfaceNode.GetName();
96         out["hasConsumer"] = surfaceNode.GetRSSurfaceHandler()->HasConsumer();
97         std::string contextAlpha = std::to_string(surfaceNode.contextAlpha_);
98         std::string propertyAlpha = std::to_string(surfaceNode.GetRenderProperties().GetAlpha());
99         subclass["Alpha"] = propertyAlpha + " (include ContextAlpha: " + contextAlpha + ")";
100         subclass["Visible"] = std::to_string(surfaceNode.GetRenderProperties().GetVisible()) + " " +
101                               surfaceNode.GetVisibleRegion().GetRegionInfo();
102         subclass["Opaque"] = surfaceNode.GetOpaqueRegion().GetRegionInfo();
103         subclass["OcclusionBg"] = std::to_string((surfaceNode.GetAbilityBgAlpha()));
104         subclass["SecurityLayer"] = surfaceNode.GetSecurityLayer();
105         subclass["skipLayer"] = surfaceNode.GetSkipLayer();
106     } else if (node.GetType() == RSRenderNodeType::ROOT_NODE) {
107         auto& rootNode = static_cast<const RSRootRenderNode&>(node);
108         subclass["Visible"] = rootNode.GetRenderProperties().GetVisible();
109         subclass["Size"] = { rootNode.GetRenderProperties().GetFrameWidth(),
110             rootNode.GetRenderProperties().GetFrameHeight() };
111         subclass["EnableRender"] = rootNode.GetEnableRender();
112     } else if (node.GetType() == RSRenderNodeType::DISPLAY_NODE) {
113         auto& displayNode = static_cast<const RSDisplayRenderNode&>(node);
114         subclass["skipLayer"] = displayNode.GetSecurityDisplay();
115     }
116     subclass.PopObject();
117 }
118 
DumpNodeOptionalFlags(const RSRenderNode & node,JsonWriter & out)119 void RSProfiler::DumpNodeOptionalFlags(const RSRenderNode& node, JsonWriter& out)
120 {
121     if (node.GetBootAnimation()) {
122         out["GetBootAnimation"] = true;
123     }
124     if (node.isContainBootAnimation_) {
125         out["isContainBootAnimation_"] = true;
126     }
127     if (node.dirtyStatus_ != RSRenderNode::NodeDirty::CLEAN) {
128         out["isNodeDirty"] = static_cast<int>(node.dirtyStatus_);
129     }
130     if (node.GetRenderProperties().IsDirty()) {
131         out["isPropertyDirty"] = true;
132     }
133     if (node.isSubTreeDirty_) {
134         out["isSubTreeDirty"] = true;
135     }
136     if (node.IsPureContainer()) {
137         out["IsPureContainer"] = true;
138     }
139 }
140 
DumpNodeDrawCmdModifiers(const RSRenderNode & node,JsonWriter & out)141 void RSProfiler::DumpNodeDrawCmdModifiers(const RSRenderNode& node, JsonWriter& out)
142 {
143     if (!node.renderContent_) {
144         return;
145     }
146 
147     auto& modifiersJson = out["DrawCmdModifiers"];
148     modifiersJson.PushArray();
149     for (auto& [type, modifiers] : node.renderContent_->drawCmdModifiers_) {
150         modifiersJson.PushObject();
151         modifiersJson["type"] = static_cast<int>(type);
152         auto& modifierDesc = modifiersJson["modifiers"];
153         modifierDesc.PushArray();
154         for (const auto& modifier : modifiers) {
155             if (modifier) {
156                 DumpNodeDrawCmdModifier(node, modifierDesc, static_cast<int>(type), *modifier);
157             }
158         }
159         modifiersJson.PopArray();
160         modifiersJson.PopObject();
161     }
162     modifiersJson.PopArray();
163 }
164 
Hex(uint32_t value)165 static std::string Hex(uint32_t value)
166 {
167     std::stringstream sstream;
168     sstream << std::hex << value;
169     return sstream.str();
170 }
171 
DumpNodeDrawCmdModifier(const RSRenderNode & node,JsonWriter & out,int type,RSRenderModifier & modifier)172 void RSProfiler::DumpNodeDrawCmdModifier(
173     const RSRenderNode& node, JsonWriter& out, int type, RSRenderModifier& modifier)
174 {
175     auto modType = static_cast<RSModifierType>(type);
176 
177     if (modType < RSModifierType::ENV_FOREGROUND_COLOR) {
178         auto propertyPtr = std::static_pointer_cast<RSRenderProperty<Drawing::DrawCmdListPtr>>(modifier.GetProperty());
179         auto drawCmdListPtr = propertyPtr ? propertyPtr->Get() : nullptr;
180         auto propertyStr = drawCmdListPtr ? drawCmdListPtr->GetOpsWithDesc() : "";
181         size_t pos = 0;
182         size_t oldpos = 0;
183 
184         out.PushObject();
185         auto& property = out["drawCmdList"];
186         property.PushArray();
187         while ((pos = propertyStr.find('\n', oldpos)) != std::string::npos) {
188             property.Append(propertyStr.substr(oldpos, pos - oldpos));
189             oldpos = pos + 1;
190         }
191         property.PopArray();
192         out.PopObject();
193     } else if (modType == RSModifierType::ENV_FOREGROUND_COLOR) {
194         auto propertyPtr = std::static_pointer_cast<RSRenderAnimatableProperty<Color>>(modifier.GetProperty());
195         if (propertyPtr) {
196             out.PushObject();
197             out["ENV_FOREGROUND_COLOR"] = "#" + Hex(propertyPtr->Get().AsRgbaInt()) + " (RGBA)";
198             out.PopObject();
199         }
200     } else if (modType == RSModifierType::ENV_FOREGROUND_COLOR_STRATEGY) {
201         auto propertyPtr =
202             std::static_pointer_cast<RSRenderProperty<ForegroundColorStrategyType>>(modifier.GetProperty());
203         if (propertyPtr) {
204             out.PushObject();
205             out["ENV_FOREGROUND_COLOR_STRATEGY"] = static_cast<int>(propertyPtr->Get());
206             out.PopObject();
207         }
208     } else if (modType == RSModifierType::GEOMETRYTRANS) {
209         auto propertyPtr = std::static_pointer_cast<RSRenderProperty<SkMatrix>>(modifier.GetProperty());
210         if (propertyPtr) {
211             std::string str;
212             propertyPtr->Get().dump(str, 0);
213             out.PushObject();
214             out["GEOMETRYTRANS"] = str;
215             out.PopObject();
216         }
217     } else if (modType == RSModifierType::CUSTOM_CLIP_TO_FRAME) {
218         auto propertyPtr = std::static_pointer_cast<RSRenderAnimatableProperty<Vector4f>>(modifier.GetProperty());
219         if (propertyPtr) {
220             std::string str;
221             propertyPtr->Dump(str);
222             out.PushObject();
223             out["CUSTOM_CLIP_TO_FRAME"] = str;
224             out.PopObject();
225         }
226     }
227 }
228 
DumpNodeProperties(const RSProperties & properties,JsonWriter & out)229 void RSProfiler::DumpNodeProperties(const RSProperties& properties, JsonWriter& out)
230 {
231     auto& json = out["Properties"];
232     json.PushObject();
233     json["Bounds"] = { properties.GetBoundsPositionX(), properties.GetBoundsPositionY(), properties.GetBoundsWidth(),
234         properties.GetBoundsHeight() };
235     json["Frame"] = { properties.GetFramePositionX(), properties.GetFramePositionY(), properties.GetFrameWidth(),
236         properties.GetFrameHeight() };
237 
238     if (!properties.GetVisible()) {
239         json["IsVisible"] = false;
240     }
241     DumpNodePropertiesClip(properties, json);
242     DumpNodePropertiesTransform(properties, json);
243     DumpNodePropertiesDecoration(properties, json);
244     DumpNodePropertiesShadow(properties, json);
245     DumpNodePropertiesEffects(properties, json);
246     DumpNodePropertiesColor(properties, json);
247     json.PopObject();
248 }
249 
DumpNodePropertiesClip(const RSProperties & properties,JsonWriter & out)250 void RSProfiler::DumpNodePropertiesClip(const RSProperties& properties, JsonWriter& out)
251 {
252     if (properties.clipToBounds_) {
253         out["ClipToBounds"] = true;
254     }
255     if (properties.clipToFrame_) {
256         out["ClipToFrame"] = true;
257     }
258 }
259 
DumpNodePropertiesTransform(const RSProperties & properties,JsonWriter & out)260 void RSProfiler::DumpNodePropertiesTransform(const RSProperties& properties, JsonWriter& out)
261 {
262     if (!ROSEN_EQ(properties.GetPositionZ(), 0.f)) {
263         out["PositionZ"] = properties.GetPositionZ();
264     }
265     RSTransform defaultTransform;
266     Vector2f pivot = properties.GetPivot();
267     if ((!ROSEN_EQ(pivot[0], defaultTransform.pivotX_) || !ROSEN_EQ(pivot[1], defaultTransform.pivotY_))) {
268         out["Pivot"] = { pivot[0], pivot[1] };
269     }
270     if (!ROSEN_EQ(properties.GetRotation(), defaultTransform.rotation_)) {
271         out["Rotation"] = properties.GetRotation();
272     }
273     if (!ROSEN_EQ(properties.GetRotationX(), defaultTransform.rotationX_)) {
274         out["RotationX"] = properties.GetRotationX();
275     }
276     if (!ROSEN_EQ(properties.GetRotationY(), defaultTransform.rotationY_)) {
277         out["RotationY"] = properties.GetRotationY();
278     }
279     if (!ROSEN_EQ(properties.GetTranslateX(), defaultTransform.translateX_)) {
280         out["TranslateX"] = properties.GetTranslateX();
281     }
282     if (!ROSEN_EQ(properties.GetTranslateY(), defaultTransform.translateY_)) {
283         out["TranslateY"] = properties.GetTranslateY();
284     }
285     if (!ROSEN_EQ(properties.GetTranslateZ(), defaultTransform.translateZ_)) {
286         out["TranslateZ"] = properties.GetTranslateZ();
287     }
288     if (!ROSEN_EQ(properties.GetScaleX(), defaultTransform.scaleX_)) {
289         out["ScaleX"] = properties.GetScaleX();
290     }
291     if (!ROSEN_EQ(properties.GetScaleY(), defaultTransform.scaleY_)) {
292         out["ScaleY"] = properties.GetScaleY();
293     }
294 }
295 
DumpNodePropertiesDecoration(const RSProperties & properties,JsonWriter & out)296 void RSProfiler::DumpNodePropertiesDecoration(const RSProperties& properties, JsonWriter& out)
297 {
298     if (!properties.GetCornerRadius().IsZero()) {
299         out["CornerRadius"] = { properties.GetCornerRadius().x_, properties.GetCornerRadius().y_,
300             properties.GetCornerRadius().z_, properties.GetCornerRadius().w_ };
301     }
302     if (properties.pixelStretch_.has_value()) {
303         auto& pixelStretch = out["PixelStretch"];
304         pixelStretch.PushObject();
305         pixelStretch["left"] = properties.pixelStretch_->z_;
306         pixelStretch["top"] = properties.pixelStretch_->y_;
307         pixelStretch["right"] = properties.pixelStretch_->z_;
308         pixelStretch["bottom"] = properties.pixelStretch_->w_;
309         pixelStretch.PopObject();
310     }
311     if (!ROSEN_EQ(properties.GetAlpha(), 1.f)) {
312         out["Alpha"] = properties.GetAlpha();
313     }
314     if (!ROSEN_EQ(properties.GetSpherize(), 0.f)) {
315         out["Spherize"] = properties.GetSpherize();
316     }
317 
318     if (!ROSEN_EQ(properties.GetAttractionFraction(), 0.f)) {
319         out["AttractionEffect"] = properties.GetAttractionFraction();
320     }
321 
322     if (!ROSEN_EQ(properties.GetForegroundColor(), RgbPalette::Transparent())) {
323         out["ForegroundColor"] = "#" + Hex(properties.GetForegroundColor().AsArgbInt()) + " (ARGB)";
324     }
325     if (!ROSEN_EQ(properties.GetBackgroundColor(), RgbPalette::Transparent())) {
326         out["BackgroundColor"] = "#" + Hex(properties.GetBackgroundColor().AsArgbInt()) + " (ARGB)";
327     }
328     Decoration defaultDecoration;
329     if ((!ROSEN_EQ(properties.GetBgImagePositionX(), defaultDecoration.bgImageRect_.left_) ||
330         !ROSEN_EQ(properties.GetBgImagePositionY(), defaultDecoration.bgImageRect_.top_) ||
331         !ROSEN_EQ(properties.GetBgImageWidth(), defaultDecoration.bgImageRect_.width_) ||
332         !ROSEN_EQ(properties.GetBgImageHeight(), defaultDecoration.bgImageRect_.height_))) {
333         out["BgImage"] = { properties.GetBgImagePositionX(), properties.GetBgImagePositionY(),
334             properties.GetBgImageWidth(), properties.GetBgImageHeight() };
335     }
336 }
337 
DumpNodePropertiesShadow(const RSProperties & properties,JsonWriter & out)338 void RSProfiler::DumpNodePropertiesShadow(const RSProperties& properties, JsonWriter& out)
339 {
340     if (!ROSEN_EQ(properties.GetShadowColor(), Color(DEFAULT_SPOT_COLOR))) {
341         out["ShadowColor"] = "#" + Hex(properties.GetShadowColor().AsArgbInt()) + " (ARGB)";
342     }
343     if (!ROSEN_EQ(properties.GetShadowOffsetX(), DEFAULT_SHADOW_OFFSET_X)) {
344         out["ShadowOffsetX"] = properties.GetShadowOffsetX();
345     }
346     if (!ROSEN_EQ(properties.GetShadowOffsetY(), DEFAULT_SHADOW_OFFSET_Y)) {
347         out["ShadowOffsetY"] = properties.GetShadowOffsetY();
348     }
349     if (!ROSEN_EQ(properties.GetShadowAlpha(), 0.f)) {
350         out["ShadowAlpha"] = properties.GetShadowAlpha();
351     }
352     if (!ROSEN_EQ(properties.GetShadowElevation(), 0.f)) {
353         out["ShadowElevation"] = properties.GetShadowElevation();
354     }
355     if (!ROSEN_EQ(properties.GetShadowRadius(), 0.f)) {
356         out["ShadowRadius"] = properties.GetShadowRadius();
357     }
358     if (!ROSEN_EQ(properties.GetShadowIsFilled(), false)) {
359         out["ShadowIsFilled"] = properties.GetShadowIsFilled();
360     }
361 }
362 
DumpNodePropertiesEffects(const RSProperties & properties,JsonWriter & out)363 void RSProfiler::DumpNodePropertiesEffects(const RSProperties& properties, JsonWriter& out)
364 {
365     if (properties.border_ && properties.border_->HasBorder()) {
366         out["Border"] = properties.border_->ToString();
367     }
368     auto filter = properties.GetFilter();
369     if (filter && filter->IsValid()) {
370         out["Filter"] = filter->GetDescription();
371     }
372     auto backgroundFilter = properties.GetBackgroundFilter();
373     if (backgroundFilter && backgroundFilter->IsValid()) {
374         out["BackgroundFilter"] = backgroundFilter->GetDescription();
375     }
376     auto foregroundFilterCache = properties.GetForegroundFilterCache();
377     if (foregroundFilterCache && foregroundFilterCache->IsValid()) {
378         out["ForegroundFilter"] = foregroundFilterCache->GetDescription();
379     }
380     if (properties.outline_ && properties.outline_->HasBorder()) {
381         out["Outline"] = properties.outline_->ToString();
382     }
383     if (!ROSEN_EQ(properties.GetFrameGravity(), Gravity::DEFAULT)) {
384         out["FrameGravity"] = static_cast<int>(properties.GetFrameGravity());
385     }
386     if (properties.GetUseEffect()) {
387         out["GetUseEffect"] = true;
388     }
389     auto grayScale = properties.GetGrayScale();
390     if (grayScale.has_value() && !ROSEN_EQ(*grayScale, 0.f)) {
391         out["GrayScale"] = *grayScale;
392     }
393     if (!ROSEN_EQ(properties.GetLightUpEffect(), 1.f)) {
394         out["LightUpEffect"] = properties.GetLightUpEffect();
395     }
396     auto dynamicLightUpRate = properties.GetDynamicLightUpRate();
397     if (dynamicLightUpRate.has_value() && !ROSEN_EQ(*dynamicLightUpRate, 0.f)) {
398         out["DynamicLightUpRate"] = *dynamicLightUpRate;
399     }
400     auto dynamicLightUpDegree = properties.GetDynamicLightUpDegree();
401     if (dynamicLightUpDegree.has_value() && !ROSEN_EQ(*dynamicLightUpDegree, 0.f)) {
402         out["DynamicLightUpDegree"] = *dynamicLightUpDegree;
403     }
404 }
405 
DumpNodePropertiesColor(const RSProperties & properties,JsonWriter & out)406 void RSProfiler::DumpNodePropertiesColor(const RSProperties& properties, JsonWriter& out)
407 {
408     auto brightness = properties.GetBrightness();
409     if (brightness.has_value() && !ROSEN_EQ(*brightness, 1.f)) {
410         out["Brightness"] = *brightness;
411     }
412     auto contrast = properties.GetContrast();
413     if (contrast.has_value() && !ROSEN_EQ(*contrast, 1.f)) {
414         out["Contrast"] = *contrast;
415     }
416     auto saturate = properties.GetSaturate();
417     if (saturate.has_value() && !ROSEN_EQ(*saturate, 1.f)) {
418         out["Saturate"] = *saturate;
419     }
420     auto sepia = properties.GetSepia();
421     if (sepia.has_value() && !ROSEN_EQ(*sepia, 0.f)) {
422         out["Sepia"] = *sepia;
423     }
424     auto invert = properties.GetInvert();
425     if (invert.has_value() && !ROSEN_EQ(*invert, 0.f)) {
426         out["Invert"] = *invert;
427     }
428     auto hueRotate = properties.GetHueRotate();
429     if (hueRotate.has_value() && !ROSEN_EQ(*hueRotate, 0.f)) {
430         out["HueRotate"] = *hueRotate;
431     }
432     auto colorBlend = properties.GetColorBlend();
433     if (colorBlend.has_value() && !ROSEN_EQ(*colorBlend, RgbPalette::Transparent())) {
434         out["ColorBlend"] = "#" + Hex(colorBlend->AsArgbInt()) + " (ARGB)";
435     }
436     if (!ROSEN_EQ(properties.GetColorBlendMode(), 0)) {
437         out["skblendmode"] = properties.GetColorBlendMode() - 1;
438         out["blendType"] = properties.GetColorBlendApplyType();
439     }
440 }
441 
DumpNodeAnimations(const RSAnimationManager & animationManager,JsonWriter & out)442 void RSProfiler::DumpNodeAnimations(const RSAnimationManager& animationManager, JsonWriter& out)
443 {
444     if (animationManager.animations_.empty()) {
445         return;
446     }
447     auto& animations = out["RSAnimationManager"];
448     animations.PushArray();
449     for (auto [id, animation] : animationManager.animations_) {
450         if (animation) {
451             DumpNodeAnimation(*animation, animations);
452         }
453     }
454     animations.PopArray();
455 }
456 
DumpNodeAnimation(const RSRenderAnimation & animation,JsonWriter & out)457 void RSProfiler::DumpNodeAnimation(const RSRenderAnimation& animation, JsonWriter& out)
458 {
459     out.PushObject();
460     out["id"] = animation.id_;
461     std::string type;
462     animation.DumpAnimationType(type);
463     out["type"] = type;
464     out["AnimationState"] = static_cast<int>(animation.state_);
465     out["StartDelay"] = animation.animationFraction_.GetDuration();
466     out["Duration"] = animation.animationFraction_.GetStartDelay();
467     out["Speed"] = animation.animationFraction_.GetSpeed();
468     out["RepeatCount"] = animation.animationFraction_.GetRepeatCount();
469     out["AutoReverse"] = animation.animationFraction_.GetAutoReverse();
470     out["Direction"] = animation.animationFraction_.GetDirection();
471     out["FillMode"] = static_cast<int>(animation.animationFraction_.GetFillMode());
472     out["RepeatCallbackEnable"] = animation.animationFraction_.GetRepeatCallbackEnable();
473     out["FrameRateRange_min"] = animation.animationFraction_.GetFrameRateRange().min_;
474     out["FrameRateRange_max"] = animation.animationFraction_.GetFrameRateRange().max_;
475     out["FrameRateRange_prefered"] = animation.animationFraction_.GetFrameRateRange().preferred_;
476     out.PopObject();
477 }
478 
DumpNodeChildrenListUpdate(const RSRenderNode & node,JsonWriter & out)479 void RSProfiler::DumpNodeChildrenListUpdate(const RSRenderNode& node, JsonWriter& out)
480 {
481     if (!node.isFullChildrenListValid_) {
482         auto& childrenUpdate = out["children update"];
483         childrenUpdate.PushObject();
484         childrenUpdate["current count"] = node.fullChildrenList_->size();
485         std::string expected = std::to_string(node.GetSortedChildren()->size());
486         if (!node.disappearingChildren_.empty()) {
487             childrenUpdate["disappearing count"] = node.disappearingChildren_.size();
488             expected += " + " + std::to_string(node.disappearingChildren_.size());
489         }
490         childrenUpdate["expected count"] = expected;
491         childrenUpdate.PopObject();
492     }
493 }
494 
495 } // namespace OHOS::Rosen