常用Trace及寄义
下面将从渲染流程入手,共同常用场景先容常用Trace。
渲染流程
与其他利用系统相同,OpenHarmony也是由Vsync信号控制每一帧绘制利用的时机。Vsync信号是一个垂直同步信号,它指示显示器在垂直空白期之后开始下一帧的刷新。设备的屏幕以固定的频率发送Vsync信号,以刷新率60Hz举例,则屏幕每隔16.6ms发送一次Vsync信号。在收到Vsync信号后,UI后端引擎开始预备屏幕的下一帧绘制,然后应用程序提交渲染下令,用于描述图形绘制、纹理设置、着色器利用等。一旦应用程序提交了渲染下令,UI后端引擎会将其添加到渲染队列中,并在符合的时机执行这些渲染下令,通常会在后台线程执行,以确保主线程不被长时间壅闭。当这些渲染下令被UI后端引擎执行时,它们会被传递给图形系统Render Service进行处理处罚,图形系统会根据下令进行相应的图形盘算和渲染利用,如极点变换、光照、纹理贴图等。在图形系统完成渲染后,渲染结果将被写入帧缓冲区。帧缓冲区是一个内存区域,存储用于显示器输出的图像数据。一旦帧缓冲区更新完成,UI后端引擎会等候直到下一个Vsync信号到来,这个过程是为了确保渲染结果在显示器垂直消隐之前预备好。当下一个Vsync信号到来时,UI后端引擎将已经预备好的帧缓冲区的内容发送给显示器,显示器根据这些数据刷新自己的像素,至此完成一整个渲染周期。如图1所示。
图1 渲染流程图
从Trace角度来看,一帧的渲染流程如下:
(1)Vsync信号到达; (2)UI后端引擎进行第一帧绘制; (3)向Render Service通信,传输绘制下令并哀求一帧; (4)Render Service对多个图层进行合并,盘算刷新区域,然后进行渲染和绘制本帧; (5)完成一帧绘制后交给屏幕。
一帧的渲染流程中的UI后端引擎的常用Trace的寄义如图2所示。
图2 UI后端引擎渲染Trace泳道图
序号Trace参数说明描述1OnVsyncEvent now:%" PRIu64 "当前时间戳--纳秒级收到Vsync信号,渲染流程开始2FlushVsync刷新视图同步事件,包括记录帧信息、刷新任务、绘制渲染上下文、处理处罚用户输入3UITaskScheduler::FlushTask刷新UI界面,包括结构、渲染和动画等4FlushMessages发送消息通知图形侧进行渲染5FlushLayoutTask执行结构任务6FlushRenderTask %zu当前页面上的必要渲染的节点的数量总渲染任务执行7Layout节点结构8FrameNode::RenderTask单个渲染任务执行9ListLayoutAlgorithm::MeasureListItem:%d当火线表项索引盘算列表项的结构尺寸 图形图像子系统中的Render Service,是负责界面内容绘制的部件,处理处罚由各个应用提交的同一渲染任务,将差别应用渲染的图层进行合并、送显。在收到每个Vsync周期信号时,首先处理处罚应用提交的指令,包括应用渲染树节点的新增、删除、修改,然后进举措画盘算和遮挡盘算,以上是为了对同一渲染树进行更新。接下来开始对渲染树执行绘制,首先预处理处罚每个节点,盘算绝对位置和脏区信息,然后针对脏区进行绘制,优先利用硬件合成器进行绘制,当碰到无法合成绘制的,交由GPU执行重绘,绘制的全部结果都将存入屏幕缓冲区,末了将绘制结果提交送显、上屏展示。
当Vsync信号刷新时,如图3所示。
图3 RS侧渲染Trace泳道图
序号Trace描述1RSMainThread: oComposition合成渲染树上各节点图层2RSMainThread: rocessCommand处理处罚client端指令3Animate动画处理处罚4RSMainThread::CalcOcclusion遮挡盘算5ProcessDisplayRenderNode[x]单个显示器画面的绘制流程6ProcessSurfaceNode:x单个节点的合成器处理处罚7Repaint硬件合成器合成绘制8Redraw无法进行合成,则执行重绘9RenderFrameGPU执行绘制10SwapBuffers刷新屏幕缓冲区11Commit绘制结果提交上屏 懒加载
懒加载利用LazyForEach实现,LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当LazyForEach在滚动容器中利用时,框架会根据滚动容器可视区域按需创建组件。当组件滑出可视区域外时,框架会进行组件烧毁以降低内存占用。图4抓取的是懒加载过程中一帧的Trace。
图4 懒加载Trace泳道图
序号Trace参数说明描述1OnIdle, targettime:%" PRId64 "时间戳,在这个时间之前完成该任务idle事件循环中检查是否有新的事件必要处理处罚,如果有,则将任务调度器加入UI线程中并执行猜测任务2expiringItem_ count:[%zu]懒加载Item的个数预构建,包罗处理处罚全部懒加载项3List predict添加猜测结构任务4Builder:BuildLazyItem [%d]需创建的项目索引在必要时创建项,并进行缓存5Layout[%s][self:%d][parent:%d]tag标签,当前节点在UINode树中的索引,父节点在UINode树中的索引当前帧节点结构6Build[%s][self:%d][parent:%d]tag标签,当前节点在UINode树中的索引,父节点在UINode树中的索引当前帧节点构建7CustomNode:BuildRecycle %sJS视图名称触发复用渲染8ExecuteJS执行JS代码 页面加载
当触发页面加载时,OpenHarmony会创建一个新的页面实例,然后按照特定的程序调用页面的生命周期方法。在生命周期方法中加载页面的结构,然后将数据绑定到页面上的视图元素,使页面能够显示和更新数据。图5抓取的是页面加载中一帧的Trace。
图5 页面加载帧Trace泳道图
序号Trace参数说明描述1PageRouterManager::RunPage页面路由预处理处罚及加载页面2PageRouterManager: oadPage加载页面并路由3JsiDeclarativeEngine: oadPageSource加载一个JavaScript文件并将其解析为ABC字节码4JsiDeclarativeEngine: oadJsWithModule Execute Page code : %s页面url地点执行页面代码5Build[%s][self:%d][parent:%d]tag标签,当前节点在UINode树中的索引,父节点在UINode树中的索引当前帧节点构建6CustomNode:BuildItem %sJS视图名称渲染子节点然后将其挂载到父节点上7ViewChangeCallback(%d, %d)视图宽,视图高视图变革回调 Trace实践
以下示例采用LazyForEach的方式遍历列表,并借助SmartPerf-Host调试工具追踪代码执行流程。 在代码示例中,利用一个List容器组件,通过懒加载方式来创建出120个IconView自定义组件。在IconView组件中,利用了Flex容器组件包罗Image和Text子组件,形成了图文混合列表。
- [/code] ts
- 代码解读
- 复制代码
- // src/main/ets/pages/LazyForEachPage.ets @Entry @Component struct LazyForEachPage { private iconItemSourceList = new ListData(); aboutToAppear() { // 添加120个IconItem的数据 ...... } build() { Column() { Text('懒加载示例') .fontSize(24) .fontColor(Color.Black) .fontWeight(FontWeight.Bold) .textAlign(TextAlign.Start) .width('90%') .height(50) List({ space: 20 }) { LazyForEach(this.iconItemSourceList, (item: IconItemModel) => { ListItem() { IconItem({ image: item.image, text: item.text }) } }, (item: IconItemModel, index) => index.toString()) } .divider({ strokeWidth: 2, startMargin: 20, endMargin: 20 }) // 每行之间的分界限 .width('100%') .height('100%') .layoutWeight(1) } .width('100%') .height('100%') .alignItems(HorizontalAlign.Center) } }
- [hr] [code]
复制代码 ts
代码解读
复制代码
// src/main/ets/view/IconView.ets @Component export struct IconItem { image: string | Resource = ''; text: string | Resource = ''; build() { Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Center, alignContent: FlexAlign.Center }) { Image(this.image) .height(40) .width(40) .objectFit(ImageFit.Contain) .margin({ left: 15 }) Text(this.text) .fontSize(20) .fontColor(Color.Black) .width(100) .height(50) .textAlign(TextAlign.Center) } .width('100%') .height(50) } }
DD一下:欢迎大家关注公众号<程序猿百晓生>,可以了解到一下知识点。
- [/code] erlang
- 代码解读
- 复制代码
- 1.OpenHarmony开发基础 2.OpenHarmony北向开发情况搭建 3.鸿蒙南向开发情况的搭建 4.鸿蒙生态应用开发白皮书V2.0 & V3.0 5.鸿蒙开发口试真题(含参考答案) 6.TypeScript入门学习手册 7.OpenHarmony 经典口试题(含参考答案) 8.OpenHarmony设备开发入门【最新版】 9.沉浸式剖析OpenHarmony源代码 10.系统定制指南 11.【OpenHarmony】Uboot 驱动加载流程 12.OpenHarmony构建系统--GN与子系统、部件、模块详解 13.ohos开机init启动流程 14.鸿蒙版性能优化指南 .......
- 下面利用SmartPerf-Host调试工具抓取htrace文件,并生成一个跟踪泳道分析图,来了解示例代码的加载流程。跟踪泳道分析图被分为五个部门,每个部门都标注数字并框选出相应的标签,从而使得团体的过程能够得到更好的理解。
- [b]图6 LazyForEach遍历的列表的泳道分析图[/b]
- [align=center][img]https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp6-xtjj-sign.byteimg.com%2Ftos-cn-i-73owjymdk6%2F43318e498b57448786824f06bdcd0a72~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5Yir6K-05oiR5LuA5LmI6YO95LiN5Lya%3Aq75.awebp&pos_id=ZD23ws3N[/img][/align]
- 接下来,逐一解析这五个模块的详情:
- [b]1.加载并路由LazyForEach页面[/b]
- [b]图7 加载并路由LazyForEach页面泳道图[/b]
- [align=center][img]https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp6-xtjj-sign.byteimg.com%2Ftos-cn-i-73owjymdk6%2F2dc353637d724af9b57d3acc9dc4b91a~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5Yir6K-05oiR5LuA5LmI6YO95LiN5Lya%3Aq75.awebp&pos_id=oR1DzPh6[/img][/align]
-
- [list]
- [*]H:JsiDeclarativeEngine::LoadPageSource加载一个 JavaScript 文件,并且解析为 ABC 字节码;
- [*]H:FlushPipelineWithoutAnimation 清算渲染管道的利用;
- [*]H:CustomNode:OnAppear 用于构建当前 OnAppear 生命周期的利用,并执行aboutToAppear生命周期函数;
- [*]H:CustomNode:BuildItem LazyForEachPage 渲染子节点并挂载在 LazyForEachPage 页面上。
- [/list] [b]2.对当前帧节点Stage,执行结构任务、执行渲染任务并通知图形侧进行渲染[/b]
- [b]图8 对当前帧节点Stage,执行结构任务、执行渲染任务并通知图形侧进行渲染泳道图[/b]
- [align=center][img]https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp6-xtjj-sign.byteimg.com%2Ftos-cn-i-73owjymdk6%2Fbbded14bb97f4796b72d6693a85e8271~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5Yir6K-05oiR5LuA5LmI6YO95LiN5Lya%3Aq75.awebp&pos_id=ljQyAf63[/img][/align]
-
- [list]
- [*]H:Layout[stage][self:1][parent:0]对当前帧节点Stage,执行结构任务;(Stage作为框架,承载着页面Page节点。因此,标签的呈现会从Stage开始)
- [list]
- [*]H:Measure[%s][self:17][parent:16] 对Page、Column、Row、Image、Text等组件结构尺寸盘算;
- [*]H:Builder:BuildLazyItem [0]和H:ListLayoutAlgorithm::MeasureListItem:0 分别为创建一个LazyItem项目和盘算列表项的结构尺寸;
- [*]H:Layout[%s][self:38][parent:37] 对Page、Column、Row、Image、Text等组件执行结构任务;
- [/list]
- [*]H:FrameNode::RenderTask 执行渲染任务;
- [*]H:RequestNextVSync 哀求下一帧Vsync信号。
- [/list] [b]3.对当前帧节点Flex,执行结构任务、执行渲染任务并通知图形侧进行渲染[/b]
- [b]图9 对当前帧节点Flex,执行结构任务、执行渲染任务并通知图形侧进行渲染泳道图[/b]
- [align=center][img]https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp6-xtjj-sign.byteimg.com%2Ftos-cn-i-73owjymdk6%2Fb237649d67fc49dfa7176e07cf0b9964~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5Yir6K-05oiR5LuA5LmI6YO95LiN5Lya%3Aq75.awebp&pos_id=heESeuUd[/img][/align]
-
- [list]
- [*]H:Layout[Flex][self:63][parent:62]对当前帧节点Flex,执行结构任务**;**
- [list]
- [*]H:Measure[%s][self:17][parent:16] 对Image、Text等组件结构尺寸盘算;
- [/list]
- [*]H:FrameNode::RenderTask Flex渲染任务执行;
- [*]H:RequestNextVSync 哀求下一帧Vsync信号。
- [/list] [b]4.构建前预处理处罚数据及添加猜测结构任务[/b]
- [b]图10 构建前预处理处罚数据及添加猜测结构任务泳道图[/b]
- [align=center][img]https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp6-xtjj-sign.byteimg.com%2Ftos-cn-i-73owjymdk6%2F60cc59cdf0e24eef87d6eb6821946caa~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5Yir6K-05oiR5LuA5LmI6YO95LiN5Lya%3Aq75.awebp&pos_id=TQFgQ3ds[/img][/align]
-
- [list]
- [*]H:Builder:BuildLazyItem [11]构建前预处理处罚数据了11条数据;
- [*]H:Layout[ListItem][self:76][parent:-1] 添加一条Flex、Image、Text的猜测结构;
- [*]H:FlushMessages 发送消息通知图形侧进行渲染。
- [/list] [b]5.合成渲染树上各节点图层任务[/b]
- [b]图11 合成渲染树上各节点图层任务泳道图[/b]
- [align=center][img]https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp6-xtjj-sign.byteimg.com%2Ftos-cn-i-73owjymdk6%2F66133c284b9946639c522fa6f6d29110~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5Yir6K-05oiR5LuA5LmI6YO95LiN5Lya%3Aq75.awebp&pos_id=Ye8VkImN[/img][/align]
-
- [list]
- [*]H:AcquireBuffer、H:ProcessSurfaceNode:EntryView XYWH[0 0 720 1280]获取屏幕缓冲区并绘制EntryView、SystemUi_StatusBar、SystemUi_NavigationBar等;
- [*]H:Repaint 硬件合成器合成绘制当前节点树。
- [/list] [size=4]自定义Trace[/size]
- 开发者可以根据业务需求,利用hiTraceMeter进行自定义Trace打点跟踪,目前支持ArkTS和Native,具体利用细节可参考下方链接:
- 性能打点跟踪开发指导(ArkTS) 性能打点跟踪开发指导(Native)
- 添加自定义Trace后,可在SmartPerf-Host调试工具上检察,自定义Trace将以独立泳道的情势呈现在对应打点的进程下。 下图两条泳道利用了startTrace和finishTrace方法,表示程序运行过程中,指定标签从调用startTrace到调用finishTrace的耗时统计。图中记录了CUSTOM_TRACE_TAG_1和CUSTOM_TRACE_TAG_2两个标签,先后呈现了2个标签的耗时统计。
- [b]图12 自定义Trace示例[/b]
- [align=center][img]https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp6-xtjj-sign.byteimg.com%2Ftos-cn-i-73owjymdk6%2F010e63f74a634403b6e2812ebbaf243e~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5Yir6K-05oiR5LuA5LmI6YO95LiN5Lya%3Aq75.awebp&pos_id=VMgkJ8ha[/img][/align]
- 下图两条泳道利用了TraceByValue方法,表示程序运行过程中,指定Trace在对应时间段内的状态值,状态值寄义可按需传参,开发者可以通过鼠标放置在对应数据块上,来检察具体的状态值。图中记录了CUSTOM_TRACE_TAG_2标签在红色方框标识的时间段内,打点状态值为2001。
- [b]图13 自定义状态值示例[/b]
- [align=center][img]https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp6-xtjj-sign.byteimg.com%2Ftos-cn-i-73owjymdk6%2F0c356b9460a44d318dbd2c39bdf073ee~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5Yir6K-05oiR5LuA5LmI6YO95LiN5Lya%3Aq75.awebp&pos_id=28sEEr6n[/img][/align]
- [size=4]性能打点原理[/size]
- Trace的生成依靠了DFX子系统中的HiTrace组件,此中包罗的hiTraceMeter模块为开发者提供系统性能打点接口,具体细节可参考下方链接:
- HiTrace组件 hiTraceMeter模块
- hiTraceMeter拥有两套开始和结束打点接口,实现对逻辑行为的耗时统计。由于耗时统计大多数以方法为单位,所以hiTraceMeter也提供了快速打点单个方法执行耗时的宏定义HITRACE_METER、HITRACE_METER_NAME、HITRACE_METER_FMT,利用它们,只必要在方法起始位置调用即可。这些宏定义依靠了方法内局部变量的生命周期,其原理是在方法开始时构造了一个打点实例,在实例构造函数中调用开始打点接口,当方法执行完毕,打点实例随着方法结束而执行析构,在实例析构函数中调用结束打点接口。
- [size=3]App中的打点示例[/size]
- ArkUI框架子系统应用hiTraceMeter的例子,来源于 ArkUI开发框架 源码。 以下代码对hiTraceMeter进行接口封装,其原理与HITRACE_METER等相同,依靠方法内局部变量的生命周期实现快速打点。
- [code]
复制代码 cpp
代码解读
复制代码
// frameworks/base/log/ace_trace.h #define ACE_SCOPED_TRACE(fmt, ...) AceScopedTrace aceScopedTrace(fmt, ##__VA_ARGS__) #define ACE_FUNCTION_TRACE() ACE_SCOPED_TRACE(__func__) class ACE_FORCE_EXPORT AceScopedTrace final { public: explicit AceScopedTrace(const char* format, ...) __attribute__((__format__(printf, 2, 3))); ~AceScopedTrace(); ACE_DISALLOW_COPY_AND_MOVE(AceScopedTrace); private: bool traceEnabled_ { false }; };
以下代码是刷新视图同步事件,包括记录帧信息、刷新任务、绘制渲染上下文、处理处罚用户输入。在方法开头调用宏定义ACE_FUNCTION_TRACE,将函数名FlushVsync作为Trace名称记录下来,并记录函数开始时间,在函数结束时记录函数结束时间,得出执行耗时。
- [/code] cpp
- 代码解读
- 复制代码
- // frameworks/core/pipeline/pipeline_context.cpp void PipelineContext::FlushVsync(uint64_t nanoTimestamp, uint32_t frameCount) { ACE_FUNCTION_TRACE(); // 此处省略方法内的其他业务逻辑 // ... }
- [size=3]RS中的打点示例[/size]
- 图形子系统应用hiTraceMeter的例子,来源于图形子系统源码。 以下代码对hiTraceMeter进行接口封装。
- [code]
复制代码 cpp
代码解读
复制代码
// utils/log/rs_trace.h #include "hitrace_meter.h" #define ROSEN_TRACE_BEGIN(tag, name) StartTrace(tag, name) #define RS_TRACE_BEGIN(name) ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, name) #define ROSEN_TRACE_END(tag) FinishTrace(tag) #define RS_TRACE_END() ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP) #define RS_TRACE_NAME(name) HITRACE_METER_NAME(HITRACE_TAG_GRAPHIC_AGP, name) #define RS_TRACE_NAME_FMT(fmt, ...) HITRACE_METER_FMT(HITRACE_TAG_GRAPHIC_AGP, fmt, ##__VA_ARGS__) #define RS_ASYNC_TRACE_BEGIN(name, value) StartAsyncTrace(HITRACE_TAG_GRAPHIC_AGP, name, value) #define RS_ASYNC_TRACE_END(name, value) FinishAsyncTrace(HITRACE_TAG_GRAPHIC_AGP, name, value) #define RS_TRACE_INT(name, value) CountTrace(HITRACE_TAG_GRAPHIC_AGP, name, value) #define RS_TRACE_FUNC() RS_TRACE_NAME(__func__)
以下代码在显示器画面绘制方法。在方法开头调用宏定义RS_TRACE_NAME,将函数名ProcessDisplayRenderNode与对应的显示器id组合后,作为Trace名称记录下来,同时由于其本质是利用了快速打点单个方法的宏定义HITRACE_METER_NAME,于是只必要调用一次,即可收集到ProcessDisplayRenderNode函数的执行起尽头时间,得出执行耗时。
[code][/code] cpp
代码解读
复制代码
// rosen/modules/render_service/core/pipeline/rs_surface_capture_task.cpp void RSSurfaceCaptureVisitor: rocessDisplayRenderNode(RSDisplayRenderNode &node) { RS_TRACE_NAME("RSSurfaceCaptureVisitor: rocessDisplayRenderNode:" + std::to_string(node.GetId())); // 此处省略方法内的其他业务逻辑 // ... }
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |