24
GHC 6.12.1 GHC 6.12.1 マルチコア対応ランタイムシステム マルチコア対応ランタイムシステム について について id:maoe

GHC 6.12.1 マルチコア対応ランタイムシステムについて

Embed Size (px)

DESCRIPTION

2009年Haskell忘年会前哨戦

Citation preview

Page 1: GHC 6.12.1 マルチコア対応ランタイムシステムについて

GHC 6.12.1GHC 6.12.1マルチコア対応ランタイムシステムマルチコア対応ランタイムシステム

についてについて

id:maoe

Page 2: GHC 6.12.1 マルチコア対応ランタイムシステムについて

id:maoeid:maoe

青江光敏http://d.hatena.ne.jp/maoe/

http://github.com/maoe

Keepalived.confの文法チェッカ

Haskell歴は4年

Page 3: GHC 6.12.1 マルチコア対応ランタイムシステムについて

id:maoeid:maoe

青江光敏http://d.hatena.ne.jp/maoe/

http://github.com/maoe

Keepalived.confの文法チェッカ

Haskell歴は4年

興味を持ったきっかけは、2005年のLLDNでsakai

さんの発表が全く意味不明だったこと

Page 4: GHC 6.12.1 マルチコア対応ランタイムシステムについて

内容は内容は

プログラミングモデルの話はすっ飛ばして

GHC 6.12.1の並列ランタイム性能改善の元となったと思われる論文”Runtime Support for Multicore Haskell”から

5分では時間がない(つっこまれると答えられない)ので要点を絞って

GHCのスレッドモデル

並列ランタイムの仕組み

最適化の試みを少しだけ

Page 5: GHC 6.12.1 マルチコア対応ランタイムシステムについて

GHCGHCのスレッドモデルのスレッドモデル

CPU #3CPU #2CPU #1CPU #0

CPU数と同数程度の

重いOSスレッド(worker threads)

軽いHaskellスレッド(OSスレッドの100x以上軽い)

とても軽いスパーク(sparks)

a `par` b

forkIO a

./a.out +RTS -N

Page 6: GHC 6.12.1 マルチコア対応ランタイムシステムについて

並列ランタイムの仕組み並列ランタイムの仕組み

CPU #3CPU #2CPU #1CPU #0

HaskellExecution Context #1

(HEC)

HEC #2 HEC #3 HEC #4

● An ownership field

● An message queue

● A run queue

● An allocation area

● GC remembered set

● A spark pool

● A worker pool

● An ownership field

● An message queue

...

... ...

Page 7: GHC 6.12.1 マルチコア対応ランタイムシステムについて

並列ランタイムの仕組み並列ランタイムの仕組み

CPU #0

HaskellExecution Context #1

(HEC)

● An ownership field

● An message queue

● A run queue

● An allocation area

● GC remembered set

● A spark pool

● A worker pool

Haskell Execution Context (HEC)

CPUごとに一つ作られる

+RTS -Nで指定する数だけ作られる

worker threadがHaskell threadを実行するのに必要なデータを持っている

“Capability”とか”virtual

processor”とも呼ばれる

Page 8: GHC 6.12.1 マルチコア対応ランタイムシステムについて

並列ランタイムの仕組み並列ランタイムの仕組み

CPU #0

HaskellExecution Context #1

(HEC)

● An ownership field

● An message queue

● A run queue

● An allocation area

● GC remembered set

● A spark pool

● A worker pool

Haskellスレッドの実体はThread State Object

(TSO)というヒープに割り当てられたデータ構造

15 words + sizeof stack + αで小さい

run queueに入っているのをHECが順次round-

robinで実行していく

parで作られるsparkはspark poolに入る

システムの負荷が高くないときに、GCを生き延びた一部のsparkのみspark threadが作られ並列評価される

つまり必ず並列評価されるわけではない

Page 9: GHC 6.12.1 マルチコア対応ランタイムシステムについて

並列ランタイムの仕組み並列ランタイムの仕組み

CPU #0

HaskellExecution Context #1

(HEC)

● An ownership field

● An message queue

● A run queue

● An allocation area

● GC remembered set

● A spark pool

● A worker pool

HECのライフサイクル

message queueのメッセージを処理

run queueのスレッドを走らせる

spark poolにsparkが入っていればspark threadを起動し実行

HEC内でなくglobalな、black hole

poolをpollingして、いずれかのスレッドが実行できるようになったら実行

Page 10: GHC 6.12.1 マルチコア対応ランタイムシステムについて

最適化の例最適化の例

HEC間のspark poolの共有をpushモデルから、work stealing

queueというロックフリーなデータ構造を使うようにした

並列GCの改善

並列コピー式GCでimmutableなオブジェクトを扱うときは同期処理をしないように変更した

remembered setをHECごとに用意して局所性を高めた

ここでもwork stealing queueを使うことでGCのロードバランスをやめ、局所性を高めた

Control.Parallel.Strategiesを使うときに起こるメモリリーク問題を解消した

ThreadScopeが活躍したみたい

どのタイミングでどのHECが頑張っていたのか一目瞭然

Page 11: GHC 6.12.1 マルチコア対応ランタイムシステムについて

まとめというより所感まとめというより所感

純粋関数型は簡単に並列化できるとは言うものの実際に効率的なプログラムにするのは大変

ラインタイムをこつこつと計測して、こつこつとチューニング

GCなどに他の言語でも利用されている技術を適用

Strategy周りはもう少し勉強が必要

速度向上と環境整備でHaskellの並列プログラミングが一般的になっていくといいな

Page 12: GHC 6.12.1 マルチコア対応ランタイムシステムについて

参考文献参考文献

Runtime Support for Multicore Haskell

(たぶん)GHC 6.12.1に取り込まれた改良に関する論文

Multicore Haskell Now! ACM Reflections

par/pseqを使った並列プログラミングに始まり、並行プログラミング、STM、データ並列までマルチコアを活用するための仕組みを一通り解説

サンプルコードが豊富

GHC Commentary

ちょっと情報が古いかもしれないけど参考になる

Page 13: GHC 6.12.1 マルチコア対応ランタイムシステムについて

1

GHC 6.12.1GHC 6.12.1マルチコア対応ランタイムシステムマルチコア対応ランタイムシステム

についてについて

id:maoe

Page 14: GHC 6.12.1 マルチコア対応ランタイムシステムについて

2

id:maoeid:maoe

青江光敏http://d.hatena.ne.jp/maoe/

http://github.com/maoe

Keepalived.confの文法チェッカ

Haskell歴は4年

Page 15: GHC 6.12.1 マルチコア対応ランタイムシステムについて

3

id:maoeid:maoe

青江光敏http://d.hatena.ne.jp/maoe/

http://github.com/maoe

Keepalived.confの文法チェッカ

Haskell歴は4年

興味を持ったきっかけは、2005年のLLDNでsakai

さんの発表が全く意味不明だったこと

Page 16: GHC 6.12.1 マルチコア対応ランタイムシステムについて

4

内容は内容は

プログラミングモデルの話はすっ飛ばして

GHC 6.12.1の並列ランタイム性能改善の元となったと思われる論文”Runtime Support for Multicore Haskell”から

5分では時間がない(つっこまれると答えられない)ので要点を絞って

GHCのスレッドモデル

並列ランタイムの仕組み

最適化の試みを少しだけ

Page 17: GHC 6.12.1 マルチコア対応ランタイムシステムについて

5

GHCGHCのスレッドモデルのスレッドモデル

CPU #3CPU #2CPU #1CPU #0

CPU数と同数程度の

重いOSスレッド(worker threads)

軽いHaskellスレッド(OSスレッドの100x以上軽い)

とても軽いスパーク(sparks)

a `par` b

forkIO a

./a.out +RTS -N

Page 18: GHC 6.12.1 マルチコア対応ランタイムシステムについて

6

並列ランタイムの仕組み並列ランタイムの仕組み

CPU #3CPU #2CPU #1CPU #0

HaskellExecution Context #1

(HEC)

HEC #2 HEC #3 HEC #4

● An ownership field

● An message queue

● A run queue

● An allocation area

● GC remembered set

● A spark pool

● A worker pool

● An ownership field

● An message queue

...

... ...

Page 19: GHC 6.12.1 マルチコア対応ランタイムシステムについて

7

並列ランタイムの仕組み並列ランタイムの仕組み

CPU #0

HaskellExecution Context #1

(HEC)

● An ownership field

● An message queue

● A run queue

● An allocation area

● GC remembered set

● A spark pool

● A worker pool

Haskell Execution Context (HEC)

CPUごとに一つ作られる

+RTS -Nで指定する数だけ作られる

worker threadがHaskell threadを実行するのに必要なデータを持っている

“Capability”とか”virtual

processor”とも呼ばれる

- ownership fieldは、どのworker threadがcapabilityを持っているか(実行中か)

- message queueは、他のHECからの要求を受け取るためのキュー。たとえば”スレッドTを起こして!”というような具合

- run queueは実行準備ができているスレッドのキュー- allocation areaは、HEC固有のアロケーション領域。ヒープは一つを共有するけど、固有のもあるらしい。

- GC remembered setsは?- spark poolはa `par` bとするときのaのサンクが入る- worker poolはスペアのworker threadとforeign call用のプール

Page 20: GHC 6.12.1 マルチコア対応ランタイムシステムについて

8

並列ランタイムの仕組み並列ランタイムの仕組み

CPU #0

HaskellExecution Context #1

(HEC)

● An ownership field

● An message queue

● A run queue

● An allocation area

● GC remembered set

● A spark pool

● A worker pool

Haskellスレッドの実体はThread State Object

(TSO)というヒープに割り当てられたデータ構造

15 words + sizeof stack + αで小さい

run queueに入っているのをHECが順次round-

robinで実行していく

parで作られるsparkはspark poolに入る

システムの負荷が高くないときに、GCを生き延びた一部のsparkのみspark threadが作られ並列評価される

つまり必ず並列評価されるわけではない

Page 21: GHC 6.12.1 マルチコア対応ランタイムシステムについて

9

並列ランタイムの仕組み並列ランタイムの仕組み

CPU #0

HaskellExecution Context #1

(HEC)

● An ownership field

● An message queue

● A run queue

● An allocation area

● GC remembered set

● A spark pool

● A worker pool

HECのライフサイクル

message queueのメッセージを処理

run queueのスレッドを走らせる

spark poolにsparkが入っていればspark threadを起動し実行

HEC内でなくglobalな、black hole

poolをpollingして、いずれかのスレッドが実行できるようになったら実行

Page 22: GHC 6.12.1 マルチコア対応ランタイムシステムについて

10

最適化の例最適化の例

HEC間のspark poolの共有をpushモデルから、work stealing

queueというロックフリーなデータ構造を使うようにした

並列GCの改善

並列コピー式GCでimmutableなオブジェクトを扱うときは同期処理をしないように変更した

remembered setをHECごとに用意して局所性を高めた

ここでもwork stealing queueを使うことでGCのロードバランスをやめ、局所性を高めた

Control.Parallel.Strategiesを使うときに起こるメモリリーク問題を解消した

ThreadScopeが活躍したみたい

どのタイミングでどのHECが頑張っていたのか一目瞭然

Page 23: GHC 6.12.1 マルチコア対応ランタイムシステムについて

11

まとめというより所感まとめというより所感

純粋関数型は簡単に並列化できるとは言うものの実際に効率的なプログラムにするのは大変

ラインタイムをこつこつと計測して、こつこつとチューニング

GCなどに他の言語でも利用されている技術を適用

Strategy周りはもう少し勉強が必要

速度向上と環境整備でHaskellの並列プログラミングが一般的になっていくといいな

Page 24: GHC 6.12.1 マルチコア対応ランタイムシステムについて

12

参考文献参考文献

Runtime Support for Multicore Haskell

(たぶん)GHC 6.12.1に取り込まれた改良に関する論文

Multicore Haskell Now! ACM Reflections

par/pseqを使った並列プログラミングに始まり、並行プログラミング、STM、データ並列までマルチコアを活用するための仕組みを一通り解説

サンプルコードが豊富

GHC Commentary

ちょっと情報が古いかもしれないけど参考になる