一: Time Profiler
Time Profiler用來分析代碼的執行時間,主要用來分析CPU使用情況。
注意:要在release模式(或者自定義的其他的打包模式)下分析,原因在release模式下:
- 會開啟編譯器優化,提高代碼運行效率
- 生成調試的符號表,這樣才能夠在profile的時候看到代碼的調用棧
- 多數條件編譯只會在debug模式下生效,release模式和生產環境是一樣的。
二: 原理
Time Profiler每隔1ms會對線程的調用棧采樣,然后用統計學的方式去做出分析。
圖中虛線是采樣點,最后統計出調用棧和對應函數出現的個數。
從圖中不難看出,method3
并沒有出現在統計結果中,也就意味著方法運行的足夠快的時候,很有可能統計不到,但這對于分析來說并不會有太大影響,因為運行快的方法往往不會引起性能問題。
Tips:Time Profiler并不會精確的統計出方法的執行時間,當線程處于掛起和等待執行的狀態時候,timer profiler并不能統計到,它只能統計到真正在CPU上執行的。
三: Demo
Demo工程是一個簡易的相冊應用,故意寫的很爛,包含了三個界面:
? 第一個界面只提供一個入口
? main界面用瀑布流的方式提供圖片預覽,圖片被加了濾鏡
? detail界面可以查看大圖
在iPhone 6上運行,在進入main界面的時候會看到明顯的卡頓:
我們通過Time Profile來找到原因:Product -> Profile
這會讓XCode執行一次Release的build,然后啟動Instrument
我們選擇Time Profiler啟動,然后正常操作App,采集到了數據后,停止Instrument。
對圖中的幾點說明:
- 各個線程的采集數據匯總
- 點擊1中的某一行,可以看到采集到的堆棧,注意2區域的右上角,可以選擇隱藏系統的符號
- 可以選擇關注的隊列/CPU等。
- 可以用pinch手勢來放大縮小時間范圍,鼠標可以拖動選擇一段區域
Tips:
Weight表示占用全部的百分比
Self Wight表示當前方法執行占用的百分比,如果看到是0,表示當前方法其實不占用什么時間,時間都是子程序調用占用的。
我們用鼠標拖動,選擇選擇CPU占用較高的部分,可以看到堆棧如下:
Tips: 按住Option,然后鼠標左鍵點圖中的箭頭,可以快速展開。
從圖中看到:大部分時間占用在-[MainController loadAllImages]
這個方法:讀取本地圖片,然后對圖加濾鏡
- (void)loadAllImages{
NSMutableArray * images = [NSMutableArray new];
for (long i = 1; i < 40; i++) {
NSString * imageName = [NSString stringWithFormat:@"image_%ld",i % 20 + 1];
NSString * imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:@"jpeg"];
UIImage * image = [UIImage imageWithContentsOfFile:imagePath];
[images addObject:[self filterdImage:image]];
}
self.images = [images copy];
}
我們可以勾選以下選項,來看得更清楚一些:
- Hide System Libraries 隱藏系統的庫
- Invert Call Tree 倒置函數隊戰
勾選后
Timer Profiler的基本debug邏輯:分析 -> 找到最大的占用函數 -> 修復 -> 繼續分析…,直到完全修復。有時候自己的代碼會引起系統代碼卡頓,所以查看系統庫的卡頓也很有必要的。
可以通過雙擊一行,進入源代碼界面,看看具體某一行的占用情況:
也可以選擇查看次數:
查看次數:
或者,查看反匯編
四: FAQ
為什么我在Time Profiler看不到類和方法的名稱呢?
絕大部分原因是你的打包模式沒有開啟dSYM
或者debug symbols
為什么明明我的App很卡,可是用Time Profiler分析卻找不到相關代碼?
卡頓的原因主要分為兩大類:CPU瓶頸和GPU瓶頸
當界面有大量的shadow,mask或者有非常多的View/Layer,GPU渲染紋理和頂點的時候可能會有壓力,這時候應該用Core Animation觀察GPU的使用率。
CPU引起的卡頓大多可以通過Time Profiler
找到,如果找不到可能的原因有兩個:
- 代碼引起了大量系統調用,占用CPU時間,這種情況你需要仔細分析Time Profiler中的系統占用。
- 頻繁的鎖和線程切換。因為線程被掛起的時候,time profiler無法采樣到,這種情況可以通過System Trace分析。