برنامه نویسی

بهبود بهره وری با CMake و ادغام کش کامپایلر

Summarize this content to 400 words in Persian Lang

معرفی

زمان ساخت می تواند به طور قابل توجهی بر بهره وری توسعه دهندگان تأثیر بگذارد. در حالی که آنچه که ساخت کند یا سریع است ذهنی است، واضح است که ساخت‌های آهسته حلقه‌های بازخورد طولانی‌تری ایجاد می‌کنند و منجر به سوئیچ‌های زمینه بیشتری می‌شوند که در نتیجه بهره‌وری کاهش می‌یابد.

کامپایلرهای C++ کند هستند و استفاده از کتابخانه استاندارد C++ و سایر کتابخانه های محبوب، به ویژه آنهایی که فقط سربرگ دارند، این موضوع را تشدید می کند. در اینجا، می توانید هزینه را از نظر زمان ساخت برای گنجاندن هدرهای خاص بررسی کنید.

یک مطالعه نشان می دهد که حتی پیشرفت های اندک در زمان ساخت می تواند بر بهره وری توسعه دهندگان تأثیر مثبت بگذارد.

راه اثبات شده برای بهینه سازی زمان ساخت

یکی از راه های اثبات شده برای بهینه سازی زمان ساخت، استفاده از برنامه های کش کامپایلر مانند ccache یا scache است. این برنامه ها نتایج کامپایل را در حافظه پنهان ذخیره می کنند و مجدداً از آنها استفاده می کنند و اگر ورودی ها تغییر نکرده باشند، تماس های بعدی کامپایلر را حذف می کنند.

با توجه به اندازه گیری های عملکرد انجام شده توسط تیم ccache، بهبود زمان ساخت در کامپایل های بعدی می تواند از 5x تا 145x باشد.

از تجربه شخصی من، بسته به عوامل متعددی مانند سخت افزار ماشین ساخت، سیستم عامل، کامپایلر و کد منبع پروژه، بهبودهای واقعی می تواند از 1.5x تا 10x متغیر باشد.

بنابراین، معامله چیست؟

اگر برنامه‌های کش کامپایلر می‌توانند چنین پیشرفت‌هایی را به ارمغان بیاورند، چرا در همه جا برای هر پروژه C++ استفاده نمی‌شوند؟ یکی از پاسخ های احتمالی دشواری ادغام است. چندین سیستم ساخت و انواع کامپایلر وجود دارد که هر کدام در هنگام ادغام برنامه های کش کامپایلر ویژگی های خاص خود را دارند. ماهیت چند پلتفرمی نرم افزار مدرن، پیچیدگی بیشتری را به فرآیند یکپارچه سازی اضافه می کند.

امروزه، برای بسیاری از پروژه‌های نرم‌افزاری C/C++ کراس پلتفرم، CMake سیستم ساخت‌وساز است. طبق نظرسنجی توسعه‌دهندگان Stack Overflow در سال 2023، 14.34 درصد از توسعه‌دهندگان از CMake استفاده می‌کنند و تنها Make است که به‌عنوان یک سیستم ساخت C++ بین پلتفرمی بیشتر استفاده می‌شود. با این حال، اگر به scache README نگاه کنید، یک بخش طولانی در مورد نحوه شروع استفاده از کش کامپایلر و قابل استفاده کردن آن با CMake وجود دارد. این بخش تمام ترکیبات ممکن از سیستم عامل ها، کامپایلرها و ژنراتورهای پشتیبانی شده توسط CMake را پوشش نمی دهد.

راه حل برای CMake

برای حل این مشکل ماژول cmake-findccache ایجاد شد. همانطور که از نام آن پیداست، یک برنامه کش کامپایلر مناسب پیدا می کند و پروژه CMake را برای فعال کردن استفاده از کش کامپایلر پیکربندی می کند.

این برنامه از ژنراتورهای Xcode، Ninja، Unix Makefiles و Visual Studio پشتیبانی می کند و با کامپایلرهای gcc، clang و MSVC در لینوکس، macOS و ویندوز آزمایش شده است.

همانطور که در پروژه مثال نشان داده شده است، در بیشتر موارد، تنها به چند خط برای فعال کردن استفاده از ccache نیاز است:

list(APPEND CMAKE_MODULE_PATH “${CMAKE_SOURCE_DIR}/..”)

find_package(ccache)

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به طور پیش فرض، ماژول فقط به دنبال آن خواهد بود ccache. برای امتحان سایر برنامه های کش کامپایلر، آن را تعریف کنید CCACHE_PROGRAMS متغیر با لیست برنامه های کش کامپایلر مورد نظر به ترتیب اولویت، به عنوان مثال:

set(CCACHE_PROGRAMS “ccache;sccache;buildcache” CACHE STRING _ FORCE)

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر یک برنامه ccache پیدا شد و ژنراتور پشتیبانی می‌شود، گزارش فاز پیکربندی CMake باید حاوی خطوطی مشابه موارد زیر باشد:

— Found ccache: /usr/bin/ccache
— Using compiler cache: YES

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس از اولین ساخت موفقیت آمیز پروژه، با اجرا کردن، آمار ccache را بررسی کنید ccache –show-stats. نتیجه باید مشابه خروجی زیر باشد. آمار تماس‌های کش باید غیر صفر باشد و پس از اولین ساخت، بیشتر تماس‌ها به دلیل خالی بودن کش منجر به از دست رفتن حافظه پنهان می‌شوند.

Cacheable calls: 2 / 2 (100.0%)
Hits: 0 / 2 ( 0.00%)
Direct: 0
Preprocessed: 0
Misses: 2 / 2 (100.0%)
Local storage:
Cache size (GiB): 0.0 / 5.0 ( 0.00%)
Hits: 0 / 2 ( 0.00%)
Misses: 2 / 2 (100.0%)

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در ساخت‌های بعدی، آمار تماس‌های ذخیره‌سازی شده باید به همراه تعداد بازدیدها افزایش یابد. مثلا:

Cacheable calls: 4 / 4 (100.0%)
Hits: 2 / 4 (50.00%)
Direct: 2 / 2 (100.0%)
Preprocessed: 0 / 2 ( 0.00%)
Misses: 2 / 4 (50.00%)
Local storage:
Cache size (GiB): 0.0 / 5.0 ( 0.00%)
Hits: 2 / 4 (50.00%)
Misses: 2 / 4 (50.00%)

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این زمانی است که زمان کامپایل باید کاهش یابد، به لطف استفاده از نتایج کش شده به جای فراخوانی کامپایلر!

اما… هنوز هم تجربی و شکننده است

پس از بررسی ترکیب‌های بیشتری از سیستم‌عامل‌ها، ژنراتورها و کامپایلرها، مشخص شد که در برخی از ترکیب‌ها، کش کامپایلر آن‌طور که انتظار می‌رود کار نمی‌کند:

در ویندوز با MSYS2، هیچکدام mingw64 نه clang64 با Ninja ژنراتور، در نتیجه یک ccache: error: Could not find compiler “D:\a\_temp\msys64\clang64\bin\clang++.exe” in PATH خطا در حین تدوین
در ویندوز GitHub Runner (Windows Server 2019) با CL کامپایلر و Visual Studio 17 2022 ژنراتور، ccache رفتار عجیبی دارد. نتایج کامپایل را از اولین اجرای بیلد ذخیره می‌کند، اما برای اجرای دوم، کامپایل‌ها اصلاً در آمار لحاظ نمی‌شوند. با این حال، در Windows 10 Pro، راه اندازی مشابه به خوبی کار می کند.

بهبودهای بیشتر

برای مشکلات فوق راه حل هایی را برطرف کنید یا پیدا کنید.
اضافه کردن پشتیبانی برای کامپایلرهای بیشتر، مانند clang-cl.
با سایر ابزارهای کش تست کنید، مانند sccache.

برای بهبود پشتیبانی کش کامپایلر در CMake، به راحتی می توانید درخواست های کشش را به پروژه cmake-findccache شبیه سازی کنید و ارسال کنید!

نتیجه

پشتیبانی کش کامپایلر می تواند بهبود قابل توجهی در زمان ساخت و افزایش بهره وری داشته باشد. با این حال، حتی با وجود ادغام بهبود یافته بین برنامه‌های حافظه پنهان CMake و کامپایلر ارائه شده توسط cmake-findccache، این ویژگی در برخی از پلتفرم‌ها و پیکربندی‌ها یک ویژگی آزمایشی یا غیرقابل دسترس باقی می‌ماند.

معرفی

زمان ساخت می تواند به طور قابل توجهی بر بهره وری توسعه دهندگان تأثیر بگذارد. در حالی که آنچه که ساخت کند یا سریع است ذهنی است، واضح است که ساخت‌های آهسته حلقه‌های بازخورد طولانی‌تری ایجاد می‌کنند و منجر به سوئیچ‌های زمینه بیشتری می‌شوند که در نتیجه بهره‌وری کاهش می‌یابد.

کامپایلرهای C++ کند هستند و استفاده از کتابخانه استاندارد C++ و سایر کتابخانه های محبوب، به ویژه آنهایی که فقط سربرگ دارند، این موضوع را تشدید می کند. در اینجا، می توانید هزینه را از نظر زمان ساخت برای گنجاندن هدرهای خاص بررسی کنید.

یک مطالعه نشان می دهد که حتی پیشرفت های اندک در زمان ساخت می تواند بر بهره وری توسعه دهندگان تأثیر مثبت بگذارد.

راه اثبات شده برای بهینه سازی زمان ساخت

یکی از راه های اثبات شده برای بهینه سازی زمان ساخت، استفاده از برنامه های کش کامپایلر مانند ccache یا scache است. این برنامه ها نتایج کامپایل را در حافظه پنهان ذخیره می کنند و مجدداً از آنها استفاده می کنند و اگر ورودی ها تغییر نکرده باشند، تماس های بعدی کامپایلر را حذف می کنند.

با توجه به اندازه گیری های عملکرد انجام شده توسط تیم ccache، بهبود زمان ساخت در کامپایل های بعدی می تواند از 5x تا 145x باشد.

از تجربه شخصی من، بسته به عوامل متعددی مانند سخت افزار ماشین ساخت، سیستم عامل، کامپایلر و کد منبع پروژه، بهبودهای واقعی می تواند از 1.5x تا 10x متغیر باشد.

بنابراین، معامله چیست؟

اگر برنامه‌های کش کامپایلر می‌توانند چنین پیشرفت‌هایی را به ارمغان بیاورند، چرا در همه جا برای هر پروژه C++ استفاده نمی‌شوند؟ یکی از پاسخ های احتمالی دشواری ادغام است. چندین سیستم ساخت و انواع کامپایلر وجود دارد که هر کدام در هنگام ادغام برنامه های کش کامپایلر ویژگی های خاص خود را دارند. ماهیت چند پلتفرمی نرم افزار مدرن، پیچیدگی بیشتری را به فرآیند یکپارچه سازی اضافه می کند.

امروزه، برای بسیاری از پروژه‌های نرم‌افزاری C/C++ کراس پلتفرم، CMake سیستم ساخت‌وساز است. طبق نظرسنجی توسعه‌دهندگان Stack Overflow در سال 2023، 14.34 درصد از توسعه‌دهندگان از CMake استفاده می‌کنند و تنها Make است که به‌عنوان یک سیستم ساخت C++ بین پلتفرمی بیشتر استفاده می‌شود. با این حال، اگر به scache README نگاه کنید، یک بخش طولانی در مورد نحوه شروع استفاده از کش کامپایلر و قابل استفاده کردن آن با CMake وجود دارد. این بخش تمام ترکیبات ممکن از سیستم عامل ها، کامپایلرها و ژنراتورهای پشتیبانی شده توسط CMake را پوشش نمی دهد.

راه حل برای CMake

برای حل این مشکل ماژول cmake-findccache ایجاد شد. همانطور که از نام آن پیداست، یک برنامه کش کامپایلر مناسب پیدا می کند و پروژه CMake را برای فعال کردن استفاده از کش کامپایلر پیکربندی می کند.

این برنامه از ژنراتورهای Xcode، Ninja، Unix Makefiles و Visual Studio پشتیبانی می کند و با کامپایلرهای gcc، clang و MSVC در لینوکس، macOS و ویندوز آزمایش شده است.

همانطور که در پروژه مثال نشان داده شده است، در بیشتر موارد، تنها به چند خط برای فعال کردن استفاده از ccache نیاز است:

list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/..")

find_package(ccache)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به طور پیش فرض، ماژول فقط به دنبال آن خواهد بود ccache. برای امتحان سایر برنامه های کش کامپایلر، آن را تعریف کنید CCACHE_PROGRAMS متغیر با لیست برنامه های کش کامپایلر مورد نظر به ترتیب اولویت، به عنوان مثال:

set(CCACHE_PROGRAMS "ccache;sccache;buildcache" CACHE STRING _ FORCE)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر یک برنامه ccache پیدا شد و ژنراتور پشتیبانی می‌شود، گزارش فاز پیکربندی CMake باید حاوی خطوطی مشابه موارد زیر باشد:

-- Found ccache: /usr/bin/ccache
-- Using compiler cache: YES
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس از اولین ساخت موفقیت آمیز پروژه، با اجرا کردن، آمار ccache را بررسی کنید ccache --show-stats. نتیجه باید مشابه خروجی زیر باشد. آمار تماس‌های کش باید غیر صفر باشد و پس از اولین ساخت، بیشتر تماس‌ها به دلیل خالی بودن کش منجر به از دست رفتن حافظه پنهان می‌شوند.

Cacheable calls:      2 /   2 (100.0%)
  Hits:               0 /   2 ( 0.00%)
    Direct:           0
    Preprocessed:     0
  Misses:             2 /   2 (100.0%)
Local storage:
  Cache size (GiB): 0.0 / 5.0 ( 0.00%)
  Hits:               0 /   2 ( 0.00%)
  Misses:             2 /   2 (100.0%)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در ساخت‌های بعدی، آمار تماس‌های ذخیره‌سازی شده باید به همراه تعداد بازدیدها افزایش یابد. مثلا:

Cacheable calls:      4 /   4 (100.0%)
  Hits:               2 /   4 (50.00%)
    Direct:           2 /   2 (100.0%)
    Preprocessed:     0 /   2 ( 0.00%)
  Misses:             2 /   4 (50.00%)
Local storage:
  Cache size (GiB): 0.0 / 5.0 ( 0.00%)
  Hits:               2 /   4 (50.00%)
  Misses:             2 /   4 (50.00%)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این زمانی است که زمان کامپایل باید کاهش یابد، به لطف استفاده از نتایج کش شده به جای فراخوانی کامپایلر!

اما… هنوز هم تجربی و شکننده است

پس از بررسی ترکیب‌های بیشتری از سیستم‌عامل‌ها، ژنراتورها و کامپایلرها، مشخص شد که در برخی از ترکیب‌ها، کش کامپایلر آن‌طور که انتظار می‌رود کار نمی‌کند:

  • در ویندوز با MSYS2، هیچکدام mingw64 نه clang64 با Ninja ژنراتور، در نتیجه یک ccache: error: Could not find compiler "D:\a\_temp\msys64\clang64\bin\clang++.exe" in PATH خطا در حین تدوین
  • در ویندوز GitHub Runner (Windows Server 2019) با CL کامپایلر و Visual Studio 17 2022 ژنراتور، ccache رفتار عجیبی دارد. نتایج کامپایل را از اولین اجرای بیلد ذخیره می‌کند، اما برای اجرای دوم، کامپایل‌ها اصلاً در آمار لحاظ نمی‌شوند. با این حال، در Windows 10 Pro، راه اندازی مشابه به خوبی کار می کند.

بهبودهای بیشتر

  • برای مشکلات فوق راه حل هایی را برطرف کنید یا پیدا کنید.
  • اضافه کردن پشتیبانی برای کامپایلرهای بیشتر، مانند clang-cl.
  • با سایر ابزارهای کش تست کنید، مانند sccache.

برای بهبود پشتیبانی کش کامپایلر در CMake، به راحتی می توانید درخواست های کشش را به پروژه cmake-findccache شبیه سازی کنید و ارسال کنید!

نتیجه

پشتیبانی کش کامپایلر می تواند بهبود قابل توجهی در زمان ساخت و افزایش بهره وری داشته باشد. با این حال، حتی با وجود ادغام بهبود یافته بین برنامه‌های حافظه پنهان CMake و کامپایلر ارائه شده توسط cmake-findccache، این ویژگی در برخی از پلتفرم‌ها و پیکربندی‌ها یک ویژگی آزمایشی یا غیرقابل دسترس باقی می‌ماند.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا