पॉइंटर इन्क्रीमेंट की तुलना में मेम्पी () और मेमोव () क्यों तेज हैं?


92

मैं कॉपी करने हूँ एन से बाइट्स pSrcके लिए pDest। यह एक ही लूप में किया जा सकता है:

for (int i = 0; i < N; i++)
    *pDest++ = *pSrc++

क्यों इस की तुलना में धीमी है memcpyया memmove? इसे तेज करने के लिए वे कौन से टोटके का उपयोग करते हैं


2
आपका लूप केवल एक स्थान की प्रतिलिपि बनाता है। मुझे लगता है कि आप किसी तरह संकेत को बढ़ाने के लिए थे।
5

13
या, आप इसे उनके लिए ठीक कर सकते हैं, जैसे मैंने किया। और, बीटीडब्ल्यू, कोई भी सच्चा सी प्रोग्रामर कभी भी मायने नहीं रखता 1है N, यह हमेशा से 0होता है N-1:-)
paxdiablo

6
@paxdiablo: यदि आप सरणियों पर लूपिंग कर रहे हैं, तो सुनिश्चित करें। लेकिन ऐसे बहुत से मामले हैं जहां 1 से एन तक लूपिंग ठीक है। इस बात पर निर्भर करता है कि आप डेटा के साथ क्या कर रहे हैं - यदि आप एक उपयोगकर्ता के लिए, उदाहरण के लिए, 1 पर शुरू की गई एक संख्या वाली सूची प्रदर्शित कर रहे हैं, तो 1 पर शुरू करना संभवतः अधिक समझ में आता है। किसी भी मामले में, यह उस बड़ी समस्या को नजरअंदाज intकरता है जो काउंटर के रूप में उपयोग कर रही है जब size_tइसके बजाय एक अहस्ताक्षरित प्रकार का उपयोग किया जाना चाहिए।
बिली ओनेल

2
@paxdiablo आप N से 1 तक भी गिन सकते हैं। कुछ प्रोसेसरों पर जो एक तुलना निर्देश को समाप्त कर देगा, क्योंकि जब यह शून्य हो जाता है, तो शाखा अनुदेश के लिए उचित बिट सेट हो जाएगा।
प्रातः

6
मुझे लगता है कि प्रश्न का आधार गलत है। आधुनिक संकलक इसे ( memcpyया इस बात पर memmoveनिर्भर करता है कि वे बता सकते हैं कि क्या संकेत उर्फ ​​हो सकते हैं)।
डेविड श्वार्ट्ज

जवाबों:


120

चूँकि बाइट पॉइंटर्स की जगह मेम्पी शब्द का उपयोग करता है, इसलिए मेमेकपी कार्यान्वयन अक्सर SIMD निर्देशों के साथ लिखे जाते हैं जो एक बार में 128 बिट्स को फेरबदल करना संभव बनाता है।

SIMD निर्देश विधानसभा निर्देश हैं जो वेक्टर में प्रत्येक तत्व पर 16 बाइट तक लंबे समय तक एक ही ऑपरेशन कर सकते हैं। जिसमें लोड और स्टोर निर्देश शामिल हैं।


15
जब आप GCC को चालू करते हैं -O3, तो यह लूप के लिए SIMD का उपयोग करेगा, कम से कम अगर यह जानता है pDestऔर pSrcउपनाम नहीं।
डिट्रीच एप्प

मैं वर्तमान में 64 बाइट्स (512 बिट्स) SIMD के साथ एक Xeon Phi पर काम कर रहा हूं, इसलिए "16 बाइट्स तक" का यह सामान मुझे मुस्कुराता है। इसके अलावा, आपको निर्दिष्ट करना होगा कि आप सीपीयू को सक्षम करने के लिए सीपीयू को क्या लक्ष्य कर रहे हैं, उदाहरण के लिए -mch = देशी के साथ।
यकौद्बज

शायद मुझे अपने उत्तर को संशोधित करना चाहिए। :)
२१

पोस्टिंग के समय भी यह बहुत पुराना है। एवीएक्स वैक्टर x86 पर (2011 में शिप किया गया) 32 बाइट्स लंबा है, और एवीएक्स -51 64-बाइट लंबा है। 1024-बिट या 2048-बिट वैक्टर के साथ कुछ आर्किटेक्चर हैं, या एआरएम
एसवीई

@phuclv जबकि निर्देश उपलब्ध हो सकते हैं, तो क्या आपके पास कोई सबूत है जो मेमसीपी उनका उपयोग करता है? आमतौर पर पुस्तकालयों को पकड़ने में थोड़ा समय लगता है, और नवीनतम मैं SSSE3 का उपयोग कर सकता हूं और 2011 की तुलना में बहुत अधिक हाल के हैं।
पीट किर्कम

81

मेमोरी कॉपी रूट पॉइंटर्स के माध्यम से सरल मेमोरी कॉपी की तुलना में कहीं अधिक जटिल और तेज हो सकता है:

void simple_memory_copy(void* dst, void* src, unsigned int bytes)
{
  unsigned char* b_dst = (unsigned char*)dst;
  unsigned char* b_src = (unsigned char*)src;
  for (int i = 0; i < bytes; ++i)
    *b_dst++ = *b_src++;
}

सुधार

पहला सुधार जो एक शब्द सीमा पर बिंदुओं में से एक को संरेखित करना है (शब्द से मेरा मतलब है मूल पूर्णांक आकार, आमतौर पर 32 बिट्स / 4 बाइट्स, लेकिन नए आर्किटेक्चर पर 64 बिट्स / 8 बाइट्स हो सकते हैं) और शब्द आकार चाल का उपयोग करें / निर्देश कॉपी करें। जब तक एक पॉइंटर को संरेखित नहीं किया जाता है तब तक बाइट कॉपी का उपयोग करना पड़ता है।

void aligned_memory_copy(void* dst, void* src, unsigned int bytes)
{
  unsigned char* b_dst = (unsigned char*)dst;
  unsigned char* b_src = (unsigned char*)src;

  // Copy bytes to align source pointer
  while ((b_src & 0x3) != 0)
  {
    *b_dst++ = *b_src++;
    bytes--;
  }

  unsigned int* w_dst = (unsigned int*)b_dst;
  unsigned int* w_src = (unsigned int*)b_src;
  while (bytes >= 4)
  {
    *w_dst++ = *w_src++;
    bytes -= 4;
  }

  // Copy trailing bytes
  if (bytes > 0)
  {
    b_dst = (unsigned char*)w_dst;
    b_src = (unsigned char*)w_src;
    while (bytes > 0)
    {
      *b_dst++ = *b_src++;
      bytes--;
    }
  }
}

यदि स्रोत या गंतव्य सूचक उचित रूप से संरेखित है, तो विभिन्न आर्किटेक्चर अलग-अलग तरीके से प्रदर्शन करेंगे। उदाहरण के लिए एक XScale प्रोसेसर पर मुझे स्रोत सूचक के बजाय गंतव्य पॉइंटर को संरेखित करके बेहतर प्रदर्शन मिला।

प्रदर्शन को और बेहतर बनाने के लिए कुछ लूप को अनियंत्रित किया जा सकता है, ताकि प्रोसेसर के अधिक रजिस्टरों को डेटा के साथ लोड किया जा सके और इसका मतलब है कि लोड / स्टोर निर्देशों को इंटरलेय किया जा सकता है और अतिरिक्त निर्देश (जैसे लूप काउंटिंग आदि) द्वारा उनकी विलंबता छिपी हो। यह लाभ प्रोसेसर द्वारा काफी भिन्न होता है, क्योंकि लोड / स्टोर निर्देश विलंबताएं काफी भिन्न हो सकती हैं।

इस स्तर पर कोड सी (या C ++) के बजाय असेंबली में लिखा जा रहा है क्योंकि आपको विलंबता छुपाने और थ्रूपुट का अधिकतम लाभ प्राप्त करने के लिए मैन्युअल रूप से लोड और स्टोर करने के निर्देशों की आवश्यकता होती है।

आम तौर पर डेटा की एक पूरी कैश लाइन को अनियंत्रित लूप के एक पुनरावृत्ति में कॉपी किया जाना चाहिए।

जो मुझे पूर्व-सुधार को जोड़ते हुए अगले सुधार में लाता है। ये विशेष निर्देश हैं जो प्रोसेसर के कैश सिस्टम को मेमोरी के विशिष्ट भागों को उसके कैश में लोड करने के लिए कहते हैं। चूंकि निर्देश जारी करने और कैश लाइन को भरे जाने के बीच देरी होती है, इसलिए निर्देशों को इस तरह से रखा जाना चाहिए ताकि डेटा तब उपलब्ध हो जब उसे कॉपी किया जाना है, और जल्द / बाद में नहीं।

इसका मतलब फ़ंक्शन की शुरुआत में और साथ ही मुख्य कॉपी लूप के अंदर प्रीफैच निर्देश डालना है। प्रीपीच निर्देशों के साथ कॉपी लूप के डेटा के बीच में जो कई पुनरावृत्तियों समय में कॉपी किया जाएगा।

मुझे याद नहीं है, लेकिन यह गंतव्य पते के साथ-साथ स्रोत वाले लोगों को भी पूर्वनिर्मित करने के लिए फायदेमंद हो सकता है।

कारक

मेमोरी को कितनी तेजी से कॉपी किया जा सकता है, इसे प्रभावित करने वाले मुख्य कारक हैं:

  • प्रोसेसर, उसके कैश और मुख्य मेमोरी के बीच विलंबता।
  • प्रोसेसर की कैश लाइनों का आकार और संरचना।
  • प्रोसेसर की मेमोरी चाल / कॉपी निर्देश (विलंबता, प्रवाह, रजिस्टर आकार, आदि)।

इसलिए यदि आप एक कुशल और तेज़ मेमोरी फेस रुटीन लिखना चाहते हैं, तो आपको उस प्रोसेसर और आर्किटेक्चर के बारे में बहुत कुछ जानना होगा जो आप लिख रहे हैं। कहने के लिए पर्याप्त, जब तक आप कुछ एम्बेडेड प्लेटफ़ॉर्म पर नहीं लिख रहे हैं, यह सिर्फ मेमोरी कॉपी रूटीन में निर्मित उपयोग करने के लिए बहुत आसान होगा।


आधुनिक सीपीयू एक लीनियर मेमोरी एक्सेस पैटर्न का पता लगाएगा और अपने आप प्रीफ़ेट करना शुरू कर देगा। मुझे उम्मीद है कि प्रीफैच निर्देशों की वजह से ज्यादा फर्क नहीं पड़ेगा।
maxy

@maxy कुछ आर्किटेक्चर पर जो मैंने प्रीफ़ेच जोड़ने के लिए मेमोरी कॉपी रूटीन लागू किया है, ने औसत दर्जे की मदद की है। हालांकि यह सच हो सकता है कि वर्तमान पीढ़ी इंटेल / एएमडी चिप्स बहुत आगे तक प्रीफैच करते हैं, पुराने चिप्स और अन्य आर्किटेक्चर के बहुत सारे हैं जो ऐसा नहीं करते हैं।
डेमिन

क्या कोई समझा सकता है "(b_src & 0x3)! = 0"? मैं इसे समझ नहीं सकता, और यह भी - यह संकलित नहीं करेगा (एक त्रुटि फेंकता है: अमान्य ऑपरेटर बाइनरी और: अहस्ताक्षरित चार और इंट);
डेविड रेफेली

"(b_src & 0x3)! = 0" जाँच रहा है कि क्या सबसे कम 2 बिट्स 0. नहीं हैं। यदि स्रोत पॉइंटर 4 बाइट्स के एक से अधिक में संरेखित है या नहीं। आपकी संकलित त्रुटि तब होती है क्योंकि यह 0x3 को एक बाइट नहीं के रूप में मान रहा है, आप इसे 0x00000003 या 0x3i (मुझे लगता है) का उपयोग करके ठीक कर सकते हैं।
डेमिन

b_src & 0x3संकलन नहीं करेंगे क्योंकि आपको सूचक प्रकारों पर बिटवाइज़ अंकगणित करने की अनुमति नहीं है। आपको इसे (u)intptr_tपहले करना होगा
phuclv

18

memcpyकंप्यूटर की वास्तुकला के आधार पर एक बार में एक से अधिक बाइट कॉपी कर सकते हैं। अधिकांश आधुनिक कंप्यूटर एक एकल प्रोसेसर निर्देश में 32 बिट्स या अधिक के साथ काम कर सकते हैं।

से एक उदाहरण दिया गया :

    00026 * शीघ्र प्रतिलिपि के लिए, सामान्य स्थिति को अनुकूलित करें जहां दोनों बिंदु हों
    00027 * और लंबाई शब्द-संरेखित हैं, और इसके बजाय शब्द-पर-ए-समय की प्रतिलिपि बनाएँ
    00028 * बाइट-ऑफ-ए-टाइम। अन्यथा, बाइट्स द्वारा कॉपी करें।

8
एक 386 (एक उदाहरण के लिए), जिस पर कोई ऑन-बोर्ड कैश नहीं था, इससे बहुत फर्क पड़ा। अधिकांश आधुनिक प्रोसेसरों पर, रीड एंड राइट एक समय में एक कैश-लाइन होगा, और मेमोरी के लिए बस आमतौर पर अड़चन होगी, इसलिए कुछ प्रतिशत के सुधार की उम्मीद करें, कहीं भी चौगुनी के करीब नहीं।
जेरी कॉफिन

2
मुझे लगता है कि आपको "स्रोत से" कहने पर आपको थोड़ा और स्पष्ट होना चाहिए। यकीन है, कि कुछ आर्किटेक्चर पर "स्रोत" है, लेकिन यह निश्चित रूप से नहीं है, कहते हैं, बीएसडी या विंडोज मशीन। (और नरक, यहां तक ​​कि GNU सिस्टम के बीच भी इस फ़ंक्शन में अक्सर बहुत अंतर होता है)
बिली ओनली

@ बिली ओनली: +1 बिलकुल सही ... एक बिल्ली की त्वचा के लिए एक से अधिक तरीके हैं। वह सिर्फ एक उदाहरण था। फिक्स्ड! रचनात्मक टिप्पणी के लिए धन्यवाद।
मार्क बायर्स

7

आप memcpy()निम्नलिखित तकनीकों में से किसी का उपयोग करके कार्यान्वित कर सकते हैं , प्रदर्शन के लाभ के लिए आपकी वास्तुकला पर निर्भर हैं, और वे सभी आपके कोड से बहुत तेज़ होंगे:

  1. बाइट्स के बजाय 32-बिट शब्दों जैसी बड़ी इकाइयों का उपयोग करें। आप यहां भी संरेखण के साथ सौदा कर सकते हैं (या हो सकता है)। आप कुछ प्लेटफार्मों पर उदाहरण के लिए विषम स्मृति स्थान पर 32-बिट शब्द पढ़ने / लिखने नहीं जा सकते हैं, और अन्य प्लेटफार्मों पर आप एक बड़े पैमाने पर प्रदर्शन का जुर्माना देते हैं। इसे ठीक करने के लिए, पते को 4. से विभाज्य इकाई होना चाहिए। आप 64 बिट सीपीयू के लिए इसे 64-बिट तक ले जा सकते हैं, या SIMD (एकल निर्देश, एकाधिक डेटा) निर्देशों ( MMX , SSE , आदि) का उपयोग करके भी अधिक कर सकते हैं ।

  2. आप विशेष सीपीयू निर्देशों का उपयोग कर सकते हैं जो आपके कंपाइलर सी से अनुकूलन करने में सक्षम नहीं हो सकते हैं। उदाहरण के लिए, 80386 पर, आप एन बाइट्स को एन में रखकर निर्धारित किए जाने वाले एन बाइट्स को स्थानांतरित करने के लिए "प्रतिनिधि" उपसर्ग निर्देश + "Movsb" निर्देश का उपयोग कर सकते हैं। रजिस्टर करें। अच्छा संकलक आपके लिए बस यही करेगा, लेकिन आप एक ऐसे मंच पर हो सकते हैं जिसमें अच्छे संकलक का अभाव है। ध्यान दें, यह उदाहरण गति का एक बुरा प्रदर्शन है, लेकिन संरेखण + बड़ी इकाई निर्देशों के साथ संयुक्त है, यह कुछ सीपीयू पर बाकी सभी चीजों की तुलना में तेज हो सकता है।

  3. अनियंत्रित लूप - कुछ सीपीयू पर शाखाएं काफी महंगी हो सकती हैं, इसलिए लूप को अनियंत्रित करने से शाखाओं की संख्या कम हो सकती है। यह SIMD निर्देशों और बहुत बड़े आकार की इकाइयों के साथ संयोजन के लिए एक अच्छी तकनीक है।

उदाहरण के लिए, http://www.agner.org/optimize/#asmlib में एक memcpyकार्यान्वयन है जो वहां सबसे अधिक धड़कता है (बहुत छोटी राशि से)। यदि आप स्रोत कोड पढ़ते हैं, तो यह उन सभी तीन तकनीकों को खींचता है, जो उपरोक्त सभी तीन तकनीकों को खींचती हैं, जिनमें से कौन सी CPU आप पर चल रही है, उसके आधार पर चुनकर भरी हुई होगी।

ध्यान दें, ऐसी ही अनुकूलन हैं जो बफ़र में बाइट खोजने के लिए भी किए जा सकते हैं। strchr()और दोस्त अक्सर आपके हाथ के बराबर तेजी से लुढ़क जाएंगे। यह .NET और जावा के लिए विशेष रूप से सच है । उदाहरण के लिए, .NET में, अंतर्निहित बॉयर-मूर स्ट्रिंग खोज कीString.IndexOf() तुलना में बहुत तेज है , क्योंकि यह उपरोक्त अनुकूलन तकनीकों का उपयोग करता है।


1
वही एग्नर फॉग जिसे आप लिंक कर रहे हैं, यह भी प्रमाणित करता है कि लूप का अनियंत्रण आधुनिक सीपीयू पर उल्टा है

आजकल अधिकांश सीपीयू में अच्छी शाखा भविष्यवाणी होती है, जो कि विशिष्ट मामलों में लूप के लाभ को नकारना चाहिए। एक अच्छा अनुकूलन कंपाइलर अभी भी कभी-कभी इसका उपयोग कर सकता है।
थोमसट्रेटर

5

संक्षिप्त जवाब:

  • कैश भरना
  • जहाँ संभव हो बाइट वालों के बजाय स्थानान्तरण को शब्दों में बयां करें
  • SIMD जादू

4

मुझे नहीं पता कि यह वास्तव में किसी भी वास्तविक दुनिया के कार्यान्वयन में उपयोग किया जाता है memcpy, लेकिन मुझे लगता है कि डफ का डिवाइस यहां उल्लेख के योग्य है।

से विकिपीडिया :

send(to, from, count)
register short *to, *from;
register count;
{
        register n = (count + 7) / 8;
        switch(count % 8) {
        case 0:      do {     *to = *from++;
        case 7:              *to = *from++;
        case 6:              *to = *from++;
        case 5:              *to = *from++;
        case 4:              *to = *from++;
        case 3:              *to = *from++;
        case 2:              *to = *from++;
        case 1:              *to = *from++;
                } while(--n > 0);
        }
}

ध्यान दें कि ऊपर नहीं है memcpyक्योंकि यह जानबूझकर toसंकेतक को नहीं बढ़ाता है । यह एक अलग ऑपरेशन को कार्यान्वित करता है: लेखन एक मेमोरी-मैप्ड रजिस्टर में। विवरण के लिए विकिपीडिया लेख देखें।


डफ का उपकरण, या सिर्फ शुरुआती कूद तंत्र, पहले 1..3 (या 1..7) बाइट्स को कॉपी करने के लिए एक अच्छा उपयोग है ताकि पॉइंटर्स को एक अच्छे सीमा से जोड़ा जाए जहां बड़ी मेमोरी मूव निर्देशों का उपयोग किया जा सके।
डेमिन

@MarkByers: कोड थोड़ा अलग ऑपरेशन दिखाता है ( *toएक मेमोरी-मैप्ड रजिस्टर को संदर्भित करता है और इसे जानबूझकर नहीं बढ़ाया जाता है - लिंक किए गए लेख को देखें)। जैसा कि मैंने सोचा था कि मैंने स्पष्ट कर दिया है, मेरा जवाब एक कुशल प्रदान करने का प्रयास नहीं करता है memcpy, यह केवल एक जिज्ञासु तकनीक का उल्लेख करता है।
एनपीई

@ डैमिन सहमत, जैसा कि आपने कहा कि आप {} को छोड़ सकते हैं जबकि () और स्विच को कंपाइलर द्वारा जंप टेबल में अनुवाद किया जाएगा। बहुत उपयोगी है जब आप शेष डेटा की देखभाल करना चाहते हैं। डफ के उपकरण के बारे में एक चेतावनी का उल्लेख किया जाना चाहिए, जाहिरा तौर पर नए आर्किटेक्चर (नए x86) पर, शाखा की भविष्यवाणी इतनी कुशल है कि डफ का उपकरण वास्तव में एक साधारण लूप की तुलना में धीमा है।
onemasse

1
अरे नहीं .. डफ का उपकरण नहीं। कृपया डफ के उपकरण का उपयोग न करें। कृप्या। PGO का उपयोग करें और मुझे संकलक करते हैं, जहां यह समझ में आता है कि आपके लिए अनियंत्रित है।
बिली ओनली

नहीं, किसी भी आधुनिक कार्यान्वयन में डफ़ का उपकरण निश्चित रूप से उपयोग नहीं किया जाता है।
gnasher729

3

जैसे अन्य लोग कहते हैं कि मेम्फकी प्रतियां 1-बाइट की तुलना में बड़ी हैं। शब्द के आकार के विखंडू में नकल करना बहुत तेज है। हालांकि, अधिकांश कार्यान्वयन इसे एक कदम आगे ले जाते हैं और लूपिंग से पहले कई MOV (शब्द) निर्देश चलाते हैं। प्रति में 8 शब्द ब्लॉक प्रति कॉपी करने का लाभ यह है कि लूप स्वयं महंगा है। यह तकनीक विशाल ब्लॉकों के लिए प्रतिलिपि का अनुकूलन करते हुए, 8 के कारक द्वारा सशर्त शाखाओं की संख्या को कम करती है।


1
मुझे नहीं लगता कि यह सच है। आप लूप को अनियंत्रित कर सकते हैं, लेकिन आप लक्ष्य आर्किटेक्चर पर एक समय में पता करने योग्य से अधिक एकल निर्देश में कॉपी नहीं कर सकते। इसके अलावा, वहाँ भी लूप unrolling के उपरि है ...
बिली ONeal

@ बिली ONeal: मुझे नहीं लगता कि VoidStar का मतलब क्या है। कई लगातार कदम निर्देश होने से इकाइयों की संख्या की गिनती का ओवरहेड कम हो जाता है।
11:05

@ बिली ओनली: आप इस बिंदु को याद कर रहे हैं। एक समय में 1-शब्द MOV, JMP, MOV, JMP, आदि की तरह है, जहाँ आप MOV MOV MOV MOV JMP कर सकते हैं। मैंने पहले भी लिखा है और मैंने इसे करने के कई तरीके
निर्धारित किए हैं

@wallyk: शायद। लेकिन वह कहते हैं, "कॉपी और भी बड़ा हिस्सा" - जो वास्तव में संभव नहीं हैं। यदि वह लूप अनरोलिंग का मतलब है, तो उसे कहना चाहिए "अधिकांश कार्यान्वयन इसे एक कदम आगे ले जाते हैं और लूप को अनियंत्रित करते हैं।" लिखित रूप में उत्तर सबसे भ्रामक है, सबसे गलत है।
बिली ओनेल

@VoidStar: सहमत --- यह अब बेहतर है। +1।
बिली ओनली

2

उत्तर बहुत अच्छे हैं, लेकिन अगर आप अभी भी memcpyखुद को तेजी से लागू करना चाहते हैं , तो सी में तेजी से मेमचैपी, फास्ट मेमसीपी के बारे में एक दिलचस्प ब्लॉग पोस्ट है

void *memcpy(void* dest, const void* src, size_t count)
{
    char* dst8 = (char*)dest;
    char* src8 = (char*)src;

    if (count & 1) {
        dst8[0] = src8[0];
        dst8 += 1;
        src8 += 1;
    }

    count /= 2;
    while (count--) {
        dst8[0] = src8[0];
        dst8[1] = src8[1];

        dst8 += 2;
        src8 += 2;
    }
    return dest;
}

यहां तक ​​कि, यह मेमोरी एक्सेस को अनुकूलित करने के साथ बेहतर हो सकता है।


1

क्योंकि कई लाइब्रेरी रूटीन की तरह यह आपके द्वारा चलाए जा रहे आर्किटेक्चर के लिए अनुकूलित किया गया है। दूसरों ने विभिन्न तकनीकों को पोस्ट किया है जिनका उपयोग किया जा सकता है।

पसंद को देखते हुए, अपने स्वयं के रोल के बजाय लाइब्रेरी रूटीन का उपयोग करें। यह डीआरवाई पर एक भिन्नता है जिसे मैं डीआरओ कहता हूं (दूसरों को न दोहराएं)। इसके अलावा, लाइब्रेरी रूटीन आपके अपने कार्यान्वयन से कम गलत हैं।

मैंने मेमोरी एक्सेस चेकर्स को मेमोरी या स्ट्रिंग बफ़र पर सीमा से बाहर की शिकायत के बारे में देखा है जो कि शब्द आकार के एक से अधिक नहीं थे। यह उपयोग किए जा रहे अनुकूलन का एक परिणाम है।


0

आप एमएसीओएस कार्यान्वयन को मेमसेट, मेमसीपी और मेमोव पर देख सकते हैं।

बूट समय पर, ओएस निर्धारित करता है कि यह किस प्रोसेसर पर चल रहा है। यह प्रत्येक समर्थित प्रोसेसर के लिए विशेष रूप से अनुकूलित कोड में बनाया गया है, और बूट समय पर एक निश्चित रीड / केवल स्थान में सही कोड के लिए एक जेएमपी निर्देश संग्रहीत करता है।

सी मेमसेट, मेम्ची और मेमोवे कार्यान्वयन केवल उस निश्चित स्थान पर एक छलांग है।

कार्यान्वयन मेम्के और मेमोव के लिए स्रोत और गंतव्य के संरेखण के आधार पर विभिन्न कोड का उपयोग करते हैं। वे स्पष्ट रूप से सभी उपलब्ध वेक्टर क्षमताओं का उपयोग करते हैं। जब आप बड़ी मात्रा में डेटा की प्रतिलिपि बनाते हैं, तो वे गैर-कैशिंग संस्करण का भी उपयोग करते हैं, और पृष्ठ तालिकाओं के लिए प्रतीक्षा को कम करने के निर्देश होते हैं। यह सिर्फ कोडांतरक कोड नहीं है, यह कोडांतरक कोड है जो किसी व्यक्ति द्वारा प्रत्येक प्रोसेसर वास्तुकला के बहुत अच्छे ज्ञान के साथ लिखा गया है।

इंटेल ने असेंबलर निर्देशों को भी जोड़ा है जो स्ट्रिंग ऑपरेशन को तेज कर सकता है। उदाहरण के लिए, एक चक्र में 256 बाइट की तुलना करने वाली स्ट्रैस का समर्थन करने के निर्देश के साथ।


ऐप्पल के ओपन सोर्स वर्जन ऑफ़ मेमसेट / मेम्पी / मेमोव सिर्फ एक जेनेरिक वर्जन है जो कि SIMD का उपयोग करके असली वर्जन की तुलना में काफी धीमा होगा
phuclv
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.