Kotlin/NativeのiOSにおけるオーバーヘッド

 Kotlin/NativeのiOSにおけるオーバーヘッド

マイクロベンチマークを用いてKotlin/NativeのiOSにおけるオーバーヘッドを測定していきます。
(指摘があったので注釈)
測定はデバッグビルドで行いました。スプレッドシートにはリリースビルドでの結果も後日反映いたします。

A87027204ff57be1dadbf36a78a73c1b?s=128

Takaki Hoshikawa

March 27, 2019
Tweet

Transcript

  1. Kotlin/Nativeの iOSにおけるオーバーヘッド エムスリー株式会社 星川貴樹 @どこでもKotlin #7

  2. Profile - 星川貴樹 (@oboenikui) - エムスリー株式会社所属 (2017〜) - Androidエンジニア -

    この勉強会の運営やってます
  3. Contents - マイクロベンチマークの実行結果とその考察 - 相互運用におけるオーバーヘッド - ツール紹介 - まとめ

  4. ベンチマーク

  5. マイクロベンチマークについて - Swift, Kotlin/Nativeで同等の処理を書き、iOS端末 (第5世代 iPad)上で実行 - ベンチマークの測定側のコードも各言語で実装 - ベンチマークに用いるコードは、以下の記事のものを一部

    Kotlin/Native用に改変したものを使用 Kotlin's hidden costs - Benchmarks - SingleShotTime (一定回数回すのにかかる時間) で測定 https://github.com/oboenikui/kotlin-ios-benchmarks
  6. お詫び - Xcodeを昨日アップデートしたら (?) ベンチマークプロジェクトの ビルドが通らなくなったので確認中です - Xcodeに精通しているiOSエンジニアの方いらっしゃったら懇親会で こっそり話しかけてください

  7. 諸注意 - ベンチマーク結果は2019/03/27現在の最新バージョンによるもの - 今後最適化が進み速くなる可能性は十分あります - マイクロベンチマークの結果は鵜呑みにしすぎないで - for文など、ボトルネックとなる部分が別に存在する可能性も -

    特徴的な結果のみピックアップ - 全ての結果はこちらに
  8. ラムダ式 (クロージャ) の比較 inlineの有無についても比較 // no inline fun transaction(db: DB,

    body: ((DB) -> Int)): Int { db.beginTransaction() return try { val result = body(db) db.setTransactionSuccessful() result } finally { db.endTransaction() } } Kotlinコード Swiftコード
  9. ラムダ式 (クロージャ) の比較 inlineの有無についても比較 // inline inline fun inlineTransaction(db: DB,

    body: ((DB) -> Int)): Int { db.beginTransaction() return try { val result = body(db) db.setTransactionSuccessful() result } finally { db.endTransaction() } } Kotlinコード Swiftコード
  10. ラムダ式 (クロージャ) の比較結果 - Kotlin/Nativeのラムダ式は現状遅い - inline化できる場合はSwiftと謙遜ない - (同様にローカル関数も遅い) no

    inline (ops/ms) inline (ops/ms) Swift 14,517 18,912 Kotlin 3,005 16,985
  11. in (contains) の比較 IntおよびStringのRange内存在判定を比較 // 1..10 (local) fun isInOneToTenWithLocalRange(i: Int)

    = i in 1..10 // 1..10 (indirect) private val myRange get() = 1..10 fun isInOneToTenWithIndirectRange(i: Int) = i in myRange
  12. in (contains) の比較 IntおよびStringのRange内存在判定を比較 // Alfred..Alicia (local) fun isBetweenNamesWithLocalRange(name: String)

    = name in "Alfred".."Alicia" // Alfred..Alicia (constant) private val NAMES = "Alfred".."Alicia" fun isBetweenNamesWithLocalRange(name: String) = name in NAMES
  13. in (contains) の比較結果 - Kotlinは大体が遅い(おそらく最適化されていない) - containsを使う場合は定数化することが望ましそう 1..10 (local) (indirect)

    Alfred..Alicia (local) (constant) Swift 33,291 32,639 2,570 24,078 Kotlin 3,728 3,213 3,034 6,655
  14. forEachの比較 RangeのforEachをforEachメソッド、for文で比較 // method (1..10).forEach { blackHole.consume(it) }

  15. forEachの比較 RangeのforEachをforEachメソッド、for文で比較 // loop for (it in 1..10) { blackHole.consume(it)

    }
  16. forEachの比較 RangeのforEachをforEachメソッド、for文で比較 // loop w/ step for (it in 1..10

    step 1) { blackHole.consume(it) }
  17. forEachの比較結果 - Kotlinの方が圧倒的に速い!?? - BlackHoleの実装で差が出た? → 後述 method loop loop

    w/ step Swift 198 1,660 416 Kotlin 474 3,405 3,441
  18. ツール紹介

  19. AppCode (EAP) - 言わずと知れたSwift, Objective-Cを快適に書けるIDE - Kotlin/NativeプラグインもEAP版に提供中 - MPPを簡単に始められる! -

    stdlibのメソッドとかエラーになるのですが、そうならないノウハ ウをお持ちの方懇親会で教えてください!
  20. Hopper Disassembler - Intel, ARM, PowerPC向けバイナリの逆アセンブルツール - 個人ライセンスは ¥11,272 (時価)、無償トライアル版あり

    - アイコンがXcodeっぽいけど多分無関係 - C-likeな擬似コードに逆コンパイルする機能があるので、自分のよ うなアセンブリ読みたくないマンにも優しい - Kotlin/Native関連のバグ調査に使えそう
  21. Hopper Disassembler Control Flow Graph (tutorialより引用)

  22. Hopper Disassembler Pseudo-Code (tutorialより引用)

  23. 相互運用のオーバーヘッド

  24. SwiftからKotlinを呼ぶコード

  25. SwiftからKotlinを呼ぶコード 本来ここでコードとベンチマークを貼る予定だったのですが、Xcode アップデートでビルド & 実行ができなくなってしまいました とにかく何が言いたかったかと言うと……

  26. SwiftからKotlinを呼ぶコード 遅い!!!! !!!!!!!! (Swiftのクラス初期化が4,000 ops/msに対して Kotlinのクラスは1,400 ops/msくらいだった気がする)

  27. SwiftからKotlinを呼ぶコードを調べてみる アセンブリアレルギーでもHopperを使って簡単に辿れることを実演しま す

  28. まとめ - Kotlin/Native内で完結する処理は割と高速に動く - 現状速度を気にする場合は相互運用のコードに注意が必要 - Hopper便利