39
Intel TSX HLE を触ってみた x86/x64最適化勉強会6 2013-08-31 星野喬@サイボウズ・ラボ / @starpoz 1

Intel TSX HLE を触ってみた x86opti

Embed Size (px)

DESCRIPTION

Intel TSX HLE の可能性を探るべく,いくつかのマイクロベンチマークで性能評価した.

Citation preview

Page 1: Intel TSX HLE を触ってみた x86opti

Intel TSX HLE を触ってみた

x86/x64最適化勉強会6 2013-08-31

星野喬@サイボウズ・ラボ / @starpoz

1

Page 2: Intel TSX HLE を触ってみた x86opti

自己紹介

•  星野 喬(@starpoz) – サイボウズ・ラボ

•  興味 – データベース,ストレージ,分散アルゴリズムなど

•  今の仕事: #walbdev – Linux における block device の効率的な 増分記録ドライバ •  http://developer.cybozu.co.jp/tech/?p=5130‎

2

Page 3: Intel TSX HLE を触ってみた x86opti

今日の話

•  Intel の最新 CPU (Haswell) の 新機能のひとつ TSX HLE を使い 性能評価をしてみて トランザクショナルメモリの可能性を探る

•  後追い実験大歓迎 J

3

Page 4: Intel TSX HLE を触ってみた x86opti

トランザクショナルメモリ (TM)

•  「Intel TSX について」参照 – http://www.slideshare.net/starpos/intel-tsx-

x86opti4

•  要約: atomic メモリアクセスを実現する技術 – 他と競合したくない一連のメモリアクセス – Lock-free な時代がすぐそこに(反論アリ

4

Page 5: Intel TSX HLE を触ってみた x86opti

Intel TSX

•  Transactional Synchronization eXtension •  2 つのインターフェースを提供 – HLE: Lock prefix の拡張で細粒度の排他を実現 – RTM: 制約はあるが HardwareTM そのもの

•  楽観的な振舞 •  CPU L1 キャッシュ上で必要なデータを管理 •  キャッシュライン単位での競合検出

5

Page 6: Intel TSX HLE を触ってみた x86opti

競合 (collision)

•  あるリソースへの複数主体からのアクセスが同時に起きること(要出典)

•  Intel TSX の場合: – リソース: キャッシュライン単位のメモリ領域 – 主体: スレッド – アクセス: read/write (全て read の場合を除く) – 同時: クリティカルセクションの実行期間が重複

6

Page 7: Intel TSX HLE を触ってみた x86opti

HLE: Hardware Lock Elision

•  楽観的挙動 –(失敗)à 悲観的挙動 •  失敗すると電気代が無駄になる

7

競合発生しないケース 競合発生するケース

ロックを無視して 投機実行開始

競合発生しなかった めでたしめでたし

競合発生 変更破棄 ロック待ち体制

ロック取れたので 必ず実行できる

時間 時間

Page 8: Intel TSX HLE を触ってみた x86opti

Spinlock with HLE

•  GCC 4.8 の場合 (マニュアル参照)

8

class SpinlockHle { private: char &lock_; public: explicit SpinlockHle(char &lock) : lock_(lock) { int flags = __ATOMIC_ACQUIRE | __ATOMIC_HLE_ACQUIRE; while (__atomic_exchange_n(&lock_, 1, flags)) _mm_pause(); } ~SpinlockHle() noexcept { int flags = __ATOMIC_RELEASE | __ATOMIC_HLE_RELEASE; __atomic_clear(&lock_, flags); } };

Page 9: Intel TSX HLE を触ってみた x86opti

HLE on/off の違い

9

--- t1.hle0.s 2013-08-31 09:23:58.000000000 +0900 +++ t1.hle1.s 2013-08-31 09:23:30.000000000 +0900 @@ -13,12 +13,12 @@ .L3: rep nop .L2: movl %edx, %eax - xchgb -1(%rsp), %al + xacquire xchgb -1(%rsp), %al testb %al, %al jne .L3 - movb $0, -1(%rsp) + xrelease movb $0, -1(%rsp) xorl %eax, %eax ret .cfi_endproc .LFE859:

Page 10: Intel TSX HLE を触ってみた x86opti

実験環境

•  CPU: Core i7-4770 – 4cores 8HT – HT 有効 – TurboBoost 有効

•  メモリ: 16GB •  OS: Ubuntu 13.04 x86_64 kernel 3.8.19 •  コンパイラ: GCC 4.8.1 – 最適化フラグ: -O2 のみ

10

Page 11: Intel TSX HLE を触ってみた x86opti

実験方法

•  スレッドを必要なだけ起動して,X 秒間クリティカルセクション (CS) を繰り返し実行

•  Spinlock を使って CS の排他を取る –  HLE 有効/無効は実験パラメータ – 終了判定のために CS 実行毎に atomic<bool> を load するオーバーヘッドあり

•  CS の実行回数の合計値を X で割ったものを スループットとする

•  上記実験を Y 回行い,スループットの avg, min, max を計算

11

Page 12: Intel TSX HLE を触ってみた x86opti

Experiments

•  Expr1: simple counter(s) •  Expr2: counter(s) with delay •  Expr3: collision timing •  Expr4: access area size •  Expr5: map operations

12

Page 13: Intel TSX HLE を触ってみた x86opti

Counter

Expr1: simple counter(s)

•  クリティカルセクションループ

•  パラメータ – 競合率 100%: counter を全スレッドで共有 – 競合率 0%: スレッド毎に counter を持つ

•  キャッシュラインが異なるように 64byte 毎に配置

13

Counter

競合率 100% 競合率 0%

Thread Thread

while (!isEnd_.load(std::memory_order_relaxed)) { SpinlockHle<useHLE> lk(mutex_); counter_++; }

Page 14: Intel TSX HLE を触ってみた x86opti

Expr1: result

14 10 sec, 20 trials

44.7x

spinlock なしの 8 threads 実行で 4309M なので, isEnd.load() のオーバーヘッドは 8% 程度

Page 15: Intel TSX HLE を触ってみた x86opti

Expr1: result (scaled)

15 10 sec, 20 trials

競合100% のときは オーバーヘッドの分 性能悪化

Page 16: Intel TSX HLE を触ってみた x86opti

Expr2: counter(s) with delay •  1us delay (誤差は実測 70ns 以下)

•  クリティカルセクション

16

void delayUsec(uint64_t usec) { auto ts0 = std::chrono::high_resolution_clock::now(); uint64_t diff = 0; while (diff < usec * 1000) { auto ts1 = std::chrono::high_resolution_clock::now(); diff = std::chrono::duration_cast< std::chrono::nanoseconds>(ts1 - ts0).count(); } }

while (!isEnd_.load(std::memory_order_relaxed)) { SpinlockHle<useHLE> lk(mutex_); counter_++; delayUsec(1); }

Page 17: Intel TSX HLE を触ってみた x86opti

Expr2: result

17 10 sec, 20 trials cs が 1us でも最大 5 倍程度の性能アップを期待できる

Page 18: Intel TSX HLE を触ってみた x86opti

Expr3:

•  1us delay の前/後にカウンタを更新する

•  目的 – 競合発覚するのが CS の最初か最後かで楽観的実行が失敗する頻度が変化するのを観察したい

18

while (!isEnd_.load(std::memory_order_relaxed)) { SpinlockHle<useHLE> lk(mutex_); if (isBefore) delayUsec(1); counter_++; if (!isBefore) delayUsec(1); }

Page 19: Intel TSX HLE を触ってみた x86opti

Expr3: result

19 10 sec, 20 trials

Page 20: Intel TSX HLE を触ってみた x86opti

Expr4:

•  目的 – write buffer や read flag を管理する領域は有限なので,HLE で恩恵が受けられるアクセスサイズの上限を知りたい

•  手段 – X 個の 64bytes メモリ断片をスレッド毎に用意 – CS の中で Y 個にアクセスする(重複アリ) – 他の条件を同じにするため,Y は固定 – 2 <= X <= Y で評価 – 今回は write の評価のみ

20

Page 21: Intel TSX HLE を触ってみた x86opti

Expr4: 1-4 thread 16 clines

21

1 threads 2 threads

3 threads 4 threads

10 sec, 20 trials CS 内では 12 lines までのアクセスにした方が良さそう

Page 22: Intel TSX HLE を触ってみた x86opti

Expr4: 5-8 thread 16 clines

22

5 threads 6 threads

7 threads 8 threads

10 sec, 20 trials 安定しない結果.12 lines を越えても効果があるケースも

Page 23: Intel TSX HLE を触ってみた x86opti

Expr4: 5-8 thread 64 clines

23

5 threads 6 threads

7 threads 8 threads

5 sec, 100 trials 安定しない結果,実験方法に問題があるかも?

Page 24: Intel TSX HLE を触ってみた x86opti

Expr5:

•  目的: – 実用的なデータ構造で HLE の効果を知る

•  手段: – std::map<uint32_t, uint32_t> をひとつの

spinlock で排他 –  read 比率を変える: 0%, 90%, 99%, 100%

•  read 操作: ランダムキーで lower_bound 検索 •  write 操作: ひとつ削除,その後 insert

– 初期アイテム数: 10K (約2MB), 1M (約100MB) – (ついでに自作の btree map でも試す)

24

Page 25: Intel TSX HLE を触ってみた x86opti

20131022追記

•  以下 expr5 の結果グラフのスループットは全て誤って 3 倍に集計されていたことが発覚 – 集計スクリプトのミス

•  スループットを見るときは表記の 1/3 にしてご覧ください

25

Page 26: Intel TSX HLE を触ってみた x86opti

Expr5: 10K items, read 0%

26

std::map はスレッド数増加で HLE on が逆転 性能上昇は最大で 39% (8 threads)

btree も同様の傾向

Page 27: Intel TSX HLE を触ってみた x86opti

Expr5: 10K items, read 90%

27

std::map では 2 threads 以上で HLE on が上回る. 最大46%性能Up (3 threads)

btree では傾向が安定しないが 概ね同程度と言える

Page 28: Intel TSX HLE を触ってみた x86opti

Expr5: 10K items, read 99%

28

std::map は最大 2.9 倍の性能 (3 threads)

btree も最大 2.4 倍の性能 (3 threads)

Page 29: Intel TSX HLE を触ってみた x86opti

Expr5: 10K items, read 100%

29

std::map は 6 threads で 7.4 倍 btree は 4 threads で 3.4 倍

Page 30: Intel TSX HLE を触ってみた x86opti

Expr5: 1M items, read 0%

30

3 threads 以上で HLE on の方が良い std::map 6.9% up (3 threads) btree: 7.3% up (3 threads)

Page 31: Intel TSX HLE を触ってみた x86opti

Expr5: 1M items, read 90%

31

std::map は 58% up (3 threads) btree は 54% up (3 threads)

Page 32: Intel TSX HLE を触ってみた x86opti

Expr5: 1M items, read 99%

32

std::map は 2.4 倍 (3 threads) btree は 2.4 倍 (3 threads)

Page 33: Intel TSX HLE を触ってみた x86opti

Expr5: 1M items read 100%

33

std::map は 2.6 倍 (4 threads) btree は 2.6 倍 (3 threads)

Page 34: Intel TSX HLE を触ってみた x86opti

Expr5: まとめ

•  性能向上 – 10K items で 最大 7.4 倍 (read 100%) – 1M items で 最大 2.6 倍 (read 100%)

•  現状の結論 – データがキャッシュに乗る程度に小さく read 比率が低いと HLE のオーバーヘッドが目立つ

•  考察 – critical section でより多くの操作をするケースも評価すべき

34

Page 35: Intel TSX HLE を触ってみた x86opti

HLE 評価まとめ

•  手間なしで性能が向上する魔法 – 楽観的挙動 à 悲観的挙動なので 性能最悪値を保証してくれるのも魅力

– デッドロックは従来通り気をつける必要あり

•  使うべき条件 – 条件1: 競合が起きにくい (read 比率が高い) – 条件2: クリティカルセクション実行時間が短い – 条件3: アクセス対象メモリが少ない

35

Page 36: Intel TSX HLE を触ってみた x86opti

今後の展望

•  HLE には条件分岐予測のように elision すべきかどうかを予測して性能向上させる余地があるのではないか? – 今回あまり調べてないので既にやってたらごめんなさい

•  RTMは? –  L1 のみならず,L2/L3 そしてメモリコントローラまで

TM のことを考えてくれるようになるまで様子見したい – 速度が重要じゃない用途なら STM と連動できるようになった時点で開発効率の点から有用なのではないか

36

Page 37: Intel TSX HLE を触ってみた x86opti

おまけ: 私の単体 CPU 購入歴

•  AMD K6-300 •  Intel Pentium II 333MHz •  AMD Athlon 64 3200+ •  AMD Athlon X2 BE-2400 •  AMD Phenom II X4 910e •  AMD Phenom II X6 1065T

•  こんな私が買う気になってるのだから Haswell は凄い!

37

Page 38: Intel TSX HLE を触ってみた x86opti

実験してみたい人へ

•  用意するもの – TSX サポート付きの Haswell CPU – Linux OS (古いものはオススメしない) – GCC 4.8 以降

•  ソースコード – https://github.com/starpos/hle_bench

38

Page 39: Intel TSX HLE を触ってみた x86opti

ありがとうございました

•  ご質問,コメントはご気軽にどうぞ J

39