-1

次のコードは、2 つのセッターの呼び出しのクロック時間をテストします。1 つはヌル ポインターをチェックし、もう 1 つはチェックしません。-O3 フラグをコンパイルしたプログラムの出力は、同じ時間を示します。

  0.000000 ticks (0.000000 secs)
  0.000000 ticks (0.000000 secs)

-O0 フラグを使用すると、タイミングの違いはまだ小さい

  4250000.0000 ticks (4.25000 secs)
  4230000.0000 ticks (4.25000 secs)

これは for ループでコンパイラによって最適化されていますか? もしそうなら、2つの効率の違いに関する「実際の」シナリオをどのようにテストする必要がありますか?

class B {};
class A
{
public:
      void set( int a ) { a_ = a; }
      int get() const { return a_; }
private:
      int a_;
};

class A1

public:
      A1() : b_(0) {}

      void set( int a ) { if( b_ ) a_ = a; }
      int get() const { return a_; }

private:
      int a_;
      B* b_;
}; 


int main()
{
      const int n=1000000000;
      clock_t t0, t1;

      A a;
      A1 a1;

      t0 = clock();
      for( int i=0; i < n; ++i ) 
            a.set( i );
      t1 = clock();
      printf( "%f ticks (%.6f secs)\n", (double) t1-t0, ((double) t1-t0) / CLOCKS_PER_SEC );

      t0 = clock();
      for( int i=0; i < n; ++i ) 
            a1.set( i );
      t1 = clock();
      printf( "%f ticks (%.6f secs)\n", (double) t1-t0, ((double) t1-t0) / CLOCKS_PER_SEC );

      return 0;
}
4

2 に答える 2

4

null ポインターのチェックは、ほぼ確実に 1 クロックサイクルの操作です。最新のプロセッサでは、これは 20 億分の 1 秒になります。これは、ティックカウンターの解像度を超えていると思います(プラットフォームに応じて、ミリ秒またはマイクロ秒になります)。

本当に知りたい場合は、デバッガーで出力されたアセンブラー コードを見てください。

于 2013-07-10T03:07:08.477 に答える
0

この場合の測定結果-O3は 0 であるため、明らかに、コンパイラは単なる null ポインター チェック以上のものを最適化しました。ループを完全に削除しました。その理由は、ループで生成された結果が使用されないためです。

ループで生成された値を取得するコードにはa.get();anda1.get();がありますが、これらの関数呼び出しの結果は副作用に関係しないため、コンパイラはそれらを削除します。

これらの呼び出しを呼び出しの後に配置されget()た print ステートメントに置き換えると(IO が時間測定に含まれないようにするため)、異なる結果が得られます (出力と出力から実際の値を削除しました)。clock()aa1

2540000.000000 ticks (2.540000 secs)
0.000000 ticks (0.000000 secs)

したがって、最初のループは実際のアクションを実行するようになりましたが、2 番目のループはまだ最適化されていません (Clang 3.3)。この理由はおそらく、 の設定が、初期化されてからループ内で変更されないa1._aポインターに依存しているためです。0への関数呼び出しをメイン ループにインライン展開した後、コンパイラは の割り当てが決して行われないa1.set()ことをすぐに確認できます。a1._a


(注:a1._a実際には設定されていないため、その値を出力するということは、初期化されていない変数の値を出力することを意味します。実際、非常にランダムに見える出力が得られます。もちろん、厳密に言えば、その値を出力すると、未定義の動作が呼び出されます。)

于 2013-07-10T03:24:36.153 に答える