Flutter应用程序性能测试

Flutter框架默认情况下运行良好且快速,但这是否意味着您根本不需要考虑性能? 不行 编写会很慢的Flutter应用程序是绝对真实的。 另一方面,您也可以最大程度地使用该框架,从而使您的应用程序不仅快速而且高效,消耗更少的处理器和电池时间。



这就是我们希望看到的结果:通过一些重要指标比较应用程序的两个版本的统计结果。 继续阅读以了解操作方法。


有一些通用准则可优化Flutter中的性能:


  • 更新状态时尽可能少地参与小部件。
  • 仅在必要时更新状态。
  • build方法中取出计算密集型任务,理想情况下从主隔离中取出。

可悲的事实是,对于许多有关优化性能的问题,答案将是“多么幸运”。 这种特定的优化是否值得该特定小部件的工作量和维护成本? 在这种特定情况下,这种特定方法是否有意义?


这些问题的唯一有用的答案是测试和测量。 量化每个选择如何影响性能并根据此数据做出决策。


好消息是Flutter提供了出色的性能分析工具,例如Dart DevTools (当前在预览版本中),其中包括Flutter Inspector,或者您可以直接从Android Studio中使用Flutter Inspector (安装了Flutter插件)。 您有Flutter Driver来测试您的应用程序和Profile mode以保存性能信息。


坏消息是现代智能手机太聪明了。


监管机构的问题


对于iOS和Android控制器,量化Flutter应用程序的性能尤其困难。 这些系统级守护程序根据负载来控制中央处理器和图形处理器的速度。 当然,基本上这是个好办法,因为它可以减少电池消耗,提供平稳的运行。


缺点是您可以通过增加应用程序执行的工作量来加快应用程序的速度。


在下面,您可以看到对应用程序添加无意义的打印调用周期如何使调节器将CPU切换到更高的频率,从而使应用程序更快,性能更可预测。


监管机构的问题:默认情况下,您无法信任您的电话号码。 在此跨度图中,我们在x轴上有单独的运行(以它们开始的确切时间标记),在Y轴上有构建时间,如您所见,当我们引入一些完全不必要的打印语句时,这导致构建时间减少但没有。


在此实验中,最差的代码导致更快的构建时间(请参见上文),更快的光栅化时间和更高的帧速率。 当客观上较差的代码导致改进的性能指标时,您不能依靠这些指标作为指导(推荐)。


这只是移动应用程序性能测试如何直观而复杂的一个示例。


下面,我分享了在使用Flutter的Google I / O 开发人员任务应用程序时收集的一些技巧。


一般提示


  • 不要在调试模式( DEBUG mode )下测量性能。 仅在配置文件Profile mode测量性能。
  • 在真实设备上而非在iOS Simulator或Android Emulator上进行测量。 软件仿真器非常适合开发,但是其性能特征与真实仿真器不同。 Flutter不允许您在模拟设备上以配置文件模式工作,因为这没有任何意义。 您以这种方式收集的数据不适用于实际性能。
  • 理想情况下,使用完全相同的物理设备。 使其成为专用的性能测试设备,切勿将其用于其他任何用途。
  • 探索Flutter 性能分析工具

CPU / GPU调节器


如上所述,现代操作系统会根据负载和其他启发式方法更改每个处理器和GPU的频率。 (例如,触摸屏幕通常会提高Android手机的速度。)


在Android上,您可以禁用这些控件。 我们称此过程为“缩放锁定”。


  • 创建一个脚本来禁用设备上的控件以测试性能。 您可以使用Skia示例获取灵感。 您也可以签出Unix CPU API
  • 如果您不做像Skia一样多的测试工作,那么您可能会想要一些功能更轻巧的东西。 在Developer Quest中查看Shell脚本,以了解去向。 例如,脚本的下一部分将为用户空间控制器(唯一不更改处理器频率本身的控制器)设置CPU。
     #!/usr/bin/env bash GOV="userspace" echo "Setting CPU governor to: ${GOV}" adb shell "echo ${GOV} > /sys/devices/system/cpu/cpu${CPU_NO}/cpufreq/scaling_governor" ACTUAL_GOV=`adb shell "cat /sys/devices/system/cpu/cpu${CPU_NO}/cpufreq/scaling_governor"` echo "- result: ${ACTUAL_GOV}" 
  • 您的目标不是模拟真实性能(用户不关闭设备上的稳压器),而是在两次运行之间具有可比较的性能指标。
  • 最后,您需要进行实验并使Shell脚本适应将要使用的设备。 这行得通,但是除非您执行此操作,否则性能数据会欺骗您。


Developer Quest的早期版本,已在我的台式机上经过Flutter驱动程序测试。


颤振驱动程序


Flutter Driver允许您自动测试您的应用程序。 阅读flutter.dev上的“性能分析”部分,以了解在对应用程序进行性能分析时如何使用它。


  • 要测试性能,请不要手动测试您的应用程序。 始终使用Flutter驱动程序获取真正的指示性数据。
  • 编写Flutter驱动程序代码,以便它检查您真正要测量的内容。 如果需要整体应用程序性能,请尝试遍历应用程序的所有部分,然后执行用户会做的事情。
  • 如果您的应用程序具有随机性( Random ,网络事件等),则为此类情况创建“模拟”。 试运行应尽可能接近。
  • 如果需要,可以使用Timeline类的startSync()finishSync()方法将自定义事件添加到时间线 。 如果您对特定功能的性能感兴趣,这将很有用。 将startSync()放在其开始处,并将finishSync()放在其末尾。
  • 保存摘要( writeSummaryToFile ),更重要的是保存原始时间轴( writeTimelineToFile )。
  • 多次测试应用程序的每个版本。 对于Developer Quest,我花了100个开始。 (当您测量可能比较吵杂的事情(例如使用p99度量标准时,可能需要进行更多次运行)。)对于基于POSIX的系统,这仅意味着要执行以下操作: for i in {1..100}; do flutter drive --target=test_driver/perf.dart --profile; done for i in {1..100}; do flutter drive --target=test_driver/perf.dart --profile; done for i in {1..100}; do flutter drive --target=test_driver/perf.dart --profile; done

Chrome的时间轴工具,用于在Flutter中检查分析结果。


时间表


时间线是概要分析结果的原始输出。 Flutter将此信息写入JSON文件,该文件可以通过chrome://tracing下载。


  • 了解如何在Chrome中打开完整的时间表。 您只需打开chrome://tracing在Chrome浏览器中进行chrome://tracing ,单击“加载”并选择JSON文件。 您可以在此简短指南中阅读更多内容。 (目前还有一个Flutter时间轴工具正在技术预览中。我没有使用它,因为在Flutter工具准备好之前启动了Developer Quest项目。)
  • 使用WSAD键在chrome://tracing浏览时间轴chrome://tracing和1234更改操作模式。
  • 首次设置性能测试时,请考虑使用Systrace Android工具运行Flutter Driver。 这样可以使您更好地了解设备中实际发生的情况,包括有关缩放处理器频率的信息。 不要使用Systrace测量整个应用程序,因为这会使一切变慢并且难以预测。
  • 如何使用Flutter Driver运行Android Systrace? 首先,使用/path/to/your/android/sdk/platform-tools/systrace/systrace.py --atrace-categories=gfx,input,view,webview,wm,am,sm,audio,video,camera,hal,app,res,dalvik,rs,bionic,power,pm,ss,database,network,adb,pdx,sched,irq,freq,idle,disk,load,workq,memreclaim,regulators,binder_driver,binder_lock启动Android Systrace /path/to/your/android/sdk/platform-tools/systrace/systrace.py --atrace-categories=gfx,input,view,webview,wm,am,sm,audio,video,camera,hal,app,res,dalvik,rs,bionic,power,pm,ss,database,network,adb,pdx,sched,irq,freq,idle,disk,load,workq,memreclaim,regulators,binder_driver,binder_lock 。 然后flutter run test_driver/perf.dart --profile --trace-systrace应用程序flutter run test_driver/perf.dart --profile --trace-systrace 。 最后,运行Flutter Driver flutter drive --driver=test_driver/perf_test.dart --use-existing-app=http://127.0.0.1:NNNNN/ (其中NNNNN是使您在上面运行flutter应用程序的端口)。

指标


最好查看尽可能多的指标,但我认为某些指标比其他指标更有用。


  • 构建时间和栅格化时间(度量标准是使用TimelineSummary默认提供的)仅对真正艰难的性能测试有用,该性能测试除了创建用户界面外不包含其他内容。


  • 不要将TimelineSummary.frameCount视为计算每秒帧数(FPS)的方法。 Flutter分析工具不提供真实的帧速率信息。 TimelineSummary提供了countFrames()方法,但是它仅计算完成的框架装配的数量。 一个经过优化的应用程序可以限制不必要的重建(更新),其FPS会比未经优化的应用程序频繁地重建。


  • 就个人而言,我通过测量执行Dart代码所花费的总处理器时间来获得最有用的数据。 这将计算在build方法中以及在build方法之外执行的代码。 假设您在规模锁定的设备上运行性能分析测试,则可以将总CPU时间视为您的应用程序将消耗多少电池的良好估计。


  • 找出执行Dart代码所花费的处理器总时间的最简单方法是估计时间轴上的MessageLoop:FlushTasks事件的数量。 对于Developer Quest,我编写了Dart工具来提取它们。


  • 要查找垃圾(垃圾)(即掉落的帧),请寻找极端。 例如,对于特定情况的Developer Quest和我们测试过的设备,查看第95个百分点的构建时间很有用。 (即使将代码的性能水平完全比较,第90个百分位数的构建时间也非常相似,而第99个百分位数的数量通常很吵。您的性能可能会有所不同。)


  • 如上所述,测试您的应用程序的每个版本几次(也许100次)。 然后,将平均或百分位数数据与错误字段一起使用。 更好的是,使用跨度图。



结果


调整后,您可以放心地比较提交并进行实验。 在下面,您可以看到一个常见难题的答案:“这种维护成本的优化值得吗?”


我认为在这种特殊情况下,答案是肯定的。 只需几行代码,我们的应用程序的每个自动通道平均就可以减少12%的CPU时间。


但是-这是本文的主要内容-另一个优化的结果可能显示出完全不同的情况。 试图过于广泛地推断性能度量是很诱人的,但却是错误的。


换句话说:“多么幸运”。 我们必须忍受它。

Source: https://habr.com/ru/post/zh-CN451840/


All Articles