मैं यहां सामान्य ज्ञान के खिलाफ जा रहा हूं std::copyजिसमें थोड़ा, लगभग अगोचर प्रदर्शन नुकसान होगा। मैंने सिर्फ एक परीक्षण किया और पाया कि असत्य होना: मैंने एक प्रदर्शन अंतर पर ध्यान दिया। हालांकि, विजेता था std::copy।
मैंने C ++ SHA-2 कार्यान्वयन लिखा था। मेरे परीक्षण में, मेरे पास सभी चार SHA-2 संस्करणों (224, 256, 384, 512) और 300 बार लूप का उपयोग करके 5 तार हैं। मैं Boost.timer का उपयोग करके समय को मापता हूं। यह 300 लूप काउंटर मेरे परिणामों को पूरी तरह से स्थिर करने के लिए पर्याप्त है। मैंने प्रत्येक memcpyसंस्करण और संस्करण के बीच बारी-बारी से 5 बार परीक्षण किया std::copy। मेरा कोड यथासंभव बड़ी मात्रा में डेटा को हथियाने का लाभ उठाता है (कई अन्य कार्यान्वयन char/ के साथ काम करते हैं char *, जबकि मैं T/ के साथ काम करता हूं / T *(जहां Tउपयोगकर्ता के कार्यान्वयन में सबसे बड़ा प्रकार है जिसमें अतिप्रवाह व्यवहार होता है), इसलिए तीव्र मेमोरी एक्सेस मेरे एल्गोरिथ्म के प्रदर्शन का सबसे बड़ा प्रकार केंद्रीय हो सकता है। ये मेरे परिणाम हैं:
SHA-2 परीक्षणों को पूरा करने के लिए समय (सेकंड में)
std::copy memcpy % increase
6.11 6.29 2.86%
6.09 6.28 3.03%
6.10 6.29 3.02%
6.08 6.27 3.03%
6.08 6.27 3.03%
Std की गति में कुल औसत वृद्धि :: memcpy पर प्रतिलिपि: 2.99%
मेरा संकलक Fedora 16 x86_64 पर 4.6.3 है। मेरे अनुकूलन झंडे हैं -Ofast -march=native -funsafe-loop-optimizations।
मेरे SHA-2 कार्यान्वयन के लिए कोड।
मैंने अपने एमडी 5 कार्यान्वयन पर एक परीक्षण चलाने का फैसला किया। परिणाम बहुत कम स्थिर थे, इसलिए मैंने 10 रन बनाने का फैसला किया। हालाँकि, मेरे पहले कुछ प्रयासों के बाद, मुझे एक परिणाम मिला कि एक रन से लेकर दूसरे तक अलग-अलग तरीके से, इसलिए मैं अनुमान लगा रहा हूं कि कुछ प्रकार की ओएस गतिविधि चल रही थी। मैंने शुरू करने का फैसला किया।
एक ही संकलक सेटिंग्स और झंडे। MD5 का केवल एक संस्करण है, और यह SHA-2 की तुलना में तेज़ है, इसलिए मैंने 5 सेट स्ट्रिंग्स के समान सेट पर 3000 लूप किए।
ये मेरे अंतिम 10 परिणाम हैं:
एमडी 5 परीक्षणों को पूरा करने के लिए समय (सेकंड में)
std::copy memcpy % difference
5.52 5.56 +0.72%
5.56 5.55 -0.18%
5.57 5.53 -0.72%
5.57 5.52 -0.91%
5.56 5.57 +0.18%
5.56 5.57 +0.18%
5.56 5.53 -0.54%
5.53 5.57 +0.72%
5.59 5.57 -0.36%
5.57 5.56 -0.18%
एसटीडी की गति में कुल औसत कमी :: मेमकीपी पर प्रतिलिपि: 0.11%
मेरे एमडी 5 कार्यान्वयन के लिए कोड
ये परिणाम बताते हैं कि कुछ अनुकूलन है जो मेरे SHA-2 परीक्षणों में उपयोग की जाने वाली std :: copy है std::copyजो मेरे MD5 परीक्षणों में उपयोग नहीं हो सकता है। SHA-2 परीक्षणों में, दोनों सरणियों को एक ही फ़ंक्शन में बनाया गया था जिसे std::copy/ कहा जाता है memcpy। मेरे एमडी 5 परीक्षणों में, फ़ंक्शन में से एक को फ़ंक्शन पैरामीटर के रूप में पारित किया गया था।
मैंने यह देखने के लिए थोड़ा और परीक्षण किया कि मैं std::copyफिर से तेज करने के लिए क्या कर सकता हूं । उत्तर सरल निकला: लिंक समय अनुकूलन चालू करें। ये एलटीओ के साथ मेरे परिणाम हैं (विकल्प-जीपीएल में जीसीसी):
एमडीएफ परीक्षण के साथ -फ्लोटो के पूरा होने में समय (सेकंड में)
std::copy memcpy % difference
5.54 5.57 +0.54%
5.50 5.53 +0.54%
5.54 5.58 +0.72%
5.50 5.57 +1.26%
5.54 5.58 +0.72%
5.54 5.57 +0.54%
5.54 5.56 +0.36%
5.54 5.58 +0.72%
5.51 5.58 +1.25%
5.54 5.57 +0.54%
एसटीडी की गति में कुल औसत वृद्धि :: मेमेकपी पर प्रतिलिपि: 0.72%
सारांश में, उपयोग करने के लिए प्रदर्शन जुर्माना नहीं लगता है std::copy। वास्तव में, एक प्रदर्शन लाभ प्रतीत होता है।
परिणामों की व्याख्या
तो क्यों std::copyएक प्रदर्शन को बढ़ावा दे सकता है ?
सबसे पहले, मैं इसे किसी भी कार्यान्वयन के लिए धीमा होने की उम्मीद नहीं करूंगा, जब तक कि इनलाइनिंग का अनुकूलन चालू नहीं हो जाता। सभी संकलक आक्रामक रूप से इनलाइन करते हैं; यह संभवतः सबसे महत्वपूर्ण अनुकूलन है क्योंकि यह कई अन्य अनुकूलन को सक्षम करता है। std::copy(और मुझे संदेह है कि सभी वास्तविक विश्व कार्यान्वयन करते हैं) यह पता लगाते हैं कि तर्क तुच्छ रूप से प्रतिलिपि योग्य हैं और यह स्मृति क्रमबद्ध रूप से रखी गई है। इसका मतलब है कि सबसे खराब स्थिति में, जब memcpyकानूनी है, तो std::copyकोई बुरा प्रदर्शन नहीं करना चाहिए। std::copyउस डिफ़र के तुच्छ कार्यान्वयन को memcpyआपके कंपाइलर के मानदंडों को पूरा करना चाहिए "गति या आकार के लिए अनुकूलन करते समय इसे हमेशा इनलाइन करें"।
हालाँकि, std::copyइसकी अधिक जानकारी भी रखता है। जब आप कॉल करते हैं std::copy, तो फ़ंक्शन प्रकार बरकरार रहता है। memcpyपर काम करता है void *, जो लगभग सभी उपयोगी जानकारी देता है। उदाहरण के लिए, यदि मैं किसी सरणी में गुजरता हूं, तो std::uint64_tकंपाइलर या लाइब्रेरी कार्यान्वयनकर्ता 64-बिट संरेखण का लाभ उठाने में सक्षम हो सकता है std::copy, लेकिन ऐसा करना अधिक कठिन हो सकता है memcpy। एल्गोरिदम के कई कार्यान्वयन इस तरह काम करते हैं पहले रेंज के शुरू में अनलग्ड हिस्से पर काम करते हैं, फिर गठबंधन वाले हिस्से, फिर अंत में अनलगइन किए गए हिस्से को। यदि यह सब संरेखित होने की गारंटी है, तो कोड सरल और तेज हो जाता है, और सही करने के लिए आपके प्रोसेसर में शाखा भविष्यवक्ता के लिए आसान हो जाता है।
समय से पहले अनुकूलन?
std::copyएक दिलचस्प स्थिति में है। मुझे उम्मीद है कि यह memcpyकिसी भी आधुनिक अनुकूलन कंपाइलर के मुकाबले कभी-कभी धीमा और कभी तेज हो सकता है । इसके अलावा, कुछ भी जो आप कर सकते हैं memcpy, आप कर सकते हैं std::copy। memcpyबफ़र्स में किसी भी ओवरलैप की अनुमति नहीं देता है, जबकि std::copyएक दिशा में ओवरलैप का समर्थन करता है ( std::copy_backwardओवरलैप की दूसरी दिशा के साथ)। memcpyकेवल, संकेत पर काम करता है std::copyकिसी भी iterators पर काम करता है ( std::map, std::vector, std::deque, या मेरे स्वयं के कस्टम प्रकार)। दूसरे शब्दों में, आपको बस std::copyउस समय का उपयोग करना चाहिए जब आपको आस-पास डेटा की मात्रा की प्रतिलिपि बनाने की आवश्यकता हो।
charकार्यान्वयन के आधार पर हस्ताक्षर या अहस्ताक्षरित किया जा सकता है। यदि बाइट्स की संख्या> = 128 हो सकती है, तोunsigned charअपने बाइट सरणियों के लिए उपयोग करें। ((int *)कलाकारों को भी सुरक्षित किया जाएगा(unsigned int *)।)