آئی ٹی سی ایم بمقابلہ ڈی ٹی سی ایم بمقابلہ ڈی ڈی آر: ایمبیڈڈ میموری کی اقسام کی وضاحت کی گئی [Full Handbook]

زیادہ تر ایمبیڈڈ انجینئرز کو ابتدائی طور پر اس مسئلے کا سامنا کرنا پڑا ہے۔ ایک ہی پروسیسر پر ایک ہی کوڈ ایک منظر نامے میں تیزی سے چل سکتا ہے اور دوسرے میں ناقابل یقین حد تک سست۔ مجرم تقریباً ہمیشہ ہوتا ہے۔ کہاں کوڈ اور ڈیٹا میموری میں محفوظ ہیں۔

ڈیسک ٹاپ اور سرور پروسیسر ملٹی لیول کیچز کے پیچھے میموری کی تاخیر کو چھپاتے ہیں۔ بہت سے ایمبیڈڈ پروسیسرز، خاص طور پر ARM Cortex-M اور Cortex-R پر مبنی چپس، ایک مختلف طریقہ اختیار کرتے ہیں۔ آپ متعدد میموری والے علاقوں کو براہ راست کنٹرول کر سکتے ہیں، ہر ایک بہت مختلف کارکردگی کی خصوصیات کے ساتھ۔

یہ ہینڈ بک اس بات کا احاطہ کرتی ہے کہ ITCM، DTCM، اور DDR میموری کیا ہیں، کیا فرق ہیں، کوڈ اور ڈیٹا کو صحیح علاقوں میں کیسے رکھا جائے، اور وقت کے ساتھ ساتھ فرم ویئر میموری کے استعمال کی پروفائل اور نگرانی کیسے کی جائے۔

انڈیکس

شرطیں

اس گائیڈ سے زیادہ سے زیادہ فائدہ اٹھانے کے لیے، آپ کو C پروگرامنگ کی بنیادی سمجھ ہونی چاہیے، بشمول پوائنٹرز، ڈھانچے، اور جامد اور مقامی متغیر کے درمیان فرق۔

ایمبیڈڈ ڈویلپمنٹ تصورات سے کچھ واقفیت حاصل کرنا مددگار ثابت ہوگا، جیسے کہ ٹارگٹ بورڈ میں فرم ویئر کو مرتب کرنا، لنک کرنا اور چمکانا۔

آخر میں، ایک عام فہم کہ کس طرح ایک CPU ہدایات کو حاصل کرتا ہے اور اس پر عمل درآمد کرتا ہے کارکردگی کے مباحث کو سمجھنے میں آسان بنا سکتا ہے۔

آپ کو ان میں سے کسی میں ماہر ہونے کی ضرورت نہیں ہے۔ یہ مضمون ہر تصور کی وضاحت کرتا ہے جیسا کہ یہ ظاہر ہوتا ہے۔

ایمبیڈڈ میموری آرکیٹیکچر کیوں اہمیت رکھتا ہے۔

جدید ایمبیڈڈ پروسیسرز کو 400 میگا ہرٹز سے زیادہ پر کلاک کیا جا سکتا ہے۔ آپ ہر چند نینو سیکنڈ میں کمانڈ چلا سکتے ہیں۔

تاہم، اگر آپ کو اس ہدایت کو بازیافت کرنے یا میموری سے متغیر کو پڑھنے کی ضرورت ہے تو، میموری برقرار رکھنے کے قابل نہیں ہوسکتی ہے۔ پروسیسر بالآخر میموری سب سسٹم کے انتظار میں لٹکا رہتا ہے کہ وہ مطلوبہ ڈیٹا فراہم کرے۔ یہ اسٹال سائیکل تیزی سے بڑھ جاتے ہیں۔

ڈیسک ٹاپ کمپیوٹرز میں، ہارڈویئر کیچز (L1, L2, L3) CPU اور مین میموری کے درمیان واقع ہوتے ہیں تاکہ حال ہی میں استعمال شدہ ڈیٹا کو خود بخود قریب میں رکھا جا سکے۔ کیش ہارڈویئر فیصلہ کرتا ہے کہ کیا رکھنا ہے اور کیا ہٹانا ہے، اور یہ شفاف طریقے سے کرتا ہے۔ پروگرامرز کو شاذ و نادر ہی اس کے بارے میں سوچنا پڑتا ہے، اور کارکردگی عام طور پر دستی مداخلت کے بغیر کافی ہوتی ہے۔

بہت سے ایمبیڈڈ پروسیسرز کے لیے صورتحال مختلف ہے۔ ہارڈ ویئر کیشے کے بجائے تین مختلف میموری کے علاقےہر ایک مختلف طریقے سے CPU سے جڑتا ہے۔

میموری کی قسم کیا ذخیرہ کرنا ہے رسائی کی رفتار عام سائز
آئی ٹی سی ایم ہدایات (قابل عمل کوڈ) سنگل سائیکل (تعیناتی) 512KB~2MB
ڈی ٹی سی ایم ڈیٹا (متغیر، اسٹیک، بفر) سنگل سائیکل (تعیناتی) 512KB~1.5MB
ڈی ڈی آر باقی سب کچھ ملٹی سائیکل (متغیر) 4MB سے کئی GB تک

اوپر والا جدول ایک عام ARM Cortex-M یا Cortex-R پر مبنی ایمبیڈڈ سسٹم میں پائی جانے والی میموری کی تین اقسام کو دکھاتا ہے۔ ITCM اور DTCM تیز لیکن چھوٹے ہیں۔ DDR سست لیکن بڑا ہے۔

TCM کے "ڈیٹرمنسٹک” لیبل کا مطلب ہے کہ رسائی کے اوقات ہمیشہ ایک جیسے ہوتے ہیں، اس سے قطع نظر کہ اس میموری تک پہلے کیا ہوا یا چپ پر کیا ہوتا ہے۔ DDR کے "متغیر” لیبل کا مطلب ہے کہ رسائی کے اوقات DDR چپ اور اس کے کنٹرولر کی اندرونی حالت کے لحاظ سے تبدیل ہو سکتے ہیں۔

ڈویلپرز کنٹرول کرتے ہیں کہ فرم ویئر کا ہر حصہ کس علاقے میں رہتا ہے۔ کمپائلرز اور لنکرز یہ فیصلے خود بخود نہیں کرتے ہیں۔ آپ لنکر اسکرپٹ میں سورس کوڈ اور پلیسمنٹ رولز میں سیکشن پراپرٹیز کے ذریعے اس کی وضاحت کرتے ہیں۔ یہ صحیح طریقے سے کرنا اکثر فرم ویئر کو ریئل ٹائم ڈیڈ لائن کو پورا کرنے اور اسے غائب کرنے میں فرق ہوتا ہے۔

انسٹرکشن ٹائٹلی کپلڈ میموری (ITCM) کیا ہے؟

ITCM کا مطلب ہے: ہدایات مضبوطی سے جوڑے میموری.

"ہدایت” والے حصے کا مطلب ہے کہ یہ میموری قابل عمل مشین کوڈ کو ذخیرہ کرنے کے لیے استعمال کی جاتی ہے، مرتب کردہ ہدایات جو CPU لاتی ہے اور اس پر عمل درآمد کرتی ہے۔

"مضبوطی سے جوڑے” والے حصے کا مطلب ہے کہ میموری جسمانی طور پر اسی سلکان ڈائی پر واقع ہے جس میں CPU کور ہے اور بغیر کسی ثالثی یا تنازعہ کے ایک وقف بس کے ذریعے منسلک ہے۔ مقابلہ کرنے کے لیے کوئی مشترکہ بسیں نہیں ہیں۔ عبور کرنے کے لیے کوئی کیش درجہ بندی نہیں ہے۔ سی پی یو ہدایات کی درخواست کرتا ہے اور آئی ٹی سی ایم انہیں براہ راست نجی راستے سے گزرتا ہے جس میں چپ پر کوئی اور چیز مداخلت نہیں کر سکتی۔

سی پی یو ایک ساتھ آئی ٹی سی ایم سے ہدایات حاصل کر سکتا ہے۔ ایک گھڑی سائیکل، ہر وقت. رسائی کا یہ وقت تیز اور فیصلہ کن ہے۔ یہ رسائی کے نمونوں، حالیہ تاریخ یا بس میں کیا ہو رہا ہے اس پر منحصر نہیں ہے۔

یہ عزم اتنا ہی اہم ہے جتنا خام رفتار کیونکہ یہ بدترین صورت میں عمل درآمد کے وقت کے تجزیہ کو قابل بناتا ہے۔ حفاظت کے لیے اہم نظاموں کو اس قابل ہونا چاہیے: ثابت کریں ایک فنکشن ہمیشہ ایک مخصوص چکر کے اندر مکمل ہوتا ہے۔ ITCM ثبوت کو بہت آسان بنا دیتا ہے۔

سنگل سائیکل کی بازیافت کیوں اہم ہے۔

C کوڈ کی ہر لائن کو ایک یا زیادہ مشین ہدایات میں مرتب کیا جاتا ہے۔ اس سے پہلے کہ CPU ہدایات کو ڈی کوڈ اور اس پر عمل درآمد کر سکے ہر ہدایت کو میموری سے لایا جانا چاہیے۔ چونکہ یہ بازیافت کا مرحلہ ہر ایک ہدایت کے لئے ہوتا ہے، یہاں تک کہ چھوٹی فی-ہدایت میں تاخیر بھی تیزی سے لوپس میں مل سکتی ہے اور اکثر فنکشن کہلاتی ہے۔

ایک لوپ پر غور کریں جو 1,000,000 تکرار کو انجام دیتا ہے۔ یہاں، ہر تکرار میں 10 ہدایات لانا شامل ہے۔ کل 10 ملین لائے گئے۔

ITCM:  10,000,000 fetches x 1 cycle  = 10,000,000 cycles
DDR:   10,000,000 fetches x 8 cycles = 80,000,000 cycles

Difference: 70,000,000 cycles
At 400 MHz: 70,000,000 / 400,000,000 = 0.175 seconds = 175 ms

یہ حساب سائیکلوں کی کل تعداد کا موازنہ کرتا ہے جب ITCM اور DDR میں ایک ہی لوپ چلتا ہے۔ ITCM کے ساتھ، ہر بازیافت 1 سائیکل لیتا ہے، لہذا 10 ملین بازیافت 10 ملین سائیکل لیتا ہے۔

DDR کے ساتھ، ہر بازیافت میں 8 سائیکل لگتے ہیں (ایک قدامت پسند اوسط)، لہذا اسی 10 ملین بازیافت میں 80 ملین سائیکل لگیں گے۔ فرق 70 ملین سائیکلوں کا ہے، جو 400MHz پر 175 ملی سیکنڈز کے مساوی ہے۔

1 کلو ہرٹز پر کنٹرول لوپ چلانے والے ریئل ٹائم سسٹم میں (ہر 1 ایم ایس پر ایک تکرار)، پروسیسنگ میں 175 ایم ایس اضافی تاخیر کا پھیلنا کوئی معمولی تکلیف نہیں ہے۔ اس کی وجہ سے سسٹم ڈیڈ لائن سے محروم ہو سکتا ہے، سنسر کی ریڈنگ ناقص ہو سکتی ہے، یا غلط آؤٹ پٹ پیدا کر سکتی ہے۔ موٹر کنٹرول ایپلی کیشنز میں ڈیڈ لائن غائب ہونا ہارڈ ویئر کو جسمانی نقصان پہنچا سکتا ہے۔ آڈیو پروسیسنگ میں، اس کا مطلب ایک قابل سماعت خرابی ہے۔ سست ہدایات کی بازیافت کی قیمت خلاصہ نہیں ہے۔

ITCM میں کیا جانا چاہئے؟

چونکہ ITCMs چھوٹے ہیں (عام طور پر 512KB سے 2MB)، ان میں مکمل فرم ویئر نہیں ہو سکتا۔ آپ کو اس بات کا انتخاب کرنا ہوگا کہ آپ کو کیا مقام ملتا ہے۔

انٹرپٹ سروس روٹین (ISR) یہ سب سے زیادہ ترجیحی امیدوار ہے۔ ISR ہارڈ ویئر کے واقعات کے جواب میں چلتا ہے، جیسے ٹائمر کی ٹک، ADC کی تبدیلی مکمل ہو رہی ہے، یا مواصلاتی پیریفیرل سے موصول ہونے والا ڈیٹا۔ اس پر عملدرآمد کیا جائے اور جلد از جلد واپس کیا جائے۔

ایک سست ISR کسی بھی کم ترجیحی مداخلتوں میں تاخیر کر سکتا ہے اور یاد ہونے والے واقعات کا سبب بن سکتا ہے۔ جب کوئی ISR کسی DDR سے ہدایات حاصل کرتا ہے، تو ہر بازیافت ایک سے زیادہ سائیکل لیتا ہے اور ISR کے عمل درآمد کا کل وقت اس عنصر سے بڑھ جاتا ہے جس کے ذریعے آخری تاریخ سے تجاوز کیا جا سکتا ہے۔

آئی ٹی سی ایم میں آئی ایس آر کی تعیناتی اس بات کو یقینی بناتی ہے کہ یہ مکمل طور پر قابل پیشن گوئی کے ساتھ پوری رفتار سے چلتا ہے۔

ریئل ٹائم پروسیسنگ فنکشن اگلی ترجیح۔ اس میں سگنل پروسیسنگ کے معمولات، موٹر کنٹرول لوپس، آڈیو پروسیسنگ پائپ لائنز، اور تمام فنکشنز شامل ہیں جو ایک مقررہ شرح پر چلتے ہیں اور انہیں سخت وقت کے بجٹ کے اندر مکمل کرنا چاہیے۔

اگر آڈیو کوڈیک کال بیک کو ہر 5ms پر ایک نمونہ بفر پر کارروائی کرنے کی ضرورت ہے، تو ہر کمانڈ کی بازیافت کا دور شمار کیا جاتا ہے۔ ان فنکشنز کو ITCM میں رکھنے سے آپ کو میموری کا انتظار کرنے کی بجائے اصل حساب کے لیے CPU کا زیادہ سے زیادہ وقت ملتا ہے۔

مین پروسیسنگ پائپ لائن کا اندرونی لوپ مزید برآں، ITCM کی تعیناتی سے اہم فوائد حاصل کیے جا سکتے ہیں۔ اگر فرم ویئر اپنا 80% وقت چند فنکشنز پر صرف کرتا ہے تو وہ فنکشنز ITCM میں ہونے چاہئیں۔ پروفائلنگ ٹولز اور لنکر میپ فائلوں کا استعمال (بعد میں اس مضمون میں بحث کی جائے گی) آپ کو مقبول ترین خصوصیات کی شناخت میں مدد کر سکتے ہیں۔

فنکشنز جن کے لیے مقررہ وقت کی ضرورت ہوتی ہے۔ اگرچہ یہ تیز ترین راستہ نہیں ہے، یہ ITCM کے تحت آتا ہے۔ ITCM تک رسائی کے اوقات تبدیل نہیں ہوتے ہیں، جس سے ٹائمنگ کے تجزیہ کو قابل قیاس بنایا جا سکتا ہے۔ یہ حفاظت کے لیے اہم نظاموں (آٹو موٹیو، میڈیکل، ایرو اسپیس) کے لیے اہم ہے جہاں سرٹیفیکیشن باڈیز کے لیے بدترین صورت میں عمل درآمد کے اوقات کا مظاہرہ کرنا ضروری ہے۔

آئی ٹی سی ایم میں فنکشنز کیسے رکھیں

کمپائلر کو بتانے کے لیے جی سی سی سیکشن کی خصوصیات کا استعمال کریں کہ فنکشن کسی مخصوص میموری سیکشن سے تعلق رکھتا ہے۔ لنکر اسکرپٹ پھر اس حصے کو ITCM میموری ایریا میں نقشہ بناتا ہے۔

__attribute__((section(".itcm_text")))
void my_critical_isr(void) {
    volatile uint32_t *sensor_reg = (volatile uint32_t *)0x40001000;
    uint32_t reading = *sensor_reg;
    process_sample(reading);
}

اس کوڈ میں __attribute__((section(".itcm_text"))) ہدایت کمپائلر کو اس فنکشن کے لیے مرتب کردہ مشین کوڈ بھیجنے کو کہتی ہے۔ .itcm_text پہلے سے طے شدہ کے بجائے .text پارٹ ٹائم نوکری. فنکشن خود سینسر رجسٹر کو میموری کے نقشے والے ایڈریس سے پڑھتا ہے۔ 0x40001000نتیجہ کو مقامی متغیر میں اسٹور کریں اور اسے منتقل کریں۔ process_sample() مزید پروسیسنگ کے لیے۔ کہ volatile کلیدی لفظ کمپائلر کو بتاتا ہے کہ چونکہ یہ میموری ایڈریس ایک ہارڈویئر رجسٹر ہے اور کسی بھی وقت تبدیل ہوسکتا ہے، اس لیے کمپائلر کو پڑھنے کو بہتر نہیں بنانا چاہیے۔

خود سے، سیکشن پراپرٹی اس بات کا تعین نہیں کرتی ہے کہ فنکشن جسمانی میموری میں کہاں ختم ہوتا ہے۔ یہ صرف کمپائلر کو مخصوص سیکشن کے ناموں کے ساتھ فنکشن کوڈ کو لیبل کرنے کی ہدایت کرتا ہے۔

جسمانی میموری کی جگہ کا تعین لنکر اسکرپٹ کا کام ہے۔ .itcm_text ITCM ایڈریس رینج کے ساتھ۔ لنکر اسکرپٹس کو بعد کے حصوں میں مزید تفصیل سے احاطہ کیا جائے گا۔

ITCM عام طور پر کتنا ہے؟

پیمانے پر ایمبیڈڈ پروجیکٹس کے لیے اصلی میموری پروفائل:

Memory region         Used Size  Region Size  %age Used
            ITCM:      570936 B         2 MB     27.22%
            DTCM:      727240 B    1572608 B     46.24%
             DDR:      622915 B         4 MB     14.85%

یہ آؤٹ پٹ لنکر میپ فائل کے سمری سیکشن سے آتا ہے۔ یہ میموری کے تین علاقوں کو دکھاتا ہے اور مرتب کردہ فرم ویئر کے ذریعہ ہر علاقہ کتنا استعمال ہوتا ہے۔

ITCM کے پاس 2 MB خالی جگہ ہے اور فرم ویئر تقریباً 557 KB (27.22%) استعمال کر رہا ہے۔ DTCM کے پاس تقریباً 1.5 MB دستیاب جگہ ہے اور وہ 727 KB (46.24%) استعمال کر رہا ہے۔ DDR 4 MB دستیاب ہے اور تقریباً 609 KB (14.85%) استعمال کر رہا ہے۔

یہ پروجیکٹ 2 MB دستیاب ITCM میں سے تقریباً 557 KB (تقریباً 27%) استعمال کرتا ہے۔ یہ ترقی کے لئے اچھی جگہ چھوڑ دیتا ہے.

عملی طور پر، ہم مستقبل میں فیچر اور لائبریری اپ ڈیٹس کے لیے جگہ بنانے کے لیے ITCM کے استعمال کو 80-85% سے کم رکھنے کی کوشش کرتے ہیں۔ جیسا کہ استعمال 90% سے بڑھ جاتا ہے، آپ کو فعال طور پر کم اہم کوڈ کو DDR میں منتقل کرنا چاہیے کیونکہ آپ تعمیراتی ناکامیوں کو روکنے کے لیے خصوصیات شامل کرتے ہیں۔

ڈیٹا ٹائٹلی کپلڈ میموری (DTCM) کیا ہے؟

DTCM کا مطلب ہے: مضبوطی سے جوڑے ڈیٹا کے ساتھ میموری. یہ انہی اصولوں پر کام کرتا ہے جیسے ITCM (جسمانی طور پر CPU کور کے قریب، ایک وقف بس کے ذریعے منسلک، سنگل سائیکل تک رسائی)، لیکن ڈیٹا ہدایات کے بجائے۔

اگر ITCM وہ جگہ ہے جہاں کوڈ ہے، تو DTCM وہ جگہ ہے جہاں کوڈ ہے۔ فیکٹری. ایک تیز سکریچ اسپیس جس سے CPU کارکردگی کے اہم افعال کو انجام دیتے ہوئے پڑھتا اور لکھتا ہے۔ تمام ویری ایبل ریڈز، تمام سرنی تک رسائی، اور ہاٹ کوڈ پاتھ میں تمام اسٹیک پش اور پاپ ڈیٹا میموری سے گزرتے ہیں۔ اس ڈیٹا کو جتنی جلدی ممکن ہو میموری بنانا تاخیر کی سب سے بڑی وجوہات میں سے ایک کو ختم کرتا ہے۔

کس قسم کے ڈیٹا کا تعلق DTCM سے ہے؟

اسٹیک فریم ڈی ٹی سی ایم میں سب سے اہم بات، ہر فنکشن کال ایک اسٹیک فریم کو آگے بڑھاتی ہے جس میں مقامی متغیرات، واپسی کا پتہ، اور محفوظ شدہ رجسٹر ہوتے ہیں۔ ہر فنکشن ریٹرن اس فریم کو پاپ کرتا ہے۔ میں

جب اسٹیک ڈی ٹی سی ایم میں ہوتا ہے، تو فنکشن کال اور ریٹرن کا میموری تک رسائی کا حصہ ایک ہی چکر میں ہوتا ہے۔ جب اسٹیک DDR میں ہوتا ہے تو، ہر فنکشن کال اور ریٹرن میں میموری لیٹنسی کے کئی چکر آتے ہیں صرف اسٹیک آپریشنز کے لیے اس سے پہلے کہ فنکشن مفید کام کرنا شروع کر سکے۔

زیادہ تر Cortex-M اور Cortex-R کنفیگریشنز میں، سٹارٹ اپ کوڈ پہلے سے طے شدہ طور پر DTCM کی طرف اشارہ کرنے کے لیے اسٹیک پوائنٹر کو شروع کرتا ہے، تاکہ آپ بغیر کسی اضافی کنفیگریشن کے یہ فائدہ حاصل کر سکیں۔

عالمی متغیرات تک اکثر رسائی ایک اور مضبوط امیدوار۔ سٹیٹ مشین ویری ایبلز، کنٹرول فلیگ، سینسر ریڈنگز جو اپ ڈیٹ ہوتی ہیں اور ہر لوپ تکرار پر پڑھی جاتی ہیں، کاؤنٹر جو ISR میں بڑھتے ہیں اور مین لوپ میں پڑھتے ہیں: سبھی سنگل سائیکل رسائی سے فائدہ اٹھاتے ہیں۔

اگر ایک متغیر کو فی سیکنڈ ہزاروں بار پڑھا یا لکھا جاتا ہے، تو DTCM اور DDR کے درمیان مجموعی تاخیر کا فرق بڑھ جاتا ہے۔

ہاٹ پاسز کے لیے استعمال ہونے والی چھوٹی تلاش کی میز اگر یہ فٹ ہونے کے لیے کافی چھوٹا ہے، تو اس کا تعلق DTCM میں ہے۔ عام مثالوں میں موٹر کنٹرول کے لیے سائن/کوزائن ٹیبلز، آڈیو پروسیسنگ کے لیے فلٹر گتانک، اور کمیونیکیشن پروٹوکولز کے لیے CRC ٹیبلز شامل ہیں۔

یہ میزیں عام طور پر سینکڑوں بائٹس سے لے کر چند کلو بائٹس تک ہوتی ہیں اور پروسیسنگ لوپ کے ہر تکرار کے ساتھ ان تک رسائی حاصل کی جاتی ہے۔ کلیدی لفظ "چھوٹا” ہے۔ 512 بائٹ سائن ٹیبل DTCM کے لیے موزوں ہے۔ 64KB کیلیبریشن ٹیبل اس کے بجائے DDR میں نہیں جاتی ہے اور ضروری ہے۔

ڈی ایم اے بفر کبھی کبھی آپ DTCM میں جا سکتے ہیں، لیکن یہ چپ کے بس کے فن تعمیر پر منحصر ہے۔ کچھ چپس میں، DMA کنٹرولر کے پاس بس میٹرکس کے ذریعے DTCM تک براہ راست راستہ ہوتا ہے۔ دیگر معاملات میں، DMA کنٹرولر صرف DDR اور دیگر SRAM علاقوں تک پہنچ سکتا ہے۔ اگر آپ ڈی ایم اے بفر کو ڈی ٹی سی ایم میں ایسی چپ پر رکھتے ہیں جس تک ڈی ایم اے کنٹرولر نہیں پہنچ سکتا، تو ٹرانسفر خود بخود ناکام ہو جائے گا یا مکمل طور پر غلط ایڈریس پر لکھا جائے گا۔

ڈی ٹی سی ایم میں ڈی ایم اے بفر ڈالنے سے پہلے ریفرنس مینوئل میں چپ کے بس میٹرکس ڈایاگرام کو ہمیشہ چیک کریں۔

ڈی ٹی سی ایم میں ڈیٹا کیسے رکھا جائے۔

ڈی ٹی سی ایم میں ڈیٹا رکھنے میں آئی ٹی سی ایم کی طرح سیکشن کی خصوصیت کا طریقہ کار استعمال ہوتا ہے، لیکن سیکشن کے ناموں کا استعمال کرتا ہے جو لنکر اسکرپٹ ڈی ٹی سی ایم ایڈریس رینج میں نقشہ بناتا ہے۔

__attribute__((section(".dtcm_data")))
static int16_t audio_buffer[256];

__attribute__((section(".dtcm_data")))
static volatile uint32_t sensor_state = 0;

اس کوڈ میں audio_buffer ڈی ٹی سی ایم میں 256 دستخط شدہ 16 بٹ انٹیجرز (کل 512 بائٹس) کی ایک صف۔ یہ آڈیو نمونوں کے لیے بفر ہو سکتا ہے جو DMA ٹرانسفرز کے ذریعے بھرے جاتے ہیں اور ISR کے ذریعے پروسیس کیے جاتے ہیں۔ کہ static کلیدی لفظ کا مطلب یہ ہے کہ بفر کے پاس فائل کی گنجائش ہے اور وہ پروگرام کی زندگی تک برقرار رہتا ہے (اسے اسٹیک پر مختص نہیں کیا جاتا ہے)۔

کہ sensor_state متغیر ایک 32 بٹ غیر دستخط شدہ عدد ہے، جس کی نمائندگی اس طرح کی گئی ہے: volatileاس کا مطلب یہ ہے کہ مرتب کرنے والے کو ہر بار میموری سے پڑھنا چاہیے، بجائے اس کے کہ اسے رجسٹر میں کیش کیا جائے۔

یہ ISR پر لکھے گئے اور مین لوپ سے پڑھنے والے متغیرات کے لیے اہم ہے۔ کیونکہ مرتب کرنے والے کو یہ جاننے کی ضرورت ہے کہ قدر کسی بھی وقت بدل سکتی ہے۔ اسے ڈی ٹی سی ایم میں رکھنے سے آئی ایس آر رائٹ اور مین لوپ دونوں ایک ہی چکر میں ہوتے ہیں۔

DTCM ITCM سے زیادہ تیزی سے بھرتا ہے۔

میموری پروفائل کو دوبارہ دیکھ کر، ایسا لگتا ہے:

            DTCM:      727240 B    1572608 B     46.24%

لنکر میپ فائل کے خلاصے کی یہ ایک لائن ظاہر کرتی ہے کہ DTCM کے پاس 1,572,608 بائٹس (تقریباً 1.5 MB) دستیاب ہیں اور فرم ویئر 727,240 بائٹس (تقریباً 710 KB) استعمال کر رہا ہے، جو اس کی کل صلاحیت کا 46.24 فیصد ہے۔

DTCM ITCM سے زیادہ تیزی سے بھرتا ہے کیونکہ بہت سے مسابقتی آئٹمز ہیں، بشمول اسٹیک، ہیپ (اگر کوئی ہے)، عالمی متغیرات، اور کسی بھی لائبریری کے ڈیٹا سیکشن جن سے آپ لنک کرتے ہیں۔ ہر سی لائبریری فنکشن، ہر RTOS ڈیٹا ڈھانچہ، اور ہر مڈل ویئر جزو جو جامد ڈیٹا کا استعمال کرتا ہے اس کی اپنی ڈیٹا کی جگہ حاصل ہوتی ہے۔ یہ ایک مسلسل پیمانے پر مشق پیدا کرتا ہے.

ڈیٹا کے ہر ڈھانچے کے لیے، آپ کو درج ذیل سوالات پوچھنے چاہئیں: کیا یہ واقعی ایک سائیکل تک رسائی کی ضرورت ہے یا یہ DDR میں کام کر سکتا ہے؟

کارکردگی کے اثرات کی مخصوص مثالیں۔

فرض کریں کہ آپ کا پروسیسر 400 میگاہرٹز پر چلتا ہے۔ DTCM ایک سائیکل تک رسائی فراہم کرتا ہے۔ DDR 8 سائیکل تک رسائی فراہم کرتا ہے۔ میرے پاس ایک تلاش کی میز ہے جس تک فی سیکنڈ 100,000 بار رسائی حاصل کی جاتی ہے۔

DTCM: 100,000 accesses x 1 cycle  = 100,000 cycles/sec
DDR:  100,000 accesses x 8 cycles = 800,000 cycles/sec

Difference: 700,000 cycles/sec
At 400 MHz: 700,000 / 400,000,000 = 0.00175 seconds = 1.75 ms

یہ حساب کتاب میموری کی دونوں اقسام کے لیے فی سیکنڈ 100,000 میموری رسائی سائیکل کی لاگت کو ظاہر کرتا ہے۔ DTCM میں، ہر ایک رسائی 1 سائیکل ہے، کل 100,000 سائیکلوں کے لیے۔ DDR میں، ہر ایک رسائی 8 سائیکلوں پر مشتمل ہے، کل 800,000 سائیکلوں کے لیے۔ 400 میگاہرٹز گھڑی کی رفتار پر، 700,000 سائیکل فی سیکنڈ کا فرق میموری کے انتظار میں 1.75 ملی سیکنڈ اضافی CPU وقت کا ترجمہ کرتا ہے۔

اگر آپ ریئل ٹائم کنٹرول لوپ 1 کلو ہرٹز (1 ایم ایس پیریڈ) پر چلاتے ہیں، تو 1.75 ایم ایس فی سیکنڈ کی اضافی میموری لیٹینسی کا مطلب ہے کہ کچھ انفرادی تکرار ان کے 1 ایم ایس بجٹ سے زیادہ چلیں گی۔ چاہے اس کی وجہ سے آپ اصل ڈیڈ لائن سے محروم ہوجاتے ہیں اس کا انحصار اس بات پر ہوگا کہ کس طرح رسائی کو تکرار میں تقسیم کیا جاتا ہے اور آپ کا وقت کا بجٹ کتنا آرام دہ ہے، لیکن یہ ظاہر کرتا ہے کہ ایمبیڈڈ سسٹمز میں میموری کی جگہ کے فیصلے کے حقیقی دنیا کے نتائج کیوں ہوتے ہیں۔

ڈبل ڈیٹا ریٹ (DDR) میموری کیا ہے؟

ڈی ڈی آر بیرونی میموری ہے۔ یہ پروسیسر ڈائی کے باہر سرکٹ بورڈ پر واقع ہے اور میموری کنٹرولر کے ذریعے جڑا ہوا ہے۔ اگرچہ وہ TCMs سے بہت بڑے ہیں (عام طور پر 4 MB سے کئی GB تک)، رسائی کی رفتار نمایاں طور پر سست ہے۔

"ڈبل ڈیٹا ریٹ” نام سے مراد ڈی ڈی آر چپ اور میموری کنٹرولر کے درمیان ڈیٹا کی منتقلی کا طریقہ ہے۔ گھڑی کے سگنل کے بڑھتے ہوئے اور گرتے ہوئے دونوں کناروں پر ڈیٹا منتقل کیا جاتا ہے، جو کہ ایک ڈیٹا ریٹ ڈیزائن کے مقابلے میں منتقلی کی شرح کو مؤثر طریقے سے دوگنا کرتا ہے۔ تاہم، یہ DDR چپ کے اندر قطاروں اور کالموں کو چالو کرنے کی تاخیر کو ختم نہیں کرتا، جو سست روی کا سبب بنتا ہے۔

DDR رسائی کیسے کام کرتی ہے۔

جب CPU DDR سے پڑھتا ہے، تو میموری کنٹرولر اور DDR چپ کے اندر ایک کثیر مرحلہ عمل ہوتا ہے۔

سب سے پہلے، CPU میموری کنٹرولر کو ایڈریس کی درخواست بھیجتا ہے۔ میموری کنٹرولر پروسیسر کے اندر ایک ہارڈویئر بلاک ہے جو CPU پتوں کو مخصوص قطار اور کالم پتوں میں ترجمہ کرتا ہے جسے DDR چپ سمجھتی ہے۔

دوسرا، میموری کنٹرولر DDR چپ کے اندر درست قطاروں کو چالو کرتا ہے۔ اس مرحلے کو Row Address Strobe (RAS) مرحلہ کہا جاتا ہے۔ DDR چپس چھوٹے کیپسیٹرز کے ایک گرڈ سے بنی ہوتی ہیں، اور "ایک قطار کو چالو کرنے” کا مطلب ہے کہ اس قطار میں موجود تمام capacitors کو DDR چپ کے اندر موجود قطار کے بفر میں پڑھنا ہے۔ اس میں کئی گھڑیوں کے چکر لگتے ہیں۔

تیسرا، میموری کنٹرولر فعال قطار میں صحیح کالم کا انتخاب کرتا ہے۔ اسے کالم ایڈریس اسٹروب (CAS) مرحلہ کہا جاتا ہے۔ DDR چپ قطار بفر سے صحیح بٹ کو منتخب کرنے کے لیے کالم کا پتہ استعمال کرتی ہے۔ اس میں کئی گھڑیوں کے چکر بھی لگتے ہیں۔

چوتھا، ڈیٹا کو واپس میموری کنٹرولر اور وہاں سے CPU میں منتقل کیا جاتا ہے۔ ڈیٹا کی منتقلی گھڑی کے دو کناروں پر ہوتی ہے ("ڈبل ڈیٹا ریٹ” حصہ)، جو تھرو پٹ میں مدد کرتا ہے لیکن RAS اور CAS مراحل کی ابتدائی تاخیر کو کم نہیں کرتا ہے۔

درخواست کے آنے پر انتظار کا کل وقت میموری کی حالت پر منحصر ہے۔ اگر پچھلی رسائی سے درست قطار پہلے ہی فعال ہو چکی ہے ("رو ہٹ”) تو RAS قدم کو چھوڑا جا سکتا ہے اور رسائی تیز تر ہو جائے گی۔ اگر دوسری قطاریں فعال ہیں اور نئی قطار کھولنے سے پہلے انہیں بند (پہلے سے چارج شدہ) کرنے کی ضرورت ہے ("غائب قطاریں”)، تو ان تک رسائی میں زیادہ وقت لگے گا۔ اس وقت، DDR چپ ایک ریفریش سائیکل انجام دے گی، رسائی میں مزید تاخیر کرے گی۔

عملی طور پر، رسائی کے نمونوں اور وقت کے لحاظ سے ڈی ڈی آر تک رسائی میں تاخیر تقریباً 5 سے 20+ CPU کلاک سائیکلوں تک ہوتی ہے۔

ڈی ڈی آر کیوں؟

اس کی وجہ یہ ہے کہ فرم ویئر اکثر اکیلے TCM کے لیے موزوں نہیں ہوتا ہے۔ ایک حقیقی ایمبیڈڈ پروجیکٹ میں پروٹوکول اسٹیک، کنکشن لائبریریز، فائل سسٹم ڈرائیورز، ڈیبگ انٹرفیس وغیرہ شامل ہیں۔ TCMs عام طور پر 2-3.5MB کل ہوتے ہیں (ITCM + DTCM مشترکہ) اور ایک مکمل خصوصیات والی فرم ویئر امیج آسانی سے اس سے تجاوز کر سکتی ہے۔

وائرلیس کنیکٹیویٹی اسٹیک کو شامل کرنے سے پہلے اور بعد میں میموری کا استعمال ظاہر کرنے والی حقیقی دنیا کی مثال:

Without connectivity stack:
    ITCM:      506,996 B     (24.18%)
    DTCM:      628,408 B     (39.96%)
    DDR:       558,779 B     (13.32%)

With connectivity stack:
    ITCM:      570,936 B     (27.22%)
    DTCM:      727,240 B     (46.24%)
    DDR:       622,915 B     (14.85%)

Delta:
    ITCM: +63,940 B   (~62 KB of additional code)
    DTCM: +98,832 B   (~96 KB of additional data)
    DDR:  +64,136 B   (~62 KB of additional data/code)

یہ موازنہ وائرلیس کنیکٹیویٹی اسٹیک کے ساتھ اور اس کے بغیر اسی پروجیکٹ کے میموری استعمال کو ظاہر کرتا ہے۔

"کوئی نہیں” قطاریں بیس لائن کی نشاندہی کرتی ہیں۔ "کے ساتھ” قطار کنکشن کی خصوصیت کو شامل کرنے کے بعد استعمال کو ظاہر کرتی ہے۔ "ڈیلٹا” قطار اختلافات کو ظاہر کرتی ہے۔

اس واحد خصوصیت کو شامل کرنے سے میموری کے تینوں علاقوں میں اضافی ~220KB خرچ ہوتا ہے۔ اسٹیک کے وقت کے اہم حصے (انٹرپٹ ہینڈلرز، بفر مینجمنٹ) ITCM اور DTCM میں چلے گئے۔ باقی (پیکٹ پارسر، کنکشن مینجمنٹ، کنفیگریشن لاجک) DDR میں چلا گیا جہاں سنگل سائیکل کی کارکردگی کی ضرورت نہیں تھی۔

DDR میں کیا شامل ہے؟

ابتدائی اور ترتیب کوڈ یہ سب سے آسان زمرہ ہے۔ بوٹ پر ایک بار چلنے والے فنکشنز کے لیے تیز عمل درآمد کی ضرورت نہیں ہے، جیسے کنفیگریشن فائلوں کو پارس کرنا، پیری فیرلز کو شروع کرنا، یا ڈیٹا سٹرکچر ترتیب دینا۔ یہ ایک بار چلتا ہے، DDR تاخیر کی وجہ سے کچھ اور ملی سیکنڈ لیتا ہے، اور دوبارہ کبھی نہیں چلتا ہے۔ کوئی نوٹس نہیں کرتا۔ اسے DDR میں رکھیں اور TCM جگہ کو کوڈ کے لیے محفوظ کریں جو فی سیکنڈ میں دس لاکھ بار چلتا ہے۔

بڑا بفر یہ TCM کے لیے موزوں نہیں ہے، اس لیے ہمیں DDR کے لیے جانا پڑے گا۔ 16 بٹس فی پکسل کے ساتھ 320×240 ڈسپلے کے لیے امیج فریم بفر 150KB ہے۔ نیٹ ورک پیکٹ پول 32KB سے بڑا ہو سکتا ہے۔ فائل سسٹم کیش 64KB ہو سکتی ہے۔ یہ بفرز ڈی ٹی سی ایم کی کل صلاحیت کا ایک اہم حصہ استعمال کرتے ہیں، اسٹیک اور متغیرات کے لیے کوئی جگہ نہیں چھوڑتے جن کے لیے درحقیقت سنگل سائیکل تک رسائی کی ضرورت ہوتی ہے۔

کبھی کبھار رسائی حاصل کردہ ڈیٹا اس کا تعلق بھی ڈی ڈی آر سے ہے۔ کیلیبریشن ٹیبلز جو بوٹ پر ایک بار لوڈ ہوتی ہیں اور آپریشن کے دوران کبھی کبھار پڑھی جاتی ہیں، ڈیبگ میسجز کے لیے سٹرنگ ٹیبلز جو صرف ڈیولپمنٹ یا خرابی کے حالات کے دوران پرنٹ ہوتے ہیں، اور خرابی کی تفصیل کی میزیں DDR کے ساتھ ٹھیک ہیں۔ اگر رسائی کی تعداد کم ہے تو، فی رسائی اضافی تاخیر متعلقہ نہیں ہے۔

کوڈ جہاں وقت اہم نہیں ہے۔ اس سے DDR زمرہ ختم ہوتا ہے۔ پروٹوکول اسٹیک (بلوٹوتھ، وائی فائی، ٹی سی پی/آئی پی)، فائل سسٹم ڈرائیورز، او ٹی اے اپ ڈیٹ ہینڈلرز، اور شیل/ڈیبگ کمانڈ انٹرپریٹرز سبھی اہم کام انجام دیتے ہیں، لیکن ان میں سے کسی کو بھی فی کمانڈ ایک گھڑی کے چکر میں چلانے کی ضرورت نہیں ہے۔ یہ نظام کے رویے کو متاثر کیے بغیر ڈی ڈی آر کی زیادہ تاخیر کا مقابلہ کر سکتا ہے۔

ڈی ڈی آر میں کوڈ اور ڈیٹا کو کیسے تعینات کریں۔

__attribute__((section(".ddr_text")))
void parse_config_file(const char *path) {
    // Runs from DDR, slower instruction fetch,
    // but config parsing happens once at boot,
    // so the latency does not affect runtime performance.
}

__attribute__((section(".ddr_bss")))
static uint8_t network_packet_pool[32768];

__attribute__((section(".ddr_bss")))
static uint8_t framebuffer[320 * 240 * 2];  // 150 KB, far too large for TCM

اس کوڈ میں parse_config_file میں رکھا گیا ہے۔ .ddr_text یہ وہ سیکشن ہے جسے لنکر اسکرپٹ DDR سے نقشہ بناتا ہے۔ اس فنکشن میں تمام ہدایات ملٹی سائیکل لیٹنسی کے ساتھ DDR سے کھینچی گئی ہیں، لیکن کنفیگریشن پارسنگ ایک بار بوٹ پر ہوتی ہے، اس لیے اضافی وقت نہ ہونے کے برابر ہے۔

کہ network_packet_pool میں ایک 32KB بفر رکھا گیا ہے۔ .ddr_bss. کہ .bss لاحقہ ایک کنونشن ہے جو اس بات کی نشاندہی کرتا ہے کہ یہ صفر سے شروع کردہ ڈیٹا ہے (لنک کرنے والا یقینی بناتا ہے کہ فرم ویئر امیج میں صفر کے 32KB کو ذخیرہ کرنے کے بجائے، سٹارٹ اپ کے وقت میموری صفر ہے)۔ یہ بفر ایسے نیٹ ورک پیکٹوں کو ذخیرہ کرنے کے لیے استعمال کیا جاتا ہے جو ڈی ٹی سی ایم اسپیس کا جواز پیش کرنے کے لیے کافی وقت کے قابل نہیں ہیں۔

کہ framebuffer ایک 150KB بفر (320 پکسل چوڑا، 240 پکسل اونچا، 2 بائٹس فی پکسل) بھی رکھا گیا ہے: .ddr_bss. 150KB پر، یہ واحد بفر DTCM کی کل صلاحیت کا تقریباً 10% استعمال کرتا ہے۔ یہ بہت مہنگا ہے جب تک کہ ڈسپلے اپ ڈیٹس مشکل ریئل ٹائم آپریشنز نہ ہوں۔

موازنہ کیسے کریں: پہلو بہ پہلو جائزہ

جائیداد آئی ٹی سی ایم ڈی ٹی سی ایم ڈی ڈی آر
مقصد کمانڈ محفوظ کریں۔ ڈیٹا اسٹوریج یونیورسل اسٹوریج
مقام آن ڈائی پرائیویٹ بس آن ڈائی پرائیویٹ بس آف چپ، میموری کنٹرولر کے ذریعے
تاخیر تک رسائی 1 سائیکل (تعیناتی) 1 سائیکل (تعیناتی) 5 سے 20+ سائیکل (متغیر)
عام سائز 512KB~2MB 512KB~1.5MB 4MB سے کئی GB تک
ٹیکنالوجی SRAM SRAM DRAM (ریفریش درکار ہے)
طاقت کم (تازہ کاری کی ضرورت نہیں) کم (تازہ کاری کی ضرورت نہیں) ہائی (مسلسل ریفریش)
کے لیے بہترین موزوں ہے۔ آئی ایس آر، ریئل ٹائم لوپ، ڈی ایس پی اسٹیک، گرم متغیرات، تلاش کی میزیں بڑے بفرز، ابتدائی کوڈ، پروٹوکول اسٹیک

یہ جدول میموری کی تین اقسام کے درمیان اہم فرق کا خلاصہ کرتا ہے۔ سب سے اہم کالم "ایکسیس لیٹنسی” اور "Typical Size” ہیں۔ کیونکہ یہ ایک بنیادی توازن کی نمائندگی کرتا ہے۔ TCM تیز لیکن چھوٹا ہے، DDR سست لیکن بڑا ہے۔

"ٹیکنالوجی” کالم اس کی وجہ بتاتا ہے۔ TCM جامد RAM (SRAM) کا استعمال کرتا ہے، جو ہر ایک بٹ کو فلپ فلاپ سرکٹس کا استعمال کرتے ہوئے ذخیرہ کرتا ہے جو بجلی کے استعمال کے دوران اپنی حالت کو برقرار رکھتے ہیں۔ DDR متحرک RAM (DRAM) کا استعمال کرتا ہے، جو ہر ایک بٹ کو ایک چھوٹے کیپسیٹر میں چارج کے طور پر محفوظ کرتا ہے۔ چونکہ کیپسیٹرز کا چارج لیک ہوتا ہے، اس لیے DRAM کو وقتا فوقتا ریفریش کیا جانا چاہیے، جس سے بجلی کی کھپت میں اضافہ ہوتا ہے اور بعض اوقات ریفریش سائیکل پڑھنے کی درخواستوں کے ساتھ موافق ہونے پر رسائی میں تاخیر کا سبب بنتا ہے۔

میموری نقشہ

Address Space:
  +------------------------------+  0x00000000
  |                              |
  |         ITCM (2 MB)          |  Single-cycle Inst Fetch
  |    ISRs, real-time loops,    |
  |    DSP, critical code        |
  |                              |
  +------------------------------+  0x00200000
  |       (reserved/gap)         |
  +------------------------------+  0x20000000
  |                              |
  |       DTCM (~1.5 MB)         |  Single-cycle Data Access
  |    Stack, hot variables,     |
  |    lookup tables, DMA bufs   |
  |                              |
  +------------------------------+  0x20180000
  |       (reserved/gap)         |
  +------------------------------+  0x80000000
  |                              |
  |         DDR (4 MB)           |  Multi-cycle Access
  |    Large buffers, init code, |
  |    protocol stacks, config   |
  |                              |
  +------------------------------+  0x80400000

یہ خاکہ ایک CPU کے ایڈریس اسپیس کو دکھاتا ہے جو اوپر سے کم پتوں سے لے کر نیچے تک اعلیٰ پتوں تک ہے۔ ITCM پتہ 0x00000000 سے شروع ہوتا ہے اور سب سے کم 2 MB پر قبضہ کرتا ہے۔ محفوظ/غیر استعمال شدہ ایڈریس اسپیس میں وقفے کے بعد، DTCM 0x20000000 پر واقع ہے اور اس کا سائز تقریباً 1.5 MB ہے۔ محفوظ جگہ میں ایک اور خلا آتا ہے اور DDR 4MB جگہ کے ساتھ 0x80000000 سے شروع ہوتا ہے۔

علاقوں کے درمیان تفاوت اہم ہے۔ یہ ایک مخصوص ایڈریس رینج ہے جو فزیکل میموری میں میپ نہیں کی گئی ہے۔ اگر آپ کا کوڈ غلطی سے ان خالی جگہوں میں سے کسی ایک ایڈریس سے پڑھتا یا لکھتا ہے، تو نتائج کا انحصار چپ کی بس کی خرابی کی ترتیب پر ہوگا۔ یہ ہارڈ فالٹ استثناء کو متحرک کر سکتا ہے یا خود بخود کوڑے کا ڈیٹا واپس کر سکتا ہے۔

یہ پتہ صرف مثال کے مقاصد کے لیے ہے۔ ہر چپ کا اپنا میموری نقشہ ہوتا ہے، جو ٹیکنیکل ریفرنس مینوئل (TRM) میں درج ہوتا ہے۔ درست پتہ اور سائز کے لیے ہمیشہ چپ کے TRM سے چیک کریں۔

کوڈ اور ڈیٹا کہاں رکھنا ہے اس کا فیصلہ کیسے کریں۔

Is it code or data?
|
+-- CODE (instructions):
|   +-- Called from an ISR or runs in a real-time loop?
|   |   +-- YES -> ITCM (deterministic timing is critical)
|   +-- Called frequently in the main processing pipeline?
|   |   +-- YES -> ITCM (if space is available)
|   +-- Called rarely (init, config, debug)?
|       +-- DDR (save ITCM space for critical code)
|
+-- DATA (variables, buffers, tables):
    +-- Accessed in an ISR or real-time context?
    |   +-- YES -> DTCM (single-cycle, deterministic)
    +-- Small and frequently accessed?
    |   +-- YES -> DTCM (if space is available)
    +-- Large buffer (>16 KB)?
    |   +-- Probably DDR (DTCM cannot afford the space)
    +-- Accessed only once at boot or very rarely?
        +-- DDR (do not use DTCM for this)

یہ فیصلہ ٹری ہر فرم ویئر کو صحیح میموری والے علاقے میں رکھنے کے سوچنے کے عمل کو حاصل کرتا ہے۔

یہ پوچھ کر شروع کریں کہ آیا آپ کوڈ (ہدایات) یا ڈیٹا (متغیرات، بفرز، ٹیبلز) رکھ رہے ہیں۔ کوڈ کے لیے، اہم سوالات یہ ہیں کہ یہ کتنی بار چلتا ہے اور کیا وقت کی پابندیاں ہیں۔ ISR کوڈ اور ریئل ٹائم لوپ کوڈ ITCM میں جاتے ہیں۔ باقی سب کچھ DDR میں جاتا ہے۔ جب ڈیٹا کی بات آتی ہے تو سب سے اہم سوالات یہ ہیں کہ اس تک کتنی بار اور کتنی بڑی رسائی ہوگی۔ چھوٹا، کثرت سے رسائی حاصل کرنے والا ڈیٹا DTCM میں جاتا ہے۔ بڑے بفرز اور شاذ و نادر ہی رسائی شدہ ڈیٹا DDR میں جاتا ہے۔

عمومی اصول: اپنا سب سے مشہور کوڈ اور ڈیٹا TCM اور باقی سب کچھ DDR میں ڈالیں۔. "ہاٹ” کا مطلب ہے وہ چیز جس تک کثرت سے رسائی حاصل کی جاتی ہے اور یا تو تاخیر سے حساس ہوتی ہے یا اس کے لیے مقررہ وقت کی ضرورت ہوتی ہے۔ جب شک ہو، DDR تعیناتی کے ساتھ شروع کریں اور TCM میں تبھی جائیں جب پروفائلنگ اس کی ضرورت کی نشاندہی کرے۔ رکاوٹوں کو دریافت کرنے کے بعد DDR سے ITCM تک فعالیت کو فروغ دینا اس سے کہیں زیادہ آسان ہے کہ ہر چیز کو شروع سے ITCM میں ڈالنے کی کوشش کی جائے اور جگہ ختم ہو جائے۔

لنکر اسکرپٹ میموری پلیسمنٹ کو کیسے کنٹرول کرتا ہے۔

ہر وہ چیز جس پر ہم نے اب تک بات کی ہے (سیکشن پراپرٹیز، میموری پلیسمنٹ، ایڈریس ایلوکیشن) لنکر سکرپٹ. یہ ایک فائل ہے (عام طور پر .ld ایکسٹینشن) لنکر کو بالکل بتاتا ہے کہ کون سا سیکشن میموری کے کس علاقے میں جاتا ہے۔ لنکر اسکرپٹ فرم ویئر کے میموری لے آؤٹ کے بارے میں سچائی کا واحد ذریعہ ہے۔

MEMORY
{
    ITCM    (rx)  : ORIGIN = 0x00000000, LENGTH = 2M
    DTCM    (rw)  : ORIGIN = 0x20000000, LENGTH = 1536K
    DDR     (rwx) : ORIGIN = 0x80000000, LENGTH = 4M
}

SECTIONS
{
    /* === ITCM: Critical code === */
    .itcm_text :
    {
        KEEP(*(.isr_vector))          /* Interrupt vector table */
        *(.itcm_text)                 /* Functions with __attribute__((section(".itcm_text"))) */
        *audio_processing.o(.text)    /* All code from audio_processing.c */
        *motor_control.o(.text)       /* All code from motor_control.c */
    } > ITCM

    /* === DDR: Non-critical code === */
    .ddr_text :
    {
        *(.text)                      /* Default catch-all for remaining code */
        *(.text*)
        *(.rodata)                    /* Read-only data (string literals, constants) */
        *(.rodata*)
    } > DDR

    /* === DTCM: Critical data === */
    .dtcm_data :
    {
        *(.dtcm_data)                 /* Data with __attribute__((section(".dtcm_data"))) */
        *audio_processing.o(.data)    /* All initialized data from audio_processing.c */
        *audio_processing.o(.bss)     /* All zero-initialized data from audio_processing.c */
    } > DTCM

    /* === DTCM: Stack === */
    .stack (NOLOAD) :
    {
        . = ALIGN(8);
        __stack_start = .;
        . = . + 8K;                  /* 8 KB stack */
        __stack_end = .;
    } > DTCM

    /* === DDR: Everything else === */
    .ddr_data :
    {
        *(.data)                      /* Default catch-all for remaining initialized data */
        *(.bss)                       /* Default catch-all for remaining zero-initialized data */
        *(COMMON)
    } > DDR
}

اس لنکر اسکرپٹ میں دو اہم بلاکس ہیں: MEMORY اور SECTIONS.

کہ MEMORY ایک بلاک ایک چپ پر دستیاب جسمانی میموری کے علاقے کی وضاحت کرتا ہے۔ ہر لائن میں علاقے کا نام، متعلقہ اتھارٹی (rx پڑھنے کے عمل کے لیے، rw پڑھنے لکھنے کے لیے، rwx پڑھنے لکھنے کے عمل کے لیے)، ابتدائی پتہ (ORIGIN) اور سائز (LENGTH)۔ اس قدر کو چپ کے جسمانی میموری کے نقشے سے مماثل ہونا چاہیے جیسا کہ حوالہ دستی میں بیان کیا گیا ہے۔

کہ SECTIONS ایک بلاک اس بات کی وضاحت کرتا ہے کہ کس طرح لنکر مرتب شدہ کوڈ اور ڈیٹا کو اس میموری والے علاقے میں تقسیم کرتا ہے۔ ہر سیکشن کے اصول میں ایک سیکشن کا نام ہوتا ہے، جیسے .itcm_text)، ان پٹ پیٹرن کی ایک فہرست جو یہ بتاتی ہے کہ کون سے آبجیکٹ فائل سیکشنز کو شامل کرنا ہے، اور > REGION ایک ہدایت جو لنکر کو بتاتی ہے کہ آؤٹ پٹ سیکشن کو میموری میں کہاں رکھنا ہے۔

کہ .itcm_text سیکشن مداخلت ویکٹر ٹیبل کو جمع کرتا ہے (KEEP(*(.isr_vector)))، تمام افعال کو واضح طور پر نشان زد کیا گیا ہے۔ __attribute__((section(".itcm_text")))اور تمام کوڈ ہے۔ audio_processing.o اور motor_control.o. کہ KEEP ہدایت لنکر کو ردی کی ٹوکری کے جمع کرنے کے دوران رکاوٹ ویکٹر ٹیبل کو ضائع کرنے سے روکتی ہے، یہاں تک کہ اگر کوئی کوڈ جو براہ راست حوالہ دیتا ہو ظاہر نہ ہو۔ یہ سب ITCM پر لاگو ہوتا ہے۔

کہ .ddr_text سیکشن ایک جامع نمونہ استعمال کرتا ہے۔ *(.text) اور *(.text*) کوئی بھی باقی کوڈ جمع کریں جس کا اوپر ITCM سیکشن میں دعویٰ نہیں کیا گیا تھا۔ مزید برآں، صرف پڑھنے کے لیے ڈیٹا (.rodata)، جس میں سٹرنگ لٹریلز اور const متغیر یہ سب ڈی ڈی آر پر لاگو ہوتا ہے۔

کہ .dtcm_data یہ سیکشن تمام ڈیٹا کے ساتھ ساتھ واضح طور پر رکھا گیا ڈیٹا بھی جمع کرتا ہے۔ audio_processing.o. کہ .stack سیکشن ایک 8 بائٹ منسلک اسٹیک کے لیے 8KB محفوظ رکھتا ہے۔ __stack_start اور __stack_end ایک علامت جو اسٹارٹ اپ کوڈ اور اسٹیک پروفائلنگ کوڈ کا حوالہ دے سکتی ہے۔ دونوں DTCM میں جاتے ہیں۔

کہ .ddr_data سیکشن تمام بقیہ ڈیٹا کو کیچ آل پیٹرن میں جمع کرتا ہے اور DDR میں داخل ہوتا ہے۔

سیکشن میچنگ کیسے کام کرتی ہے۔

لنکر اوپر سے نیچے تک حصوں پر کارروائی کرتا ہے۔ اگر آپ کو درج ذیل وائلڈ کارڈ پیٹرن کا سامنا کرنا پڑتا ہے: *(.text)تمام میچ .text وہ حصے جن کا اسکرپٹ میں پہلے زیادہ مخصوص قواعد کے ذریعہ ابھی تک دعویٰ نہیں کیا گیا ہے۔

تو اوپر کی مثال میں *audio_processing.o(.text) ITCM سیکشن میں تمام کوڈز درج ذیل کوڈز پر زور دیتے ہیں: audio_processing.c پہلے پھر جب لنک کرنے والا پہنچ جاتا ہے۔ *(.text) ڈی ڈی آر سیکشن میں audio_processing.oایس .text سیکشن پہلے ہی رکھا جا چکا ہے اس لیے اسے چھوڑ دیا جائے گا۔ صرف غیر دعویدار .text دیگر آبجیکٹ فائلوں کے حصے DDR کیچ آل سے ملتے ہیں۔

اس کا مطلب ہے: لنکر اسکرپٹ میں حصوں کی ترتیب اہم ہے۔. عام آفاقی اصولوں سے پہلے مخصوص اصول (انفرادی آبجیکٹ فائلیں، نام والے حصے) رکھیں۔ اگر آپ ڈالیں۔ *(.text) پکڑنے سے پہلے *audio_processing.o(.text) اصول کے مطابق، ایک کیچ آل کے لیے ہر چیز کو پہلے مماثل کرنے کی ضرورت ہوتی ہے، اور ایک مخصوص اصول کسی چیز سے میل نہیں کھاتا۔

سے بچنے کے لئے عام غلطیاں

1. DTCM میں اسٹیک اوور فلو

اسٹیک ڈی ٹی سی ایم میں ہے۔ DTCM چھوٹا ہے۔ اگر آپ کسی فنکشن کے اندر ایک بڑی مقامی صف کا اعلان کرتے ہیں، تو یہ اسٹیک پر محفوظ ہو جائے گا۔

void problematic_function(void) {
    uint8_t huge_local_buffer[65536];  // 64 KB allocated on the stack
    // This consumes 64 KB of DTCM immediately
}

یہ کوڈ 64KB مقامی صف کا اعلان کرتا ہے۔ کیونکہ یہ ایک مقامی متغیر ہے (نہیں۔ static)، جب فنکشن کو بلایا جاتا ہے تو اسے اسٹیک پر مختص کیا جاتا ہے۔ اگر اسٹیک کا کل سائز 8 KB ہے، جیسا کہ اوپر لنکر اسکرپٹ کی مثال میں ہے، تو یہ واحد اعلامیہ اسٹیک کو 56 KB سے اوور فلو کر دے گا، جو DTCM کے اسٹیک سے ملحق تمام میموری پر لکھے گا۔

ڈیسک ٹاپ OS میں، اسٹیک اوور فلو سیگمنٹیشن کی خرابیوں کا سبب بنتا ہے کیونکہ OS ان کا پتہ لگانے کے لیے ورچوئل میموری اور گارڈ پیجز کا استعمال کرتا ہے۔

میموری پروٹیکشن کے بغیر ایمبیڈڈ سسٹمز میں، اسٹیک خود بخود ملحقہ میموری والے علاقوں میں بڑھ جاتا ہے، وہاں ذخیرہ شدہ ڈیٹا کو خراب کر دیتا ہے۔ نتیجے میں پیدا ہونے والے کیڑے کی تشخیص کرنا بہت مشکل ہے کیونکہ علامات (خراب متغیرات، غیر معمولی رویے، وقفے وقفے سے کریش) ظاہر ہوتے ہیں جو اصل وجہ سے غیر متعلق ہوتے ہیں۔ بظاہر بے ترتیب اعداد و شمار کے بدعنوانی کے مسائل کو ڈیبگ کرنے میں کئی دن لگ سکتے ہیں اس سے پہلے کہ یہ محسوس ہو کہ بنیادی وجہ فنکشن تین کال لیولز میں اسٹیک اوور فلو ہے۔

ٹھیک کرتا ہے۔: استعمال کریں۔ static ایک بڑے بفر کے لیے مختص یا ہیپ ایلوکیشن کریں اور اسے DDR میں رکھیں۔

void fixed_function(void) {
    __attribute__((section(".ddr_bss")))
    static uint8_t huge_buffer[65536];  // In DDR, not on the stack

    // Stack is safe, DTCM is not wasted
}

بفر بنا کر staticاسے اب اسٹیک پر مختص نہیں کیا گیا ہے۔ اس کے بجائے، لنکر اسے ایک بار مختص کرتا ہے۔ .ddr_bss سیکشنز کو ڈی ڈی آر میں میپ کیا گیا ہے۔ بفر پروگرام کی پوری زندگی تک برقرار رہتا ہے (جیسے ایک عالمی متغیر)، لیکن اس کا نام اس فنکشن کے دائرہ کار میں ہے۔ اسٹیک میں صرف بفرز کی طرف اشارہ ہوتا ہے جو سائز میں چند بائٹس ہیں، 64KB نہیں۔

2. آئی ٹی سی ایم اوور چارج

اگر آپ ITCM کی گنجائش سے تجاوز کرتے ہیں، تو لنکر "علاقہ ITCM N بائٹس سے بھرا ہوا” کی خطوط پر ایک خرابی پیدا کرے گا۔ لیکن اگر آپ بند جب حد تک پہنچ جائے گی، تو لائبریری اپ ڈیٹس یا فیچر میں اضافے کی وجہ سے تعمیر کی ناکامی ناکام ہو جائے گی۔ RTOS یا کنیکٹیویٹی اسٹیک میں ایک معمولی ورژن کا ٹکرانا ITCM کو کنارے پر دھکیلنے کے لیے کافی کوڈ کا اضافہ کر سکتا ہے۔

ہیڈ روم کو برقرار رکھیں۔ پہلے دکھایا گیا 27% استعمال اچھا ہے۔ 85% سے اوپر، آپ کو کم اہم کوڈ کو DDR میں منتقل کرنے کے لیے فعال طور پر کام کرنا چاہیے۔ 95% سے زیادہ کسی بھی چیز کا مطلب ہے کہ ترقی کی کوئی گنجائش نہیں ہے اور آپ کو فوری طور پر تبدیل کرنے کی ضرورت ہے۔ آپ کی CI پائپ لائن میں خودکار میموری بجٹ کی جانچ پڑتال (بعد میں اس مضمون میں بحث کی جائے گی) آپ کو حیرت سے بچنے میں مدد دے سکتی ہے۔

3. صف بندی کی ضروریات کو نظر انداز کرنا

TCM یادوں میں اکثر سیدھ کے تقاضے ہوتے ہیں۔ Cortex-M پروسیسرز پر جو سخت سیدھ کو نافذ کرتے ہیں، غیر منسلک ایڈریس پر 32 بٹ ویلیو تک رسائی ہارڈفالٹ استثناء کو بڑھاتی ہے۔

/* Problematic: packed struct can create unaligned fields */
__attribute__((section(".dtcm_data"), packed))
struct badly_aligned {
    uint8_t  flag;
    uint32_t counter;  // May be at byte offset 1, unaligned
};

/* Correct: natural alignment, with minor padding */
__attribute__((section(".dtcm_data")))
struct properly_aligned {
    uint32_t counter;  // At offset 0, 4-byte aligned
    uint8_t  flag;     // At offset 4
    // 3 bytes of padding follow, a small cost for correctness
};

پہلے ڈھانچے میں packed انتساب کمپائلر سے کہتا ہے کہ فیلڈز کے درمیان پیڈنگ کا استعمال نہ کریں۔ اس کا مطلب ہے: counter بائٹ آفسیٹ 1 سے شروع ہو رہا ہے (فوری طور پر 1 بائٹ کے بعد)۔ flag)، جو کہ 4 کا ضرب نہیں ہے۔ اگر CPU TCM میں 4-بائٹ غیر منسلک ایڈریس سے 32 بٹ ویلیو پڑھنے کی کوشش کرتا ہے، تو یہ سختی سے منسلک پروسیسرز (بشمول زیادہ تر Cortex-M cores) پر ہارڈ فالٹ کو متحرک کرے گا۔

دوسرے ڈھانچے میں، فیلڈز کو اس طرح ترتیب دیا گیا ہے: counter (4 بائٹس) سب سے پہلے آفسیٹ 0 پر آتا ہے، جو 4 بائٹس بطور ڈیفالٹ منسلک ہوتا ہے۔ کہ flag (1 بائٹ) آفسیٹ 4 پر ہوتا ہے۔ کمپائلر اس کے بعد پیڈنگ کے 3 بائٹس داخل کرتا ہے۔ flag ہم کوشش کر رہے ہیں کہ ساخت کا سائز 8 بائٹس (4 کا کثیر) ہو، لیکن درست اور تنازعات سے پاک آپریشن کی ادائیگی کے لیے یہ ایک چھوٹی قیمت ہے۔

4. غیر مطابقت پذیر بس آرکیٹیکچرز پر TCM میں DMA کی منتقلی

کچھ DMA کنٹرولرز TCM میموری تک رسائی حاصل نہیں کر سکتے ہیں۔ آیا DMA TCM تک پہنچ سکتا ہے اس کا انحصار مکمل طور پر چپ کے اندرونی بس فن تعمیر (بس میٹرکس) پر ہے۔

اگر آپ پیریفیرل سے ڈی ٹی سی ایم بفر میں ڈی ایم اے ٹرانسفر سیٹ اپ کرتے ہیں، لیکن ڈی ایم اے کنٹرولر کے پاس ڈی ٹی سی ایم کے لیے بس کا راستہ نہیں ہے، تو ٹرانسفر خود بخود ناکام ہو جائے گا یا غلط ایڈریس پر لکھا جائے گا۔

نہ ہی کوئی واضح غلطی پیدا کرتا ہے۔ DMA کنٹرولر سوچتا ہے کہ یہ کامیابی سے مکمل ہو گیا ہے، آپ کا کوڈ نئے ڈیٹا کی توقع کرنے والے بفر کو پڑھتا ہے، اور اس کے بجائے آپ کو پرانی یا ردی کی قیمتیں مل جاتی ہیں۔ یہ سرایت شدہ ترقی میں سب سے زیادہ مبہم کیڑے میں سے ایک ہے۔ ظاہری شکل آپ کا کوڈ درست ہے۔

ہمیشہ اپنی چپ کا بس میٹرکس ڈایاگرام چیک کریں۔ براہ کرم TCM بفرز کے ساتھ DMA استعمال کرنے سے پہلے حوالہ جاتی دستاویزات سے رجوع کریں۔ بس میٹرکس ڈایاگرام سے پتہ چلتا ہے کہ کن ماسٹرز (سی پی یو، ڈی ایم اے، یو ایس بی، وغیرہ) کو کن غلاموں (آئی ٹی سی ایم، ڈی ٹی سی ایم، ایس آر اے ایم، ڈی ڈی آر، پیری فیرلز) تک رسائی حاصل ہے۔ یقینی بنائیں کہ DMA کنٹرولر پر ماسٹر پورٹ کی TCM غلام بندرگاہ سے کنکشن لائن ہے۔ بصورت دیگر TCM میں DMA کی منتقلی کام نہیں کرے گی۔

غلطیوں کے ساتھ کارکردگی کا موازنہ

مندرجہ ذیل جدول 400 MHz پر Cortex-R کلاس پروسیسر کو فرض کرتے ہوئے، میموری کی اقسام میں رسائی میں تاخیر کا موازنہ کرتا ہے۔

+---------------------+----------+----------+----------+
| Operation           | ITCM/    |   DDR    | Slowdown |
|                     | DTCM     |          | Factor   |
+---------------------+----------+----------+----------+
| Instruction fetch   | 1 cycle  | 5-20 cyc |   5-20x  |
| Data read (32-bit)  | 1 cycle  | 5-20 cyc |   5-20x  |
| Data write (32-bit) | 1 cycle  | 5-20 cyc |   5-20x  |
| Sequential burst    | 1 cyc/wd | 2-4 cy/wd|    2-4x  |
| Random access       | 1 cycle  | 10-20 cyc|  10-20x  |
+---------------------+----------+----------+----------+

یہ جدول پانچ قسم کے میموری آپریشنز کے لیے تاخیر کو ظاہر کرتا ہے۔ پہلی تین قطاریں (ہدایات بازیافت، ڈیٹا پڑھنا، ڈیٹا لکھنا) ظاہر کرتی ہیں کہ TCM تک انفرادی رسائی ہمیشہ 1 سائیکل ہوتی ہے، جب کہ میموری کی اندرونی حالت کے لحاظ سے DDR کی حد 5 سے 20 سائیکل تک ہوتی ہے۔ سست روی کا عنصر دونوں کے درمیان تناسب ہے۔

"Sequential Burst” قطار دکھاتی ہے کہ جب ترتیب وار پتے پڑھے یا لکھے جاتے ہیں تو کیا ہوتا ہے۔ ڈی ڈی آر برسٹ موڈ میں بہت بہتر کارکردگی کا مظاہرہ کرتا ہے (5-20 سائیکلوں کی بجائے 2-4 سائیکل فی لفظ) کیونکہ ایک بار ایک قطار فعال ہونے کے بعد، اسی قطار کے بعد کے ریڈز RAS مرحلے کو چھوڑ دیتے ہیں۔ TCM میں DDR کی قطار/کالم کی ساخت نہیں ہے، لہذا یہ اب بھی فی لفظ ایک سائیکل ہے۔

"رینڈم رسائی” کی قطار DDR کے لیے بدترین صورت کو ظاہر کرتی ہے۔ چونکہ ہر ایک رسائی مختلف قطار سے ٹکراتی ہے، میموری کنٹرولر کو پچھلی قطار کو پہلے سے چارج کرنا چاہیے اور ہر بار نئی قطار کو چالو کرنا چاہیے۔ یہ 10-20 سائیکل کی رینج میں ہے، اور میموری کو تیز کرنے والے کام کے بوجھ کے لیے عام ہے (لنک لسٹ ٹراورسلز، ہیش ٹیبل تلاش، اور فنکشن پوائنٹرز کی صفوں کے ذریعے بالواسطہ فنکشن کالز)۔

عملی نقطہ: اگر آپ کا کوڈ DDR ڈیٹا تک رسائی حاصل کرتا ہے، تو ترتیب وار اس تک رسائی کی کوشش کریں۔ ترتیب میں ایک صف کے ذریعے تکرار کرنا بے ترتیب پوزیشن پر جانے سے کہیں زیادہ تیز ہے۔ میموری کنٹرولر اور DDR چپ کی اندرونی پری فیچ منطق ترتیب وار رسائی کے نمونوں کے دوران سازگار طریقے سے کام کرتی ہے۔

بجلی کی کھپت پر TCM کا اثر

میموری کی جگہ کا تعین بجلی کی کھپت کو براہ راست متاثر کرتا ہے، جو بیٹری سے چلنے والی مصنوعات کے لیے اہم ہے۔

DDR کو مستقل ریفریش سائیکل کی ضرورت ہوتی ہے۔ DRAM ہر ایک بٹ کو ایک چھوٹے کیپسیٹر میں چارج کے طور پر اسٹور کرتا ہے، جو وقت کے ساتھ چارج لیک ہو جاتا ہے۔

ڈیٹا کے نقصان کو روکنے کے لیے، میموری کنٹرولر کو DDR چپ پر تقریباً ہر 64 ms پر ہر قطار کو پڑھنا اور دوبارہ لکھنا چاہیے۔ یہ ریفریش عمل پاور استعمال کرتا ہے یہاں تک کہ جب پروسیسر سلیپ موڈ میں ہو اور کوئی کوڈ نہ چل رہا ہو۔ کچھ سسٹمز پر، ڈی ڈی آر ریفریشز مجموعی نیند پاور بجٹ کا ایک اہم حصہ لے سکتے ہیں۔

TCM SRAM پر مبنی ہے اور اسے ریفریش کی ضرورت نہیں ہے۔ SRAM فلپ فلاپ سرکٹس کا استعمال کرتے ہوئے ڈیٹا کو اسٹور کرتا ہے جو پاور لاگو ہونے کے دوران اپنی حالت کو برقرار رکھتے ہیں۔ کچھ رساو کرنٹ ہے (کوئی ٹرانزسٹر کامل نہیں ہے)، لیکن یہ ڈی ڈی آر ری جنریٹیو پاور سے بہت کم ہے۔

بیٹری سے چلنے والے آلات (پہننے کے قابل، IoT سینسر، طبی آلات) کے لیے، اس کا مطلب ہے کہ DTCM کے سلیپ موڈ میں زندہ رہنے والے ڈیٹا کو جب بھی ممکن ہو آرکائیو کیا جانا چاہیے۔

اگر آپ کا ہارڈویئر اس کی حمایت کرتا ہے، تو ریفریش پاور کو مکمل طور پر ختم کرنے کے لیے ہائبرنیشن کے دوران DDR چپ کو پاور کریں۔ فرم ویئر رن ٹائم پر جتنا کم DDR استعمال کرتا ہے، اتنا ہی فعال طور پر یہ DDR پاور سٹیٹس کو منظم کر سکتا ہے، جو براہ راست بیٹری کی زندگی کو بڑھاتا ہے۔

میموری کے استعمال کو کیسے پروفائل کریں۔

اپنے کوڈ اور ڈیٹا کو ITCM، DTCM، اور DDR میں تعینات کرنے کے بعد، آپ کو یہ یقینی بنانا ہوگا کہ سب کچھ ٹھیک ہے، وقت کے ساتھ استعمال کی نگرانی کریں، اور تعمیراتی ناکامیوں کا سبب بننے سے پہلے رجعت کو پکڑیں۔ اس کے لیے مختلف تکنیکیں ہیں، جن میں سادہ کمانڈ لائن ٹولز سے لے کر خودکار CI چیکنگ تک شامل ہیں۔

طریقہ 1: لنکر میپ فائل

جب بھی آپ فرم ویئر بناتے ہیں، لنکر نقشہ فائلایک تفصیلی ٹیکسٹ فائل جو ریکارڈ کرتی ہے کہ ہر علامت (فنکشن، متغیر، مستقل) کہاں ختم ہوتی ہے اور اس کا سائز۔ میموری کے استعمال کو سمجھنے کے لیے ایمبیڈڈ ڈیولپمنٹ میں یہ واحد سب سے مفید نمونہ ہے۔

اسے بنانے کے لیے، شامل کریں: -Wl,-Map=output.map لنکر جھنڈوں میں:

arm-none-eabi-gcc \
    -T linker_script.ld \
    -Wl,-Map=firmware.map \
    -o firmware.elf \
    main.o audio.o bluetooth.o

یہ کمانڈ اے آر ایم جی سی سی ٹول چین کو تین آبجیکٹ فائلیں بنانے کے لیے کال کرتی ہے (main.o, audio.o, bluetooth.o) لنکر اسکرپٹ استعمال کریں۔ linker_script.ld. کہ -Wl,-Map=firmware.map جی سی سی کا جھنڈا -Map=firmware.map لنکر میں آپشن شامل کرنے سے یہ آؤٹ پٹ ELF بائنری کے ساتھ ایک تفصیلی نقشہ فائل بنائے گا۔ نقشہ کی فائلیں ہزاروں لائنیں لمبی ہوسکتی ہیں، لیکن سب سے مفید حصہ آخر میں خلاصہ ہے۔

نقشہ فائل کے آخر میں خلاصہ میموری کے علاقے کے ذریعہ مجموعی استعمال کو ظاہر کرتا ہے۔

Memory region         Used Size  Region Size  %age Used
            ITCM:      570936 B         2 MB     27.22%
            DTCM:      727240 B    1572608 B     46.24%
             DDR:      622915 B         4 MB     14.85%

یہ خلاصہ تین کالم دکھاتا ہے: استعمال شدہ بائٹس کی تعداد، رقبہ کا کل سائز، اور استعمال شدہ فیصد۔ آپ فرم ویئر کی حیثیت کو ایک نظر میں دیکھ سکتے ہیں۔ انگوٹھے کے اصول کے طور پر، 80% سے کم کوئی بھی چیز صحت مند ہوتی ہے جس میں نشوونما کی گنجائش ہوتی ہے۔ 80% اور 90% کے درمیان تیزی سے کمی ہو رہی ہے اور ہمیں اگلی خصوصیت کو ایڈجسٹ کرنے کے طریقے کی منصوبہ بندی کرنے کی ضرورت ہے۔ 90 فیصد سے تجاوز کرنے کے لیے کارروائی کی ضرورت ہے۔ ایک سستی میموری والے علاقے میں جائیں یا اپنی موجودہ تعیناتی کو بہتر بنانا شروع کریں۔

طریقہ 2: ماڈیول بہ ماڈیول تجزیہ کے لیے نقشہ فائل کو پارس کریں۔

آپ اسے خلاصہ میں دیکھ سکتے ہیں۔ کتنا یادداشت استعمال ہوتی ہے لیکن استعمال نہیں ہوتی۔ ڈبلیو ایچ او میں اسے استعمال کر رہا ہوں۔ نقشہ کی فائلوں میں علامت کے ساتھ مخصوص تفصیلات ہوتی ہیں، لیکن دستی طور پر پڑھنا مشکل ہوتا ہے کیونکہ فائلیں ہزاروں لائنیں لمبی ہو سکتی ہیں جس کی شکل انسانی استعمال کے لیے ڈیزائن نہیں کی گئی ہے۔

مندرجہ ذیل Python اسکرپٹ نقشہ کی فائل کو پارس کرتی ہے اور ماڈیول کے لیے مخصوص رپورٹ تیار کرتی ہے جس میں دکھایا گیا ہے کہ کون سی آبجیکٹ فائلیں میموری کو کن علاقوں میں استعمال کر رہی ہیں۔

#!/usr/bin/env python3
"""Parse a linker map file and report memory usage per object file."""

import re
import sys
from collections import defaultdict

def parse_map_file(map_path):
    """Extract symbol placements from a GCC linker map file."""
    usage = defaultdict(lambda: defaultdict(int))

    regions = {
        'ITCM': (0x00000000, 0x00200000),
        'DTCM': (0x20000000, 0x20180000),
        'DDR':  (0x80000000, 0x80400000),
    }

    def addr_to_region(addr):
        for name, (start, end) in regions.items():
            if start <= addr < end:
                return name
        return 'UNKNOWN'

    symbol_re = re.compile(
        r'^\s+\S+\s+(0x[0-9a-fA-F]+)\s+(0x[0-9a-fA-F]+)\s+(\S+\.o)'
    )

    with open(map_path) as f:
        for line in f:
            m = symbol_re.match(line)
            if m:
                addr = int(m.group(1), 16)
                size = int(m.group(2), 16)
                obj = m.group(3).split('/')[-1]
                region = addr_to_region(addr)
                usage[obj][region] += size

    return usage

def print_report(usage):
    """Print a sorted memory usage report."""
    print(f"{'Object File':<35} {'ITCM':>10} {'DTCM':>10} {'DDR':>10} {'Total':>10}")
    print("-" * 80)

    totals = defaultdict(int)
    rows = []

    for obj, regions in usage.items():
        total = sum(regions.values())
        rows.append((obj, regions, total))
        for r, s in regions.items():
            totals[r] += s

    rows.sort(key=lambda x: x[2], reverse=True)

    for obj, regions, total in rows[:20]:
        print(f"{obj:<35} "
              f"{regions.get('ITCM', 0):>10,} "
              f"{regions.get('DTCM', 0):>10,} "
              f"{regions.get('DDR', 0):>10,} "
              f"{total:>10,}")

    print("-" * 80)
    grand = sum(totals.values())
    print(f"{'TOTAL':<35} "
          f"{totals.get('ITCM', 0):>10,} "
          f"{totals.get('DTCM', 0):>10,} "
          f"{totals.get('DDR', 0):>10,} "
          f"{grand:>10,}")

if __name__ == '__main__':
    usage = parse_map_file(sys.argv[1])
    print_report(usage)

یہ اسکرپٹ تین چیزیں کرتا ہے: پہلا، parse_map_file نقشہ کی فائل کو لائن بہ لائن پڑھا جاتا ہے، ان لائنوں کی تلاش میں جو علامت کی جگہ کے اندراجات (سیکشن کا نام، پتہ، سائز، اور آبجیکٹ فائل کا نام) کے فارمیٹ سے مماثل ہوں۔ ہر میچ کے لیے، ہیکساڈیسیمل ایڈریس کو ایک عدد میں تبدیل کریں اور اس بات کا تعین کریں کہ اس کا استعمال کرنے والے میموری کے کس علاقے سے تعلق ہے: addr_to_region یہ ایک مددگار ہے اور آبجیکٹ فائل اور ریجن کے ذریعہ کلید کردہ نیسٹڈ لغات میں سائز جمع کرتا ہے۔

دوسرا print_report کل میموری استعمال کے لحاظ سے آبجیکٹ فائلوں کو ترتیب دیتا ہے (سب سے پہلے سب سے بڑا)، ٹاپ 20 پرنٹ کرتا ہے، اور دکھاتا ہے کہ ہر فائل ہر علاقے میں کتنا استعمال کرتی ہے۔

تیسرا، if __name__ == '__main__' بلاکس آپ کو کمانڈ لائن سے اسکرپٹ چلانے کی اجازت دیتے ہیں۔

آپ کو اپنے پتے کی حد کو ایڈجسٹ کرنے کی ضرورت پڑ سکتی ہے۔ regions ایک لغت جو چپ کے میموری میپ سے ملتی ہے۔

اسے استعمال کرتے ہوئے چلائیں:

python3 parse_map.py firmware.map

نمونہ آؤٹ پٹ:

Object File                              ITCM       DTCM        DDR      Total
--------------------------------------------------------------------------------
bluetooth_stack.o                      42,380     65,200     38,400    146,080
audio_processing.o                     89,200     32,000          0    121,200
wifi_driver.o                          21,560     33,632     25,736     80,928
sensor_hub.o                           45,000     18,400          0     63,400
libc.a(memcpy.o)                       12,340          0          0     12,340
...
--------------------------------------------------------------------------------
TOTAL                                 570,936    727,240    622,915  1,921,091

یہ آؤٹ پٹ فرم ویئر کے اعلی میموری صارفین کو کل استعمال کے لحاظ سے ترتیب دیتا ہے۔ ہر قطار آبجیکٹ فائل اور بائٹس کی تعداد کو دکھاتی ہے جو ہر میموری ایریا میں حصہ ڈالتی ہے۔

کہ bluetooth_stack.o فائلوں کو تینوں خطوں میں تقسیم کیا گیا ہے اور یہ سب سے بڑے صارف ہیں، جن کی کل تعداد 146 KB ہے۔ کہ audio_processing.o فائل ITCM اور DTCM دونوں میں 121 KB استعمال کرتی ہے (DDR میں 0 بائٹس)۔ یہ سمجھ میں آتا ہے کیونکہ آڈیو پروسیسنگ وقت اہم ہے اور اسے مکمل طور پر TCM میں رکھا گیا ہے۔ کہ libc.a(memcpy.o) اندراج ITCM میں رکھے گئے C لائبریری کے افعال کو ظاہر کرتا ہے کیونکہ انہیں کارکردگی کے اہم کوڈ کے راستوں سے بلایا جاتا ہے۔

طریقہ 3: size حکم

اگر آپ نقشہ کی فائل کو پارس کیے بغیر جلدی سے چیک کرنا چاہتے ہیں تو استعمال کریں: arm-none-eabi-size:

arm-none-eabi-size -A firmware.elf

حساب کتاب:

firmware.elf  :
section               size        addr
.itcm_text          570936           0
.dtcm_data          530240   536870912
.dtcm_bss           196000   537401152
.stack                8192   537600000
.ddr_text           422915  2147483648
.ddr_data           120000  2147906563
.ddr_bss             80000  2148026563
Total              1928283

یہ آؤٹ پٹ ELF بائنری کے تمام حصوں، بائٹس میں ان کا سائز، اور ان کا ابتدائی پتہ (اعشاریہ میں) درج کرتا ہے۔

آپ کسی حصے کو میموری والے علاقے میں اس کا پتہ حل کر کے نقشہ بنا سکتے ہیں۔ 0 کے قریب پتے ITCM ہیں، 536 ملین (0x20000000) کے قریب پتے DTCM ہیں، اور 2.1 بلین (0x80000000) کے قریب پتے DDR ہیں۔

یا، سیکشن کا نام خود مقامی ہے (.itcm_text یہ ITCM میں ہے، .dtcm_data اور .dtcm_bss یہ DTCM میں ہے، .ddr_text اور .ddr_data اور .ddr_bss ڈی ڈی آر)۔

کہ -A پرچم ڈیفالٹ BSD فارمیٹ آؤٹ پٹ کے بجائے فی سیکشن سائز فراہم کرتا ہے۔ یہ نقشہ فائل کے نقطہ نظر سے کم تفصیلی ہے، لیکن باکس سے باہر چلتا ہے اور آپ کو بڑی تصویر دیتا ہے۔

طریقہ 4: رن ٹائم اسٹیک پروفائلنگ

جامد تجزیہ (نقشے کی فائلیں، size آؤٹ پٹ) آپ کو کمپائل ٹائم پلیسمنٹ کے بارے میں بتاتا ہے۔ تاہم، کچھ میموری کا استعمال متحرک ہے، خاص طور پر اسٹیک، جو کال کی گہرائی اور مقامی متغیر سائز کے لحاظ سے رن ٹائم پر بڑھتا اور سکڑتا ہے۔ ایک فنکشن جو 2KB مقامی بفر کو مختص کرتا ہے وہ اسٹیک اسپیس کو صرف اس وقت استعمال کرتا ہے جب یہ چل رہا ہو، لہذا جامد تجزیہ زیادہ سے زیادہ اسٹیک استعمال کو ظاہر نہیں کرتا ہے۔

عام تکنیکیں ہیں۔ اسٹیک واٹر مارکنگ: بوٹ کے وقت، پورے اسٹیک ایریا کو معلوم پیٹرن سے بھریں، پھر وقتاً فوقتاً چیک کریں کہ پیٹرن کا کتنا احاطہ کیا گیا ہے۔

#define STACK_FILL_PATTERN 0xDEADBEEF

void stack_watermark_init(void) {
    extern uint32_t __stack_start;
    extern uint32_t __stack_end;
    uint32_t *p = &__stack_start;

    register uint32_t sp asm("sp");
    while (p < (uint32_t *)(sp - 64)) {
        *p++ = STACK_FILL_PATTERN;
    }
}

uint32_t stack_usage_bytes(void) {
    extern uint32_t __stack_start;
    extern uint32_t __stack_end;
    uint32_t *p = &__stack_start;

    while (p < &__stack_end && *p == STACK_FILL_PATTERN) {
        p++;
    }

    return (uint32_t)(&__stack_end) - (uint32_t)p;
}

void check_stack_health(void) {
    uint32_t used = stack_usage_bytes();
    uint32_t total = 8192;
    uint32_t percent = (used * 100) / total;

    if (percent > 80) {
        log_warning("Stack usage: %lu / %lu bytes (%lu%%)",
                    used, total, percent);
    }
}

کہ stack_watermark_init فنکشنز اسٹیک میموری کو بھرتے ہیں۔ __stack_start موجودہ اسٹیک پوائنٹر کے نیچے) پیٹرن کا استعمال کرتے ہوئے 0xDEADBEEF. کہ extern اعلان لنکر اسکرپٹ میں بیان کردہ لنکر علامتوں کا حوالہ دیتا ہے۔ .stack پارٹ ٹائم نوکری. کہ register uint32_t sp asm("sp") لائن موجودہ اسٹیک پوائنٹر ویلیو کو پڑھتی ہے تاکہ فنکشن کو معلوم ہو کہ بھرنا کہاں روکنا ہے (وہ اپنے اسٹیک فریم کو اوور رائٹ نہیں کرنا چاہتا)۔ ایک 64 بائٹ حفاظتی مارجن اس بات کو یقینی بناتا ہے کہ فل لوپ فعال اسٹیک کے زیادہ قریب نہ ہو۔

کہ stack_usage_bytes فنکشن اسٹیک کے نیچے سے اوپر کی طرف اسکین کرتا ہے، یہ گنتا ہے کہ کتنے الفاظ ابھی بھی فل پیٹرن پر مشتمل ہیں۔ کہنے کا پہلا لفظ ~ نہیں اگر پیٹرن مماثل ہے، تو یہ اس گہرے نقطہ (پانی کی بلند ترین سطح) کی نشاندہی کرتا ہے جہاں اسٹیک پہنچ گیا ہے۔ یہ فنکشن اس پوائنٹ سے اسٹیک کے اوپری حصے تک بائٹس کی تعداد لوٹاتا ہے۔

کہ check_stack_health فنکشن استعمال شدہ اسٹیک کے فیصد کا حساب لگاتا ہے اور اگر یہ 80% سے زیادہ ہو تو وارننگ لاگ کرتا ہے۔ اسٹیک کے استعمال کو مانیٹر کرنے کے لیے، عام آپریشن کے دوران وقتاً فوقتاً اس فنکشن کو کال کریں۔

کال stack_watermark_init() آپ کے سٹارٹ اپ کوڈ میں جتنی جلدی ممکن ہو (پہلے main() (اگر ممکن ہو تو) کال کریں۔ check_stack_health() معمول کے آپریشن کے دوران وقفے وقفے سے۔ یہ آپ کو ہائی واٹر مارک بتاتا ہے، جو کہ فرم ویئر کی اب تک پہنچی ہوئی زیادہ سے زیادہ گہرائی ہے۔

طریقہ 5: پوری تعمیر میں میموری کو ٹریک کریں۔

جب بھی آپ خصوصیات شامل کرتے ہیں یا تبدیلیوں کو ضم کرتے ہیں، اس سے پہلے اور بعد میں میموری پروفائل چلائیں:

arm-none-eabi-size -A firmware_before.elf > mem_before.txt
arm-none-eabi-size -A firmware_after.elf > mem_after.txt
diff mem_before.txt mem_after.txt

یہ تینوں کمانڈز دونوں فرم ویئر کی تعمیر کے سیکشن سائز (تبدیلیوں سے پہلے اور بعد میں) کو ٹیکسٹ فائل میں کیپچر کرتی ہیں اور پھر یہ دیکھنے کے لیے فرق چیک کریں کہ کیا تبدیلی آئی ہے۔ یہ مفید ہے، لیکن خام ڈِف آؤٹ پٹ کو پڑھنا مشکل ہو سکتا ہے۔ درج ذیل اسکرپٹ ڈیلٹا فی میموری ریجن کا حساب لگا کر ایک صاف نظارہ فراہم کرتا ہے۔

#!/bin/bash
# memory_diff.sh - Compare memory usage between two builds

echo "Memory Impact of Change:"
echo "========================"

parse_size() {
    arm-none-eabi-size -A "$1" | awk '
    /\.itcm/  { itcm += $2 }
    /\.dtcm/  { dtcm += $2 }
    /\.ddr/   { ddr += $2 }
    /\.stack/ { dtcm += $2 }
    END { printf "%d %d %d", itcm, dtcm, ddr }
    '
}

read itcm_before dtcm_before ddr_before <<< \((parse_size "\)1")
read itcm_after  dtcm_after  ddr_after  <<< \((parse_size "\)2")

printf "ITCM: %+d bytes (%d -> %d)\n" \
    \(((itcm_after - itcm_before)) \)itcm_before $itcm_after
printf "DTCM: %+d bytes (%d -> %d)\n" \
    \(((dtcm_after - dtcm_before)) \)dtcm_before $dtcm_after
printf "DDR:  %+d bytes (%d -> %d)\n" \
    \(((ddr_after - ddr_before)) \)ddr_before $ddr_after

یہ اسکرپٹ دو ELF فائلوں کو بطور دلیل لیتا ہے (ایک "پہلے” اور "بعد” تعمیر)۔ کہ parse_size فنکشن پر عملدرآمد arm-none-eabi-size -A دی گئی ELF فائل کے لیے میں استعمال کرتا ہوں: awk ہر میموری ایریا کے لیے سیکشن سائز کا خلاصہ کریں۔ وہ حصے جن کے نام شامل ہیں۔ .itcm درج ذیل پر مشتمل سیکشنز کو ITCM کے طور پر شمار کیا جاتا ہے: .dtcm یا .stack ڈی ٹی سی ایم کی سمت اور حصے جن میں شامل ہیں: .ddr DDR کی طرف، جسم پہلے اور بعد کی اقدار کو پڑھتا ہے اور پھر ہر علاقے کے لیے ڈیلٹا پرنٹ کرتا ہے۔ + یا - علامت

استعمال اور آؤٹ پٹ:

$ ./memory_diff.sh firmware_without_bt.elf firmware_with_bt.elf

Memory Impact of Change:
========================
ITCM: +63940 bytes (506996 -> 570936)
DTCM: +98832 bytes (628408 -> 727240)
DDR:  +64136 bytes (558779 -> 622915)

یہ آؤٹ پٹ ظاہر کرتا ہے کہ بلوٹوتھ کی فعالیت کو شامل کرنے سے ITCM میں تقریباً 62KB، DTCM تقریباً 96KB، اور DDR تقریباً 62KB بڑھ جاتا ہے۔ آپ اسے اپنی CI/CD پائپ لائن میں ڈال سکتے ہیں تاکہ یہ یقینی بنایا جا سکے کہ ہر پل کی درخواست میموری کی قیمت کو درست طریقے سے دکھاتی ہے۔

طریقہ 6: CI میں خودکار میموری بجٹ چیک کریں۔

اپنی CI/CD پائپ لائن میں میموری پروفائلنگ کو ضم کرکے، آپ مرکزی برانچ تک پہنچنے سے پہلے اوور فلو کو پکڑ سکتے ہیں۔

#!/bin/bash
# memory_check.sh - Fail CI if memory usage exceeds thresholds

ITCM_LIMIT=85   # percent
DTCM_LIMIT=80
DDR_LIMIT=90

check_region() {
    local name=\(1 used=\)2 total=\(3 limit=\)4
    local percent=$((used * 100 / total))

    if [ \(percent -ge \)limit ]; then
        echo "FAIL: \(name usage is \){percent}% (limit: ${limit}%)"
        echo "      Used: \(used / \)total bytes"
        return 1
    else
        echo "OK:   \(name usage is \){percent}% (limit: ${limit}%)"
        return 0
    fi
}

ITCM_USED=\((grep "ITCM:" firmware.map | awk '{print \)2}')
ITCM_TOTAL=$((2 * 1024 * 1024))

DTCM_USED=\((grep "DTCM:" firmware.map | awk '{print \)2}')
DTCM_TOTAL=1572608

DDR_USED=\((grep "DDR:" firmware.map | awk '{print \)2}')
DDR_TOTAL=$((4 * 1024 * 1024))

FAILED=0
check_region "ITCM" \(ITCM_USED \)ITCM_TOTAL $ITCM_LIMIT || FAILED=1
check_region "DTCM" \(DTCM_USED \)DTCM_TOTAL $DTCM_LIMIT || FAILED=1
check_region "DDR"  \(DDR_USED  \)DDR_TOTAL  $DDR_LIMIT  || FAILED=1

exit $FAILED

یہ اسکرپٹ لنکر میپ فائل سے میموری کے استعمال کے اعداد و شمار کو پڑھتا ہے اور ان کا موازنہ قابل ترتیب فیصد حد سے کرتا ہے۔ کہ check_region فنکشن مقامی نام، استعمال شدہ بائٹس کی تعداد، دستیاب کل بائٹس، اور فیصد کی حدیں لیتا ہے۔ اصل فیصد کا حساب لگائیں اور نمبر کے ساتھ "OK” یا "FAIL” پرنٹ کریں۔ اگر خطہ حد سے تجاوز کر جاتا ہے، تو اسکرپٹ غیر صفر کی حیثیت کے ساتھ باہر نکل جائے گا، جس کی وجہ سے CI تعمیر ناکام ہو جائے گی۔

اوپری دہلیز (ITCM کے لیے 85%، DTCM کے لیے 80%، اور DDR کے لیے 90%) آپ کے پروجیکٹ کی شرح نمو اور آپ جس خالی جگہ کو برقرار رکھنا چاہتے ہیں اس کی بنیاد پر ایڈجسٹ کیا جانا چاہیے۔ DTCM کی حد کم ہے کیونکہ یہ تیزی سے بھرتا ہے اور محفوظ کرنا مشکل ہے۔

اس اسکرپٹ کو اپنی بلڈ پائپ لائن میں شامل کریں تاکہ ہر پل کی درخواست میموری کی قیمت کو ظاہر کرے۔ اگر کسی تبدیلی کی وجہ سے علاقہ حد سے تجاوز کر جاتا ہے، تو تعمیر ناکام ہو جائے گی اور ڈویلپرز کو فوری طور پر مطلع کیا جائے گا۔

طریقہ 7: رن ٹائم پر ہیپ ٹریکنگ

اگر آپ کا ایمبیڈڈ پروجیکٹ ڈائنامک میموری ایلوکیشن استعمال کرتا ہے (malloc/free)، آپ استعمال کو ٹریک کرنے کے لیے مختص کرنے والے کو لپیٹ سکتے ہیں۔

static size_t heap_used = 0;
static size_t heap_peak = 0;

void *tracked_malloc(size_t size) {
    size_t *block = (size_t *)malloc(size + sizeof(size_t));
    if (!block) return NULL;

    *block = size;
    heap_used += size;
    if (heap_used > heap_peak) {
        heap_peak = heap_used;
    }

    return (void *)(block + 1);
}

void tracked_free(void *ptr) {
    if (!ptr) return;
    size_t *block = ((size_t *)ptr) - 1;
    heap_used -= *block;
    free(block);
}

void print_heap_stats(void) {
    printf("Heap: current=%zu bytes, peak=%zu bytes\n",
           heap_used, heap_peak);
}

یہ کوڈ لپیٹ دیا گیا ہے: malloc اور free ٹریکنگ منطق پر مشتمل ہے۔ کہ tracked_malloc فنکشن درخواست سے تھوڑی زیادہ میموری مختص کرتا ہے (اضافی sizeof(size_t) بائٹس) مختص کے پہلے لفظ میں درخواست کردہ سائز کو اسٹور کرتا ہے۔ پھر heap_used کاؤنٹر کو فعال اور اپ ڈیٹ کیا جاتا ہے جب نیا ٹوٹل پچھلی بلندی سے بڑھ جاتا ہے۔ heap_peak. یہ سائز ہیڈر کے پیچھے ایک پوائنٹر آفسیٹ لوٹاتا ہے، لہذا کالر اس ڈیٹا کے لیے باقاعدہ پوائنٹر دیکھتا ہے۔

کہ tracked_free ایک فنکشن عمل کو الٹ دیتا ہے۔ یعنی 1 کو گھٹائیں۔ size_t پوشیدہ سائز ہیڈر تلاش کرنے کے لیے پوائنٹر سے اس سائز کو گھٹائیں۔ heap_usedاصلی فون free اصل بلاک میں

کہ print_heap_stats فنکشن موجودہ اور زیادہ سے زیادہ ہیپ استعمال کو پرنٹ کرتا ہے۔ ڈیبگ انٹرفیس (UART کنسول، ڈیبگ CLI) کے ذریعے باقاعدہ یا آن ڈیمانڈ کال کر کے فرم ویئر کے ذریعے استعمال ہونے والے ہیپ کی مقدار کی نگرانی کریں۔

اس نقطہ نظر میں کچھ اوور ہیڈ (ایک اضافی لفظ فی مختص) ہے، لیکن متحرک میموری کے استعمال میں مرئیت فراہم کرتا ہے جو بصورت دیگر مکمل طور پر پوشیدہ ہے۔ یہ خاص طور پر میموری لیکس کو ٹریک کرنے کے لیے مفید ہے۔ heap_used یہ وقت کے ساتھ ساتھ کم ہونے کے بجائے بڑھتا ہی چلا جاتا ہے اور کچھ جاری ہونے کے بجائے مختص کیا جاتا ہے۔

خلاصہ

ARM Cortex-M اور Cortex-R آرکیٹیکچرز پر مبنی ایمبیڈڈ پروسیسرز بہت مختلف کارکردگی کی خصوصیات کے ساتھ تین میموری والے علاقوں کو براہ راست کنٹرول کرنے کی اجازت دیتے ہیں۔

انسٹرکشن ٹائٹلی کپلڈ میموری (ITCM) کوڈ کو محفوظ کریں جہاں کارکردگی سب سے اہم ہے۔ سنگل سائیکل ڈیٹرمنسٹک انسٹرکشن فیچ فراہم کرتا ہے۔ یہ چھوٹا ہے (عام طور پر 512KB سے 2MB) اس لیے اسے ISR، ریئل ٹائم پروسیسنگ فنکشنز، اور ہاٹ لوپس کے لیے محفوظ رکھیں۔

ڈیٹا ٹائٹلی کپلڈ میموری (DTCM) کارکردگی کے لیے انتہائی اہم ڈیٹا کو اسٹور کریں۔ یہ سنگل سائیکل ڈیٹرمنسٹک رسائی بھی فراہم کرتا ہے۔ اسٹیک یہاں بطور ڈیفالٹ ہے۔ یہ ITCM سے بہت چھوٹا ہے اور تیزی سے بھر جاتا ہے، اس لیے احتیاط سے فیصلہ کریں کہ آپ اس میں کیا ڈالتے ہیں۔

ڈی ڈی آر (ڈبل ڈیٹا ریٹ) میموری باقی سب کچھ بچائیں۔ بہت بڑا لیکن سست (5-20+ سائیکل فی رسائی، متغیر تاخیر)۔ اسے ابتدائی کوڈ، بڑے بفرز، پروٹوکول اسٹیک، اور کسی بھی ایسی چیز کے لیے استعمال کریں جس کے لیے مقررہ وقت کی ضرورت نہ ہو۔

آپ تقرری کو کنٹرول کرتے ہیں بذریعہ: __attribute__((section(...))) یہ لنکر اسکرپٹ کے سی کوڈ اور سیکشن-لوکل میپنگ میں ہے۔ اگر آپ نقشہ کی فائل کے ذریعے ترتیب کو چیک کرتے ہیں، size رن ٹائم پروفائلنگ تکنیک جیسے ہدایات اور اسٹیک واٹر مارکنگ۔ کلیدی مہارت یہ جاننا ہے کہ فرم ویئر کا ہر حصہ کس علاقے سے تعلق رکھتا ہے اور غلطیوں کو جلد پکڑنے کے لیے ٹولز رکھتا ہے۔

اوپر تک سکرول کریں۔