TimeProfilerとはXcodeのInstrumentsに含まれているプロファイリング用のツールです。

XcodeでProfileビルドをすると、Instrumentsが立ち上がって選択できます。

Profile  MedicineNote

TimeProfilerを立ち上げると、上部トレースデータが表示されていますが、今回の主役は下部にあるCall Treeです。

Instruments1 3

初期の設定だとシステムのメソッドなども混ざってとてもわかにくいので、上記の設定にチェックを入れておくと
作成したメソッドだけになるので見やすくなると思います。

これで、準備は出来たので後はアプリを触っていて重たい感じのするを見ていけば、Call Treeにメソッド毎の処理時間や処理の割合が表示されます。

例として、カレンダー画面がとても重たくなっていたアプリを見ていきます。
カレンダーを表示した時のCall Treeです。
Instruments2

カレンダーを表示した時に324msもかかっている部分が存在するのが分かります
viewWillAppear -> updatecalendarメソッド内から呼ばれているisEqualToDateIgnoringTimeというメソッドがとても重たい事が分かります。
このメソッドはErica女史が書かれたカテゴリライブラリのNSDate-Extensions に含まれているメソッドで、NSDate同士の年月日で比較を行なっているメソッドです。
このisEqualToDateIgnoringTimeメソッド自体は凄く重たいわけではありませんが、ループ内でこのメソッドを使って比較していたのが原因だと分かりました。
Call Treeでは呼び出された分だけ積み重なって表示されているので、一回程度なら全然問題ない比較も何十回もループを回して比較するような使い方をすると、
このように重たい処理になってしまいます。

Call TreeでSymbol Nameで該当のメソッドをダブルクリックすると、ソースコードレベルで処理が重たい場所を表示してくれます。

Instruments2 1

該当部分を見ると、NSDateComponentsの部分がとても重たい(%はそのメソッドの処理時間の割合)事が分かります


#define DATE_COMPONENTS (NSYearCalendarUnit| NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekCalendarUnit |  NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSWeekdayCalendarUnit | NSWeekdayOrdinalCalendarUnit)
#define CURRENT_CALENDAR [NSCalendar currentCalendar]
- (BOOL) isEqualToDateIgnoringTime: (NSDate *) aDate
{
	NSDateComponents *components1 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
	NSDateComponents *components2 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:aDate];
	return (([components1 year] == [components2 year]) &&
			([components1 month] == [components2 month]) &&
			([components1 day] == [components2 day]));
}

Taming NSDate-Utilities « Pat Zearfoss でも書かれていますが、 NSDate-Extensionsのメソッドは基本的に日付を比較できるようにするために、
NSDateComponentsやNSCalendarのallocを行なっているため、元々少し重たいのもあって何度も呼ばれると画面が固まるような重さになってしまいます。

これを解消するために今回は、次のようにNSDateFormatter + staticで初期化処理はキャッシュして比較できるようにしてみました。

この変更を適応した状態で、もう一度TimeProfilerを使って処理時間を計測してみます。

Instruments1 1

324ms -> 16.0ms と1/20ぐらい処理時間が短くなりました。

TimeProfilerを使えば、大体重たい場所はわかってるけど、どのメソッドが重たいのかが分からない等といった時に、
メソッド呼び出し毎の時間などを計測できるので、パフォーマンスチューニングにはかなり有用なツールになると思います。

Post Navigation