实战技巧 DevEco Profiler 性能调优 Time
背景
DevEco Studio 开发工具中提供了 Profiler 面板,可以让我们在针对实际开发应用过程中碰到的一些性能相关的问题提供解决方案。如响应速度慢、动画卡顿、内存泄漏、发热、耗电快等等场景。其中 Profiler 提供了实时监控、深度录制等监控过程的功能。从分析的角度入手,主要有以下几个纬度进行分析:
场景 | 面板 |
---|---|
基础耗时分析 | Time |
基础内存分析 | Allocation |
内存泄露分析 | Snapshot |
CPU 活动分析 | CPU |
冷启动分析 | Launch |
并行并发分析 | Concurrency |
加载丢帧分析 | ArkWeb |
网络诊断 | Network |
不过需要注意的是 Profiler 只能配合真机来使用,模拟器暂时不支持。
Time
Time 面板常见的需求是对应用中的函数耗时进行分析。函数作为应用开发基本的基石,一般常见的耗时工作都是放在函数中进行的。
Time 可以对同步函数和异步函数进行分析。还提供了很方便的一键跳转到源码的功能,给开发者调试代码提供了很高效率的保证。
调试素材
为了方便调试,我们提供了以下素材。
typescript">import { promptAction } from '@kit.ArkUI'@Entry
@Component
struct Index {fn1() {this.fn2()}fn2() {this.fn3()}fn3() {this.fn4()}fn4() {promptAction.showToast({ message: `快速任务结束` })}build() {Column() {Button("快速任务").onClick(() => {this.fn1()})}.width("100%").height("100%").justifyContent(FlexAlign.Center)}
}
设置函数名称
在模块的 build-profile.json5 中添加以下配置,否则采集到的函数可能都是匿名函数
entry/build-profile.json5 中 设置 strip 为 false
{"apiType": "stageMode","buildOption": {"nativeLib": {"debugSymbol": {"strip": false}}},
选择应用和进程
点击菜单中的 Profiler,然后选择对应的设备和应用,进程会自动选中的。
然后选中 Time 菜单
开始跟踪,定位耗时任务
-
一切准备就绪后,点击创建 Session
-
然后点击 按钮开始录制
-
在录制过程中,开始使用你的应用来重现问题。操作完毕后,记得点击结束。完成这次流程的录制。
Time 面板介绍
在点击结束录制后,便能看到这个画面
ArkTS Callstack
方舟运行时函数调用泳道,基于时间轴展示 CPU 使用率和虚拟机的执行状态,以及当前调用栈名称和调用类型。由于隐私安全政策,已上架应用市场的应用不支持录制此泳道。
调用栈分类从语言层面分为 ArkTS、NAPI 以及 Native,从归属层面分为开发者代码以及系统代码。从这两个方面可以将调用栈类型归类如下:
-
ArkTS:程序正在执行 ArkTS 代码;
-
NAPI:程序正在运行的 NAPI 代码;
-
Native:程序正在执行的 Native 代码;
其中每一个类型的亮色和灰色分别代表开发者和系统的代码。
-
ArkTs Callstack 包含有开发者自己写的代码。点击它,会在下方显示详情面板
-
Weight 表示函数的总耗时,Self 表示函数自身的耗时。如
-
Heaviest Stack 表示是Details区域选择节点所处的耗时最长的完整调用栈
-
绿色部分表示开发者自己编写的代码,可以看见右侧还有对应的 fn1、fn2、fn3 等等。通过这个函数调用栈便可获知哪个函数比较行耗时了
-
此时,如果想要快速定位到源码,双击函数即可
User Trace
Time 面板一般直接用来分析同步代码,如果想要分析和定位异步代码,建议搭配 hiTraceMeter 接口配套 User Trace 使用
hiTraceMeter 接口
接口名 | 描述 |
---|---|
hiTraceMeter.startTrace(name: string, taskId: number) | 异步时间片跟踪接口,标记一个预跟踪耗时任务的开始。taskId 是 trace 中用来表示关联的 ID,如果有多个 name 相同的任务并行执行,则每次调用 startTrace 的 taskId 不同;如果具有相同 name 的任务是串行执行的,则 taskId 可以相同。 |
hiTraceMeter.finishTrace(name: string, taskId: number) | 异步时间片跟踪接口,name 和 taskId 必须与流程开始的 hiTraceMeter.startTrace 对应参数值保持一致。 |
调试素材
typescript">import { hiTraceMeter } from '@kit.PerformanceAnalysisKit'@Entry
@Component
struct Index {sleep(n: number) {const promise = new Promise<void>(resolve => {setTimeout(() => {resolve()}, n * 1000)})return promise}async asyncCb1() {hiTraceMeter.startTrace("异步长时任务", 1)await this.sleep(1)hiTraceMeter.finishTrace("异步长时任务", 1)await this.asyncCb2()}async asyncCb2() {hiTraceMeter.startTrace("异步长时任务", 2)await this.sleep(2)hiTraceMeter.finishTrace("异步长时任务", 2)await this.asyncCb3()}async asyncCb3() {hiTraceMeter.startTrace("异步长时任务", 3)await this.sleep(3)hiTraceMeter.finishTrace("异步长时任务", 3)}build() {Column() {Button("异步长时任务").onClick(async () => {await this.asyncCb1()AlertDialog.show({ message: JSON.stringify('结束', null, 2) })})}.width("100%").height("100%").justifyContent(FlexAlign.Center)}
}
分析
- 展开 User Trace
- 可以看见 User Trace 泳道上存在粉色的 3 个异步任务
- 点击以上随便一个,可以在 detail 中看见这个函数的具体耗时
总结
开发应用或服务过程中,如果遇到卡顿、加载耗时等性能问题,开发者通常会关注相关函数执行的耗时情况。DevEco Profiler 提供的 Time 场景分析任务,可在应用/服务运行时,展示热点区域内基于 CPU 和进程耗时分析的调用栈情况,并提供跳转至相关代码的能力,使开发者更便捷地进行代码优化。