2009-09-29 6 views
7

私は、計算のためにかなりの内部一時記憶域を必要とする関数を持っています(いくつかの行列演算)、私はこの関数が頻繁に呼び出されることを知っています(プログラムの実行時には1ミリ秒ごと)。私の直感は、それらの一時的な変数を静的なものとして宣言する方が良いことを示しているので、関数を呼び出すたびに何度も繰り返し作成する管理上の努力はあまりありません。私は関数を呼び出すたびにそれらを初期化しなければならないので、関数を生かしておくことは関数的な目的のために必要ではありません。私はそれらを静的にすることでスレッドの安全性が損なわれることを認識していますが、ここでは問題にはなりません。内部静的変数を使用してパフォーマンスを向上させますか?

知識は通常どんな腸の感覚よりも優れているので、私はこのケースを扱う正しい方法が何であるか知りたいと思います。

void frequentlyCalledFunction(void) 
{ 
    double matrix1[10][10]; 
    double matrix2[10][10]; 
    /* do something with the matrices ... */ 
} 

または

void frequentlyCalledFunction(void) 
{ 
    static double matrix1[10][10]; 
    static double matrix2[10][10]; 
    /* do something with the matrices ... */ 
} 

答えて

16

違いはありません。初期化されていない配列を作成するためのコードは必要ありません。

スタティックアレイの場合、メモリは予約されており、常時利用可能です。自動配列の場合、それはスタック上にあり、スタックポインタを移動するために必要なのは、関数の入力時に起こることです。

(そして、ある日、あなたはマルチスレッドプログラムでその機能を使用しようとするだろう、と静的バージョンは時々断続あなたが飲むためにドライブの障害や薬物を被るだろう。それはリスクだけの価値はありません。)

+0

ローカル変数を作成するためのオーバーヘッドはないかもしれませんが、スタックポインタまたはベースポインタを基準にしてアクセスする必要があるため、測定可能なパフォーマンスが得られる可能性があります。 – Christoph

+0

@Christoph:面白い点。現代のプロセッサーに違いがあるのだろうか?私はそうではないと確信していますが、私はアセンブリウィザードではありません。 :-) – RichieHindle

+0

私はこれが問題となるプラットフォームを考えようとしています。指定されたスタックフレームから修正されると、問題は発生しません。たとえば、mipsでLD r1、frame_offset(stack_frame_base)を実行すると、フリーになります。 MOVのEAX、[ESP + frame_offset]は、同様に自由である... – Goz

1

知る唯一の方法は、それを試してテストすることです。しかし、それほど大きな違いはありません。

2

ベンチマークなしでマイクロ最適化を試行していますが、これは一般的に悪いことです。常にベンチマークを行うべきです。それ以外の場合は、最適化の試みが確実に行われたことをどのように知っていますか?

これから何かを得ることはまずありません。コードの可読性と保守性がまず必要です。

+0

とdownvoteはなぜですか? –

5

いつものように、まずプロファイリングする必要があります。ローカル変数はたぶんスタックポインタを少しだけ減らし、パフォーマンス上のペナルティはないはずです。

9

私は間違いなく、最も簡単で最も読みやすい方法を書いています。 1ミリ秒に一度は非常にのように聞こえることはほとんどありません。実行機能はマイクロ最適化することはほとんどありません。

作業が完了したら、それをベンチマークします。パフォーマンスが十分に良いかどうかを判断する。そうでない場合は、再度最適化とベンチマークを行います。 Do notあなたの決定をバックアップするために非常に実数のない形のコードを曲げてください。

2

スタック変数の割り当ては、ヒープ変数の割り当てと同じではありません。スタックポインタは、関数が必要とするすべてのメモリを割り当てるために十分に下に移動されます。 1つまたは複数の変数をスタックフレームに割り当てる際にオーバーヘッドはありません。スタックポインタは、たとえ変数がゼロであっても関数が呼び出されたときに既に移動されています(どこに戻るかを記録するため)。

0

変数の空き領域を自動記憶期間で確保するということは、これらが唯一のローカル変数でない限り、オーバーヘッドはありません。パフォーマンスを傷つけるかもしれない何

は、そのスタックに割り当てられた変数では多少パフォーマンスが向上する可能性がありますstaticを使用して、スタックまたはベースポインタを基準に対処する必要があります。

いつものように、ベンチマークを確実にするコード。特に、64ビットモードでSPARCについて

1

、静的場合は遅くなります。 (静的であり、それは機能の範囲に制限されている唯一の名前です)グローバル変数へのアクセスは配列のアドレスを取得するために、あなたのケースで3レジスタを使用して5つの命令、10の指示を必要とします。既に指摘されたような非静的バージョンでは、スタックポインタは、16のバイトを成長または200は全く違いがない場合、フレームは、どんな場合でも構築されるように、オーバーヘッドを有していません。 しかし、配列を初期化すると、高価な隠れたmemsetが生成される可能性があります。

void frequentlyCalledFunction(void) 
{ 
    double matrix1[10][10]={0.0}; 
    double matrix2[10][10]={0.0}; 
    /* do something with the matrices ... */ 
} 

はおそらく、1つまたは2つのmemcpyまたはmemset呼び出しを呼び出して配列を初期化します。

関連する問題