RISC では、Gforth エンジンは限りなく最適な状態に近くなります。 逆に、 通常、 RISC以外では、 顕著に高速なスレッド化コード・エンジンを作成することは不可能です。
386 アーキテクチャー・プロセッサのようにレジスターの数が不足しているマシンでは、 明示的なレジスター宣言があっても gcc
が人間ほどにはレジスターを利用しないため、 人間による改善が可能です。 たとえば、Bernd Beuster は Forth
システムの断片をアセンブリ言語で作成し、 486 用に手動で調整しました。 このシステムは、 486DX2/66 での Sieve ベンチマークでは、
-DFORCE_REG
を使用して gcc-2.6.3
でコンパイルした Gforth よりも 1.19 倍高速です。
この状況は gcc-2.95 と gforth-0.4.9 で改善されました。 これで、
最も重要な仮想マシンのレジスターが実際のレジスターに収まるようになり(更に、 TOS 最適化を使用する余裕さえあります)、 結果として以前の結果よりも
1.14 高速化されました。 また、動的スーパー命令によりさらに高速化が実現されます(ただし、 486 では約 1.2 倍にすぎません)。
アセンブリ言語で実装する潜在的な利点は、 Forth システムでは必ずしも現実のモノにはなりません。 Gforth
をアセンブリ言語で書かれたシステムと比較しました: Gforth-0.5.9 (直接スレッド化、 gcc-2.95.1
、
-DFORCE_REG
でコンパイル)、 Gforth-0.5.9 の Win32Forth 版 1.2093
(新しいバージョンははるかに高速であると報告されています))、 LMI の NT Forth (1994年5月のベータ版)、
Eforth(スレッド化されたコードののぞき穴(peephole; 別名 針の穴(pinhole))最適化の有無)。 また、Gforth を
C言語で書かれた 3 つのシステムと比較しました: PFE-0.9.14 (Linux のデフォルト構成で gcc-2.6.3
でコンパイル: -O2 -fomit-frame-pointer -DUSE_REGS -DUNROLL_NEXT
)、 ThisForth
Beta (gcc-2.6.3 -O3 -fomit-frame-pointer
でコンパイル; ThisForth
はスレッド化されたコードののぞき穴最適化を採用)、 TILE (make opt
でコンパイル)。 Linux 上の 486DX2/66
で、 Gforth と PFE と ThisForth と TILE のベンチマークを実行しました。 Kenneth O’Heskin は、
Windows NT で同様のメモリー・パフォーマンスを備えた 486DX2/66 上の Win32Forth と NT Forth
の結果を親切に提供してくれました。 Marcel Hendrix は Eforth を Linux に移植し、 ベンチマークを実行できるように拡張し、
覗き穴・オプティマイザーを追加してベンチマークを実行し、 結果を報告しました。
私たちは 4 つの小さなベンチマークを使用しました。 ユビキタスのふるい。 バブルソートと行列乗算はスタンフォード整数ベンチマーク由来で、 Martin Fraeman によって Forth に変換されました。 TILE Forth パッケージに含まれているバージョンを使用しましたが、 データ・セット・サイズが大きくなりました。 そして、 呼び出しパフォーマンス(calling performance)のベンチマークのための再帰的フィボナッチ数計算です。 以下の表は、 ベンチマークにかかる時間を Gforth にかかった時間で換算したものです(つまり、 Gforth が他のシステムに対して達成した高速化係数を示しています)。
relative Win32- NT eforth This- time Gforth Forth Forth eforth +opt PFE Forth TILE sieve 1.00 2.16 1.78 2.16 1.32 2.46 4.96 13.37 bubble 1.00 1.93 2.07 2.18 1.29 2.21 5.70 matmul 1.00 1.92 1.76 1.90 0.96 2.06 5.32 fib 1.00 2.32 2.03 1.86 1.31 2.64 4.55 6.54
あなたは、 アセンブリ言語で書かれたシステムと比較したとき、 Gforth の優れたパフォーマンスに驚かれるかもしれません。
これら他のシステムのパフォーマンスが期待外れである重要な理由の 1 つは、 おそらく、 それらが 486
用に最適化して書かれていないことです(たとえば、lods
命令を使用している)。 さらに、 Win32Forth は、 Forth
イメージを再配置するために快適ではありますがコストのかかる方法を使用します: これは cforth
と同様に、
実行時に実際のアドレスが計算され、 NEXT
毎に 2 つのアドレス計算が行われます(see Image File Background)。
PFE や ThisForth や TILE に対する Gforth の高速化は、 前者達のシステムが標準 C に対して自ら課した制限によって簡単に説明できます: これにより、 効率的なスレッド化が不可能になります(ただし、 観測された PFE の実装では GNU C 拡張機能が使用されています see Defining Global Register Variables in GNU C Manual)。 さらに言えば、 現在の C コンパイラーは、 ThisForth や TILE ソースの他の側面を最適化するのに苦労しています。
386 アーキテクチャー・プロセッサ上の Gforth のパフォーマンスは、 使用する gcc
のバージョンによって大きく異なります。
たとえば、gcc-2.5.8
は、 それ自身では仮想マシン・レジスターを実マシン・レジスターに割り当てることに失敗し、 かつ、
明示的なレジスター宣言では正しく動作しないため、 (Sieve ベンチマークを実行している 486DX2/66
では、)上記で測定したエンジンよりも大幅に遅いエンジンが出来上がります。
注意: ここで紹介したリリース以降、 Win32Forth のリリースがいくつかあるため、 上記の結果は現在の Win32Forth のパフォーマンスを予測する値がほとんどない可能性があることに注意してください(i486DX2/66 での現在のリリースの結果報告をお待ちしています)。
Translating Forth to Efficient C by M. Anton Ertl and Martin Maierhofer (presented at EuroForth ’95) では、 Gforth の間接スレッド化バージョンが、 Win32Forth や NT Forth や PFE や ThisForth や、 いくつかのネイティブ・コード・システムと比較されます。 そのバージョンの Gforth は、 486 ではここで使用されているバージョンよりも遅くなります。 これらの測定値の新しいバージョンは https://www.complang.tuwien.ac.at/forth/performance.html で見つけることができます。 あなたは Benchres でさまざまなマシン上の Gforth の数値を見つけることができます。