移动性能测试 iOS instruments trace 文件解析方案

hyddd · March 28, 2016 · Last by 李鹏 replied at October 23, 2019 · 3819 hits
本帖已被设为精华帖!

原文在这:http://www.cnblogs.com/hyddd/p/5329608.html

前言

已很少写文章,不过这次感觉有必要写一下。因为:

  1. 这个方案通过debug逆向得来,很有参考意义。
  2. iOS这方面资料非常少,做这块时,无论国内外,翻遍了google,baidu都没太多合适的资料。 故此,我觉得把整个流程记录下来,你可以认为,这是一次iOS的debug之旅。

问题起因

最近做iOS性能测试,要监控一段时间内App的CPU占用和网络流量。遗憾的是,iOS instruments提供的Activity Monitor和Network模板并不满足我的需求。在UI工具中,Activity Monitor只提供了CPU瞬时值,Network也只提供了总流量,它们均不提供采集样本值。

由于iOS闭源,放出的资料又少,故解决此问题的方案屈指可数:

(1). 设备越狱,通过后台守护进程采集数据。
缺陷:新设备无法越狱。

(2). 在产品中嵌入性能数据采集模块。
缺陷:我不倾向在产品中嵌入测试模块;另外,该方案对第三方产品也失效。

(3). 从instruments结果文件(.trace)中尝试获取样本值。
缺陷:能不能做都不知道…

因方案1,2有硬伤,故选方案3尝试。

其实,我开始时也并不确定trace文件包含样本数据,但instruments可通过trace文件恢复监控过程的柱状图,它给了我继续这个方向的信心。

而从trace文件获取样本值,有2个方向:

(1)分析trace结构,获取明文数据
trace其实是文件夹,但里面文件内容均为二进制,遂放弃......

(2)通过Undocumented API解析trace文件
由于instruments可以解析trace文件,那么(2)方法是一定可行的,问题是怎么找到相关的Undocumented API。

Undocumented API可行性确认

Lucky,我同事发现了这玩意:TraceUtility,它一个是获取Time Profiler样本值的工具(那作者也和我一样遇到这种蛋疼问题......),并且Readme中找到重要线索:

(1)所需的Undocumented API在/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/Frameworks:

  • DVTInstrumentsFoundation.framework
  • InstrumentsPlugIn.framework

(2)Instruments模板以PlugIns形式存在于
/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns

TraceUtility源码分析

项目就2个文件:

InstrumentsPrivateHeader.h: Undocumented API和Undocumented数据结构声明。

main.m:样本数据提取主流程。

深入Debug分析

然而TraceUtility仅用于获取Time Profiler样本数据,并不能满足我获取CPU和网络流量样本的要求。

我需要解决的问题是:

(1)确定instruments处理类。
(2)从处理类中读出样本数据。

1. 确定instruments处理类

方式很简单,在loadDocument后,debug变量trace._baseInstruments


对比图1、2

  • XRSamplerInstrument=>XRSamplerRun
  • XRActivityInstrument=>XRActivityRun?
  • XRNetworkingInstrument=>XRNetworkingRun?

在另一个github项目class-dump-o-tron, 搜到了相关信息:XRSamplerRun.h,然而在ActivityPlugin.xrplugin下却没找到XRActivityRun.h,而是XRActivityInstrumentRun.h(大Apple的命名能统一点嘛……);在XRNetworkingPlugIn.xrplugin下,找到了XRNetworkingRun.h;

  • XRSamplerInstrument=>XRSamplerRun
  • XRActivityInstrument=>XRActivityInstrumentRun
  • XRNetworkingInstrument=>XRNetworkingRun

2. 读取trace样本数据

(1)CPU样本结果

debug变量run._data,发现了样本数据

TraceUtility使用了Undocumented API获取数据,而我在XRActivityInstrumentRun.h没找到相关API,直接通过反射获取吧。


至此,CPU样本数据获取完成。

(2)网络流量样本结果

XRNetworkRun和XRActivityInstrumentRun对象属性不一样,没有_data,但_saveActivityQueries中有段sql,初步预估这玩意用了localdb,但db类型未明。另外,估计_saveInstrumentUUID应该db文件。

然后cat 2A183EAD-5B9C-45DD-B2BA-D63DCD1165D4看下,因为文件可能会在头部加注类型信息,cat结果如下:

捕获SQLite文件一个……接下来的事情就是分析表结构了,没什么难度,不作详述了。至此,网络流量样本数据获取完成。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 26 条回复 时间 点赞
hyddd #1 · March 28, 2016 作者

格式转换得不好,凑合着看吧

#1楼 @hyddd 好久没见到这个id了...

hyddd #3 · March 28, 2016 作者

@seveniruby 是啊,比较忙,很久没上来混了,先来发靠谱的:)

是真的好久不见了

#3楼 @hyddd 😄 instruments是个好东西, mac有个dtrace工具很强大. 不知道iOS里面能不能搞.

hyddd #6 · March 28, 2016 作者

@seveniruby dtrace 没了解,有空看下,哈哈

hyddd #7 · March 28, 2016 作者

收到打赏信息,感谢各位打赏:)

赞,ios这块空白区终于填上了

思路值得借鉴,顶个。

https://github.com/powerli/InstrumentsParser 这也有一个开源的, 可以试试看

赞~ 学习了~

#7楼 @hyddd 分享到 Testerhome 公众号了,顺便更新了一下格式,你看下现在格式有没有问题?

我的instruments下面没有这个框架,DVTInstrumentsFoundation.framework

hyddd #14 · March 29, 2016 作者

@noshuai 👌
@chenhengjie123 格式没问题;有朋友早上告诉testhome公众号有转发了
@wangcityboy xcode目录下搜下吧,我的在.//Contents/SharedFrameworks/DVTInstrumentsFoundation.framework

调用PFTLoadPlugins();时总是crash掉

在PFTLoadPlugins();这一句中crash了,下面是回溯,请问这是什么原因呢?我的是Xcode7.3,是不是Xcode6之前才可以?
2016-04-08 15:11:36.017 TraceUtility[79428:2047286] [MT] DVTAssertions: ASSERTION FAILURE in /Library/Caches/com.apple.xbs/Sources/DVTFrameworks/DVTFrameworks-10174/DVTFoundation/DeveloperStructure/DVTDeveloperPaths.m:58
Details: +[DVTDeveloperPaths applicationDirectoryName] was called, but +initializeApplicationDirectoryName: has not been called yet. Your process must initialize the application directory name if you use this class.
Object:
Method: +applicationDirectoryName
Thread: {number = 1, name = main}
Hints: None
Backtrace:
0 -DVTAssertionHandler handleFailureInMethod:object:fileName:lineNumber:assertionSignature:messageFormat:arguments:
1 _DVTAssertionHandler (in DVTFoundation)
2 _DVTAssertionFailureHandler (in DVTFoundation)
3 +DVTDeveloperPaths applicationDirectoryName
4 -DVTDeveloperPaths sourceSpecificationSearchPathForPlatform:
5 +DVTSourceSpecification searchForAndRegisterAllAvailableSpecifications
6 __PFTLoadPlugins_block_invoke (in InstrumentsPlugIn)
7 _dispatch_client_callout (in libdispatch.dylib)
8 dispatch_once_f (in libdispatch.dylib)
9 PFTLoadPlugins (in InstrumentsPlugIn)
10 main at /Users/yemingyu/Desktop/InstrumentParse/TraceUtility-master/TraceUtility/main.m:13 (in TraceUtility)
11 start (in libdyld.dylib)

hyddd #17 · April 24, 2016 作者

#16楼 @yemingyu 解决方案看原文补充部分,不转帖这里了

#17楼 @hyddd 你本人试过能行吗?

hyddd #19 · April 26, 2016 作者

#18楼 @quqing 不行我写出来找喷么.....

#19楼 @hyddd 文中提到“(3). 从instruments结果文件(.trace)中尝试获取样本值”,为什么我导其他的可以,这两个却不行(求助贴:https://testerhome.com/topics/4747):
instruments -w #udid# -v -t "Activity Monitor" -D Activity_Monitor.trace xxx.ipa
instruments -w #udid# -v -t "Network" -D Network.trace xxx.ipa
你是如何获取这两个trace的,盼望回复!

7.3的.trace文件貌似解析不出来啊,大神@hyddd

#10楼 @noshuai 这个开源的你用过吗?xcode7.3 怎么解析失败呢?

#20楼 @quqing 你好 请问一下 你用脚本怎么取instruments关于cpu等这些数据的?😄

24Floor has been deleted
扫地僧 回复

trace 文件没有符号化,那怎么自动解决啊。手动可以载入。
但是在做的是自动化的性能数据解析平台
感谢!

李鹏 回复

麻烦问一下,又找到自动化解析 trace 文件的方法么?

rhyme 回复

就是在研究这个TraceUtility啊。目前没看到别的。
这个研究起来很需要OC语言背景啊,有点吃力,。。。。

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up