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<FRHIUniformBuffer>*, TArray<CrossCompiler::FUniformBufferCopyInfo, FDefaultAllocator> 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<unsigned short>(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<FViewInfo const*>)
               |    |    |    |    |    |--0.27%-- [hit in function]
               |    |    |    |    |    |
               |    |    |    |    |    |--96.10%-- libUE4.so[+4876e90]
               |    |    |    |    |    |    |
               |    |    |    |    |    |    |--99.95%-- int TStaticMeshDrawList<TMobileBasePassDrawingPolicy<FUniformLightMapPolicy, 0> >::DrawVisibleFrontToBackInner<(InstancedStereoPolicy)2>(FRHICommandList&, FViewInfo const&, FDrawingPolicyRenderState&, FMeshDrawingPolicy::ContextDataType, TBitArray<SceneRenderingBitArrayAllocator> const*, TArray<unsigned long long, SceneRenderingAllocator> const*, StereoPair const*, int)
               |    |    |    |    |    |    |    |--2.50%-- [hit in function]
               |    |    |    |    |    |    |    |
               |    |    |    |    |    |    |    |--96.98%-- int TStaticMeshDrawList<TMobileBasePassDrawingPolicy<FUniformLightMapPolicy, 0> >::DrawElement<(InstancedStereoPolicy)2>(FRHICommandList&, FViewInfo const&, FMeshDrawingPolicy::ContextDataType, FDrawingPolicyRenderState&, TStaticMeshDrawList<TMobileBasePassDrawingPolicy<FUniformLightMapPolicy, 0> >::FElement const&, unsigned long long, TStaticMeshDrawList<TMobileBasePassDrawingPolicy<FUniformLightMapPolicy, 0> >::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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269