euphonictechnologies’s diary

Haskell超初心者の日記です。OCamlが好きです。

follow us in feedly

Swift - Swift1.2のコンパイラの最適化

Swiftの言語仕様が新しくなってたのはSwift 1.2というやつだったらしい

そうだとは知らずにまた開発者に告知もなく言語仕様を変えやがったのかと思っていました。アップグレードならまあ、仕方ない。

blog.euphonictech.com

で、私が一番期待しているのは言語仕様ではありません。これ以上開発者を混乱させる一貫性のないシンタックスシュガーはいりません。僕の考えた最強のプログラミング言語は好きなんですが、選択肢が他にあっての話だから。毎日チーズ入りハンバーグとかうまいけど死ぬぞ。アンダース・ヘルスバーグ氏を招いたほうがいいのではないか。

参考資料

一番わかり易い公式ブログです。2画面ぐらいにまとめてあって字も大きくてわかりやすいです。

developer.apple.com

リリースノート。開発者の人しかアクセス出来ないみたいです。

developer.apple.com

ちょっとおしゃれチックなプレゼン付きブログポストです。こういうプレゼンってカリフォルニアあたりで流行ってるんですかね。

blog.human-friendly.com

これもアップグレードまとめのブログポストです。

www.raywenderlich.com

変更点

  • コンパイラはすごい早くなったよ。
  • インクリメンタルビルドするよ。

  • as!は実行時に失敗する可能性がある動的キャストをするときに使えよ!

  • letの使いようがすごく広がったよ。例えばif letで複数のnullablesをパターンマッチできたりするし(スゴイ気持ち悪いif文が書けるよ!)、すぐに初期化しないでもif文で分岐する中で初期化時代入してuse文で初期化完了を教えてあげたりするんだよ!
if a = somethingA && b = somethingB, let c = somethingOptionalInteger where c > someThreshold {
...
}

let x: SomeThing
if condition {
  x = foo()
} else {
  x = bar()
}
use(x)
  • SourceKitのクラッシュが減ったよ!
  • 型チェッカが修正されてだいぶ"too complex!"エラーが減ったよ!

らしいです。発展途上なので、これからも頑張って欲しいです。私達にもはやObjective-Cに戻るという選択肢は(あんまり)ありません。Objective-C++の利点といえば初期化指定子ぐらいです(ComponentKitで使われています。参考:

componentkit.org )

"私はコンパイラの最適化に興味があります"

私が一番期待しているのはコンパイラの最適化具合です。書いているオセロプログラムが(とんちんかんなメモリ管理の犠牲になって)とんでもなく遅いので、ここを何とかしてほしいと思っています。

最適化をコードに施して、実際に数字を拾って比較するのは面倒なので、リリースノートに書いてある効きそうなこと、効いてそうなことを感覚ベースで記録に残しておこうと思います。

私の作っているFlat ReversiNegaAlpha探索のコンピュータの思考スピードで速さ(もしくは遅さ)で体感してみます。

探索コードはものすごくタイトなforループの中にビット演算がたくさん入っています。

f:id:euphonictechnologies:20150415000422p:plain

  • Swift 1.1 時代のスピード : 深さ7の探索の場合、NPS(1秒間にサーチできたゲーム木のノードの数)

    • min 30,000 ~ max 300,000, だいたい中盤辺りのスピード150,000
  • Swift 1.2 時代のスピード : 同じく深さ7の探索の場合、NPS

    • min 65,000 ~ max 500,000, だいたい中盤辺りのスピード160,000

アップグレード前後で少し速くなったような感じがしたので、中盤辺りのスピードを測ってみました。トップスピードははっきりと上がっていることが感じ取れました。最適化の度合いは確かに上がっているらしい。最低値もほんのり上がっているようなので、全体的にスピードアップしていると言って良いと思います。全く使い物にならなかった深さ9の探索が1手1分ルールならなんとか動く感じになったので、速くなっていることが実感できます。

コンパイラのバージョンを上げただけで全体的にほんのりスピードアップしているのが嬉しいですね。まだまだ全然嬉しいスピードじゃないですが。

これでも一部のコードをCで書いてスピードを稼いでいるのですが、まだまだです。

新しく導入された最適化のうち私が気になるもの

  • Whole Module Optimization

これは-whole-module-optimizationをコンパイラのフラグに追加することで、ファイルごとのコンパイルから全部ファイルをガッチャンコしてコンパイルしてくれるらしいです。当然インライン化に期待しちゃいます。ゲーム木探索なんかは相当の数の関数がすごく小さくてがんがんインライン化できますから、これには期待です。試したらアップデートします。

  • unsafeMutableBuffer

これはアンセーフなデータタイプの一つで、こんな感じで使います。例えば1つArray、var array = [SomeObject];があるときに

array.withUnsafeMutableBufferPointer{ ( inout pArrayBuffer:UnsafeMutableBufferPointer<SomeObject> -> () in
...
    // Can read value from pArrayBuffer
    // or can write value from pArrayBuffer
    pArrayBuffer[i + 10] = <...something...>;
    // But no boundary check. If you access outside of the boundary, the behaviour is undefined. Be careful!
...
}

こんな感じ?ブロックの中ではポインタ直触りできます。エロいですね。Haskell触ってるとこういうコードはCとインタラクトするためによく書きますね。当然境界チェックが走らないので速いです。

  • あとはメソッドをfinalで宣言してダイナミックディスパッチを出来る限り避ける

これでしょうか。当然ダイナミックディスパッチは遅いので避けたいです。finalでダイナミックディスパッチが必要ないことをコンパイラに教えてあげることができます。文脈からクラスが同定できるとき、そしてそのメソッドがfinalの時、ダイナミックディスパッチは必要ないはずです。型推論に任せるとSwiftの型推論器が弱っちょろいのもあってダイナミックディスパッチされるかもしれないので、スピードセンシティブな所では型宣言すべきでしょう。

朗報としてはprivateもfinal扱いでちゃんとコンパイラがよきに計らってくれます。なのでprivateは大正義です。がんがんprivateしましょう。2015年なので継承なんてほとんど必要ないはずです、ハーブ・サッターも言っていたように思います。

パフォーマンス関係のとても役に立つ参考資料

公式ブログのパフォーマンス周りの詳説です。ダイナミックディスパッチを出来る限り避ける方法と、そのWhole Module Optimizationとの関わりについて書かれています。

developer.apple.com

Swiftのパフォーマンスについて詳しい方のブログポストです。

blog.human-friendly.com

unsafeMutableBuffer関係の資料です。

blog.human-friendly.com

Swift, C libraries, and Mapping Swift types to C pointer&nbsp;typestetontech.wordpress.com

owensd.io

final周りの話です。

blog.human-friendly.com

長いですが必読です。Swiftのパフォーマンス周りのことがたくさん書いてあります。

mikeash.com: Friday Q&A 2014-07-04: Secrets of Swift's Speed