【PL/I学習|実務向け】ALIGNED属性を活用した「偽の共有(False Sharing)」対策とキャッシュ効率の最適化

導入

マルチプロセッサ環境におけるメインフレームの性能チューニングにおいて、スループットを劇的に低下させる要因の一つが「偽の共有(False Sharing)」です。これは、本来無関係なデータが同一のキャッシュライン上に配置されることで、プロセッサ間での不要なキャッシュ同期(キャッシュコヒーレンシ・トラフィック)が発生する現象です。本記事では、PL/IのALIGNED属性と明示的なパディングを組み合わせ、データ構造をキャッシュライン境界に整列させるテクニックを解説します。

基礎知識

CPUはメモリからデータを読み込む際、「キャッシュライン」と呼ばれる単位(一般的に64バイトや128バイト)で一括してキャッシュへロードします。もし、複数のスレッドが頻繁に更新する変数が、たまたま同じキャッシュライン上に隣接して存在していると、プロセッサAが変数を更新するたびに、プロセッサBのキャッシュラインが無効化されます。これにより、計算資源が同期処理に浪費されます。ALIGNED属性は、構造体のメンバーをメモリ境界に配置するようコンパイラに指示する属性で、これを利用してメモリレイアウトを制御します。

実装/解決策

解決策は、頻繁にアクセスされる変数をキャッシュラインの先頭に配置し、その後にダミー領域(パディング)を設けることで、他の変数と同一キャッシュラインに重ならないようにすることです。ALIGNED(64)のように大きな境界を指定するか、構造体の中にフィラー(Filler)を明示的に宣言します。

サンプルプログラム

以下は、PL/Iにおけるキャッシュラインを意識したデータ宣言の例です。

/ 共有データ構造の定義 /
DECLARE 1 SHARED_DATA ALIGNED,
/ 頻繁に更新されるカウンター /
2 COUNTER_A FIXED BIN(31) ALIGNED,
/ キャッシュライン(64バイト)へのパディング:
COUNTER_Aが他の変数とキャッシュラインを共有しないようにする /
2 FILLER_1 CHAR(60) INITIAL(”),

/ 別のプロセッサが更新するカウンター /
2 COUNTER_B FIXED BIN(31) ALIGNED,
/ 同様にパディングを配置 /
2 FILLER_2 CHAR(60) INITIAL(”);

/ 解説:
COUNTER_AとCOUNTER_Bが別々のキャッシュラインに配置されるよう、
合計64バイトになるよう調整しています。
これにより、COUNTER_A更新時のキャッシュ無効化がCOUNTER_Bに波及しません。 /

応用・注意点

注意点1:ハードウェア仕様の確認
対象となるメインフレームのCPUモデルによってキャッシュラインサイズ(64バイトまたは128バイトなど)が異なります。環境に合わせてパディング量を調整してください。

注意点2:メモリ消費量とのトレードオフ
パディングを多用すると、データ構造のメモリ占有量が増大します。大量のインスタンスを生成する場合、メモリ不足やキャッシュミス(今度はキャッシュ容量不足によるもの)を引き起こす可能性があるため、負荷試験による実測が不可欠です。

補足:モダン言語への移行
Javaの@ContendedアノテーションやGo言語の構造体パディングなど、現代の言語にもこの思想は引き継がれています。メインフレームからオープン系へロジックを移行する際は、単にコードを移植するだけでなく、こうした「物理的なメモリ配置の意図」を設計書から読み取り、ターゲット環境に合わせて再実装することが、高負荷システムにおける性能維持の鍵となります。

コメント

タイトルとURLをコピーしました