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




             id:maoe
id:maoe

青江光敏
http://d.hatena.ne.jp/maoe/
http://github.com/maoe
  Keepalived.confの文法チェッカ

Haskell歴は4年
id:maoe

青江光敏
http://d.hatena.ne.jp/maoe/
http://github.com/maoe
  Keepalived.confの文法チェッカ

Haskell歴は4年
  興味を持ったきっかけは、2005年のLLDNでsakai
  さんの発表が全く意味不明だったこと
内容は
プログラミングモデルの話はすっ飛ばして
GHC 6.12.1の並列ランタイム性能改善の元となったと思
われる論文”Runtime Support for Multicore Haskell”か
ら
5分では時間がない(つっこまれると答えられない)ので
要点を絞って
 GHCのスレッドモデル
 並列ランタイムの仕組み
 最適化の試みを少しだけ
GHCのスレッドモデル
                                                 とても軽い
a `par` b                                         スパーク
                                                 (sparks)

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


                                                  CPU数と
./a.out                                          同数程度の
  +RTS -N                                       重いOSスレッド
                                                  (worker
                                                  threads)

            CPU #0   CPU #1   CPU #2   CPU #3
並列ランタイムの仕組み
       Haskell                     HEC #2               HEC #3         HEC #4
     Execution
     Context #1
       (HEC)

●   An ownership field   ●   An ownership field   ...            ...
●   An message queue     ●   An message queue
●   A run queue              ...
●   An allocation area
●   GC remembered
    set
●   A spark pool
●   A worker pool




        CPU #0                     CPU #1               CPU #2         CPU #3
並列ランタイムの仕組み
       Haskell
     Execution
                         Haskell Execution Context (HEC)
     Context #1
       (HEC)               CPUごとに一つ作られる
●   An ownership field       +RTS -Nで指定する数だけ作られる
●   An message queue
●   A run queue
                           worker threadがHaskell threadを実
●   An allocation area     行するのに必要なデータを持っている
●   GC remembered
    set                    “Capability”とか”virtual
    A spark pool
                           processor”とも呼ばれる
●



●   A worker pool




        CPU #0
並列ランタイムの仕組み
       Haskell
                         Haskellスレッドの実体はThread State Object
     Execution
     Context #1          (TSO)というヒープに割り当てられたデータ構造
       (HEC)
                           15 words + sizeof stack + αで小さい
●   An ownership field
                           run queueに入っているのをHECが順次round-
●   An message queue
●   A run queue
                           robinで実行していく
●   An allocation area   parで作られるsparkはspark poolに入る
●   GC remembered
    set                    システムの負荷が高くないときに、GCを生き延
    A spark pool
                           びた一部のsparkのみspark threadが作られ並列
●



    A worker pool
                           評価される
●




                           つまり必ず並列評価されるわけではない
        CPU #0
並列ランタイムの仕組み
       Haskell
     Execution           HECのライフサイクル
     Context #1
       (HEC)              message queueのメッセージを処理
●   An ownership field    run queueのスレッドを走らせる
●   An message queue
●   A run queue           spark poolにsparkが入っていれば
●   An allocation area
                          spark threadを起動し実行
●   GC remembered
    set
                          HEC内でなくglobalな、black hole
●   A spark pool
●   A worker pool         poolをpollingして、いずれかのスレッ
                          ドが実行できるようになったら実行

        CPU #0
最適化の例
HEC間のspark poolの共有をpushモデルから、work stealing
queueというロックフリーなデータ構造を使うようにした
並列GCの改善
 並列コピー式GCでimmutableなオブジェクトを扱うときは同期処理をしな
 いように変更した
 remembered setをHECごとに用意して局所性を高めた
 ここでもwork stealing queueを使うことでGCのロードバランスをやめ、
 局所性を高めた

Control.Parallel.Strategiesを使うときに起こるメモリリーク問題
を解消した
ThreadScopeが活躍したみたい
 どのタイミングでどのHECが頑張っていたのか一目瞭然
まとめというより所感

純粋関数型は簡単に並列化できるとは言うもの
の実際に効率的なプログラムにするのは大変
 ラインタイムをこつこつと計測して、こつこつと
 チューニング
 GCなどに他の言語でも利用されている技術を適用
 Strategy周りはもう少し勉強が必要

速度向上と環境整備でHaskellの並列プログラミ
ングが一般的になっていくといいな
参考文献
Runtime Support for Multicore Haskell
  (たぶん)GHC 6.12.1に取り込まれた改良に関する論文
Multicore Haskell Now! ACM Reflections
  par/pseqを使った並列プログラミングに始まり、並行プロ
  グラミング、STM、データ並列までマルチコアを活用する
  ための仕組みを一通り解説
  サンプルコードが豊富
GHC Commentary
  ちょっと情報が古いかもしれないけど参考になる
GHC 6.12.1
マルチコア対応ランタイムシステム
      について




             id:maoe

                   1
id:maoe

青江光敏
http://d.hatena.ne.jp/maoe/
http://github.com/maoe
  Keepalived.confの文法チェッカ

Haskell歴は4年




                              2
id:maoe

青江光敏
http://d.hatena.ne.jp/maoe/
http://github.com/maoe
  Keepalived.confの文法チェッカ

Haskell歴は4年
  興味を持ったきっかけは、2005年のLLDNでsakai
  さんの発表が全く意味不明だったこと

                                 3
内容は
プログラミングモデルの話はすっ飛ばして
GHC 6.12.1の並列ランタイム性能改善の元となったと思
われる論文”Runtime Support for Multicore Haskell”か
ら
5分では時間がない(つっこまれると答えられない)ので
要点を絞って
 GHCのスレッドモデル
 並列ランタイムの仕組み
 最適化の試みを少しだけ

                                            4
GHCのスレッドモデル
                                                 とても軽い
a `par` b                                        スパーク
                                                 (sparks)

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


                                                  CPU数と
./a.out                                          同数程度の
  +RTS -N                                       重いOSスレッド
                                                  (worker
                                                  threads)

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

                                                        5
並列ランタイムの仕組み
       Haskell                     HEC #2               HEC #3         HEC #4
     Execution
     Context #1
       (HEC)

●   An ownership field   ●   An ownership field   ...            ...
●   An message queue     ●   An message queue
●   A run queue              ...
●   An allocation area
●   GC remembered
    set
●   A spark pool
●   A worker pool




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

                                                                                6
並列ランタイムの仕組み
            Haskell
          Execution
                              Haskell Execution Context (HEC)
          Context #1
            (HEC)               CPUごとに一つ作られる
     ●   An ownership field       +RTS -Nで指定する数だけ作られる
         An message queue
                                worker threadがHaskell threadを実
     ●



     ●   A run queue
     ●   An allocation area     行するのに必要なデータを持っている
     ●   GC remembered
         set                    “Capability”とか”virtual
         A spark pool
                                processor”とも呼ばれる
     ●



     ●   A worker pool




             CPU #0

                                                                 7




- 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用
   のプール
並列ランタイムの仕組み
       Haskell
     Execution
                         Haskellスレッドの実体はThread State Object
     Context #1          (TSO)というヒープに割り当てられたデータ構造
       (HEC)
                           15 words + sizeof stack + αで小さい
●   An ownership field
                           run queueに入っているのをHECが順次round-
●   An message queue
●   A run queue
                           robinで実行していく
●   An allocation area   parで作られるsparkはspark poolに入る
●   GC remembered
    set                    システムの負荷が高くないときに、GCを生き延
    A spark pool
                           びた一部のsparkのみspark threadが作られ並列
●



    A worker pool
                           評価される
●




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

                                                              8
並列ランタイムの仕組み
       Haskell
     Execution           HECのライフサイクル
     Context #1
       (HEC)              message queueのメッセージを処理
●   An ownership field    run queueのスレッドを走らせる
●   An message queue
●   A run queue           spark poolにsparkが入っていれば
●   An allocation area
                          spark threadを起動し実行
●   GC remembered
    set
                          HEC内でなくglobalな、black hole
●   A spark pool
●   A worker pool         poolをpollingして、いずれかのスレッ
                          ドが実行できるようになったら実行

        CPU #0

                                                      9
最適化の例
HEC間のspark poolの共有をpushモデルから、work stealing
queueというロックフリーなデータ構造を使うようにした
並列GCの改善
 並列コピー式GCでimmutableなオブジェクトを扱うときは同期処理をしな
 いように変更した
 remembered setをHECごとに用意して局所性を高めた
 ここでもwork stealing queueを使うことでGCのロードバランスをやめ、
 局所性を高めた

Control.Parallel.Strategiesを使うときに起こるメモリリーク問題
を解消した
ThreadScopeが活躍したみたい
 どのタイミングでどのHECが頑張っていたのか一目瞭然
                                               10
まとめというより所感

純粋関数型は簡単に並列化できるとは言うもの
の実際に効率的なプログラムにするのは大変
 ラインタイムをこつこつと計測して、こつこつと
 チューニング
 GCなどに他の言語でも利用されている技術を適用
 Strategy周りはもう少し勉強が必要

速度向上と環境整備でHaskellの並列プログラミ
ングが一般的になっていくといいな
                           11
参考文献
Runtime Support for Multicore Haskell
  (たぶん)GHC 6.12.1に取り込まれた改良に関する論文
Multicore Haskell Now! ACM Reflections
  par/pseqを使った並列プログラミングに始まり、並行プロ
  グラミング、STM、データ並列までマルチコアを活用する
  ための仕組みを一通り解説
  サンプルコードが豊富
GHC Commentary
  ちょっと情報が古いかもしれないけど参考になる

                                         12

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