यह सवाल, हालांकि पुराना है, कुछ मानदंड की जरूरत है, क्योंकि यह सबसे मुहावरेदार तरीके के लिए नहीं कहता है, या जिस तरह से सबसे कम लाइनों में लिखा जा सकता है, लेकिन सबसे तेज़ तरीका है। और यह कुछ वास्तविक परीक्षण के बिना उस सवाल का जवाब देने के लिए मूर्खतापूर्ण है। इसलिए मैंने चार समाधानों की तुलना की, मेमसेट बनाम एसटीडी :: एईटी के उत्तर के जीरो बनाम जीरो बनाम एक समाधान जो मैंने एवीएक्स इंट्रेंसिक्स का उपयोग करके बनाया है।
ध्यान दें कि यह समाधान सामान्य नहीं है, यह केवल 32 या 64 बिट्स के डेटा पर काम करता है। कृपया टिप्पणी करें कि क्या यह कोड कुछ गलत कर रहा है।
#include<immintrin.h>
#define intrin_ZERO(a,n){\
size_t x = 0;\
const size_t inc = 32 / sizeof(*(a));/*size of 256 bit register over size of variable*/\
for (;x < n-inc;x+=inc)\
_mm256_storeu_ps((float *)((a)+x),_mm256_setzero_ps());\
if(4 == sizeof(*(a))){\
switch(n-x){\
case 3:\
(a)[x] = 0;x++;\
case 2:\
_mm_storeu_ps((float *)((a)+x),_mm_setzero_ps());break;\
case 1:\
(a)[x] = 0;\
break;\
case 0:\
break;\
};\
}\
else if(8 == sizeof(*(a))){\
switch(n-x){\
case 7:\
(a)[x] = 0;x++;\
case 6:\
(a)[x] = 0;x++;\
case 5:\
(a)[x] = 0;x++;\
case 4:\
_mm_storeu_ps((float *)((a)+x),_mm_setzero_ps());break;\
case 3:\
(a)[x] = 0;x++;\
case 2:\
((long long *)(a))[x] = 0;break;\
case 1:\
(a)[x] = 0;\
break;\
case 0:\
break;\
};\
}\
}
मैं यह दावा नहीं करूंगा कि यह सबसे तेज़ तरीका है, क्योंकि मैं निम्न स्तर का अनुकूलन विशेषज्ञ नहीं हूं। बल्कि यह एक सही आर्किटेक्चर पर निर्भर कार्यान्वयन का एक उदाहरण है जो कि शुरुआत की तुलना में तेज है।
अब, परिणामों पर। मैंने आकार 100 इंट और लंबे लंबे सरणियों के लिए प्रदर्शन की गणना की, दोनों स्टेटिक और डायनामिक रूप से आवंटित, लेकिन msvc के अपवाद के साथ, जिसने स्थिर सरणियों पर एक मृत कोड उन्मूलन किया, परिणाम बेहद तुलनीय थे, इसलिए मैं केवल गतिशील सरणी प्रदर्शन दिखाऊंगा। टाइम मार्किंग 1 मिलियन पुनरावृत्तियों के लिए एमएस हैं, time.h की कम परिशुद्धता घड़ी फ़ंक्शन का उपयोग करते हुए।
क्लैंग 3.8 (क्लैंग-क्ल फ्रंटेंड, ऑप्टिमाइज़ेशन फ्लैग = / ओएक्स / आर्क: एवीएक्स / ओआई / ओट का उपयोग करके)
int:
memset: 99
fill: 97
ZERO: 98
intrin_ZERO: 90
long long:
memset: 285
fill: 286
ZERO: 285
intrin_ZERO: 188
gcc 5.1.0 (अनुकूलन झंडे: -O3 -march = देशी -mtune = देशी-mavx):
int:
memset: 268
fill: 268
ZERO: 268
intrin_ZERO: 91
long long:
memset: 402
fill: 399
ZERO: 400
intrin_ZERO: 185
msvc 2015 (अनुकूलन झंडे: / OX / मेहराब: AVX / Oi / Ot):
int
memset: 196
fill: 613
ZERO: 221
intrin_ZERO: 95
long long:
memset: 273
fill: 559
ZERO: 376
intrin_ZERO: 188
यहाँ बहुत दिलचस्प चल रहा है: हत्या कर रहा हूँ gcc, MSVC के विशिष्ट धब्बेदार अनुकूलन (यह स्थिर सरणियों पर एक प्रभावशाली मृत कोड उन्मूलन करता है और फिर भराव के लिए भयानक प्रदर्शन होता है)। हालांकि मेरा कार्यान्वयन काफी तेज है, यह केवल इसलिए हो सकता है क्योंकि यह मानता है कि बिट क्लियरिंग में किसी भी अन्य सेटिंग ऑपरेशन की तुलना में बहुत कम ओवरहेड है।
क्लैंग का कार्यान्वयन अधिक देखने योग्य है, क्योंकि यह काफी तेज है। कुछ अतिरिक्त परीक्षण से पता चलता है कि इसकी शुरुआत वास्तव में शून्य के लिए विशिष्ट है - 400 बाइट सरणी के लिए गैर शून्य मेमसेट्स बहुत धीमे (~ 220ms) हैं और जीसीसी के लिए तुलनीय हैं। हालांकि, 800 बाइट सरणी के साथ नॉनजरो मेमसेटिंग में कोई गति अंतर नहीं होता है, यही वजह है कि शायद इस मामले में, उनके कार्यान्वयन में मेरे कार्यान्वयन की तुलना में खराब प्रदर्शन है - विशेषज्ञता केवल छोटे सरणियों के लिए है, और कटऑफ 800 सेंटीमीटर के लिए सही है। यह भी ध्यान दें कि gcc 'fill' और 'ZERO' को याद करने के लिए अनुकूलन नहीं है (उत्पन्न कोड को देखते हुए), gcc केवल समान प्रदर्शन विशेषताओं के साथ कोड जनरेट कर रहा है।
निष्कर्ष: मेमसेट वास्तव में इस कार्य के लिए अनुकूलित नहीं है, साथ ही साथ लोग यह दिखावा भी करेंगे (अन्यथा gcc और msvc और llvm के मेमसेट का प्रदर्शन समान होगा)। यदि प्रदर्शन मायने रखता है, तो मेमसेट अंतिम समाधान नहीं होना चाहिए, विशेष रूप से इन अजीब मध्यम आकार के सरणियों के लिए, क्योंकि यह बिट क्लियरिंग के लिए विशेष नहीं है, और यह संकलित नहीं है जो संकलक की तुलना में बेहतर है।
new
है सी ++ ...