পাঠ ৩৭ · ৫৭-এর মধ্যে · মডিউল ৮
Home / Courses / Computer Architecture & Digital Logic / মেমরি হায়ারার্কি

মেমরি হায়ারার্কির ধারণা — লোকালিটি অফ রেফারেন্স

Memory hierarchy concept — locality of reference
৮ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • মেমরি হায়ারার্কি কী এবং কেন গতি/আকার/খরচের মধ্যে একটা স্তরভিত্তিক কাঠামো দরকার হয়
  • টেম্পোরাল লোকালিটি ও স্পেশিয়াল লোকালিটি — এই দুই ধরনের লোকালিটির নির্ভুল সংজ্ঞা
  • কেন 2D অ্যারে row-major ক্রমে অ্যাক্সেস করলে column-major-এর চেয়ে দ্রুত চলে — একটি বাস্তব প্রোগ্রামিং পরিণতি
  • Python দিয়ে সিকোয়েনশিয়াল বনাম র‍্যান্ডম অ্যাক্সেস প্যাটার্নের লোকালিটি স্কোর মেপে তুলনা

১ · মেমরি হায়ারার্কি — কেন একটি একক মেমরি যথেষ্ট নয়

একটি আদর্শ মেমরি হতো এমন যা রেজিস্টারের মতো দ্রুত, কিন্তু ডিস্কের মতো বিশাল ও সস্তা — বাস্তবে এই দুটো একসাথে পাওয়া যায় না। দ্রুত মেমরি টেকনোলজি (যেমন M3-এর ফ্লিপ-ফ্লপ দিয়ে তৈরি রেজিস্টার) প্রতি বিটে অনেক বেশি ট্রানজিস্টর ও খরচ লাগে, তাই বড় আকারে বানানো অবাস্তব। তাই বাস্তব কম্পিউটার একটি মেমরি হায়ারার্কিMemory Hierarchyগতি, আকার ও খরচের ট্রেড-অফ মেনে একাধিক স্তরে সাজানো মেমরি কাঠামো — উপরে দ্রুত-ছোট-দামি, নিচে ধীর-বড়-সস্তা ব্যবহার করে — উপরে সবচেয়ে দ্রুত কিন্তু সবচেয়ে ছোট স্তর, নিচের দিকে ক্রমেই ধীর কিন্তু বড় ও সস্তা স্তর।

রেজিস্টার (CPU-এর ভেতরে) ক্যাশ — L1/L2/L3 (এই মডিউল) প্রধান মেমরি — RAM (মডিউল ৯) ডিস্ক / SSD — সেকেন্ডারি স্টোরেজ দ্রুততম সবচেয়ে বড় সবচেয়ে ছোট ধীরতম
যত নিচে নামা যায়, স্টোরেজ তত বড় ও সস্তা হয়, কিন্তু তত ধীর — উপরের স্তরগুলো আসলে নিচের স্তরের ডেটার একটা "কপি" মাত্র।
Operating Systems কোর্সের সাথে সম্পর্ক

Operating Systems কোর্স এই হায়ারার্কির নিচের স্তরগুলো (RAM ও ডিস্ক) সফটওয়্যার দিয়ে কীভাবে ম্যানেজ করা হয় তা শেখায় — পেজিং, ভার্চুয়াল মেমরি, পেজ রিপ্লেসমেন্ট অ্যালগরিদম। এই কোর্স (M8) ঠিক তার উপরের স্তর — ক্যাশ — কীভাবে হার্ডওয়্যার দিয়ে বানানো হয় তা দেখায়। দুটো একই সমস্যার (সীমিত দ্রুত স্টোরেজ কীভাবে সবচেয়ে কাজে লাগানো যায়) দুই ভিন্ন স্তরের সমাধান।

২ · লোকালিটি অফ রেফারেন্স — যে কারণে ক্যাশিং আসলেই কাজ করে

শুধু হায়ারার্কি বানালেই হবে না — সেটা কাজ করবে কি না তা নির্ভর করে একটি মৌলিক পর্যবেক্ষণের উপর। বাস্তব প্রোগ্রাম মেমরি অ্যাক্সেস র‍্যান্ডমভাবে করে না — বরং একটি নির্দিষ্ট প্যাটার্ন অনুসরণ করে, যাকে বলা হয় লোকালিটি অফ রেফারেন্স। এর দুটি রূপ —

টেম্পোরাল লোকালিটিTemporal Localityএকটি মেমরি অবস্থান সদ্য অ্যাক্সেস হলে, নিকট ভবিষ্যতে সেটি আবার অ্যাক্সেস হওয়ার সম্ভাবনা বেশি
সদ্য-অ্যাক্সেসড কোনো অবস্থান আবার শীঘ্রই অ্যাক্সেস হওয়ার সম্ভাবনা — যেমন একটি লুপ ভ্যারিয়েবল বারবার পড়া/লেখা হয়।
স্পেশিয়াল লোকালিটিSpatial Localityসদ্য অ্যাক্সেস হওয়া অবস্থানের কাছাকাছি কোনো অবস্থানও শীঘ্রই অ্যাক্সেস হওয়ার সম্ভাবনা বেশি
সদ্য-অ্যাক্সেসড অবস্থানের কাছাকাছি কোনো অবস্থান শীঘ্রই অ্যাক্সেস হওয়ার সম্ভাবনা — যেমন একটি অ্যারে ক্রমান্বয়ে অ্যাক্সেস করা।

যদি মেমরি অ্যাক্সেস সত্যিই র‍্যান্ডম হতো, ক্যাশিং থেকে প্রায় কোনো লাভই হতো না — কারণ ক্যাশে যা রাখা হচ্ছে তা আবার লাগার সম্ভাবনা কম হতো। লোকালিটি অফ রেফারেন্স-ই একমাত্র কারণ যার জন্য "সদ্য/কাছাকাছি ব্যবহৃত ডেটার একটি ছোট কপি দ্রুত মেমরিতে রাখা" আসলে কাজে লাগে — পুরো M8 মডিউলের ভিত্তি এটাই।

৩ · একটি বাস্তব পরিণতি — row-major বনাম column-major

একটি 2D অ্যারে মেমরিতে row-major ক্রমে (প্রতিটি row-এর উপাদানগুলো পাশাপাশি) সংরক্ষিত থাকে বেশিরভাগ ভাষায় (Python, C)। অ্যারেটি যদি row-major ক্রমে (বাম থেকে ডানে, উপরের row আগে) অ্যাক্সেস করা হয়, পরপর অ্যাক্সেসগুলো মেমরিতে পাশাপাশি অবস্থানেই পড়ে — শক্তিশালী স্পেশিয়াল লোকালিটি। কিন্তু column-major ক্রমে (একই column-এর সব row একে একে) অ্যাক্সেস করলে, পরপর অ্যাক্সেসগুলো মেমরিতে অনেক দূরে দূরে পড়ে — লোকালিটি নষ্ট হয়ে যায়, ফলে বাস্তবে row-major traversal প্রায়ই column-major-এর চেয়ে লক্ষণীয়ভাবে দ্রুত চলে।

এটি একটি বিশুদ্ধ তাত্ত্বিক আলোচনা নয় — যেকোনো বড় 2D অ্যারে/ম্যাট্রিক্স নিয়ে কাজ করা প্রোগ্রামে অ্যাক্সেস-ক্রম সাজানোটা সরাসরি রানটাইম পারফরম্যান্সে প্রভাব ফেলে, শুধু অ্যালগরিদমের "বিগ-ও" জটিলতা একই থাকলেও।

৪ · লোকালিটি স্কোর মেপে দেখা

নিচের কোড সেলে দুটি ভিন্ন অ্যাক্সেস প্যাটার্ন — একটি সিকোয়েনশিয়াল (0,1,2,3...) এবং একটি নির্দিষ্ট, স্থির র‍্যান্ডম-সদৃশ লিস্ট — নিয়ে একটি সরল "লোকালিটি স্কোর" গণনা করা হয়েছে: পরপর দুই অ্যাক্সেসের দূরত্ব ছোট হলে স্কোর বাড়ে। ফলাফল সংখ্যাগতভাবেই দেখায় দুই প্যাটার্নের লোকালিটির পার্থক্য কতটা বড়।

Python
memory = list(range(64))

def locality_score(access_sequence, window=2):
    """পরপর দুই অ্যাক্সেসের দূরত্ব window-এর মধ্যে হলে +1 করে -- স্প্যাশিয়াল লোকালিটির একটি সরল পরিমাপ"""
    score = 0
    for i in range(1, len(access_sequence)):
        distance = abs(access_sequence[i] - access_sequence[i - 1])
        if distance <= window:
            score += 1
    return score

sequential_pattern = list(range(0, 16))
random_pattern = [3, 47, 12, 61, 5, 33, 9, 55, 21, 2, 44, 17, 38, 1, 50, 8]

seq_score = locality_score(sequential_pattern)
rand_score = locality_score(random_pattern)

print("প্যাটার্ন            | লোকালিটি স্কোর (সর্বোচ্চ", len(sequential_pattern) - 1, ")")
print("-" * 55)
print(f"sequential (0..15)   | {seq_score}")
print(f"random (fixed list)  | {rand_score}")
print()
print(f"sequential প্যাটার্ন {seq_score - rand_score} গুণ বেশি স্পেশিয়াল লোকালিটি দেখাচ্ছে random-এর তুলনায়")

    
sequential প্যাটার্নে প্রতিটি পরপর জোড়ার দূরত্ব ঠিক ১ (window=2-এর মধ্যে), তাই স্কোর সর্বোচ্চ (১৫/১৫) — random প্যাটার্নে বেশিরভাগ জোড়ার দূরত্ব অনেক বড়, তাই স্কোর ০। এটাই সংখ্যাগতভাবে দেখায় কেন সিকোয়েনশিয়াল অ্যাক্সেস ক্যাশ-বান্ধব আর ছড়ানো-ছিটানো অ্যাক্সেস নয়।
মূল কথা · Key takeaway

মেমরি হায়ারার্কি একটি ইঞ্জিনিয়ারিং সমঝোতা — গতি, আকার ও খরচের মধ্যে। কিন্তু এই সমঝোতা কার্যকর হয় শুধু লোকালিটি অফ রেফারেন্সের কারণে — প্রোগ্রাম যদি সত্যিই র‍্যান্ডম অ্যাক্সেস করত, ক্যাশ কোনো লাভ দিত না। পরের পাঠে (L38) এই নীতির উপর ভিত্তি করে প্রথম বাস্তব ক্যাশ ডিজাইন — ডিরেক্ট ম্যাপড ক্যাশ — বানানো হবে।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ শুধু "সবচেয়ে দ্রুত মেমরি বড় আকারে বানিয়ে ফেলি" — এই সমাধান কেন বাস্তবে সম্ভব নয়?

কারণ দ্রুততম মেমরি প্রযুক্তি (রেজিস্টার/SRAM-স্টাইল, M3-এর ফ্লিপ-ফ্লপ থেকে তৈরি) প্রতি বিটে অনেক বেশি ট্রানজিস্টর ও এলাকা লাগে (M9-এ দেখা যাবে SRAM-এর প্রতি বিটে ৬টি ট্রানজিস্টর লাগে) — তাই বড় আকারে বানালে খরচ ও চিপের জায়গা আকাশছোঁয়া হয়ে যায়। তাই বাস্তবে ছোট-দ্রুত আর বড়-সস্তার মধ্যে স্তরভিত্তিক সমঝোতা করতেই হয়।

প্র ০২ টেম্পোরাল ও স্পেশিয়াল লোকালিটি — এই দুটো কি একই ঘটনার দুটো নাম, নাকি সত্যিই আলাদা?

সত্যিই আলাদা, যদিও প্রায়ই একসাথে ঘটে। টেম্পোরাল লোকালিটি সময়ের সাথে সম্পর্কিত — একই অবস্থান বারবার (যেমন একটি লুপ কাউন্টার ভ্যারিয়েবল)। স্পেশিয়াল লোকালিটি অবস্থানের সাথে সম্পর্কিত — ভিন্ন কিন্তু কাছাকাছি অবস্থান পরপর (যেমন অ্যারে ট্রাভার্সাল)। একটি লুপের ভেতরে অ্যারে অ্যাক্সেস করলে সাধারণত দুটোই একসাথে ঘটে, কিন্তু আলাদাভাবে সংজ্ঞায়িত এবং আলাদা কারণেই কাজ করে — ক্যাশ ডিজাইন (L38-L42) দুটোকেই আলাদাভাবে কাজে লাগায়।

প্র ০৩ উপরের কোড সেলে "লোকালিটি স্কোর"-এর window মান ২-এর বদলে অনেক বড় (যেমন ৩২) করলে কী হবে?

window বড় করলে "কাছাকাছি" হিসেবে ধরার সীমা বেড়ে যায়, তাই random প্যাটার্নও কিছু জোড়ায় স্কোর পেতে শুরু করবে (কিছু র‍্যান্ডম মানও কাকতালীয়ভাবে কাছাকাছি পড়তে পারে) — অর্থাৎ পার্থক্যটা কম স্পষ্ট দেখাবে। এটাই দেখায় "লোকালিটি স্কোর" পরিমাপটি একটি সরলীকৃত টিচিং টুল — বাস্তব ক্যাশ হার্ডওয়্যার লোকালিটি মাপে না, বরং সরাসরি hit/miss রেট (L41) দিয়ে তার প্রভাব পরিমাপ করে।

অনুশীলন

  1. চিন্তা করুন: একটি ৩x৩ 2D অ্যারে row-major ক্রমে মেমরিতে সংরক্ষিত থাকলে, নিচের কোন অ্যাক্সেস-ক্রমটি স্পেশিয়াল লোকালিটি সবচেয়ে বেশি দেখাবে — (ক) প্রতিটি row একে একে বাম থেকে ডানে, নাকি (খ) প্রতিটি column একে একে উপর থেকে নিচে?

    (ক) — কারণ row-major স্টোরেজে একই row-এর উপাদানগুলো মেমরিতে টানা পাশাপাশি থাকে, তাই row ধরে ধরে অ্যাক্সেস করলে পরপর অ্যাক্সেসগুলো মেমরিতেও পাশাপাশি পড়ে (দূরত্ব ১)। (খ) column ধরে অ্যাক্সেস করলে পরপর অ্যাক্সেসগুলোর মধ্যে মেমরিতে পুরো একটি row-এর দূরত্ব থাকে — লোকালিটি অনেক কম।

  2. পরীক্ষা করুন: উপরের কোড সেলে random_pattern-এর মান বদলে এমন একটি লিস্ট বসানোর কথা ভাবুন যেখানে প্রতিটি মান আগেরটার ঠিক ২ বেশি (যেমন [0,2,4,6,...]) — এই প্যাটার্নের লোকালিটি স্কোর কেমন হবে (এখনো কোড পরিবর্তন করবেন না)?

    পরপর প্রতিটি জোড়ার দূরত্ব ঠিক ২, যা window=2-এর ভেতরেই পড়ে — তাই এই প্যাটার্নেরও sequential-এর মতো সর্বোচ্চ স্কোর হবে, যদিও এটি "টানা পরপর" (0,1,2,3) নয়। এটা দেখায় স্পেশিয়াল লোকালিটি মানে ঠিক পাশাপাশি হওয়া বাধ্যতামূলক নয় — "যথেষ্ট কাছাকাছি" হলেই যথেষ্ট।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
এক্সসেপশন ও ইন্টারাপ্ট হ্যান্ডলিং ইন পাইপলাইন