رفتن به محتوا
بایت

00001001

جاسوس‌های سیلیکونی

پردازنده‌ها چگونه خودشان را مانیتور می‌کنند؟

۴ دقیقه مطالعه

جادوی PMC ها و نفوذ به عمیق‌ترین لایه‌های CPU

شاید تا به حال برایتان این پرسش پیش آمده باشد که سیستم‌عامل اصلاً از کجا می‌فهمد پردازنده چند بار در خواندن دیتا از Cache، اصطلاحاً Hit داشته یا Miss؟ چند بار انجام داده؟ چقدر در اجرای دستورات بی‌کار مانده و منابعش قفل شده‌است؟ یا شاخص حیاتی (تعداد دستورالعمل‌های اجرا‌شده در هر دورۀ کلاک) را چطور با این دقت محاسبه می‌کند؟

شاید فکر کنید لینوکس یا ویندوز با اجرای کد نرم‌افزاری این آمار را می‌گیرند؛ اما در این صورت، فاجعه رخ می‌داد. همین «سربار شمردن» باعث می‌شد پردازنده تمام وقتش را صرف شمردن کارهای خودش کند و منابع سیستم فلج شوند! در مهندسی نرم‌افزار به این پدیده «» می‌گویند؛ یعنی خود مانیتورینگ، رفتار سیستم را تغییر می‌دهد.

برای حل این بن‌بست، مهندسان سخت‌افزار یک شاهکار تکنولوژی به نام را وارد معماری پردازنده‌ها کردند که دقیقاً نقش یک دستگاه مانیتورینگ بدون سربار را برای مغز سیستم بازی می‌کند.

ماجرا از این قرار است که غول‌هایی مثل اینتل، AMD و ARM در همان لایۀ سیلیکونی و فیزیکی CPU، یک تعداد رجیستر سخت‌افزاری بسیار خاص تعبیه کرده‌اند که به آن‌ها می‌گویند. وقتی شما ابزار قدرتمندی مثل perf را در لینوکس اجرا می‌کنید، سیستم‌عامل به‌طور مستقیم با سخت‌افزار حرف می‌زند و به یکی از این رجیسترهای کنترلی یک « هگزادسیمال» می‌دهد. سیستم‌عامل به زبان سخت‌افزار می‌گوید:

  • از الان، هر زمان دیتایی در L3 Cache پیدا نشد، یک واحد به این رجیستر اضافه کن.
  • هر زمان، پیش‌بینی اجرای یک حلقه اشتباه از آب درآمد، این‌جا ثبت کن.
  • هر زمان، پردازنده منتظر رسیدن دیتا از RAM ماند و اصطلاحاً بلاک شد، کلاک‌های هدر‌رفته را بشمار.

از این لحظه به بعد، سیستم‌عامل کنار می‌کشد و خود سخت‌افزار CPU به‌صورت فیزیکی، شروع به شمردن این رویدادها می‌کند. لینوکس فقط گاهی (مثلاً هر یک ثانیه)، عدد داخل این رجیسترها را می‌خواند و به شما نمایش می‌دهد. این، یعنی شما بدون هیچ سربار نرم‌افزاری، در حال مانیتور کردن عمیق‌ترین اتفاقات داخل پردازنده هستید؛ قابلیتی که در بهینه‌سازی کدهای C++ ،Rust یا پایگاه‌های دادۀ عظیم واقعاً یک معجزه است.

ابزار perf: پنجره‌ای به درون پردازنده

برای این‌که بتوانیم از این جادوی سخت‌افزاری استفاده کنیم، لینوکس ابزار قدرتمندی به نام perf را در اختیار ما قرار داده‌است. این ابزار دقیقاً همان مترجمی است که خواسته‌های ما را به رجیسترهای MSR می‌فهماند و استفاده از آن معمولاً در دو فاز اصلی انجام می‌شود.

دیدن نمای کلی با perf stat: اگر می‌خواهید بدانید برنامۀ شما در حالت کلی چقدر منابع پردازنده را هدر داده‌است، کافی است دستور perf stat -d ./my_program را در ترمینال اجرا کنید. به محض اجرای برنامه، گزارشی می‌بینید که نشان می‌دهد کد شما چند میلیون بار در خواندن Cache شکست خورده، چند دورۀ پردازشی را طی کرده و چه تعداد پرش اشتباه داشته‌است.

نقطه‌زنی با perf record و perf report: اگر perf stat به شما بگوید که cache-miss بالایی دارید، پرسش بعدی این است: «دقیقاً کجای کد من این مشکل را ایجاد کرده‌است؟» این‌جاست که دستور perf record وارد می‌شود. این دستور در حین اجرای برنامه، هزاران بار در ثانیه از وضعیت پردازنده عکس‌برداری می‌کند، سپس با اجرای perf report می‌توانید دقیقاً به خطی (یا تابعی) از کد برسید که بیش‌ترین زمان پردازنده یا بیش‌ترین cache-miss را به خود اختصاص داده‌است؛ یعنی پیدا کردن دقیق گلوگاه، بدون این‌که حتی یک خط کد دیباگ در برنامه‌تان نوشته باشید!

روی تاریک PMC: چالش‌های اعصاب‌خردکن

البته در دنیای عملی همه‌چیز به این قشنگی نیست و درگیر شدن با PMC ها در محیط پروداکشن چالش‌های خاص خودش را دارد.

فقر منابع فیزیکی: از آن‌جا که این شمارنده‌ها قطعات فیزیکی، ترانزیستورهای واقعی و گران‌قیمت روی سطح سیلیکونی CPU هستند، تعدادشان به‌شدت محدود است. شما نمی‌توانید هم‌زمان ۵۰ متریک مختلف را مانیتور کنید و در نهایت باید به همان ۴ تا ۸ رجیستری که روی هر هسته قرار دارد، قناعت کنید.

تکنیک و افت دقت: اگر بخواهید رویدادهای بیشتری را هم‌زمان مانیتور کنید (مثلاً ۱۵ متریک با ۴ رجیستر)، سیستم‌عامل مجبور است همواره این رجیسترهای محدود را بین متریک‌های مختلف جابه‌جا کند. اصطلاحاً به این کار Time-slicing می‌گویند. این جابه‌جایی‌های مداوم باعث می‌شوند بخشی از رویدادها را در زمان خاموش بودن متریک از دست بدهید. در این حالت، لینوکس مجبور است اعداد را تخمین بزند (Scaling) که این باعث افت شدید دقت دادۀ خروجی می‌شود.

جهنم وابستگی به معماری: همان‌طور که از کلمۀ «Model-Specific» در نام MSR پیداست، این رجیسترها و کدهای رویداد آن‌ها به‌شدت وابسته به مدل دقیق پردازنده هستند. یعنی کدی که در پردازندۀ Intel Skylake برای مانیتور کردن پرش‌های اشتباه می‌زنید، در پردازندۀ AMD Zen 3 یا حتی در نسل جدیدتر خود اینتل ممکن است کاملاً متفاوت باشد. این نبود استاندارد باعث می‌شود ابزارها و اسکریپت‌های مانیتورینگ شما پرتابل نباشند و با جابه‌جایی سرور، به‌راحتی از کار بیفتند.

به‌طور خلاصه، ابزارهایی مثل perf stat بخش زیادی از این چالش‌های سخت‌افزاری را برای ما پنهان می‌کنند و یک خروجی تمیز تحویل می‌دهند؛ اما پشت پرده، این نبرد ثانیه‌ای رجیسترهاست که قدرت واقعی سیستم را نمایان می‌کند.

مطالب مرتبط