2012-08-10 3 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 :: has_nothrow_copy가 참이면, 힙 할당을 사용하지 않고 훨씬 빠르게 작업을 수행해야한다는 Boost.Variant 문서를 읽었습니다. int 및 float의 경우 boost :: has_nothrow_copy가 true입니다.

다음은 서로에 대한 두 가지 접근법을 측정하기위한 코드입니다. 나는 약간 좌절 된 후 관심이있는 사람들을 위해

#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를 전달했으며 결과는 다음과 같습니다. Virtual : 00 : 00 : 00.018806 Variant : 00 : 00 : 00.000001 변형에 00: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