簡単に言えば、次のうちどれがより良い選択になる可能性があります。
somestruct data[lots];
for(int i=0;i<lots;i++) {
a(&data[i]);
b(&data[i]);
c(&data[i]);
}
//....
void a(somestruct* d) { ..stuff with d.. }
void b(somestruct* d) { ..stuff with d.. }
void c(somestruct* d) { ..stuff with d.. }
また
somestruct data[lots];
a(lots,data);
b(lots,data);
c(lots,data);
//...
void a(int n, somestruct* d) {
for(int i<n;i++) {
..stuff with d[i]..
} }
void b(int n, somestruct* d) {
for(int i<n;i++) {
..stuff with d[i]..
} }
void c(int n, somestruct* d) {
for(int i<n;i++) {
..stuff with d[i]..
} }
私の理解では、A の場合、現在アクティブな構造がキャッシュされて改善されますが、関数呼び出しが大量に発生します (マイナス)。一方、B の場合、キャッシュを破棄しますが、3*lots 関数呼び出しではなく、3 つの関数呼び出しがあります。
私のコンパイラが a、b、および c をインライン化することを決定した場合、最初のオプションが最良の選択であるはずです (現在、両方の長所が得られているため)。関数呼び出しは、メモリ アクセスよりもはるかに高いです。
知る唯一の方法は、特定のアプリケーションをベンチマークすることであることは承知していますが、ここで見逃していた経験則があるかどうか知りたいと思っていました。最初のバージョンは、私の特定のケースに対してややクリーンなコードを生成しますが、違いはほとんどありません。
編集
関数に入るコスト (スタック ポインターの割り当てなど) とキャッシュ ミスのコストを比較する方法について質問しようとしていました。一般的な回答は、他の人にも役立つと思います。ただし、質問の一般的な形式には満足のいく回答ができないようです。そのため、正しく数えたと仮定して、完全な統計を以下に示します。
- data は 100,000 個の構造体で、それぞれに 6 つの double と int が含まれています。
- a() は、6 つの double 読み取り、3 つの double 乗算、3 つの double add、および 3 つの double store です。
- b() は、3 回の二重読み取り、3 回の二重乗算、4 回の加算、2 回の二重比較、および条件付きの c の呼び出しです。
- c() は、3 つの二重乗算、3 つの関数呼び出し、および 3 つの二重書き込みです。