コメントに記載されているように、「現在のコンパイラ(Bigloo、SBCL、Gambit、Chickenなど)は、同等のCコードよりも20〜50倍遅い」と述べるのは正確ではありません。あなたがテストした。
以下のために私の使用、私は多くの事のためギャンビットとチキンスキームは、一般的に高速チキン(4.9.0.1)よりしかしギャンビット(4.7.3)の現在のバージョンでは、非常に近い速度で同等の「C」コードにしていることがわかり、事前オーバー-最適化出力「C」コード(利用可能なレジスタの数を想定-x686を想定)-追加のメモリ要件に対してスタックメモリの使用を強制します。この決定は、Chickenが行うように 'C'コンパイラに任せる必要があります。 「C」コンパイラーが独自の最適化を実行しないようにするための追加のレジスターと結合処理ステップの要件)非常にタイトな小さなループが「C」(またはチキン)の同じタイトな小さなループの約2倍の速度になる); Chickenは、与えられた関数にローカルとなる変数を定義します(ほとんどの場合不変に使用されます)。そして、コンパイラーに依存してそれらのほとんどを最適化します。鶏肉は
EDIT_ADD: 私はChickenおよびGambit-Cスキームバージョンについてさらに調査を行い、次のことを発見しました。
上記の理由により、小さなタイトなループの場合、ChickenはGambitよりも高速です(最適化は 'C'コンパイラーに依存し、それ自体は何もしないため、x86-64の余分なレジスターをより有効に活用します)。ループ内の「POLL」スタックメンテナンスチェック。Gambitはループ内の「POLL」チェックを含みます。これがトリガーされない場合(通常の場合)でも、何も必要でないと判断するのに数CPUクロックサイクルかかります(約6サイクル)。将来のよりスマートなコンパイラは、タイトなループの内側でスタック構築操作を行わずにスタックチェックを行う必要がないことを確認し、ループの直前または直後に行うことで、この時間を節約できます。
Gambitの「C」マクロは、特に固定スタックサイズの演算を含め、演算の実行方法を正確に定義する上で、あまりにも多くの作業を行います。これらは、「C」コンパイラが最適化するのが難しい可能性があります。レジスタをより効果的に使用すると、タイトなループ時間をおそらく4サイクル削減できます。
いずれも、適切な変更が行われ、コンパイラーが実行するようにコードを出力しない、たとえばベクター操作の「読み取り/変更/書き込み」最適化を出力しません。LLVMなどのよりスマートなバックエンドをHaskellで使用すると、このようなことが行われます。これにより、個別の読み取り、変更の計算、および同じ場所への書き込みではなく、単一の命令のみを使用する場合のレジスタの使用と実行時間が1つ削減されます。これは、変更(たとえば、または少し)の計算になり、次に読み取り変更(| =)書き込み単一命令になります。これにより、速度がサイクル程度速くなる可能性があります
どちらも動的に型指定され、データの「タグ」ビットをデータの一部として処理します。タイトなループがタグを削減し、「タグなし」でループを実行してから、タグをループからの結果に追加するのに十分なほどスマートではありません。場合によっては、これらの操作を組み合わせます。ここでの最適化により、ループにもよりますが、CPUサイクル数回程度ループ時間を短縮できます。
非常にタイトな「C」ループは、メモリキャッシュアクセス速度が抑制されていない高速のCPU(AMD Bulldozerなど、約2倍遅い)では、ループごとに約3.5 CPUクロックサイクルかかる可能性があります。Chickenの同じループは現在約6サイクルかかり、Gambitは約16.9サイクルかかります。上記のすべての最適化により、Schemeのこれらの実装がそれを実行できなかった理由はありませんが、いくつかの作業が必要です。
Gambitの場合、より困難な作業は、「POLL」テストを挿入する必要がない場合を認識するようにフロー分析を改善することです(つまり、これは割り込み駆動である可能性がありますが、コンパイラーは一部の用途で割り込みをオフにすることを許可しますか? ); より簡単な改善は、より良いレジスタ使用法を実装することです(つまり、デフォルトのx686アーキテクチャよりもx86-64レジスタをよりよく認識します)。どちらの場合も、フロー分析は、データ、特に「fixnum」、「flonum」、およびベクトルのデータの「タグ付けを解除」できることを認識し、これらの操作がタイトなループ内で必要なく、読み取り/変更/書き込み命令を組み合わせる必要がないことを認識します。これらの目的は両方とも、LLVMなどのより優れたバックエンドを使用することで達成できます(些細な作業ではありませんが、両方とも既に部分的に存在しています)。
結論:チキンは現在、最速のCPUで「C」よりも約50%遅く(「ブルドーザー」ではなく、「C」コードのキャッシュスロットリングによりほぼ同じ速度です)、Gambitは約400%遅くなっています(約遅いブルドーザーでは125%遅くなります)。ただし、コンパイラの将来の改善により、コードが「C」より遅くならないように、またはOPが指定するマージン内に収まるように、これを減らすことができます。
Haskellなどのより複雑な言語。LLVMバックエンドを使用するときは、厳格な使用(デフォルトでは常に熱心なスキームの問題ではない)に注意を払い、適切なデータ構造(タイトループのリストではなくSTボックス化されていない配列)を使用します。スキームをベクトルを使用して多少適用可能)、LLVMバックエンドが完全な最適化で使用されている場合、「C」とほぼ同じ速度で実行されます。これが可能であれば、Schemeでも上記のコンパイラーの改善を行うことができます。
再び、これらのいずれかが適切な最適化フラグと一緒に使用された場合、20倍から50倍遅いということはありません。END_EDIT_ADD
もちろん、本番環境の場合のように適切な最適化設定を使用しないと、すべてのベンチマークが無効になります...
商用のChez Schemeコンパイラは、GambitやChickenと同じように高パフォーマンスの出力を生み出すのに大いに役立つと思います。商用であることには確かに「かなりの時間とお金が費やされている」からです。
GambitまたはChickenを「Cの20〜50倍」の速度で実行できる唯一の方法は、最適化設定を使用しないことです。この場合、REPLで解釈されるよりも速く実行されないことがよくあります。 -これらの設定を適切に使用するよりも数十倍遅い。
OPがこれらの設定を適切に使用してテストされていない可能性はありますか?
OPがテスト手順を明確にすることに関心がある場合は、この回答を喜んで編集して、少なくともGambitとChickenがそれほど遅くなくてもよいことを示します。
(declare (optimize ...))
、(declare (<type> <var))
および(the <type> <expr>)
関数でテストしたと思いますか?そうでなければ、それはほとんど公平な比較ではありません:)