2012-08-10 13 views
8

私はBoost.Variantを使用して仮想インターフェイスを使用するパフォーマンスの違いを測定しようとしています。たとえば、Boost.Variantを使用して異なるタイプの数値を一様に増やしたいとします。私は、boost :: variantをintおよびfloatに使用し、静的ビジターはそれぞれを増分します。クラスインタフェースを使用して、純粋な仮想クラス番号とそれから派生し、 "インクリメント"メソッドを実装するnumber_intクラスとnumber_floatクラスを使用します。

私のテストでは、インターフェイスを使用する方がBoost.Variantを使用するよりもはるかに高速です。 は私が一番下にあるコードを実行し、これらの結果を受けた:
仮想:00:00:00.001028
バリアント:00:00:00.012081
Boost.Variantと仮想インターフェイスのパフォーマンス

あなたはこの差があると思いますなぜ?私はBoost.Variantがもっと速くなると思った。

**注:通常Boost.Variantは、バリアントが常に空でないことを保証するためにヒープ割り当てを使用します。しかし、boost :: has_nothrow_copyが真である場合、ヒープ割り当てを使用しないため、作業が大幅に高速化されるはずです。 intとfloatの場合、boost :: has_nothrow_copyはtrueです。

ここでは、2つのアプローチを相互に測定するためのコードを示します。興味のある方のため

#include <iostream> 

#include <boost/variant/variant.hpp> 
#include <boost/variant/static_visitor.hpp> 
#include <boost/variant/apply_visitor.hpp> 

#include <boost/date_time/posix_time/ptime.hpp> 
#include <boost/date_time/posix_time/posix_time_types.hpp> 
#include <boost/date_time/posix_time/posix_time_io.hpp> 

#include <boost/format.hpp> 

const int iterations_count = 100000; 

// a visitor that increments a variant by N 
template <int N> 
struct add : boost::static_visitor<> { 
    template <typename T>  
    void operator() (T& t) const { 
     t += N; 
    } 
}; 

// a number interface 
struct number {   
    virtual void increment() = 0; 
}; 

// number interface implementation for all types 
template <typename T> 
struct number_ : number { 
    number_(T t = 0) : t(t) {} 
    virtual void increment() { 
     t += 1; 
    } 
    T t; 
}; 

void use_virtual() { 
    number_<int> num_int; 
    number* num = &num_int; 

    for (int i = 0; i < iterations_count; i++) { 
     num->increment(); 
    } 
} 

void use_variant() { 
    typedef boost::variant<int, float, double> number; 
    number num = 0; 

    for (int i = 0; i < iterations_count; i++) { 
     boost::apply_visitor(add<1>(), num); 
    } 
} 

int main() { 
    using namespace boost::posix_time; 

    ptime start, end; 
    time_duration d1, d2; 

    // virtual 
    start = microsec_clock::universal_time(); 
    use_virtual(); 
    end = microsec_clock::universal_time(); 

    // store result 
    d1 = end - start; 

    // variant 
    start = microsec_clock::universal_time(); 
    use_variant(); 
    end = microsec_clock::universal_time(); 

    // store result 
    d2 = end - start; 

    // output 
    std::cout << 
     boost::format(
      "Virtual: %1%\n" 
      "Variant: %2%\n" 
     ) % d1 % d2; 
} 

答えて

14

私は少しイライラした後、私は、コンパイラに、オプション-O2に合格し、後押し::バリアントは、仮想呼び出しよりも道速かったです。
ありがとう

+0

おかげで、私が興味を持っていました! –

+0

あなたの結果とコンパイラは何ですか? Boost 1.52とMingw 4.7を使用すると、リリースモードで約8倍の遅れが発生します。奇妙なことに、 '-O2'は' -O3'より少し速いです。/ – AbstractDissonance

+0

g ++ 4.7を使っていますが、Boostのバージョンは分かりませんが、おそらく1.5xです。私はコンパイラに-O2を渡して、結果は次のようになりました: バーチャル:00:00:00.018806 バリアント:00:00:00.000001 ほとんどの場合、私は0000:00:00を変種に渡しますので、iterations_countを10000000に設定します 私はこのテストを2.8Ghz Intel Core i7 CPUで実行しています。 –

4

-O2は、ループ全体が最適化されているため、バリアント時間が短縮されることは明らかです。オプティマイザは、ループを削除しないように、呼び出し側に蓄積された結果を返すように実装を変更し、あなたが本当の違いを得るでしょう:

出力:
仮想:00:00:00.000120 = 10000000
バリアント:00:00:00.013483 = 10000000

#include <iostream> 

#include <boost/variant/variant.hpp> 
#include <boost/variant/static_visitor.hpp> 
#include <boost/variant/apply_visitor.hpp> 

#include <boost/date_time/posix_time/ptime.hpp> 
#include <boost/date_time/posix_time/posix_time_types.hpp> 
#include <boost/date_time/posix_time/posix_time_io.hpp> 

#include <boost/format.hpp> 

const int iterations_count = 100000000; 

// a visitor that increments a variant by N 
template <int N> 
struct add : boost::static_visitor<> { 
    template <typename T> 
    void operator() (T& t) const { 
     t += N; 
    } 
}; 

// a visitor that increments a variant by N 
template <typename T, typename V> 
T get(const V& v) { 
    struct getter : boost::static_visitor<T> { 
     T operator() (T t) const { return t; } 
    }; 
    return boost::apply_visitor(getter(), v); 
} 

// a number interface 
struct number { 
    virtual void increment() = 0; 
}; 

// number interface implementation for all types 
template <typename T> 
struct number_ : number { 
    number_(T t = 0) : t(t) {} 
    virtual void increment() { t += 1; } 
    T t; 
}; 

int use_virtual() { 
    number_<int> num_int; 
    number* num = &num_int; 

    for (int i = 0; i < iterations_count; i++) { 
     num->increment(); 
    } 

    return num_int.t; 
} 

int use_variant() { 
    typedef boost::variant<int, float, double> number; 
    number num = 0; 

    for (int i = 0; i < iterations_count; i++) { 
     boost::apply_visitor(add<1>(), num); 
    } 

    return get<int>(num); 
} 
int main() { 
    using namespace boost::posix_time; 

    ptime start, end; 
    time_duration d1, d2; 

    // virtual 
    start = microsec_clock::universal_time(); 
    int i1 = use_virtual(); 
    end = microsec_clock::universal_time(); 

    // store result 
    d1 = end - start; 

    // variant 
    start = microsec_clock::universal_time(); 
    int i2 = use_variant(); 
    end = microsec_clock::universal_time(); 

    // store result 
    d2 = end - start; 

    // output 
    std::cout << 
     boost::format(
      "Virtual: %1% = %2%\n" 
      "Variant: %3% = %4%\n" 
     ) % d1 % i1 % d2 % i2; 
} 
フォローアップを投稿するための
+3

それでも仮想を表示するのは2桁も速いのですか? –

+0

コンパイラがデバッグしていないのは確かですか? – Brahim

関連する問題