HarmonyOS开发实战( Beta5版)使用AOT进行性能优化实践规范

157 篇文章 0 订阅
157 篇文章 0 订阅

AOT运行机制介绍

在未启用AOT时,源代码在IDE侧通过编译得到字节码,并且打包成可被安装的可执行文件,在应用运行时,运行时会将字节码解释为机器可执行的机器码。在这个期间,如果有热点代码被反复的执行,那么会增加解释执行的成本,造成性能开销。

图1 未启用AOT执行示意图 

采用AOT编译的方式,首先需要在IDE侧,通过hdc或者IDE直接执行相应指令,生成记录运行时信息的ap文件,然后在安装时将ap文件提供给AOT编译器。开启AOT后,在设备侧运行时会执行AOT编译,对ap文件中保存的执行信息(热点函数,分支语句、运行时变量的类型信息等)进行编译优化,生成高性能的机器码,在程序解释执行时,对于热点函数执行时,将直接执行优化后的机器码,便能够极大提升执行效率。

图2 启用AOT编译示意图 

使用AOT编译

本案例基于业界编程语言Benchmarks Game中提出的模拟N体问题,编写了类木星体轨道计算程序的ArkTS实现。

轨道计算作为一个计算密集型程序,会大量占用系统资源计算能力的任务,需要长时间运行,这段时间会阻塞线程其它事件的处理,不适宜放在主线程进行。所以,本文案例基于多线程并发机制,以提高CPU利用率,提升应用程序响应速度。针对500万次时间推移的轨道计算,任务不需要长时间(>3分钟)占据后台线程,且是一个个独立的任务时,所以使用TaskPool开启多线程实现:

关于开启AOT编译的方法可以参考开启AOT编译模式

代码实现

其中主要执行计算的主函数体如下:

export function computeNBodyByTaskPool(totalTimeSteps: number): void {
  Logger.info(TAG, "computeNBodyByTaskPool: start executing")
  let task: taskpool.Task = new taskpool.Task(computeTask, totalTimeSteps);
  try {
    Logger.info(TAG, 'computeNBodyByTaskPool: start calculating...')
    // 向taskpool线程池派发子线程任务
    taskpool.execute(task, taskpool.Priority.HIGH).then((res: number) => {
      Logger.info(TAG, 'computeNBodyByTaskPool: executed successfully, total time costed = ' + res + ' ms.')
      AppStorage.set<String>('timeCost', 'Total time costed = ' + res + ' ms.')
    })
  } catch (err) {
    Logger.error(TAG, 'computeNBodyByTaskPool: execute failed, ' + (err as BusinessError).toString())
  }
  Logger.info(TAG, 'computeNBodyByTaskPool: finish executing')
}

被子线程执行的计算任务如下:

@Concurrent
export function computeTask(totalTimeSteps: number): number {
  const tagInTask: string = 'computeTask';
  const timeStep: number = 0.01; // 单位:hour
  const fractionDigits: number = 9; // 机械能数值小数位
  let start: number = new Date().getTime();

  // 建立孤立系统的动量守恒
  offsetMomentum();
  Logger.info(tagInTask, energy().toFixed(fractionDigits));

  // 更新天体在按指定的时间变化后的位置信息
  for (let i: number = 0; i < totalTimeSteps; i++) {
    advance(timeStep);
  }

  // 判断系统计算前后机械能守恒
  Logger.info(tagInTask, energy().toFixed(fractionDigits));
  let end: number = new Date().getTime();
  return end - start;
}

AOT收益对比

案例采用TaskPool和Worker两种方式开启子线程,来验证不同数据量规模下,AOT启用与否,对应用运行时间性能的影响。

可以采用Chrome浏览器JavaScript Profiler工具或者Deveco Studio的Profiler工具,抓取项目性能数据如下:

本文中是抓取的结果仅供参考。

  • 使用TaskPool开启子线程,计算500万次时间推移期间,天体的运行轨道:
    图3 未启用AOT


    图4 启用AOT

    可以看到,该项目核心计算函数advance的计算性能,提升了8倍左右。

  • 使用Worker开启子线程,计算5000万次时间推移期间,天体的运行轨道:
    图5 未启用AOT


    图6 启用AOT


    可以看到,该项目计算性能,提升了10倍左右。

    说明:

    该案例实际所基于的开发环境基本信息如下:
    IDE: 4.0.3.601
    AOT的收益在不同操作场景下、不同项目间都有差异性,取决于热点场景采集覆盖率、项目本身的TS/ArkTS负载率等因素。上述示例中的收益率不具有普适指导意义。

AOT预先编译在提升性能的同时,也会带来一些负向的开销,主要体现在编译时间、代码大小等方面的影响。开发者需要在性能收益和开销间进行权衡,从业务需求决策如何使用AOT预先编译。

AOT的开销影响

  1. 代码大小
    PGO为了提高程序的执行效率,会对代码进行优化,使得代码大小增加。对于OpenHarmony应用,可以从abc(ArkCompiler Bytecode)方舟字节码文件大小和hap应用包大小两方面评代码大小。

  2. 编译时间
    PGO需要对源代码进行静态分析,生成性能配置文件,然后将配置文件与源代码一起编译。这个过程会导致编译时间增加。
    针对实践案例中项目N-Body问题,其开销数据如下:

    AOT开启状态abc大小hap大小编译时间
    未启用AOT32832 Byte196 KB6 s 212 ms
    启用AOT32832 Byte206 KB6 s 558 ms

    说明:

    AOT开销的膨胀率在不同操作场景下、不同项目间都有差异性,取决于热点场景采集覆盖率、项目本身的TS/ArkTS负载率等因素。上述示例中的膨胀率不具有普适指导意义。

最后

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

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

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

GitCode - 全球开发者的开源社区,开源代码托管平台


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

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

路线图适合人群:

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

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

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

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

                   

鸿蒙APP开发必备

​​

总结

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

  • 18
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值