简介
SimplePref是Android NDK自带的Profiler工具,
官方文档:
https://developer.android.com/ndk/guides/simpleperf
simplepref是一个命令行的工具(shell), 提供一个python的工具, 可在PC里通过adb shell里调用simplepref来运行.
要使用 Simpleperf,您必须遵循以下要求:
- 使用运行 Android 5.0(API 级别 21)或更高版本的设备来分析您的应用。
- 通过 USB 调试连接,将设备连接至您的开发计算机。
- 要运行 Python 脚本以进行记录和报告(推荐),需在您的开发计算机上安装以下项目:
- Python 2.7 或更高版本。
- 最新版 Android SDK 和 NDK。 您可通过 Android Studio 中的 SDK Manager 安装这些项目。`
simplepref工具的参数:
https://developer.android.com/ndk/guides/simpleperf-commands
基于版本 NDK r17
SimplePerf Python
app_profiler.py
开始record:
python app_profiler.py -p com.your.packagename
例如:
python app_profiler.py \--app com.uboxue4.demo.u416 --skip_collect_binaries --disable_adb_root -r "-e task-clock:u -f 1000 -g --call-graph fp" -o perf.data2
则真实在手机上运行的命令为:
/data/local/tmp/simpleperf record -o /data/local/tmp/perf.data -e task-clock:u -f 1000 -g --duration 60 --call-graph fp --app com.uboxue4.demo.u416
不传入 --duration 60 则在Ctrl+C的时候 停止, 模拟Ctrl+C, 可以使用信号量 (Ctrl+C的信号量为15 SIGTERM ) , 例如
kill -15 pid
参数:
- --record_options 传入到simpleperf里的record参数
- --native_lib_dir 本地含有符号的so文件的目录(会遍历这个目录下的所有so文件传入到手机中的/data/local/tmp/native_libs/目录 , 并将该目录作为simpleperf的 -symfs 目录传入 )
- --skip_collect_binaries 默认情况下会收集所有的so文件包括系统的so到PC的build_cache, 用作分析(report_html.py在用)
- --disable_adb_root 默认会使用root模式运行, 该参数可关闭root, 使用普通用户权限
Android < N:
- 在某些机器上默认的 --call-graph dwarf,8192 不支持, 需要使用 --call-graph fp
- 在Android >= N的时候会使用 package compile -f -m speed来完整的重新编译Java Code
启动APP的命令
am force-stop packagename
// android N上面force-stop可能不能, 需要kill
kill -9 pid
查询指定包名的pid命令
pidof packagename
遍历native_lib_dirs下所有so文件, 使用 readelf 读取so的 build_id, 是否包括debug信息段, 然后将这些so文件push到手机的 /data/local/tmp/native_libs/ 目录.
这个目录会作为参数传给simpleperf, simpleperf会使用这些so读取符号信息.
在本地的native_library_dir和手机的native_libs目录会进行同步.
拷贝simpleperf二进制文件
adb push simpleperf /data/local/tmp
adb shell chmod a+x /data/local/tmp/simpleperf
运行simpleperf命令, 在一个子进程里运行
adb shell /data/local/tmp/simpleperf record -o /data/local/tmp/perf.data \--symfs /data/local/tmp/native_libs/ ##args
然后一直等待这个子进程主动退出, 如果returncode为0, 则表示正常退出, 准备收集已经采集好的数据.
将数据从手机拉取到电脑:
adb pull /data/local/tmp/perf.data
如果没有skip_collect_binaries参数, 则会调用 binary_cache_builder.py 去拉取手机里所有涉及到的so文件(包括系统的so文件)
binary_cache_builder.py
参数:
- perf_data_path, perf.data的路径
- symfs_dirs 符号文件路径
- ndk_path NDK路径
收集使用的so文件
遍历perf.data里的所有samples, 每个sample都包括: symbols, 和 callchain
首先从函数调用栈 callchain 里获取所有涉及到的symbol, 将其合并到symbols里.
然后遍历所有symbol, 获取dso_name (SO的文件名, 含路径)
即得到了perf.data里所有涉及到的符号所在的so文件列表.
保存到一个dict里, key为so_name, value为so_build_id
从symfs_dirs拷贝so文件
遍历 symfs_dirs, 对比其中的so名称, build_id, 如果是perf.data里使用的, 则将其拷贝到 build_cache 目录
从手机拷贝so文件
然后遍历perf.data所有用到的so文件, 将其so_name作为路径, 全部pull到电脑上的build_cache目录(但是会跳过之前在symfs_dirs目录的so文件, 因为该目录下的so文件会比手机上的so文件提供更多的符号信息)
拷贝文件都会先将文件从原始目录 临时拷贝(cp) 到 /data/local/tmp 目录, 然后再 pull, 然后删除到 /data/local/tmp 目录下的临时so文件.
从手机拷贝内核符号文件
如果是root手机, 则会去修改手机里的 /proc/sys/kernel/kptr_restrict 文件为 0, 关闭掉这个限制, 然后拷贝内核符号文件
/proc/kallsyms
report.py
report.py 只是 simpleperf report 命令的一个python壳子, 这个脚本有两种模式:
- 直接调用 simpleperf report 生成报告文件
- 调用simpleperf report生成报告文件后, 使用GUI来展示数据. (使用--gui参数即可)
将pref.data数据转换为txt数据
python report.py -o output_report.txt
其内部执行的命令为:
simpleperf report --full-callgraph -o pref.report ##args
数据格式默认为:
Cmdline: /data/local/tmp/simpleperf record -o /data/local/tmp/perf.data -e task-clock:u -f 1000 -g --duration 10 --app com.uboxue4.demo.u416
Arch: arm64
Event: task-clock:u (type 1, config 1)
Samples: 8988
Event count: 8988000000
Overhead Command Pid Tid Shared Object Symbol
1.46% RenderThread 2 13321 13400 /system/lib/libc.so memcpy
1.07% RenderThread 2 13321 13400 /data/app/com.uboxue4.demo.u416-1/lib/arm/libUE4.so FOpenGLShaderParameterCache::CommitPackedUniformBuffers(FOpenGLLinkedProgram*, int, TRefCountPtr*, TArray const&)
1.00% Thread-2 13321 13359 /data/app/com.uboxue4.demo.u416-1/lib/arm/libgnustl_shared.so .udivsi3_skip_div0_test
0.96% RenderThread 2 13321 13400 /system/vendor/lib/egl/libGLESv2_adreno.so EsxGfxMem::UpdateTimestamp(EsxContext const*, EsxAccessType, EsxBucketIdReference*)
0.92% RenderThread 0 13321 13390 /data/app/com.uboxue4.demo.u416-1/lib/arm/libUE4.so void FLandscapeSharedBuffers::CreateIndexBuffers(ERHIFeatureLevel::Type, bool)
0.88% RenderThread 2 13321 13400 /system/lib/libc.so memset
0.80% Thread-2 13321 13359 /system/lib/libc.so memcpy
有函数调用关系的格式为: (参数 -g callee 被调用关系)
Cmdline: /data/local/tmp/simpleperf record -o /data/local/tmp/perf.data -e task-clock:u -f 1000 -g --duration 10 --app com.uboxue4.demo.u416
Arch: arm64
Event: task-clock:u (type 1, config 1)
Samples: 8988
Event count: 8988000000
Children Self Command Pid Tid Shared Object Symbol
49.14% 0.00% RenderThread 2 13321 13400 /data/app/com.uboxue4.demo.u416-1/lib/arm/libUE4.so FNamedTaskThread::ProcessTasksUntilQuit(int)
|
-- FNamedTaskThread::ProcessTasksUntilQuit(int)
|
-- RenderingThreadMain(FEvent*)
FRenderingThread::Run()
FRunnableThreadPThread::Run()
FRunnableThreadPThread::_ThreadProc(void*)
__pthread_start(void*)
__start_thread
49.14% 0.00% RenderThread 2 13321 13400 /system/lib/libc.so __start_thread
49.14% 0.00% RenderThread 2 13321 13400 /data/app/com.uboxue4.demo.u416-1/lib/arm/libUE4.so FRenderingThread::Run()
[skipped in brief callgraph mode]
49.14% 0.00% RenderThread 2 13321 13400 /data/app/com.uboxue4.demo.u416-1/lib/arm/libUE4.so FRunnableThreadPThread::Run()
[skipped in brief callgraph mode]
49.14% 0.00% RenderThread 2 13321 13400 /data/app/com.uboxue4.demo.u416-1/lib/arm/libUE4.so FRunnableThreadPThread::_ThreadProc(void*)
[skipped in brief callgraph mode]
49.14% 0.00% RenderThread 2 13321 13400 /data/app/com.uboxue4.demo.u416-1/lib/arm/libUE4.so RenderingThreadMain(FEvent*)
[skipped in brief callgraph mode]
49.14% 0.00% RenderThread 2 13321 13400 /system/lib/libc.so __pthread_start(void*)
[skipped in brief callgraph mode]
49.02% 0.06% RenderThread 2 13321 13400 /data/app/com.uboxue4.demo.u416-1/lib/arm/libUE4.so FNamedTaskThread::ProcessTasksNamedThread(int, bool)
|
-- FNamedTaskThread::ProcessTasksNamedThread(int, bool)
|
--99.89%-- FNamedTaskThread::ProcessTasksUntilQuit(int)
RenderingThreadMain(FEvent*)
FRenderingThread::Run()
FRunnableThreadPThread::Run()
FRunnableThreadPThread::_ThreadProc(void*)
__pthread_start(void*)
__start_thread
函数调用关系格式( -g caller)
Cmdline: /data/local/tmp/simpleperf record -o /data/local/tmp/perf.data -e task-clock:u -f 1000 -g --duration 10 --app com.uboxue4.demo.u416
Arch: arm64
Event: task-clock:u (type 1, config 1)
Samples: 8988
Event count: 8988000000
Children Self Command Pid Tid Shared Object Symbol
49.14% 0.00% RenderThread 2 13321 13400 /system/lib/libc.so __start_thread
|
-- __start_thread
|
-- __pthread_start(void*)
FRunnableThreadPThread::_ThreadProc(void*)
FRunnableThreadPThread::Run()
FRenderingThread::Run()
RenderingThreadMain(FEvent*)
FNamedTaskThread::ProcessTasksUntilQuit(int)
|
|--99.75%-- FNamedTaskThread::ProcessTasksNamedThread(int, bool)
| |--0.11%-- [hit in function]
| |
| |--80.07%-- libUE4.so[+4586d24]
| | |
| | |--99.23%-- libUE4.so[+4526690]
| | | |
| | | |--99.83%-- FMobileSceneRenderer::Render(FRHICommandListImmediate&)
| | | | |--0.11%-- [hit in function]
| | | | |
| | | | |--63.03%-- FMobileSceneRenderer::RenderMobileBasePass(FRHICommandListImmediate&, TArrayView)
| | | | | |--0.27%-- [hit in function]
| | | | | |
| | | | | |--96.10%-- libUE4.so[+4876e90]
| | | | | | |
| | | | | | |--99.95%-- int TStaticMeshDrawList >::DrawVisibleFrontToBackInner<(InstancedStereoPolicy)2>(FRHICommandList&, FViewInfo const&, FDrawingPolicyRenderState&, FMeshDrawingPolicy::ContextDataType, TBitArray const*, TArray const*, StereoPair const*, int)
| | | | | | | |--2.50%-- [hit in function]
| | | | | | | |
| | | | | | | |--96.98%-- int TStaticMeshDrawList >::DrawElement<(InstancedStereoPolicy)2>(FRHICommandList&, FViewInfo const&, FMeshDrawingPolicy::ContextDataType, FDrawingPolicyRenderState&, TStaticMeshDrawList >::FElement const&, unsigned long long, TStaticMeshDrawList >::FDrawingPolicyLink*, bool&)
参数:
- --gui 可视化
- 其他参数直接传入到simpleperf report
NOTE ATTRIBUTES
Created Date: 2018-08-03 07:12:45
Last Evernote Update Date: 2019-04-27 05:04:01