9

私の博士号の一環として。研究では、大気と海洋循環の数値モデルの開発に取り組んでいます。これらには、約 10^4 時間ステップにわたって、約 10^6 格子点の PDE のシステムを数値的に解くことが含まれます。したがって、典型的なモデル シミュレーションは、数十の CPU で MPI を実行すると、完了するまでに数時間から数日かかります。当然のことながら、結果がバイトごとに同一であることを確認しながら、可能な限りモデルの効率を改善することが重要です。

私は自分の Fortran プログラミングに非常に満足しており、コードをより効率的にするためのいくつかのトリックを認識していますが、まだ改善の余地があり、気付いていないトリックがあると感じています。

現在、使用する除算をできるだけ少なくし、リテラル定数を使用しないようにしています (非常に早い段階からこれを行うように教えられました。たとえば、実際の計算では 0.5 の代わりに half=0.5 を使用します)。超越関数はできるだけ使用しません。などなど。

他にどのようなパフォーマンスに敏感な要素がありますか? 現時点では、私はいくつかについて疑問に思っています:

1) 数学演算の順序は重要ですか? たとえば、私が持っている場合:

a=1E-7 ; b=2E4 ; c=3E13
d=a*b*c

乗算の順序に基づいて異なる効率で評価しますか? 現在、これはコンパイラ固有のものでなければなりませんが、明確な答えはありますか? d が次数 (精度限界) に基づいて (わずかに) 異なる値を取得していることに気付きましたが、これは効率に影響しますか?

2) サブルーチン内のモジュールからこれらの配列にアクセスするのと比較して、サブルーチンへの引数として多数 (たとえば、数十個) の配列を渡しますか?

3) Fortran 95 構造 (FORALL および WHERE) と DO および IF との違いは? コードのベクトル化が大きな問題だった 90 年代にこれらが重要だったことは知っていますが、明示的な DO ループをベクトル化できる最新のコンパイラーとの違いはありますか? (私は仕事で PGI、Intel、および IBM コンパイラーを使用しています)

4) 数値を整数乗するか、掛け算するか? 例えば:

b=a**4

また

b=a*a*a*a

私は、可能な場合は常に後者を使用するように教えられてきました。これは効率や精度に影響しますか? (おそらくコンパイラにも依存します)

Fortran コードの効率を改善するために知っているトリックやヒントがあれば、議論したり追加したりしてください。他に何がありますか?上記の各コンパイラがこの質問に関連して何をするかについて何か知っている場合は、それも含めてください。

追加: ボトルネックやパフォーマンスの問題自体はありません。操作の意味でコードを最適化するための一般的なルールがあるかどうかを尋ねています。

ありがとう!

4

3 に答える 3

12

申し訳ありませんが、あなたが言及したすべてのトリックは単純に...ばかげています。より正確には、それらは実際には意味がありません。例えば:

  • 0.5の代わりにhalf(= 0.5)を使用する利点は何でしょうか?
  • コンピューティング用のidema**4またはa*a*a*a(a*a)** 2別の可能性もあります。私の個人的な好みはa**4です。なぜなら、自動的に最良の方法を選択する優れたコンパイラーだからです。

の場合**、重要になる可能性がある唯一のポイントはとの違いでa ** 4ありa ** 4.、後者はCPU時間をはるかに消費します。しかし、この点でさえ、実際のシミュレーションでの測定なしには意味がありません。

実際、あなたのアプローチは間違っています。可能な限りコードを開発します。その後、コードのさまざまな部分のコストを客観的に測定します。以前に測定せずに最適化することは、単に無意味です。

パーツがCPUの高い割合(たとえば50%)を示す場合、そのパーツを最適化しても、コード全体のコストを2より大きい係数で割ることはできないことを忘れないでください。とにかく、最も高価な部分(ボトルネック)から最適化作業を開始します。

また、主な改善点は一般的に、より優れたアルゴリズムによるものであることも忘れないでください。

于 2011-10-15T19:05:48.943 に答える
10

あなたが教えられてきたこれらのトリックは、この時代にはばかげているというアドバイスを支持します. コンパイラがこれを行います。このようなマイクロ最適化が大きな違いを生む可能性は低く、移植性がない可能性があります。明確でわかりやすいコードを記述します。アルゴリズムを慎重に選択してください。違いを生むことができることの1つは、多次元配列のインデックスを正しい順序で使用することです.MXN配列をNXMに再キャストすると、プログラムによるデータアクセスのパターンに応じて役立ちます. この後、プログラムが遅すぎる場合は、CPU を消費している部分を測定し、その部分だけを改善します。経験上、推測はしばしば間違っており、理由もなく不透明なコードを書くことになります。プログラムがその時間の 1% を 2 倍の速さで費やすコード セクションを作成しても、違いはありません。

FORALL と WHERE に関する以前の回答は次のとおりです。 Fortran FORALL 構造が並列化されていることを確認するにはどうすればよいですか? WHERE 、FORALL、SPREAD などの Fortran 95 構造体は、通常、並列コードを高速化しますか?

于 2011-10-15T20:55:16.163 に答える
8

何をすべきかについてアプリオリなアイデアがあり、それらのいくつかは実際に役立つかもしれませんが、最大の見返りは事後分析にあります。
(追加:言い換えれば、a*b*c別の順序に入ることで数サイクルを節約できるかもしれません (私は疑います) と同時に、正当な理由もなく 1000 サイクルを費やしている何かによって不意を突かれていないことを知りません) .)

どんなに慎重にコーディングしても、予測していなかった高速化の機会があります。これが私がそれらを見つける方法です。(この方法は議論の余地があると考える人もいます)。

これを行うときは、最適化フラグをオフにして開始することをお勧めします。これにより、コードがすべて混乱することはありません。後でそれらをオンにして、コンパイラーに任せることができます。

適切な時間実行できるように、十分なワークロードを備えたデバッガーで実行します。実行中は、手動で中断し、実行内容と理由を詳しく調べてください。これを数回 (10 回など) 行って、何に時間を費やしているかについて誤った結論を導き出さないようにします。

以下は、見つかる可能性のあるものの例です。

  • 一部の式のコーディング方法が原因で、または以前の呼び出しと同じ引数値を使用して、数学ライブラリ関数を不必要に呼び出すことにかなりの時間を費やしている可能性があります。
  • ファイル I/O を実行したり、ファイルを開いたり閉じたりするためにかなりの時間を費やしている可能性があります。
  • 上位関数への引数フラグをチェックする目的で、従属サブルーチンを呼び出す汎用ライブラリ関数内にある可能性があります。そのような場合、専用の関数を作成して代わりに呼び出すことで、その時間の多くを削減できます。

この操作全体を 2 ~ 3 回実行すると、最初に作成されたときにソフトウェアに侵入する愚かなものが削除されます。その後、最適化や並列処理などを有効にして、ばかげたことに時間を費やさないようにすることができます。

于 2011-10-15T21:39:19.817 に答える