Skip to content

並列シミュレーション ​

Celox は 1 つの設計を複数スレッドで評価できます。コンパイル時に、組み合わせ回路の 評価(settle)と各クロックイベントの順序回路更新を、スレッドごとの レーン に分割し、 レーンを並行実行します。結果は逐次シミュレーションと常に一致します。

スレッドの有効化 ​

rust
use celox::Simulator;

let mut sim = Simulator::builder(code, "Top")
    .threads(4)
    .build()?;
typescript
const sim = await Simulator.create(module, { threads: 4 });

threads は呼び出し元スレッドを含む数です。threads(4) ではワーカースレッドを 3 つ起動します。既定値の 1 では逐次カーネルのみをコンパイルします。

効果が出る場合 ​

1 サイクル内に独立した処理が多い設計で効果があります。たとえばデータパスの 多数のインスタンス、幅の広い複製ロジック、大きなレジスタ群などです。1 サイクル あたり数百ナノ秒程度の同期コストが固定でかかるため、1 サイクルの処理がおよそ 1 マイクロ秒以下の小さな設計は速くなりません。

Celox は次の 2 段階で、並列化によって遅くなることを防ぎます。

  1. コンパイル時: 見積もった高速化が同期コストを上回るフェーズだけを分割し、 そうでないフェーズは逐次コードのままにします。
  2. 実行時: 分割したフェーズは最初の数十回の呼び出しで逐次版と実測比較し、 速い方を使い続けます。比較は間隔を倍々に広げながら再実行されるため、 マシンが混雑していた時の判断も後で修正されます。

測定は通常のシミュレーションの一部として行われるため、結果は変わりません。 1 回の測定のコストは遅い方の実装を数十回実行する分だけです。

スレッド数の選び方 ​

  • 物理コア数以下にしてください。レーン間の待ち合わせはスピンで行うため、 SMT の兄弟スレッドやコアの過剰割り当ては全体を遅くします。
  • 最適化レベルと同様に、同じ入力とサイクル数で 実際のワークロード全体を測定してください。
  • スレッドを増やして効果があるのは、各レーンに 1 サイクルあたり十分な処理が 残っている間だけです。

並列化されるフェーズ ​

フェーズ分割
組み合わせ回路の評価(eval_comb)あり
1 つのクロック/リセットイベントの順序回路更新あり
同時に発火する複数クロックドメイン、カスケードクロック逐次
ネイティブの comb + FF 融合ティックループ分割フェーズの方が速い場合に置き換え

$display やアサーションなどのランタイムイベント、クロックイベントを発火しうる ストアの順序は、逐次シミュレーションとまったく同じに保たれます。

バックエンド ​

並列実行はネイティブの x86-64・AArch64 バックエンドと Cranelift で利用できます。 WebAssembly バックエンドとインタプリタは常に逐次実行です。外部インタフェース向けの ネイティブ force サポートを有効にした場合も逐次実行になります。

メモリ配置 ​

各レーンの状態は、キャッシュライン境界に揃えガードバイトで区切った専用の メモリセグメントに置かれます。そのため、設計上複数レーンが書くオブジェクト (たとえば同じ配列の別要素)を除き、レーン同士が同じキャッシュラインに書き込む ことはありません。設計の詳細は 並列実行 を 参照してください。