当前位置:   article > 正文

【性能优化】Simpleperf的认识和使用

simpleperf

引言

Simpleperf 是一个Android平台上的一个cpu剖析工具,它可以用来分析app进程和native进程,分析Java和C++代码,simpleperf可执行程序最低运行在L版本,python脚本工具最低运行在N版本。–翻译自googlesource

内容

Simpleperf 目录包含两部分:simpleperf 可执行程序和python脚本。python脚本是对simpleperf的封装和调用,基本操作使用脚本更加简单遍历,本文只关注python脚本的入门使用。(直接使用simpleperf可执行程序也可以,需要手动push到设备中去,然后掌握语法就可以)

安装

方法1,simpleperf包含在ndk中,如果已经安装android studio,可从AS上直接下载安装ndk组件,在sdk下命名为ndk-bundle,也可以单独下载ndk。

方法2,单独下载simpleperf压缩包(可根据ndk版本进行选择)

查看下simpleperf根目录
在这里插入图片描述
其中,Simpleperf的可执行程序在bin目录下可以看到,不同平台的都提供了,如果只是在windows下,就只需要android和
windows就够了。
在这里插入图片描述

采集脚本

我们回头来看看脚本,可以根据他们的功能分为三类:

功能脚本
录制app_profiler.py, run_simpleperf_without_usb_connection.py,inferno,run_simpleperf_on_device.py
生成报告report.py,report_sample.py
解析数据simpleperf_report_lib.py

那么如何使用呢?看一下官方提供的方法。稍后我们自己实操一下。

app_profiler.py

Record cpu profiling data of an android app or native program.
It downloads simpleperf on device, uses it to collect profiling data on the selected app,
and pulls profiling data and related binaries on host.

点击查看官网例程 - app_profiler.py

查看下使用手册

$ python .\app_profiler.py --help

usage: app_profiler.py [-h]
                       (-p APP | -np NATIVE_PROGRAM | -cmd CMD | --pid PID [PID ...] | --tid TID [TID ...] | --system_wide)
                       [--compile_java_code] [-a ACTIVITY | -t TEST]
                       [-r RECORD_OPTIONS] [-lib NATIVE_LIB_DIR]
                       [-o PERF_DATA_PATH] [-nb] [--ndk_path NDK_PATH]
                       [--disable_adb_root] [--log {debug,info,warning}]

app_profiler.py: Record cpu profiling data of an android app or native program.

    It downloads simpleperf on device, uses it to collect profiling data on the selected app,
    and pulls profiling data and related binaries on host.

optional arguments:
  -h, --help            show this help message and exit

Select profiling target:
  -p APP, --app APP     Profile an Android app, given the package name. Like
                        `-p com.example.android.myapp`.
  -np NATIVE_PROGRAM, --native_program NATIVE_PROGRAM
                        Profile a native program running on the Android
                        device. Like `-np surfaceflinger`.
  -cmd CMD              Profile running a command on the Android device. Like
                        `-cmd "pm -l"`.
  --pid PID [PID ...]   Profile native processes running on device given their
                        process ids.
  --tid TID [TID ...]   Profile native threads running on device given their
                        thread ids.
  --system_wide         Profile system wide.

Extra options for profiling an app:
  --compile_java_code   Used with -p. On Android N and Android O, we need to
                        compile Java code into native instructions to profile
                        Java code. Android O also needs wrap.sh in the apk to
                        use the native instructions.
  -a ACTIVITY, --activity ACTIVITY
                        Used with -p. Profile the launch time of an activity
                        in an Android app. The app will be started or
                        restarted to run the activity. Like `-a
                        .MainActivity`.
  -t TEST, --test TEST  Used with -p. Profile the launch time of an
                        instrumentation test in an Android app. The app will
                        be started or restarted to run the instrumentation
                        test. Like `-t test_class_name`.

Select recording options:
  -r RECORD_OPTIONS, --record_options RECORD_OPTIONS
                        Set recording options for `simpleperf record` command.
                        Use `run_simpleperf_on_device.py record -h` to see all
                        accepted options. Default is "-e task-clock:u -f 1000
                        -g --duration 10".
  -lib NATIVE_LIB_DIR, --native_lib_dir NATIVE_LIB_DIR
                        When profiling an Android app containing native
                        libraries, the native libraries are usually stripped
                        and lake of symbols and debug information to provide
                        good profiling result. By using -lib, you tell
                        app_profiler.py the path storing unstripped native
                        libraries, and app_profiler.py will search all shared
                        libraries with suffix .so in the directory. Then the
                        native libraries will be downloaded on device and
                        collected in build_cache.
  -o PERF_DATA_PATH, --perf_data_path PERF_DATA_PATH
                        The path to store profiling data. Default is
                        perf.data.
  -nb, --skip_collect_binaries
                        By default we collect binaries used in profiling data
                        from device to binary_cache directory. It can be used
                        to annotate source code and disassembly. This option
                        skips it.

Other options:
  --ndk_path NDK_PATH   Set the path of a ndk release. app_profiler.py needs
                        some tools in ndk, like readelf.
  --disable_adb_root    Force adb to run in non root mode. By default,
                        app_profiler.py will try to switch to root mode to be
                        able to profile released Android apps.
  --log {debug,info,warning}
                        set log level
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

run_simpleperf_on_device.py

This script pushes the simpleperf executable on the device, and run a simpleperf command on the device. It is more convenient than running adb commands manually.
这个脚本会把simpleperf 可执行程序push到设备上,然后在设备上执行命令,比直接通过adb命令去执行更加方便

点击查看官网举例 - Profile from launch of an application

查看下手册,其实它的subcommands就几乎等于simpleperf的,想查看的同学可以执行下simpleperf -h看下。

$ python .\run_simpleperf_on_device.py -h

Usage: simpleperf [common options] subcommand [args_for_subcommand]
common options:
    -h/--help     Print this help information.
    --log <severity> Set the minimum severity of logging. Possible severities
                     include verbose, debug, warning, info, error, fatal.
                     Default is info.
    --log-to-android-buffer  Write log to android log buffer instead of stderr.
    --version     Print version of simpleperf.
subcommands:
    api-collect         Collect recording data generated by app api
    api-prepare         Prepare recording via app api
    debug-unwind        Debug/test offline unwinding.
    dump                dump perf record file
    help                print help information for simpleperf
    inject              parse etm instruction tracing data
    kmem                collect kernel memory allocation information
    list                list available event types
    record              record sampling info in perf.data
    report              report sampling information in perf.data
    report-sample       report raw sample information in perf.data
    stat                gather performance counter information
    trace-sched         Trace system-wide process runtime events.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

run_simpleperf_without_usb_connection.py

run_simpleperf_without_usb_connection.py records profiling data while the USB cable isn‘t connected. Maybe api_profiler.py is more suitable, which also don’t need USB cable when recording. Below is an example.
在不连接USB的情况下,记录数据,可能api_profiler.py更适用,它在记录数据的时候也不需要连接usb

点击查看官网举例 - run_simpleperf_without_usb_connection_py

看下手册

$ python .\run_simpleperf_without_usb_connection.py -h
usage: run_simpleperf_without_usb_connection.py [-h] {start,stop} ...

    Support profiling without usb connection in below steps:
    1. With usb connection, start simpleperf recording.
    2. Unplug the usb cable and play the app you want to profile, while the process of
       simpleperf keeps running and collecting samples.
    3. Replug the usb cable, stop simpleperf recording and pull recording file on host.

    Note that recording is stopped once the app is killed. So if you restart the app
    during profiling time, simpleperf only records the first running.

positional arguments:
  {start,stop}
    start       Start recording.
    stop        Stop recording.

optional arguments:
  -h, --help    show this help message and exit
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

根据介绍,大概是说,连接前执行下start,结束录制时,连上usb,执行stop后pull出采集的数据,适用于不连接usb充电的场景。需要注意的是:如果途中app被kill,会自动结束采集数据。

查看报告

上一步我们主要学会怎么执行脚本来采集数据,有了数据就是以哪种形式查看和分析了。官网给出了N多个选择(点击浏览

先看一个自带的,其他方法还没试过,目的都是以图形化的形式辅助我们分析函数耗时。

report_html.py

report_html.py generates report.html based on the profiling data. Then the report.html can show the profiling result without depending on other files. So it can be shown in local browsers or passed to other machines. Depending on which command-line options are used, the content of the report.html can include: chart statistics, sample table, flamegraphs, annotated source code for each function, annotated disassembly for each function.

转换prof.data 为html报告的形式。其中可包含火焰图。

看下手册

$ python .\report_html.py -h
usage: report_html.py [-h] [-i RECORD_FILE [RECORD_FILE ...]] [-o REPORT_PATH]
                      [--min_func_percent MIN_FUNC_PERCENT]
                      [--min_callchain_percent MIN_CALLCHAIN_PERCENT]
                      [--add_source_code]
                      [--source_dirs SOURCE_DIRS [SOURCE_DIRS ...]]
                      [--add_disassembly]
                      [--binary_filter BINARY_FILTER [BINARY_FILTER ...]]
                      [--ndk_path NDK_PATH] [--no_browser] [--show_art_frames]
                      [--aggregate-by-thread-name]

report profiling data

optional arguments:
  -h, --help            show this help message and exit
  -i RECORD_FILE [RECORD_FILE ...], --record_file RECORD_FILE [RECORD_FILE ...]
                        Set profiling data file to report. Default is
                        perf.data.
  -o REPORT_PATH, --report_path REPORT_PATH
                        Set output html file. Default is report.html.
  --min_func_percent MIN_FUNC_PERCENT
                        Set min percentage of functions shown in the report.
                        For example, when set to 0.01, only functions taking
                        >= 0.01% of total event count are collected in the
                        report. Default is 0.01.
  --min_callchain_percent MIN_CALLCHAIN_PERCENT
                        Set min percentage of callchains shown in the report.
                        It is used to limit nodes shown in the function
                        flamegraph. For example, when set to 0.01, only
                        callchains taking >= 0.01% of the event count of the
                        starting function are collected in the report. Default
                        is 0.01.
  --add_source_code     Add source code.
  --source_dirs SOURCE_DIRS [SOURCE_DIRS ...]
                        Source code directories.
  --add_disassembly     Add disassembled code.
  --binary_filter BINARY_FILTER [BINARY_FILTER ...]
                        Annotate source code and disassembly only for selected
                        binaries.
  --ndk_path NDK_PATH   Find tools in the ndk path.
  --no_browser          Don't open report in browser.
  --show_art_frames     Show frames of internal methods in the ART Java
                        interpreter.
  --aggregate-by-thread-name
                        aggregate samples by thread name instead of thread id.
                        This is useful for showing multiple perf.data
                        generated for the same app.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

通过一个例子来观察APP冷启动(以抖音为例)

  1. 确定下包名和lancherActivity。

PackageName : com.ss.android.ugc.aweme
LancherActivity: com.ss.android.ugc.aweme/.splash.SplashActivity

提前执行一下:adb shell am force-stop com.ss.android.ugc.aweme

  1. 执行开始监控命令

python .\app_profiler.py -p com.ss.android.ugc.aweme -a com.ss.android.ugc.aweme.splash.SplashActivity -r “-e task-clock:u -f 100 -g --duration 10”

  1. 上一步完成后会得到一个默认命名为perf.data的文件(可增加-o参数重命名)。继续执行下:

python .\report_html.py

  1. 完成解析后会得到一个默认命名为report.html的文件(可增加-o参数重命名),一般会自动打开。

火焰图分析

切换到第三个选项卡:Flamegraph(火焰图)

  • 每一列代表一个调用栈(栈帧),每一个格子代表一个函数。

  • 纵轴代表调用栈的深度,越高代表调用栈越深,下面的方格是上面方格的复函数。

  • 横轴代表火焰图将采集的多个调用栈信息,通过按字母横向排序的方式将众多信息聚合在一起。需要注意的是它并不代表时间。

  • 火焰图格子的颜色是随机的暖色调。

先确定下主线程,然后搜索下我们熟悉的onCreate方法,匹配到的方法会标识为紫色。

在这里插入图片描述
点击函数,可以以这个函数为新的底,以此来跟踪它的子调用。(点击zoom out返回上一级)

分析函数耗时,就是主要看“平顶”函数,耗时越长越能高概率被抽样到,“回回抽查都有你”。

个人理解,函数耗时长进一步分析思路:

  • 设计:关注函数自身逻辑是否设计合理,是否有递归?
  • 调度:线程优先级是否较低,在大核还是小核被调度?
  • 限频:频率是否被限制,可配合trace一起分析。
  • 阻塞:是否有阻塞等待,binder调用等待。
  • 锁:锁竞争

结束

当前的主要目的是学会Simpleperf的抓取和采集方法,并能识别出一些比较明显的函数耗时问题,其实官网的描述是最全面的,本文也在各个地方插入了超链接方便跳转,如果有想对一些细节或一些其他用法的需要,可以查看官网。

参考

【译】Simpleperf分析之Android系统篇

【官网 - Executable commands reference 不借助脚本原始使用Simpleperf】

【官网 - Simpleperf # Android platform profiling 采集系统进程】

【官网 - Simpleperf # Android application profiling 采集应用程序】

【官网 - Simpleperf # Scripts reference 脚本的使用】

【官网 - Simpleperf # view_the_profile 查看报告的各种方式】

⁨Firefox Profiler⁩

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/196553
推荐阅读
相关标签
  

闽ICP备14008679号