0

私のプロジェクトでは、実行時間が最初の目標であるクラスがあります。そのため、メンテナンスや注文などはあまり気にしません。せめて昨日までは気にならなかったのに…。

私は、カメラからの画像に対して複数のスキャンを実行するクラス、つまりAを持っています。つまり、可変幅のウィンドウがそれらをリアルタイムでスキャンします。



    class A{  
    // methods and attributes of A:  
    ...  
    void runiterator(){  
      ...  
    for{    // change window’s dimension  
      for{  // rows  
       for{ // columns  
          // many lines of code of operations to be executed for each window at each position  
          ...      
       }  
      }   
     }  
    }  
    }; 

パフォーマンスはすでに少し遅れていますが、画像の限られた領域をスキップすることで解決できました。さらに、B という 2 番目の関数があります。これは A とまったく同じスキームを持ち、スキャンごとに異なる操作を実行します (幸いなことに、A よりもはるかに高速です)。

さて、今度はすべての操作を結合して、全体的な結果を大幅に改善する時が来ました。コードが本当にめちゃくちゃになり、巨大で、本当に異なるものが混ざり合っているということだけです。反復を行い、各スキャンで A_new の 1 つの関数と B_new の 1 つの関数への関数呼び出しを実行するクラス X を定義することを考えました。しかし、画像ごとに約 200000x2 関数呼び出しを行うと、パフォーマンスが低下するのではないかと心配しています。

あなたのアドバイスは何ですか?

編集
Anew のみを呼び出すクラス X (したがって、現在の A とのみ比較できます) では、多くの繰り返しから平均して取得します。

一連の 56 枚の画像で X を実行する時間 = 6.15 秒 56 枚の
同じ一連の画像で A を実行する時間 = 5.98 秒

私の容疑者はそれほど素朴ではなかったようです。
差は約3%とそれほどでもないのですが、それでも損はしてしまいます。

__forceinline を使用すると、X の時間も 5.98 秒になりますが、これに頼らない方がよいでしょう。

コードは最適化されており、さらなる改善の余地はほとんどないと思います。
実際、比較的短い時間で多くの処理を画像に対して行います。
クラス A ではデータを順次処理することはできません。これは、画像から得られる予測不可能な値に基づいているためです。これが、クラス B (それを実行する) がはるかに高速である理由です。

4

3 に答える 3

1

関数呼び出しのオーバーヘッドは、呼び出す関数の種類に大きく依存します。アセンブラ レベルでは (卑劣な OS ページ フォールト処理がないことを前提として) call address、最新の Intel プロセッサの命令は 0 サイクルかかります (命令についても同じことが言えますjmp address)。関数アドレスが vtbl ルックアップ、外部 DLL の呼び出し (Win32 を使用している場合) などのデータ ソースから計算される場合、または関連する条件がある場合、オーバーヘッドが発生します。これらには、メモリへのアクセスとキャッシュの汚染が含まれます。それは私たちを大物に導きます。

ほとんどのパフォーマンスは、データが CPU に到着するのを待っているときに失われます。CPU の速度は、RAM からデータを読み取る速度よりもはるかに高速です。これが、キャッシングにいくつかのレベルがある理由です。各レベルは通常、前のレベルよりも大きく、低速です。関数呼び出しのコストは、複雑なものであっても、データ読み取り時にキャッシュを失うことで失われる時間よりも少なくなります。

この種のことは、「マイクロ最適化」という見出しの下にあります。

一般に、ランダムなデータ アクセスを避け、データを順番に処理します。つまり、項目 n を実行し、次に n+1、n+2 などを実行し、n、n+100、n+200 などではなく、n+1、n+101、n を実行します。 +201など

また、コンパイラーに関数をインライン化する機会を与えます。そうすれば、結果がより高速なコードを生成する場合にインライン化が行われます (コンパイラーは、それが有益な場合について非常に良い考えを持っています)。

また、大きな関数は多くの小さな関数よりも遅くなる可能性があることに注意してください (これは、CPU がローカルにキャッシュする uops のバッファーに関係しています)。すべてを一度に行うよりも、データを数回反復する方が速い場合があります。コードをプロファイリングするだけで、どちらが速いかがわかります。

最後に、通常、より優れたアルゴリズムは、より優れたパフォーマンスへの道です。あなたのアルゴリズムは最適ですか?

于 2012-10-10T12:11:57.197 に答える
1

心配する前に、パフォーマンスの問題が発生することを実際に測定する必要があります。

問題がある場合、テンプレートを使用して実行してみてください。関数の 2 つのバリアントを記述し、反復を行う関数テンプレートでファンクターとして使用します。両方のバージョンをインスタンス化し、適切なバージョンを呼び出します。コンパイラは呼び出しをインライン化する必要があります (ただし、これを確認することをお勧めします)。

私はこれを医療画像操作に使用しましたが、魅力的に機能しました。

于 2012-10-10T11:57:13.477 に答える
0

コンパイラが実際に何を生成するかを判断するのは難しいため、効果を測定する必要があります。特にO3. 確かに、関数がコンパイラによってインライン化されていない場合、関数呼び出しにはオーバーヘッドがあります。inline関数をインライン化できる場合は、コンパイラにヒントを提供してみてください。

于 2012-10-10T11:58:44.703 に答える