মাল্টিকোর প্রসেসর আর্কিটেকচার
এই পাঠে যা শিখবেন
- মাল্টিকোর প্রসেসর কী এবং L50-এর MIMD ক্যাটাগরির সাথে এর সরাসরি সম্পর্ক
- প্রাইভেট L1/L2 ক্যাশ ও শেয়ার্ড L3 ক্যাশ — কোরের মধ্যে ক্যাশ কীভাবে সংগঠিত হয়
- মাল্টিকোর কেন এলো — ক্লক স্পিডের ভৌত সীমাবদ্ধতা থেকে প্যারালালিজমের দিকে স্থানান্তর
- Symmetric Multiprocessing (SMP) মডেল, এবং একাধিক কোরের মেমরি-অ্যাক্সেস লুকআপ-অর্ডার
১ · মাল্টিকোর প্রসেসর কী
মাল্টিকোর প্রসেসর হলো একটিমাত্র ফিজিক্যাল CPU চিপ, যার ভেতরে একাধিক স্বাধীন কোর থাকে — প্রতিটি কোর নিজস্ব ইনস্ট্রাকশন স্ট্রিম চালাতে সক্ষম, সম্পূর্ণ স্বাধীনভাবে। এটাই L50-এর MIMD ক্যাটাগরির সবচেয়ে সাধারণ, বাস্তব উদাহরণ — একাধিক ইনস্ট্রাকশন স্ট্রিম, একাধিক ডেটা স্ট্রিমে, একই সাথে কাজ করছে, কিন্তু এবার একই চিপের ভেতরে।
২ · ক্যাশ সংগঠন — প্রাইভেট L1/L2, শেয়ার্ড L3
প্রতিটি কোরের সাধারণত নিজস্ব প্রাইভেট L1 (এবং প্রায়ই L2) ক্যাশ থাকে — L42-এর মাল্টি-লেভেল ক্যাশ ধারণার সরাসরি প্রয়োগ, তবে এখন প্রতিটি কোরের নিজস্ব কপি। কিন্তু সব কোর মিলে সাধারণত একটি বড়, শেয়ার্ড L3 ক্যাশ এবং মূল মেমরি সিস্টেম ব্যবহার করে। এই শেয়ারিং-ই ঠিক সেই কারণ, যা পরের পাঠ (L52)-এর "ক্যাশ কোহেরেন্স" সমস্যাকে জন্ম দেয় — যদি একাধিক কোরের প্রাইভেট ক্যাশে একই অ্যাড্রেসের কপি থাকে, একটি কোরের আপডেট অন্য কোরের কাছে অদৃশ্য থেকে যেতে পারে।
৩ · মাল্টিকোর কেন এলো
একটি গুরুত্বপূর্ণ ইঞ্জিনিয়ারিং ইতিহাস: বহু বছর ধরে CPU ডিজাইনাররা একক কোরের ক্লক স্পিড বাড়িয়ে পারফরম্যান্স বাড়িয়েছেন। কিন্তু ক্লক স্পিড বাড়ানো একটি ভৌত সীমায় আটকে গিয়েছিল — উচ্চতর ক্লক ফ্রিকোয়েন্সিতে পাওয়ার খরচ ও তাপ উৎপাদন এত দ্রুত বাড়ে যে তা ব্যবহারিকভাবে সামলানো কঠিন হয়ে পড়ে। তাই একটিমাত্র কোরকে আরও দ্রুততর করার বদলে, ডিজাইনাররা একাধিক, মাঝারি-দ্রুত কোর একই চিপে একসাথে বসাতে শুরু করলেন — কাঁচা প্রতি-কোর গতির বদলে প্যারালালিজম দিয়ে সামগ্রিক পারফরম্যান্স বাড়ানোর কৌশল।
OS কোর্স মাল্টিপ্রসেসর শিডিউলিং ও Amdahl's Law-এর মাধ্যমে সফটওয়্যার-সাইড থেকে দেখায় কীভাবে একাধিক কোরের সুবিধা নেওয়া যায়। এই পাঠ উল্টো দিক থেকে আসে — হার্ডওয়্যার-সাইডে কেন একাধিক কোর তৈরি হলো এবং সেগুলো চিপের ভেতরে কীভাবে সংগঠিত।
৪ · Symmetric Multiprocessing (SMP)
আধুনিক মাল্টিকোর CPU-র স্ট্যান্ডার্ড মডেল হলো Symmetric Multiprocessing (SMP)সব কোর অভিন্ন এবং শেয়ার্ড মেমরিতে সমান অ্যাক্সেস রাখে -- আধুনিক মাল্টিকোর CPU-র স্ট্যান্ডার্ড মডেল। — সব কোর অভিন্ন এবং শেয়ার্ড মেমরিতে সমান অ্যাক্সেস রাখে (কোনো একটি কোর বিশেষ সুবিধাপ্রাপ্ত নয়)। এটি Operating Systems কোর্সের মাল্টিপ্রসেসর-শিডিউলিং টার্মিনোলজির সরাসরি হার্ডওয়্যার-ভিত্তি।
নিচের কোড সেলে একটি সরল মাল্টিকোর চিপ-লেআউট সিমুলেট করা হলো — দুটি কোর, প্রতিটির নিজস্ব প্রাইভেট L1 ক্যাশ, আর একটি শেয়ার্ড L3 ক্যাশ। একটি মেমরি-অ্যাক্সেস ফাংশন প্রথমে কোরের নিজস্ব L1 চেক করে, তারপর শেয়ার্ড L3, তারপর মূল মেমরি — দুটি কোরের ওভারল্যাপিং ও ভিন্ন অ্যাড্রেস অ্যাক্সেসে এই লুকআপ-অর্ডার কনক্রিটভাবে দেখা যাক।
# সিমুলেটেড মাল্টিকোর ক্যাশ লুকআপ -- বাস্তব হার্ডওয়্যার ক্যাশ নয়, শুধুই ধারণা বোঝানোর সিমুলেশন
def core_access(core_id, address, private_caches, shared_l3, main_memory):
"""কোরের মেমরি অ্যাক্সেস: প্রথমে নিজস্ব প্রাইভেট L1, তারপর শেয়ার্ড L3, তারপর মূল মেমরি --
মিস হলে উপরের স্তরে কপি বসানো হয় (সিমুলেটেড ক্যাশ-ফিল লজিক)"""
l1 = private_caches[core_id]
if address in l1:
return l1[address], f"Core {core_id}: প্রাইভেট L1 HIT (address={hex(address)})"
if address in shared_l3:
value = shared_l3[address]
l1[address] = value # L1-এ কপি বসানো হলো
return value, f"Core {core_id}: L1 MISS, শেয়ার্ড L3 HIT (address={hex(address)})"
value = main_memory[address]
shared_l3[address] = value
l1[address] = value
return value, f"Core {core_id}: L1 MISS, L3 MISS, মূল মেমরি (address={hex(address)})"
main_memory = {0x100: 10, 0x200: 20, 0x300: 30}
private_caches = {0: {}, 1: {}}
shared_l3 = {}
# ওভারল্যাপিং ও ভিন্ন অ্যাড্রেস অ্যাক্সেস মিলিয়ে ৬টি অ্যাক্সেস, ২টি কোর জুড়ে
accesses = [
(0, 0x100), # Core 0 প্রথমবার 0x100 চাইলো -- কোথাও নেই, মেমরি থেকে আসবে
(1, 0x100), # Core 1 একই address চাইলো -- Core 0 ইতিমধ্যে L3-এ বসিয়েছে -- L3 HIT
(0, 0x100), # Core 0 আবার -- এবার নিজের L1-এই আছে -- L1 HIT
(1, 0x200), # Core 1 -- সম্পূর্ণ ভিন্ন address -- মেমরি থেকে আসবে
(0, 0x200), # Core 0 -- একই address যা Core 1 এনেছিল -- L3 HIT
(1, 0x300), # Core 1 -- আরেকটি ভিন্ন address, কখনো স্পর্শ হয়নি -- মেমরি থেকে আসবে
]
for core_id, addr in accesses:
value, trace = core_access(core_id, addr, private_caches, shared_l3, main_memory)
print(f"{trace} -> মান = {value}")
print()
print(f"Core 0-এর প্রাইভেট L1: {private_caches[0]}")
print(f"Core 1-এর প্রাইভেট L1: {private_caches[1]}")
print(f"শেয়ার্ড L3: {shared_l3}")
0x100 চাইলো, সেটি Core 0-এর প্রাইভেট L1-এ নয়,
বরং শেয়ার্ড L3-এ পেয়ে গেলো (কারণ Core 0-এর আগের অ্যাক্সেসে সেটি L3-এ বসানো হয়েছিল) — এটাই
শেয়ার্ড L3-এর মূল সুবিধা: এক কোরের আনা ডেটা অন্য কোরও দ্রুত পেতে পারে, প্রতিবার মূল মেমরিতে না
গিয়েই। কিন্তু প্রতিটি কোরের নিজস্ব L1-এও পরে একটি কপি বসে যায় — যা পরের পাঠে (L52) দেখাবে কেন
এই কপিগুলো সিঙ্ক্রোনাইজড রাখা একটি বাস্তব চ্যালেঞ্জ।
মাল্টিকোর প্রসেসর L50-এর MIMD ধারণাকে বাস্তব সিলিকনে রূপ দেয় — প্রাইভেট L1/L2 প্রতিটি কোরকে দ্রুত, স্বাধীন অ্যাক্সেস দেয়, আর শেয়ার্ড L3 কোরগুলোর মধ্যে ডেটা পুনঃব্যবহারের সুযোগ তৈরি করে। কিন্তু এই একই শেয়ারিং-সুবিধা একটি নতুন সমস্যার জন্ম দেয় — একাধিক প্রাইভেট কপি সবসময় সিঙ্ক্রোনাইজড থাকবে তার কোনো গ্যারান্টি নেই। পরের পাঠ (L52) ঠিক এই সমস্যাটি — ক্যাশ কোহেরেন্স — এবং তার সমাধান (MESI প্রোটোকল) নিয়ে আলোচনা করবে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ যদি প্রতিটি কোরের একটিও প্রাইভেট ক্যাশ না থাকতো, শুধু একটি শেয়ার্ড ক্যাশ থাকতো, তাহলে কী সমস্যা হতে পারত?
একটিমাত্র শেয়ার্ড ক্যাশের ওপর সব কোর নির্ভর করলে, সেই ক্যাশ একটি "বটলনেক" হয়ে যেত — একসাথে একাধিক কোর অ্যাক্সেস করতে চাইলে দ্বন্দ্ব (contention) তৈরি হতো, এবং প্রতিটি অ্যাক্সেসের বিলম্বও বাড়ত (শেয়ার্ড ক্যাশ সাধারণত প্রাইভেট L1-এর চেয়ে শারীরিকভাবে দূরে ও ধীর, L42-এর মাল্টি-লেভেল ক্যাশ আলোচনার সাথে সংগতিপূর্ণ)। প্রাইভেট L1 প্রতিটি কোরকে দ্রুততম সম্ভাব্য অ্যাক্সেস দেয়, দ্বন্দ্ব ছাড়াই, বেশিরভাগ অ্যাক্সেসের জন্য।
প্র ০২ ক্লক স্পিড বাড়ানোর বদলে মাল্টিকোরে যাওয়ার সিদ্ধান্তটি কি সব ধরনের সফটওয়্যারের জন্য সমানভাবে উপকারী?
না — মাল্টিকোরের সুবিধা তখনই পাওয়া যায় যখন সফটওয়্যার প্যারালালাইজযোগ্য (একাধিক স্বাধীন কাজে ভাগ করা যায়)। যে প্রোগ্রাম মূলত একটি দীর্ঘ, সিকোয়েনশিয়াল হিসাব চালায় (একটি ধাপ শেষ না হলে পরের ধাপ শুরু করা যায় না), সেটি অতিরিক্ত কোর থেকে সরাসরি উপকৃত হয় না — সেই একটি কোরের গতিই তার পারফরম্যান্স নির্ধারণ করে। এই সীমাবদ্ধতাই OS কোর্সের Amdahl's Law-এর মূল বিষয়বস্তু।
প্র ০৩
উপরের কোড সেলে 0x300 শুধু Core 1 অ্যাক্সেস করেছে, Core 0 কখনো নয়। যদি এরপর Core 0 core_access(0, 0x300, ...) কল করে, ফলাফল কী হবে?
Core 0-এর প্রাইভেট L1-এ 0x300 নেই (কখনো অ্যাক্সেস হয়নি), কিন্তু Core 1-এর
অ্যাক্সেসের সময় এটি ইতিমধ্যে shared_l3-তে বসানো হয়েছে — তাই Core 0-এর জন্য এটি
"L1 MISS, শেয়ার্ড L3 HIT" হবে, সরাসরি মূল মেমরিতে না গিয়েই। এটাই আবার শেয়ার্ড L3-এর মূল
মূল্য দেখায় — একটি কোরের আনা ডেটা পরে অন্য যেকোনো কোরের জন্য দ্রুত সহজলভ্য থাকে।
অনুশীলন
-
চিন্তা করুন: উপরের কোড সেলের
accessesতালিকায় শেষে(1, 0x100)আরেকবার যোগ করলে, ট্রেস মেসেজে কী দেখাবে বলে মনে করেন — এবং কেন?"Core 1: প্রাইভেট L1 HIT (address=0x100)" দেখাবে — কারণ Core 1 আগেই একবার (দ্বিতীয় অ্যাক্সেসে)
0x100চেয়েছিল, তখন সেটি শেয়ার্ড L3 থেকে পেয়ে নিজের L1-এও কপি বসিয়ে নিয়েছিল। তাই পরের বার সেই একই কোরের জন্য এটি সরাসরি নিজের L1-তেই পাওয়া যাবে, L3 পর্যন্ত যেতেও হবে না। -
পরীক্ষা করুন: কোড সেলে একটি তৃতীয় কোর (
core_id=2) যোগ করুনprivate_caches-এ একটি নতুন খালি dict দিয়ে, এবং সেটি দিয়ে0x200অ্যাক্সেস করুন — এটি কোন স্তর থেকে সার্ভ হবে?"L1 MISS, শেয়ার্ড L3 HIT" — কারণ
0x200ইতিমধ্যে আগের অ্যাক্সেসগুলোর মধ্য দিয়েshared_l3-তে বসানো হয়ে গেছে, কিন্তু নতুন কোর 2-এর নিজস্ব L1 এখনো সম্পূর্ণ খালি (কখনো ব্যবহার হয়নি)। এটা দেখায় শেয়ার্ড L3 কীভাবে নতুন কোরকেও অবিলম্বে উপকৃত করে, তার নিজের ক্যাশ ইতিহাস না থাকা সত্ত্বেও।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পূর্ববর্তী পাঠ: ফ্লিনস ট্যাক্সোনমি L50 SISD, SIMD, MISD, MIMD — মাল্টিকোর ঠিক কোন ক্যাটাগরির বাস্তব রূপ তা এই পাঠে দেখানো হয়েছে।
- পরবর্তী পাঠ: ক্যাশ কোহেরেন্স প্রবলেম L52 এই পাঠের প্রাইভেট L1 শেয়ারিং-ই যে সমস্যার জন্ম দেয়, MESI প্রোটোকল দিয়ে তার সমাধান।
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ লজিক গেট থেকে CPU ডেটাপাথ, ক্যাশ মেমরি ও প্যারালাল আর্কিটেকচার পর্যন্ত সম্পূর্ণ কোর্স।