プログラムの呼び出し | ![]() |
この章では、プログラムのパフォーマンスを最適化する手法について説明します。具体的な内容は次のとおりです。
ここで紹介する情報は、原則的にネイティブコードにコンパイルするプログラムが対象であり、特に明記していない限り中間コードは対象外です。
ここでは、Server Express システムによって生成されるプログラムのネイティブコードを最適化するためのテクニックをいくつか紹介します。これらのテクニックを正しく活用すると、アプリケーションコードを軽量化し、パフォーマンスを高めることができます。なお、紹介するテクニックは原則的なものと理解してください。つまり、これらのテクニックを使用しなくても正しく動作するプログラムは開発できますが、最適なパフォーマンスが得られる可能性は低くなります。
Server Express で開発したプログラムは、移植性に関するいくつかの条件を満たせば、他の COBOL 環境でも動作します。
正しいデータ型の選択は、アプリケーションの処理効率、特に演算パフォーマンスを最適化するうえで重要です。データ型によるデータ格納形式の違いについては、『言語リファレンス』を参照してください。それぞれのデータ型の特徴を次に示します。
データ型
|
処理速度および説明
|
---|---|
COMP-5 | COMP-5 データ項目は、ネイティブの 2 進データとして処理されます。
COMP-5 データ項目の処理速度は、デフォルトのコンパイラ指令 COMP-5"2" を使用したプログラムで最適になります。この指令の詳細については、『Server Express ユーザガイド』の『コンパイラへの指令』の章を参照してください。 |
COMP-X | COMP-X データ項目は、2 進データとして処理されます。
このデータ項目は COBOL のバイトオーダに従って格納されますが、その順序は必ずしもネイティブのバイトオーダとは一致しません。たとえば、Intel 80x86 プロセッサや Digital Alpha プロセッサを搭載したシステムとその他のプロセッサを搭載したシステムでは、バイトオーダは異なります。演算対象のデータ長が 1 バイトを超えると、演算の前にバイトデータの並べ替えが実行されるため、COMP-5 データ項目に比べると演算速度はやや劣ります。 |
COMP | COMP データ項目は、デフォルトでは ANSI 規格に従って処理されます。演算結果を COMP 項目に格納する前に切り捨て処理が実行されるため、COMP-X データ項目に比べると処理速度は低くなります。ただし、COMP 指令と NOTRUNC 指令を使用してコンパイルしたプログラムでは、COMP データ項目が COMP-X 項目と同様に処理されます。 |
COMP-3 | COMP-3 データ項目はパック 10 進数として処理されます。その結果、COMP 項目に比べると処理速度はかなり見劣りすることになり、算術演算での使用は避けるべきです。中間コードでの演算処理でも、DISPLAY 項目の方が効率的です。 |
DISPLAY | DISPLAY データ項目の演算速度は COMP 項目に比べるとかなり見劣りするため、算術演算での使用は避けるべきです。ただし、DISPLAY 項目には次のような特徴もあります。
|
32 ビットシステム
32 ビットの COBOL システムは、演算対象の数値データが 9 桁以下 (2 進データの場合は 4 バイト以下) の場合に、最も効率的で軽量なコードを生成します。
数値データの桁数が 9 桁 (2 進数では 4 バイト) を超えると演算効率が著しく低下し、コードのサイズも大きくなります。
64 ビットシステム
64 ビットの COBOL システムは、演算対象の数値データが 18 桁以下 (2 進データの場合は 8 バイト以下) の場合に、最も効率的で軽量なコードを生成します。
表内の全項目が正しく整列されていることを確認します。表内のいずれかの項目のサイズ (表内の基本項目の大きさ) が 2 バイト、4 バイト、または 8 バイトの倍数かをチェックし、必要に応じてパディングを施します。次に例を示します。
01 a occurs 10. 03 b pic x(4) comp-5. 03 c pic x. 03 filler pic x(3).
この例は、表内の c 項目に 3 バイトの FILLER(無名項目) を追加し、4 バイト境界で整列しています。
ここでは、プログラムのサイズとパフォーマンスに影響を与える手続き部 (PROCEDURE DIVISION) の要素を明らかにし、これらの要素を最も効率的に使用する方法を示します。
原則的に処理が単純であれば、それだけ実行速度は上がり、コンパイル後のコードサイズも小さくなります。1 つの複雑な処理を記述する場合より、いくつかの単純な処理に分けて記述する方が、より良いパフォーマンスが得られることがあります。プログラムのサイズとパフォーマンスを最適化するうえで、望ましい手続き部の記述方法を次に示します。
算術演算のパフォーマンスを最適化するためにも、常に最も単純な記述方法を選んでください。
次の例は、4 バイト以下の COMP-5 (および COMP-X) データ項目用に最適化した文を示しています。
move a to b add a to b subtract a from b multiply a by b divide a into b if a condition b
a
は 4 バイト以下の数字リテラルまたは数字データ項目、 b
は 4 バイト以下の数字データ項目です。
単純な文を使用すると、他のデータ型でも処理速度が向上します。ただし、その効果は COMP-5 や COMP-X の場合ほど顕著ではありません。
3 つ以上のオペランドを持つ文など、より複雑な文を使用すると、生成されるコードのパフォーマンスに影響を与える可能性があります。
オペランドのデータ型は統一してください。使用するデータ型としては、4 バイト長の COMP-5 が最適です。最適化した COMPUTE 文の例を次に示します。
compute a = b * c + d compute a = b * 4 + 2 compute a = b + c - d + e
次のような IF 文より、テンポラリ項目を使用する方法(a と b の加算結果をテンポラリ項目に格納し、テンポラリ項目を IF 文で使用する)の方が、高いパフォーマンスが得られます。
if a + b > c
中間コードの生成時にランタイムエラー 163 (数字項目の値が無効) が通知されます。生成したコードを実行すると、予期せぬ結果が発生します。
予期せぬ結果が発生します。
この問題を回避するためにも、数字項目は使用前に必ず数値で初期化してください。
英数字データの最も効率的な操作方法は次のとおりです。
item (literal:) item (literal:literal) item (literal:variable) item (variable:variable) item (variable + literal:literal) item (variable - literal:literal) item (variable + literal:variable) item (variable - literal:variable)
このリストに含まれない形式の部分参照は、効率的ではありません。
表の最も効率的な操作方法は次のとおりです。
01 a pic xx occurs 10. 01 b pic xx occurs 10. 01 c pic xx occurs 10. 01 d pic xx occurs 10. . . . move a(i) to b(i) if c(i) = d(i) display "pass" end-if
添字、 i
は 2 つの文で 4 回にわたって使用されますが、その値が評価されるのは一度のみです。各項目の大きさはいずれも
2 です。
USAGE DISPLAY の添字を使用している場合には、BOUNDOPT 指令を指定すると、生成されるプログラムのパフォーマンスが向上します(この指令のかわりに NOBOUND を指定することもできます)。次に例を示します。
. . . 01 array pic x occurs 20. 01 array-index pic 9(5) value 2. . . . move "a" to array(array-index). . . .
このプログラムを BOUNDOPT なしでコンパイルすると、添字の評価に array-index
の 5 つの桁すべてが使用されます。一方、BOUNDOPT
を指定した場合は、array-index
の最後の 2 桁のみが使用されます。表に含まれる 20 個の要素にアクセスするには、実際には
2 桁で十分であるためです。
条件文の最も効率的な使用方法は次のとおりです。
ビット単位での論理演算の実行には、多くの COBOL システムライブラリルーチンが使用可能です(詳細については、『拡張言語機能』を参照してください)。これらのルーチンを使用すると、ビット単位で AND や OR、XOR などの論理演算を実行できます。
コンパイラはこれらのルーチンの呼び出しを検出すると、可能であれば最適化を行います。最適化では、ランタイムシステムの呼び出しのかわりにインラインコードが生成されます。インラインコードとは、呼び出しを行わずに関数を直接実行するネイティブコードのことです。最適化が行われない場合は、汎用ランタイムルーチンが呼び出されます。
呼び出しの最適化は、データ長をリテラルで指定している場合に実行されます。
AND および OR の論理演算は、VALUE 句を使用して実行することも可能です。詳細については、『言語リファレンス』を参照してください。
PERFORM 文は、ほとんどの処理で優れたパフォーマンスを発揮し、プログラムサイズの増加を抑制する手段としても効果的です。さらに、プログラム構造が保守しやすくなるという利点もあります。PERFORM 文の最も効果的な使用方法は次のとおりです。
これはコーディング手法として望ましいのみでなく、リソース消費の抑制にも効果的です。また、編集転記や副プログラムの呼び出し、ファイル入出力などの独立した文にも有効です。
PERFORM 文の実行範囲内で、別の PERFORM の実行範囲が完結している場合には、この PERFORM の実行が、範囲の完結点を超えて継続されてしまいます。この事態を回避するためにも、PERFORM の実行範囲内では、他の PERFORM の実行範囲を完結させるべきではありません。
たとえば次の例では、最初の PERFORM の実行範囲内で 2 番めの PERFORM の実行範囲が完結しているため、生成されるコードでは最初の PERFORM の処理がきわめて非効率になります。
perform a thru e perform b thru d stop run a. . . . b. . . . c. . . . d. . . . e. . . .
各種の CALL 文の最も効率的な使用方法は次のとおりです。
連絡項目に多くの参照を行わないでください。連絡項目とは、連絡節で定義されている項目、CBL_ALLOC_MEM 割り当てメモリに設定されている項目、および EXTERNAL 定義されている項目などです。
連絡項目へのアクセスは、常に作業場所節で定義している項目へのアクセスより遅くなります。そのため、連絡節で定義している項目を頻繁に使用するようであれば、その項目をプログラムの呼び出し時に作業場所節の項目に転記することによってアクセス効率を改善できます。転記された項目は、呼び出し元プログラムに制御を戻すときに必要に応じて連絡節の項目に転記します。呼び出されたプログラムでは作業場所節の項目に転記された項目が一貫して使用され、連絡節内の項目は使用されません。
ファイルのソート処理で入力手続きおよび出力手続きを実装する場合には、効率的な手続きを作成することが大切です。入力手続きおよび出力手続きの処理効率が低いと、ソート処理がきわめて遅くなる可能性があります。
ネイティブコードのプログラムのパフォーマンスは、さまざまなコンパイラ指令を使用して向上させることが可能です。ただし、一部の指令については、プログラムの動作を確認しながら慎重に使用する必要があります。
通常、プログラムをネイティブコードにコンパイルする際には、次の各指令を使用します。
NOALTER
ALIGN"4" (32 ビットシステムの場合)
ALIGN"8" (64 ビットシステムの場合)
COMP
NOBOUND
NOCHECK
NOCHECKDIV
NONESTCALL
NOODOSLIDE
NOQUAL
NOSEG
NOTRUNC
生成されるコードのパフォーマンスを重視する場合には、次の各項目も効果的です。
REMOVE "ROUNDED"
REMOVE "ERROR"
REMOVE "INITIALIZE"
REMOVE "CORRESPONDING"
REMOVE "THRU"
REMOVE "THROUGH"
これらの予約語を除去すると、プログラムで非効率的な構文が使用される事態を回避できます。
プログラムのパフォーマンスは、さまざまなコンパイラ指令を使用して向上させることが可能です。コンパイラ指令のデフォルトが、そのままパフォーマンス向上に有効な場合もありますが、パフォーマンスを優先するためにデフォルト値から変更すべき指令もあります。ここでは、後者の指令を紹介します。
パフォーマンスを重視するプログラムには、ALTER 文は使用すべきではありません。さらに、コードの生成を回避するため、NOALTER 指令を指定してコンパイルします。
NOBOUND を指定してコンパイルするとアプリケーションのパフォーマンスが向上し、サイズは抑制されます。この指令を指定しないと、コンパイラは表項目への参照を検出するたびに領域チェック用のコードを生成します。
テスト段階では BOUND 指令を使用し、プログラムが表領域外のデータを参照していないことを確認します。完成版のコンパイルでは NOBOUND を使用して、プログラムのパフォーマンスを向上させます。
次の 2 つの条件が満たされる場合には、BOUNDOPT 指令でプログラムのパフォーマンスを最適化できます。
BOUNDOPT を指定すると、USAGE DISPLAY 添字内の表サイズを超える桁は無視されます。たとえば、表のエントリ数が 100 未満の場合、PIC 9(3) の添字は PIC 9(2) と同様に扱われます。
USAGE DISPLAY の添字は、特に理由がない限り使用しないことをお奨めします。
COMP 指令を使用すると、数値のオーバーフローのチェックが無効になり、非常にコンパクトで処理効率に優れたコードが生成されます。
COMP は、USAGE COMP で定義したデータ項目の演算方法を変更します。その結果、コードの処理効率は向上しますが、演算方法は ANSI 規格に準拠しません。
使用方法に注意して正しく活用すると、COMP 指令はプログラムのパフォーマンス向上に優れた効果を発揮します。
NESTCALL は、ネストしているプログラムの呼び出しを可能にする指令です。そのような呼び出しが不要であれば、NONESTCALL 指令を指定してください。その結果、生成されるコードのパフォーマンスがやや向上します。
TRUNC 指令を指定すると、USAGE COMP で定義したデータ項目に切り捨て処理が必要かを判定するコードが生成されます。
COMP 型データ項目に対する切り捨て処理が不要であれば、NOTRUNC 指令を指定することによって、より効率的なコードを生成できます。
プログラムのサイズは、さまざまなコンパイラ指令を使用して最適化することが可能です。コンパイラ指令のデフォルトが、そのままサイズの最適化に有効な場合もありますが、サイズを最適化するためにデフォルト値から変更すべき指令もあります。ここでは、後者の指令を紹介します。
ALIGN 指令は、01 レベルおよび 77 レベル項目の境界を指定します。この境界は、常に 2 のべき乗 (2、4、8 など) になります。32 ビットの COBOL システムでは 4 以上 (ALIGN"4")、64 ビットのオペレーティングシステムでは 8 (ALIGN"8") を指定してください。高めの値はパフォーマンスの面で有効ですが、データレコード間に使用されないスペースを増加させます。
浮動小数を含む算術演算では正確な演算結果が得られない可能性があります。これは、COBOL ではデフォルトで数値が丸められないためです。次に例を示します (この例の WS02 は COMP-2 型のデータ項目です)。
accept ws02 compute ws01 = ws02 display ws01
このプログラムで最初に 2.3 を入力しても、最後に表示される値は 2.29 になります。
値を丸めるには、ROUNDED 指定を指定する必要があります。上記の例を ROUNDED 指定を使用して書き直したコードを次に示します。
accept ws02 compute ws01 rounded = ws02 display ws01
FP-ROUNDING コンパイラ指令を使用すると、プログラム内のすべてのデータ項目に丸めや切り捨てが実行されるように指定できます。この指令の詳細については、『Server Express ユーザガイド』の『コンパイラへの指令』の章を参照してください。
Server Express は IEEE の浮動小数点規格に準拠しています。ここでは、Server Express の各浮動小数点型でカバーされる値の範囲と精度を示します。
COBOL の 2 つの浮動小数点バイナリデータ型でカバーされる値の範囲は次のとおりです。
COMP-1 | 8.43E-37 | 〜 | 3.37E38 |
-8.43E-37 | 〜 | -3.37E38 | |
COMP-2 | 4.19E-307 | 〜 | 1.67E308 |
-4.19E-307 | 〜 | -1.67E308 |
注: Server Express の浮動小数点型は上記の範囲をカバーしますが、実際に使用できるのは 2 桁の指数のみです。
データ型のサイズと有効桁数の関係を次に示します。
データ型
|
サイズ
|
有効桁数
|
---|---|---|
COMP-1 | 4 バイト | 6 〜 7 |
COMP-2 | 8 バイト | 15 〜 16 |
コンパイラは浮動小数点リテラルを検出すると、メインフレーム環境との互換性を検証します。その結果、リテラル値が次の 2 つの範囲から外れている場合には、コンパイル時にエラーが発生します。
0.54 E -78 | 〜 | 0.72 E +76 | |
-0.54 E -78 | 〜 | -0.72 E +76 |
IEEE 規格に準拠する 2 進浮動小数は、次の要素から構成されます。
値がゼロ以外の場合は、指数から定数を差し引いた値が、仮数の開始桁の計算に使用されます。そのため、倍精度浮動小数 (COMP-2) は、仮数 (m) で次のように表されます。
1*(2**m) + mb0*(2**(m-1)) + mb1*(2**(m-2)) + mb2*(2**(m-3)) + ... + mb51*(2**(m-52))
各仮数ビット (この例では mb0 〜 mb51) は 0 または 1 です。単精度浮動小数 (COMP-1) 項目では 2 の指数部の最大値と最小値の差が 23 を超えた場合、COMP-2 項目では 52 を超えた場合に、精度の問題が生じる可能性があります。
たとえば、2**56 を掛け合わせる仮数ビットと 2**2 を掛け合わせる仮数ビットの組み合わせで表現される COMP-2 項目は、指数部の差 (56 - 2) が 52 を超えるため、近似値への変換が必要になります。この規則は、浮動小数の実装やハードウェアプラットフォームの違いにかかわらず共通です。また、浮動小数の内部格納形式は、オペレーティングシステムの種類によって異なる場合があります。詳細については、『言語リファレンス』を参照してください。オペレーティングシステム間の内部格納形式の違いによって誤差が生じることもあります。
2 進浮動小数が表現できる数値は、符号の違いにかかわらず、常に 2 のべき乗とその組み合わせのみです。たとえば、10 進の小数は 1/2、1/4、1/8、1/16、1/32 など、2 のべき乗の分母を持つ分数を組み合わせた値で表現されます。そのため、0.625 (1/2 + 1/8) などの値は正確に表現できますが、それ以外は実際の値をごくわずか上回る (または下回る) 近似値で表現されます。整数も同様に、1、2、4、8、16 など 2 のべき乗の組み合わせで表現されます。そのため、625 (1 + 16 + 32 + 64 + 512) などの値は正確に表現できますが、それ以外は近似値で表現されます。
Server Express システムでは、静的にリンクされたコードと動的にロードされたコードを実行することが可能です。静的にリンクされたコードとは、実行ファイルの一部としてプログラム内に組み込まれたコードのことです。また、動的にロードされたコードとは、実行ファイルとは別のファイルに格納されているコード、具体的には COBOL から呼び出し可能な共有オブジェクトや、呼び出し時のみロードされて実行される .int ファイル (または .gnt ファイル) のことです。
動的にロードされた COBOL プログラムの開発時には、利用可能なメモリが効率的に利用されるように配慮する必要があります。Server Express では、プログラムをいくつかの小さい部分に分け、COBOL の呼び出しメカニズムを活用することによって、コンピュータに搭載されている容量以上のメモリを使用するプログラムを作成し、実行することが可能です。詳細については、『プログラムの呼び出し』の章を参照してください。
Copyright © 2002 Micro Focus International Limited. All rights reserved.
本書、ならびに使用されている固有の商標および商品名は国際著作権法で保護されています。
プログラムの呼び出し | ![]() |