دام عملکردی store forwarding: وقتی load از store بزرگ‌تر است

چرا مهم است

اگر با دسترسی‌های کوچک و بزرگ به یک buffer کار می‌کنی، اندازه و هم‌پوشانی آن‌ها می‌تواند باعث شکست store forwarding شود. آزمایش‌های مقاله نشان می‌دهند هزینهٔ این الگو روی پردازنده‌های مختلف یکسان نیست.

قبل از خواندن، این‌ها را بدان۴ مفهوم
store forwarding

سازوکاری که به load اجازه می‌دهد دادهٔ نوشته‌شده را پیش از رسیدن به cache،؜ از store buffer دریافت کند.

بیشتر درباره این مفهوم

store buffer

محلی در پردازنده که دادهٔ عملیات store پیش از رسیدن به cache در آن قرار می‌گیرد.

بیشتر درباره این مفهوم

cache

حافظه‌ای نزدیک پردازنده برای نگهداری داده و کاهش نیاز به دسترسی به حافظهٔ اصلی.

بیشتر درباره این مفهوم

register

محل نگهداری مقدار درون پردازنده که دستورها می‌توانند برای محاسبه و تغییر داده از آن استفاده کنند.

بیشتر درباره این مفهوم

عملیات store مستقیماً به cache نمی‌رود؛ ابتدا در store buffer قرار می‌گیرد، چون انتظار برای تکمیل نوشتن، پردازنده را متوقف می‌کند. یک load بعدی می‌تواند داده را از همین buffer بگیرد؛ این سازوکار store forwarding نام دارد. اما اندازه و محدودهٔ دسترسی تعیین می‌کنند که این مسیر قابل استفاده باشد یا نه.

طبق مقاله، store forwarding زمانی کار می‌کند که load هم‌اندازهٔ store باشد، یا کوچک‌تر باشد و کاملاً داخل محدودهٔ آن قرار بگیرد. اگر load بزرگ‌تر باشد یا دو محدوده فقط بخشی از یکدیگر را بپوشانند، این سازوکار شکست می‌خورد و load باید منتظر رسیدن store به cache بماند.

نمونهٔ مقاله در C ابتدا با memcpy یک byte را در buffer بازنویسی می‌کند و سپس با memcpy هشت byte را از همان آدرس می‌خواند. این الگو معمولاً باعث شکست store forwarding می‌شود. نوشتن چهار byte و سپس خواندن هشت byte نیز همین مسئله را دارد. حتی نوشتن و خواندن هشت byte هم اگر خواندن از چهار byte جلوتر آغاز شود، به‌دلیل هم‌پوشانی ناقص مشکل‌ساز است.

راه جایگزینِ نشان‌داده‌شده، انجام تغییر در register است: ابتدا هشت byte خوانده می‌شود، مقدار با عملیات بیتی تغییر می‌کند و سپس نتیجهٔ هشت‌byte‌ای نوشته و همان مقدار برگردانده می‌شود. همچنین اگر همان هشت byte نوشته‌شده دوباره خوانده شود، compiler ممکن است خواندن مجدد را حذف کند.

در آزمایش‌های نویسنده، الگوی نوشتن و خواندن هشت byte از یک آدرس در Xeon Gold 6548N،؜ Xeon 6975P-C و EPYC 9R45 یک cycle طول کشید. با نوشتن چهار byte و خواندن هشت byte،؜ این عدد در دو Xeon به ۱۹ و در EPYC به ۱۴ رسید. همین الگو در Graviton 5 و Apple M4 Max پنج cycle زمان برد. دو نوشتنِ چهارbyte‌ای پیش از خواندن هشت byte نیز برای Apple M4 Max هشت cycle ثبت کرد. این اندازه‌گیری‌ها نشان می‌دهند هزینهٔ الگوهای بررسی‌شده به پردازنده وابسته است.

نکته کلیدی

وقتی پس از نوشتن چند byte مقدار بزرگ‌تری می‌خوانی، محدودهٔ دو دسترسی را بررسی کن. الگوی جایگزین مقاله را به خاطر بسپار: مقدار را ابتدا بخوان، در register تغییر بده و نتیجه را بنویس.

خواندن مقاله اصلی (در زبانه‌ی جدید باز می‌شود)
برچسب‌ها (۳)