मेमोरी कॉपी रूट पॉइंटर्स के माध्यम से सरल मेमोरी कॉपी की तुलना में कहीं अधिक जटिल और तेज हो सकता है:
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 ++) के बजाय असेंबली में लिखा जा रहा है क्योंकि आपको विलंबता छुपाने और थ्रूपुट का अधिकतम लाभ प्राप्त करने के लिए मैन्युअल रूप से लोड और स्टोर करने के निर्देशों की आवश्यकता होती है।
आम तौर पर डेटा की एक पूरी कैश लाइन को अनियंत्रित लूप के एक पुनरावृत्ति में कॉपी किया जाना चाहिए।
जो मुझे पूर्व-सुधार को जोड़ते हुए अगले सुधार में लाता है। ये विशेष निर्देश हैं जो प्रोसेसर के कैश सिस्टम को मेमोरी के विशिष्ट भागों को उसके कैश में लोड करने के लिए कहते हैं। चूंकि निर्देश जारी करने और कैश लाइन को भरे जाने के बीच देरी होती है, इसलिए निर्देशों को इस तरह से रखा जाना चाहिए ताकि डेटा तब उपलब्ध हो जब उसे कॉपी किया जाना है, और जल्द / बाद में नहीं।
इसका मतलब फ़ंक्शन की शुरुआत में और साथ ही मुख्य कॉपी लूप के अंदर प्रीफैच निर्देश डालना है। प्रीपीच निर्देशों के साथ कॉपी लूप के डेटा के बीच में जो कई पुनरावृत्तियों समय में कॉपी किया जाएगा।
मुझे याद नहीं है, लेकिन यह गंतव्य पते के साथ-साथ स्रोत वाले लोगों को भी पूर्वनिर्मित करने के लिए फायदेमंद हो सकता है।
कारक
मेमोरी को कितनी तेजी से कॉपी किया जा सकता है, इसे प्रभावित करने वाले मुख्य कारक हैं:
- प्रोसेसर, उसके कैश और मुख्य मेमोरी के बीच विलंबता।
- प्रोसेसर की कैश लाइनों का आकार और संरचना।
- प्रोसेसर की मेमोरी चाल / कॉपी निर्देश (विलंबता, प्रवाह, रजिस्टर आकार, आदि)।
इसलिए यदि आप एक कुशल और तेज़ मेमोरी फेस रुटीन लिखना चाहते हैं, तो आपको उस प्रोसेसर और आर्किटेक्चर के बारे में बहुत कुछ जानना होगा जो आप लिख रहे हैं। कहने के लिए पर्याप्त, जब तक आप कुछ एम्बेडेड प्लेटफ़ॉर्म पर नहीं लिख रहे हैं, यह सिर्फ मेमोरी कॉपी रूटीन में निर्मित उपयोग करने के लिए बहुत आसान होगा।