simpleperf源码阅读-0.Python

简介


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壳子, 这个脚本有两种模式:

  1. 直接调用 simpleperf report 生成报告文件
  2. 调用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

你可能感兴趣的:(simpleperf源码阅读-0.Python)