Signposts は Xcode 10 で導入されたパフォーマンスを計測するためのマーカーです。この記事では Signposts を実際に活用する人のために、Signposts でできることをまとめておきます。初心者用の Signpost の使い方についてはこちらの記事をご覧下さい。
Signposts と Instruments でパフォーマンスを計測する:入門編
https://qiita.com/hsawada/items/e027b85480c8778f154a
#処理の時間を測る
パフォーマンス計測用のマーカーなので、まずは処理の時間を測るのが基本です。
let logSomething = OSLog(subsystem: "com.example.your-app", category: "Something")
os_signpost(.begin, log: logSomething, name: "fetch something")
fetchSomething()
os_signpost(.end, log: logSomething, name: "fetch something")
ログのハンドルを取得して、計測したい箇所を os_signpost()
の .begin
と .end
で囲みます。
#非同期処理の時間を測る
上記の fetchSomething()
が非同期に何度も呼ばれると、 .begin
と .end
が対応しなくなり、正しく計測できなくなってしまいます。そういう時は OSSignpostID()
を使って、ID を作成し、対応する .begin
と .end
に同じ ID を指定するようにします。
let spid = OSSignpostID(log: logSomething)
os_signpost(.begin, log: logSomething, name: "fetch something", signpostID: spid)
fetchSomething()
os_signpost(.end, log: logSomething, name: "fetch something", signpostID: spid)
ただ、これだと、 ID の管理が面倒になることが多いので、オブジェクトから ID を取得する方法を取るのが便利だと思います。
let spid = OSSignpostID(log: logSomething, object: element)
オブジェクトごとに ID が取得できるので、下記のような使い方ができます。
let logSomething = OSLog(subsystem: "com.example.your-app", category: "Something")
for element in panel.elements {
let spid = OSSignpostID(log: logSomething, object: element)
os_signpost(.begin, log: logSomething, name: "fetch something", signpostID: spid)
fetchSomethingAsync() {
os_signpost(.end, log: logSomething, name: "fetch something", signpostID: spid)
}
}
#メタデータを記録する
時間を測ると同時にその時に必要なメタデータを記録することもできます。例えば、イメージのダウンロードあれば、そのイメージのサイズなどをログとして記録することができます。
os_signpost(.begin, log: logSomething, name: "fetch something", "%d %.1f", x1, y1)
フォーマットさえきちんと指定すれば、いろいろなタイプでたくさんの引数を指定することが可能です。
ここでは簡単な例を示すために、数値を並べていますが、実際に使用する時には、それぞれの数値の説明も含めて記録しておくべきです。後で分析する時に何の数値の羅列かを、コードと照らし合わせなければ、分からなくなってしまうからです。
#イベントを記録する
パフォーマンスを分析する時、処理にかかる時間ばかりでなく、何かのイベントを記録したいこともよくあります。そんな時には os_signpost()
に .event
を指定します。
os_signpost(.event, log: logSomething, name: "tap something")
タップやスワイプなどのユーザー操作や、ネットワークコネクション確立後のイメージのダウンロード開始など、いわゆる普通のログと同じように、パフォーマンス分析において、興味のあるイベントをこれで記録します。
#マーカーを無効にする
Signposts は非常に軽量で、アプリのリソースに影響はほとんど与えないそうです。しかしながら、限られた場所に大量にマーカーがあって、その影響が懸念される場合や、一部のマーカーを無効にして、分析しやすくしたい場合には、カテゴリーごとにマーカーを無効化できます。
マーカーのカテゴリーは、ログのハンドルを取得する際に指定しています。
let logSomething = OSLog(subsystem: "com.example.your-app", category: "Something")
このログのハンドルに対して、 OSLog.disabled
をセットすると、このハンドルを使用するマーカーは全て動かなくなります。つまり、このカテゴリーのマーカーは全て動かなくなるわけです。
logSomething = .disabled
したがって、マーカーを入れていく際には、ログをどのようにカテゴリー分けするかについて、よく考慮しておいた方が良いと思います。パフォーマンスのマーカーを使い始めると、至る所に入れまくってしまい、いざ分析するときに注目したいデータが埋もれてしまうことがよくあるからです。適切にカテゴリー分けをしておけば、後々の管理がずっと楽になると思います。
#計測専用のコードを分離する
上記のマーカーの無効化に関係しますが、計測専用のコードを書く場合には、ログハンドルの .signpostsEnabled
を使って、通常のコードから分離しておいた方がいいと思います。
if logSomething.signpostEnabled {
fetchMetadata()
}
例えば、画像のファイルサイズの取得など、記録したいメタデータを取得するためだけにコードを書く場合には、このようにして通常コードと分離しておけば、そのカテゴリーが無効の時に、メタデータ取得のコードは実行されなくなります。
#まとめ
Signposts を使うと、処理の継続時間やイベントを記録でき、それと同時に任意のメタデータも記録できます。また、状況に応じて、カテゴリごとにマーカーや計測用のコードを無効化することもできます。
#参考文献
Measuring Performance Using Logging
https://developer.apple.com/videos/play/wwdc2018/405