Slide 1

Slide 1 text

継続的にアプリ パフォーマンスを計測する iOSDC Japan 2020 kariad

Slide 2

Slide 2 text

自己紹介 ● kariad / 片山大樹 / @kariad_uu ● DeNA > SWET > Automation test iOS team ○ Software Engineer in Test ● ソフトウェアテスト、それを支えるプロセス改善

Slide 3

Slide 3 text

じめに 今回 発表で 、SWETで取り組んでいるアプリ パフォーマンス計測について話しま す パフォーマンス計測に関する知見 多く なく、試行錯誤しながら作っていったため、失 敗もたくさんあります そうした失敗や今 こうしているといった知見を紹介できたらと

Slide 4

Slide 4 text

アジェンダ 1. なぜパフォーマンス計測が必要な か? 2. iOSアプリにおけるパフォーマンス計測方法 3. 継続して計測する仕組み 作成 4. 運用してみて 5. これからについて

Slide 5

Slide 5 text

なぜパフォーマンス計測が必要な か?

Slide 6

Slide 6 text

アプリ パフォーマンスが悪いと ひとくちにパフォーマンスと言っても様々 ● なかなか読み込みが終わらない ● 短時間 利用で端末が熱くなる ● 動作が重い、カクカク、もっさり 場合によって パフォーマンスが悪いことでクラッシュも起こりうる

Slide 7

Slide 7 text

アプリ パフォーマンスが悪いと ユーザーがアプリを快適に利用できない →ユーザー 離脱 可能性 防ぐために リリース前に機能が正しく実装されているかだけで なくパフォー マンス観点でもテストを行い、問題ないかを確認できると良い

Slide 8

Slide 8 text

iOSアプリにおけるパフォーマンス計測

Slide 9

Slide 9 text

iOSアプリにおけるパフォーマンス計測 代表的な例 ● Instruments ● MetricKit ● 外部(Apple以外が提供している)サービス ど ような情報が取れるか、ど ように情報が取れるか、計測タイミングなど 異なる

Slide 10

Slide 10 text

Instruments ● Xcode 一部として提供されているパフォーマンス計測ツール ● どこ パフォーマンスが悪い か分析、特定する機能をサポート ● TimeProfiler, Leaks, Network等多く テンプレートを持ち様々な角度から 計測 が可能 ● 原因 特定 dSYMがあれ 実際 コード どこ 部分かというところまで特定で きる

Slide 11

Slide 11 text

Instruments Templateが充実していて選ぶだけで簡単に計測ができる

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Instruments GUIだけで なくCUIからでも計測が可能 instruments -t ${template} -w ${UDID} -l ${timeLimit} -D ${fileName}

Slide 14

Slide 14 text

Instruments GUIだけで なくCUIからでも計測が可能 instruments -t ${template} -w ${UDID} -l ${timeLimit} -D ${fileName} ※保存時に少し時間がかかる で注意 template名(e.g. Time Profiler) 計測に利用する端末 UDID 計測時間 上限(ms) 保存時 ファイル名 (xxx.trace)

Slide 15

Slide 15 text

MetricKit ● iOS13から利用可能 ● 実際にコードに埋め込んでデバイス上 情報を取得できる ● 起動時間、CPU使用時間、バッテリー消費量、クラッシュなど ● ユーザ 環境で計測し、24時間に一回サーバにデータが送られる WWDC セッションによるとMetricKitを用いてTestFlight ベータテスターや実際 ユーザー 手元で何が起こっているかを計測するべきだと述べられている 詳しく知りたい方 WWDC 2020 「What’s new in MetricKit」がおすすめ https://developer.apple.com/videos/play/wwdc2020/10081/

Slide 16

Slide 16 text

外部サービス SDKとして組み込んで計測するタイプ ● Firebase Performance Monitoring デバイスファームとセットになったサービス ● HeadSpin → 計測できる指標 サービスによりけり

Slide 17

Slide 17 text

継続して計測する仕組み

Slide 18

Slide 18 text

継続的な計測 ● 常に安定したアプリをリリースするに 悪くなってからで 遅い ● そ ために継続的にパフォーマンス計測が行える仕組みが必要 ○ 継続して計測することで改善も実施しやすくなる ● 毎回手動で実施する 大変な で自動で実施したい

Slide 19

Slide 19 text

今回計測したかった内容 Pocochaで視聴者が多い配信で 端末 温度上昇とそれに伴うパフォーマンス低下が 問題になっていた そ ため一定時間負荷をかけ続けたアプリ 状態を配信/視聴画面まで移動してから計 測対象とした ● 計測時間: 30分, 2時間 ● 計測内容: CPU使用率と端末 温度(Thermal state) 変化 ● 計測タイミング: 毎晩

Slide 20

Slide 20 text

継続的な計測で必要と考えたも ● 計測ツール ● 最新 アプリ ● 実機 ○ 計測する内容にもよるが、端末 温度など 実機でしか計測ができない ● 定期的に実行させるため 環境(CIサービス) ● アプリを操作するUIテスト ● アプリに負荷をかけるツール

Slide 21

Slide 21 text

計測ツール Instrumentsを採用 ● すでにパフォーマンスが問題になり始めているということもありリリース前、開発中 に問題ないかを確認したかった ● 問題がある場合 早く原因を特定したい ○ InstrumentsならdSYMがあれ 原因まで調査できる

Slide 22

Slide 22 text

最新 アプリ 毎日 変更に追従した最新 アプリで計測(場合によって 任意 ブランチなど) デバッグ用にdSYMも必要なためCIでArtifactsとして残す必要 さらにInstrumentsで正しく計測するために 以下 条件を満たす必要がある ● コンパイラ 最適化を実際 releaseビルドと合わせる ● development 証明書でsignしている

Slide 23

Slide 23 text

最新 アプリ コンパイラ 最適化 問題 ● Xcode デフォルト 設定で debugビルドとreleaseビルドで最適化 設定 異 なっている ● 最適化 差異がパフォーマンス計測に影響がでる可能性がある ● 実際にユーザが利用するreleaseビルドと同等 最適化がされたアプリで計測する 必要がある ● WWDC 2019 Getting Started with Instrumentsセッションが参考になる ○ https://developer.apple.com/videos/play/wwdc2019/411/

Slide 24

Slide 24 text

最新 アプリ signする証明書 問題 ● Instrumentsで計測するために development certificateでsignしたも でなくて いけない(配布用で 計測できない) release 最適化設定を利用しながらdevelopmentでsignが必要

Slide 25

Slide 25 text

最新 アプリ ipa resign ● ipaに対して証明書を付け替えることができる ● releaseでビルドしたipaに対してdevelopment 証明書でresignできる ● fastlane resignを利用 ○ https://docs.fastlane.tools/actions/resign/

Slide 26

Slide 26 text

最新 アプリ fastlane resign resign( ipa: ipa_path, signing_identity: "iPhone Developer: Xxxxxx Xxxxxxx(FFFFFFFFF)", provisioning_profile: { "com.swet.app" => provisioning_profile_path, "com.swet.app.notificationservice" => provisioning_profile_notification_path }, display_name: "SWET Debug" )

Slide 27

Slide 27 text

最新 アプリ fastlane resign resign( ipa: ipa_path, signing_identity: "iPhone Developer: Xxxxxx Xxxxxxx(FFFFFFFFF)", provisioning_profile: { "com.swet.app" => provisioning_profile_path, "com.swet.app.notificationservice" => provisioning_profile_notification_path }, display_name: "SWET Debug" ) resign後 identity(今回 例で release→development な でdevelopment を記載) 左側に今signしているBundle identifier(今回 release) 右側にresignするProvisioning profile path 後からわかるようにdisplay nameも変えられる

Slide 28

Slide 28 text

実機 Thermal stateを計測するために実機で 計測が必要 ● 自前で管理 コストが高い ○ テストが走っているタイミングで他 テストが走らないようにする排他制御が必要 ○ OS バージョン管理 ○ 場所も取る ○ 問題が発生したときに出社が必要

Slide 29

Slide 29 text

実機 クラウド型 デバイスファーム Web等から実際 実機と同じようにアクセス、操作できるサービス ● AWS Device Farm ● Remote Testkit ● HeadSpin

Slide 30

Slide 30 text

HeadSpin 様々なパフォーマンス計測もできるデバイスファーム 端末単位 契約で端末を他社と共有すること ない ● Xcodeから直接Runができる ● Wi-Fiだけでなく特定 SIMで4G回線で 利用もできる ● 実機でできる大体 こと できる ● AppiumサーバーがHeadSpin側で用意されている 今回計測 Instrumentsを使うことにした でHeadSpin 機能 使っていない(将来的 に計測項目が増えた際に使いたいと 思っている)

Slide 31

Slide 31 text

HeadSpin Appiumについて 補足 Appiumクライアント Appiumサーバー Web driver agent テストスクリプト テスト対象アプリ 端末 Appium動かすに ここが必要

Slide 32

Slide 32 text

HeadSpin

Slide 33

Slide 33 text

HeadSpin APIも充実していて例え ● ipa インストール、アンインストール ● スクリーンショット 撮影 ● デバイス ロック、アンロック ● OSアップデート ポップアップを消す 等々、他にも色々ある

Slide 34

Slide 34 text

HeadSpin Appiumから利用する場合 ● Capability server_urlにHeadSpin側に表示されるURLをセットするだけで Appiumサーバーを立てずに利用できる(UDID等 必要) ● Appium DesktopからもHeadSpin Web Driver URLをセットするだけで利用できる ● Appium バージョンもCapabilityから指定できる(インストールされていない場合 お願いしたらすぐ対応してくれる)

Slide 35

Slide 35 text

HeadSpin Appium以外から利用する場合 ● HeadSpin CLIを使ってbridgeする ● XcodeからRunできる、Instrumentsで計測もできる

Slide 36

Slide 36 text

CI 今回 計測で 2種類 用途がある ● 計測対象 アプリをビルド、resignする ● 計測を行う(負荷ツールを動かす) 元々Bitriseを利用していた でビルド Bitriseで問題ない 計測 最大2時間を想定していたためBitriseで 不可能(現時点 最大 90分) → 色々やりたいと考えるとひとまず選択肢として Jenkins

Slide 37

Slide 37 text

CI Jenkins ● Jenkins自体 管理が必要 → SWET CI/CDチームが管理してくれているJenkinsに相乗り Xcode 新しいバージョンも簡単にインストールできる仕組みが整っている (Jenkinsに詳しいメンバーが周りにいる で困ったら気軽に質問できる) ただし最終的に 脱Jenkinsを考えて いる

Slide 38

Slide 38 text

アプリ操作用 UITestフレームワーク 目的 画面までアプリ 操作が必要 ● Appium x Ruby(RSpec) ● XCUITest HeadSpinを利用する予定だった でAppiumサーバーを用意する必要がなく、Appium が相性が良かった AppiumからInstrumentsを利用することもできた も◯

Slide 39

Slide 39 text

Appium Insturmentsで 計測がAppium コード経由で実行することができる # Rubyで 例 # 計測開始 @driver.start_performance_record( timeout: ENV['TIMEOUT'], profile_name: 'Time Profiler' ) # 計測完了 @driver.get_performance_record( save_file_path: "fine_name", profile_name: 'Time Profiler' )

Slide 40

Slide 40 text

Appium Capabilityで 注意点 ● 実機 場合 bundleId 指定が必須 ● 待ちが発生するためnewCommandTimeout 設定をしてTimeoutを防ぐ ● HeadSpin Appiumサーバーを利用する場合 serverUrlに設定する

Slide 41

Slide 41 text

アプリに負荷をかけるツール 必ずしも必要なも と 限らないが、今回 要件で 必要だった ● SWET 他チーム(Goチーム) メンバーと協力して作成 ● 変更が入った場合でも常に最新 も を利用するためGitHub Release Assets からDLできるように

Slide 42

Slide 42 text

こ 構成で起きた問題 必要なも すべて揃った、後 組み合わせるだけ... そう上手いこといくわけ なかった 起きた問題 一例として ● Appium server 問題 ● Instruments データ取得 問題

Slide 43

Slide 43 text

Appium server 問題 最初Appium server HeadSpin も を使う想定だった いくつか 理由からAppium serverをJenkins上で持つ形に ● Xcode バージョン ● traceファイル 保存先 Appium serverをHeadSpin側 も を利用するということ 、Instruments バージョン (Xcode バージョン)も向こうに依存してしまう 新しくしたりビルドと合わせたりと柔軟性がほしかった

Slide 44

Slide 44 text

Appium server 問題 traceファイル 保存先 Instrumentsで 計測自体 HeadSpin サーバーで実行されている → traceファイルを転送する必要がある ● 転送先を考える必要性 ○ 転送 仕組み自体 Appiumで実装されている Xcode バージョン 問題とを考慮してJenkins上でAppium serverを建てる方法を採 用 → HeadSpin 端末 み 利用に

Slide 45

Slide 45 text

Instruments 問題 Instruments 問題点として計測結果を定量的な数値で取得する方法がない (実際に ある程度とれるも * あったがこ 時点で 存在 知らなかった) そ ため、結果 確認 Instruments appを開いてGUIで結果を確認する必要がある ● 30分 計測ともなるとファイルサイズ(150〜200MB程度)も大きく、開く に時間が かかる ○ 1分くらいかかることも ... ● 毎回手動で結果を確認する かなり面倒 *TraceUtility(https://github.com/Qusic/TraceUtility )

Slide 46

Slide 46 text

Nominal → Fair → Serious → Critical

Slide 47

Slide 47 text

Nominal → Fair → Serious → Critical 各state 開始時間と終了時間が表示される

Slide 48

Slide 48 text

CPU使用率 推移 グラフで み表示される 詳細に表示される ど 処理が何%CPUを利用しているか グラフ 最大値がそ 回 一番使用率が高い値になってしまう (全く同じグラフだったとしても同じ使用率と 限らない)

Slide 49

Slide 49 text

Instruments 問題 XCUITestを用いた強引な解決策 ● XCUITest Instrumentsを操作することもできる ● XCUITestでtraceファイルを開いてThermal stateとCPU使用率 部分でスクリー ンショットを撮影、Slackに投稿させた ● Thermal stateについて 文字列で 情報も取れるためSeriousまで行ったら失敗 させるといったこともできる ● CPU使用率について 厳しかった

Slide 50

Slide 50 text

Instruments 問題 Slackへ 投稿

Slide 51

Slide 51 text

検討した上で 今回 構成 ● 計測ツール: Instruments(Appiumから利用) ● 最新 アプリ: Bitriseでビルド ● 実機: HeadSpin ● CI(計測): Jenkins ● アプリ操作用 UITestフレームワーク: Appium ● 負荷をかけるツール: お手製 複数 ツールに跨っていて終わったら次、といった感じにピタゴラスイッチみたいにに なってしまった

Slide 52

Slide 52 text

Bitrise 1. releaseビルドでipaを生成 2. development証明書でresign

Slide 53

Slide 53 text

Bitrise 5. Jenkins jobトリガーAPIを実行 Jenkins 3. dSYMをArtifacts化 HeadSpin 4. HeadSpin APIを使ってipaを配布

Slide 54

Slide 54 text

Bitrise 7. 負荷ツール DL、Appiumサー バー 起動等 準備 Jenkins HeadSpin 6. HeadSpin 端末に接続 Appium サーバー

Slide 55

Slide 55 text

Bitrise 8. 計測開始 9. 計測完了 Jenkins HeadSpin Appium サーバー

Slide 56

Slide 56 text

Bitrise 10. traceファイルをXCUITestで操作 して結果を取得 Jenkins HeadSpin Appium サーバー trace ファイル

Slide 57

Slide 57 text

Bitrise 11. traceファイル Artifacts化 12. 結果 Slackへ 投稿 Jenkins HeadSpin Appium サーバー

Slide 58

Slide 58 text

処理 流れ(概要) 1. Bitriseでreleaseビルドでipaを作成 2. ipaに対してdevelopment証明書でresign 3. 最終的なipaをHeadSpinにAPI経由で配布、dSYMをArtifacts化 4. BitriseからJenkins トリガー実行 5. Jenkinsで負荷ツール DL、起動、HeadSpinへ 接続等 準備 6. 計測開始 7. 計測完了 8. 結果 traceファイルをXCUITestを用いて結果 SSを撮影 9. 結果をSlackに通知、traceファイル等 Artifacts化

Slide 59

Slide 59 text

そしてJenkinsfileが長くなる 処理が多くJenkinsfileがどうしても長くなってしまう で可読性等 が低い 前述 流れ 中でさらにいろいろやっている デバッグもしづらくメンテナンスがしづらい問題 ある

Slide 60

Slide 60 text

実際に運用してみて

Slide 61

Slide 61 text

実際に運用してみて 実際に運用をしていく中で想定していた問題や、新たな問題が発生 ● Appium 不安定さ ● 実行パターン 増加 ● 季節 ● インカメラへ 利用 ● 結果確認 方法

Slide 62

Slide 62 text

Appium 不安定さ 負荷をかけ続けた状態で一定時間経つと、connection errorが発生する 最後 最後でInstrumentsが完了できないということも ● 本来 使い方で ない で仕方が無いといえ 仕方がない かもしれない ● Appium serverとクライアントで通信をしながら操作しているため起きた問題かも ● 詳細な原因 わからずじまい

Slide 63

Slide 63 text

Appium 不安定さ 採用理由がHeadSpinでAppiumサーバーが用意されていて便利だったから HeadSpin Appium serverを利用しなくなった時点でAppiumである必要性がほぼなく なっていた → であれ XCUITestでもいい で ないか ● 現在 XCUITestに移行済み ● InstrumentsもCUIで実行している

Slide 64

Slide 64 text

実行パターン 増加 最初 1パターンx2(30分, 2時間)で 計測 新機能追加に伴う色々な状態で 計測が求められるように ● 端末温度が上昇するためそ まま次を計測してしまうと、前回 結果に引きづられ る正しい計測ができない ● 環境にもよるが、最低でも30分 間隔を空けないと実機で前回 影響を受けずに 正しい計測 できない

Slide 65

Slide 65 text

実行パターン 計測 クールタイム 計測 計測 クールタイム 計測 端末A 端末B 端末数を増やして対応(ど 端末が何分待ったかという調整 必要)

Slide 66

Slide 66 text

季節 外部気温 変化によるThermal stateへ 影響 ● 実装時 冬〜春 ● 運用中に夏に ● 同じ条件でも外部気温 影響でより やく端末温度 上昇が起きた ただこれ ユーザーにも同じことが言えるため、夏でも問題ないようにパフォーマンスを 良くするべき

Slide 67

Slide 67 text

インカメラ 利用 計測パターンでインカメラに人 顔を写した状態で計測する必要が出てきた HeadSpin 場合 同一 端末を契約単位で利用している インカメラに特定 画像を写し続けるといった特別な対応も行ってくれる → HeadSpin おかげで解決

Slide 68

Slide 68 text

結果確認フロー 問題 Slackに投稿していると いえCPU使用率に関して 実際に開いてみないとわかりづら い問題がや りある ● 結果として毎回100MB超え ファイルをDLして、起動に時間がかかり...を手動で チェックする必要があった ● CPU使用率に関して GUIですら明確な数値が出せない ● グラフも最大値に合わせて上下してしまう ○ 定量的に判断が難しい ● まだ未解決

Slide 69

Slide 69 text

運用した結果 変更 ● 計測ツール: Instruments CLI ● 最新 アプリ: Bitriseでビルド ● 実機: HeadSpin(端末数が増えた) ● CI(計測): Jenkins ● アプリ操作用 UITestフレームワーク: XCUITest ● 負荷をかけるツール: お手製 そ 他細かいところ 調整している

Slide 70

Slide 70 text

これから 展望

Slide 71

Slide 71 text

xctrace Xcode12からInstrumentsコマンドがdeprecatedとなりxctraceが追加された ● 基本的にInstrumentsコマンドでできていたこと できる ● traceファイルからXML形式でデータが取得可能 ● Thermal stateが取得できること 確認済み ● CPU使用率について 現時点で 難しいかもしれない

Slide 72

Slide 72 text

Bitrise(MacStadium)へ 移行 当初2時間で 計測も考えていたが、今 30分 計測 みに変わった ● 結果として90分制限に縛られなくなったためBitriseへ 移行も考えている ● Instrumentsで 計測にそれなり スペックがないと不安定な でそこだけ心配 一方でJenkinsもオンプレからMacStadiumへ移行している ● Mac miniを借りれるクラウド ● MacStadiumだと再起動が出社なしで可能

Slide 73

Slide 73 text

他項目 計測 今計測している項目以外でも計測したいも が出てきている そ ため現在、FPSなど 新たな項目で 計測 準備をしている そちら Big Queryにデータを入れてData studio等で可視化を検討している こ パフォーマンス計測もそこに合わせてデータを可視化したい

Slide 74

Slide 74 text

さいごに 今回紹介した計測方法 あくまでも一例 アプリ 特性や何を計測したいかでも変わってくる アプリ 特性にもよるが、パフォーマンスがまだ問題になっていない であれ MetricKitから導入してみる がいいかもしれない そこから改善 サイクルを回していきましょう

Slide 75

Slide 75 text

DeNA Tech Twitter アカウントで 、 DeNA エンジニアリングに関する 登壇資料やブログを紹介しています! 後日ブログで紹介しきれなかったところを書く でそ 告知もあります

Slide 76

Slide 76 text

ありがとうございました!