COBOLのパフォーマンスボトルネック見極め方!初心者向け高速化と負荷原因の調査方法
生徒
「コボルで作られたプログラムの動きがとても重くて遅いのですが、どこが原因で行き詰まっているのかを調べる方法はありますか?」
先生
「プログラムの処理速度が低下して遅くなる現象をパフォーマンスボトルネックと呼びます。コボルでは、特定の書き方やデータの読み込み方に原因があることが多いです。」
生徒
「プログラミングが未経験でパソコンの操作も詳しくないのですが、どこが遅いのかを見極めることはできますか?」
先生
「大丈夫です。処理が遅くなる原因の見つけ方と、それをきれいに解決するための基本的な考え方を分かりやすく順番に解説していきますね!」
1. パフォーマンスボトルネックとは何か
プログラミングの世界では、プログラムの実行速度が極端に落ちてしまう場所のことをパフォーマンスボトルネックと呼びます。ボトルネックとは「瓶の首」という意味です。牛乳瓶などを思い浮かべてみてください。瓶の胴体がどれだけ太くても、出口である首の細い部分があるせいで、中身が少しずつしか出てきません。これと同じように、パソコンの計算速度がどれだけ速くても、プログラムの中に一箇所でも処理が極端に遅い場所があると、全体の動きがそこでせき止められて遅くなってしまいます。この速度低下の原因となっている特定の処理や場所を見極めることが、システムを快適に動かすための第一歩となります。
コボルという言語は、銀行のシステムや企業の給与計算など、膨大なデータをまとめて処理する「バッチ処理」と呼ばれる仕組みでよく使われています。そのため、少しの無駄が何百万回、何千万回と繰り返されることで、全体の処理時間が何時間も延びてしまうという問題が発生しやすいのです。どこが原因で遅くなっているのかを正確に突き止める作業を「ボトルネックの見極め」や「プロファイリング」と呼びます。パソコンに詳しくない方でも、日常の交通渋滞の原因を探るような感覚で理解していくことができます。
2. なぜコボルのプログラムが遅くなるのか
コボルのプログラムが遅くなる最大の原因は、パソコンの頭脳である中央処理装置(これをコプロセッサやシーピーユーと呼びます)の計算スピードに対して、ハードディスクや外部の保管場所からデータを読み書きするスピードが圧倒的に遅いことにあります。このデータの読み書きのことをアイオー処理(入出力処理)と呼びます。パソコンの内部では、データの移動にとても時間がかかります。たとえば、机の上にあるノートを見るのは一瞬ですが、遠くの倉庫まで本を取りに行くのには時間がかかります。プログラムにとって、外部のファイルやデータベースからデータを一行ずつ持ってくる作業は、まさに倉庫まで往復するような大変な作業なのです。
もう一つの大きな原因は、同じような処理を何度も何度も無駄に繰り返してしまうことです。プログラムでは、特定の処理を繰り返し実行する命令のことを「ループ処理」や「繰り返し構文」と呼びますが、このループの中で何度も重たい処理を呼び出していると、あっという間に実行時間が膨れ上がってしまいます。これらの原因を一つずつ取り除いていくことで、古いプログラムであっても驚くほど高速に動かすことができるようになります。
3. 繰り返し処理の中にある無駄を見つける方法
コボルで最もボトルネックになりやすいのが、PERFORM(パフォーム)という命令を使った繰り返し処理の中身です。パフォームは、指定した回数や条件を満たすまで、特定の処理を何度も実行する命令です。この繰り返しの中に、一回だけ行えば十分な処理が混ざっていると、それが大きな速度低下の原因になります。たとえば、一万回繰り返す箱の中で、毎回同じ看板を書き直しているような状態です。看板は最初に一回だけ書けば良いはずです。このような無駄を見極めるには、繰り返しの外に出せる処理がないかを徹底的に探す必要があります。
初心者の方向けに、まずは簡単なコボルのプログラム例を見てみましょう。下記のコードは、繰り返しの中で毎回同じ初期化の処理を行ってしまっている、悪い効率のプログラムの例です。
IDENTIFICATION DIVISION.
PROGRAM-ID. SLOW-LOOP-EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 COUNTER-X PIC 9(4) VALUE 0.
01 FIXED-NUMBER PIC 9(4) VALUE 0.
PROCEDURE DIVISION.
MAIN-PROCESS.
PERFORM 1000 TIMES
MOVE 100 TO FIXED-NUMBER
ADD FIXED-NUMBER TO COUNTER-X
END-PERFORM
DISPLAY "計算結果は" COUNTER-X
STOP RUN.
このプログラムでは、千回繰り返す処理の中で、毎回FIXED-NUMBERという変数(データを入れておく箱)に「100」という数値を代入しています。数値の100は途中で変わらないため、この代入作業は繰り返しの前に一回だけやれば十分です。これを見極めて修正することで、無駄な動きを減らすことができます。
4. データの読み込み回数を減らす工夫
次に、コボルで最も重たい処理である「ファイルの読み込み」について解説します。コボルでは、書類が大量に詰まったファイルから、一行ずつデータを読み込んで処理を行います。この一行ずつ読み込む命令をREAD(リード)命令と呼びます。このリード命令が、何百万回も実行されると、ハードディスクへのアクセスが多発して画面が固まったように遅くなります。これを見極めるための対策として、データを一回ずつ取りに行くのではなく、大きめのカゴにまとめてデータを入れて一気に持ってくるという方法があります。これをバッファリングや「ブロック化」と呼びます。
日常の例で言うと、買い物に行くときに消しゴムを一個買うために毎回お店に往復するのではなく、必要な文房具をノートにまとめて一度に全部買ってくるような仕組みです。プログラムでも、データをある程度まとめてメモリと呼ばれるパソコンの一時的な記憶場所に保存しておくことで、倉庫への往復回数を劇的に減らすことができます。コボルの設定ファイルの中に記述する「ブロック化係数」という数値を調整するだけで、プログラムを一切書き換えずに速度が何倍も速くなることがあります。
5. 条件分岐の順番による速度の違い
プログラムの中では、条件によって進む道を分ける条件分岐処理が頻繁に使われます。コボルでは主にIF(イフ)文やEVALUATE(エバリュエイト)文という命令を使います。この条件分岐の書き方の順番によっても、パフォーマンスに大きな差が出ます。見極めのコツは「最もよく起こる条件を一番最初に書く」ということです。パソコンは、上から順番に条件が正しいかどうかを検証していきます。もし、滅多に起きない珍しい条件を一番上に書いてしまうと、毎回その条件のチェックが無駄に行われることになります。
例えば、日本の在住者を対象にしたアンケートデータを取り扱う場合、国籍が日本である人が大半を占めます。そのときに、他の国籍かどうかを先に何十回も判定するよりも、最初に日本かどうかを判定してしまえば、大半のデータは一瞬で判定を通過できます。具体的なコボルのイフ文の書き方の例を見てみましょう。
IDENTIFICATION DIVISION.
PROGRAM-ID. IF-SPEED-EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 COUNTRY-CODE PIC X(3) VALUE "JPN".
01 STATUS-MSG PIC X(20) VALUE SPACES.
PROCEDURE DIVISION.
MAIN-PROCESS.
IF COUNTRY-CODE = "JPN" THEN
MOVE "国内居住者です" TO STATUS-MSG
ELSE
IF COUNTRY-CODE = "USA" THEN
MOVE "米国居住者です" TO STATUS-MSG
ELSE
MOVE "その他の地域です" TO STATUS-MSG
END-IF
END-IF
DISPLAY STATUS-MSG
STOP RUN.
このように、最も確率が高い条件を一番最初のイフ文で捕まえるように構成することで、それ以降の無駄な条件判定をスキップさせることができます。これだけで、何万件ものデータを処理するときの全体の速度が大きく向上します。プログラムの負荷を抑えるための非常に簡単かつ効果的なテクニックです。
6. 無駄な画面表示を減らして高速化する
プログラミングの学習を始めると、画面に文字を表示させるためにDISPLAY(ディスプレイ)という命令をよく使います。画面に現在の状況や計算結果が表示されると安心するものですが、実はこのディスプレイ命令は、プログラムの処理を著しく遅くする隠れたボトルネックの原因になります。パソコンにとって、画面に文字を描画してスクロールさせるという作業は、内部の計算処理に比べて非常に大きな負担がかかる重たい処理なのです。
データが正しく処理されているか不安だからといって、百万回繰り返すループ処理の中で毎回「いま何件目を処理しました」と画面に表示させていると、プログラムの実行時間は何倍にも伸びてしまいます。開発中のテストのときは表示させても良いですが、実際に本番のシステムとして動かすときには、画面への表示を消すか、あるいは「一万件ごとに一回だけ表示する」というように表示の頻度を制限することが大切です。これを見極めるだけでも、劇的なパフォーマンスの改善が見込めます。
7. 文字列の扱い方とデータ型の適切な選び方
コボルは数字や文字を扱うときに、そのデータの形式(これをデータ型と呼びます)を細かく指定する特徴があります。例えば、数字を扱う場合でも、文字としての数字なのか、純粋に計算するための数字なのかを区別します。このデータ型の選び方が不適切だと、パソコンの内部で毎回「文字から数字へ変換する」という余計な翻訳作業が発生してしまい、これがボトルネックになります。特に、計算を何度も行う変数には、計算に適したデータ型を選んでおく必要があります。
コボルでは、計算専用の形式としてCOMP-3(コンパックサン、内部十進数)やCOMP(コンパック、バイナリ形式)という特別な設定があります。これらを使用すると、パソコンが翻訳の手間をかけずに直接素早く計算できるようになります。初心者の方には少し難しく感じられるかもしれませんが、数字の宣言の仕方ひとつで、処理速度が大幅に変わるということだけ覚えておいてください。具体的な宣言の例を以下のプログラムで示します。
IDENTIFICATION DIVISION.
PROGRAM-ID. DATA-TYPE-EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 SLOW-COUNTER PIC 9(5) VALUE 0.
01 FAST-COUNTER PIC S9(5) COMP-3 VALUE 0.
PROCEDURE DIVISION.
MAIN-PROCESS.
PERFORM 5000 TIMES
ADD 1 TO FAST-COUNTER
END-PERFORM
DISPLAY "高速計算終了"
STOP RUN.
この例にあるFAST-COUNTERのように、お尻にCOMP-3と書かれた変数は、内部で効率的に計算ができる仕組みになっています。大量の足し算や引き算を行う場所を見極めて、このような最適な型に置き換えることが高速化の鍵となります。
8. ボトルネックを実際に見極めるための手順
では、実際にプログラムが遅いと感じたときに、未経験の方が具体的にどのような手順でボトルネックを見極めていけばよいか、その手順を整理します。まずは、勘に頼らずに「時間を計る」ということが最も重要です。プログラム全体の開始時間と終了時間を記録して、どの処理に何分かかっているのかを大雑把につかみます。コボルでは現在の時刻を取得する命令がありますので、それを使って処理の前後の時間を画面に出力してみるのが確実です。
時間がかかっている特定の処理(関数や節と呼ばれるまとまり)が見つかったら、その中に大きなファイルを読み込んでいる場所がないか、あるいは何万回も回っているループ処理がないかを確認します。そして、これまでに紹介した「繰り返しのなかの無駄」「多すぎる画面表示」「最適でない条件分岐の順番」といったチェックリストと照らし合わせていきます。複雑な道具を使わなくても、プログラムの動きを観察して、時間を計るだけで、ほとんどのボトルネックの原因は突き止めることができます。
9. 初心者が陥りがちな注意点と対策
パフォーマンスを上げようとして、初心者の人がよくやってしまう失敗があります。それは、プログラムを速くすることに集中しすぎるあまり、コードの内容が複雑になってしまい、他の人が読んだときに意味が分からなくなってしまうことです。プログラムにとって、動く速度が速いことも大切ですが、それと同じくらい「誰が見ても読みやすく、修正しやすいこと」も大切です。速度を追い求めるあまり、無理な書き方をしてシステムがバグ(プログラムの不具合や間違い)だらけになってしまっては本末転倒です。
まずは、普通に分かりやすいプログラムを書きましょう。その上で、どうしても全体の動きが遅くて困るという場合にだけ、今回紹介したようなボトルネックの見極めを行い、ピンポイントで速度が出ない原因の場所だけを修正するようにしてください。全体の1パーセントの場所を直すだけで、全体の速度が何倍も速くなることはよくあります。安全に、そして効果的にプログラムを改善していく視点を持つことが、優れたプログラマーへの近道です。