科学ソフトウェアは、チューニングが必要なものを知る方法に関しては、他のソフトウェアとそれほど違いはありません。
私が使用する方法は、ランダムな一時停止です。私が見つけた高速化の一部を以下に示します。
時間の大部分がlog
やなどの関数に費やされexp
ている場合、それらが呼び出されているポイントの関数として、それらの関数の引数が何であるかを見ることができます。多くの場合、同じ引数で繰り返し呼び出されます。もしそうなら、メモすることは大きなスピードアップ要因を生み出します。
BLASまたはLAPACK関数を使用している場合、配列のコピー、行列の乗算、コレスキ変換などのルーチンにかなりの時間が費やされることがあります。
配列をコピーするルーチンは速度のためではなく、利便性のためにあります。それほど便利ではないが、より高速な方法があります。
行列を乗算または反転する、またはコレスキ変換を行うルーチンには、上三角または下三角の「U」または「L」などのオプションを指定する文字引数が含まれる傾向があります。繰り返しになりますが、これらは便宜上のものです。私が見つけたのは、マトリックスがそれほど大きくないため、ルーチンは、オプションを解読するためだけに文字を比較するサブルーチンを呼び出す時間の半分以上を費やしていたということです。最も高価な数学ルーチンの特別な目的のバージョンを書くと、大幅に高速化されました。
後者を拡張できる場合:行列乗算ルーチンDGEMMはLSAMEを呼び出して、文字引数をデコードします。包括的パーセント時間(見る価値のある唯一の統計)を見ると、「良い」と見なされるプロファイラーは、80%などの合計時間の数パーセントを使用してDGEMMを示し、50%などの合計時間の数パーセントを使用してLSAMEを表示できます 前者を見ると、「それは十分に最適化されている必要があるので、それについて私ができることはあまりない」と言いたくなるでしょう。後者を見ると、「ハァッ、それは何なの?それはほんの小さなルーチンです。このプロファイラーは間違っているに違いありません!」と言いたくなるでしょう。
それは間違っていません、あなたが知る必要があることをあなたに言っていないだけです。ランダムに一時停止すると、DGEMMがスタックサンプルの80%にあり、LSAMEが50%にあることがわかります。(それを検出するのに多くのサンプルは必要ありません。通常は10で十分です。)さらに、これらのサンプルの多くで、DGEMMは2、3の異なるコード行からLSAMEを呼び出しています。
これで、なぜ両方のルーチンが包括的な時間を費やしているのかがわかりました。また、この時間を費やすためにコードのどこから呼び出されているかも知っています。だからこそ、私はランダムな一時停止を使用し、プロファイラーがどれほどよく作られていても、プロファイラーを慎重に見ます。彼らは、何が起こっているかを伝えることよりも、測定値を取得することに関心があります。
数学ライブラリルーチンがn番目の程度に最適化されていると仮定するのは簡単ですが、実際、それらは幅広い目的に使用できるように最適化されています。推測しやすいものではなく、実際に何が起こっているのかを確認する必要があります。
追加:最後の2つの質問に答えるために:
最初に試すべき最も重要なことは何ですか?
10〜20個のスタックサンプルを取り、それらを要約するだけでなく、それぞれがあなたに言っていることを理解してください。これを最初に、最後に、そしてその間に行います。(「試用」はありません、若いスカイウォーカー。)
どれだけのパフォーマンスが得られるかを知るにはどうすればよいですか?
バツβ(s + 1 、(n − s )+ 1 )sn1 /(1 − x )n = 10s = 5バツ
バツバツ
以前に指摘したように、これ以上できなくなるまで手順全体を繰り返すことができ、複合化された高速化率は非常に大きくなる可能性があります。
(S + 1 )/(N + 2 )= 3 / 22 = 13.6 %。)次のグラフの下部の曲線はその分布です。
40個ものサンプル(一度に持っているものよりも多い)を取り、そのうちの2つだけで問題が発生したかどうかを検討してください。より高い曲線に示すように、その問題の推定コスト(モード)は5%です。
「誤検知」とは何ですか?問題を修正した場合、予想よりも非常に小さなゲインを実現するため、修正したことを後悔します。曲線は(問題が「小さい」場合)、ゲインはそれを示すサンプルの割合よりも小さい可能性がありますが、平均して大きくなることを示しています。
はるかに深刻なリスクがあります-「偽陰性」。それは問題があるときですが、見つかりません。(これに貢献しているのは「確認バイアス」であり、証拠の欠如は、欠如の証拠として扱われる傾向があります。)
あなたはプロファイラ(良いもの)を取得することで、問題が実際にどの程度あまり正確な情報を犠牲にし、はるかに正確な測定(偽陽性のため、少ないチャンスを)取得されている(それを見つけると取得のため、少ないチャンス任意のゲイン)。これにより、達成可能な全体的な高速化が制限されます。
プロファイラーのユーザーには、実際に実際に得られるスピードアップ要因を報告することをお勧めします。
再作成する別のポイントがあります。偽陽性に関するペドロの質問。
彼は、高度に最適化されたコードで小さな問題に取りかかるのは難しいかもしれないと述べました。(私にとって、小さな問題は、合計時間の5%以下を占める問題です。)
5%を除いて完全に最適なプログラムを構築することは完全に可能であるため、この点はこの回答のように経験的にしか対処できません。経験的経験から一般化するには、次のようになります。
書かれているように、プログラムには通常、最適化の機会がいくつか含まれています。(これらを「問題」と呼ぶこともできますが、多くの場合、完全に優れたコードであり、単にかなりの改善が可能です。)この図は、ある程度の時間(たとえば100秒) ...見つかって修正すると、元の100の30%、21%などを節約できます。
問題Fのコストは元の時間の5%であるため、「小さな」問題であり、40以上のサンプルがないと見つけることは困難です。
ただし、最初の10個のサンプルで問題Aを簡単に見つけることができます。**これが修正されると、プログラムは70秒しかかかりません。100/ 70 = 1.43xの高速化です。これはプログラムを高速化するだけでなく、残りの問題が占める割合をその比率で拡大します。たとえば、問題Bは元々21秒で合計21%でしたが、Aを削除すると、Bは70秒のうち21秒、つまり30%になります。したがって、プロセス全体が繰り返されるときを見つけやすくなります。
プロセスが5回繰り返されると、実行時間は16.8秒になり、そのうち問題Fは5%ではなく30%であるため、10個のサンプルで簡単に見つけることができます。
それがポイントです。経験的に、プログラムにはサイズの分布を持つ一連の問題が含まれており、問題を見つけて修正すると、残りの問題を簡単に見つけることができます。これを達成するために、問題をスキップすることはできません。問題がある場合は、時間がかかり、全体の高速化が制限され、残りの問題が拡大されないためです。
そのため、隠れている問題を見つけることが非常に重要です。
問題A〜Fが見つかって修正された場合、スピードアップは100 / 11.8 = 8.5xです。それらのいずれかが欠落している場合、たとえばDの場合、スピードアップは100 /(11.8 + 10.3)= 4.5xのみです。
それが偽陰性の代価です。
そのため、プロファイラーが「ここに重大な問題はないようだ」(つまり、優れたコーダー、これは実際に最適なコードです)と言うとき、それは正しいかもしれませんし、そうでないかもしれません。(偽陰性。)高速化のために、別のプロファイリング方法を試して問題があることを発見しない限り、修正すべき問題があるかどうかはわかりません。私の経験では、プロファイリング方法は、多数のサンプルを要約する必要はなく、少数のサンプルが必要です。各サンプルは、最適化の機会を認識するのに十分に理解されています。
2 / 0.3 = 6.671 - pbinom(1, numberOfSamples, sizeOfProblem)
1 - pbinom(1, 20, 0.3) = 0.9923627
xβ(s+1,(n−s)+1)nsy1/(1−x)xyy−1BetaPrimeディストリビューション。私はこの振る舞いに到達する200万のサンプルでそれをシミュレートしました:
distribution of speedup
ratio y
s, n 5%-ile 95%-ile mean
2, 2 1.58 59.30 32.36
2, 3 1.33 10.25 4.00
2, 4 1.23 5.28 2.50
2, 5 1.18 3.69 2.00
2,10 1.09 1.89 1.37
2,20 1.04 1.37 1.17
2,40 1.02 1.17 1.08
3, 3 1.90 78.34 42.94
3, 4 1.52 13.10 5.00
3, 5 1.37 6.53 3.00
3,10 1.16 2.29 1.57
3,20 1.07 1.49 1.24
3,40 1.04 1.22 1.11
4, 4 2.22 98.02 52.36
4, 5 1.72 15.95 6.00
4,10 1.25 2.86 1.83
4,20 1.11 1.62 1.31
4,40 1.05 1.26 1.14
5, 5 2.54 117.27 64.29
5,10 1.37 3.69 2.20
5,20 1.15 1.78 1.40
5,40 1.07 1.31 1.17
(n+1)/(n−s)s=ny
これは、5、4、3、および2つのサンプルのうち2つのヒットに対する、高速化係数の分布とその平均のプロットです。たとえば、3つのサンプルが取得され、そのうち2つが問題でヒットし、その問題を除去できる場合、平均的な高速化係数は4倍になります。2つのヒットが2つのサンプルのみで見られる場合、平均的なスピードアップは未定義です-概念的には、無限ループを持つプログラムがゼロ以外の確率で存在するためです!