web-dev-qa-db-ja.com

科学計算におけるF#のパフォーマンス

F#のパフォーマンスとC++のパフォーマンスの比較について知りたいのですが。 Javaについても同様の質問をしましたが、Javaは大量の数値処理には適していません。

F#の方がスケーラブルでパフォーマンスが高いはずですが、実際のパフォーマンスはC++と比べてどうですか。現在の実装に関する特定の質問は次のとおりです。

  • 浮動小数点はどの程度うまく機能しますか?
  • ベクトル命令を許可しますか
  • コンパイラーの最適化に向けてどれほど親切ですか?
  • それはどのくらいのメモリフットプリントを持っていますか?メモリの局所性をきめ細かく制御できますか?
  • クレイなどの分散メモリプロセッサ用の容量はありますか?
  • 重い数の処理が関係する計算科学にとって興味深い可能性のある機能は何ですか?
  • それを使用する実際の科学計算の実装はありますか?

ありがとう

72
Anycorn
  • F#は、.NET CLRで可能な限り高速に浮動小数点計算を行います。 C#や他の.NET言語とそれほど大きな違いはありません。
  • F#はそれ自体でベクトル命令を許可しませんが、CLRにこれらのAPIがある場合、F#はそれを使用する際に問題を抱えてはなりません。たとえば Mono を参照してください。
  • 私の知る限りでは、現時点ではF#コンパイラは1つしかありません。そのため、「最適化に関しては、F#コンパイラはどの程度優れているのでしょうか?」いずれにせよ、答えは「潜在的にC#コンパイラと同等か、おそらく現時点では少し悪い」です。 F#は、たとえば、コンパイル時のインライン化をサポートするC#。これにより、ジェネリックスに依存するより効率的なコードが可能になります。
  • F#プログラムのメモリフットプリントは、他の.NET言語のものと同様です。割り当てとガベージコレクションを制御する量は、他の.NET言語と同じです。
  • 分散メモリのサポートについて知りません。
  • F#には、フラットなデータ構造を処理するための非常に優れたプリミティブがあります。配列とリスト。たとえば、配列モジュールの内容を見てください:map、map2、mapi、iter、fold、Zip ...配列は科学計算で人気があります。それらは本質的に優れたメモリ局所性プロパティがあるためです。
  • F#を使用する科学計算パッケージの場合は、Jon Harropが実行していることを確認する必要があります。
40
Joh

F#のパフォーマンスとC++のパフォーマンスの比較について知りたいのですが。

アプリケーションによって大きく異なります。マルチスレッドプログラムで高度なデータ構造を広範囲に使用している場合は、F#が大いに役立ちます。配列を変更するタイトな数値ループにほとんどの時間を費やしている場合、C++は2〜3倍高速になる可能性があります。

ケーススタディ:レイトレーサー私のベンチマーク here は、階層的カリングにツリーを使用し、数値の光線と球の交差コードを使用して出力を生成します画像。このベンチマークは数年前のものであり、C++コードは何年にもわたって何十回も改善され、何十万人もの人が読んでいます。 MicrosoftのDon Symeは、MSVCでコンパイルしてOpenMPを使用して並列化した場合、最速のC++コードよりも少し速いであるF#実装を作成することができました。

F#の方がスケーラブルでパフォーマンスが高いはずですが、実際のパフォーマンスはC++と比べてどうですか。

コードの開発は、C++よりもF#の方がはるかに簡単で高速です。これは、最適化とメンテナンスに適用されます。したがって、プログラムの最適化を開始すると、C++の代わりにF#を使用すると、同じ量の労力でパフォーマンスが大幅に向上します。ただし、F#はより高水準の言語であるため、パフォーマンスの上限は低くなります。したがって、最適化に費やす時間が無限にある場合は、理論上は常に、C++でより高速なコードを生成できる必要があります。

もちろん、これはC++がFortranを超え、Fortranが手書きのアセンブラを超えていたのとまったく同じ利点です。

ケーススタディ:QR分解これは、LAPACKなどのライブラリによって提供される線形代数からの基本的な数値法です。 LAPACKのリファレンス実装は、Fortranの2,077行です。同じレベルのパフォーマンスを実現する80行未満のコードで F#実装 を記述しました。しかし、リファレンス実装は高速ではありません。IntelのMath Kernel Library(MKL)などのベンダーが調整した実装は、多くの場合10倍高速です。驚くべきことに、F#コードを適切に最適化することができましたbeyondコードを150行未満に保ち、完全に汎用的なコード(単精度と倍精度、および複雑なものを処理できます)を維持しながら、インテルのハードウェアで実行されるインテルの実装のパフォーマンスシンボリック行列も!):高い細い行列の場合、私のF#コードはIntel MKLより最大3倍高速です。

このケーススタディの教訓は、F#がベンダー調整ライブラリよりも高速であることを期待する必要があるということではなく、低レベルの言語しか使用しない場合、Intelのような専門家でさえ、生産的な高レベルの最適化を見逃すことに注意してください。 Intelの数値最適化の専門家は並列処理を完全に活用できなかったと思います。なぜなら、F#では並列処理が非常に面倒であるのに対し、F#では並列処理が困難だからです。

浮動小数点はどの程度うまく機能しますか?

パフォーマンスはANSI Cに似ていますが、一部の機能(丸めモードなど)は.NETから利用できません。

ベクトル命令を許可しますか

番号。

コンパイラーの最適化に対して、どれほど親切ですか?

この質問は意味がありません。F#は、単一のコンパイラを備えたMicrosoftの独自の.NET言語です。

それはどのくらいのメモリフットプリントを持っていますか?

空のアプリケーションはここでは1.3Mbを使用します。

メモリの局所性をきめ細かく制御できますか?

ほとんどのメモリセーフ言語より優れていますが、Cほどではありません。たとえば、F#で任意のデータ構造を「構造体」として表現することにより、それらのボックスを解除できます。

クレイなどの分散メモリプロセッサの容量はありますか?

「容量」の意味によって異なります。そのCrayで.NETを実行できる場合は、F#でメッセージパッシングを使用できます(次の言語と同じように)が、F#は主にデスクトップマルチコアx86マシン用です。

重い数の処理が関与する計算科学にとって興味深い可能性のある機能は何ですか?

メモリの安全性とは、セグメンテーション違反やアクセス違反が発生しないことを意味します。 .NET 4での並列処理のサポートは良好です。 Visual Studio 2010のF#インタラクティブセッションを介してオンザフライでコードを実行する機能は、インタラクティブテクニカルコンピューティングに非常に役立ちます。

それを使用する実際の科学計算の実装はありますか?

私たちの 商用製品 F#での科学計算用には、すでに何百人ものユーザーがいます。

ただし、あなたの質問の行は、科学計算を高性能の計算(例:Cray)であり、インタラクティブな技術計算(例:MATLAB、Mathematica)ではないと考えていることを示しています。 F#は後者を対象としています。

62
Jon Harrop

他の人が言ったことに加えて、F#について重要な点が1つあります。それはparallelismです。通常のF#コードのパフォーマンスはCLRによって決まりますが、F#からLAPACKを使用できる場合や、プロジェクトの一部としてC++/CLIを使用してネイティブコールを実行できる場合があります。

ただし、適切に設計された関数型プログラムは、並列化がはるかに容易になる傾向があります。つまり、マルチコアCPUを使用することで、簡単にパフォーマンスを得ることができます。ここにいくつかの関連リンクがあります:

分散コンピューティングに関しては、.NETプラットフォームで利用可能な任意の分散コンピューティングフレームワークを使用できます。 F#で適切に動作するMPI.NETプロジェクトがありますが、MSRプロジェクトであるDryadLINQを使用することもできます。

42
Tomas Petricek

すべての言語/パフォーマンスの比較と同様に、マイレージは、コードをどれだけうまく記述できるかに大きく依存します。

F#はOCamlの派生物です。 OCamlは、数値計算のパフォーマンスが非常に重要である金融業界で多く使用されていることを知って驚きました。 OCamlが最速のCおよびC++コンパイラーと同等のパフォーマンスを備えた高速言語の1つであることを知って、さらに驚きました。

F#は [〜#〜] clr [〜#〜] に基づいて構築されています。 CLRでは、コードはCommon Intermediate Languageと呼ばれるバイトコードの形式で表現されます。そのため、コードが適切に記述されていれば、JITの最適化機能の恩恵を受け、C#(必ずしもC++とは限りません)に匹敵するパフォーマンスが得られます。

CILコードは、ネイティブイメージジェネレーター(NGEN)を使用することにより、ランタイム前の別のステップでネイティブコードにコンパイルできます。これにより、CILからネイティブへのコンパイルが不要になるため、ソフトウェアの以降のすべての実行が高速化されます。

考慮すべき1つのことは、F#のような関数型言語は、より宣言的なプログラミングスタイルの恩恵を受けるということです。ある意味では、C++などの命令型言語でソリューションを過剰に指定しているため、最適化するコンパイラの機能が制限されます。より宣言的なプログラミングスタイルは、理論的には、コンパイラーにアルゴリズム最適化の追加の機会を与えることができます。

16
Robert Harvey

それは、どのような科学計算を行っているかによって異なります。

traditional heavy computing、例:線形代数、さまざまな最適化を行う場合は、コードを.Netフレームワークに配置しないでください。少なくともF#には適していません。これはアルゴリズムレベルであるため、実行時間とメモリ使用量のパフォーマンスを向上させるには、ほとんどのアルゴリズムを命令型言語でコーディングする必要があります。他の人は並列について言及しましたが、並列SVD実装のような低レベルのものを実行するときにはおそらく役に立たないと言う必要があります。 SVDを並列化する方法を知っている場合は、高水準言語を使用しないだけなので、Fortran、C、または変更されたC(例: cilk )がお友達です。

しかし、今日の科学計算の多くはこの種のものではありません。これは、ある種の高レベルのアプリケーションです。統計計算とデータマイニング。これらのタスクには、線形代数、または最適化の他に、データフロー、IO、前提、グラフィックスなどが多数あります。これらのタスクでは、F#は非常に強力で、簡潔さ、機能性、安全性、およびパラレルなど.

他の人が述べたように、.NetはPlatform Invokeを十分にサポートしています。実際、MS内のかなりの数のプロジェクトが.NetとP/Invokeを一緒に使用してボトルネックのパフォーマンスを向上させています。

9
Yin Zhu

残念ながら、信頼できる情報がたくさんあるとは思いません。 F#はまだ非常に新しい言語であるため、パフォーマンスの高いワークロードに理想的に適していたとしても、かなりの経験を積んで報告する人はそれほど多くありません。さらに、パフォーマンスを正確に測定することは非常に難しく、マイクロベンチマークを一般化することは困難です。 C++内でも、コンパイラー間の劇的な違いを見ることができます-F#がanyC++コンパイラーと競合するのか、または架空の「可能な限り」と競合するのか疑問に思いますかC++実行可能ファイル?

C++に対する特定のベンチマークについて、関連する可能性のあるリンクをいくつか示します。 O'Caml vs. F#:QR分解 ; F#と並列数値のアンマネージC++ 。 F#関連資料の作成者およびF#ツールのベンダーとして、作者はF#の成功に既得権を持っていることに注意してください。したがって、これらの主張には細心の注意を払ってください。

F#が実行時間で競争しているアプリケーションもあれば、そうでないアプリケーションもあると言っても差し支えないと思います。ほとんどの場合、F#はおそらくより多くのメモリを必要とします。もちろん、最終的なパフォーマンスはプログラマーのスキルにも大きく依存します。F#は、適度に有能なプログラマーにとって、プログラミングするためのより生産的な言語になると思います。さらに、現時点では、WindowsのCLRは、ほとんどのタスクでほとんどのOSのMonoよりもパフォーマンスが良いと思います。もちろん、F#はC++よりも並列化が簡単なため、実行する予定のハードウェアの種類にも依存します。

最終的に、この質問に本当に答える唯一の方法は、実行する計算のタイプを表すF#およびC++コードを記述して、それらを比較することだと思います。

7
kvb

ここに私が共有できる2つの例があります:

  1. 行列乗算:私はブログ投稿 さまざまな行列乗算実装の比較 を行っています。

  2. LBFGS

C++でコーディングされているLBFGS最適化を使用した大規模ロジスティック回帰ソルバーがあります。実装は十分に調整されています。一部のコードをC++/CLIのコードに変更しました。つまり、コードを.Netにコンパイルしました。 .Netバージョンは、異なるデータセットでコンパイルされた単純なバージョンよりも3〜5倍遅くなります。 LBFGSをF#でコーディングする場合、パフォーマンスはC++/CLIまたはC#よりも優れていることはありません(ただし、非常に近いです)。

F#がデータマイニングの言語である理由 に関する別の投稿がありますが、ここで懸念するパフォーマンスの問題とはあまり関係ありませんが、F#の科学計算にかなり関係しています。

4
Yin Zhu

「2〜3年後にもう一度尋ねてください」と言ったら、あなたの質問に完全に答えると思います:-)

まず、わざと複雑な再帰を意図的に行っており、数値について質問して以来そうでないと思わない限り、F#がC#パフォーマンスと異なるとは思わないでください。

浮動小数点に関しては、Javaより優れている必要があります。CLRはクロスプラットフォームの均一性を目指していないため、JITはできる限り80ビットに移行します。反対側では十分なFPレジスタが存在することを確認するために変数の数を監視する以外に、それを制御することはできません。

ベクトル的に言えば、Direct3Dが一般的なAPIとして.NETに入っており、XNAで実行されるC#コードがXboxで実行されているため、2〜3年で何かが発生すると、CLRで取得できるベアメタルに近づきます。それでも、自分で中間コードを作成する必要があることを意味します。

そのため、CUDAや、NVIDIA libsをリンクするだけの機能を期待しないでください。 Haskellは必要以上にリンクしやすいように設計されているので、何らかの理由で本当に「関数型」言語が本当に必要な場合は、Haskellでこのアプローチを試してみるとはるかに幸運になります。

Mono.Simdは既に言及されており、CLRにバック移植可能である必要がありますが、実際にそれを行うにはかなりの作業になる可能性があります。

そこには、.NETでのSSE3の使用に関する social.msdnポスティング のかなりのコード、C++/CLIとC#の使用、配列ブリット、perf用のSSE3コードの挿入などがあります。

コンパイルされたC#で [〜#〜] cecil [〜#〜] を実行してパーツをHLSLに抽出し、シェーダーにコンパイルして、グルーコードをリンクしてスケジュールする(CUDAが同等のとにかく)でも、そこから実行可能なものが出てくるとは思いません。

すぐに何かを試してみたいなら、もっと価値のあるものは PhysX.Net on codeplex です。単に解凍して魔法をかけるとは思わないでください。ただし、ihには現在アクティブな作成者がおり、コードは通常のC++とC++/CLIの両方であり、詳細に進み、CUDAに同様のアプローチを使用したい場合は、yopuが作成者から助けを得ることができます。フルスピードのCUDAの場合は、独自のカーネルをコンパイルしてから.NETにインターフェースするだけでよいので、その部分が簡単になり、幸せになります。

無料であるはずの CUDA.NET libがありますが、ページには電子メールアドレスしか表示されないので、いくつかの文字列が添付されていることを期待し、著者が blog を書いている間にライブラリの内容については特におしゃべりではありません。

ああ、あなたが予算を持っているなら、あなたはそれを与えるかもしれません Psi Lambda 一見(KappaCUDAnetは.NETの部分です)。どうやら彼らは11月に価格を引き上げようとしている(それがセールストリックでない場合:-)

3
ZXX

まず、CはC++よりも大幅に高速です。したがって、非常に高速な処理が必要な場合は、libなどをcで作成する必要があります。

F#に関して、ほとんどのベンチマークは、Boehm GCの使用が原因でMS CLRよりも最大2 *遅いMonoを使用します(新しいGCとLVVMがありますが、これらはまだジェネリックをサポートしておらず、ジェネリックをサポートしていません)。

.NEt言語自体はIR(CIL)にコンパイルされ、C++と同じくらい効率的にネイティブコードにコンパイルされます。ほとんどのGC言語で問題となる1つの問題セットがあり、それは大量の変更可能な書き込みです(これには、前述のC++ .NETが含まれます)。そして、これを必要とする特定の科学的な問題セットがあり、これらはおそらくネイティブライブラリを使用するか、Flyweightパターンを使用してプールからオブジェクトを再利用する必要があります(書き込みを減らします)。その理由は、.NET CLRに書き込みバリアがあり、参照フィールド(ボックスを含む)を更新すると、テーブルにビットが設定され、このテーブルが変更されたことを通知するためです。コードがそのような多数の書き込みで構成されている場合、影響を受けます。

多くの静的コード、構造体、構​​造体へのref/outを使用するC#のような.NETアプリは、Cのようなパフォーマンスを生成できますが、このようにコーディングしたり、コード(Cのように)を維持することは非常に困難です。

ただし、F#が優れているのは、読み取りベースの問題が増え続ける不変データに対する並列性です。ほとんどのベンチマークは、変更可能な書き込みでは実際のアプリケーションよりもはるかに高いことに注意してください。

浮動小数点に関しては、速度が遅いため、oCamlのものに代わるlib(つまり.Netのもの)を使用する必要があります。 C/C++は、oCamlがデフォルトでは行わない、より低い精度でより高速にできます。

最後に、C#、F#などの高水準言語と適切なプロファイリングにより、同じ開発時間でCやC++より優れたパフォーマンスが得られると主張します。ボトルネックをc lib pinvoke呼び出しに変更すると、重要な領域のパフォーマンスもCのようになります。それはあなたが無制限の予算を持っていて、スピードをもっと気にかけているなら、Cよりもメンテナンスが行く方法です(C++ではありません)。

1
ben

最後に、ほとんどの科学計算はまだFORTRANで行われていました。線形代数の問題については、Java、C、C++、C#、F#ではなく、何よりも高速です。 LINPACKは適切に最適化されています。

しかし、「マイレージは異なる場合があります」という発言は、すべてのベンチマークに当てはまります。ブランケットステートメント(私のものを除く)が真実であることはめったにありません。

1
duffymo