ورود

View Full Version : عملیات بزرگتر از اندازه ثبات داخل پردازنده ها



pswin.pooya
چهارشنبه 19 آبان 1395, 01:15 صبح
یکی دو روز پیش از یکی شنیدم که بهش گفته بودن نمی شه عملیات بزرگتر از 32 بیتی روی پردازنده های 32 بیتی داشت. تصمیم گرفتم که یه مقاله کوچیک بنویسم تا این سوء تفاهم حل بشه. شما داخل پردازنده های 32 بیتی هم می تونید عملیات بزرگتر از 32 بیت داشته باشید و هم میزان حافظه بیشتر. اما چه شکلی؟

حافظه بیشتر:
پردازنده های x86 ( و شاید خانواده های دیگه) که 32 بیتی هستن می تونن میزان حافظه بیشتر از 32 بیت رو قبول کنن. این کار توسط یک الحاقی پردازنده صورت می گیره به اسم PAE که میزان آدرس باس پردازنده رو زیاد می کنه. مثلا پردازنده های 32 بیتی هستن که آدرس باس 48 بیتی دارن. اما چه شکلی؟ سیستم عامل یکسری مفصر (descriptor) آدرس برای هر برنامه تعریف می کنه که به اسمهای GDT و LDT معروف هستن. این دو یه چیزی شبیه همون سگمتهای 16 بیتی هستن منتها با ساختارها پیچیده تر و کاملتر و البته قابلیت های بیشتر. توی حالت 32 بیتی میزان هر کدوم از این سگمنت های جدید همون 2 به توان 32 یا چهار گیگ هست اما یه فلگ (پرچم) داخلشون هست که به شما امکان می ده اندازه صفحه رو بجای 4 کیلوبایت به شیش مگابایت تغییر بدین. در نتیجه هر برنامه به تنهایی به همون چهار گیگ حافظه دسترسی داره (که به اصطلاح می گن می تونه آدرس دهی کنه) اما کل سیستم عامل می تونه از حافظه بیشتری بهره ببره. مثلا چهار گیگ رو به یه برنامه و چهار گیگ دیگه رو به یه برنامه دیگه اختصاص بده.



عملیات بیشتر از 32 بیت روی پردازنده 32 بیت:
راستش رو بخوایین یه ثبات 32 بیتی خیلی محدود هست و نمی شه عدد بزرگی توش جا داد مثلا int که حتی روی پردازنده 64 بیتی هم 32 بیت هست خیلی کارهای رو نمی تونه راه بندازه برای همین توی C/C++‎‎‎ شما می تونید از long long برای عملیات و محاسبات 64 بیتی استفاده کنید (حتی اگر پردازنده 32 بیتی باشه).


با عملیات بیشتر از 64 بیت چیکار کنیم؟
راستش رو بخوایین کلی راه حل هست:

1. بعضی از کامپایلر ها مثل GCC و MSVC دارای یکسری الحاقی ساده هستن که به کمک اونها می شه با اعداد 128 بیت و یا 256 بیت کار کرد:

https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html

من دقیقا نمی دونم اینها پشت صحنه چیکار می کنن. اما خب بالاخره دارن ساپورت می دن (به احتمال زیاد از چند دستور اسمبلی و یا دستورهای خاص اسمبلی استفاده می کنن و یا مواردی که در ادامه بررسیشون می کنم)


2. پردازندههایی مثل ARM و Intel دارای یک مجموعه دستور هستند که بهشون Super Scaler و یا بعضا SIMD گفته می شه. (البته توی معماری های دیگه می تونه MIMD هم باشه) این دستورها می تونن چندین عمیات جمع و ضرب و ... رو باهم انجام بدم و در نتیجه ثباتهای بزرگی دارن مثلا ثباتهای MMX در پردازنده x86 (حتی پردازندهایی مثل پنتیوم 3) دارای 128 بیت و سری دستورهای AVX ثباتهاشون 256 بیت هستن. این دستورها این امکان رو می دن که اعدادی به بزرگی 128 بیتی روشون عملیات انجام بگیره (و یا حتی در AVX2 به 512 هم رسیده که می شه چهار عملیات 128 بیتی همزمان). البته اگر برنامه نویس یکم وارد باشه و یکم هم اصول برنامه نویسی بدونه می تونه سوء استفاده خوبی بکنه و عملیات 128 و حتی 256 بیتی رو انجام بده. مثلا در مورد جمع 128 بیتی با دستورهای SSE:


z = _mm_add_epi64(x,y);
c = _mm_unpacklo_epi64(_mm_setzero_si128(), unsigned_lessthan(z,x));
z = _mm_sub_epi64(z,c)



https://en.wikibooks.org/wiki/X86_Assembly/SSE
https://en.wikipedia.org/wiki/Advanced_Vector_Extensions

به هر حال اکثر کامپایلرها از این دستورها پشتیبانی می کنن و شاید هم پشت صحنه الحاقی های همون مورد اول همین دستورها باشن.



3. راه سوم. اگر برنامه نویس یکم اصول برنامه نویسی بلد باشه می تونه با عملیات بیتی خیلی ساده خودش توابعی طراحی کنه که اینکار رو انجام بدن. مثلا برای جمع 128 بیتی کافیه مقدار carry رو برای جمع 32 بیتی بدست بیارین و عملیات معروف xor و and رو انجام بدین. و البته همه عملیات ریاضی به کمک این توابع ساده بیتی قابل پیاده سازی هستن و شما به چند دستور ساده اسمبلی و حتی C می تونید از پس این مشکل بر بیاین. (البته بگذریم از اینکه پردازنده های x86 اصلا برای اینکار هم دستورهای مثل adc و sbb رو دارن.)


4. از کتابخونه ها استفاده کنید:
کتابخونه های زیادی برای کار با عملیات ریاضی و مخصوصا عملیات بزرگ و یا امن داخل سی پلاس پلاس و سی طراحی شدن که می تونن این عملیات رو برای شما انجام بدن و دیگه لازم نیست استعداد خاصی مثل یاد گیری SSE و ... به خرج بدین. تنها کاری که باید بکنید. اینه که باید توابع اونها رو صدا بزنید:

https://gmplib.org/manual/


سخن آخر:
برنامه نویسی C/C++‎‎‎ تفاوتی که با بقیه زبانها داره اینه که برنامه نویس میانی نداره. یعنی یا برنامه نویس حرفه ای هست و یا هیچی نمی دونه و برنامه نویس حرفه ای این زبان برنامه نویسی هست که نه تنها تسلط کافی روی نرم افزار داشته باشه بلکه سخت افزار رو هم خوب بشناسه. لطفا قبل از هرگونه ادعا توی این زمینه و خراب کردن اعصاب بقیه تمرکز خودتون رو بزراید روی یادگیری بیشتر.

pswin.pooya
چهارشنبه 19 آبان 1395, 02:10 صبح
یه مطب دیگه در مورد سوپر اسکالرها: (دیدم اشاره کردم اما زیاد دقیق نگفتم)

ما چندین نوع موازی سازی داریم از جمله موازی سازی در سطح وظیفه، در سطح دستور و در سطح داده. پردازنده های سوپر اسکالر پردازندهایی هستند که می تونن موازی سازی در سطح دستور رو انجام بدن. یعنی اینکه با یک دستور می تونن چندین داده رو جمع کنن.

از جمله معروفترین این ست دستوری SIMD هست که با یک دستور می تونه چندین داده رو جمع و ضرب و ... کنه در حقیقت SIMD مخفف Single Instruction Multiple Data هست. یک ست از معروفترین دستورهای SIMD که سالیان سال هست داره ازش استفاده می شه دستورهای SSE داخل پردازندهای X86 هستن. این دستورها می تونن چهار و یا دو داده مختلف رو باهم جمع و ... بکنن. اینکار توی عملیات محاسباتی مثل ضرب ماتریسهای چهار در چهار و ... که به شدت توی سیستم های کامپیوتری استفاده می شن کاربرد داره. و باعث می شه سرعت برنامه افزایش چشم گیری پیدا کنه.

نوع دیگه سری دستورهای MIMD هستن که بیشتر توی کارتهای گرافیک و ... می تونیم اونها رو ببینیم تا پردازندهای همه منظوره. این دستورها Multiple Instruction Multiple Data هستن. یعنی چند عملیات و چند داده. مثلا کل ضرب ماتریسی رو یکجا روی یک ماتریس چهار در چهار انجام میده.

یکی از مزیتهای C++ این هستش که شما می تونید از این دستورها داخل کد خودتون استفاده کنید و سرعت برنامه خودتون رو بدون موازی سازی معمول یعنی استفاده از نخ و ... به شکل چشم گیر افزایش دهید. مثلا توی یکی از تست های من روی یک الگوریتم سرعت چیزی حدود 5 برابر افزایش پیدا کرده بود و یا روی همون ماتریسهای چهار در چهار حدود دو برابر.

پردازنده های X86 ست های مختلفی از این دستورها رو دارن که شامل MMX، SSE 1,2,3,4.x و AVX می شه. همینطور داخل پردازنده های ARM به مجموعه دستورهای NEON شناخته می شن. خلاصه تمام پردازنده های همه کاره امروزی یا حداقل 99.99 درصد اونها از این مدل دستورها پشتیبانی می کنن. جالبتر این هست که حتی ریجیستر فایل این دستورها توی خیلی موارد از ریجیستر فایل اصلی خود پردازنده هم بزرگتر هست. مثلا دستورهای SSE2 که حدودا 15 سال پیش معرفی شدن حدود 15 تا ریجیستر همه منظوره داشتن و یا AVX2 دارای 32 عدد ثبات هست!!!