AppleTrace iOS 应用性能分析工具开源项目

我要开发同款
匿名用户2019年06月13日
87阅读
开发技术C/C++Object-c
所属分类性能测试和优化、开发工具
授权协议MIT

作品详情

AppleTrace是一个用来分析iOSApp性能的工具。

背景

一般情况下使用Instruments(主要是TimeProfiler)进行iOSApp的性能分析就足够了,但是TimeProfiler把调用方法都合并了起来,失去了时序的表现。直到有一天看到Android开发的同事使用 systrace 分析性能,systrace生成一个html文件,把函数(方法)的调用耗时按照先后顺序表现出来。心里想:要是iOS也有这样的工具就好了。了解到这个html文件是 catapult 生成的。

一天看到iosre论坛一篇hookobjc_msgSend的帖子。突然想到,可以结合catapult来生成ObjectiveC方法的性能分析图(暂且这么叫吧)。(虽然一直也有hookobjc_msgSend的方法,但这次煮好的佳肴终于忍不住下手了)。

说搞就开始搞,暂停几天开发MachOExplorer。近期一直利用少之又少的业余时间蜗牛般开发MachOExplorer,但现在看来生成性能分析图更是重要,回想过去的一些苦力加班,如果能生成这个性能分析图,当时岂不是很快就解决问题了。

目标

hook所有的objc_msgSend,也就是把每个ObjectiveC方法的耗时计算出来,并按照先后顺序生成性能分析图。

要解决的问题如何生成最终的html

从这里可以了解到catapult是如何生成html的。其中一种方式可以是:Chrome’s trace_eventformat。简单来说,trace_eventformat 就是个json格式,按照这个约定的json格式填充数据后,就可以使用trace2html命令(python脚本)转换为最终的html文件了。

$CATAPULT/tracing/bin/trace2htmlmy_trace.json--output=my_trace.html&&openmy_trace.html如何Hookobjc_msgSend

见文章使用HookZz快速逆向(Hackobjc_msgSend)理清逻辑

HookZz是jmpews开发的微型hook框架,使用起来十分灵活。详见 https://jmpews.github.io/zzpp/

如何生成trace_eventformat的json文件

参考文档Chrome’s trace_eventformat 可以了解到,最简单的json文件,可以是这样:

[{"name":"Asub","cat":"PERF","ph":"B","pid":22630,"tid":22630,"ts":829},{"name":"Asub","cat":"PERF","ph":"E","pid":22630,"tid":22630,"ts":833}]

每一行表示一个Event,

{"name":"myName","cat":"category,list","ph":"B","ts":12345,"pid":123,"tid":456,"args":{"someArg":1,"anotherArg":{"value":"myvalue"}}}

每个字段的含义如下:

-name:Thenameoftheevent,asdisplayedinTraceViewer-cat:Theeventcategories.Thisisacommaseparatedlistofcategoriesfortheevent.ThecategoriescanbeusedtohideeventsintheTraceViewerUI.-ph:Theeventtype.Thisisasinglecharacterwhichchangesdependingonthetypeofeventbeingoutput.Thevalidvaluesarelistedinthetablebelow.Wewilldiscusseachphasetypebelow.-ts:Thetracingclocktimestampoftheevent.Thetimestampsareprovidedatmicrosecondgranularity.-tts:Optional.Thethreadclocktimestampoftheevent.Thetimestampsareprovidedatmicrosecondgranularity.-pid:TheprocessIDfortheprocessthatoutputthisevent.-tid:ThethreadIDforthethreadthatoutputthisevent.-args:Anyargumentsprovidedfortheevent.Someoftheeventtypeshaverequiredargumentfields,otherwise,youcanputanyinformationyouwishinhere.TheargumentsaredisplayedinTraceViewerwhenyouviewaneventintheanalysissection.

其中ph(eventtype)是需要关心的:

EventtypeEventphasesDurationEventsB(begin),E(end)……

也就是说一个方法的调用,至少有两行,ph=B和ph=E。

格式弄清楚后,就需要生成json文件了。生成这个json文件本质上就是个日志功能,为了尽最大可能不影响App的性能,使用内存映射mmap方法来写文件。同时为了简单的处理多线程问题,使用了串行queue。代码见这里

最终trace文件会生成在App沙盒中的Library/appletracedata目录。由于日志量可能很大,又结合mmap的特性,日志文件会以下面的逻辑生成:

trace.appletracetrace_1.appletracetrace_2.appletracetrace_3.appletrace...trace_N.appletrace

每个appletrace文件16MB,由于mmap的特性(只能映射固定大小文件),文件末尾一般会有\0来填充。

生成这些appletrace文件后,需要从App的沙盒中复制出来。使用merge.py把appletrace文件转换为trace_eventformat的json文件。

pythonmerge.py-d<appletracedatadirectory>

最终执行catapult的trace2html脚本,生成最终的html文件。

pythoncatapult/tracing/bin/trace2htmlappletracedata/trace.json--output=appletracedata/trace.html 使用方法采集数据

目前有两种采集数据的方式。

手动APTBeginSection和APTEndSection

这种场景是:我不想hook所有的ObjectiveC方法,我只想在分析性能时,一点一点手动添加开始点和结束点。(这点Android的systrace也是支持)虽然麻烦,但在定位到大体方向后,这样更加精细和准确,避免了hook对App本身性能的影响。

(1)只需要把 appletrace.h和appletrace.mm文件拖入自己的功能即可。(当然这里可以做成CocoaPods,有时间可以做下)。

(2)然后在函数(方法)的开头和结尾(或者自己感兴趣的区间),调用APTBeginSection 和 APTEndSection即可。对于ObjectiveC方法可以使用宏APTBegin和APTEnd。

//ObjectiveCclassmethod#defineAPTBeginAPTBeginSection([NSStringstringWithFormat:@"[%@]%@",self,NSStringFromSelector(_cmd)].UTF8String)#defineAPTEndAPTEndSection([NSStringstringWithFormat:@"[%@]%@",self,NSStringFromSelector(_cmd)].UTF8String)

参考例子 sample/ManualSectionDemo。

Hookobjc_msgSend

这种场景是:我想初步定为哪里有耗时的操作,可以整体上Hookobjc_msgSend一次,对整个App的流程有个大致了解。

(1)把动态库的工程appletrace.xcodeproj拖拽到目标工程。(2)并配置动态库的依赖 TargetDependencies 和 CopyFiles。

参考 sample/TraceAllMsgDemo。

注意:

需要关闭BitCode。仅支持arm64。处理数据,生成html

从App的沙盒中复制出 Library/appletracedata 目录。(例如:Xcode可以直接Dump出整个沙盒)

然后,

//处理mmap的日志文件pythonmerge.py-d<appletracedatadirectory>//生成htmlpythoncatapult/tracing/bin/trace2htmlappletracedata/trace.json--output=appletracedata/trace.html//打开opentrace.html

就可以看到

性能影响

目前对App性能的影响主要是:

Hookobjc_msgSend:这个是主要的影响,因此生成的最终结果仅用于分析、对比,而不能认为就是耗费了这些数值。日志文件:为了写日志,mmap了文件,还创建了队列。对App本身的性能也有影响。局限

由于HookZz对objc_msgSend的hook仅实现了arm64架构,因此只能在真机上分析。(当然这也足够了,主流设备就是arm64)

计划计划1:dtrace

对于数据的产生来源,目前有两种:

手动APTBeginSection和APTEndSectionHookobjc_msgSend

最近一段时间对 dtrace也学习了一段时间了,完全可以针对模拟器使用dtrace来生成数据。dtrace由于是内核层,对App本身的性能影响很小,而且dtrace不仅仅可以hook(trace)ObjectiveC方法,还可以traceC方法、swift方法。这是下一步的计划。

计划2:白名单类/黑名单类

Hookobjc_msgSend的方法,有的类可能并不关心。可以采用白名单或者黑名单的方式,缩小分析范围。

计划3:Hook+loadandC++staticinitializers

见Amethodofhookstaticinitializers 和Amethodofhookobjectivec+load

总结

这个工具本身的代码不多(写日志),主要是组合了catapult和HookZz,再次感谢catapult和HookZz。

声明:本文仅代表作者观点,不代表本站立场。如果侵犯到您的合法权益,请联系我们删除侵权资源!如果遇到资源链接失效,请您通过评论或工单的方式通知管理员。未经允许,不得转载,本站所有资源文章禁止商业使用运营!
下载安装【程序员客栈】APP
实时对接需求、及时收发消息、丰富的开放项目需求、随时随地查看项目状态

评论