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事…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...
