MetricKit 入門

この記事は、[ZOZOテクノロジーズ #4 AdventCalendar2020](https://qiita.com/advent-calendar/2020/zozo_tech4)の記事です。

昨日は[@r-tezuka](https://qiita.com/r-tezuka)さんの[「GKE上でgcloudコマンドを叩く為のPodをDeployしたら詰まった話」](https://qiita.com/r-tezuka/items/ea920f41c28b24d26d88)の記事でした。
ぜひご覧ください！

ZOZOテクノロジーズ iOSエンジニアの[@ahiru](https://twitter.com/ahiru___z)です。

皆さんはアプリのパフォーマンス計測を行っていますか？

パフォーマンス計測はどのように行っていますか？

手法としては様々ありますが、近年Appleはこの分野に力を入れて取り組んでおりAppleの標準フレームワークであるMetricKitを使用するのも一つの手です。

Xcode11 / iOS13より登場したMetricKitはiOS14になって大きな進化を遂げましたが、おそらくあまり知られていない(?)と思いますので本稿でまとめていきます。

# Xcode 11 と iOS 13 で追加された機能の振り返り

Xcode12時代に突入している今日ではありますが、新機能の説明の前に簡単に振り返りをします。

Xcode11 と iOS13からは metrics に関する3つのツールが導入されました。

### XCTest Metrics

XCTest から直接メトリックスの収集を行えるようになりました。

[XCTPerformanceMetric](https://developer.apple.com/documentation/xctest/xctperformancemetric) というパフォーマンス計測のための metrics は Xcode9 から取得可能でしたが、Xcode11 からは [XCTMetric](https://developer.apple.com/documentation/xctest/xctmetric) という protocol が追加され、下記 [function](https://developer.apple.com/documentation/xctest/xctestcase/1496290-measure) によって cpu やメモリに関する metrics が取得できるようになりました。

```swift
func measure(metrics: [XCTMetric], 
       block: () -> Void)
```

XCTest Metrics は特定の機能の影響を見極めるのに有効です。

### MetricKit

アプリユーザーの使用状況(メトリックス)の収集を行うためのフレームワークです。

概要に関しては[こちらの記事](https://qiita.com/ahiru___/items/d794caae35ecfb4a1dfb)を読んでみてください！去年のアドベントカレンダーで書きました、、

端的に説明すると下記のようになります。

> MetricKitを使用すると、オンデバイスのアプリ診断や、システムがキャプチャした電力とパフォーマンスのメトリックスを受け取ることができます。登録されたアプリは、最大でも 1 日 1 回、過去 24 時間分のデータを含むレポートを受信します。
レポートのデータを使用して、アプリのパフォーマンスを向上させることができます。

なんと言っても、**アプリユーザーの環境での使用状況を詳細に把握することができる**というのが最大のメリットです。

実装方法については後ほどご紹介いたします。

### Metrics Organizer 

みなさんご存知の機能かと思いますが、ノンコードでOrgnizerから集約されたデータの確認ができるようになりました。
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122157/49384856-66f3-3de4-4423-7cc19df7d5d2.png)

# MetricKit の実装方法

```swift
import MetricKit

@main
class AppDelegate: UIResponder, UIApplicationDelgate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool) {
        MXMetricManager.shared.add(self)
        return true
    }

    func applicationWillTerminate(_ application: UIApplication) {
        MXMetricManager.shared.remove(self)
    }
}

extension AppDelegate: MXMetricManagerSubscriber {
    func didReceive(_ payload: [MXMetricPayload]) {
        // データを自社サーバーへ送信するなど
    }
}
```
基本的にたったこれだけで実装完了です。

##### 1. MetricKitをimport
##### 2. `MXMetricManager.shared.add` をアプリ起動時に実装
##### 3. `MXMetricManager.shared.remove` をteminate時に実装
##### 4. `didReceive` で metrics のデータを取得

実際に動かしてみると様々なmetricsが取得できます。(実機でのみテストが可能)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122157/f2721e25-e2f7-7f3a-e970-b1b5a5530059.png)

# iOS14からの MetricKit の新機能

ようやく本題です。

iOS14 で MetricKit は進化を遂げ、2つのアップデートがありました。

### 1. 取得できる metrics の種類が増えた

1つ目は取得できる metrics の種類が増えました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122157/9ee83f3b-78ca-85a3-0b7b-a114cd817761.png)
増えたのは、「CPU命令数」「スクロールヒッチ」「アプリケーションの終了理由」です。

#### CPU命令数
![スクリーンショット 2020-12-05 22.30.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122157/2c5288e8-3605-407a-acf1-75a4f164613e.png)
 
[MXCPUMetric](https://developer.apple.com/documentation/metrickit/mxcpumetric?changes=_3_8)は CPU の使用に関するメトリックを表すクラスです。

iOS13では使用したCPUの合計量のみが取得可能でしたが、iOS14からはCPUの命令総数が取得できるようになりました。

これの何が嬉しいかですが、CPU命令数はハードウェアや周波数に依存しないアプリケーションが行った作業の絶対的なメトリックと言えるのでアプリケーションの合計負荷をより正確に数量化できるようになります。

#### スクロールヒッチ
![スクリーンショット 2020-12-05 22.32.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122157/524243d9-9e6a-a4db-0970-d078f921ed57.png)
[MXAnimationMetric](https://developer.apple.com/documentation/metrickit/mxanimationmetric) はアプリ内のアニメーションの応答性に関する指標を表すクラスです。

スクロールの中ヒッチングに費やした時間の比率を取得できるようになったのですが、スクロールヒッチに関する詳しい説明はWWDC2020で発表された [Eliminate animation hitches with XCTest](https://developer.apple.com/videos/play/wwdc2020/10077) をご覧ください！

#### アプリケーションの終了理由
![スクリーンショット 2020-12-05 22.41.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122157/279a25c9-2cbc-cacb-a1c8-babbd037835c.png)
[MXAppExitMetric](https://developer.apple.com/documentation/metrickit/mxappexitmetric) はフォアグラウンドとバックグラウンドでのアプリの終了(kill)原因に関するメトリックを表すクラスです。

つまりアプリがなぜkillされたのか、その原因調査をすることがかなり容易になりました。
これはかなり大きなアップデートだと感じています。

この部分に関しては、WWDC2020のセッションの一つである [Why is my app getting killed?](https://developer.apple.com/videos/play/wwdc2020/10078/) をぜひみてください！

### 2. MetricKit診断

MetricKit Diagnostic(メトリックキット診断)と呼ばれるものが追加されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122157/dc613b57-01aa-4090-f96d-c562bf529bee.png)

iOS13では純粋に metrics を取得するだけだった MetricKit ですが、iOS14からは不具合の原因特定に役立つような情報も取得できるようになりました。

iOS13とiOS14を比較するとこんな感じです。

#### iOS13
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122157/7a34839d-f49c-9c18-d6c4-621f238c6596.png)

#### iOS14
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122157/66939802-0854-137b-16a5-b0b476925a7e.png)
metricsだけではなくクラッシュに関する情報なども取得できるようになります。

クラッシュに関してはcrashlyticsなどサードパーティ製ツールを使用することがほとんどかと思いますが、これがApple純正のフレームワークに置き換わる未来があるかもしれません。

# まとめ
- MetricKitはベータ版 / リリース版のアプリのパフォーマンスについてユーザーの環境ベースで様々なメトリックスを収集するためのフレームワーク
- (やりたいことにもよると思うが)基本的に実装は簡単
- 収集したメトリックスは自社サーバーやサードパーティ製ツールへ送信・蓄積して分析を行いアプリのパフォーマンス改善に役立てる(パフォーマンスのデグレに効果的)
- MetricKitはiOS14で進化しており今後主流となる可能性を秘めていると感じたが、現状は情報が極端に少なく実装方法など調べるのも一苦労