2012-08-10 42 views
8

मैं Boost.Variant का उपयोग करने और वर्चुअल इंटरफेस का उपयोग करने के बीच प्रदर्शन अंतर को मापने की कोशिश कर रहा हूं। उदाहरण के लिए, मान लीजिए कि मैं Boost.Variant का उपयोग करके अलग-अलग प्रकार की संख्याओं को समान रूप से बढ़ाना चाहता हूं। मैं int और float पर एक boost :: संस्करण का उपयोग करता हूं और एक स्थिर विज़िटर जो उनमें से प्रत्येक को बढ़ाता है। कक्षा इंटरफेस का उपयोग करके मैं एक शुद्ध आभासी वर्ग संख्या और संख्या_आईंट और संख्या_फ्लोट कक्षाओं का उपयोग करता हूं जो इससे प्राप्त होते हैं और "वृद्धि" विधि को लागू करते हैं।

मेरे परीक्षण से, इंटरफेस का उपयोग Boost.Variant का उपयोग करने से कहीं अधिक तेज़ है। मैं तल पर कोड भाग गया और इन परिणामों प्राप्त किया:
वर्चुअल: 00: 00: ००.००१०२८
संस्करण: 00: 00: 00,012081
बूस्ट। संस्करण Vs वर्चुअल इंटरफ़ेस प्रदर्शन

तुम क्यों लगता है कि यह अंतर है? मैंने बूस्ट सोचा। संस्करण बहुत तेज़ होगा।

** नोट: आमतौर पर बूस्ट। वैरिएंट हेप आवंटन का उपयोग करता है यह गारंटी देने के लिए कि संस्करण हमेशा खाली नहीं होगा। लेकिन मैंने Boost.Variant प्रलेखन पर पढ़ा है कि अगर boost :: has_nothrow_copy सही है तो यह ढेर आवंटन का उपयोग नहीं करता है जो चीजों को काफी तेज़ी से बनाना चाहिए। Int और float boost के लिए :: has_nothrow_copy सत्य है।

एक दूसरे के खिलाफ दो दृष्टिकोणों को मापने के लिए मेरा कोड यहां दिया गया है।

#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

आपके परिणाम क्या थे और क्या संकलक थे? बूस्ट 1.52 और मिंगव 4.7 का उपयोग करके मुझे रिहाई मोड में 8 गुणा धीमा हो जाता है। अजीब रूप से पर्याप्त '-ओ 2' '-O3' से थोड़ा तेज है;/ – AbstractDissonance

+0

मैं g ++ 4.7 का उपयोग कर रहा हूं और मुझे यकीन नहीं है कि बूस्ट संस्करण क्या है लेकिन यह शायद 1.5x है। मैंने कंपाइलर को -ओ 2 पास कर दिया और मेरे परिणाम थे: वर्चुअल: 00: 00: 00.018806 संस्करण: 00: 00: 00.000001 अधिकांश बार मुझे संस्करण पर 00:00:00 मिलेंगे इसलिए मैंने iterations_count को 10000000 पर सेट किया मैं इस परीक्षण को 2.8 गीगा इंटेल कोर i7 CPU पर चला रहा हूं। –

4

यह स्पष्ट है कि -ओ 2 भिन्नता समय को कम कर देता है, क्योंकि पूरे लूप को अनुकूलित किया जाता है। कार्यान्वयन बदलें, फोन करने वाले को संचित परिणाम वापस जाने के लिए इतना है कि अनुकूलक पाश को दूर नहीं होगा, और आप वास्तविक अंतर मिलेगा:

आउटपुट:
वर्चुअल: 00: 00: ००.०,००,१२० = 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

क्या आप सुनिश्चित हैं कि संकलक devirtualizing नहीं है? – Brahim