Simpleperf详细使用
一、Simpleperf介绍
Simpleperf是一个强大的命令行工具,它包含在NDK中,可以帮助我们分析应用的CPU性能。Simpleperf可以帮助我们找到应用的热点,而热点往往与性能问题相关,这样我们就可以分析修复热点源。
如果您更喜欢使用命令行,可以直接使用 Simpleperf。Simpleperf 是一个通用的命令行 CPU 性能剖析工具,包含在面向 Mac、Linux 和 Windows 的 NDK 中。
如需查看完整的文档,请先阅读 Simpleperf https://android.googlesource.com/platform/system/extras/+/master/simpleperf/doc/README.md。
官方的资料:
- Simpleperf 命令和选项参考
- Simpleperf 用法
二、基本工作原理
现代 CPU 具有一个硬件组件,称为性能监控单元(PMU)。PMU 具有一些硬件计数器,计数一些诸如经历了多少次 CPU 周期,执行了多少条指令,或发生了多少次缓存未命中等事件。
Linux 内核将这些硬件计数器包装到硬件 perf 事件中。此外,Linux 内核还提供了独立于硬件的软件事件和跟踪点事件。Linux 内核通过 perf_event_open 系统调用将这些暴露给用户空间,这正是 simpleperf 所使用的机制。
Simpleperf 具有三个主要的功能:stat,record 和 report。
Stat 命令给出了在一段时间内被剖析的进程中发生了多少事件的摘要。以下是它的工作原理:
- 给定用户选项,simpleperf 通过对 linux 内核执行系统调用来启用剖析。
- Linux 内核在调度到被剖析进程时启用计数器。
- 剖析之后,simpleperf 从内核读取计数器,并报告计数器摘要。
Record 命令记录一段时间内被剖析进程的采样。它的工作原理如下:
- 给定用户选项,simpleperf 通过对 linux 内核执行系统调用来启用剖析。
- Simpleperf 在 simpleperf 和 linux 内核之间创建映射缓冲区。
- Linux 内核在调度到被剖析进程时启用计数器。
- 每次给定数量的事件发生时,linux 内核将样本转储到映射缓冲区。
- Simpleperf 从映射缓冲区读取样本并stat生成 perf.data。
Report 命令读取 “perf.data” 文件及所有被剖析进程用到的共享库,并输出一份报告,展示时间消耗在了哪里。
三、环境要求
为了使用Simpleperf, 需要以下环境:
- 待分析的App应运行在Android 5.0或者更高版本的设备上
- 手机的USB 连接到操作机器
- 应用程序应该是 debuggable 的。由于安全限制的原因,只有 android::debuggable 设置为 true 的应用程序才能剖析。(在一个已经 root 的设备上,所有应用程序都可以剖析。)在 Android Studio 中,这意味着我们需要使用 debug 构建类型,而不是 release 构建类型。
- 为了能够运行Python scripts,宿主机器应安装:
-
- Python 2.7或者更高版本
- NDK的版本应不低于r13b
通常剖析 Android 应用程序性能包含三个步骤:
- 准备应用程序。
- 记录剖析数据。
- 生成剖析数据的分析报告。
Simpleperf的获取路径:https://android.googlesource.com/platform/prebuilts/simpleperf/
在页面内,可以直接压缩包下载,既可以选择NDK相对应的版本(R13~N21),也可以选择master。建议直接选择NDK对应的版本即可。当然,也可以git直接拉取仓库。
git clone https://android.googlesource.com/platform/prebuilts/simpleperf
查看下载的simpleperf目录,可以看出:它的工具集包涵client端和host端;client端运行在Android系统上,负责收集性能数据;host端则运行在开发机上,负责对数据进行分析和可视化(这些可执行文件在下载后的bin文件夹的android和win/linux下)。
除了bin文件夹之外,最上层还有很多.py的脚本文件。这些脚本和配置文件主要是官方写的一些傻瓜式的使用脚本,只需要对配置文件进行配置,就可以在直接在开发机上直接运行脚本,一键生成最终的结果。
Python 脚本根据它们的功能被分为三个部分:
- 用于简化剖析数据记录的脚本,如 app_profiler.py。
- 用于生成剖析报告的脚本,如 report.py,report_html.py,inferno。
- 用于解析剖析数据的脚本,如 simpleperf_report_lib.py。
主要的脚本是:app_profiler.py和report.py两个。
在android-ndk\simpleperf中包含了 simpleperf 可执行文件和 Python 脚本,它们的功能如下:
- bin/:包含可执行文件及共享库,里面包含了android和windows。
- bin/android/${arch}/simpleperf:设备上运行的静态 simpleperf 可执行文件。其中 ${arch} 为目标设备的 CPU 架构,如 arm 和 arm64。
- bin/${host}/${arch}/simpleperf:用于主机的 simpleperf 可执行文件,只支持生成报告。其中 ${host} 为主机的操作系统平台,如 linux,${arch} 为主机的 CPU 架构,如 x86_64。
- bin/${host}/${arch}/libsimpleperf_report.${so/dylib/dll}:用于主机的报告生成库。其中 ${host} 指主机的操作系统平台,${arch} 为主机的 CPU 架构。
- app_profiler.py:用于记录剖析数据的 Python 脚本。
- binary_cache_builder.py:用于为剖析数据构建二进制缓存的 Python 脚本。
- report.py:用于生成剖析报告并输出到标准输出的 Python 脚本。
- report_html.py:用于生成剖析报告并输出为 html 文件的 Python 脚本。
- inferno.sh (或 Windows 平台的 inferno.bat ):用于生成火焰图并输出为 html 文件的脚本工具。
- inferno/:inferno 的实现。由 inferno.sh 使用。
- pprof_proto_generator.py:将剖析数据的格式转换为 pprof 使用的格式的 Python 脚本。
- report_sample.py:将剖析数据的格式转换为 FlameGraph 使用的格式的 Python 脚本。
- simpleperf_report_lib.py:解析剖析数据的库。
脚本的主要内容,就是读取配置文件,然后执行adb shell ...的命令,其实本质上和命令行的输入没什么区别。但是,如果直接运行,不仅仅需要查看配置文件各个配置项的含义,还可能会出现许多意想不到的BUG,不太建议直接使用脚本,不得精髓啊。
四、支持的命令
debug-unwind命令:基于debug / test dwarf的离线展开,用于调试simpleperf。
dump命令:转储perf.data中的内容,用于调试simpleperf。
help命令:打印其他命令的帮助信息。
kmem命令:收集内核内存分配信息(将被Python脚本替换)。
list命令:列出Android设备支持的所有事件类型。
记录命令:配置文件处理并在perf.data中存储分析数据。
report命令:报告perf.data中的分析数据。
report-sample命令:报告perf.data中的每个样本,用于支持集成Android Studio中的simpleperf。
stat命令:profiles处理并打印计数器摘要。
每个命令都支持不同的选项,可以通过帮助消息查看,如下示例:
# List all commands. $ simpleperf --help # Print help message for record command. $ simpleperf record --help
五、操作流程
方式一:使用adb shell进入手机页面操作
1、将simpleperf文件push到手机
在simpleperf/bin/android目录下包含有不同体系架构的 Android 上运行的静态二进制文件,在arm目录下打开命令窗口,执行命令:
adb push simpleperf data/data/
2、将simpleperf授权为可读可写可执行文件:
adb shell cd data/data/ chmod 777 simpleperf
3、对某些特定进程或者线程监控
./simpleperf record -p 4281(pid 或tid) --duration 30(时间/s)
得到错误提示,说只读分区无法写入 perf.data:
simpleperf E 04-19 15:09:29 4109 4109 record_file_writer.cpp:47] failed to open record file 'perf.data': Read-only f
4、 用 -o 参数设置存储记录的路径
simpleperf I cmd_record.cpp:729] Recorded for 29.9851 seconds. Start post processing. simpleperf I cmd_record.cpp:809] Samples recorded: 1457. Samples lost: 0.
5、用report 报告perf.data中的分析数据
simpleperf record -p 17465--duration 4 -f 1000 -o /data/local/tmp/perf.data --call-graph fp
simpleperf report -i /data/perf.data -n --sort dso
simpleperf W 04-19 15:31:17 4564 4564 dso.cpp:274] /data/local/rvdecApp doesn't contain symbol table simpleperf W 04-19 15:31:17 4564 4564 dso.cpp:335] Symbol addresses in /proc/kallsyms are all zero. `echo 0 >/proc/sys/kernel/kptr_restrict` if possible. Cmdline: /data/local/tmp/simpleperf record -p 4281 --duration 30 -o /data/perf.data Arch: arm64 Event: cpu-cycles (type 0, config 0) Samples: 125526 Event count: 43633757353Overhead Sample Shared Object 88.93% 106529 /data/local/rvdecApp 8.05% 10560 /system/lib/libc.so 3.01% 8437 [kernel.kallsyms]
其中的 –sort 参数是用来指定结果显示哪些列,我们这里只写了一个 dso(即 dynamic shared object),所以结果只显示一列 “Shared Object”,而且按 dso 分类,结果也只有三行而已。
如果不加 –sort 参数,默认显示这几列:Command,Pid,Tid,Shared Object,Symbol,相当于:
--sort comm,pid,tid,dso,symbol
- -n 参数用来显示 Sample 那列,表示该行共命中了多少个 Sample,加不加随意。
- 可以看到,百分之 88.93 的时间都耗费在了我们的被测程序上,这是预期中的。
6、查看app 内部,函数占比:
simpleperf report -i /data/perf.data --dsos /data/local/rvdecApp --sort symbol
- 结果如下:
impleperf W 04-19 15:57:34 5046 5046 dso.cpp:274] /data/local/rvdecApp doesn't contain symbol table simpleperf W 04-19 15:57:34 5046 5046 dso.cpp:335] Symbol addresses in /proc/kallsyms are all zero. `echo 0 >/proc/sys/kernel/kptr_restrict` if possible. Cmdline: /data/local/tmp/simpleperf record -p 4281 --duration 30 -o /sdcard/perf.data Arch: arm64 Event: cpu-cycles (type 0, config 0) Samples: 106529 Event count: 38804869540Overhead Sample Symbol 5.06% 5373 rvdecApp[+24380] 4.57% 4890 rvdecApp[+24420] 1.43% 1588 rvdecApp[+13a44] 1.01% 1083 rvdecApp[+21f94] 0.94% 999 rvdecApp[+20188] ...
其中的 –dsos 参数是 simpleperf 的 5 个 filter 之一,意思是按照指定的 dynamic shared objects 进行过滤,只显示参数指定的 dso 里面的结果。全部 5 个 filter 是:
–comms: 按 command 过滤,比如:--comm rvdecApp
–pids: 按 pid 过来
–tids: 按 tid(线程id)过滤
–dsos: 按库文件/可执行文件名过滤
–symbols: 按函数名过滤,比如: --symbols "RVComFunc::getPUMVPredictor(RefBlockInfo*, unsigned int, int, int, unsigned int)",注意函数里有空格的,需要用双引号引起来。
可以看到,结果里没有函数名字。那是因为我们的 rvdecApp 是没有符号表的版本。我们用带符号表的 app 进行分析即可。
带符号表的 app 可执行文件可以在 obj 目录下找到。把它 push 到手机上,覆盖原来的可执行文件。
注意,不用重新执行 rvdecApp 并重新采集 perf.data, 只需要在分析时使用带有符号表的 rvdecApp 即可。
还用刚才的命令:
./simpleperf report -i /data/perf.data -n --dsos /data/local/rvdecApp --sort symbol
- 得到如下结果:
Overhead Sample Symbol 10.45% 5354 RVComFunc::DBFShiftedProcess8x8(unsigned char**, int*, unsigned char*, int, unsigned char*, int, bool, bool, bool, bool, unsigned char) 5.55% 3722 RVComFunc::deblockCUTree(TCBDataTree*, unsigned char**, unsigned int*, int, int, RefBlockInfo*, int, unsigned char**, int*, unsigned char) 4.49% 3675 RVComFunc::reconstructInterPredictors(TCUData*, unsigned char**, unsigned int*, TRefPicList*, RefBlockInfo*, unsigned int, unsigned int, unsigned int, unsigned int) 2.25% 3518 RVComFunc::deriveDBFStrengthFUbyMotionInfo(unsigned char*, unsigned char*, int, int, RefBlockInfo*, int, int, unsigned char, unsigned char, bool, bool) 2.68% 3320 Decoder::parseBitStream_FrameNew() 2.79% 2927 NEON_DBF_EdgeFilter4_Vertical 2.52% 2651 RVComFunc::DBFShiftedProcessFu(unsigned char**, int*, unsigned char*, int, unsigned char*, int, int, bool, bool, bool, bool, unsigned char) 2.36% 2553 (anonymous namespace)::decode_gen_vlc(unsigned long const*, int, (anonymous namespace)::VLC*, int, int) ...
可以看到DBFShiftedProcess8x8函数是最耗时的函数,需要被优化。
方式二:使用linux环境,使用python脚本操作
1、 运行app-profiler.py
进入simpleperf目录下,我们可以使用 app-profiler.py 剖析 Android 应用程序。输出路径等可以修改app_profiler.py配置文件
14:47:33,547 [INFO] (app_profiler.py:206) prepare profiling 14:47:33,730 [INFO] (app_profiler.py:208) start profiling 14:47:33,806 [INFO] (app_profiler.py:244) run adb cmd: ['adb', 'shell', '/data/local/tmp/simpleperf', 'record', '-o', '/data/local/tmp/perf.data', '-e task-clock:u -f 1000 -g --duration 10', '--log', 'info', '--app', 'com.afmobi.boomplayer'] simpleperf I cmd_record.cpp:696] Recorded for 9.96625 seconds. Start post processing. simpleperf W dso.cpp:446] /vendor/lib64/egl/libGLES_mali.so doesn't contain symbol table simpleperf W dso.cpp:446] /vendor/lib64/hw/android.hardware.graphics.mapper@4.0-impl-mediatek.so doesn't contain symbol table simpleperf W dso.cpp:446] /data/app/~~EKnZoTKaDLH3FYfxteqUvg==/com.google.android.trichromelibrary_541411734-ozjH9V7NI4SknoCd0t2CPg==/base.apk!/lib/arm64-v8a/libmonochrome_64.so doesn't contain symbol table simpleperf W dso.cpp:446] /data/app/~~3WfX5_4-OAPL17xSEBkRfg==/com.afmobi.boomplayer-yFLZq2TqjDUJV1OB-um-UQ==/lib/arm64/libmmkv.so doesn't contain symbol table simpleperf I cmd_record.cpp:771] Samples recorded: 8647. Samples lost: 0. 14:47:45,689 [INFO] (app_profiler.py:211) collect profiling data 14:47:46,745 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\apex\com.android.runtime\lib64\bionic\libc.so 14:47:46,770 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\vendor\lib64\libged.so 14:47:46,800 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\vendor\lib64\egl\libGLES_mali.so 14:47:46,835 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\system\lib64\libEGL.so 14:47:46,867 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\system\lib64\libhwui.so 14:47:46,888 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\system\lib64\libutils.so 14:47:46,913 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\system\lib64\libgui.so 14:47:46,932 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\system\lib64\libnativewindow.so 14:47:46,992 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\system\framework\arm64\boot-framework.oat 14:47:47,069 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\apex\com.android.art\lib64\libart.so 14:47:47,130 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\system\framework\arm64\boot.oat 14:47:47,159 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\system\lib64\libandroid_runtime.so 14:47:47,179 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\system\bin\app_process64 14:47:47,206 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\apex\com.android.vndk.v31\lib64\libhidlbase.so 14:47:47,230 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\system\lib64\libhidlbase.so 14:47:47,260 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\system\lib64\android.hardware.graphics.mapper@4.0.so 14:47:47,301 [INFO] (binary_cache_builder.py:184) use current file in binary_cache: binary_cache\system\lib64\libui.so
2、运行 report.py脚本, 剖析报告并输出
simpleperf W dso.cpp:448] failed to read symbols from /data/app/~~3WfX5_4-OAPL17xSEBkRfg==/com.afmobi.boomplayer-yFLZq2TqjDUJV1OB-um-UQ==/lib/arm64/libmmkv.so: File not found Cmdline: /data/local/tmp/simpleperf record -o /data/local/tmp/perf.data -e task-clock:u -f 1000 -g --duration 10 --app com.afmobi.boomplayer Arch: arm64 Event: task-clock:u (type 1, config 1) Samples: 8647 Event count: 8647000000Overhead Shared Object Pid 27.69% /system/lib64/libhwui.so 31183 17.32% /apex/com.android.art/lib64/libart.so 31183 9.06% /apex/com.android.runtime/lib64/bionic/libc.so 31183 8.60% /vendor/lib64/egl/libGLES_mali.so 31183 8.50% /system/framework/arm64/boot-framework.oat 31183 4.75% /data/app/~~3WfX5_4-OAPL17xSEBkRfg==/com.afmobi.boomplayer-yFLZq2TqjDUJV1OB-um-UQ==/oat/arm64/base.odex 31183 3.05% /system/framework/arm64/boot.oat 31183 2.67% /system/lib64/libandroidfw.so 31183 2.58% [JIT app cache] 31183 1.78% /system/lib64/libgui.so 31183 1.58% /data/app/~~EKnZoTKaDLH3FYfxteqUvg==/com.google.android.trichromelibrary_541411734-ozjH9V7NI4SknoCd0t2CPg==/base.apk!/lib/arm64-v8a/libmonochrome_64.so 31183 1.02% /system/lib64/libbinder.so 31183 0.75% /apex/com.android.art/lib64/libart-compiler.so 31183 0.74% /system/lib64/libminikin.so 31183 0.73% /system/lib64/libz.so 31183 0.68% /system/lib64/libsqlite.so 31183 0.65% /system/lib64/libutils.so 31183 0.64% /system/lib64/libjpeg.so 31183 0.53% /apex/com.android.conscrypt/lib64/libcrypto.so 31183 0.43% /apex/com.android.i18n/lib64/libicuuc.so 31183 0.39% /apex/com.android.runtime/bin/linker64 31183 0.39% /system/framework/arm64/boot-core-libart.oat 31183 0.36% /system/lib64/libc++.so 31183 0.27% /system/lib64/libandroid_runtime.so 31183 0.25% /system/framework/arm64/boot-okhttp.oat 31183 0.24% [vdso] 31183 0.22% /apex/com.android.conscrypt/lib64/libssl.so 31183 0.21% /system/lib64/libcutils.so 31183 0.21% /system/lib64/libui.so 31183 0.19% /apex/com.android.vndk.v31/lib64/libgralloctypes.so 31183 .....
3、 产生调用图的报告,并输出至标准输出:
Cmdline: /data/local/tmp/simpleperf record -o /data/local/tmp/perf.data -e task-clock:u -f 1000 -g --duration 10 --app com.afmobi.boomplayer Arch: arm64 Event: task-clock:u (type 1, config 1) Samples: 10841 Event count: 10841000000Children Self Command Pid Tid Shared Object Symbol 66.11% 0.00% RenderThread 31183 11235 /apex/com.android.runtime/lib64/bionic/libc.so __start_thread|-- __start_thread|-- __pthread_start(void*)android::Thread::_threadLoop(void*)android::uirenderer::renderthread::RenderThread::threadLoop()|--0.01%-- [hit in function]||--99.96%-- android::uirenderer::WorkQueue::process()| |--0.03%-- [hit in function]| || |--99.94%-- std::__1::__function::__func<android::uirenderer::renderthread::DrawFrameTask::postAndWait()::$_0, std::__1::allocator<android::uirenderer::renderthread::DrawFrameTask::postAndWait()::$_0>, void ()>::operator()() (.c1671e787f244890c877724752face20)| | |--0.01%-- [hit in function]| | || | |--86.61%-- android::uirenderer::renderthread::CanvasContext::draw()| | | |--0.11%-- [hit in function]| | | || | | |--77.75%-- android::uirenderer::skiapipeline::SkiaOpenGLPipeline::draw(android::uirenderer::renderthread::Frame const&, SkRect const&, SkRect const&, android::uirenderer::LightGeometry const&, android::uirenderer::LayerUpdateQueue*, android::uirenderer::Rect const&, bool, android::uirenderer::LightInfo const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode> > > const&, android::uirenderer::FrameInfoVisualizer*)| | | | |--0.08%-- [hit in function]| | | | || | | | |--58.87%-- android::uirenderer::skiapipeline::SkiaPipeline::renderFrame(android::uirenderer::LayerUpdateQueue const&, SkRect const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode> > > const&, bool, android::uirenderer::Rect const&, sk_sp<SkSurface>, SkMatrix const&)| | | | | || | | | | |--86.22%-- android::uirenderer::skiapipeline::SkiaPipeline::renderFrameImpl(SkRect const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode> > > const&, bool, android::uirenderer::Rect const&, SkCanvas*, SkMatrix const&)| | | | | | |--0.12%-- [hit in function]
4、 展示火焰图
为了展示火焰图,我们首先需要记录调用图。火焰图由 report_html.py 在 Flamegraph 标签中展示。也可以直接双击inferno.bat展示火焰图。
我们也可以使用 GitHub - brendangregg/FlameGraph: Stack trace visualizer 构建火焰图。请确保已经安装了 perl。
$ git clone https://github.com/brendangregg/FlameGraph.git $ python report_sample.py --symfs binary_cache >out.perf $ FlameGraph/stackcollapse-perf.pl out.perf >out.folded $ FlameGraph/flamegraph.pl out.folded >a.svg
用浏览器打开就可以看,解析出来的火焰图如下:
- 从上面的火焰图里面就可以看到netd一直在执行什么,这样就可以交由netd的同仁继续跟踪
y 轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方都是它的父函数。
x 轴表示抽样数,如果一个函数在 x 轴占据的宽度越宽,就表示它被抽到的次数多,即执行的时间长。注意,x 轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的。
火焰图就是看顶层的哪个函数占据的宽度最大。只要有"平顶"(plateaus),就表示该函数可能存在性能问题。
颜色没有特殊含义,因为火焰图表示的是 CPU 的繁忙程度,所以一般选择暖色调。
详细火焰图使用可以参考如何读懂火焰图? - 阮一峰的网络日志
六、提示与诀窍
如果您刚开始使用 Simpleperf,不妨试试以下一些特别实用的命令。如需了解更多命令和选项,请参阅 Simpleperf 命令和选项参考。
1.查找执行时间最长的共享库
您可以运行此命令来查看哪些 .so 文件占用了最大的执行时间百分比(基于 CPU 周期数)。启动性能分析会话时,首先运行此命令是个不错的选择。
simpleperf report --sort dso
例:
Cmdline: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data Arch: arm64 Event: cpu-cycles (type 0, config 0) Samples: 3294 Event count: 1193555038Overhead Sample Shared Object 57.18% 2114 [kernel.kallsyms] 8.01% 225 /system/lib64/libhwui.so 7.16% 192 /apex/com.android.runtime/lib64/bionic/libc.so 5.96% 169 /vendor/lib64/egl/libGLES_mali.so 4.73% 125 /apex/com.android.art/lib64/libart.so 4.55% 128 /system/framework/arm64/boot-framework.oat 3.84% 96 /system/lib64/libgui.so 1.39% 44 /system/framework/arm64/boot.oat 1.06% 28 /system/lib64/libutils.so 0.74% 24 /system/lib64/libbinder.so 0.43% 12 /system/lib64/libui.so 0.42% 10 /system/lib64/libminikin.so 0.34% 10 /system/lib64/libandroid_runtime.so 0.34% 10 /system/lib64/libc++.so 0.29% 7 /apex/com.android.vndk.v31/lib64/libgralloctypes.so 0.27% 8 /vendor/lib64/egl/libGLES_meow.so 0.27% 6 /system/framework/arm64/boot-mediatek-framework.oat 0.24% 8 [JIT app cache] 0.22% 7 /system/lib64/libEGL.so 0.19% 5 /vendor/lib64/libged.so 0.19% 6 /apex/com.android.vndk.v31/lib64/libhidlbase.so 0.18% 4 unknown 0.16% 5 /system/lib64/libcutils.so 0.15% 2 /apex/com.android.i18n/lib64/libicuuc.so 0.15% 5 /system/framework/arm64/boot-core-libart.oat ...............
2.查找执行时间最长的函数
当您确定占用最多执行时间的共享库后,就可以运行此命令来查看执行该 .so 文件的函数所用时间的百分比。
simpleperf report --dsos library.so --sort symbol
例:
simpleperf E command.cpp:59] Unknown option -dsos. Try `simpleperf help report`. 1|TECNO-KI7:/ # simpleperf report -i /data/perf.data --dsos [kernel.kallsyms] --sort symbol Cmdline: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data Arch: arm64 Event: cpu-cycles (type 0, config 0) Samples: 2114 Event count: 682442263Overhead Symbol 8.22% _raw_spin_unlock_irqrestore 6.87% __blockdev_direct_IO 6.72% get_user_pages_fast 6.61% dio_bio_complete 4.13% memblock_start_of_DRAM 3.97% el0_da 3.71% blk_queue_split 3.39% iov_iter_fault_in_readable 2.72% _raw_spin_unlock_irq 2.30% fscrypt_mergeable_bio 2.29% el0_svc_common 2.23% free_unref_page_list 2.02% queue_work_on 1.98% mod_delayed_work_on 1.83% blk_crypto_submit_bio 1.79% clear_page 1.68% _mtk_btag_pidlog_set_pid 1.47% get_page_from_freelist 1.35% f2fs_is_valid_blkaddr 1.18% fscrypt_generate_dun 1.02% __save_stack_trace 0.97% pagecache_get_page 0.95% __handle_speculative_fault 0.82% depot_save_stack 0.80% f2fs_map_blocks 0.73% __rcu_read_unlock 0.67% __pi_memset 0.64% f2fs_wait_on_block_writeback 0.56% __rcu_read_lock 0.54% kmem_cache_alloc
3.查找线程中所用时间的百分比
.so 文件中的执行时间可以跨多个线程分配。您可以运行此命令来查看每个线程所用时间的百分比。
simpleperf report --sort tid,comm
例:
Cmdline: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data Arch: arm64 Event: cpu-cycles (type 0, config 0) Samples: 3294 Event count: 1193555038Overhead Tid Command 42.01% 12182 Thread-4 29.48% 11834 RenderThread 16.96% 10167 com.andromeda.androbench2 6.04% 11853 mali-cmar-backe 2.70% 11876 binder:10167_4 1.24% 11854 ged-swd 0.67% 11844 mali-mem-purge 0.62% 12087 binder:10167_6 0.26% 11968 binder:10167_2 0.01% 11820 Jit thread pool 0.00% 11824 FinalizerWatchd 0.00% 11859 GPU completion
4.查找对象模块中所用时间的百分比
在找到占用大部分执行时间的线程之后,可以使用此命令来隔离在这些线程上占用最长执行时间的对象模块。
simpleperf report --tids threadID --sort dso
例:
Cmdline: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data Arch: arm64 Event: cpu-cycles (type 0, config 0) Samples: 1457 Event count: 501433272Overhead Shared Object 96.72% [kernel.kallsyms] 2.80% /apex/com.android.runtime/lib64/bionic/libc.so 0.33% /apex/com.android.art/lib64/libart.so 0.08% /vendor/lib/modules/memfusion.ko 0.07% /system/lib64/libutils.so
5.了解函数调用的相关性
调用图可直观呈现 Simpleperf 在对会话进行性能剖析期间记录的堆栈轨迹。
您可以使用 report -g 命令打印调用图,以查看其他函数调用的函数。这有助于确定是某个函数本身运行缓慢还是因为它调用的一个或多个函数运行较慢。
您还可以使用 Python 脚本 report.py -g 来启动显示函数的交互式工具。您可以点击每个函数,查看它的子函数所用的时间。
simpleperf report -g
例:
TECNO-KI7:/ # simpleperf report -g simpleperf E record_file_reader.cpp:83] failed to open record file 'perf.data': No such file or directory 1|TECNO-KI7:/ # simpleperf report -i /data/perf.data -g Cmdline: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data Arch: arm64 Event: cpu-cycles (type 0, config 0) Samples: 3294 Event count: 1193555038Children Self Command Pid Tid Shared Object Symbol 3.93% 3.93% Thread-4 10167 12182 [kernel.kallsyms] __blockdev_direct_IO 3.84% 3.84% Thread-4 10167 12182 [kernel.kallsyms] get_user_pages_fast 3.78% 3.78% Thread-4 10167 12182 [kernel.kallsyms] dio_bio_complete 2.55% 2.55% mali-cmar-backe 10167 11853 [kernel.kallsyms] _raw_spin_unlock_irqrestore 2.36% 2.36% Thread-4 10167 12182 [kernel.kallsyms] memblock_start_of_DRAM 2.27% 2.27% Thread-4 10167 12182 [kernel.kallsyms] el0_da 2.12% 2.12% Thread-4 10167 12182 [kernel.kallsyms] blk_queue_split 1.94% 1.94% Thread-4 10167 12182 [kernel.kallsyms] iov_iter_fault_in_readable 1.31% 1.31% Thread-4 10167 12182 [kernel.kallsyms] fscrypt_mergeable_bio 1.27% 1.27% Thread-4 10167 12182 [kernel.kallsyms] free_unref_page_list 1.15% 1.15% RenderThread 10167 11834 [kernel.kallsyms] queue_work_on 1.15% 1.15% Thread-4 10167 12182 /apex/com.android.runtime/lib64/bionic/libc.so memset 1.13% 1.13% Thread-4 10167 12182 [kernel.kallsyms] mod_delayed_work_on 1.05% 1.05% Thread-4 10167 12182 [kernel.kallsyms] blk_crypto_submit_bio 1.02% 1.02% Thread-4 10167 12182 [kernel.kallsyms] clear_page 1.01% 1.01% RenderThread 10167 11834 [kernel.kallsyms] _raw_spin_unlock_irqrestore 0.96% 0.96% Thread-4 10167 12182 [kernel.kallsyms] _mtk_btag_pidlog_set_pid 0.77% 0.77% Thread-4 10167 12182 [kernel.kallsyms] f2fs_is_valid_blkaddr 0.76% 0.76% RenderThread 10167 11834 /apex/com.android.runtime/lib64/bionic/libc.so __vfprintf 0.70% 0.70% RenderThread 10167 11834 [kernel.kallsyms] _raw_spin_unlock_irq 0.68% 0.68% Thread-4 10167 12182 [kernel.kallsyms] fscrypt_generate_dun 0.67% 0.67% Thread-4 10167 12182 [kernel.kallsyms] get_page_from_freelist 0.64% 0.64% RenderThread 10167 11834 [kernel.kallsyms] el0_svc_common 0.62% 0.62% Thread-4 10167 12182 [kernel.kallsyms] _raw_spin_unlock_irqrestore 0.58% 0.58% Thread-4 10167 12182 [kernel.kallsyms] __save_stack_trace 0.55% 0.55% Thread-4 10167 12182 [kernel.kallsyms] pagecache_get_page 0.54% 0.54% com.andromeda.androbench2 10167 10167 /apex/com.android.art/lib64/libart.so ExecuteNterpImpl 0.51% 0.51% Thread-4 10167 12182 [kernel.kallsyms] __handle_speculative_fault 0.46% 0.46% Thread-4 10167 12182 [kernel.kallsyms] f2fs_map_blocks 0.45% 0.45% RenderThread 10167 11834 /apex/com.android.runtime/lib64/bionic/libc.so scudo::Allocator<scudo::AndroidConfig, &(scudo_malloc_postinit)> rigin, unsigned long, bool) 0.44% 0.44% RenderThread 10167 11834 /system/lib64/libgui.so @plt 0.41% 0.41% Thread-4 10167 12182 [kernel.kallsyms] depot_save_stack 0.36% 0.36% Thread-4 10167 12182 [kernel.kallsyms] f2fs_wait_on_block_writeback 0.36% 0.36% Thread-4 10167 12182 [kernel.kallsyms] _raw_spin_unlock_irq 0.34% 0.34% Thread-4 10167 12182 [kernel.kallsyms] __rcu_read_unlock 0.34% 0.34% com.andromeda.androbench2 10167 10167 [kernel.kallsyms] _raw_spin_unlock_irq 0.32% 0.32% Thread-4 10167 12182 [kernel.kallsyms] __pi_memset 0.31% 0.31% Thread-4 10167 12182 [kernel.kallsyms] kmem_cache_alloc 0.31% 0.31% com.andromeda.androbench2 10167 10167 /apex/com.android.art/lib64/libart.so artAllocStringFromCharsFromCodeRegionTLAB 0.26% 0.26% mali-cmar-backe 10167 11853 [kernel.kallsyms] el0_svc_common 0.26% 0.26% RenderThread 10167 11834 /apex/com.android.runtime/lib64/bionic/libc.so write 0.25% 0.25% Thread-4 10167 12182 [kernel.kallsyms] pte_map_lock ........
6. 获取被剖析程序或系统范围内的原始事件计数器信息
simpleperf stat 被用于获取被剖析程序或系统范围内的原始事件计数器信息。通过传入选项,我们可以选择使用哪些事件,监视哪个进程/线程,监视多长时间,以及打印的间隔。
Performance counter statistics:# count event_name # count / runtime17,839,958,825 cpu-cycles # 1.758283 GHz6,411,685,476 stalled-cycles-frontend # 632.274 M/sec5,413,391,502 stalled-cycles-backend # 534.113 M/sec11,755,131,810 instructions # 1.160 G/sec1,409,829,788 branch-instructions # 139.262 M/sec171,458,771 branch-misses # 16.946 M/sec10070.704634(ms) task-clock # 1.006817 cpus used7,210 context-switches # 716.330 /sec94,430 page-faults # 9.387 K/secTotal test time: 10.002513 seconds.
七、参考文档
【Simpleperf】Android的CPU分析,性能优化利器_android perf_Yngz_Miao的博客-CSDN博客
Profile 工具系列之四:simpleperf_old_man的博客-CSDN博客
使用 Simpleperf 分析本地代码性能 | WolfcsTech
如何读懂火焰图? - 阮一峰的网络日志
Simpleperf介绍 | WolfcsTech
Simpleperf | Android NDK | Android Developers
Simpleperf 命令和选项参考文档 | Android NDK | Android Developers
相关文章:
Simpleperf详细使用
一、Simpleperf介绍 Simpleperf是一个强大的命令行工具,它包含在NDK中,可以帮助我们分析应用的CPU性能。Simpleperf可以帮助我们找到应用的热点,而热点往往与性能问题相关,这样我们就可以分析修复热点源。 如果您更喜欢使用命令…...
【算法基础】二分图(染色法 匈牙利算法)
一、二分图 1. 染色法 一个图是二分图,当且仅当,图中不含奇数环。在判别一个图是否为二分图⑩,其实相当于染色问题,每条边的两个点必须是不同的颜色,一共有两种颜色,如果染色过程中出现矛盾,则说明不是二分图。 for i = 1 to n:if i 未染色DFS(i, 1); //将i号点染色未…...
Caputo 分数阶微分方程-慢扩散方程初边值问题基于L1 逼近的空间二阶方法及其Matlab程序实现
2.3.3 Caputo 分数阶一维问题基于 L1 逼近的空间二阶方法 考虑如下时间分数阶慢扩散方程初边值问题 { 0 C D t α u ( x , t ) = u...
I.MX6ULL_Linux_驱动篇(29) GPIO驱动
Linux 下的任何外设驱动,最终都是要配置相应的硬件寄存器。所以本篇的 LED 灯驱动最终也是对 I.MX6ULL 的 IO 口进行配置,与裸机实验不同的是,在 Linux 下编写驱动要符合 Linux 的驱动框架。I.MX6U-ALPHA 开发板上的 LED 连接到 I.MX6ULL 的 …...
jupyter的安装和使用
目录 ❤ Jupyter Notebook是什么? notebook jupyter 简介 notebook jupyter 组成 网页应用 文档 主要特点 ❤ jupyter notebook的安装 notebook jupyter 安装有两种途径 1.通过Anaconda进行安装 2.通过pip进行安装 启动jupyter notebook ❤ jupyter …...
Springboot新手开发 Cloud篇
前言: 👏作者简介:我是笑霸final,一名热爱技术的在校学生。 📝个人主页:个人主页1 || 笑霸final的主页2 📕系列专栏:后端专栏 📧如果文章知识点有错误的地方,…...
Linux:函数指针做函数参数
#include <stdio.h> #include <stdlib.h> //创建带有函数指针做参数的函数框架api //调用者要先实现回调函数 //调用者再去调用函数框架 //所谓的回调是指 调用者去调用一个带有函数指针做参数的函数框架,函数框架反过来要调用调用者提供的回调函数 …...
Vue3(递归组件) + 原生Table 实现树结构复杂表格
一、递归组件 什么是递归,Javascript中经常能接触到递归函数。也就是函数自己调用自己。那对于组件来说也是一样的逻辑。平时工作中见得最多应该就是菜单组件,大部分系统里面的都是递归组件。文章中我做了按需引入的配置,所以看不到我引用组…...
ArrayList底层源码解析
Java源码系列:下方连接 http://t.csdn.cn/Nwzed 文章目录前言一、**ArrayList底层结构和源码分析**无参构造调用创建ArrayList集合无参构造总结:发文3个工作日后 up 会把总结放入前言部分,但也诚邀读者总结,可放入评论区有参构造…...
python:DIY字符画的程序使用说明.doc
目录开发环境要求运行方法具体的操作步骤如下:代码示例源码及运行程序下载地址开发环境要求 本系统的软件开发及运行环境具体如下。 操作系统:Windows 7、Windows 10。 Python版本:Python 3.7.0。 开发工具:Python IDLE。 …...
【Python/Opencv】图像权重加法函数:cv2.addWeighted()详解
【Python/Opencv】图像权重加法函数:cv2.addWeighted()详解 文章目录【Python/Opencv】图像权重加法函数:cv2.addWeighted()详解1. 介绍2. API3. 代码示例与效果3.1 代码3.2 效果4. 参考1. 介绍 在OpenCV图像加法cv2.add函数详解详细介绍了图像的加法运…...
容器的老祖宗LXC和Docker的关系
一、什么是LXC? LXC(Linux Container的缩写)是一个基于Linux内核的容器虚拟化技术,它提供了一种轻量级、快速、简便的方式来创建和管理系统容器。与传统虚拟化技术不同,LXC并不会模拟硬件,而是利用Linux内…...
Webpack迁移Rspack速攻实战教程(前瞻版)
前言 rspack 即将开源,但社区中不乏有已经落地的 case ,比如 rspack-migration-showcase 、 modern.js 等。 基于此,本文将介绍如何迁移一个近似于 CRA( create-react-app ) 的项目到 rspack 。 在阅读本文前&#…...
一行代码“黑”掉任意网站
文章目录只需一行代码,轻轻一点就可以把任意网站变成暗黑模式。 首先我们先做一个实验,在任意网站中,打开浏览器开发者工具(F12),在 C1onsole 控制台输入如下代码并回车: document.documentElement.style.filterinve…...
51单片机入门 -驱动 8x8 LED 点阵屏
硬件型号、软件版本、以及烧录流程 操作系统:Windows 10 x84-64单片机:STC89C52RC编译器:SDCC烧录软件:stcgal 1.6开发板:普中51单片机开发板A2套件(2022) 在 VS Code 中新建项目到烧录的过程…...
Xinlinx zynq7045国产替代 FMQL45T900全国产化 ARM 核心板+扩展板
TES745D 是一款基于 FMQL45T900 的全国产化 ARM 核心板。该核心板将 FMQL45T900(与XC7Z045-2FFG900I 兼容)的最小系统集成在了一个 87*117mm 的核心板上,可以作为一个核心模块,进行功能性扩展,能够快速的搭建起一个信号…...
硬刚ChatGPT!文心一言能否为百度止颓?中国版ChatGPT“狂飙”的机会在哪儿?
文章目录目录产品背景发展历程科技简介主要功能合作伙伴结语文心一言 (英文名:ERNIE Bot) *是百度基于文心大模型技术推出的生成式对话产品,被外界誉为“中国版ChatGPT”,将于2023年3月份面向公众开放。 [40] 百度在人…...
Python 异步: 在非阻塞子进程中运行命令(19)
动动发财的小手,点个赞吧! 我们可以从 asyncio 执行命令。该命令将在我们可以使用非阻塞 I/O 写入和读取的子进程中运行。 1. 什么是 asyncio.subprocess.Process asyncio.subprocess.Process 类提供了由 asyncio 运行的子进程的表示。它在 asyncio 程序…...
蓝桥杯嵌入式第五课--输入捕获
前言输入捕获的考题十分明确,就是测量输入脉冲波形的占空比和频率,对我们的板子而言,就是检测板载的两个信号发生器产生的信号:具体来说就是使用PA15和PB4来做输入捕获。输入捕获原理简介输入捕获能够对输入信号的上升沿和下降沿进…...
Spring事务和事务传播机制
目录 Spring中事务的实现 1、通过代码的方式手动实现事务 2、通过注解的方式实现声明式事务 2.1、Transactional作用范围 2.2、Transactional参数说明 2.3、注意事项 2.4、Transactional工作原理 事务隔离级别 1、事务特性 2、Spring中设置事务隔离级别 2.1、MySQL事…...
基于OpenCV+CUDA实时视频抠绿、背景合成以及抠绿算法小结
一、关于抠绿 百度百科上描述抠绿“抠绿是指在摄影或摄像时,以绿色为背景进行拍摄,在后期制作时使用特技机的“色键”将绿色背景抠去,改换其他更理想的背景的技术。”绿幕的使用已经非常普遍,大到好莱坞大片,小到自媒体的节目,一些商业娱乐场景,几乎都用使用。但是很多非…...
MySQL 中的 UNION 语句
文章目录一、数据准备一、UNION 和 UNION ALL二、UNION 的执行顺序(UNION 和其他语句一同出现)三、MySQL 使用 UNION(ALL) ORDER 导致排序失效四、UNION 报错语法一、数据准备 -- 创建表 CREATE TABLE test_user (ID int(11) NO…...
高完整性系统工程(三): Logic Intro Formal Specification
目录 1. Propositions 命题 2.1 Propositional Connectives 命题连接词 2.2 Variables 变量 2.3 Sets 2.3.1 Set Operations 2.4 Predicates 2.5 Quantification 量化 2.6 Relations 2.6.1 What Is A Relation? 2.6.2 Relations as Sets 2.6.3 Binary Relations as…...
【linux】多线程概念详述
文章目录一、线程基本概念1.1 进程地址空间与页表1.2 页表结构1.3 线程的理解1.3.1 如何描述线程1.4 再谈进程1.5 代码理解1.5.1 原生库提供线程pthread_create1.6 资源共享问题1.7 资源私有问题二、总结2.1 什么是线程2.2 并行与并发2.3 线程的优点2.4 线程的缺点2.5 线程异常…...
【Java】P8 面向对象(3)方法 基本知识
面向对象 方法方法方法的声明权限修饰符返回值类型方法名形参列表方法体简单案例方法 方法 是对类或对象行为特征的抽象,用来完成某个功能的操作。方法的目的 是为了实现代码复用,减少冗余,简化代码;方法不能独立存在,…...
js中null和undefined的区别
js中null和undefined的区别?这也是一个常见的js面试题 相同点 1,都是基本类型。 2,做判断值都是false。 !!null false // true !!undefined false // true不同点 1,诞生时间null在前,undefined在后。因为js作者Brendan-Eic…...
【Linux】linux中的c++怎么调试?gdb的介绍和使用。
背景1.1.前提知识程序的发布方式有两种,debug模式和release模式Linux gcc/g出来的二进制程序,默认是release模式 要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g 选项windows上的调试方法有区别吗?1.调试思路是一样的2…...
提升Python代码性能的六个技巧
文章目录前言为什么要写本文?1、代码性能检测1.1、使用 timeit 库1.2、使用 memory_profiler 库1.3、使用 line_profiler 库2、使用内置函数和库3、使用内插字符串 f-string4、使用列表推导式5、使用 lru_cache 装饰器缓存数据6、针对循环结构的优化7、选择合适算法…...
VI的常用命令
VI的常用命令 文章目录VI的常用命令vi/vim是什么?VI普通模式命令VI编辑模式命令VI指令模式vi/vim是什么? VI是Unix操作系统和类Unix操作系统中最通用的文本编辑器 VIM编辑器是从VI发展出来的一个性能更强大的文本编辑器。可以主动的将字体颜色辨别语法…...
【数据结构】万字深入浅出讲解单链表(附原码 | 超详解)
🚀write in front🚀 📝个人主页:认真写博客的夏目浅石. 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝 📣系列专栏:C语言实现数据结构 💬总结:希望你看完…...
网站 数据库 sql 导入数据库文件/文件外链网站
刚装上Windows7,Ghost版的,本人不喜欢像这样的版本,但从朋友借来的CD只有这个版本,没办法,只能装上这个尝个鲜。 装上还特别快。不到20分钟就装好了(我的机子是4核,2G内存)。 装好后,…...
图标不显示wordpress/什么是搜索引擎营销?
我们都知道,管理信息系统类的项目报表的位置是何等重要,业务运营数据最后给领导的反应就是那么几张综合的业务数据报表,我从事软件开发的这八、九年中,98%的项目都是管理信息系统项目,都时时被报表纠结着,早年用VB开发…...
泉州专业建站公司/深圳seo关键词优化
1.自定义指令 在angular中,module下面的directive方法用于创建自定义指令,用法: m1.directive(myTab,function(){ return { restrict : AE, replace : true, templateUrl : , }; }); 大致用法如上,在directive的第二个参数里面ret…...
免费logo设计生成器下载/快速排名优化公司
本课件包含的主要内容为: 研究动机:稀疏正则化 次梯度与次微分 L1正则化问题的次微分 练习:次梯度方法 次梯度的替代方法 近端梯度法 近端算子的有用特性 非平滑优化的最速下降 英文原文课件下载地址: http://page2.dfpa…...
北京快三是官方的吗/百度seo如何做
亚马逊6月27日宣布他们在亚太地区的第6个AWS数据中心已经上线提供服务。新数据中心在印度孟买,亚太地区的其他5个数据中心是北京、首尔、新加坡、悉尼和东京。加上孟买之后,亚马逊在全球的13个大地理区域里已经有了35个数据中心在提供服务。\\现阶段孟买…...
适合个人站长的网站有哪些/网络营销招聘
windows下直接用 __asm("int3") 是不标准的做法, 应该是调用DebugBreak(); linux 下可以用 abort(); 本文转自 zhegaozhouji 51CTO博客,原文链接:http://blog.51cto.com/1038741/1763687...