この章では、SPARC ベースのワークステーションで使用される浮動小数点ユニットに関連する問題について説明し、特定のワークステーションに最適なコード生成フラグを決定する方法を示します。
このセクションでは、多数の SPARC プロセッサを示し、それらがサポートする命令セットと例外処理機能について説明します。
次の表に、最近の SPARC システムで使用されているハードウェア浮動小数点実装を示します。
|
|
Oracle Solaris 10 Update 10 以前の Oracle Solaris リリースで Oracle Solaris Studio 12.4 を使用してコンパイルされたプログラムはサポート対象ではありませんが、ほとんどの場合、以前の Oracle Solaris Studio リリースをサポートする旧 SPARC システムで実行できます。このようなプラットフォームでテストする実行可能ファイルを作成するには、次のオプションを使用してコンパイルしてみてください。
–m32 –xarch=generic –xchip=generic
サポート対象のソリューションについては、使用するもっとも古い Oracle Solaris リリース上でコンパイルし、その Oracle Solaris リリースでサポートされる最新の Oracle Solaris Studio バージョンを使用してコンパイルします。
前述の表の最後の列は、それぞれの FPU で最速のコードを取得するために使用するコンパイラフラグを示しています。これらのフラグは、コード生成の 2 つの独立した属性を制御します。–xarch フラグはコンパイラが使用できる命令セットを決定し、–xchip フラグはコードのスケジューリングにおけるプロセッサのパフォーマンス特性に関するコンパイラによる仮定を決定します。デフォルトの –xarch を使用するか、明示的な –xarch=sparc を使用してコンパイルされたプログラムは、前述の SPARC ベースシステムすべてで実行されますが、最新のプロセッサの機能を十分に活用できない場合があります。同様に、特定の –xchip 値を使用してコンパイルされたプログラムは、–xarch で指定された命令セットをサポートするすべての SPARC ベースシステムで実行されますが、指定以外のプロセッサを備えたシステムでは実行速度が低下する場合があります。
UltraSPARC I、 UltraSPARC II、 UltraSPARC IIe、 UltraSPARC IIi、 UltraSPARC III、 UltraSPARC IIIi、 UltraSPARC IV、および UltraSPARC IV+ 浮動小数点ユニットは、4 倍精度の命令を除き、『SPARC Architecture Manual』バージョン 9 で定義されている浮動小数点命令セットを実装します。具体的には、これらは 32 倍精度の浮動小数点レジスタを提供しています。–xarch=sparc でコンパイルすると、コンパイラはこれらのすべての機能を使用できます。これらのプロセッサは、命令セットの拡張機能も提供しています。今までのこれらの追加命令は、次の –xarch 値で有効になります。
sparcvis
sparcvis2
sparcvis2
sparc4
sparc5
これらの追加命令の多くは、コンパイラによって自動的に生成されることはまれですが、その場合はアセンブリコードで使用できます。
–xarch と –xchip オプションは、–xtarget マクロオプションを使用して同時に指定できます。–xtarget フラグは、–xarch、–xchip、および –xcache フラグの適切な組み合わせとしてのみ展開します。デフォルトのコード生成オプションは -xtarget=generic です。–xarch、–xchip、および –xtarget の値の完全なリストを含む詳細については、cc(1)、CC(1)、および f95(1) のマニュアルページとOracle Solaris Studio 12.4: Fortran ユーザーズガイド 、Oracle Solaris Studio 12.4: C ユーザーガイド 、およびOracle Solaris Studio 12.4: C++ ユーザーズガイド のコンパイラマニュアルを参照してください。
すべての SPARC 浮動小数点ユニットは、実装する SPARC アーキテクチャーのバージョンとは関係なく、FPU に関連したステータスビットおよびコントロールビットを含む浮動小数点ステータスレジスタ (FSR) を提供しています。遅延浮動小数点トラップを実装する SPARC FPU はすべて、現在実行中の浮動小数点命令に関する情報を含む浮動小数点キュー (FQ) を提供しています。FSR はユーザーソフトウェアからアクセスして、発生した浮動小数点例外を検出し、丸め方向、トラップ、および非標準演算モードを制御できます。FQ はオペレーティングシステムカーネルによって浮動小数点トラップの処理に使用され、通常、ユーザーソフトウェアからは見えません。
ソフトウェアは、FSR をメモリーに格納する STFSR 命令と、メモリーからロードする LDFSR 命令を介して、浮動小数点ステータスレジスタにアクセスします。SPARC アセンブリ言語では、これらの命令は次のように記述されます。
st %fsr, [addr] ! store FSR at specified address ld [addr], %fsr ! load FSR from specified address
Sun Studio コンパイラに付属のライブラリを含むディレクトリにあるインラインテンプレートファイル libm.il には、STFSR および LDFSR 命令の使用例があります。
次の図に、浮動小数点ステータスレジスタのビットフィールドのレイアウトを示します。
図 B-1 SPARC 浮動小数点ステータスレジスタ
バージョン 7 および 8 の SPARC アーキテクチャーでは、図に示すように FSR は 32 ビットを占めます。バージョン 9 では、FSR は 64 ビットに拡張されますが、そのうち下位の 32 ビットがこの図に一致し、上位 32 ビットには 3 つの追加浮動小数点条件コードフィールドが入っているのみで、大部分が未使用です。
この図では、res は予約されているビットを示し、ver は、FPU のバージョンを示す読み取り専用フィールドであり、ftt と qne は浮動小数点トラップを処理するときにシステムによって使用されます。残りのフィールドについては、次の表で説明します。
|
RM フィールドには、浮動小数点演算での丸め方向を指定する 2 ビットが保持されます。NS ビットは、非標準演算モードを実装する SPARC FPU ではこのモードを有効にし、実装していない場合はこのビットが無視されます。fcc フィールドには、浮動小数点比較命令によって生成され、分岐演算および条件付き移動演算で使用される浮動小数点条件コードが保持されます。TEM、aexc、および cexc フィールドには、トラップを制御し、5 つの IEEE 754 浮動小数点例外それぞれについて累積例外フラグと現在の例外フラグを記録する 5 つのビットが含まれます。これらのフィールドは、次の表に示すようにさらに分割されます。
|
(上記の記号 NV、OF、UF、DZ、および NX は、それぞれ無効演算、オーバーフロー、アンダーフロー、ゼロ除算、および不正確な例外を表します)。
ほとんどの場合、SPARC 浮動小数点ユニットは、ハードウェア内で完全に命令を実行し、ソフトウェアサポートを必要とすることはありません。ただし、次の 4 つの場合は、ハードウェアでは浮動小数点命令が正常に完了しません。
浮動小数点ユニットが無効になっている場合。
SPARC FPU での 4 倍精度命令など、命令がハードウェアによって実装されていない場合。
ハードウェアが命令のオペランドに対して正しい結果を出すことができない場合。
命令によって IEEE 754 浮動小数点例外が発生し、その例外のトラップが有効になっている場合。
どの場合でも初期応答は同じです。プロセスがシステムカーネルにトラップを発行すると、システムカーネルがトラップの原因を特定して適切なアクションを実行します。「トラップ」という用語は、通常の制御フローの割り込みを意味します。最初の 3 つの場合では、カーネルはソフトウェア内でトラップ命令をエミュレートします。エミュレートされた命令でもまた、トラップが有効になっている例外が発生する可能性があることに注意してください。
上記の最初の 3 つの場合では、エミュレートされた命令によって、トラップが有効になっている IEEE 浮動小数点例外が発生しなければ、カーネルは命令を完了します。命令が浮動小数点の比較である場合は、カーネルは結果を反映させるために条件コードを更新します。命令が算術演算である場合は、適切な結果をデスティネーションレジスタに配布します。カーネルはまた、命令によって発生したすべての (トラップされていない) 例外を反映するように現在の例外フラグも更新し、これらの例外を累積例外フラグに加えます。続いてカーネルは、トラップが行われた位置からプロセスの実行を継続するように準備します。
ハードウェアが実行する、またはカーネルソフトウェアがエミュレートする命令によって、トラップが有効になっている IEEE 浮動小数点例外が発生した場合、その命令は完了しません。デスティネーションレジスタ、浮動小数点条件コード、および累積例外フラグは変更されず、トラップの原因となった特定の例外を反映するように現在の例外フラグが設定され、カーネルは SIGFPE シグナルをプロセスに送信します。
次の擬似コードは、浮動小数点トラップの処理の概要を示しています。aexc フィールドは通常、ソフトウェアでしかクリアできないことに注意してください。
FPop provokes a trap; if trap type is fp_disabled, unimplemented_FPop, or unfinished_FPop then emulate FPop; texc = all IEEE exceptions generated by FPop; if (texc and TEM) = 0 then f[rd] = fp_result; // if fpop is an arithmetic op fcc = fcc_result; // if fpop is a compare cexc = texc; aexc = (aexc or texc); else cexc = trapped IEEE exception generated by FPop; throw SIGFPE;
多くの浮動小数点命令をカーネルがエミュレートする必要がある場合、プログラムのパフォーマンスは大幅に低下します。この低下の相対的な発生頻度は、トラップの種類など、いくつかの要因によって異なります。
通常の環境下では、fp_disabled トラップは、プロセスごとに一度だけ発生します。システムカーネルは、プロセスが最初に開始されるときに浮動小数点ユニットを無効にします。このため、プロセスによって実行される最初の浮動小数点演算によってトラップが発生します。トラップを処理したあと、カーネルによって浮動小数点ユニットが有効なり、プロセスの実行中は有効なままになります。(システム全体に対して浮動小数点ユニットを無効にすることは可能ですが、これは推奨されていません。カーネルまたはハードウェアのデバッグプロセスでのみ実行します)。
unimplemented_FPop トラップは、浮動小数点ユニットが実装していない命令に遭遇すると必ず発生します。現在の SPARC 浮動小数点ユニットのほとんどは、4 倍精度命令を除き、少なくとも『SPARC Architecture Manual』バージョン 8 に定義されている命令セットを実装しており、また、Oracle Solaris Studio コンパイラは 4 倍精度命令を生成しないため、この種のトラップは、–xarch=sparc でコンパイルされたほとんどのシステムで発生することはありません。
残る 2 種類のトラップである unfinished_FPop およびトラップされた IEEE 例外は通常、NaN、無限大、および非正規数を含む特殊な演算状況に関連しています。
浮動小数点命令がトラップが有効になっている IEEE 浮動小数点例外に遭遇すると、その命令は完了されません。代わりにシステムから SIGFPE シグナルがプロセスに送信されます。プロセスが SIGFPE シグナルハンドラを確立している場合は、そのハンドラが呼び出され、確立していない場合はプロセスが中止します。トラップはほとんどの場合、例外発生時にプログラムを中止させることを目的として有効になっているため、メッセージを出力しプログラムを終了させるシグナルハンドラを呼び出した場合、またはシグナルハンドラがインストールされていないときにシステムのデフォルト動作に分類し直した場合、ほとんどのプログラムでは、トラップされた IEEE 浮動小数点例外の発生は少なくなります。ただし、Chapter 4, 例外と例外処理で説明しているように、シグナルハンドラがトラップ命令の結果を供給し、実行を継続することもできます。多くの浮動小数点例外がトラップされ、この方法で処理される場合、パフォーマンスが大幅に低下する可能性があることに注意してください。
SPARC 浮動小数点ユニットの中には、トラップが無効になっている場合や、命令によってトラップが有効になっている例外が発生しない場合でも、少なくとも無限オペランド、NaN オペランド、あるいは IEEE 浮動小数点例外を含むケースをトラップするものがあります。これは、ハードウェアがこのような特殊なケースをサポートしていない場合に発生します。代わりに unfinished_FPop トラップが生成され、そのままカーネルエミュレーションソフトウェアで命令を続行させます。SPARC FPU が異なれば、unfinished_FPop トラップを発生させる条件も異なります。たとえば、もっとも初期の SPARC FPU は、トラップが有効かどうかにかかわらず、すべての IEEE 浮動小数点例外をトラップしますが、UltraSPARC FPU は、浮動小数点例外のトラップが有効であり、命令によって例外が発生するかどうかをハードウェアが判断できない場合に、悲観的にトラップすることがあります。ただし、最新の SPARC プロセッサであればどれでも、ハードウェアの例外的なケースがすべて処理されるため、unfinished_FPop トラップが生成されることはありません。
ほとんどの unfinished_FPop トラップは浮動小数点例外とともに発生するため、プログラムでは、例外フラグのテスト、結果のトラップおよび代用、または例外発生時の停止などの例外処理を採用することによって、これらのトラップの過剰な発生を回避できます。例外処理にかかるコストと、例外による unfinished_FPop トラップの発生を許容するコストのバランスを取るようにしてください。
一部の SPARC 浮動小数点ユニットが unfinished_FPop でトラップを発生させるもっとも一般的な状況には、非正規数が関係しています。これまでの SPARC 浮動小数点ユニットの多くは、浮動小数点演算に非正規オペランドが含まれているか、ゼロ以外の非正規結果、つまり段階的アンダーフローを招く結果を必ず生成する場合に常にトラップします。アンダーフローの発生はそれほど多くありませんが、プログラムが困難であり、また、アンダーフローした中間結果の正確さは、計算の最終結果全体の正確さにほとんど影響しないため、SPARC アーキテクチャーでは、非正規数を含む unfinished_FPop トラップによるパフォーマンス低下の回避方法をユーザーに提供する非標準演算モードを定義しています。
SPARC アーキテクチャーでは非標準演算モードを明確には定義していません。このモードが有効になっていると、これをサポートするプロセッサが IEEE 754 標準に準拠しない結果を生成する可能性があることを述べているだけです。ただし、このモードをサポートする既存の SPARC 実装はすべて、このモードを使用して段階的アンダーフローを無効にし、非正規オペランドと結果をゼロに置き換えます。
SPARC 実装すべてに非標準モードが用意されているわけではありません。このモードをサポートしていない SPARC 実装では、単に無視されるため、非標準モードでも数値結果と例外結果は同じです。これらのプロセッサでは、段階的アンダーフローでパフォーマンスが低下することはありません。
段階的アンダーフローがプログラムのパフォーマンスに影響しているかどうかを判断するには、最初にアンダーフローが発生しているかどうかを判断し、次にプログラムがどれだけのシステム時間を使用しているかを確認する必要があります。アンダーフローが発生しているかどうかを判断するには、数学ライブラリ関数 ieee_retrospective() を使用して、プログラムの終了時にアンダーフロー例外フラグが発生するかどうかを確認できます。Fortran プログラムはデフォルトで ieee_retrospective() を呼び出します。C および C++ プログラムは、終了する前に明示的に ieee_retrospective() を呼び出す必要があります。アンダーフローが発生した場合、 ieee_retrospective() が次のようなメッセージを出力します。
Note: IEEE floating-point exception flags raised: Inexact; Underflow; See the Numerical Computation Guide, ieee_flags(3M)
プログラムがアンダーフローに遭遇した場合、time コマンドでプログラムの実行時間を測定することによって、プログラムがどれだけのシステム時間を使用しているかを判断できます。
demo% /bin/time myprog > myprog.output real 305.3 user 32.4 sys 271.9
システム時間 (前述の出力の 3 番目の数値) が異常に高い場合、複数のアンダーフローが原因であると考えられます。この場合、プログラムが段階的アンダーフローの正確さに依存していなければ、非標準モードを有効にしてパフォーマンスを高めることができます。
そのためには、次の 2 つの方法を利用します。まず、マクロ –fast および –fnonstd の一部として暗黙的に指定されている –fns フラグを使用してコンパイルし、プログラムの起動時に非標準モードを有効にすることができます。次に、付加価値数学ライブラリ libsunmath では、非標準モードをそれぞれ有効および無効にする 2 つの関数を提供しており、nonstandard_arithmetic() を呼び出すと、非標準モードが有効になり (サポートされている場合)、 standard_arithmetic() を呼び出すと IEEE 動作が復元されます。これらの関数を呼び出す C および Fortran の構文は次のとおりです。
|
注意 - 非標準演算モードでは、段階的アンダーフローの利点である正確さが失われるため、使用の際は注意が必要です。段階的アンダーフローについての詳細は、Chapter 2, IEEE 演算を参照してください。 |
非標準モードを実装する SPARC 浮動小数点ユニットでは、このモードを有効にすると、ハードウェアが非正規オペランドをゼロとして扱い、非正規結果をゼロにフラッシュします。ただし、トラップした浮動小数点命令のエミュレートに使用されるカーネルソフトウェアは、非標準モードを実装していません。その理由の 1 つは、このモードの影響が定義されておらず、実装に依存するためであり、また 1 つは、段階的アンダーフローの処理にかかる追加コストが、ソフトウェアでの浮動小数点演算のエミュレーションのコストに比べれば微々たるものであるためです。
非標準モードの影響を受ける浮動小数点演算に割り込みが発生する場合 (たとえば、発行後にコンテキストスイッチが行われたり、別の浮動小数点命令によってトラップが発生したため完了しなかった場合など)、標準 IEEE 演算を使用して、カーネルソフトウェアによってエミュレーションされます。そのため、特殊な状況下では、非標準モードで実行しているプログラムが、システム負荷に応じてわずかに異なる結果を生成する可能性があります。実際には、この動作は観察されてはいません。これは、数百回の演算のうちある 1 つの演算が段階的アンダーフローと突発的アンダーフローのどちらで実行されるかということに対して感度の高いプログラムだけに影響すると考えられます。
コンパイラに付属の fpversion ユーティリティーは、装備されている CPU を識別し、プロセッサおよびシステムバスの クロック速度を推定します。fpversion は、CPU および FPU によって格納されている識別情報を解釈して、CPU と FPU の種類を特定します。このユーティリティーは、予測可能な所要時間内に動作する単純な命令を実行するループの時間を計測することによって、クロック速度を推定します。時間計測の正確さを高めるため、このループは何度も実行されます。このため、fpversion は即座には完了しません。実行には数秒かかる場合があります。
fpversion は、ホストシステムでの使用に最適な –xtarget コード生成オプションも報告します。
T4-2 サーバーでは、fpversion は次のような情報を表示します。これはタイミングやマシン構成の違いによって異なる場合があります。
demo% fpversion A SPARC-based CPU is available. Kernel says CPU's clock rate is 1500.0 MHz. Kernel says main memory's clock rate is 150.0 MHz. Sun-4 floating-point controller version 0 found. An UltraSPARC chip is available. Use "-xtarget=T4 -xcache=16/32/4/8:128/32/8/8:4096/64/16/64" code-generation option. Hostid = hardware_host_id
詳細は、fpversion(1) のマニュアルページを参照してください。