お手軽バッチ・パフォーマンス改善 – III
データセットのI/O効率を上げる(続き)
順次編成データセットのブロックサイズを最適化する
現在のz/OSでもそうですが、MVSは確かESAの頃からDCBのBLKSIZEに0を指定して新規データセットを割り振ると、ディスクのトラック長に応じてOS(DFP)が最適なブロック長をデータセットに設定してくれるようになりました。なので比較的新しいデータセットでは効率のよいブロック長になっていることが多いのですが、過去のJCLをそのまま流用していたり、これまでの慣習や何となくでブロック長を決めていたり、二十年以上も前から延々と運用で使われているようなデータセットの中には、比較的小さなブロックサイズが使われていたりします。昔のディスクのトラック長は今よりはるかに短かったのでその頃の名残が残っている例は少なからずあります。
右のグラフは、ブロック長が大きくなるにつれ(ブロック化因数が増えるにつれ)データセットのI/Oブロック数が減り、ジョブの実行時間が短くなっていくことを示しています。実行時間はブロック化因数10(BLKSIZE=5120)としたときのエラップ時間(実際にジョブがSTARTしてENDするまでの実経過時間)を1とした相対時間です。
非ブロッキング・データセットでは10レコード=1ブロックとした場合の実に6から7倍もの実行時間が必要です。I/Oブロック数は10倍多くなっていて、I/Oブロック数の多さがいかにパフォーマンスに影響するかを示しています。最適なブロックサイズではブロック化因数は54となり、ブロック化因数10の約5倍ですが、実行時間は半分から6割程度の削減で単純に反比例するわけではありません。それでも適当に決めたブロックサイズより最適なブロックサイズの方がパフォーマンス面でも十分効果があることを示していると言えるでしょう。
サンプル測定に使用したプログラムは単にデータセットのレコードを読み書きするだけで他の処理は何もしていませんので、ELAPに占めるCPU時間はほとんどデータセットのアクセスのために費やす時間です。I/Oブロック数の削減は同時にCPU使用量の削減にもつながることがわかります。レコードが大量に格納されているデータセットをアクセスして、全てのレコードに対して何らかの処理を行っているジョブ・ステップがある場合、そのデータセットのブロックサイズを改めて確認し、10KB未満の小さなサイズであればブロックサイズの最適化はパフォーマンス向上に寄与する価値があると言えるでしょう。
なおブロックサイズが大きくなるとアクセスする際に必要なメモリーも増えますがグラフのサンプルの場合は最も少ないメモリー量(非ブロッキングの場合)と最も大きなメモリー量(最適なブロックサイズの場合)の差は128KB程度でした。これはデータセット1つあたりの増加量です。複数のデータセットを同時にアクセスする場合はその数に応じてさらに必要ですが、z/OSのCOBOLプログラムならI/Oバッファーは16MBラインより上の拡張リージョンに作られますし、気にするほどのことはないでしょう。ただしMSPの場合はSAMのI/Oバッファーは16MBラインより下の基本リージョンにしか作れないので、今現在がギリギリのREGIONサイズで動いていれば注意が必要です。
左のグラフは、ブロック長が大きくなるにつれ(ブロック化因数が増えるにつれ)同じレコード数でも必要とするディスクスペース量が減っていくことを示しています。特に非ブロッキング・データセットを10レコード=1ブロックとしただけで半減しています。
着目して欲しいのはブロック長10240バイトのよりもより大きなブロック長20480バイトのときに、スペース量が増えてしまっていることです。これはディスクのトラック長と関係があります。3390ではトラックのユーザーデータ長は56,664バイトです。GAP長があるので単純ではありませんが、10240バイトのブロックなら1トラックに5ブロック書けます。1ブロックには20レコード入るので20*5で1トラックに100レコードが入ります。しかし20480バイトになると2ブロックしか書けません。ブロック長が倍になったので1ブロックには40レコード入りますがトラックには2ブロックしか書けないので40*2で1トラックには80レコードしか入りません。そのため格納効率が悪くなってしまうのです。
最適なブロックサイズとは単に大きくすればいいのではなく、トラックに無駄なく目一杯データを書けるサイズでかつOSのアクセス法が許す最大長である32760に最も近いサイズということになります。RECFM=FBでLRECL=512の場合、3390ディスクであれば27,648バイトが最適なブロックサイズです。
ブロックサイズは新規のデータセット作成であれば、JCLのDDステートメントにDCBパラメーターの追加で行うことができます。既存のデータセットの場合は、ICEGENERやDFDSSなどでコピーし直す方法があります。ただしアプリケーションプログラムの場合、プログラム内でブロック化因数の指定(COBOLの場合)やDCBマクロでBLKSIZE(ASMの場合)を指定してしまっているとJCLでのBLKSIZE=0では最適化サイズの設定ができません。BLKSIZEパラメーターにはLRECLに応じた最適値を明示的に指定する必要があります。
//SYSUT2 DD DISP=(,CATLG),DSN=dsname, // UNIT=SYSDA,VOL=SER=volnam,SPACE=(CYL,(500,100),RLSE), // DCB=(BLKSIZE=0) または DCB=(BLKSIZE=nnnnn)
//COPY EXEC PGM=ICEGENER //SYSPRINT DD SYSOUT=* //SYSUT1 DD DISP=SHR,DSN=origin dsname //SYSUT2 DD DISP=(,CATLG),DSN=new dsname, // UNIT=SYSDA,VOL=SER=volnam,SPACE=(CYL,(1000,200),RLSE) //SYSIN DD DUMMY // //MOVE EXEC PGM=ADRDSSU,REGION=4M //SYSPRINT DD SYSOUT=* //SYSIN DD * COPY DATASET(INCLUDE(origin dsname)) - OUTDY(newvol) REBLOCK(**) DELETE RECAT(*) //
ブロックサイズはSORTユーティリティーによるSORT処理のパフォーマンスにも影響を与えますが、z/OSのDFSORTの場合はSORTの入力データセットをSAMではなくEXCPによりトラック単位のI/Oを行うためブロックサイズによるパフォーマンスの違いは気にするほどありません。
テープの場合はトラック長というものはないので、ブロックサイズは32760に近いほど効率が上がります。それをさらに超えるものがLBIで、32760を超える長さのブロックサイズをサポートします。LBIの使用については各言語プログラム、各ユーティリティーおよびDFSMSのマニュアルを参照します。