根据Call Tree 去计算时间
instruments -> Time Profiler
Profiler你的app
切换到CPU strategy view,找到你的app的启动的第一帧
刚开始我们拿到分析数据时往往是这样的:
这里显示的是执行代码完整路径,其中系统和应用本身一些调用路径完全揉捏在一起。完全看不到我们关心的应用程序中实际代码执行耗时和代码路径实际所在位置。
怎么办?我们可以看到右侧有一个“齿轮形状”的设置按钮。
图8
Call Tree:
Separate By Thread:线程分离,只有这样才能在调用路径中能够清晰看到占用CPU最大的线程;
Invert Call Tree:从上到下跟踪堆栈信息.这个选项可以快捷的看到方法调用路径最深方法占用CPU耗时,比如FuncA{FunB{FunC}},勾选后堆栈以C->B->A把调用层级最深的C显示最外面;
Hide System Libraries:这个就更有用了,勾选后耗时调用路径只会显示app耗时的代码,性能分析普遍我们都比较关系自己代码的耗时而不是系统的.基本是必选项.注意有些代码耗时也会纳入系统层级,可以进行勾选前后前后对执行路径进行比对会非常有用。
Top Functions:按耗时降序排列。
简单的方式可以快速勾选右边Call Tree中Separate by Thread和Hide System Libraries两个选项[后面会解释选项作用]:
图9-10
勾选Invert Call Tree:
图11
勾选前后对比:
图12
图13
●算出启动时间。
首次加载坐了如下操作:
A: 链接和载入:可以在Time Profile中显示dyld载入库函数,库会被映射到地址空间,同时完成绑定以及静态初始化。
B: UIKit初始化:如果应用的Root View Controller是由XIB实现的,也会在启动时被初始化.
C: 应用回调:调用UIApplicationDeleagte的回调:application:didFinishLaunchingWithOptions。
D: 第一次Core Animation调用:在启动后的方法-[UIApplication_resportAppLaunchFinished]中调用CA::Transaction::commit实现第一帧画面的绘制。
应用程序首次加载中启动方法willFinishLaunchingWithOptions和didFinishLaunchingWithOptions只做应用程序首次启动必须的要操作,而针对_dyid_start在初始化库framework函数的操作。不必要的Framework不要链接,避免首次加载耗时。
搜索-[UIApplication_reportAppLaunchFinished]的最后一帧,即可算出启动时间。
图14
Running Time列中显示运行每个方法所耗费的时间,根据耗时和占比猜测是否有代码需要优化。双击中间主窗口中的方法名进入具体的代码行查看,耗时多的代码行有颜色标记,并显示占比。
当然对于开发而已,这种利用Time Profiler的方式计算启动耗时比较麻烦,他们更喜欢埋点。
启动耗时——NSLog
●获取某段代码的执行时间MKBlockTimer
●利用类库测试代码的运行时间MGBenchmark
评估总体运行时间;
评估单步代码的运行时间;
找到所有代码x最耗时的代码;
找到代码的平均运行时间;
可以对不同的线程进行评估(thread safe)
●启动时间
看之前XXX的性能资料,是在AppDelegate里打点并不合理。算出的只是main
调用AppDelegate文件的时间。
图16
图17
所以是错误的。
业界对此的算法不同。贴吧是在内存创建完成就算是启动成功,即:didLoad
个人觉得其实应该是didAppear,即ui展示出来为准。
埋点步骤:
在main.m中记当前时间StartTime:
图18
不能在ALATabBarController.h函数里面声明,会被多次调用,相当于多次声明全局变量;所以在ALATabBarController.m里面定义全局变量。
图19
但是不可见,所以在ALATabBarController.h文件用extern,将extern置于变量或者函数前,以表示变量或者函数的定义在别的文件中,即CFAbsoluteTime StartTime在ALATabBarController.m文件中声明过。
图20
计算启动时间(didLoad):
图21
计算启动时间(didAppear):
图22
在log输出窗口看准确时间输出:
22/2<12