メインフレームの深淵:ALIGNとUNALIGNEDが語る「速度」と「密度」の哲学
やあ。今日もレガシーシステムの迷宮で、コードと格闘している諸君。
今日はPL/Iにおける「ストレージの最適化」という、一見地味だが、大規模バッチの性能を左右する極めて重要なトピックについて話そうと思う。
PL/Iという言語の面白いところは、予約語が事実上存在しないという懐の深さだ。しかし、その柔軟さゆえに、「何をどう定義するか」という設計者のセンスが、そのままシステムの実行効率に直結する。特に`ALIGN`と`UNALIGNED`の使い分けは、ベテランと若手を分かつ境界線の一つだ。
—
1. なぜ「境界調整(Alignment)」が必要なのか
まず、ハードウェアの視点を持とう。CPUがメモリ上のデータにアクセスする際、4バイトや8バイトの境界(バウンダリ)にデータが配置されていると、非常に効率よく読み書きができる。これが`ALIGN`の正体だ。
逆に、`UNALIGNED`は「詰め込み」を意味する。データ間の隙間を極限まで削り、メモリ使用量を節約する。しかし、その代償として、CPUはデータを読み取る際、わざわざビットシフトや複数回のメモリアクセスを行うことになる。
どちらを選ぶべきか?
- `ALIGN` (デフォルト): CPUのキャッシュ効率と命令サイクルを優先する。オンライン処理や、頻繁に計算に用いる数値変数には必須だ。
- `UNALIGNED`: メモリ消費量を削減する。特に大量のレコードをメモリ上にバッファリングするようなバッチ処理や、VSAMファイルのレコード構造定義(Copybookと合わせる場合)で重宝する。
—
2. 実践的なコーディング例:構造体の定義
現場でよく見かけるケースとして、VSAMファイルから読み込んだデータを構造体にマッピングする例を挙げよう。
1
/ —————————————————————– /
/ 構造体の境界調整による最適化の例 /
/ —————————————————————– /
DCL 1 ACCOUNT_RECORD UNALIGNED,
5 ACCOUNT_ID CHAR(10), / 固定長文字は詰め込まれる /
5 BALANCE BIN FIXED(31),
5 FILLER CHAR(2);
DCL 1 WORK_CALC_AREA ALIGN,
5 TEMP_VAL BIN FIXED(31), / 計算用変数はALIGNで高速化 /
5 WORK_FLAG BIT(8);
/ ビルトイン関数を利用したデータ操作 /
TEMP_VAL = BINARY(SUBSTR(ACCOUNT_RECORD.BALANCE,1,4), 31);
この例では、`ACCOUNT_RECORD`を`UNALIGNED`にしている。なぜか? ファイルレイアウトそのものが「隙間なし」で定義されているケースがほとんどだからだ。これを`ALIGN`で宣言してしまうと、コンパイラは勝手にパディング(隙間)を挿入し、ファイル上のオフセットと構造体のメンバ位置がズレてしまい、致命的なデータ破損を招く。
—
3. ONユニットとデータアクセスの落とし穴
次に、この設定が`ON`ユニットやI/O処理にどう影響するかを解説する。
`UNALIGNED`なデータに対して演算を行うと、PL/Iのコンパイラは動的に境界を合わせるためのコードを生成する。これが重なると、ループ処理の中でジワジワとCPU時間を食いつぶすことになる。「なぜかこのバッチだけCPU使用率が高い」という場合、構造体の属性と、ループ内で多用する数値変数の属性が不一致を起こしていないか確認することをお勧めする。
特に、`ON CONVERSION`ユニットが頻発している場合、境界調整の不備による不正なデータ読み込みが原因であることも多い。
1
/ 異常発生時のデバッグ用ONユニット /
ON CONVERSION
BEGIN;
PUT SKIP LIST (‘データ変換エラー発生:境界設定を確認せよ’);
STOP;
END;
—
4. 現場の教訓:マイグレーション時の心得
私が過去に手がけた大規模マイグレーションでは、従来のホスト環境から新プラットフォームへの移行時に、この`ALIGN`の挙動の違いで苦労したことがある。
1. 外部設計書を信じるな: 設計書に「詰め込み」と書いてあっても、実際のVSAMコピーブックがどうなっているか、`DUMP`コマンドで16進数を確認してくれ。
2. `UNALIGNED`を安易に使うな: メモリ節約は、物理メモリが潤沢な現代では優先度が低いことが多い。アクセス速度を優先するなら、デフォルト(`ALIGN`)に任せるのが安全だ。
3. キャストを恐れるな: `BINARY`や`DECIMAL`といったビルトイン関数を使い、明示的に型変換することで、コンパイラに「どう処理すべきか」を明確に指示するんだ。
結びに
PL/Iのコードは、書いた人間の「意図」をコンパイラに伝えるための手紙のようなものだ。`ALIGN`か`UNALIGNED`か。たった一つの属性だが、そこに諸君が「何を優先しているのか(速度か、空間か)」というエンジニアとしての矜持を込めてほしい。
もし、デバッグ中に不可解な挙動に出会ったら、まずはコンパイラの生成リスト(`LIST`オプション)を出力し、変数がメモリ上でどう配置されているかを確認してみよう。機械は嘘をつかない。嘘をつくのは、いつだって仕様を読み違えた人間の方なのだから。
さて、コーヒーでも飲んで、次のモジュールのコンパイルを通しに行こうか。また何かあれば、いつでも相談してくれ。
