2014-04-23 8 views
22

सी ++ 11 के यादृच्छिक मॉड्यूल का उपयोग करना, मैं जब एक uniform_real_distribution के साथ संयोजन में std::mt19937 (32 और 64 बिट संस्करण) का उपयोग कर एक अजीब प्रदर्शन ड्रॉप का सामना करना पड़ा (नाव या डबल, कोई फर्क नहीं पड़ता) । की तुलना में एक ग्राम ++ संकलन, यह परिमाण धीमी की एक आदेश की तुलना में अधिक है!बजना प्रदर्शन ड्रॉप

अपराधी सिर्फ एमटी जनरेटर, यह एक uniform_int_distribution साथ तेज है के रूप में नहीं है। और यह uniform_real_distribution में एक सामान्य कमी थी जिसके कारण default_random_engine जैसे अन्य जनरेटर के साथ तेज है के बाद से नहीं है। बस उस विशिष्ट संयोजन अजीब धीमी है।

मैं इंट्रिनिक्स से बहुत परिचित नहीं हूं, लेकिन मेर्सन ट्विस्टर एल्गोरिदम कम या ज्यादा सख्ती से परिभाषित किया गया है, इसलिए कार्यान्वयन में एक अंतर मुझे इस अंतर के लिए जिम्मेदार नहीं ठहरा सकता है?

gcc 4.8.1 
runtime_int_default: 185.6 
runtime_int_mt: 179.198 
runtime_int_mt_64: 175.195 
runtime_float_default: 45.375 
runtime_float_mt: 58.144 
runtime_float_mt_64: 94.188 

clang 3.4 
runtime_int_default: 215.096 
runtime_int_mt: 201.064 
runtime_int_mt_64: 199.836 
runtime_float_default: 55.143 
runtime_float_mt: 744.072 <--- this and 
runtime_float_mt_64: 783.293 <- this is slow 

कार्यक्रम इस पैदा करते हैं और अपने आप को बाहर की कोशिश करने के:

#include <iostream> 
#include <vector> 
#include <chrono> 
#include <random> 

template< typename T_rng, typename T_dist> 
double time_rngs(T_rng& rng, T_dist& dist, int n){ 
    std::vector< typename T_dist::result_type > vec(n, 0); 
    auto t1 = std::chrono::high_resolution_clock::now(); 
    for (int i = 0; i < n; ++i) 
     vec[i] = dist(rng); 
    auto t2 = std::chrono::high_resolution_clock::now(); 
    auto runtime = std::chrono::duration_cast<std::chrono::microseconds>(t2-t1).count()/1000.0; 
    auto sum = vec[0]; //access to avoid compiler skipping 
    return runtime; 
} 

int main(){ 
    const int n = 10000000; 
    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); 
    std::default_random_engine rng_default(seed); 
    std::mt19937 rng_mt (seed); 
    std::mt19937_64 rng_mt_64 (seed); 
    std::uniform_int_distribution<int> dist_int(0,1000); 
    std::uniform_real_distribution<float> dist_float(0.0, 1.0); 

    // print max values 
    std::cout << "rng_default_random.max(): " << rng_default.max() << std::endl; 
    std::cout << "rng_mt.max(): " << rng_mt.max() << std::endl; 
    std::cout << "rng_mt_64.max(): " << rng_mt_64.max() << std::endl << std::endl; 

    std::cout << "runtime_int_default: " << time_rngs(rng_default, dist_int, n) << std::endl; 
    std::cout << "runtime_int_mt: " << time_rngs(rng_mt_64, dist_int, n) << std::endl; 
    std::cout << "runtime_int_mt_64: " << time_rngs(rng_mt_64, dist_int, n) << std::endl; 
    std::cout << "runtime_float_default: " << time_rngs(rng_default, dist_float, n) << std::endl; 
    std::cout << "runtime_float_mt: " << time_rngs(rng_mt, dist_float, n) << std::endl; 
    std::cout << "runtime_float_mt_64: " << time_rngs(rng_mt_64, dist_float, n) << std::endl; 
} 

clang++ -O3 -std=c++11 random.cpp के माध्यम से संकलन को मापने कार्यक्रम पीछा कर रहा है, लेकिन यहाँ बजना 3.4 और जीसीसी 4.8.1 एक 64 बिट Linux मशीन पर के लिए मेरे परिणाम हैं या क्रमशः जी ++। कोई विचार?

संपादित करें: अंत में, माथीउ एम के लिए एक महान विचार था: अपराधी को इनलाइन है, या बल्कि एक उसके अभाव। क्लैंग इनलाइनिंग सीमा को बढ़ाने से प्रदर्शन जुर्माना समाप्त हो गया। वास्तव में मुझे कई प्रदर्शन विषमताओं का सामना करना पड़ा। धन्यवाद, मैंने कुछ नया सीखा।

+0

हो सकता है कि आप चीजों को थोड़ा सा प्रोफाइल करना चाहते हैं (उदा। कॉलग्रिंड के साथ) और जेनरेट असेंबलर की तुलना करें ... – PlasmaHH

+3

मैं इसे 'float_mt'64' के लिए नहीं बल्कि 'float_mt' केस के लिए पुन: उत्पन्न कर सकता हूं। मैंने फेडोरा 20 64-बिट पर clang3.4 के साथ अपना कोड इस्तेमाल किया। –

+0

एक बग रिपोर्ट के बाद कहने के लिए जा रहा था लेकिन मैंने देखा कि आप पहले से ही किया था, http://llvm.org/bugs/show_bug.cgi?id=19542 – pyCthon

उत्तर

4

जैसा कि पहले ही टिप्पणी में कहा गया है, समस्या तथ्य के कारण होता है कि जीसीसी inlines बजना तुलना में अधिक आक्रामक। हम बहुत आक्रामक तरीके से बजना इनलाइन करते हैं, प्रभाव गायब हो जाता है:

संकलन g++ -O3 के साथ अपने कोड

runtime_int_default: 3000.32 
runtime_int_mt: 3112.11 
runtime_int_mt_64: 3069.48 
runtime_float_default: 859.14 
runtime_float_mt: 1027.05 
runtime_float_mt_64: 1777.48 

जबकि clang++ -O3 -mllvm -inline-threshold=10000 पैदावार

runtime_int_default: 3623.89 
runtime_int_mt: 751.484 
runtime_int_mt_64: 751.132 
runtime_float_default: 1072.53 
runtime_float_mt: 968.967 
runtime_float_mt_64: 1781.34 

जाहिर है, बजना अब पैदावार int_mt में बाहर inlines जीसीसी मामलों, लेकिन अन्य सभी रनटाइम अब परिमाण के एक ही क्रम में हैं। मैंने फेडोरा 20 64 बिट पर जीसीसी 4.8.3 और क्लैंग 3.4 का इस्तेमाल किया।

संबंधित मुद्दे