您的位置:首页 > 移动开发

如何用 Telemetry 测试移动 APP H5性能?

2016-10-24 14:29 921 查看

Telemetry 是什么

Chromium 将其性能测试自动化框架取名为 Telemetry。而在英文中,telemetry 的意思是远距离测量,或者说遥测。顾名思义,在 Chromium 测试人员看来 Telemetry 是一种可以用来很方便对 Chromium 性能进行测试并查看其性能报表的平台。更详细的资料可以查看其 项目主页

一般而言,我们讨论 Chromium 中的 Telemetry 包含了两个部分:

Telemetry 性能测试框架:

在 Chromium 源码中的相对路径:src/external/github.com/catapult-project/catapult/telemetry。

一种基于远程调试协议运行的 Python 框架,单独剥离出来用作性能测试,可以实现在一组网页上运行任意操作, 并生成性能报表。

Chromium Telemetry 性能测试 Benchmark 集

在 Chromium 源码中的相对路径:src/tools/perf/

Chromium 预定义性能测试 Benchmark 集合,涵盖丰富的各类性能测试项目。

在本文中,我们讨论的 Telemetry 包含了性能测试框架以及 Chromium Benchmark 集合两个部分。

Telemetry 可以做什么

Telemetry 是 Chromium/Chrome 项目组开发的,显然 Telemetry 最主要的功能是提供支持 Chromium 和 Chrome 的性能测试。当然也可以在对代码进行修改的基础上支持基于 Chromium 内核的其他浏览器。

这部分功能 Telemetry 支持得十分到位,Chromium 性能测试的测试用例可以在其源码 src/tools/perf 中获得。其中几乎涵盖了对浏览器的所有性能测试项。

但是,Telemetry 的并不局限于此。以下是 开发人员的介绍

The most urgent customer of telemetry is chrome engineers driving graphs on chromeperf. However, we also want telemetry to be usable by people building web content that targets chrome. That latter case is the one that is at play here.

If you’re a web-view based app, and you wanted to test smoothness, then you want to test the smoothness of your app, then you’d want to test your full app. If one of these customizations is affecting the smoothness, then its a good thing that these customizations get caught by telemetry.

对于包含 WebView 的 APP而言,Telemetry 也能支持对其 WebView 部分的性能测试。以下是 开发人员脑洞的部分使用场景:

some random examples which come to my mind:

put random code in the middle of the network loader stack (overriding the various ShouldOverride… On… callbacks)

put the webview on a (semi)-transparent window or putting extra native UI on top of the webview (it’s my understanding that is going to penalize rendering performance)

Force the WebView to work in sw-rendering mode (ditto + some tests might fail completely?)

Inject javascript execution at random points (or more likely in correspondence of some WebView events)

Do some other computation in the embedder app.

另外,现在也有部分的 Web 服务基于 Telemetry 框架来测试自身的Web服务性能,这也是对框架的一种灵活使用。

例如,Adobe的 Edge Code 和 Edge Reflow 使用 Telemetry 框架进行性能测试:

在 Telemetry 所支持的整组基准测试中,滚动基准测试最适合我们的使用情形。这种基准测试会在页面中滚动,并收集有关响应速度的指标,例如每秒绘制的百万像素数、丢弃的帧数以及帧速率(通过帧平均传输时间)

又如,Github 中的开源工程 Topcoat 也是使用 Telemetry 框架进行性能测试:

A telemetry test is essentially any sub-class of multi_page_benchmark.MultiPageBenchmark. Take a look at LoadingBenchmark (in src/tools/perf/loading_benchmark.py) and SmoothnessBenchmark (in src/tools/perf/smoothness_benchmark.py) - these two tests are of particular importance for us.

综上,Telemetry 的适用范围很广。从 Web 服务,到浏览器(含Webview & 内核),到 基于 Webview 的 Embedder App 都可以用它来测试其性能。

Telemetry 环境怎么搭建

搭建 Telemetry 测试环境,最佳的做法是获取整个 Chromium 源代码。

笔者尝试在 Mac 以及 Windows 上按 The Chromium Projects 中 Telemetry: Run Benchmarks Locally 提供的指引搭建 Android 的测试环境,均告失败(但 Mac Chrome 和 Windwos Chrome 可以执行 )。后来才在网上查到:

Unfortunately, the telemetry code has some nasty dependencies on the chromium codebase - my attempt to extract only the telemetry code for simpler use in topcoat have failed. Extracting the full chromium codebase is necessary.

不过如果你使用 Linux 进行测试,那么就简单许多了。可以直接下载 The Chromium Projects 中 Telemetry: Run Benchmarks Locally 提供的 latest Telemetry archive 并解压。当然你还需要按照其指引安装必备的工具,如 python,adb,python-psutil,libstdc++6:i386 等等。相当简单,由此猜想 Chromium 的标准开发环境应该是 Linux 了。

搭建完成后,我们可以可以使用 Telmetry 进行本地的测试了。

例如,我们可以使用一下命令执行测试:

./run_benckmark smoothness.top_25 --browser=android-chrome-beta --reset-results --use-live-sites


其中,–reset-results 指定了生成 HTML 结果,而使用 –use-live-sites 则是为了避免因权限或网络问题导致无法使用离线缓存页面。

其他的一些常用参数如下表所示:

NameEffect
–browser={list, version}Change the version of the browser used.
–repeat=NRepeats the test N times. Note that flaky tests might fail after repetition.
–story-filter=regexOnly run pages from the pageset that match the given regex.
–story-filter-exclude=regexInverse of the above.
-v, -vvChange log level
–show-stdoutShow browser stdout
–extra-browser-args=regexPass extra arguments when invoking the browser.
更多的参数用法可以查看使用说明:

./run_benckmark run --help


Telemetry Benckmark 自带了哪些功能

在 Chromium 的性能测试用例中包含了以下的 benchmark:blink, v8, smooth, memory, power, page load, webrtc, gpu 等等,几乎涵盖了性能的方方面面。

此外,Telemetry 中的 benchmark 还标明了其对不同浏览器的支持程度。例如,有些用例只支持 Android 平台,有的有不支持 Windows,有的需要测试对象具备 tab 页等等。

具体的情况我们可以通过 Telemetry 进行查看,例如查看 beta 版本 chrome 可以执行一下命令:

./run_benckmark list --browser=android-chrome-beta


当然如果你需要查看其他的浏览器的支持情况,只需要更改 –browser 参数后的数值即可。

Telemetry 源码结构是怎样的

我们以 The Chromium Projects 中 Telemetry: Run Benchmarks Locally 提供的 latest Telemetry archive 为蓝本,简单分析一下 Telemetry 的源码结构:

该分析的时间为2016年10月,后期的 Telmetry 源码可能有更新,不过预计变动程度应该不会太大。请各位看官周知。

根目录 & src目录:
.
|-- record_wpr         #Record Web Page to Replay
|-- run_benchmark      #Run Benchmark
|-- run_gpu_test.py    #Run GPU Test
|-- src                #源码及实现部分
|   |-- chrome         #略,下详
|   |-- content        #略,下详
|   |-- testing        #略,下详
|   |-- third_party    #略,下详
|   |-- tools          #略,下详

src - chrome 目录:
|-- test
|   |-- data

src - content 目录:
|-- test
|   |-- data    #GPU 测试框架所需数据
|   |-- gpu     #GPU 测试框架

src - testing 目录:
|-- test
|   |-- variations    #To ensure testing coverage of the experiments

src - third_party 目录:
|-- catapult    #chromium 的性能测试框架
|   |-- bin                   #可执行文件
|   |-- catapult_base         #?
|   |-- catapult_build        #?
|   |-- dashboard             #App Engine web app for displaying and monitoring performance test results
|   |-- dependency_manager    #依赖管理
|   |-- devil                 #用于 Android 设备交互的工具
|   |-- experimental          #处于实验阶段的功能
|   |-- firefighter           #App Engine dashboard that visualizes time series data
|   |-- hooks                 #?
|   |-- infra                 #?
|   |-- lighthouse            #一款面向网页开发者的性能测试工具
|   |-- per_insights          #一款用于批量分析 trace 的 UI 工具
|   |-- systrace              #Android Systrace 工具
|   |-- telemetry             #Telemetry工具
|-- webgl    #目前,仅提供 WebGL conformance test suite

src - tools 目录:
|-- perf         #chromium 源码中的性能测试用例
|   |-- benchmarks                #基准集合
|   |-- chrome_telemetry_build    #用于提供本地 Telemetry 运行所必需的文件
|   |-- clear_system_cache        #清理系统缓存的命令行工具
|   |-- core                      #核心逻辑模块,主要用于组织测试任务的相关配置信息
|   |-- docs                      #文档
|   |-- generated_profiles        #获取到的 Chrome profiles
|   |-- measurements              #测量方法集合
|   |-- metrics                   #测量指标集合
|   |-- page_sets                 #网页集合
|   |-- profile_creators          #用于获取 Chrome profiles
|   |-- third_party               #三方工具,目前仅包含用于SVN代码同步的辅助工具
|   |-- utils                     #自定义工具集合,目前仅包含用于查看结果的辅助工具
|-- telemetry     #与 ./src/third_party/catapult/telemetry 重复
|-- variations    #?


Telemetry 如何支持自定义浏览器

Telemetry 除了可以支持浏览器性能测试外,对 Android 中 第三方 APP 的 Webview 页面也能进行部分基准测试。因此,这部分中,我们除了介绍如何添加 Android 三方浏览器外,还要讨论如何添加 Android 的第三方APP。

如何添加基于 Chromium 内核的三方浏览器/APP

由于强大的 Chromium 内核是开源的,因此市面上绝大多数第三方 Android 浏览器都是基于 Chromium 内核的,因此理论上这些浏览器都可以支持 Telemetry。但是需要注意的是由于种种原因,大部分第三方浏览器的发行版本可能会移除 Inspector,这使得 Telemetry 无法正常工作 。因此,我们需要确认我们进行测试的浏览器是带有 Inspector 的。

增加支持共分为两个步骤:

第一步:在 android_browser_backend_settings.py 增加支持项

/src/third_party/catapult/telemetry/telemetry/internal/backends/android_browser_backend_settings.py

这是 Telemetry 中自带的 Chrome APP 以及系统自带浏览器的例子:

class ChromeBackendSettings(AndroidBrowserBackendSettings):
# Stores a default Preferences file, re-used to speed up "--page-repeat".
_default_preferences_file = None

def GetCommandLineFile(self, is_user_debug_build):
if is_user_debug_build:
return '/data/local/tmp/chrome-command-line'
else:
return '/data/local/chrome-command-line'

def __init__(self, package):
super(ChromeBackendSettings, self).__init__(
activity='com.google.android.apps.chrome.Main',
cmdline_file=None,
package=package,
pseudo_exec_name='chrome',
supports_tab_control=True)

def GetDevtoolsRemotePort(self, device):
return 'localabstract:chrome_devtools_remote'

class WebviewBackendSettings(AndroidBrowserBackendSettings):
def __init__(self,
package,
activity='org.chromium.webview_shell.TelemetryActivity',
cmdline_file='/data/local/tmp/webview-command-line'):
super(WebviewBackendSettings, self).__init__(
activity=activity,
cmdline_file=cmdline_file,
package=package,
pseudo_exec_name='webview',
supports_tab_control=False)

def GetDevtoolsRemotePort(self, device):
# The DevTools socket name for WebView depends on the activity PID's.
retries = 0
timeout = 1
pid = None
while True:
pids = device.GetPids(self.package)
if not pids or self.package not in pids:
time.sleep(timeout)
retries += 1
timeout *= 2
if retries == 4:
logging.critical('android_browser_backend: Timeout while waiting for '
'activity %s:%s to come up',
self.package,
self.activity)
raise exceptions.BrowserGoneException(self.browser,
'Timeout waiting for PID.')
if len(pids[self.package]) > 1:
raise Exception(
'At most one instance of process %s expected but found pids: '
'%s' % (self.package, pids))
pid = pids[self.package][0]
break
return 'localabstract:webview_devtools_remote_%s' % str(pid)


我们可以依样画葫芦,添加一个第三方浏览器(假设其包名为com.sanfang.browser,浏览页面为MainActivity)

class SanfangBrowserBackendSettings(AndroidBrowserBackendSettings):
def __init__(self,
package,
activity='com.sanfang.browser.MainActivity',
cmdline_file='/data/local/tmp/webview-command-line'):
super(QBWebviewBackendSettings, self).__init__(
activity=activity,
cmdline_file=cmdline_file,
package=package,
pseudo_exec_name='sanfangbrowser',
supports_tab_control=True)

def GetDevtoolsRemotePort(self, device):
# The DevTools socket name for WebView depends on the activity PID's.
retries = 0
timeout = 1
pid = None
while True:
pids = device.GetPids(self.package)
if not pids or self.package not in pids:
time.sleep(timeout)
retries += 1
timeout *= 2
if retries == 4:
logging.critical('safang_browser_backend: Timeout while waiting for '
'activity %s:%s to come up',
self.package,
self.activity)
raise exceptions.BrowserGoneException(self.browser,
'Timeout waiting for PID.')
if len(pids[self.package]) > 1:
raise Exception(
'At most one instance of process %s expected but found pids: '
'%s' % (self.package, pids))
pid = pids[self.package][0]
break
return 'localabstract:webview_devtools_remote_%s' % str(pid)


第二步:在 android_browser_finder.py 增加支持项

/src/third_party/catapult/telemetry/telemetry/internal/backends/chrome/android_browser_finder.py

这是 Telemetry 中自带的 Chrome APP 以及系统自带浏览器的例子:

CHROME_PACKAGE_NAMES = {
...
'android-chrome':
['com.google.android.apps.chrome',
android_browser_backend_settings.ChromeBackendSettings,
'Chrome.apk'],
...
'android-system-browser':
['com.android.browser',
android_browser_backend_settings.WebviewBackendSettings,
None],
...
}


我们也同样的依样画葫芦:

CHROME_PACKAGE_NAMES = {
...
'android-sanfang-browser':
['com.sanfang.browser',
android_browser_backend_settings.SanfangBrowserBackendSettings,
None],
...
}


如何添加第三方 APP

如何你要添加的 APP 是基于 WebView 开发的,那么添加过程很简单,只需要在 android_browser_finder.py 增加支持项即可:

/src/third_party/catapult/telemetry/telemetry/internal/backends/chrome/android_browser_finder.py

CHROME_PACKAGE_NAMES = {
...
'android-sanfang-app':
['com.sanfang.app',
android_browser_backend_settings.WebviewBackendSettings,
None],
...
}


不过需要注意的是,在这种情况下,Telemetry 假定该 APP 有且只用 1 个 Webview 页面。然后 Telemetry 会自动的根据你提供的包名找到他的PID,最终获取 Remote Devtools Socket “localabstract:webview_devtools_remote_$PID”

Telemetry 如何支持自定义的用例

咱们还是先来看看 Chromium 项目是如何使用 Telemetry 的,即一个所谓的 Benckmark 是如何定义的:



在 Telemetry 中, 一个 Benchmark(基准测试) 由以下部分组成: 一种 Measurement(测量方法), 一个 Page Set(页面集合) 以及一系列的 Browser options(浏览器参数)。这样封装的好处是,Benchmark 中几乎已经包含了测试所需要的所有配置,因此我们可以很方便来执行一次基准测试.

那么,如果要定义自己的 Benchmark 也就需要依次搞定 Measurement(测量方法), Page Set(页面集合).

自定义 Measurement(测量方法)

首先,需要提前声明一点的是:自定义 Measurement 难度较高,而且几乎很需求较少(需要同时满足,现有 Measurements 不支持,并且确实业务上又有需求)。笔者脑洞了一下,也许只有某天出现了新的性能测试方向或者性能测试技术出现更新,这样的需求才会出现。

这是官方的声明:

Are you sure you want to add a measurement?

Writing a good measurement is really hard. We already have a bunch of measurements in tools/perf/measurements for you to use. If you are looking to write a new benchmark, you probably just need to add or modify an existing story set and you might need to add new metrics to an existing measurement. Think twice before you write another measurement.

What is a measurement?

A measurement is a python class that obtains a set of Numbers about a Page. Measurements must work for all pages, not just one specific page.

正如 Telemetry 声明的那样, 一个 Measurement 需要支持所有的测试页面,不能仅仅只针对某一个页面单独设计。

由于,一个 Benchmark 严格对应一个 Measurement。因此,为了在一次 Benchmark 测试中获取到多维度的性能指标一个 Measurement 可以对应多个 Metrics(测量指标)。

Telemetry 推荐使用 Timeline-Based Measurement 来设计具体的 Metrics 并组合成你自己需要的 Measurement,这样的话,可以用统一的方式从 trace 当中获取数据。Timeline-Based Measurement 的相关代码在 src/tools/telemetry/telemetry/web_perf 可以查看。

如果需要获取更多 Timeline-Based Measurement 的资料可以访问以下链接:

Why choose TimelineBasedMeasurement over other measurements?

How does TimelineBasedMeasurement work?

自定义 Page Set(页面集合)

创建自己的 Page Set

在 Telemetry 中的 Page Set 都在 src/tools/perf/page_sets/ 目录下。一个只含有单个页面的 Page Set 写法如下:

from telemetry.page import page
from telemetry.page import page_set

class MyPageSet(page_set.PageSet):
def __init__(self):
super(MyPageSet, self).__init__(
user_agent_type='desktop',
archive_data_file='data/my_page_set.json',
bucket=page_set.PUBLIC_BUCKET)
self.AddPage(page.Page(
name='example',
url='http://example.com/',
page_set=self))


其中需要关注的两个参数是:

user_agent_type:指定 user agent 是 desktop, mobile, or tablet

archive_data_file:在 Record Page Set 模块中,指定了各页面分别存储的位置

bucket:为规避法律风险,为 Record Page Set 指明云存储位置,PUBLIC_BUCKET 所有人均可访问,PARTNER_BUCKET | INTERNAL_BUCKET 在外部使用都需要额外开通权限。

将自己的 Page Set 进行离线缓存

为了在性能测试中获得更为稳定的测试结果,我们需要控制测试站点页面变更以及网络环境波动对我们造成的影响。因此,我们需要使用到 Web Page Replay 来进行页面缓存。

下图说明了 Web Page Replay 的工作流程:



具体使用上,我们可以通过 ./record_wpr 工具进行页面缓存。命令如下:

./record_wpr --browser=(release|system) <page_set_name>_page_set


页面缓存之后将形成一下一些文件:

.wpr: 缓存内容的记录文件(注意,.wpr 后缀文件已被设置为 git ignore list 之中)

.wpr.sha1: 记录 wpr 文件的 SHA1 信息

.json : 记录 wpr 文件的 metadata

按正常流程,最后一步将会是把我们的缓存文件提交给云存储。但由于国内网络环境原因以及 bucket 的各种环境影响,一般而言,我们不需要将我们的 wpr 文件上传至云存储也即可正常使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息