HarmonyOS开发实战( Beta5版)耗时分析器Time Profiler实践指导

DevEco Studio集成的DevEco Profiler性能调优工具(以下简称为Profiler),提供Time、Allocation、Snapshot、CPU等场景化分析任务类型。开发应用或服务过程中,如果遇到卡顿、加载耗时等性能问题,开发者通常会关注相关函数执行的耗时情况。Profiler提供的Time场景分析任务,可在应用/服务运行时,展示热点区域内基于CPU和进程耗时分析的调用栈情况,并提供跳转至相关代码的能力,使开发者更便捷地进行代码优化。

使用约束

已通过USB连接设备并在设备上打开需要调试的设备。

仅在应用为debug编译模式时使用。

仅支持OpenHarmony API 9及以上版本的Stage工程。

场景示例

本示例设置两个页面,示例场景存在页面跳转时间过长的问题。

主页面代码如下,包含一个页面跳转按钮。

import router from '@ohos.router'

@Entry
@Component
struct Index {
 build() {
  Row() {
   Column() {
    Button("点击跳转").onClick(() => {
     onJumpClick();
    })
   }
   .width('100%')
  }
  .height('100%')
 }
}

// 跳转下个页面
function onJumpClick(): void {
 router.pushUrl({
  url: 'pages/second' // 目标url
 }, router.RouterMode.Standard, (err) => {
  if (err) {
   console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`);
   return;
  }
  console.info('Invoke pushUrl succeeded.');
 });
}

跳转后页面代码如下,页面包含100个Swiper组件,每个Swiper组件的子组件为带有100个ListItem的List组件,搭配ForEach进行渲染。

@Component
struct SwiperChild { // Swiper的子组件:带有100个ListItem的List组件
 @State arr: number[] = [];

 aboutToAppear(): void {
  for (let i = 1; i <= 100; i++) {
   this.arr.push(i);
  }
 }

 build() {
  Column() {
   List({ space: 20 }) {
    ForEach(this.arr, (index: number) => {
     ListItem() {
      Text(index.toString())
       .height('4.5%')
       .fontSize(16)
       .textAlign(TextAlign.Center)
       .backgroundColor(0xFFFFFF)
     }
     .border({ width: 2, color: Color.Green })
    }, (index: number) => index.toString());
   }
   .height("95%")
   .width("95%")
   .border({ width: 3, color: Color.Red })
   .lanes({ minLength: 40, maxLength: 40 })
   .alignListItem(ListItemAlign.Start)
   .scrollBar(BarState.Off)

  }.width('100%').height('100%').padding({ top: 5 });
 }
}

@Entry
@Preview
@Component
struct SecondPage { // 跳转后的页面
 @State data: Number[] = [];

 aboutToAppear(): void {
  for (let i = 1; i <= 100; i++) {
   this.data.push(i)
  }
 }

 build() {
  Column({ space: 5 }) {
   Swiper() {
    ForEach(this.data, (_: number) => {
     ChildPage();
    }, (item: number) => item.toString());
   }
   .loop(false)
   .indicator(true)
   .duration(100)
   .curve(Curve.Linear)

  }.width('100%')
  .margin({ top: 5 })
 }
}

打开耗时分析器

以DevEco Studio 4.0.0.400版本为例,在DevEco Studio菜单栏上单击****View**** > *Tool Windows* > *Profiler*,或者在DevEco Studio底部工具栏单击Profiler按钮,打开Profiler性能分析器,点选Time选项,再点击Create Session按钮创建耗时分析任务。

开始耗时分析任务录制

耗时分析任务创建完成后,窗口显示如下:

耗时分析任务支持在录制前单击按钮指定要录制的泳道:

ArkTS Callstack:基于时间轴展示CPU使用率和状态的变化,以及当前调用栈名称和调用类型。调用栈的类型包括:System、ArkTS、NAPI、Native。

User Trace:基于时间轴展示当前时段内触发用户自定义打点任务的具体情况。

Native Callstack:基于时间轴展示进程/线程的活动状态,以及在一段时间内对CPU的占用情况和函数调用栈。

点击按钮即可开始耗时分析任务录制,开始录制后在应用首页点击页面跳转按钮,等待成功跳转至下个页面后,结束录制任务。

提示

在任务录制(recording)及分析(analyzing)的过程中,请不要主动断开应用或者设备,否则可能导致分析任务异常失败。

进行耗时分析

耗时分析任务录制结束后,任务分析窗口如下:

在"ArkTS Callstack"泳道或"Native Callstack"子泳道上长按鼠标左键并拖拽,框选应用正在进行页面跳转的时间段。

此时"Details"区域显示所选时间段内的函数栈耗时分布情况,"Heaviest Stack"列表给出所选时段内函数栈耗时排序,并展示这些函数的节点路径。

分析函数栈耗时排序可以发现,跳转页面加载时间达到了1.46s,图中框出的ForEach接口占用了大部分页面跳转耗时间。在"Details"中双击ForEach接口下的(ARKUI_ENGINE)节点,可快速跳转至对应工程源码。

函数栈耗时分布有两种展现方式:

默认为列表方式,其中,"Weight"字段表示当前所属函数的总耗时,"Self"字段表示函数自身耗时,"Category"字段表示函数调用类型。

打开页面下方的"Flame Chart"开关,以火焰图模式展示函数栈调用情况。其中,横轴表示调用栈,纵轴表示栈的深度。火焰图模式如下,利用火焰图可以更清晰地发现ForEach接口的异常耗时。

提示

在任务分析窗口,可以通过"Ctrl+鼠标滚轮"缩放时间轴,通过"Shift+鼠标滚轮"左右移动时间轴。

将鼠标置于泳道任意位置,可查看到对应时间点的CPU使用率。

单击任意泳道名称后方的按钮可将其置顶。

火焰图条块支持搜索,搜索结果不匹配的条块会被置灰。

在火焰图中选中任一节点,使用"Alt+左键"可将该节点左置底并将其占比放大到100%,其上从属节点按同比例放大显示。该快捷操作同样适用于列表方式,用于将指定节点置顶并截取所属下级节点。

可使用工具页左下方的搜索栏通过关键词搜索函数栈。

代码优化

使用LazyForEach懒加载机制替换ForEach,使得页面跳转时不一次性加载所有的Swiper子组件。跳转后页面代码修改为如下所示:

class MyDataSource implements IDataSource { // LazyForEach的数据源
 private list: number[] = [];

 constructor(list: number[]) {
  this.list = list;
 }

 totalCount(): number {
  return this.list.length;
 }

 getData(index: number): number {
  return this.list[index];
 }

 registerDataChangeListener(_: DataChangeListener): void {
 }

 unregisterDataChangeListener(): void {
 }
}

@Component
struct ChildPage { // 带有100个ListItem的List组件
 @State arr: number[] = [];

 aboutToAppear(): void {
  for (let i = 1; i <= 100; i++) {
   this.arr.push(i);
  }
 }

 build() {
  Column() {
   List({ space: 20 }) {
    ForEach(this.arr, (index: number) => {
     ListItem() {
      Text(index.toString())
       .height('4.5%')
       .fontSize(16)
       .textAlign(TextAlign.Center)
       .backgroundColor(0xFFFFFF)
     }
     .border({ width: 2, color: Color.Green })
    }, (index: number) => index.toString());
   }
   .height("95%")
   .width("95%")
   .border({ width: 3, color: Color.Red })
   .lanes({ minLength: 40, maxLength: 40 })
   .alignListItem(ListItemAlign.Start)
   .scrollBar(BarState.Off)

  }.width('100%').height('100%').padding({ top: 5 });
 }
}

@Entry
@Preview
@Component
struct SecondPage {
 private dataSrc: MyDataSource = new MyDataSource([]);

 aboutToAppear(): void {
  let list = []
  for (let i = 1; i <= 100; i++) {
   list.push(i);
  }
  this.dataSrc = new MyDataSource(list);
 }

 build() {
  Column({ space: 5 }) {
   Swiper() {
    LazyForEach(this.dataSrc, (_: number) => { // 使用懒加载机制
     ChildPage();
    }, (item: number) => item.toString());
   }
   .loop(false)
   .cachedCount(1) // 提前加载后一项的内容
   .indicator(true)
   .duration(100)
   .curve(Curve.Linear)

  }.width('100%')
  .margin({ top: 5 })
 }
}

优化结果

如图所示,跳转页面加载时间从1.46s降低至19ms。

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,不同的角度的问了一些问题,我明显感觉到一点,那就是许多人参与鸿蒙开发,但是又不知道从哪里下手,因为资料太多,太杂,教授的人也多,无从选择。有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)文档用来跟着学习是非常有必要的。

为了确保高效学习,建议规划清晰的学习路线,涵盖以下关键阶段:

希望这一份鸿蒙学习文档能够给大家带来帮助~


鸿蒙(HarmonyOS NEXT)最新学习路线

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员: 想要拓展职业边界
零基础小白: 鸿蒙爱好者,希望从0到1学习,增加一项技能。
**技术提升/进阶跳槽:**发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.视频教程+学习PDF文档

(鸿蒙语法ArkTS、TypeScript、ArkUI教程......)

纯血版鸿蒙全套学习文档(面试、文档、全套视频等)

鸿蒙APP开发必备

​​

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线

相关推荐
爱分享的码瑞哥1 分钟前
利用正则表达式高效处理复杂HTML结构
前端·正则表达式·html
阿语!5 分钟前
Vue生命周期详解
前端·vue.js
蓝桉柒75 分钟前
web前端开发--动画效果
开发语言·前端·css
大风吹PP凉6 分钟前
45系统调用与内核API
java·linux·服务器
叫我王员外就行13 分钟前
Vue第一篇:组件模板总结
前端·javascript·vue.js
hummhumm15 分钟前
第 32 章 - Go语言 部署与运维
java·运维·开发语言·后端·python·sql·golang
techdashen15 分钟前
Go与黑客(第二部分)
开发语言·后端·golang
LightOfNight21 分钟前
一文学会Golang里拼接字符串的6种方式(性能对比)
开发语言·golang
GoldenFingers22 分钟前
【体验分享】各前端部署平台详细体验汇总
前端·部署
2401_8784673224 分钟前
大连环保公益管理系统|Java|SSM|Vue| 前后端分离
java·开发语言·学习·tomcat·maven