BEAM は SMP(マルチコア) 環境と非 SMP 環境では動作が大きくことなります。SMP環境と非SMP環境に分けてスレッド構成を記載します。
調査対象の OTP のバージョンは R16B03-1です。
非SMP環境
Erlang Interactive Shell を起動する際に、オプションとして '-smp disable' を付与すると、CPUはSMPでも、BEAMとしては非SMPモードで起動できます。
'erl -smp disable' で起動すると、11個のスレッドが見つかりました。11スレッドの内訳は以下のようになります。
スレッド名 | 関数名 | 個数 |
---|---|---|
Main Thread | process_main | 1 |
Async Thread | async_main | 10 |
Main Thread
BEAM byte-code を解釈し、実行するスレッドです。Erlang プロセスをスケジュールします。
Async Thread
Erlang プロセスによるファイル操作を非同期に行います。プロセスが file モジュールを通じてファイルの読み書きや開閉を行うと、Main Thread に代わってAsync Threadがそれらの処理を請け負います。byte-code を解釈実行する Main Thread の動作を止めないために、処理を肩代わりしているのです。スレッドの起床は futex()システムコールでおこないます。
Async Thread の個数は erl 起動時に '+A' オプションで変更できます。例えば、'erl +A 5' とすると、Async Thread は5個になります。ちなみに riak はデフォルトで64個起動します。
SMP環境
SMP環境では些か構成が複雑になります。オプションなしで erl を起動すると、論理4core(物理2core)環境では19スレッドできました。内訳は以下になります。
スレッド名 | 関数名 | 個数 |
---|---|---|
Main Thread | erts_sys_main_thread | 1 |
Signal Handling Thread | signal_dispatcher_thread_func | 1 |
System Message Handling Thread | sys_msg_dispatcher_func | 1 |
Async Thread | async_main | 10 |
Child Waiting Thread | child_waiter | 1 |
Scheduling Thread | sched_thread_func | 4 |
Aux Thread | aux_thread | 1 |
Main Thread
非SMP環境とは異なり、Erlang プロセスの実行はしません。単にシグナルを受信して、pipe経由でSignal Handling Thread に通知するだけのスレッドです。select(0, NULL, NULL, NULL, NULL) で待ちぼうけです。
Signal Handling Thread
シグナルハンドラ本体です。Main Threadが受信したシグナルに相当するハンドラを起動します。erl 起動時に '+B' オプションでシグナル受信時の挙動を変更できます。例えば 'erl +B i' でブレークシグナルを無視するようになります。
System Message Handling Thread
システムメッセージのハンドラです。システムメッセージは、トレース情報の出力やプロセスの再開・中断等をリクエストする特殊なメッセージです。詳しくは sys module のドキュメントを参照ください。
Async Thread
非SMP環境と同様の非同期I/Oスレッドです。
Child Waiting Thread
「OTP-3906 : Solaris で子スレッドが大量に終了した際、 SIGCHLD がうまく伝わらない問題」を修正するため、子スレッドの終了を waitpid() で待ち受けます。
Scheduling Thread
process_main() を実行し、 byte-code 解釈実行、プロセススケジューリングを行います。デフォルトでは論理コアと同じ数だけ生成されます。'+S' オプションでスレッド数を調整できます。他の Scheduling Thread と比較して負荷が偏らないようにバランシングとプロセスマイグレーションも行います。
Aux Thread
若干時間のかかる処理を受け持つ補助的なスレッドです。メモリアロケーションやGCの情報を取得する際等に、Scheduling Thread から処理をオフロードされます。例えば、'elrang:statistics(garbage_collection)' でのGC統計情報取得は、aux_threadで行われます。
通常 erl 起動時に作られるスレッドは以上ですが、他にも、NIF や driver 関係のスレッドがあります。
まとめ
・Erlang VM(BEAM)のスレッド構成はSMP/非SMPで大きく異なる
・Scheduling Thread の動作を阻害しないために、一部処理が他スレッドにオフロードされる
参考文献
Erlang User's Guide: erl
Erlang/OTP のソースコード (otp/erts)