お手軽バッチ・パフォーマンス改善 – I
パフォーマンス・チューニングというと、とかくRMFレポートと格闘してPARMLIBのIPSやICSのパラメーターをいじる(z/OSではWLMのワークロードやサービスクラスの設定)というイメージがあります。
より細かい現状分析にはRMF(MSPではPDA)レポートなどを見ることは避けられませんが、ここではそんな高度(面倒)なことではなく、もっと身近なもので比較的お手軽にできるパフォーマンス・アップを考えてみます。
いろいろなアプローチがありますが、大きく分けるとCPU使用量を減らすかI/O効率を上げるかになります。
その他にも「待ち」を減らす、というのもあります。ジョブの多重度が上がるほど「待ち」はELAP時間(実行時間)に大きく影響します。CPUを10秒使う、I/Oを100000回行う、といった同じ処理を実行しても、そのジョブしか動かない場合ではELAP時間は30秒なのに、他に別の10ジョブが並行して動いているような場合では2分掛かる、という具合です。このような待ち時間の大小によるパフォーマンスのぶれを調整し、適切なリソース配分やプライオリティ調整をすることもチューニングの大切な作業です。しかしそれはこのトピックの目的とずれてしまうので機会を改めることとし、ここでは採り上げません。このトピックでは個々のジョブ・ステップ単独での効率アップについて見てみます。
アプリケーションプログラム自身が使うCPU使用量を減らす
CPUについてはプログラム論理の見直しで使用量を削減するのは、元がよほどひどいプログラムでない限りあまり大きな期待はできません。そういう箇所を見つける苦労の割りには効果が薄いです。現実的にはコンパイラーのオプション(OPTIMIZE)によって最適化されたコードを生成する、という感じでしょうか。最適化は実行コードとストレージ量の2つの観点によって行われます。
またコンパイラーで注意すべきことの1つとしてデバッグオプションの付けっぱなしがあります。何らかの理由で後から1本だけ直してテストしたものが、誤ってデバッグオプションが付いたまま運用されてしまったようなケースです。本来なら不要な命令を常に実行し続けることになります。何かあったときに調べられないと困るから、デバッグオプションははずせないという考え方もありますが、基本的には本番の運用では不要でしょう。
その他にもタイミングを取るためにループで待ち合わせるプログラムなどがあると極端なCPUを使うことがあります。普段は通らないが何らかのケースの状態が起きるとタイミングを取る必要が生じて、それをループで行っているようなプログラムがあるとそこでCPUが極端に使われます。常に通るところでループしていれば簡単にわかりますが、月に数回とかたまにとかの頻度でしかループによる待ち合わせロジックを通ることがなく、しかもループ時間もそう長くない、という場合はみつけにくいです。
一般的にメインフレームのプログラムではアプリケーション側がループで待ち合わせるような作り方はしないのですが、COBOLなどにはタイマー待ち合わせ(SLEEP)などの機能がないので、ループの中で現時刻を得て一定時間が過ぎたかをチェックしてループから抜けたり、データセットの特定のレコードを何度も読み出してその内容が変わっていたら待ち合わせ終了にするなどのロジックが作られることもあります。このようなケースではプログラムの修正が必要なので、お手軽チューニングの範疇を超えますが、実際にそういうこともあり得るのだと知っておくといいでしょう。
I/Oを減らせばCPUも減る
プログラムの特性としてCPUバウンダリーなのかI/Oバウンダリーなのかというのがあります。メインフレーム、特にバッチ処理ではCPUバウンダリーの代表例がデータの圧縮、I/Oバウンダリーの代表例がデータのコピーです。編集や加工を伴わない単純なものほどI/Oバウンダリーに傾きます。
I/OはCPUに比べれば時間が掛かる処理ですが、すべてがデバイスの動作待ち時間ではありません。OSにとってI/Oの制御というのはとっても複雑な処理です。アプリケーションプログラムでは単にREAD、WRITEと書くだけですが、実際にそのI/O要求がチャネルに渡るまでにOSはさまざまな制御ロジックを実行します。またI/Oが完了した後も、要求したI/Oが正しく実行できたかを調べアプリケーションプログラムにファイルのレコードデータとして渡すなどの制御ロジックを実行します。これらの処理にも当然CPUは使われますから、I/OバウンダリーなプログラムほどI/O回数を減らすことはそれに伴って使われるCPU量を減らすことになります。