AppleTrace 是一个用来分析 iOS App 性能的工具。
一般情况下使用Instruments(主要是Time Profiler)进行iOS App的性能分析就足够了,但是Time Profiler 把调用方法都合并了起来,失去了时序的表现。直到有一天看到Android开发的同事使用 systrace 分析性能,systrace生成一个html文件,把函数(方法)的调用耗时按照先后顺序表现出来。心里想:要是iOS也有这样的工具就好了。了解到这个html文件是 catapult 生成的。
一天看到iosre论坛一篇hook objc_msgSend的帖子。突然想到,可以结合catapult来生成Objective C方法的性能分析图(暂且这么叫吧)。(虽然一直也有hook objc_msgSend的方法,但这次煮好的佳肴终于忍不住下手了)。
说搞就开始搞,暂停几天开发MachOExplorer。近期一直利用少之又少的业余时间蜗牛般开发MachOExplorer,但现在看来生成性能分析图
更是重要,回想过去的一些苦力加班,如果能生成这个性能分析图,当时岂不是很快就解决问题了。
hook 所有的objc_msgSend,也就是把每个Objective C方法的耗时计算出来,并按照先后顺序生成性能分析图
。
从这里可以了解到catapult是如何生成html的。其中一种方式可以是:Chrome’s trace_event format。简单来说,trace_event format
就是个json格式,按照这个约定的json格式填充数据后,就可以使用trace2html命令(python脚本)转换为最终的html文件了。
$CATAPULT/tracing/bin/trace2html my_trace.json --output=my_trace.html && open my_trace.html
见文章使用HookZz快速逆向(Hack objc_msgSend) 理清逻辑
HookZz是jmpews开发的微型hook框架,使用起来十分灵活。详见 https://jmpews.github.io/zzpp/
参考文档 Chrome’s trace_event format 可以了解到,最简单的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": "my value"
}
}
}
每个字段的含义如下:
- name: The name of the event, as displayed in Trace Viewer
- cat: The event categories. This is a comma separated list of categories for the event. The categories can be used to hide events in the Trace Viewer UI.
- ph: The event type. This is a single character which changes depending on the type of event being output. The valid values are listed in the table below. We will discuss each phase type below.
- ts: The tracing clock timestamp of the event. The timestamps are provided at microsecond granularity.
- tts: Optional. The thread clock timestamp of the event. The timestamps are provided at microsecond granularity.
- pid: The process ID for the process that output this event.
- tid: The thread ID for the thread that output this event.
- args: Any arguments provided for the event. Some of the event types have required argument fields, otherwise, you can put any information you wish in here. The arguments are displayed in Trace Viewer when you view an event in the analysis section.
其中ph(event type)是需要关心的:
Event type | Event phases |
---|---|
Duration Events | B(begin), E(end) |
… | … |
也就是说一个方法的调用,至少有两行,ph=B和ph=E。
格式弄清楚后,就需要生成json文件了。生成这个json文件本质上就是个日志功能,为了尽最大可能不影响App的性能,使用内存映射mmap方法来写文件。同时为了简单的处理多线程问题,使用了串行queue。代码见这里
最终trace文件会生成在App沙盒中的Library/appletracedata
目录。由于日志量可能很大,又结合mmap的特性,日志文件会以下面的逻辑生成:
trace.appletrace
trace_1.appletrace
trace_2.appletrace
trace_3.appletrace
...
trace_N.appletrace
每个appletrace文件16MB,由于mmap的特性(只能映射固定大小文件),文件末尾一般会有\0
来填充。
生成这些appletrace文件后,需要从App的沙盒中复制出来。使用merge.py
把appletrace文件转换为trace_event format
的json文件。
python merge.py -d <appletracedata directory>
最终执行catapult的trace2html脚本,生成最终的html文件。
python catapult/tracing/bin/trace2html appletracedata/trace.json --output=appletracedata/trace.html
目前有两种采集数据的方式。
这种场景是:我不想hook所有的Objective C方法,我只想在分析性能时,一点一点手动添加开始点和结束点
。(这点Android的systrace也是支持)虽然麻烦,但在定位到大体方向后,这样更加精细和准确,避免了hook对App本身性能的影响。
(1)只需要把 appletrace.h
和appletrace.mm
文件拖入自己的功能即可。(当然这里可以做成CocoaPods,有时间可以做下)。
(2)然后在函数(方法)的开头和结尾(或者自己感兴趣的区间),调用APTBeginSection
和 APTEndSection
即可。对于ObjectiveC方法可以使用宏APTBegin
和APTEnd
。
// Objective C class method
#define APTBegin APTBeginSection([NSString stringWithFormat:@"[%@]%@",self,NSStringFromSelector(_cmd)].UTF8String)
#define APTEnd APTEndSection([NSString stringWithFormat:@"[%@]%@",self,NSStringFromSelector(_cmd)].UTF8String)
参考例子 sample/ManualSectionDemo
。
这种场景是:我想初步定为哪里有耗时的操作,可以整体上Hook objc_msgSend一次,对整个App的流程有个大致了解。
(1)把动态库的工程appletrace.xcodeproj
拖拽到目标工程。 (2)并配置动态库的依赖 Target Dependencies
和 Copy Files
。
参考 sample/TraceAllMsgDemo
。
注意:
从App的沙盒中复制出 Library/appletracedata
目录。(例如:Xcode可以直接Dump出整个沙盒)
然后,
// 处理mmap的日志文件
python merge.py -d <appletracedata directory>
// 生成html
python catapult/tracing/bin/trace2html appletracedata/trace.json --output=appletracedata/trace.html
// 打开
open trace.html
就可以看到
目前对App性能的影响主要是:
由于HookZz对objc_msgSend的hook仅实现了arm64
架构,因此只能在真机上分析。(当然这也足够了,主流设备就是arm64)
对于数据的产生来源,目前有两种:
最近一段时间对 dtrace
也学习了一段时间了,完全可以针对模拟器使用dtrace
来生成数据。dtrace由于是内核层,对App本身的性能影响很小,而且dtrace不仅仅可以hook(trace)ObjectiveC方法,还可以trace C方法、swift方法。这是下一步的计划。
Hook objc_msgSend的方法,有的类可能并不关心。可以采用白名单或者黑名单的方式,缩小分析范围。
见A method of hook static initializers 和A method of hook objective c +load
这个工具本身的代码不多(写日志),主要是组合了catapult和HookZz,再次感谢catapult和HookZz。
主要内容:一、查看系统性能参数,,二、定位执行慢的SQL:慢查询日志,三、查看 SQL 执行成本:SHOW PROFILE,四、分析查询语句:EXPLAIN,EXPLAIN各列作用:一、查看系统性能参数 通过SHOW STATUS语句查询一些MySQL数据库服务器的性能参数、执行频率。 一些常用的性能参数如下: Connections:连接MySQL服务器的次数。 Uptime:MySQL服务器的上线时间。单位:s Slow_queries:慢查询的次数。 Innodb_rows_read:Se
本文向大家介绍Python性能分析工具Profile使用实例,包括了Python性能分析工具Profile使用实例的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了Python性能分析工具Profile使用实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码优化的前提是需要了解性能瓶颈在什么地方,程序运行的主要时间是消耗在哪里,对于
我正在写一份棘手的申请书。该应用程序运行在64位八核linux机器上 Netty应用程序是一个简单的路由器,它接受请求(传入管道),从请求中读取一些元数据,并将数据转发给远程服务(传出管道)。 此远程服务将向传出管道返回一个或多个响应。Netty应用程序将把响应路由回发起客户端(传入管道) 会有成千上万的客户。将会有成千上万的远程服务。 我正在做一些小规模的测试(十个客户端,十个远程服务),但我没
性能分析 StackExchange.Redis 公开了少量的方法和类型来开启性能分析。由于其异步性和多路复用行为,性能分析是一个有点复杂的话题。 接口 性能分析接口是由这些组成的:IProfiler,ConnectionMultiplexer.RegisterProfiler(IProfiler),ConnectionMultiplexer.BeginProfiling(object), Con
使用perf内核性能分析工具,可以分析出很多问题。具体参考perf命令的用法。 还有oprofile可以分析性能。mpstat查看cpu的使用分布。strace查看系统调用情况。参考:http://blog.csdn.net/win_lin/article/details/9377209
SRS支持gprof性能分析。 SRS性能分析 SRS使用gprof分析的步骤如下: 配置:./configure --with-gprof 编译:make 直接启动即可:rm -f gmon.out; ./objs/srs -c conf/console.conf 退出SRS:killall -2 srs # or CTRL+C to stop gprof 生成gprof报告:gprof -b
本文向大家介绍Java CPU性能分析工具代码实例,包括了Java CPU性能分析工具代码实例的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了Java CPU性能分析工具代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 背景 有处理过生产问题的同学基本都能遇到系统忽然缓慢,CPU突然飙升,甚至整个应用请求不可用。当出现这种情况下
问题内容: 我有一个Spring应用程序,我认为它存在一些瓶颈,因此我想用一个探查器运行它来衡量哪些功能需要花费多少时间。有什么建议我应该怎么做? 我正在运行STS,该项目是一个maven项目,并且正在运行Spring 3.0.1 问题答案: 我已经使用Spring AOP做到了。 有时,我需要有关在项目中执行某些方法(例如,控制器的方法)花费多少时间的信息。 在servlet xml中,我把 另