OpenHarmony实战开发-使用SmartPerf-Host分析应用性能

简介

SmartPerf-Host是一款深入挖掘数据、细粒度展示数据的性能功耗调优工具,可采集CPU调度、频点、进程线程时间片、堆内存、帧率等数据,采集的数据通过泳道图清晰地呈现给开发者,同时通过GUI以可视化的方式进行分析。该工具当前为开发者提供了五个分析模板,分别是帧率分析、CPU/线程调度分析、应用启动分析、TaskPool分析、动效分析。关于工具使用的更多内容可查看SmartPerf-Host调优工具使用指导。

本文提供一些性能分析示例,介绍如何使用帧率分析和应用启动分析两个模板采集数据、分析数据,从而发现性能优化点。

本地部署
使用SmartPerf-Host进行性能分析前,需要先完成本地部署,本地部署的详细指导请参考如何编译TraceStreamer和SmartPerf-Host编译部署指导。在本地部署成功后,可通过https://[部署机器ip地址]:9000/application/访问,如下图。

图1 本地部署访问页

在这里插入图片描述

性能分析示例

FrameTimeline帧率分析
SmartPerf-Host提供FrameTimeline帧率分析功能,可以抓取记录每一帧的渲染数据,自动标识其中的卡顿帧,并提供同时段的系统Trace信息,帮助开发者高效分析卡顿位置和原因。

场景示例
如下场景代码使用了Grid来实现了一个网格布局,在应用界面上下滑动时发现有卡顿掉帧现象。下文基于这个场景来介绍FrameTimeline帧率分析功能的使用方式。

@Entry  
@Component  
struct Index {  
  @State children: number[] = Array.from<undefined, number>(Array(2000).fill(undefined), (_v: undefined, k) => k);  
  build() {  
    Scroll() {  
      Grid() {  
       ForEach(this.children, (item: number) => {  
          GridItem() {  
            Stack() {  
              Stack() {  
                Stack() {  
                  Text(item.toString())  
                    .fontSize(32)  
                }  
              }  
            }  
          }  
        }, (item: number) => item.toString())  
      }  
      .columnsTemplate('1fr 1fr 1fr 1fr')  
      .columnsGap(0)  
      .rowsGap(0)  
      .size({ width: "100%", height: "100%" })  
    }  
  }  
}

抓取数据
下面介绍使用FrameTimeline帧率分析模板抓取数据的步骤:

1.打开Record template -> Trace template -> FrameTimeline模板的配置开关。

图2 FrameTimeline模板配置

在这里插入图片描述

2.自定义配置抓取时间、抓取数据大小和结果文件名称。

图3 抓取配置项

在这里插入图片描述

3.点击右上角Record开始抓取,同时在设备上复现应用掉帧或卡顿的操作过程,抓取完成后页面会自动加载trace数据。

说明:

  • 在数据抓取和分析的过程中,请不要主动退出应用或者设备,否则可能导致分析任务失败。
  • 点击Record时,网站上方出现please kill otherhdc-server!的提醒,表示设备连接失败,说明设备的hdc连接端口被占用,需要在cmd命令行中执行hdckill指令,然后再重新连接设备进行抓取。

分析数据
完整的一个渲染流程,首先是App侧响应用户输入完成UI绘制,然后提交给Render Service,由Render Service协调GPU等资源完成渲染、合成和送显操作,在这个过程中App侧和Render Service侧都有可能出现卡顿最终导致丢帧现象。

通过图4、图5、图6三组泳道数据,开发者们可以快速发现丢帧的位置,并完成初步的定界。

图4 UI + RenderService总耗时

在这里插入图片描述

图5 UI耗时

在这里插入图片描述

图6 RenderService耗时

在这里插入图片描述

  • Expected Timeline是理想帧泳道图,Actual Timeline是真实帧泳道图。
  • 绿色帧为正常帧,橙色帧为卡顿帧,黄色帧表示RS进程与App进程起止异常。
  • UI耗时(图5)显示了应用侧每一帧的处理耗时,方块的长度即为具体的耗时,RenderService耗时(图6)同理。
  • App侧帧/RS侧帧卡顿的计算标准为帧的实际结束时间晚于帧的期望结束时间即为卡顿。
  • App侧有橙色出现,需要审视UI线程的处理逻辑是否过于复杂或低效,以及是否被其它任务抢占资源。
  • RS侧有橙色出现,需要审视界面布局是否过于复杂,可以使用布局检查器ArkUIInspector工具和HiDumper命令行工具辅助分析定位,相关指导可以参考使用HiDumper命令行工具优化性能。

从图5和图6结合来看可以确定场景示例明显属于App侧的帧卡顿。点击卡顿帧进行详细分析,相应的关联帧会通过线连起来,同时在Current Selection显示它的Details信息,如图7。

图7 App卡顿帧

在这里插入图片描述

  • Duration表示帧的持续时间。
  • Jank Type表示卡顿类型。APP Deadline Missed表示应用侧卡顿。
  • FrameTimeLine flows Slice表示链接FrameTimeLine关联帧。
  • Preceding flows Slice表示链接RS关联帧。

如下图,展开的应用泳道图中,存在两个名字和Pid一样的泳道,第一个为线程的使用情况,第二个为线程内的方法栈调用情况。结合卡顿帧对应时间段的Trace数据,可以定位到FlushLayoutTask耗时过长,它的作用是重新测量和布局所有的Item。其中Layout[Gird]耗时最久,因此卡顿原因可以确定为Gird布局处理逻辑过于复杂或低效。

图8 应用布局绘制trace数据

在这里插入图片描述

定位到Grid布局代码段,经过分析,去除了冗余的3层stack容器,并将源数据提前处理为布局中需要的string类型,减少布局消耗。同时给Grid添加cachedCount参数结合LazyForEach进行预加载,cachedCount的值设定为一屏能够渲染的GridItem数量。优化后采用同样的方式抓取数据,得到的FrameTimeline泳道数据如图9,并且滑动过程中无卡顿丢帧现象。

图9 优化后FrameTimeline泳道图

在这里插入图片描述

优化后的示例代码如下:

class MyDataSource implements IDataSource { // LazyForEach的数据源  
  private list: string[] = [];  
  
  constructor(list: string[]) {  
    this.list = list;  
  }  
  
  totalCount(): number {  
    return this.list.length;  
  }  
  
  getData(index: number): string {  
    return this.list[index];  
  }  
  
  registerDataChangeListener(_: DataChangeListener): void {  
  }  
  
  unregisterDataChangeListener(): void {  
  }  
}  
@Entry  
@Component  
struct Index {  
  @State children: string[] = Array.from<undefined, string>(Array(2000).fill(undefined), (_v: undefined, k) => k.toString());  
  @State data: MyDataSource = new MyDataSource(this.children)  
  build() {  
    Scroll() {  
      Grid() {  
        LazyForEach(this.data, (item: string) => {  
          GridItem() {  
            Text(item)  
              .fontSize(32)  
          }  
        }, (item: string) => item)  
      }  
      .cachedCount(80)  
      .columnsTemplate('1fr 1fr 1fr 1fr')  
      .columnsGap(0)  
      .rowsGap(0)  
      .size({ width: "100%", height: "100%" })  
    }  
  }  
}

AppStartup应用启动分析

SmartPerf-Host提供了AppStartup功能,以便于分析应用启动时各个阶段耗时情况。应用启动分析功能主要是提供应用启动分析模板,帮助系统调优人员做应用启动慢场景问题分析,快速查找系统侧启动慢阶段和耗时长调用栈信息。

场景示例
以下示例代码展示AppStartup功能。

@Entry  
@Component  
struct Index {  
  @State private text: string = "hello world";  
  private count: number = 0;  
  
  aboutToAppear() {  
    this.computeTask();  
  }  
  
  build() {  
    Column({space: 10}) {  
      Text(this.text).fontSize(50)  
    }  
    .width('100%')  
    .height('100%')  
    .padding(10)  
  }  
  
  computeTask() {  
    this.count = 0;  
    while (this.count < 10000000) {  
      this.count++;  
    }  
  }  
}

抓取数据
使用如下步骤进行AppStartup数据的抓取:

1.切换到Flags页面,将AppStartup选项切换到Enabled,开启AppStartup模板。

图10 AppStartup特性开关

在这里插入图片描述

切换到Record template页面,点击Trace template,开启AppStartup。

图11 AppStartup模板配置

在这里插入图片描述

Record setting内设置文件名、大小以及抓取时长。

图12 抓取配置项

在这里插入图片描述

4.点击右上角Record开始抓取,同时在设备上打开目标应用。可提前点击StopRecord完成抓取,或者等待时间自动完成抓取。抓取完成后会页面会自动加载trace数据。

图13 停止抓取选项

在这里插入图片描述

分析数据
等待分析结果自动生成。点击右上角的筛选按钮,选中AppStartup,便于查看分析。

图14 模板数据筛选

在这里插入图片描述

展开对应应用的泳道,找到应用启动时的时间段。选中AppStartup泳道全部阶段,可以在下方详情内看到具体阶段的耗时情况。

图15 AppStartup各阶段耗时情况——优化前

在这里插入图片描述

  • ProcessTouchEvent:点击事件输入及处理
  • StartUIAbilityBySCB:处理创建进程信息&创建窗口
  • LoadAbility:拉起进程
  • Application Launching:加载应用
  • UI Ability Launching:加载UI Ability
  • UI Ability OnForeground:应用进入前台
  • First Frame - App Phase:首帧渲染提交-应用
  • First Frame - Render Phase:首帧渲染提交-Render Service

上图展示结果显示,执行耗时最长的是UI Ability OnForeground阶段。目前耗时Duration为323ms。

图16 UI Ability OnForeground阶段耗时——优化前

在这里插入图片描述

在这个阶段里,通过阶段内下方泳道可以发现生命周期aboutToAppear耗时较长,点击该泳道内容可以看到具体耗时Duration,为268ms,占整个UI Ability OnForeground阶段的82%。

图17 aboutToAppear耗时——优化前

在这里插入图片描述

查看代码后发现,在aboutToAppear生命周期函数内执行了耗时的计算任务,导致应用冷启动耗时长。

随后对aboutToAppear内容进行异步延迟处理。优化后代码如下:

@Entry  
@Component  
struct Index {  
  @State private text: string = "hello world";  
  private count: number = 0;  
  
  aboutToAppear() {  
    setTimeout(() => {  
      this.computeTask();  
    }, 0)  
  }  
  
  build() {  
    Column({space: 10}) {  
      Text(this.text).fontSize(10)  
    }  
    .width('100%')  
    .height('100%')  
    .padding(10)  
  }  
  
  computeTask() {  
    this.count = 0;  
    while (this.count < 10000000) {  
      this.count++;  
    }  
  }  
}

处理后用同样的方式获取一遍数据。

图18 AppStartup各阶段耗时情况——优化后

在这里插入图片描述

继续聚焦到aboutToAppear生命周期所在的UI Ability OnForeground阶段,目前耗时Duration为81ms。

图19 UI Ability OnForeground阶段耗时——优化后

在这里插入图片描述

在这个阶段里,通过阶段内下方泳道可以发现需要查看的生命周期aboutToAppear,点击该泳道内容可以看到具体耗时Duration,为2ms,目前只占整个UI Ability OnForeground阶段的2.5%。

图20 aboutToAppear耗时——优化后

在这里插入图片描述

如果大家还没有掌握鸿蒙,现在想要在最短的时间里吃透它,我这边特意整理了《鸿蒙语法ArkTS、TypeScript、ArkUI等…视频教程》以及《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

鸿蒙语法ArkTS、TypeScript、ArkUI等…视频教程:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

OpenHarmony APP开发教程步骤:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

《鸿蒙开发学习手册》:

如何快速入门:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

1.基本概念
2.构建第一个ArkTS应用
3.……

在这里插入图片描述

开发基础知识:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

在这里插入图片描述

基于ArkTS 开发:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

在这里插入图片描述

鸿蒙生态应用开发白皮书V2.0PDF:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/585705.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker在linux上的安装与使用

我的操作系统centos7本地vm docker安装 1、卸载旧版本 如果系统中已经存在旧的Docker&#xff0c;则先卸载 yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine 2、配置一…

Android 音视频基础知识

本系列文章会介绍两个 Android NDK Demo&#xff0c;拉流端会实现一个基于 FFmpeg 的视频播放器 Demo&#xff0c;推流端会实现一个视频直播 Demo&#xff0c;当然在做 Demo 之前会介绍音视频的基础知识。以下是本系列文章的目录&#xff1a; Android 音视频基础知识 Android 音…

【langchain】快速封装替换自定义LLM(基于自定义API或本地模型)

1. 引言 你可能已经注意到&#xff0c;LLM时代下的许多项目&#xff08;特别是Github上的论文项目、工程项目&#xff09;都要求我们设置OpenAI的API Key&#xff0c;就像这样&#xff1a; os.environ["OPENAI_API_KEY"] "sk-"from langchain_openai im…

SDKMAN!

概述 官网&#xff0c;SDKMAN是一款管理多版本SDK的工具&#xff0c;可以实现在多个版本间的快速切换。 其他特性&#xff1a; 易用&#xff1a;安装SDK不再需要去Google想安装的某个软件的官网的下载页&#xff0c;或找其他下载页面&#xff0c;然后下载安装包、解压、设置…

.NET C# ORM 瀚高数据库

SqlSugar ORM SqlSugar 是一款 老牌 .NET开源ORM框架&#xff0c;由果糖大数据科技团队维护和更新 &#xff0c;开箱即用最易上手的ORM 优点 &#xff1a;【生态丰富】【高性能】【超简单】 【功能全面】 【多库兼容】【适合产品】 【SqlSugar视频教程】 支持 &#xff1a…

C语言指针和数组的一些笔试题

文章目录 前言一、一维数组二、字符数组-1三、字符数组-2总结 前言 C语言指针和数组的一些笔试题 一、一维数组 #include <stdio.h> int main() {int a[] { 1,2,3,4 };printf("%d\n", sizeof(a));printf("%d\n", sizeof(a 0));printf("%d\n…

Eclipse MAT工具分析内存溢出

1、通过dominator_tree可以查看哪些对象大 可以看到com.codex.terry.entity.User对象有57万个 2、打开thread_overview查看内存溢出的代码

TCP重传,滑动窗口,流量控制,拥塞控制

TCP重传&#xff0c;滑动窗口&#xff0c;流量控制&#xff0c;拥塞控制 TCP重传机制&#xff1a; 超时重传快速重传SACKD-SACK 通过序列号与确认应答判断是否要重传 超时重传&#xff1a; 超过指定时间没有收到确认应答报文&#xff0c;就会重发该数据 触发超时重传的情况…

(十四)Servlet教程——Servlet中HttpSession的使用

除了使用Cookie&#xff0c;Web应用程序中还经常使用Session来记录客户端状态。Session是服务器端使用的一种记录客户端状态的机制&#xff0c;相应地也增加了服务器的存储压力。 1. 什么是Session Session是另外一种记录客户端状态的机制&#xff0c;不同的是Cookie保存在客户…

2024年618哪些数码家电值得入手?热门家电好物抢先看!

618购物狂欢节即将来临&#xff0c;这是一年一度的大促销活动&#xff0c;家电和数码产品在这个时间段内通常都会有优惠和折扣。但随着产品的多样化&#xff0c;很多时候一款产品就有多款品牌&#xff0c;在这不同品牌又各自擅长不同的东西&#xff0c;看着眼花缭乱。今天我就给…

基于python+django网易新闻+评论的舆情热点分析平台

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Php和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

Java中优雅实现泛型类型的强制转换

在Java中经常遇到将对象强制转换成泛型类的情况&#xff1a; Map<String, Object> data Map.of("name", "XiaoMing","age", 17,"scores", List.of(80, 90, 70) );List<Integer> scores (List<Integer>) data.get…

Docker容器添加修改端口映射的方法与详细步骤

1、先找到要修改的容器hash值&#xff1a; 2、然后退出docker Desktop服务 &#xff08;因为在线状态配置文件修改保存不了&#xff09; 3、资源管理器中打开最新安装的Docker的配置文件的路径&#xff1a; 4、打开后修改其中的 config.v2.json 和 hostconfig.json 5、启动…

【C++】哈希表的底层逻辑

目录 一、哈希概念 1、哈希冲突 2、哈希冲突的解决 a、闭散列 &#x1f7e2;插入 &#x1f7e2;查找 &#x1f7e2;删除 &#x1f7e2;其他类型的数据 &#x1f7e2;实现 b、 开散列 &#x1f7e2;插入 &#x1f7e2;查找 &#x1f7e2;删除 &#x1f7e2;析构 &a…

《霍格沃茨之遗》找不到emp.dll如何修复?分享5种亲测有效的方法

在我们享受电脑游戏带来的乐趣时&#xff0c;偶尔会遇到一些技术上问题&#xff0c;具体来说&#xff0c;当你启动一款游戏&#xff0c;系统却弹出一个提示“由于找不到emp.dll文件&#xff0c;因此无法继续执行代码”&#xff0c;这样的情况确实让人感到扫兴。这究竟是什么原因…

.net core ef 连表查询

Information和TypeInfo连表查询 类似&#xff1a; select st.Title1,si.* from [Star_Information] si left join Star_TypeInfo st on si.typeId2st.id 先在EfCoreDbContext.cs配置 protected override void OnModelCreating(ModelBuilder builder){base.OnModelCreating(b…

Jupyter Notebook 中使用虚拟环境的Python解释器

问题&#xff1a;创建虚拟环境&#xff0c;在pycharm中配置虚拟环境的Python解释器&#xff0c;然后在pycharm中打开ipynb&#xff0c;执行发现缺少包&#xff0c;但是虚拟环境中已经安装了 解决方式&#xff1a; 配置Jupyter Notebook 使用虚拟环境的Python解释器 1&#x…

ElasticSearch总结2

一、创建索引库&#xff1a;PUT ES中通过Restful请求操作索引库、文档。请求内容用DSL语句来表示。创建索引库和mapping的DSL语法如下&#xff1a; 整个jason 里边&#xff0c;它有一个叫mapping的属性&#xff0c;代表的是映射。映射里边有properties代表就是字段。可以看到这…

C++入门系列-缺省参数

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 缺省参数的概念 缺省参数是生命或者定义函数时为函数的参数指定一个缺省值&#xff0c;在调用该函数时&#xff0c;如果没有指定实参则采用该形参的缺省值&#xff0c;否则使用…

一单利润100+,不起眼的小生意,却能闷声发财!

今天&#xff0c;我想向大家介绍一个看似不太热门&#xff0c;但实际上需求很高的项目——酒店代订。这个项目其实很早以前就已经有人开始尝试了&#xff0c;但可能并没有被大众所熟知。简而言之&#xff0c;酒店代订就是帮助他人通过我们来预订他们想要入住的酒店。 当客户将…