कैश लाइनें कैसे काम करती हैं?


169

मैं समझता हूं कि प्रोसेसर कैश लाइनों के माध्यम से डेटा को कैश में लाता है, जो - उदाहरण के लिए, मेरे एटम प्रोसेसर पर - एक समय में लगभग 64 बाइट्स लाता है, जो भी वास्तविक डेटा का आकार पढ़ा जा रहा है।

मेरा सवाल यह है कि:

कल्पना कीजिए कि आपको मेमोरी से एक बाइट पढ़ने की ज़रूरत है, जो 64 बाइट कैश में लाई जाएगी?

मैं जो दो संभावनाएं देख सकता हूं, वह यह है कि या तो 64 बाइट्स ब्याज की बाइट के नीचे निकटतम 64 बाइट्स सीमा पर शुरू होती हैं, या 64 बाइट्स कुछ पूर्व निर्धारित तरीके से बाइट के चारों ओर फैली हुई हैं (उदाहरण के लिए, आधा नीचे, आधा ऊपर, या सभी उपरोक्त)।

यह किसका है?


22
इस पढ़ें: क्या हर प्रोग्रामर स्मृति के बारे में पता होना चाहिए । तो इसे फिर से पढ़ें। यहां बेहतर (पीडीएफ) स्रोत
andersoj

जवाबों:


129

यदि आपके द्वारा लोड की जा रही बाइट या शब्द वाली कैश लाइन पहले से कैश में मौजूद नहीं है, तो आपका सीपीयू 64 बाइट्स का अनुरोध करेगा, जो कि कैश लाइन की सीमा पर शुरू होता है (आपके द्वारा आवश्यक सबसे बड़ा पता जो 64 से अधिक है) ।

आधुनिक पीसी मेमोरी मॉड्यूल एक बार में आठ हस्तांतरण के फटने पर 64 बिट्स (8 बाइट्स) को स्थानांतरित करते हैं , इसलिए एक कमांड मेमोरी से एक पूर्ण कैश लाइन के पढ़ने या लिखने को ट्रिगर करता है। (DDR1 / 2/3/4 SDRAM बर्स्ट ट्रांसफर साइज़ 64B तक कॉन्फ़िगर करने योग्य है; सीपीयू बर्स्ट ट्रांसफर साइज़ को उनके कैश लाइन साइज़ से मैच करने के लिए सिलेक्ट करेगा, लेकिन 64B कॉमन है)

अंगूठे के एक नियम के रूप में, यदि प्रोसेसर मेमोरी एक्सेस का पूर्वानुमान नहीं लगा सकता है (और इसे प्रीफ़ैच कर सकता है), पुनर्प्राप्ति प्रक्रिया ~ 90 नैनोसेकंड, या ~ 250 घड़ी चक्र (सीपीयू से सीपीयू को पता प्राप्त डेटा प्राप्त कर सकती है) ले सकती है।

इसके विपरीत, L1 कैश में एक हिट में 3 या 4 चक्रों का लोड-उपयोग विलंबता है, और स्टोर-रीलोड में आधुनिक x86 CPUs पर 4 या 5 चक्रों का स्टोर-फ़ॉरवर्डिंग विलंबता है। हालात अन्य आर्किटेक्चर पर समान हैं।

आगे पढ़ें: अलरिक ड्रेपपर की क्या हर प्रोग्रामर चाहिए नो स्मृति के बारे में । सॉफ़्टवेयर-प्रीफ़ैच सलाह थोड़ी पुरानी है: आधुनिक एचडब्ल्यू प्रीफ़ैचर्स स्मार्ट हैं, और हाइपरथ्रेडिंग पी 4 दिनों की तुलना में बेहतर है (इसलिए प्रीफ़ेच थ्रेड आमतौर पर एक बेकार है)। यह भी टैग विकि में उस वास्तुकला के लिए बहुत सारे प्रदर्शन लिंक हैं।


1
यह जवाब बिल्कुल कोई मतलब नहीं है। 64 बाइट के साथ करने के लिए 64 बिट मेमोरी बैंडविड्थ (जो उस संबंध में गलत भी है) क्या करता है? साथ ही अगर आप राम को मारते हैं तो 10 से 30 एनएस भी पूरी तरह से गलत हैं। यह L3 या L2 कैश के लिए सही हो सकता है लेकिन RAM के लिए नहीं जहाँ यह 90ns की तरह है। आपके कहने का मतलब है कि बर्स्ट टाइम - अगले क्वैड-वर्ड को बर्स्ट मोड में पहुंचने का समय (जो वास्तव में सही उत्तर है)
मार्टिन केर्स्टन

5
@MartinKersten: DDR1 / 2/3/4 SDRAM का एक चैनल 64-बिट डेटा बस चौड़ाई का उपयोग करता है। पूरी कैश लाइन का एक फट ट्रांसफर प्रत्येक 8B के आठ स्थानान्तरण लेता है, और वास्तव में ऐसा होता है। यह अभी भी सही हो सकता है कि यह प्रक्रिया वांछित बाइट वाले 8B- संरेखित चंक को स्थानांतरित करके अनुकूलित की गई है, अर्थात वहां पर फट शुरू करना (और अगर यह फटने वाले आकार का पहला 8B नहीं था तो चारों ओर लपेटना)। बहु-स्तरीय कैश के साथ आधुनिक सीपीयू शायद ऐसा नहीं करते हैं, हालांकि, इसका मतलब यह होगा कि एल 1 कैश तक फटने के पहले ब्लॉक (एस) को रिले करना होगा।
पीटर कॉर्ड्स

2
Haswell में L2 और L1D कैश (यानी एक पूर्ण कैश लाइन चौड़ाई) के बीच 64B पथ है , इसलिए अनुरोधित बाइट वाले 8B को स्थानांतरित करना उस बस के अक्षम उपयोग के लिए होगा। @ मॉर्टिन एक लोड के लिए एक्सेस टाइम के बारे में भी सही है जिसमें मुख्य मेमोरी पर जाना है।
पीटर कॉर्ड्स

3
इस बारे में अच्छा सवाल है कि क्या डेटा एक ही बार में मेमोरी पदानुक्रम तक जाता है, या क्या L3 इसे L2 तक भेजने के लिए शुरू करने से पहले मेमोरी से पूरी लाइन की प्रतीक्षा करता है। कैश के विभिन्न स्तरों के बीच स्थानांतरण बफ़र हैं, और प्रत्येक बकाया मिस क्लेम। तो ( कुल अनुमान ) शायद L3 मेमोरी नियंत्रक से बाइट्स को अपने स्वयं के प्राप्त बफर में उसी समय डालता है जैसे कि एल 2 कैश के लिए उपयुक्त लोड बफर में डालते हैं जो इसे चाहते थे। जब रेखा पूरी तरह से मेमोरी से स्थानांतरित हो जाती है, तो L3 L2 को सूचित करता है कि लाइन तैयार है, और इसे अपने स्वयं के सरणी में कॉपी करता है।
पीटर कॉर्ड्स

2
@ मर्टिन: मैंने आगे बढ़ने और इस जवाब को संपादित करने का फैसला किया। मुझे लगता है कि यह अब और अधिक सटीक है, और अभी भी सरल है। भविष्य के पाठक: माइक के प्रश्न और मेरे उत्तर को भी देखें: stackoverflow.com/questions/39182060/…
पीटर कॉर्ड्स

22

यदि कैश लाइनें 64 बाइट्स चौड़ी हैं, तो वे मेमोरी के ब्लॉक से मेल खाते हैं जो उन एड्रेस पर शुरू होते हैं जो 64 से विभाज्य हैं। किसी भी एड्रेस के कम से कम 6 बिट्स कैश लाइन में एक ऑफसेट हैं।

तो किसी भी बाइट के लिए, जिस कैश लाइन को लाना होता है, वह पते के कम से कम साइनफ़िसेंट छह बिट्स को साफ़ करके पाई जा सकती है, जो कि निकटतम पते के लिए गोलाई से मेल खाती है जो 64 से विभाज्य है।

यद्यपि यह हार्डवेयर द्वारा किया जाता है, हम कुछ संदर्भ C मैक्रो परिभाषाओं का उपयोग करके गणना दिखा सकते हैं:

#define CACHE_BLOCK_BITS 6
#define CACHE_BLOCK_SIZE (1U << CACHE_BLOCK_BITS)  /* 64 */
#define CACHE_BLOCK_MASK (CACHE_BLOCK_SIZE - 1)    /* 63, 0x3F */

/* Which byte offset in its cache block does this address reference? */
#define CACHE_BLOCK_OFFSET(ADDR) ((ADDR) & CACHE_BLOCK_MASK)

/* Address of 64 byte block brought into the cache when ADDR accessed */
#define CACHE_BLOCK_ALIGNED_ADDR(ADDR) ((ADDR) & ~CACHE_BLOCK_MASK)

1
इसे समझने के लिए मेरे पास कठिन समय है। मुझे पता है कि 2 साल बाद है, लेकिन क्या आप मुझे इसके लिए उदाहरण कोड दे सकते हैं? एक या दो लाइनें।
निक

1
@ इस कारण से यह विधि द्विआधारी संख्या प्रणाली में निहित है। 2 की किसी भी शक्ति का केवल एक बिट सेट है और सभी शेष बिट्स साफ़ हो गए हैं, इसलिए 64 के लिए, आपने 0b1000000देखा है कि अंतिम 6 अंक शून्य हैं, इसलिए जब आप उन 6 सेटों में से कुछ के साथ कुछ संख्या रखते हैं (जो संख्या का प्रतिनिधित्व करते हैं % 64), उन्हें साफ़ करने से आपको निकटतम 64-बाइट संरेखित मेमोरी पता मिल जाएगा।
लीजेंड्स 2k

21

सबसे पहले एक मुख्य मेमोरी एक्सेस बहुत महंगी है। वर्तमान में एक 2GHz CPU (सबसे धीमा एक बार) 2G टिक (चक्र) प्रति सेकंड है। एक सीपीयू (आजकल वर्चुअल कोर) टिक के अनुसार अपने रजिस्टरों से एक मूल्य प्राप्त कर सकता है। चूंकि एक आभासी कोर में कई प्रसंस्करण इकाइयाँ (ALU - अंकगणितीय तर्क इकाई, FPU आदि) होती हैं, यह वास्तव में यदि संभव हो तो समानांतर में कुछ निर्देशों को संसाधित कर सकता है।

मुख्य मेमोरी की पहुंच लगभग 70ns से 100ns (DDR4 थोड़ी तेज़) है। यह समय मूल रूप से L1, L2 और L3 कैश को देख रहा है और मेमोरी को हिट करने से (मेमोरी कंट्रोलर को कमांड भेजें, जो इसे मेमोरी बैंकों को भेजता है), प्रतिक्रिया की प्रतीक्षा करें और किया।

100ns का मतलब लगभग 200 टिक होता है। इसलिए मूल रूप से अगर कोई प्रोग्राम हमेशा उन कैश को याद रखेगा जो प्रत्येक मेमोरी एक्सेस करता है, तो सीपीयू अपने समय का लगभग 99,5% खर्च करेगा (यदि यह केवल मेमोरी पढ़ता है) बेकार है जो मेमोरी का इंतजार कर रहा है।

चीजों को गति देने के लिए एल 1, एल 2, एल 3 कैश है। वे मेमोरी को सीधे चिप पर रखे जाने और दिए गए बिट्स को स्टोर करने के लिए एक अलग तरह के ट्रांजिस्टर सर्किट का उपयोग करते हैं। यह अधिक कमरे, अधिक ऊर्जा लेता है और मुख्य मेमोरी की तुलना में अधिक महंगा है क्योंकि एक सीपीयू आमतौर पर एक अधिक उन्नत तकनीक और एल 1, एल 2 में उत्पादन विफलता का उपयोग करके उत्पादित होता है, एल 3 मेमोरी में सीपीयू को बेकार (दोष) को प्रस्तुत करने का मौका होता है। बड़े L1, L2, L3 कैश त्रुटि दर को बढ़ाते हैं जो पैदावार को घटाता है जो सीधे ROI घटता है। जब उपलब्ध कैश आकार की बात आती है तो बहुत बड़ा व्यापार बंद होता है।

(वर्तमान में कोई व्यक्ति अधिक L1, L2, L3 कैश बनाता है ताकि कुछ भागों को निष्क्रिय करने में सक्षम हो सके ताकि वास्तविक उत्पादन दोष कैश मेमोरी क्षेत्रों में CPU दोष को एक पूरे के रूप में प्रस्तुत किया जा सके)।

एक समय पर विचार देने के लिए (स्रोत: कैश और मेमोरी तक पहुंचने के लिए लागत )

  • L1 कैश: 1ns से 2ns (2-4 चक्र)
  • L2 कैश: 3ns से 5ns (6-10 चक्र)
  • L3 कैश: 12ns से 20ns (24-40 चक्र)
  • RAM: 60ns (120 चक्र)

चूंकि हम अलग-अलग सीपीयू प्रकारों का मिश्रण करते हैं, ये केवल अनुमान हैं, लेकिन एक अच्छा विचार दें कि वास्तव में क्या हो रहा है जब कोई मेमोरी वैल्यू प्राप्त होती है और हमारे पास निश्चित कैश लेयर में हिट या मिस हो सकती है।

तो एक कैश मूल रूप से मेमोरी एक्सेस को बहुत तेज कर देता है (60ns बनाम 1ns)।

एक मूल्य प्राप्त करना, इसे कैश में संग्रहीत करना फिर से चलाने की संभावना के लिए यह उन चर के लिए अच्छा है जो अक्सर एक्सेस किए जाते हैं लेकिन मेमोरी कॉपी संचालन के लिए यह अभी भी धीमा करना होगा क्योंकि एक मूल्य पढ़ता है, कहीं मूल्य लिखता है और कभी भी मूल्य नहीं पढ़ता है। फिर से ... कोई कैश हिट नहीं होता है, मृत धीमी गति से (इसके पास समानांतर में हो सकता है क्योंकि हमारे पास ऑर्डर निष्पादन से बाहर है)।

यह मेमोरी कॉपी इतनी महत्वपूर्ण है कि इसे गति देने के लिए अलग-अलग साधन हैं। शुरुआती दिनों में मेमोरी अक्सर सीपीयू के बाहर मेमोरी को कॉपी करने में सक्षम थी। इसे सीधे मेमोरी कंट्रोलर द्वारा हैंडल किया गया था, इसलिए मेमोरी कॉपी ऑपरेशन ने कैश को प्रदूषित नहीं किया।

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

इसलिए मेमोरी एक्सेस पैटर्न का विश्लेषण करके यह स्पष्ट था कि डेटा को क्रमिक रूप से बहुत बार पढ़ा जाता है। इस बात की बहुत अधिक संभावना थी कि यदि कोई प्रोग्राम इंडेक्स i पर वैल्यू पढ़ता है, तो वह प्रोग्राम वैल्यू i + 1 को भी पढ़ेगा। यह संभावना इस संभावना से थोड़ी अधिक है कि एक ही कार्यक्रम भी i + 2 और इसी तरह के मूल्य को पढ़ेगा।

इसलिए एक स्मृति पता दिया गया था (और अभी भी) आगे पढ़ने और अतिरिक्त मूल्यों को प्राप्त करने के लिए एक अच्छा विचार है। यही कारण है कि एक बढ़ावा मोड है।

बूस्ट मोड में मेमोरी एक्सेस का मतलब है, एक पता भेजना और कई मान क्रमिक रूप से भेजना है। प्रत्येक अतिरिक्त मूल्य भेजें केवल अतिरिक्त 10ns (या नीचे भी) लेता है।

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

उदाहरण के लिए 64 बाइट्स की एक कैश लाइन का मतलब है कि मेमोरी को मेमोरी के अलग-अलग (गैर-ओवरलैपिंग) ब्लॉक में विभाजित किया गया है, जिसका आकार 64bytes है। 64bytes का अर्थ है कि प्रत्येक ब्लॉक के प्रारंभ पते में हमेशा शून्य होने के लिए सबसे कम छह पता बिट्स होते हैं। इसलिए हर बार इन छह शून्य बिट्स को भेजने की जरूरत नहीं है, पते की चौड़ाई (स्वागत प्रभाव) की किसी भी संख्या के लिए पता स्थान को 64 गुना बढ़ाने की आवश्यकता है।

एक अन्य समस्या कैश लाइन हल करती है (आगे पढ़ने और पता बस पर छह बिट्स को सहेजने / मुक्त करने के साथ) जिस तरह से कैश का आयोजन किया जाता है। उदाहरण के लिए यदि एक कैश को 8 बाइट (64 बिट) ब्लॉक (सेल) में विभाजित किया जाएगा, तो किसी को मेमोरी सेल के पते को स्टोर करने की आवश्यकता होती है, यह कैश सेल इसके लिए मान रखता है। यदि पता भी 64bit होगा तो इसका मतलब है कि पते के आधे कैश आकार का उपभोग किया जाता है जिसके परिणामस्वरूप 100% ओवरहेड होता है।

चूंकि एक कैश लाइन 64bytes है और एक सीपीयू 64 बिट - 6 बिट = 58 बिट (शून्य बिट्स को भी स्टोर करने की आवश्यकता नहीं है) का उपयोग कर सकता है, इसका मतलब है कि हम 58 बिट (11% ओवरहेड) के ओवरहेड के साथ 64 बिट्स या 512 बिट्स को कैश कर सकते हैं। वास्तविकता में संग्रहीत पते इससे भी छोटे होते हैं लेकिन स्टेटस informations होते हैं (जैसे कैश लाइन वैध और सटीक, गंदी और राम आदि में वापस लिखने की आवश्यकता होती है)।

एक और पहलू यह है कि हमारे पास सेट-एसोसिएटिव कैश है। प्रत्येक कैश सेल एक निश्चित पते को संग्रहीत करने में सक्षम नहीं है, लेकिन केवल उन का एक सबसेट है। यह आवश्यक संग्रहीत पता बिट्स भी छोटे बना देता है, कैश की समानांतर एक्सेस (प्रत्येक सबसेट एक बार पहुँचा जा सकता है लेकिन अन्य सबसेट से स्वतंत्र) की अनुमति देता है।

विशेष रूप से तब होता है जब अलग-अलग आभासी कोर के बीच कैश / मेमोरी एक्सेस को सिंक्रनाइज़ करने की बात आती है, प्रति कोर में उनकी कई स्वतंत्र प्रसंस्करण इकाइयाँ और अंत में एक मेनबोर्ड पर कई प्रोसेसर होते हैं (जो कि बोर्ड आवास 48 से अधिक प्रोसेसर और अधिक होते हैं)।

यह मूल रूप से वर्तमान विचार है कि हमारे पास कैश लाइनें क्यों हैं। आगे पढ़ने से लाभ बहुत अधिक है और कैश-लाइन से एक भी बाइट पढ़ने का सबसे खराब मामला है और बाकी कभी नहीं पढ़ा है क्योंकि संभावना बहुत पतली है।

कैश-लाइन का आकार (64) बड़ी कैश-लाइनों के बीच एक बुद्धिमान चुना हुआ व्यापार है, जो इसे अंतिम बाइट के निकट भविष्य में भी पढ़ने की संभावना नहीं बनाता है, जिस अवधि को पूरा कैश लाइन प्राप्त करना होता है। स्मृति से कैश संगठन में भूमि के ऊपर और कैश और स्मृति उपयोग का बनता है (और इसे वापस लिखने के लिए) और भी।


1
एक सेट-एसोसिएटिव कैश एक सेट का चयन करने के लिए कुछ एड्रेस बिट्स का उपयोग करता है, इसलिए टैग आपके उदाहरण से भी कम हो सकते हैं। बेशक, कैश को इस बात पर भी नज़र रखने की ज़रूरत है कि सेट में कौन सा टैग किस डेटा सरणी के साथ जाता है, लेकिन आमतौर पर सेट के भीतर तरीकों की तुलना में अधिक सेट होते हैं। (उदा। 32kB 8-वे एसोसिएटिव L1D कैश, 64B लाइनों के साथ, इंटेल x86 CPUs में: 6 बिट, इंडेक्स 6 बिट्स ऑफसेट। टैग केवल 48-12 बिट्स चौड़े होने की आवश्यकता है, क्योंकि x86-64 (अभी के लिए) केवल 48 बिट्स है। बिट भौतिक पते। जैसा कि मुझे पता है कि आप जानते हैं, यह एक संयोग नहीं है कि निम्न 12 बिट्स पृष्ठ ऑफसेट है, इसलिए एल 1 एलएटीएस के बिना VIPT हो सकता है।)
पीटर कॉर्ड्स

अद्भुत जवाब कली ... वहाँ एक "की तरह" बटन कहीं भी है?
एजगार्ड लीमा

@EdgardLima, upvote बटन नहीं?
Pacerier

6

प्रोसेसर में बहु-स्तरीय कैश (एल 1, एल 2, एल 3) हो सकते हैं, और ये आकार और गति पर भिन्न होते हैं।

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

शाखा भविष्यवक्ता , सीपीयू कैश और प्रतिस्थापन नीतियों के बारे में पढ़ें ।

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


4

मैं निश्चित रूप से नहीं कह सकता क्योंकि हर हार्डवेयर अलग होता है, लेकिन यह आमतौर पर "64 बाइट्स सबसे नीचे 64 बाइट्स बाउंड्री पर शुरू होता है" क्योंकि यह सीपीयू के लिए बहुत तेज और सरल ऑपरेशन है।


2
मैं कुछ के लिए कह सकता हूँ । किसी भी उचित कैश डिज़ाइन में आकार के साथ लाइनें होंगी जो 2 की शक्ति हैं, और जो स्वाभाविक रूप से संरेखित हैं। (उदाहरण 64B- संरेखित)। यह सिर्फ तेज और सरल नहीं है, यह सचमुच मुक्त है: आप उदाहरण के लिए पते के कम 6 बिट्स को अनदेखा करते हैं। कैश अक्सर विभिन्न श्रेणियों के पते के साथ अलग-अलग चीजें करते हैं। (जैसे कैश हिट और मिस का पता लगाने के लिए टैग और इंडेक्स के बारे में परवाह करता है, फिर केवल डेटा डालने / निकालने के लिए कैश लाइन के भीतर ऑफसेट का उपयोग करते हुए)
पीटर कॉर्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.