【実務・中級編】UNALIGNED属性が構造体レイアウトに与える影響 – PL/Iの基本構文とデータ制御実践ガイド

おい、最近あちこちの現場で「オープン系への移行」だの「COBOLからJavaへ」だのという威勢のいい掛け声が飛び交っているが、我々が日々向き合っているこの巨大なIBMメインフレームの心臓部では、今もなお高密度で洗練されたPL/Iのバッチ群が、何百万件ものトランザクションを黙々と処理し続けている。

その中でも、データ構造の設計、特にメモリレイアウトの制御は、バッチの実行時間を秒単位で削り、スプール溢れやアベンド(ABEND)を防ぐための職人技が試される領域だ。

今回は、PL/Iのデータ制御における隠れた曲者であり、かつ強力な武器でもある「UNALIGNED属性」について、構造体レイアウトに与える影響と実務でのトレードオフを徹底的に紐解いていこう。

1. 境界調整(Alignment)というメインフレームの宿命

まずは基本のおさらいだ。IBM System/z(現z/Architecture)のCPUは、メモリ上のデータを読み書きする際、そのデータ型に応じた「自然境界(Natural Boundary)」に合致している方が効率よくアクセスできる。

  • 半ワード(2バイト)整数 (`FIXED BIN(15)`): 2の倍数のメモリアドレス
  • フルワード(4バイト)整数 (`FIXED BIN(31)`): 4の倍数のメモリアドレス
  • 倍精度浮動小数点(8バイト): 8の倍数のメモリアドレス

PL/Iコンパイラは、デフォルトではパフォーマンスを最優先するため、構造体内の各メンバがこの自然境界に綺麗に乗るように、自動的に「パディング(意味のない空き領域・隙間)」を挿入する。これが ALIGNED属性(デフォルト) だ。

しかし、ここで現場のエンジニアが直面する現実がある。「外部ファイル(VSAMやQSAM)のレコードレイアウトや、他システムから送られてきた電文レイアウトと1バイト単位で一致させなければならない」という要件だ。ここでデフォルトのALIGNEDが効いていると、勝手に挿入されたパディングのせいでオフセットがズレ、データがズタズタになる。

ここで登場するのが UNALIGNED属性 である。

2. UNALIGNED属性がもたらす「メモリ節約」と「代償」

構造体全体、あるいは個別のメンバに `UNALIGNED` を指定すると、コンパイラはパディングの挿入を一切行わなくなる。

メリット:強烈なメモリ節約とレイアウトの一致

  • 外部インターフェースの完全一致: COBOLの `PIC X(10)` のあとに `PIC S9(4) COMP` が続くような、パディングを許さない密なレコードレイアウトを完全に再現できる。
  • メモリフットプリントの削減: 大規模な配列を持つ構造体などでは、パディングが消えることで数メガバイト単位のメモリ(および仮想ストレージ)を節約できる。

デプロイの代償:アクセス速度のトレードオフ(CPU負荷増大)

もし奇数アドレスや境界を跨ぐ位置に `FIXED BIN(31)` が配置された場合、CPUはそれを1回の機械語命令(Lなど)でロードできなくなる。コンパイラは、その変数を読み書きするために、内部で複数のシフト命令やマスク命令を生成してアライメントを調整する。
これが、いわゆる「アンアラインド・アクセスによるパフォーマンス劣化」だ。現代のz/Architectureはハードウェアレベルでアンアラインド・アクセスをかなり高速に処理してくれるようになったが、大規模バッチで何億回もループする処理であれば、確実にCPU時間の肥大化(SRB/TCB時間の増加)として跳ね返ってくる。

3. 実践:PL/Iコードで見るUNALIGNEDの挙動

百聞は一見にしかず。実際のメインフレーム開発を想定した、構造体定義とVSAMレコード入出力のサンプルコードを見てみよう。ここでは、全社共通の顧客マスタ(VSAM KSDS)からレコードを読み込み、フィールドを操作するバッチプログラムの一部を抜粋する。

/ —————————————————- /
/ 顧客マスタ・アンアラインド構造体定義サンプル /
/ —————————————————- /
CUST_BATCH_PRC: PROC OPTIONS(MAIN);

/ — 1. 外部ファイル(VSAM)定義 — /
DCL CUST_FILE FILE RECORD SEQUENTIAL INPUT
ENV(FB BLKSIZE(27920) LRECL(280));

/ — 2. 構造体定義:UNALIGNED属性の適用 — /
/
【重要】外側、あるいは個別に UNALIGNED を指定することで、
コンパイラによるパディングを抑制し、LRECL(280) の物理レイアウトと
完全に同期させる。
/
DCL 1 CUST_RECORD UNALIGNED,
5 CUST_ID FIXED BIN(31,0), / 4バイト: 顧客番号 /
5 CUST_NAME CHAR(40), / 40バイト: 顧客名 /
5 CUST_TYPE CHAR(1), / 1バイト: 顧客種別 /
/ ここで通常ならパディングが3バイト入るが、UNALIGNEDにより排除 /
5 CUST_REG_DATE FIXED BIN(31,0), / 4バイト: 登録日(YYYYMMDD) /
5 CUST_BALANCE FIXED DEC(15,2), / 8バイト: 預金残高 /
5 FILLER CHAR(222); / 予備領域 (計280バイト) /

Dcl EOF_FLG BIT(1) INIT(‘0’B);
Dcl READ_CNT FIXED BIN(31,0) INIT(0);

/ 終了条件(ON-UNIT)の定義 /
ON ENDFILE(CUST_FILE) EOF_FLG = ‘1’B;

/ ファイルオープン /
OPEN FILE(CUST_FILE);

/ メインループ /
DO WHILE(^EOF_FLG);

READ FILE(CUST_FILE) INTO(CUST_RECORD);

IF EOF_FLG THEN LEAVE;

READ_CNT = READ_CNT + 1;

/ — 3. ビルトイン関数とデータ制御の例 — /
/ 顧客種別が ‘A’ かつ残高がマイナスの顧客を検知するビジネスロジック /
IF CUST_TYPE = ‘A’ & CUST_BALANCE < 0 THEN DO PUT SKIP EDIT ('ALERT: CUSTOMER ID = ', CUST_ID, ' BALANCE = ', CUST_BALANCE) (A, F(10), A, F(12,2)); END; END; CLOSE FILE(CUST_FILE); PUT SKIP EDIT ('TOTAL READ RECORDS = ', READ_CNT) (A, F(10)); END CUST_BATCH_PRC;

コードのポイント解説

1. `UNALIGNED` キーワードの指定位置:
上記では `1 CUST_RECORD UNALIGNED` と一括で指定している。これにより、配下のすべてのメンバ(`FIXED BIN` や `FIXED DEC` を含む)に対して再帰的にアライメント調整が無効化される。大規模な電文レイアウトやファイル定義では、この一括指定がコーディングミスを防ぐ鉄則だ。
2. ビルトイン関数の活用とパフォーマンス:
ループ内で使用している算術比較や文字列操作は、メインフレームのコンパイラ(IBM Enterprise PL/I)が高度に最適化する。しかし、`UNALIGNED` が指定された `FIXED BIN(31)` に対する頻繁な演算は、アライメント違反を回避するための内部処理が挟まるため、純粋な演算速度だけで言えば `ALIGNED` に一歩譲る。このトレードオフを意識して設計することが、アーキテクトの腕の見せ所だ。

4. ベテランからの実務アドバイス:トラブルを防ぐための極意

最後に、現場で後輩によく言い聞かせている「ハマりどころ」をいくつか伝授しておこう。

  • 構造体のパラメータ渡し(BYVALUE / BYADDR)の罠:

サブルーチンや外部関数に `UNALIGNED` な構造体やメンバを `BYADDR`(デフォルト)で渡す分にはアドレスがそのまま渡るが、ポインタ経由や異言語(C言語やCOBOLなど)連携の際にアライメントの差異でデータ化けを起こすことがある。インターフェース仕様書を過信せず、必ずストレージ・ダンプ(CEEDUMPやSYSUDUMP)を採取して実メモリ上のオフセットを目視確認する習慣をつけろ。

  • 「とりあえず全部UNALIGNED」は悪手:

「レイアウトが狂うのが怖いから全部UNALIGNEDにしておけ」という安易な設計は、バッチ全体のCPU使用量を無駄にハネ上げる原因になる。外部ファイル入出力や外部電文とバインドする「境界上の構造体」だけに `UNALIGNED` を適用し、内部のワーキングストレージ用構造体は極力 `ALIGNED`(またはデフォルト)で設計するのが、高パフォーマンスなメインフレームシステムの定石だ。

PL/Iは古い言語などではない。マシンの物理特性(メモリとCPU)を極限まで手懐けることができる、極めてスパルタンで美しい言語だ。この `UNALIGNED` の挙動一つをとっても、ハードウェアとソフトウェアの対話を楽しめるようになってこそ、一人前のメインフレーム・アーキテクトと言える。

さあ、今日のバッチジョブのJCLとシミュレーション結果を確認しに行こうか。

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